From 3ba3a95d05adec9af14de18b85e086daa0b8fea7 Mon Sep 17 00:00:00 2001 From: Chris Sangwin <C.J.Sangwin@ed.ac.uk> Date: Wed, 1 Jun 2022 08:54:57 +0100 Subject: [PATCH] Squashed commit of the following: commit 292bab008c6507b1cd565e293baf8e6ce390bbde Author: Chris Sangwin <C.J.Sangwin@ed.ac.uk> Date: Wed Jun 1 08:13:30 2022 +0100 Update the docs. commit b4330bdfdb24bf85fd6c5feeb84e89fe22613b89 Author: Chris Sangwin <C.J.Sangwin@ed.ac.uk> Date: Wed Jun 1 07:35:37 2022 +0100 Add namespace: further code tidy. commit e1b8ca10386039794fd730fb62dcd59a2f3b096a Merge: b86ea123 e73cd13f Author: Chris Sangwin <C.J.Sangwin@ed.ac.uk> Date: Wed Jun 1 05:13:34 2022 +0100 Merge branch 'jsxgraph_update' of https://github.com/maths/moodle-qtype_stack into jsxgraph_update commit b86ea123b616dd58cb794d81ec71b7931a770ff6 Author: Chris Sangwin <C.J.Sangwin@ed.ac.uk> Date: Wed Jun 1 05:12:36 2022 +0100 Code tidy: add namespace to unit test classes (WIP). commit e73cd13fac2ca4e0b5b057f20438db44a0a1c3e6 Merge: 3b362d45 abe2a2e0 Author: Chris Sangwin <c.j.sangwin@gmail.com> Date: Tue May 31 18:05:39 2022 +0100 Merge pull request #806 from timhunt/fix-behat Update Behat tests to work with 4.0 commit f5f2676bebc040e6f92957063baa8ff15d316f79 Author: Chris Sangwin <C.J.Sangwin@ed.ac.uk> Date: Tue May 31 17:23:49 2022 +0100 Move mariadb test to older moodle. commit abe2a2e0395c8d4dfb80082f406f8c2a63e1a878 Author: Tim Hunt <T.J.Hunt@open.ac.uk> Date: Tue May 31 15:46:53 2022 +0100 Update Behat tests to work with 4.0 commit 3b362d450e7e70a5c9fc5cad1c5fd9f6b5658c33 Author: Chris Sangwin <C.J.Sangwin@ed.ac.uk> Date: Tue May 31 17:10:53 2022 +0100 WIP code tidy. commit 46435f94fbd0cb52371a16839d0d2901df65145d Author: Chris Sangwin <C.J.Sangwin@ed.ac.uk> Date: Tue May 31 16:46:22 2022 +0100 Rebuild JS files. commit 9380fb70fd03da82c739c45e14a4c1652c84b6d8 Author: Chris Sangwin <C.J.Sangwin@ed.ac.uk> Date: Tue May 31 16:02:33 2022 +0100 WIP code tidy: add coverage information to test classes. commit 4466fbca411d34c718f14712e02185ddad32c8c9 Author: Chris Sangwin <C.J.Sangwin@ed.ac.uk> Date: Tue May 31 15:59:22 2022 +0100 Code tidy: revert attempt to add namespace and coverage. commit f5114460a758431724d9b814d7b58f9253bfb6c7 Author: Chris Sangwin <C.J.Sangwin@ed.ac.uk> Date: Tue May 31 15:45:23 2022 +0100 WIP: code tidy, adding namespace to test files. commit 742fc9de1a2036054f64526324a0adbd7b3af176 Author: Chris Sangwin <C.J.Sangwin@ed.ac.uk> Date: Tue May 31 15:12:13 2022 +0100 Code tidy. commit b4d67fb5cd712c0e4fb8f09ccab93f643fc82d76 Author: Chris Sangwin <c.j.sangwin@gmail.com> Date: Tue May 31 13:29:10 2022 +0100 Update Updating_JSXGraph.md Update the docs. commit 9ac55ec2b7837ed2fb7efe6d831b9cdd0d0485d0 Author: Michael Kallweit <michael.kallweit@rub.de> Date: Tue May 31 12:22:12 2022 +0200 Added source map for minified jsxgraph commit 79df67068d06769f7140ec0b5f59e39faaa4fa83 Author: Chris Sangwin <C.J.Sangwin@ed.ac.uk> Date: Tue May 31 08:00:46 2022 +0100 Rebuild input.min.js.map, and update the docs. commit d63364e5dfe6d5bf3d9ae52017b00817a57937db Author: Chris Sangwin <C.J.Sangwin@ed.ac.uk> Date: Mon May 30 22:26:52 2022 +0100 Postpone unit test to dev branch. commit 2f946df443f92855be5c15ef7e42df4e3374c8d1 Author: Chris Sangwin <C.J.Sangwin@ed.ac.uk> Date: Mon May 30 21:43:06 2022 +0100 Move commented out code to future plans. commit 3b1bfed1079cba839318e64818975949e751f534 Author: Chris Sangwin <C.J.Sangwin@ed.ac.uk> Date: Mon May 30 20:53:23 2022 +0100 Code tidy. commit f20be9a1a9e1766444b84fbec02eb1a5d8f871cd Author: Chris Sangwin <C.J.Sangwin@ed.ac.uk> Date: Mon May 30 20:22:17 2022 +0100 Update google-ci config to fix unit tests, remove references to travis and tidy. commit ef99433f3924c613e8c1702f58fa9b45a041e521 Author: Chris Sangwin <C.J.Sangwin@ed.ac.uk> Date: Mon May 30 18:13:04 2022 +0100 Adopt moodle-ci. commit e37b68a67832bf396bd5548683a76a646165cce9 Merge: 887e5dfb fccc53de Author: Chris Sangwin <C.J.Sangwin@ed.ac.uk> Date: Mon May 30 16:26:39 2022 +0100 Merge branch 'jsxgraph_update' of https://github.com/maths/moodle-qtype_stack into jsxgraph_update commit 887e5dfbc600c84a2ac514f7ab7a485098d554d4 Author: Chris Sangwin <C.J.Sangwin@ed.ac.uk> Date: Mon May 30 16:26:30 2022 +0100 Bump version number. commit fccc53de573d68ad5ebcb4ff44ef57cd40d6da6a Author: Michael Kallweit <michael.kallweit@rub.de> Date: Mon May 30 17:16:04 2022 +0200 Minor text changes commit e69739ed5fa7b4c388eddbc55c5bb79b84b23b8a Author: Michael Kallweit <michael.kallweit@rub.de> Date: Mon May 30 17:06:44 2022 +0200 Added doc on how to update jsxgraph commit e3c44f236a94fafcf9fccc123a6bab3e8b1e9099 Merge: dc422f00 869d228b Author: Chris Sangwin <C.J.Sangwin@ed.ac.uk> Date: Mon May 30 15:55:18 2022 +0100 Merge branch 'jsxgraph_update' of https://github.com/maths/moodle-qtype_stack into jsxgraph_update commit dc422f007e33773482b4fbbbc36aced10b0b0de8 Author: Chris Sangwin <C.J.Sangwin@ed.ac.uk> Date: Mon May 30 15:54:27 2022 +0100 Prepare for the 4.3.11 release. commit 869d228b0989dc25054d2103eb6e0cb446289c16 Author: Michael Kallweit <michael.kallweit@rub.de> Date: Mon May 30 16:38:03 2022 +0200 Added minified file for jsxgraph 1.4.4 commit bbcc9f0be0f6f09298dc13f7dfd1b12615295cf0 Author: Michael Kallweit <michael.kallweit@rub.de> Date: Mon May 30 14:21:43 2022 +0200 Update JSXGraph to 1.4.4 --- .github/workflows/moodle-ci.yml | 157 + .travis.yml | 128 - Readme.md | 4 +- amd/build/input.min.js | 26 +- amd/build/input.min.js.map | 2 +- amd/build/jsxgraph.min.js | 5 +- amd/build/jsxgraph.min.js.map | 2 +- amd/build/jsxgraphcore-lazy.min.js | 86 +- amd/build/jsxgraphcore-lazy.min.js.map | 1 + amd/src/input.js | 2 +- amd/src/jsxgraph.js | 34 +- amd/src/jsxgraphcore-lazy.js | 73632 +++++++++------- .../backup_qtype_stack_plugin.class.php | 4 - classes/privacy/provider.php | 1 - cli/ast_test_generator.php | 6 + doc/en/Developer/Development_history.md | 7 + doc/en/Developer/Development_track.md | 2 - doc/en/Developer/Future_plans.md | 6 + doc/en/Developer/Releasing.md | 9 +- doc/en/Developer/Unit_tests.md | 9 +- doc/en/Developer/Updating_JSXGraph.md | 48 + doc/meta_en.json | 5 + lib.php | 4 - questiontestrun.php | 5 +- renderer.php | 2 - stack/answertest/anstest.class.php | 2 - stack/bulktester.class.php | 4 +- stack/cas/castext/block.factory.php | 2 - stack/cas/connector.dbcache.class.php | 2 - stack/cas/connector.interface.php | 2 - stack/cas/connector.linux.class.php | 2 - stack/cas/connector.server.class.php | 2 - stack/cas/connector.windows.class.php | 2 - .../542_no_functions_at_all.filter.php | 2 +- stack/graphlayout/graphclump.php | 4 - stack/graphlayout/graphnode.php | 4 - stack/graphlayout/svgrenderer.php | 4 - stack/input/algebraic/algebraic.class.php | 2 - stack/input/boolean/boolean.class.php | 2 - stack/input/dropdown/dropdown.class.php | 2 - stack/input/matrix/matrix.class.php | 2 - stack/input/numerical/numerical.class.php | 2 - stack/input/singlechar/singlechar.class.php | 2 - stack/input/units/units.class.php | 2 - stack/input/varmatrix/varmatrix.class.php | 2 - stack/mathsoutput/fact_sheets.class.php | 2 - stack/maxima/stackmaxima.mac | 2 +- stack/options.class.php | 2 - stack/questiontestresult.php | 2 - styles.css | 2 +- tests/answertest_general_cas_test.php | 11 + tests/answertest_general_fixtures_test.php | 7 +- tests/ast_container_test.php | 7 + ...00_099_common_core_auto_generated_test.php | 6 + ..._group_or_function_auto_generated_test.php | 6 + ...lter_002_log_candy_auto_generated_test.php | 6 + ...ter_003_no_dot_dot_auto_generated_test.php | 6 + ...s_never_a_function_auto_generated_test.php | 6 + ...g_replace_synonyms_auto_generated_test.php | 6 + ..._025_no_trig_power_auto_generated_test.php | 6 + ..._030_no_trig_space_auto_generated_test.php | 6 + ...1_no_trig_brackets_auto_generated_test.php | 6 + ...ained_inequalities_auto_generated_test.php | 6 + ...rbidden_characters_auto_generated_test.php | 6 + ...lter_101_no_floats_auto_generated_test.php | 6 + ...ter_102_no_strings_auto_generated_test.php | 6 + ...ilter_103_no_lists_auto_generated_test.php | 6 + ...filter_104_no_sets_auto_generated_test.php | 6 + ..._105_no_grouppings_auto_generated_test.php | 6 + ...06_no_control_flow_auto_generated_test.php | 6 + ..._filter_120_no_arc_auto_generated_test.php | 6 + ...ig_figs_validation_auto_generated_test.php | 6 + ..._places_validation_auto_generated_test.php | 6 + ..._as_multiplication_auto_generated_test.php | 6 + ...mmon_function_name_auto_generated_test.php | 6 + ...er_letter_boundary_auto_generated_test.php | 6 + ...er_number_boundary_auto_generated_test.php | 6 + ...ied_variable_names_auto_generated_test.php | 6 + ...0_single_char_vars_auto_generated_test.php | 6 + ...olidate_subscripts_auto_generated_test.php | 6 + ..._unknown_functions_auto_generated_test.php | 6 + ...plit_all_functions_auto_generated_test.php | 6 + ...r_450_split_floats_auto_generated_test.php | 6 + ...ter_502_replace_pm_auto_generated_test.php | 6 + ..._tuples_for_groups_auto_generated_test.php | 6 + ..._evaluation_groups_auto_generated_test.php | 6 + ...quality_with_logic_auto_generated_test.php | 6 + ..._unknown_functions_auto_generated_test.php | 6 + ...o_functions_at_all_auto_generated_test.php | 6 + ..._singleton_numeric_auto_generated_test.php | 6 + ...02_singleton_units_auto_generated_test.php | 6 + ..._float_for_display_auto_generated_test.php | 6 + ...0_no_fixing_spaces_auto_generated_test.php | 6 + ...91_no_fixing_stars_auto_generated_test.php | 6 + ...97_string_security_auto_generated_test.php | 6 + ...ilter_998_security_auto_generated_test.php | 6 + ..._filter_999_strict_auto_generated_test.php | 6 + tests/behat/create_preview_edit.feature | 9 +- tests/behat/restore_demo.feature | 2 +- .../validation_no_maths_in_question.feature | 10 +- tests/behat/xml_import.feature | 7 +- tests/caskeyval_exception_test.php | 8 +- tests/caskeyval_test.php | 8 + tests/cassession2_exception_test.php | 8 + tests/cassession2_test.php | 14 +- tests/castext_exception_test.php | 9 +- tests/castext_test.php | 11 + tests/connection_test.php | 5 + tests/docslib_test.php | 4 + tests/fact_sheets_test.php | 5 + tests/fixtures/answertestfixtures.class.php | 16 +- tests/fixtures/equivfixtures.class.php | 58 +- tests/fixtures/inputfixtures.class.php | 12 +- .../fixtures/maximacorrectiveparser.class.php | 4 +- tests/fixtures/numbersfixtures.class.php | 5 +- tests/fixtures/subscriptsfixtures.class.php | 2 - tests/fixtures/test_base.php | 26 +- .../generator/behat_qtype_stack_generator.php | 3 - tests/generator/lib.php | 2 - tests/graphlayout_test.php | 7 +- tests/helper.php | 2 - tests/input_algebraic_test.php | 9 + tests/input_boolean_validation_test.php | 8 + tests/input_checkbox_test.php | 11 +- tests/input_dropdown_exception_test.php | 10 +- tests/input_equiv_test.php | 14 +- tests/input_matrix_test.php | 14 +- tests/input_notes_test.php | 10 + tests/input_numerical_test.php | 10 + tests/input_singlechar_test.php | 10 + tests/input_singlechar_validation_test.php | 9 + tests/input_string_test.php | 10 + tests/input_textarea_test.php | 10 +- tests/input_units_test.php | 9 + tests/input_varmatrix_test.php | 9 + tests/inputstate_test.php | 7 + tests/mathsoutputmathjax_test.php | 6 + tests/mathsoutputtex_test.php | 6 + tests/maxima_corrective_parser_test.php | 5 + tests/multilang_test.php | 5 + tests/parser_rule_201_test.php | 7 + tests/parser_rule_202_test.php | 7 + tests/parser_rule_410_test.php | 7 + tests/parser_rule_541_test.php | 7 + tests/parser_rule_542_test.php | 7 + tests/parser_rule_801_test.php | 7 + tests/parser_test.php | 7 + tests/potentialresponsenode_test.php | 8 + tests/potentialresponsetree_test.php | 11 + tests/restore_logic_test.php | 11 +- tests/stack_options_test.php | 9 +- tests/stack_utils_test.php | 6 + tests/studentinput_test.php | 7 +- tests/subscript_test.php | 7 +- thirdpartylibs.xml | 7 +- version.php | 4 +- 156 files changed, 42501 insertions(+), 32561 deletions(-) create mode 100644 .github/workflows/moodle-ci.yml delete mode 100644 .travis.yml create mode 100644 amd/build/jsxgraphcore-lazy.min.js.map create mode 100644 doc/en/Developer/Updating_JSXGraph.md diff --git a/.github/workflows/moodle-ci.yml b/.github/workflows/moodle-ci.yml new file mode 100644 index 000000000..1c7b864e1 --- /dev/null +++ b/.github/workflows/moodle-ci.yml @@ -0,0 +1,157 @@ +name: Moodle Plugin CI + +on: [push, pull_request] + +jobs: + test: + runs-on: ubuntu-18.04 + + services: + postgres: + image: postgres:10 + env: + POSTGRES_USER: 'postgres' + POSTGRES_HOST_AUTH_METHOD: 'trust' + ports: + - 5432:5432 + options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 3 + mariadb: + image: mariadb:10 + env: + MYSQL_USER: 'root' + MYSQL_ALLOW_EMPTY_PASSWORD: "true" + MYSQL_CHARACTER_SET_SERVER: "utf8mb4" + MYSQL_COLLATION_SERVER: "utf8mb4_unicode_ci" + + ports: + - 3306:3306 + options: --health-cmd="mysqladmin ping" --health-interval 10s --health-timeout 5s --health-retries 3 + + strategy: + fail-fast: false + matrix: # I don't know why, but mariadb is much slower, so mostly use pgsql. + include: + - php: '7.4' + moodle-branch: 'master' + database: 'pgsql' + - php: '7.4' + moodle-branch: 'MOODLE_311_STABLE' + database: 'pgsql' + - php: '7.3' + moodle-branch: 'MOODLE_310_STABLE' + database: 'pgsql' + - php: '7.2' + moodle-branch: 'MOODLE_39_STABLE' + database: 'pgsql' + - php: '7.1' + moodle-branch: 'MOODLE_38_STABLE' + database: 'mariadb' + + steps: + - name: Install required libraries + run: | + sudo apt-get install gnuplot maxima maxima-share texinfo + maxima --list-avail + echo "diff(x^2,x);" | maxima + + - name: Check out repository code + uses: actions/checkout@v2 + with: + path: plugin + + - name: Setup PHP ${{ matrix.php }} + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + extensions: ${{ matrix.extensions }} + ini-values: max_input_vars=5000 + coverage: none + + - name: Initialise moodle-plugin-ci + run: | + composer create-project -n --no-dev --prefer-dist moodlehq/moodle-plugin-ci ci ^3 + echo $(cd ci/bin; pwd) >> $GITHUB_PATH + echo $(cd ci/vendor/bin; pwd) >> $GITHUB_PATH + sudo locale-gen en_AU.UTF-8 + echo "NVM_DIR=$HOME/.nvm" >> $GITHUB_ENV + + - name: Install moodle-plugin-ci + run: | + moodle-plugin-ci add-plugin maths/moodle-qbehaviour_dfexplicitvaildate + moodle-plugin-ci add-plugin maths/moodle-qbehaviour_dfcbmexplicitvaildate + moodle-plugin-ci add-plugin maths/moodle-qbehaviour_adaptivemultipart + + moodle-plugin-ci install --plugin ./plugin --db-host=127.0.0.1 + + moodle-plugin-ci add-config 'define("QTYPE_STACK_TEST_CONFIG_MAXIMAVERSION", "5.41.0");' + moodle-plugin-ci add-config 'define("QTYPE_STACK_TEST_CONFIG_MAXIMACOMMAND", "maxima");' + moodle-plugin-ci add-config 'define("QTYPE_STACK_TEST_CONFIG_MAXIMACOMMANDOPT", "timeout --kill-after=10s 10s ${{ github.workspace }}/maxima_opt_auto -eval '\''(cl-user::run)'\''");' + moodle-plugin-ci add-config 'define("QTYPE_STACK_TEST_CONFIG_MAXIMACOMMANDSERVER", "http://pool.home:8080/MaximaPool/MaximaPool");' + moodle-plugin-ci add-config 'define("QTYPE_STACK_TEST_CONFIG_CASTIMEOUT", "10");' + moodle-plugin-ci add-config 'define("QTYPE_STACK_TEST_CONFIG_MAXIMALIBRARIES", "stats, distrib, descriptive, simplex");' + moodle-plugin-ci add-config 'define("QTYPE_STACK_TEST_CONFIG_CASPREPARSE", "true");' + moodle-plugin-ci add-config 'define("QTYPE_STACK_TEST_CONFIG_PLATFORM", "linux-optimised");' + moodle-plugin-ci add-config 'define("QTYPE_STACK_TEST_CONFIG_CASRESULTSCACHE", "db");' + moodle-plugin-ci add-config 'define("QTYPE_STACK_TEST_CONFIG_PLOTCOMMAND", "");' + moodle-plugin-ci add-config 'define("QTYPE_STACK_TEST_CONFIG_CASDEBUGGING", "0");' + + #cat ${{ github.workspace }}/moodle/config.php + + cp ${{ github.workspace }}/moodledata/phpu_moodledata/stack/maxima_opt_auto ${{ github.workspace }}/maxima_opt_auto + # Try a command on the command line. + # echo "1+1; quit();" | timeout --kill-after=10s 10s ${{ github.workspace }}/maxima_opt_auto -eval '(cl-user::run)' + + + env: + DB: ${{ matrix.database }} + MOODLE_BRANCH: ${{ matrix.moodle-branch }} + + - name: PHP Lint + if: ${{ always() }} + run: moodle-plugin-ci phplint + + - name: PHP Copy/Paste Detector + continue-on-error: true # This step will show errors but will not fail. + if: ${{ always() }} + run: moodle-plugin-ci phpcpd + + - name: PHP Mess Detector + continue-on-error: true # This step will show errors but will not fail. + if: ${{ always() }} + run: moodle-plugin-ci phpmd + + - name: Moodle Code Checker + continue-on-error: true # Currently fails. We really ought to get this passing. + if: ${{ always() }} + run: moodle-plugin-ci codechecker --max-warnings 0 + + - name: Moodle PHPDoc Checker + continue-on-error: true # Currently fails. We really ought to get this passing. + if: ${{ always() }} + run: moodle-plugin-ci phpdoc + + - name: Validating + if: ${{ always() }} + run: moodle-plugin-ci validate + + - name: Check upgrade savepoints + if: ${{ always() }} + run: moodle-plugin-ci savepoints + + - name: Mustache Lint + if: ${{ always() }} + run: moodle-plugin-ci mustache + + - name: Grunt + if: ${{ matrix.moodle-branch == 'MOODLE_311_STABLE' }} + run: moodle-plugin-ci grunt + + - name: PHPUnit tests + if: ${{ always() }} + run: moodle-plugin-ci phpunit + + - name: Behat features + continue-on-error: true # Currently fails. We really ought to get this passing. + if: ${{ always() }} + run: moodle-plugin-ci behat --profile chrome + diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 4b0a289a9..000000000 --- a/.travis.yml +++ /dev/null @@ -1,128 +0,0 @@ -language: php - -os: linux -dist: bionic - -services: - - mysql - - postgresql - - docker - -addons: - apt: - packages: - - maxima - - maxima-share - - texinfo - -cache: - directories: - - $HOME/.composer/cache - - $HOME/.npm - -jobs: - include: - # Travis tends to run the jobs in order, and runs up to 5 jobs in - # parallel. Therefore, our scheme of jobs is: - # - # 1. & 2. PHPUnit on our newest and oldest supported Moodle versions. - # These are our most detailed tests, so we want the results first. - # - # 3. Behat on our newest supported Moodle version. - # - # 4. & 5. Code style checks, expected passes and fails. - # Moodle version here needs to match the one we are using to - # run grunt to compile the JavaScript. - # - # 6. - 8. PHPUnit on other supported moodle versions & latest master. - # - # Ideally, we'd also test Behat in oldest supported version, but currently - # one test does something that only works in Moodle 3.8 or later. - # - # We try to distribute tests across PHP versions and DB types. - # Where we test PHPunit and Behat with the same Moodle version, we - # ensure PHP and DB are different. We don't bother to run Behat on all branches. - # Moodle 3.5 should support PHP 7.0, but we can't test this on Bionic, which we - # need to get a decent Maxima version. - # - # Ideally we would also run the tests with different Maxima versions. - - php: 7.3 - env: TASK=PHPUNIT MOODLE_BRANCH=MOODLE_39_STABLE DB=mysqli - - - php: 7.1 - env: TASK=PHPUNIT MOODLE_BRANCH=MOODLE_35_STABLE DB=pgsql - - - php: 7.4 - env: TASK=BEHAT MOODLE_BRANCH=MOODLE_39_STABLE DB=pgsql - - - php: 7.3 - env: TASK=CODESTYLE MOODLE_BRANCH=MOODLE_38_STABLE DB=mysqli - - - php: 7.3 - env: TASK=CODEKNOWNFAILS MOODLE_BRANCH=MOODLE_38_STABLE DB=mysqli - - - php: 7.4 - env: TASK=PHPUNIT MOODLE_BRANCH=master DB=pgsql - - - php: 7.2 - env: TASK=PHPUNIT MOODLE_BRANCH=MOODLE_38_STABLE DB=pgsql - - - php: 7.1 - env: TASK=PHPUNIT MOODLE_BRANCH=MOODLE_37_STABLE DB=mysqli - - allow_failures: - # This relates to the bit right at the end, where we run some of the coding style checks in this group. - # We don't care if these checks fail, but we want to be able to see the results. - - php: 7.3 - env: TASK=CODEKNOWNFAILS MOODLE_BRANCH=MOODLE_38_STABLE DB=mysqli - - -before_install: - - phpenv config-rm xdebug.ini - - cd ../.. - - composer create-project -n --no-dev --prefer-dist moodlehq/moodle-plugin-ci ci ^3 - - export PATH="$(cd ci/bin; pwd):$(cd ci/vendor/bin; pwd):$PATH" - -install: - - moodle-plugin-ci add-plugin maths/moodle-qbehaviour_dfexplicitvaildate - - moodle-plugin-ci add-plugin maths/moodle-qbehaviour_dfcbmexplicitvaildate - - moodle-plugin-ci add-plugin maths/moodle-qbehaviour_adaptivemultipart - - moodle-plugin-ci install - - moodle-plugin-ci add-config 'define("QTYPE_STACK_TEST_CONFIG_PLATFORM", "linux-optimised");' - - moodle-plugin-ci add-config 'define("QTYPE_STACK_TEST_CONFIG_MAXIMAVERSION", "'`maxima --version | sed 's/Maxima //'`'");' - - moodle-plugin-ci add-config 'define("QTYPE_STACK_TEST_CONFIG_CASTIMEOUT", "10");' - - moodle-plugin-ci add-config 'define("QTYPE_STACK_TEST_CONFIG_CASRESULTSCACHE", "db");' - - moodle-plugin-ci add-config 'define("QTYPE_STACK_TEST_CONFIG_CASPREPARSE", "true");' - - moodle-plugin-ci add-config 'define("QTYPE_STACK_TEST_CONFIG_MAXIMACOMMAND", "");' - - moodle-plugin-ci add-config 'define("QTYPE_STACK_TEST_CONFIG_MAXIMACOMMANDOPT", "timeout --kill-after=10s 10s /home/travis/build/maxima_opt_auto -eval '\''(cl-user::run)'\''");' - - moodle-plugin-ci add-config 'define("QTYPE_STACK_TEST_CONFIG_MAXIMACOMMANDSERVER", "http://pool.home:8080/MaximaPool/MaximaPool");' - - moodle-plugin-ci add-config 'define("QTYPE_STACK_TEST_CONFIG_PLOTCOMMAND", "gnuplot");' - - moodle-plugin-ci add-config 'define("QTYPE_STACK_TEST_CONFIG_MAXIMALIBRARIES", "stats, distrib, descriptive, simplex");' - - moodle-plugin-ci add-config 'define("QTYPE_STACK_TEST_CONFIG_CASDEBUGGING", "0");' - - cp /home/travis/build/moodledata/phpu_moodledata/stack/maxima_opt_auto /home/travis/build/maxima_opt_auto - - # Output some diagnostic about how the install went. - - maxima --list-avail - - cat ./moodle/config.php - - echo 'ATAlgEquiv(x^2-1,(x-1)*(x+1));quit();' | timeout --kill-after=10s 10s /home/travis/build/maxima_opt_auto -eval '(cl-user::run)' - -script: - # Run all the PHP unit tests. - - if [ "$TASK" = 'PHPUNIT' ]; then moodle-plugin-ci phpunit; fi - - # Run all the Behat tests. - - if [ "$TASK" = 'BEHAT' ]; then moodle-plugin-ci behat --profile chrome; fi - - # Run all the various code style tests - this subset should all pass. - - if [ "$TASK" = 'CODESTYLE' ]; then moodle-plugin-ci phplint; fi - - if [ "$TASK" = 'CODESTYLE' ]; then moodle-plugin-ci validate; fi - - if [ "$TASK" = 'CODESTYLE' ]; then moodle-plugin-ci savepoints; fi - - if [ "$TASK" = 'CODESTYLE' ]; then moodle-plugin-ci mustache; fi - - if [ "$TASK" = 'CODESTYLE' ]; then moodle-plugin-ci grunt; fi - - # Run all the various code style tests - these ones are konwn to fail. - # Once we get them passing, move them to the CODESTYLE section above. - - if [ "$TASK" = 'CODEKNOWNFAILS' ]; then moodle-plugin-ci codechecker; fi - - if [ "$TASK" = 'CODEKNOWNFAILS' ]; then moodle-plugin-ci phpdoc; fi - - if [ "$TASK" = 'CODEKNOWNFAILS' ]; then moodle-plugin-ci phpmd; fi - - if [ "$TASK" = 'CODEKNOWNFAILS' ]; then moodle-plugin-ci phpcpd; fi diff --git a/Readme.md b/Readme.md index b4c9b69f5..aacf00207 100644 --- a/Readme.md +++ b/Readme.md @@ -1,4 +1,4 @@ -# STACK 4.3.10 [](https://travis-ci.org/github/maths/moodle-qtype_stack/) +# STACK 4.3.11 STACK is an assessment system for mathematics, science and related disciplines. STACK is a question type for the Moodle learning management system, and also the ILIAS learning management system. @@ -8,7 +8,7 @@ STACK is based on continuing research and use at the University of Edinburgh, th ## Current state of development -STACK 4.3 contains some important re-engineering of core components. This will enable significant new features in future releases. STACK 4.3.10 contains bug fixes and minor improvements. +STACK 4.3 contains some important re-engineering of core components. This will enable significant new features in future releases. STACK 4.3.11 contains an update of JSXGraph (in advance of the forthcoming 4.4 release) to facilitate immediate materials development. Please continue to report any bugs you find at https://github.com/maths/moodle-qtype_stack/issues. diff --git a/amd/build/input.min.js b/amd/build/input.min.js index 1dab46550..9c8699bf7 100644 --- a/amd/build/input.min.js +++ b/amd/build/input.min.js @@ -1,2 +1,24 @@ -define ("qtype_stack/input",["core/ajax","core/event"],function(Ajax,CustomEvents){"use strict";function StackInput(validationDiv,prefix,qaid,name,input){var TYPING_DELAY=1e3,delayTimeoutHandle=null,validationResults={},lastValidatedValue=getInputValue();function cancelTypingDelay(){if(delayTimeoutHandle){clearTimeout(delayTimeoutHandle)}delayTimeoutHandle=null}input.addEventHandlers(valueChanging);function valueChanging(){cancelTypingDelay();showWaiting();delayTimeoutHandle=setTimeout(valueChanged,1000);setTimeout(function(){checkNoChange()},0)}function checkNoChange(){if(getInputValue()===lastValidatedValue){cancelTypingDelay();validationDiv.classList.remove("waiting")}}function valueChanged(){cancelTypingDelay();if(!showValidationResults()){validateInput()}}function validateInput(){Ajax.call([{methodname:"qtype_stack_validate_input",args:{qaid:qaid,name:name,input:getInputValue()},done:function done(a){validationReceived(a)},fail:function fail(a){showValidationFailure(a)}}]);showLoading()}function getInputValue(){return input.getValue()}function validationReceived(a){if("invalid"===a.status){showValidationFailure(a);return}validationResults[a.input]=a;showValidationResults()}function extractScripts(a,b){var c=/<script[^>]*>([\s\S]*?)<\/script>/g,d;while(null!==(d=c.exec(a))){b.push(d[1])}return a.replace(c,"")}function showValidationResults(){var val=getInputValue();if(!validationResults[val]){showWaiting();return!1}var results=validationResults[val];lastValidatedValue=val;var scriptCommands=[];validationDiv.innerHTML=extractScripts(results.message,scriptCommands);for(var i=0;i<scriptCommands.length;i++){eval(scriptCommands[i])}removeAllClasses();if(!results.message){validationDiv.classList.add("empty")}CustomEvents.notifyFilterContentUpdated(validationDiv);return!0}function showValidationFailure(a){lastValidatedValue="";validationDiv.innerHTML=a.message;removeAllClasses();validationDiv.classList.add("error");CustomEvents.notifyFilterContentUpdated(validationDiv)}function showLoading(){removeAllClasses();validationDiv.classList.add("loading")}function showWaiting(){removeAllClasses();validationDiv.classList.add("waiting")}function removeAllClasses(){validationDiv.classList.remove("empty");validationDiv.classList.remove("error");validationDiv.classList.remove("loading");validationDiv.classList.remove("waiting")}}function StackSimpleInput(a){this.addEventHandlers=function(b){a.addEventListener("input",b)};this.getValue=function(){return a.value.replace(/^\s+|\s+$/g,"")}}function StackTextareaInput(a){this.addEventHandlers=function(b){a.addEventListener("input",b)};this.getValue=function(){var b=a.value.replace(/^\s+|\s+$/g,"");return b.split(/\s*[\r\n]\s*/).join("<br>")}}function StackRadioInput(a){this.addEventHandlers=function(b){a.addEventListener("input",b)};this.getValue=function(){var b=a.querySelector(":checked");if(b){return b.value}else{return""}}}function StackCheckboxInput(a){this.addEventHandlers=function(b){a.addEventListener("input",b)};this.getValue=function(){for(var b=a.querySelectorAll(":checked"),c=[],d=0;d<b.length;d++){c[d]=b[d].value}if(0<c.length){return c.join(",")}else{return""}}}function StackMatrixInput(a,b){var c=0,d=0;b.querySelectorAll("input[type=text]").forEach(function(b){if(b.name.slice(0,a.length+5)!==a+"_sub_"){return}var e=b.name.substring(a.length+5).split("_");d=Math.max(d,parseInt(e[0],10)+1);c=Math.max(c,parseInt(e[1],10)+1)});this.addEventHandlers=function(a){b.addEventListener("input",a)};this.getValue=function(){for(var e=Array(d),f=0;f<d;f++){e[f]=Array(c)}b.querySelectorAll("input[type=text]").forEach(function(b){if(b.name.slice(0,a.length+5)!==a+"_sub_"){return}var c=b.name.substring(a.length+5).split("_");e[c[0]][c[1]]=b.value.replace(/^\s+|\s+$/g,"")});return"matrix(["+e.join("],[")+"])"}}function initInputs(a,b,c,d){for(var e=document.getElementById(a),f=!0,g=0;g<d.length;g++){f=initInput(e,b,c,d[g])&&f}if(f&&(e.classList.contains("dfexplicitvaildate")||e.classList.contains("dfcbmexplicitvaildate"))){e.querySelector(".im-controls input.submit").hidden=!0}}function initInput(a,b,c,d){var e=document.getElementById(b+d+"_val");if(!e){return!1}var f=getInputTypeHandler(a,b,d);if(f){new StackInput(e,b,c,d,f);return!0}else{return!1}}function getInputTypeHandler(a,b,c){var d=a.querySelector("[name=\""+b+c+"\"]");if(d){if("TEXTAREA"===d.nodeName){return new StackTextareaInput(d)}else if("radio"===d.type){return new StackRadioInput(d.closest(".answer"))}else{return new StackSimpleInput(d)}}d=a.querySelector("[name=\""+b+c+"_1\"]");if(d&&"checkbox"===d.type){return new StackCheckboxInput(d.closest(".answer"))}var e=document.getElementById(b+c+"_container");if(e){return new StackMatrixInput(b+c,e)}return null}return{initInputs:initInputs}}); -//# sourceMappingURL=input.min.js.map +/** + * A javascript module to handle the real-time validation of the input the student types + * into STACK questions. + * + * The overall way this works is as follows: + * + * - right at the end of this file are the init methods, which set things up. + * - The work common to all input types is done by StackInput. + * - Sending the Ajax request. + * - Updating the validation display. + * - The work specific to different input types (getting the content of the inputs) is done by + * the classes like + * - StackSimpleInput + * - StackTextareaInput + * - StackMatrixInput + * objects of these types need to implement the two methods addEventHandlers and getValue(). + * + * @module qtype_stack/input + * @copyright 2018 The Open University + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +define("qtype_stack/input",["core/ajax","core/event"],(function(Ajax,CustomEvents){function StackInput(validationDiv,prefix,qaid,name,input){var TYPING_DELAY=1e3,delayTimeoutHandle=null,validationResults={},lastValidatedValue=getInputValue();function cancelTypingDelay(){delayTimeoutHandle&&clearTimeout(delayTimeoutHandle),delayTimeoutHandle=null}function valueChanging(){cancelTypingDelay(),showWaiting(),delayTimeoutHandle=setTimeout(valueChanged,TYPING_DELAY),setTimeout((function(){checkNoChange()}),0)}function checkNoChange(){getInputValue()===lastValidatedValue&&(cancelTypingDelay(),validationDiv.classList.remove("waiting"))}function valueChanged(){cancelTypingDelay(),showValidationResults()||validateInput()}function validateInput(){Ajax.call([{methodname:"qtype_stack_validate_input",args:{qaid:qaid,name:name,input:getInputValue()},done:function(response){validationReceived(response)},fail:function(response){showValidationFailure(response)}}]),showLoading()}function getInputValue(){return input.getValue()}function validationReceived(response){"invalid"!==response.status?(validationResults[response.input]=response,showValidationResults()):showValidationFailure(response)}function extractScripts(html,scriptCommands){for(var result,scriptregexp=/<script[^>]*>([\s\S]*?)<\/script>/g;null!==(result=scriptregexp.exec(html));)scriptCommands.push(result[1]);return html.replace(scriptregexp,"")}function showValidationResults(){var val=getInputValue();if(!validationResults[val])return showWaiting(),!1;var results=validationResults[val];lastValidatedValue=val;var scriptCommands=[];validationDiv.innerHTML=extractScripts(results.message,scriptCommands);for(var i=0;i<scriptCommands.length;i++)eval(scriptCommands[i]);return removeAllClasses(),results.message||validationDiv.classList.add("empty"),CustomEvents.notifyFilterContentUpdated(validationDiv),!0}function showValidationFailure(response){lastValidatedValue="",validationDiv.innerHTML=response.message,removeAllClasses(),validationDiv.classList.add("error"),CustomEvents.notifyFilterContentUpdated(validationDiv)}function showLoading(){removeAllClasses(),validationDiv.classList.add("loading")}function showWaiting(){removeAllClasses(),validationDiv.classList.add("waiting")}function removeAllClasses(){validationDiv.classList.remove("empty"),validationDiv.classList.remove("error"),validationDiv.classList.remove("loading"),validationDiv.classList.remove("waiting")}input.addEventHandlers(valueChanging)}function StackSimpleInput(input){this.addEventHandlers=function(valueChanging){input.addEventListener("input",valueChanging)},this.getValue=function(){return input.value.replace(/^\s+|\s+$/g,"")}}function StackTextareaInput(textarea){this.addEventHandlers=function(valueChanging){textarea.addEventListener("input",valueChanging)},this.getValue=function(){return textarea.value.replace(/^\s+|\s+$/g,"").split(/\s*[\r\n]\s*/).join("<br>")}}function StackRadioInput(container){this.addEventHandlers=function(valueChanging){container.addEventListener("input",valueChanging)},this.getValue=function(){var selected=container.querySelector(":checked");return selected?selected.value:""}}function StackCheckboxInput(container){this.addEventHandlers=function(valueChanging){container.addEventListener("input",valueChanging)},this.getValue=function(){for(var selected=container.querySelectorAll(":checked"),result=[],i=0;i<selected.length;i++)result[i]=selected[i].value;return result.length>0?result.join(","):""}}function StackMatrixInput(idPrefix,container){var numcol=0,numrow=0;container.querySelectorAll("input[type=text]").forEach((function(element){if(element.name.slice(0,idPrefix.length+5)===idPrefix+"_sub_"){var bits=element.name.substring(idPrefix.length+5).split("_");numrow=Math.max(numrow,parseInt(bits[0],10)+1),numcol=Math.max(numcol,parseInt(bits[1],10)+1)}})),this.addEventHandlers=function(valueChanging){container.addEventListener("input",valueChanging)},this.getValue=function(){for(var values=new Array(numrow),i=0;i<numrow;i++)values[i]=new Array(numcol);return container.querySelectorAll("input[type=text]").forEach((function(element){if(element.name.slice(0,idPrefix.length+5)===idPrefix+"_sub_"){var bits=element.name.substring(idPrefix.length+5).split("_");values[bits[0]][bits[1]]=element.value.replace(/^\s+|\s+$/g,"")}})),"matrix(["+values.join("],[")+"])"}}function initInputs(questionDivId,prefix,qaid,inputs){for(var questionDiv=document.getElementById(questionDivId),allok=!0,i=0;i<inputs.length;i++)allok=initInput(questionDiv,prefix,qaid,inputs[i])&&allok;allok&&(questionDiv.classList.contains("dfexplicitvaildate")||questionDiv.classList.contains("dfcbmexplicitvaildate"))&&(questionDiv.querySelector(".im-controls input.submit").hidden=!0)}function initInput(questionDiv,prefix,qaid,name){var validationDiv=document.getElementById(prefix+name+"_val");if(!validationDiv)return!1;var inputTypeHandler=getInputTypeHandler(questionDiv,prefix,name);return!!inputTypeHandler&&(new StackInput(validationDiv,prefix,qaid,name,inputTypeHandler),!0)}function getInputTypeHandler(questionDiv,prefix,name){var input=questionDiv.querySelector('[name="'+prefix+name+'"]');if(input)return"TEXTAREA"===input.nodeName?new StackTextareaInput(input):"radio"===input.type?new StackRadioInput(input.closest(".answer")):new StackSimpleInput(input);if((input=questionDiv.querySelector('[name="'+prefix+name+'_1"]'))&&"checkbox"===input.type)return new StackCheckboxInput(input.closest(".answer"));var matrix=document.getElementById(prefix+name+"_container");return matrix?new StackMatrixInput(prefix+name,matrix):null}return{initInputs:initInputs}})); + +//# sourceMappingURL=input.min.js.map \ No newline at end of file diff --git a/amd/build/input.min.js.map b/amd/build/input.min.js.map index 5b6f65241..c7002e534 100644 --- a/amd/build/input.min.js.map +++ b/amd/build/input.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["../src/input.js"],"names":["define","Ajax","CustomEvents","StackInput","validationDiv","prefix","qaid","name","input","TYPING_DELAY","delayTimeoutHandle","validationResults","lastValidatedValue","getInputValue","cancelTypingDelay","clearTimeout","addEventHandlers","valueChanging","showWaiting","setTimeout","valueChanged","checkNoChange","classList","remove","showValidationResults","validateInput","call","methodname","args","done","response","validationReceived","fail","showValidationFailure","showLoading","getValue","status","extractScripts","html","scriptCommands","scriptregexp","result","exec","push","replace","val","results","innerHTML","message","i","length","eval","removeAllClasses","add","notifyFilterContentUpdated","StackSimpleInput","addEventListener","value","StackTextareaInput","textarea","raw","split","join","StackRadioInput","container","selected","querySelector","StackCheckboxInput","querySelectorAll","StackMatrixInput","idPrefix","numcol","numrow","forEach","element","slice","bits","substring","Math","max","parseInt","values","Array","initInputs","questionDivId","inputs","questionDiv","document","getElementById","allok","initInput","contains","hidden","inputTypeHandler","getInputTypeHandler","nodeName","type","closest","matrix"],"mappings":"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","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * A javascript module to handle the real-time validation of the input the student types\n * into STACK questions.\n *\n * The overall way this works is as follows:\n *\n * - right at the end of this file are the init methods, which set things up.\n * - The work common to all input types is done by StackInput.\n * - Sending the Ajax request.\n * - Updating the validation display.\n * - The work specific to different input types (getting the content of the inputs) is done by\n * the classes like\n * - StackSimpleInput\n * - StackTextareaInput\n * - StackMatrixInput\n * objects of these types need to implement the two methods addEventHandlers and getValue().\n *\n * @package qtype_stack\n * @copyright 2018 The Open University\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine([\n 'core/ajax',\n 'core/event'\n], function(\n Ajax,\n CustomEvents\n) {\n\n \"use strict\";\n\n /**\n * Class constructor representing an input in a Stack question.\n *\n * @constructor\n * @param {HTMLElement} validationDiv The div to display the validation in.\n * @param {String} prefix prefix added to the input name to get HTML ids.\n * @param {String} qaid id of the question_attempt.\n * @param {String} name the name of the input we are validating.\n * @param {Object} input An object representing the input element for this input.\n */\n function StackInput(validationDiv, prefix, qaid, name, input) {\n /** @type {number} delay between the user stopping typing, and the ajax request being sent. */\n var TYPING_DELAY = 1000;\n\n /** @type {?int} if not null, the id of the timer for the typing delay. */\n var delayTimeoutHandle = null;\n\n /** @type {Object} cache of validation results we have already received. */\n var validationResults = {};\n\n /** @type {String} the last value that we sent to be validated. */\n var lastValidatedValue = getInputValue();\n\n /**\n * Cancel any typing pause timer.\n */\n function cancelTypingDelay() {\n if (delayTimeoutHandle) {\n clearTimeout(delayTimeoutHandle);\n }\n delayTimeoutHandle = null;\n }\n\n input.addEventHandlers(valueChanging);\n\n /**\n * Called when the input contents changes. Will validate after TYPING_DELAY if nothing else happens.\n */\n function valueChanging() {\n cancelTypingDelay();\n showWaiting();\n delayTimeoutHandle = setTimeout(valueChanged, TYPING_DELAY);\n setTimeout(function() {\n checkNoChange();\n }, 0);\n }\n\n /**\n * After a small delay, detect the case where the user has got the input back\n * to where they started, so no validation is necessary.\n */\n function checkNoChange() {\n if (getInputValue() === lastValidatedValue) {\n cancelTypingDelay();\n validationDiv.classList.remove('waiting');\n }\n }\n\n /**\n * Called to actually validate the input now.\n */\n function valueChanged() {\n cancelTypingDelay();\n if (!showValidationResults()) {\n validateInput();\n }\n }\n\n /**\n * Make an ajax call to validate the input.\n */\n function validateInput() {\n Ajax.call([{\n methodname: 'qtype_stack_validate_input',\n args: {qaid: qaid, name: name, input: getInputValue()},\n done: function(response) {\n validationReceived(response);\n },\n fail: function(response) {\n showValidationFailure(response);\n }\n }]);\n showLoading();\n }\n\n /**\n * Returns the current value of the input.\n *\n * @return {String}.\n */\n function getInputValue() {\n return input.getValue();\n }\n\n /**\n * Update the validation div to show the results of the validation.\n *\n * @param {Object} response The data that came back from the ajax validation call.\n */\n function validationReceived(response) {\n if (response.status === 'invalid') {\n showValidationFailure(response);\n return;\n }\n validationResults[response.input] = response;\n showValidationResults();\n }\n\n /**\n * Some browsers cannot execute JavaScript just by inserting script tags.\n * To avoid that problem, remove all script tags from the given content,\n * and run them later.\n *\n * @param {String} html HTML content\n * @param {Array} scriptCommands An array of script tags for later use.\n * @return {String} HTML with JS removed\n */\n function extractScripts(html, scriptCommands) {\n var scriptregexp = /<script[^>]*>([\\s\\S]*?)<\\/script>/g;\n var result;\n while ((result = scriptregexp.exec(html)) !== null) {\n scriptCommands.push(result[1]);\n }\n return html.replace(scriptregexp, '');\n }\n\n /**\n * Update the validation div to show the results of the validation.\n *\n * @return {boolean} true if we could show the validation. false we we are we don't have it.\n */\n function showValidationResults() {\n /* eslint no-eval: \"off\" */\n var val = getInputValue();\n if (!validationResults[val]) {\n showWaiting();\n return false;\n }\n var results = validationResults[val];\n lastValidatedValue = val;\n var scriptCommands = [];\n validationDiv.innerHTML = extractScripts(results.message, scriptCommands);\n // Run script commands.\n for (var i = 0; i < scriptCommands.length; i++) {\n eval(scriptCommands[i]);\n }\n removeAllClasses();\n if (!results.message) {\n validationDiv.classList.add('empty');\n }\n // This fires the Maths filters for content in the validation div.\n CustomEvents.notifyFilterContentUpdated(validationDiv);\n return true;\n }\n\n /**\n * Update the validation div after an ajax validation call failed.\n *\n * @param {Object} response The data that came back from the ajax validation call.\n */\n function showValidationFailure(response) {\n lastValidatedValue = '';\n // Reponse usually contains backtrace, debuginfo, errorcode, link, message and moreinfourl.\n validationDiv.innerHTML = response.message;\n removeAllClasses();\n validationDiv.classList.add('error');\n // This fires the Maths filters for content in the validation div.\n CustomEvents.notifyFilterContentUpdated(validationDiv);\n }\n\n /**\n * Display the loader icon.\n */\n function showLoading() {\n removeAllClasses();\n validationDiv.classList.add('loading');\n }\n\n /**\n * Update the validation div to show that the input contents have changed,\n * so the validation results are no longer relevant.\n */\n function showWaiting() {\n removeAllClasses();\n validationDiv.classList.add('waiting');\n }\n\n /**\n * Strip all our class names from the validation div.\n */\n function removeAllClasses() {\n validationDiv.classList.remove('empty');\n validationDiv.classList.remove('error');\n validationDiv.classList.remove('loading');\n validationDiv.classList.remove('waiting');\n }\n }\n\n /**\n * Input type for inputs that are a single input or select.\n *\n * @constructor\n * @param {HTMLElement} input the HTML input that is this STACK input.\n */\n function StackSimpleInput(input) {\n /**\n * Add the event handler to call when the user input changes.\n *\n * @param {Function} valueChanging the callback to call when we detect a value change.\n */\n this.addEventHandlers = function(valueChanging) {\n // The input event fires on any change in value, even if pasted in or added by speech\n // recognition to dictate text. Change only fires after loosing focus.\n // Should also work on mobile.\n input.addEventListener('input', valueChanging);\n };\n\n /**\n * Get the current value of this input.\n *\n * @return {String}.\n */\n this.getValue = function() {\n return input.value.replace(/^\\s+|\\s+$/g, '');\n };\n }\n\n /**\n * Input type for textarea inputs.\n *\n * @constructor\n * @param {Object} textarea The input element wrapped in jquery.\n */\n function StackTextareaInput(textarea) {\n /**\n * Add the event handler to call when the user input changes.\n *\n * @param {Function} valueChanging the callback to call when we detect a value change.\n */\n this.addEventHandlers = function(valueChanging) {\n textarea.addEventListener('input', valueChanging);\n };\n\n /**\n * Get the current value of this input.\n *\n * @return {String}.\n */\n this.getValue = function() {\n var raw = textarea.value.replace(/^\\s+|\\s+$/g, '');\n // Using <br> here is weird, but it gets sorted out at the PHP end.\n return raw.split(/\\s*[\\r\\n]\\s*/).join('<br>');\n };\n }\n\n /**\n * Input type for inputs that are a set of radio buttons.\n *\n * @constructor\n * @param {HTMLElement} container container <div> of this input.\n */\n function StackRadioInput(container) {\n /**\n * Add the event handler to call when the user input changes.\n *\n * @param {Function} valueChanging the callback to call when we detect a value change.\n */\n this.addEventHandlers = function(valueChanging) {\n // The input event fires on any change in value, even if pasted in or added by speech\n // recognition to dictate text. Change only fires after loosing focus.\n // Should also work on mobile.\n container.addEventListener('input', valueChanging);\n };\n\n /**\n * Get the current value of this input.\n *\n * @return {String}.\n */\n this.getValue = function() {\n var selected = container.querySelector(':checked');\n if (selected) {\n return selected.value;\n } else {\n return '';\n }\n };\n }\n\n /**\n * Input type for inputs that are a set of checkboxes.\n *\n * @constructor\n * @param {HTMLElement} container container <div> of this input.\n */\n function StackCheckboxInput(container) {\n /**\n * Add the event handler to call when the user input changes.\n *\n * @param {Function} valueChanging the callback to call when we detect a value change.\n */\n this.addEventHandlers = function(valueChanging) {\n // The input event fires on any change in value, even if pasted in or added by speech\n // recognition to dictate text. Change only fires after loosing focus.\n // Should also work on mobile.\n container.addEventListener('input', valueChanging);\n };\n\n /**\n * Get the current value of this input.\n *\n * @return {String}.\n */\n this.getValue = function() {\n var selected = container.querySelectorAll(':checked');\n var result = [];\n for (var i = 0; i < selected.length; i++) {\n result[i] = selected[i].value;\n }\n if (result.length > 0) {\n return result.join(',');\n } else {\n return '';\n }\n };\n }\n\n /**\n * Class constructor representing matrix inputs (one input).\n *\n * @constructor\n * @param {String} idPrefix input id, which is the start of the id of all the different text boxes.\n * @param {HTMLElement} container <div> of this input.\n */\n function StackMatrixInput(idPrefix, container) {\n var numcol = 0;\n var numrow = 0;\n container.querySelectorAll('input[type=text]').forEach(function(element) {\n if (element.name.slice(0, idPrefix.length + 5) !== idPrefix + '_sub_') {\n return;\n }\n var bits = element.name.substring(idPrefix.length + 5).split('_');\n numrow = Math.max(numrow, parseInt(bits[0], 10) + 1);\n numcol = Math.max(numcol, parseInt(bits[1], 10) + 1);\n });\n\n /**\n * Add the event handler to call when the user input changes.\n *\n * @param {Function} valueChanging the callback to call when we detect a value change.\n */\n this.addEventHandlers = function(valueChanging) {\n container.addEventListener('input', valueChanging);\n };\n\n /**\n * Get the current value of this input.\n *\n * @return {String}.\n */\n this.getValue = function() {\n var values = new Array(numrow);\n for (var i = 0; i < numrow; i++) {\n values[i] = new Array(numcol);\n }\n\t container.querySelectorAll('input[type=text]').forEach(function(element) {\n if (element.name.slice(0, idPrefix.length + 5) !== idPrefix + '_sub_') {\n return;\n }\n var bits = element.name.substring(idPrefix.length + 5).split('_');\n values[bits[0]][bits[1]] = element.value.replace(/^\\s+|\\s+$/g, '');\n });\n return 'matrix([' + values.join('],[') + '])';\n };\n };\n\n /**\n * Initialise all the inputs in a STACK question.\n *\n * @param {String} questionDivId id of the outer dic of the question.\n * @param {String} prefix prefix added to the input names for this question.\n * @param {String} qaid Moodle question_attempt id.\n * @param {String[]} inputs names of all the inputs that should have instant validation.\n */\n function initInputs(questionDivId, prefix, qaid, inputs) {\n var questionDiv = document.getElementById(questionDivId);\n\n // Initialise all inputs.\n var allok = true;\n for (var i = 0; i < inputs.length; i++) {\n allok = initInput(questionDiv, prefix, qaid, inputs[i]) && allok;\n }\n\n // With JS With instant validation, we don't need the Check button, so hide it.\n if (allok && (questionDiv.classList.contains('dfexplicitvaildate') ||\n questionDiv.classList.contains('dfcbmexplicitvaildate'))) {\n questionDiv.querySelector('.im-controls input.submit').hidden = true;\n }\n }\n\n /**\n * Initialise one input.\n *\n * @param {HTMLElement} questionDiv outer <div> of this question.\n * @param {String} prefix prefix added to the input names for this question.\n * @param {String} qaid Moodle question_attempt id.\n * @param {String} name the input to initialise.\n * @return {boolean} true if this input was successfully initialised, else false.\n */\n function initInput(questionDiv, prefix, qaid, name) {\n var validationDiv = document.getElementById(prefix + name + '_val');\n if (!validationDiv) {\n return false;\n }\n\n var inputTypeHandler = getInputTypeHandler(questionDiv, prefix, name);\n if (inputTypeHandler) {\n new StackInput(validationDiv, prefix, qaid, name, inputTypeHandler);\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * Get the input type handler for a named input.\n *\n * @param {HTMLElement} questionDiv outer <div> of this question.\n * @param {String} prefix prefix added to the input names for this question.\n * @param {String} name the input to initialise.\n * @return {?Object} the input hander, if we can handle it, else null.\n */\n function getInputTypeHandler(questionDiv, prefix, name) {\n // See if it is an ordinary input.\n var input = questionDiv.querySelector('[name=\"' + prefix + name + '\"]');\n if (input) {\n if (input.nodeName === 'TEXTAREA') {\n return new StackTextareaInput(input);\n } else if (input.type === 'radio') {\n return new StackRadioInput(input.closest('.answer'));\n } else {\n return new StackSimpleInput(input);\n }\n }\n\n // See if it is a checkbox input.\n input = questionDiv.querySelector('[name=\"' + prefix + name + '_1\"]');\n if (input && input.type === 'checkbox') {\n return new StackCheckboxInput(input.closest('.answer'));\n }\n\n // See if it is a matrix input.\n var matrix = document.getElementById(prefix + name + '_container');\n if (matrix) {\n return new StackMatrixInput(prefix + name, matrix);\n }\n\n return null;\n }\n\n /** Export our entry point. */\n return {\n /**\n * Initialise all the inputs in a STACK question.\n *\n * @param {String} questionDivId id of the outer dic of the question.\n * @param {String} prefix prefix added to the input names for this question.\n * @param {String} qaid Moodle question_attempt id.\n * @param {String[]} inputs names of all the inputs that should have instant validation.\n */\n initInputs: initInputs\n };\n});\n"],"file":"input.min.js"} \ No newline at end of file +{"version":3,"file":"input.min.js","sources":["../src/input.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * A javascript module to handle the real-time validation of the input the student types\n * into STACK questions.\n *\n * The overall way this works is as follows:\n *\n * - right at the end of this file are the init methods, which set things up.\n * - The work common to all input types is done by StackInput.\n * - Sending the Ajax request.\n * - Updating the validation display.\n * - The work specific to different input types (getting the content of the inputs) is done by\n * the classes like\n * - StackSimpleInput\n * - StackTextareaInput\n * - StackMatrixInput\n * objects of these types need to implement the two methods addEventHandlers and getValue().\n *\n * @module qtype_stack/input\n * @copyright 2018 The Open University\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine([\n 'core/ajax',\n 'core/event'\n], function(\n Ajax,\n CustomEvents\n) {\n\n \"use strict\";\n\n /**\n * Class constructor representing an input in a Stack question.\n *\n * @constructor\n * @param {HTMLElement} validationDiv The div to display the validation in.\n * @param {String} prefix prefix added to the input name to get HTML ids.\n * @param {String} qaid id of the question_attempt.\n * @param {String} name the name of the input we are validating.\n * @param {Object} input An object representing the input element for this input.\n */\n function StackInput(validationDiv, prefix, qaid, name, input) {\n /** @type {number} delay between the user stopping typing, and the ajax request being sent. */\n var TYPING_DELAY = 1000;\n\n /** @type {?int} if not null, the id of the timer for the typing delay. */\n var delayTimeoutHandle = null;\n\n /** @type {Object} cache of validation results we have already received. */\n var validationResults = {};\n\n /** @type {String} the last value that we sent to be validated. */\n var lastValidatedValue = getInputValue();\n\n /**\n * Cancel any typing pause timer.\n */\n function cancelTypingDelay() {\n if (delayTimeoutHandle) {\n clearTimeout(delayTimeoutHandle);\n }\n delayTimeoutHandle = null;\n }\n\n input.addEventHandlers(valueChanging);\n\n /**\n * Called when the input contents changes. Will validate after TYPING_DELAY if nothing else happens.\n */\n function valueChanging() {\n cancelTypingDelay();\n showWaiting();\n delayTimeoutHandle = setTimeout(valueChanged, TYPING_DELAY);\n setTimeout(function() {\n checkNoChange();\n }, 0);\n }\n\n /**\n * After a small delay, detect the case where the user has got the input back\n * to where they started, so no validation is necessary.\n */\n function checkNoChange() {\n if (getInputValue() === lastValidatedValue) {\n cancelTypingDelay();\n validationDiv.classList.remove('waiting');\n }\n }\n\n /**\n * Called to actually validate the input now.\n */\n function valueChanged() {\n cancelTypingDelay();\n if (!showValidationResults()) {\n validateInput();\n }\n }\n\n /**\n * Make an ajax call to validate the input.\n */\n function validateInput() {\n Ajax.call([{\n methodname: 'qtype_stack_validate_input',\n args: {qaid: qaid, name: name, input: getInputValue()},\n done: function(response) {\n validationReceived(response);\n },\n fail: function(response) {\n showValidationFailure(response);\n }\n }]);\n showLoading();\n }\n\n /**\n * Returns the current value of the input.\n *\n * @return {String}.\n */\n function getInputValue() {\n return input.getValue();\n }\n\n /**\n * Update the validation div to show the results of the validation.\n *\n * @param {Object} response The data that came back from the ajax validation call.\n */\n function validationReceived(response) {\n if (response.status === 'invalid') {\n showValidationFailure(response);\n return;\n }\n validationResults[response.input] = response;\n showValidationResults();\n }\n\n /**\n * Some browsers cannot execute JavaScript just by inserting script tags.\n * To avoid that problem, remove all script tags from the given content,\n * and run them later.\n *\n * @param {String} html HTML content\n * @param {Array} scriptCommands An array of script tags for later use.\n * @return {String} HTML with JS removed\n */\n function extractScripts(html, scriptCommands) {\n var scriptregexp = /<script[^>]*>([\\s\\S]*?)<\\/script>/g;\n var result;\n while ((result = scriptregexp.exec(html)) !== null) {\n scriptCommands.push(result[1]);\n }\n return html.replace(scriptregexp, '');\n }\n\n /**\n * Update the validation div to show the results of the validation.\n *\n * @return {boolean} true if we could show the validation. false we we are we don't have it.\n */\n function showValidationResults() {\n /* eslint no-eval: \"off\" */\n var val = getInputValue();\n if (!validationResults[val]) {\n showWaiting();\n return false;\n }\n var results = validationResults[val];\n lastValidatedValue = val;\n var scriptCommands = [];\n validationDiv.innerHTML = extractScripts(results.message, scriptCommands);\n // Run script commands.\n for (var i = 0; i < scriptCommands.length; i++) {\n eval(scriptCommands[i]);\n }\n removeAllClasses();\n if (!results.message) {\n validationDiv.classList.add('empty');\n }\n // This fires the Maths filters for content in the validation div.\n CustomEvents.notifyFilterContentUpdated(validationDiv);\n return true;\n }\n\n /**\n * Update the validation div after an ajax validation call failed.\n *\n * @param {Object} response The data that came back from the ajax validation call.\n */\n function showValidationFailure(response) {\n lastValidatedValue = '';\n // Reponse usually contains backtrace, debuginfo, errorcode, link, message and moreinfourl.\n validationDiv.innerHTML = response.message;\n removeAllClasses();\n validationDiv.classList.add('error');\n // This fires the Maths filters for content in the validation div.\n CustomEvents.notifyFilterContentUpdated(validationDiv);\n }\n\n /**\n * Display the loader icon.\n */\n function showLoading() {\n removeAllClasses();\n validationDiv.classList.add('loading');\n }\n\n /**\n * Update the validation div to show that the input contents have changed,\n * so the validation results are no longer relevant.\n */\n function showWaiting() {\n removeAllClasses();\n validationDiv.classList.add('waiting');\n }\n\n /**\n * Strip all our class names from the validation div.\n */\n function removeAllClasses() {\n validationDiv.classList.remove('empty');\n validationDiv.classList.remove('error');\n validationDiv.classList.remove('loading');\n validationDiv.classList.remove('waiting');\n }\n }\n\n /**\n * Input type for inputs that are a single input or select.\n *\n * @constructor\n * @param {HTMLElement} input the HTML input that is this STACK input.\n */\n function StackSimpleInput(input) {\n /**\n * Add the event handler to call when the user input changes.\n *\n * @param {Function} valueChanging the callback to call when we detect a value change.\n */\n this.addEventHandlers = function(valueChanging) {\n // The input event fires on any change in value, even if pasted in or added by speech\n // recognition to dictate text. Change only fires after loosing focus.\n // Should also work on mobile.\n input.addEventListener('input', valueChanging);\n };\n\n /**\n * Get the current value of this input.\n *\n * @return {String}.\n */\n this.getValue = function() {\n return input.value.replace(/^\\s+|\\s+$/g, '');\n };\n }\n\n /**\n * Input type for textarea inputs.\n *\n * @constructor\n * @param {Object} textarea The input element wrapped in jquery.\n */\n function StackTextareaInput(textarea) {\n /**\n * Add the event handler to call when the user input changes.\n *\n * @param {Function} valueChanging the callback to call when we detect a value change.\n */\n this.addEventHandlers = function(valueChanging) {\n textarea.addEventListener('input', valueChanging);\n };\n\n /**\n * Get the current value of this input.\n *\n * @return {String}.\n */\n this.getValue = function() {\n var raw = textarea.value.replace(/^\\s+|\\s+$/g, '');\n // Using <br> here is weird, but it gets sorted out at the PHP end.\n return raw.split(/\\s*[\\r\\n]\\s*/).join('<br>');\n };\n }\n\n /**\n * Input type for inputs that are a set of radio buttons.\n *\n * @constructor\n * @param {HTMLElement} container container <div> of this input.\n */\n function StackRadioInput(container) {\n /**\n * Add the event handler to call when the user input changes.\n *\n * @param {Function} valueChanging the callback to call when we detect a value change.\n */\n this.addEventHandlers = function(valueChanging) {\n // The input event fires on any change in value, even if pasted in or added by speech\n // recognition to dictate text. Change only fires after loosing focus.\n // Should also work on mobile.\n container.addEventListener('input', valueChanging);\n };\n\n /**\n * Get the current value of this input.\n *\n * @return {String}.\n */\n this.getValue = function() {\n var selected = container.querySelector(':checked');\n if (selected) {\n return selected.value;\n } else {\n return '';\n }\n };\n }\n\n /**\n * Input type for inputs that are a set of checkboxes.\n *\n * @constructor\n * @param {HTMLElement} container container <div> of this input.\n */\n function StackCheckboxInput(container) {\n /**\n * Add the event handler to call when the user input changes.\n *\n * @param {Function} valueChanging the callback to call when we detect a value change.\n */\n this.addEventHandlers = function(valueChanging) {\n // The input event fires on any change in value, even if pasted in or added by speech\n // recognition to dictate text. Change only fires after loosing focus.\n // Should also work on mobile.\n container.addEventListener('input', valueChanging);\n };\n\n /**\n * Get the current value of this input.\n *\n * @return {String}.\n */\n this.getValue = function() {\n var selected = container.querySelectorAll(':checked');\n var result = [];\n for (var i = 0; i < selected.length; i++) {\n result[i] = selected[i].value;\n }\n if (result.length > 0) {\n return result.join(',');\n } else {\n return '';\n }\n };\n }\n\n /**\n * Class constructor representing matrix inputs (one input).\n *\n * @constructor\n * @param {String} idPrefix input id, which is the start of the id of all the different text boxes.\n * @param {HTMLElement} container <div> of this input.\n */\n function StackMatrixInput(idPrefix, container) {\n var numcol = 0;\n var numrow = 0;\n container.querySelectorAll('input[type=text]').forEach(function(element) {\n if (element.name.slice(0, idPrefix.length + 5) !== idPrefix + '_sub_') {\n return;\n }\n var bits = element.name.substring(idPrefix.length + 5).split('_');\n numrow = Math.max(numrow, parseInt(bits[0], 10) + 1);\n numcol = Math.max(numcol, parseInt(bits[1], 10) + 1);\n });\n\n /**\n * Add the event handler to call when the user input changes.\n *\n * @param {Function} valueChanging the callback to call when we detect a value change.\n */\n this.addEventHandlers = function(valueChanging) {\n container.addEventListener('input', valueChanging);\n };\n\n /**\n * Get the current value of this input.\n *\n * @return {String}.\n */\n this.getValue = function() {\n var values = new Array(numrow);\n for (var i = 0; i < numrow; i++) {\n values[i] = new Array(numcol);\n }\n container.querySelectorAll('input[type=text]').forEach(function(element) {\n if (element.name.slice(0, idPrefix.length + 5) !== idPrefix + '_sub_') {\n return;\n }\n var bits = element.name.substring(idPrefix.length + 5).split('_');\n values[bits[0]][bits[1]] = element.value.replace(/^\\s+|\\s+$/g, '');\n });\n return 'matrix([' + values.join('],[') + '])';\n };\n }\n\n /**\n * Initialise all the inputs in a STACK question.\n *\n * @param {String} questionDivId id of the outer dic of the question.\n * @param {String} prefix prefix added to the input names for this question.\n * @param {String} qaid Moodle question_attempt id.\n * @param {String[]} inputs names of all the inputs that should have instant validation.\n */\n function initInputs(questionDivId, prefix, qaid, inputs) {\n var questionDiv = document.getElementById(questionDivId);\n\n // Initialise all inputs.\n var allok = true;\n for (var i = 0; i < inputs.length; i++) {\n allok = initInput(questionDiv, prefix, qaid, inputs[i]) && allok;\n }\n\n // With JS With instant validation, we don't need the Check button, so hide it.\n if (allok && (questionDiv.classList.contains('dfexplicitvaildate') ||\n questionDiv.classList.contains('dfcbmexplicitvaildate'))) {\n questionDiv.querySelector('.im-controls input.submit').hidden = true;\n }\n }\n\n /**\n * Initialise one input.\n *\n * @param {HTMLElement} questionDiv outer <div> of this question.\n * @param {String} prefix prefix added to the input names for this question.\n * @param {String} qaid Moodle question_attempt id.\n * @param {String} name the input to initialise.\n * @return {boolean} true if this input was successfully initialised, else false.\n */\n function initInput(questionDiv, prefix, qaid, name) {\n var validationDiv = document.getElementById(prefix + name + '_val');\n if (!validationDiv) {\n return false;\n }\n\n var inputTypeHandler = getInputTypeHandler(questionDiv, prefix, name);\n if (inputTypeHandler) {\n new StackInput(validationDiv, prefix, qaid, name, inputTypeHandler);\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * Get the input type handler for a named input.\n *\n * @param {HTMLElement} questionDiv outer <div> of this question.\n * @param {String} prefix prefix added to the input names for this question.\n * @param {String} name the input to initialise.\n * @return {?Object} the input hander, if we can handle it, else null.\n */\n function getInputTypeHandler(questionDiv, prefix, name) {\n // See if it is an ordinary input.\n var input = questionDiv.querySelector('[name=\"' + prefix + name + '\"]');\n if (input) {\n if (input.nodeName === 'TEXTAREA') {\n return new StackTextareaInput(input);\n } else if (input.type === 'radio') {\n return new StackRadioInput(input.closest('.answer'));\n } else {\n return new StackSimpleInput(input);\n }\n }\n\n // See if it is a checkbox input.\n input = questionDiv.querySelector('[name=\"' + prefix + name + '_1\"]');\n if (input && input.type === 'checkbox') {\n return new StackCheckboxInput(input.closest('.answer'));\n }\n\n // See if it is a matrix input.\n var matrix = document.getElementById(prefix + name + '_container');\n if (matrix) {\n return new StackMatrixInput(prefix + name, matrix);\n }\n\n return null;\n }\n\n /** Export our entry point. */\n return {\n /**\n * Initialise all the inputs in a STACK question.\n *\n * @param {String} questionDivId id of the outer dic of the question.\n * @param {String} prefix prefix added to the input names for this question.\n * @param {String} qaid Moodle question_attempt id.\n * @param {String[]} inputs names of all the inputs that should have instant validation.\n */\n initInputs: initInputs\n };\n});\n"],"names":["define","Ajax","CustomEvents","StackInput","validationDiv","prefix","qaid","name","input","TYPING_DELAY","delayTimeoutHandle","validationResults","lastValidatedValue","getInputValue","cancelTypingDelay","clearTimeout","valueChanging","showWaiting","setTimeout","valueChanged","checkNoChange","classList","remove","showValidationResults","validateInput","call","methodname","args","done","response","validationReceived","fail","showValidationFailure","showLoading","getValue","status","extractScripts","html","scriptCommands","result","scriptregexp","exec","push","replace","val","results","innerHTML","message","i","length","eval","removeAllClasses","add","notifyFilterContentUpdated","addEventHandlers","StackSimpleInput","addEventListener","value","StackTextareaInput","textarea","split","join","StackRadioInput","container","selected","querySelector","StackCheckboxInput","querySelectorAll","StackMatrixInput","idPrefix","numcol","numrow","forEach","element","slice","bits","substring","Math","max","parseInt","values","Array","initInputs","questionDivId","inputs","questionDiv","document","getElementById","allok","initInput","contains","hidden","inputTypeHandler","getInputTypeHandler","nodeName","type","closest","matrix"],"mappings":"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"} \ No newline at end of file diff --git a/amd/build/jsxgraph.min.js b/amd/build/jsxgraph.min.js index c135b47cb..f8dc6e351 100644 --- a/amd/build/jsxgraph.min.js +++ b/amd/build/jsxgraph.min.js @@ -1,2 +1,3 @@ -define ("qtype_stack/jsxgraph",["qtype_stack/jsxgraphcore-lazy"],function(a){return{find_input_id:function find_input_id(a,b){var c=document.getElementById(a);while((c=c.parentElement)&&!(c.classList.contains("formulation")&&c.parentElement.classList.contains("content"))){}c=c.querySelector("input[id$=\"_"+b+"\"]");c.addEventListener("change",function(){M.core_formchangechecker.set_form_changed()});return c.id},bind_point:function bind_point(b,c){var d=document.getElementById(b);if(d.value&&""!=d.value){var e=JSON.parse(d.value);try{c.setPosition(a.COORDS_BY_USER,e)}catch(a){}c.board.update();c.update()}var f=c.X(),g=c.Y();c.board.on("update",function(){if(f!==c.X()||g!==c.Y()){var a=JSON.stringify([c.X(),c.Y()]);f=!1;g=!1;if(d.value!=a){d.value=a;if(-1===window.location.pathname.indexOf("preview.php")){var b=new Event("change");d.dispatchEvent(b)}}}});var h=JSON.stringify([c.X(),c.Y()]);d.addEventListener("input",function(){if(d.value!=h){try{var b=JSON.parse(d.value);if("number"==typeof b[0]&&"number"==typeof b[1]){c.setPosition(a.COORDS_BY_USER,b);c.board.update();c.update()}}catch(a){}h=d.value}});d.addEventListener("change",function(){if(d.value!=h){try{var b=JSON.parse(d.value);if("number"==typeof b[0]&&"number"==typeof b[1]){c.setPosition(a.COORDS_BY_USER,b);c.board.update();c.update()}}catch(a){}h=d.value}})},bind_point_dual:function bind_point_dual(b,c,d){var f=document.getElementById(b);if(f.value&&""!=f.value){var g=JSON.parse(f.value);try{c.setPosition(a.COORDS_BY_USER,g[0]);d.setPosition(a.COORDS_BY_USER,g[1])}catch(a){}c.board.update();c.update();d.board.update();d.update()}var h=c.X(),i=c.Y();c.board.on("update",function(){if(h!==c.X()||i!==c.Y()){var a=JSON.stringify([[c.X(),c.Y()],[d.X(),d.Y()]]);h=!1;i=!1;if(f.value!=a){f.value=a;if(-1===window.location.pathname.indexOf("preview.php")){var b=new Event("change");f.dispatchEvent(b)}}}});var j=d.X(),k=d.Y();d.board.on("update",function(){if(j!==d.X()||k!==d.Y()){var a=JSON.stringify([[c.X(),c.Y()],[d.X(),d.Y()]]);j=!1;k=!1;if(f.value!=a){f.value=a;if(-1===window.location.pathname.indexOf("preview.php")){var b=new Event("change");f.dispatchEvent(b)}}}});var l=JSON.stringify([[c.X(),c.Y()],[d.X(),d.Y()]]);f.addEventListener("input",function(){if(f.value!=l){try{var b=JSON.parse(f.value);if("number"==typeof b[0][0]&&"number"==typeof b[0][1]){c.setPosition(a.COORDS_BY_USER,b[0])}if("number"==typeof b[1][0]&&"number"==typeof b[1][1]){d.setPosition(a.COORDS_BY_USER,b[1]);c.board.update();c.update();d.board.update();d.update()}}catch(a){}l=f.value}});f.addEventListener("change",function(){if(f.value!=l){try{var b=JSON.parse(f.value);if("number"==typeof b[0][0]&&"number"==typeof b[0][1]){c.setPosition(a.COORDS_BY_USER,b[0])}if("number"==typeof b[1][0]&&"number"==typeof b[1][1]){d.setPosition(a.COORDS_BY_USER,b[1]);c.board.update();c.update();d.board.update();d.update()}}catch(a){}l=f.value}})},bind_point_relative:function bind_point_relative(c,d,f){var g=document.getElementById(c);if(g.value&&""!=g.value){var h=JSON.parse(g.value);try{d.setPosition(a.COORDS_BY_USER,h[0]);var i=[h[0][0]+h[1][0],h[0][1]+h[1][1]];f.setPosition(a.COORDS_BY_USER,i)}catch(a){}d.board.update();d.update();f.board.update();f.update()}var b=d.X(),j=d.Y();d.board.on("update",function(){if(b!==d.X()||j!==d.Y()){var a=JSON.stringify([[d.X(),d.Y()],[f.X()-d.X(),f.Y()-d.Y()]]);b=!1;j=!1;if(g.value!=a){g.value=a;if(-1===window.location.pathname.indexOf("preview.php")){var c=new Event("change");g.dispatchEvent(c)}}}});var k=f.X(),l=f.Y();f.board.on("update",function(){if(k!==f.X()||l!==f.Y()){var a=JSON.stringify([[d.X(),d.Y()],[f.X()-d.X(),f.Y()-d.Y()]]);k=!1;l=!1;if(g.value!=a){g.value=a;if(-1===window.location.pathname.indexOf("preview.php")){var b=new Event("change");g.dispatchEvent(b)}}}});var m=JSON.stringify([[d.X(),d.Y()],[f.X()-d.X(),f.Y()-d.Y()]]);g.addEventListener("input",function(){if(g.value!=m){try{var c=JSON.parse(g.value);if("number"==typeof c[0][0]&&"number"==typeof c[0][1]){d.setPosition(a.COORDS_BY_USER,c[0])}if("number"==typeof c[1][0]&&"number"==typeof c[1][1]){var e=[c[0][0]+c[1][0],c[0][1]+c[1][1]];f.setPosition(a.COORDS_BY_USER,e);d.board.update();d.update();f.board.update();f.update()}}catch(a){}m=g.value}});g.addEventListener("change",function(){if(g.value!=m){try{var c=JSON.parse(g.value);if("number"==typeof c[0][0]&&"number"==typeof c[0][1]){d.setPosition(a.COORDS_BY_USER,c[0])}if("number"==typeof c[1][0]&&"number"==typeof c[1][1]){var e=[c[0][0]+c[1][0],c[0][1]+c[1][1]];f.setPosition(a.COORDS_BY_USER,e);d.board.update();d.update();f.board.update();f.update()}}catch(a){}m=g.value}})},bind_point_direction:function bind_point_direction(c,d,f){var g=document.getElementById(c);if(g.value&&""!=g.value){var h=JSON.parse(g.value);try{d.setPosition(a.COORDS_BY_USER,h[0]);var i=h[1][0],j=h[1][1],k=[h[0][0],h[0][1]];if(0<j){k[0]=k[0]+j*Math.cos(i);k[1]=k[1]+j*Math.sin(i)}f.setPosition(a.COORDS_BY_USER,k)}catch(a){}d.board.update();d.update();f.board.update();f.update()}var b=d.X(),l=d.Y();d.board.on("update",function(){if(b!==d.X()||l!==d.Y()){var a=JSON.stringify([[d.X(),d.Y()],[Math.atan2(f.Y()-d.Y(),f.X()-d.X()),Math.sqrt((f.X()-d.X())*(f.X()-d.X())+(f.Y()-d.Y())*(f.Y()-d.Y()))]]);b=!1;l=!1;if(g.value!=a){g.value=a;if(-1===window.location.pathname.indexOf("preview.php")){var c=new Event("change");g.dispatchEvent(c)}}}});var m=f.X(),n=f.Y();f.board.on("update",function(){if(m!==f.X()||n!==f.Y()){var a=JSON.stringify([[d.X(),d.Y()],[Math.atan2(f.Y()-d.Y(),f.X()-d.X()),Math.sqrt((f.X()-d.X())*(f.X()-d.X())+(f.Y()-d.Y())*(f.Y()-d.Y()))]]);m=!1;n=!1;if(g.value!=a){g.value=a;if(-1===window.location.pathname.indexOf("preview.php")){var b=new Event("change");g.dispatchEvent(b)}}}});var o=JSON.stringify([[d.X(),d.Y()],[Math.atan2(f.Y()-d.Y(),f.X()-d.X()),Math.sqrt((f.X()-d.X())*(f.X()-d.X())+(f.Y()-d.Y())*(f.Y()-d.Y()))]]);g.addEventListener("input",function(){if(g.value!=o){try{var c=JSON.parse(g.value);if("number"==typeof c[0][0]&&"number"==typeof c[0][1]){d.setPosition(a.COORDS_BY_USER,c[0])}if("number"==typeof c[1][0]&&"number"==typeof c[1][1]){var e=c[1][0],h=c[1][1],i=[c[0][0],c[0][1]];if(0<h){i[0]=i[0]+h*Math.cos(e);i[1]=i[1]+h*Math.sin(e)}f.setPosition(a.COORDS_BY_USER,i);d.board.update();d.update();f.board.update();f.update()}}catch(a){}o=g.value}});g.addEventListener("change",function(){if(g.value!=o){try{var c=JSON.parse(g.value);if("number"==typeof c[0][0]&&"number"==typeof c[0][1]){d.setPosition(a.COORDS_BY_USER,c[0])}if("number"==typeof c[1][0]&&"number"==typeof c[1][1]){var e=c[1][0],h=c[1][1],i=[c[0][0],c[0][1]];if(0<h){i[0]=i[0]+h*Math.cos(e);i[1]=i[1]+h*Math.sin(e)}f.setPosition(a.COORDS_BY_USER,i);d.board.update();d.update();f.board.update();f.update()}}catch(a){}o=g.value}})},bind_slider:function bind_slider(a,b){var c=document.getElementById(a);if(c.value&&""!=c.value){try{b.setValue(JSON.parse(c.value))}catch(a){}b.board.update();b.update()}var d=b.Value();b.board.on("update",function(){if(d!=b.Value()){var a=JSON.stringify(b.Value());d=!1;if(c.value!=a){c.value=a;if(-1===window.location.pathname.indexOf("preview.php")){var f=new Event("change");c.dispatchEvent(f)}}}});var e=JSON.stringify(b.Value());c.addEventListener("input",function(){if(c.value!==e){try{var a=JSON.parse(c.value);if("number"==typeof a){b.setValue(a);b.board.update();b.update()}}catch(a){}e=c.value}});c.addEventListener("change",function(){if(c.value!==e){try{var a=JSON.parse(c.value);if("number"==typeof a){b.setValue(a);b.board.update();b.update()}}catch(a){}e=c.value}})}}}); -//# sourceMappingURL=jsxgraph.min.js.map +define("qtype_stack/jsxgraph",["qtype_stack/jsxgraphcore-lazy"],(function(JXG){return{find_input_id:function(divid,name){for(var tmp=document.getElementById(divid);(tmp=tmp.parentElement)&&(!tmp.classList.contains("formulation")||!tmp.parentElement.classList.contains("content")););return(tmp=tmp.querySelector('input[id$="_'+name+'"]')).addEventListener("change",(function(){M.core_formchangechecker.set_form_changed()})),tmp.id},bind_point:function(inputRef,point){var theInput=document.getElementById(inputRef);if(theInput.value&&""!=theInput.value){var coords=JSON.parse(theInput.value);try{point.setPosition(JXG.COORDS_BY_USER,coords)}catch(err){}point.board.update(),point.update()}var initialX=point.X(),initialY=point.Y();point.board.on("update",(function(){if(initialX!==point.X()||initialY!==point.Y()){var tmp=JSON.stringify([point.X(),point.Y()]);if(initialX=!1,initialY=!1,theInput.value!=tmp&&(theInput.value=tmp,-1===window.location.pathname.indexOf("preview.php"))){var e=new Event("change");theInput.dispatchEvent(e)}}}));var lastValue=JSON.stringify([point.X(),point.Y()]);theInput.addEventListener("input",(function(){if(theInput.value!=lastValue){try{var tmp=JSON.parse(theInput.value);"number"==typeof tmp[0]&&"number"==typeof tmp[1]&&(point.setPosition(JXG.COORDS_BY_USER,tmp),point.board.update(),point.update())}catch(err){}lastValue=theInput.value}})),theInput.addEventListener("change",(function(){if(theInput.value!=lastValue){try{var tmp=JSON.parse(theInput.value);"number"==typeof tmp[0]&&"number"==typeof tmp[1]&&(point.setPosition(JXG.COORDS_BY_USER,tmp),point.board.update(),point.update())}catch(err){}lastValue=theInput.value}}))},bind_point_dual:function(inputRef,point1,point2){var theInput=document.getElementById(inputRef);if(theInput.value&&""!=theInput.value){var coords=JSON.parse(theInput.value);try{point1.setPosition(JXG.COORDS_BY_USER,coords[0]),point2.setPosition(JXG.COORDS_BY_USER,coords[1])}catch(err){}point1.board.update(),point1.update(),point2.board.update(),point2.update()}var initial1X=point1.X(),initial1Y=point1.Y();point1.board.on("update",(function(){if(initial1X!==point1.X()||initial1Y!==point1.Y()){var tmp=JSON.stringify([[point1.X(),point1.Y()],[point2.X(),point2.Y()]]);if(initial1X=!1,initial1Y=!1,theInput.value!=tmp&&(theInput.value=tmp,-1===window.location.pathname.indexOf("preview.php"))){var e=new Event("change");theInput.dispatchEvent(e)}}}));var initial2X=point2.X(),initial2Y=point2.Y();point2.board.on("update",(function(){if(initial2X!==point2.X()||initial2Y!==point2.Y()){var tmp=JSON.stringify([[point1.X(),point1.Y()],[point2.X(),point2.Y()]]);if(initial2X=!1,initial2Y=!1,theInput.value!=tmp&&(theInput.value=tmp,-1===window.location.pathname.indexOf("preview.php"))){var e=new Event("change");theInput.dispatchEvent(e)}}}));var lastValue=JSON.stringify([[point1.X(),point1.Y()],[point2.X(),point2.Y()]]);theInput.addEventListener("input",(function(){if(theInput.value!=lastValue){try{var tmp=JSON.parse(theInput.value);"number"==typeof tmp[0][0]&&"number"==typeof tmp[0][1]&&point1.setPosition(JXG.COORDS_BY_USER,tmp[0]),"number"==typeof tmp[1][0]&&"number"==typeof tmp[1][1]&&(point2.setPosition(JXG.COORDS_BY_USER,tmp[1]),point1.board.update(),point1.update(),point2.board.update(),point2.update())}catch(err){}lastValue=theInput.value}})),theInput.addEventListener("change",(function(){if(theInput.value!=lastValue){try{var tmp=JSON.parse(theInput.value);"number"==typeof tmp[0][0]&&"number"==typeof tmp[0][1]&&point1.setPosition(JXG.COORDS_BY_USER,tmp[0]),"number"==typeof tmp[1][0]&&"number"==typeof tmp[1][1]&&(point2.setPosition(JXG.COORDS_BY_USER,tmp[1]),point1.board.update(),point1.update(),point2.board.update(),point2.update())}catch(err){}lastValue=theInput.value}}))},bind_point_relative:function(inputRef,point1,point2){var theInput=document.getElementById(inputRef);if(theInput.value&&""!=theInput.value){var coords=JSON.parse(theInput.value);try{point1.setPosition(JXG.COORDS_BY_USER,coords[0]);var b=[coords[0][0]+coords[1][0],coords[0][1]+coords[1][1]];point2.setPosition(JXG.COORDS_BY_USER,b)}catch(err){}point1.board.update(),point1.update(),point2.board.update(),point2.update()}var initial1X=point1.X(),initial1Y=point1.Y();point1.board.on("update",(function(){if(initial1X!==point1.X()||initial1Y!==point1.Y()){var tmp=JSON.stringify([[point1.X(),point1.Y()],[point2.X()-point1.X(),point2.Y()-point1.Y()]]);if(initial1X=!1,initial1Y=!1,theInput.value!=tmp&&(theInput.value=tmp,-1===window.location.pathname.indexOf("preview.php"))){var e=new Event("change");theInput.dispatchEvent(e)}}}));var initial2X=point2.X(),initial2Y=point2.Y();point2.board.on("update",(function(){if(initial2X!==point2.X()||initial2Y!==point2.Y()){var tmp=JSON.stringify([[point1.X(),point1.Y()],[point2.X()-point1.X(),point2.Y()-point1.Y()]]);if(initial2X=!1,initial2Y=!1,theInput.value!=tmp&&(theInput.value=tmp,-1===window.location.pathname.indexOf("preview.php"))){var e=new Event("change");theInput.dispatchEvent(e)}}}));var lastValue=JSON.stringify([[point1.X(),point1.Y()],[point2.X()-point1.X(),point2.Y()-point1.Y()]]);theInput.addEventListener("input",(function(){if(theInput.value!=lastValue){try{var tmp=JSON.parse(theInput.value);if("number"==typeof tmp[0][0]&&"number"==typeof tmp[0][1]&&point1.setPosition(JXG.COORDS_BY_USER,tmp[0]),"number"==typeof tmp[1][0]&&"number"==typeof tmp[1][1]){var b=[tmp[0][0]+tmp[1][0],tmp[0][1]+tmp[1][1]];point2.setPosition(JXG.COORDS_BY_USER,b),point1.board.update(),point1.update(),point2.board.update(),point2.update()}}catch(err){}lastValue=theInput.value}})),theInput.addEventListener("change",(function(){if(theInput.value!=lastValue){try{var tmp=JSON.parse(theInput.value);if("number"==typeof tmp[0][0]&&"number"==typeof tmp[0][1]&&point1.setPosition(JXG.COORDS_BY_USER,tmp[0]),"number"==typeof tmp[1][0]&&"number"==typeof tmp[1][1]){var b=[tmp[0][0]+tmp[1][0],tmp[0][1]+tmp[1][1]];point2.setPosition(JXG.COORDS_BY_USER,b),point1.board.update(),point1.update(),point2.board.update(),point2.update()}}catch(err){}lastValue=theInput.value}}))},bind_point_direction:function(inputRef,point1,point2){var theInput=document.getElementById(inputRef);if(theInput.value&&""!=theInput.value){var coords=JSON.parse(theInput.value);try{point1.setPosition(JXG.COORDS_BY_USER,coords[0]);var angle=coords[1][0],len=coords[1][1],b=[coords[0][0],coords[0][1]];len>0&&(b[0]=b[0]+len*Math.cos(angle),b[1]=b[1]+len*Math.sin(angle)),point2.setPosition(JXG.COORDS_BY_USER,b)}catch(err){}point1.board.update(),point1.update(),point2.board.update(),point2.update()}var initial1X=point1.X(),initial1Y=point1.Y();point1.board.on("update",(function(){if(initial1X!==point1.X()||initial1Y!==point1.Y()){var tmp=JSON.stringify([[point1.X(),point1.Y()],[Math.atan2(point2.Y()-point1.Y(),point2.X()-point1.X()),Math.sqrt((point2.X()-point1.X())*(point2.X()-point1.X())+(point2.Y()-point1.Y())*(point2.Y()-point1.Y()))]]);if(initial1X=!1,initial1Y=!1,theInput.value!=tmp&&(theInput.value=tmp,-1===window.location.pathname.indexOf("preview.php"))){var e=new Event("change");theInput.dispatchEvent(e)}}}));var initial2X=point2.X(),initial2Y=point2.Y();point2.board.on("update",(function(){if(initial2X!==point2.X()||initial2Y!==point2.Y()){var tmp=JSON.stringify([[point1.X(),point1.Y()],[Math.atan2(point2.Y()-point1.Y(),point2.X()-point1.X()),Math.sqrt((point2.X()-point1.X())*(point2.X()-point1.X())+(point2.Y()-point1.Y())*(point2.Y()-point1.Y()))]]);if(initial2X=!1,initial2Y=!1,theInput.value!=tmp&&(theInput.value=tmp,-1===window.location.pathname.indexOf("preview.php"))){var e=new Event("change");theInput.dispatchEvent(e)}}}));var lastValue=JSON.stringify([[point1.X(),point1.Y()],[Math.atan2(point2.Y()-point1.Y(),point2.X()-point1.X()),Math.sqrt((point2.X()-point1.X())*(point2.X()-point1.X())+(point2.Y()-point1.Y())*(point2.Y()-point1.Y()))]]);theInput.addEventListener("input",(function(){if(theInput.value!=lastValue){try{var tmp=JSON.parse(theInput.value);if("number"==typeof tmp[0][0]&&"number"==typeof tmp[0][1]&&point1.setPosition(JXG.COORDS_BY_USER,tmp[0]),"number"==typeof tmp[1][0]&&"number"==typeof tmp[1][1]){var angle=tmp[1][0],len=tmp[1][1],b=[tmp[0][0],tmp[0][1]];len>0&&(b[0]=b[0]+len*Math.cos(angle),b[1]=b[1]+len*Math.sin(angle)),point2.setPosition(JXG.COORDS_BY_USER,b),point1.board.update(),point1.update(),point2.board.update(),point2.update()}}catch(err){}lastValue=theInput.value}})),theInput.addEventListener("change",(function(){if(theInput.value!=lastValue){try{var tmp=JSON.parse(theInput.value);if("number"==typeof tmp[0][0]&&"number"==typeof tmp[0][1]&&point1.setPosition(JXG.COORDS_BY_USER,tmp[0]),"number"==typeof tmp[1][0]&&"number"==typeof tmp[1][1]){var angle=tmp[1][0],len=tmp[1][1],b=[tmp[0][0],tmp[0][1]];len>0&&(b[0]=b[0]+len*Math.cos(angle),b[1]=b[1]+len*Math.sin(angle)),point2.setPosition(JXG.COORDS_BY_USER,b),point1.board.update(),point1.update(),point2.board.update(),point2.update()}}catch(err){}lastValue=theInput.value}}))},bind_slider:function(inputRef,slider){var theInput=document.getElementById(inputRef);if(theInput.value&&""!=theInput.value){try{slider.setValue(JSON.parse(theInput.value))}catch(err){}slider.board.update(),slider.update()}var initialValue=slider.Value();slider.board.on("update",(function(){if(initialValue!=slider.Value()){var tmp=JSON.stringify(slider.Value());if(initialValue=!1,theInput.value!=tmp&&(theInput.value=tmp,-1===window.location.pathname.indexOf("preview.php"))){var e=new Event("change");theInput.dispatchEvent(e)}}}));var lastValue=JSON.stringify(slider.Value());theInput.addEventListener("input",(function(){if(theInput.value!==lastValue){try{var tmp=JSON.parse(theInput.value);"number"==typeof tmp&&(slider.setValue(tmp),slider.board.update(),slider.update())}catch(err){}lastValue=theInput.value}})),theInput.addEventListener("change",(function(){if(theInput.value!==lastValue){try{var tmp=JSON.parse(theInput.value);"number"==typeof tmp&&(slider.setValue(tmp),slider.board.update(),slider.update())}catch(err){}lastValue=theInput.value}}))}}})); + +//# sourceMappingURL=jsxgraph.min.js.map \ No newline at end of file diff --git a/amd/build/jsxgraph.min.js.map b/amd/build/jsxgraph.min.js.map index e87627920..fe6aa5595 100644 --- a/amd/build/jsxgraph.min.js.map +++ b/amd/build/jsxgraph.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["../src/jsxgraph.js"],"names":["define","JXG","find_input_id","divid","name","tmp","document","getElementById","parentElement","classList","contains","querySelector","addEventListener","M","core_formchangechecker","set_form_changed","id","bind_point","inputRef","point","theInput","value","coords","JSON","parse","setPosition","COORDS_BY_USER","err","board","update","initialX","X","initialY","Y","on","stringify","window","location","pathname","indexOf","e","Event","dispatchEvent","lastValue","bind_point_dual","point1","point2","initial1X","initial1Y","initial2X","initial2Y","bind_point_relative","b","bind_point_direction","angle","len","Math","cos","sin","atan2","sqrt","bind_slider","slider","setValue","initialValue","Value"],"mappings":"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","sourcesContent":["/// NOTE! This code does eval() a string with no validation.\n// So lets hope this is the correct way to name a Moodle AMD module\ndefine([\"qtype_stack/jsxgraphcore-lazy\"], function(JXG) {\n return {\n find_input_id: function(divid, name) {\n var tmp = document.getElementById(divid);\n while ((tmp = tmp.parentElement) && !(tmp.classList.contains(\"formulation\") && tmp.parentElement.classList.contains(\"content\"))) {}\n tmp = tmp.querySelector('input[id$=\"_' + name + '\"]');\n // We use this function to also tie into the change tracking of Moodle.\n // We do it here so that all possible code written by authors will also be tracked.\n // The author just needst to generate a change event they do not need to know how the VLE works.\n tmp.addEventListener('change', function(e) {\n M.core_formchangechecker.set_form_changed();\n });\n return tmp.id;\n },\n\n bind_point: function(inputRef, point) {\n // This function takes a JXG point object and binds its coordinates to a given input.\n var theInput = document.getElementById(inputRef);\n if (theInput.value && theInput.value != '') {\n // if a value exists move the point to it.\n // the value is stored as a list of float values e.g. \"[1,0.43]\"\n var coords = JSON.parse(theInput.value);\n try {\n point.setPosition(JXG.COORDS_BY_USER, coords);\n } catch (err) {\n // We do not care about this.\n }\n point.board.update();\n point.update();\n }\n\n var initialX = point.X();\n var initialY = point.Y();\n\n // Then the binding from graph to input.\n point.board.on('update', function() {\n // We do not want to set the input before the point actually moves.\n if (initialX !== point.X() || initialY !== point.Y()) {\n var tmp = JSON.stringify([point.X(), point.Y()]);\n initialX = false; // ignore these after initial change.\n initialY = false;\n if (theInput.value != tmp) {\n // Avoid resetting this, as some event models migth trigger\n // change events even when no change actually happens.\n theInput.value = tmp;\n // As we set the inputs value programmatically no events\n // will be fired. But for two way binding we want to fire them...\n // However we do not need this in the preview where it annoys people.\n if (window.location.pathname.indexOf('preview.php') === -1) {\n var e = new Event('change');\n theInput.dispatchEvent(e);\n }\n }\n }\n });\n\n var lastValue = JSON.stringify([point.X(), point.Y()]);\n\n // Then from input to graph. 'input' for live stuff and 'change' for other.\n theInput.addEventListener('input', function(e) {\n if (theInput.value != lastValue) {\n // Only when something changed.\n try {\n var tmp = JSON.parse(theInput.value);\n if (typeof tmp[0] == 'number' && typeof tmp[1] == 'number') {\n point.setPosition(JXG.COORDS_BY_USER, tmp);\n point.board.update();\n point.update();\n }\n } catch (err) {\n // We do not care about this.\n }\n lastValue = theInput.value;\n }\n });\n theInput.addEventListener('change', function(e) {\n if (theInput.value != lastValue) {\n // Only when something changed.\n try {\n var tmp = JSON.parse(theInput.value);\n if (typeof tmp[0] == 'number' && typeof tmp[1] == 'number') {\n point.setPosition(JXG.COORDS_BY_USER, tmp);\n point.board.update();\n point.update();\n }\n } catch (err) {\n // We do not care about this.\n }\n lastValue = theInput.value;\n }\n });\n },\n\n bind_point_dual: function(inputRef, point1, point2) {\n // This function takes two JXG point object and binds their coordinates to a given input.\n var theInput = document.getElementById(inputRef);\n if (theInput.value && theInput.value != '') {\n // if a value exists move the points there.\n // the value is stored as a list of float values e.g. \"[[1,0.43],[2.1,-4]]\"\n var coords = JSON.parse(theInput.value);\n try {\n point1.setPosition(JXG.COORDS_BY_USER, coords[0]);\n point2.setPosition(JXG.COORDS_BY_USER, coords[1]);\n } catch (err) {\n // We do not care about this.\n }\n point1.board.update();\n point1.update();\n point2.board.update();\n point2.update();\n }\n\n var initial1X = point1.X();\n var initial1Y = point1.Y();\n\n // Then the binding from graph to input.\n point1.board.on('update', function() {\n // We do not want to set the input before the point actually moves.\n if (initial1X !== point1.X() || initial1Y !== point1.Y()) {\n var tmp = JSON.stringify([[point1.X(), point1.Y()],[point2.X(), point2.Y()]]);\n initial1X = false; // ignore these after initial change.\n initial1Y = false;\n if (theInput.value != tmp) {\n // Avoid resetting this, as some event models migth trigger\n // change events even when no change actually happens.\n theInput.value = tmp;\n // As we set the inputs value programmatically no events\n // will be fired. But for two way binding we want to fire them...\n // However we do not need this in the preview where it annoys people.\n if (window.location.pathname.indexOf('preview.php') === -1) {\n var e = new Event('change');\n theInput.dispatchEvent(e);\n }\n }\n }\n });\n\n var initial2X = point2.X();\n var initial2Y = point2.Y();\n\n // Then the binding from graph to input.\n point2.board.on('update', function() {\n // We do not want to set the input before the point actually moves.\n if (initial2X !== point2.X() || initial2Y !== point2.Y()) {\n var tmp = JSON.stringify([[point1.X(), point1.Y()],[point2.X(), point2.Y()]]);\n initial2X = false; // ignore these after initial change.\n initial2Y = false;\n if (theInput.value != tmp) {\n // Avoid resetting this, as some event models migth trigger\n // change events even when no change actually happens.\n theInput.value = tmp;\n // As we set the inputs value programmatically no events\n // will be fired. But for two way binding we want to fire them...\n // However we do not need this in the preview where it annoys people.\n if (window.location.pathname.indexOf('preview.php') === -1) {\n var e = new Event('change');\n theInput.dispatchEvent(e);\n }\n }\n }\n });\n\n var lastValue = JSON.stringify([[point1.X(), point1.Y()],[point2.X(), point2.Y()]]);\n\n // Then from input to graph. 'input' for live stuff and 'change' for other.\n theInput.addEventListener('input', function(e) {\n if (theInput.value != lastValue) {\n // Only when something changed.\n try {\n var tmp = JSON.parse(theInput.value);\n if (typeof tmp[0][0] == 'number' && typeof tmp[0][1] == 'number') {\n point1.setPosition(JXG.COORDS_BY_USER, tmp[0]);\n }\n if (typeof tmp[1][0] == 'number' && typeof tmp[1][1] == 'number') {\n point2.setPosition(JXG.COORDS_BY_USER, tmp[1]);\n point1.board.update();\n point1.update();\n point2.board.update();\n point2.update();\n }\n } catch (err) {\n // We do not care about this.\n }\n lastValue = theInput.value;\n }\n });\n theInput.addEventListener('change', function(e) {\n if (theInput.value != lastValue) {\n // Only when something changed.\n try {\n var tmp = JSON.parse(theInput.value);\n if (typeof tmp[0][0] == 'number' && typeof tmp[0][1] == 'number') {\n point1.setPosition(JXG.COORDS_BY_USER, tmp[0]);\n\n }\n if (typeof tmp[1][0] == 'number' && typeof tmp[1][1] == 'number') {\n point2.setPosition(JXG.COORDS_BY_USER, tmp[1]);\n point1.board.update();\n point1.update();\n point2.board.update();\n point2.update();\n }\n } catch (err) {\n // We do not care about this.\n }\n lastValue = theInput.value;\n }\n });\n\n },\n\n bind_point_relative: function(inputRef, point1, point2) {\n // This function takes two JXG point object and binds their coordinates to a given input.\n var theInput = document.getElementById(inputRef);\n if (theInput.value && theInput.value != '') {\n // if a value exists move the points there.\n // the value is stored as a list of float values e.g. \"[[1,0.43],[2.1,-4]]\"\n var coords = JSON.parse(theInput.value);\n try {\n point1.setPosition(JXG.COORDS_BY_USER, coords[0]);\n var b = [coords[0][0] + coords[1][0], coords[0][1] + coords[1][1]];\n point2.setPosition(JXG.COORDS_BY_USER, b);\n } catch (err) {\n // We do not care about this.\n }\n point1.board.update();\n point1.update();\n point2.board.update();\n point2.update();\n }\n\n var initial1X = point1.X();\n var initial1Y = point1.Y();\n\n // Then the binding from graph to input.\n point1.board.on('update', function() {\n // We do not want to set the input before the point actually moves.\n if (initial1X !== point1.X() || initial1Y !== point1.Y()) {\n var tmp = JSON.stringify([[point1.X(), point1.Y()],[point2.X() - point1.X(), point2.Y() - point1.Y()]]);\n initial1X = false; // ignore these after initial change.\n initial1Y = false;\n if (theInput.value != tmp) {\n // Avoid resetting this, as some event models migth trigger\n // change events even when no change actually happens.\n theInput.value = tmp;\n // As we set the inputs value programmatically no events\n // will be fired. But for two way binding we want to fire them...\n // However we do not need this in the preview where it annoys people.\n if (window.location.pathname.indexOf('preview.php') === -1) {\n var e = new Event('change');\n theInput.dispatchEvent(e);\n }\n }\n }\n });\n\n var initial2X = point2.X();\n var initial2Y = point2.Y();\n\n // Then the binding from graph to input.\n point2.board.on('update', function() {\n // We do not want to set the input before the point actually moves.\n if (initial2X !== point2.X() || initial2Y !== point2.Y()) {\n var tmp = JSON.stringify([[point1.X(), point1.Y()],[point2.X() - point1.X(), point2.Y() - point1.Y()]]);\n initial2X = false; // ignore these after initial change.\n initial2Y = false;\n if (theInput.value != tmp) {\n // Avoid resetting this, as some event models migth trigger\n // change events even when no change actually happens.\n theInput.value = tmp;\n // As we set the inputs value programmatically no events\n // will be fired. But for two way binding we want to fire them...\n // However we do not need this in the preview where it annoys people.\n if (window.location.pathname.indexOf('preview.php') === -1) {\n var e = new Event('change');\n theInput.dispatchEvent(e);\n }\n }\n }\n });\n\n var lastValue = JSON.stringify([[point1.X(), point1.Y()],[point2.X() - point1.X(), point2.Y() - point1.Y()]]);\n\n // Then from input to graph. 'input' for live stuff and 'change' for other.\n theInput.addEventListener('input', function(e) {\n if (theInput.value != lastValue) {\n // Only when something changed.\n try {\n var tmp = JSON.parse(theInput.value);\n if (typeof tmp[0][0] == 'number' && typeof tmp[0][1] == 'number') {\n point1.setPosition(JXG.COORDS_BY_USER, tmp[0]);\n }\n if (typeof tmp[1][0] == 'number' && typeof tmp[1][1] == 'number') {\n var b = [tmp[0][0] + tmp[1][0], tmp[0][1] + tmp[1][1]];\n point2.setPosition(JXG.COORDS_BY_USER, b);\n point1.board.update();\n point1.update();\n point2.board.update();\n point2.update();\n }\n } catch (err) {\n // We do not care about this.\n }\n lastValue = theInput.value;\n }\n });\n theInput.addEventListener('change', function(e) {\n if (theInput.value != lastValue) {\n // Only when something changed.\n try {\n var tmp = JSON.parse(theInput.value);\n if (typeof tmp[0][0] == 'number' && typeof tmp[0][1] == 'number') {\n point1.setPosition(JXG.COORDS_BY_USER, tmp[0]);\n }\n if (typeof tmp[1][0] == 'number' && typeof tmp[1][1] == 'number') {\n var b = [tmp[0][0] + tmp[1][0], tmp[0][1] + tmp[1][1]];\n point2.setPosition(JXG.COORDS_BY_USER, b);\n point1.board.update();\n point1.update();\n point2.board.update();\n point2.update();\n }\n } catch (err) {\n // We do not care about this.\n }\n lastValue = theInput.value;\n }\n });\n },\n\n bind_point_direction: function(inputRef, point1, point2) {\n // This function takes two JXG point object and binds their coordinates to a given input.\n var theInput = document.getElementById(inputRef);\n if (theInput.value && theInput.value != '') {\n // if a value exists move the points there.\n // the value is stored as a list of float values e.g. \"[[1,0.43],[2.1,1.1]]\"\n // The second pair is now the angle in radians and the length.\n var coords = JSON.parse(theInput.value);\n try {\n point1.setPosition(JXG.COORDS_BY_USER, coords[0]);\n var angle = coords[1][0];\n var len = coords[1][1];\n var b = [coords[0][0], coords[0][1]];\n if (len > 0) {\n b[0] = b[0] + len*Math.cos(angle);\n b[1] = b[1] + len*Math.sin(angle);\n }\n point2.setPosition(JXG.COORDS_BY_USER, b);\n } catch (err) {\n // We do not care about this.\n }\n point1.board.update();\n point1.update();\n point2.board.update();\n point2.update();\n }\n\n var initial1X = point1.X();\n var initial1Y = point1.Y();\n\n // Then the binding from graph to input.\n point1.board.on('update', function() {\n // We do not want to set the input before the point actually moves.\n if (initial1X !== point1.X() || initial1Y !== point1.Y()) {\n var tmp = JSON.stringify([[point1.X(), point1.Y()],\n [Math.atan2(point2.Y() - point1.Y(), point2.X() - point1.X()),\n Math.sqrt((point2.X() - point1.X())*(point2.X() - point1.X()) + (point2.Y() - point1.Y())*(point2.Y() - point1.Y()))]]);\n initial1X = false; // ignore these after initial change.\n initial1Y = false;\n if (theInput.value != tmp) {\n // Avoid resetting this, as some event models migth trigger\n // change events even when no change actually happens.\n theInput.value = tmp;\n // As we set the inputs value programmatically no events\n // will be fired. But for two way binding we want to fire them...\n // However we do not need this in the preview where it annoys people.\n if (window.location.pathname.indexOf('preview.php') === -1) {\n var e = new Event('change');\n theInput.dispatchEvent(e);\n }\n }\n }\n });\n\n var initial2X = point2.X();\n var initial2Y = point2.Y();\n\n // Then the binding from graph to input.\n point2.board.on('update', function() {\n // We do not want to set the input before the point actually moves.\n if (initial2X !== point2.X() || initial2Y !== point2.Y()) {\n var tmp = JSON.stringify([[point1.X(), point1.Y()],\n [Math.atan2(point2.Y() - point1.Y(), point2.X() - point1.X()),\n Math.sqrt((point2.X() - point1.X())*(point2.X() - point1.X()) + (point2.Y() - point1.Y())*(point2.Y() - point1.Y()))]]);\n initial2X = false; // ignore these after initial change.\n initial2Y = false;\n if (theInput.value != tmp) {\n // Avoid resetting this, as some event models migth trigger\n // change events even when no change actually happens.\n theInput.value = tmp;\n // As we set the inputs value programmatically no events\n // will be fired. But for two way binding we want to fire them...\n // However we do not need this in the preview where it annoys people.\n if (window.location.pathname.indexOf('preview.php') === -1) {\n var e = new Event('change');\n theInput.dispatchEvent(e);\n }\n }\n }\n });\n\n\n var lastValue = JSON.stringify([[point1.X(), point1.Y()],\n [Math.atan2(point2.Y() - point1.Y(), point2.X() - point1.X()),\n Math.sqrt((point2.X() - point1.X())*(point2.X() - point1.X()) + (point2.Y() - point1.Y())*(point2.Y() - point1.Y()))]]);\n\n // Then from input to graph. 'input' for live stuff and 'change' for other.\n theInput.addEventListener('input', function(e) {\n if (theInput.value != lastValue) {\n // Only when something changed.\n try {\n var tmp = JSON.parse(theInput.value);\n if (typeof tmp[0][0] == 'number' && typeof tmp[0][1] == 'number') {\n point1.setPosition(JXG.COORDS_BY_USER, tmp[0]);\n }\n if (typeof tmp[1][0] == 'number' && typeof tmp[1][1] == 'number') {\n var angle = tmp[1][0];\n var len = tmp[1][1];\n var b = [tmp[0][0], tmp[0][1]];\n if (len > 0) {\n b[0] = b[0] + len*Math.cos(angle);\n b[1] = b[1] + len*Math.sin(angle);\n }\n point2.setPosition(JXG.COORDS_BY_USER, b);\n point1.board.update();\n point1.update();\n point2.board.update();\n point2.update();\n }\n } catch (err) {\n // We do not care about this.\n }\n lastValue = theInput.value;\n }\n });\n theInput.addEventListener('change', function(e) {\n if (theInput.value != lastValue) {\n // Only when something changed.\n try {\n var tmp = JSON.parse(theInput.value);\n if (typeof tmp[0][0] == 'number' && typeof tmp[0][1] == 'number') {\n point1.setPosition(JXG.COORDS_BY_USER, tmp[0]);\n }\n if (typeof tmp[1][0] == 'number' && typeof tmp[1][1] == 'number') {\n var angle = tmp[1][0];\n var len = tmp[1][1];\n var b = [tmp[0][0], tmp[0][1]];\n if (len > 0) {\n b[0] = b[0] + len*Math.cos(angle);\n b[1] = b[1] + len*Math.sin(angle);\n }\n point2.setPosition(JXG.COORDS_BY_USER, b);\n point1.board.update();\n point1.update();\n point2.board.update();\n point2.update();\n }\n } catch (err) {\n // We do not care about this.\n }\n lastValue = theInput.value;\n }\n });\n\n },\n\n bind_slider: function(inputRef, slider) {\n // This function takes a JXG slider object and binds its value to a given input.\n var theInput = document.getElementById(inputRef);\n if (theInput.value && theInput.value != '') {\n // if a value exists move the slider to it.\n // the value is stored as a float value \"0.43\"\n try {\n slider.setValue(JSON.parse(theInput.value));\n } catch (err) {\n // We do not care about this.\n }\n slider.board.update();\n slider.update();\n }\n\n var initialValue = slider.Value();\n\n // The binding from graph to input.\n slider.board.on('update', function() {\n // We do not want to set the input before the point actually moves.\n if (initialValue != slider.Value()) {\n var tmp = JSON.stringify(slider.Value());\n initialValue = false;\n if (theInput.value != tmp) {\n // Avoid resetting this, as some event models migth trigger\n // change events even when no change actually happens.\n theInput.value = tmp;\n // As we set the inputs value programmatically no events\n // will be fired. But for two way binding we want to fire them...\n // However we do not need this in the preview where it annoys people.\n if (window.location.pathname.indexOf('preview.php') === -1) {\n var e = new Event('change');\n theInput.dispatchEvent(e);\n }\n }\n }\n });\n\n var lastValue = JSON.stringify(slider.Value());\n\n // Then from input to graph. 'input' for live stuff and 'change' for other.\n theInput.addEventListener('input', function(e) {\n if (theInput.value !== lastValue) {\n // Only when something changed.\n try {\n var tmp = JSON.parse(theInput.value);\n if (typeof tmp == 'number') {\n slider.setValue(tmp);\n slider.board.update();\n slider.update();\n }\n } catch (err) {\n // We do not care about this.\n }\n lastValue = theInput.value;\n }\n });\n theInput.addEventListener('change', function(e) {\n if (theInput.value !== lastValue) {\n // Only when something changed.\n try {\n var tmp = JSON.parse(theInput.value);\n if (typeof tmp == 'number') {\n slider.setValue(tmp);\n slider.board.update();\n slider.update();\n }\n } catch (err) {\n // We do not care about this.\n }\n lastValue = theInput.value;\n }\n });\n }\n };\n });\n"],"file":"jsxgraph.min.js"} \ No newline at end of file +{"version":3,"file":"jsxgraph.min.js","sources":["../src/jsxgraph.js"],"sourcesContent":["/// NOTE! This code does eval() a string with no validation.\n// So lets hope this is the correct way to name a Moodle AMD module\ndefine([\"qtype_stack/jsxgraphcore-lazy\"], function(JXG) {\n return {\n find_input_id: function(divid, name) {\n var tmp = document.getElementById(divid);\n while ((tmp = tmp.parentElement) && !(tmp.classList.contains(\"formulation\") &&\n tmp.parentElement.classList.contains(\"content\"))) {}\n tmp = tmp.querySelector('input[id$=\"_' + name + '\"]');\n // We use this function to also tie into the change tracking of Moodle.\n // We do it here so that all possible code written by authors will also be tracked.\n // The author just needst to generate a change event they do not need to know how the VLE works.\n tmp.addEventListener('change', function() {\n M.core_formchangechecker.set_form_changed();\n });\n return tmp.id;\n },\n\n bind_point: function(inputRef, point) {\n // This function takes a JXG point object and binds its coordinates to a given input.\n var theInput = document.getElementById(inputRef);\n if (theInput.value && theInput.value != '') {\n // if a value exists move the point to it.\n // the value is stored as a list of float values e.g. \"[1,0.43]\"\n var coords = JSON.parse(theInput.value);\n try {\n point.setPosition(JXG.COORDS_BY_USER, coords);\n } catch (err) {\n // We do not care about this.\n }\n point.board.update();\n point.update();\n }\n\n var initialX = point.X();\n var initialY = point.Y();\n\n // Then the binding from graph to input.\n point.board.on('update', function() {\n // We do not want to set the input before the point actually moves.\n if (initialX !== point.X() || initialY !== point.Y()) {\n var tmp = JSON.stringify([point.X(), point.Y()]);\n initialX = false; // ignore these after initial change.\n initialY = false;\n if (theInput.value != tmp) {\n // Avoid resetting this, as some event models migth trigger\n // change events even when no change actually happens.\n theInput.value = tmp;\n // As we set the inputs value programmatically no events\n // will be fired. But for two way binding we want to fire them...\n // However we do not need this in the preview where it annoys people.\n if (window.location.pathname.indexOf('preview.php') === -1) {\n var e = new Event('change');\n theInput.dispatchEvent(e);\n }\n }\n }\n });\n\n var lastValue = JSON.stringify([point.X(), point.Y()]);\n\n // Then from input to graph. 'input' for live stuff and 'change' for other.\n theInput.addEventListener('input', function() {\n if (theInput.value != lastValue) {\n // Only when something changed.\n try {\n var tmp = JSON.parse(theInput.value);\n if (typeof tmp[0] == 'number' && typeof tmp[1] == 'number') {\n point.setPosition(JXG.COORDS_BY_USER, tmp);\n point.board.update();\n point.update();\n }\n } catch (err) {\n // We do not care about this.\n }\n lastValue = theInput.value;\n }\n });\n theInput.addEventListener('change', function() {\n if (theInput.value != lastValue) {\n // Only when something changed.\n try {\n var tmp = JSON.parse(theInput.value);\n if (typeof tmp[0] == 'number' && typeof tmp[1] == 'number') {\n point.setPosition(JXG.COORDS_BY_USER, tmp);\n point.board.update();\n point.update();\n }\n } catch (err) {\n // We do not care about this.\n }\n lastValue = theInput.value;\n }\n });\n },\n\n bind_point_dual: function(inputRef, point1, point2) {\n // This function takes two JXG point object and binds their coordinates to a given input.\n var theInput = document.getElementById(inputRef);\n if (theInput.value && theInput.value != '') {\n // if a value exists move the points there.\n // the value is stored as a list of float values e.g. \"[[1,0.43],[2.1,-4]]\"\n var coords = JSON.parse(theInput.value);\n try {\n point1.setPosition(JXG.COORDS_BY_USER, coords[0]);\n point2.setPosition(JXG.COORDS_BY_USER, coords[1]);\n } catch (err) {\n // We do not care about this.\n }\n point1.board.update();\n point1.update();\n point2.board.update();\n point2.update();\n }\n\n var initial1X = point1.X();\n var initial1Y = point1.Y();\n\n // Then the binding from graph to input.\n point1.board.on('update', function() {\n // We do not want to set the input before the point actually moves.\n if (initial1X !== point1.X() || initial1Y !== point1.Y()) {\n var tmp = JSON.stringify([[point1.X(), point1.Y()],[point2.X(), point2.Y()]]);\n initial1X = false; // ignore these after initial change.\n initial1Y = false;\n if (theInput.value != tmp) {\n // Avoid resetting this, as some event models migth trigger\n // change events even when no change actually happens.\n theInput.value = tmp;\n // As we set the inputs value programmatically no events\n // will be fired. But for two way binding we want to fire them...\n // However we do not need this in the preview where it annoys people.\n if (window.location.pathname.indexOf('preview.php') === -1) {\n var e = new Event('change');\n theInput.dispatchEvent(e);\n }\n }\n }\n });\n\n var initial2X = point2.X();\n var initial2Y = point2.Y();\n\n // Then the binding from graph to input.\n point2.board.on('update', function() {\n // We do not want to set the input before the point actually moves.\n if (initial2X !== point2.X() || initial2Y !== point2.Y()) {\n var tmp = JSON.stringify([[point1.X(), point1.Y()],[point2.X(), point2.Y()]]);\n initial2X = false; // ignore these after initial change.\n initial2Y = false;\n if (theInput.value != tmp) {\n // Avoid resetting this, as some event models migth trigger\n // change events even when no change actually happens.\n theInput.value = tmp;\n // As we set the inputs value programmatically no events\n // will be fired. But for two way binding we want to fire them...\n // However we do not need this in the preview where it annoys people.\n if (window.location.pathname.indexOf('preview.php') === -1) {\n var e = new Event('change');\n theInput.dispatchEvent(e);\n }\n }\n }\n });\n\n var lastValue = JSON.stringify([[point1.X(), point1.Y()],[point2.X(), point2.Y()]]);\n\n // Then from input to graph. 'input' for live stuff and 'change' for other.\n theInput.addEventListener('input', function() {\n if (theInput.value != lastValue) {\n // Only when something changed.\n try {\n var tmp = JSON.parse(theInput.value);\n if (typeof tmp[0][0] == 'number' && typeof tmp[0][1] == 'number') {\n point1.setPosition(JXG.COORDS_BY_USER, tmp[0]);\n }\n if (typeof tmp[1][0] == 'number' && typeof tmp[1][1] == 'number') {\n point2.setPosition(JXG.COORDS_BY_USER, tmp[1]);\n point1.board.update();\n point1.update();\n point2.board.update();\n point2.update();\n }\n } catch (err) {\n // We do not care about this.\n }\n lastValue = theInput.value;\n }\n });\n theInput.addEventListener('change', function() {\n if (theInput.value != lastValue) {\n // Only when something changed.\n try {\n var tmp = JSON.parse(theInput.value);\n if (typeof tmp[0][0] == 'number' && typeof tmp[0][1] == 'number') {\n point1.setPosition(JXG.COORDS_BY_USER, tmp[0]);\n\n }\n if (typeof tmp[1][0] == 'number' && typeof tmp[1][1] == 'number') {\n point2.setPosition(JXG.COORDS_BY_USER, tmp[1]);\n point1.board.update();\n point1.update();\n point2.board.update();\n point2.update();\n }\n } catch (err) {\n // We do not care about this.\n }\n lastValue = theInput.value;\n }\n });\n\n },\n\n bind_point_relative: function(inputRef, point1, point2) {\n // This function takes two JXG point object and binds their coordinates to a given input.\n var theInput = document.getElementById(inputRef);\n if (theInput.value && theInput.value != '') {\n // if a value exists move the points there.\n // the value is stored as a list of float values e.g. \"[[1,0.43],[2.1,-4]]\"\n var coords = JSON.parse(theInput.value);\n try {\n point1.setPosition(JXG.COORDS_BY_USER, coords[0]);\n var b = [coords[0][0] + coords[1][0], coords[0][1] + coords[1][1]];\n point2.setPosition(JXG.COORDS_BY_USER, b);\n } catch (err) {\n // We do not care about this.\n }\n point1.board.update();\n point1.update();\n point2.board.update();\n point2.update();\n }\n\n var initial1X = point1.X();\n var initial1Y = point1.Y();\n\n // Then the binding from graph to input.\n point1.board.on('update', function() {\n // We do not want to set the input before the point actually moves.\n if (initial1X !== point1.X() || initial1Y !== point1.Y()) {\n var tmp = JSON.stringify([[point1.X(), point1.Y()],[point2.X() - point1.X(), point2.Y() - point1.Y()]]);\n initial1X = false; // ignore these after initial change.\n initial1Y = false;\n if (theInput.value != tmp) {\n // Avoid resetting this, as some event models migth trigger\n // change events even when no change actually happens.\n theInput.value = tmp;\n // As we set the inputs value programmatically no events\n // will be fired. But for two way binding we want to fire them...\n // However we do not need this in the preview where it annoys people.\n if (window.location.pathname.indexOf('preview.php') === -1) {\n var e = new Event('change');\n theInput.dispatchEvent(e);\n }\n }\n }\n });\n\n var initial2X = point2.X();\n var initial2Y = point2.Y();\n\n // Then the binding from graph to input.\n point2.board.on('update', function() {\n // We do not want to set the input before the point actually moves.\n if (initial2X !== point2.X() || initial2Y !== point2.Y()) {\n var tmp = JSON.stringify([[point1.X(), point1.Y()],[point2.X() - point1.X(), point2.Y() - point1.Y()]]);\n initial2X = false; // ignore these after initial change.\n initial2Y = false;\n if (theInput.value != tmp) {\n // Avoid resetting this, as some event models migth trigger\n // change events even when no change actually happens.\n theInput.value = tmp;\n // As we set the inputs value programmatically no events\n // will be fired. But for two way binding we want to fire them...\n // However we do not need this in the preview where it annoys people.\n if (window.location.pathname.indexOf('preview.php') === -1) {\n var e = new Event('change');\n theInput.dispatchEvent(e);\n }\n }\n }\n });\n\n var lastValue = JSON.stringify([[point1.X(), point1.Y()],[point2.X() - point1.X(), point2.Y() - point1.Y()]]);\n\n // Then from input to graph. 'input' for live stuff and 'change' for other.\n theInput.addEventListener('input', function() {\n if (theInput.value != lastValue) {\n // Only when something changed.\n try {\n var tmp = JSON.parse(theInput.value);\n if (typeof tmp[0][0] == 'number' && typeof tmp[0][1] == 'number') {\n point1.setPosition(JXG.COORDS_BY_USER, tmp[0]);\n }\n if (typeof tmp[1][0] == 'number' && typeof tmp[1][1] == 'number') {\n var b = [tmp[0][0] + tmp[1][0], tmp[0][1] + tmp[1][1]];\n point2.setPosition(JXG.COORDS_BY_USER, b);\n point1.board.update();\n point1.update();\n point2.board.update();\n point2.update();\n }\n } catch (err) {\n // We do not care about this.\n }\n lastValue = theInput.value;\n }\n });\n theInput.addEventListener('change', function() {\n if (theInput.value != lastValue) {\n // Only when something changed.\n try {\n var tmp = JSON.parse(theInput.value);\n if (typeof tmp[0][0] == 'number' && typeof tmp[0][1] == 'number') {\n point1.setPosition(JXG.COORDS_BY_USER, tmp[0]);\n }\n if (typeof tmp[1][0] == 'number' && typeof tmp[1][1] == 'number') {\n var b = [tmp[0][0] + tmp[1][0], tmp[0][1] + tmp[1][1]];\n point2.setPosition(JXG.COORDS_BY_USER, b);\n point1.board.update();\n point1.update();\n point2.board.update();\n point2.update();\n }\n } catch (err) {\n // We do not care about this.\n }\n lastValue = theInput.value;\n }\n });\n },\n\n bind_point_direction: function(inputRef, point1, point2) {\n // This function takes two JXG point object and binds their coordinates to a given input.\n var theInput = document.getElementById(inputRef);\n if (theInput.value && theInput.value != '') {\n // if a value exists move the points there.\n // the value is stored as a list of float values e.g. \"[[1,0.43],[2.1,1.1]]\"\n // The second pair is now the angle in radians and the length.\n var coords = JSON.parse(theInput.value);\n try {\n point1.setPosition(JXG.COORDS_BY_USER, coords[0]);\n var angle = coords[1][0];\n var len = coords[1][1];\n var b = [coords[0][0], coords[0][1]];\n if (len > 0) {\n b[0] = b[0] + len*Math.cos(angle);\n b[1] = b[1] + len*Math.sin(angle);\n }\n point2.setPosition(JXG.COORDS_BY_USER, b);\n } catch (err) {\n // We do not care about this.\n }\n point1.board.update();\n point1.update();\n point2.board.update();\n point2.update();\n }\n\n var initial1X = point1.X();\n var initial1Y = point1.Y();\n\n // Then the binding from graph to input.\n point1.board.on('update', function() {\n // We do not want to set the input before the point actually moves.\n if (initial1X !== point1.X() || initial1Y !== point1.Y()) {\n var tmp = JSON.stringify([[point1.X(), point1.Y()],\n [Math.atan2(point2.Y() - point1.Y(), point2.X() - point1.X()),\n Math.sqrt((point2.X() - point1.X())*(point2.X() - point1.X()) +\n (point2.Y() - point1.Y())*(point2.Y() - point1.Y()))]]);\n initial1X = false; // ignore these after initial change.\n initial1Y = false;\n if (theInput.value != tmp) {\n // Avoid resetting this, as some event models migth trigger\n // change events even when no change actually happens.\n theInput.value = tmp;\n // As we set the inputs value programmatically no events\n // will be fired. But for two way binding we want to fire them...\n // However we do not need this in the preview where it annoys people.\n if (window.location.pathname.indexOf('preview.php') === -1) {\n var e = new Event('change');\n theInput.dispatchEvent(e);\n }\n }\n }\n });\n\n var initial2X = point2.X();\n var initial2Y = point2.Y();\n\n // Then the binding from graph to input.\n point2.board.on('update', function() {\n // We do not want to set the input before the point actually moves.\n if (initial2X !== point2.X() || initial2Y !== point2.Y()) {\n var tmp = JSON.stringify([[point1.X(), point1.Y()],\n [Math.atan2(point2.Y() - point1.Y(), point2.X() - point1.X()),\n Math.sqrt((point2.X() - point1.X())*(point2.X() - point1.X()) +\n (point2.Y() - point1.Y())*(point2.Y() - point1.Y()))]]);\n initial2X = false; // ignore these after initial change.\n initial2Y = false;\n if (theInput.value != tmp) {\n // Avoid resetting this, as some event models migth trigger\n // change events even when no change actually happens.\n theInput.value = tmp;\n // As we set the inputs value programmatically no events\n // will be fired. But for two way binding we want to fire them...\n // However we do not need this in the preview where it annoys people.\n if (window.location.pathname.indexOf('preview.php') === -1) {\n var e = new Event('change');\n theInput.dispatchEvent(e);\n }\n }\n }\n });\n\n\n var lastValue = JSON.stringify([[point1.X(), point1.Y()],\n [Math.atan2(point2.Y() - point1.Y(), point2.X() - point1.X()),\n Math.sqrt((point2.X() - point1.X())*(point2.X() - point1.X()) +\n (point2.Y() - point1.Y())*(point2.Y() - point1.Y()))]]);\n\n // Then from input to graph. 'input' for live stuff and 'change' for other.\n theInput.addEventListener('input', function() {\n if (theInput.value != lastValue) {\n // Only when something changed.\n try {\n var tmp = JSON.parse(theInput.value);\n if (typeof tmp[0][0] == 'number' && typeof tmp[0][1] == 'number') {\n point1.setPosition(JXG.COORDS_BY_USER, tmp[0]);\n }\n if (typeof tmp[1][0] == 'number' && typeof tmp[1][1] == 'number') {\n var angle = tmp[1][0];\n var len = tmp[1][1];\n var b = [tmp[0][0], tmp[0][1]];\n if (len > 0) {\n b[0] = b[0] + len*Math.cos(angle);\n b[1] = b[1] + len*Math.sin(angle);\n }\n point2.setPosition(JXG.COORDS_BY_USER, b);\n point1.board.update();\n point1.update();\n point2.board.update();\n point2.update();\n }\n } catch (err) {\n // We do not care about this.\n }\n lastValue = theInput.value;\n }\n });\n theInput.addEventListener('change', function() {\n if (theInput.value != lastValue) {\n // Only when something changed.\n try {\n var tmp = JSON.parse(theInput.value);\n if (typeof tmp[0][0] == 'number' && typeof tmp[0][1] == 'number') {\n point1.setPosition(JXG.COORDS_BY_USER, tmp[0]);\n }\n if (typeof tmp[1][0] == 'number' && typeof tmp[1][1] == 'number') {\n var angle = tmp[1][0];\n var len = tmp[1][1];\n var b = [tmp[0][0], tmp[0][1]];\n if (len > 0) {\n b[0] = b[0] + len*Math.cos(angle);\n b[1] = b[1] + len*Math.sin(angle);\n }\n point2.setPosition(JXG.COORDS_BY_USER, b);\n point1.board.update();\n point1.update();\n point2.board.update();\n point2.update();\n }\n } catch (err) {\n // We do not care about this.\n }\n lastValue = theInput.value;\n }\n });\n\n },\n\n bind_slider: function(inputRef, slider) {\n // This function takes a JXG slider object and binds its value to a given input.\n var theInput = document.getElementById(inputRef);\n if (theInput.value && theInput.value != '') {\n // if a value exists move the slider to it.\n // the value is stored as a float value \"0.43\"\n try {\n slider.setValue(JSON.parse(theInput.value));\n } catch (err) {\n // We do not care about this.\n }\n slider.board.update();\n slider.update();\n }\n\n var initialValue = slider.Value();\n\n // The binding from graph to input.\n slider.board.on('update', function() {\n // We do not want to set the input before the point actually moves.\n if (initialValue != slider.Value()) {\n var tmp = JSON.stringify(slider.Value());\n initialValue = false;\n if (theInput.value != tmp) {\n // Avoid resetting this, as some event models migth trigger\n // change events even when no change actually happens.\n theInput.value = tmp;\n // As we set the inputs value programmatically no events\n // will be fired. But for two way binding we want to fire them...\n // However we do not need this in the preview where it annoys people.\n if (window.location.pathname.indexOf('preview.php') === -1) {\n var e = new Event('change');\n theInput.dispatchEvent(e);\n }\n }\n }\n });\n\n var lastValue = JSON.stringify(slider.Value());\n\n // Then from input to graph. 'input' for live stuff and 'change' for other.\n theInput.addEventListener('input', function() {\n if (theInput.value !== lastValue) {\n // Only when something changed.\n try {\n var tmp = JSON.parse(theInput.value);\n if (typeof tmp == 'number') {\n slider.setValue(tmp);\n slider.board.update();\n slider.update();\n }\n } catch (err) {\n // We do not care about this.\n }\n lastValue = theInput.value;\n }\n });\n theInput.addEventListener('change', function() {\n if (theInput.value !== lastValue) {\n // Only when something changed.\n try {\n var tmp = JSON.parse(theInput.value);\n if (typeof tmp == 'number') {\n slider.setValue(tmp);\n slider.board.update();\n slider.update();\n }\n } catch (err) {\n // We do not care about this.\n }\n lastValue = theInput.value;\n }\n });\n }\n };\n });\n"],"names":["define","JXG","find_input_id","divid","name","tmp","document","getElementById","parentElement","classList","contains","querySelector","addEventListener","M","core_formchangechecker","set_form_changed","id","bind_point","inputRef","point","theInput","value","coords","JSON","parse","setPosition","COORDS_BY_USER","err","board","update","initialX","X","initialY","Y","on","stringify","window","location","pathname","indexOf","e","Event","dispatchEvent","lastValue","bind_point_dual","point1","point2","initial1X","initial1Y","initial2X","initial2Y","bind_point_relative","b","bind_point_direction","angle","len","Math","cos","sin","atan2","sqrt","bind_slider","slider","setValue","initialValue","Value"],"mappings":"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"} \ No newline at end of file diff --git a/amd/build/jsxgraphcore-lazy.min.js b/amd/build/jsxgraphcore-lazy.min.js index 19b10bb0d..c855f9a21 100644 --- a/amd/build/jsxgraphcore-lazy.min.js +++ b/amd/build/jsxgraphcore-lazy.min.js @@ -1,82 +1,8 @@ -/* - JSXGraph 1.2.1 - - Copyright 2008-2021 - Matthias Ehmann, - Michael Gerhaeuser, - Carsten Miller, - Bianca Valentin, - Alfred Wassermann, - Andreas Walter, - Peter Wilfahrt - - This file is part of JSXGraph. - - JSXGraph is free software dual licensed under the GNU LGPL or MIT License. - - You can redistribute it and/or modify it under the terms of the - - * GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version - OR - * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT - - JSXGraph is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License and - the MIT License along with JSXGraph. If not, see <https://www.gnu.org/licenses/> - and <https://opensource.org/licenses/MIT/>. -*/ - +function _typeof(obj){return _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(obj){return typeof obj}:function(obj){return obj&&"function"==typeof Symbol&&obj.constructor===Symbol&&obj!==Symbol.prototype?"symbol":typeof obj},_typeof(obj)}define("qtype_stack/jsxgraphcore-lazy",function(){ /** - * almond 0.2.5 Copyright (c) 2011-2012, The Dojo Foundation All Rights Reserved. - * Available via the MIT or new BSD license. - * see: https://github.com/jrburke/almond for details - */ + * @license almond 0.3.3 Copyright jQuery Foundation and other contributors. + * Released under MIT license, http://github.com/requirejs/almond/LICENSE + */ +var requirejs,require,define;return function(undef){var main,_req,makeMap,handlers,defined={},waiting={},config={},defining={},hasOwn=Object.prototype.hasOwnProperty,aps=[].slice,jsSuffixRegExp=/\.js$/;function hasProp(obj,prop){return hasOwn.call(obj,prop)}function normalize(name,baseName){var nameParts,nameSegment,mapValue,foundMap,lastIndex,foundI,foundStarMap,starI,i,j,part,baseParts=baseName&&baseName.split("/"),map=config.map,starMap=map&&map["*"]||{};if(name){for(lastIndex=(name=name.split("/")).length-1,config.nodeIdCompat&&jsSuffixRegExp.test(name[lastIndex])&&(name[lastIndex]=name[lastIndex].replace(jsSuffixRegExp,"")),"."===name[0].charAt(0)&&baseParts&&(name=baseParts.slice(0,baseParts.length-1).concat(name)),i=0;i<name.length;i++)if("."===(part=name[i]))name.splice(i,1),i-=1;else if(".."===part){if(0===i||1===i&&".."===name[2]||".."===name[i-1])continue;i>0&&(name.splice(i-1,2),i-=2)}name=name.join("/")}if((baseParts||starMap)&&map){for(i=(nameParts=name.split("/")).length;i>0;i-=1){if(nameSegment=nameParts.slice(0,i).join("/"),baseParts)for(j=baseParts.length;j>0;j-=1)if((mapValue=map[baseParts.slice(0,j).join("/")])&&(mapValue=mapValue[nameSegment])){foundMap=mapValue,foundI=i;break}if(foundMap)break;!foundStarMap&&starMap&&starMap[nameSegment]&&(foundStarMap=starMap[nameSegment],starI=i)}!foundMap&&foundStarMap&&(foundMap=foundStarMap,foundI=starI),foundMap&&(nameParts.splice(0,foundI,foundMap),name=nameParts.join("/"))}return name}function makeRequire(relName,forceSync){return function(){var args=aps.call(arguments,0);return"string"!=typeof args[0]&&1===args.length&&args.push(null),_req.apply(undefined,args.concat([relName,forceSync]))}}function makeLoad(depName){return function(value){defined[depName]=value}}function callDep(name){if(hasProp(waiting,name)){var args=waiting[name];delete waiting[name],defining[name]=!0,main.apply(undefined,args)}if(!hasProp(defined,name)&&!hasProp(defining,name))throw new Error("No "+name);return defined[name]}function splitPrefix(name){var prefix,index=name?name.indexOf("!"):-1;return index>-1&&(prefix=name.substring(0,index),name=name.substring(index+1,name.length)),[prefix,name]}function makeRelParts(relName){return relName?splitPrefix(relName):[]}function makeConfig(name){return function(){return config&&config.config&&config.config[name]||{}}}makeMap=function(name,relParts){var plugin,relName,parts=splitPrefix(name),prefix=parts[0],relResourceName=relParts[1];return name=parts[1],prefix&&(plugin=callDep(prefix=normalize(prefix,relResourceName))),prefix?name=plugin&&plugin.normalize?plugin.normalize(name,(relName=relResourceName,function(name){return normalize(name,relName)})):normalize(name,relResourceName):(prefix=(parts=splitPrefix(name=normalize(name,relResourceName)))[0],name=parts[1],prefix&&(plugin=callDep(prefix))),{f:prefix?prefix+"!"+name:name,n:name,pr:prefix,p:plugin}},handlers={require:function(name){return makeRequire(name)},exports:function(name){var e=defined[name];return void 0!==e?e:defined[name]={}},module:function(name){return{id:name,uri:"",exports:defined[name],config:makeConfig(name)}}},main=function(name,deps,callback,relName){var cjsModule,depName,ret,map,i,relParts,usingExports,args=[],callbackType=_typeof(callback);if(relParts=makeRelParts(relName=relName||name),"undefined"===callbackType||"function"===callbackType){for(deps=!deps.length&&callback.length?["require","exports","module"]:deps,i=0;i<deps.length;i+=1)if("require"===(depName=(map=makeMap(deps[i],relParts)).f))args[i]=handlers.require(name);else if("exports"===depName)args[i]=handlers.exports(name),usingExports=!0;else if("module"===depName)cjsModule=args[i]=handlers.module(name);else if(hasProp(defined,depName)||hasProp(waiting,depName)||hasProp(defining,depName))args[i]=callDep(depName);else{if(!map.p)throw new Error(name+" missing "+depName);map.p.load(map.n,makeRequire(relName,!0),makeLoad(depName),{}),args[i]=defined[depName]}ret=callback?callback.apply(defined[name],args):void 0,name&&(cjsModule&&undefined!==cjsModule.exports&&cjsModule.exports!==defined[name]?defined[name]=cjsModule.exports:undefined===ret&&usingExports||(defined[name]=ret))}else name&&(defined[name]=callback)},requirejs=require=_req=function(deps,callback,relName,forceSync,alt){if("string"==typeof deps)return handlers[deps]?handlers[deps](callback):callDep(makeMap(deps,makeRelParts(callback)).f);if(!deps.splice){if((config=deps).deps&&_req(config.deps,config.callback),!callback)return;callback.splice?(deps=callback,callback=relName,relName=null):deps=undefined}return callback=callback||function(){},"function"==typeof relName&&(relName=forceSync,forceSync=alt),forceSync?main(undefined,deps,callback,relName):setTimeout((function(){main(undefined,deps,callback,relName)}),4),_req},_req.config=function(cfg){return _req(cfg)},requirejs._defined=defined,(define=function(name,deps,callback){if("string"!=typeof name)throw new Error("See almond README: incorrect module build, no module name");deps.splice||(callback=deps,deps=[]),hasProp(defined,name)||hasProp(waiting,name)||(waiting[name]=[name,deps,callback])}).amd={jQuery:!0}}(),define("../node_modules/almond/almond",(function(){})),define("jxg",[],(function(){var jxg={};return"object"!==("undefined"==typeof JXG?"undefined":_typeof(JXG))||JXG.extend||(jxg=JXG),jxg.extend=function(object,extension,onlyOwn,toLower){var e;for(e in onlyOwn=onlyOwn||!1,toLower=toLower||!1,extension)(!onlyOwn||onlyOwn&&extension.hasOwnProperty(e))&&(object[toLower?e.toLowerCase():e]=extension[e])},jxg.defineConstant=function(object,name,value,ignoreRedefine){(ignoreRedefine=ignoreRedefine||!1)&&jxg.exists(object[name])||Object.defineProperty(object,name,{value:value,writable:!1,enumerable:!0,configurable:!1})},jxg.extendConstants=function(object,constants,onlyOwn,toUpper){var e,e2;for(e in onlyOwn=onlyOwn||!1,toUpper=toUpper||!1,constants)(!onlyOwn||onlyOwn&&constants.hasOwnProperty(e))&&(e2=toUpper?e.toUpperCase():e,this.defineConstant(object,e2,constants[e]))},jxg.extend(jxg,{boards:{},readers:{},elements:{},registerElement:function(element,creator){element=element.toLowerCase(),this.elements[element]=creator},registerReader:function(reader,ext){var i,e;for(i=0;i<ext.length;i++)e=ext[i].toLowerCase(),"function"!=typeof this.readers[e]&&(this.readers[e]=reader)},shortcut:function(object,fun){return function(){return object[fun].apply(this,arguments)}},getRef:function(board,s){return jxg.deprecated("JXG.getRef()","Board.select()"),board.select(s)},getReference:function(board,s){return jxg.deprecated("JXG.getReference()","Board.select()"),board.select(s)},getBoardByContainerId:function(s){var b;for(b in JXG.boards)if(JXG.boards.hasOwnProperty(b)&&JXG.boards[b].container===s)return JXG.boards[b];return null},deprecated:function(what,replacement){var warning=what+" is deprecated.";replacement&&(warning+=" Please use "+replacement+" instead."),jxg.warn(warning)},warn:function(warning){"object"===("undefined"==typeof window?"undefined":_typeof(window))&&window.console&&console.warn?console.warn("WARNING:",warning):"object"===("undefined"==typeof document?"undefined":_typeof(document))&&document.getElementById("warning")&&(document.getElementById("debug").innerHTML+="WARNING: "+warning+"<br />")},debugInt:function(s){var i,p;for(i=0;i<arguments.length;i++)p=arguments[i],"object"===("undefined"==typeof window?"undefined":_typeof(window))&&window.console&&console.log?console.log(p):"object"===("undefined"==typeof document?"undefined":_typeof(document))&&document.getElementById("debug")&&(document.getElementById("debug").innerHTML+=p+"<br/>")},debugWST:function(s){var e=new Error;jxg.debugInt.apply(this,arguments),e&&e.stack&&(jxg.debugInt("stacktrace"),jxg.debugInt(e.stack.split("\n").slice(1).join("\n")))},debugLine:function(s){var e=new Error;jxg.debugInt.apply(this,arguments),e&&e.stack&&jxg.debugInt("Called from",e.stack.split("\n").slice(2,3).join("\n"))},debug:function(s){jxg.debugInt.apply(this,arguments)}}),jxg})),define("base/constants",["jxg"],(function(JXG){var constants;return constants={version:"1.4.4",licenseText:"JSXGraph v1.4.4 Copyright (C) see https://jsxgraph.org",COORDS_BY_USER:1,COORDS_BY_SCREEN:2,OBJECT_TYPE_ARC:1,OBJECT_TYPE_ARROW:2,OBJECT_TYPE_AXIS:3,OBJECT_TYPE_AXISPOINT:4,OBJECT_TYPE_TICKS:5,OBJECT_TYPE_CIRCLE:6,OBJECT_TYPE_CONIC:7,OBJECT_TYPE_CURVE:8,OBJECT_TYPE_GLIDER:9,OBJECT_TYPE_IMAGE:10,OBJECT_TYPE_LINE:11,OBJECT_TYPE_POINT:12,OBJECT_TYPE_SLIDER:13,OBJECT_TYPE_CAS:14,OBJECT_TYPE_GXTCAS:15,OBJECT_TYPE_POLYGON:16,OBJECT_TYPE_SECTOR:17,OBJECT_TYPE_TEXT:18,OBJECT_TYPE_ANGLE:19,OBJECT_TYPE_INTERSECTION:20,OBJECT_TYPE_TURTLE:21,OBJECT_TYPE_VECTOR:22,OBJECT_TYPE_OPROJECT:23,OBJECT_TYPE_GRID:24,OBJECT_TYPE_TANGENT:25,OBJECT_TYPE_HTMLSLIDER:26,OBJECT_TYPE_CHECKBOX:27,OBJECT_TYPE_INPUT:28,OBJECT_TYPE_BUTTON:29,OBJECT_TYPE_TRANSFORMATION:30,OBJECT_TYPE_FOREIGNOBJECT:31,OBJECT_TYPE_VIEW3D:32,OBJECT_CLASS_POINT:1,OBJECT_CLASS_LINE:2,OBJECT_CLASS_CIRCLE:3,OBJECT_CLASS_CURVE:4,OBJECT_CLASS_AREA:5,OBJECT_CLASS_OTHER:6,OBJECT_CLASS_TEXT:7,GENTYPE_ABC:1,GENTYPE_AXIS:2,GENTYPE_MID:3,GENTYPE_REFLECTION:4,GENTYPE_MIRRORELEMENT:5,GENTYPE_REFLECTION_ON_LINE:4,GENTYPE_REFLECTION_ON_POINT:5,GENTYPE_TANGENT:6,GENTYPE_PARALLEL:7,GENTYPE_BISECTORLINES:8,GENTYPE_BOARDIMG:9,GENTYPE_BISECTOR:10,GENTYPE_NORMAL:11,GENTYPE_POINT:12,GENTYPE_GLIDER:13,GENTYPE_INTERSECTION:14,GENTYPE_CIRCLE:15,GENTYPE_CIRCLE2POINTS:16,GENTYPE_LINE:17,GENTYPE_TRIANGLE:18,GENTYPE_QUADRILATERAL:19,GENTYPE_TEXT:20,GENTYPE_POLYGON:21,GENTYPE_REGULARPOLYGON:22,GENTYPE_SECTOR:23,GENTYPE_ANGLE:24,GENTYPE_PLOT:25,GENTYPE_SLIDER:26,GENTYPE_TRUNCATE:27,GENTYPE_JCODE:28,GENTYPE_MOVEMENT:29,GENTYPE_COMBINED:30,GENTYPE_RULER:31,GENTYPE_SLOPETRIANGLE:32,GENTYPE_PERPSEGMENT:33,GENTYPE_LABELMOVEMENT:34,GENTYPE_VECTOR:35,GENTYPE_NONREFLEXANGLE:36,GENTYPE_REFLEXANGLE:37,GENTYPE_PATH:38,GENTYPE_DERIVATIVE:39,GENTYPE_DELETE:41,GENTYPE_COPY:42,GENTYPE_MIRROR:43,GENTYPE_ROTATE:44,GENTYPE_ABLATION:45,GENTYPE_MIGRATE:46,GENTYPE_VECTORCOPY:47,GENTYPE_POLYGONCOPY:48,GENTYPE_CTX_TYPE_G:51,GENTYPE_CTX_TYPE_P:52,GENTYPE_CTX_TRACE:53,GENTYPE_CTX_VISIBILITY:54,GENTYPE_CTX_CCVISIBILITY:55,GENTYPE_CTX_MPVISIBILITY:56,GENTYPE_CTX_WITHLABEL:57,GENTYPE_CTX_LABEL:58,GENTYPE_CTX_FIXED:59,GENTYPE_CTX_STROKEWIDTH:60,GENTYPE_CTX_LABELSIZE:61,GENTYPE_CTX_SIZE:62,GENTYPE_CTX_FACE:63,GENTYPE_CTX_STRAIGHT:64,GENTYPE_CTX_ARROW:65,GENTYPE_CTX_COLOR:66,GENTYPE_CTX_RADIUS:67,GENTYPE_CTX_COORDS:68,GENTYPE_CTX_TEXT:69,GENTYPE_CTX_ANGLERADIUS:70,GENTYPE_CTX_DOTVISIBILITY:71,GENTYPE_CTX_FILLOPACITY:72,GENTYPE_CTX_PLOT:73,GENTYPE_CTX_SCALE:74,GENTYPE_CTX_INTVAL:75,GENTYPE_CTX_POINT1:76,GENTYPE_CTX_POINT2:77,GENTYPE_CTX_LABELSTICKY:78,GENTYPE_CTX_TYPE_I:79,GENTYPE_CTX_HASINNERPOINTS:80,GENTYPE_CTX_SNAPWIDTH:81,GENTYPE_CTX_SNAPTOGRID:82},JXG.extendConstants(JXG,constants),constants})),define("utils/type",["jxg","base/constants"],(function(JXG,Const){return JXG.extend(JXG,{isId:function(board,s){return"string"==typeof s&&!!board.objects[s]},isName:function(board,s){return"string"==typeof s&&!!board.elementsByName[s]},isGroup:function(board,s){return"string"==typeof s&&!!board.groups[s]},isString:function(v){return"string"==typeof v},isNumber:function(v){return"number"==typeof v||"[Object Number]"===Object.prototype.toString.call(v)},isFunction:function(v){return"function"==typeof v},isArray:function(v){return Array.isArray?Array.isArray(v):null!==v&&"object"===_typeof(v)&&"function"==typeof v.splice&&"function"==typeof v.join},isObject:function(v){return"object"===_typeof(v)&&!this.isArray(v)},isPoint:function(v){return null!==v&&"object"===_typeof(v)&&v.elementClass===Const.OBJECT_CLASS_POINT},isPointType:function(board,v){var val,p;return!!this.isArray(v)||(!!(this.isFunction(v)&&(val=v(),this.isArray(val)&&val.length>1))||(p=board.select(v),this.isPoint(p)))},isTransformationOrArray:function(v){if(null!==v){if(this.isArray(v)&&v.length>0)return this.isTransformationOrArray(v[0]);if("object"===_typeof(v))return v.type===Const.OBJECT_TYPE_TRANSFORMATION}return!1},exists:function(v,checkEmptyString){var result=!(null==v||null===v);return(checkEmptyString=checkEmptyString||!1)?result&&""!==v:result},isEmpty:function(v){return 0===Object.keys(v).length},def:function(v,d){return this.exists(v)?v:d},str2Bool:function(s){return!this.exists(s)||("boolean"==typeof s?s:!!this.isString(s)&&"true"===s.toLowerCase())},createEvalFunction:function(board,param,n){var i,f=[];for(i=0;i<n;i++)f[i]=JXG.createFunction(param[i],board,"",!0);return function(k){return f[k]()}},createFunction:function(term,board,variableName,evalGeonext){var f=null;return this.exists(evalGeonext)&&!evalGeonext||!this.isString(term)?this.isFunction(term)?f=term:(this.isNumber(term)||this.isString(term))&&(f=function(){return term}):f=board.jc.snippet(term,!0,variableName,!0),null!==f&&(f.origin=term),f},providePoints:function(board,parents,attributes,attrClass,attrArray){var i,j,len,attr,val,lenAttr=0,points=[];for(this.isArray(parents)||(parents=[parents]),len=parents.length,this.exists(attrArray)&&(lenAttr=attrArray.length),0===lenAttr&&(attr=this.copyAttributes(attributes,board.options,attrClass)),i=0;i<len;++i)if(lenAttr>0&&(j=Math.min(i,lenAttr-1),attr=this.copyAttributes(attributes,board.options,attrClass,attrArray[j])),this.isArray(parents[i])&&parents[i].length>1?(points.push(board.create("point",parents[i],attr)),points[points.length-1]._is_new=!0):this.isFunction(parents[i])?(val=parents[i](),this.isArray(val)&&val.length>1&&(points.push(board.create("point",[parents[i]],attr)),points[points.length-1]._is_new=!0)):points.push(board.select(parents[i])),!this.isPoint(points[i]))return!1;return points},bind:function(fn,owner){return function(){return fn.apply(owner,arguments)}},evaluate:function(val){return this.isFunction(val)?val():val},indexOf:function(array,value,sub){var i,s=this.exists(sub);if(Array.indexOf&&!s)return array.indexOf(value);for(i=0;i<array.length;i++)if(s&&array[i][sub]===value||!s&&array[i]===value)return i;return-1},eliminateDuplicates:function(a){var i,len=a.length,result=[],obj={};for(i=0;i<len;i++)obj[a[i]]=0;for(i in obj)obj.hasOwnProperty(i)&&result.push(i);return result},swap:function(arr,i,j){var tmp;return tmp=arr[i],arr[i]=arr[j],arr[j]=tmp,arr},uniqueArray:function(arr){var i,j,isArray,ret=[];if(0===arr.length)return[];for(i=0;i<arr.length;i++)if(isArray=this.isArray(arr[i]),this.exists(arr[i]))for(j=i+1;j<arr.length;j++)isArray&&JXG.cmpArrays(arr[i],arr[j])?arr[i]=[]:isArray||arr[i]!==arr[j]||(arr[i]="");else arr[i]="";for(j=0,i=0;i<arr.length;i++)(isArray=this.isArray(arr[i]))||""===arr[i]?isArray&&0!==arr[i].length&&(ret[j]=arr[i].slice(0),j++):(ret[j]=arr[i],j++);return arr=ret,ret},isInArray:function(arr,val){return JXG.indexOf(arr,val)>-1},coordsArrayToMatrix:function(coords,split){var i,x=[],m=[];for(i=0;i<coords.length;i++)split?(x.push(coords[i].usrCoords[1]),m.push(coords[i].usrCoords[2])):m.push([coords[i].usrCoords[1],coords[i].usrCoords[2]]);return split&&(m=[x,m]),m},cmpArrays:function(a1,a2){var i;if(a1===a2)return!0;if(a1.length!==a2.length)return!1;for(i=0;i<a1.length;i++)if(this.isArray(a1[i])&&this.isArray(a2[i])){if(!this.cmpArrays(a1[i],a2[i]))return!1}else if(a1[i]!==a2[i])return!1;return!0},removeElementFromArray:function(ar,el){var i;for(i=0;i<ar.length;i++)if(ar[i]===el)return ar.splice(i,1),ar;return ar},trunc:function(n,p){return p=JXG.def(p,0),this.toFixed(n,p)},_decimalAdjust:function(type,value,exp){return void 0===exp||0==+exp?Math[type](value):(value=+value,exp=+exp,isNaN(value)||"number"!=typeof exp||exp%1!=0?NaN:(value=value.toString().split("e"),+((value=(value=Math[type](+(value[0]+"e"+(value[1]?+value[1]-exp:-exp)))).toString().split("e"))[0]+"e"+(value[1]?+value[1]+exp:exp))))},_round10:function(value,exp){return this._decimalAdjust("round",value,exp)},_floor10:function(value,exp){return this._decimalAdjust("floor",value,exp)},_ceil10:function(value,exp){return this._decimalAdjust("ceil",value,exp)},toFixed:function(num,digits){return this._round10(num,-digits).toFixed(digits)},autoDigits:function(val){var x=Math.abs(val);return x>.1?this.toFixed(val,2):x>=.01?this.toFixed(val,4):x>=1e-4?this.toFixed(val,6):val},keys:function(object,onlyOwn){var property,keys=[];for(property in object)onlyOwn?object.hasOwnProperty(property)&&keys.push(property):keys.push(property);return keys},clone:function(obj){var cObj={};return cObj.prototype=obj,cObj},cloneAndCopy:function(obj,obj2){var r,cObj=function(){};for(r in cObj.prototype=obj,obj2)cObj[r]=obj2[r];return cObj},merge:function(obj1,obj2){var i,j;for(i in obj2)if(obj2.hasOwnProperty(i))if(this.isArray(obj2[i]))for(obj1[i]||(obj1[i]=[]),j=0;j<obj2[i].length;j++)"object"===_typeof(obj2[i][j])?obj1[i][j]=this.merge(obj1[i][j],obj2[i][j]):obj1[i][j]=obj2[i][j];else"object"===_typeof(obj2[i])?(obj1[i]||(obj1[i]={}),obj1[i]=this.merge(obj1[i],obj2[i])):obj1[i]=obj2[i];return obj1},deepCopy:function(obj,obj2,toLower){var c,i,prop,i2;if(toLower=toLower||!1,"object"!==_typeof(obj)||null===obj)return obj;if(this.isArray(obj))for(c=[],i=0;i<obj.length;i++)"object"===_typeof(prop=obj[i])?this.exists(prop.board)?c[i]=prop.id:c[i]=this.deepCopy(prop):c[i]=prop;else{for(i in c={},obj)obj.hasOwnProperty(i)&&(i2=toLower?i.toLowerCase():i,null!==(prop=obj[i])&&"object"===_typeof(prop)?this.exists(prop.board)?c[i2]=prop.id:c[i2]=this.deepCopy(prop):c[i2]=prop);for(i in obj2)obj2.hasOwnProperty(i)&&(i2=toLower?i.toLowerCase():i,"object"===_typeof(prop=obj2[i])?this.isArray(prop)||!this.exists(c[i2])?c[i2]=this.deepCopy(prop):c[i2]=this.deepCopy(c[i2],prop,toLower):c[i2]=prop)}return c},copyAttributes:function(attributes,options,s){var a,i,len,o,isAvail,primitives={circle:1,curve:1,image:1,line:1,point:1,polygon:1,text:1,ticks:1,integral:1};for(a=(len=arguments.length)<3||primitives[s]?JXG.deepCopy(options.elements,null,!0):{},len<4&&this.exists(s)&&this.exists(options.layer[s])&&(a.layer=options.layer[s]),o=options,isAvail=!0,i=2;i<len;i++){if(!this.exists(o[arguments[i]])){isAvail=!1;break}o=o[arguments[i]]}for(isAvail&&(a=JXG.deepCopy(a,o,!0)),o="object"===_typeof(attributes)?attributes:{},isAvail=!0,i=3;i<len;i++){if(!this.exists(o[arguments[i]])){isAvail=!1;break}o=o[arguments[i]]}if(isAvail&&this.extend(a,o,null,!0),"board"===arguments[2])return a;for(o=options,isAvail=!0,i=2;i<len;i++){if(!this.exists(o[arguments[i]])){isAvail=!1;break}o=o[arguments[i]]}return isAvail&&this.exists(o.label)&&(a.label=JXG.deepCopy(o.label,a.label)),a.label=JXG.deepCopy(options.label,a.label),a},copyPrototypeMethods:function(subObject,superObject,constructorName){var key;for(key in subObject.prototype[constructorName]=superObject.prototype.constructor,superObject.prototype)superObject.prototype.hasOwnProperty(key)&&(subObject.prototype[key]=superObject.prototype[key])},toJSON:function(obj,noquote){var list,prop,i,val;if(noquote=JXG.def(noquote,!1),("undefined"==typeof JSON||_typeof(JSON))&&JSON.stringify&&!noquote)try{return JSON.stringify(obj)}catch(e){}switch(_typeof(obj)){case"object":if(obj){if(list=[],this.isArray(obj)){for(i=0;i<obj.length;i++)list.push(JXG.toJSON(obj[i],noquote));return"["+list.join(",")+"]"}for(prop in obj)if(obj.hasOwnProperty(prop)){try{val=JXG.toJSON(obj[prop],noquote)}catch(e2){val=""}noquote?list.push(prop+":"+val):list.push('"'+prop+'":'+val)}return"{"+list.join(",")+"} "}return"null";case"string":return"'"+obj.replace(/(["'])/g,"\\$1")+"'";case"number":case"boolean":return obj.toString()}return"0"},clearVisPropOld:function(el){return el.visPropOld={cssclass:"",cssdefaultstyle:"",cssstyle:"",fillcolor:"",fillopacity:"",firstarrow:!1,fontsize:-1,lastarrow:!1,left:-1e5,linecap:"",shadow:!1,strokecolor:"",strokeopacity:"",strokewidth:"",tabindex:-1e5,transitionduration:0,top:-1e5,visible:null},el},isInObject:function(obj,val){var el;for(el in obj)if(obj.hasOwnProperty(el)&&obj[el]===val)return!0;return!1},escapeHTML:function(str){return str.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")},unescapeHTML:function(str){return str.replace(/<\/?[^>]+>/gi,"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")},capitalize:function(str){return str.charAt(0).toUpperCase()+str.substring(1).toLowerCase()},trimNumber:function(str){return"."!==(str=(str=str.replace(/^0+/,"")).replace(/0+$/,""))[str.length-1]&&","!==str[str.length-1]||(str=str.slice(0,-1)),"."!==str[0]&&","!==str[0]||(str="0"+str),str},filterElements:function(list,filter){var i,f,item,flower,value,visPropValue,pass,l=list.length,result=[];if("function"!=typeof filter&&"object"!==_typeof(filter))return result;for(i=0;i<l;i++){if(pass=!0,item=list[i],"object"===_typeof(filter)){for(f in filter)if(filter.hasOwnProperty(f)&&(flower=f.toLowerCase(),value="function"==typeof item[f]?item[f]():item[f],visPropValue=item.visProp&&"function"==typeof item.visProp[flower]?item.visProp[flower]():item.visProp&&item.visProp[flower],!(pass="function"==typeof filter[f]?filter[f](value)||filter[f](visPropValue):value===filter[f]||visPropValue===filter[f])))break}else"function"==typeof filter&&(pass=filter(item));pass&&result.push(item)}return result},trim:function(str){return str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,"")},sanitizeHTML:function(str,caja){return"function"==typeof html_sanitize&&caja?html_sanitize(str,(function(){}),(function(id){return id})):(str&&"string"==typeof str&&(str=str.replace(/</g,"<").replace(/>/g,">")),str)},evalSlider:function(s){return s&&s.type===Const.OBJECT_TYPE_GLIDER&&"function"==typeof s.Value?s.Value():s}}),JXG})),define("utils/env",["jxg","utils/type"],(function(JXG,Type){return JXG.extendConstants(JXG,{touchProperty:"touches"}),JXG.extend(JXG,{isTouchEvent:function(evt){return JXG.exists(evt[JXG.touchProperty])},isPointerEvent:function(evt){return JXG.exists(evt.pointerId)},isMouseEvent:function(evt){return!JXG.isTouchEvent(evt)&&!JXG.isPointerEvent(evt)},getNumberOfTouchPoints:function(evt){var n=-1;return JXG.isTouchEvent(evt)&&(n=evt[JXG.touchProperty].length),n},isFirstTouch:function(evt){var touchPoints=JXG.getNumberOfTouchPoints(evt);return JXG.isPointerEvent(evt)?evt.isPrimary:1===touchPoints},isBrowser:"object"===("undefined"==typeof window?"undefined":_typeof(window))&&"object"===("undefined"==typeof document?"undefined":_typeof(document)),supportsES6:function(){try{return new Function("(a = 0) => a"),!0}catch(err){return!1}},supportsVML:function(){return this.isBrowser&&!!document.namespaces},supportsSVG:function(){return this.isBrowser&&document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure","1.1")},supportsCanvas:function(){var hasCanvas=!1;if(this.isNode())try{hasCanvas=!!("object"===("undefined"==typeof module?"undefined":_typeof(module))?module.require("canvas"):require("canvas"))}catch(err){}return hasCanvas||this.isBrowser&&!!document.createElement("canvas").getContext},isNode:function(){return!this.isBrowser&&("object"===("undefined"==typeof module?"undefined":_typeof(module))&&!!module.exports||"object"===("undefined"==typeof global?"undefined":_typeof(global))&&global.requirejsVars&&!global.requirejsVars.isBrowser)},isWebWorker:function(){return!this.isBrowser&&"object"===("undefined"==typeof self?"undefined":_typeof(self))&&"function"==typeof self.postMessage},supportsPointerEvents:function(){return!!(this.isBrowser&&window.navigator&&(window.PointerEvent||window.navigator.pointerEnabled||window.navigator.msPointerEnabled))},isTouchDevice:function(){return this.isBrowser&&void 0!==window.ontouchstart},isAndroid:function(){return Type.exists(navigator)&&navigator.userAgent.toLowerCase().indexOf("android")>-1},isWebkitAndroid:function(){return this.isAndroid()&&navigator.userAgent.indexOf(" AppleWebKit/")>-1},isApple:function(){return Type.exists(navigator)&&(navigator.userAgent.indexOf("iPad")>-1||navigator.userAgent.indexOf("iPhone")>-1)},isWebkitApple:function(){return this.isApple()&&navigator.userAgent.search(/Mobile\/[0-9A-Za-z.]*Safari/)>-1},isMetroApp:function(){return"object"===("undefined"==typeof window?"undefined":_typeof(window))&&window.clientInformation&&window.clientInformation.appVersion&&window.clientInformation.appVersion.indexOf("MSAppHost")>-1},isMozilla:function(){return Type.exists(navigator)&&navigator.userAgent.toLowerCase().indexOf("mozilla")>-1&&-1===navigator.userAgent.toLowerCase().indexOf("apple")},isFirefoxOS:function(){return Type.exists(navigator)&&-1===navigator.userAgent.toLowerCase().indexOf("android")&&-1===navigator.userAgent.toLowerCase().indexOf("apple")&&navigator.userAgent.toLowerCase().indexOf("mobile")>-1&&navigator.userAgent.toLowerCase().indexOf("mozilla")>-1},ieVersion:function(){var div,all,v=3;if("object"!==("undefined"==typeof document?"undefined":_typeof(document)))return 0;all=(div=document.createElement("div")).getElementsByTagName("i");do{div.innerHTML="\x3c!--[if gt IE "+ ++v+"]><i></i><![endif]--\x3e"}while(all[0]);return v>4?v:void 0}(),getDimensions:function(elementId,doc){var element,display,els,originalVisibility,originalPosition,originalDisplay,originalWidth,originalHeight,style,pixelDimRegExp=/\d+(\.\d*)?px/;if(!this.isBrowser||null===elementId)return{width:500,height:500};if(element=(doc=doc||document).getElementById(elementId),!Type.exists(element))throw new Error("\nJSXGraph: HTML container element '"+elementId+"' not found.");return"none"!==(display=element.style.display)&&null!==display?element.clientWidth>0&&element.clientHeight>0?{width:element.clientWidth,height:element.clientHeight}:(style=window.getComputedStyle?window.getComputedStyle(element):element.style,{width:pixelDimRegExp.test(style.width)?parseFloat(style.width):0,height:pixelDimRegExp.test(style.height)?parseFloat(style.height):0}):(originalVisibility=(els=element.style).visibility,originalPosition=els.position,originalDisplay=els.display,els.visibility="hidden",els.position="absolute",els.display="block",originalWidth=element.clientWidth,originalHeight=element.clientHeight,els.display=originalDisplay,els.position=originalPosition,els.visibility=originalVisibility,{width:originalWidth,height:originalHeight})},addEvent:function(obj,type,fn,owner){var el=function(){return fn.apply(owner,arguments)};el.origin=fn,owner["x_internal"+type]=owner["x_internal"+type]||[],owner["x_internal"+type].push(el),Type.exists(obj)&&Type.exists(obj.addEventListener)&&obj.addEventListener(type,el,!1),Type.exists(obj)&&Type.exists(obj.attachEvent)&&obj.attachEvent("on"+type,el)},removeEvent:function(obj,type,fn,owner){var i;if(Type.exists(owner))if(Type.exists(owner["x_internal"+type]))if(Type.isArray(owner["x_internal"+type]))if(-1!==(i=Type.indexOf(owner["x_internal"+type],fn,"origin"))){try{Type.exists(obj)&&Type.exists(obj.removeEventListener)&&obj.removeEventListener(type,owner["x_internal"+type][i],!1),Type.exists(obj)&&Type.exists(obj.detachEvent)&&obj.detachEvent("on"+type,owner["x_internal"+type][i])}catch(e){JXG.debug("event not registered in browser: ("+type+" -- "+fn+")")}owner["x_internal"+type].splice(i,1)}else JXG.debug("removeEvent: no such event function in internal list: "+fn);else JXG.debug("owner[x_internal + "+type+"] is not an array");else JXG.debug("no such type: "+type);else JXG.debug("no such owner")},removeAllEvents:function(obj,type,owner){var i;if(owner["x_internal"+type]){for(i=owner["x_internal"+type].length-1;i>=0;i--)JXG.removeEvent(obj,type,owner["x_internal"+type][i].origin,owner);owner["x_internal"+type].length>0&&JXG.debug("removeAllEvents: Not all events could be removed.")}},getPosition:function(e,index,doc){var i,len,evtTouches,posx=0,posy=0;if(e||(e=window.event),doc=doc||document,evtTouches=e[JXG.touchProperty],Type.exists(evtTouches)&&0===evtTouches.length&&(evtTouches=e.changedTouches),Type.exists(index)&&Type.exists(evtTouches))if(-1===index){for(len=evtTouches.length,i=0;i<len;i++)if(evtTouches[i]){e=evtTouches[i];break}}else e=evtTouches[index];return e.clientX&&(posx=e.clientX,posy=e.clientY),[posx,posy]},getOffset:function(obj){var cPos,o=obj,o2=obj,l=o.offsetLeft-o.scrollLeft,t=o.offsetTop-o.scrollTop;for(l=(cPos=this.getCSSTransform([l,t],o))[0],t=cPos[1],o=o.offsetParent;o;){for(l+=o.offsetLeft,t+=o.offsetTop,o.offsetParent&&(l+=o.clientLeft-o.scrollLeft,t+=o.clientTop-o.scrollTop),l=(cPos=this.getCSSTransform([l,t],o))[0],t=cPos[1],o2=o2.parentNode;o2!==o;)l+=o2.clientLeft-o2.scrollLeft,t+=o2.clientTop-o2.scrollTop,l=(cPos=this.getCSSTransform([l,t],o2))[0],t=cPos[1],o2=o2.parentNode;o=o.offsetParent}return[l,t]},getStyle:function(obj,stylename){var r,doc=obj.ownerDocument;return doc.defaultView&&doc.defaultView.getComputedStyle?r=doc.defaultView.getComputedStyle(obj,null).getPropertyValue(stylename):obj.currentStyle&&JXG.ieVersion>=9?r=obj.currentStyle[stylename]:obj.style&&(stylename=stylename.replace(/-([a-z]|[0-9])/gi,(function(all,letter){return letter.toUpperCase()})),r=obj.style[stylename]),r},getProp:function(el,css){var n=parseInt(this.getStyle(el,css),10);return isNaN(n)?0:n},getCSSTransform:function(cPos,obj){var i,j,str,start,len,len2,arr,t=["transform","webkitTransform","MozTransform","msTransform","oTransform"];for(len=t.length,i=0,str="";i<len;i++)if(Type.exists(obj.style[t[i]])){str=obj.style[t[i]];break}if(""!==str&&(start=str.indexOf("("))>0){for(len=str.length,j=0,len2=(arr=str.substring(start+1,len-1).split(",")).length;j<len2;j++)arr[j]=parseFloat(arr[j]);0===str.indexOf("matrix")?(cPos[0]+=arr[4],cPos[1]+=arr[5]):0===str.indexOf("translateX")?cPos[0]+=arr[0]:0===str.indexOf("translateY")?cPos[1]+=arr[0]:0===str.indexOf("translate")&&(cPos[0]+=arr[0],cPos[1]+=arr[1])}return Type.exists(obj.style.zoom)&&""!==(str=obj.style.zoom)&&(cPos[0]*=parseFloat(str),cPos[1]*=parseFloat(str)),cPos},getCSSTransformMatrix:function(obj){var i,j,str,start,len,len2,arr,st,doc=obj.ownerDocument,t=["transform","webkitTransform","MozTransform","msTransform","oTransform"],mat=[[1,0,0],[0,1,0],[0,0,1]];if(doc.defaultView&&doc.defaultView.getComputedStyle)str=(st=doc.defaultView.getComputedStyle(obj,null)).getPropertyValue("-webkit-transform")||st.getPropertyValue("-moz-transform")||st.getPropertyValue("-ms-transform")||st.getPropertyValue("-o-transform")||st.getPropertyValue("transform");else for(len=t.length,i=0,str="";i<len;i++)if(Type.exists(obj.style[t[i]])){str=obj.style[t[i]];break}if(""!==str&&(start=str.indexOf("("))>0){for(len=str.length,j=0,len2=(arr=str.substring(start+1,len-1).split(",")).length;j<len2;j++)arr[j]=parseFloat(arr[j]);0===str.indexOf("matrix")?mat=[[1,0,0],[0,arr[0],arr[1]],[0,arr[2],arr[3]]]:0===str.indexOf("scaleX")?mat[1][1]=arr[0]:0===str.indexOf("scaleY")?mat[2][2]=arr[0]:0===str.indexOf("scale")&&(mat[1][1]=arr[0],mat[2][2]=arr[1])}return Type.exists(obj.style.zoom)&&""!==(str=obj.style.zoom)&&(mat[1][1]*=parseFloat(str),mat[2][2]*=parseFloat(str)),mat},timedChunk:function(items,process,context,callback){var todo=items.concat();window.setTimeout((function timerFun(){var start=+new Date;do{process.call(context,todo.shift())}while(todo.length>0&&+new Date-start<300);todo.length>0?window.setTimeout(timerFun,1):callback(items)}),1)},_getScaleFactors:function(node){var width=node.getBoundingClientRect().width,height=node.getBoundingClientRect().height,r_w=window.screen.width/width,r_h=window.screen.height/height,vshift=.5*(window.screen.height-height),scale=Math.min(r_w,r_h);return window.matchMedia&&window.matchMedia("(orientation:landscape)").matches&&window.screen.width<window.screen.height&&(r_w=window.screen.height/width,r_h=window.screen.width/height,scale=Math.min(r_w,r_h),vshift=.5*(window.screen.width-height)),{scale:scale*=.85,vshift:vshift,width:width}},scaleJSXGraphDiv:function(wrap_id,inner_id,scale,vshift){var style,i,len=document.styleSheets.length,pseudo_keys=[":fullscreen",":-webkit-full-screen",":-moz-full-screen",":-ms-fullscreen"],len_pseudo=pseudo_keys.length,rule_inner="{margin:0 auto;transform:matrix("+scale+",0,0,"+scale+",0,"+vshift+");}",regex=new RegExp(".*#"+wrap_id+":.*full.*screen.*#"+inner_id+".*auto;.*transform:.*matrix");for(0===len&&((style=document.createElement("style")).appendChild(document.createTextNode("")),document.body.appendChild(style),len=document.styleSheets.length),document.styleSheets[len-1].cssRules.length>0&®ex.test(document.styleSheets[len-1].cssRules[0].cssText)&&document.styleSheets[len-1].deleteRule&&document.styleSheets[len-1].deleteRule(0),i=0;i<len_pseudo;i++)try{document.styleSheets[len-1].insertRule("#"+wrap_id+pseudo_keys[i]+" #"+inner_id+rule_inner,0);break}catch(err){}i===len_pseudo&&(console.log("JXG.scaleJSXGraphDiv: Could not add any CSS rule."),console.log("One possible reason could be that the id of the JSXGraph container does not start with a letter."))}}),JXG})),define("utils/xml",["jxg","utils/type"],(function(JXG,Type){return JXG.XML={cleanWhitespace:function(el){for(var cur=el.firstChild;Type.exists(cur);)3!==cur.nodeType||/\S/.test(cur.nodeValue)?1===cur.nodeType&&this.cleanWhitespace(cur):el.removeChild(cur),cur=cur.nextSibling},parse:function(str){var tree,DP;return DP="function"==typeof DOMParser||"object"===("undefined"==typeof DOMParser?"undefined":_typeof(DOMParser))?DOMParser:function(){this.parseFromString=function(str){var d;return"function"==typeof ActiveXObject&&(d=new ActiveXObject("MSXML.DomDocument")).loadXML(str),d}},tree=(new DP).parseFromString(str,"text/xml"),this.cleanWhitespace(tree),tree}},JXG.XML})),define("utils/event",["jxg","utils/type"],(function(JXG,Type){return JXG.EventEmitter={eventHandlers:{},suspended:{},trigger:function(event,args){var i,j,h,evt,len1,len2;for(len1=event.length,j=0;j<len1;j++)if(evt=this.eventHandlers[event[j]],!this.suspended[event[j]]){if(this.suspended[event[j]]=!0,evt)for(len2=evt.length,i=0;i<len2;i++)(h=evt[i]).handler.apply(h.context,args);this.suspended[event[j]]=!1}return this},on:function(event,handler,context){return Type.isArray(this.eventHandlers[event])||(this.eventHandlers[event]=[]),context=Type.def(context,this),this.eventHandlers[event].push({handler:handler,context:context}),this},off:function(event,handler){var i;return event&&Type.isArray(this.eventHandlers[event])?(handler?((i=Type.indexOf(this.eventHandlers[event],handler,"handler"))>-1&&this.eventHandlers[event].splice(i,1),0===this.eventHandlers[event].length&&delete this.eventHandlers[event]):delete this.eventHandlers[event],this):this},eventify:function(o){o.eventHandlers={},o.on=this.on,o.off=this.off,o.triggerEventHandlers=this.trigger,o.trigger=this.trigger,o.suspended={}}},JXG.EventEmitter})),define("math/math",["jxg","utils/type"],(function(JXG,Type){var memoizer=function(f){var cache,join;return f.memo||(cache={},join=Array.prototype.join,f.memo=function(){var key=join.call(arguments);return undefined!==cache[key]?cache[key]:cache[key]=f.apply(this,arguments)}),f.memo};return JXG.Math={eps:1e-6,relDif:function(a,b){var c=Math.abs(a),d=Math.abs(b);return 0===(d=Math.max(c,d))?0:Math.abs(a-b)/d},mod:function(a,m){return a-Math.floor(a/m)*m},vector:function(n,init){var r,i;for(init=init||0,r=[],i=0;i<n;i++)r[i]=init;return r},matrix:function(n,m,init){var r,i,j;for(init=init||0,m=m||n,r=[],i=0;i<n;i++)for(r[i]=[],j=0;j<m;j++)r[i][j]=init;return r},identity:function(n,m){var r,i;for(undefined===m&&"number"!=typeof m&&(m=n),r=this.matrix(n,m),i=0;i<Math.min(n,m);i++)r[i][i]=1;return r},frustum:function(l,r,b,t,n,f){var ret=this.matrix(4,4);return ret[0][0]=2*n/(r-l),ret[0][1]=0,ret[0][2]=(r+l)/(r-l),ret[0][3]=0,ret[1][0]=0,ret[1][1]=2*n/(t-b),ret[1][2]=(t+b)/(t-b),ret[1][3]=0,ret[2][0]=0,ret[2][1]=0,ret[2][2]=-(f+n)/(f-n),ret[2][3]=-f*n*2/(f-n),ret[3][0]=0,ret[3][1]=0,ret[3][2]=-1,ret[3][3]=0,ret},projection:function(fov,ratio,n,f){var t=n*Math.tan(fov/2),r=t*ratio;return this.frustum(-r,r,-t,t,n,f)},matVecMult:function(mat,vec){var i,s,k,m=mat.length,n=vec.length,res=[];if(3===n)for(i=0;i<m;i++)res[i]=mat[i][0]*vec[0]+mat[i][1]*vec[1]+mat[i][2]*vec[2];else for(i=0;i<m;i++){for(s=0,k=0;k<n;k++)s+=mat[i][k]*vec[k];res[i]=s}return res},matMatMult:function(mat1,mat2){var i,j,s,k,m=mat1.length,n=m>0?mat2[0].length:0,m2=mat2.length,res=this.matrix(m,n);for(i=0;i<m;i++)for(j=0;j<n;j++){for(s=0,k=0;k<m2;k++)s+=mat1[i][k]*mat2[k][j];res[i][j]=s}return res},transpose:function(M){var MT,i,j,m,n;for(m=M.length,n=M.length>0?M[0].length:0,MT=this.matrix(n,m),i=0;i<n;i++)for(j=0;j<m;j++)MT[i][j]=M[j][i];return MT},inverse:function(Ain){var i,j,k,s,ma,r,swp,n=Ain.length,A=[],p=[],hv=[];for(i=0;i<n;i++){for(A[i]=[],j=0;j<n;j++)A[i][j]=Ain[i][j];p[i]=i}for(j=0;j<n;j++){for(ma=Math.abs(A[j][j]),r=j,i=j+1;i<n;i++)Math.abs(A[i][j])>ma&&(ma=Math.abs(A[i][j]),r=i);if(ma<=this.eps)return[];if(r>j){for(k=0;k<n;k++)swp=A[j][k],A[j][k]=A[r][k],A[r][k]=swp;swp=p[j],p[j]=p[r],p[r]=swp}for(s=1/A[j][j],i=0;i<n;i++)A[i][j]*=s;for(A[j][j]=s,k=0;k<n;k++)if(k!==j){for(i=0;i<n;i++)i!==j&&(A[i][k]-=A[i][j]*A[j][k]);A[j][k]=-s*A[j][k]}}for(i=0;i<n;i++){for(k=0;k<n;k++)hv[p[k]]=A[i][k];for(k=0;k<n;k++)A[i][k]=hv[k]}return A},innerProduct:function(a,b,n){var i,s=0;for(undefined!==n&&Type.isNumber(n)||(n=a.length),i=0;i<n;i++)s+=a[i]*b[i];return s},crossProduct:function(c1,c2){return[c1[1]*c2[2]-c1[2]*c2[1],c1[2]*c2[0]-c1[0]*c2[2],c1[0]*c2[1]-c1[1]*c2[0]]},norm:function(a,n){var i,sum=0;for(undefined!==n&&Type.isNumber(n)||(n=a.length),i=0;i<n;i++)sum+=a[i]*a[i];return Math.sqrt(sum)},axpy:function(a,x,y){var i,le=x.length,p=[];for(i=0;i<le;i++)p[i]=a*x[i]+y[i];return p},factorial:memoizer((function(n){return n<0?NaN:0===(n=Math.floor(n))||1===n?1:n*this.factorial(n-1)})),binomial:memoizer((function(n,k){var b,i;if(k>n||k<0)return NaN;if(k=Math.round(k),n=Math.round(n),0===k||k===n)return 1;for(b=1,i=0;i<k;i++)b*=n-i,b/=i+1;return b})),cosh:Math.cosh||function(x){return.5*(Math.exp(x)+Math.exp(-x))},sinh:Math.sinh||function(x){return.5*(Math.exp(x)-Math.exp(-x))},acosh:Math.acosh||function(x){return Math.log(x+Math.sqrt(x*x-1))},asinh:Math.asinh||function(x){return x===-1/0?x:Math.log(x+Math.sqrt(x*x+1))},cot:function(x){return 1/Math.tan(x)},acot:function(x){return(x>=0?.5:-.5)*Math.PI-Math.atan(x)},nthroot:function(x,n){var inv=1/n;return n<=0||Math.floor(n)!==n?NaN:0===x?0:x>0?Math.exp(inv*Math.log(x)):n%2==1?-Math.exp(inv*Math.log(-x)):NaN},cbrt:Math.cbrt||function(x){return this.nthroot(x,3)},pow:function(base,exponent){return 0===base?0===exponent?1:0:Math.floor(exponent)===exponent?Math.pow(base,exponent):base>0?Math.exp(exponent*Math.log(base)):NaN},ratpow:function(base,m,n){var g;return 0===m?1:0===n?NaN:(g=this.gcd(m,n),this.nthroot(this.pow(base,m/g),n/g))},log10:function(x){return Math.log(x)/Math.log(10)},log2:function(x){return Math.log(x)/Math.log(2)},log:function(x,b){return void 0!==b&&Type.isNumber(b)?Math.log(x)/Math.log(b):Math.log(x)},sign:Math.sign||function(x){return 0===(x=+x)||isNaN(x)?x:x>0?1:-1},squampow:function(base,exponent){var result;if(Math.floor(exponent)===exponent){for(result=1,exponent<0&&(base=1/base,exponent*=-1);0!==exponent;)1&exponent&&(result*=base),exponent>>=1,base*=base;return result}return this.pow(base,exponent)},gcd:function(a,b){if(a=Math.abs(a),b=Math.abs(b),!Type.isNumber(a)||!Type.isNumber(b))return NaN;if(b>a){var temp=a;a=b,b=temp}for(;;){if(0===(a%=b))return b;if(0===(b%=a))return a}},lcm:function(a,b){var ret;return Type.isNumber(a)&&Type.isNumber(b)?0!==(ret=a*b)?ret/this.gcd(a,b):0:NaN},erf:function(x){return this.ProbFuncs.erf(x)},erfc:function(x){return this.ProbFuncs.erfc(x)},erfi:function(x){return this.ProbFuncs.erfi(x)},ndtr:function(x){return this.ProbFuncs.ndtr(x)},ndtri:function(x){return this.ProbFuncs.ndtri(x)},lt:function(a,b){return a<b},leq:function(a,b){return a<=b},gt:function(a,b){return a>b},geq:function(a,b){return a>=b},eq:function(a,b){return a===b},neq:function(a,b){return a!==b},and:function(a,b){return a&&b},not:function(a){return!a},or:function(a,b){return a||b},xor:function(a,b){return(a||b)&&!(a&&b)},normalize:function(stdform){var n,signr,a2=2*stdform[3],r=stdform[4]/a2;return stdform[5]=r,stdform[6]=-stdform[1]/a2,stdform[7]=-stdform[2]/a2,isFinite(r)?Math.abs(r)>=1?(stdform[0]=(stdform[6]*stdform[6]+stdform[7]*stdform[7]-r*r)/(2*r),stdform[1]=-stdform[6]/r,stdform[2]=-stdform[7]/r,stdform[3]=1/(2*r),stdform[4]=1):(signr=r<=0?-1:1,stdform[0]=signr*(stdform[6]*stdform[6]+stdform[7]*stdform[7]-r*r)*.5,stdform[1]=-signr*stdform[6],stdform[2]=-signr*stdform[7],stdform[3]=signr/2,stdform[4]=signr*r):(n=Math.sqrt(stdform[1]*stdform[1]+stdform[2]*stdform[2]),stdform[0]/=n,stdform[1]/=n,stdform[2]/=n,stdform[3]=0,stdform[4]=1),stdform},toGL:function(m){var v,i,j;if(v="function"==typeof Float32Array?new Float32Array(16):new Array(16),4!==m.length&&4!==m[0].length)return v;for(i=0;i<4;i++)for(j=0;j<4;j++)v[i+4*j]=m[i][j];return v},Vieta:function(x){var m,k,y,n=x.length,s=[];for(s=x.slice(),m=1;m<n;++m){for(y=s[m],s[m]*=s[m-1],k=m-1;k>=1;--k)s[k]+=s[k-1]*y;s[0]+=y}return s}},JXG.Math})),define("base/coords",["jxg","base/constants","utils/event","utils/type","math/math"],(function(JXG,Const,EventEmitter,Type,Mat){return JXG.Coords=function(method,coordinates,board,emitter){this.board=board,this.usrCoords=[],this.scrCoords=[],this.emitter=!Type.exists(emitter)||emitter,this.emitter&&EventEmitter.eventify(this),this.setCoordinates(method,coordinates,!1,!0)},JXG.extend(JXG.Coords.prototype,{normalizeUsrCoords:function(){Math.abs(this.usrCoords[0])>Mat.eps&&(this.usrCoords[1]/=this.usrCoords[0],this.usrCoords[2]/=this.usrCoords[0],this.usrCoords[0]=1)},usr2screen:function(doRound){var mround=Math.round,b=this.board,uc=this.usrCoords,oc=b.origin.scrCoords;!0===doRound?(this.scrCoords[0]=mround(uc[0]),this.scrCoords[1]=mround(uc[0]*oc[1]+uc[1]*b.unitX),this.scrCoords[2]=mround(uc[0]*oc[2]-uc[2]*b.unitY)):(this.scrCoords[0]=uc[0],this.scrCoords[1]=uc[0]*oc[1]+uc[1]*b.unitX,this.scrCoords[2]=uc[0]*oc[2]-uc[2]*b.unitY)},screen2usr:function(){var o=this.board.origin.scrCoords,sc=this.scrCoords,b=this.board;this.usrCoords[0]=1,this.usrCoords[1]=(sc[1]-o[1])/b.unitX,this.usrCoords[2]=(o[2]-sc[2])/b.unitY},distance:function(coord_type,coordinates){var c,f,sum=0,ucr=this.usrCoords,scr=this.scrCoords;if(coord_type===Const.COORDS_BY_USER){if(c=coordinates.usrCoords,(sum=(f=ucr[0]-c[0])*f)>Mat.eps*Mat.eps)return Number.POSITIVE_INFINITY;sum+=(f=ucr[1]-c[1])*f,sum+=(f=ucr[2]-c[2])*f}else c=coordinates.scrCoords,sum+=(f=scr[1]-c[1])*f,sum+=(f=scr[2]-c[2])*f;return Math.sqrt(sum)},setCoordinates:function(coord_type,coordinates,doRound,noevent){var uc=this.usrCoords,sc=this.scrCoords,ou=[uc[0],uc[1],uc[2]],os=[sc[0],sc[1],sc[2]];return coord_type===Const.COORDS_BY_USER?(2===coordinates.length?(uc[0]=1,uc[1]=coordinates[0],uc[2]=coordinates[1]):(uc[0]=coordinates[0],uc[1]=coordinates[1],uc[2]=coordinates[2],this.normalizeUsrCoords()),this.usr2screen(doRound)):(2===coordinates.length?(sc[1]=coordinates[0],sc[2]=coordinates[1]):(sc[1]=coordinates[1],sc[2]=coordinates[2]),this.screen2usr()),!this.emitter||noevent||os[1]===sc[1]&&os[2]===sc[2]||this.triggerEventHandlers(["update"],[ou,os]),this},copy:function(obj,offset){return void 0===offset&&(offset=0),this[obj].slice(offset)},isReal:function(){return!isNaN(this.usrCoords[1]+this.usrCoords[2])&&Math.abs(this.usrCoords[0])>Mat.eps},__evt__update:function(ou,os){},__evt:function(){}}),JXG.Coords})),define("utils/expect",["jxg","utils/type","base/constants","base/coords"],(function(JXG,Type,Const,Coords){var Expect={each:function(a,format,copy){var i,len,r=[];if(Type.exists(a.length))for(len=a.length,i=0;i<len;i++)r.push(format.call(this,a[i],copy));return r},coords:function(c,copy){var coord=c;return c&&c.elementClass===Const.OBJECT_CLASS_POINT?coord=c.coords:c.usrCoords&&c.scrCoords&&c.usr2screen&&(coord=c),copy&&(coord=new Coords(Const.COORDS_BY_USER,coord.usrCoords,coord.board)),coord},coordsArray:function(c,copy){var coord;return(coord=Type.isArray(c)?c:this.coords(c).usrCoords).length<3&&coord.unshift(1),copy&&(coord=[coord[0],coord[1],coord[2]]),coord}};return JXG.Expect=Expect,Expect})),define("math/probfuncs",["math/math","utils/type"],(function(Mat,Type){return Mat.ProbFuncs={MAXNUM:17014118346046923e22,SQRTH:.7071067811865476,SQRT2:1.4142135623730951,MAXLOG:708.3964185322641,P:[2.461969814735305e-10,.5641895648310689,7.463210564422699,48.63719709856814,196.5208329560771,526.4451949954773,934.5285271719576,1027.5518868951572,557.5353353693994],Q:[13.228195115474499,86.70721408859897,354.9377788878199,975.7085017432055,1823.9091668790973,2246.3376081871097,1656.6630919416134,557.5353408177277],R:[.5641895835477551,1.275366707599781,5.019050422511805,6.160210979930536,7.4097426995044895,2.9788666537210022],S:[2.2605286322011726,9.396035249380015,12.048953980809666,17.08144507475659,9.608968090632859,3.369076451000815],T:[9.604973739870516,90.02601972038427,2232.005345946843,7003.325141128051,55592.30130103949],U:[33.56171416475031,521.3579497801527,4594.323829709801,22629.000061389095,49267.39426086359],M:128,MINV:.0078125,expx2:function(x,sign){var u,u1,m,f;return x=Math.abs(x),sign<0&&(x=-x),u=(m=this.MINV*Math.floor(this.M*x+.5))*m,u1=2*m*(f=x-m)+f*f,sign<0&&(u=-u,u1=-u1),u+u1>this.MAXLOG?1/0:u=Math.exp(u)*Math.exp(u1)},polevl:function(x,coef,N){var ans,i;if(Type.exists(coef.reduce))return coef.reduce((function(acc,c){return acc*x+c}),0);for(i=0,ans=0;i<=N;i++)ans=ans*x+coef[i];return ans},p1evl:function(x,coef,N){var ans,i;if(Type.exists(coef.reduce))return coef.reduce((function(acc,c){return acc*x+c}),1);for(i=0,ans=1;i<N;i++)ans=ans*x+coef[i];return ans},ndtr:function(a){var x,y,z;return x=a*this.SQRTH,(z=Math.abs(x))<1?y=.5+.5*this.erf(x):(y=.5*this.erfce(z),z=this.expx2(a,-1),y*=Math.sqrt(z),x>0&&(y=1-y)),y},_underflow:function(a){return console.log("erfc","UNDERFLOW"),a<0?2:0},erfc:function(a){var p,q,x,y,z;return(x=a<0?-a:a)<1?1-this.erf(a):(z=-a*a)<-this.MAXLOG?this._underflow(a):(z=this.expx2(a,-1),x<8?(p=this.polevl(x,this.P,8),q=this.p1evl(x,this.Q,8)):(p=this.polevl(x,this.R,5),q=this.p1evl(x,this.S,6)),y=z*p/q,a<0&&(y=2-y),0===y?this._underflow(a):y)},erfce:function(x){var p,q;return x<8?(p=this.polevl(x,this.P,8),q=this.p1evl(x,this.Q,8)):(p=this.polevl(x,this.R,5),q=this.p1evl(x,this.S,6)),p/q},erf:function(x){var z;return Math.abs(x)>1?1-this.erfc(x):(z=x*x,x*this.polevl(z,this.T,4)/this.p1evl(z,this.U,5))},s2pi:2.5066282746310007,P0:[-59.96335010141079,98.00107541859997,-56.67628574690703,13.931260938727968,-1.2391658386738125],Q0:[1.9544885833814176,4.676279128988815,86.36024213908905,-225.46268785411937,200.26021238006066,-82.03722561683334,15.90562251262117,-1.1833162112133],P1:[4.0554489230596245,31.525109459989388,57.16281922464213,44.08050738932008,14.684956192885803,2.1866330685079025,-.1402560791713545,-.03504246268278482,-.0008574567851546854],Q1:[15.779988325646675,45.39076351288792,41.3172038254672,15.04253856929075,2.504649462083094,-.14218292285478779,-.03808064076915783,-.0009332594808954574],P2:[3.2377489177694603,6.915228890689842,3.9388102529247444,1.3330346081580755,.20148538954917908,.012371663481782003,.00030158155350823543,26580697468673755e-22,6.239745391849833e-9],Q2:[6.02427039364742,3.6798356385616087,1.3770209948908132,.21623699359449663,.013420400608854318,.00032801446468212774,28924786474538068e-22,6.790194080099813e-9],ndtri:function(y0){var x,y,z,y2,code;return y0<=0?-1/0:y0>=1?1/0:(code=1,(y=y0)>.8646647167633873&&(y=1-y,code=0),y>.1353352832366127?(x=(y-=.5)+y*((y2=y*y)*this.polevl(y2,this.P0,4)/this.p1evl(y2,this.Q0,8)),x*=this.s2pi):(z=1/(x=Math.sqrt(-2*Math.log(y))),x=x-Math.log(x)/x-(x<8?z*this.polevl(z,this.P1,8)/this.p1evl(z,this.Q1,8):z*this.polevl(z,this.P2,8)/this.p1evl(z,this.Q2,8)),0!==code&&(x=-x),x))},erfi:function(x){return this.ndtri(.5*(x+1))*this.SQRTH}},Mat.ProbFuncs})),define("math/ia",["jxg","math/math","utils/type"],(function(JXG,Mat,Type){JXG.Math.DoubleBits=function(){var doubleBitsLE,toDoubleLE,lowUintLE,highUintLE,doubleBitsBE,toDoubleBE,lowUintBE,highUintBE,DOUBLE_VIEW=new Float64Array(1),UINT_VIEW=new Uint32Array(DOUBLE_VIEW.buffer);void 0!==Float64Array&&(DOUBLE_VIEW[0]=1,!0,1072693248===UINT_VIEW[1]?(doubleBitsLE=function(n){return DOUBLE_VIEW[0]=n,[UINT_VIEW[0],UINT_VIEW[1]]},toDoubleLE=function(lo,hi){return UINT_VIEW[0]=lo,UINT_VIEW[1]=hi,DOUBLE_VIEW[0]},lowUintLE=function(n){return DOUBLE_VIEW[0]=n,UINT_VIEW[0]},highUintLE=function(n){return DOUBLE_VIEW[0]=n,UINT_VIEW[1]},this.doubleBits=doubleBitsLE,this.pack=toDoubleLE,this.lo=lowUintLE,this.hi=highUintLE):1072693248===UINT_VIEW[0]&&(doubleBitsBE=function(n){return DOUBLE_VIEW[0]=n,[UINT_VIEW[1],UINT_VIEW[0]]},toDoubleBE=function(lo,hi){return UINT_VIEW[1]=lo,UINT_VIEW[0]=hi,DOUBLE_VIEW[0]},lowUintBE=function(n){return DOUBLE_VIEW[0]=n,UINT_VIEW[1]},highUintBE=function(n){return DOUBLE_VIEW[0]=n,UINT_VIEW[0]},this.doubleBits=doubleBitsBE,this.pack=toDoubleBE,this.lo=lowUintBE,this.hi=highUintBE))},JXG.extend(JXG.Math.DoubleBits.prototype,{sign:function(n){return this.hi(n)>>>31},exponent:function(n){return(this.hi(n)<<1>>>21)-1023},fraction:function(n){var lo=this.lo(n),hi=this.hi(n),b=1048575&hi;return 2146435072&hi&&(b+=1<<20),[lo,b]},denormalized:function(n){return!(2146435072&this.hi(n))}});var doubleBits=new JXG.Math.DoubleBits,MatInterval=function MatInterval(lo,hi){if(void 0!==lo&&void 0!==hi){if(Mat.IntervalArithmetic.isInterval(lo)){if(!Mat.IntervalArithmetic.isSingleton(lo))throw new TypeError("JXG.Math.IntervalArithmetic: interval `lo` must be a singleton");this.lo=lo.lo}else this.lo=lo;if(Mat.IntervalArithmetic.isInterval(hi)){if(!Mat.IntervalArithmetic.isSingleton(hi))throw new TypeError("JXG.Math.IntervalArithmetic: interval `hi` must be a singleton");this.hi=hi.hi}else this.hi=hi}else{if(void 0!==lo)return Array.isArray(lo)?new MatInterval(lo[0],lo[1]):new MatInterval(lo,lo);this.lo=this.hi=0}};return JXG.extend(MatInterval.prototype,{print:function(){console.log("[",this.lo,this.hi,"]")},set:function(lo,hi){return this.lo=lo,this.hi=hi,this},bounded:function(lo,hi){return this.set(Mat.IntervalArithmetic.prev(lo),Mat.IntervalArithmetic.next(hi))},boundedSingleton:function(v){return this.bounded(v,v)},assign:function(lo,hi){if("number"!=typeof lo||"number"!=typeof hi)throw new TypeError("JXG.Math.Interval#assign: arguments must be numbers");return isNaN(lo)||isNaN(hi)||lo>hi?this.setEmpty():this.set(lo,hi)},setEmpty:function(){return this.set(Number.POSITIVE_INFINITY,Number.NEGATIVE_INFINITY)},setWhole:function(){return this.set(Number.NEGATIVE_INFINITY,Number.POSITIVE_INFINITY)},open:function(lo,hi){return this.assign(Mat.IntervalArithmetic.next(lo),Mat.IntervalArithmetic.prev(hi))},halfOpenLeft:function(lo,hi){return this.assign(Mat.IntervalArithmetic.next(lo),hi)},halfOpenRight:function(lo,hi){return this.assign(lo,Mat.IntervalArithmetic.prev(hi))},toArray:function(){return[this.lo,this.hi]},clone:function(){return(new MatInterval).set(this.lo,this.hi)}}),JXG.Math.IntervalArithmetic={Interval:function(lo,hi){return new MatInterval(lo,hi)},isInterval:function(i){return null!==i&&"object"===_typeof(i)&&"number"==typeof i.lo&&"number"==typeof i.hi},isSingleton:function(i){return i.lo===i.hi},add:function(x,y){return Type.isNumber(x)&&(x=this.Interval(x)),Type.isNumber(y)&&(y=this.Interval(y)),new MatInterval(this.addLo(x.lo,y.lo),this.addHi(x.hi,y.hi))},sub:function(x,y){return Type.isNumber(x)&&(x=this.Interval(x)),Type.isNumber(y)&&(y=this.Interval(y)),new MatInterval(this.subLo(x.lo,y.hi),this.subHi(x.hi,y.lo))},mul:function(x,y){var xl,xh,yl,yh,out;return Type.isNumber(x)&&(x=this.Interval(x)),Type.isNumber(y)&&(y=this.Interval(y)),this.isEmpty(x)||this.isEmpty(y)?this.EMPTY.clone():(xl=x.lo,xh=x.hi,yl=y.lo,yh=y.hi,out=new MatInterval,xl<0?xh>0?yl<0?yh>0?(out.lo=Math.min(this.mulLo(xl,yh),this.mulLo(xh,yl)),out.hi=Math.max(this.mulHi(xl,yl),this.mulHi(xh,yh))):(out.lo=this.mulLo(xh,yl),out.hi=this.mulHi(xl,yl)):yh>0?(out.lo=this.mulLo(xl,yh),out.hi=this.mulHi(xh,yh)):(out.lo=0,out.hi=0):yl<0?yh>0?(out.lo=this.mulLo(xl,yh),out.hi=this.mulHi(xl,yl)):(out.lo=this.mulLo(xh,yh),out.hi=this.mulHi(xl,yl)):yh>0?(out.lo=this.mulLo(xl,yh),out.hi=this.mulHi(xh,yl)):(out.lo=0,out.hi=0):xh>0?yl<0?yh>0?(out.lo=this.mulLo(xh,yl),out.hi=this.mulHi(xh,yh)):(out.lo=this.mulLo(xh,yl),out.hi=this.mulHi(xl,yh)):yh>0?(out.lo=this.mulLo(xl,yl),out.hi=this.mulHi(xh,yh)):(out.lo=0,out.hi=0):(out.lo=0,out.hi=0),out)},div:function(x,y){return Type.isNumber(x)&&(x=this.Interval(x)),Type.isNumber(y)&&(y=this.Interval(y)),this.isEmpty(x)||this.isEmpty(y)?this.EMPTY.clone():this.zeroIn(y)?0!==y.lo?0!==y.hi?this.divZero(x):this.divNegative(x,y.lo):0!==y.hi?this.divPositive(x,y.hi):this.EMPTY.clone():this.divNonZero(x,y)},positive:function(x){return new MatInterval(x.lo,x.hi)},negative:function(x){return Type.isNumber(x)?new MatInterval(-x):new MatInterval(-x.hi,-x.lo)},isEmpty:function(i){return i.lo>i.hi},isWhole:function(i){return i.lo===-1/0&&i.hi===1/0},zeroIn:function(i){return this.hasValue(i,0)},hasValue:function(i,value){return!this.isEmpty(i)&&(i.lo<=value&&value<=i.hi)},hasInterval:function(x,y){return!!this.isEmpty(x)||!this.isEmpty(y)&&y.lo<=x.lo&&x.hi<=y.hi},intervalsOverlap:function(x,y){return!this.isEmpty(x)&&!this.isEmpty(y)&&(x.lo<=y.lo&&y.lo<=x.hi||y.lo<=x.lo&&x.lo<=y.hi)},divNonZero:function(x,y){var xl=x.lo,xh=x.hi,yl=y.lo,yh=y.hi,out=new MatInterval;return xh<0?yh<0?(out.lo=this.divLo(xh,yl),out.hi=this.divHi(xl,yh)):(out.lo=this.divLo(xl,yl),out.hi=this.divHi(xh,yh)):xl<0?yh<0?(out.lo=this.divLo(xh,yh),out.hi=this.divHi(xl,yh)):(out.lo=this.divLo(xl,yl),out.hi=this.divHi(xh,yl)):yh<0?(out.lo=this.divLo(xh,yh),out.hi=this.divHi(xl,yl)):(out.lo=this.divLo(xl,yh),out.hi=this.divHi(xh,yl)),out},divPositive:function(x,v){return 0===x.lo&&0===x.hi?x:this.zeroIn(x)?this.WHOLE:x.hi<0?new MatInterval(Number.NEGATIVE_INFINITY,this.divHi(x.hi,v)):new MatInterval(this.divLo(x.lo,v),Number.POSITIVE_INFINITY)},divNegative:function(x,v){return 0===x.lo&&0===x.hi?x:this.zeroIn(x)?this.WHOLE:x.hi<0?new MatInterval(this.divLo(x.hi,v),Number.POSITIVE_INFINITY):new MatInterval(Number.NEGATIVE_INFINITY,this.divHi(x.lo,v))},divZero:function(x){return 0===x.lo&&0===x.hi?x:this.WHOLE},fmod:function(x,y){var yb,n;return Type.isNumber(x)&&(x=this.Interval(x)),Type.isNumber(y)&&(y=this.Interval(y)),this.isEmpty(x)||this.isEmpty(y)?this.EMPTY.clone():(yb=x.lo<0?y.lo:y.hi,n=(n=x.lo/yb)<0?Math.ceil(n):Math.floor(n),this.sub(x,this.mul(y,new MatInterval(n))))},multiplicativeInverse:function(x){return Type.isNumber(x)&&(x=this.Interval(x)),this.isEmpty(x)?this.EMPTY.clone():this.zeroIn(x)?0!==x.lo?0!==x.hi?this.WHOLE:new MatInterval(Number.NEGATIVE_INFINITY,this.divHi(1,x.lo)):0!==x.hi?new MatInterval(this.divLo(1,x.hi),Number.POSITIVE_INFINITY):this.EMPTY.clone():new MatInterval(this.divLo(1,x.hi),this.divHi(1,x.lo))},pow:function(x,power){var yl,yh;if(Type.isNumber(x)&&(x=this.Interval(x)),this.isEmpty(x))return this.EMPTY.clone();if(this.isInterval(power)){if(!this.isSingleton(power))return this.EMPTY.clone();power=power.lo}return 0===power?0===x.lo&&0===x.hi?this.EMPTY.clone():this.ONE.clone():power<0?this.pow(this.multiplicativeInverse(x),-power):power%1==0?x.hi<0?(yl=this.powLo(-x.hi,power),yh=this.powHi(-x.lo,power),1==(1&power)?new MatInterval(-yh,-yl):new MatInterval(yl,yh)):x.lo<0?1==(1&power)?new MatInterval(-this.powLo(-x.lo,power),this.powHi(x.hi,power)):new MatInterval(0,this.powHi(Math.max(-x.lo,x.hi),power)):new MatInterval(this.powLo(x.lo,power),this.powHi(x.hi,power)):(console.warn("power is not an integer, you should use nth-root instead, returning an empty interval"),this.EMPTY.clone())},sqrt:function(x){return Type.isNumber(x)&&(x=this.Interval(x)),this.nthRoot(x,2)},nthRoot:function(x,n){var power,yl,yh,yp,yn;if(Type.isNumber(x)&&(x=this.Interval(x)),this.isEmpty(x)||n<0)return this.EMPTY.clone();if(this.isInterval(n)){if(!this.isSingleton(n))return this.EMPTY.clone();n=n.lo}return power=1/n,x.hi<0?n%1==0&&1==(1&n)?(yl=this.powHi(-x.lo,power),yh=this.powLo(-x.hi,power),new MatInterval(-yl,-yh)):this.EMPTY.clone():x.lo<0?(yp=this.powHi(x.hi,power),n%1==0&&1==(1&n)?(yn=-this.powHi(-x.lo,power),new MatInterval(yn,yp)):new MatInterval(0,yp)):new MatInterval(this.powLo(x.lo,power),this.powHi(x.hi,power))},exp:function(x){return Type.isNumber(x)&&(x=this.Interval(x)),this.isEmpty(x)?this.EMPTY.clone():new MatInterval(this.expLo(x.lo),this.expHi(x.hi))},log:function(x){var l;return Type.isNumber(x)&&(x=this.Interval(x)),this.isEmpty(x)?this.EMPTY.clone():(l=x.lo<=0?Number.NEGATIVE_INFINITY:this.logLo(x.lo),new MatInterval(l,this.logHi(x.hi)))},ln:function(x){return this.log(x)},log10:function(x){return this.isEmpty(x)?this.EMPTY.clone():this.div(this.log(x),this.log(new MatInterval(10,10)))},log2:function(x){return this.isEmpty(x)?this.EMPTY.clone():this.div(this.log(x),this.log(new MatInterval(2,2)))},hull:function(x,y){var badX=this.isEmpty(x),badY=this.isEmpty(y);return badX&&badY?this.EMPTY.clone():badX?y.clone():badY?x.clone():new MatInterval(Math.min(x.lo,y.lo),Math.max(x.hi,y.hi))},intersection:function(x,y){var lo,hi;return this.isEmpty(x)||this.isEmpty(y)?this.EMPTY.clone():(lo=Math.max(x.lo,y.lo))<=(hi=Math.min(x.hi,y.hi))?new MatInterval(lo,hi):this.EMPTY.clone()},union:function(x,y){if(!this.intervalsOverlap(x,y))throw new Error("Interval#unions do not overlap");return new MatInterval(Math.min(x.lo,y.lo),Math.max(x.hi,y.hi))},difference:function(x,y){if(this.isEmpty(x)||this.isWhole(y))return this.EMPTY.clone();if(this.intervalsOverlap(x,y)){if(x.lo<y.lo&&y.hi<x.hi)throw new Error("Interval.difference: difference creates multiple intervals");return y.lo<=x.lo&&y.hi===1/0||y.hi>=x.hi&&y.lo===-1/0?this.EMPTY.clone():y.lo<=x.lo?(new MatInterval).halfOpenLeft(y.hi,x.hi):(new MatInterval).halfOpenRight(x.lo,y.lo)}return x.clone()},width:function(x){return this.isEmpty(x)?0:this.subHi(x.hi,x.lo)},abs:function(x){return Type.isNumber(x)&&(x=this.Interval(x)),this.isEmpty(x)?this.EMPTY.clone():x.lo>=0?x.clone():x.hi<=0?this.negative(x):new MatInterval(0,Math.max(-x.lo,x.hi))},max:function(x,y){var badX=this.isEmpty(x),badY=this.isEmpty(y);return badX&&badY?this.EMPTY.clone():badX?y.clone():badY?x.clone():new MatInterval(Math.max(x.lo,y.lo),Math.max(x.hi,y.hi))},min:function(x,y){var badX=this.isEmpty(x),badY=this.isEmpty(y);return badX&&badY?this.EMPTY.clone():badX?y.clone():badY?x.clone():new MatInterval(Math.min(x.lo,y.lo),Math.min(x.hi,y.hi))},onlyInfinity:function(x){return!isFinite(x.lo)&&x.lo===x.hi},_handleNegative:function(interval){var n;return interval.lo<0&&(interval.lo===-1/0?(interval.lo=0,interval.hi=1/0):(n=Math.ceil(-interval.lo/this.piTwiceLow),interval.lo+=this.piTwiceLow*n,interval.hi+=this.piTwiceLow*n)),interval},cos:function(x){var cache,pi2,t,cosv,lo,hi,rlo,rhi;return this.isEmpty(x)||this.onlyInfinity(x)?this.EMPTY.clone():(cache=(new MatInterval).set(x.lo,x.hi),this._handleNegative(cache),pi2=this.PI_TWICE,t=this.fmod(cache,pi2),this.width(t)>=pi2.lo?new MatInterval(-1,1):t.lo>=this.piHigh?(cosv=this.cos(this.sub(t,this.PI)),this.negative(cosv)):(lo=t.lo,hi=t.hi,rlo=this.cosLo(hi),rhi=this.cosHi(lo),hi<=this.piLow?new MatInterval(rlo,rhi):hi<=pi2.lo?new MatInterval(-1,Math.max(rlo,rhi)):new MatInterval(-1,1)))},sin:function(x){return this.isEmpty(x)||this.onlyInfinity(x)?this.EMPTY.clone():this.cos(this.sub(x,this.PI_HALF))},tan:function(x){var cache,t,pi;return this.isEmpty(x)||this.onlyInfinity(x)?this.EMPTY.clone():(cache=(new MatInterval).set(x.lo,x.hi),this._handleNegative(cache),pi=this.PI,(t=this.fmod(cache,pi)).lo>=this.piHalfLow&&(t=this.sub(t,pi)),t.lo<=-this.piHalfLow||t.hi>=this.piHalfLow?this.WHOLE.clone():new MatInterval(this.tanLo(t.lo),this.tanHi(t.hi)))},asin:function(x){var lo,hi;return this.isEmpty(x)||x.hi<-1||x.lo>1?this.EMPTY.clone():(lo=x.lo<=-1?-this.piHalfHigh:this.asinLo(x.lo),hi=x.hi>=1?this.piHalfHigh:this.asinHi(x.hi),new MatInterval(lo,hi))},acos:function(x){var lo,hi;return this.isEmpty(x)||x.hi<-1||x.lo>1?this.EMPTY.clone():(lo=x.hi>=1?0:this.acosLo(x.hi),hi=x.lo<=-1?this.piHigh:this.acosHi(x.lo),new MatInterval(lo,hi))},atan:function(x){return this.isEmpty(x)?this.EMPTY.clone():new MatInterval(this.atanLo(x.lo),this.atanHi(x.hi))},sinh:function(x){return this.isEmpty(x)?this.EMPTY.clone():new MatInterval(this.sinhLo(x.lo),this.sinhHi(x.hi))},cosh:function(x){return this.isEmpty(x)?this.EMPTY.clone():x.hi<0?new MatInterval(this.coshLo(x.hi),this.coshHi(x.lo)):x.lo>=0?new MatInterval(this.coshLo(x.lo),this.coshHi(x.hi)):new MatInterval(1,this.coshHi(-x.lo>x.hi?x.lo:x.hi))},tanh:function(x){return this.isEmpty(x)?this.EMPTY.clone():new MatInterval(this.tanhLo(x.lo),this.tanhHi(x.hi))},equal:function(x,y){return this.isEmpty(x)?this.isEmpty(y):!this.isEmpty(y)&&x.lo===y.lo&&x.hi===y.hi},notEqual:function(x,y){return this.isEmpty(x)?!this.isEmpty(y):this.isEmpty(y)||x.hi<y.lo||x.lo>y.hi},lt:function(x,y){return Type.isNumber(x)&&(x=this.Interval(x)),Type.isNumber(y)&&(y=this.Interval(y)),!this.isEmpty(x)&&!this.isEmpty(y)&&x.hi<y.lo},gt:function(x,y){return Type.isNumber(x)&&(x=this.Interval(x)),Type.isNumber(y)&&(y=this.Interval(y)),!this.isEmpty(x)&&!this.isEmpty(y)&&x.lo>y.hi},leq:function(x,y){return Type.isNumber(x)&&(x=this.Interval(x)),Type.isNumber(y)&&(y=this.Interval(y)),!this.isEmpty(x)&&!this.isEmpty(y)&&x.hi<=y.lo},geq:function(x,y){return Type.isNumber(x)&&(x=this.Interval(x)),Type.isNumber(y)&&(y=this.Interval(y)),!this.isEmpty(x)&&!this.isEmpty(y)&&x.lo>=y.hi},piLow:3.141592653589793,piHigh:3.1415926535897936,piHalfLow:1.5707963267948966,piHalfHigh:1.5707963267948968,piTwiceLow:6.283185307179586,piTwiceHigh:6.283185307179587,identity:function(v){return v},_prev:function(v){return v===1/0?v:this.nextafter(v,-1/0)},_next:function(v){return v===-1/0?v:this.nextafter(v,1/0)},prev:function(v){return this._prev(v)},next:function(v){return this._next(v)},toInteger:function(x){return x<0?Math.ceil(x):Math.floor(x)},addLo:function(x,y){return this.prev(x+y)},addHi:function(x,y){return this.next(x+y)},subLo:function(x,y){return this.prev(x-y)},subHi:function(x,y){return this.next(x-y)},mulLo:function(x,y){return this.prev(x*y)},mulHi:function(x,y){return this.next(x*y)},divLo:function(x,y){return this.prev(x/y)},divHi:function(x,y){return this.next(x/y)},intLo:function(x){return this.toInteger(this.prev(x))},intHi:function(x){return this.toInteger(this.next(x))},logLo:function(x){return this.prev(Math.log(x))},logHi:function(x){return this.next(Math.log(x))},expLo:function(x){return this.prev(Math.exp(x))},expHi:function(x){return this.next(Math.exp(x))},sinLo:function(x){return this.prev(Math.sin(x))},sinHi:function(x){return this.next(Math.sin(x))},cosLo:function(x){return this.prev(Math.cos(x))},cosHi:function(x){return this.next(Math.cos(x))},tanLo:function(x){return this.prev(Math.tan(x))},tanHi:function(x){return this.next(Math.tan(x))},asinLo:function(x){return this.prev(Math.asin(x))},asinHi:function(x){return this.next(Math.asin(x))},acosLo:function(x){return this.prev(Math.acos(x))},acosHi:function(x){return this.next(Math.acos(x))},atanLo:function(x){return this.prev(Math.atan(x))},atanHi:function(x){return this.next(Math.atan(x))},sinhLo:function(x){return this.prev(Mat.sinh(x))},sinhHi:function(x){return this.next(Mat.sinh(x))},coshLo:function(x){return this.prev(Mat.cosh(x))},coshHi:function(x){return this.next(Mat.cosh(x))},tanhLo:function(x){return this.prev(Mat.tanh(x))},tanhHi:function(x){return this.next(Mat.tanh(x))},sqrtLo:function(x){return this.prev(Math.sqrt(x))},sqrtHi:function(x){return this.next(Math.sqrt(x))},powLo:function(x,power){var y;if(power%1!=0)return this.prev(Math.pow(x,power));for(y=1==(1&power)?x:1,power>>=1;power>0;)x=this.mulLo(x,x),1==(1&power)&&(y=this.mulLo(x,y)),power>>=1;return y},powHi:function(x,power){var y;if(power%1!=0)return this.next(Math.pow(x,power));for(y=1==(1&power)?x:1,power>>=1;power>0;)x=this.mulHi(x,x),1==(1&power)&&(y=this.mulHi(x,y)),power>>=1;return y},disable:function(){this.next=this.prev=this.identity},enable:function(){this.prev=function(v){return this._prev(v)},this.next=function(v){return this._next(v)}},SMALLEST_DENORM:Math.pow(2,-1074),UINT_MAX:-1>>>0,nextafter:function(x,y){var lo,hi;return isNaN(x)||isNaN(y)?NaN:x===y?x:0===x?y<0?-this.SMALLEST_DENORM:this.SMALLEST_DENORM:(hi=doubleBits.hi(x),lo=doubleBits.lo(x),y>x==x>0?lo===this.UINT_MAX?(hi+=1,lo=0):lo+=1:0===lo?(lo=this.UINT_MAX,hi-=1):lo-=1,doubleBits.pack(lo,hi))}},JXG.Math.IntervalArithmetic.PI=new MatInterval(Mat.IntervalArithmetic.piLow,Mat.IntervalArithmetic.piHigh),JXG.Math.IntervalArithmetic.PI_HALF=new MatInterval(Mat.IntervalArithmetic.piHalfLow,Mat.IntervalArithmetic.piHalfHigh),JXG.Math.IntervalArithmetic.PI_TWICE=new MatInterval(Mat.IntervalArithmetic.piTwiceLow,Mat.IntervalArithmetic.piTwiceHigh),JXG.Math.IntervalArithmetic.ZERO=new MatInterval(0),JXG.Math.IntervalArithmetic.ONE=new MatInterval(1),JXG.Math.IntervalArithmetic.WHOLE=(new MatInterval).setWhole(),JXG.Math.IntervalArithmetic.EMPTY=(new MatInterval).setEmpty(),JXG.Math.IntervalArithmetic})),define("math/extrapolate",["math/math"],(function(Mat){return Mat.Extrapolate={upper:15,infty:1e4,wynnEps:function(s_n,n,e){var j,aux1,aux2,diff,estlim;if(e[n]=s_n,0===n)estlim=s_n;else{for(aux2=0,j=n;j>0;j--)aux1=aux2,aux2=e[j-1],diff=e[j]-aux2,Math.abs(diff)<=1e-15?e[j-1]=1e20:(1,e[j-1]=1*aux1+1/diff);estlim=e[n%2]}return estlim},aitken:function(s_n,n,a){var estlim,denom,v,lowmax,j,m;if(a[n]=s_n,n<2)estlim=s_n;else{for(lowmax=n/2,j=1;j<=lowmax;j++)denom=a[(m=n-2*j)+2]-2*a[m+1]+a[m],Math.abs(denom)<1e-15?a[m]=1e20:(v=a[m]-a[m+1],a[m]-=v*v/denom);estlim=a[n%2]}return estlim},brezinski:function(s_n,n,a){var estlim,denom,d0,d1,d2,lowmax,j,m;if(a[n]=s_n,n<3)estlim=s_n;else{for(lowmax=n/3,m=n,j=1;j<=lowmax;j++)d0=a[(m-=3)+1]-a[m],d1=a[m+2]-a[m+1],denom=(d2=a[m+3]-a[m+2])*(d1-d0)-d0*(d2-d1),Math.abs(denom)<1e-15?a[m]=1e20:a[m]=a[m+1]-d0*d1*(d2-d1)/denom;estlim=a[n%3]}return estlim},iteration:function(x0,h0,f,method,step_type){var n,v,w,diff,estlim=NaN,E=[],result="finite",h=h0;for(step_type=step_type||0,n=1;n<=this.upper;n++){if(v=f(x0+(h=0===step_type?h0/(n+1):.5*h),!0),w=this[method](v,n-1,E),isNaN(w)){result="NaN";break}if(0!==v&&w/v>this.infty){estlim=w,result="infinite";break}if(diff=w-estlim,Math.abs(diff)<1e-7)break;estlim=w}return[estlim,result,1-(n-1)/this.upper]},levin:function(s_n,n,omega,beta,numer,denom){var j,fact,ratio,term;if(term=1/(beta+n),numer[n]=s_n/omega,denom[n]=1/omega,n>0&&(numer[n-1]=numer[n]-numer[n-1],denom[n-1]=denom[n]-denom[n-1],n>1))for(ratio=(beta+n-1)*term,j=2;j<=n;j++)fact=(beta+n-j)*Math.pow(ratio,j-2)*term,numer[n-j]=numer[n-j+1]-fact*numer[n-j],denom[n-j]=denom[n-j+1]-fact*denom[n-j],term*=ratio;return Math.abs(denom[0])<1e-15?1e20:numer[0]/denom[0]},iteration_levin:function(x0,h0,f,step_type){var n,v,w,v_prev,delta,diff,omega,estlim=NaN,numer=[],denom=[],result="finite",h=h0;for(step_type=step_type||0,v_prev=f(x0+h0,!0),n=1;n<=this.upper;n++){if(delta=(v=f(x0+(h=0===step_type?h0/(n+1):.5*h),!0))-v_prev,omega="u"===(Math.abs(delta)<1?"u":"t")?(1+n)*delta:delta,v_prev=v,diff=(w=this.levin(v,n-1,omega,1,numer,denom))-estlim,isNaN(w)){result="NaN";break}if(0!==v&&w/v>this.infty){estlim=w,result="infinite";break}if(Math.abs(diff)<1e-7)break;estlim=w}return[estlim,result,1-(n-1)/this.upper]},limit:function(x0,h0,f){return this.iteration_levin(x0,h0,f,0)}},Mat.Extrapolate})),define("math/qdt",["math/math","utils/type"],(function(Mat,Type){return Mat.Quadtree=function(bbox){this.capacity=10,this.points=[],this.xlb=bbox[0],this.xub=bbox[2],this.ylb=bbox[3],this.yub=bbox[1],this.northWest=null,this.northEast=null,this.southEast=null,this.southWest=null},Type.extend(Mat.Quadtree.prototype,{contains:function(x,y){return this.xlb<x&&x<=this.xub&&this.ylb<y&&y<=this.yub},insert:function(p){return!!this.contains(p.usrCoords[1],p.usrCoords[2])&&(this.points.length<this.capacity?(this.points.push(p),!0):(null===this.northWest&&this.subdivide(),!!this.northWest.insert(p)||(!!this.northEast.insert(p)||(!!this.southEast.insert(p)||!!this.southWest.insert(p)))))},subdivide:function(){var i,l=this.points.length,mx=this.xlb+(this.xub-this.xlb)/2,my=this.ylb+(this.yub-this.ylb)/2;for(this.northWest=new Mat.Quadtree([this.xlb,this.yub,mx,my]),this.northEast=new Mat.Quadtree([mx,this.yub,this.xub,my]),this.southEast=new Mat.Quadtree([this.xlb,my,mx,this.ylb]),this.southWest=new Mat.Quadtree([mx,my,this.xub,this.ylb]),i=0;i<l;i+=1)this.northWest.insert(this.points[i]),this.northEast.insert(this.points[i]),this.southEast.insert(this.points[i]),this.southWest.insert(this.points[i])},_query:function(x,y){var r;if(this.contains(x,y)){if(null===this.northWest)return this;if(r=this.northWest._query(x,y))return r;if(r=this.northEast._query(x,y))return r;if(r=this.southEast._query(x,y))return r;if(r=this.southWest._query(x,y))return r}return!1},query:function(xp,y){var _x,_y;return Type.exists(y)?(_x=xp,_y=y):(_x=xp.usrCoords[1],_y=xp.usrCoords[2]),this._query(_x,_y)}}),Mat.Quadtree})),define("math/numerics",["jxg","utils/type","utils/env","math/math"],(function(JXG,Type,Env,Mat){var predefinedButcher={rk4:{s:4,A:[[0,0,0,0],[.5,0,0,0],[0,.5,0,0],[0,0,1,0]],b:[1/6,1/3,1/3,1/6],c:[0,.5,.5,1]},heun:{s:2,A:[[0,0],[1,0]],b:[.5,.5],c:[0,1]},euler:{s:1,A:[[0]],b:[1],c:[0]}};return Mat.Numerics={Gauss:function(A,b){var i,j,k,Acopy,x,eps=Mat.eps,n=A.length>0?A[0].length:0;if(n!==b.length||n!==A.length)throw new Error("JXG.Math.Numerics.Gauss: Dimensions don't match. A must be a square matrix and b must be of the same length as A.");for(Acopy=[],x=b.slice(0,n),i=0;i<n;i++)Acopy[i]=A[i].slice(0,n);for(j=0;j<n;j++){for(i=n-1;i>j;i--)if(Math.abs(Acopy[i][j])>eps)if(Math.abs(Acopy[j][j])<eps)Type.swap(Acopy,i,j),Type.swap(x,i,j);else for(Acopy[i][j]/=Acopy[j][j],x[i]-=Acopy[i][j]*x[j],k=j+1;k<n;k++)Acopy[i][k]-=Acopy[i][j]*Acopy[j][k];if(Math.abs(Acopy[j][j])<eps)throw new Error("JXG.Math.Numerics.Gauss(): The given matrix seems to be singular.")}return this.backwardSolve(Acopy,x,!0),x},backwardSolve:function(R,b,canModify){var x,m,n,i,j;for(x=canModify?b:b.slice(0,b.length),m=R.length,n=R.length>0?R[0].length:0,i=m-1;i>=0;i--){for(j=n-1;j>i;j--)x[i]-=R[i][j]*x[j];x[i]/=R[i][i]}return x},gaussBareiss:function(mat){var k,c,s,i,j,p,n,M,t,eps=Mat.eps;if((n=mat.length)<=0)return 0;for(mat[0].length<n&&(n=mat[0].length),M=[],i=0;i<n;i++)M[i]=mat[i].slice(0,n);for(c=1,s=1,k=0;k<n-1;k++){if(p=M[k][k],Math.abs(p)<eps){for(i=k+1;i<n&&!(Math.abs(M[i][k])>=eps);i++);if(i===n)return 0;for(j=k;j<n;j++)t=M[i][j],M[i][j]=M[k][j],M[k][j]=t;s=-s,p=M[k][k]}for(i=k+1;i<n;i++)for(j=k+1;j<n;j++)t=p*M[i][j]-M[i][k]*M[k][j],M[i][j]=t/c;c=p}return s*M[n-1][n-1]},det:function(mat){return 2===mat.length&&2===mat[0].length?mat[0][0]*mat[1][1]-mat[1][0]*mat[0][1]:this.gaussBareiss(mat)},Jacobi:function(Ain){var i,j,k,aa,si,co,tt,ssum,amax,eps=Mat.eps*Mat.eps,sum=0,n=Ain.length,V=[[0,0,0],[0,0,0],[0,0,0]],A=[[0,0,0],[0,0,0],[0,0,0]],nloops=0;for(i=0;i<n;i++){for(j=0;j<n;j++)V[i][j]=0,A[i][j]=Ain[i][j],sum+=Math.abs(A[i][j]);V[i][i]=1}if(1===n)return[A,V];if(sum<=0)return[A,V];sum/=n*n;do{for(ssum=0,amax=0,j=1;j<n;j++)for(i=0;i<j;i++)if((aa=Math.abs(A[i][j]))>amax&&(amax=aa),ssum+=aa,aa>=eps){for(aa=.5*Math.atan2(2*A[i][j],A[i][i]-A[j][j]),si=Math.sin(aa),co=Math.cos(aa),k=0;k<n;k++)tt=A[k][i],A[k][i]=co*tt+si*A[k][j],A[k][j]=-si*tt+co*A[k][j],tt=V[k][i],V[k][i]=co*tt+si*V[k][j],V[k][j]=-si*tt+co*V[k][j];for(A[i][i]=co*A[i][i]+si*A[j][i],A[j][j]=-si*A[i][j]+co*A[j][j],A[i][j]=0,k=0;k<n;k++)A[i][k]=A[k][i],A[j][k]=A[k][j]}nloops+=1}while(Math.abs(ssum)/sum>eps&&nloops<2e3);return[A,V]},NewtonCotes:function(interval,f,config){var evaluation_point,i,number_of_intervals,integral_value=0,number_of_nodes=config&&Type.isNumber(config.number_of_nodes)?config.number_of_nodes:28,available_types={trapez:!0,simpson:!0,milne:!0},integration_type=config&&config.integration_type&&available_types.hasOwnProperty(config.integration_type)&&available_types[config.integration_type]?config.integration_type:"milne",step_size=(interval[1]-interval[0])/number_of_nodes;switch(integration_type){case"trapez":for(integral_value=.5*(f(interval[0])+f(interval[1])),evaluation_point=interval[0],i=0;i<number_of_nodes-1;i++)integral_value+=f(evaluation_point+=step_size);integral_value*=step_size;break;case"simpson":if(number_of_nodes%2>0)throw new Error("JSXGraph: INT_SIMPSON requires config.number_of_nodes dividable by 2.");for(number_of_intervals=number_of_nodes/2,integral_value=f(interval[0])+f(interval[1]),evaluation_point=interval[0],i=0;i<number_of_intervals-1;i++)integral_value+=2*f(evaluation_point+=2*step_size);for(evaluation_point=interval[0]-step_size,i=0;i<number_of_intervals;i++)integral_value+=4*f(evaluation_point+=2*step_size);integral_value*=step_size/3;break;default:if(number_of_nodes%4>0)throw new Error("JSXGraph: Error in INT_MILNE: config.number_of_nodes must be a multiple of 4");for(number_of_intervals=.25*number_of_nodes,integral_value=7*(f(interval[0])+f(interval[1])),evaluation_point=interval[0],i=0;i<number_of_intervals-1;i++)integral_value+=14*f(evaluation_point+=4*step_size);for(evaluation_point=interval[0]-3*step_size,i=0;i<number_of_intervals;i++)integral_value+=32*(f(evaluation_point+=4*step_size)+f(evaluation_point+2*step_size));for(evaluation_point=interval[0]-2*step_size,i=0;i<number_of_intervals;i++)integral_value+=12*f(evaluation_point+=4*step_size);integral_value*=2*step_size/45}return integral_value},Romberg:function(interval,f,config){var a,b,h,s,n,k,i,q,p=[],integral=0,last=1/0,m=config&&Type.isNumber(config.max_iterations)?config.max_iterations:20,eps=config&&Type.isNumber(config.eps)?config.eps:config.eps||1e-7;for(a=interval[0],h=(b=interval[1])-a,n=1,p[0]=.5*h*(f(a)+f(b)),k=0;k<m;++k){for(s=0,h*=.5,n*=2,q=1,i=1;i<n;i+=2)s+=f(a+i*h);for(p[k+1]=.5*p[k]+s*h,integral=p[k+1],i=k-1;i>=0;--i)q*=4,p[i]=p[i+1]+(p[i+1]-p[i])/(q-1),integral=p[i];if(Math.abs(integral-last)<eps*Math.abs(integral))break;last=integral}return integral},GaussLegendre:function(interval,f,config){var a,b,i,m,xp,xm,xi,w,result=0,table_xi=[],table_w=[],n=config&&Type.isNumber(config.n)?config.n:12;if(n>18&&(n=18),table_xi[2]=[.5773502691896257],table_w[2]=[1],table_xi[4]=[.33998104358485626,.8611363115940526],table_w[4]=[.6521451548625461,.34785484513745385],table_xi[6]=[.2386191860831969,.6612093864662645,.932469514203152],table_w[6]=[.46791393457269104,.3607615730481386,.17132449237917036],table_xi[8]=[.1834346424956498,.525532409916329,.7966664774136267,.9602898564975363],table_w[8]=[.362683783378362,.31370664587788727,.22238103445337448,.10122853629037626],table_xi[10]=[.14887433898163122,.4333953941292472,.6794095682990244,.8650633666889845,.9739065285171717],table_w[10]=[.29552422471475287,.26926671930999635,.21908636251598204,.1494513491505806,.06667134430868814],table_xi[12]=[.1252334085114689,.3678314989981802,.5873179542866175,.7699026741943047,.9041172563704749,.9815606342467192],table_w[12]=[.24914704581340277,.2334925365383548,.20316742672306592,.16007832854334622,.10693932599531843,.04717533638651183],table_xi[14]=[.10805494870734367,.31911236892788974,.5152486363581541,.6872929048116855,.827201315069765,.9284348836635735,.9862838086968123],table_w[14]=[.2152638534631578,.2051984637212956,.18553839747793782,.15720316715819355,.12151857068790319,.08015808715976021,.03511946033175186],table_xi[16]=[.09501250983763744,.2816035507792589,.45801677765722737,.6178762444026438,.755404408355003,.8656312023878318,.9445750230732326,.9894009349916499],table_w[16]=[.1894506104550685,.18260341504492358,.16915651939500254,.14959598881657674,.12462897125553388,.09515851168249279,.062253523938647894,.027152459411754096],table_xi[18]=[.0847750130417353,.2518862256915055,.41175116146284263,.5597708310739475,.6916870430603532,.8037049589725231,.8926024664975557,.9558239495713977,.9915651684209309],table_w[18]=[.1691423829631436,.16427648374583273,.15468467512626524,.14064291467065065,.12255520671147846,.10094204410628717,.07642573025488905,.0497145488949698,.02161601352648331],table_xi[3]=[0,.7745966692414834],table_w[3]=[.8888888888888888,.5555555555555556],table_xi[5]=[0,.5384693101056831,.906179845938664],table_w[5]=[.5688888888888889,.47862867049936647,.23692688505618908],table_xi[7]=[0,.4058451513773972,.7415311855993945,.9491079123427585],table_w[7]=[.4179591836734694,.3818300505051189,.27970539148927664,.1294849661688697],table_xi[9]=[0,.3242534234038089,.6133714327005904,.8360311073266358,.9681602395076261],table_w[9]=[.3302393550012598,.31234707704000286,.26061069640293544,.1806481606948574,.08127438836157441],table_xi[11]=[0,.26954315595234496,.5190961292068118,.7301520055740494,.8870625997680953,.978228658146057],table_w[11]=[.2729250867779006,.26280454451024665,.23319376459199048,.18629021092773426,.1255803694649046,.05566856711617366],table_xi[13]=[0,.2304583159551348,.44849275103644687,.6423493394403402,.8015780907333099,.9175983992229779,.9841830547185881],table_w[13]=[.2325515532308739,.22628318026289723,.2078160475368885,.17814598076194574,.13887351021978725,.09212149983772845,.04048400476531588],table_xi[15]=[0,.20119409399743451,.3941513470775634,.5709721726085388,.7244177313601701,.8482065834104272,.937273392400706,.9879925180204854],table_w[15]=[.2025782419255613,.19843148532711158,.1861610000155622,.16626920581699392,.13957067792615432,.10715922046717194,.07036604748810812,.03075324199611727],table_xi[17]=[0,.17848418149584785,.3512317634538763,.5126905370864769,.6576711592166907,.7815140038968014,.8802391537269859,.9506755217687678,.9905754753144174],table_w[17]=[.17944647035620653,.17656270536699264,.16800410215645004,.15404576107681028,.13513636846852548,.11188384719340397,.08503614831717918,.0554595293739872,.02414830286854793],a=interval[0],b=interval[1],m=n+1>>1,xi=table_xi[n],w=table_w[n],xm=.5*(b-a),xp=.5*(b+a),!0&n)for(result=w[0]*f(xp),i=1;i<m;++i)result+=w[i]*(f(xp+xm*xi[i])+f(xp-xm*xi[i]));else for(result=0,i=0;i<m;++i)result+=w[i]*(f(xp+xm*xi[i])+f(xp-xm*xi[i]));return xm*result},_rescale_error:function(err,result_abs,result_asc){var scale,min_err;return err=Math.abs(err),0!==result_asc&&0!==err&&(err=(scale=Math.pow(200*err/result_asc,1.5))<1?result_asc*scale:result_asc),result_abs>20041683600089728e-310&&(min_err=11102230246251565e-30*result_abs)>err&&(err=min_err),err},_gaussKronrod:function(interval,f,n,xgk,wg,wgk,resultObj){var up,result,mean,err,j,jtw,abscissa,fval1,fval2,fsum,jtwm1,a=interval[0],b=interval[1],center=.5*(a+b),half_length=.5*(b-a),abs_half_length=Math.abs(half_length),f_center=f(center),result_gauss=0,result_kronrod=f_center*wgk[n-1],result_abs=Math.abs(result_kronrod),result_asc=0,fv1=[],fv2=[];for(n%2==0&&(result_gauss=f_center*wg[n/2-1]),up=Math.floor((n-1)/2),j=0;j<up;j++)fsum=(fval1=f(center-(abscissa=half_length*xgk[jtw=2*j+1])))+(fval2=f(center+abscissa)),fv1[jtw]=fval1,fv2[jtw]=fval2,result_gauss+=wg[j]*fsum,result_kronrod+=wgk[jtw]*fsum,result_abs+=wgk[jtw]*(Math.abs(fval1)+Math.abs(fval2));for(up=Math.floor(n/2),j=0;j<up;j++)fval1=f(center-(abscissa=half_length*xgk[jtwm1=2*j])),fval2=f(center+abscissa),fv1[jtwm1]=fval1,fv2[jtwm1]=fval2,result_kronrod+=wgk[jtwm1]*(fval1+fval2),result_abs+=wgk[jtwm1]*(Math.abs(fval1)+Math.abs(fval2));for(mean=.5*result_kronrod,result_asc=wgk[n-1]*Math.abs(f_center-mean),j=0;j<n-1;j++)result_asc+=wgk[j]*(Math.abs(fv1[j]-mean)+Math.abs(fv2[j]-mean));return err=(result_kronrod-result_gauss)*half_length,result_abs*=abs_half_length,result_asc*=abs_half_length,result=result_kronrod*=half_length,resultObj.abserr=this._rescale_error(err,result_abs,result_asc),resultObj.resabs=result_abs,resultObj.resasc=result_asc,result},GaussKronrod15:function(interval,f,resultObj){return this._gaussKronrod(interval,f,8,[.9914553711208126,.9491079123427585,.8648644233597691,.7415311855993945,.5860872354676911,.4058451513773972,.20778495500789848,0],[.1294849661688697,.27970539148927664,.3818300505051189,.4179591836734694],[.022935322010529224,.06309209262997856,.10479001032225019,.14065325971552592,.1690047266392679,.19035057806478542,.20443294007529889,.20948214108472782],resultObj)},GaussKronrod21:function(interval,f,resultObj){return this._gaussKronrod(interval,f,11,[.9956571630258081,.9739065285171717,.9301574913557082,.8650633666889845,.7808177265864169,.6794095682990244,.5627571346686047,.4333953941292472,.2943928627014602,.14887433898163122,0],[.06667134430868814,.1494513491505806,.21908636251598204,.26926671930999635,.29552422471475287],[.011694638867371874,.032558162307964725,.054755896574351995,.07503967481091996,.0931254545836976,.10938715880229764,.12349197626206584,.13470921731147334,.14277593857706009,.14773910490133849,.1494455540029169],resultObj)},GaussKronrod31:function(interval,f,resultObj){return this._gaussKronrod(interval,f,16,[.9980022986933971,.9879925180204854,.9677390756791391,.937273392400706,.8972645323440819,.8482065834104272,.790418501442466,.7244177313601701,.650996741297417,.5709721726085388,.4850818636402397,.3941513470775634,.29918000715316884,.20119409399743451,.1011420669187175,0],[.03075324199611727,.07036604748810812,.10715922046717194,.13957067792615432,.16626920581699392,.1861610000155622,.19843148532711158,.2025782419255613],[.005377479872923349,.015007947329316122,.02546084732671532,.03534636079137585,.04458975132476488,.05348152469092809,.06200956780067064,.06985412131872826,.07684968075772038,.08308050282313302,.08856444305621176,.09312659817082532,.09664272698362368,.09917359872179196,.10076984552387559,.10133000701479154],resultObj)},_workspace:function(interval,n){return{limit:n,size:0,nrmax:0,i:0,alist:[interval[0]],blist:[interval[1]],rlist:[0],elist:[0],order:[0],level:[0],qpsrt:function(){var errmax,errmin,i,k,top,last=this.size-1,limit=this.limit,i_nrmax=this.nrmax,i_maxerr=this.order[i_nrmax];if(last<2)return this.order[0]=0,this.order[1]=1,void(this.i=i_maxerr);for(errmax=this.elist[i_maxerr];i_nrmax>0&&errmax>this.elist[this.order[i_nrmax-1]];)this.order[i_nrmax]=this.order[i_nrmax-1],i_nrmax--;for(top=last<limit/2+2?last:limit-last+1,i=i_nrmax+1;i<top&&errmax<this.elist[this.order[i]];)this.order[i-1]=this.order[i],i++;for(this.order[i-1]=i_maxerr,errmin=this.elist[last],k=top-1;k>i-2&&errmin>=this.elist[this.order[k]];)this.order[k+1]=this.order[k],k--;this.order[k+1]=last,i_maxerr=this.order[i_nrmax],this.i=i_maxerr,this.nrmax=i_nrmax},set_initial_result:function(result,error){this.size=1,this.rlist[0]=result,this.elist[0]=error},update:function(a1,b1,area1,error1,a2,b2,area2,error2){var i_max=this.i,i_new=this.size,new_level=this.level[this.i]+1;error2>error1?(this.alist[i_max]=a2,this.rlist[i_max]=area2,this.elist[i_max]=error2,this.level[i_max]=new_level,this.alist[i_new]=a1,this.blist[i_new]=b1,this.rlist[i_new]=area1,this.elist[i_new]=error1,this.level[i_new]=new_level):(this.blist[i_max]=b1,this.rlist[i_max]=area1,this.elist[i_max]=error1,this.level[i_max]=new_level,this.alist[i_new]=a2,this.blist[i_new]=b2,this.rlist[i_new]=area2,this.elist[i_new]=error2,this.level[i_new]=new_level),this.size++,new_level>this.maximum_level&&(this.maximum_level=new_level),this.qpsrt()},retrieve:function(){var i=this.i;return{a:this.alist[i],b:this.blist[i],r:this.rlist[i],e:this.elist[i]}},sum_results:function(){var k,nn=this.size,result_sum=0;for(k=0;k<nn;k++)result_sum+=this.rlist[k];return result_sum},subinterval_too_small:function(a1,a2,b2){var tmp=1.0000000000000222*(Math.abs(a2)+22250738585072014e-321);return Math.abs(a1)<=tmp&&Math.abs(b2)<=tmp}}},Qag:function(interval,f,config){var area,errsum,result0,abserr0,resabs0,resasc0,tolerance,a1,b1,a2,b2,a_i,b_i,r_i,e_i,resasc1,wsObj,delta,ws=this._workspace(interval,1e3),limit=config&&Type.isNumber(config.limit)?config.limit:15,epsrel=config&&Type.isNumber(config.epsrel)?config.epsrel:1e-7,epsabs=config&&Type.isNumber(config.epsabs)?config.epsabs:1e-7,q=config&&Type.isFunction(config.q)?config.q:this.GaussKronrod15,resultObj={},iteration=0,roundoff_type1=0,roundoff_type2=0,error_type=0,area1=0,area2=0,area12=0,error1=0,error2=0,error12=0;if(limit>ws.limit&&JXG.warn("iteration limit exceeds available workspace"),epsabs<=0&&(epsrel<50*Mat.eps||epsrel<5e-29)&&JXG.warn("tolerance cannot be acheived with given epsabs and epsrel"),result0=q.apply(this,[interval,f,resultObj]),abserr0=resultObj.abserr,resabs0=resultObj.resabs,resasc0=resultObj.resasc,ws.set_initial_result(result0,abserr0),tolerance=Math.max(epsabs,epsrel*Math.abs(result0)),abserr0<=11102230246251565e-30*resabs0&&abserr0>tolerance)return result0,JXG.warn("cannot reach tolerance because of roundoff error on first attempt"),-1/0;if(abserr0<=tolerance&&abserr0!==resasc0||0===abserr0)return result0;if(1===limit)return result0,JXG.warn("a maximum of one iteration was insufficient"),-1/0;area=result0,errsum=abserr0,iteration=1;do{area1=0,area2=0,area12=0,error1=0,error2=0,error12=0,a_i=(wsObj=ws.retrieve()).a,b_i=wsObj.b,r_i=wsObj.r,e_i=wsObj.e,a1=a_i,a2=b1=.5*(a_i+b_i),b2=b_i,area1=q.apply(this,[[a1,b1],f,resultObj]),error1=resultObj.abserr,resasc1=resultObj.resasc,area2=q.apply(this,[[a2,b2],f,resultObj]),errsum+=(error12=error1+(error2=resultObj.abserr))-e_i,area+=(area12=area1+area2)-r_i,resasc1!==error1&&resultObj.resasc!==error2&&(delta=r_i-area12,Math.abs(delta)<=1e-5*Math.abs(area12)&&error12>=.99*e_i&&roundoff_type1++,iteration>=10&&error12>e_i&&roundoff_type2++),errsum>(tolerance=Math.max(epsabs,epsrel*Math.abs(area)))&&((roundoff_type1>=6||roundoff_type2>=20)&&(error_type=2),ws.subinterval_too_small(a1,a2,b2)&&(error_type=3)),ws.update(a1,b1,area1,error1,a2,b2,area2,error2),a_i=(wsObj=ws.retrieve()).a_i,b_i=wsObj.b_i,r_i=wsObj.r_i,e_i=wsObj.e_i,iteration++}while(iteration<limit&&!error_type&&errsum>tolerance);return ws.sum_results()},I:function(interval,f){return this.Qag(interval,f,{q:this.GaussKronrod15,limit:15,epsrel:1e-7,epsabs:1e-7})},Newton:function(f,x,context){var df,i=0,h=Mat.eps,newf=f.apply(context,[x]);for(Type.isArray(x)&&(x=x[0]);i<50&&Math.abs(newf)>h;)df=this.D(f,context)(x),Math.abs(df)>h?x-=newf/df:x+=.2*Math.random()-1,newf=f.apply(context,[x]),i+=1;return x},root:function(f,x,context){return this.chandrupatla(f,x,context)},generalizedNewton:function(c1,c2,t1ini,t2ini){var t1,t2,a,b,c,d,disc,e,f,F,D00,D01,D10,D11,count=0;for(this.generalizedNewton.t1memo?(t1=this.generalizedNewton.t1memo,t2=this.generalizedNewton.t2memo):(t1=t1ini,t2=t2ini),F=(e=c1.X(t1)-c2.X(t2))*e+(f=c1.Y(t1)-c2.Y(t2))*f,D00=this.D(c1.X,c1),D01=this.D(c2.X,c2),D10=this.D(c1.Y,c1),D11=this.D(c2.Y,c2);F>Mat.eps&&count<10;)a=D00(t1),b=-D01(t2),c=D10(t1),t1-=((d=-D11(t2))*e-b*f)/(disc=a*d-b*c),t2-=(a*f-c*e)/disc,F=(e=c1.X(t1)-c2.X(t2))*e+(f=c1.Y(t1)-c2.Y(t2))*f,count+=1;return this.generalizedNewton.t1memo=t1,this.generalizedNewton.t2memo=t2,Math.abs(t1)<Math.abs(t2)?[c1.X(t1),c1.Y(t1)]:[c2.X(t2),c2.Y(t2)]},Neville:function(p){var w=[],makeFct=function(fun){return function(t,suspendedUpdate){var i,d,s,bin=Mat.binomial,len=p.length,len1=len-1,num=0,denom=0;if(!suspendedUpdate)for(s=1,i=0;i<len;i++)w[i]=bin(len1,i)*s,s*=-1;for(d=t,i=0;i<len;i++){if(0===d)return p[i][fun]();s=w[i]/d,d-=1,num+=p[i][fun]()*s,denom+=s}return num/denom}};return[makeFct("X"),makeFct("Y"),0,function(){return p.length-1}]},splineDef:function(x,y){var pair,i,l,n=Math.min(x.length,y.length),diag=[],z=[],data=[],dx=[],delta=[],F=[];if(2===n)return[0,0];for(i=0;i<n;i++)pair={X:x[i],Y:y[i]},data.push(pair);for(data.sort((function(a,b){return a.X-b.X})),i=0;i<n;i++)x[i]=data[i].X,y[i]=data[i].Y;for(i=0;i<n-1;i++)dx.push(x[i+1]-x[i]);for(i=0;i<n-2;i++)delta.push(6*(y[i+2]-y[i+1])/dx[i+1]-6*(y[i+1]-y[i])/dx[i]);for(diag.push(2*(dx[0]+dx[1])),z.push(delta[0]),i=0;i<n-3;i++)l=dx[i+1]/diag[i],diag.push(2*(dx[i+1]+dx[i+2])-l*dx[i+1]),z.push(delta[i+1]-l*z[i]);for(F[n-3]=z[n-3]/diag[n-3],i=n-4;i>=0;i--)F[i]=(z[i]-dx[i+1]*F[i+1])/diag[i];for(i=n-3;i>=0;i--)F[i+1]=F[i];return F[0]=0,F[n-1]=0,F},splineEval:function(x0,x,y,F){var i,j,a,b,c,d,x_,n=Math.min(x.length,y.length),l=1,asArray=!1,y0=[];for(Type.isArray(x0)?(l=x0.length,asArray=!0):x0=[x0],i=0;i<l;i++){if(x0[i]<x[0]||x[i]>x[n-1])return NaN;for(j=1;j<n&&!(x0[i]<=x[j]);j++);a=y[j-=1],b=(y[j+1]-y[j])/(x[j+1]-x[j])-(x[j+1]-x[j])/6*(F[j+1]+2*F[j]),c=F[j]/2,d=(F[j+1]-F[j])/(6*(x[j+1]-x[j])),x_=x0[i]-x[j],y0.push(a+(b+(c+d*x_)*x_)*x_)}return asArray?y0:y0[0]},generatePolynomialTerm:function(coeffs,deg,varname,prec){var i,t=[];for(i=deg;i>=0;i--)t=t.concat(["(",coeffs[i].toPrecision(prec),")"]),i>1?t=t.concat(["*",varname,"<sup>",i,"<","/sup> + "]):1===i&&(t=t.concat(["*",varname," + "]));return t.join("")},lagrangePolynomial:function(p){var w=[],that=this,fct=function(x,suspendedUpdate){var i,k,xi,s,len=p.length,num=0,denom=0;if(!suspendedUpdate)for(i=0;i<len;i++){for(w[i]=1,xi=p[i].X(),k=0;k<len;k++)k!==i&&(w[i]*=xi-p[k].X());w[i]=1/w[i]}for(i=0;i<len;i++){if(x===(xi=p[i].X()))return p[i].Y();denom+=s=w[i]/(x-xi),num+=s*p[i].Y()}return num/denom};return fct.getTerm=function(digits,param,dot){return that.lagrangePolynomialTerm(p,digits,param,dot)()},fct},lagrangePolynomialTerm:function(points,digits,param,dot){return function(){var n,t,i,j,c,p,len=points.length,zeroes=[],coeffs=[],coeffs_sum=[],isLeading=!0;for(param=param||"x",void 0===dot&&(dot=" * "),n=len-1,j=0;j<len;j++)coeffs_sum[j]=0;for(i=0;i<len;i++){for(c=points[i].Y(),p=points[i].X(),zeroes=[],j=0;j<len;j++)j!==i&&(c/=p-points[j].X(),zeroes.push(points[j].X()));for(coeffs=[1].concat(Mat.Vieta(zeroes)),j=0;j<coeffs.length;j++)coeffs_sum[j]+=(j%2==1?-1:1)*coeffs[j]*c}for(t="",j=0;j<coeffs_sum.length;j++)c=coeffs_sum[j],Math.abs(c)<Mat.eps||(JXG.exists(digits)&&(c=Env._round10(c,-digits)),isLeading?(t+=c>0?c:"-"+-c,isLeading=!1):t+=c>0?" + "+c:" - "+-c,n-j>1?t+=dot+param+"^"+(n-j):n-j==1&&(t+=dot+param));return t}},_initCubicPoly:function(x1,x2,t1,t2){return[x1,t1,-3*x1+3*x2-2*t1-t2,2*x1-2*x2+t1+t2]},CardinalSpline:function(points,tau_param,type){var p,makeFct,tau,_tau,coeffs=[],that=this;return _tau=Type.isFunction(tau_param)?tau_param:function(){return tau_param},void 0===type&&(type="uniform"),makeFct=function(which){return function(t,suspendedUpdate){var s,c,first,last,t1,t2,dt0,dt1,dt2,len;if(points.length<2)return NaN;if(!suspendedUpdate)for(tau=_tau(),first={X:function(){return 2*points[0].X()-points[1].X()},Y:function(){return 2*points[0].Y()-points[1].Y()},Dist:function(p){var dx=this.X()-p.X(),dy=this.Y()-p.Y();return Math.sqrt(dx*dx+dy*dy)}},last={X:function(){return 2*points[points.length-1].X()-points[points.length-2].X()},Y:function(){return 2*points[points.length-1].Y()-points[points.length-2].Y()},Dist:function(p){var dx=this.X()-p.X(),dy=this.Y()-p.Y();return Math.sqrt(dx*dx+dy*dy)}},len=(p=[first].concat(points,[last])).length,coeffs[which]=[],s=0;s<len-3;s++)"centripetal"===type?(dt0=p[s].Dist(p[s+1]),dt1=p[s+2].Dist(p[s+1]),dt2=p[s+3].Dist(p[s+2]),dt0=Math.sqrt(dt0),dt1=Math.sqrt(dt1),dt2=Math.sqrt(dt2),dt1<Mat.eps&&(dt1=1),dt0<Mat.eps&&(dt0=dt1),dt2<Mat.eps&&(dt2=dt1),t1=(p[s+1][which]()-p[s][which]())/dt0-(p[s+2][which]()-p[s][which]())/(dt1+dt0)+(p[s+2][which]()-p[s+1][which]())/dt1,t2=(p[s+2][which]()-p[s+1][which]())/dt1-(p[s+3][which]()-p[s+1][which]())/(dt2+dt1)+(p[s+3][which]()-p[s+2][which]())/dt2,t1*=dt1,t2*=dt1,coeffs[which][s]=that._initCubicPoly(p[s+1][which](),p[s+2][which](),tau*t1,tau*t2)):coeffs[which][s]=that._initCubicPoly(p[s+1][which](),p[s+2][which](),tau*(p[s+2][which]()-p[s][which]()),tau*(p[s+3][which]()-p[s+1][which]()));return isNaN(t)?NaN:(len=points.length,t<=0?points[0][which]():t>=len?points[len-1][which]():(s=Math.floor(t))===t?points[s][which]():(t-=s,void 0===(c=coeffs[which][s])?NaN:((c[3]*t+c[2])*t+c[1])*t+c[0]))}},[makeFct("X"),makeFct("Y"),0,function(){return points.length-1}]},CatmullRomSpline:function(points,type){return this.CardinalSpline(points,.5,type)},regressionPolynomial:function(degree,dataX,dataY){var coeffs,deg,dX,dY,inputType,fct,term="";if(Type.isPoint(degree)&&Type.isFunction(degree.Value))deg=function(){return degree.Value()};else if(Type.isFunction(degree))deg=degree;else{if(!Type.isNumber(degree))throw new Error("JSXGraph: Can't create regressionPolynomial from degree of type'"+_typeof(degree)+"'.");deg=function(){return degree}}if(3===arguments.length&&Type.isArray(dataX)&&Type.isArray(dataY))inputType=0;else if(2===arguments.length&&Type.isArray(dataX)&&dataX.length>0&&Type.isPoint(dataX[0]))inputType=1;else{if(!(2===arguments.length&&Type.isArray(dataX)&&dataX.length>0&&dataX[0].usrCoords&&dataX[0].scrCoords))throw new Error("JSXGraph: Can't create regressionPolynomial. Wrong parameters.");inputType=2}return(fct=function(x,suspendedUpdate){var i,j,M,MT,y,B,c,s,d,len=dataX.length;if(d=Math.floor(deg()),!suspendedUpdate){if(1===inputType)for(dX=[],dY=[],i=0;i<len;i++)dX[i]=dataX[i].X(),dY[i]=dataX[i].Y();if(2===inputType)for(dX=[],dY=[],i=0;i<len;i++)dX[i]=dataX[i].usrCoords[1],dY[i]=dataX[i].usrCoords[2];if(0===inputType)for(dX=[],dY=[],i=0;i<len;i++)Type.isFunction(dataX[i])?dX.push(dataX[i]()):dX.push(dataX[i]),Type.isFunction(dataY[i])?dY.push(dataY[i]()):dY.push(dataY[i]);for(M=[],j=0;j<len;j++)M.push([1]);for(i=1;i<=d;i++)for(j=0;j<len;j++)M[j][i]=M[j][i-1]*dX[j];y=dY,MT=Mat.transpose(M),B=Mat.matMatMult(MT,M),c=Mat.matVecMult(MT,y),coeffs=Mat.Numerics.Gauss(B,c),term=Mat.Numerics.generatePolynomialTerm(coeffs,d,"x",3)}for(s=coeffs[d],i=d-1;i>=0;i--)s=s*x+coeffs[i];return s}).getTerm=function(){return term},fct},bezier:function(points){var len,flen,makeFct=function(which){return function(t,suspendedUpdate){var z=3*Math.floor(t),t0=t%1,t1=1-t0;return suspendedUpdate||(flen=3*Math.floor((points.length-1)/3),len=Math.floor(flen/3)),t<0?points[0][which]():t>=len?points[flen][which]():isNaN(t)?NaN:t1*t1*(t1*points[z][which]()+3*t0*points[z+1][which]())+(3*t1*points[z+2][which]()+t0*points[z+3][which]())*t0*t0}};return[makeFct("X"),makeFct("Y"),0,function(){return Math.floor(points.length/3)}]},bspline:function(points,order){var knots,makeFct=function(which){return function(t,suspendedUpdate){var y,j,s,N,len=points.length,n=len-1,k=order;if(n<=0)return NaN;if(n+2<=k&&(k=n+1),t<=0)return points[0][which]();if(t>=n-k+2)return points[n][which]();for(s=Math.floor(t)+k-1,knots=function(n,k){var j,kn=[];for(j=0;j<n+k+1;j++)kn[j]=j<k?0:j<=n?j-k+1:n-k+2;return kn}(n,k),N=function(t,kn,k,s){var i,j,a,b,den,N=[];for(kn[s]<=t&&t<kn[s+1]?N[s]=1:N[s]=0,i=2;i<=k;i++)for(j=s-i+1;j<=s;j++)a=j<=s-i+1||j<0?0:N[j],b=j>=s?0:N[j+1],den=kn[j+i-1]-kn[j],N[j]=0===den?0:(t-kn[j])/den*a,0!=(den=kn[j+i]-kn[j+1])&&(N[j]+=(kn[j+i]-t)/den*b);return N}(t,knots,k,s),y=0,j=s-k+1;j<=s;j++)j<len&&j>=0&&(y+=points[j][which]()*N[j]);return y}};return[makeFct("X"),makeFct("Y"),0,function(){return points.length-1}]},D:function(f,obj){return Type.exists(obj)?function(x,suspendedUpdate){var h=1e-5;return(f.apply(obj,[x+h,suspendedUpdate])-f.apply(obj,[x-h,suspendedUpdate]))/2e-5}:function(x,suspendedUpdate){var h=1e-5;return(f(x+h,suspendedUpdate)-f(x-h,suspendedUpdate))/2e-5}},_riemannValue:function(x,f,type,delta){var y,y1,x1,delta1;if(delta<0&&("trapezoidal"!==type&&(x+=delta),delta*=-1,"lower"===type?type="upper":"upper"===type&&(type="lower")),delta1=.01*delta,"right"===type)y=f(x+delta);else if("middle"===type)y=f(x+.5*delta);else if("left"===type||"trapezoidal"===type)y=f(x);else if("lower"===type){for(y=f(x),x1=x+delta1;x1<=x+delta;x1+=delta1)(y1=f(x1))<y&&(y=y1);(y1=f(x+delta))<y&&(y=y1)}else if("upper"===type){for(y=f(x),x1=x+delta1;x1<=x+delta;x1+=delta1)(y1=f(x1))>y&&(y=y1);(y1=f(x+delta))>y&&(y=y1)}else y="random"===type?f(x+delta*Math.random()):"simpson"===type?(f(x)+4*f(x+.5*delta)+f(x+delta))/6:f(x);return y},riemann:function(gf,n,type,start,end){var i,delta,y,f,g,ylow,yup,xarr=[],yarr=[],j=0,x=start,sum=0;if(Type.isArray(gf)?(g=gf[0],f=gf[1]):f=gf,(n=Math.floor(n))<=0)return[xarr,yarr,sum];for(delta=(end-start)/n,i=0;i<n;i++)y=this._riemannValue(x,f,type,delta),xarr[j]=x,yarr[j]=y,j+=1,x+=delta,"trapezoidal"===type&&(y=f(x)),xarr[j]=x,yarr[j]=y,j+=1;for(i=0;i<n;i++)y=g?this._riemannValue(x,g,type,-delta):0,xarr[j]=x,yarr[j]=y,j+=1,x-=delta,"trapezoidal"===type&&g&&(y=g(x)),xarr[j]=x,yarr[j]=y,"trapezoidal"!==type?(ylow=y,yup=yarr[2*(n-1)-2*i]):(yup=.5*(f(x+delta)+f(x)),ylow=g?.5*(g(x+delta)+g(x)):0),sum+=(yup-ylow)*delta,xarr[j+=1]=x,yarr[j]=yarr[2*(n-1)-2*i],j+=1;return[xarr,yarr,sum]},riemannsum:function(f,n,type,start,end){return JXG.deprecated("Numerics.riemannsum()","Numerics.riemann()"),this.riemann(f,n,type,start,end)[2]},rungeKutta:function(butcher,x0,I,N,f){var e,i,j,k,l,s,x=[],y=[],h=(I[1]-I[0])/N,t=I[0],dim=x0.length,result=[],r=0;for(Type.isString(butcher)&&(butcher=predefinedButcher[butcher]||predefinedButcher.euler),s=butcher.s,e=0;e<dim;e++)x[e]=x0[e];for(i=0;i<N;i++){for(result[r]=[],e=0;e<dim;e++)result[r][e]=x[e];for(r+=1,k=[],j=0;j<s;j++){for(e=0;e<dim;e++)y[e]=0;for(l=0;l<j;l++)for(e=0;e<dim;e++)y[e]+=butcher.A[j][l]*h*k[l][e];for(e=0;e<dim;e++)y[e]+=x[e];k.push(f(t+butcher.c[j]*h,y))}for(e=0;e<dim;e++)y[e]=0;for(l=0;l<s;l++)for(e=0;e<dim;e++)y[e]+=butcher.b[l]*k[l][e];for(e=0;e<dim;e++)x[e]=x[e]+h*y[e];t+=h}return result},maxIterationsRoot:80,maxIterationsMinimize:500,findBracket:function(f,x0,object){var a,aa,fa,blist,b,fb,u,fu,i,len;if(Type.isArray(x0))return x0;for(a=x0,fa=f.call(object,a),len=(blist=[a-.1*(aa=0===a?1:a),a+.1*aa,a-1,a+1,a-.5*aa,a+.5*aa,a-.6*aa,a+.6*aa,a-1*aa,a+1*aa,a-2*aa,a+2*aa,a-5*aa,a+5*aa,a-10*aa,a+10*aa,a-50*aa,a+50*aa,a-100*aa,a+100*aa]).length,i=0;i<len&&(b=blist[i],!(fa*(fb=f.call(object,b))<=0));i++);return b<a&&(u=a,a=b,b=u,fu=fa,fa=fb,fb=fu),[a,fa,b,fb]},fzero:function(f,x0,object){var a,b,c,fa,fb,fc,res,prev_step,t1,cb,t2,tol_act,p,q,new_step,eps=Mat.eps,maxiter=this.maxIterationsRoot,niter=0;if(Type.isArray(x0)){if(x0.length<2)throw new Error("JXG.Math.Numerics.fzero: length of array x0 has to be at least two.");a=x0[0],fa=f.call(object,a),b=x0[1],fb=f.call(object,b)}else a=(res=this.findBracket(f,x0,object))[0],fa=res[1],b=res[2],fb=res[3];if(Math.abs(fa)<=eps)return a;if(Math.abs(fb)<=eps)return b;if(fa*fb>0)return Type.isArray(x0)?this.fminbr(f,[a,b],object):this.Newton(f,a,object);for(c=a,fc=fa;niter<maxiter;){if(prev_step=b-a,Math.abs(fc)<Math.abs(fb)&&(a=b,b=c,c=a,fa=fb,fb=fc,fc=fa),tol_act=2*eps*Math.abs(b)+.5*eps,new_step=.5*(c-b),Math.abs(new_step)<=tol_act||Math.abs(fb)<=eps)return b;Math.abs(prev_step)>=tol_act&&Math.abs(fa)>Math.abs(fb)&&(cb=c-b,a===c?(p=cb*(t1=fb/fa),q=1-t1):(p=(t2=fb/fa)*(cb*(q=fa/fc)*(q-(t1=fb/fc))-(b-a)*(t1-1)),q=(q-1)*(t1-1)*(t2-1)),p>0?q=-q:p=-p,p<.75*cb*q-.5*Math.abs(tol_act*q)&&p<Math.abs(prev_step*q*.5)&&(new_step=p/q)),Math.abs(new_step)<tol_act&&(new_step=new_step>0?tol_act:-tol_act),a=b,fa=fb,b+=new_step,((fb=f.call(object,b))>0&&fc>0||fb<0&&fc<0)&&(c=a,fc=fa),niter++}return b},chandrupatla:function(f,x0,object){var a,fa,b,fb,res,x1,x2,x3,x,f1,f2,f3,y,xm,fm,tl,xi,ph,fl,fh,niter=0,maxiter=this.maxIterationsRoot,rand=1+.001*Math.random(),t=.5*rand,eps=Mat.eps;if(Type.isArray(x0)){if(x0.length<2)throw new Error("JXG.Math.Numerics.fzero: length of array x0 has to be at least two.");a=x0[0],fa=f.call(object,a),b=x0[1],fb=f.call(object,b)}else a=(res=this.findBracket(f,x0,object))[0],fa=res[1],b=res[2],fb=res[3];if(fa*fb>0)return Type.isArray(x0)?this.fminbr(f,[a,b],object):this.Newton(f,a,object);x1=a,x2=b,f1=fa,f2=fb;do{if(x=x1+t*(x2-x1),y=f.call(object,x),Math.sign(y)===Math.sign(f1)?(x3=x1,x1=x,f3=f1,f1=y):(x3=x2,x2=x1,f3=f2,f2=f1),xm=x1=x,fm=f1=y,Math.abs(f2)<Math.abs(f1)&&(xm=x2,fm=f2),(tl=(2*eps*Math.abs(xm)+5e-6)/Math.abs(x2-x1))>.5||0===fm)break;xi=(x1-x2)/(x3-x2),ph=(f1-f2)/(f3-f2),fl=1-Math.sqrt(1-xi),fh=Math.sqrt(xi),(t=fl<ph&&ph<fh?f1/(f2-f1)*(f3/(f2-f3))+f1/(f3-f1)*(f2/(f3-f2))*((x3-x1)/(x2-x1)):.5*rand)<tl&&(t=tl),t>1-tl&&(t=1-tl),niter++}while(niter<=maxiter);return xm},fminbr:function(f,x0,context){var a,b,x,v,w,fx,fv,fw,range,middle_range,tol_act,new_step,p,q,t,ft,r=.5*(3-Math.sqrt(5)),tol=Mat.eps,sqrteps=Mat.eps,maxiter=this.maxIterationsMinimize,niter=0;if(!Type.isArray(x0)||x0.length<2)throw new Error("JXG.Math.Numerics.fminbr: length of array x0 has to be at least two.");for(x=v=(a=x0[0])+r*((b=x0[1])-a),w=v,fx=fv=f.call(context,v),fw=fv;niter<maxiter;){if(range=b-a,middle_range=.5*(a+b),tol_act=sqrteps*Math.abs(x)+tol/3,Math.abs(x-middle_range)+.5*range<=2*tol_act)return x;new_step=r*(x<middle_range?b-x:a-x),Math.abs(x-w)>=tol_act&&(p=(x-v)*(q=(x-v)*(fx-fw))-(x-w)*(t=(x-w)*(fx-fv)),(q=2*(q-t))>0?p=-p:q=-q,Math.abs(p)<Math.abs(new_step*q)&&p>q*(a-x+2*tol_act)&&p<q*(b-x-2*tol_act)&&(new_step=p/q)),Math.abs(new_step)<tol_act&&(new_step=new_step>0?tol_act:-tol_act),t=x+new_step,(ft=f.call(context,t))<=fx?(t<x?b=x:a=x,v=w,w=x,x=t,fv=fw,fw=fx,fx=ft):(t<x?a=t:b=t,ft<=fw||w===x?(v=w,w=t,fv=fw,fw=ft):(ft<=fv||v===x||v===w)&&(v=t,fv=ft)),niter+=1}return x},RamerDouglasPeucker:function(pts,eps){var i,k,len,allPts=[],newPts=[],RDP=function RDP(pts,i,j,eps,newPts){var result=function(pts,i,j){var d,k,ci,cj,ck,x0,y0,x1,y1,den,lbda,dist=0,f=i;if(j-i<2)return[-1,0];if(ci=pts[i].scrCoords,cj=pts[j].scrCoords,isNaN(ci[1])||isNaN(ci[2]))return[NaN,i];if(isNaN(cj[1])||isNaN(cj[2]))return[NaN,j];for(k=i+1;k<j;k++){if(ck=pts[k].scrCoords,isNaN(ck[1])||isNaN(ck[2]))return[NaN,k];x0=(x0=(x0=ck[1]-ci[1])==1/0?1e4:x0)===-1/0?-1e4:x0,y0=(y0=(y0=ck[2]-ci[2])==1/0?1e4:y0)===-1/0?-1e4:y0,(den=(x1=(x1=(x1=cj[1]-ci[1])==1/0?1e4:x1)===-1/0?-1e4:x1)*x1+(y1=(y1=(y1=cj[2]-ci[2])==1/0?1e4:y1)===-1/0?-1e4:y1)*y1)>=Mat.eps?((lbda=(x0*x1+y0*y1)/den)<0?lbda=0:lbda>1&&(lbda=1),d=(x0-=lbda*x1)*x0+(y0-=lbda*y1)*y0):(lbda=0,d=x0*x0+y0*y0),d>dist&&(dist=d,f=k)}return[Math.sqrt(dist),f]}(pts,i,j),k=result[1];if(isNaN(result[0])){RDP(pts,i,k-1,eps,newPts),newPts.push(pts[k]);do{++k}while(k<=j&&isNaN(pts[k].scrCoords[1]+pts[k].scrCoords[2]));k<=j&&newPts.push(pts[k]),RDP(pts,k+1,j,eps,newPts)}else result[0]>eps?(RDP(pts,i,k,eps,newPts),RDP(pts,k,j,eps,newPts)):newPts.push(pts[j])};for(len=pts.length,i=0;;){for(;i<len&&isNaN(pts[i].scrCoords[1]+pts[i].scrCoords[2]);)i+=1;for(k=i+1;k<len&&!isNaN(pts[k].scrCoords[1]+pts[k].scrCoords[2]);)k+=1;if(k--,i<len&&k>i&&((newPts=[])[0]=pts[i],RDP(pts,i,k,eps,newPts),allPts=allPts.concat(newPts)),i>=len)break;k<len-1&&allPts.push(pts[k+1]),i=k+1}return allPts},RamerDouglasPeuker:function(pts,eps){return JXG.deprecated("Numerics.RamerDouglasPeuker()","Numerics.RamerDouglasPeucker()"),this.RamerDouglasPeucker(pts,eps)},Visvalingam:function(pts,numPoints){var i,len,vol,lastVol,lft,rt,lft2,rt2,obj,linkedList=[],heap=[],points=[];if((len=pts.length)<=2)return pts;for(linkedList[0]={used:!0,lft:null,node:null},lft=0,i=1;i<len-1;i++)vol=Math.abs(JXG.Math.Numerics.det([pts[i-1].usrCoords,pts[i].usrCoords,pts[i+1].usrCoords])),isNaN(vol)||(obj={v:vol,idx:i},heap.push(obj),linkedList[i]={used:!0,lft:lft,node:obj},linkedList[lft].rt=i,lft=i);for(linkedList[len-1]={used:!0,rt:null,lft:lft,node:null},linkedList[lft].rt=len-1,lastVol=-1/0;heap.length>numPoints;)heap.sort((function(a,b){return b.v-a.v})),linkedList[i=heap.pop().idx].used=!1,lastVol=linkedList[i].node.v,lft=linkedList[i].lft,rt=linkedList[i].rt,linkedList[lft].rt=rt,linkedList[rt].lft=lft,null!==(lft2=linkedList[lft].lft)&&(vol=Math.abs(JXG.Math.Numerics.det([pts[lft2].usrCoords,pts[lft].usrCoords,pts[rt].usrCoords])),linkedList[lft].node.v=vol>=lastVol?vol:lastVol),null!==(rt2=linkedList[rt].rt)&&(vol=Math.abs(JXG.Math.Numerics.det([pts[lft].usrCoords,pts[rt].usrCoords,pts[rt2].usrCoords])),linkedList[rt].node.v=vol>=lastVol?vol:lastVol);points=[pts[i=0]];do{i=linkedList[i].rt,points.push(pts[i])}while(null!==linkedList[i].rt);return points}},Mat.Numerics})),define("math/nlp",["jxg"],(function(JXG){return JXG.Math.Nlp={arr:function(n){var i,a=new Array(n);for(i=0;i<n;i++)a[i]=0;return a},arr2:function(n,m){for(var i=0,a=new Array(n);i<n;)a[i]=this.arr(m),i++;return a},arraycopy:function(x,a,iox,b,n){for(var i=0;i<n;)iox[i+b]=x[i+a],i++},Normal:0,MaxIterationsReached:1,DivergingRoundingErrors:2,FindMinimum:function(calcfc,n,m,x,rhobeg,rhoend,iprint,maxfun){var status,fcalcfc,mpp=m+2,iox=this.arr(n+1),that=this;return iox[0]=0,this.arraycopy(x,0,iox,1,n),fcalcfc=function(n,m,thisx,con){var ocon,f,ix=that.arr(n);return that.arraycopy(thisx,1,ix,0,n),ocon=that.arr(m),f=calcfc(n,m,ix,ocon),that.arraycopy(ocon,0,con,1,m),f},status=this.cobylb(fcalcfc,n,m,mpp,iox,rhobeg,rhoend,iprint,maxfun),this.arraycopy(iox,1,x,0,n),status},cobylb:function(calcfc,n,m,mpp,x,rhobeg,rhoend,iprint,maxfun){var total,i,j,k,l,temp,tempa,nfvals,jdrop,ibrnch,skipVertexIdent,phimin,nbest,error,pareta,wsig,weta,cvmaxp,cvmaxm,dxsign,resnew,barmu,phi,trured,ratio,edgmax,cmin,cmax,denom,status=-1,f=0,resmax=0,np=n+1,mp=m+1,rho=rhobeg,parmu=0,iflag=!1,ifull=!1,parsig=0,prerec=0,prerem=0,con=this.arr(1+mpp),sim=this.arr2(1+n,1+np),simi=this.arr2(1+n,1+n),datmat=this.arr2(1+mpp,1+np),a=this.arr2(1+n,1+mp),vsig=this.arr(1+n),veta=this.arr(1+n),sigbar=this.arr(1+n),dx=this.arr(1+n),w=this.arr(1+n);for(iprint>=2&&console.log("The initial value of RHO is "+rho+" and PARMU is set to zero."),nfvals=0,temp=1/rho,i=1;i<=n;++i)sim[i][np]=x[i],sim[i][i]=rho,simi[i][i]=temp;jdrop=np,ibrnch=!1;L_40:for(;;){if(nfvals>=maxfun&&nfvals>0){status=this.MaxIterationsReached;break L_40}for(++nfvals,f=calcfc(n,m,x,con),resmax=0,k=1;k<=m;++k)resmax=Math.max(resmax,-con[k]);if(nfvals!==iprint-1&&3!==iprint||this.PrintIterationResult(nfvals,f,resmax,x,n,iprint),con[mp]=f,con[mpp]=resmax,skipVertexIdent=!0,!ibrnch){for(skipVertexIdent=!1,i=1;i<=mpp;++i)datmat[i][jdrop]=con[i];if(nfvals<=np){if(jdrop<=n)if(datmat[mp][np]<=f)x[jdrop]=sim[jdrop][np];else{for(sim[jdrop][np]=x[jdrop],k=1;k<=mpp;++k)datmat[k][jdrop]=datmat[k][np],datmat[k][np]=con[k];for(k=1;k<=jdrop;++k){for(sim[jdrop][k]=-rho,temp=0,i=k;i<=jdrop;++i)temp-=simi[i][k];simi[jdrop][k]=temp}}if(nfvals<=n){x[jdrop=nfvals]+=rho;continue L_40}}ibrnch=!0}L_140:for(;;){L_550:do{if(!skipVertexIdent){for(phimin=datmat[mp][np]+parmu*datmat[mpp][np],nbest=np,j=1;j<=n;++j)(temp=datmat[mp][j]+parmu*datmat[mpp][j])<phimin?(nbest=j,phimin=temp):temp===phimin&&0===parmu&&datmat[mpp][j]<datmat[mpp][nbest]&&(nbest=j);if(nbest<=n){for(i=1;i<=mpp;++i)temp=datmat[i][np],datmat[i][np]=datmat[i][nbest],datmat[i][nbest]=temp;for(i=1;i<=n;++i){for(temp=sim[i][nbest],sim[i][nbest]=0,sim[i][np]+=temp,tempa=0,k=1;k<=n;++k)sim[i][k]-=temp,tempa-=simi[k][i];simi[nbest][i]=tempa}}for(error=0,i=1;i<=n;++i)for(j=1;j<=n;++j)temp=this.DOT_PRODUCT(this.PART(this.ROW(simi,i),1,n),this.PART(this.COL(sim,j),1,n))-(i===j?1:0),error=Math.max(error,Math.abs(temp));if(error>.1){status=this.DivergingRoundingErrors;break L_40}for(k=1;k<=mp;++k){for(con[k]=-datmat[k][np],j=1;j<=n;++j)w[j]=datmat[k][j]+con[k];for(i=1;i<=n;++i)a[i][k]=(k===mp?-1:1)*this.DOT_PRODUCT(this.PART(w,1,n),this.PART(this.COL(simi,i),1,n))}for(iflag=!0,parsig=.25*rho,pareta=2.1*rho,j=1;j<=n;++j){for(wsig=0,k=1;k<=n;++k)wsig+=simi[j][k]*simi[j][k];for(weta=0,k=1;k<=n;++k)weta+=sim[k][j]*sim[k][j];vsig[j]=1/Math.sqrt(wsig),veta[j]=Math.sqrt(weta),(vsig[j]<parsig||veta[j]>pareta)&&(iflag=!1)}if(!ibrnch&&!iflag){for(jdrop=0,temp=pareta,j=1;j<=n;++j)veta[j]>temp&&(jdrop=j,temp=veta[j]);if(0===jdrop)for(j=1;j<=n;++j)vsig[j]<temp&&(jdrop=j,temp=vsig[j]);for(temp=.5*rho*vsig[jdrop],k=1;k<=n;++k)dx[k]=temp*simi[jdrop][k];for(cvmaxp=0,cvmaxm=0,total=0,k=1;k<=mp;++k)total=this.DOT_PRODUCT(this.PART(this.COL(a,k),1,n),this.PART(dx,1,n)),k<mp&&(temp=datmat[k][np],cvmaxp=Math.max(cvmaxp,-total-temp),cvmaxm=Math.max(cvmaxm,total-temp));for(dxsign=parmu*(cvmaxp-cvmaxm)>2*total?-1:1,temp=0,i=1;i<=n;++i)dx[i]=dxsign*dx[i],sim[i][jdrop]=dx[i],temp+=simi[jdrop][i]*dx[i];for(k=1;k<=n;++k)simi[jdrop][k]/=temp;for(j=1;j<=n;++j){if(j!==jdrop)for(temp=this.DOT_PRODUCT(this.PART(this.ROW(simi,j),1,n),this.PART(dx,1,n)),k=1;k<=n;++k)simi[j][k]-=temp*simi[jdrop][k];x[j]=sim[j][np]+dx[j]}continue L_40}if(!(ifull=this.trstlp(n,m,a,con,rho,dx))){for(temp=0,k=1;k<=n;++k)temp+=dx[k]*dx[k];if(temp<.25*rho*rho){ibrnch=!0;break L_550}}for(total=0,resnew=0,con[mp]=0,k=1;k<=mp;++k)total=con[k]-this.DOT_PRODUCT(this.PART(this.COL(a,k),1,n),this.PART(dx,1,n)),k<mp&&(resnew=Math.max(resnew,total));if(parmu<1.5*(barmu=(prerec=datmat[mpp][np]-resnew)>0?total/prerec:0))for(parmu=2*barmu,iprint>=2&&console.log("Increase in PARMU to "+parmu),phi=datmat[mp][np]+parmu*datmat[mpp][np],j=1;j<=n;++j)if((temp=datmat[mp][j]+parmu*datmat[mpp][j])<phi||temp===phi&&0===parmu&&datmat[mpp][j]<datmat[mpp][np])continue L_140;for(prerem=parmu*prerec-total,k=1;k<=n;++k)x[k]=sim[k][np]+dx[k];ibrnch=!0;continue L_40}for(skipVertexIdent=!1,trured=datmat[mp][np]+parmu*datmat[mpp][np]-(f+parmu*resmax),0===parmu&&f===datmat[mp][np]&&(prerem=prerec,trured=datmat[mpp][np]-resmax),ratio=trured<=0?1:0,jdrop=0,j=1;j<=n;++j)(temp=Math.abs(this.DOT_PRODUCT(this.PART(this.ROW(simi,j),1,n),this.PART(dx,1,n))))>ratio&&(jdrop=j,ratio=temp),sigbar[j]=temp*vsig[j];for(edgmax=1.1*rho,l=0,j=1;j<=n;++j)if(sigbar[j]>=parsig||sigbar[j]>=vsig[j]){if(temp=veta[j],trured>0){for(temp=0,k=1;k<=n;++k)temp+=Math.pow(dx[k]-sim[k][j],2);temp=Math.sqrt(temp)}temp>edgmax&&(l=j,edgmax=temp)}if(l>0&&(jdrop=l),0!==jdrop){for(temp=0,i=1;i<=n;++i)sim[i][jdrop]=dx[i],temp+=simi[jdrop][i]*dx[i];for(k=1;k<=n;++k)simi[jdrop][k]/=temp;for(j=1;j<=n;++j)if(j!==jdrop)for(temp=this.DOT_PRODUCT(this.PART(this.ROW(simi,j),1,n),this.PART(dx,1,n)),k=1;k<=n;++k)simi[j][k]-=temp*simi[jdrop][k];for(k=1;k<=mpp;++k)datmat[k][jdrop]=con[k];if(trured>0&&trured>=.1*prerem)continue L_140}}while(0);if(iflag){if(rho<=rhoend){status=this.Normal;break L_40}if(cmin=0,cmax=0,(rho*=.5)<=1.5*rhoend&&(rho=rhoend),parmu>0){for(denom=0,k=1;k<=mp;++k){for(cmax=cmin=datmat[k][np],i=1;i<=n;++i)cmin=Math.min(cmin,datmat[k][i]),cmax=Math.max(cmax,datmat[k][i]);k<=m&&cmin<.5*cmax&&(temp=Math.max(cmax,0)-cmin,denom=denom<=0?temp:Math.min(denom,temp))}0===denom?parmu=0:cmax-cmin<parmu*denom&&(parmu=(cmax-cmin)/denom)}iprint>=2&&console.log("Reduction in RHO to "+rho+" and PARMU = "+parmu),2===iprint&&this.PrintIterationResult(nfvals,datmat[mp][np],datmat[mpp][np],this.COL(sim,np),n,iprint)}else ibrnch=!1}}switch(status){case this.Normal:if(iprint>=1&&console.log("%nNormal return from subroutine COBYLA%n"),ifull)return iprint>=1&&this.PrintIterationResult(nfvals,f,resmax,x,n,iprint),status;break;case this.MaxIterationsReached:iprint>=1&&console.log("%nReturn from subroutine COBYLA because the MAXFUN limit has been reached.%n");break;case this.DivergingRoundingErrors:iprint>=1&&console.log("%nReturn from subroutine COBYLA because rounding errors are becoming damaging.%n")}for(k=1;k<=n;++k)x[k]=sim[k][np];return f=datmat[mp][np],resmax=datmat[mpp][np],iprint>=1&&this.PrintIterationResult(nfvals,f,resmax,x,n,iprint),status},trstlp:function(n,m,a,b,rho,dx){var icon,resmax,i,k,first,optold,icount,step,stpful,optnew,ratio,isave,vsave,total,kp,kk,sp,alpha,beta,tot,spabs,acca,accb,zdotv,zdvabs,kw,dd,ss,sd,zdotw,zdwabs,sumabs,tempa,temp=0,nactx=0,resold=0,z=this.arr2(1+n,1+n),zdota=this.arr(2+m),vmultc=this.arr(2+m),sdirn=this.arr(1+n),dxnew=this.arr(1+n),vmultd=this.arr(2+m),iact=this.arr(2+m),mcon=m,nact=0;for(i=1;i<=n;++i)z[i][i]=1,dx[i]=0;if(icon=0,resmax=0,m>=1){for(k=1;k<=m;++k)b[k]>resmax&&(resmax=b[k],icon=k);for(k=1;k<=m;++k)iact[k]=k,vmultc[k]=resmax-b[k]}first=!0;do{L_60:for(;;){(!first||first&&0===resmax)&&(icon=mcon=m+1,iact[mcon]=mcon,vmultc[mcon]=0),first=!1,optold=0,icount=0,step=0,stpful=0;L_70:do{if(optnew=mcon===m?resmax:-this.DOT_PRODUCT(this.PART(dx,1,n),this.PART(this.COL(a,mcon),1,n)),0===icount||optnew<optold?(optold=optnew,nactx=nact,icount=3):nact>nactx?(nactx=nact,icount=3):--icount,0===icount)break L_60;if(ratio=0,icon<=nact){if(icon<nact){isave=iact[icon],vsave=vmultc[icon],k=icon;do{for(kk=iact[kp=k+1],sp=this.DOT_PRODUCT(this.PART(this.COL(z,k),1,n),this.PART(this.COL(a,kk),1,n)),temp=Math.sqrt(sp*sp+zdota[kp]*zdota[kp]),alpha=zdota[kp]/temp,beta=sp/temp,zdota[kp]=alpha*zdota[k],zdota[k]=temp,i=1;i<=n;++i)temp=alpha*z[i][kp]+beta*z[i][k],z[i][kp]=alpha*z[i][k]-beta*z[i][kp],z[i][k]=temp;iact[k]=kk,vmultc[k]=vmultc[kp],k=kp}while(k<nact);iact[k]=isave,vmultc[k]=vsave}if(--nact,mcon>m)for(temp=1/zdota[nact],k=1;k<=n;++k)sdirn[k]=temp*z[k][nact];else for(temp=this.DOT_PRODUCT(this.PART(sdirn,1,n),this.PART(this.COL(z,nact+1),1,n)),k=1;k<=n;++k)sdirn[k]-=temp*z[k][nact+1]}else{for(kk=iact[icon],k=1;k<=n;++k)dxnew[k]=a[k][kk];for(tot=0,k=n;k>nact;){for(sp=0,spabs=0,i=1;i<=n;++i)sp+=temp=z[i][k]*dxnew[i],spabs+=Math.abs(temp);if(acca=spabs+.1*Math.abs(sp),accb=spabs+.2*Math.abs(sp),(spabs>=acca||acca>=accb)&&(sp=0),0===tot)tot=sp;else for(kp=k+1,alpha=sp/(temp=Math.sqrt(sp*sp+tot*tot)),beta=tot/temp,tot=temp,i=1;i<=n;++i)temp=alpha*z[i][k]+beta*z[i][kp],z[i][kp]=alpha*z[i][kp]-beta*z[i][k],z[i][k]=temp;--k}if(0===tot){ratio=-1,k=nact;do{for(zdotv=0,zdvabs=0,i=1;i<=n;++i)zdotv+=temp=z[i][k]*dxnew[i],zdvabs+=Math.abs(temp);if(acca=zdvabs+.1*Math.abs(zdotv),accb=zdvabs+.2*Math.abs(zdotv),zdvabs<acca&&acca<accb){if((temp=zdotv/zdota[k])>0&&iact[k]<=m&&(tempa=vmultc[k]/temp,(ratio<0||tempa<ratio)&&(ratio=tempa)),k>=2)for(kw=iact[k],i=1;i<=n;++i)dxnew[i]-=temp*a[i][kw];vmultd[k]=temp}else vmultd[k]=0}while(--k>0);if(ratio<0)break L_60;for(k=1;k<=nact;++k)vmultc[k]=Math.max(0,vmultc[k]-ratio*vmultd[k]);if(icon<nact){isave=iact[icon],vsave=vmultc[icon],k=icon;do{for(kw=iact[kp=k+1],sp=this.DOT_PRODUCT(this.PART(this.COL(z,k),1,n),this.PART(this.COL(a,kw),1,n)),temp=Math.sqrt(sp*sp+zdota[kp]*zdota[kp]),alpha=zdota[kp]/temp,beta=sp/temp,zdota[kp]=alpha*zdota[k],zdota[k]=temp,i=1;i<=n;++i)temp=alpha*z[i][kp]+beta*z[i][k],z[i][kp]=alpha*z[i][k]-beta*z[i][kp],z[i][k]=temp;iact[k]=kw,vmultc[k]=vmultc[kp],k=kp}while(k<nact);iact[k]=isave,vmultc[k]=vsave}if(0===(temp=this.DOT_PRODUCT(this.PART(this.COL(z,nact),1,n),this.PART(this.COL(a,kk),1,n))))break L_60;zdota[nact]=temp,vmultc[icon]=0,vmultc[nact]=ratio}else zdota[++nact]=tot,vmultc[icon]=vmultc[nact],vmultc[nact]=0;if(iact[icon]=iact[nact],iact[nact]=kk,mcon>m&&kk!==mcon){for(k=nact-1,sp=this.DOT_PRODUCT(this.PART(this.COL(z,k),1,n),this.PART(this.COL(a,kk),1,n)),temp=Math.sqrt(sp*sp+zdota[nact]*zdota[nact]),alpha=zdota[nact]/temp,beta=sp/temp,zdota[nact]=alpha*zdota[k],zdota[k]=temp,i=1;i<=n;++i)temp=alpha*z[i][nact]+beta*z[i][k],z[i][nact]=alpha*z[i][k]-beta*z[i][nact],z[i][k]=temp;iact[nact]=iact[k],iact[k]=kk,temp=vmultc[k],vmultc[k]=vmultc[nact],vmultc[nact]=temp}if(mcon>m)for(temp=1/zdota[nact],k=1;k<=n;++k)sdirn[k]=temp*z[k][nact];else for(kk=iact[nact],temp=(this.DOT_PRODUCT(this.PART(sdirn,1,n),this.PART(this.COL(a,kk),1,n))-1)/zdota[nact],k=1;k<=n;++k)sdirn[k]-=temp*z[k][nact]}for(dd=rho*rho,sd=0,ss=0,i=1;i<=n;++i)Math.abs(dx[i])>=1e-6*rho&&(dd-=dx[i]*dx[i]),sd+=dx[i]*sdirn[i],ss+=sdirn[i]*sdirn[i];if(dd<=0)break L_60;if(temp=Math.sqrt(ss*dd),Math.abs(sd)>=1e-6*temp&&(temp=Math.sqrt(ss*dd+sd*sd)),step=stpful=dd/(temp+sd),mcon===m){if(accb=step+.2*resmax,step>=(acca=step+.1*resmax)||acca>=accb)break L_70;step=Math.min(step,resmax)}for(k=1;k<=n;++k)dxnew[k]=dx[k]+step*sdirn[k];if(mcon===m)for(resold=resmax,resmax=0,k=1;k<=nact;++k)temp=b[kk=iact[k]]-this.DOT_PRODUCT(this.PART(this.COL(a,kk),1,n),this.PART(dxnew,1,n)),resmax=Math.max(resmax,temp);k=nact;do{for(zdotw=0,zdwabs=0,i=1;i<=n;++i)zdotw+=temp=z[i][k]*dxnew[i],zdwabs+=Math.abs(temp);if(acca=zdwabs+.1*Math.abs(zdotw),accb=zdwabs+.2*Math.abs(zdotw),(zdwabs>=acca||acca>=accb)&&(zdotw=0),vmultd[k]=zdotw/zdota[k],k>=2)for(kk=iact[k],i=1;i<=n;++i)dxnew[i]-=vmultd[k]*a[i][kk]}while(k-- >=2);for(mcon>m&&(vmultd[nact]=Math.max(0,vmultd[nact])),k=1;k<=n;++k)dxnew[k]=dx[k]+step*sdirn[k];if(mcon>nact)for(k=nact+1;k<=mcon;++k){for(total=resmax-b[kk=iact[k]],sumabs=resmax+Math.abs(b[kk]),i=1;i<=n;++i)total+=temp=a[i][kk]*dxnew[i],sumabs+=Math.abs(temp);acca=sumabs+.1*Math.abs(total),accb=sumabs+.2*Math.abs(total),(sumabs>=acca||acca>=accb)&&(total=0),vmultd[k]=total}for(ratio=1,icon=0,k=1;k<=mcon;++k)vmultd[k]<0&&(temp=vmultc[k]/(vmultc[k]-vmultd[k]))<ratio&&(ratio=temp,icon=k);for(temp=1-ratio,k=1;k<=n;++k)dx[k]=temp*dx[k]+ratio*dxnew[k];for(k=1;k<=mcon;++k)vmultc[k]=Math.max(0,temp*vmultc[k]+ratio*vmultd[k]);mcon===m&&(resmax=resold+ratio*(resmax-resold))}while(icon>0);if(step===stpful)return!0}}while(mcon===m);return!1},PrintIterationResult:function(nfvals,f,resmax,x,n,iprint){iprint>1&&console.log("NFVALS = "+nfvals+" F = "+f+" MAXCV = "+resmax),iprint>1&&console.log("X = "+this.PART(x,1,n))},ROW:function(src,rowidx){return src[rowidx].slice()},COL:function(src,colidx){var row,rows=src.length,dest=this.arr(rows);for(row=0;row<rows;++row)dest[row]=src[row][colidx];return dest},PART:function(src,from,to){return src.slice(from,to+1)},FORMAT:function(x){return x.join(",")},DOT_PRODUCT:function(lhs,rhs){var i,sum=0,len=lhs.length;for(i=0;i<len;++i)sum+=lhs[i]*rhs[i];return sum}},JXG.Math.Nlp})),define("math/statistics",["jxg","math/math","utils/type"],(function(JXG,Mat,Type){return Mat.Statistics={sum:function(arr){var i,len=arr.length,res=0;for(i=0;i<len;i++)res+=arr[i];return res},prod:function(arr){var i,len=arr.length,res=1;for(i=0;i<len;i++)res*=arr[i];return res},mean:function(arr){return arr.length>0?this.sum(arr)/arr.length:0},median:function(arr){var tmp,len;return arr.length>0?(ArrayBuffer.isView(arr)?(tmp=new Float64Array(arr)).sort():(tmp=arr.slice(0)).sort((function(a,b){return a-b})),1&(len=tmp.length)?tmp[parseInt(.5*len,10)]:.5*(tmp[.5*len-1]+tmp[.5*len])):0},percentile:function(arr,_percentile){var tmp,len,i,p,per,res=[];if(arr.length>0){for(ArrayBuffer.isView(arr)?(tmp=new Float64Array(arr)).sort():(tmp=arr.slice(0)).sort((function(a,b){return a-b})),len=tmp.length,p=Type.isArray(_percentile)?_percentile:[_percentile],i=0;i<p.length;i++)per=len*p[i]*.01,parseInt(per,10)===per?res.push(.5*(tmp[per-1]+tmp[per])):res.push(tmp[parseInt(per,10)]);return Type.isArray(_percentile)?res:res[0]}return 0},variance:function(arr){var m,res,i,len=arr.length;if(len>1){for(m=this.mean(arr),res=0,i=0;i<len;i++)res+=(arr[i]-m)*(arr[i]-m);return res/(arr.length-1)}return 0},sd:function(arr){return Math.sqrt(this.variance(arr))},weightedMean:function(arr,w){if(arr.length!==w.length)throw new Error("JSXGraph error (Math.Statistics.weightedMean): Array dimension mismatch.");return arr.length>0?this.mean(this.multiply(arr,w)):0},max:function(arr){return Math.max.apply(this,arr)},min:function(arr){return Math.min.apply(this,arr)},range:function(arr){return[this.min(arr),this.max(arr)]},abs:function(arr){var i,len,res;if(Type.isArray(arr))if(arr.map)res=arr.map(Math.abs);else for(len=arr.length,res=[],i=0;i<len;i++)res[i]=Math.abs(arr[i]);else res=ArrayBuffer.isView(arr)?arr.map(Math.abs):Math.abs(arr);return res},add:function(arr1,arr2){var i,len,res=[];if(arr1=Type.evalSlider(arr1),arr2=Type.evalSlider(arr2),Type.isArray(arr1)&&Type.isNumber(arr2))for(len=arr1.length,i=0;i<len;i++)res[i]=arr1[i]+arr2;else if(Type.isNumber(arr1)&&Type.isArray(arr2))for(len=arr2.length,i=0;i<len;i++)res[i]=arr1+arr2[i];else if(Type.isArray(arr1)&&Type.isArray(arr2))for(len=Math.min(arr1.length,arr2.length),i=0;i<len;i++)res[i]=arr1[i]+arr2[i];else res=arr1+arr2;return res},div:function(arr1,arr2){var i,len,res=[];if(arr1=Type.evalSlider(arr1),arr2=Type.evalSlider(arr2),Type.isArray(arr1)&&Type.isNumber(arr2))for(len=arr1.length,i=0;i<len;i++)res[i]=arr1[i]/arr2;else if(Type.isNumber(arr1)&&Type.isArray(arr2))for(len=arr2.length,i=0;i<len;i++)res[i]=arr1/arr2[i];else if(Type.isArray(arr1)&&Type.isArray(arr2))for(len=Math.min(arr1.length,arr2.length),i=0;i<len;i++)res[i]=arr1[i]/arr2[i];else res=arr1/arr2;return res},divide:function(){JXG.deprecated("Statistics.divide()","Statistics.div()"),Mat.Statistics.div.apply(Mat.Statistics,arguments)},mod:function(arr1,arr2,math){var i,len,res=[],mod=function(a,m){return a%m};if((math=Type.def(math,!1))&&(mod=Mat.mod),arr1=Type.evalSlider(arr1),arr2=Type.evalSlider(arr2),Type.isArray(arr1)&&Type.isNumber(arr2))for(len=arr1.length,i=0;i<len;i++)res[i]=mod(arr1[i],arr2);else if(Type.isNumber(arr1)&&Type.isArray(arr2))for(len=arr2.length,i=0;i<len;i++)res[i]=mod(arr1,arr2[i]);else if(Type.isArray(arr1)&&Type.isArray(arr2))for(len=Math.min(arr1.length,arr2.length),i=0;i<len;i++)res[i]=mod(arr1[i],arr2[i]);else res=mod(arr1,arr2);return res},multiply:function(arr1,arr2){var i,len,res=[];if(arr1=Type.evalSlider(arr1),arr2=Type.evalSlider(arr2),Type.isArray(arr1)&&Type.isNumber(arr2))for(len=arr1.length,i=0;i<len;i++)res[i]=arr1[i]*arr2;else if(Type.isNumber(arr1)&&Type.isArray(arr2))for(len=arr2.length,i=0;i<len;i++)res[i]=arr1*arr2[i];else if(Type.isArray(arr1)&&Type.isArray(arr2))for(len=Math.min(arr1.length,arr2.length),i=0;i<len;i++)res[i]=arr1[i]*arr2[i];else res=arr1*arr2;return res},subtract:function(arr1,arr2){var i,len,res=[];if(arr1=Type.evalSlider(arr1),arr2=Type.evalSlider(arr2),Type.isArray(arr1)&&Type.isNumber(arr2))for(len=arr1.length,i=0;i<len;i++)res[i]=arr1[i]-arr2;else if(Type.isNumber(arr1)&&Type.isArray(arr2))for(len=arr2.length,i=0;i<len;i++)res[i]=arr1-arr2[i];else if(Type.isArray(arr1)&&Type.isArray(arr2))for(len=Math.min(arr1.length,arr2.length),i=0;i<len;i++)res[i]=arr1[i]-arr2[i];else res=arr1-arr2;return res},TheilSenRegression:function(coords){var i,j,slopes=[],tmpslopes=[],yintercepts=[];for(i=0;i<coords.length;i++){for(tmpslopes.length=0,j=0;j<coords.length;j++)Math.abs(coords[j].usrCoords[1]-coords[i].usrCoords[1])>Mat.eps&&(tmpslopes[j]=(coords[j].usrCoords[2]-coords[i].usrCoords[2])/(coords[j].usrCoords[1]-coords[i].usrCoords[1]));slopes[i]=this.median(tmpslopes),yintercepts.push(coords[i].usrCoords[2]-slopes[i]*coords[i].usrCoords[1])}return[this.median(yintercepts),this.median(slopes),-1]},generateGaussian:function(mean,stdDev){var u,v,s;if(this.hasSpare)return this.hasSpare=!1,this.spare*stdDev+mean;do{s=(u=2*Math.random()-1)*u+(v=2*Math.random()-1)*v}while(s>=1||0===s);return s=Math.sqrt(-2*Math.log(s)/s),this.spare=v*s,this.hasSpare=!0,mean+stdDev*u*s}},Mat.Statistics})),define("math/geometry",["jxg","base/constants","base/coords","math/math","math/numerics","utils/type","utils/expect"],(function(JXG,Const,Coords,Mat,Numerics,Type,Expect){return Mat.Geometry={},JXG.extend(Mat.Geometry,{angle:function(A,B,C){var u,v,s,t,a=[],b=[],c=[];return JXG.deprecated("Geometry.angle()","Geometry.rad()"),A.coords?(a[0]=A.coords.usrCoords[1],a[1]=A.coords.usrCoords[2]):(a[0]=A[0],a[1]=A[1]),B.coords?(b[0]=B.coords.usrCoords[1],b[1]=B.coords.usrCoords[2]):(b[0]=B[0],b[1]=B[1]),C.coords?(c[0]=C.coords.usrCoords[1],c[1]=C.coords.usrCoords[2]):(c[0]=C[0],c[1]=C[1]),u=a[0]-b[0],v=a[1]-b[1],s=c[0]-b[0],t=c[1]-b[1],Math.atan2(u*t-v*s,u*s+v*t)},trueAngle:function(A,B,C){return 57.29577951308232*this.rad(A,B,C)},rad:function(A,B,C){var ax,ay,bx,by,cx,cy,phi;return A.coords?(ax=A.coords.usrCoords[1],ay=A.coords.usrCoords[2]):(ax=A[0],ay=A[1]),B.coords?(bx=B.coords.usrCoords[1],by=B.coords.usrCoords[2]):(bx=B[0],by=B[1]),C.coords?(cx=C.coords.usrCoords[1],cy=C.coords.usrCoords[2]):(cx=C[0],cy=C[1]),(phi=Math.atan2(cy-by,cx-bx)-Math.atan2(ay-by,ax-bx))<0&&(phi+=6.283185307179586),phi},angleBisector:function(A,B,C,board){var phiA,phiC,phi,x,y,Ac=A.coords.usrCoords,Bc=B.coords.usrCoords,Cc=C.coords.usrCoords;return Type.exists(board)||(board=A.board),0===Bc[0]?new Coords(Const.COORDS_BY_USER,[1,.5*(Ac[1]+Cc[1]),.5*(Ac[2]+Cc[2])],board):(x=Ac[1]-Bc[1],y=Ac[2]-Bc[2],phiA=Math.atan2(y,x),x=Cc[1]-Bc[1],y=Cc[2]-Bc[2],phi=.5*(phiA+(phiC=Math.atan2(y,x))),phiA>phiC&&(phi+=Math.PI),x=Math.cos(phi)+Bc[1],y=Math.sin(phi)+Bc[2],new Coords(Const.COORDS_BY_USER,[1,x,y],board))},reflection:function(line,point,board){var x0,x1,y1,v,w,mu,pc=point.coords.usrCoords,p1c=line.point1.coords.usrCoords,p2c=line.point2.coords.usrCoords;return Type.exists(board)||(board=point.board),v=p2c[1]-p1c[1],w=p2c[2]-p1c[2],x0=pc[1]-p1c[1],mu=(v*(pc[2]-p1c[2])-w*x0)/(v*v+w*w),x1=pc[1]+2*mu*w,y1=pc[2]-2*mu*v,new Coords(Const.COORDS_BY_USER,[x1,y1],board)},rotation:function(rotpoint,point,phi,board){var x0,y0,c,s,x1,y1,pc=point.coords.usrCoords,rotpc=rotpoint.coords.usrCoords;return Type.exists(board)||(board=point.board),x0=pc[1]-rotpc[1],y0=pc[2]-rotpc[2],x1=x0*(c=Math.cos(phi))-y0*(s=Math.sin(phi))+rotpc[1],y1=x0*s+y0*c+rotpc[2],new Coords(Const.COORDS_BY_USER,[x1,y1],board)},perpendicular:function(line,point,board){var x,y,change,c,z,A=line.point1.coords.usrCoords,B=line.point2.coords.usrCoords,C=point.coords.usrCoords;return Type.exists(board)||(board=point.board),point===line.point1?(x=A[1]+B[2]-A[2],y=A[2]-B[1]+A[1],z=A[0]*B[0],Math.abs(z)<Mat.eps&&(x=B[2],y=-B[1]),c=[z,x,y],change=!0):point===line.point2?(x=B[1]+A[2]-B[2],y=B[2]-A[1]+B[1],z=A[0]*B[0],Math.abs(z)<Mat.eps&&(x=A[2],y=-A[1]),c=[z,x,y],change=!1):Math.abs(Mat.innerProduct(C,line.stdform,3))<Mat.eps?(x=C[1]+B[2]-C[2],y=C[2]-B[1]+C[1],z=B[0],Math.abs(z)<Mat.eps&&(x=B[2],y=-B[1]),change=!0,Math.abs(z)>Mat.eps&&Math.abs(x-C[1])<Mat.eps&&Math.abs(y-C[2])<Mat.eps&&(x=C[1]+A[2]-C[2],y=C[2]-A[1]+C[1],change=!1),c=[z,x,y]):(c=[0,line.stdform[1],line.stdform[2]],c=Mat.crossProduct(c,C),c=Mat.crossProduct(c,line.stdform),change=!0),[new Coords(Const.COORDS_BY_USER,c,board),change]},circumcenterMidpoint:function(){JXG.deprecated("Geometry.circumcenterMidpoint()","Geometry.circumcenter()"),this.circumcenter.apply(this,arguments)},circumcenter:function(point1,point2,point3,board){var u,v,m1,m2,A=point1.coords.usrCoords,B=point2.coords.usrCoords,C=point3.coords.usrCoords;return Type.exists(board)||(board=point1.board),u=[B[0]-A[0],-B[2]+A[2],B[1]-A[1]],v=[.5*(A[0]+B[0]),.5*(A[1]+B[1]),.5*(A[2]+B[2])],m1=Mat.crossProduct(u,v),u=[C[0]-B[0],-C[2]+B[2],C[1]-B[1]],v=[.5*(B[0]+C[0]),.5*(B[1]+C[1]),.5*(B[2]+C[2])],m2=Mat.crossProduct(u,v),new Coords(Const.COORDS_BY_USER,Mat.crossProduct(m1,m2),board)},distance:function(array1,array2,n){var i,sum=0;for(n||(n=Math.min(array1.length,array2.length)),i=0;i<n;i++)sum+=(array1[i]-array2[i])*(array1[i]-array2[i]);return Math.sqrt(sum)},affineDistance:function(array1,array2,n){var d;return(d=this.distance(array1,array2,n))>Mat.eps&&(Math.abs(array1[0])<Mat.eps||Math.abs(array2[0])<Mat.eps)?1/0:d},affineRatio:function(a,b,c){var dx;return Type.exists(a.usrCoords)&&(a=a.usrCoords),Type.exists(b.usrCoords)&&(b=b.usrCoords),Type.exists(c.usrCoords)&&(c=c.usrCoords),dx=b[1]-a[1],Math.abs(dx)>Mat.eps?(c[1]-a[1])/dx:(c[2]-a[2])/(b[2]-a[2])},sortVertices:function(p){for(var ll,ps=Expect.each(p,Expect.coordsArray),N=ps.length,lastPoint=null;ps[0][0]===ps[N-1][0]&&ps[0][1]===ps[N-1][1]&&ps[0][2]===ps[N-1][2];)lastPoint=ps.pop(),N--;return ll=ps[0],ps.sort((function(a,b){return(a[2]===ll[2]&&a[1]===ll[1]?-1/0:Math.atan2(a[2]-ll[2],a[1]-ll[1]))-(b[2]===ll[2]&&b[1]===ll[1]?-1/0:Math.atan2(b[2]-ll[2],b[1]-ll[1]))})),null!==lastPoint&&ps.push(lastPoint),ps},signedTriangle:function(p1,p2,p3){var A=Expect.coordsArray(p1),B=Expect.coordsArray(p2),C=Expect.coordsArray(p3);return.5*((B[1]-A[1])*(C[2]-A[2])-(B[2]-A[2])*(C[1]-A[1]))},signedPolygon:function(p,sort){var i,N,A=0,ps=Expect.each(p,Expect.coordsArray);for(void 0===sort&&(sort=!0),sort?ps.unshift(ps[ps.length-1]):ps=this.sortVertices(ps),N=ps.length,i=1;i<N;i++)A+=ps[i-1][1]*ps[i][2]-ps[i][1]*ps[i-1][2];return.5*A},GrahamScan:function(points){var i,M=1,ps=Expect.each(points,Expect.coordsArray),N=ps.length;for(N=(ps=this.sortVertices(ps)).length,i=2;i<N;i++){for(;this.signedTriangle(ps[M-1],ps[M],ps[i])<=0;){if(M>1)M-=1;else if(i===N-1)break;i+=1}M+=1,ps=Type.swap(ps,M,i)}return ps.slice(0,M)},calcStraight:function(el,point1,point2,margin){var takePoint1,takePoint2,intersection,intersect1,intersect2,straightFirst,straightLast,c,p1,p2;if(Type.exists(margin)||(margin=10),straightFirst=Type.evaluate(el.visProp.straightfirst),straightLast=Type.evaluate(el.visProp.straightlast),Math.abs(point1.scrCoords[0])<Mat.eps&&(straightFirst=!0),Math.abs(point2.scrCoords[0])<Mat.eps&&(straightLast=!0),(straightFirst||straightLast)&&((c=[])[0]=el.stdform[0]-el.stdform[1]*el.board.origin.scrCoords[1]/el.board.unitX+el.stdform[2]*el.board.origin.scrCoords[2]/el.board.unitY,c[1]=el.stdform[1]/el.board.unitX,c[2]=-el.stdform[2]/el.board.unitY,!isNaN(c[0]+c[1]+c[2]))){if(!1,!1,takePoint1=!straightFirst&&Math.abs(point1.usrCoords[0])>=Mat.eps&&point1.scrCoords[1]>=0&&point1.scrCoords[1]<=el.board.canvasWidth&&point1.scrCoords[2]>=0&&point1.scrCoords[2]<=el.board.canvasHeight,takePoint2=!straightLast&&Math.abs(point2.usrCoords[0])>=Mat.eps&&point2.scrCoords[1]>=0&&point2.scrCoords[1]<=el.board.canvasWidth&&point2.scrCoords[2]>=0&&point2.scrCoords[2]<=el.board.canvasHeight,intersect1=(intersection=this.meetLineBoard(c,el.board,margin))[0],intersect2=intersection[1],!takePoint1&&!takePoint2){if(!straightFirst&&straightLast&&!this.isSameDirection(point1,point2,intersect1)&&!this.isSameDirection(point1,point2,intersect2))return;if(straightFirst&&!straightLast&&!this.isSameDirection(point2,point1,intersect1)&&!this.isSameDirection(point2,point1,intersect2))return}takePoint1?takePoint2||(p2=this.isSameDir(point1,point2,intersect1,intersect2)?intersect2:intersect1):takePoint2?p1=this.isSameDir(point1,point2,intersect1,intersect2)?intersect1:intersect2:this.isSameDir(point1,point2,intersect1,intersect2)?(p1=intersect1,p2=intersect2):(p2=intersect1,p1=intersect2),p1&&point1.setCoordinates(Const.COORDS_BY_USER,p1.usrCoords),p2&&point2.setCoordinates(Const.COORDS_BY_USER,p2.usrCoords)}},calcLineDelimitingPoints:function(el,point1,point2){var distP1P2,boundingBox,intersect1,intersect2,straightFirst,straightLast,c,p1,p2,takePoint1,takePoint2;if(straightFirst=Type.evaluate(el.visProp.straightfirst),straightLast=Type.evaluate(el.visProp.straightlast),Math.abs(point1.scrCoords[0])<Mat.eps&&(straightFirst=!0),Math.abs(point2.scrCoords[0])<Mat.eps&&(straightLast=!0),(c=[])[0]=el.stdform[0]-el.stdform[1]*el.board.origin.scrCoords[1]/el.board.unitX+el.stdform[2]*el.board.origin.scrCoords[2]/el.board.unitY,c[1]=el.stdform[1]/el.board.unitX,c[2]=-el.stdform[2]/el.board.unitY,!isNaN(c[0]+c[1]+c[2])){if(takePoint1=!straightFirst,takePoint2=!straightLast,boundingBox=el.board.getBoundingBox(),el.getSlope()>=0?(intersect1=this.projectPointToLine({coords:{usrCoords:[1,boundingBox[2],boundingBox[1]]}},el,el.board),intersect2=this.projectPointToLine({coords:{usrCoords:[1,boundingBox[0],boundingBox[3]]}},el,el.board)):(intersect1=this.projectPointToLine({coords:{usrCoords:[1,boundingBox[0],boundingBox[1]]}},el,el.board),intersect2=this.projectPointToLine({coords:{usrCoords:[1,boundingBox[2],boundingBox[3]]}},el,el.board)),!takePoint1&&!takePoint2){if(!straightFirst&&!straightLast){if(distP1P2=point1.distance(Const.COORDS_BY_USER,point2),Math.abs(point1.distance(Const.COORDS_BY_USER,intersect1)+intersect1.distance(Const.COORDS_BY_USER,point2)-distP1P2)>Mat.eps)return;if(Math.abs(point1.distance(Const.COORDS_BY_USER,intersect2)+intersect2.distance(Const.COORDS_BY_USER,point2)-distP1P2)>Mat.eps)return}if(!straightFirst&&straightLast&&!this.isSameDirection(point1,point2,intersect1)&&!this.isSameDirection(point1,point2,intersect2))return;if(straightFirst&&!straightLast&&!this.isSameDirection(point2,point1,intersect1)&&!this.isSameDirection(point2,point1,intersect2))return}takePoint1?takePoint2||(p2=this.isSameDir(point1,point2,intersect1,intersect2)?intersect2:intersect1):takePoint2?p1=this.isSameDir(point1,point2,intersect1,intersect2)?intersect1:intersect2:this.isSameDir(point1,point2,intersect1,intersect2)?(p1=intersect1,p2=intersect2):(p2=intersect1,p1=intersect2),p1&&point1.setCoordinates(Const.COORDS_BY_USER,p1.usrCoords),p2&&point2.setCoordinates(Const.COORDS_BY_USER,p2.usrCoords)}},calcLabelQuadrant:function(angle){return angle<0&&(angle+=2*Math.PI),["rt","urt","top","ulft","lft","llft","lrt"][Math.floor((angle+Math.PI/8)/(Math.PI/4))%8]},isSameDir:function(p1,p2,i1,i2){var dpx=p2.usrCoords[1]-p1.usrCoords[1],dpy=p2.usrCoords[2]-p1.usrCoords[2],dix=i2.usrCoords[1]-i1.usrCoords[1],diy=i2.usrCoords[2]-i1.usrCoords[2];return Math.abs(p2.usrCoords[0])<Mat.eps&&(dpx=p2.usrCoords[1],dpy=p2.usrCoords[2]),Math.abs(p1.usrCoords[0])<Mat.eps&&(dpx=-p1.usrCoords[1],dpy=-p1.usrCoords[2]),dpx*dix+dpy*diy>=0},isSameDirection:function(start,p,s){var dx,dy,sx,sy,r=!1;return dx=p.usrCoords[1]-start.usrCoords[1],dy=p.usrCoords[2]-start.usrCoords[2],sx=s.usrCoords[1]-start.usrCoords[1],sy=s.usrCoords[2]-start.usrCoords[2],Math.abs(dx)<Mat.eps&&(dx=0),Math.abs(dy)<Mat.eps&&(dy=0),Math.abs(sx)<Mat.eps&&(sx=0),Math.abs(sy)<Mat.eps&&(sy=0),(dx>=0&&sx>=0||dx<=0&&sx<=0)&&(r=dy>=0&&sy>=0||dy<=0&&sy<=0),r},intersectionFunction:function(board,el1,el2,i,j,alwaysintersect){var el1_isArcType,el2_isArcType,that=this;return el1_isArcType=el1.elementClass===Const.OBJECT_CLASS_CURVE&&(el1.type===Const.OBJECT_TYPE_ARC||el1.type===Const.OBJECT_TYPE_SECTOR),el2_isArcType=el2.elementClass===Const.OBJECT_CLASS_CURVE&&(el2.type===Const.OBJECT_TYPE_ARC||el2.type===Const.OBJECT_TYPE_SECTOR),el1.elementClass!==Const.OBJECT_CLASS_CURVE&&el2.elementClass!==Const.OBJECT_CLASS_CURVE||el1.elementClass!==Const.OBJECT_CLASS_CURVE&&el1.elementClass!==Const.OBJECT_CLASS_CIRCLE||el2.elementClass!==Const.OBJECT_CLASS_CURVE&&el2.elementClass!==Const.OBJECT_CLASS_CIRCLE?el1.elementClass===Const.OBJECT_CLASS_CURVE&&!el1_isArcType&&el2.elementClass===Const.OBJECT_CLASS_LINE||el2.elementClass===Const.OBJECT_CLASS_CURVE&&!el2_isArcType&&el1.elementClass===Const.OBJECT_CLASS_LINE?function(){return that.meetCurveLine(el1,el2,i,el1.board,alwaysintersect)}:el1.type===Const.OBJECT_TYPE_POLYGON||el2.type===Const.OBJECT_TYPE_POLYGON?el1.elementClass===Const.OBJECT_CLASS_LINE?function(){return that.meetPolygonLine(el2,el1,i,el1.board,alwaysintersect)}:el2.elementClass===Const.OBJECT_CLASS_LINE?function(){return that.meetPolygonLine(el1,el2,i,el1.board,alwaysintersect)}:function(){return that.meetPathPath(el1,el2,i,el1.board)}:el1.elementClass===Const.OBJECT_CLASS_LINE&&el2.elementClass===Const.OBJECT_CLASS_LINE?function(){var res,c,first1=Type.evaluate(el1.visProp.straightfirst),last1=Type.evaluate(el1.visProp.straightlast),first2=Type.evaluate(el2.visProp.straightfirst),last2=Type.evaluate(el2.visProp.straightlast);return Type.evaluate(alwaysintersect)||first1&&last1&&first2&&last2?that.meet(el1.stdform,el2.stdform,i,el1.board):(res=that.meetSegmentSegment(el1.point1.coords.usrCoords,el1.point2.coords.usrCoords,el2.point1.coords.usrCoords,el2.point2.coords.usrCoords),c=!first1&&res[1]<0||!last1&&res[1]>1||!first2&&res[2]<0||!last2&&res[2]>1?[0,NaN,NaN]:res[0],new Coords(Const.COORDS_BY_USER,c,el1.board))}:function(){var first,last,r,res=that.meet(el1.stdform,el2.stdform,i,el1.board),has=!0;return alwaysintersect?res:(el1.elementClass!==Const.OBJECT_CLASS_LINE||(first=Type.evaluate(el1.visProp.straightfirst),last=Type.evaluate(el1.visProp.straightlast),first&&last||(r=that.affineRatio(el1.point1.coords,el1.point2.coords,res),!(!last&&r>1+Mat.eps||!first&&r<0-Mat.eps))))&&(el2.elementClass!==Const.OBJECT_CLASS_LINE||(first=Type.evaluate(el2.visProp.straightfirst),last=Type.evaluate(el2.visProp.straightlast),first&&last||(r=that.affineRatio(el2.point1.coords,el2.point2.coords,res),!(!last&&r>1+Mat.eps||!first&&r<0-Mat.eps))))?el1_isArcType&&((has=that.coordsOnArc(el1,res))&&el2_isArcType&&(has=that.coordsOnArc(el2,res)),!has)?new Coords(JXG.COORDS_BY_USER,[0,NaN,NaN],el1.board):res:new Coords(JXG.COORDS_BY_USER,[0,NaN,NaN],el1.board)}:function(){return that.meetCurveCurve(el1,el2,i,j,el1.board)}},coordsOnArc:function(arc,coords){var angle=this.rad(arc.radiuspoint,arc.center,coords.usrCoords.slice(1)),alpha=0,beta=this.rad(arc.radiuspoint,arc.center,arc.anglepoint),ev_s=Type.evaluate(arc.visProp.selection);return("minor"===ev_s&&beta>Math.PI||"major"===ev_s&&beta<Math.PI)&&(alpha=beta,beta=2*Math.PI),!(angle<alpha||angle>beta)},meet:function(el1,el2,i,board){var eps=Mat.eps;return Math.abs(el1[3])<eps&&Math.abs(el2[3])<eps?this.meetLineLine(el1,el2,i,board):Math.abs(el1[3])>=eps&&Math.abs(el2[3])<eps?this.meetLineCircle(el2,el1,i,board):Math.abs(el1[3])<eps&&Math.abs(el2[3])>=eps?this.meetLineCircle(el1,el2,i,board):this.meetCircleCircle(el1,el2,i,board)},meetLineBoard:function(line,board,margin){var intersect1,intersect2,i,j,s=[];for(Type.exists(margin)||(margin=0),s[0]=Mat.crossProduct(line,[margin,0,1]),s[1]=Mat.crossProduct(line,[margin,1,0]),s[2]=Mat.crossProduct(line,[-margin-board.canvasHeight,0,1]),s[3]=Mat.crossProduct(line,[-margin-board.canvasWidth,1,0]),i=0;i<4;i++)if(Math.abs(s[i][0])>Mat.eps){for(j=2;j>0;j--)s[i][j]/=s[i][0];s[i][0]=1}return Math.abs(s[1][0])<Mat.eps?(intersect1=s[0],intersect2=s[2]):Math.abs(s[0][0])<Mat.eps?(intersect1=s[1],intersect2=s[3]):s[1][2]<0?(intersect1=s[0],intersect2=s[3][2]>board.canvasHeight?s[2]:s[3]):s[1][2]>board.canvasHeight?(intersect1=s[2],intersect2=s[3][2]<0?s[0]:s[3]):(intersect1=s[1],intersect2=s[3][2]<0?s[0]:s[3][2]>board.canvasHeight?s[2]:s[3]),[intersect1=new Coords(Const.COORDS_BY_SCREEN,intersect1.slice(1),board),intersect2=new Coords(Const.COORDS_BY_SCREEN,intersect2.slice(1),board)]},meetLineLine:function(l1,l2,i,board){var s=isNaN(l1[5]+l2[5])?[0,0,0]:Mat.crossProduct(l1,l2);return new Coords(Const.COORDS_BY_USER,s,board)},meetLineCircle:function(lin,circ,i,board){var a,b,c,d,n,A,B,k,t;return circ[4]<Mat.eps?Math.abs(Mat.innerProduct([1,circ[6],circ[7]],lin,3))<Mat.eps?new Coords(Const.COORDS_BY_USER,circ.slice(6,8),board):new Coords(Const.COORDS_BY_USER,[NaN,NaN],board):(c=circ[0],b=circ.slice(1,3),a=circ[3],d=lin[0],n=lin.slice(1,3),A=a,(k=(B=b[0]*n[1]-b[1]*n[0])*B-4*A*(a*d*d-(b[0]*n[0]+b[1]*n[1])*d+c))>-Mat.eps*Mat.eps?(t=[(-B+(k=Math.sqrt(Math.abs(k))))/(2*A),(-B-k)/(2*A)],new Coords(Const.COORDS_BY_USER,0===i?[-t[0]*-n[1]-d*n[0],-t[0]*n[0]-d*n[1]]:[-t[1]*-n[1]-d*n[0],-t[1]*n[0]-d*n[1]],board)):new Coords(Const.COORDS_BY_USER,[0,0,0],board))},meetCircleCircle:function(circ1,circ2,i,board){var radicalAxis;return circ1[4]<Mat.eps?Math.abs(this.distance(circ1.slice(6,2),circ2.slice(6,8))-circ2[4])<Mat.eps?new Coords(Const.COORDS_BY_USER,circ1.slice(6,8),board):new Coords(Const.COORDS_BY_USER,[0,0,0],board):circ2[4]<Mat.eps?Math.abs(this.distance(circ2.slice(6,2),circ1.slice(6,8))-circ1[4])<Mat.eps?new Coords(Const.COORDS_BY_USER,circ2.slice(6,8),board):new Coords(Const.COORDS_BY_USER,[0,0,0],board):(radicalAxis=[circ2[3]*circ1[0]-circ1[3]*circ2[0],circ2[3]*circ1[1]-circ1[3]*circ2[1],circ2[3]*circ1[2]-circ1[3]*circ2[2],0,1,1/0,1/0,1/0],radicalAxis=Mat.normalize(radicalAxis),this.meetLineCircle(radicalAxis,circ1,i,board))},meetCurveCurve:function(c1,c2,nr,t2ini,board,method){var co;return co=Type.exists(method)&&"newton"===method?Numerics.generalizedNewton(c1,c2,nr,t2ini):3===c1.bezierDegree||3===c2.bezierDegree?this.meetBezierCurveRedBlueSegments(c1,c2,nr):this.meetCurveRedBlueSegments(c1,c2,nr),new Coords(Const.COORDS_BY_USER,co,board)},meetCurveLine:function(el1,el2,nr,board,alwaysIntersect){var cu,li;return Type.exists(board)||(board=el1.board),el1.elementClass===Const.OBJECT_CLASS_CURVE?(cu=el1,li=el2):(cu=el2,li=el1),this.meetCurveLineDiscrete(cu,li,nr,board,!alwaysIntersect)},meetCurveLineContinuous:function(cu,li,nr,board,testSegment){var t,func0,func1,v,x,y,z,delta,tnew,i,tmin,fmin,ft,eps=Mat.eps,epsLow=Mat.eps;for(v=this.meetCurveLineDiscrete(cu,li,nr,board,testSegment),x=v.usrCoords[1],y=v.usrCoords[2],func0=function(t){var c1,c2;return t>cu.maxX()||t<cu.minX()?1/0:(c1=x-cu.X(t))*c1+(c2=y-cu.Y(t))*c2},func1=function(t){var v=li.stdform[0]+li.stdform[1]*cu.X(t)+li.stdform[2]*cu.Y(t);return v*v},50,delta=(cu.maxX()-cu.minX())/50,tnew=cu.minX(),fmin=1e-4,tmin=NaN,i=0;i<50&&(t=Numerics.root(func0,[Math.max(tnew,cu.minX()),Math.min(tnew+delta,cu.maxX())]),!((ft=Math.abs(func0(t)))<=fmin&&(tmin=t,(fmin=ft)<eps)));i++)tnew+=delta;return t=tmin,ft=func1(t=Numerics.root(func1,[Math.max(t-delta,cu.minX()),Math.min(t+delta,cu.maxX())])),z=isNaN(ft)||Math.abs(ft)>epsLow?0:1,new Coords(Const.COORDS_BY_USER,[z,cu.X(t),cu.Y(t)],board)},meetCurveLineDiscrete:function(cu,li,nr,board,testSegment){var i,j,p1,p2,p,q,res,lip1=li.point1.coords.usrCoords,lip2=li.point2.coords.usrCoords,cnt=0,len=cu.numberPoints,ev_sf=Type.evaluate(li.visProp.straightfirst),ev_sl=Type.evaluate(li.visProp.straightlast);for(q=new Coords(Const.COORDS_BY_USER,[0,NaN,NaN],board),0===lip1[0]?lip1=[1,lip2[1]+li.stdform[2],lip2[2]-li.stdform[1]]:0===lip2[0]&&(lip2=[1,lip1[1]+li.stdform[2],lip1[2]-li.stdform[1]]),p2=cu.points[0].usrCoords,i=1;i<len;i+=cu.bezierDegree)if(p1=p2.slice(0),p2=cu.points[i].usrCoords,this.distance(p1,p2)>Mat.eps)for(res=3===cu.bezierDegree?this.meetBeziersegmentBeziersegment([cu.points[i-1].usrCoords.slice(1),cu.points[i].usrCoords.slice(1),cu.points[i+1].usrCoords.slice(1),cu.points[i+2].usrCoords.slice(1)],[lip1.slice(1),lip2.slice(1)],testSegment):[this.meetSegmentSegment(p1,p2,lip1,lip2)],j=0;j<res.length;j++)if(0<=(p=res[j])[1]&&p[1]<=1){if(cnt===nr)return testSegment&&(!ev_sf&&p[2]<0||!ev_sl&&p[2]>1)?q:q=new Coords(Const.COORDS_BY_USER,p[0],board);cnt+=1}return q},meetCurveRedBlueSegments:function(red,blue,nr){var i,j,red1,red2,blue1,blue2,m,minX,maxX,iFound=0,lenBlue=blue.numberPoints,lenRed=red.numberPoints;if(lenBlue<=1||lenRed<=1)return[0,NaN,NaN];for(i=1;i<lenRed;i++)for(red1=red.points[i-1].usrCoords,red2=red.points[i].usrCoords,minX=Math.min(red1[1],red2[1]),maxX=Math.max(red1[1],red2[1]),blue2=blue.points[0].usrCoords,j=1;j<lenBlue;j++)if(blue1=blue2,blue2=blue.points[j].usrCoords,Math.min(blue1[1],blue2[1])<maxX&&Math.max(blue1[1],blue2[1])>minX&&(m=this.meetSegmentSegment(red1,red2,blue1,blue2))[1]>=0&&m[2]>=0&&(m[1]<1&&m[2]<1||i===lenRed-1&&1===m[1]||j===lenBlue-1&&1===m[2])){if(iFound===nr)return m[0];iFound++}return[0,NaN,NaN]},meetSegmentSegment:function(p1,p2,q1,q2){var t,i,d,li1=Mat.crossProduct(p1,p2),li2=Mat.crossProduct(q1,q2),c=Mat.crossProduct(li1,li2);return Math.abs(c[0])<Mat.eps?[c,1/0,1/0]:(c[1]/=c[0],c[2]/=c[0],c[0]/=c[0],d=p1[i=Math.abs(p2[1]-p2[0]*p1[1])<Mat.eps?2:1]/p1[0],t=(c[i]-d)/(0!==p2[0]?p2[i]/p2[0]-d:p2[i]),d=q1[i=Math.abs(q2[1]-q2[0]*q1[1])<Mat.eps?2:1]/q1[0],[c,t,(c[i]-d)/(0!==q2[0]?q2[i]/q2[0]-d:q2[i])])},meetPathPath:function(path1,path2,nr,board){var S,C,len,intersections;return(len=(S=JXG.Math.Clip._getPath(path1,board)).length)>0&&this.distance(S[0].coords.usrCoords,S[len-1].coords.usrCoords,3)<Mat.eps&&S.pop(),(len=(C=JXG.Math.Clip._getPath(path2,board)).length)>0&&this.distance(C[0].coords.usrCoords,C[len-1].coords.usrCoords,3)<Mat.eps*Mat.eps&&C.pop(),nr<0||JXG.Math.Clip.isEmptyCase(S,C,"intersection")?new Coords(Const.COORDS_BY_USER,[0,0,0],board):(JXG.Math.Clip.makeDoublyLinkedList(S),JXG.Math.Clip.makeDoublyLinkedList(C),nr<(intersections=JXG.Math.Clip.findIntersections(S,C,board)[0]).length?intersections[nr].coords:new Coords(Const.COORDS_BY_USER,[0,0,0],board))},meetPolygonLine:function(path,line,nr,board,alwaysIntersect){var i,res,border,crds=[0,0,0],len=path.borders.length,intersections=[];for(i=0;i<len;i++)border=path.borders[i],res=this.meetSegmentSegment(border.point1.coords.usrCoords,border.point2.coords.usrCoords,line.point1.coords.usrCoords,line.point2.coords.usrCoords),(!alwaysIntersect||res[2]>=0&&res[2]<1)&&res[1]>=0&&res[1]<1&&intersections.push(res[0]);return nr>=0&&nr<intersections.length&&(crds=intersections[nr]),new Coords(Const.COORDS_BY_USER,crds,board)},_bezierSplit:function(curve){var p0,p1,p2,p00,p22,p000;return p0=[.5*(curve[0][0]+curve[1][0]),.5*(curve[0][1]+curve[1][1])],p1=[.5*(curve[1][0]+curve[2][0]),.5*(curve[1][1]+curve[2][1])],p2=[.5*(curve[2][0]+curve[3][0]),.5*(curve[2][1]+curve[3][1])],p000=[.5*((p00=[.5*(p0[0]+p1[0]),.5*(p0[1]+p1[1])])[0]+(p22=[.5*(p1[0]+p2[0]),.5*(p1[1]+p2[1])])[0]),.5*(p00[1]+p22[1])],[[curve[0],p0,p00,p000],[p000,p22,p2,curve[3]]]},_bezierBbox:function(curve){var bb=[];return 4===curve.length?(bb[0]=Math.min(curve[0][0],curve[1][0],curve[2][0],curve[3][0]),bb[1]=Math.max(curve[0][1],curve[1][1],curve[2][1],curve[3][1]),bb[2]=Math.max(curve[0][0],curve[1][0],curve[2][0],curve[3][0]),bb[3]=Math.min(curve[0][1],curve[1][1],curve[2][1],curve[3][1])):(bb[0]=Math.min(curve[0][0],curve[1][0]),bb[1]=Math.max(curve[0][1],curve[1][1]),bb[2]=Math.max(curve[0][0],curve[1][0]),bb[3]=Math.min(curve[0][1],curve[1][1])),bb},_bezierOverlap:function(bb1,bb2){return bb1[2]>=bb2[0]&&bb1[0]<=bb2[2]&&bb1[1]>=bb2[3]&&bb1[3]<=bb2[1]},_bezierListConcat:function(L,Lnew,t1,t2){var i,t2exists=Type.exists(t2),start=0,len=Lnew.length,le=L.length;for(le>0&&len>0&&(1===L[le-1][1]&&0===Lnew[0][1]||t2exists&&1===L[le-1][2]&&0===Lnew[0][2])&&(start=1),i=start;i<len;i++)t2exists&&(Lnew[i][2]*=.5,Lnew[i][2]+=t2),Lnew[i][1]*=.5,Lnew[i][1]+=t1,L.push(Lnew[i])},_bezierMeetSubdivision:function(red,blue,level){var bbb,bbr,ar,b0,b1,r0,r1,m,p0,p1,q0,q1,L=[];return bbr=this._bezierBbox(blue),bbb=this._bezierBbox(red),this._bezierOverlap(bbr,bbb)?level<5?(r0=(ar=this._bezierSplit(red))[0],r1=ar[1],b0=(ar=this._bezierSplit(blue))[0],b1=ar[1],this._bezierListConcat(L,this._bezierMeetSubdivision(r0,b0,level+1),0,0),this._bezierListConcat(L,this._bezierMeetSubdivision(r0,b1,level+1),0,.5),this._bezierListConcat(L,this._bezierMeetSubdivision(r1,b0,level+1),.5,0),this._bezierListConcat(L,this._bezierMeetSubdivision(r1,b1,level+1),.5,.5),L):(q0=[1].concat(red[0]),q1=[1].concat(red[3]),p0=[1].concat(blue[0]),p1=[1].concat(blue[3]),(m=this.meetSegmentSegment(q0,q1,p0,p1))[1]>=0&&m[2]>=0&&m[1]<=1&&m[2]<=1?[m]:[]):[]},_bezierLineMeetSubdivision:function(red,blue,level,testSegment){var bbb,bbr,ar,r0,r1,m,p0,p1,q0,q1,L=[];return bbb=this._bezierBbox(blue),bbr=this._bezierBbox(red),testSegment&&!this._bezierOverlap(bbr,bbb)?[]:level<5?(r0=(ar=this._bezierSplit(red))[0],r1=ar[1],this._bezierListConcat(L,this._bezierLineMeetSubdivision(r0,blue,level+1),0),this._bezierListConcat(L,this._bezierLineMeetSubdivision(r1,blue,level+1),.5),L):(q0=[1].concat(red[0]),q1=[1].concat(red[3]),p0=[1].concat(blue[0]),p1=[1].concat(blue[1]),(m=this.meetSegmentSegment(q0,q1,p0,p1))[1]>=0&&m[1]<=1&&(!testSegment||m[2]>=0&&m[2]<=1)?[m]:[])},meetBeziersegmentBeziersegment:function(red,blue,testSegment){var L,L2,i;for((L=4===red.length&&4===blue.length?this._bezierMeetSubdivision(red,blue,0):this._bezierLineMeetSubdivision(red,blue,0,testSegment)).sort((function(a,b){return 1e7*(a[1]-b[1])+(a[2]-b[2])})),L2=[],i=0;i<L.length;i++)0!==i&&L[i][1]===L[i-1][1]&&L[i][2]===L[i-1][2]||L2.push(L[i]);return L2},meetBezierCurveRedBlueSegments:function(red,blue,nr){var p,i,j,k,po,redArr,blueArr,bbr,bbb,intersections,startRed=0,startBlue=0,lenBlue=blue.numberPoints,lenRed=red.numberPoints,L=[];if(lenBlue<blue.bezierDegree+1||lenRed<red.bezierDegree+1)return[0,NaN,NaN];for(lenBlue-=blue.bezierDegree,lenRed-=red.bezierDegree,red.type===Const.OBJECT_TYPE_SECTOR&&(startRed=3,lenRed-=3),blue.type===Const.OBJECT_TYPE_SECTOR&&(startBlue=3,lenBlue-=3),i=startRed;i<lenRed;i+=red.bezierDegree)for(redArr=[(p=red.points)[i].usrCoords.slice(1),p[i+1].usrCoords.slice(1)],3===red.bezierDegree&&(redArr[2]=p[i+2].usrCoords.slice(1),redArr[3]=p[i+3].usrCoords.slice(1)),bbr=this._bezierBbox(redArr),j=startBlue;j<lenBlue;j+=blue.bezierDegree)if(blueArr=[(p=blue.points)[j].usrCoords.slice(1),p[j+1].usrCoords.slice(1)],3===blue.bezierDegree&&(blueArr[2]=p[j+2].usrCoords.slice(1),blueArr[3]=p[j+3].usrCoords.slice(1)),bbb=this._bezierBbox(blueArr),this._bezierOverlap(bbr,bbb)){if(0===(intersections=this.meetBeziersegmentBeziersegment(redArr,blueArr)).length)continue;for(k=0;k<intersections.length;k++)(po=intersections[k])[1]<-Mat.eps||po[1]>1+Mat.eps||po[2]<-Mat.eps||po[2]>1+Mat.eps||L.push(po);if(L.length>nr)return L[nr][0]}return L.length>nr?L[nr][0]:[0,NaN,NaN]},bezierSegmentEval:function(t,curve){var f,x,y,t1=1-t;return x=0,y=0,x+=(f=t1*t1*t1)*curve[0][0],y+=f*curve[0][1],x+=(f=3*t*t1*t1)*curve[1][0],y+=f*curve[1][1],x+=(f=3*t*t*t1)*curve[2][0],y+=f*curve[2][1],[1,x+=(f=t*t*t)*curve[3][0],y+=f*curve[3][1]]},bezierArc:function(A,B,C,withLegs,sgn){var p1,p2,p3,p4,r,phi,beta,co,si,ax,ay,bx,by,k,v,d,matrix,PI2=.5*Math.PI,x=B[1],y=B[2],z=B[0],dataX=[],dataY=[];for(r=this.distance(B,A),x/=z,y/=z,phi=this.rad(A.slice(1),B.slice(1),C.slice(1)),-1===sgn&&(phi=2*Math.PI-phi),(p1=A)[1]/=p1[0],p1[2]/=p1[0],p1[0]/=p1[0],p4=p1.slice(0),withLegs?(dataX=[x,x+.333*(p1[1]-x),x+.666*(p1[1]-x),p1[1]],dataY=[y,y+.333*(p1[2]-y),y+.666*(p1[2]-y),p1[2]]):(dataX=[p1[1]],dataY=[p1[2]]);phi>Mat.eps;)phi>PI2?(beta=PI2,phi-=PI2):(beta=phi,phi=0),matrix=[[1,0,0],[x*(1-(co=Math.cos(sgn*beta)))+y*(si=Math.sin(sgn*beta)),co,-si],[y*(1-co)-x*si,si,co]],p4=[(v=Mat.matVecMult(matrix,p1))[0]/v[0],v[1]/v[0],v[2]/v[0]],ax=p1[1]-x,ay=p1[2]-y,bx=p4[1]-x,by=p4[2]-y,d=Math.sqrt((ax+bx)*(ax+bx)+(ay+by)*(ay+by)),k=Math.abs(by-ay)>Mat.eps?(ax+bx)*(r/d-.5)/(by-ay)*8/3:(ay+by)*(r/d-.5)/(ax-bx)*8/3,p2=[1,p1[1]-k*ay,p1[2]+k*ax],p3=[1,p4[1]+k*by,p4[2]-k*bx],dataX=dataX.concat([p2[1],p3[1],p4[1]]),dataY=dataY.concat([p2[2],p3[2],p4[2]]),p1=p4.slice(0);return withLegs&&(dataX=dataX.concat([p4[1]+.333*(x-p4[1]),p4[1]+.666*(x-p4[1]),x]),dataY=dataY.concat([p4[2]+.333*(y-p4[2]),p4[2]+.666*(y-p4[2]),y])),[dataX,dataY]},projectPointToCircle:function(point,circle,board){var dist,P,x,y,factor,M=circle.center.coords.usrCoords;return Type.exists(board)||(board=point.board),Type.isPoint(point)?(dist=point.coords.distance(Const.COORDS_BY_USER,circle.center.coords),P=point.coords.usrCoords):(dist=point.distance(Const.COORDS_BY_USER,circle.center.coords),P=point.usrCoords),Math.abs(dist)<Mat.eps&&(dist=Mat.eps),factor=circle.Radius()/dist,x=M[1]+factor*(P[1]-M[1]),y=M[2]+factor*(P[2]-M[2]),new Coords(Const.COORDS_BY_USER,[x,y],board)},projectPointToLine:function(point,line,board){var coords,v=[0,line.stdform[1],line.stdform[2]];return Type.exists(board)||(board=Type.exists(point.coords)?point.board:line.board),coords=Type.exists(point.coords)?point.coords.usrCoords:point.usrCoords,v=Mat.crossProduct(v,coords),new Coords(Const.COORDS_BY_USER,Mat.crossProduct(v,line.stdform),board)},projectCoordsToSegment:function(p,q1,q2){var t,s=[q2[1]-q1[1],q2[2]-q1[2]],v=[p[1]-q1[1],p[2]-q1[2]];return Math.abs(s[0])<Mat.eps&&Math.abs(s[1])<Mat.eps?[q1,0]:(t=Mat.innerProduct(v,s),[[1,(t/=Mat.innerProduct(s,s))*s[0]+q1[1],t*s[1]+q1[2]],t])},projectCoordsToBeziersegment:function(pos,curve,start){var t0;return t0=JXG.Math.Numerics.fminbr((function(t){var z=[1,curve.X(start+t),curve.Y(start+t)];return z[1]-=pos[1],z[2]-=pos[2],z[1]*z[1]+z[2]*z[2]}),[0,1]),[[1,curve.X(t0+start),curve.Y(t0+start)],t0]},projectPointToCurve:function(point,curve,board){Type.exists(board)||(board=point.board);var x=point.X(),y=point.Y(),t=point.position||0;return this.projectCoordsToCurve(x,y,t,curve,board)},projectCoordsToCurve:function(x,y,t,curve,board){var newCoords,newCoordsObj,i,j,mindist,dist,lbda,v,coords,d,p1,p2,res,minfunc,t_new,f_new,f_old,delta,minX,maxX,infty=Number.POSITIVE_INFINITY;if(Type.exists(board)||(board=curve.board),"plot"===Type.evaluate(curve.visProp.curvetype)){if(t=0,mindist=infty,newCoords=0===curve.numberPoints?[0,1,1]:[curve.Z(0),curve.X(0),curve.Y(0)],curve.numberPoints>1)for(v=[1,x,y],3===curve.bezierDegree?j=0:p1=[curve.Z(0),curve.X(0),curve.Y(0)],i=0;i<curve.numberPoints-1;i++)3===curve.bezierDegree?res=this.projectCoordsToBeziersegment(v,curve,j):(p2=[curve.Z(i+1),curve.X(i+1),curve.Y(i+1)],res=this.projectCoordsToSegment(v,p1,p2)),lbda=res[1],coords=res[0],0<=lbda&&lbda<=1?(dist=this.distance(coords,v),d=i+lbda):lbda<0?(coords=p1,dist=this.distance(p1,v),d=i):lbda>1&&i===curve.numberPoints-2&&(coords=p2,dist=this.distance(coords,v),d=curve.numberPoints-1),dist<mindist&&(mindist=dist,t=d,newCoords=coords),3===curve.bezierDegree?(j++,i+=2):p1=p2;newCoordsObj=new Coords(Const.COORDS_BY_USER,newCoords,board)}else{for(minfunc=function(t){var dx,dy;return t<curve.minX()||t>curve.maxX()?1/0:(dx=x-curve.X(t))*dx+(dy=y-curve.Y(t))*dy},f_old=minfunc(t),50,minX=curve.minX(),delta=((maxX=curve.maxX())-minX)/50,t_new=minX,i=0;i<50;i++)((f_new=minfunc(t_new))<f_old||f_old===1/0)&&(t=t_new,f_old=f_new),t_new+=delta;t=(t=(t=Numerics.fminbr(minfunc,[Math.max(t-delta,minX),Math.min(t+delta,maxX)]))<minX?minX:t)>maxX?maxX:t,newCoordsObj=new Coords(Const.COORDS_BY_USER,[curve.X(t),curve.Y(t)],board)}return[curve.updateTransform(newCoordsObj),t]},projectCoordsToPolygon:function(p,pol){var i,d,projection,proj,bestprojection,len=pol.vertices.length,d_best=1/0;for(i=0;i<len-1;i++)0<=(projection=JXG.Math.Geometry.projectCoordsToSegment(p,pol.vertices[i].coords.usrCoords,pol.vertices[i+1].coords.usrCoords))[1]&&projection[1]<=1?(d=JXG.Math.Geometry.distance(projection[0],p,3),proj=projection[0]):projection[1]<0?(d=JXG.Math.Geometry.distance(pol.vertices[i].coords.usrCoords,p,3),proj=pol.vertices[i].coords.usrCoords):(d=JXG.Math.Geometry.distance(pol.vertices[i+1].coords.usrCoords,p,3),proj=pol.vertices[i+1].coords.usrCoords),d<d_best&&(bestprojection=proj.slice(0),d_best=d);return bestprojection},projectPointToTurtle:function(point,turtle,board){var newCoords,t,x,y,i,dist,el,minEl,res,newPos,np=0,npmin=0,mindist=Number.POSITIVE_INFINITY,len=turtle.objects.length;for(Type.exists(board)||(board=point.board),i=0;i<len;i++)(el=turtle.objects[i]).elementClass===Const.OBJECT_CLASS_CURVE&&(newCoords=(res=this.projectPointToCurve(point,el))[0],newPos=res[1],(dist=this.distance(newCoords.usrCoords,point.coords.usrCoords))<mindist&&(x=newCoords.usrCoords[1],y=newCoords.usrCoords[2],t=newPos,mindist=dist,minEl=el,npmin=np),np+=el.numberPoints);return newCoords=new Coords(Const.COORDS_BY_USER,[x,y],board),[minEl.updateTransform(newCoords),t+npmin]},projectPointToPoint:function(point,dest){return dest.coords},projectPointToBoard:function(point,board){var i,l,c,brd=board||point.board,config=[[1,1,0,0,3,0,1],[-1,2,1,0,1,2,1],[-1,1,2,2,1,2,3],[1,2,3,0,3,2,3]],coords=point.coords||point,bbox=brd.getBoundingBox();for(i=0;i<4;i++)(c=config[i])[0]*coords.usrCoords[c[1]]<c[0]*bbox[c[2]]&&((l=Mat.crossProduct([1,bbox[c[3]],bbox[c[4]]],[1,bbox[c[5]],bbox[c[6]]]))[3]=0,l=Mat.normalize(l),coords=this.projectPointToLine({coords:coords},{stdform:l},brd));return coords},distPointLine:function(point,line){var nom,a=line[1],b=line[2],c=line[0];return Math.abs(a)+Math.abs(b)<Mat.eps?Number.POSITIVE_INFINITY:(nom=a*point[1]+b*point[2]+c,a*=a,b*=b,Math.abs(nom)/Math.sqrt(a+b))},reuleauxPolygon:function(points,nr){var beta,pi2=2*Math.PI,pi2_n=pi2/nr,diag=(nr-1)/2,d=0,makeFct=function(which,trig){return function(t,suspendUpdate){var t1=(t%pi2+pi2)%pi2,j=Math.floor(t1/pi2_n)%nr;return suspendUpdate||(d=points[0].Dist(points[diag]),beta=Mat.Geometry.rad([points[0].X()+1,points[0].Y()],points[0],points[diag%nr])),isNaN(j)?j:(t1=.5*t1+j*pi2_n*.5+beta,points[j][which]()+d*Math[trig](t1))}};return[makeFct("X","cos"),makeFct("Y","sin"),0,pi2]},meet3Planes:function(n1,d1,n2,d2,n3,d3){var n31,n12,n23,denom,i,p=[0,0,0];for(n31=Mat.crossProduct(n3,n1),n12=Mat.crossProduct(n1,n2),n23=Mat.crossProduct(n2,n3),denom=Mat.innerProduct(n1,n23,3),i=0;i<3;i++)p[i]=(d1*n23[i]+d2*n31[i]+d3*n12[i])/denom;return p},meetPlanePlane:function(v11,v12,v21,v22){var i,no1,no2,v=[0,0,0],w=[0,0,0];for(i=0;i<3;i++)v[i]=Type.evaluate(v11[i]),w[i]=Type.evaluate(v12[i]);for(no1=Mat.crossProduct(v,w),i=0;i<3;i++)v[i]=Type.evaluate(v21[i]),w[i]=Type.evaluate(v22[i]);return no2=Mat.crossProduct(v,w),Mat.crossProduct(no1,no2)},project3DTo3DPlane:function(point,normal,foot){var le,lbda;return foot=foot||[0,0,0],le=Mat.norm(normal),lbda=(Mat.innerProduct(point,normal,3)-Mat.innerProduct(foot,normal,3))/le,Mat.axpy(-lbda,normal,point)},getPlaneBounds:function(v1,v2,q,s,e){var s1,s2,mat,rhs,sol;return v1[2]+v2[0]!==0?(mat=[[v1[0],v2[0]],[v1[1],v2[1]]],rhs=[s-q[0],s-q[1]],s1=(sol=Numerics.Gauss(mat,rhs))[0],s2=sol[1],rhs=[e-q[0],e-q[1]],[s1,(sol=Numerics.Gauss(mat,rhs))[0],s2,sol[1]]):null}}),Mat.Geometry})),define("math/plot",["jxg","base/constants","base/coords","math/math","math/extrapolate","math/numerics","math/statistics","math/geometry","math/ia","utils/type"],(function(JXG,Const,Coords,Mat,Extrapolate,Numerics,Statistics,Geometry,IntervalArithmetic,Type){return Mat.Plot={checkReal:function(points){var i,p,b=!1,len=points.length;for(i=0;i<len;i++)if(p=points[i].usrCoords,!isNaN(p[1])&&!isNaN(p[2])&&Math.abs(p[0])>Mat.eps){b=!0;break}return b},updateParametricCurveNaive:function(curve,mi,ma,len){var i,t,suspendUpdate=!1,stepSize=(ma-mi)/len;for(i=0;i<len;i++)t=mi+i*stepSize,curve.points[i].setCoordinates(Const.COORDS_BY_USER,[curve.X(t,suspendUpdate),curve.Y(t,suspendUpdate)],!1),curve.points[i]._t=t,suspendUpdate=!0;return curve},isSegmentOutside:function(x0,y0,x1,y1,board){return y0<0&&y1<0||y0>board.canvasHeight&&y1>board.canvasHeight||x0<0&&x1<0||x0>board.canvasWidth&&x1>board.canvasWidth},isDistOK:function(dx,dy,MAXX,MAXY){return Math.abs(dx)<MAXX&&Math.abs(dy)<MAXY&&!isNaN(dx+dy)},isSegmentDefined:function(x0,y0,x1,y1){return!(isNaN(x0+y0)&&isNaN(x1+y1))},updateParametricCurveOld:function(curve,mi,ma){var i,t,x,y,x0,y0,top,depth,MAX_DEPTH,MAX_XDIST,MAX_YDIST,suspendUpdate=!1,po=new Coords(Const.COORDS_BY_USER,[0,0],curve.board,!1),dyadicStack=[],depthStack=[],pointStack=[],divisors=[],distOK=!1,j=0,distFromLine=function(p1,p2,p0){var lbda,d,x0=p0[1]-p1[1],y0=p0[2]-p1[2],x1=p2[0]-p1[1],y1=p2[1]-p1[2],den=x1*x1+y1*y1;return den>=Mat.eps&&(lbda=(x0*x1+y0*y1)/den)>0&&(lbda<=1?(x0-=lbda*x1,y0-=lbda*y1):(x0-=x1,y0-=y1)),d=x0*x0+y0*y0,Math.sqrt(d)};for(JXG.deprecated("Curve.updateParametricCurveOld()"),curve.board.updateQuality===curve.board.BOARD_QUALITY_LOW?(MAX_DEPTH=15,MAX_XDIST=10,MAX_YDIST=10):(MAX_DEPTH=21,MAX_XDIST=.7,MAX_YDIST=.7),divisors[0]=ma-mi,i=1;i<MAX_DEPTH;i++)divisors[i]=.5*divisors[i-1];i=1,dyadicStack[0]=1,depthStack[0]=0,t=mi,po.setCoordinates(Const.COORDS_BY_USER,[curve.X(t,suspendUpdate),curve.Y(t,suspendUpdate)],!1),suspendUpdate=!0,x0=po.scrCoords[1],y0=po.scrCoords[2],t=ma,po.setCoordinates(Const.COORDS_BY_USER,[curve.X(t,suspendUpdate),curve.Y(t,suspendUpdate)],!1),x=po.scrCoords[1],y=po.scrCoords[2],pointStack[0]=[x,y],top=1,depth=0,curve.points=[],curve.points[j++]=new Coords(Const.COORDS_BY_SCREEN,[x0,y0],curve.board,!1);do{for(distOK=this.isDistOK(x-x0,y-y0,MAX_XDIST,MAX_YDIST)||this.isSegmentOutside(x0,y0,x,y,curve.board);depth<MAX_DEPTH&&(!distOK||depth<6)&&(depth<=7||this.isSegmentDefined(x0,y0,x,y));)dyadicStack[top]=i,depthStack[top]=depth,pointStack[top]=[x,y],top+=1,t=mi+(i=2*i-1)*divisors[++depth],po.setCoordinates(Const.COORDS_BY_USER,[curve.X(t,suspendUpdate),curve.Y(t,suspendUpdate)],!1,!0),x=po.scrCoords[1],y=po.scrCoords[2],distOK=this.isDistOK(x-x0,y-y0,MAX_XDIST,MAX_YDIST)||this.isSegmentOutside(x0,y0,x,y,curve.board);j>1&&distFromLine(curve.points[j-2].scrCoords,[x,y],curve.points[j-1].scrCoords)<.015&&(j-=1),curve.points[j]=new Coords(Const.COORDS_BY_SCREEN,[x,y],curve.board,!1),curve.points[j]._t=t,j+=1,x0=x,y0=y,t,x=pointStack[top-=1][0],y=pointStack[top][1],depth=depthStack[top]+1,i=2*dyadicStack[top]}while(top>0&&j<5e5);return curve.numberPoints=curve.points.length,curve},_insertPoint_v2:function(curve,pnt,t){var lastReal=!isNaN(this._lastCrds[1]+this._lastCrds[2]),newReal=!isNaN(pnt.scrCoords[1]+pnt.scrCoords[2]),cw=curve.board.canvasWidth,ch=curve.board.canvasHeight;(!(newReal=newReal&&pnt.scrCoords[1]>-500&&pnt.scrCoords[2]>-500&&pnt.scrCoords[1]<cw+500&&pnt.scrCoords[2]<ch+500)&&lastReal||newReal&&(!lastReal||Math.abs(pnt.scrCoords[1]-this._lastCrds[1])>.7||Math.abs(pnt.scrCoords[2]-this._lastCrds[2])>.7))&&(pnt._t=t,curve.points.push(pnt),this._lastCrds=pnt.copy("scrCoords"))},neighborhood_isNaN_v2:function(curve,t0){var t,p,pnt=new Coords(Const.COORDS_BY_USER,[0,0],curve.board,!1);return t=t0+Mat.eps,pnt.setCoordinates(Const.COORDS_BY_USER,[curve.X(t,!0),curve.Y(t,!0)],!1),p=pnt.usrCoords,!!(isNaN(p[1]+p[2])||(t=t0-Mat.eps,pnt.setCoordinates(Const.COORDS_BY_USER,[curve.X(t,!0),curve.Y(t,!0)],!1),p=pnt.usrCoords,isNaN(p[1]+p[2])))},_borderCase:function(curve,a,b,c,ta,tb,tc,depth){var t,pnt,p,j,t_nan,t_real,t_real2,p_good=null,is_undef=!1;if(depth<=1){if(pnt=new Coords(Const.COORDS_BY_USER,[0,0],curve.board,!1),isNaN(a[1]+a[2])&&!isNaN(c[1]+c[2])&&!this.neighborhood_isNaN_v2(curve,ta))return!1;if(isNaN(b[1]+b[2])&&!isNaN(c[1]+c[2])&&!this.neighborhood_isNaN_v2(curve,tb))return!1;if(isNaN(c[1]+c[2])&&(!isNaN(a[1]+a[2])||!isNaN(b[1]+b[2]))&&!this.neighborhood_isNaN_v2(curve,tc))return!1;j=0;do{if(isNaN(a[1]+a[2])&&!isNaN(c[1]+c[2]))t_nan=ta,t_real=tc,t_real2=tb;else if(isNaN(b[1]+b[2])&&!isNaN(c[1]+c[2]))t_nan=tb,t_real=tc,t_real2=ta;else if(isNaN(c[1]+c[2])&&!isNaN(b[1]+b[2]))t_nan=tc,t_real=tb,t_real2=tb+(tb-tc);else{if(!isNaN(c[1]+c[2])||isNaN(a[1]+a[2]))return!1;t_nan=tc,t_real=ta,t_real2=ta-(tc-ta)}t=.5*(t_nan+t_real),pnt.setCoordinates(Const.COORDS_BY_USER,[curve.X(t,!0),curve.Y(t,!0)],!1),p=pnt.usrCoords,(is_undef=isNaN(p[1]+p[2]))?t_nan=t:(t_real2=t_real,t_real=t),++j}while(is_undef&&j<30);if(j<30&&(p_good=p.slice(),c=p.slice(),t_real=t),(curve.X(t_real,!0)-curve.X(t_real2,!0))/(t_real-t_real2),(curve.Y(t_real,!0)-curve.Y(t_real2,!0))/(t_real-t_real2),null!==p_good)return this._insertPoint_v2(curve,new Coords(Const.COORDS_BY_USER,p_good,curve.board,!1)),!0}return!1},_plotRecursive_v2:function(curve,a,ta,b,tb,depth,delta){var tc,c,ds,isSmooth,isJump,mindepth=0,pnt=new Coords(Const.COORDS_BY_USER,[0,0],curve.board,!1);if(!(curve.numberPoints>65536))return depth<this.nanLevel&&this._isUndefined(curve,a,ta,b,tb)||depth<this.nanLevel&&this._isOutside(a,ta,b,tb,curve.board)?this:(tc=.5*(ta+tb),pnt.setCoordinates(Const.COORDS_BY_USER,[curve.X(tc,!0),curve.Y(tc,!0)],!1),c=pnt.scrCoords,this._borderCase(curve,a,b,c,ta,tb,tc,depth)||(ds=this._triangleDists(a,b,c),isSmooth=depth<this.smoothLevel&&ds[3]<delta,isJump=depth<this.jumpLevel&&(ds[2]>.99*ds[0]||ds[1]>.99*ds[0]||ds[0]===1/0||ds[1]===1/0||ds[2]===1/0),depth<this.smoothLevel+2&&ds[0]<.5*(ds[1]+ds[2])&&(mindepth=0,isSmooth=!1),--depth,isJump?this._insertPoint_v2(curve,new Coords(Const.COORDS_BY_SCREEN,[NaN,NaN],curve.board,!1),tc):depth<=mindepth||isSmooth?this._insertPoint_v2(curve,pnt,tc):(this._plotRecursive_v2(curve,a,ta,c,tc,depth,delta),isNaN(pnt.scrCoords[1]+pnt.scrCoords[2])||this._insertPoint_v2(curve,pnt,tc),this._plotRecursive_v2(curve,c,tc,b,tb,depth,delta))),this)},updateParametricCurve_v2:function(curve,mi,ma){var ta,tb,a,b,depth,delta,w2,bbox,ret_arr,suspendUpdate=!1,pa=new Coords(Const.COORDS_BY_USER,[0,0],curve.board,!1),pb=new Coords(Const.COORDS_BY_USER,[0,0],curve.board,!1);return curve.board.updateQuality===curve.board.BOARD_QUALITY_LOW?(depth=Type.evaluate(curve.visProp.recursiondepthlow)||13,delta=2,this.smoothLevel=depth-6,this.jumpLevel=3):(depth=Type.evaluate(curve.visProp.recursiondepthhigh)||17,delta=2,this.smoothLevel=depth-9,this.jumpLevel=2),this.nanLevel=depth-4,curve.points=[],"x"===this.xterm?(w2=.3*((bbox=curve.board.getBoundingBox())[2]-bbox[0]),.3*(bbox[1]-bbox[3]),ta=Math.max(mi,bbox[0]-w2),tb=Math.min(ma,bbox[2]+w2)):(ta=mi,tb=ma),pa.setCoordinates(Const.COORDS_BY_USER,[curve.X(ta,suspendUpdate),curve.Y(ta,suspendUpdate)],!1),suspendUpdate=!0,pb.setCoordinates(Const.COORDS_BY_USER,[curve.X(tb,suspendUpdate),curve.Y(tb,suspendUpdate)],!1),ret_arr=this._findStartPoint(curve,pa.scrCoords,ta,pb.scrCoords,tb),pa.setCoordinates(Const.COORDS_BY_SCREEN,ret_arr[0],!1),ta=ret_arr[1],ret_arr=this._findStartPoint(curve,pb.scrCoords,tb,pa.scrCoords,ta),pb.setCoordinates(Const.COORDS_BY_SCREEN,ret_arr[0],!1),tb=ret_arr[1],this._visibleArea=[ta,tb],a=pa.copy("scrCoords"),b=pb.copy("scrCoords"),pa._t=ta,curve.points.push(pa),this._lastCrds=pa.copy("scrCoords"),this._plotRecursive_v2(curve,a,ta,b,tb,depth,delta),pb._t=tb,curve.points.push(pb),curve.numberPoints=curve.points.length,curve},_insertLimesPoint:function(curve,pnt,t,depth,limes){var p0,p1,p2;Math.abs(this._lastUsrCrds[1])===1/0&&Math.abs(limes.left_x)===1/0||Math.abs(this._lastUsrCrds[2])===1/0&&Math.abs(limes.left_y)===1/0||((p0=new Coords(Const.COORDS_BY_USER,[limes.left_x,limes.left_y],curve.board))._t=t,curve.points.push(p0),isNaN(limes.left_x)||isNaN(limes.left_y)||isNaN(limes.right_x)||isNaN(limes.right_y)||!(Math.abs(limes.left_x-limes.right_x)>Mat.eps||Math.abs(limes.left_y-limes.right_y)>Mat.eps)||((p1=new Coords(Const.COORDS_BY_SCREEN,pnt,curve.board))._t=t,curve.points.push(p1)),(p2=new Coords(Const.COORDS_BY_USER,[limes.right_x,limes.right_y],curve.board))._t=t,curve.points.push(p2),this._lastScrCrds=p2.copy("scrCoords"),this._lastUsrCrds=p2.copy("usrCoords"))},_insertPoint:function(curve,pnt,t,depth,limes){var p,last_is_real=!isNaN(this._lastScrCrds[1]+this._lastScrCrds[2]),point_is_real=!isNaN(pnt[1]+pnt[2]),cw=curve.board.canvasWidth,ch=curve.board.canvasHeight;Type.exists(limes)?this._insertLimesPoint(curve,pnt,t,depth,limes):(point_is_real=point_is_real&&pnt[1]>-500&&pnt[2]>-500&&pnt[1]<cw+500&&pnt[2]<ch+500,(last_is_real||point_is_real)&&(point_is_real&&last_is_real&&Math.abs(pnt[1]-this._lastScrCrds[1])<.8&&Math.abs(pnt[2]-this._lastScrCrds[2])<.8||Math.abs(pnt[1])===1/0&&Math.abs(this._lastUsrCrds[1])===1/0||Math.abs(pnt[2])===1/0&&Math.abs(this._lastUsrCrds[2])===1/0||((p=new Coords(Const.COORDS_BY_SCREEN,pnt,curve.board))._t=t,curve.points.push(p),this._lastScrCrds=p.copy("scrCoords"),this._lastUsrCrds=p.copy("usrCoords"))))},_triangleDists:function(a,b,c){var d;return d=[a[0]*b[0],.5*(a[1]+b[1]),.5*(a[2]+b[2])],[Geometry.distance(a,b,3),Geometry.distance(a,c,3),Geometry.distance(c,b,3),Geometry.distance(c,d,3)]},_isUndefined:function(curve,a,ta,b,tb){var t,i,pnt;if(!isNaN(a[1]+a[2])||!isNaN(b[1]+b[2]))return!1;for(pnt=new Coords(Const.COORDS_BY_USER,[0,0],curve.board,!1),i=0;i<20;++i)if(t=ta+Math.random()*(tb-ta),pnt.setCoordinates(Const.COORDS_BY_USER,[curve.X(t,!0),curve.Y(t,!0)],!1),!isNaN(pnt.scrCoords[0]+pnt.scrCoords[1]+pnt.scrCoords[2]))return!1;return!0},_isOutside:function(a,ta,b,tb,board){var cw=board.canvasWidth,ch=board.canvasHeight;return!!(a[1]<-500&&b[1]<-500||a[2]<-500&&b[2]<-500||a[1]>cw+500&&b[1]>cw+500||a[2]>ch+500&&b[2]>ch+500)},_isOutsidePoint:function(a,board){var cw=board.canvasWidth,ch=board.canvasHeight;return!!(a[1]<-500||a[2]<-500||a[1]>cw+500||a[2]>ch+500)},_findStartPoint:function(curve,a,ta,b,tb){new Coords(Const.COORDS_BY_USER,[0,0],curve.board,!1),curve.board.getBoundingBox();return[a,ta]},_getBorderPos:function(curve,ta,a,tc,c,tb,b){var t,pnt,p,j,t_good,t_bad;if(pnt=new Coords(Const.COORDS_BY_USER,[0,0],curve.board,!1),j=0,isNaN(a[1]+a[2])&&!isNaN(c[1]+c[2]))t_bad=ta,t_good=tc,tb;else if(isNaN(b[1]+b[2])&&!isNaN(c[1]+c[2]))t_bad=tb,t_good=tc,ta;else if(isNaN(c[1]+c[2])&&!isNaN(b[1]+b[2]))t_bad=tc,t_good=tb,tb+(tb-tc);else{if(!isNaN(c[1]+c[2])||isNaN(a[1]+a[2]))return!1;t_bad=tc,t_good=ta,ta-(tc-ta)}do{t=.5*(t_good+t_bad),pnt.setCoordinates(Const.COORDS_BY_USER,[curve.X(t,!0),curve.Y(t,!0)],!1),p=pnt.usrCoords,isNaN(p[1]+p[2])?t_bad=t:(t_good,t_good=t),++j}while(j<30&&Math.abs(t_good-t_bad)>Mat.eps);return t},_getCuspPos:function(curve,ta,tb){var a=[curve.X(ta,!0),curve.Y(ta,!0)],b=[curve.X(tb,!0),curve.Y(tb,!0)];return Numerics.fminbr((function(t){var c=[curve.X(t,!0),curve.Y(t,!0)];return-(Math.sqrt((a[0]-c[0])*(a[0]-c[0])+(a[1]-c[1])*(a[1]-c[1]))+Math.sqrt((b[0]-c[0])*(b[0]-c[0])+(b[1]-c[1])*(b[1]-c[1])))}),[ta,tb],curve)},_getJumpPos:function(curve,ta,tb){return Numerics.fminbr((function(t){var e=Mat.eps*Mat.eps,c1=[curve.X(t,!0),curve.Y(t,!0)],c2=[curve.X(t+e,!0),curve.Y(t+e,!0)];return-Math.abs((c2[1]-c1[1])/(c2[0]-c1[0]))}),[ta,tb],curve)},_getLimits:function(curve,t){var res,x_l,x_r,y_l,y_r,step=2/(curve.maxX()-curve.minX());return x_l=(res=Extrapolate.limit(t,-step,curve.X))[0],"infinite"===res[1]&&(x_l=Math.sign(x_l)*(1/0)),y_l=(res=Extrapolate.limit(t,-step,curve.Y))[0],"infinite"===res[1]&&(y_l=Math.sign(y_l)*(1/0)),x_r=(res=Extrapolate.limit(t,step,curve.X))[0],"infinite"===res[1]&&(x_r=Math.sign(x_r)*(1/0)),y_r=(res=Extrapolate.limit(t,step,curve.Y))[0],"infinite"===res[1]&&(y_r=Math.sign(y_r)*(1/0)),{left_x:x_l,left_y:y_l,right_x:x_r,right_y:y_r,t:t}},_getLimes:function(curve,ta,a,tc,c,tb,b,may_be_special,depth){var t;return"border"===may_be_special?t=this._getBorderPos(curve,ta,a,tc,c,tb,b):"cusp"===may_be_special?t=this._getCuspPos(curve,ta,tb):"jump"===may_be_special&&(t=this._getJumpPos(curve,ta,tb)),this._getLimits(curve,t)},_plotNonRecursive:function(curve,a,ta,b,tb,d){var tc,c,ds,a_nan,b_nan,x,y,oc,depth,ds0,item,limes=null,isSmooth=!1,may_be_special="",stack=[],stack_length=0;for(oc=curve.board.origin.scrCoords,stack[stack_length++]=[a,ta,b,tb,d,1/0];stack_length>0;){if(a=(item=stack[--stack_length])[0],ta=item[1],b=item[2],tb=item[3],depth=item[4],ds0=item[5],isSmooth=!1,may_be_special="",limes=null,curve.points.length>65536)return;if(depth<this.nanLevel){if(this._isUndefined(curve,a,ta,b,tb))continue;if(this._isOutside(a,ta,b,tb,curve.board))continue}tc=.5*(ta+tb),x=curve.X(tc,!0),y=curve.Y(tc,!0),c=[1,oc[1]+x*curve.board.unitX,oc[2]-y*curve.board.unitY],ds=this._triangleDists(a,b,c),a_nan=isNaN(a[1]+a[2]),b_nan=isNaN(b[1]+b[2]),a_nan&&!b_nan||!a_nan&&b_nan?may_be_special="border":ds[0]>.66*ds0||ds[0]<this.cusp_threshold*(ds[1]+ds[2])||ds[1]>5*ds[2]||ds[2]>5*ds[1]?may_be_special="cusp":(ds[2]>this.jump_threshold*ds[0]||ds[1]>this.jump_threshold*ds[0]||ds[0]===1/0||ds[1]===1/0||ds[2]===1/0)&&(may_be_special="jump"),isSmooth=""===may_be_special&&depth<this.smoothLevel&&ds[3]<this.smooth_threshold,depth<this.testLevel&&!isSmooth&&(""===may_be_special?isSmooth=!0:limes=this._getLimes(curve,ta,a,tc,c,tb,b,may_be_special,depth)),null!==limes?(c=[1,NaN,NaN],this._insertPoint(curve,c,tc,depth,limes)):depth<=0||isSmooth?this._insertPoint(curve,c,tc,depth,null):(stack[stack_length++]=[c,tc,b,tb,depth-1,ds[0]],stack[stack_length++]=[a,ta,c,tc,depth-1,ds[0]])}return this},updateParametricCurve_v3:function(curve,mi,ma){var ta,tb,a,b,depth,w2,bbox,ret_arr,suspendUpdate=!1,pa=new Coords(Const.COORDS_BY_USER,[0,0],curve.board,!1),pb=new Coords(Const.COORDS_BY_USER,[0,0],curve.board,!1);return depth=curve.board.updateQuality===curve.board.BOARD_QUALITY_LOW?Type.evaluate(curve.visProp.recursiondepthlow)||14:Type.evaluate(curve.visProp.recursiondepthhigh)||17,this.smoothLevel=7,this.nanLevel=depth-4,this.testLevel=4,this.cusp_threshold=.5,this.jump_threshold=.99,this.smooth_threshold=2,curve.points=[],"x"===curve.xterm?(w2=.3*((bbox=curve.board.getBoundingBox())[2]-bbox[0]),ta=Math.max(mi,bbox[0]-w2),tb=Math.min(ma,bbox[2]+w2)):(ta=mi,tb=ma),pa.setCoordinates(Const.COORDS_BY_USER,[curve.X(ta,suspendUpdate),curve.Y(ta,suspendUpdate)],!1),suspendUpdate=!0,pb.setCoordinates(Const.COORDS_BY_USER,[curve.X(tb,suspendUpdate),curve.Y(tb,suspendUpdate)],!1),ret_arr=this._findStartPoint(curve,pa.scrCoords,ta,pb.scrCoords,tb),pa.setCoordinates(Const.COORDS_BY_SCREEN,ret_arr[0],!1),ta=ret_arr[1],ret_arr=this._findStartPoint(curve,pb.scrCoords,tb,pa.scrCoords,ta),pb.setCoordinates(Const.COORDS_BY_SCREEN,ret_arr[0],!1),tb=ret_arr[1],this._visibleArea=[ta,tb],a=pa.copy("scrCoords"),b=pb.copy("scrCoords"),pa._t=ta,curve.points.push(pa),this._lastScrCrds=pa.copy("scrCoords"),this._lastUsrCrds=pa.copy("usrCoords"),this._plotNonRecursive(curve,a,ta,b,tb,depth),pb._t=tb,curve.points.push(pb),curve.numberPoints=curve.points.length,curve},_criticalInterval:function(vec,le,level){var i,j,le1,med,sgn,sgnChange,abs_vec,isGroup=!1,last=-1/0,very_small=!1,smooth=!1,group=0,groups=[],types=[],positions=[];for(abs_vec=Statistics.abs(vec),(med=Statistics.median(abs_vec))<1e-7?(med=1e-7,very_small=!0):med*=this.criticalThreshold,i=0;i<le;i++)abs_vec[i]>med?(positions.push({i:i,v:vec[i],group:group}),last=i,isGroup||(isGroup=!0)):isGroup&&i>last+4&&(positions.length>0&&groups.push(positions.slice(0)),positions=[],isGroup=!1,group++);for(isGroup&&positions.length>1&&groups.push(positions.slice(0)),very_small&&0===groups.length&&(smooth=!0),j=0;j<groups.length;j++)if(types[j]="point",!((le1=groups[j].length)<64)){for(sgnChange=0,sgn=Math.sign(groups[j][0].v),i=1;i<le1;i++)Math.sign(groups[j][i].v)!==sgn&&(sgnChange++,sgn=Math.sign(groups[j][i].v));6*sgnChange>le1&&(types[j]="interval")}return{smooth:smooth,groups:groups,types:types}},Component:function(){this.left_isNaN=!1,this.right_isNaN=!1,this.left_t=null,this.right_t=null,this.t_values=[],this.x_values=[],this.y_values=[],this.len=0},findComponents:function(curve,mi,ma,steps){var i,t,h,x,y,comp,components=[],comp_nr=0,cnt=0,cntNaNs=0,comp_started=!1,suspended=!1;for(h=(ma-mi)/steps,components[comp_nr]=new this.Component,comp=components[comp_nr],i=0,t=mi;i<=steps;i++,t+=h)x=curve.X(t,suspended),y=curve.Y(t,suspended),isNaN(x)||isNaN(y)?++cntNaNs>1&&comp_started&&(comp.right_isNaN=!0,comp.right_t=t-h,comp.len=cnt,comp_started=!1,components[++comp_nr]=new this.Component,comp=components[comp_nr],cntNaNs=0):(comp_started||(comp_started=!0,cnt=0,cntNaNs>0&&(comp.left_t=t-h,comp.left_isNaN=!0)),cntNaNs=0,comp.t_values[cnt]=t,comp.x_values[cnt]=x,comp.y_values[cnt]=y,cnt++),0===i&&(suspended=!0);return comp_started?comp.len=cnt:components.pop(),components},getPointType:function(curve,pos,t_approx,t_values,x_table,y_table,len){var x_values=x_table[0],y_values=y_table[0],full_len=t_values.length,result={idx:pos,t:t_approx,x:x_values[pos],y:y_values[pos],type:"other"};return pos<5?(result.type="borderleft",result.idx=0,result.t=t_values[0],result.x=x_values[0],result.y=y_values[0],result):pos>len-6?(result.type="borderright",result.idx=full_len-1,result.t=t_values[full_len-1],result.x=x_values[full_len-1],result.y=y_values[full_len-1],result):result},newtonApprox:function(idx,t,h,level,table){var i,s=0;for(i=level;i>0;i--)s=(s+table[i][idx])*(t-(i-1)*h)/i;return s+table[0][idx]},thiele:function(t,recip,t_values,idx,degree){var i,v=0;for(i=degree;i>1;i--)v=(t-t_values[idx+i])/(recip[i][idx+1]-recip[i-2][idx+1]+v);return recip[0][idx+1]+(t-t_values[idx+1])/(recip[1][idx+1]+v)},differenceMethodExperiments:function(component,curve){var i,level,le,up,h,numerator,pos,ma,j,v,groups,t_values=component.t_values,x_values=component.x_values,y_values=component.y_values,x_diffs=[],y_diffs=[],x_slopes=[],y_slopes=[],x_table=[],y_table=[],x_recip=[],y_recip=[],foundCriticalPoint=0,criticalPoints=[];for(h=t_values[1]-t_values[0],x_table.push([]),y_table.push([]),x_recip.push([]),y_recip.push([]),le=y_values.length,i=0;i<le;i++)x_table[0][i]=x_values[i],y_table[0][i]=y_values[i],x_recip[0][i]=x_values[i],y_recip[0][i]=y_values[i];for(x_table.push([]),y_table.push([]),x_recip.push([]),y_recip.push([]),numerator=h,le=y_values.length-1,i=0;i<le;i++)x_diffs[i]=x_values[i+1]-x_values[i],y_diffs[i]=y_values[i+1]-y_values[i],x_slopes[i]=x_diffs[i],y_slopes[i]=y_diffs[i],x_table[1][i]=x_diffs[i],y_table[1][i]=y_diffs[i],x_recip[1][i]=numerator/x_diffs[i],y_recip[1][i]=numerator/y_diffs[i];for(le--,up=Math.min(8,y_values.length-1),level=1;level<up;level++){for(x_table.push([]),y_table.push([]),x_recip.push([]),y_recip.push([]),numerator*=h,i=0;i<le;i++)x_diffs[i]=x_diffs[i+1]-x_diffs[i],y_diffs[i]=y_diffs[i+1]-y_diffs[i],x_table[level+1][i]=x_diffs[i],y_table[level+1][i]=y_diffs[i],x_recip[level+1][i]=numerator/(x_recip[level][i+1]-x_recip[level][i])+x_recip[level-1][i+1],y_recip[level+1][i]=numerator/(y_recip[level][i+1]-y_recip[level][i])+y_recip[level-1][i+1];if(!1===(groups=this._criticalPoints(y_diffs,le,level))){console.log("Polynomial of degree",level),groups=[];break}if(groups.length>0&&++foundCriticalPoint>1&&level%2==0)break;le--}for(i=0;i<groups.length;i++){for(ma=-1/0,j=0;j<groups[i].length;j++)(v=Math.abs(groups[i][j].v))>ma&&(ma=v,pos=j);pos=Math.floor(groups[i][pos].i+level/2),criticalPoints.push(this.getPointType(curve,pos,t_values,x_values,y_values,x_slopes,y_slopes,le+1))}return[criticalPoints,x_table,y_table,x_recip,y_recip]},getCenterOfCriticalInterval:function(group,degree,t_values){var ma,j,pos,v,pos_mean,num=0,den=0,h=t_values[1]-t_values[0],range=[];for(ma=-1/0,range=[],j=0;j<group.length;j++)(v=Math.abs(group[j].v))>ma?(range=[j],ma=v,pos=j):ma===v&&range.push(j);if(range.length>0&&(pos_mean=range.reduce((function(total,val){return total+val}),0)/range.length,pos=Math.floor(pos_mean),pos_mean+=group[0].i),ma<1/0){for(j=0;j<group.length;j++)num+=Math.abs(group[j].v)*group[j].i,den+=Math.abs(group[j].v);pos_mean=num/den}return pos_mean+=degree/2,[group[pos].i+degree/2,pos_mean,t_values[Math.floor(pos_mean)]+h*(pos_mean-Math.floor(pos_mean))]},differenceMethod:function(component,curve){var i,level,le,up,pos,res,res_x,res_y,t_approx,types,t_values=component.t_values,x_values=component.x_values,y_values=component.y_values,x_table=[],y_table=[],foundCriticalPoint=0,degree_x=-1,degree_y=-1,groups=[],criticalPoints=[];for(le=y_values.length,x_table.push(new Float64Array(x_values)),y_table.push(new Float64Array(y_values)),le--,up=Math.min(12,le),level=0;level<up&&(x_table.push(new Float64Array(le)),y_table.push(new Float64Array(le)),x_table[level+1]=x_table[level].map((function(v,idx,arr){return arr[idx+1]-v})),y_table[level+1]=y_table[level].map((function(v,idx,arr){return arr[idx+1]-v})),!0===(res_y=this._criticalInterval(y_table[level+1],le,level)).smooth&&(degree_y=level,groups=[]),res_x=this._criticalInterval(x_table[level+1],le,level),-1===degree_x&&!0===res_x.smooth&&(degree_x=level),!(degree_y>=0));level++){if(res_y.groups.length>0&&++foundCriticalPoint>2&&(level+1)%2==0){groups=res_y.groups,types=res_y.types;break}le--}for(i=0;i<groups.length;i++)"interval"!==types[i]&&(res=this.getCenterOfCriticalInterval(groups[i],level+1,t_values),res_y[0],pos=Math.floor(res[1]),t_approx=res[2],criticalPoints.push(this.getPointType(curve,pos,t_approx,t_values,x_table,y_table,le+1)));return[criticalPoints,x_table,y_table,degree_x,degree_y]},_insertPoint_v4:function(curve,crds,t,doLog){var p,x,y,prev=null;curve.points.length>0&&(prev=curve.points[curve.points.length-1].scrCoords),p=new Coords(Const.COORDS_BY_USER,crds,curve.board),null!==prev&&(x=p.scrCoords[1]-prev[1])*x+(y=p.scrCoords[2]-prev[2])*y<.8*.8||(p._t=t,curve.points.push(p))},getInterval:function(curve,ta,tb){var t_int,y_int;return IntervalArithmetic.disable(),t_int=IntervalArithmetic.Interval(ta,tb),curve.board.mathLib=IntervalArithmetic,curve.board.mathLibJXG=IntervalArithmetic,curve.X(t_int,!0),y_int=curve.Y(t_int,!0),curve.board.mathLib=Math,curve.board.mathLibJXG=JXG.Math,y_int},sign:function(v){return v<0?-1:v>0?1:0},handleBorder:function(curve,comp,group,x_table,y_table){var t,t1,t2,y_int,x,y,lo,hi,i,components2,le,h,idx=group.idx;if(h=comp.t_values[1]-comp.t_values[0],"borderleft"===group.type?t2=(t1=t=comp.left_isNaN?comp.left_t:group.t-h)+h:"borderright"===group.type?t1=(t2=t=comp.right_isNaN?comp.right_t:group.t+h)-h:console.log("No bordercase!!!"),0!==(components2=this.findComponents(curve,t1,t2,32)).length){for("borderleft"===group.type&&(t1=components2[0].left_t,t2=components2[0].t_values[0],h=components2[0].t_values[1]-components2[0].t_values[0],t=t1=null===t1?t2-h:t1,y_int=this.getInterval(curve,t1,t2),Type.isObject(y_int)&&(lo=y_int.lo,hi=y_int.hi,x=curve.X(t,!0),y=y_table[1][idx]<0?hi:lo,this._insertPoint_v4(curve,[1,x,y],t))),le=components2[0].t_values.length,i=0;i<le;i++)t=components2[0].t_values[i],x=components2[0].x_values[i],y=components2[0].y_values[i],this._insertPoint_v4(curve,[1,x,y],t);"borderright"===group.type&&(t1=components2[0].t_values[le-1],t2=components2[0].right_t,h=components2[0].t_values[1]-components2[0].t_values[0],t=t2=null===t2?t1+h:t2,y_int=this.getInterval(curve,t1,t2),Type.isObject(y_int)&&(lo=y_int.lo,hi=y_int.hi,x=curve.X(t,!0),y=y_table[1][idx]>0?hi:lo,this._insertPoint_v4(curve,[1,x,y],t)))}},_seconditeration_v4:function(curve,comp,group,x_table,y_table){var i,t1,t2,ret,components2,comp2,idx,groups2,g,x_table2,y_table2,start,le;for(t1=comp.t_values[group.idx-2],t2=comp.t_values[group.idx+2],components2=this.findComponents(curve,t1,t2,64),idx=0;idx<components2.length;idx++){for(comp2=components2[idx],groups2=(ret=this.differenceMethod(comp2,curve))[0],x_table2=ret[1],y_table2=ret[2],start=0,g=0;g<=groups2.length;g++){for(le=g===groups2.length?comp2.len:groups2[g].idx,i=start;i<le;i++)isNaN(comp2.x_values[i])||isNaN(comp2.y_values[i])||this._insertPoint_v4(curve,[1,comp2.x_values[i],comp2.y_values[i]],comp2.t_values[i]);g<groups2.length&&(this.handleSingularity(curve,comp2,groups2[g],x_table2,y_table2),start=groups2[g].idx+1)}le=comp2.len,idx<components2.length-1&&this._insertPoint_v4(curve,[1,NaN,NaN],comp2.right_t)}return this},_recurse_v4:function(curve,t1,t2,x1,y1,x2,y2,level){var dx,dy,t=.5*(t1+t2),x=curve.X(t,!0),y=curve.Y(t,!0);0!==level?(dx=(x-x1)*curve.board.unitX,dy=(y-y1)*curve.board.unitY,Math.sqrt(dx*dx+dy*dy)>2?this._recurse_v4(curve,t1,t,x1,y1,x,y,level-1):this._insertPoint_v4(curve,[1,x,y],t),dx=(x-x2)*curve.board.unitX,dy=(y-y2)*curve.board.unitY,Math.sqrt(dx*dx+dy*dy)>2?this._recurse_v4(curve,t,t2,x,y,x2,y2,level-1):this._insertPoint_v4(curve,[1,x,y],t)):this._insertPoint_v4(curve,[1,NaN,NaN],t)},handleSingularity:function(curve,comp,group,x_table,y_table){var t,t1,t2,y_int,i1,i2,x,lo,hi,d_lft,d_rgt,idx=group.idx;t=group.t,console.log("HandleSingularity at t =",t),t1=comp.t_values[idx-5],t2=comp.t_values[idx+5],y_int=this.getInterval(curve,t1,t2),Type.isObject(y_int)?(lo=y_int.lo,hi=y_int.hi):y_table[0][idx-1]<y_table[0][idx+1]?(lo=y_table[0][idx-1],hi=y_table[0][idx+1]):(lo=y_table[0][idx+1],hi=y_table[0][idx-1]),x=curve.X(t,!0),d_lft=(y_table[0][idx-3]-y_table[0][idx-5])/(comp.t_values[idx-3]-comp.t_values[idx-5]),d_rgt=(y_table[0][idx+3]-y_table[0][idx+5])/(comp.t_values[idx+3]-comp.t_values[idx+5]),console.log(":::",d_lft,d_rgt),d_lft<-100?(this._insertPoint_v4(curve,[1,x,lo],t,!0),d_rgt<=100&&this._insertPoint_v4(curve,[1,NaN,NaN],t)):d_lft>100?(this._insertPoint_v4(curve,[1,x,hi],t),d_rgt>=-100&&this._insertPoint_v4(curve,[1,NaN,NaN],t)):(lo===-1/0&&(this._insertPoint_v4(curve,[1,x,lo],t,!0),this._insertPoint_v4(curve,[1,NaN,NaN],t)),hi===1/0&&(this._insertPoint_v4(curve,[1,NaN,NaN],t),this._insertPoint_v4(curve,[1,x,hi],t,!0)),group.t<comp.t_values[idx]?(i1=idx-1,i2=idx):(i1=idx,i2=idx+1),t1=comp.t_values[i1],t2=comp.t_values[i2],this._recurse_v4(curve,t1,t2,x_table[0][i1],y_table[0][i1],x_table[0][i2],y_table[0][i2],10)),d_rgt<-100?this._insertPoint_v4(curve,[1,x,hi],t):d_rgt>100&&this._insertPoint_v4(curve,[1,x,lo],t)},steps:1021,criticalThreshold:1e3,plot_v4:function(curve,ta,tb,steps){var i,le,components,idx,comp,groups,g,start,ret,x_table,y_table,t,t1,t2,y_int,h=(tb-ta)/steps,Ypl=function(x){return curve.Y(x,!0)},Ymi=function(x){return-curve.Y(x,!0)},h2=.5*h;for(components=this.findComponents(curve,ta,tb,steps),idx=0;idx<components.length;idx++){for(comp=components[idx],groups=(ret=this.differenceMethod(comp,curve))[0],x_table=ret[1],y_table=ret[2],ret[3],ret[4],0!==groups.length&&"borderleft"===groups[0].type||groups.unshift({idx:0,t:comp.t_values[0],x:comp.x_values[0],y:comp.y_values[0],type:"borderleft"}),"borderright"!==groups[groups.length-1].type&&(le=comp.t_values.length,groups.push({idx:le-1,t:comp.t_values[le-1],x:comp.x_values[le-1],y:comp.y_values[le-1],type:"borderright"})),start=0,g=0;g<=groups.length;g++){for(le=g===groups.length?comp.len:groups[g].idx-1,0,0,i=start;i<le-2;i++)this._insertPoint_v4(curve,[1,comp.x_values[i],comp.y_values[i]],comp.t_values[i]),Math.max(0,i-2),i>=start+3&&i<le-3&&y_table.length>3&&Math.abs(y_table[2][i])>.2*Math.abs(y_table[0][i])?(t=comp.t_values[i],h2=.25*h,y_int=this.getInterval(curve,t,t+h),Type.isObject(y_int)?y_table[2][i]>0?this._insertPoint_v4(curve,[1,t+h2,y_int.lo],t+h2):this._insertPoint_v4(curve,[1,t+h-h2,y_int.hi],t+h-h2):(t1=Numerics.fminbr(Ypl,[t,t+h]))<(t2=Numerics.fminbr(Ymi,[t,t+h]))?(this._insertPoint_v4(curve,[1,curve.X(t1,!0),curve.Y(t1,!0)],t1),this._insertPoint_v4(curve,[1,curve.X(t2,!0),curve.Y(t2,!0)],t2)):(this._insertPoint_v4(curve,[1,curve.X(t2,!0),curve.Y(t2,!0)],t2),this._insertPoint_v4(curve,[1,curve.X(t1,!0),curve.Y(t1,!0)],t1))):0;g<groups.length&&(i=groups[g].idx,"borderleft"===groups[g].type||"borderright"===groups[g].type?this.handleBorder(curve,comp,groups[g],x_table,y_table):this._seconditeration_v4(curve,comp,groups[g],x_table,y_table),start=groups[g].idx+1+1)}le=comp.len,idx<components.length-1&&this._insertPoint_v4(curve,[1,NaN,NaN],comp.right_t)}},updateParametricCurve_v4:function(curve,mi,ma){var ta,tb,w2,bbox;"x"===curve.xterm?(w2=.3*((bbox=curve.board.getBoundingBox())[2]-bbox[0]),ta=Math.max(mi,bbox[0]-w2),tb=Math.min(ma,bbox[2]+w2)):(ta=mi,tb=ma),curve.points=[],this.plot_v4(curve,ta,tb,this.steps),curve.numberPoints=curve.points.length},updateParametricCurve:function(curve,mi,ma){return this.updateParametricCurve_v2(curve,mi,ma)}},Mat.Plot})),define("math/metapost",["utils/type","math/math"],(function(Type,Mat){return Mat.Metapost={MP_ENDPOINT:0,MP_EXPLICIT:1,MP_GIVEN:2,MP_CURL:3,MP_OPEN:4,MP_END_CYCLE:5,UNITY:1,FRACTION_ONE:1,FRACTION_THREE:3,ONE_EIGHTY_DEG:Math.PI,THREE_SIXTY_DEG:2*Math.PI,EPS_SQ:1e-5*1e-5,make_choices:function(knots){var dely,h,k,delx,n,q,p,s,cosine,t,sine,delta_x,delta_y,delta,psi;p=knots[0];do{if(!p)break;q=p.next,p.rtype>this.MP_EXPLICIT&&(p.x-q.x)*(p.x-q.x)+(p.y-q.y)*(p.y-q.y)<this.EPS_SQ&&(p.rtype=this.MP_EXPLICIT,p.ltype===this.MP_OPEN&&(p.ltype=this.MP_CURL,p.set_left_curl(this.UNITY)),q.ltype=this.MP_EXPLICIT,q.rtype===this.MP_OPEN&&(q.rtype=this.MP_CURL,q.set_right_curl(this.UNITY)),p.rx=p.x,q.lx=p.x,p.ry=p.y,q.ly=p.y),p=q}while(p!==knots[0]);for(h=knots[0];h.ltype===this.MP_OPEN&&h.rtype===this.MP_OPEN;)if((h=h.next)===knots[0]){h.ltype=this.MP_END_CYCLE;break}for(p=h;p;){if(q=p.next,p.rtype>=this.MP_GIVEN){for(;q.ltype===this.MP_OPEN&&q.rtype===this.MP_OPEN;)q=q.next;for(k=0,s=p,n=knots.length,delta_x=[],delta_y=[],delta=[],psi=[null];t=s.next,delta_x.push(t.x-s.x),delta_y.push(t.y-s.y),delta.push(this.mp_pyth_add(delta_x[k],delta_y[k])),k>0&&(sine=delta_y[k-1]/delta[k-1],cosine=delta_x[k-1]/delta[k-1],psi.push(Math.atan2(delta_y[k]*cosine-delta_x[k]*sine,delta_x[k]*cosine+delta_y[k]*sine))),k++,(s=t)===q&&(n=k),!(k>=n&&s.ltype!==this.MP_END_CYCLE););k===n?psi.push(0):psi.push(psi[1]),q.ltype===this.MP_OPEN&&((delx=q.rx-q.x)*delx+(dely=q.ry-q.y)*dely<this.EPS_SQ?(q.ltype=this.MP_CURL,q.set_left_curl(this.UNITY)):(q.ltype=this.MP_GIVEN,q.set_left_given(Math.atan2(dely,delx)))),p.rtype===this.MP_OPEN&&p.ltype===this.MP_EXPLICIT&&((delx=p.x-p.lx)*delx+(dely=p.y-p.ly)*dely<this.EPS_SQ?(p.rtype=this.MP_CURL,p.set_right_curl(this.UNITY)):(p.rtype=this.MP_GIVEN,p.set_right_given(Math.atan2(dely,delx)))),this.mp_solve_choices(p,q,n,delta_x,delta_y,delta,psi)}else p.rtype===this.MP_ENDPOINT&&(p.rx=p.x,p.ry=p.y,q.lx=q.x,q.ly=q.y);if((p=q)===h)break}},mp_solve_choices:function(p,q,n,delta_x,delta_y,delta,psi){var aa,acc,vv,bb,ldelta,ee,k,s,ww,uu,lt,r,t,ff,theta,rt,dd,cc,ct_st,ct,st,cf_sf,cf,sf,i,k_idx;for(ldelta=delta.length+1,uu=new Array(ldelta),ww=new Array(ldelta),vv=new Array(ldelta),theta=new Array(ldelta),i=0;i<ldelta;i++)theta[i]=vv[i]=ww[i]=uu[i]=0;for(k=0,s=p,r=0;;){if(t=s.next,0===k)if(s.rtype===this.MP_GIVEN){if(t.ltype===this.MP_GIVEN)return aa=Math.atan2(delta_y[0],delta_x[0]),ct=(ct_st=this.mp_n_sin_cos(p.right_given()-aa))[0],st=ct_st[1],cf=(cf_sf=this.mp_n_sin_cos(q.left_given()-aa))[0],sf=cf_sf[1],void this.mp_set_controls(p,q,delta_x[0],delta_y[0],st,ct,-sf,cf);vv[0]=s.right_given()-Math.atan2(delta_y[0],delta_x[0]),vv[0]=this.reduce_angle(vv[0]),uu[0]=0,ww[0]=0}else if(s.rtype===this.MP_CURL){if(t.ltype===this.MP_CURL)return p.rtype=this.MP_EXPLICIT,q.ltype=this.MP_EXPLICIT,lt=Math.abs(q.left_tension()),rt=Math.abs(p.right_tension()),ff=this.UNITY/(3*rt),p.rx=p.x+delta_x[0]*ff,p.ry=p.y+delta_y[0]*ff,ff=this.UNITY/(3*lt),q.lx=q.x-delta_x[0]*ff,void(q.ly=q.y-delta_y[0]*ff);cc=s.right_curl(),lt=Math.abs(t.left_tension()),rt=Math.abs(s.right_tension()),uu[0]=this.mp_curl_ratio(cc,rt,lt),vv[0]=-psi[1]*uu[0],ww[0]=0}else s.rtype===this.MP_OPEN&&(uu[0]=0,vv[0]=0,ww[0]=this.FRACTION_ONE);else if(s.ltype===this.MP_END_CYCLE||s.ltype===this.MP_OPEN){if(aa=this.UNITY/(3*Math.abs(r.right_tension())-this.UNITY),dd=delta[k]*(this.FRACTION_THREE-this.UNITY/Math.abs(r.right_tension())),bb=this.UNITY/(3*Math.abs(t.left_tension())-this.UNITY),ee=delta[k-1]*(this.FRACTION_THREE-this.UNITY/Math.abs(t.left_tension())),dd*=cc=this.FRACTION_ONE-uu[k-1]*aa,(lt=Math.abs(s.left_tension()))<(rt=Math.abs(s.right_tension()))?dd*=Math.pow(lt/rt,2):lt>rt&&(ee*=Math.pow(rt/lt,2)),ff=ee/(ee+dd),uu[k]=ff*bb,acc=-psi[k+1]*uu[k],r.rtype===this.MP_CURL?(ww[k]=0,vv[k]=acc-psi[1]*(this.FRACTION_ONE-ff)):(ff=(this.FRACTION_ONE-ff)/cc,acc-=psi[k]*ff,ff*=aa,vv[k]=acc-vv[k-1]*ff,ww[k]=-ww[k-1]*ff),s.ltype===this.MP_END_CYCLE){for(aa=0,bb=this.FRACTION_ONE;0===(k-=1)&&(k=n),aa=vv[k]-aa*uu[k],bb=ww[k]-bb*uu[k],k!==n;);for(aa/=this.FRACTION_ONE-bb,theta[n]=aa,vv[0]=aa,k_idx=1;k_idx<n;k_idx++)vv[k_idx]=vv[k_idx]+aa*ww[k_idx];break}}else{if(s.ltype===this.MP_CURL){cc=s.left_curl(),lt=Math.abs(s.left_tension()),rt=Math.abs(r.right_tension()),ff=this.mp_curl_ratio(cc,lt,rt),theta[n]=-vv[n-1]*ff/(this.FRACTION_ONE-ff*uu[n-1]);break}if(s.ltype===this.MP_GIVEN){theta[n]=s.left_given()-Math.atan2(delta_y[n-1],delta_x[n-1]),theta[n]=this.reduce_angle(theta[n]);break}}r=s,s=t,k+=1}for(k=n-1;k>-1;k--)theta[k]=vv[k]-theta[k+1]*uu[k];for(s=p,k=0;t=s.next,ct=(ct_st=this.mp_n_sin_cos(theta[k]))[0],st=ct_st[1],cf=(cf_sf=this.mp_n_sin_cos(-psi[k+1]-theta[k+1]))[0],sf=cf_sf[1],this.mp_set_controls(s,t,delta_x[k],delta_y[k],st,ct,sf,cf),s=t,++k!==n;);},mp_n_sin_cos:function(z){return[Math.cos(z),Math.sin(z)]},mp_set_controls:function(p,q,delta_x,delta_y,st,ct,sf,cf){var rt,ss,lt,sine,rr;lt=Math.abs(q.left_tension()),rt=Math.abs(p.right_tension()),rr=this.mp_velocity(st,ct,sf,cf,rt),ss=this.mp_velocity(sf,cf,st,ct,lt),(p.right_tension()<0||q.left_tension()<0)&&(st>=0&&sf>=0||st<=0&&sf<=0)&&(sine=Math.abs(st)*cf+Math.abs(sf)*ct)>0&&(sine*=1.00024414062,p.right_tension()<0&&this.mp_ab_vs_cd(Math.abs(sf),this.FRACTION_ONE,rr,sine)<0&&(rr=Math.abs(sf)/sine),q.left_tension()<0&&this.mp_ab_vs_cd(Math.abs(st),this.FRACTION_ONE,ss,sine)<0&&(ss=Math.abs(st)/sine)),p.rx=p.x+(delta_x*ct-delta_y*st)*rr,p.ry=p.y+(delta_y*ct+delta_x*st)*rr,q.lx=q.x-(delta_x*cf+delta_y*sf)*ss,q.ly=q.y-(delta_y*cf-delta_x*sf)*ss,p.rtype=this.MP_EXPLICIT,q.ltype=this.MP_EXPLICIT},mp_pyth_add:function(a,b){return Math.sqrt(a*a+b*b)},mp_curl_ratio:function(gamma,a_tension,b_tension){var alpha=1/a_tension,beta=1/b_tension;return Math.min(4,((3-alpha)*alpha*alpha*gamma+beta*beta*beta)/(alpha*alpha*alpha*gamma+(3-beta)*beta*beta))},mp_ab_vs_cd:function(a,b,c,d){return a*b==c*d?0:a*b>c*d?1:-1},mp_velocity:function(st,ct,sf,cf,t){return Math.min(4,(2+Math.sqrt(2)*(st-sf/16)*(sf-st/16)*(ct-cf))/(1.5*t*(2+(Math.sqrt(5)-1)*ct+(3-Math.sqrt(5))*cf)))},reduce_angle:function(A){return Math.abs(A)>this.ONE_EIGHTY_DEG&&(A>0?A-=this.THREE_SIXTY_DEG:A+=this.THREE_SIXTY_DEG),A},makeknots:function(p,tension,cycle){var i,len,knots=[];for(tension=tension||1,len=p.length,i=0;i<len;i++)knots.push({x:p[i][0],y:p[i][1],ltype:this.MP_OPEN,rtype:this.MP_OPEN,ly:tension,ry:tension,lx:tension,rx:tension,left_curl:function(){return this.lx||0},right_curl:function(){return this.rx||0},left_tension:function(){return this.ly||(this.ly=1),this.ly},right_tension:function(){return this.ry||(this.ry=1),this.ry},set_right_curl:function(x){this.rx=x||0},set_left_curl:function(x){this.lx=x||0}});for(len=knots.length,i=0;i<len;i++)knots[i].next=knots[i+1]||knots[i],knots[i].set_right_given=knots[i].set_right_curl,knots[i].set_left_given=knots[i].set_left_curl,knots[i].right_given=knots[i].right_curl,knots[i].left_given=knots[i].left_curl;return knots[len-1].next=knots[0],cycle||(knots[len-1].rtype=this.MP_ENDPOINT,knots[len-1].ltype=this.MP_CURL,knots[0].rtype=this.MP_CURL),knots},curve:function(point_list,controls){var knots,len,i,val,x=[],y=[];for(i in controls=controls||{tension:1,direction:{},curl:{},isClosed:!1},len=(knots=this.makeknots(point_list,Type.evaluate(controls.tension),controls.isClosed)).length,controls.direction)controls.direction.hasOwnProperty(i)&&(val=Type.evaluate(controls.direction[i]),Type.isArray(val)?(!1!==val[0]&&(knots[i].lx=val[0]*Math.PI/180,knots[i].ltype=this.MP_GIVEN),!1!==val[1]&&(knots[i].rx=val[1]*Math.PI/180,knots[i].rtype=this.MP_GIVEN)):(knots[i].lx=val*Math.PI/180,knots[i].rx=val*Math.PI/180,knots[i].ltype=knots[i].rtype=this.MP_GIVEN));for(i in controls.curl)controls.curl.hasOwnProperty(i)&&(val=Type.evaluate(controls.curl[i]),0===parseInt(i,10)?(knots[i].rtype=this.MP_CURL,knots[i].set_right_curl(val)):parseInt(i,10)===len-1&&(knots[i].ltype=this.MP_CURL,knots[i].set_left_curl(val)));for(this.make_choices(knots),i=0;i<len-1;i++)x.push(knots[i].x),x.push(knots[i].rx),x.push(knots[i+1].lx),y.push(knots[i].y),y.push(knots[i].ry),y.push(knots[i+1].ly);return x.push(knots[len-1].x),y.push(knots[len-1].y),controls.isClosed&&(x.push(knots[len-1].rx),y.push(knots[len-1].ry),x.push(knots[0].lx),y.push(knots[0].ly),x.push(knots[0].x),y.push(knots[0].y)),[x,y]}},Mat.Metapost})),define("utils/zip",["jxg"],(function(JXG){var bitReverse=[0,128,64,192,32,160,96,224,16,144,80,208,48,176,112,240,8,136,72,200,40,168,104,232,24,152,88,216,56,184,120,248,4,132,68,196,36,164,100,228,20,148,84,212,52,180,116,244,12,140,76,204,44,172,108,236,28,156,92,220,60,188,124,252,2,130,66,194,34,162,98,226,18,146,82,210,50,178,114,242,10,138,74,202,42,170,106,234,26,154,90,218,58,186,122,250,6,134,70,198,38,166,102,230,22,150,86,214,54,182,118,246,14,142,78,206,46,174,110,238,30,158,94,222,62,190,126,254,1,129,65,193,33,161,97,225,17,145,81,209,49,177,113,241,9,137,73,201,41,169,105,233,25,153,89,217,57,185,121,249,5,133,69,197,37,165,101,229,21,149,85,213,53,181,117,245,13,141,77,205,45,173,109,237,29,157,93,221,61,189,125,253,3,131,67,195,35,163,99,227,19,147,83,211,51,179,115,243,11,139,75,203,43,171,107,235,27,155,91,219,59,187,123,251,7,135,71,199,39,167,103,231,23,151,87,215,55,183,119,247,15,143,79,207,47,175,111,239,31,159,95,223,63,191,127,255],cplens=[3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,0,0],cplext=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,99,99],cpdist=[1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577],cpdext=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13],border=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15];return JXG.Util=JXG.Util||{},JXG.Util.Unzip=function(barray){var gpflags,fileout,flens,fmax,outputArr=[],files=0,unzipped=[],buf32k=new Array(32768),bIdx=0,modeZIP=!1,barraylen=barray.length,bytepos=0,bb=1,literalTree=new Array(288),distanceTree=new Array(32),treepos=0,Places=null,len=(new Array(64),new Array(64),0),fpos=new Array(17),nameBuf=[];function readByte(){return 8,bytepos<barraylen?barray[bytepos++]:-1}function byteAlign(){bb=1}function readBit(){var carry;try{return carry=1&bb,0===(bb>>=1)&&(carry=1&(bb=readByte()),bb=bb>>1|128),carry}catch(e){throw e}}function readBits(a){var res=0,i=a;try{for(;i--;)res=res<<1|readBit();a&&(res=bitReverse[res]>>8-a)}catch(e){throw e}return res}function flushBuffer(){bIdx=0}function addBuffer(a){buf32k[bIdx++]=a,outputArr.push(String.fromCharCode(a)),32768===bIdx&&(bIdx=0)}function HufNode(){this.b0=0,this.b1=0,this.jump=null,this.jumppos=-1}function isPat(){for(;;){if(fpos[len]>=fmax)return-1;if(flens[fpos[len]]===len)return fpos[len]++;fpos[len]++}}function rec(){var tmp,curplace=Places[treepos];if(17===len)return-1;if(treepos++,len++,(tmp=isPat())>=0)curplace.b0=tmp;else if(curplace.b0=32768,rec())return-1;if((tmp=isPat())>=0)curplace.b1=tmp,curplace.jump=null;else if(curplace.b1=32768,curplace.jump=Places[treepos],curplace.jumppos=treepos,rec())return-1;return len--,0}function createTree(currentTree,numval,lengths,show){var i;for(Places=currentTree,treepos=0,flens=lengths,fmax=numval,i=0;i<17;i++)fpos[i]=0;return len=0,rec()?-1:0}function decodeValue(currentTree){for(var len,i,xtreepos=0,X=currentTree[xtreepos];;)if(readBit()){if(!(32768&X.b1))return X.b1;for(X=X.jump,len=currentTree.length,i=0;i<len;i++)if(currentTree[i]===X){xtreepos=i;break}}else{if(!(32768&X.b0))return X.b0;X=currentTree[++xtreepos]}}function deflateLoop(){var last,type,i,j,l,ll,ll2,len,blockLen,dist,cSum,n,literalCodes,distCodes,lenCodes;do{if(last=readBit(),0===(type=readBits(2)))for(byteAlign(),blockLen=readByte(),blockLen|=readByte()<<8,cSum=readByte(),65535&(blockLen^~(cSum|=readByte()<<8))&&JXG.debug("BlockLen checksum mismatch\n");blockLen--;)addBuffer(readByte());else if(1===type)for(;;)if((j=bitReverse[readBits(7)]>>1)>23?(j=j<<1|readBit())>199?j=(j-=128)<<1|readBit():(j-=48)>143&&(j+=136):j+=256,j<256)addBuffer(j);else{if(256===j)break;for(len=readBits(cplext[j-=257])+cplens[j],j=bitReverse[readBits(5)]>>3,cpdext[j]>8?(dist=readBits(8),dist|=readBits(cpdext[j]-8)<<8):dist=readBits(cpdext[j]),dist+=cpdist[j],j=0;j<len;j++)addBuffer(buf32k[bIdx-dist&32767])}else if(2===type){for(ll=new Array(320),literalCodes=257+readBits(5),distCodes=1+readBits(5),lenCodes=4+readBits(4),j=0;j<19;j++)ll[j]=0;for(j=0;j<lenCodes;j++)ll[border[j]]=readBits(3);for(len=distanceTree.length,i=0;i<len;i++)distanceTree[i]=new HufNode;if(createTree(distanceTree,19,ll))return flushBuffer(),1;for(n=literalCodes+distCodes,i=0,-1;i<n;)if((j=decodeValue(distanceTree))<16)ll[i++]=j;else if(16===j){if(i+(j=3+readBits(2))>n)return flushBuffer(),1;for(l=i?ll[i-1]:0;j--;)ll[i++]=l}else{if(i+(j=17===j?3+readBits(3):11+readBits(7))>n)return flushBuffer(),1;for(;j--;)ll[i++]=0}for(len=literalTree.length,i=0;i<len;i++)literalTree[i]=new HufNode;if(createTree(literalTree,literalCodes,ll))return flushBuffer(),1;for(len=literalTree.length,i=0;i<len;i++)distanceTree[i]=new HufNode;for(ll2=[],i=literalCodes;i<ll.length;i++)ll2[i-literalCodes]=ll[i];if(createTree(distanceTree,distCodes,ll2))return flushBuffer(),1;for(;;)if((j=decodeValue(literalTree))>=256){if(0===(j-=256))break;for(len=readBits(cplext[j-=1])+cplens[j],j=decodeValue(distanceTree),cpdext[j]>8?(dist=readBits(8),dist|=readBits(cpdext[j]-8)<<8):dist=readBits(cpdext[j]),dist+=cpdist[j];len--;)addBuffer(buf32k[bIdx-dist&32767])}else addBuffer(j)}}while(!last);return flushBuffer(),byteAlign(),0}function nextFile(){var i,c,extralen,filelen,method,tmp=[];try{if(outputArr=[],modeZIP=!1,tmp[0]=readByte(),tmp[1]=readByte(),120===tmp[0]&&218===tmp[1]&&(deflateLoop(),unzipped[files]=[outputArr.join(""),"geonext.gxt"],files++),31===tmp[0]&&139===tmp[1]&&(skipdir(),unzipped[files]=[outputArr.join(""),"file"],files++),80===tmp[0]&&75===tmp[1]){if(modeZIP=!0,tmp[2]=readByte(),tmp[3]=readByte(),3===tmp[2]&&4===tmp[3]){for(tmp[0]=readByte(),tmp[1]=readByte(),gpflags=readByte(),gpflags|=readByte()<<8,method=readByte(),method|=readByte()<<8,readByte(),readByte(),readByte(),readByte(),readByte(),readByte()<<8,readByte()<<16,readByte()<<24,readByte(),readByte()<<8,readByte()<<16,readByte()<<24,readByte(),readByte()<<8,readByte()<<16,readByte()<<24,filelen=readByte(),filelen|=readByte()<<8,extralen=readByte(),extralen|=readByte()<<8,i=0,nameBuf=[];filelen--;)"/"===(c=readByte())|":"===c?i=0:i<255&&(nameBuf[i++]=String.fromCharCode(c));for(fileout||(fileout=nameBuf),i=0;i<extralen;)c=readByte(),i++;if(0,8===method&&(deflateLoop(),unzipped[files]=new Array(2),unzipped[files][0]=outputArr.join(""),unzipped[files][1]=nameBuf.join(""),files++),skipdir())return!1}return!0}}catch(e){throw e}return!1}function skipdir(){var i,c,tmp=[];if(8&gpflags&&(tmp[0]=readByte(),tmp[1]=readByte(),tmp[2]=readByte(),tmp[3]=readByte(),80===tmp[0]&&75===tmp[1]&&7===tmp[2]&&8===tmp[3]?(readByte(),readByte()<<8,readByte()<<16,readByte()<<24):tmp[0]|tmp[1]<<8|tmp[2]<<16|tmp[3]<<24,readByte(),readByte()<<8,readByte()<<16,readByte()<<24,readByte(),readByte()<<8,readByte()<<16,readByte()<<24),modeZIP&&nextFile())return!1;if(tmp[0]=readByte(),8!==tmp[0])return!0;if(gpflags=readByte(),readByte(),readByte(),readByte(),readByte(),readByte(),readByte(),4&gpflags)for(tmp[0]=readByte(),tmp[2]=readByte(),len=tmp[0]+256*tmp[1],i=0;i<len;i++)readByte();if(8&gpflags)for(i=0,nameBuf=[],c=readByte();c;)"7"!==c&&":"!==c||(i=0),i<255&&(nameBuf[i++]=c),c=readByte();if(16&gpflags)for(c=readByte();c;)c=readByte();return 2&gpflags&&(readByte(),readByte()),deflateLoop(),readByte(),readByte()<<8,readByte()<<16,readByte()<<24,readByte(),readByte()<<8,readByte()<<16,readByte()<<24,modeZIP&&nextFile(),!1}fpos[0]=0,JXG.Util.Unzip.prototype.unzipFile=function(name){var i;for(this.unzip(),i=0;i<unzipped.length;i++)if(unzipped[i][1]===name)return unzipped[i][0];return""},JXG.Util.Unzip.prototype.unzip=function(){return nextFile(),unzipped}},JXG.Util})),define("utils/encoding",["jxg"],(function(JXG){var UTF8D=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3,11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,0,12,24,36,60,96,84,12,12,12,48,72,12,12,12,12,12,12,12,12,12,12,12,12,12,0,12,12,12,12,12,0,12,0,12,12,12,24,12,12,12,12,12,24,12,24,12,12,12,12,12,12,12,12,12,24,12,12,12,12,12,24,12,12,12,12,12,12,12,24,12,12,12,12,12,12,12,12,12,36,12,36,12,12,12,36,12,12,12,12,12,36,12,36,12,12,12,36,12,12,12,12,12,12,12,12,12,12];return JXG.Util=JXG.Util||{},JXG.Util.UTF8={encode:function(string){var n,c,utftext="",len=string.length;if(string=string.replace(/\r\n/g,"\n"),"function"==typeof unescape&&"function"==typeof encodeURIComponent)return unescape(encodeURIComponent(string));for(n=0;n<len;n++)(c=string.charCodeAt(n))<128?utftext+=String.fromCharCode(c):c>127&&c<2048?(utftext+=String.fromCharCode(c>>6|192),utftext+=String.fromCharCode(63&c|128)):(utftext+=String.fromCharCode(c>>12|224),utftext+=String.fromCharCode(c>>6&63|128),utftext+=String.fromCharCode(63&c|128));return utftext},decode:function(utftext){var i,charCode,type,j=0,codepoint=0,state=0,chars=[],len=utftext.length,results=[];for(i=0;i<len;i++)charCode=utftext.charCodeAt(i),type=UTF8D[charCode],codepoint=0!==state?63&charCode|codepoint<<6:255>>type&charCode,0===(state=UTF8D[256+state+type])&&(codepoint>65535?chars.push(55232+(codepoint>>10),56320+(1023&codepoint)):chars.push(codepoint),++j%1e4==0&&(results.push(String.fromCharCode.apply(null,chars)),chars=[]));return results.push(String.fromCharCode.apply(null,chars)),results.join("")},asciiCharCodeAt:function(str,i){var c=str.charCodeAt(i);if(c>255)switch(c){case 8364:c=128;break;case 8218:c=130;break;case 402:c=131;break;case 8222:c=132;break;case 8230:c=133;break;case 8224:c=134;break;case 8225:c=135;break;case 710:c=136;break;case 8240:c=137;break;case 352:c=138;break;case 8249:c=139;break;case 338:c=140;break;case 381:c=142;break;case 8216:c=145;break;case 8217:c=146;break;case 8220:c=147;break;case 8221:c=148;break;case 8226:c=149;break;case 8211:c=150;break;case 8212:c=151;break;case 732:c=152;break;case 8482:c=153;break;case 353:c=154;break;case 8250:c=155;break;case 339:c=156;break;case 382:c=158;break;case 376:c=159}return c}},JXG.Util.UTF8})),define("utils/base64",["jxg","utils/encoding"],(function(JXG,Encoding){var alphabet="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";function _getByte(s,i){return 255&s.charCodeAt(i)}function _getIndex(s,i){return alphabet.indexOf(s.charAt(i))}return JXG.Util=JXG.Util||{},JXG.Util.Base64={encode:function(input){var i,bin,len,padLen,encInput,buffer=[];for(padLen=(len=(encInput=Encoding.encode(input)).length)%3,i=0;i<len-padLen;i+=3)bin=_getByte(encInput,i)<<16|_getByte(encInput,i+1)<<8|_getByte(encInput,i+2),buffer.push(alphabet.charAt(bin>>18),alphabet.charAt(bin>>12&63),alphabet.charAt(bin>>6&63),alphabet.charAt(63&bin));switch(padLen){case 1:bin=_getByte(encInput,len-1),buffer.push(alphabet.charAt(bin>>2),alphabet.charAt(bin<<4&63),"=","=");break;case 2:bin=_getByte(encInput,len-2)<<8|_getByte(encInput,len-1),buffer.push(alphabet.charAt(bin>>10),alphabet.charAt(bin>>4&63),alphabet.charAt(bin<<2&63),"=")}return buffer.join("")},decode:function(input,utf8){var encInput,i,len,padLen,bin,output,result=[],buffer=[];if((len=(encInput=input.replace(/[^A-Za-z0-9+/=]/g,"")).length)%4!=0)throw new Error("JSXGraph/utils/base64: Can't decode string (invalid input length).");for("="===encInput.charAt(len-1)&&(padLen=1,"="===encInput.charAt(len-2)&&(padLen=2),len-=4),i=0;i<len;i+=4)bin=_getIndex(encInput,i)<<18|_getIndex(encInput,i+1)<<12|_getIndex(encInput,i+2)<<6|_getIndex(encInput,i+3),buffer.push(bin>>16,bin>>8&255,255&bin),i%1e4==0&&(result.push(String.fromCharCode.apply(null,buffer)),buffer=[]);switch(padLen){case 1:bin=_getIndex(encInput,len)<<12|_getIndex(encInput,len+1)<<6|_getIndex(encInput,len+2),buffer.push(bin>>10,bin>>2&255);break;case 2:bin=_getIndex(encInput,i)<<6|_getIndex(encInput,i+1),buffer.push(bin>>4)}return result.push(String.fromCharCode.apply(null,buffer)),output=result.join(""),utf8&&(output=Encoding.decode(output)),output},decodeAsArray:function(input){var i,dec=this.decode(input),ar=[],len=dec.length;for(i=0;i<len;i++)ar[i]=dec.charCodeAt(i);return ar}},JXG.Util.Base64})),define("server/server",["jxg","utils/zip","utils/base64","utils/type"],(function(JXG,Zip,Base64,Type){return JXG.Server={modules:{},runningCalls:{},handleError:function(data){JXG.debug("error occured, server says: "+data.message)},callServer:function(action,callback,data,sync){var fileurl,passdata,AJAX,id,dataJSONStr,k,cb;for(k in sync=sync||!1,"",data)data.hasOwnProperty(k)&&"&"+escape(k)+"="+escape(data[k]);dataJSONStr=Type.toJSON(data);do{id=action+Math.floor(4096*Math.random())}while(Type.exists(this.runningCalls[id]));return this.runningCalls[id]={action:action},Type.exists(data.module)&&(this.runningCalls[id].module=data.module),fileurl=JXG.serverBase+"JXGServer.py",passdata="action="+escape(action)+"&id="+id+"&dataJSON="+escape(Base64.encode(dataJSONStr)),this.cbp=function(d){var str,data,tmp,inject,paramlist,id,i,j;if(str=new Zip.Unzip(Base64.decodeAsArray(d)).unzip(),Type.isArray(str)&&str.length>0&&(str=str[0][0]),Type.exists(str))if("error"===(data=window.JSON&&window.JSON.parse?window.JSON.parse(str):new Function("return "+str)()).type)this.handleError(data);else if("response"===data.type){for(id=data.id,i=0;i<data.fields.length;i++)inject=(tmp=data.fields[i]).namespace+("object"===_typeof(new Function("return "+tmp.namespace)())?".":".prototype.")+tmp.name+" = "+tmp.value,new Function(inject)();for(i=0;i<data.handler.length;i++){for(tmp=data.handler[i],paramlist=[],j=0;j<tmp.parameters.length;j++)paramlist[j]='"'+tmp.parameters[j]+'": '+tmp.parameters[j];inject="if(typeof JXG.Server.modules."+this.runningCalls[id].module+' == "undefined")JXG.Server.modules.'+this.runningCalls[id].module+" = {};",inject+="JXG.Server.modules."+this.runningCalls[id].module+"."+tmp.name+"_cb = "+tmp.callback+";",inject+="JXG.Server.modules."+this.runningCalls[id].module+"."+tmp.name+" = function ("+tmp.parameters.join(",")+', __JXGSERVER_CB__, __JXGSERVER_SYNC) {if(typeof __JXGSERVER_CB__ == "undefined") __JXGSERVER_CB__ = JXG.Server.modules.'+this.runningCalls[id].module+"."+tmp.name+"_cb;var __JXGSERVER_PAR__ = {"+paramlist.join(",")+', "module": "'+this.runningCalls[id].module+'", "handler": "'+tmp.name+'" };JXG.Server.callServer("exec", __JXGSERVER_CB__, __JXGSERVER_PAR__, __JXGSERVER_SYNC);};',new Function(inject)()}delete this.runningCalls[id],callback(data.data)}},this.cb=JXG.bind(this.cbp,this),window.XMLHttpRequest?(AJAX=new XMLHttpRequest).overrideMimeType("text/plain; charset=iso-8859-1"):AJAX=new ActiveXObject("Microsoft.XMLHTTP"),!(!AJAX||(AJAX.open("POST",fileurl,!sync),AJAX.setRequestHeader("Content-type","application/x-www-form-urlencoded"),sync||(AJAX.onreadystatechange=(cb=this.cb,function(){return 4===AJAX.readyState&&200===AJAX.status&&(cb(AJAX.responseText),!0)})),AJAX.send(passdata),!sync))&&(this.cb(AJAX.responseText),!0)},loadModule_cb:function(data){var i;for(i=0;i<data.length;i++)JXG.debug(data[i].name+": "+data[i].value)},loadModule:function(module){return JXG.Server.callServer("load",JXG.Server.loadModule_cb,{module:module},!0)}},JXG.Server.load=JXG.Server.loadModule,JXG.Server})),define("math/symbolic",["base/constants","base/coords","math/math","math/geometry","server/server","utils/type"],(function(Const,Coords,Mat,Geometry,Server,Type){return Mat.Symbolic={generateSymbolicCoordinatesPartial:function(board,element,variable,append){var t_num,t,k,list=element.ancestors,count=0,makeCoords=function(num){return"underscore"===append?variable+"_{"+num+"}":"brace"===append?variable+"["+num+"]":variable+num};for(t in board.listOfFreePoints=[],board.listOfDependantPoints=[],list)if(list.hasOwnProperty(t)&&(t_num=0,Type.isPoint(list[t]))){for(k in list[t].ancestors)list[t].ancestors.hasOwnProperty(k)&&t_num++;0===t_num?(list[t].symbolic.x=list[t].coords.usrCoords[1],list[t].symbolic.y=list[t].coords.usrCoords[2],board.listOfFreePoints.push(list[t])):(count+=1,list[t].symbolic.x=makeCoords(count),count+=1,list[t].symbolic.y=makeCoords(count),board.listOfDependantPoints.push(list[t]))}return Type.isPoint(element)&&(element.symbolic.x="x",element.symbolic.y="y"),count},clearSymbolicCoordinates:function(board){var clear=function(list){var t,l=list&&list.length||0;for(t=0;t<l;t++)Type.isPoint(list[t])&&(list[t].symbolic.x="",list[t].symbolic.y="")};clear(board.listOfFreePoints),clear(board.listOfDependantPoints),delete board.listOfFreePoints,delete board.listOfDependantPoints},generatePolynomials:function(board,element,generateCoords){var t,k,i,number_of_ancestors,list=element.ancestors,pgs=[],result=[];for(t in generateCoords&&this.generateSymbolicCoordinatesPartial(board,element,"u","brace"),list[element.id]=element,list)if(list.hasOwnProperty(t)&&(number_of_ancestors=0,pgs=[],Type.isPoint(list[t]))){for(k in list[t].ancestors)list[t].ancestors.hasOwnProperty(k)&&number_of_ancestors++;if(number_of_ancestors>0)for(pgs=list[t].generatePolynomial(),i=0;i<pgs.length;i++)result.push(pgs[i])}return generateCoords&&this.clearSymbolicCoordinates(board),result},geometricLocusByGroebnerBase:function(board,point){var polyStr,result,P1,P2,i,xs,xe,ys,ye,c,s,tx,bol=board.options.locus,oldRadius={},numDependent=this.generateSymbolicCoordinatesPartial(board,point,"u","brace"),xsye=new Coords(Const.COORDS_BY_USR,[0,0],board),xeys=new Coords(Const.COORDS_BY_USR,[board.canvasWidth,board.canvasHeight],board),sf=1,transx=0,transy=0,rot=0;if(undefined===Server.modules.geoloci&&Server.loadModule("geoloci"),undefined===Server.modules.geoloci)throw new Error("JSXGraph: Unable to load JXG.Server module 'geoloci.py'.");if(xs=xsye.usrCoords[1],xe=xeys.usrCoords[1],ys=xeys.usrCoords[2],ye=xsye.usrCoords[2],bol.translateToOrigin&&board.listOfFreePoints.length>0){for(transx=(P1=undefined!==bol.toOrigin&&null!==bol.toOrigin&&Type.isInArray(board.listOfFreePoints,bol.toOrigin.id)?bol.toOrigin:board.listOfFreePoints[0]).symbolic.x,transy=P1.symbolic.y,i=0;i<board.listOfFreePoints.length;i++)board.listOfFreePoints[i].symbolic.x-=transx,board.listOfFreePoints[i].symbolic.y-=transy;if(xs-=transx,xe-=transx,ys-=transy,ye-=transy,bol.translateTo10&&board.listOfFreePoints.length>1){for(P2=undefined!==bol.to10&&null!==bol.to10&&bol.to10.id!==bol.toOrigin.id&&Type.isInArray(board.listOfFreePoints,bol.to10.id)?bol.to10:board.listOfFreePoints[0].id===P1.id?board.listOfFreePoints[1]:board.listOfFreePoints[0],rot=Geometry.rad([1,0],[0,0],[P2.symbolic.x,P2.symbolic.y]),c=Math.cos(-rot),s=Math.sin(-rot),i=0;i<board.listOfFreePoints.length;i++)tx=board.listOfFreePoints[i].symbolic.x,board.listOfFreePoints[i].symbolic.x=c*board.listOfFreePoints[i].symbolic.x-s*board.listOfFreePoints[i].symbolic.y,board.listOfFreePoints[i].symbolic.y=s*tx+c*board.listOfFreePoints[i].symbolic.y;if(P2.symbolic.y=0,tx=xs,xs=c*xs-s*ys,ys=s*tx+c*ys,tx=xe,xe=c*xe-s*ye,ye=s*tx+c*ye,bol.stretch&&Math.abs(P2.symbolic.x)>Mat.eps){for(sf=P2.symbolic.x,i=0;i<board.listOfFreePoints.length;i++)board.listOfFreePoints[i].symbolic.x/=sf,board.listOfFreePoints[i].symbolic.y/=sf;for(i=0;i<board.objectsList.length;i++)board.objectsList[i].elementClass===Const.OBJECT_CLASS_CIRCLE&&"pointRadius"===board.objectsList[i].method&&(oldRadius[i]=board.objectsList[i].radius,board.objectsList[i].radius/=sf);xs/=sf,xe/=sf,ys/=sf,ye/=sf,P2.symbolic.x=1}}for(i=0;i<board.listOfFreePoints.length;i++)tx=board.listOfFreePoints[i].symbolic.x,Math.abs(tx)<Mat.eps&&(board.listOfFreePoints[i].symbolic.x=0),Math.abs(tx-Math.round(tx))<Mat.eps&&(board.listOfFreePoints[i].symbolic.x=Math.round(tx)),tx=board.listOfFreePoints[i].symbolic.y,Math.abs(tx)<Mat.eps&&(board.listOfFreePoints[i].symbolic.y=0),Math.abs(tx-Math.round(tx))<Mat.eps&&(board.listOfFreePoints[i].symbolic.y=Math.round(tx))}for(i in polyStr=this.generatePolynomials(board,point).join(","),this.cbp=function(data){result=data},this.cb=Type.bind(this.cbp,this),Server.modules.geoloci.lociCoCoA(xs,xe,ys,ye,numDependent,polyStr,sf,rot,transx,transy,this.cb,!0),this.clearSymbolicCoordinates(board),oldRadius)oldRadius.hasOwnProperty(i)&&(board.objects[i].radius=oldRadius[i]);return result}},Mat.Symbolic})),define("math/clip",["jxg","base/constants","base/coords","math/math","math/geometry","utils/type"],(function(JXG,Const,Coords,Mat,Geometry,Type){return Mat.Clip={_isSeparator:function(node){return isNaN(node.coords.usrCoords[1])&&isNaN(node.coords.usrCoords[2])},makeDoublyLinkedList:function(S){var i,first=null,components=[],le=S.length;if(le>0)for(i=0;i<le;i++)this._isSeparator(S[i])?(S[i]._next=S[(i+1)%le],S[i]._prev=S[(le+i-1)%le]):(null===first&&(first=i,components.push(first)),this._isSeparator(S[(i+1)%le])||i===le-1?(S[i]._next=S[first],S[first]._prev=S[i],S[i]._end=!0,first=null):(S[i]._next=S[(i+1)%le],S[first]._prev=S[i]),this._isSeparator(S[(le+i-1)%le])||(S[i]._prev=S[(le+i-1)%le]));return components},det:function(p1,p2,q){return(p1[1]-q[1])*(p2[2]-q[2])-(p2[1]-q[1])*(p1[2]-q[2])},windingNumber:function(usrCoords,path){var p1,p2,d,sign,i,wn=0,le=path.length,x=usrCoords[1],y=usrCoords[2];if(0===le)return 0;if(isNaN(x)||isNaN(y))return 1;if(path[0].coords.usrCoords[1]===x&&path[0].coords.usrCoords[2]===y)return 1;for(i=0;i<le;i++)if(p1=path[i].coords.usrCoords,p2=path[(i+1)%le].coords.usrCoords,!(0===p1[0]||0===p2[0]||isNaN(p1[1])||isNaN(p2[1])||isNaN(p1[2])||isNaN(p2[2]))){if(p2[2]===y){if(p2[1]===x)return 1;if(p1[2]===y&&p2[1]>x==p1[1]<x)return 0}if(p1[2]<y!=p2[2]<y)if(sign=2*(p2[2]>p1[2]?1:0)-1,p1[1]>=x)if(p2[1]>x)wn+=sign;else{if(0===(d=this.det(p1,p2,usrCoords)))return 0;d>0==p2[2]>p1[2]&&(wn+=sign)}else p2[1]>x&&(d=this.det(p1,p2,usrCoords))>0+Mat.eps==p2[2]>p1[2]&&(wn+=sign)}return wn},Vertex:function(coords,i,alpha,path,pathname,type){this.pos=i,this.intersection=!0,this.coords=coords,this.elementClass=Const.OBJECT_CLASS_POINT,this.data={alpha:alpha,path:path,pathname:pathname,done:!1,type:type,idx:0},this.neighbour=null,this.entry_exit=!1},_addToList:function(list,coords,pos){var len=list.length,eps=Mat.eps*Mat.eps;len>0&&Math.abs(list[len-1].coords.usrCoords[0]-coords.usrCoords[0])<eps&&Math.abs(list[len-1].coords.usrCoords[1]-coords.usrCoords[1])<eps&&Math.abs(list[len-1].coords.usrCoords[2]-coords.usrCoords[2])<eps||list.push({pos:pos,intersection:!1,coords:coords,elementClass:Const.OBJECT_CLASS_POINT})},sortIntersections:function(P_crossings){var i,j,P,Q,last,next_node,P_intersect=[],P_le=P_crossings.length;for(i=0;i<P_le;i++)if(P_crossings[i].sort((function(a,b){return a.data.alpha>b.data.alpha?1:-1})),P_crossings[i].length>0){for(last=P_crossings[i].length-1,next_node=(Q=(P=P_crossings[i][0]).data.path[P.pos])._next,i===P_le-1&&(Q._end=!1),0===P.data.alpha&&"T"===P.data.type?(Q.intersection=!0,Q.data=P.data,Q.neighbour=P.neighbour,Q.neighbour.neighbour=Q,Q.entry_exit=!1,P_crossings[i][0]=Q):(P._prev=Q,P._prev._next=P),j=1;j<=last;j++)(P=P_crossings[i][j])._prev=P_crossings[i][j-1],P._prev._next=P;(P=P_crossings[i][last])._next=next_node,P._next._prev=P,i===P_le-1&&(P._end=!0),P_intersect=P_intersect.concat(P_crossings[i])}return P_intersect},_inbetween:function(q,p1,p2){var alpha,eps=Mat.eps*Mat.eps,px=p2[1]-p1[1],py=p2[2]-p1[2],qx=q[1]-p1[1],qy=q[2]-p1[2];return 0===px&&0===py&&0===qx&&0===qy||(alpha=Math.abs(qx)<eps&&Math.abs(px)<eps?qy/py:qx/px,Math.abs(alpha)<eps&&(alpha=0),alpha)},_print_array:function(arr){var i,end;for(i=0;i<arr.length;i++)try{end="",arr[i]._end&&(end=" end"),console.log(i,arr[i].coords.usrCoords,arr[i].data.type,"\t","prev",arr[i]._prev.coords.usrCoords,"next",arr[i]._next.coords.usrCoords+end)}catch(e){console.log(i,arr[i].coords.usrCoords)}},_print_list:function(P){for(var alpha,cnt=0;cnt<100&&(alpha=P.data?P.data.alpha:"-",console.log("\t",P.coords.usrCoords,"\n\t\tis:",P.intersection,"end:",P._end,alpha,"\n\t\t-:",P._prev.coords.usrCoords,"\n\t\t+:",P._next.coords.usrCoords,"\n\t\tn:",P.intersection?P.neighbour.coords.usrCoords:"-"),!P._end);)P=P._next,cnt++},_noOverlap:function(p1,p2,q1,q2){var k,minp,maxp,minq,maxq,eps=Math.sqrt(Mat.eps),no_overlap=!1;for(k=0;k<3;k++)if(minp=Math.min(p1[k],p2[k]),maxp=Math.max(p1[k],p2[k]),minq=Math.min(q1[k],q2[k]),maxq=Math.max(q1[k],q2[k]),maxp<minq-eps||minp>maxq+eps){no_overlap=!0;break}return no_overlap},findIntersections:function(S,C,board){var i,j,crds,Si,Si1,Cj,Cj1,d1,d2,alpha,type,IS,IC,res=[],eps=Mat.eps,S_le=S.length,C_le=C.length,S_intersect=[],S_crossings=[],C_crossings=[],hasMultCompsS=!1,hasMultCompsC=!1;for(j=0;j<C_le;j++)C_crossings.push([]);for(i=0;i<S_le;i++)if(S_crossings.push([]),this._isSeparator(S[i])||this._isSeparator(S[(i+1)%S_le]))hasMultCompsS=!0;else{if(hasMultCompsS&&i===S_le-1)break;for(Si=S[i].coords.usrCoords,Si1=S[(i+1)%S_le].coords.usrCoords,j=0;j<C_le;j++)if(this._isSeparator(C[j])||this._isSeparator(C[(j+1)%C_le]))hasMultCompsC=!0;else{if(hasMultCompsC&&j===C_le-1)break;if(Cj=C[j].coords.usrCoords,Cj1=C[(j+1)%C_le].coords.usrCoords,!this._noOverlap(Si,Si1,Cj,Cj1)&&(res=Geometry.meetSegmentSegment(Si,Si1,Cj,Cj1),d1=Geometry.distance(Si,Si1,3),d2=Geometry.distance(Cj,Cj1,3),res[1]*d1>-eps&&res[1]<1-eps/d1&&res[2]*d2>-eps&&res[2]<1-eps/d2||res[1]===1/0&&res[2]===1/0&&Mat.norm(res[0],3)<eps)){if(crds=new Coords(Const.COORDS_BY_USER,res[0],board),type="X",Math.abs(res[1])*d1<eps||Math.abs(res[2])*d2<eps)type="T",Math.abs(res[1])*d1<eps&&(res[1]=0),Math.abs(res[2])*d2<eps&&(res[2]=0),crds=0===res[1]?new Coords(Const.COORDS_BY_USER,Si,board):new Coords(Const.COORDS_BY_USER,Cj,board);else if(res[1]===1/0&&res[2]===1/0&&Mat.norm(res[0],3)<eps){(alpha=this._inbetween(Si,Cj,Cj1))>=0&&alpha<1&&(type="T",crds=new Coords(Const.COORDS_BY_USER,Si,board),res[1]=0,res[2]=alpha,IS=new this.Vertex(crds,i,res[1],S,"S",type),IC=new this.Vertex(crds,j,res[2],C,"C",type),IS.neighbour=IC,IC.neighbour=IS,S_crossings[i].push(IS),C_crossings[j].push(IC)),alpha=this._inbetween(Cj,Si,Si1),Geometry.distance(Si,Cj,3)>eps&&alpha>=0&&alpha<1&&(type="T",crds=new Coords(Const.COORDS_BY_USER,Cj,board),res[1]=alpha,res[2]=0,IS=new this.Vertex(crds,i,res[1],S,"S",type),IC=new this.Vertex(crds,j,res[2],C,"C",type),IS.neighbour=IC,IC.neighbour=IS,S_crossings[i].push(IS),C_crossings[j].push(IC));continue}false,IS=new this.Vertex(crds,i,res[1],S,"S",type),IC=new this.Vertex(crds,j,res[2],C,"C",type),IS.neighbour=IC,IC.neighbour=IS,S_crossings[i].push(IS),C_crossings[j].push(IC)}}}for(S_intersect=this.sortIntersections(S_crossings),i=0;i<S_intersect.length;i++)S_intersect[i].data.idx=i,S_intersect[i].neighbour.data.idx=i;return[S_intersect,this.sortIntersections(C_crossings)]},_getPosition:function(q,p1,p2,p3){var s1=this.det(q,p1,p2),s2=this.det(q,p2,p3);return this.det(p1,p2,p3)>=0?s1>=0&&s2>=0?"left":"right":s1>=0||s2>=0?"left":"right"},_classifyDegenerateIntersections:function(P){var Pp,Pm,Qp,Qm,Q,side,cnt,tmp,oppositeDir,s1,s2,s3,s4;for(false,cnt=0,P._tours=0;;){if(P.intersection&&"T"===P.data.type&&(Pp=P._next.coords.usrCoords,Pm=P._prev.coords.usrCoords,Geometry.distance(P.coords.usrCoords,Pp,3)<Mat.eps&&(Pp=P._next._next.coords.usrCoords),Geometry.distance(P.coords.usrCoords,Pm,3)<Mat.eps&&(Pm=P._prev._prev.coords.usrCoords),Qm=(Q=P.neighbour)._prev.coords.usrCoords,Qp=Q._next.coords.usrCoords,Geometry.distance(Q.coords.usrCoords,Qp,3)<Mat.eps&&(Qp=Q._next._next.coords.usrCoords),Geometry.distance(Q.coords.usrCoords,Qm,3)<Mat.eps&&(Qm=Q._prev._prev.coords.usrCoords),s1=this.det(P.coords.usrCoords,Pm,Qm),s2=this.det(P.coords.usrCoords,Pp,Qp),s3=this.det(P.coords.usrCoords,Pm,Qp),s4=this.det(P.coords.usrCoords,Pp,Qm),0===s1&&0===s2&&0===s3&&0===s4&&(P.coords.usrCoords[1]*=1+Math.random()*Mat.eps,P.coords.usrCoords[2]*=1+Math.random()*Mat.eps,Q.coords.usrCoords[1]=P.coords.usrCoords[1],Q.coords.usrCoords[2]=P.coords.usrCoords[2],s1=this.det(P.coords.usrCoords,Pm,Qm),s2=this.det(P.coords.usrCoords,Pp,Qp),s3=this.det(P.coords.usrCoords,Pm,Qp),s4=this.det(P.coords.usrCoords,Pp,Qm)),oppositeDir=!1,0===s1?Geometry.affineRatio(P.coords.usrCoords,Pm,Qm)<0&&(oppositeDir=!0):0===s2?Geometry.affineRatio(P.coords.usrCoords,Pp,Qp)<0&&(oppositeDir=!0):0===s3?Geometry.affineRatio(P.coords.usrCoords,Pm,Qp)>0&&(oppositeDir=!0):0===s4&&Geometry.affineRatio(P.coords.usrCoords,Pp,Qm)>0&&(oppositeDir=!0),oppositeDir&&(tmp=Qm,Qm=Qp,Qp=tmp,tmp=s1,s1=s3,s3=tmp,tmp=s2,s2=s4,s4=tmp),Type.exists(P.delayedStatus)||(P.delayedStatus=[]),0===s1&&0===s2?P.delayedStatus=["on","on"]:0===s1?(side=this._getPosition(Pp,Qm,Q.coords.usrCoords,Qp),P.delayedStatus=["on",side]):0===s2?(side=this._getPosition(Pm,Qm,Q.coords.usrCoords,Qp),P.delayedStatus=[side,"on"]):0===P.delayedStatus.length&&(this._getPosition(Pm,Qm,Q.coords.usrCoords,Qp)!==this._getPosition(Pp,Qm,Q.coords.usrCoords,Qp)?P.data.type="X":P.data.type="B")),Type.exists(P._tours)&&P._tours++,P._tours>3||P._end||cnt>1e3){cnt>1e3&&console.log("Clipping: _classifyDegenerateIntersections exit"),Type.exists(P._tours)&&delete P._tours;break}P.intersection&&cnt++,P=P._next}},_handleIntersectionChains:function(P){var P_start,cnt=0,start_status="Null",intersection_chain=!1,wait_for_exit=!1;for(false;!0===P.intersection&&("T"===P.data.type&&("on"!==P.delayedStatus[0]&&"on"===P.delayedStatus[1]?(intersection_chain=!0,P_start=P,start_status=P.delayedStatus[0]):intersection_chain&&"on"===P.delayedStatus[0]&&"on"===P.delayedStatus[1]?P.data.type="B":intersection_chain&&"on"===P.delayedStatus[0]&&"on"!==P.delayedStatus[1]&&(intersection_chain=!1,start_status===P.delayedStatus[1]?(P_start.data.type="DB",P.data.type="DB"):(P_start.data.type="DX",P.data.type="DX"))),cnt++),P._end&&(wait_for_exit=!0),!wait_for_exit||intersection_chain;){if(cnt>1e3){console.log("Warning: _handleIntersectionChains: intersection chain reached maximum numbers of iterations");break}P=P._next}},_handleFullyDegenerateCase:function(S,C,board){var P,Q,l,M,q1,q2,node,i,j,le,le2,is_on_Q,is_fully_degenerated,arr=[S,C];for(l=0;l<2;l++){for(le=(P=arr[l]).length,i=0,is_fully_degenerated=!0;i<le;i++)if(!P[i].intersection){is_fully_degenerated=!1;break}if(is_fully_degenerated)for(le2=(Q=arr[(l+1)%2]).length,i=0;i<le;i++){for(q1=P[i].coords.usrCoords,q2=P[(i+1)%le].coords.usrCoords,M=[.5*(q1[0]+q2[0]),.5*(q1[1]+q2[1]),.5*(q1[2]+q2[2])],j=0,is_on_Q=!1;j<le2;j++)if(Math.abs(this.det(Q[j].coords.usrCoords,Q[(j+1)%le2].coords.usrCoords,M))<Mat.eps){is_on_Q=!0;break}if(!is_on_Q){node={pos:i,intersection:!1,coords:new Coords(Const.COORDS_BY_USER,M,board),elementClass:Const.OBJECT_CLASS_POINT},P[i]._next=node,node._prev=P[i],P[(i+1)%le]._prev=node,node._next=P[(i+1)%le],P[i]._end&&(P[i]._end=!1,node._end=!0);break}}}},_getStatus:function(P,path){for(;P.intersection&&!P._end;)P=P._next;return[P,this.windingNumber(P.coords.usrCoords,path)%2==0?"entry":"exit"]},markEntryExit:function(path1,path2,starters){var status,P,cnt,res,i,len,start,chain_start=null,intersection_chain=0;for(len=starters.length,i=0;i<len;i++)for(start=starters[i],this._classifyDegenerateIntersections(path1[start]),this._handleIntersectionChains(path1[start]),P=(res=this._getStatus(path1[start],path2))[0],status=res[1],P._starter=!0,cnt=0,chain_start=null,intersection_chain=0;!0===P.intersection&&("X"===P.data.type&&1===intersection_chain&&(chain_start.entry_exit=status,"exit"===status&&(chain_start.data.type="X"),intersection_chain=2),"X"!==P.data.type&&"DB"!==P.data.type||(P.entry_exit=status,status="entry"===status?"exit":"entry"),"DX"===P.data.type&&(0===intersection_chain?(chain_start=P,intersection_chain=1):1===intersection_chain?(P.entry_exit=status,chain_start.entry_exit=status,"exit"===status?chain_start.data.type="X":P.data.type="X",status="entry"===status?"exit":"entry",chain_start=null,intersection_chain=0):2===intersection_chain&&(P.entry_exit=status,P.data.type="X",status="entry"===status?"exit":"entry",chain_start=null,intersection_chain=0))),P=P._next,!(Type.exists(P._starter)||cnt>1e4);)cnt++},_stayOnPath:function(P,status){var stay=!0;return P.intersection&&"B"!==P.data.type&&(stay=status===P.entry_exit),stay},_addVertex:function(path,vertex,DEBUG){return isNaN(vertex.coords.usrCoords[1])||isNaN(vertex.coords.usrCoords[2])||path.push(vertex),vertex.intersection&&vertex.data.done?(DEBUG&&console.log("Add last intersection point",vertex.coords.usrCoords,"on",vertex.data.pathname,vertex.entry_exit,vertex.data.type),!0):(vertex.intersection&&(vertex.data.done=!0,DEBUG&&console.log("Add intersection point",vertex.coords.usrCoords,"on",vertex.data.pathname,vertex.entry_exit,vertex.data.type)),!1)},tracing:function(S,S_intersect,clip_type){var P,current,start,status,cnt=0,S_idx=0,path=[],done=!1;for(false;S_idx<S_intersect.length&&cnt<1e4;)if((current=S_intersect[S_idx]).data.done||"X"!==current.data.type)S_idx++;else{false,path.length>0&&path.push([NaN,NaN]),start=current.data.idx,P=S,done=this._addVertex(path,current,false),status=current.entry_exit;do{if(done)break;if("intersection"===clip_type&&"entry"===current.entry_exit||"union"===clip_type&&"exit"===current.entry_exit||"difference"===clip_type&&P===S==("exit"===current.entry_exit)){false;do{if(current=current._next,done=this._addVertex(path,current,false))break}while(this._stayOnPath(current,status));cnt++}else{false;do{if(current=current._prev,done=this._addVertex(path,current,false))break}while(this._stayOnPath(current,status));cnt++}if(done)break;if(!current.neighbour)return console.log("Tracing: emergency break - no neighbour!!!!!!!!!!!!!!!!!",cnt),[[0],[0]];if((current=current.neighbour).data.done)break;current.data.done=!0,status=current.entry_exit,P=current.data.path}while(current.data.idx!==start&&cnt<1e4);cnt>=1e4&&console.log("Tracing: stopping an infinite loop!",cnt),S_idx++}return this._getCoordsArrays(path,!1)},isEmptyCase:function(S,C,clip_type){return"intersection"===clip_type&&(0===S.length||0===C.length)||("union"===clip_type&&0===S.length&&0===C.length||"difference"===clip_type&&0===S.length)},_getCoordsArrays:function(path,doClose){var i,pathX=[],pathY=[],le=path.length;for(i=0;i<le;i++)path[i].coords?(pathX.push(path[i].coords.usrCoords[1]),pathY.push(path[i].coords.usrCoords[2])):(pathX.push(path[i][0]),pathY.push(path[i][1]));return doClose&&le>0&&(path[0].coords?(pathX.push(path[0].coords.usrCoords[1]),pathY.push(path[0].coords.usrCoords[2])):(pathX.push(path[0][0]),pathY.push(path[0][1]))),[pathX,pathY]},handleEmptyIntersection:function(S,C,clip_type){var P,Q,doClose=!1,path=[];if(0===S.length)return path="union"===clip_type?C:[],this._getCoordsArrays(path,!0);if(0===C.length)return path="intersection"===clip_type?[]:S,this._getCoordsArrays(path,!0);if(S.length>0)for(P=S[0];P.intersection&&!(P=P._next)._end;);if(C.length>0)for(Q=C[0];Q.intersection&&!(Q=Q._next)._end;);return 0===this.windingNumber(P.coords.usrCoords,C)?0!==this.windingNumber(Q.coords.usrCoords,S)?("union"===clip_type?(path=path.concat(S)).push(S[0]):"difference"===clip_type&&((path=path.concat(S)).push(S[0]),Geometry.signedPolygon(S)*Geometry.signedPolygon(C)>0&&path.reverse(),path.push([NaN,NaN])),"difference"!==clip_type&&"intersection"!==clip_type||((path=path.concat(C)).push(C[0]),doClose=!1)):"difference"===clip_type?(path=path.concat(S),doClose=!0):"union"===clip_type&&((path=path.concat(S)).push(S[0]),path.push([NaN,NaN]),(path=path.concat(C)).push(C[0])):"intersection"===clip_type?(path=path.concat(S),doClose=!0):"union"===clip_type&&(path=path.concat(C)).push(C[0]),this._getCoordsArrays(path,doClose)},_countCrossingIntersections:function(intersections){var i,le=intersections.length,sum=0;for(i=0;i<le;i++)"X"===intersections[i].data.type&&sum++;return sum},_getPath:function(obj,board){var i,len,r,rad,angle,alpha,steps,S=[];if(obj.elementClass!==Const.OBJECT_CLASS_CURVE||obj.type!==Const.OBJECT_TYPE_ARC&&obj.type!==Const.OBJECT_TYPE_SECTOR){if(obj.elementClass===Const.OBJECT_CLASS_CURVE&&Type.exists(obj.points))for(len=obj.numberPoints,i=0;i<len;i++)this._addToList(S,obj.points[i],i);else if(obj.type===Const.OBJECT_TYPE_POLYGON)for(i=0;i<obj.vertices.length;i++)this._addToList(S,obj.vertices[i].coords,i);else if(obj.elementClass===Const.OBJECT_CLASS_CIRCLE)for(steps=359,r=obj.Radius(),rad=2*Math.PI/steps,i=0;i<=steps;i++)this._addToList(S,new Coords(Const.COORDS_BY_USER,[obj.center.coords.usrCoords[0],obj.center.coords.usrCoords[1]+Math.cos(i*rad)*r,obj.center.coords.usrCoords[2]+Math.sin(i*rad)*r],board),i);else if(Type.isArray(obj))for(len=obj.length,i=0;i<len;i++)Type.exists(obj[i].coords)?this._addToList(S,obj[i].coords,i):Type.isArray(obj[i])?this._addToList(S,new Coords(Const.COORDS_BY_USER,obj[i],board),i):Type.exists(obj[i].usrCoords)&&this._addToList(S,obj[i],i)}else{for(angle=Geometry.rad(obj.radiuspoint,obj.center,obj.anglepoint),steps=Math.floor(180*angle/Math.PI),r=obj.Radius(),rad=angle/steps,alpha=Math.atan2(obj.radiuspoint.coords.usrCoords[2]-obj.center.coords.usrCoords[2],obj.radiuspoint.coords.usrCoords[1]-obj.center.coords.usrCoords[1]),obj.type===Const.OBJECT_TYPE_SECTOR&&this._addToList(S,obj.center.coords,0),i=0;i<=steps;i++)this._addToList(S,new Coords(Const.COORDS_BY_USER,[obj.center.coords.usrCoords[0],obj.center.coords.usrCoords[1]+Math.cos(i*rad+alpha)*r,obj.center.coords.usrCoords[2]+Math.sin(i*rad+alpha)*r],board),i+1);obj.type===Const.OBJECT_TYPE_SECTOR&&this._addToList(S,obj.center.coords,steps+2)}return S},greinerHormann:function(subject,clip,clip_type,board){var len,S_intersect,S_starters,C_starters,S=[],C=[];return(len=(S=this._getPath(subject,board)).length)>0&&Geometry.distance(S[0].coords.usrCoords,S[len-1].coords.usrCoords,3)<Mat.eps&&S.pop(),(len=(C=this._getPath(clip,board)).length)>0&&Geometry.distance(C[0].coords.usrCoords,C[len-1].coords.usrCoords,3)<Mat.eps*Mat.eps&&C.pop(),this.isEmptyCase(S,C,clip_type)?[[],[]]:(S_starters=this.makeDoublyLinkedList(S),C_starters=this.makeDoublyLinkedList(C),S_intersect=this.findIntersections(S,C,board)[0],this._handleFullyDegenerateCase(S,C,board),this.markEntryExit(S,C,S_starters),this.markEntryExit(C,S,C_starters),0===this._countCrossingIntersections(S_intersect)?this.handleEmptyIntersection(S,C,clip_type):this.tracing(S,S_intersect,clip_type))},union:function(path1,path2,board){return this.greinerHormann(path1,path2,"union",board)},intersection:function(path1,path2,board){return this.greinerHormann(path1,path2,"intersection",board)},difference:function(path1,path2,board){return this.greinerHormann(path1,path2,"difference",board)}},JXG.extend(Mat.Clip,{}),Mat.Clip})),define("math/poly",["jxg","math/math","utils/type"],(function(JXG,Mat,Type){return Mat.Poly={},Mat.Poly.Ring=function(variables){this.vars=variables},JXG.extend(Mat.Poly.Ring.prototype,{}),Mat.Poly.Monomial=function(ring,coefficient,exponents){var i;if(!Type.exists(ring))throw new Error("JSXGraph error: In JXG.Math.Poly.monomial missing parameter 'ring'.");for(Type.isArray(exponents)||(exponents=[]),i=(exponents=exponents.slice(0,ring.vars.length)).length;i<ring.vars.length;i++)exponents.push(0);this.ring=ring,this.coefficient=coefficient||0,this.exponents=Type.deepCopy(exponents)},JXG.extend(Mat.Poly.Monomial.prototype,{copy:function(){return new Mat.Poly.Monomial(this.ring,this.coefficient,this.exponents)},print:function(){var i,s=[];for(i=0;i<this.ring.vars.length;i++)s.push(this.ring.vars[i]+"^"+this.exponents[i]);return this.coefficient+"*"+s.join("*")}}),Mat.Poly.Polynomial=function(ring,str){var mons;if(!Type.exists(ring))throw new Error("JSXGraph error: In JXG.Math.Poly.polynomial missing parameter 'ring'.");mons=Type.exists(str)&&Type.isString(str)?void 0:[],this.ring=ring,this.monomials=mons},JXG.extend(Mat.Poly.Polynomial.prototype,{findSignature:function(sig){var i;for(i=0;i<this.monomials.length;i++)if(Type.cmpArrays(this.monomials[i].exponents,sig))return i;return-1},addSubMonomial:function(m,factor){var i;(i=this.findSignature(m.exponents))>-1?this.monomials[i].coefficient+=factor*m.coefficient:(m.coefficient*=factor,this.monomials.push(m))},add:function(mp){var i;if(!Type.exists(mp)||mp.ring!==this.ring)throw new Error("JSXGraph error: In JXG.Math.Poly.polynomial.add either summand is undefined or rings don't match.");if(Type.isArray(mp.exponents))this.addSubMonomial(mp,1);else for(i=0;i<mp.monomials.length;i++)this.addSubMonomial(mp.monomials[i],1)},sub:function(mp){var i;if(!Type.exists(mp)||mp.ring!==this.ring)throw new Error("JSXGraph error: In JXG.Math.Poly.polynomial.sub either summand is undefined or rings don't match.");if(Type.isArray(mp.exponents))this.addSubMonomial(mp,-1);else for(i=0;i<mp.monomials.length;i++)this.addSubMonomial(mp.monomials[i],-1)},copy:function(){var i,p;for(p=new Mat.Poly.Polynomial(this.ring),i=0;i<this.monomials.length;i++)p.monomials.push(this.monomials[i].copy());return p},print:function(){var i,s=[];for(i=0;i<this.monomials.length;i++)s.push("("+this.monomials[i].print()+")");return s.join("+")}}),Mat.Poly})),define("math/complex",["jxg","utils/type"],(function(JXG,Type){return JXG.Complex=function(x,y){this.isComplex=!0,x&&x.isComplex&&(y=x.imaginary,x=x.real),this.real=x||0,this.imaginary=y||0,this.absval=0,this.angle=0},JXG.extend(JXG.Complex.prototype,{toString:function(){return this.real+" + "+this.imaginary+"i"},add:function(c){return Type.isNumber(c)?this.real+=c:(this.real+=c.real,this.imaginary+=c.imaginary),this},sub:function(c){return Type.isNumber(c)?this.real-=c:(this.real-=c.real,this.imaginary-=c.imaginary),this},mult:function(c){var re,im;return Type.isNumber(c)?(this.real*=c,this.imaginary*=c):(re=this.real,im=this.imaginary,this.real=re*c.real-im*c.imaginary,this.imaginary=re*c.imaginary+im*c.real),this},div:function(c){var denom,im,re;if(Type.isNumber(c)){if(Math.abs(c)<Math.eps)return this.real=1/0,this.imaginary=1/0,this;this.real/=c,this.imaginary/=c}else{if(Math.abs(c.real)<Math.eps&&Math.abs(c.imaginary)<Math.eps)return this.real=1/0,this.imaginary=1/0,this;denom=c.real*c.real+c.imaginary*c.imaginary,re=this.real,im=this.imaginary,this.real=(re*c.real+im*c.imaginary)/denom,this.imaginary=(im*c.real-re*c.imaginary)/denom}return this},conj:function(){return this.imaginary*=-1,this}}),JXG.C={},JXG.C.add=function(z1,z2){var z=new JXG.Complex(z1);return z.add(z2),z},JXG.C.sub=function(z1,z2){var z=new JXG.Complex(z1);return z.sub(z2),z},JXG.C.mult=function(z1,z2){var z=new JXG.Complex(z1);return z.mult(z2),z},JXG.C.div=function(z1,z2){var z=new JXG.Complex(z1);return z.div(z2),z},JXG.C.conj=function(z1){var z=new JXG.Complex(z1);return z.conj(),z},JXG.C.abs=function(z1){var z=new JXG.Complex(z1);return z.conj(),z.mult(z1),Math.sqrt(z.real)},JXG.Complex.C=JXG.C,JXG.Complex})),define("utils/color",["jxg","utils/type","math/math"],(function(JXG,Type,Mat){var simpleColors={aliceblue:"f0f8ff",antiquewhite:"faebd7",aqua:"00ffff",aquamarine:"7fffd4",azure:"f0ffff",beige:"f5f5dc",bisque:"ffe4c4",black:"000000",blanchedalmond:"ffebcd",blue:"0000ff",blueviolet:"8a2be2",brown:"a52a2a",burlywood:"deb887",cadetblue:"5f9ea0",chartreuse:"7fff00",chocolate:"d2691e",coral:"ff7f50",cornflowerblue:"6495ed",cornsilk:"fff8dc",crimson:"dc143c",cyan:"00ffff",darkblue:"00008b",darkcyan:"008b8b",darkgoldenrod:"b8860b",darkgray:"a9a9a9",darkgreen:"006400",darkkhaki:"bdb76b",darkmagenta:"8b008b",darkolivegreen:"556b2f",darkorange:"ff8c00",darkorchid:"9932cc",darkred:"8b0000",darksalmon:"e9967a",darkseagreen:"8fbc8f",darkslateblue:"483d8b",darkslategray:"2f4f4f",darkturquoise:"00ced1",darkviolet:"9400d3",deeppink:"ff1493",deepskyblue:"00bfff",dimgray:"696969",dodgerblue:"1e90ff",feldspar:"d19275",firebrick:"b22222",floralwhite:"fffaf0",forestgreen:"228b22",fuchsia:"ff00ff",gainsboro:"dcdcdc",ghostwhite:"f8f8ff",gold:"ffd700",goldenrod:"daa520",gray:"808080",green:"008000",greenyellow:"adff2f",honeydew:"f0fff0",hotpink:"ff69b4",indianred:"cd5c5c",indigo:"4b0082",ivory:"fffff0",khaki:"f0e68c",lavender:"e6e6fa",lavenderblush:"fff0f5",lawngreen:"7cfc00",lemonchiffon:"fffacd",lightblue:"add8e6",lightcoral:"f08080",lightcyan:"e0ffff",lightgoldenrodyellow:"fafad2",lightgrey:"d3d3d3",lightgreen:"90ee90",lightpink:"ffb6c1",lightsalmon:"ffa07a",lightseagreen:"20b2aa",lightskyblue:"87cefa",lightslateblue:"8470ff",lightslategray:"778899",lightsteelblue:"b0c4de",lightyellow:"ffffe0",lime:"00ff00",limegreen:"32cd32",linen:"faf0e6",magenta:"ff00ff",maroon:"800000",mediumaquamarine:"66cdaa",mediumblue:"0000cd",mediumorchid:"ba55d3",mediumpurple:"9370d8",mediumseagreen:"3cb371",mediumslateblue:"7b68ee",mediumspringgreen:"00fa9a",mediumturquoise:"48d1cc",mediumvioletred:"c71585",midnightblue:"191970",mintcream:"f5fffa",mistyrose:"ffe4e1",moccasin:"ffe4b5",navajowhite:"ffdead",navy:"000080",oldlace:"fdf5e6",olive:"808000",olivedrab:"6b8e23",orange:"ffa500",orangered:"ff4500",orchid:"da70d6",palegoldenrod:"eee8aa",palegreen:"98fb98",paleturquoise:"afeeee",palevioletred:"d87093",papayawhip:"ffefd5",peachpuff:"ffdab9",peru:"cd853f",pink:"ffc0cb",plum:"dda0dd",powderblue:"b0e0e6",purple:"800080",red:"ff0000",rosybrown:"bc8f8f",royalblue:"4169e1",saddlebrown:"8b4513",salmon:"fa8072",sandybrown:"f4a460",seagreen:"2e8b57",seashell:"fff5ee",sienna:"a0522d",silver:"c0c0c0",skyblue:"87ceeb",slateblue:"6a5acd",slategray:"708090",snow:"fffafa",springgreen:"00ff7f",steelblue:"4682b4",tan:"d2b48c",teal:"008080",thistle:"d8bfd8",tomato:"ff6347",turquoise:"40e0d0",violet:"ee82ee",violetred:"d02090",wheat:"f5deb3",white:"ffffff",whitesmoke:"f5f5f5",yellow:"ffff00",yellowgreen:"9acd32"},colorDefs=[{re:/^\s*rgba\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*([\d.]{1,3})\s*\)\s*$/,example:["rgba(123, 234, 45, 0.5)","rgba(255,234,245,1.0)"],process:function(bits){return[parseInt(bits[1],10),parseInt(bits[2],10),parseInt(bits[3],10)]}},{re:/^\s*rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)\s*$/,example:["rgb(123, 234, 45)","rgb(255,234,245)"],process:function(bits){return[parseInt(bits[1],10),parseInt(bits[2],10),parseInt(bits[3],10)]}},{re:/^(\w{2})(\w{2})(\w{2})$/,example:["#00ff00","336699"],process:function(bits){return[parseInt(bits[1],16),parseInt(bits[2],16),parseInt(bits[3],16)]}},{re:/^(\w{1})(\w{1})(\w{1})$/,example:["#fb0","f0f"],process:function(bits){return[parseInt(bits[1]+bits[1],16),parseInt(bits[2]+bits[2],16),parseInt(bits[3]+bits[3],16)]}}];return JXG.rgbParser=function(color,ag,ab){var color_string,channels,re,processor,bits,i,r,g,b,testFloat,values=color;if(!Type.exists(color))return[];if(Type.exists(ag)&&Type.exists(ab)&&(values=[color,ag,ab]),color_string=values,testFloat=!1,Type.isArray(color_string)){for(i=0;i<3;i++)testFloat=testFloat||/\./.test(values[i].toString());for(i=0;i<3;i++)testFloat=testFloat&&values[i]>=0&&values[i]<=1;return testFloat?[Math.ceil(255*values[0]),Math.ceil(255*values[1]),Math.ceil(255*values[2])]:values}for("string"==typeof values&&(color_string=values),"#"===color_string.charAt(0)&&(color_string=color_string.substr(1,6)),color_string=color_string.replace(/ /g,"").toLowerCase(),color_string=simpleColors[color_string]||color_string,i=0;i<colorDefs.length;i++)re=colorDefs[i].re,processor=colorDefs[i].process,(bits=re.exec(color_string))&&(r=(channels=processor(bits))[0],g=channels[1],b=channels[2]);return isNaN(r)||isNaN(g)||isNaN(b)?[]:[r=r<0||isNaN(r)?0:r>255?255:r,g=g<0||isNaN(g)?0:g>255?255:g,b=b<0||isNaN(b)?0:b>255?255:b]},JXG.rgb2css=function(color,ag,ab){var r;return"rgb("+(r=JXG.rgbParser(color,ag,ab))[0]+", "+r[1]+", "+r[2]+")"},JXG.rgb2hex=function(color,ag,ab){var r,g,b;return g=(r=JXG.rgbParser(color,ag,ab))[1],b=r[2],r=(r=r[0]).toString(16),g=g.toString(16),b=b.toString(16),1===r.length&&(r="0"+r),1===g.length&&(g="0"+g),1===b.length&&(b="0"+b),"#"+r+g+b},JXG.hex2rgb=function(hex){return JXG.deprecated("JXG.hex2rgb()","JXG.rgb2css()"),JXG.rgb2css(hex)},JXG.hsv2rgb=function(H,S,V){var R,G,B,f,i,hTemp,p,q,t;if(H=(H%360+360)%360,0===S){if(!(isNaN(H)||H<Mat.eps))return"#ffffff";R=V,G=V,B=V}else switch(hTemp=H>=360?0:H,p=V*(1-S),q=V*(1-S*(f=(hTemp/=60)-(i=Math.floor(hTemp)))),t=V*(1-S*(1-f)),i){case 0:R=V,G=t,B=p;break;case 1:R=q,G=V,B=p;break;case 2:R=p,G=V,B=t;break;case 3:R=p,G=q,B=V;break;case 4:R=t,G=p,B=V;break;case 5:R=V,G=p,B=q}return["#",R=2===(R=Math.round(255*R).toString(16)).length?R:1===R.length?"0"+R:"00",G=2===(G=Math.round(255*G).toString(16)).length?G:1===G.length?"0"+G:"00",B=2===(B=Math.round(255*B).toString(16)).length?B:1===B.length?"0"+B:"00"].join("")},JXG.rgb2hsv=function(color,ag,ab){var r,g,b,fr,fg,fb,fmax,fmin,h,s,v,max,min;return g=(r=JXG.rgbParser(color,ag,ab))[1],b=r[2],fr=(r=r[0])/255,fg=g/255,fb=b/255,max=Math.max(r,g,b),fmin=(min=Math.min(r,g,b))/255,s=0,(v=fmax=max/255)>0&&(s=(v-fmin)/v),h=1/(fmax-fmin),s>0&&(max===r?h*=fg-fb:h=max===g?2+(fb-fr)*h:4+(fr-fg)*h),(h*=60)<0&&(h+=360),max===min&&(h=0),[h,s,v]},JXG.rgb2LMS=function(color,ag,ab){var r,g,b,l,m,s,ret,matrix=[[.05059983,.08585369,.0095242],[.01893033,.08925308,.01370054],[.00292202,.00975732,.07145979]];return g=(r=JXG.rgbParser(color,ag,ab))[1],b=r[2],r=r[0],r=Math.pow(r,.476190476),g=Math.pow(g,.476190476),b=Math.pow(b,.476190476),(ret=[l=r*matrix[0][0]+g*matrix[0][1]+b*matrix[0][2],m=r*matrix[1][0]+g*matrix[1][1]+b*matrix[1][2],s=r*matrix[2][0]+g*matrix[2][1]+b*matrix[2][2]]).l=l,ret.m=m,ret.s=s,ret},JXG.LMS2rgb=function(l,m,s){var r,g,b,ret,matrix=[[30.830854,-29.832659,1.610474],[-6.481468,17.715578,-2.532642],[-.37569,-1.199062,14.273846]],lut_lookup=function(value){for(var offset=127,step=64;step>0;){if(Math.pow(offset,.476190476)>value)offset-=step;else{if(Math.pow(offset+1,.476190476)>value)return offset;offset+=step}step/=2}return 254===offset&&13.994955247<value?255:offset};return r=l*matrix[0][0]+m*matrix[0][1]+s*matrix[0][2],g=l*matrix[1][0]+m*matrix[1][1]+s*matrix[1][2],b=l*matrix[2][0]+m*matrix[2][1]+s*matrix[2][2],(ret=[r=lut_lookup(r),g=lut_lookup(g),b=lut_lookup(b)]).r=r,ret.g=g,ret.b=b,ret},JXG.rgba2rgbo=function(rgba){var opacity;return 9===rgba.length&&"#"===rgba.charAt(0)?(opacity=parseInt(rgba.substr(7,2).toUpperCase(),16)/255,rgba=rgba.substr(0,7)):opacity=1,[rgba,opacity]},JXG.rgbo2rgba=function(rgb,o){var rgba;return"none"===rgb?rgb:(1===(rgba=Math.round(255*o).toString(16)).length&&(rgba="0"+rgba),rgb+rgba)},JXG.rgb2bw=function(color){var x,tmp,arr;return"none"===color?color:(arr=JXG.rgbParser(color),x=Math.floor(.3*arr[0]+.59*arr[1]+.11*arr[2]),color="#"+(tmp="0123456789ABCDEF".charAt(x>>4&15)+"0123456789ABCDEF".charAt(15&x))+tmp+tmp)},JXG.rgb2cb=function(color,deficiency){var rgb,l,m,s,lms,a1,b1,c1,a2,b2,c2,HexChars="0123456789ABCDEF";if("none"===color)return color;switch(l=(lms=JXG.rgb2LMS(color))[0],m=lms[1],s=lms[2],deficiency=deficiency.toLowerCase()){case"protanopia":a1=-.06150039994295001,b1=.08277001656812001,c1=-.013200141220000003,a2=.05858939668799999,b2=-.07934519995360001,c2=.013289415272000003,l=s/m<.6903216543277437?-(b1*m+c1*s)/a1:-(b2*m+c2*s)/a2;break;case"tritanopia":a1=-.00058973116217,b1=.007690316482,c1=-.01011703519052,a2=.025495080838999994,b2=-.0422740347,c2=.017005316784,s=m/l<.8349489908460004?-(a1*l+b1*m)/c1:-(a2*l+b2*m)/c2;break;default:a1=-.06150039994295001,b1=.08277001656812001,c1=-.013200141220000003,a2=.05858939668799999,b2=-.07934519995360001,c2=.013289415272000003,m=s/l<.5763833686400911?-(a1*l+c1*s)/b1:-(a2*l+c2*s)/b2}return rgb=JXG.LMS2rgb(l,m,s),color="#"+(HexChars.charAt(rgb[0]>>4&15)+HexChars.charAt(15&rgb[0])),color+=HexChars.charAt(rgb[1]>>4&15)+HexChars.charAt(15&rgb[1]),color+=HexChars.charAt(rgb[2]>>4&15)+HexChars.charAt(15&rgb[2])},JXG.autoHighlight=function(colstr){var col=JXG.rgba2rgbo(colstr),c=col[0],opa=col[1];return"#"===colstr.charAt(0)?(opa*=opa<.3?1.8:.4,JXG.rgbo2rgba(c,opa)):colstr},JXG.contrast=function(hexColor,darkColor,lightColor,threshold){var rgb,rgbBlack,l1,l2,contrastRatio;return darkColor=darkColor||"#000000",lightColor=lightColor||"#ffffff",threshold=threshold||7,rgb=JXG.rgbParser(hexColor),rgbBlack=JXG.rgbParser("#000000"),contrastRatio=(l1=.2126*Math.pow(rgb[0]/255,2.2)+.7152*Math.pow(rgb[1]/255,2.2)+.0722*Math.pow(rgb[2]/255,2.2))>(l2=.2126*Math.pow(rgbBlack[0]/255,2.2)+.7152*Math.pow(rgbBlack[1]/255,2.2)+.0722*Math.pow(rgbBlack[2]/255,2.2))?Math.floor((l1+.05)/(l2+.05)):Math.floor((l2+.05)/(l1+.05)),(contrastRatio-=1)>threshold?darkColor:lightColor},JXG.setClassicColors=function(){JXG.Options.elements.strokeColor="blue",JXG.Options.elements.fillColor="red",JXG.Options.hatch.strokeColor="blue",JXG.Options.angle.fillColor="#ff7f00",JXG.Options.angle.highlightFillColor="#ff7f00",JXG.Options.angle.strokeColor="#ff7f00",JXG.Options.angle.label.strokeColor="blue",JXG.Options.arc.strokeColor="blue",JXG.Options.circle.center.fillColor="red",JXG.Options.circle.center.strokeColor="blue",JXG.Options.circumcircle.strokeColor="blue",JXG.Options.circumcircle.center.fillColor="red",JXG.Options.circumcircle.center.strokeColor="blue",JXG.Options.circumcirclearc.strokeColor="blue",JXG.Options.circumcirclesector.strokeColor="blue",JXG.Options.circumcirclesector.fillColor="green",JXG.Options.circumcirclesector.highlightFillColor="green",JXG.Options.conic.strokeColor="blue",JXG.Options.curve.strokeColor="blue",JXG.Options.incircle.strokeColor="blue",JXG.Options.incircle.center.fillColor="red",JXG.Options.incircle.center.strokeColor="blue",JXG.Options.inequality.fillColor="red",JXG.Options.integral.fillColor="red",JXG.Options.integral.curveLeft.color="red",JXG.Options.integral.curveRight.color="red",JXG.Options.line.strokeColor="blue",JXG.Options.point.fillColor="red",JXG.Options.point.strokeColor="red",JXG.Options.polygon.fillColor="green",JXG.Options.polygon.highlightFillColor="green",JXG.Options.polygon.vertices.strokeColor="red",JXG.Options.polygon.vertices.fillColor="red",JXG.Options.regularpolygon.fillColor="green",JXG.Options.regularpolygon.highlightFillColor="green",JXG.Options.regularpolygon.vertices.strokeColor="red",JXG.Options.regularpolygon.vertices.fillColor="red",JXG.Options.riemannsum.fillColor="yellow",JXG.Options.sector.fillColor="green",JXG.Options.sector.highlightFillColor="green",JXG.Options.semicircle.center.fillColor="red",JXG.Options.semicircle.center.strokeColor="blue",JXG.Options.slopetriangle.fillColor="red",JXG.Options.slopetriangle.highlightFillColor="red",JXG.Options.turtle.arrow.strokeColor="blue"},JXG.extend(JXG,{paletteWong:{black:"#000000",orange:"#E69F00",skyblue:"#56B4E9",bluishgreen:"#009E73",yellow:"#F0E442",darkblue:"#0072B2",vermillion:"#D55E00",reddishpurple:"#CC79A7",blue:"#0072B2",red:"#D55E00",green:"#009E73",purple:"#CC79A7",white:"#ffffff"}}),JXG.palette=JXG.paletteWong,JXG})),define("options",["jxg","base/constants","math/math","utils/color","utils/type"],(function(JXG,Const,Mat,Color,Type){return JXG.Options={jc:{enabled:!0,compile:!0},board:{boundingBox:[-5,5,5,-5],maxBoundingBox:[-1/0,1/0,1/0,-1/0],zoomFactor:1,zoomX:1,zoomY:1,title:"",description:"",showCopyright:!0,axis:!1,defaultAxes:{x:{name:"x",ticks:{label:{visible:"inherit",anchorX:"middle",anchorY:"top",fontSize:12,offset:[0,-3]},drawZero:!1,visible:"inherit"}},y:{name:"y",ticks:{label:{visible:"inherit",anchorX:"right",anchorY:"middle",fontSize:12,offset:[-6,0]},tickEndings:[1,0],drawZero:!1,visible:"inherit"}}},showNavigation:!0,showZoom:!0,showReload:!1,showScreenshot:!1,screenshot:{scale:1,type:"png",symbol:"⌘",css:"background-color:#eeeeee; opacity:1.0; border:2px solid black; border-radius:10px; text-align:center",cssButton:"padding: 4px 10px; border: solid #356AA0 1px; border-radius: 5px; position: absolute; right: 2ex; top: 2ex; background-color: rgba(255, 255, 255, 0.3);"},showFullscreen:!1,fullscreen:{symbol:"□",id:null},showClearTraces:!1,keepAspectRatio:!1,ignoreLabels:!0,maxNameLength:1,document:!1,takeFirst:!1,takeSizeFromFile:!1,renderer:"auto",animationDelay:35,maxFrameRate:40,registerEvents:!0,minimizeReflow:"none",offsetX:0,offsetY:0,zoom:{enabled:!0,factorX:1.25,factorY:1.25,wheel:!0,needShift:!0,min:1e-4,max:1e4,pinchHorizontal:!0,pinchVertical:!0,pinchSensitivity:7},pan:{needShift:!0,needTwoFingers:!1,enabled:!0},drag:{enabled:!0},keyboard:{enabled:!0,dx:10,dy:10,panShift:!0,panCtrl:!1},resize:{enabled:!0,throttle:10},moveTarget:null,selection:{enabled:!1,name:"selectionPolygon",needShift:!1,needCtrl:!0,withLines:!1,vertices:{visible:!1},fillColor:"#ffff00",visible:!1},showInfobox:!0},navbar:{strokeColor:"#333333",fillColor:"transparent",highlightFillColor:"#aaaaaa",padding:"2px",position:"absolute",fontSize:"14px",cursor:"pointer",zIndex:"100",right:"5px",bottom:"5px"},elements:{strokeColor:Color.palette.blue,highlightStrokeColor:"#c3d9ff",fillColor:Color.palette.red,highlightFillColor:"none",strokeOpacity:1,highlightStrokeOpacity:1,fillOpacity:1,highlightFillOpacity:1,gradient:null,gradientSecondColor:"#ffffff",gradientSecondOpacity:1,gradientStartOffset:0,gradientEndOffset:1,gradientAngle:0,gradientCX:.5,gradientCY:.5,gradientR:.5,gradientFX:.5,gradientFY:.5,gradientFR:0,transitionDuration:100,strokeWidth:2,highlightStrokeWidth:2,fixed:!1,frozen:!1,withLabel:!1,visible:!0,priv:!1,layer:0,dash:0,shadow:!1,trace:!1,traceAttributes:{},highlight:!0,needsRegularUpdate:!0,snapToGrid:!1,scalable:!0,dragToTopOfLayer:!1,precision:"inherit",draft:{draft:!1,strokeColor:"#565656",fillColor:"#565656",strokeOpacity:.8,fillOpacity:.8,strokeWidth:1},isLabel:!1,tabindex:0},ticks:{generateLabelText:null,generateLabelValue:null,drawLabels:!1,label:{},beautifulScientificTickLabels:!1,useUnicodeMinus:!0,anchor:"left",drawZero:!1,insertTicks:!1,minTicksDistance:10,minorHeight:4,majorHeight:10,tickEndings:[1,1],minorTicks:4,scale:1,scaleSymbol:"",labels:[],maxLabelLength:5,precision:3,digits:3,ticksDistance:1,face:"|",strokeOpacity:1,strokeWidth:1,strokeColor:"#000000",highlightStrokeColor:"#888888",fillColor:"none",highlightFillColor:"none",visible:"inherit",includeBoundaries:!1,type:"linear"},hatch:{drawLabels:!1,drawZero:!0,majorHeight:20,anchor:"middle",face:"|",strokeWidth:2,strokeColor:Color.palette.blue,ticksDistance:.2},precision:{touch:30,touchMax:100,mouse:4,pen:4,epsilon:1e-4,hasPoint:4},layer:{numlayers:20,unused9:19,unused8:18,unused7:17,unused6:16,unused5:15,unused4:14,unused3:13,unused2:12,unused1:11,unused0:10,text:9,point:9,glider:9,arc:8,line:7,circle:6,curve:5,turtle:5,polygon:3,sector:3,angle:3,integral:3,axis:2,ticks:2,grid:1,image:0,trace:0},angle:{withLabel:!0,radius:"auto",type:"sector",orthoType:"square",orthoSensitivity:1,fillColor:Color.palette.orange,highlightFillColor:Color.palette.orange,strokeColor:Color.palette.orange,fillOpacity:.3,highlightFillOpacity:.3,radiuspoint:{withLabel:!1,visible:!1,name:""},pointsquare:{withLabel:!1,visible:!1,name:""},dot:{visible:!1,strokeColor:"none",fillColor:"#000000",size:2,face:"o",withLabel:!1,name:""},label:{position:"top",offset:[0,0],strokeColor:Color.palette.blue},arc:{visible:!1,fillColor:"none"}},arc:{selection:"auto",hasInnerPoints:!1,label:{anchorX:"auto",anchorY:"auto"},firstArrow:!1,lastArrow:!1,fillColor:"none",highlightFillColor:"none",strokeColor:Color.palette.blue,highlightStrokeColor:"#c3d9ff",useDirection:!1,center:{},radiusPoint:{},anglePoint:{}},arrow:{firstArrow:!1,lastArrow:{type:1,highlightSize:6,size:6}},axis:{name:"",needsRegularUpdate:!1,strokeWidth:1,lastArrow:{type:1,highlightSize:8,size:8},strokeColor:"#666666",highlightStrokeWidth:1,highlightStrokeColor:"#888888",withTicks:!0,straightFirst:!0,straightLast:!0,margin:-4,withLabel:!1,scalable:!1,ticks:{label:{offset:[4,-9],parse:!1,needsRegularUpdate:!1,display:"internal",visible:"inherit",layer:9},visible:"inherit",needsRegularUpdate:!1,strokeWidth:1,strokeColor:"#666666",highlightStrokeColor:"#888888",drawLabels:!0,drawZero:!1,insertTicks:!0,minTicksDistance:5,minorHeight:10,majorHeight:-1,tickEndings:[0,1],minorTicks:4,ticksDistance:1,strokeOpacity:.25},point1:{needsRegularUpdate:!1,visible:!1},point2:{needsRegularUpdate:!1,visible:!1},tabindex:-1,label:{position:"lft",offset:[10,10]}},bisector:{strokeColor:"#000000",point:{visible:!1,fixed:!1,withLabel:!1,name:""}},bisectorlines:{line1:{strokeColor:"#000000"},line2:{strokeColor:"#000000"}},boxplot:{dir:"vertical",smallWidth:.5,strokeWidth:2,strokeColor:Color.palette.blue,fillColor:Color.palette.blue,fillOpacity:.2,highlightStrokeWidth:2,highlightStrokeColor:Color.palette.blue,highlightFillColor:Color.palette.blue,highlightFillOpacity:.1},button:{disabled:!1,display:"html"},cardinalspline:{createPoints:!0,isArrayOfCoordinates:!1,points:{strokeOpacity:.05,fillOpacity:.05,highlightStrokeOpacity:1,highlightFillOpacity:1,withLabel:!1,name:"",fixed:!1}},chart:{chartStyle:"line",colors:["#B02B2C","#3F4C6B","#C79810","#D15600","#FFFF88","#c3d9ff","#4096EE","#008C00"],highlightcolors:null,fillcolor:null,highlightonsector:!1,highlightbysize:!1,fillOpacity:.6,withLines:!1,label:{}},checkbox:{disabled:!1,checked:!1,display:"html"},circle:{hasInnerPoints:!1,fillColor:"none",highlightFillColor:"none",strokeColor:Color.palette.blue,highlightStrokeColor:"#c3d9ff",center:{visible:!1,withLabel:!1,fixed:!1,fillColor:Color.palette.red,strokeColor:Color.palette.red,highlightFillColor:"#c3d9ff",highlightStrokeColor:"#c3d9ff",name:""},point2:{visible:!1,withLabel:!1,fixed:!1,name:""},label:{position:"urt"}},circumcircle:{fillColor:"none",highlightFillColor:"none",strokeColor:Color.palette.blue,highlightStrokeColor:"#c3d9ff",center:{visible:!1,fixed:!1,withLabel:!1,fillColor:Color.palette.red,strokeColor:Color.palette.red,highlightFillColor:"#c3d9ff",highlightStrokeColor:"#c3d9ff",name:""}},circumcirclearc:{fillColor:"none",highlightFillColor:"none",strokeColor:Color.palette.blue,highlightStrokeColor:"#c3d9ff",center:{visible:!1,withLabel:!1,fixed:!1,name:""}},circumcirclesector:{useDirection:!0,fillColor:Color.palette.yellow,highlightFillColor:Color.palette.yellow,fillOpacity:.3,highlightFillOpacity:.3,strokeColor:Color.palette.blue,highlightStrokeColor:"#c3d9ff",point:{visible:!1,fixed:!1,withLabel:!1,name:""}},conic:{fillColor:"none",highlightFillColor:"none",strokeColor:Color.palette.blue,highlightStrokeColor:"#c3d9ff",foci:{fixed:!1,visible:!1,withLabel:!1,name:""},center:{visible:!1,withLabel:!1,name:""},point:{withLabel:!1,name:""},line:{visible:!1}},curve:{strokeWidth:1,strokeColor:Color.palette.blue,fillColor:"none",fixed:!0,useQDT:!1,handDrawing:!1,curveType:null,RDPsmoothing:!1,numberPointsHigh:1600,numberPointsLow:400,doAdvancedPlot:!0,recursionDepthHigh:17,recursionDepthLow:15,doAdvancedPlotOld:!1,plotVersion:2,label:{position:"lft"},firstArrow:!1,lastArrow:!1},foreignobject:{attractors:[],fixed:!0,visible:!0},glider:{label:{}},grid:{needsRegularUpdate:!1,hasGrid:!1,gridX:1,gridY:1,strokeColor:"#c0c0c0",strokeOpacity:.5,strokeWidth:1,dash:0,snapToGrid:!1,snapSizeX:10,snapSizeY:10},group:{needsRegularUpdate:!0},htmlslider:{widthRange:100,widthOut:34,step:.01,frozen:!0,isLabel:!1,strokeColor:"#000000",display:"html",anchorX:"left",anchorY:"middle",withLabel:!1},image:{imageString:null,fillOpacity:1,highlightFillOpacity:.6,cssClass:"JXGimage",highlightCssClass:"JXGimageHighlight",rotate:0,snapSizeX:1,snapSizeY:1,attractors:[]},incircle:{fillColor:"none",highlightFillColor:"none",strokeColor:Color.palette.blue,highlightStrokeColor:"#c3d9ff",center:{visible:!1,fixed:!1,withLabel:!1,fillColor:Color.palette.red,strokeColor:Color.palette.red,highlightFillColor:"#c3d9ff",highlightStrokeColor:"#c3d9ff",name:""}},inequality:{fillColor:Color.palette.red,fillOpacity:.2,strokeColor:"none",inverse:!1},infobox:{fontSize:12,isLabel:!1,strokeColor:"#bbbbbb",display:"html",anchorX:"left",anchorY:"middle",cssClass:"JXGinfobox",rotate:0,visible:!0,parse:!1,transitionDuration:0,needsRegularUpdate:!1},integral:{axis:"x",withLabel:!0,fixed:!0,strokeWidth:0,strokeOpacity:0,fillColor:Color.palette.red,fillOpacity:.3,highlightFillColor:Color.palette.red,highlightFillOpacity:.2,curveLeft:{visible:!0,withLabel:!1,color:Color.palette.red,fillOpacity:.8,layer:9},baseLeft:{visible:!1,fixed:!1,withLabel:!1,name:""},curveRight:{visible:!0,withLabel:!1,color:Color.palette.red,fillOpacity:.8,layer:9},baseRight:{visible:!1,fixed:!1,withLabel:!1,name:""},label:{fontSize:20}},input:{disabled:!1,maxlength:524288,display:"html"},intersection:{alwaysIntersect:!0},label:{visible:"inherit",strokeColor:"#000000",strokeOpacity:1,highlightStrokeOpacity:.666666,highlightStrokeColor:"#000000",fixed:!0,position:"urt",offset:[10,10],autoPosition:!1},legend:{style:"vertical",labels:["1","2","3","4","5","6","7","8"],colors:["#B02B2C","#3F4C6B","#C79810","#D15600","#FFFF88","#c3d9ff","#4096EE","#008C00"],rowHeight:20,strokeWidth:5},line:{firstArrow:!1,lastArrow:!1,margin:0,straightFirst:!0,straightLast:!0,fillColor:"none",highlightFillColor:"none",strokeColor:Color.palette.blue,highlightStrokeColor:"#c3d9ff",withTicks:!1,point1:{visible:!1,withLabel:!1,fixed:!1,name:""},point2:{visible:!1,withLabel:!1,fixed:!1,name:""},ticks:{drawLabels:!0,label:{offset:[4,-9]},drawZero:!1,insertTicks:!1,minTicksDistance:50,minorHeight:4,majorHeight:-1,minorTicks:4,defaultDistance:1,strokeOpacity:.3,visible:"inherit"},label:{position:"llft"},snapToGrid:!1,snapSizeX:1,snapSizeY:1,touchFirstPoint:!1,touchLastPoint:!1,lineCap:"butt"},locus:{translateToOrigin:!1,translateTo10:!1,stretch:!1,toOrigin:null,to10:null},metapostspline:{createPoints:!0,isArrayOfCoordinates:!1,points:{strokeOpacity:.05,fillOpacity:.05,highlightStrokeOpacity:1,highlightFillOpacity:1,withLabel:!1,name:"",fixed:!1}},mirrorelement:{fixed:!0,point:{},center:{},type:"Euclidean"},normal:{strokeColor:"#000000",point:{visible:!1,fixed:!1,withLabel:!1,name:""}},orthogonalprojection:{},parallel:{strokeColor:"#000000",point:{visible:!1,fixed:!1,withLabel:!1,name:""},label:{position:"llft"}},perpendicular:{strokeColor:"#000000",straightFirst:!0,straightLast:!0},perpendicularsegment:{strokeColor:"#000000",straightFirst:!1,straightLast:!1,point:{visible:!1,fixed:!0,withLabel:!1,name:""}},point:{withLabel:!0,label:{},style:5,face:"o",size:3,sizeUnit:"screen",strokeWidth:2,fillColor:Color.palette.red,strokeColor:Color.palette.red,highlightFillColor:"#c3d9ff",highlightStrokeColor:"#c3d9ff",zoom:!1,showInfobox:"inherit",infoboxDigits:"auto",draft:!1,attractors:[],attractorUnit:"user",attractorDistance:0,snatchDistance:0,snapToGrid:!1,attractToGrid:!1,snapSizeX:1,snapSizeY:1,snapToPoints:!1,ignoredSnapToPoints:[]},polygon:{hasInnerPoints:!1,fillColor:Color.palette.yellow,highlightFillColor:Color.palette.yellow,fillOpacity:.3,highlightFillOpacity:.2,withLines:!0,borders:{withLabel:!1,strokeWidth:1,highlightStrokeWidth:1,layer:5,label:{position:"top"},visible:"inherit"},vertices:{layer:9,withLabel:!1,name:"",strokeColor:Color.palette.red,fillColor:Color.palette.red,fixed:!1,visible:"inherit"},label:{offset:[0,0]}},polygonalchain:{fillColor:"none",highlightFillColor:"none"},prescribedangle:{anglePoint:{size:2,visible:!1,withLabel:!1}},reflection:{fixed:!0,center:{},type:"Euclidean"},regularpolygon:{hasInnerPoints:!1,fillColor:Color.palette.yellow,highlightFillColor:Color.palette.yellow,fillOpacity:.3,highlightFillOpacity:.2,withLines:!0,borders:{withLabel:!1,strokeWidth:1,highlightStrokeWidth:1,layer:5,label:{position:"top"}},vertices:{layer:9,withLabel:!0,strokeColor:Color.palette.red,fillColor:Color.palette.red,fixed:!1},label:{offset:[0,0]}},riemannsum:{withLabel:!1,fillOpacity:.3,fillColor:Color.palette.yellow},sector:{fillColor:Color.palette.yellow,highlightFillColor:Color.palette.yellow,fillOpacity:.3,highlightFillOpacity:.3,highlightOnSector:!1,highlightStrokeWidth:0,selection:"auto",arc:{visible:!1,fillColor:"none"},radiusPoint:{visible:!1,withLabel:!1},center:{visible:!1,withLabel:!1},anglePoint:{visible:!1,withLabel:!1},label:{offset:[0,0],anchorX:"auto",anchorY:"auto"}},segment:{label:{position:"top"}},semicircle:{center:{visible:!1,withLabel:!1,fixed:!1,fillColor:Color.palette.red,strokeColor:Color.palette.red,highlightFillColor:"#eeeeee",highlightStrokeColor:Color.palette.red,name:""}},slider:{snapWidth:-1,precision:2,digits:2,firstArrow:!1,lastArrow:!1,withTicks:!0,withLabel:!0,suffixLabel:null,unitLabel:null,postLabel:null,layer:9,showInfobox:!1,name:"",visible:!0,strokeColor:"#000000",highlightStrokeColor:"#888888",fillColor:"#ffffff",highlightFillColor:"none",size:6,point1:{needsRegularUpdate:!1,showInfobox:!1,withLabel:!1,visible:!1,fixed:!0,name:""},point2:{needsRegularUpdate:!1,showInfobox:!1,withLabel:!1,visible:!1,fixed:!0,name:""},baseline:{needsRegularUpdate:!1,visible:"inherit",fixed:!0,scalable:!1,tabindex:null,name:"",strokeWidth:1,strokeColor:"#000000",highlightStrokeColor:"#888888"},ticks:{needsRegularUpdate:!1,fixed:!0,drawLabels:!1,digits:2,includeBoundaries:1,drawZero:!0,label:{offset:[-4,-14],display:"internal"},minTicksDistance:30,insertTicks:!0,minorHeight:4,majorHeight:5,minorTicks:0,defaultDistance:1,strokeOpacity:1,strokeWidth:1,tickEndings:[0,1],strokeColor:"#000000",visible:"inherit"},highline:{strokeWidth:3,visible:"inherit",fixed:!0,tabindex:null,name:"",strokeColor:"#000000",highlightStrokeColor:"#888888"},label:{visible:"inherit",strokeColor:"#000000"},moveOnUp:!0},comb:{frequency:.2,width:.4,angle:Math.PI/3,reverse:!1,point1:{visible:!1,withLabel:!1,fixed:!1,name:""},point2:{visible:!1,withLabel:!1,fixed:!1,name:""},curve:{strokeWidth:1,strokeColor:"#000000",fillColor:"none"}},slopetriangle:{fillColor:Color.palette.red,fillOpacity:.4,highlightFillColor:Color.palette.red,highlightFillOpacity:.3,borders:{lastArrow:{type:1,size:6}},glider:{fixed:!0,visible:!1,withLabel:!1},baseline:{visible:!1,withLabel:!1,name:""},basepoint:{visible:!1,withLabel:!1,name:""},tangent:{visible:!1,withLabel:!1,name:""},toppoint:{visible:!1,withLabel:!1,name:""},label:{visible:!0}},stepfunction:{},tapemeasure:{strokeColor:"#000000",strokeWidth:2,highlightStrokeColor:"#000000",withTicks:!0,withLabel:!0,precision:2,digits:2,point1:{visible:"inherit",strokeColor:"#000000",fillColor:"#ffffff",fillOpacity:0,highlightFillOpacity:.1,size:6,snapToPoints:!0,attractorUnit:"screen",attractorDistance:20,showInfobox:!1,withLabel:!1,name:""},point2:{visible:"inherit",strokeColor:"#000000",fillColor:"#ffffff",fillOpacity:0,highlightFillOpacity:.1,size:6,snapToPoints:!0,attractorUnit:"screen",attractorDistance:20,showInfobox:!1,withLabel:!1,name:""},ticks:{drawLabels:!1,drawZero:!0,insertTicks:!0,minorHeight:8,majorHeight:16,minorTicks:4,tickEndings:[0,1],defaultDistance:.1,strokeOpacity:1,strokeWidth:1,strokeColor:"#000000",visible:"inherit"},label:{position:"top"}},text:{fontSize:12,fontUnit:"px",digits:2,parse:!0,useCaja:!1,isLabel:!1,strokeColor:"#000000",highlightStrokeColor:"#000000",highlightStrokeOpacity:.666666,cssDefaultStyle:"font-family: Arial, Helvetica, Geneva, sans-serif;",highlightCssDefaultStyle:"font-family: Arial, Helvetica, Geneva, sans-serif;",cssStyle:"",highlightCssStyle:"",useASCIIMathML:!1,useMathJax:!1,useKatex:!1,display:"html",anchor:null,anchorX:"left",anchorY:"middle",cssClass:"JXGtext",highlightCssClass:"JXGtext",dragArea:"all",withLabel:!1,rotate:0,visible:!0,snapSizeX:1,snapSizeY:1,attractors:[]},tracecurve:{strokeColor:"#000000",fillColor:"none",numberPoints:100},turtle:{strokeWidth:1,fillColor:"none",strokeColor:"#000000",arrow:{strokeWidth:2,withLabel:!1,strokeColor:Color.palette.red,lastArrow:!0}},shortcuts:{color:["strokeColor","fillColor"],opacity:["strokeOpacity","fillOpacity"],highlightColor:["highlightStrokeColor","highlightFillColor"],highlightOpacity:["highlightStrokeOpacity","highlightFillOpacity"],strokeWidth:["strokeWidth","highlightStrokeWidth"]}},JXG.Validator=function(){var i,validateColor=function(v){return Type.isString(v)},validateInteger=function(v){return Math.abs(v-Math.round(v))<Mat.eps},validatePositiveInteger=function(v){return validateInteger(v)&&v>0},validatePositive=function(v){return v>0},validateNotNegative=function(v){return v>=0},v={},validators={attractorDistance:validateNotNegative,color:validateColor,defaultDistance:Type.isNumber,display:function(v){return"html"===v||"internal"===v},doAdvancedPlot:!1,draft:!1,drawLabels:!1,drawZero:!1,face:function(v){return Type.exists(JXG.normalizePointFace(v))},factor:Type.isNumber,fillColor:validateColor,fillOpacity:Type.isNumber,firstArrow:!1,fontSize:validateInteger,dash:validateInteger,gridX:Type.isNumber,gridY:Type.isNumber,hasGrid:!1,highlightFillColor:validateColor,highlightFillOpacity:Type.isNumber,highlightStrokeColor:validateColor,highlightStrokeOpacity:Type.isNumber,insertTicks:!1,lastArrow:!1,layer:function(v){return validateInteger(v)&&v>=0},majorHeight:validateInteger,minorHeight:validateInteger,minorTicks:validateNotNegative,minTicksDistance:validatePositiveInteger,numberPointsHigh:validatePositiveInteger,numberPointsLow:validatePositiveInteger,opacity:Type.isNumber,radius:Type.isNumber,RDPsmoothing:!1,renderer:function(v){return"vml"===v||"svg"===v||"canvas"===v||"no"===v},right:function(v){return/^[0-9]+px$/.test(v)},showCopyright:!1,showInfobox:!1,showNavigation:!1,size:validateNotNegative,snapSizeX:validatePositive,snapSizeY:validatePositive,snapWidth:Type.isNumber,snapToGrid:!1,snatchDistance:validateNotNegative,straightFirst:!1,straightLast:!1,stretch:!1,strokeColor:validateColor,strokeOpacity:Type.isNumber,strokeWidth:validateNotNegative,takeFirst:!1,takeSizeFromFile:!1,to10:!1,toOrigin:!1,translateTo10:!1,translateToOrigin:!1,useASCIIMathML:!1,useDirection:!1,useMathJax:!1,withLabel:!1,withTicks:!1,zoom:!1};for(i in validators)validators.hasOwnProperty(i)&&(v[i.toLowerCase()]=validators[i]);return v}(),JXG.normalizePointFace=function(s){return{cross:"x",x:"x",circle:"o",o:"o",square:"[]","[]":"[]",plus:"+","+":"+",diamond:"<>","<>":"<>",triangleup:"^",a:"^","^":"^",triangledown:"v",v:"v",triangleleft:"<","<":"<",triangleright:">",">":">"}[s]},JXG.useStandardOptions=function(board){var el,t,p,copyProps,o=JXG.Options,boardHadGrid=board.hasGrid;for(el in board.options.grid.hasGrid=o.grid.hasGrid,board.options.grid.gridX=o.grid.gridX,board.options.grid.gridY=o.grid.gridY,board.options.grid.gridColor=o.grid.gridColor,board.options.grid.gridOpacity=o.grid.gridOpacity,board.options.grid.gridDash=o.grid.gridDash,board.options.grid.snapToGrid=o.grid.snapToGrid,board.options.grid.snapSizeX=o.grid.SnapSizeX,board.options.grid.snapSizeY=o.grid.SnapSizeY,board.takeSizeFromFile=o.takeSizeFromFile,copyProps=function(p,o){p.visProp.fillcolor=o.fillColor,p.visProp.highlightfillcolor=o.highlightFillColor,p.visProp.strokecolor=o.strokeColor,p.visProp.highlightstrokecolor=o.highlightStrokeColor},board.objects)if(board.objects.hasOwnProperty(el))if((p=board.objects[el]).elementClass===Const.OBJECT_CLASS_POINT)copyProps(p,o.point);else if(p.elementClass===Const.OBJECT_CLASS_LINE)for(copyProps(p,o.line),t=0;t<p.ticks.length;t++)p.ticks[t].majorTicks=o.line.ticks.majorTicks,p.ticks[t].minTicksDistance=o.line.ticks.minTicksDistance,p.ticks[t].visProp.minorheight=o.line.ticks.minorHeight,p.ticks[t].visProp.majorheight=o.line.ticks.majorHeight;else p.elementClass===Const.OBJECT_CLASS_CIRCLE?copyProps(p,o.circle):p.type===Const.OBJECT_TYPE_ANGLE?copyProps(p,o.angle):p.type===Const.OBJECT_TYPE_ARC?copyProps(p,o.arc):p.type===Const.OBJECT_TYPE_POLYGON?copyProps(p,o.polygon):p.type===Const.OBJECT_TYPE_CONIC?copyProps(p,o.conic):p.type===Const.OBJECT_TYPE_CURVE?copyProps(p,o.curve):p.type===Const.OBJECT_TYPE_SECTOR&&(p.arc.visProp.fillcolor=o.sector.fillColor,p.arc.visProp.highlightfillcolor=o.sector.highlightFillColor,p.arc.visProp.fillopacity=o.sector.fillOpacity,p.arc.visProp.highlightfillopacity=o.sector.highlightFillOpacity);board.fullUpdate(),boardHadGrid&&!board.hasGrid?board.removeGrids(board):!boardHadGrid&&board.hasGrid&&board.create("grid",[])},JXG.useBlackWhiteOptions=function(board){var o=JXG.Options;o.point.fillColor=Color.rgb2bw(o.point.fillColor),o.point.highlightFillColor=Color.rgb2bw(o.point.highlightFillColor),o.point.strokeColor=Color.rgb2bw(o.point.strokeColor),o.point.highlightStrokeColor=Color.rgb2bw(o.point.highlightStrokeColor),o.line.fillColor=Color.rgb2bw(o.line.fillColor),o.line.highlightFillColor=Color.rgb2bw(o.line.highlightFillColor),o.line.strokeColor=Color.rgb2bw(o.line.strokeColor),o.line.highlightStrokeColor=Color.rgb2bw(o.line.highlightStrokeColor),o.circle.fillColor=Color.rgb2bw(o.circle.fillColor),o.circle.highlightFillColor=Color.rgb2bw(o.circle.highlightFillColor),o.circle.strokeColor=Color.rgb2bw(o.circle.strokeColor),o.circle.highlightStrokeColor=Color.rgb2bw(o.circle.highlightStrokeColor),o.arc.fillColor=Color.rgb2bw(o.arc.fillColor),o.arc.highlightFillColor=Color.rgb2bw(o.arc.highlightFillColor),o.arc.strokeColor=Color.rgb2bw(o.arc.strokeColor),o.arc.highlightStrokeColor=Color.rgb2bw(o.arc.highlightStrokeColor),o.polygon.fillColor=Color.rgb2bw(o.polygon.fillColor),o.polygon.highlightFillColor=Color.rgb2bw(o.polygon.highlightFillColor),o.sector.fillColor=Color.rgb2bw(o.sector.fillColor),o.sector.highlightFillColor=Color.rgb2bw(o.sector.highlightFillColor),o.curve.strokeColor=Color.rgb2bw(o.curve.strokeColor),o.grid.gridColor=Color.rgb2bw(o.grid.gridColor),JXG.useStandardOptions(board)},JXG.Options.normalizePointFace=JXG.normalizePointFace,JXG.Options})),define("renderer/abstract",["jxg","options","base/coords","base/constants","math/math","math/geometry","utils/type","utils/env"],(function(JXG,Options,Coords,Const,Mat,Geometry,Type,Env){return JXG.AbstractRenderer=function(){this.vOffsetText=0,this.enhancedRendering=!0,this.container=null,this.type="",this.supportsForeignObject=!1},JXG.extend(JXG.AbstractRenderer.prototype,{_updateVisual:function(el,not,enhanced){(enhanced||this.enhancedRendering)&&(not=not||{},this.setObjectTransition(el),Type.evaluate(el.visProp.draft)?this.setDraft(el):(not.stroke||(el.highlighted?(this.setObjectStrokeColor(el,el.visProp.highlightstrokecolor,el.visProp.highlightstrokeopacity),this.setObjectStrokeWidth(el,el.visProp.highlightstrokewidth)):(this.setObjectStrokeColor(el,el.visProp.strokecolor,el.visProp.strokeopacity),this.setObjectStrokeWidth(el,el.visProp.strokewidth))),not.fill||(el.highlighted?this.setObjectFillColor(el,el.visProp.highlightfillcolor,el.visProp.highlightfillopacity):this.setObjectFillColor(el,el.visProp.fillcolor,el.visProp.fillopacity)),not.dash||this.setDashStyle(el,el.visProp),not.shadow||this.setShadow(el),not.gradient||this.setShadow(el),not.tabindex||this.setTabindex(el)))},_getHighlighted:function(el){var isTrace=!1;return Type.exists(el.board)&&Type.exists(el.board.highlightedObjects)||(isTrace=!0),!isTrace&&Type.exists(el.board.highlightedObjects[el.id])?"highlight":""},drawPoint:function(el){var prim,face=Options.normalizePointFace(Type.evaluate(el.visProp.face));prim="o"===face?"ellipse":"[]"===face?"rect":"path",el.rendNode=this.appendChildPrim(this.createPrim(prim,el.id),Type.evaluate(el.visProp.layer)),this.appendNodesToElement(el,prim),this._updateVisual(el,{dash:!0,shadow:!0},!0),this.updatePoint(el)},updatePoint:function(el){var s1,size=Type.evaluate(el.visProp.size),face=Options.normalizePointFace(Type.evaluate(el.visProp.face)),unit=Type.evaluate(el.visProp.sizeunit),zoom=Type.evaluate(el.visProp.zoom);isNaN(el.coords.scrCoords[2]+el.coords.scrCoords[1])||("user"===unit&&(size*=Math.sqrt(el.board.unitX*el.board.unitY)),s1=0===(size*=el.board&&zoom?Math.sqrt(el.board.zoomX*el.board.zoomY):1)?0:size+1,"o"===face?this.updateEllipsePrim(el.rendNode,el.coords.scrCoords[1],el.coords.scrCoords[2],s1,s1):"[]"===face?this.updateRectPrim(el.rendNode,el.coords.scrCoords[1]-size,el.coords.scrCoords[2]-size,2*size,2*size):this.updatePathPrim(el.rendNode,this.updatePathStringPoint(el,size,face),el.board),this._updateVisual(el,{dash:!1,shadow:!1}),this.setShadow(el))},changePointStyle:function(el){var node=this.getElementById(el.id);Type.exists(node)&&this.remove(node),this.drawPoint(el),Type.clearVisPropOld(el),el.visPropCalc.visible||this.display(el,!1),Type.evaluate(el.visProp.draft)&&this.setDraft(el)},drawLine:function(el){el.rendNode=this.appendChildPrim(this.createPrim("line",el.id),Type.evaluate(el.visProp.layer)),this.appendNodesToElement(el,"lines"),this.updateLine(el)},updateLine:function(el){this._updateVisual(el),this.updatePathWithArrowHeads(el),this.setLineCap(el)},drawCurve:function(el){el.rendNode=this.appendChildPrim(this.createPrim("path",el.id),Type.evaluate(el.visProp.layer)),this.appendNodesToElement(el,"path"),this.updateCurve(el)},updateCurve:function(el){this._updateVisual(el),this.updatePathWithArrowHeads(el),this.setLineCap(el)},updatePathWithArrowHeads:function(el,doHighlight){var w,arrowData,ev=el.visProp,hl=doHighlight?"highlight":"";w=doHighlight&&ev.highlightstrokewidth?Math.max(Type.evaluate(ev.highlightstrokewidth),Type.evaluate(ev.strokewidth)):Type.evaluate(ev.strokewidth),arrowData=this.getArrowHeadData(el,w,hl),this.makeArrows(el,arrowData),el.elementClass===Const.OBJECT_CLASS_LINE?this.updateLineWithEndings(el,arrowData):el.elementClass===Const.OBJECT_CLASS_CURVE&&this.updatePath(el),this.setArrowSize(el,arrowData)},getArrowHeadData:function(el,strokewidth,hl){var typeFirst,typeLast,off,size,minlen=Mat.eps,offFirst=0,offLast=0,sizeFirst=0,sizeLast=0,ev_fa=Type.evaluate(el.visProp.firstarrow),ev_la=Type.evaluate(el.visProp.lastarrow);return(ev_fa||ev_la)&&(typeFirst=Type.exists(ev_fa.type)?Type.evaluate(ev_fa.type):el.elementClass===Const.OBJECT_CLASS_LINE?1:7,typeLast=Type.exists(ev_la.type)?Type.evaluate(ev_la.type):el.elementClass===Const.OBJECT_CLASS_LINE?1:7,ev_fa&&(size=6,Type.exists(ev_fa.size)&&(size=Type.evaluate(ev_fa.size)),""!==hl&&Type.exists(ev_fa[hl+"size"])&&(size=Type.evaluate(ev_fa[hl+"size"])),off=strokewidth*size,2===typeFirst?(off*=.5,minlen+=strokewidth*size):3===typeFirst?(off=strokewidth*size/3,minlen+=strokewidth):4===typeFirst||5===typeFirst||6===typeFirst?(off=strokewidth*size/1.5,minlen+=strokewidth*size):7===typeFirst?(off=0,size=10,minlen+=strokewidth):minlen+=strokewidth*size,offFirst+=off,sizeFirst=size),ev_la&&(size=6,Type.exists(ev_la.size)&&(size=Type.evaluate(ev_la.size)),""!==hl&&Type.exists(ev_la[hl+"size"])&&(size=Type.evaluate(ev_la[hl+"size"])),off=strokewidth*size,2===typeLast?(off*=.5,minlen+=strokewidth*size):3===typeLast?(off=strokewidth*size/3,minlen+=strokewidth):4===typeLast||5===typeLast||6===typeLast?(off=strokewidth*size/1.5,minlen+=strokewidth*size):7===typeLast?(off=0,size=10,minlen+=strokewidth):minlen+=strokewidth*size,offLast+=off,sizeLast=size)),el.visPropCalc.typeFirst=typeFirst,el.visPropCalc.typeLast=typeLast,{evFirst:ev_fa,evLast:ev_la,typeFirst:typeFirst,typeLast:typeLast,offFirst:offFirst,offLast:offLast,sizeFirst:sizeFirst,sizeLast:sizeLast,showFirst:1,showLast:1,minLen:minlen,strokeWidth:strokewidth}},updateLineWithEndings:function(el,arrowData){var c1,c2,margin;return c1=new Coords(Const.COORDS_BY_USER,el.point1.coords.usrCoords,el.board),c2=new Coords(Const.COORDS_BY_USER,el.point2.coords.usrCoords,el.board),margin=Type.evaluate(el.visProp.margin),Geometry.calcStraight(el,c1,c2,margin),this.handleTouchpoints(el,c1,c2,arrowData),this.getPositionArrowHead(el,c1,c2,arrowData),this.updateLinePrim(el.rendNode,c1.scrCoords[1],c1.scrCoords[2],c2.scrCoords[1],c2.scrCoords[2],el.board),this},updatePath:function(el){return Type.evaluate(el.visProp.handdrawing)?this.updatePathPrim(el.rendNode,this.updatePathStringBezierPrim(el),el.board):this.updatePathPrim(el.rendNode,this.updatePathStringPrim(el),el.board),this},getPositionArrowHead:function(el,c1,c2,a){var d,d1x,d1y,d2x,d2y;return(a.evFirst||a.evLast)&&(d1x=d1y=d2x=d2y=0,d=c1.distance(Const.COORDS_BY_SCREEN,c2),a.evFirst&&"vml"!==el.board.renderer.type&&(d>=a.minLen?(d1x=(c2.scrCoords[1]-c1.scrCoords[1])*a.offFirst/d,d1y=(c2.scrCoords[2]-c1.scrCoords[2])*a.offFirst/d):a.showFirst=0),a.evLast&&"vml"!==el.board.renderer.type&&(d>=a.minLen?(d2x=(c2.scrCoords[1]-c1.scrCoords[1])*a.offLast/d,d2y=(c2.scrCoords[2]-c1.scrCoords[2])*a.offLast/d):a.showLast=0),c1.setCoordinates(Const.COORDS_BY_SCREEN,[c1.scrCoords[1]+d1x,c1.scrCoords[2]+d1y],!1,!0),c2.setCoordinates(Const.COORDS_BY_SCREEN,[c2.scrCoords[1]-d2x,c2.scrCoords[2]-d2y],!1,!0)),this},handleTouchpoints:function(el,c1,c2,a){var s1,s2,d,d1x,d1y,d2x,d2y;return(a.evFirst||a.evLast)&&(d=d1x=d1y=d2x=d2y=0,s1=Type.evaluate(el.point1.visProp.size)+Type.evaluate(el.point1.visProp.strokewidth),s2=Type.evaluate(el.point2.visProp.size)+Type.evaluate(el.point2.visProp.strokewidth),a.evFirst&&Type.evaluate(el.visProp.touchfirstpoint)&&(d=c1.distance(Const.COORDS_BY_SCREEN,c2),d1x=(c2.scrCoords[1]-c1.scrCoords[1])*s1/d,d1y=(c2.scrCoords[2]-c1.scrCoords[2])*s1/d),a.evLast&&Type.evaluate(el.visProp.touchlastpoint)&&(d=c1.distance(Const.COORDS_BY_SCREEN,c2),d2x=(c2.scrCoords[1]-c1.scrCoords[1])*s2/d,d2y=(c2.scrCoords[2]-c1.scrCoords[2])*s2/d),c1.setCoordinates(Const.COORDS_BY_SCREEN,[c1.scrCoords[1]+d1x,c1.scrCoords[2]+d1y],!1,!0),c2.setCoordinates(Const.COORDS_BY_SCREEN,[c2.scrCoords[1]-d2x,c2.scrCoords[2]-d2y],!1,!0)),this},setArrowSize:function(el,a){return a.evFirst&&this._setArrowWidth(el.rendNodeTriangleStart,a.showFirst*a.strokeWidth,el.rendNode,a.sizeFirst),a.evLast&&this._setArrowWidth(el.rendNodeTriangleEnd,a.showLast*a.strokeWidth,el.rendNode,a.sizeLast),this},setLineCap:function(el){},drawTicks:function(el){el.rendNode=this.appendChildPrim(this.createPrim("path",el.id),Type.evaluate(el.visProp.layer)),this.appendNodesToElement(el,"path")},updateTicks:function(element){},drawEllipse:function(el){el.rendNode=this.appendChildPrim(this.createPrim("ellipse",el.id),Type.evaluate(el.visProp.layer)),this.appendNodesToElement(el,"ellipse"),this.updateEllipse(el)},updateEllipse:function(el){this._updateVisual(el);var radius=el.Radius();radius>0&&Math.abs(el.center.coords.usrCoords[0])>Mat.eps&&!isNaN(radius+el.center.coords.scrCoords[1]+el.center.coords.scrCoords[2])&&radius*el.board.unitX<2e6&&this.updateEllipsePrim(el.rendNode,el.center.coords.scrCoords[1],el.center.coords.scrCoords[2],radius*el.board.unitX,radius*el.board.unitY)},drawPolygon:function(el){el.rendNode=this.appendChildPrim(this.createPrim("polygon",el.id),Type.evaluate(el.visProp.layer)),this.appendNodesToElement(el,"polygon"),this.updatePolygon(el)},updatePolygon:function(el){this._updateVisual(el,{stroke:!0,dash:!0}),this.updatePolygonPrim(el.rendNode,el)},displayCopyright:function(str,fontsize){},drawInternalText:function(element){},updateInternalText:function(element){},drawText:function(el){var node,z,level,ev_visible;"html"===Type.evaluate(el.visProp.display)&&Env.isBrowser&&"no"!==this.type?((node=this.container.ownerDocument.createElement("div")).style.position="absolute",node.className=Type.evaluate(el.visProp.cssclass),level=Type.evaluate(el.visProp.layer),Type.exists(level)||(level=0),z=""===this.container.style.zIndex?0:parseInt(this.container.style.zIndex,10),node.style.zIndex=z+level,this.container.appendChild(node),node.setAttribute("id",this.container.id+"_"+el.id)):node=this.drawInternalText(el),el.rendNode=node,el.htmlStr="",el.visProp.islabel&&Type.exists(el.visProp.anchor)?(ev_visible=Type.evaluate(el.visProp.anchor.visProp.visible),el.prepareUpdate().updateVisibility(ev_visible)):el.prepareUpdate().updateVisibility(),this.updateText(el)},updateText:function(el){var v,c,parentNode,scale,vshift,id,wrap_id,ax,ay,content=el.plaintext;if(el.visPropCalc.visible)if(this.updateTextStyle(el,!1),"html"===Type.evaluate(el.visProp.display)&&"no"!==this.type){if(isNaN(el.coords.scrCoords[1]+el.coords.scrCoords[2])||(c=el.coords.scrCoords[1],c=Math.abs(c)<1e6?c:1e6,v="right"===(ax=el.getAnchorX())?el.board.canvasWidth-c:"middle"===ax?c-.5*el.size[0]:c,el.visPropOld.left!==ax+v&&("right"===ax?(el.rendNode.style.right=v+"px",el.rendNode.style.left="auto"):(el.rendNode.style.left=v+"px",el.rendNode.style.right="auto"),el.visPropOld.left=ax+v),c=el.coords.scrCoords[2]+this.vOffsetText,c=Math.abs(c)<1e6?c:1e6,v="bottom"===(ay=el.getAnchorY())?el.board.canvasHeight-c:"middle"===ay?c-.5*el.size[1]:c,el.visPropOld.top!==ay+v&&("bottom"===ay?(el.rendNode.style.top="auto",el.rendNode.style.bottom=v+"px"):(el.rendNode.style.bottom="auto",el.rendNode.style.top=v+"px"),el.visPropOld.top=ay+v)),el.htmlStr!==content){try{el.type===Type.OBJECT_TYPE_BUTTON?el.rendNodeButton.innerHTML=content:el.type===Type.OBJECT_TYPE_CHECKBOX||el.type===Type.OBJECT_TYPE_INPUT?el.rendNodeLabel.innerHTML=content:el.rendNode.innerHTML=content}catch(e){parentNode=el.rendNode.parentNode,el.rendNode.parentNode.removeChild(el.rendNode),el.rendNode.innerHTML=content,parentNode.appendChild(el.rendNode)}if(el.htmlStr=content,Type.evaluate(el.visProp.usemathjax))try{MathJax.typeset?MathJax.typeset([el.rendNode]):MathJax.Hub.Queue(["Typeset",MathJax.Hub,el.rendNode]),wrap_id="fullscreenwrap_"+(id=el.board.container),document.getElementById(wrap_id)&&(scale=el.board.containerObj._cssFullscreenStore.scale,vshift=el.board.containerObj._cssFullscreenStore.vshift,Env.scaleJSXGraphDiv("#"+wrap_id,"#"+id,scale,vshift))}catch(e){JXG.debug("MathJax (not yet) loaded")}else if(Type.evaluate(el.visProp.usekatex))try{katex.render(content,el.rendNode,{throwOnError:!1})}catch(e){JXG.debug("KaTeX (not yet) loaded")}else if(Type.evaluate(el.visProp.useasciimathml))try{AMprocessNode(el.rendNode,!1)}catch(e){JXG.debug("AsciiMathML (not yet) loaded")}}this.transformImage(el,el.transformations)}else this.updateInternalText(el)},_css2js:function(cssString){var i,len,key,val,s,pairs=[],list=Type.trim(cssString).replace(/;$/,"").split(";");for(len=list.length,i=0;i<len;++i)""!==Type.trim(list[i])&&(s=list[i].split(":"),key=Type.trim(s[0].replace(/-([a-z])/gi,(function(match,char){return char.toUpperCase()}))),val=Type.trim(s[1]),pairs.push({key:key,val:val}));return pairs},updateTextStyle:function(el,doHighlight){var fs,so,sc,css,node,cssList,prop,style,cssString,ev=el.visProp,display=Env.isBrowser?ev.display:"internal",nodeList=["rendNode","rendNodeTag","rendNodeLabel"],lenN=nodeList.length,fontUnit=Type.evaluate(ev.fontunit),styleList=["cssdefaultstyle","cssstyle"],lenS=styleList.length;if(doHighlight?(sc=ev.highlightstrokecolor,so=ev.highlightstrokeopacity,css=ev.highlightcssclass):(sc=ev.strokecolor,so=ev.strokeopacity,css=ev.cssclass),"no"!==this.type&&("html"===display||"canvas"!==this.type)){for(style=0;style<lenS;style++)if(""!==(cssString=Type.evaluate(ev[(doHighlight?"highlight":"")+styleList[style]]))&&el.visPropOld[styleList[style]]!==cssString){for(cssList=this._css2js(cssString),node=0;node<lenN;node++)if(Type.exists(el[nodeList[node]]))for(prop in cssList)cssList.hasOwnProperty(prop)&&(el[nodeList[node]].style[cssList[prop].key]=cssList[prop].val);el.visPropOld[styleList[style]]=cssString}if(fs=Type.evaluate(ev.fontsize),el.visPropOld.fontsize!==fs){el.needsSizeUpdate=!0;try{for(node=0;node<lenN;node++)Type.exists(el[nodeList[node]])&&(el[nodeList[node]].style.fontSize=fs+fontUnit)}catch(e){for(node=0;node<lenN;node++)Type.exists(el[nodeList[node]])&&(el[nodeList[node]].style.fontSize=fs)}el.visPropOld.fontsize=fs}}return this.setObjectTransition(el),"html"===display&&"no"!==this.type?(el.visPropOld.cssclass!==css&&(el.rendNode.className=css,el.visPropOld.cssclass=css,el.needsSizeUpdate=!0),this.setObjectStrokeColor(el,sc,so)):this.updateInternalTextStyle(el,sc,so),this},updateInternalTextStyle:function(el,strokeColor,strokeOpacity){this.setObjectStrokeColor(el,strokeColor,strokeOpacity)},drawImage:function(element){},updateImage:function(el){this.updateRectPrim(el.rendNode,el.coords.scrCoords[1],el.coords.scrCoords[2]-el.size[1],el.size[0],el.size[1]),this.updateImageURL(el),this.transformImage(el,el.transformations),this._updateVisual(el,{stroke:!0,dash:!0},!0)},joinTransforms:function(el,transformations){var i,ox=el.board.origin.scrCoords[1],oy=el.board.origin.scrCoords[2],ux=el.board.unitX,uy=el.board.unitY,len=transformations.length,m=[[1,0,0],[-ox/ux,1/ux,0],[oy/uy,0,-1/uy]];for(i=0;i<len;i++)m=Mat.matMatMult(transformations[i].matrix,m);return m=Mat.matMatMult([[1,0,0],[ox,ux,0],[oy,0,-uy]],m)},transformImage:function(element,transformations){},updateImageURL:function(element){},updateImageStyle:function(el,doHighlight){el.rendNode.className=Type.evaluate(doHighlight?el.visProp.highlightcssclass:el.visProp.cssclass)},drawForeignObject:function(el){},updateForeignObject:function(el){},appendChildPrim:function(node,level){},appendNodesToElement:function(element,type){},createPrim:function(type,id){return null},remove:function(node){},makeArrows:function(element,arrowData){},_setArrowWidth:function(node,width,parentNode){},updateEllipsePrim:function(node,x,y,rx,ry){},updateLinePrim:function(node,p1x,p1y,p2x,p2y,board){},updatePathPrim:function(node,pathString,board){},updatePathStringPoint:function(element,size,type){},updatePathStringPrim:function(element){},updatePathStringBezierPrim:function(element){},updatePolygonPrim:function(node,element){},updateRectPrim:function(node,x,y,w,h){},setPropertyPrim:function(node,key,val){},setTabindex:function(element){var val;element.board.attr.keyboard.enabled&&Type.exists(element.rendNode)&&(val=Type.evaluate(element.visProp.tabindex),element.visPropCalc.visible&&!Type.evaluate(element.visProp.fixed)||(val=null),val!==element.visPropOld.tabindex&&(element.rendNode.setAttribute("tabindex",val),element.visPropOld.tabindex=val))},display:function(element,value){element&&(element.visPropOld.visible=value)},show:function(element){},hide:function(element){},setBuffering:function(node,type){},setDashStyle:function(element){},setDraft:function(el){if(Type.evaluate(el.visProp.draft)){var draftColor=el.board.options.elements.draft.color,draftOpacity=el.board.options.elements.draft.opacity;this.setObjectTransition(el),el.type===Const.OBJECT_TYPE_POLYGON?this.setObjectFillColor(el,draftColor,draftOpacity):(el.elementClass===Const.OBJECT_CLASS_POINT?this.setObjectFillColor(el,draftColor,draftOpacity):this.setObjectFillColor(el,"none",0),this.setObjectStrokeColor(el,draftColor,draftOpacity),this.setObjectStrokeWidth(el,el.board.options.elements.draft.strokeWidth))}},removeDraft:function(el){this.setObjectTransition(el),el.type===Const.OBJECT_TYPE_POLYGON?this.setObjectFillColor(el,el.visProp.fillcolor,el.visProp.fillopacity):(el.type===Const.OBJECT_CLASS_POINT&&this.setObjectFillColor(el,el.visProp.fillcolor,el.visProp.fillopacity),this.setObjectStrokeColor(el,el.visProp.strokecolor,el.visProp.strokeopacity),this.setObjectStrokeWidth(el,el.visProp.strokewidth))},setGradient:function(element){},updateGradient:function(element){},setObjectTransition:function(element,duration){},setObjectFillColor:function(element,color,opacity){},setObjectStrokeColor:function(element,color,opacity){},setObjectStrokeWidth:function(element,width){},setShadow:function(element){},highlight:function(el){var i,sw,ev=el.visProp;if(this.setObjectTransition(el),!ev.draft){if(el.type===Const.OBJECT_TYPE_POLYGON)for(this.setObjectFillColor(el,ev.highlightfillcolor,ev.highlightfillopacity),i=0;i<el.borders.length;i++)this.setObjectStrokeColor(el.borders[i],el.borders[i].visProp.highlightstrokecolor,el.borders[i].visProp.highlightstrokeopacity);else el.elementClass===Const.OBJECT_CLASS_TEXT?this.updateTextStyle(el,!0):el.type===Const.OBJECT_TYPE_IMAGE?(this.updateImageStyle(el,!0),this.setObjectFillColor(el,ev.highlightfillcolor,ev.highlightfillopacity)):(this.setObjectStrokeColor(el,ev.highlightstrokecolor,ev.highlightstrokeopacity),this.setObjectFillColor(el,ev.highlightfillcolor,ev.highlightfillopacity));ev.highlightstrokewidth&&(sw=Math.max(Type.evaluate(ev.highlightstrokewidth),Type.evaluate(ev.strokewidth)),this.setObjectStrokeWidth(el,sw),el.elementClass!==Const.OBJECT_CLASS_LINE&&el.elementClass!==Const.OBJECT_CLASS_CURVE||this.updatePathWithArrowHeads(el,!0))}return this},noHighlight:function(el){var i,sw,ev=el.visProp;if(this.setObjectTransition(el),!Type.evaluate(el.visProp.draft)){if(el.type===Const.OBJECT_TYPE_POLYGON)for(this.setObjectFillColor(el,ev.fillcolor,ev.fillopacity),i=0;i<el.borders.length;i++)this.setObjectStrokeColor(el.borders[i],el.borders[i].visProp.strokecolor,el.borders[i].visProp.strokeopacity);else el.elementClass===Const.OBJECT_CLASS_TEXT?this.updateTextStyle(el,!1):el.type===Const.OBJECT_TYPE_IMAGE?(this.updateImageStyle(el,!1),this.setObjectFillColor(el,ev.fillcolor,ev.fillopacity)):(this.setObjectStrokeColor(el,ev.strokecolor,ev.strokeopacity),this.setObjectFillColor(el,ev.fillcolor,ev.fillopacity));sw=Type.evaluate(ev.strokewidth),this.setObjectStrokeWidth(el,sw),el.elementClass!==Const.OBJECT_CLASS_LINE&&el.elementClass!==Const.OBJECT_CLASS_CURVE||this.updatePathWithArrowHeads(el,!1)}return this},suspendRedraw:function(){},unsuspendRedraw:function(){},drawZoomBar:function(board,attr){var doc,node,cancelbubble=function(e){e||(e=window.event),e.stopPropagation?e.stopPropagation():e.cancelBubble=!0},createButton=function(label,handler){var button;button=doc.createElement("span"),node.appendChild(button),button.appendChild(doc.createTextNode(label)),button.style.paddingLeft="7px",button.style.paddingRight="7px",void 0!==button.classList&&button.classList.add("JXG_navigation_button"),Env.addEvent(button,"click",(function(e){return Type.bind(handler,board)(),!1}),board),Env.addEvent(button,"mouseup",cancelbubble,board),Env.addEvent(button,"mousedown",cancelbubble,board),Env.addEvent(button,"touchend",cancelbubble,board),Env.addEvent(button,"touchstart",cancelbubble,board)};Env.isBrowser&&"no"!==this.type&&(doc=board.containerObj.ownerDocument,(node=doc.createElement("div")).setAttribute("id",board.containerObj.id+"_navigationbar"),node.style.color=attr.strokecolor,node.style.backgroundColor=attr.fillcolor,node.style.padding=attr.padding,node.style.position=attr.position,node.style.fontSize=attr.fontsize,node.style.cursor=attr.cursor,node.style.zIndex=attr.zindex,board.containerObj.appendChild(node),node.style.right=attr.right,node.style.bottom=attr.bottom,void 0!==node.classList&&node.classList.add("JXG_navigation"),board.attr.showfullscreen&&createButton(board.attr.fullscreen.symbol,(function(){board.toFullscreen(board.attr.fullscreen.id)})),board.attr.showscreenshot&&createButton(board.attr.screenshot.symbol,(function(){window.setTimeout((function(){board.renderer.screenshot(board,"",!1)}),330)})),board.attr.showreload&&createButton("↻",(function(){board.reload()})),board.attr.showcleartraces&&createButton("⊗",(function(){board.clearTraces()})),board.attr.shownavigation&&(board.attr.showzoom&&(createButton("–",board.zoomOut),createButton("o",board.zoom100),createButton("+",board.zoomIn)),createButton("←",board.clickLeftArrow),createButton("↓",board.clickUpArrow),createButton("↑",board.clickDownArrow),createButton("→",board.clickRightArrow)))},getElementById:function(id){return Type.exists(this.container)?this.container.ownerDocument.getElementById(this.container.id+"_"+id):""},removeToInsertLater:function(el){var parentNode=el.parentNode,nextSibling=el.nextSibling;if(null!==parentNode)return parentNode.removeChild(el),function(){nextSibling?parentNode.insertBefore(el,nextSibling):parentNode.appendChild(el)}},resize:function(w,h){},createTouchpoints:function(n){},showTouchpoint:function(i){},hideTouchpoint:function(i){},updateTouchpoint:function(i,pos){},dumpToDataURI:function(_ignoreTexts){},dumpToCanvas:function(canvasId,w,h,_ignoreTexts){},screenshot:function(board){},setLayer:function(el,level){}}),JXG.AbstractRenderer})),define("reader/file",["jxg","utils/env","utils/type","utils/encoding","utils/base64"],(function(JXG,Env,Type,Encoding,Base64){return JXG.FileReader={handleRemoteFile:function(url,board,format,async,encoding,callback){var request=!1;try{request=new XMLHttpRequest,"raw"===format.toLowerCase()?request.overrideMimeType("text/plain; charset="+encoding):request.overrideMimeType("text/xml; charset="+encoding)}catch(e){try{request=new ActiveXObject("Msxml2.XMLHTTP")}catch(ex){try{request=new ActiveXObject("Microsoft.XMLHTTP")}catch(exc){request=!1}}}if(request){request.open("GET",url,async),"raw"===format.toLowerCase()?this.cbp=function(){var req=request;4===req.readyState&&board(req.responseText)}:this.cbp=function(){var req=request,text="";4===req.readyState&&(text=!Type.exists(req.responseStream)||"PK"!==req.responseText.slice(0,2)&&31!==Encoding.asciiCharCodeAt(req.responseText.slice(0,1),0)?req.responseText:Base64.decode(jxgBinFileReader(req)),this.parseString(text,board,format,callback))},this.cb=Type.bind(this.cbp,this),request.onreadystatechange=this.cb;try{request.send(null)}catch(ex2){throw new Error("JSXGraph: A problem occurred while trying to read remote file '"+url+"'.")}}else JXG.debug("AJAX not activated!")},handleLocalFile:function(url,board,format,async,encoding,callback){Type.exists(async)||(async=!0),"raw"===format.toLowerCase()?this.cbp=function(e){board(e.target.result)}:this.cbp=function(e){var text=e.target.result;this.parseString(text,board,format,callback)},this.cb=Type.bind(this.cbp,this);var reader=new FileReader;reader.onload=this.cb,"raw"===format.toLowerCase()?reader.readAsText(url):reader.readAsText(url,encoding)},parseFileContent:function(url,board,format,async,encoding,callback){Type.isString(url)||void 0===FileReader?this.handleRemoteFile(url,board,format,async,encoding,callback):this.handleLocalFile(url,board,format,async,encoding,callback)},parseString:function(str,board,format,callback){var Reader;if(format=format.toLowerCase(),Reader=JXG.readers[format],Type.exists(Reader))new Reader(board,str).read();else if("jessiecode"!==format)throw new Error("JSXGraph: There is no reader available for '"+format+"'.");Type.isFunction(callback)&&callback(board)}},!Env.isMetroApp()&&Env.isBrowser&&"object"===("undefined"==typeof navigator?"undefined":_typeof(navigator))&&/msie/i.test(navigator.userAgent)&&!/opera/i.test(navigator.userAgent)&&document&&document.write&&document.write('<script type="text/vbscript">\nFunction Base64Encode(inData)\n Const Base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"\n Dim cOut, sOut, I\n For I = 1 To LenB(inData) Step 3\n Dim nGroup, pOut, sGroup\n nGroup = &H10000 * AscB(MidB(inData, I, 1)) + _\n &H100 * MyASC(MidB(inData, I + 1, 1)) + MyASC(MidB(inData, I + 2, 1))\n nGroup = Oct(nGroup)\n nGroup = String(8 - Len(nGroup), "0") & nGroup\n pOut = Mid(Base64, CLng("&o" & Mid(nGroup, 1, 2)) + 1, 1) + _\n Mid(Base64, CLng("&o" & Mid(nGroup, 3, 2)) + 1, 1) + _\n Mid(Base64, CLng("&o" & Mid(nGroup, 5, 2)) + 1, 1) + _\n Mid(Base64, CLng("&o" & Mid(nGroup, 7, 2)) + 1, 1)\n sOut = sOut + pOut\n Next\n Select Case LenB(inData) Mod 3\n Case 1: \'8 bit final\n sOut = Left(sOut, Len(sOut) - 2) + "=="\n Case 2: \'16 bit final\n sOut = Left(sOut, Len(sOut) - 1) + "="\n End Select\n Base64Encode = sOut\nEnd Function\n\nFunction MyASC(OneChar)\n If OneChar = "" Then MyASC = 0 Else MyASC = AscB(OneChar)\nEnd Function\n\nFunction jxgBinFileReader(xhr)\n Dim byteString\n Dim b64String\n Dim i\n byteString = xhr.responseBody\n ReDim byteArray(LenB(byteString))\n For i = 1 To LenB(byteString)\n byteArray(i-1) = AscB(MidB(byteString, i, 1))\n Next\n b64String = Base64Encode(byteString)\n jxgBinFileReader = b64String\nEnd Function\n<\/script>\n'),JXG.FileReader})),define("parser/geonext",["jxg","base/constants","utils/type"],(function(JXG,Const,Type){return JXG.GeonextParser={replacePow:function(te){var count,pos,c,previousIndex,leftop,rightop,pre,p,left,i,right,expr;for(i=(te=te.replace(/(\s*)\^(\s*)/g,"^")).indexOf("^"),previousIndex=-1;i>=0&&i<te.length-1;){if(previousIndex===i)throw new Error("JSXGraph: Error while parsing expression '"+te+"'");if(previousIndex=i,left=te.slice(0,i),right=te.slice(i+1),")"===left.charAt(left.length-1)){for(count=1,pos=left.length-2;pos>=0&&count>0;)")"===(c=left.charAt(pos))?count++:"("===c&&(count-=1),pos-=1;if(0!==count)throw new Error("JSXGraph: Missing '(' in expression");for(leftop="",pre=left.substring(0,pos+1),p=pos;p>=0&&pre.substr(p,1).match(/([\w.]+)/);)leftop=RegExp.$1+leftop,p-=1;leftop=(leftop+=left.substring(pos+1,left.length)).replace(/([()+*%^\-/\][])/g,"\\$1")}else leftop="[\\w\\.]+";if(right.match(/^([\w.]*\()/)){for(count=1,pos=RegExp.$1.length;pos<right.length&&count>0;)")"===(c=right.charAt(pos))?count-=1:"("===c&&(count+=1),pos+=1;if(0!==count)throw new Error("JSXGraph: Missing ')' in expression");rightop=(rightop=right.substring(0,pos)).replace(/([()+*%^\-/[\]])/g,"\\$1")}else rightop="[\\w\\.]+";expr=new RegExp("("+leftop+")\\^("+rightop+")"),i=(te=te.replace(expr,"pow($1,$2)")).indexOf("^")}return te},replaceIf:function(te){var left,right,i,pos,count,k1,k2,c,meat,s="",first=null,second=null,third=null;if((i=te.indexOf("If("))<0)return te;for(te=te.replace(/""/g,"0");i>=0;){for(left=te.slice(0,i),right=te.slice(i+3),count=1,pos=0,k1=-1,k2=-1;pos<right.length&&count>0;)")"===(c=right.charAt(pos))?count-=1:"("===c?count+=1:","===c&&1===count&&(k1<0?k1=pos:k2=pos),pos+=1;if(meat=right.slice(0,pos-1),right=right.slice(pos),k1<0)return"";if(k2<0)return"";first=meat.slice(0,k1),second=meat.slice(k1+1,k2),third=meat.slice(k2+1),s+=left+"(("+(first=this.replaceIf(first))+")?("+(second=this.replaceIf(second))+"):("+(third=this.replaceIf(third))+"))",first=null,second=null,i=(te=right).indexOf("If(")}return s+=right},replaceNameById:function(term,board,jc){var end,elName,el,i,pos=0,funcs=["X","Y","L","V"],printId=function(id){return jc?"$('"+id+"')":id};for(i=0;i<funcs.length;i++)for(pos=term.indexOf(funcs[i]+"(");pos>=0;)pos>=0&&(end=term.indexOf(")",pos+2))>=0&&(elName=(elName=term.slice(pos+2,end)).replace(/\\(['"])?/g,"$1"),(el=board.elementsByName[elName])&&(term=term.slice(0,pos+2)+(jc?"$('":"")+printId(el.id)+term.slice(end))),end=term.indexOf(")",pos+2),pos=term.indexOf(funcs[i]+"(",end);for(pos=term.indexOf("Dist(");pos>=0;)pos>=0&&(end=term.indexOf(",",pos+5))>=0&&(elName=(elName=term.slice(pos+5,end)).replace(/\\(['"])?/g,"$1"),(el=board.elementsByName[elName])&&(term=term.slice(0,pos+5)+printId(el.id)+term.slice(end))),end=term.indexOf(",",pos+5),pos=term.indexOf(",",end),(end=term.indexOf(")",pos+1))>=0&&(elName=(elName=term.slice(pos+1,end)).replace(/\\(['"])?/g,"$1"),(el=board.elementsByName[elName])&&(term=term.slice(0,pos+1)+printId(el.id)+term.slice(end))),end=term.indexOf(")",pos+1),pos=term.indexOf("Dist(",end);for(funcs=["Deg","Rad"],i=0;i<funcs.length;i++)for(pos=term.indexOf(funcs[i]+"(");pos>=0;)pos>=0&&(end=term.indexOf(",",pos+4))>=0&&(elName=(elName=term.slice(pos+4,end)).replace(/\\(['"])?/g,"$1"),(el=board.elementsByName[elName])&&(term=term.slice(0,pos+4)+printId(el.id)+term.slice(end))),end=term.indexOf(",",pos+4),pos=term.indexOf(",",end),(end=term.indexOf(",",pos+1))>=0&&(elName=(elName=term.slice(pos+1,end)).replace(/\\(['"])?/g,"$1"),(el=board.elementsByName[elName])&&(term=term.slice(0,pos+1)+printId(el.id)+term.slice(end))),end=term.indexOf(",",pos+1),pos=term.indexOf(",",end),(end=term.indexOf(")",pos+1))>=0&&(elName=(elName=term.slice(pos+1,end)).replace(/\\(['"])?/g,"$1"),(el=board.elementsByName[elName])&&(term=term.slice(0,pos+1)+printId(el.id)+term.slice(end))),end=term.indexOf(")",pos+1),pos=term.indexOf(funcs[i]+"(",end);return term},replaceIdByObj:function(term){var expr=/(X|Y|L)\(([\w_]+)\)/g;return term=term.replace(expr,"$('$2').$1()"),expr=/(V)\(([\w_]+)\)/g,term=term.replace(expr,"$('$2').Value()"),expr=/(Dist)\(([\w_]+),([\w_]+)\)/g,term=term.replace(expr,"dist($('$2'), $('$3'))"),expr=/(Deg)\(([\w_]+),([ \w[\w_]+),([\w_]+)\)/g,term=term.replace(expr,"deg($('$2'),$('$3'),$('$4'))"),expr=/Rad\(([\w_]+),([\w_]+),([\w_]+)\)/g,term=term.replace(expr,"rad($('$1'),$('$2'),$('$3'))"),expr=/N\((.+)\)/g,term=term.replace(expr,"($1)")},geonext2JS:function(term,board){var expr,newterm,i,from=["Abs","ACos","ASin","ATan","Ceil","Cos","Exp","Factorial","Floor","Log","Max","Min","Random","Round","Sin","Sqrt","Tan","Trunc"],to=["abs","acos","asin","atan","ceil","cos","exp","factorial","floor","log","max","min","random","round","sin","sqrt","tan","ceil"];for(newterm=term=(term=(term=term.replace(/</g,"<")).replace(/>/g,">")).replace(/&/g,"&"),newterm=this.replaceNameById(newterm,board),newterm=this.replaceIf(newterm),newterm=this.replacePow(newterm),newterm=this.replaceIdByObj(newterm),i=0;i<from.length;i++)expr=new RegExp(["(\\W|^)(",from[i],")"].join(""),"ig"),newterm=newterm.replace(expr,["$1",to[i]].join(""));return newterm=(newterm=(newterm=(newterm=(newterm=newterm.replace(/True/g,"true")).replace(/False/g,"false")).replace(/fasle/g,"false")).replace(/Pi/g,"PI")).replace(/"/g,"'")},findDependencies:function(me,term,board){var elements,el,expr,elmask;for(el in Type.exists(board)||(board=me.board),elements=board.elementsByName)elements.hasOwnProperty(el)&&el!==me.name&&(elements[el].elementClass===Const.OBJECT_CLASS_TEXT&&Type.evaluate(elements[el].visProp.islabel)||(elmask=(elmask=el.replace(/\[/g,"\\[")).replace(/\]/g,"\\]"),expr=new RegExp("\\(([\\w\\[\\]'_ ]+,)*("+elmask+")(,[\\w\\[\\]'_ ]+)*\\)","g"),term.search(expr)>=0&&elements[el].addChild(me)))},gxt2jc:function(term,board){var newterm;return newterm=term=(term=(term=term.replace(/</g,"<")).replace(/>/g,">")).replace(/&/g,"&"),newterm=(newterm=(newterm=(newterm=this.replaceNameById(newterm,board,!0)).replace(/True/g,"true")).replace(/False/g,"false")).replace(/fasle/g,"false")}},JXG.GeonextParser})),define("base/element",["jxg","base/constants","base/coords","math/math","math/statistics","options","utils/event","utils/color","utils/type"],(function(JXG,Const,Coords,Mat,Statistics,Options,EventEmitter,Color,Type){return JXG.GeometryElement=function(board,attributes,type,oclass){var name,key,attr;if(this.needsUpdate=!0,this.isDraggable=!1,this.isReal=!0,this.childElements={},this.hasLabel=!1,this.highlighted=!1,this.notExistingParents={},this.traces={},this.numTraces=0,this.transformations=[],this.baseElement=null,this.descendants={},this.ancestors={},this.parents=[],this.symbolic={},this.rendNode=null,this.elType="",this.dump=!0,this.subs={},this.inherits=[],this._pos=-1,this.stdform=[1,0,0,0,1,1,0,0],this.methodMap={setLabel:"setLabel",label:"label",setName:"setName",getName:"getName",addTransform:"addTransform",setProperty:"setAttribute",setAttribute:"setAttribute",addChild:"addChild",animate:"animate",on:"on",off:"off",trigger:"trigger",addTicks:"addTicks",removeTicks:"removeTicks",removeAllTicks:"removeAllTicks"},this.quadraticform=[[1,0,0],[0,1,0],[0,0,1]],this.visProp={},this.visPropCalc={visible:!1},EventEmitter.eventify(this),this.mouseover=!1,this.lastDragTime=new Date,arguments.length>0){for(key in this.board=board,this.type=type,this._org_type=type,this.elementClass=oclass||Const.OBJECT_CLASS_OTHER,this.id=attributes.id,name=attributes.name,Type.exists(name)||(name=this.board.generateName(this)),""!==name&&(this.board.elementsByName[name]=this),this.name=name,this.needsRegularUpdate=attributes.needsregularupdate,Type.clearVisPropOld(this),attr=this.resolveShortcuts(attributes))attr.hasOwnProperty(key)&&this._set(key,attr[key]);this.visProp.draft=attr.draft&&attr.draft.draft}},JXG.extend(JXG.GeometryElement.prototype,{addChild:function(obj){var el,el2;for(el in this.childElements[obj.id]=obj,this.addDescendants(obj),obj.ancestors[this.id]=this,this.descendants)if(this.descendants.hasOwnProperty(el))for(el2 in this.descendants[el].ancestors[this.id]=this,this.ancestors)this.ancestors.hasOwnProperty(el2)&&(this.descendants[el].ancestors[this.ancestors[el2].id]=this.ancestors[el2]);for(el in this.ancestors)if(this.ancestors.hasOwnProperty(el))for(el2 in this.descendants)this.descendants.hasOwnProperty(el2)&&(this.ancestors[el].descendants[this.descendants[el2].id]=this.descendants[el2]);return this},addDescendants:function(obj){var el;for(el in this.descendants[obj.id]=obj,obj.childElements)obj.childElements.hasOwnProperty(el)&&this.addDescendants(obj.childElements[el]);return this},addParents:function(parents){var i,len,par;for(len=(par=Type.isArray(parents)?parents:arguments).length,i=0;i<len;++i)Type.exists(par[i])&&(Type.isId(this.board,par[i])?this.parents.push(par[i]):Type.exists(par[i].id)&&this.parents.push(par[i].id));this.parents=Type.uniqueArray(this.parents)},setParents:function(parents){this.parents=[],this.addParents(parents)},removeChild:function(obj){return delete this.childElements[obj.id],this.removeDescendants(obj),delete obj.ancestors[this.id],this},removeDescendants:function(obj){var el;for(el in delete this.descendants[obj.id],obj.childElements)obj.childElements.hasOwnProperty(el)&&this.removeDescendants(obj.childElements[el]);return this},countChildren:function(){var prop,d,s=0;for(prop in d=this.childElements)d.hasOwnProperty(prop)&&prop.indexOf("Label")<0&&s++;return s},getName:function(){return this.name},addTransform:function(transform){return this},draggable:function(){return this.isDraggable&&!Type.evaluate(this.visProp.fixed)&&this.type!==Const.OBJECT_TYPE_GLIDER},setPosition:function(method,coords){var el,i,len,t,parents=[];if(!Type.exists(this.parents))return this;for(len=this.parents.length,i=0;i<len;++i)if(el=this.board.select(this.parents[i]),Type.isPoint(el)){if(!el.draggable())return this;parents.push(el)}for(3===coords.length&&(coords=coords.slice(1)),t=this.board.create("transform",coords,{type:"translate"}),(len=parents.length)>0?t.applyOnce(parents):this.transformations.length>0&&this.transformations[this.transformations.length-1].isNumericMatrix?this.transformations[this.transformations.length-1].melt(t):this.addTransform(t),i=0;i<len;++i)parents[i].type===Const.OBJECT_TYPE_GLIDER&&parents[i].updateGlider();return this},setPositionDirectly:function(method,coords,oldcoords){var c=new Coords(method,coords,this.board,!1),oldc=new Coords(method,oldcoords,this.board,!1),dc=Statistics.subtract(c.usrCoords,oldc.usrCoords);return this.setPosition(Const.COORDS_BY_USER,dc),this},generatePolynomial:function(){return[]},animate:function(hash,time,options){options=options||{};var r,p,i,delay=this.board.attr.animationdelay,steps=Math.ceil(time/delay),self=this,animateColor=function(startRGB,endRGB,property){var hsv1,hsv2,sh,ss,sv;for(hsv1=Color.rgb2hsv(startRGB),sh=((hsv2=Color.rgb2hsv(endRGB))[0]-hsv1[0])/steps,ss=(hsv2[1]-hsv1[1])/steps,sv=(hsv2[2]-hsv1[2])/steps,self.animationData[property]=[],i=0;i<steps;i++)self.animationData[property][steps-i-1]=Color.hsv2rgb(hsv1[0]+(i+1)*sh,hsv1[1]+(i+1)*ss,hsv1[2]+(i+1)*sv)},animateFloat=function(start,end,property,round){var tmp,s;if(start=parseFloat(start),end=parseFloat(end),!isNaN(start)&&!isNaN(end))for(s=(end-start)/steps,self.animationData[property]=[],i=0;i<steps;i++)tmp=start+(i+1)*s,self.animationData[property][steps-i-1]=round?Math.floor(tmp):tmp};for(r in this.animationData={},hash)if(hash.hasOwnProperty(r))switch(p=r.toLowerCase()){case"strokecolor":case"fillcolor":animateColor(this.visProp[p],hash[r],p);break;case"size":if(!Type.isPoint(this))break;animateFloat(this.visProp[p],hash[r],p,!0);break;case"strokeopacity":case"strokewidth":case"fillopacity":animateFloat(this.visProp[p],hash[r],p,!1)}return this.animationCallback=options.callback,this.board.addAnimation(this),this},update:function(){return Type.evaluate(this.visProp.trace)&&this.cloneToBackground(),this},updateRenderer:function(){return this},fullUpdate:function(visible){return this.prepareUpdate().update().updateVisibility(visible).updateRenderer()},setDisplayRendNode:function(val){var i,len,s,len_s,obj;if(void 0===val&&(val=this.visPropCalc.visible),val===this.visPropOld.visible)return this;for(this.board.renderer.display(this,val),len=this.inherits.length,s=0;s<len;s++)if(obj=this.inherits[s],Type.isArray(obj))for(len_s=obj.length,i=0;i<len_s;i++)Type.exists(obj[i])&&Type.exists(obj[i].rendNode)&&"inherit"===Type.evaluate(obj[i].visProp.visible)&&obj[i].setDisplayRendNode(val);else Type.exists(obj)&&Type.exists(obj.rendNode)&&"inherit"===Type.evaluate(obj.visProp.visible)&&obj.setDisplayRendNode(val);return this.hasLabel&&Type.exists(this.label)&&Type.exists(this.label.rendNode)&&"inherit"===Type.evaluate(this.label.visProp.visible)&&this.label.setDisplayRendNode(val),this},hide:function(){return this.setAttribute({visible:!1}),this},hideElement:function(){return this.hide(),this},show:function(){return this.setAttribute({visible:!0}),this},showElement:function(){return this.show(),this},updateVisibility:function(parent_val){var i,len,s,len_s,obj,val;if(this.needsUpdate){for(void 0!==parent_val?this.visPropCalc.visible=parent_val:(val=Type.evaluate(this.visProp.visible),Type.exists(this.hiddenByParent)&&this.hiddenByParent&&(val=!1),"inherit"!==val&&(this.visPropCalc.visible=val)),len=this.inherits.length,s=0;s<len;s++)if(obj=this.inherits[s],Type.isArray(obj))for(len_s=obj.length,i=0;i<len_s;i++)Type.exists(obj[i])&&"inherit"===Type.evaluate(obj[i].visProp.visible)&&obj[i].prepareUpdate().updateVisibility(this.visPropCalc.visible);else Type.exists(obj)&&"inherit"===Type.evaluate(obj.visProp.visible)&&obj.prepareUpdate().updateVisibility(this.visPropCalc.visible);Type.exists(this.label)&&Type.exists(this.label.visProp)&&Type.evaluate(this.label.visProp.visible)&&this.label.prepareUpdate().updateVisibility(this.visPropCalc.visible)}return this},_set:function(property,value){var el;if(property=property.toLocaleLowerCase(),this.visProp.hasOwnProperty(property)&&property.indexOf("color")>=0&&Type.isString(value)&&9===value.length&&"#"===value.charAt(0))value=Color.rgba2rgbo(value),this.visProp[property]=value[0],this.visProp[property.replace("color","opacity")]=value[1];else if(null===value||!Type.isObject(value)||Type.exists(value.id)||Type.exists(value.name))this.visProp[property]=value;else for(el in this.visProp[property]={},value)value.hasOwnProperty(el)&&(this.visProp[property][el.toLocaleLowerCase()]=value[el])},resolveShortcuts:function(attributes){var key,i,j,subattr=["traceattributes","traceAttributes"];for(key in Options.shortcuts)if(Options.shortcuts.hasOwnProperty(key)){if(Type.exists(attributes[key]))for(i=0;i<Options.shortcuts[key].length;i++)Type.exists(attributes[Options.shortcuts[key][i]])||(attributes[Options.shortcuts[key][i]]=attributes[key]);for(j=0;j<subattr.length;j++)Type.isObject(attributes[subattr[j]])&&(attributes[subattr[j]]=this.resolveShortcuts(attributes[subattr[j]]))}return attributes},setLabel:function(str){this.hasLabel||this.setAttribute({withlabel:!0}),this.setLabelText(str)},setLabelText:function(str){return Type.exists(this.label)&&(str=str.replace(/</g,"<").replace(/>/g,">"),this.label.setText(str)),this},setName:function(str){str=str.replace(/</g,"<").replace(/>/g,">"),"slider"!==this.elType&&this.setLabelText(str),this.setAttribute({name:str})},setProperty:function(){JXG.deprecated("setProperty()","setAttribute()"),this.setAttribute.apply(this,arguments)},setAttribute:function(attributes){var i,j,le,key,value,arg,opacity,pair,oldvalue,properties={};for(i=0;i<arguments.length;i++)arg=arguments[i],Type.isString(arg)?(pair=arg.split(":"),properties[Type.trim(pair[0])]=Type.trim(pair[1])):Type.isArray(arg)?properties[arg[0]]=arg[1]:JXG.extend(properties,arg);for(i in properties=this.resolveShortcuts(properties))if(properties.hasOwnProperty(i)){if(key=i.replace(/\s+/g,"").toLowerCase(),value=properties[i],Type.isObject(value)&&Type.exists(this.visProp[key])){if(this.visProp[key]=Type.merge(this.visProp[key],value),this.type===Const.OBJECT_TYPE_TICKS&&Type.exists(this.labels))for(le=this.labels.length,j=0;j<le;j++)this.labels[j].setAttribute(value);else if(Type.exists(this[key]))if(Type.isArray(this[key]))for(j=0;j<this[key].length;j++)this[key][j].setAttribute(value);else this[key].setAttribute(value);continue}switch(oldvalue=this.visProp[key],key){case"name":oldvalue=this.name,delete this.board.elementsByName[this.name],this.name=value,this.board.elementsByName[this.name]=this;break;case"needsregularupdate":this.needsRegularUpdate=!("false"===value||!1===value),this.board.renderer.setBuffering(this,this.needsRegularUpdate?"auto":"static");break;case"labelcolor":opacity=(value=Color.rgba2rgbo(value))[1],value=value[0],0===opacity&&Type.exists(this.label)&&this.hasLabel&&this.label.hideElement(),Type.exists(this.label)&&this.hasLabel&&(this.label.visProp.strokecolor=value,this.board.renderer.setObjectStrokeColor(this.label,value,opacity)),this.elementClass===Const.OBJECT_CLASS_TEXT&&(this.visProp.strokecolor=value,this.visProp.strokeopacity=opacity,this.board.renderer.setObjectStrokeColor(this,value,opacity));break;case"infoboxtext":Type.isString(value)?this.infoboxText=value:this.infoboxText=!1;break;case"visible":this.visProp.visible="false"!==value&&("true"===value||value),this.setDisplayRendNode(Type.evaluate(this.visProp.visible)),Type.evaluate(this.visProp.visible)&&Type.exists(this.updateSize)&&this.updateSize();break;case"face":Type.isPoint(this)&&(this.visProp.face=value,this.board.renderer.changePointStyle(this));break;case"trace":"false"===value||!1===value?(this.clearTrace(),this.visProp.trace=!1):this.visProp.trace="pause"!==value;break;case"gradient":this.visProp.gradient=value,this.board.renderer.setGradient(this);break;case"gradientsecondcolor":value=Color.rgba2rgbo(value),this.visProp.gradientsecondcolor=value[0],this.visProp.gradientsecondopacity=value[1],this.board.renderer.updateGradient(this);break;case"gradientsecondopacity":this.visProp.gradientsecondopacity=value,this.board.renderer.updateGradient(this);break;case"withlabel":this.visProp.withlabel=value,Type.evaluate(value)?(this.label||this.createLabel(),this.label.setAttribute({visible:"inherit"})):this.label&&this.hasLabel&&this.label.setAttribute({visible:!1}),this.hasLabel=value;break;case"radius":this.type!==Const.OBJECT_TYPE_ANGLE&&this.type!==Const.OBJECT_TYPE_SECTOR||this.setRadius(value);break;case"rotate":(this.elementClass===Const.OBJECT_CLASS_TEXT&&"internal"===Type.evaluate(this.visProp.display)||this.type===Const.OBJECT_TYPE_IMAGE)&&this.addRotation(value);break;case"ticksdistance":this.type===Const.OBJECT_TYPE_TICKS&&Type.isNumber(value)&&(this.ticksFunction=this.makeTicksFunction(value));break;case"generatelabelvalue":this.type===Const.OBJECT_TYPE_TICKS&&Type.isFunction(value)&&(this.generateLabelValue=value);break;case"onpolygon":this.type===Const.OBJECT_TYPE_GLIDER&&(this.onPolygon=!!value);break;case"disabled":Type.exists(this.rendNodeTag)&&(this.rendNodeTag.disabled=!!value);break;case"checked":Type.exists(this.rendNodeTag)&&(this.rendNodeCheckbox.checked=!!value);break;case"maxlength":Type.exists(this.rendNodeTag)&&(this.rendNodeTag.maxlength=!!value);break;case"layer":this.board.renderer.setLayer(this,Type.evaluate(value)),this._set(key,value);break;case"tabindex":Type.exists(this.rendNode)&&(this.rendNode.setAttribute("tabindex",value),this._set(key,value));break;default:Type.exists(this.visProp[key])&&(!JXG.Validator[key]||JXG.Validator[key]&&JXG.Validator[key](value)||JXG.Validator[key]&&Type.isFunction(value)&&JXG.Validator[key](value()))&&(value=(!value.toLowerCase||"false"!==value.toLowerCase())&&value,this._set(key,value))}this.triggerEventHandlers(["attribute:"+key],[oldvalue,value,this])}return this.triggerEventHandlers(["attribute"],[properties,this]),Type.evaluate(this.visProp.needsregularupdate)?this.board.update(this):this.board.fullUpdate(),this},getProperty:function(){JXG.deprecated("getProperty()","getAttribute()"),this.getProperty.apply(this,arguments)},getAttribute:function(key){var result;switch(key=key.toLowerCase()){case"needsregularupdate":result=this.needsRegularUpdate;break;case"labelcolor":result=this.label.visProp.strokecolor;break;case"infoboxtext":result=this.infoboxText;break;case"withlabel":result=this.hasLabel;break;default:result=this.visProp[key]}return result},setDash:function(dash){return this.setAttribute({dash:dash}),this},prepareUpdate:function(){return this.needsUpdate=!0,this},remove:function(){return this.board.renderer.remove(this.board.renderer.getElementById(this.id)),this.hasLabel&&this.board.renderer.remove(this.board.renderer.getElementById(this.label.id)),this},getTextAnchor:function(){return new Coords(Const.COORDS_BY_USER,[0,0],this.board)},getLabelAnchor:function(){return new Coords(Const.COORDS_BY_USER,[0,0],this.board)},setArrow:function(firstArrow,lastArrow){return this.visProp.firstarrow=firstArrow,this.visProp.lastarrow=lastArrow,lastArrow&&(this.type=Const.OBJECT_TYPE_VECTOR,this.elType="arrow"),this.prepareUpdate().update().updateVisibility().updateRenderer(),this},createGradient:function(){var ev_g=Type.evaluate(this.visProp.gradient);"linear"!==ev_g&&"radial"!==ev_g||this.board.renderer.setGradient(this)},createLabel:function(){var attr,that=this;return JXG.elements.text?((attr=Type.deepCopy(this.visProp.label,null)).id=this.id+"Label",attr.isLabel=!0,attr.anchor=this,attr.priv=this.visProp.priv,this.visProp.withlabel&&(this.label=JXG.elements.text(this.board,[0,0,function(){return Type.isFunction(that.name)?that.name():that.name}],attr),this.label.needsUpdate=!0,this.label.dump=!1,this.label.fullUpdate(),this.hasLabel=!0)):JXG.debug("JSXGraph: Can't create label: text element is not available. Make sure you include base/text"),this},highlight:function(force){return force=Type.def(force,!1),!Type.evaluate(this.visProp.highlight)||this.highlighted&&!force||(this.highlighted=!0,this.board.highlightedObjects[this.id]=this,this.board.renderer.highlight(this)),this},noHighlight:function(){return this.highlighted&&(this.highlighted=!1,delete this.board.highlightedObjects[this.id],this.board.renderer.noHighlight(this)),this},clearTrace:function(){var obj;for(obj in this.traces)this.traces.hasOwnProperty(obj)&&this.board.renderer.remove(this.traces[obj]);return this.numTraces=0,this},cloneToBackground:function(){return this},bounds:function(){return[0,0,0,0]},normalize:function(){return this.stdform=Mat.normalize(this.stdform),this},toJSON:function(){var vis,key,json=['{"name":',this.name];for(key in json.push(', "id":'+this.id),vis=[],this.visProp)this.visProp.hasOwnProperty(key)&&Type.exists(this.visProp[key])&&vis.push('"'+key+'":'+this.visProp[key]);return json.push(', "visProp":{'+vis.toString()+"}"),json.push("}"),json.join("")},addRotation:function(angle){var tOffInv,tOff,tS,tSInv,tRot,that=this;return(this.elementClass===Const.OBJECT_CLASS_TEXT&&"internal"===Type.evaluate(this.visProp.display)||this.type===Const.OBJECT_TYPE_IMAGE)&&0!==angle&&(tOffInv=this.board.create("transform",[function(){return-that.X()},function(){return-that.Y()}],{type:"translate"}),tOff=this.board.create("transform",[function(){return that.X()},function(){return that.Y()}],{type:"translate"}),tS=this.board.create("transform",[function(){return that.board.unitX/that.board.unitY},function(){return 1}],{type:"scale"}),tSInv=this.board.create("transform",[function(){return that.board.unitY/that.board.unitX},function(){return 1}],{type:"scale"}),tRot=this.board.create("transform",[function(){return Type.evaluate(angle)*Math.PI/180}],{type:"rotate"}),tOffInv.bindTo(this),tS.bindTo(this),tRot.bindTo(this),tSInv.bindTo(this),tOff.bindTo(this)),this},highlightStrokeColor:function(sColor){return JXG.deprecated("highlightStrokeColor()","setAttribute()"),this.setAttribute({highlightStrokeColor:sColor}),this},strokeColor:function(sColor){return JXG.deprecated("strokeColor()","setAttribute()"),this.setAttribute({strokeColor:sColor}),this},strokeWidth:function(width){return JXG.deprecated("strokeWidth()","setAttribute()"),this.setAttribute({strokeWidth:width}),this},fillColor:function(fColor){return JXG.deprecated("fillColor()","setAttribute()"),this.setAttribute({fillColor:fColor}),this},highlightFillColor:function(fColor){return JXG.deprecated("highlightFillColor()","setAttribute()"),this.setAttribute({highlightFillColor:fColor}),this},labelColor:function(lColor){return JXG.deprecated("labelColor()","setAttribute()"),this.setAttribute({labelColor:lColor}),this},dash:function(d){return JXG.deprecated("dash()","setAttribute()"),this.setAttribute({dash:d}),this},visible:function(v){return JXG.deprecated("visible()","setAttribute()"),this.setAttribute({visible:v}),this},shadow:function(s){return JXG.deprecated("shadow()","setAttribute()"),this.setAttribute({shadow:s}),this},getType:function(){return this.elType},getParents:function(){return Type.isArray(this.parents)?this.parents:[]},snapToGrid:function(){return this},snapToPoints:function(){return this},getAttributes:function(){var i,attributes=Type.deepCopy(this.visProp),cleanThis=[],len=cleanThis.length;for(attributes.id=this.id,attributes.name=this.name,i=0;i<len;i++)delete attributes[cleanThis[i]];return attributes},hasPoint:function(x,y){return!1},addTicks:function(ticks){return""!==ticks.id&&Type.exists(ticks.id)||(ticks.id=this.id+"_ticks_"+(this.ticks.length+1)),this.board.renderer.drawTicks(ticks),this.ticks.push(ticks),ticks.id},removeAllTicks:function(){var t;if(Type.exists(this.ticks)){for(t=this.ticks.length-1;t>=0;t--)this.removeTicks(this.ticks[t]);this.ticks=[],this.board.update()}},removeTicks:function(tick){var t,j;if(Type.exists(this.defaultTicks)&&this.defaultTicks===tick&&(this.defaultTicks=null),Type.exists(this.ticks))for(t=this.ticks.length-1;t>=0;t--)if(this.ticks[t]===tick){if(this.board.removeObject(this.ticks[t]),this.ticks[t].ticks)for(j=0;j<this.ticks[t].ticks.length;j++)Type.exists(this.ticks[t].labels[j])&&this.board.removeObject(this.ticks[t].labels[j]);delete this.ticks[t];break}},getSnapSizes:function(){var sX,sY,ticks;return sX=Type.evaluate(this.visProp.snapsizex),sY=Type.evaluate(this.visProp.snapsizey),sX<=0&&this.board.defaultAxes&&this.board.defaultAxes.x.defaultTicks&&(sX=(ticks=this.board.defaultAxes.x.defaultTicks).ticksDelta*(Type.evaluate(ticks.visProp.minorticks)+1)),sY<=0&&this.board.defaultAxes&&this.board.defaultAxes.y.defaultTicks&&(sY=(ticks=this.board.defaultAxes.y.defaultTicks).ticksDelta*(Type.evaluate(ticks.visProp.minorticks)+1)),[sX,sY]},handleSnapToGrid:function(force,fromParent){var x,y,rx,ry,rcoords,boardBB,res,sX,sY,attractToGrid=Type.evaluate(this.visProp.attracttogrid),ev_au=Type.evaluate(this.visProp.attractorunit),ev_ad=Type.evaluate(this.visProp.attractordistance);return!Type.exists(this.coords)||Type.evaluate(this.visProp.fixed)||(Type.evaluate(this.visProp.snaptogrid)||attractToGrid||!0===force)&&(x=this.coords.usrCoords[1],y=this.coords.usrCoords[2],sX=(res=this.getSnapSizes())[0],sY=res[1],sX>0&&sY>0&&(boardBB=this.board.getBoundingBox(),rx=Math.round(x/sX)*sX,ry=Math.round(y/sY)*sY,rcoords=new JXG.Coords(Const.COORDS_BY_USER,[rx,ry],this.board),(!attractToGrid||rcoords.distance("screen"===ev_au?Const.COORDS_BY_SCREEN:Const.COORDS_BY_USER,this.coords)<ev_ad)&&(x=rx,y=ry,fromParent||(x<boardBB[0]?x+=sX:x>boardBB[2]&&(x-=sX),y<boardBB[3]?y+=sY:y>boardBB[1]&&(y-=sY)),this.coords.setCoordinates(Const.COORDS_BY_USER,[x,y])))),this},getBoundingBox:function(){var i,le,v,x,y,bb=[1/0,1/0,-1/0,-1/0];if(this.type===Const.OBJECT_TYPE_POLYGON){if((le=this.vertices.length-1)<=0)return bb;for(i=0;i<le;i++)v=this.vertices[i].X(),bb[0]=v<bb[0]?v:bb[0],bb[2]=v>bb[2]?v:bb[2],v=this.vertices[i].Y(),bb[1]=v<bb[1]?v:bb[1],bb[3]=v>bb[3]?v:bb[3]}else if(this.elementClass===Const.OBJECT_CLASS_CIRCLE)x=this.center.X(),y=this.center.Y(),bb=[x-this.radius,y+this.radius,x+this.radius,y-this.radius];else if(this.elementClass===Const.OBJECT_CLASS_CURVE){if(0===(le=this.vertices.length))return bb;for(i=0;i<le;i++)v=this.points[i].coords.usrCoords[1],bb[0]=v<bb[0]?v:bb[0],bb[2]=v>bb[2]?v:bb[2],v=this.points[i].coords.usrCoords[1],bb[1]=v<bb[1]?v:bb[1],bb[3]=v>bb[3]?v:bb[3]}return bb},addEvent:JXG.shortcut(JXG.GeometryElement.prototype,"on"),removeEvent:JXG.shortcut(JXG.GeometryElement.prototype,"off"),__evt__over:function(e){},__evt__mouseover:function(e){},__evt__out:function(e){},__evt__mouseout:function(e){},__evt__move:function(e){},__evt__mousemove:function(e){},__evt__drag:function(e){},__evt__mousedrag:function(e){},__evt__pendrag:function(e){},__evt__touchdrag:function(e){},__evt__down:function(e){},__evt__mousedown:function(e){},__evt__pendown:function(e){},__evt__touchdown:function(e){},__evt__up:function(e){},__evt__mouseup:function(e){},__evt__penup:function(e){},__evt__touchup:function(e){},__evt__attribute:function(o,el){},__evt__attribute_:function(val,nval,el){},__evt:function(){}}),JXG.GeometryElement})),define("base/coordselement",["jxg","math/math","math/geometry","math/numerics","math/statistics","base/coords","base/constants","utils/type"],(function(JXG,Mat,Geometry,Numerics,Statistics,Coords,Const,Type){return JXG.CoordsElement=function(coordinates,isLabel){var i;for(Type.exists(coordinates)||(coordinates=[1,0,0]),i=0;i<coordinates.length;++i)coordinates[i]=parseFloat(coordinates[i]);this.coords=new Coords(Const.COORDS_BY_USER,coordinates,this.board),this.initialCoords=new Coords(Const.COORDS_BY_USER,coordinates,this.board),this.position=null,this.isConstrained=!1,this.onPolygon=!1,this.slideObject=null,this.slideObjects=[],this.needsUpdateFromParent=!0,this.groups=[],this.Xjc=null,this.Yjc=null,this.methodMap=Type.deepCopy(this.methodMap,{move:"moveTo",moveTo:"moveTo",moveAlong:"moveAlong",visit:"visit",glide:"makeGlider",makeGlider:"makeGlider",intersect:"makeIntersection",makeIntersection:"makeIntersection",X:"X",Y:"Y",free:"free",setPosition:"setGliderPosition",setGliderPosition:"setGliderPosition",addConstraint:"addConstraint",dist:"Dist",onPolygon:"onPolygon"}),Type.exists(this.element)&&this.addAnchor(coordinates,isLabel),this.isDraggable=!0},JXG.extend(JXG.CoordsElement.prototype,{updateConstraint:function(){return this},updateCoords:function(fromParent){return this.needsUpdate?(Type.exists(fromParent)||(fromParent=!1),Type.evaluate(this.visProp.frozen)||this.updateConstraint(),this.type===Const.OBJECT_TYPE_GLIDER&&(this.isConstrained&&(fromParent=!1),fromParent?this.updateGliderFromParent():this.updateGlider()),this.updateTransform(fromParent),this):this},updateGlider:function(){var i,p1c,p2c,d,v,poly,pos,alpha,beta,angle,cp,c,invMat,newCoords,newPos,ev_sw,res,cu,isTransformed,delta=2*Math.PI,doRound=!1,slide=this.slideObject,slides=[];if(this.needsUpdateFromParent=!1,slide.elementClass===Const.OBJECT_CLASS_CIRCLE)Type.evaluate(this.visProp.isgeonext)&&(delta=1),newCoords=Geometry.projectPointToCircle(this,slide,this.board),newPos=Geometry.rad([slide.center.X()+1,slide.center.Y()],slide.center,this)/delta;else if(slide.elementClass===Const.OBJECT_CLASS_LINE){if(this.onPolygon){if(p1c=slide.point1.coords.usrCoords,d=(p2c=slide.point2.coords.usrCoords)[i=1]-p1c[i],Math.abs(d)<Mat.eps&&(d=p2c[i=2]-p1c[i]),pos=(Geometry.projectPointToLine(this,slide,this.board).usrCoords[i]-p1c[i])/d,poly=slide.parentPolygon,pos<0){for(i=0;i<poly.borders.length;i++)if(slide===poly.borders[i]){slide=poly.borders[(i-1+poly.borders.length)%poly.borders.length];break}}else if(pos>1)for(i=0;i<poly.borders.length;i++)if(slide===poly.borders[i]){slide=poly.borders[(i+1+poly.borders.length)%poly.borders.length];break}slide.id!==this.slideObject.id&&(this.slideObject=slide)}p1c=slide.point1.coords,p2c=slide.point2.coords,(d=p1c.distance(Const.COORDS_BY_USER,p2c))<Mat.eps?(newCoords=p1c,doRound=!0,newPos=0):(newCoords=Geometry.projectPointToLine(this,slide,this.board),p1c=p1c.usrCoords.slice(0),p2c=p2c.usrCoords.slice(0),Math.abs(p2c[0])<Mat.eps?(d=p2c[i=1],Math.abs(d)<Mat.eps&&(d=p2c[i=2]),newPos=((d=(newCoords.usrCoords[i]-p1c[i])/d)>=0?1:-1)*(d=Math.abs(d))/(d+1)):Math.abs(p1c[0])<Mat.eps?(d=p1c[i=1],Math.abs(d)<Mat.eps&&(d=p1c[i=2]),newPos=(d=(newCoords.usrCoords[i]-p2c[i])/d)<0?(1-2*d)/(1-d):1/(d+1)):(d=p2c[i=1]-p1c[i],Math.abs(d)<Mat.eps&&(d=p2c[i=2]-p1c[i]),newPos=(newCoords.usrCoords[i]-p1c[i])/d)),ev_sw=Type.evaluate(this.visProp.snapwidth),Type.evaluate(ev_sw)>0&&Math.abs(this._smax-this._smin)>=Mat.eps&&(v=(newPos=Math.max(Math.min(newPos,1),0))*(this._smax-this._smin)+this._smin,newPos=((v=Math.round(v/ev_sw)*ev_sw)-this._smin)/(this._smax-this._smin),this.update(!0)),p1c=slide.point1.coords,!Type.evaluate(slide.visProp.straightfirst)&&Math.abs(p1c.usrCoords[0])>Mat.eps&&newPos<0&&(newCoords=p1c,doRound=!0,newPos=0),p2c=slide.point2.coords,!Type.evaluate(slide.visProp.straightlast)&&Math.abs(p2c.usrCoords[0])>Mat.eps&&newPos>1&&(newCoords=p2c,doRound=!0,newPos=1)}else if(slide.type===Const.OBJECT_TYPE_TURTLE)this.updateConstraint(),newCoords=(res=Geometry.projectPointToTurtle(this,slide,this.board))[0],newPos=res[1];else if(slide.elementClass===Const.OBJECT_CLASS_CURVE)if(slide.type===Const.OBJECT_TYPE_ARC||slide.type===Const.OBJECT_TYPE_SECTOR)newCoords=Geometry.projectPointToCircle(this,slide,this.board),angle=Geometry.rad(slide.radiuspoint,slide.center,this),alpha=0,beta=Geometry.rad(slide.radiuspoint,slide.center,slide.anglepoint),newPos=angle,("minor"===(ev_sw=Type.evaluate(slide.visProp.selection))&&beta>Math.PI||"major"===ev_sw&&beta<Math.PI)&&(alpha=beta,beta=2*Math.PI),(angle<alpha||angle>beta)&&(newPos=beta,(angle<alpha&&angle>.5*alpha||angle>beta&&angle>.5*beta+Math.PI)&&(newPos=alpha),this.needsUpdateFromParent=!0,this.updateGliderFromParent()),delta=beta-alpha,this.visProp.isgeonext&&(delta=1),Math.abs(delta)>Mat.eps&&(newPos/=delta);else if(this.updateConstraint(),slide.transformations.length>0){for(isTransformed=!1,(res=slide.getTransformationSource())[0]&&(isTransformed=res[0],slides.push(slide),slides.push(res[1]));res[0]&&Type.exists(res[1]._transformationSource);)res=res[1].getTransformationSource(),slides.push(res[1]);if(cu=this.coords.usrCoords,isTransformed){for(i=0;i<slides.length;i++)slides[i].updateTransformMatrix(),invMat=Mat.inverse(slides[i].transformMat),cu=Mat.matVecMult(invMat,cu);for(cp=new Coords(Const.COORDS_BY_USER,cu,this.board).usrCoords,cu=(c=Geometry.projectCoordsToCurve(cp[1],cp[2],this.position||0,slides[slides.length-1],this.board))[0].usrCoords,i=slides.length-2;i>=0;i--)cu=Mat.matVecMult(slides[i].transformMat,cu);c[0]=new Coords(Const.COORDS_BY_USER,cu,this.board)}else slide.updateTransformMatrix(),invMat=Mat.inverse(slide.transformMat),cu=Mat.matVecMult(invMat,cu),cp=new Coords(Const.COORDS_BY_USER,cu,this.board).usrCoords,c=Geometry.projectCoordsToCurve(cp[1],cp[2],this.position||0,slide,this.board);newCoords=c[0],newPos=c[1]}else newCoords=(res=Geometry.projectPointToCurve(this,slide,this.board))[0],newPos=res[1];else Type.isPoint(slide)&&(newCoords=Geometry.projectPointToPoint(this,slide,this.board),newPos=this.position);this.coords.setCoordinates(Const.COORDS_BY_USER,newCoords.usrCoords,doRound),this.position=newPos},updateGliderFromParent:function(){var p1c,p2c,r,lbda,c,res,i,isTransformed,baseangle,alpha,angle,beta,slide=this.slideObject,slides=[],delta=2*Math.PI;if(this.needsUpdateFromParent){if(slide.elementClass===Const.OBJECT_CLASS_CIRCLE)r=slide.Radius(),Type.evaluate(this.visProp.isgeonext)&&(delta=1),c=[slide.center.X()+r*Math.cos(this.position*delta),slide.center.Y()+r*Math.sin(this.position*delta)];else if(slide.elementClass===Const.OBJECT_CLASS_LINE)p1c=slide.point1.coords.usrCoords,p2c=slide.point2.coords.usrCoords,0===p1c[0]&&0===p1c[1]&&0===p1c[2]||0===p2c[0]&&0===p2c[1]&&0===p2c[2]?c=[0,0,0]:Math.abs(p2c[0])<Mat.eps?(lbda=Math.min(Math.abs(this.position),1-Mat.eps),lbda/=1-lbda,this.position<0&&(lbda=-lbda),c=[p1c[0]+lbda*p2c[0],p1c[1]+lbda*p2c[1],p1c[2]+lbda*p2c[2]]):Math.abs(p1c[0])<Mat.eps?(lbda=Math.max(this.position,Mat.eps),lbda=(lbda=Math.min(lbda,2-Mat.eps))>1?(lbda-1)/(lbda-2):(1-lbda)/lbda,c=[p2c[0]+lbda*p1c[0],p2c[1]+lbda*p1c[1],p2c[2]+lbda*p1c[2]]):(lbda=this.position,c=[p1c[0]+lbda*(p2c[0]-p1c[0]),p1c[1]+lbda*(p2c[1]-p1c[1]),p1c[2]+lbda*(p2c[2]-p1c[2])]);else if(slide.type===Const.OBJECT_TYPE_TURTLE)this.coords.setCoordinates(Const.COORDS_BY_USER,[slide.Z(this.position),slide.X(this.position),slide.Y(this.position)]),this.updateConstraint(),c=Geometry.projectPointToTurtle(this,slide,this.board)[0].usrCoords;else if(slide.elementClass===Const.OBJECT_CLASS_CURVE){for(isTransformed=!1,(res=slide.getTransformationSource())[0]&&(isTransformed=res[0],slides.push(slide),slides.push(res[1]));res[0]&&Type.exists(res[1]._transformationSource);)res=res[1].getTransformationSource(),slides.push(res[1]);if(isTransformed?this.coords.setCoordinates(Const.COORDS_BY_USER,[slides[slides.length-1].Z(this.position),slides[slides.length-1].X(this.position),slides[slides.length-1].Y(this.position)]):this.coords.setCoordinates(Const.COORDS_BY_USER,[slide.Z(this.position),slide.X(this.position),slide.Y(this.position)]),slide.type===Const.OBJECT_TYPE_ARC||slide.type===Const.OBJECT_TYPE_SECTOR)baseangle=Geometry.rad([slide.center.X()+1,slide.center.Y()],slide.center,slide.radiuspoint),alpha=0,beta=Geometry.rad(slide.radiuspoint,slide.center,slide.anglepoint),("minor"===slide.visProp.selection&&beta>Math.PI||"major"===slide.visProp.selection&&beta<Math.PI)&&(alpha=beta,beta=2*Math.PI),delta=beta-alpha,Type.evaluate(this.visProp.isgeonext)&&(delta=1),((angle=this.position*delta)<alpha||angle>beta)&&(((angle=beta)<alpha&&angle>.5*alpha||angle>beta&&angle>.5*beta+Math.PI)&&(angle=alpha),this.position=angle,Math.abs(delta)>Mat.eps&&(this.position/=delta)),r=slide.Radius(),c=[slide.center.X()+r*Math.cos(this.position*delta+baseangle),slide.center.Y()+r*Math.sin(this.position*delta+baseangle)];else if(this.updateConstraint(),isTransformed)for(c=Geometry.projectPointToCurve(this,slides[slides.length-1],this.board)[0].usrCoords,i=slides.length-2;i>=0;i--)c=new Coords(Const.COORDS_BY_USER,Mat.matVecMult(slides[i].transformMat,c),this.board).usrCoords;else c=Geometry.projectPointToCurve(this,slide,this.board)[0].usrCoords}else Type.isPoint(slide)&&(c=Geometry.projectPointToPoint(this,slide,this.board).usrCoords);this.coords.setCoordinates(Const.COORDS_BY_USER,c,!1)}else this.needsUpdateFromParent=!0},updateRendererGeneric:function(rendererMethod){return this.needsUpdate?(this.visPropCalc.visible&&(this.isReal=!isNaN(this.coords.usrCoords[1]+this.coords.usrCoords[2]),this.isReal=Math.abs(this.coords.usrCoords[0])>Mat.eps&&this.isReal,this.isReal||this.updateVisibility(!1)),this.visPropCalc.visible&&this.board.renderer[rendererMethod](this),this.hasLabel&&this.visPropCalc.visible&&this.label&&this.label.visPropCalc.visible&&this.isReal&&(this.label.update(),this.board.renderer.updateText(this.label)),this.setDisplayRendNode(),this.needsUpdate=!1,this):this},X:function(){return this.coords.usrCoords[1]},Y:function(){return this.coords.usrCoords[2]},Z:function(){return this.coords.usrCoords[0]},XEval:function(){return this.coords.usrCoords[1]},YEval:function(){return this.coords.usrCoords[2]},ZEval:function(){return this.coords.usrCoords[0]},Dist:function(point2){return this.isReal&&point2.isReal?this.coords.distance(Const.COORDS_BY_USER,point2.coords):NaN},snapToGrid:function(force){return this.handleSnapToGrid(force)},handleSnapToPoints:function(force){var i,pEl,pCoords,len,ev_au,ev_ad,len2,j,d=0,dMax=1/0,c=null,ev_is2p=Type.evaluate(this.visProp.ignoredsnaptopoints),ignore=!1;if(len=this.board.objectsList.length,ev_is2p&&(len2=ev_is2p.length),Type.evaluate(this.visProp.snaptopoints)||force){for(ev_au=Type.evaluate(this.visProp.attractorunit),ev_ad=Type.evaluate(this.visProp.attractordistance),i=0;i<len;i++){if(pEl=this.board.objectsList[i],ev_is2p){for(ignore=!1,j=0;j<len2;j++)if(pEl===this.board.select(ev_is2p[j])){ignore=!0;break}if(ignore)continue}Type.isPoint(pEl)&&pEl!==this&&pEl.visPropCalc.visible&&(pCoords=Geometry.projectPointToPoint(this,pEl,this.board),(d="screen"===ev_au?pCoords.distance(Const.COORDS_BY_SCREEN,this.coords):pCoords.distance(Const.COORDS_BY_USER,this.coords))<ev_ad&&d<dMax&&(dMax=d,c=pCoords))}null!==c&&this.coords.setCoordinates(Const.COORDS_BY_USER,c.usrCoords)}return this},snapToPoints:function(force){return this.handleSnapToPoints(force)},handleAttractors:function(){var i,el,projCoords,projection,d=0,ev_au=Type.evaluate(this.visProp.attractorunit),ev_ad=Type.evaluate(this.visProp.attractordistance),ev_sd=Type.evaluate(this.visProp.snatchdistance),ev_a=Type.evaluate(this.visProp.attractors),len=ev_a.length;if(0!==ev_ad){for(i=0;i<len;i++)if(el=this.board.select(ev_a[i]),Type.exists(el)&&el!==this){if(Type.isPoint(el)?projCoords=Geometry.projectPointToPoint(this,el,this.board):el.elementClass===Const.OBJECT_CLASS_LINE?(projection=Geometry.projectCoordsToSegment(this.coords.usrCoords,el.point1.coords.usrCoords,el.point2.coords.usrCoords),projCoords=!Type.evaluate(el.visProp.straightfirst)&&projection[1]<0?el.point1.coords:!Type.evaluate(el.visProp.straightlast)&&projection[1]>1?el.point2.coords:new Coords(Const.COORDS_BY_USER,projection[0],this.board)):el.elementClass===Const.OBJECT_CLASS_CIRCLE?projCoords=Geometry.projectPointToCircle(this,el,this.board):el.elementClass===Const.OBJECT_CLASS_CURVE?projCoords=Geometry.projectPointToCurve(this,el,this.board)[0]:el.type===Const.OBJECT_TYPE_TURTLE?projCoords=Geometry.projectPointToTurtle(this,el,this.board)[0]:el.type===Const.OBJECT_TYPE_POLYGON&&(projCoords=new Coords(Const.COORDS_BY_USER,Geometry.projectCoordsToPolygon(this.coords.usrCoords,el),this.board)),(d="screen"===ev_au?projCoords.distance(Const.COORDS_BY_SCREEN,this.coords):projCoords.distance(Const.COORDS_BY_USER,this.coords))<ev_ad){this.type===Const.OBJECT_TYPE_GLIDER&&(el===this.slideObject||this.slideObject&&this.onPolygon&&this.slideObject.parentPolygon===el)||this.makeGlider(el);break}d>=ev_sd&&(el===this.slideObject||this.slideObject&&this.onPolygon&&this.slideObject.parentPolygon===el)&&this.popSlideObject()}return this}},setPositionDirectly:function(method,coords){var i,c,dc,newCoords,oldCoords=this.coords;if(this.relativeCoords)return c=new Coords(method,coords,this.board),Type.evaluate(this.visProp.islabel)?(dc=Statistics.subtract(c.scrCoords,oldCoords.scrCoords),this.relativeCoords.scrCoords[1]+=dc[1],this.relativeCoords.scrCoords[2]+=dc[2]):(dc=Statistics.subtract(c.usrCoords,oldCoords.usrCoords),this.relativeCoords.usrCoords[1]+=dc[1],this.relativeCoords.usrCoords[2]+=dc[2]),this;for(this.coords.setCoordinates(method,coords),this.handleSnapToGrid(),this.handleSnapToPoints(),this.handleAttractors(),i=this.transformations.length-1;i>=0;i--)method===Const.COORDS_BY_SCREEN?newCoords=new Coords(method,coords,this.board).usrCoords:(2===coords.length&&(coords=[1].concat(coords)),newCoords=coords),this.initialCoords.setCoordinates(Const.COORDS_BY_USER,Mat.matVecMult(Mat.inverse(this.transformations[i].matrix),newCoords));return this.prepareUpdate().update(),this.board.isSuspendedUpdate&&this.type===Const.OBJECT_TYPE_GLIDER&&this.updateGlider(),this},setPositionByTransform:function(method,tv){var t;return tv=new Coords(method,tv,this.board),t=this.board.create("transform",tv.usrCoords.slice(1),{type:"translate"}),this.transformations.length>0&&this.transformations[this.transformations.length-1].isNumericMatrix?this.transformations[this.transformations.length-1].melt(t):this.addTransform(this,t),this.prepareUpdate().update(),this},setPosition:function(method,coords){return this.setPositionDirectly(method,coords)},setGliderPosition:function(x){return this.type===Const.OBJECT_TYPE_GLIDER&&(this.position=x,this.board.update()),this},makeGlider:function(slide){var min,i,dist,slideobj=this.board.select(slide),onPolygon=!1;if(slideobj.type===Const.OBJECT_TYPE_POLYGON){for(min=Number.MAX_VALUE,i=0;i<slideobj.borders.length;i++)(dist=JXG.Math.Geometry.distPointLine(this.coords.usrCoords,slideobj.borders[i].stdform))<min&&(min=dist,slide=slideobj.borders[i]);slideobj=this.board.select(slide),onPolygon=!0}if(!Type.exists(slideobj))throw new Error("JSXGraph: slide object undefined.");if(slideobj.type===Const.OBJECT_TYPE_TICKS)throw new Error("JSXGraph: gliders on ticks are not possible.");return this.slideObject=this.board.select(slide),this.slideObjects.push(this.slideObject),this.addParents(slide),this.type=Const.OBJECT_TYPE_GLIDER,this.elType="glider",this.visProp.snapwidth=-1,this.slideObject.addChild(this),this.isDraggable=!0,this.onPolygon=onPolygon,this.generatePolynomial=function(){return this.slideObject.generatePolynomial(this)},this.updateGlider(),this.needsUpdateFromParent=!0,this.updateGliderFromParent(),this},popSlideObject:function(){this.slideObjects.length>0&&(this.slideObjects.pop(),this.slideObject.removeChild(this),0===this.slideObjects.length?(this.type=this._org_type,this.type===Const.OBJECT_TYPE_POINT?this.elType="point":this.elementClass===Const.OBJECT_CLASS_TEXT?this.elType="text":this.type===Const.OBJECT_TYPE_IMAGE?this.elType="image":this.type===Const.OBJECT_TYPE_FOREIGNOBJECT&&(this.elType="foreignobject"),this.slideObject=null):this.slideObject=this.slideObjects[this.slideObjects.length-1])},free:function(){var ancestorId,ancestor;if(this.type!==Const.OBJECT_TYPE_GLIDER){if(this.transformations.length=0,delete this.updateConstraint,this.isConstrained=!1,this.isDraggable)return;this.isDraggable=!0,this.elementClass===Const.OBJECT_CLASS_POINT&&(this.type=Const.OBJECT_TYPE_POINT,this.elType="point"),this.XEval=function(){return this.coords.usrCoords[1]},this.YEval=function(){return this.coords.usrCoords[2]},this.ZEval=function(){return this.coords.usrCoords[0]},this.Xjc=null,this.Yjc=null}for(ancestorId in this.board.objects)this.board.objects.hasOwnProperty(ancestorId)&&(ancestor=this.board.objects[ancestorId]).descendants&&(delete ancestor.descendants[this.id],delete ancestor.childElements[this.id],this.hasLabel&&(delete ancestor.descendants[this.label.id],delete ancestor.childElements[this.label.id]));this.ancestors={},this.slideObject=null,this.slideObjects=[],this.elementClass===Const.OBJECT_CLASS_POINT?(this.type=Const.OBJECT_TYPE_POINT,this.elType="point"):this.elementClass===Const.OBJECT_CLASS_TEXT?(this.type=this._org_type,this.elType="text"):this.elementClass===Const.OBJECT_CLASS_OTHER&&(this.type=this._org_type,this.elType="image")},addConstraint:function(terms){var i,v,newfuncs=[],what=["X","Y"],makeConstFunction=function(z){return function(){return z}},makeSliderFunction=function(a){return function(){return a.Value()}};for(this.elementClass===Const.OBJECT_CLASS_POINT&&(this.type=Const.OBJECT_TYPE_CAS),this.isDraggable=!1,i=0;i<terms.length;i++)v=terms[i],Type.isString(v)?(newfuncs[i]=this.board.jc.snippet(v,!0,null,!0),2===terms.length&&(this[what[i]+"jc"]=terms[i])):Type.isFunction(v)?newfuncs[i]=v:Type.isNumber(v)?newfuncs[i]=makeConstFunction(v):Type.isObject(v)&&Type.isFunction(v.Value)&&(newfuncs[i]=makeSliderFunction(v)),newfuncs[i].origin=v;return 1===terms.length?this.updateConstraint=function(){var c=newfuncs[0]();return Type.isArray(c)?this.coords.setCoordinates(Const.COORDS_BY_USER,c):this.coords=c,this}:2===terms.length?(this.XEval=newfuncs[0],this.YEval=newfuncs[1],this.setParents([newfuncs[0].origin,newfuncs[1].origin]),this.updateConstraint=function(){return this.coords.setCoordinates(Const.COORDS_BY_USER,[this.XEval(),this.YEval()]),this}):(this.ZEval=newfuncs[0],this.XEval=newfuncs[1],this.YEval=newfuncs[2],this.setParents([newfuncs[0].origin,newfuncs[1].origin,newfuncs[2].origin]),this.updateConstraint=function(){return this.coords.setCoordinates(Const.COORDS_BY_USER,[this.ZEval(),this.XEval(),this.YEval()]),this}),this.isConstrained=!0,this.prepareUpdate().update(),this.board.isSuspendedUpdate||(this.updateVisibility().updateRenderer(),this.hasLabel&&this.label.fullUpdate()),this},addAnchor:function(coordinates,isLabel){this.relativeCoords=isLabel?new Coords(Const.COORDS_BY_SCREEN,coordinates.slice(0,2),this.board):new Coords(Const.COORDS_BY_USER,coordinates,this.board),this.element.addChild(this),isLabel&&this.addParents(this.element),this.XEval=function(){var sx,anchor,ev_o;return Type.evaluate(this.visProp.islabel)?(ev_o=Type.evaluate(this.visProp.offset),sx=parseFloat(ev_o[0]),anchor=this.element.getLabelAnchor(),new Coords(Const.COORDS_BY_SCREEN,[sx+this.relativeCoords.scrCoords[1]+anchor.scrCoords[1],0],this.board).usrCoords[1]):(anchor=this.element.getTextAnchor(),this.relativeCoords.usrCoords[1]+anchor.usrCoords[1])},this.YEval=function(){var sy,anchor,ev_o;return Type.evaluate(this.visProp.islabel)?(ev_o=Type.evaluate(this.visProp.offset),sy=-parseFloat(ev_o[1]),anchor=this.element.getLabelAnchor(),new Coords(Const.COORDS_BY_SCREEN,[0,sy+this.relativeCoords.scrCoords[2]+anchor.scrCoords[2]],this.board).usrCoords[2]):(anchor=this.element.getTextAnchor(),this.relativeCoords.usrCoords[2]+anchor.usrCoords[2])},this.ZEval=Type.createFunction(1,this.board,""),this.updateConstraint=function(){this.coords.setCoordinates(Const.COORDS_BY_USER,[this.ZEval(),this.XEval(),this.YEval()])},this.isConstrained=!0,this.updateConstraint()},updateTransform:function(fromParent){var i;if(0===this.transformations.length)return this;for(i=0;i<this.transformations.length;i++)this.transformations[i].update();return this},addTransform:function(el,transform){var i,list=Type.isArray(transform)?transform:[transform],len=list.length;for(0===this.transformations.length&&(this.baseElement=el),i=0;i<len;i++)this.transformations.push(list[i]);return this},startAnimation:function(direction,stepCount,delay){var that=this;return delay=delay||250,this.type!==Const.OBJECT_TYPE_GLIDER||Type.exists(this.intervalCode)||(this.intervalCode=window.setInterval((function(){that._anim(direction,stepCount)}),delay),Type.exists(this.intervalCount)||(this.intervalCount=0)),this},stopAnimation:function(){return Type.exists(this.intervalCode)&&(window.clearInterval(this.intervalCode),delete this.intervalCode),this},moveAlong:function(path,time,options){options=options||{};var i,neville,len,pos,part,interpath=[],p=[],steps=time/this.board.attr.animationdelay,makeFakeFunction=function(i,j){return function(){return path[i][j]}};if(Type.isArray(path)){for(len=path.length,i=0;i<len;i++)Type.isPoint(path[i])?p[i]=path[i]:p[i]={elementClass:Const.OBJECT_CLASS_POINT,X:makeFakeFunction(i,0),Y:makeFakeFunction(i,1)};if(0===(time=time||0))return this.setPosition(Const.COORDS_BY_USER,[p[p.length-1].X(),p[p.length-1].Y()]),this.board.update(this);if(!Type.exists(options.interpolate)||options.interpolate)for(neville=Numerics.Neville(p),i=0;i<steps;i++)interpath[i]=[],interpath[i][0]=neville[0]((steps-i)/steps*neville[3]()),interpath[i][1]=neville[1]((steps-i)/steps*neville[3]());else{for(len=path.length-1,i=0;i<steps;++i)part=i/steps*len-(pos=Math.floor(i/steps*len)),interpath[i]=[],interpath[i][0]=(1-part)*p[pos].X()+part*p[pos+1].X(),interpath[i][1]=(1-part)*p[pos].Y()+part*p[pos+1].Y();interpath.push([p[len].X(),p[len].Y()]),interpath.reverse()}this.animationPath=interpath}else Type.isFunction(path)&&(this.animationPath=path,this.animationStart=(new Date).getTime());return this.animationCallback=options.callback,this.board.addAnimation(this),this},moveTo:function(where,time,options){options=options||{},where=new Coords(Const.COORDS_BY_USER,where,this.board);var i,delay=this.board.attr.animationdelay,steps=Math.ceil(time/delay),coords=[],X=this.coords.usrCoords[1],Y=this.coords.usrCoords[2],dX=where.usrCoords[1]-X,dY=where.usrCoords[2]-Y,stepFun=function(i){return options.effect&&"<>"===options.effect?Math.pow(Math.sin(i/steps*Math.PI/2),2):i/steps};if(!Type.exists(time)||0===time||Math.abs(where.usrCoords[0]-this.coords.usrCoords[0])>Mat.eps)return this.setPosition(Const.COORDS_BY_USER,where.usrCoords),this.board.update(this);if(!Type.exists(options.callback)&&Math.abs(dX)<Mat.eps&&Math.abs(dY)<Mat.eps)return this;for(i=steps;i>=0;i--)coords[steps-i]=[where.usrCoords[0],X+dX*stepFun(i),Y+dY*stepFun(i)];return this.animationPath=coords,this.animationCallback=options.callback,this.board.addAnimation(this),this},visit:function(where,time,options){where=new Coords(Const.COORDS_BY_USER,where,this.board);var i,j,steps,delay=this.board.attr.animationdelay,coords=[],X=this.coords.usrCoords[1],Y=this.coords.usrCoords[2],dX=where.usrCoords[1]-X,dY=where.usrCoords[2]-Y,stepFun=function(i){var x=i<steps/2?2*i/steps:2*(steps-i)/steps;return options.effect&&"<>"===options.effect?Math.pow(Math.sin(x*Math.PI/2),2):x};for(Type.isNumber(options)?options={repeat:options}:(options=options||{},Type.exists(options.repeat)||(options.repeat=1)),steps=Math.ceil(time/(delay*options.repeat)),j=0;j<options.repeat;j++)for(i=steps;i>=0;i--)coords[j*(steps+1)+steps-i]=[where.usrCoords[0],X+dX*stepFun(i),Y+dY*stepFun(i)];return this.animationPath=coords,this.animationCallback=options.callback,this.board.addAnimation(this),this},_anim:function(direction,stepCount){var dX,dY,alpha,startPoint,newX,radius,sp1c,sp2c,res;return this.intervalCount+=1,this.intervalCount>stepCount&&(this.intervalCount=0),this.slideObject.elementClass===Const.OBJECT_CLASS_LINE?(sp1c=this.slideObject.point1.coords.scrCoords,sp2c=this.slideObject.point2.coords.scrCoords,dX=Math.round((sp2c[1]-sp1c[1])*this.intervalCount/stepCount),dY=Math.round((sp2c[2]-sp1c[2])*this.intervalCount/stepCount),direction>0?startPoint=this.slideObject.point1:(startPoint=this.slideObject.point2,dX*=-1,dY*=-1),this.coords.setCoordinates(Const.COORDS_BY_SCREEN,[startPoint.coords.scrCoords[1]+dX,startPoint.coords.scrCoords[2]+dY])):this.slideObject.elementClass===Const.OBJECT_CLASS_CURVE?(newX=direction>0?Math.round(this.intervalCount/stepCount*this.board.canvasWidth):Math.round((stepCount-this.intervalCount)/stepCount*this.board.canvasWidth),this.coords.setCoordinates(Const.COORDS_BY_SCREEN,[newX,0]),res=Geometry.projectPointToCurve(this,this.slideObject,this.board),this.coords=res[0],this.position=res[1]):this.slideObject.elementClass===Const.OBJECT_CLASS_CIRCLE&&(alpha=2*Math.PI,alpha*=direction<0?this.intervalCount/stepCount:(stepCount-this.intervalCount)/stepCount,radius=this.slideObject.Radius(),this.coords.setCoordinates(Const.COORDS_BY_USER,[this.slideObject.center.coords.usrCoords[1]+radius*Math.cos(alpha),this.slideObject.center.coords.usrCoords[2]+radius*Math.sin(alpha)])),this.board.update(this),this},getTextAnchor:function(){return this.coords},getLabelAnchor:function(){return this.coords},getParents:function(){var p=[this.Z(),this.X(),this.Y()];return 0!==this.parents.length&&(p=this.parents),this.type===Const.OBJECT_TYPE_GLIDER&&(p=[this.X(),this.Y(),this.slideObject.id]),p}}),JXG.CoordsElement.create=function(Callback,board,coords,attr,arg1,arg2){var el,i,isConstrained=!1;for(i=0;i<coords.length;i++)(Type.isFunction(coords[i])||Type.isString(coords[i]))&&(isConstrained=!0);if(isConstrained)(el=new Callback(board,[0,0],attr,arg1,arg2)).addConstraint(coords);else if(Type.isNumber(coords[0])&&Type.isNumber(coords[1]))el=new Callback(board,coords,attr,arg1,arg2),Type.exists(attr.slideobject)?el.makeGlider(attr.slideobject):el.baseElement=el,el.isDraggable=!0;else{if(!Type.isObject(coords[0])||!Type.isTransformationOrArray(coords[1]))return!1;(el=new Callback(board,[0,0],attr,arg1,arg2)).addTransform(coords[0],coords[1]),el.isDraggable=!1}return el.handleSnapToGrid(),el.handleSnapToPoints(),el.handleAttractors(),el.addParents(coords),el},JXG.CoordsElement})),define("base/text",["jxg","base/constants","base/element","parser/geonext","utils/env","utils/type","math/math","base/coordselement"],(function(JXG,Const,GeometryElement,GeonextParser,Env,Type,Mat,CoordsElement){var priv_HTMLSliderInputEventHandler=function(){this._val=parseFloat(this.rendNodeRange.value),this.rendNodeOut.value=this.rendNodeRange.value,this.board.update()};return JXG.Text=function(board,coords,attributes,content){this.constructor(board,attributes,Const.OBJECT_TYPE_TEXT,Const.OBJECT_CLASS_TEXT),this.element=this.board.select(attributes.anchor),this.coordsConstructor(coords,Type.evaluate(this.visProp.islabel)),this.content="",this.plaintext="",this.plaintextOld=null,this.orgText="",this.needsSizeUpdate=!1,this.hiddenByParent=!1,this.size=[1,1],this.id=this.board.setId(this,"T"),this.board.renderer.drawText(this),this.board.finalizeAdding(this),this.setText(content),Type.isString(this.content)&&this.notifyParents(this.content),this.elType="text",this.methodMap=Type.deepCopy(this.methodMap,{setText:"setTextJessieCode",move:"setCoords"})},JXG.Text.prototype=new GeometryElement,Type.copyPrototypeMethods(JXG.Text,CoordsElement,"coordsConstructor"),JXG.extend(JXG.Text.prototype,{hasPoint:function(x,y){var lft,rt,top,bot,ax,ay,type,r;return Type.isObject(Type.evaluate(this.visProp.precision))?(type=this.board._inputDevice,r=Type.evaluate(this.visProp.precision[type])):r=this.board.options.precision.hasPoint,this.transformations.length>0&&(x=(lft=Mat.matVecMult(Mat.inverse(this.board.renderer.joinTransforms(this,this.transformations)),[1,x,y]))[1],y=lft[2]),rt=(lft="right"===(ax=this.getAnchorX())?this.coords.scrCoords[1]-this.size[0]:"middle"===ax?this.coords.scrCoords[1]-.5*this.size[0]:this.coords.scrCoords[1])+this.size[0],top=(bot="top"===(ay=this.getAnchorY())?this.coords.scrCoords[2]+this.size[1]:"middle"===ay?this.coords.scrCoords[2]+.5*this.size[1]:this.coords.scrCoords[2])-this.size[1],"all"===Type.evaluate(this.visProp.dragarea)?x>=lft-r&&x<rt+r&&y>=top-r&&y<=bot+r:y>=top-r&&y<=bot+r&&(x>=lft-r&&x<=lft+2*r||x>=rt-2*r&&x<=rt+r)},_createFctUpdateText:function(text){var updateText,resolvedText,ev_p=Type.evaluate(this.visProp.parse),ev_um=Type.evaluate(this.visProp.usemathjax),ev_uk=Type.evaluate(this.visProp.usekatex);this.orgText=text,Type.isFunction(text)?this.updateText=function(){resolvedText=text().toString(),this.plaintext=!ev_p||ev_um||ev_uk?resolvedText:this.replaceSub(this.replaceSup(this.convertGeonextAndSketchometry2CSS(resolvedText)))}:Type.isString(text)&&!ev_p?this.updateText=function(){this.plaintext=text}:(Type.isNumber(text)?this.content=Type.toFixed(text,Type.evaluate(this.visProp.digits)):Type.evaluate(this.visProp.useasciimathml)?this.content="'`"+text+"`'":this.content=ev_um||ev_uk?"'"+text+"'":this.generateTerm(text,!0,!0),updateText=this.board.jc.snippet(this.content,!0,"",!1),this.updateText=function(){this.plaintext=updateText()})},_setText:function(text){return this._createFctUpdateText(text),this.updateText(),this.fullUpdate(),this.board.infobox&&this.id===this.board.infobox.id||this.updateSize(),this},setTextJessieCode:function(text){var s;return this.visProp.castext=text,s=Type.isFunction(text)?function(){return Type.sanitizeHTML(text())}:Type.isNumber(text)?text:Type.sanitizeHTML(text),this._setText(s)},setText:function(text){return this._setText(text)},updateSize:function(){var tmp,that,node,ev_d=Type.evaluate(this.visProp.display);return Env.isBrowser&&"no"!==this.board.renderer.type?(node=this.rendNode,"html"===ev_d||"vml"===this.board.renderer.type?Type.exists(node.offsetWidth)?(that=this,window.setTimeout((function(){that.size=[node.offsetWidth,node.offsetHeight],that.needsUpdate=!0,that.updateRenderer()}),0)):this.size=this.crudeSizeEstimate():"internal"===ev_d&&("svg"===this.board.renderer.type?(that=this,window.setTimeout((function(){try{tmp=node.getBBox(),that.size=[tmp.width,tmp.height],that.needsUpdate=!0,that.updateRenderer()}catch(e){}}),0)):"canvas"===this.board.renderer.type&&(this.size=this.crudeSizeEstimate())),this):this},crudeSizeEstimate:function(){var ev_fs=parseFloat(Type.evaluate(this.visProp.fontsize));return[ev_fs*this.plaintext.length*.45,.9*ev_fs]},utf8_decode:function(string){return string.replace(/&#x(\w+);/g,(function(m,p1){return String.fromCharCode(parseInt(p1,16))}))},replaceSub:function(te){if(!te.indexOf)return te;for(var j,i=te.indexOf("_{");i>=0;)(j=(te=te.substr(0,i)+te.substr(i).replace(/_\{/,"<sub>")).substr(i).indexOf("}"))>=0&&(te=te.substr(0,j)+te.substr(j).replace(/\}/,"</sub>")),i=te.indexOf("_{");for(i=te.indexOf("_");i>=0;)i=(te=te.substr(0,i)+te.substr(i).replace(/_(.?)/,"<sub>$1</sub>")).indexOf("_");return te},replaceSup:function(te){if(!te.indexOf)return te;for(var j,i=te.indexOf("^{");i>=0;)(j=(te=te.substr(0,i)+te.substr(i).replace(/\^\{/,"<sup>")).substr(i).indexOf("}"))>=0&&(te=te.substr(0,j)+te.substr(j).replace(/\}/,"</sup>")),i=te.indexOf("^{");for(i=te.indexOf("^");i>=0;)i=(te=te.substr(0,i)+te.substr(i).replace(/\^(.?)/,"<sup>$1</sup>")).indexOf("^");return te},getSize:function(){return this.size},setCoords:function(x,y){var coordsAnchor,dx,dy;return Type.isArray(x)&&x.length>1&&(y=x[1],x=x[0]),Type.evaluate(this.visProp.islabel)&&Type.exists(this.element)?(dx=(x-(coordsAnchor=this.element.getLabelAnchor()).usrCoords[1])*this.board.unitX,dy=-(y-coordsAnchor.usrCoords[2])*this.board.unitY,this.relativeCoords.setCoordinates(Const.COORDS_BY_SCREEN,[dx,dy])):this.coords.setCoordinates(Const.COORDS_BY_USER,[x,y]),this.fullUpdate(),this},update:function(fromParent){return this.needsUpdate?(this.updateCoords(fromParent),this.updateText(),"internal"===Type.evaluate(this.visProp.display)&&Type.isString(this.plaintext)&&(this.plaintext=this.utf8_decode(this.plaintext)),this.checkForSizeUpdate(),this.needsSizeUpdate&&this.updateSize(),this):this},checkForSizeUpdate:function(){this.board.infobox&&this.id===this.board.infobox.id?this.needsSizeUpdate=!1:(this.needsSizeUpdate=this.plaintextOld!==this.plaintext,this.needsSizeUpdate&&(this.plaintextOld=this.plaintext))},updateRenderer:function(){return Type.evaluate(this.visProp.autoposition)&&this.setAutoPosition().updateConstraint(),this.updateRendererGeneric("updateText")},expandShortMath:function(expr){return expr.replace(/([)0-9.])\s*([(a-zA-Z_])/g,"$1*$2")},generateTerm:function(contentStr,expand,avoidGeonext2JS){var res,term,i,j,plaintext='""';if(i=(contentStr=(contentStr=(contentStr=(contentStr=(contentStr=(contentStr=(contentStr=(contentStr=(contentStr=(contentStr=(contentStr=contentStr||"").replace(/\r/g,"")).replace(/\n/g,"")).replace(/"/g,"'")).replace(/'/g,"\\'")).replace(/&arc;/g,"∠")).replace(/<arc\s*\/>/g,"∠")).replace(/<arc\s*\/>/g,"∠")).replace(/<sqrt\s*\/>/g,"√")).replace(/<value>/g,"<value>")).replace(/<\/value>/g,"</value>")).indexOf("<value>"),j=contentStr.indexOf("</value>"),i>=0)for(;i>=0;)plaintext+=' + "'+this.replaceSub(this.replaceSup(contentStr.slice(0,i)))+'"',term=(term=contentStr.slice(i+7,j)).replace(/\s+/g,""),!0===expand&&(term=this.expandShortMath(term)),(res=(res=(res=avoidGeonext2JS?term:GeonextParser.geonext2JS(term,this.board)).replace(/\\"/g,"'")).replace(/\\'/g,"'")).indexOf("toFixed")<0&&Type.isNumber(Type.bind(this.board.jc.snippet(res,!0,"",!1),this)())?plaintext+="+("+res+").toFixed("+Type.evaluate(this.visProp.digits)+")":plaintext+="+("+res+")",i=(contentStr=contentStr.slice(j+8)).indexOf("<value>"),j=contentStr.indexOf("</value>");return plaintext+=' + "'+this.replaceSub(this.replaceSup(contentStr))+'"',plaintext=(plaintext=(plaintext=this.convertGeonextAndSketchometry2CSS(plaintext)).replace(/&/g,"&")).replace(/"/g,"'")},convertGeonext2CSS:function(s){return Type.isString(s)&&(s=(s=(s=(s=s.replace(/(<|<)overline(>|>)/g,"<span style=text-decoration:overline;>")).replace(/(<|<)\/overline(>|>)/g,"</span>")).replace(/(<|<)arrow(>|>)/g,"<span style=text-decoration:overline;>")).replace(/(<|<)\/arrow(>|>)/g,"</span>")),s},convertSketchometry2CSS:function(s){return Type.isString(s)&&(s=(s=(s=(s=s.replace(/(<|<)sketchofont(>|>)/g,"<span style=font-family:sketchometry-light;font-weight:500;>")).replace(/(<|<)\/sketchofont(>|>)/g,"</span>")).replace(/(<|<)sketchometry-light(>|>)/g,"<span style=font-family:sketchometry-light;font-weight:500;>")).replace(/(<|<)\/sketchometry-light(>|>)/g,"</span>")),s},convertGeonextAndSketchometry2CSS:function(s){return s=this.convertGeonext2CSS(s),s=this.convertSketchometry2CSS(s)},notifyParents:function(content){var search,res=null;content=(content=content.replace(/<value>/g,"<value>")).replace(/<\/value>/g,"</value>");do{null!==(res=(search=/<value>([\w\s*/^\-+()[\],<>=!]+)<\/value>/).exec(content))&&(GeonextParser.findDependencies(this,res[1],this.board),content=(content=content.substr(res.index)).replace(search,""))}while(null!==res);return this},getParents:function(){var p;return p=void 0!==this.relativeCoords?[this.relativeCoords.usrCoords[1],this.relativeCoords.usrCoords[2],this.orgText]:[this.Z(),this.X(),this.Y(),this.orgText],0!==this.parents.length&&(p=this.parents),p},bounds:function(){var c=this.coords.usrCoords;return Type.evaluate(this.visProp.islabel)||0===this.board.unitY||0===this.board.unitX?[0,0,0,0]:[c[1],c[2]+this.size[1]/this.board.unitY,c[1]+this.size[0]/this.board.unitX,c[2]]},getAnchorX:function(){var a=Type.evaluate(this.visProp.anchorx);if("auto"===a)switch(this.visProp.position){case"top":case"bot":return"middle";case"rt":case"lrt":case"urt":return"left";default:return"right"}return a},getAnchorY:function(){var a=Type.evaluate(this.visProp.anchory);if("auto"===a)switch(this.visProp.position){case"top":case"ulft":case"urt":return"bottom";case"bot":case"lrt":case"llft":return"top";default:return"middle"}return a},getNumberofConflicts:function(x,y,w,h){var i,obj,le,savePointPrecision,count=0;for(savePointPrecision=this.board.options.precision.hasPoint,this.board.options.precision.hasPoint=.25*(w+h),i=0,le=this.board.objectsList.length;i<le;i++)(obj=this.board.objectsList[i]).visPropCalc.visible&&"axis"!==obj.elType&&"ticks"!==obj.elType&&obj!==this.board.infobox&&obj!==this&&obj.hasPoint(x,y)&&count++;return this.board.options.precision.hasPoint=savePointPrecision,count},setAutoPosition:function(){var x,y,cx,cy,anchorCoords,start_angle,angle,delta_r,conflicts,offset,r,j,dx,dy,co,si,w=this.size[0],h=this.size[1],optimum={conflicts:1/0,angle:0,r:0},step=2*Math.PI/12;if(this===this.board.infobox||!this.visPropCalc.visible||!Type.evaluate(this.visProp.islabel)||!this.element)return this;if(offset=Type.evaluate(this.visProp.offset),cx=(anchorCoords=this.element.getLabelAnchor()).scrCoords[1],cy=anchorCoords.scrCoords[2],dx=offset[0],dy=offset[1],0===(conflicts=this.getNumberofConflicts(cx+dx,cy-dy,w,h)))return this;for(28,delta_r=.2*(r=12),start_angle=Math.atan2(dy,dx),optimum.conflicts=conflicts,optimum.angle=start_angle,optimum.r=r;optimum.conflicts>0&&r<28;){for(j=1,angle=start_angle+step;j<12&&optimum.conflicts>0&&(x=cx+r*(co=Math.cos(angle)),y=cy-r*(si=Math.sin(angle)),(conflicts=this.getNumberofConflicts(x,y,w,h))<optimum.conflicts&&(optimum.conflicts=conflicts,optimum.angle=angle,optimum.r=r),0!==optimum.conflicts);j++)angle+=step;r+=delta_r}return r=optimum.r,co=Math.cos(optimum.angle),si=Math.sin(optimum.angle),this.visProp.offset=[r*co,r*si],this.visProp.anchorx=co<-.2?"right":co>.2?"left":"middle",this}}),JXG.createText=function(board,parents,attributes){var t,attr=Type.copyAttributes(attributes,board.options,"text"),coords=parents.slice(0,-1),content=parents[parents.length-1];if(attr.anchor=attr.parent||attr.anchor,!(t=CoordsElement.create(JXG.Text,board,coords,attr,content)))throw new Error("JSXGraph: Can't create text with parent types '"+_typeof(parents[0])+"' and '"+_typeof(parents[1])+"'.\nPossible parent types: [x,y], [z,x,y], [element,transformation]");return 0!==attr.rotate&&"internal"===attr.display&&t.addRotation(attr.rotate),t},JXG.registerElement("text",JXG.createText),JXG.createHTMLSlider=function(board,parents,attributes){var t,par,attr=Type.copyAttributes(attributes,board.options,"htmlslider");if(2!==parents.length||2!==parents[0].length||3!==parents[1].length)throw new Error("JSXGraph: Can't create htmlslider with parent types '"+_typeof(parents[0])+"' and '"+_typeof(parents[1])+"'.\nPossible parents are: [[x,y], [min, start, max]]");attr.anchor=attr.parent||attr.anchor,attr.fixed=attr.fixed||!0,par=[parents[0][0],parents[0][1],'<form style="display:inline"><input type="range" /><span></span><input type="text" /></form>'],(t=JXG.createText(board,par,attr)).type=Type.OBJECT_TYPE_HTMLSLIDER,t.rendNodeForm=t.rendNode.childNodes[0],t.rendNodeRange=t.rendNodeForm.childNodes[0],t.rendNodeRange.min=parents[1][0],t.rendNodeRange.max=parents[1][2],t.rendNodeRange.step=attr.step,t.rendNodeRange.value=parents[1][1],t.rendNodeLabel=t.rendNodeForm.childNodes[1],t.rendNodeLabel.id=t.rendNode.id+"_label",attr.withlabel&&(t.rendNodeLabel.innerHTML=t.name+"="),t.rendNodeOut=t.rendNodeForm.childNodes[2],t.rendNodeOut.value=parents[1][1];try{t.rendNodeForm.id=t.rendNode.id+"_form",t.rendNodeRange.id=t.rendNode.id+"_range",t.rendNodeOut.id=t.rendNode.id+"_out"}catch(e){JXG.debug(e)}return t.rendNodeRange.style.width=attr.widthrange+"px",t.rendNodeRange.style.verticalAlign="middle",t.rendNodeOut.style.width=attr.widthout+"px",t._val=parents[1][1],JXG.supportsVML()?Env.addEvent(t.rendNodeForm,"change",priv_HTMLSliderInputEventHandler,t):Env.addEvent(t.rendNodeForm,"input",priv_HTMLSliderInputEventHandler,t),t.Value=function(){return this._val},t},JXG.registerElement("htmlslider",JXG.createHTMLSlider),{Text:JXG.Text,createText:JXG.createText,createHTMLSlider:JXG.createHTMLSlider}})),define("utils/uuid",["jxg"],(function(JXG){var uuidChars="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".split("");return JXG.Util=JXG.Util||{},JXG.Util.genUUID=function(prefix){var r,i,uuid=[],rnd=0;for(""!==(prefix=prefix||"")&&"-"!==prefix.substr(prefix.length-1)&&(prefix+="-"),i=0;i<36;i++)8===i||13===i||18===i||23===i?uuid[i]="-":14===i?uuid[i]="4":(rnd<=2&&(rnd=33554432+16777216*Math.random()|0),r=15&rnd,rnd>>=4,uuid[i]=uuidChars[19===i?3&r|8:r]);return prefix+uuid.join("")},JXG.Util})),define("parser/jessiecode",["jxg","base/constants","base/text","math/math","math/ia","math/geometry","math/statistics","utils/type","utils/uuid","utils/env"],(function(JXG,Const,Text,Mat,Interval,Geometry,Statistics,Type,UUID,Env){Object.create||(Object.create=function(o,properties){if("object"!==_typeof(o)&&"function"!=typeof o)throw new TypeError("Object prototype may only be an Object: "+o);if(null===o)throw new Error("This browser's implementation of Object.create is a shim and doesn't support 'null' as the first argument.");if(void 0!==properties)throw new Error("This browser's implementation of Object.create is a shim and doesn't support a second argument.");function F(){}return F.prototype=o,new F});var priv={modules:{math:Mat,"math/geometry":Geometry,"math/statistics":Statistics,"math/numerics":Mat.Numerics}},r,_ccache;JXG.JessieCode=function(code,geonext){this.scope={id:0,hasChild:!0,args:[],locals:{},context:null,previous:null},this.scopes=[],this.scopes.push(this.scope),this.dpstack=[[]],this.pscope=0,this.propstack=[{}],this.propscope=0,this.lhs=[],this.isLHS=!1,this.warnLog="jcwarn",this.$log=[],this.builtIn=this.defineBuiltIn(),this.operands=this.getPossibleOperands(),this.board=null,this.lineToElement={},this.parCurLine=1,this.parCurColumn=0,this.line=1,this.col=1,JXG.CA&&(this.CA=new JXG.CA(this.node,this.createNode,this)),this.code="","string"==typeof code&&this.parse(code,geonext)},JXG.extend(JXG.JessieCode.prototype,{node:function(type,value,children){return{type:type,value:value,children:children}},createNode:function(type,value,children){var i,n=this.node(type,value,[]);for(i=2;i<arguments.length;i++)n.children.push(arguments[i]);return"node_const"==n.type&&Type.isNumber(n.value)&&(n.isMath=!0),n.line=this.parCurLine,n.col=this.parCurColumn,n},pushScope:function(args){var scope={args:args,locals:{},context:null,previous:this.scope};return this.scope.hasChild=!0,this.scope=scope,scope.id=this.scopes.push(scope)-1,scope},popScope:function(){var s=this.scope.previous;return this.scope=null!==s?s:this.scope,this.scope},getElementById:function(id){return this.board.objects[id]},log:function(){this.$log.push(arguments),"object"===("undefined"==typeof console?"undefined":_typeof(console))&&console.log&&console.log.apply(console,arguments)},creator:(_ccache={},(r=function(vname){var f,that;return"function"==typeof _ccache[this.board.id+vname]?f=_ccache[this.board.id+vname]:(that=this,(f=function(parameters,attributes){var attr;return void 0===(attr=Type.exists(attributes)?attributes:{}).name&&void 0===attr.id&&(attr.name=0!==that.lhs[that.scope.id]?that.lhs[that.scope.id]:""),that.board.create(vname,parameters,attr)}).creator=!0,_ccache[this.board.id+vname]=f),f}).clearCache=function(){_ccache={}},r),letvar:function(vname,value){this.builtIn[vname]&&this._warn('"'+vname+'" is a predefined value.'),this.scope.locals[vname]=value},isLocalVariable:function(vname){for(var s=this.scope;null!==s;){if(Type.exists(s.locals[vname]))return s;s=s.previous}return null},isParameter:function(vname){for(var s=this.scope;null!==s;){if(Type.indexOf(s.args,vname)>-1)return s;s=s.previous}return null},isCreator:function(vname){return!!JXG.elements[vname]},isMathMethod:function(vname){return"E"!==vname&&!!Math[vname]},isBuiltIn:function(vname){return!!this.builtIn[vname]},getvar:function(vname,local,isFunctionName){var s;if(local=Type.def(local,!1),null!==(s=this.isLocalVariable(vname)))return s.locals[vname];if("$board"===vname||"EULER"===vname||"PI"===vname)return this.builtIn[vname];if(isFunctionName){if(this.isBuiltIn(vname))return this.builtIn[vname];if(this.isMathMethod(vname))return Math[vname];if(this.isCreator(vname))return this.creator(vname)}return local||(s=this.board.select(vname))===vname?void 0:s},resolve:function(vname){for(var s=this.scope;null!==s;){if(Type.exists(s.locals[vname]))return s.locals[vname];s=s.previous}},getvarJS:function(vname,local,withProps){var re,r="";return local=Type.def(local,!1),withProps=Type.def(withProps,!1),null!==this.isParameter(vname)?vname:null===this.isLocalVariable(vname)||withProps?this.isCreator(vname)?"(function () { var a = Array.prototype.slice.call(arguments, 0), props = "+(withProps?"a.pop()":"{}")+"; return $jc$.board.create.apply($jc$.board, ['"+vname+"'].concat([a, props])); })":(withProps&&this._error("Syntax error (attribute values are allowed with element creators only)"),this.isBuiltIn(vname)?(r=this.builtIn[vname].src||this.builtIn[vname],Type.isNumber(r)||r.match(/board\.select/)?r:(vname=r.split(".").pop(),Type.exists(this.board.mathLib)&&null!==(re=new RegExp("^Math."+vname)).exec(r)?r.replace(re,"$jc$.board.mathLib."+vname):Type.exists(this.board.mathLibJXG)&&null!==(re=new RegExp("^JXG.Math.")).exec(r)?r.replace(re,"$jc$.board.mathLibJXG."):r)):this.isMathMethod(vname)?"$jc$.board.mathLib."+vname:local?"":(Type.isId(this.board,vname)?(r="$jc$.board.objects['"+vname+"']","slider"===this.board.objects[vname].elType&&(r+=".Value()")):Type.isName(this.board,vname)?(r="$jc$.board.elementsByName['"+vname+"']","slider"===this.board.elementsByName[vname].elType&&(r+=".Value()")):Type.isGroup(this.board,vname)&&(r="$jc$.board.groups['"+vname+"']"),r)):"$jc$.resolve('"+vname+"')"},makeMap:function(f){return f.isMap=!0,f},functionCodeJS:function(node){var p=node.children[0].join(", "),bo="",bc="";return"op_map"===node.value&&(bo="{ return ",bc=" }"),"function ("+p+") {\nvar $oldscope$ = $jc$.scope;\n$jc$.scope = $jc$.scopes["+this.scope.id+"];\nvar r = (function () "+bo+this.compile(node.children[1],!0)+bc+")();\n$jc$.scope = $oldscope$;\nreturn r;\n}"},defineFunction:function defineFunction(node){var fun,i,that=this,list=node.children[0],scope=this.pushScope(list),_that;if(this.board.options.jc.compile){for(this.isLHS=!1,i=0;i<list.length;i++)scope.locals[list[i]]=list[i];this.replaceNames(node.children[1]),fun=function($jc$){var fun,str="var f = "+$jc$.functionCodeJS(node)+"; f;";try{for(fun=eval(str),scope.argtypes=[],i=0;i<list.length;i++)scope.argtypes.push(that.resolveType(list[i],node));return fun}catch(e){return $jc$._warn("error compiling function\n\n"+str+"\n\n"+e.toString()),function(){}}}(this),this.popScope()}else fun=function(_pstack,that,id){return function(){var r,oldscope;for(oldscope=that.scope,that.scope=that.scopes[id],r=0;r<_pstack.length;r++)that.scope.locals[_pstack[r]]=arguments[r];return r=that.execute(node.children[1]),that.scope=oldscope,r}}(list,this,scope.id);return fun.node=node,fun.scope=scope,fun.toJS=fun.toString,fun.toString=(_that=this,function(){return _that.compile(_that.replaceIDs(Type.deepCopy(node)))}),fun.deps={},this.collectDependencies(node.children[1],fun.deps),fun},mergeAttributes:function(o){var i,attr={};for(i=0;i<arguments.length;i++)attr=Type.deepCopy(attr,arguments[i],!0);return attr},setProp:function(o,what,value){var x,y,par={};o.elementClass!==Const.OBJECT_CLASS_POINT||"X"!==what&&"Y"!==what?o.elementClass!==Const.OBJECT_CLASS_TEXT||"X"!==what&&"Y"!==what?o.type&&o.elementClass&&o.visProp?Type.exists(o[o.methodMap[what]])&&"function"!=typeof o[o.methodMap[what]]?o[o.methodMap[what]]=value:(par[what]=value,o.setAttribute(par)):o[what]=value:("number"==typeof value?o[what]=function(){return value}:"function"==typeof value?(o.isDraggable=!1,o[what]=value):"string"==typeof value&&(o.isDraggable=!1,o[what]=Type.createFunction(value,this.board,null,!0),o[what+"jc"]=value),o[what].origin=value,this.board.update()):(what=what.toLowerCase(),o.isDraggable&&"number"==typeof value?(x="x"===what?value:o.X(),y="y"===what?value:o.Y(),o.setPosition(Const.COORDS_BY_USER,[x,y])):!o.isDraggable||"function"!=typeof value&&"string"!=typeof value?o.isDraggable||(x="x"===what?value:o.XEval.origin,y="y"===what?value:o.YEval.origin,o.addConstraint([x,y])):(x="x"===what?value:o.coords.usrCoords[1],y="y"===what?value:o.coords.usrCoords[2],o.addConstraint([x,y])),this.board.update())},_genericParse:function(code,cmd,geonext,dontstore){var i,setTextBackup,ast,result,ccode=code.replace(/\r\n/g,"\n").split("\n"),cleaned=[];dontstore||(this.code+=code+"\n"),Text&&(setTextBackup=Text.Text.prototype.setText,Text.Text.prototype.setText=Text.Text.prototype.setTextJessieCode);try{for(Type.exists(geonext)||(geonext=!1),i=0;i<ccode.length;i++)geonext&&(ccode[i]=JXG.GeonextParser.geonext2JS(ccode[i],this.board)),cleaned.push(ccode[i]);switch(code=cleaned.join("\n"),ast=parser.parse(code),this.CA&&(ast=this.CA.expandDerivatives(ast,null,ast),ast=this.CA.removeTrivialNodes(ast)),cmd){case"parse":result=this.execute(ast);break;case"manipulate":result=this.compile(ast);break;case"getAst":result=ast;break;default:result=!1}}catch(e){throw e}finally{Text&&(Text.Text.prototype.setText=setTextBackup)}return result},parse:function(code,geonext,dontstore){return this._genericParse(code,"parse",geonext,dontstore)},manipulate:function(code,geonext,dontstore){return this._genericParse(code,"manipulate",geonext,dontstore)},getAST:function(code,geonext,dontstore){return this._genericParse(code,"getAst",geonext,dontstore)},snippet:function(code,funwrap,varname,geonext){var c;return funwrap=Type.def(funwrap,!0),varname=Type.def(varname,""),geonext=Type.def(geonext,!1),c=(funwrap?" function ("+varname+") { return ":"")+code+(funwrap?"; }":"")+";",this.parse(c,geonext,!0)},replaceIDs:function(node){var i,v;if(node.replaced&&(v=this.board.objects[node.children[1][0].value],Type.exists(v)&&""!==v.name&&(node.type="node_var",node.value=v.name,node.children.length=0,delete node.replaced)),Type.isArray(node))for(i=0;i<node.length;i++)node[i]=this.replaceIDs(node[i]);if(node.children)for(i=node.children.length;i>0;i--)Type.exists(node.children[i-1])&&(node.children[i-1]=this.replaceIDs(node.children[i-1]));return node},replaceNames:function(node){var i,v;if(v=node.value,"node_op"===node.type&&"op_lhs"===v&&1===node.children.length?this.isLHS=!0:"node_var"===node.type&&(this.isLHS?this.letvar(v,!0):!Type.exists(this.getvar(v,!0))&&Type.exists(this.board.elementsByName[v])&&(node=this.createReplacementNode(node))),Type.isArray(node))for(i=0;i<node.length;i++)node[i]=this.replaceNames(node[i]);if(node.children)for(i=node.children.length;i>0;i--)Type.exists(node.children[i-1])&&(node.children[i-1]=this.replaceNames(node.children[i-1]));return"node_op"===node.type&&"op_lhs"===node.value&&1===node.children.length&&(this.isLHS=!1),node},createReplacementNode:function(node){var v=node.value,el=this.board.elementsByName[v];return(node=this.createNode("node_op","op_execfun",this.createNode("node_var","$"),[this.createNode("node_str",el.id)])).replaced=!0,node},collectDependencies:function(node,result){var i,v,e,le;if(Type.isArray(node))for(le=node.length,i=0;i<le;i++)this.collectDependencies(node[i],result);else if(v=node.value,"node_var"===node.type&&(e=this.getvar(v))&&e.visProp&&e.type&&e.elementClass&&e.id&&(result[e.id]=e),"node_op"===node.type&&"op_execfun"===node.value&&node.children.length>1&&"$"===node.children[0].value&&node.children[1].length>0&&(result[e=node.children[1][0].value]=this.board.objects[e]),node.children)for(i=node.children.length;i>0;i--)Type.exists(node.children[i-1])&&this.collectDependencies(node.children[i-1],result)},resolveProperty:function(e,v,compile){return compile=Type.def(compile,!1),e&&e.methodMap&&(Type.exists(e.subs)&&Type.exists(e.subs[v])?e=e.subs:Type.exists(e.methodMap[v])?v=e.methodMap[v]:(e=e.visProp,v=v.toLowerCase())),Type.isFunction(e)&&this._error("Accessing function properties is not allowed."),Type.exists(e)||this._error(e+" is not an object"),Type.exists(e[v])||this._error("unknown property "+v),compile&&"function"==typeof e[v]?function(){return e[v].apply(e,arguments)}:e[v]},resolveType:function(vname,node){var i,t;if(Type.isArray(node))for(i=0;i<node.length;i++)if("any"!==(t=this.resolveType(vname,node[i])))return t;if("node_op"===node.type&&"op_execfun"===node.value&&"node_var"===node.children[0].type&&node.children[0].value===vname)return"function";if("node_op"===node.type){for(i=0;i<node.children.length;i++)if("node_var"===node.children[0].type&&node.children[0].value===vname&&("op_add"===node.value||"op_sub"===node.value||"op_mul"===node.value||"op_div"===node.value||"op_mod"===node.value||"op_exp"===node.value||"op_neg"===node.value))return"any";for(i=0;i<node.children.length;i++)if("any"!==(t=this.resolveType(vname,node.children[i])))return t}return"any"},getLHS:function(node){var res;if("node_var"===node.type)res={o:this.scope.locals,what:node.value};else if("node_op"===node.type&&"op_property"===node.value)res={o:this.execute(node.children[0]),what:node.children[1]};else{if("node_op"!==node.type||"op_extvalue"!==node.value)throw new Error("Syntax error: Invalid left-hand side of assignment.");res={o:this.execute(node.children[0]),what:this.execute(node.children[1])}}return res},getLHSCompiler:function(node,js){var res;if("node_var"===node.type)res=node.value;else if("node_op"===node.type&&"op_property"===node.value)res=[this.compile(node.children[0],js),"'"+node.children[1]+"'"];else{if("node_op"!==node.type||"op_extvalue"!==node.value)throw new Error("Syntax error: Invalid left-hand side of assignment.");res=[this.compile(node.children[0],js),"node_const"===node.children[1].type?node.children[1].value:this.compile(node.children[1],js)]}return res},execute:function(node){var ret,v,i,e,l,list,ilist,fun,attr,sc,parents=[];if(ret=0,!node)return ret;switch(this.line=node.line,this.col=node.col,node.type){case"node_op":switch(node.value){case"op_none":node.children[0]&&this.execute(node.children[0]),node.children[1]&&(ret=this.execute(node.children[1]));break;case"op_assign":v=this.getLHS(node.children[0]),this.lhs[this.scope.id]=v.what,v.o.type&&v.o.elementClass&&v.o.methodMap&&"label"===v.what&&this._error("Left-hand side of assignment is read-only."),ret=this.execute(node.children[1]),v.o!==this.scope.locals||Type.isArray(v.o)&&"number"==typeof v.what?this.setProp(v.o,v.what,ret):this.letvar(v.what,ret),this.lhs[this.scope.id]=0;break;case"op_if":this.execute(node.children[0])&&(ret=this.execute(node.children[1]));break;case"op_conditional":case"op_if_else":ret=this.execute(node.children[0])?this.execute(node.children[1]):this.execute(node.children[2]);break;case"op_while":for(;this.execute(node.children[0]);)this.execute(node.children[1]);break;case"op_do":do{this.execute(node.children[0])}while(this.execute(node.children[1]));break;case"op_for":for(this.execute(node.children[0]);this.execute(node.children[1]);this.execute(node.children[2]))this.execute(node.children[3]);break;case"op_proplst":node.children[0]&&this.execute(node.children[0]),node.children[1]&&this.execute(node.children[1]);break;case"op_emptyobject":ret={};break;case"op_proplst_val":this.propstack.push({}),this.propscope++,this.execute(node.children[0]),ret=this.propstack[this.propscope],this.propstack.pop(),this.propscope--;break;case"op_prop":this.propstack[this.propscope][node.children[0]]=this.execute(node.children[1]);break;case"op_array":for(ret=[],l=node.children[0].length,i=0;i<l;i++)ret.push(this.execute(node.children[0][i]));break;case"op_extvalue":ret=this.execute(node.children[0]),ret="number"==typeof(i=this.execute(node.children[1]))&&Math.abs(Math.round(i)-i)<Mat.eps?ret[i]:undefined;break;case"op_return":if(0!==this.scope)return this.execute(node.children[0]);this._error("Unexpected return.");break;case"op_map":node.children[1].isMath||"node_var"===node.children[1].type||this._error("execute: In a map only function calls and mathematical expressions are allowed."),(fun=this.defineFunction(node)).isMap=!0,ret=fun;break;case"op_function":(fun=this.defineFunction(node)).isMap=!1,ret=fun;break;case"op_execfun":if(this.dpstack.push([]),this.pscope++,list=node.children[1],Type.exists(node.children[2]))if(node.children[3])for(ilist=node.children[2],attr={},i=0;i<ilist.length;i++)attr=Type.deepCopy(attr,this.execute(ilist[i]),!0);else attr=this.execute(node.children[2]);for(node.children[0]._isFunctionName=!0,fun=this.execute(node.children[0]),delete node.children[0]._isFunctionName,sc=fun&&fun.sc?fun.sc:this,!fun.creator&&Type.exists(node.children[2])&&this._error("Unexpected value. Only element creators are allowed to have a value after the function call."),i=0;i<list.length;i++)Type.exists(fun.scope)&&Type.exists(fun.scope.argtypes)&&"function"===fun.scope.argtypes[i]?(list[i]._isFunctionName=!0,parents[i]=this.execute(list[i]),delete list[i]._isFunctionName):parents[i]=this.execute(list[i]),this.dpstack[this.pscope].push({line:node.children[1][i].line,col:node.children[1][i].ecol});if("function"!=typeof fun||fun.creator)if("function"==typeof fun&&fun.creator){e=this.line;try{for((ret=fun(parents,attr)).jcLineStart=e,ret.jcLineEnd=node.eline,i=e;i<=node.line;i++)this.lineToElement[i]=ret;ret.debugParents=this.dpstack[this.pscope]}catch(ex){this._error(ex.toString())}}else this._error("Function '"+fun+"' is undefined.");else ret=fun.apply(sc,parents);this.dpstack.pop(),this.pscope--;break;case"op_property":e=this.execute(node.children[0]),v=node.children[1],ret=this.resolveProperty(e,v,!1),Type.exists(ret)&&(ret.sc=e);break;case"op_use":this._warn("Use of the 'use' operator is deprecated."),this.use(node.children[0].toString());break;case"op_delete":this._warn("Use of the 'delete' operator is deprecated. Please use the remove() function."),v=this.getvar(node.children[0]),ret=this.del(v);break;case"op_eq":ret=this.execute(node.children[0])==this.execute(node.children[1]);break;case"op_neq":ret=this.execute(node.children[0])!=this.execute(node.children[1]);break;case"op_approx":ret=Math.abs(this.execute(node.children[0])-this.execute(node.children[1]))<Mat.eps;break;case"op_gt":ret=this.execute(node.children[0])>this.execute(node.children[1]);break;case"op_lt":ret=this.execute(node.children[0])<this.execute(node.children[1]);break;case"op_geq":ret=this.execute(node.children[0])>=this.execute(node.children[1]);break;case"op_leq":ret=this.execute(node.children[0])<=this.execute(node.children[1]);break;case"op_or":ret=this.execute(node.children[0])||this.execute(node.children[1]);break;case"op_and":ret=this.execute(node.children[0])&&this.execute(node.children[1]);break;case"op_not":ret=!this.execute(node.children[0]);break;case"op_add":ret=this.add(this.execute(node.children[0]),this.execute(node.children[1]));break;case"op_sub":ret=this.sub(this.execute(node.children[0]),this.execute(node.children[1]));break;case"op_div":ret=this.div(this.execute(node.children[0]),this.execute(node.children[1]));break;case"op_mod":ret=this.mod(this.execute(node.children[0]),this.execute(node.children[1]),!0);break;case"op_mul":ret=this.mul(this.execute(node.children[0]),this.execute(node.children[1]));break;case"op_exp":ret=this.pow(this.execute(node.children[0]),this.execute(node.children[1]));break;case"op_neg":ret=this.neg(this.execute(node.children[0]))}break;case"node_var":ret=this.getvar(node.value,!1,node._isFunctionName);break;case"node_const":ret=null===node.value?null:Number(node.value);break;case"node_const_bool":ret=node.value;break;case"node_str":ret=node.value.replace(/\\(.)/,"$1")}return ret},compile:function(node,js){var e,i,list,ret="";if(Type.exists(js)||(js=!1),!node)return ret;switch(node.type){case"node_op":switch(node.value){case"op_none":node.children[0]&&(ret=this.compile(node.children[0],js)),node.children[1]&&(ret+=this.compile(node.children[1],js));break;case"op_assign":js?(e=this.getLHSCompiler(node.children[0],js),Type.isArray(e)?ret="$jc$.setProp("+e[0]+", "+e[1]+", "+this.compile(node.children[1],js)+");\n":(this.isLocalVariable(e)!==this.scope&&(this.scope.locals[e]=!0),ret="$jc$.scopes["+this.scope.id+"].locals['"+e+"'] = "+this.compile(node.children[1],js)+";\n")):ret=(e=this.compile(node.children[0]))+" = "+this.compile(node.children[1],js)+";\n";break;case"op_if":ret=" if ("+this.compile(node.children[0],js)+") "+this.compile(node.children[1],js);break;case"op_if_else":ret=" if ("+this.compile(node.children[0],js)+")"+this.compile(node.children[1],js),ret+=" else "+this.compile(node.children[2],js);break;case"op_conditional":ret="(("+this.compile(node.children[0],js)+")?("+this.compile(node.children[1],js),ret+="):("+this.compile(node.children[2],js)+"))";break;case"op_while":ret=" while ("+this.compile(node.children[0],js)+") {\n"+this.compile(node.children[1],js)+"}\n";break;case"op_do":ret=" do {\n"+this.compile(node.children[0],js)+"} while ("+this.compile(node.children[1],js)+");\n";break;case"op_for":ret=" for ("+this.compile(node.children[0],js)+this.compile(node.children[1],js)+"; "+this.compile(node.children[2],js).slice(0,-2)+") {\n"+this.compile(node.children[3],js)+"\n}\n";break;case"op_proplst":node.children[0]&&(ret=this.compile(node.children[0],js)+", "),ret+=this.compile(node.children[1],js);break;case"op_prop":ret=node.children[0]+": "+this.compile(node.children[1],js);break;case"op_emptyobject":ret=js?"{}":"<< >>";break;case"op_proplst_val":ret=this.compile(node.children[0],js);break;case"op_array":for(list=[],i=0;i<node.children[0].length;i++)list.push(this.compile(node.children[0][i],js));ret="["+list.join(", ")+"]";break;case"op_extvalue":ret=this.compile(node.children[0],js)+"["+this.compile(node.children[1],js)+"]";break;case"op_return":ret=" return "+this.compile(node.children[0],js)+";\n";break;case"op_map":node.children[1].isMath||"node_var"===node.children[1].type||this._error("compile: In a map only function calls and mathematical expressions are allowed."),list=node.children[0],ret=js?" $jc$.makeMap(function ("+list.join(", ")+") { return "+this.compile(node.children[1],js)+"; })":"map ("+list.join(", ")+") -> "+this.compile(node.children[1],js);break;case"op_function":list=node.children[0],this.pushScope(list),ret=js?this.functionCodeJS(node):" function ("+list.join(", ")+") "+this.compile(node.children[1],js),this.popScope();break;case"op_execfunmath":console.log("op_execfunmath: TODO"),ret="-1";break;case"op_execfun":if(node.children[2]){for(list=[],i=0;i<node.children[2].length;i++)list.push(this.compile(node.children[2][i],js));js&&(e="$jc$.mergeAttributes("+list.join(", ")+")")}for(node.children[0].withProps=!!node.children[2],list=[],i=0;i<node.children[1].length;i++)list.push(this.compile(node.children[1][i],js));ret=this.compile(node.children[0],js)+"("+list.join(", ")+(node.children[2]&&js?", "+e:"")+")"+(node.children[2]&&!js?e:""),js&&(ret+="\n"),js&&"$"===node.children[0].value&&(ret="$jc$.board.objects["+this.compile(node.children[1][0],js)+"]");break;case"op_property":ret=js&&"X"!==node.children[1]&&"Y"!==node.children[1]?"$jc$.resolveProperty("+this.compile(node.children[0],js)+", '"+node.children[1]+"', true)":this.compile(node.children[0],js)+"."+node.children[1];break;case"op_use":this._warn("Use of the 'use' operator is deprecated."),ret=js?"$jc$.use('":"use('",ret+=node.children[0].toString()+"');";break;case"op_delete":this._warn("Use of the 'delete' operator is deprecated. Please use the remove() function."),ret=js?"$jc$.del(":"remove(",ret+=this.compile(node.children[0],js)+")";break;case"op_eq":ret="("+this.compile(node.children[0],js)+" === "+this.compile(node.children[1],js)+")";break;case"op_neq":ret="("+this.compile(node.children[0],js)+" !== "+this.compile(node.children[1],js)+")";break;case"op_approx":ret="("+this.compile(node.children[0],js)+" ~= "+this.compile(node.children[1],js)+")";break;case"op_gt":ret=js?"$jc$.gt("+this.compile(node.children[0],js)+", "+this.compile(node.children[1],js)+")":"("+this.compile(node.children[0],js)+" > "+this.compile(node.children[1],js)+")";break;case"op_lt":ret=js?"$jc$.lt("+this.compile(node.children[0],js)+", "+this.compile(node.children[1],js)+")":"("+this.compile(node.children[0],js)+" < "+this.compile(node.children[1],js)+")";break;case"op_geq":ret=js?"$jc$.geq("+this.compile(node.children[0],js)+", "+this.compile(node.children[1],js)+")":"("+this.compile(node.children[0],js)+" >= "+this.compile(node.children[1],js)+")";break;case"op_leq":ret=js?"$jc$.leq("+this.compile(node.children[0],js)+", "+this.compile(node.children[1],js)+")":"("+this.compile(node.children[0],js)+" <= "+this.compile(node.children[1],js)+")";break;case"op_or":ret="("+this.compile(node.children[0],js)+" || "+this.compile(node.children[1],js)+")";break;case"op_and":ret="("+this.compile(node.children[0],js)+" && "+this.compile(node.children[1],js)+")";break;case"op_not":ret="!("+this.compile(node.children[0],js)+")";break;case"op_add":ret=js?"$jc$.add("+this.compile(node.children[0],js)+", "+this.compile(node.children[1],js)+")":"("+this.compile(node.children[0],js)+" + "+this.compile(node.children[1],js)+")";break;case"op_sub":ret=js?"$jc$.sub("+this.compile(node.children[0],js)+", "+this.compile(node.children[1],js)+")":"("+this.compile(node.children[0],js)+" - "+this.compile(node.children[1],js)+")";break;case"op_div":ret=js?"$jc$.div("+this.compile(node.children[0],js)+", "+this.compile(node.children[1],js)+")":"("+this.compile(node.children[0],js)+" / "+this.compile(node.children[1],js)+")";break;case"op_mod":ret=js?"$jc$.mod("+this.compile(node.children[0],js)+", "+this.compile(node.children[1],js)+", true)":"("+this.compile(node.children[0],js)+" % "+this.compile(node.children[1],js)+")";break;case"op_mul":ret=js?"$jc$.mul("+this.compile(node.children[0],js)+", "+this.compile(node.children[1],js)+")":"("+this.compile(node.children[0],js)+" * "+this.compile(node.children[1],js)+")";break;case"op_exp":ret=js?"$jc$.pow("+this.compile(node.children[0],js)+", "+this.compile(node.children[1],js)+")":"("+this.compile(node.children[0],js)+"^"+this.compile(node.children[1],js)+")";break;case"op_neg":ret=js?"$jc$.neg("+this.compile(node.children[0],js)+")":"(-"+this.compile(node.children[0],js)+")"}break;case"node_var":ret=js?this.getvarJS(node.value,!1,node.withProps):node.value;break;case"node_const":case"node_const_bool":ret=node.value;break;case"node_str":ret="'"+node.value+"'"}return node.needsBrackets&&(ret="{\n"+ret+"\n}\n"),ret},getName:function(obj,useId){var name="";return Type.exists(obj)&&Type.exists(obj.getName)?(name=obj.getName(),Type.exists(name)&&""!==name||!useId||(name=obj.id)):useId&&(name=obj.id),name},X:function(e){return e.X()},Y:function(e){return e.Y()},V:function(e){return e.Value()},L:function(e){return e.L()},area:function(obj){return Type.exists(obj)&&Type.exists(obj.Area)||this._error("Error: Can't calculate area."),obj.Area()},dist:function(p1,p2){return Type.exists(p1)&&Type.exists(p1.Dist)||this._error("Error: Can't calculate distance."),p1.Dist(p2)},radius:function(obj){return Type.exists(obj)&&Type.exists(obj.Radius)||this._error("Error: Can't calculate radius."),obj.Radius()},add:function(a,b){var i,len,res;if(a=Type.evalSlider(a),b=Type.evalSlider(b),Interval.isInterval(a)||Interval.isInterval(b))res=Interval.add(a,b);else if(Type.isArray(a)&&Type.isArray(b))for(len=Math.min(a.length,b.length),res=[],i=0;i<len;i++)res[i]=a[i]+b[i];else Type.isNumber(a)&&Type.isNumber(b)?res=a+b:Type.isString(a)||Type.isString(b)?res=a.toString()+b.toString():this._error("Operation + not defined on operands "+_typeof(a)+" and "+_typeof(b));return res},sub:function(a,b){var i,len,res;if(a=Type.evalSlider(a),b=Type.evalSlider(b),Interval.isInterval(a)||Interval.isInterval(b))res=Interval.sub(a,b);else if(Type.isArray(a)&&Type.isArray(b))for(len=Math.min(a.length,b.length),res=[],i=0;i<len;i++)res[i]=a[i]-b[i];else Type.isNumber(a)&&Type.isNumber(b)?res=a-b:this._error("Operation - not defined on operands "+_typeof(a)+" and "+_typeof(b));return res},neg:function(a){var i,len,res;if(a=Type.evalSlider(a),Interval.isInterval(a))res=Interval.negative(a);else if(Type.isArray(a))for(len=a.length,res=[],i=0;i<len;i++)res[i]=-a[i];else Type.isNumber(a)?res=-a:this._error("Unary operation - not defined on operand "+_typeof(a));return res},mul:function(a,b){var i,len,res;if(a=Type.evalSlider(a),b=Type.evalSlider(b),Type.isArray(a)&&Type.isNumber(b)&&(i=a,b=a=b),Interval.isInterval(a)||Interval.isInterval(b))res=Interval.mul(a,b);else if(Type.isArray(a)&&Type.isArray(b))len=Math.min(a.length,b.length),res=Mat.innerProduct(a,b,len);else if(Type.isNumber(a)&&Type.isArray(b))for(len=b.length,res=[],i=0;i<len;i++)res[i]=a*b[i];else Type.isNumber(a)&&Type.isNumber(b)?res=a*b:this._error("Operation * not defined on operands "+_typeof(a)+" and "+_typeof(b));return res},div:function(a,b){var i,len,res;if(a=Type.evalSlider(a),b=Type.evalSlider(b),Interval.isInterval(a)||Interval.isInterval(b))res=Interval.div(a,b);else if(Type.isArray(a)&&Type.isNumber(b))for(len=a.length,res=[],i=0;i<len;i++)res[i]=a[i]/b;else Type.isNumber(a)&&Type.isNumber(b)?res=a/b:this._error("Operation * not defined on operands "+_typeof(a)+" and "+_typeof(b));return res},mod:function(a,b){var i,len,res;if(a=Type.evalSlider(a),b=Type.evalSlider(b),Interval.isInterval(a)||Interval.isInterval(b))return Interval.fmod(a,b);if(Type.isArray(a)&&Type.isNumber(b))for(len=a.length,res=[],i=0;i<len;i++)res[i]=Mat.mod(a[i],b,!0);else Type.isNumber(a)&&Type.isNumber(b)?res=Mat.mod(a,b,!0):this._error("Operation * not defined on operands "+_typeof(a)+" and "+_typeof(b));return res},pow:function(a,b){return a=Type.evalSlider(a),b=Type.evalSlider(b),Interval.isInterval(a)||Interval.isInterval(b)?Interval.pow(a,b):Mat.pow(a,b)},lt:function(a,b){return Interval.isInterval(a)||Interval.isInterval(b)?Interval.lt(a,b):a<b},leq:function(a,b){return Interval.isInterval(a)||Interval.isInterval(b)?Interval.leq(a,b):a<=b},gt:function(a,b){return Interval.isInterval(a)||Interval.isInterval(b)?Interval.gt(a,b):a>b},geq:function(a,b){return Interval.isInterval(a)||Interval.isInterval(b)?Intervalt.geq(a,b):a>=b},randint:function(min,max,step){return Type.exists(step)||(step=1),Math.round(Math.random()*(max-min)/step)*step+min},DDD:function(f){console.log("Dummy derivative function. This should never appear!")},ifthen:function(cond,v1,v2){return cond?v1:v2},del:function(element){"object"===_typeof(element)&&JXG.exists(element.type)&&JXG.exists(element.elementClass)&&this.board.removeObject(element)},use:function(board){var b,ref,found=!1;if("string"==typeof board){for(b in JXG.boards)if(JXG.boards.hasOwnProperty(b)&&JXG.boards[b].container===board){ref=JXG.boards[b],found=!0;break}}else ref=board,found=!0;found?(this.board=ref,this.builtIn.$board=ref,this.builtIn.$board.src="$jc$.board"):this._error("Board '"+board+"' not found!")},findSymbol:function(v,scope){var i,s;for(s=-1===(scope=Type.def(scope,-1))?this.scope:this.scopes[scope];null!==s;){for(i in s.locals)if(s.locals.hasOwnProperty(i)&&s.locals[i]===v)return[i,s];s=s.previous}return[]},importModule:function(module){return priv.modules[module.toLowerCase()]},defineBuiltIn:function(){var builtIn={PI:Math.PI,EULER:Math.E,D:this.DDD,X:this.X,Y:this.Y,V:this.V,L:this.L,acosh:Mat.acosh,acot:Mat.acot,asinh:Mat.asinh,binomial:Mat.binomial,cbrt:Mat.cbrt,cosh:Mat.cosh,cot:Mat.cot,deg:Geometry.trueAngle,A:this.area,area:this.area,dist:this.dist,R:this.radius,radius:this.radius,erf:Mat.erf,erfc:Mat.erfc,erfi:Mat.erfi,factorial:Mat.factorial,gcd:Mat.gcd,lb:Mat.log2,lcm:Mat.lcm,ld:Mat.log2,lg:Mat.log10,ln:Math.log,log:Mat.log,log10:Mat.log10,log2:Mat.log2,ndtr:Mat.ndtr,ndtri:Mat.ndtri,nthroot:Mat.nthroot,pow:Mat.pow,rad:Geometry.rad,ratpow:Mat.ratpow,trunc:Type.trunc,sinh:Mat.sinh,randint:this.randint,IfThen:this.ifthen,import:this.importModule,use:this.use,remove:this.del,$:this.getElementById,getName:this.getName,name:this.getName,$board:this.board,$log:this.log};return builtIn.rad.sc=Geometry,builtIn.deg.sc=Geometry,builtIn.factorial.sc=Mat,builtIn.X.src="$jc$.X",builtIn.Y.src="$jc$.Y",builtIn.V.src="$jc$.V",builtIn.L.src="$jc$.L",builtIn.acosh.src="JXG.Math.acosh",builtIn.acot.src="JXG.Math.acot",builtIn.asinh.src="JXG.Math.asinh",builtIn.binomial.src="JXG.Math.binomial",builtIn.cbrt.src="JXG.Math.cbrt",builtIn.cot.src="JXG.Math.cot",builtIn.cosh.src="JXG.Math.cosh",builtIn.deg.src="JXG.Math.Geometry.trueAngle",builtIn.erf.src="JXG.Math.erf",builtIn.erfc.src="JXG.Math.erfc",builtIn.erfi.src="JXG.Math.erfi",builtIn.A.src="$jc$.area",builtIn.area.src="$jc$.area",builtIn.dist.src="$jc$.dist",builtIn.R.src="$jc$.radius",builtIn.radius.src="$jc$.radius",builtIn.factorial.src="JXG.Math.factorial",builtIn.gcd.src="JXG.Math.gcd",builtIn.lb.src="JXG.Math.log2",builtIn.lcm.src="JXG.Math.lcm",builtIn.ld.src="JXG.Math.log2",builtIn.lg.src="JXG.Math.log10",builtIn.ln.src="Math.log",builtIn.log.src="JXG.Math.log",builtIn.log10.src="JXG.Math.log10",builtIn.log2.src="JXG.Math.log2",builtIn.ndtr.src="JXG.Math.ndtr",builtIn.ndtri.src="JXG.Math.ndtri",builtIn.nthroot.src="JXG.Math.nthroot",builtIn.pow.src="JXG.Math.pow",builtIn.rad.src="JXG.Math.Geometry.rad",builtIn.ratpow.src="JXG.Math.ratpow",builtIn.trunc.src="JXG.trunc",builtIn.sinh.src="JXG.Math.sinh",builtIn.randint.src="$jc$.randint",builtIn.import.src="$jc$.importModule",builtIn.use.src="$jc$.use",builtIn.remove.src="$jc$.del",builtIn.IfThen.src="$jc$.ifthen",builtIn.$.src="(function (n) { return $jc$.board.select(n); })",builtIn.getName.src="$jc$.getName",builtIn.name.src="$jc$.getName",builtIn.$board&&(builtIn.$board.src="$jc$.board"),builtIn.$log.src="$jc$.log",builtIn},getPossibleOperands:function(){var jc,ma,merge,i,j,p,len,e,funcs,funcsJC,consts,operands,sort,pack,FORBIDDEN=["E"],jessiecode=this.defineBuiltIn(),math=Math;for(sort=function(a,b){return a.toLowerCase().localeCompare(b.toLowerCase())},pack=function(name,origin){var that=null;if("jc"===origin)that=jessiecode[name];else{if("Math"!==origin)return;that=math[name]}if(!FORBIDDEN.includes(name))return JXG.isFunction(that)?{name:name,type:"function",numParams:that.length,origin:origin}:JXG.isNumber(that)?{name:name,type:"constant",value:that,origin:origin}:void(void 0!==that&&console.error("undefined type",that))},jc=Object.getOwnPropertyNames(jessiecode).sort(sort),ma=Object.getOwnPropertyNames(math).sort(sort),merge=[],i=0,j=0;i<jc.length||j<ma.length;)jc[i]===ma[j]?(p=pack(ma[j],"Math"),JXG.exists(p)&&merge.push(p),i++,j++):!JXG.exists(ma[j])||jc[i].toLowerCase().localeCompare(ma[j].toLowerCase())<0?(p=pack(jc[i],"jc"),JXG.exists(p)&&merge.push(p),i++):(p=pack(ma[j],"Math"),JXG.exists(p)&&merge.push(p),j++);for(funcs=[],funcsJC=[],consts=[],operands={},len=merge.length,i=0;i<len;i++){switch((e=merge[i]).type){case"function":funcs.push(e.name),"jc"===e.origin&&funcsJC.push(e.name);break;case"constant":consts.push(e.name)}operands[e.name]=e}return{all:operands,list:merge,functions:funcs,functions_jessiecode:funcsJC,constants:consts}},_debug:function(log){"object"===("undefined"==typeof console?"undefined":_typeof(console))?console.log(log):Env.isBrowser&&document&&null!==document.getElementById("debug")&&(document.getElementById("debug").innerHTML+=log+"<br />")},_error:function(msg){var e=new Error("Error("+this.line+"): "+msg);throw e.line=this.line,e},_warn:function(msg){"object"===("undefined"==typeof console?"undefined":_typeof(console))?console.log("Warning("+this.line+"): "+msg):Env.isBrowser&&document&&null!==document.getElementById(this.warnLog)&&(document.getElementById(this.warnLog).innerHTML+="Warning("+this.line+"): "+msg+"<br />")},_log:function(msg){"object"!==("undefined"==typeof window?"undefined":_typeof(window))&&"object"===("undefined"==typeof self?"undefined":_typeof(self))&&self.postMessage?self.postMessage({type:"log",msg:"Log: "+msg.toString()}):console.log("Log: ",arguments)}});var parser=function(){var o=function(k,v,_o,l){for(_o=_o||{},l=k.length;l--;_o[k[l]]=v);return _o},$V0=[2,14],$V1=[1,13],$V2=[1,37],$V3=[1,14],$V4=[1,15],$V5=[1,21],$V6=[1,16],$V7=[1,17],$V8=[1,33],$V9=[1,18],$Va=[1,19],$Vb=[1,12],$Vc=[1,59],$Vd=[1,60],$Ve=[1,58],$Vf=[1,46],$Vg=[1,48],$Vh=[1,49],$Vi=[1,50],$Vj=[1,51],$Vk=[1,52],$Vl=[1,53],$Vm=[1,54],$Vn=[1,45],$Vo=[1,38],$Vp=[1,39],$Vq=[5,7,8,14,15,16,17,19,20,21,23,26,27,50,51,58,65,74,75,76,77,78,79,80,82,91,93],$Vr=[5,7,8,12,14,15,16,17,19,20,21,23,26,27,50,51,58,65,74,75,76,77,78,79,80,82,91,93],$Vs=[8,10,16,32,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,57,64,65,66,83,86],$Vt=[2,48],$Vu=[1,72],$Vv=[10,16,32,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,57,66,83,86],$Vw=[1,78],$Vx=[8,10,16,32,34,35,37,41,42,43,45,46,47,48,50,51,53,54,55,57,64,65,66,83,86],$Vy=[1,82],$Vz=[8,10,16,32,34,35,37,39,45,46,47,48,50,51,53,54,55,57,64,65,66,83,86],$VA=[1,83],$VB=[1,84],$VC=[1,85],$VD=[8,10,16,32,34,35,37,39,41,42,43,50,51,53,54,55,57,64,65,66,83,86],$VE=[1,89],$VF=[1,90],$VG=[1,91],$VH=[1,92],$VI=[1,97],$VJ=[8,10,16,32,34,35,37,39,41,42,43,45,46,47,48,53,54,55,57,64,65,66,83,86],$VK=[1,103],$VL=[1,104],$VM=[8,10,16,32,34,35,37,39,41,42,43,45,46,47,48,50,51,57,64,65,66,83,86],$VN=[1,105],$VO=[1,106],$VP=[1,107],$VQ=[1,126],$VR=[1,139],$VS=[83,86],$VT=[1,150],$VU=[10,66,86],$VV=[8,10,16,20,32,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,57,64,65,66,82,83,86],$VW=[1,167],$VX=[10,86],parser={trace:function(){},yy:{},symbols_:{error:2,Program:3,StatementList:4,EOF:5,IfStatement:6,IF:7,"(":8,Expression:9,")":10,Statement:11,ELSE:12,LoopStatement:13,WHILE:14,FOR:15,";":16,DO:17,UnaryStatement:18,USE:19,IDENTIFIER:20,DELETE:21,ReturnStatement:22,RETURN:23,EmptyStatement:24,StatementBlock:25,"{":26,"}":27,ExpressionStatement:28,AssignmentExpression:29,ConditionalExpression:30,LeftHandSideExpression:31,"=":32,LogicalORExpression:33,"?":34,":":35,LogicalANDExpression:36,"||":37,EqualityExpression:38,"&&":39,RelationalExpression:40,"==":41,"!=":42,"~=":43,AdditiveExpression:44,"<":45,">":46,"<=":47,">=":48,MultiplicativeExpression:49,"+":50,"-":51,UnaryExpression:52,"*":53,"/":54,"%":55,ExponentExpression:56,"^":57,"!":58,MemberExpression:59,CallExpression:60,PrimaryExpression:61,FunctionExpression:62,MapExpression:63,".":64,"[":65,"]":66,BasicLiteral:67,ObjectLiteral:68,ArrayLiteral:69,NullLiteral:70,BooleanLiteral:71,StringLiteral:72,NumberLiteral:73,NULL:74,TRUE:75,FALSE:76,STRING:77,NUMBER:78,NAN:79,INFINITY:80,ElementList:81,"<<":82,">>":83,PropertyList:84,Property:85,",":86,PropertyName:87,Arguments:88,AttributeList:89,Attribute:90,FUNCTION:91,ParameterDefinitionList:92,MAP:93,"->":94,$accept:0,$end:1},terminals_:{2:"error",5:"EOF",7:"IF",8:"(",10:")",12:"ELSE",14:"WHILE",15:"FOR",16:";",17:"DO",19:"USE",20:"IDENTIFIER",21:"DELETE",23:"RETURN",26:"{",27:"}",32:"=",34:"?",35:":",37:"||",39:"&&",41:"==",42:"!=",43:"~=",45:"<",46:">",47:"<=",48:">=",50:"+",51:"-",53:"*",54:"/",55:"%",57:"^",58:"!",64:".",65:"[",66:"]",74:"NULL",75:"TRUE",76:"FALSE",77:"STRING",78:"NUMBER",79:"NAN",80:"INFINITY",82:"<<",83:">>",86:",",91:"FUNCTION",93:"MAP",94:"->"},productions_:[0,[3,2],[6,5],[6,7],[13,5],[13,9],[13,7],[18,2],[18,2],[22,2],[22,3],[24,1],[25,3],[4,2],[4,0],[11,1],[11,1],[11,1],[11,1],[11,1],[11,1],[11,1],[28,2],[9,1],[29,1],[29,3],[30,1],[30,5],[33,1],[33,3],[36,1],[36,3],[38,1],[38,3],[38,3],[38,3],[40,1],[40,3],[40,3],[40,3],[40,3],[44,1],[44,3],[44,3],[49,1],[49,3],[49,3],[49,3],[56,1],[56,3],[52,1],[52,2],[52,2],[52,2],[31,1],[31,1],[59,1],[59,1],[59,1],[59,3],[59,4],[61,1],[61,1],[61,1],[61,1],[61,3],[67,1],[67,1],[67,1],[67,1],[70,1],[71,1],[71,1],[72,1],[73,1],[73,1],[73,1],[69,2],[69,3],[68,2],[68,3],[84,1],[84,3],[85,3],[87,1],[87,1],[87,1],[60,2],[60,3],[60,2],[60,4],[60,3],[88,2],[88,3],[89,1],[89,3],[90,1],[90,1],[81,1],[81,3],[62,4],[62,5],[63,5],[63,6],[92,1],[92,3]],performAction:function(yytext,yyleng,yylineno,yy,yystate,$$,_$){var $0=$$.length-1;switch(yystate){case 1:return $$[$0-1];case 2:this.$=AST.createNode(lc(_$[$0-4]),"node_op","op_if",$$[$0-2],$$[$0]);break;case 3:this.$=AST.createNode(lc(_$[$0-6]),"node_op","op_if_else",$$[$0-4],$$[$0-2],$$[$0]);break;case 4:this.$=AST.createNode(lc(_$[$0-4]),"node_op","op_while",$$[$0-2],$$[$0]);break;case 5:this.$=AST.createNode(lc(_$[$0-8]),"node_op","op_for",$$[$0-6],$$[$0-4],$$[$0-2],$$[$0]);break;case 6:this.$=AST.createNode(lc(_$[$0-6]),"node_op","op_do",$$[$0-5],$$[$0-2]);break;case 7:this.$=AST.createNode(lc(_$[$0-1]),"node_op","op_use",$$[$0]);break;case 8:this.$=AST.createNode(lc(_$[$0-1]),"node_op","op_delete",$$[$0]);break;case 9:this.$=AST.createNode(lc(_$[$0-1]),"node_op","op_return",void 0);break;case 10:this.$=AST.createNode(lc(_$[$0-2]),"node_op","op_return",$$[$0-1]);break;case 11:case 14:this.$=AST.createNode(lc(_$[$0]),"node_op","op_none");break;case 12:this.$=$$[$0-1],this.$.needsBrackets=!0;break;case 13:this.$=AST.createNode(lc(_$[$0-1]),"node_op","op_none",$$[$0-1],$$[$0]);break;case 15:case 16:case 17:case 18:case 19:case 20:case 21:case 23:case 24:case 26:case 28:case 30:case 32:case 36:case 41:case 44:case 48:case 50:case 52:case 54:case 55:case 56:case 58:case 62:case 81:case 84:case 85:case 86:this.$=$$[$0];break;case 22:case 65:case 93:this.$=$$[$0-1];break;case 25:this.$=AST.createNode(lc(_$[$0-2]),"node_op","op_assign",$$[$0-2],$$[$0]),this.$.isMath=!1;break;case 27:this.$=AST.createNode(lc(_$[$0-4]),"node_op","op_conditional",$$[$0-4],$$[$0-2],$$[$0]),this.$.isMath=!1;break;case 29:this.$=AST.createNode(lc(_$[$0-2]),"node_op","op_or",$$[$0-2],$$[$0]),this.$.isMath=!1;break;case 31:this.$=AST.createNode(lc(_$[$0-2]),"node_op","op_and",$$[$0-2],$$[$0]),this.$.isMath=!1;break;case 33:this.$=AST.createNode(lc(_$[$0-2]),"node_op","op_eq",$$[$0-2],$$[$0]),this.$.isMath=!1;break;case 34:this.$=AST.createNode(lc(_$[$0-2]),"node_op","op_neq",$$[$0-2],$$[$0]),this.$.isMath=!1;break;case 35:this.$=AST.createNode(lc(_$[$0-2]),"node_op","op_approx",$$[$0-2],$$[$0]),this.$.isMath=!1;break;case 37:this.$=AST.createNode(lc(_$[$0-2]),"node_op","op_lt",$$[$0-2],$$[$0]),this.$.isMath=!1;break;case 38:this.$=AST.createNode(lc(_$[$0-2]),"node_op","op_gt",$$[$0-2],$$[$0]),this.$.isMath=!1;break;case 39:this.$=AST.createNode(lc(_$[$0-2]),"node_op","op_leq",$$[$0-2],$$[$0]),this.$.isMath=!1;break;case 40:this.$=AST.createNode(lc(_$[$0-2]),"node_op","op_geq",$$[$0-2],$$[$0]),this.$.isMath=!1;break;case 42:this.$=AST.createNode(lc(_$[$0-2]),"node_op","op_add",$$[$0-2],$$[$0]),this.$.isMath=!0;break;case 43:this.$=AST.createNode(lc(_$[$0-2]),"node_op","op_sub",$$[$0-2],$$[$0]),this.$.isMath=!0;break;case 45:this.$=AST.createNode(lc(_$[$0-2]),"node_op","op_mul",$$[$0-2],$$[$0]),this.$.isMath=!0;break;case 46:this.$=AST.createNode(lc(_$[$0-2]),"node_op","op_div",$$[$0-2],$$[$0]),this.$.isMath=!0;break;case 47:this.$=AST.createNode(lc(_$[$0-2]),"node_op","op_mod",$$[$0-2],$$[$0]),this.$.isMath=!0;break;case 49:this.$=AST.createNode(lc(_$[$0-2]),"node_op","op_exp",$$[$0-2],$$[$0]),this.$.isMath=!0;break;case 51:this.$=AST.createNode(lc(_$[$0-1]),"node_op","op_not",$$[$0]),this.$.isMath=!1;break;case 53:this.$=AST.createNode(lc(_$[$0-1]),"node_op","op_neg",$$[$0]),this.$.isMath=!0;break;case 57:case 63:case 64:case 66:case 67:case 68:case 97:this.$=$$[$0],this.$.isMath=!1;break;case 59:case 91:this.$=AST.createNode(lc(_$[$0-2]),"node_op","op_property",$$[$0-2],$$[$0]),this.$.isMath=!0;break;case 60:case 90:this.$=AST.createNode(lc(_$[$0-3]),"node_op","op_extvalue",$$[$0-3],$$[$0-1]),this.$.isMath=!0;break;case 61:this.$=AST.createNode(lc(_$[$0]),"node_var",$$[$0]);break;case 69:this.$=$$[$0],this.$.isMath=!0;break;case 70:this.$=AST.createNode(lc(_$[$0]),"node_const",null);break;case 71:this.$=AST.createNode(lc(_$[$0]),"node_const_bool",!0);break;case 72:this.$=AST.createNode(lc(_$[$0]),"node_const_bool",!1);break;case 73:this.$=AST.createNode(lc(_$[$0]),"node_str",$$[$0].substring(1,$$[$0].length-1));break;case 74:this.$=AST.createNode(lc(_$[$0]),"node_const",parseFloat($$[$0]));break;case 75:this.$=AST.createNode(lc(_$[$0]),"node_const",NaN);break;case 76:this.$=AST.createNode(lc(_$[$0]),"node_const",1/0);break;case 77:this.$=AST.createNode(lc(_$[$0-1]),"node_op","op_array",[]);break;case 78:this.$=AST.createNode(lc(_$[$0-2]),"node_op","op_array",$$[$0-1]);break;case 79:this.$=AST.createNode(lc(_$[$0-1]),"node_op","op_emptyobject",{}),this.$.needsBrackets=!0;break;case 80:this.$=AST.createNode(lc(_$[$0-2]),"node_op","op_proplst_val",$$[$0-1]),this.$.needsBrackets=!0;break;case 82:this.$=AST.createNode(lc(_$[$0-2]),"node_op","op_proplst",$$[$0-2],$$[$0]);break;case 83:this.$=AST.createNode(lc(_$[$0-2]),"node_op","op_prop",$$[$0-2],$$[$0]);break;case 87:case 89:this.$=AST.createNode(lc(_$[$0-1]),"node_op","op_execfun",$$[$0-1],$$[$0]),this.$.isMath=!0;break;case 88:this.$=AST.createNode(lc(_$[$0-2]),"node_op","op_execfun",$$[$0-2],$$[$0-1],$$[$0],!0),this.$.isMath=!1;break;case 92:this.$=[];break;case 94:case 98:case 104:this.$=[$$[$0]];break;case 95:case 99:case 105:this.$=$$[$0-2].concat($$[$0]);break;case 96:this.$=AST.createNode(lc(_$[$0]),"node_var",$$[$0]),this.$.isMath=!0;break;case 100:this.$=AST.createNode(lc(_$[$0-3]),"node_op","op_function",[],$$[$0]),this.$.isMath=!1;break;case 101:this.$=AST.createNode(lc(_$[$0-4]),"node_op","op_function",$$[$0-2],$$[$0]),this.$.isMath=!1;break;case 102:this.$=AST.createNode(lc(_$[$0-4]),"node_op","op_map",[],$$[$0]);break;case 103:this.$=AST.createNode(lc(_$[$0-5]),"node_op","op_map",$$[$0-3],$$[$0])}},table:[o([5,7,8,14,15,16,17,19,20,21,23,26,50,51,58,65,74,75,76,77,78,79,80,82,91,93],$V0,{3:1,4:2}),{1:[3]},{5:[1,3],6:6,7:$V1,8:$V2,9:20,11:4,13:7,14:$V3,15:$V4,16:$V5,17:$V6,18:8,19:$V7,20:$V8,21:$V9,22:9,23:$Va,24:11,25:5,26:$Vb,28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{1:[2,1]},o($Vq,[2,13]),o($Vr,[2,15]),o($Vr,[2,16]),o($Vr,[2,17]),o($Vr,[2,18]),o($Vr,[2,19]),o($Vr,[2,20]),o($Vr,[2,21]),o([7,8,14,15,16,17,19,20,21,23,26,27,50,51,58,65,74,75,76,77,78,79,80,82,91,93],$V0,{4:61}),{8:[1,62]},{8:[1,63]},{8:[1,64]},{6:6,7:$V1,8:$V2,9:20,11:65,13:7,14:$V3,15:$V4,16:$V5,17:$V6,18:8,19:$V7,20:$V8,21:$V9,22:9,23:$Va,24:11,25:5,26:$Vb,28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{20:[1,66]},{20:[1,67]},{8:$V2,9:69,16:[1,68],20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{16:[1,70]},o($Vr,[2,11]),o($Vs,[2,23]),o($Vs,[2,24]),o([8,10,16,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,64,65,66,83,86],$Vt,{32:[1,71],57:$Vu}),o([8,10,16,32,35,39,41,42,43,45,46,47,48,50,51,53,54,55,57,64,65,66,83,86],[2,26],{34:[1,73],37:[1,74]}),o($Vv,[2,54],{88:77,8:$Vw,64:[1,75],65:[1,76]}),o($Vv,[2,55],{88:79,8:$Vw,64:[1,81],65:[1,80]}),o($Vx,[2,28],{39:$Vy}),o($Vs,[2,56]),o($Vs,[2,57]),o($Vs,[2,58]),o($Vz,[2,30],{41:$VA,42:$VB,43:$VC}),o($Vs,[2,61]),o($Vs,[2,62]),o($Vs,[2,63]),o($Vs,[2,64]),{8:$V2,9:86,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:[1,87]},{8:[1,88]},o($VD,[2,32],{45:$VE,46:$VF,47:$VG,48:$VH}),o($Vs,[2,66]),o($Vs,[2,67]),o($Vs,[2,68]),o($Vs,[2,69]),{20:$VI,72:98,73:99,77:$Vj,78:$Vk,79:$Vl,80:$Vm,83:[1,93],84:94,85:95,87:96},{8:$V2,20:$V8,29:102,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,66:[1,100],67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,81:101,82:$Vn,91:$Vo,93:$Vp},o($VJ,[2,36],{50:$VK,51:$VL}),o($Vs,[2,70]),o($Vs,[2,71]),o($Vs,[2,72]),o($Vs,[2,73]),o($Vs,[2,74]),o($Vs,[2,75]),o($Vs,[2,76]),o($VM,[2,41],{53:$VN,54:$VO,55:$VP}),o($Vs,[2,44]),o($Vs,[2,50]),{8:$V2,20:$V8,31:109,50:$Vc,51:$Vd,52:108,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,50:$Vc,51:$Vd,52:110,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,50:$Vc,51:$Vd,52:111,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{6:6,7:$V1,8:$V2,9:20,11:4,13:7,14:$V3,15:$V4,16:$V5,17:$V6,18:8,19:$V7,20:$V8,21:$V9,22:9,23:$Va,24:11,25:5,26:$Vb,27:[1,112],28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,9:113,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,9:114,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,9:115,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{14:[1,116]},o($Vr,[2,7]),o($Vr,[2,8]),o($Vr,[2,9]),{16:[1,117]},o($Vr,[2,22]),{8:$V2,20:$V8,29:118,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,50:$Vc,51:$Vd,52:119,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,29:120,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,36:121,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{20:[1,122]},{8:$V2,9:123,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},o($Vs,[2,87],{89:124,90:125,68:127,20:$VQ,82:$Vn}),{8:$V2,10:[1,128],20:$V8,29:102,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,81:129,82:$Vn,91:$Vo,93:$Vp},o($Vs,[2,89]),{8:$V2,9:130,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{20:[1,131]},{8:$V2,20:$V8,31:109,38:132,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,40:133,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,40:134,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,40:135,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{10:[1,136]},{10:[1,137],20:$VR,92:138},{10:[1,140],20:$VR,92:141},{8:$V2,20:$V8,31:109,44:142,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,44:143,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,44:144,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,44:145,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},o($Vs,[2,79]),{83:[1,146],86:[1,147]},o($VS,[2,81]),{35:[1,148]},{35:[2,84]},{35:[2,85]},{35:[2,86]},o($Vs,[2,77]),{66:[1,149],86:$VT},o($VU,[2,98]),{8:$V2,20:$V8,31:109,49:151,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,49:152,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,50:$Vc,51:$Vd,52:153,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,50:$Vc,51:$Vd,52:154,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,50:$Vc,51:$Vd,52:155,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},o($Vs,[2,51]),o([8,10,16,32,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,64,65,66,83,86],$Vt,{57:$Vu}),o($Vs,[2,52]),o($Vs,[2,53]),o([5,7,8,10,12,14,15,16,17,19,20,21,23,26,27,32,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,57,58,64,65,66,74,75,76,77,78,79,80,82,83,86,91,93],[2,12]),{10:[1,156]},{10:[1,157]},{16:[1,158]},{8:[1,159]},o($Vr,[2,10]),o($Vs,[2,25]),o($Vs,[2,49]),{35:[1,160]},o($Vx,[2,29],{39:$Vy}),o($Vs,[2,59]),{66:[1,161]},o([8,10,16,32,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,57,64,65,66,83],[2,88],{86:[1,162]}),o($Vs,[2,94]),o($Vs,[2,96]),o($Vs,[2,97]),o($VV,[2,92]),{10:[1,163],86:$VT},{66:[1,164]},o($Vs,[2,91]),o($Vz,[2,31],{41:$VA,42:$VB,43:$VC}),o($VD,[2,33],{45:$VE,46:$VF,47:$VG,48:$VH}),o($VD,[2,34],{45:$VE,46:$VF,47:$VG,48:$VH}),o($VD,[2,35],{45:$VE,46:$VF,47:$VG,48:$VH}),o($Vs,[2,65]),{25:165,26:$Vb},{10:[1,166],86:$VW},o($VX,[2,104]),{94:[1,168]},{10:[1,169],86:$VW},o($VJ,[2,37],{50:$VK,51:$VL}),o($VJ,[2,38],{50:$VK,51:$VL}),o($VJ,[2,39],{50:$VK,51:$VL}),o($VJ,[2,40],{50:$VK,51:$VL}),o($Vs,[2,80]),{20:$VI,72:98,73:99,77:$Vj,78:$Vk,79:$Vl,80:$Vm,85:170,87:96},{8:$V2,20:$V8,29:171,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},o($Vs,[2,78]),{8:$V2,20:$V8,29:172,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},o($VM,[2,42],{53:$VN,54:$VO,55:$VP}),o($VM,[2,43],{53:$VN,54:$VO,55:$VP}),o($Vs,[2,45]),o($Vs,[2,46]),o($Vs,[2,47]),{6:6,7:$V1,8:$V2,9:20,11:173,13:7,14:$V3,15:$V4,16:$V5,17:$V6,18:8,19:$V7,20:$V8,21:$V9,22:9,23:$Va,24:11,25:5,26:$Vb,28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{6:6,7:$V1,8:$V2,9:20,11:174,13:7,14:$V3,15:$V4,16:$V5,17:$V6,18:8,19:$V7,20:$V8,21:$V9,22:9,23:$Va,24:11,25:5,26:$Vb,28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,9:175,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,9:176,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,29:177,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},o($Vs,[2,60]),{20:$VQ,68:127,82:$Vn,90:178},o($VV,[2,93]),o($Vs,[2,90]),o($Vs,[2,100]),{25:179,26:$Vb},{20:[1,180]},{8:$V2,9:181,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{94:[1,182]},o($VS,[2,82]),o($VS,[2,83]),o($VU,[2,99]),o($Vq,[2,2],{12:[1,183]}),o($Vr,[2,4]),{16:[1,184]},{10:[1,185]},o($Vs,[2,27]),o($Vs,[2,95]),o($Vs,[2,101]),o($VX,[2,105]),o($Vs,[2,102]),{8:$V2,9:186,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{6:6,7:$V1,8:$V2,9:20,11:187,13:7,14:$V3,15:$V4,16:$V5,17:$V6,18:8,19:$V7,20:$V8,21:$V9,22:9,23:$Va,24:11,25:5,26:$Vb,28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,9:188,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{16:[1,189]},o($Vs,[2,103]),o($Vr,[2,3]),{10:[1,190]},o($Vr,[2,6]),{6:6,7:$V1,8:$V2,9:20,11:191,13:7,14:$V3,15:$V4,16:$V5,17:$V6,18:8,19:$V7,20:$V8,21:$V9,22:9,23:$Va,24:11,25:5,26:$Vb,28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},o($Vr,[2,5])],defaultActions:{3:[2,1],97:[2,84],98:[2,85],99:[2,86]},parseError:function(str,hash){if(!hash.recoverable){var error=new Error(str);throw error.hash=hash,error}this.trace(str)},parse:function(input){var self=this,stack=[0],vstack=[null],lstack=[],table=this.table,yytext="",yylineno=0,yyleng=0,recovering=0,TERROR=2,EOF=1,args=lstack.slice.call(arguments,1),lexer=Object.create(this.lexer),sharedState={yy:{}};for(var k in this.yy)Object.prototype.hasOwnProperty.call(this.yy,k)&&(sharedState.yy[k]=this.yy[k]);lexer.setInput(input,sharedState.yy),sharedState.yy.lexer=lexer,sharedState.yy.parser=this,void 0===lexer.yylloc&&(lexer.yylloc={});var yyloc=lexer.yylloc;lstack.push(yyloc);var ranges=lexer.options&&lexer.options.ranges;"function"==typeof sharedState.yy.parseError?this.parseError=sharedState.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;for(var symbol,preErrorSymbol,state,action,r,p,len,newState,expected,lex=function(){var token;return"number"!=typeof(token=lexer.lex()||EOF)&&(token=self.symbols_[token]||token),token},yyval={};;){if(state=stack[stack.length-1],this.defaultActions[state]?action=this.defaultActions[state]:(null==symbol&&(symbol=lex()),action=table[state]&&table[state][symbol]),void 0===action||!action.length||!action[0]){var errStr="";for(p in expected=[],table[state])this.terminals_[p]&&p>TERROR&&expected.push("'"+this.terminals_[p]+"'");errStr=lexer.showPosition?"Parse error on line "+(yylineno+1)+":\n"+lexer.showPosition()+"\nExpecting "+expected.join(", ")+", got '"+(this.terminals_[symbol]||symbol)+"'":"Parse error on line "+(yylineno+1)+": Unexpected "+(symbol==EOF?"end of input":"'"+(this.terminals_[symbol]||symbol)+"'"),this.parseError(errStr,{text:lexer.match,token:this.terminals_[symbol]||symbol,line:lexer.yylineno,loc:yyloc,expected:expected})}if(action[0]instanceof Array&&action.length>1)throw new Error("Parse Error: multiple actions possible at state: "+state+", token: "+symbol);switch(action[0]){case 1:stack.push(symbol),vstack.push(lexer.yytext),lstack.push(lexer.yylloc),stack.push(action[1]),symbol=null,preErrorSymbol?(symbol=preErrorSymbol,preErrorSymbol=null):(yyleng=lexer.yyleng,yytext=lexer.yytext,yylineno=lexer.yylineno,yyloc=lexer.yylloc,recovering>0&&recovering--);break;case 2:if(len=this.productions_[action[1]][1],yyval.$=vstack[vstack.length-len],yyval._$={first_line:lstack[lstack.length-(len||1)].first_line,last_line:lstack[lstack.length-1].last_line,first_column:lstack[lstack.length-(len||1)].first_column,last_column:lstack[lstack.length-1].last_column},ranges&&(yyval._$.range=[lstack[lstack.length-(len||1)].range[0],lstack[lstack.length-1].range[1]]),void 0!==(r=this.performAction.apply(yyval,[yytext,yyleng,yylineno,sharedState.yy,action[1],vstack,lstack].concat(args))))return r;len&&(stack=stack.slice(0,-1*len*2),vstack=vstack.slice(0,-1*len),lstack=lstack.slice(0,-1*len)),stack.push(this.productions_[action[1]][0]),vstack.push(yyval.$),lstack.push(yyval._$),newState=table[stack[stack.length-2]][stack[stack.length-1]],stack.push(newState);break;case 3:return!0}}return!0}},AST={node:function(type,value,children){return{type:type,value:value,children:children}},createNode:function(pos,type,value,children){var i,n=this.node(type,value,[]);for(i=3;i<arguments.length;i++)n.children.push(arguments[i]);return n.line=pos[0],n.col=pos[1],n.eline=pos[2],n.ecol=pos[3],n}},lc=function(lc1){return[lc1.first_line,lc1.first_column,lc1.last_line,lc1.last_column]},lexer=function(){var lexer={EOF:1,parseError:function(str,hash){if(!this.yy.parser)throw new Error(str);this.yy.parser.parseError(str,hash)},setInput:function(input,yy){return this.yy=yy||this.yy||{},this._input=input,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var ch=this._input[0];return this.yytext+=ch,this.yyleng++,this.offset++,this.match+=ch,this.matched+=ch,ch.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),ch},unput:function(ch){var len=ch.length,lines=ch.split(/(?:\r\n?|\n)/g);this._input=ch+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-len),this.offset-=len;var oldLines=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),lines.length-1&&(this.yylineno-=lines.length-1);var r=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:lines?(lines.length===oldLines.length?this.yylloc.first_column:0)+oldLines[oldLines.length-lines.length].length-lines[0].length:this.yylloc.first_column-len},this.options.ranges&&(this.yylloc.range=[r[0],r[0]+this.yyleng-len]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(n){this.unput(this.match.slice(n))},pastInput:function(){var past=this.matched.substr(0,this.matched.length-this.match.length);return(past.length>20?"...":"")+past.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var next=this.match;return next.length<20&&(next+=this._input.substr(0,20-next.length)),(next.substr(0,20)+(next.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var pre=this.pastInput(),c=new Array(pre.length+1).join("-");return pre+this.upcomingInput()+"\n"+c+"^"},test_match:function(match,indexed_rule){var token,lines,backup;if(this.options.backtrack_lexer&&(backup={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(backup.yylloc.range=this.yylloc.range.slice(0))),(lines=match[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=lines.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:lines?lines[lines.length-1].length-lines[lines.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+match[0].length},this.yytext+=match[0],this.match+=match[0],this.matches=match,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(match[0].length),this.matched+=match[0],token=this.performAction.call(this,this.yy,this,indexed_rule,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),token)return token;if(this._backtrack){for(var k in backup)this[k]=backup[k];return!1}return!1},next:function(){if(this.done)return this.EOF;var token,match,tempMatch,index;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var rules=this._currentRules(),i=0;i<rules.length;i++)if((tempMatch=this._input.match(this.rules[rules[i]]))&&(!match||tempMatch[0].length>match[0].length)){if(match=tempMatch,index=i,this.options.backtrack_lexer){if(!1!==(token=this.test_match(tempMatch,rules[i])))return token;if(this._backtrack){match=!1;continue}return!1}if(!this.options.flex)break}return match?!1!==(token=this.test_match(match,rules[index]))&&token:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){var r=this.next();return r||this.lex()},begin:function(condition){this.conditionStack.push(condition)},popState:function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(n){return(n=this.conditionStack.length-1-Math.abs(n||0))>=0?this.conditionStack[n]:"INITIAL"},pushState:function(condition){this.begin(condition)},stateStackSize:function(){return this.conditionStack.length},options:{},performAction:function(yy,yy_,$avoiding_name_collisions,YY_START){switch($avoiding_name_collisions){case 0:case 5:case 6:break;case 1:case 2:return 78;case 3:case 4:return 77;case 7:return 7;case 8:return 12;case 9:return 14;case 10:return 17;case 11:return 15;case 12:return 91;case 13:return 93;case 14:return 19;case 15:return 23;case 16:return 21;case 17:return 75;case 18:return 76;case 19:return 74;case 20:return 80;case 21:case 22:return 94;case 23:return 82;case 24:return 83;case 25:return 26;case 26:return 27;case 27:return 16;case 28:return"#";case 29:return 34;case 30:return 35;case 31:return 79;case 32:return 64;case 33:return 65;case 34:return 66;case 35:return 8;case 36:return 10;case 37:return 58;case 38:return 57;case 39:return 53;case 40:return 54;case 41:return 55;case 42:return 50;case 43:return 51;case 44:return 47;case 45:return 45;case 46:return 48;case 47:return 46;case 48:return 41;case 49:return 43;case 50:return 42;case 51:return 39;case 52:return 37;case 53:return 32;case 54:return 86;case 55:return 5;case 56:return 20;case 57:return"INVALID"}},rules:[/^(?:\s+)/,/^(?:[0-9]+\.[0-9]*|[0-9]*\.[0-9]+\b)/,/^(?:[0-9]+)/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:\/\/.*)/,/^(?:\/\*(.|\n|\r)*?\*\/)/,/^(?:if\b)/,/^(?:else\b)/,/^(?:while\b)/,/^(?:do\b)/,/^(?:for\b)/,/^(?:function\b)/,/^(?:map\b)/,/^(?:use\b)/,/^(?:return\b)/,/^(?:delete\b)/,/^(?:true\b)/,/^(?:false\b)/,/^(?:null\b)/,/^(?:Infinity\b)/,/^(?:->)/,/^(?:=>)/,/^(?:<<)/,/^(?:>>)/,/^(?:\{)/,/^(?:\})/,/^(?:;)/,/^(?:#)/,/^(?:\?)/,/^(?::)/,/^(?:NaN\b)/,/^(?:\.)/,/^(?:\[)/,/^(?:\])/,/^(?:\()/,/^(?:\))/,/^(?:!)/,/^(?:\^)/,/^(?:\*)/,/^(?:\/)/,/^(?:%)/,/^(?:\+)/,/^(?:-)/,/^(?:<=)/,/^(?:<)/,/^(?:>=)/,/^(?:>)/,/^(?:==)/,/^(?:~=)/,/^(?:!=)/,/^(?:&&)/,/^(?:\|\|)/,/^(?:=)/,/^(?:,)/,/^(?:$)/,/^(?:[A-Za-z_\$][A-Za-z0-9_]*)/,/^(?:.)/],conditions:{INITIAL:{rules:[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57],inclusive:!0}}};return lexer}();function Parser(){this.yy={}}return parser.lexer=lexer,Parser.prototype=parser,parser.Parser=Parser,new Parser}();return void 0!==require&&"undefined"!=typeof exports&&(exports.parser=parser,exports.Parser=parser.Parser,exports.parse=function(){return parser.parse.apply(parser,arguments)},exports.main=function(args){args[1]||(console.log("Usage: "+args[0]+" FILE"),process.exit(1));var source=require("fs").readFileSync(require("path").normalize(args[1]),"utf8");return exports.parser.parse(source)},"undefined"!=typeof module&&require.main===module&&exports.main(process.argv.slice(1))),parser.yy.parseError=parser.parseError,JXG.JessieCode})),define("base/composition",["jxg","utils/type"],(function(JXG,Type){return JXG.Composition=function(elements){var e,that=this,genericMethods=["setAttribute","setParents","prepareUpdate","updateRenderer","update","fullUpdate","highlight","noHighlight"],generateMethod=function(what){return function(){var i;for(i in that.elements)that.elements.hasOwnProperty(i)&&Type.exists(that.elements[i][what])&&that.elements[i][what].apply(that.elements[i],arguments);return that}};for(e=0;e<genericMethods.length;e++)this[genericMethods[e]]=generateMethod(genericMethods[e]);for(e in this.elements={},this.objects=this.elements,this.elementsByName={},this.objectsList=[],this.groups={},this.methodMap={setAttribute:"setAttribute",setProperty:"setAttribute",setParents:"setParents",add:"add",remove:"remove",select:"select"},elements)elements.hasOwnProperty(e)&&this.add(e,elements[e]);this.dump=!0,this.subs={}},JXG.extend(JXG.Composition.prototype,{add:function(what,element){return!(Type.exists(this[what])||!Type.exists(element))&&(Type.exists(element.id)?this.elements[element.id]=element:this.elements[what]=element,Type.exists(element.name)&&(this.elementsByName[element.name]=element),element.on("attribute:name",this.nameListener,this),this.objectsList.push(element),this[what]=element,this.methodMap[what]=element,!0)},remove:function(what){var e,found=!1;for(e in this.elements)if(this.elements.hasOwnProperty(e)&&this.elements[e].id===this[what].id){found=!0;break}return found&&(delete this.elements[this[what].id],delete this[what]),found},nameListener:function(oval,nval,el){delete this.elementsByName[oval],this.elementsByName[nval]=el},select:function(filter){return Type.exists(JXG.Board)?JXG.Board.prototype.select.call(this,filter):new JXG.Composition},getParents:function(){return this.parents},getType:function(){return this.elType},getAttributes:function(){var e,attr={};for(e in this.subs)this.subs.hasOwnProperty(e)&&(attr[e]=this.subs[e].visProp);return this.attr}}),JXG.Composition})),define("base/board",["jxg","base/constants","base/coords","options","math/numerics","math/math","math/geometry","math/complex","math/statistics","parser/jessiecode","utils/color","utils/type","utils/event","utils/env","base/composition"],(function(JXG,Const,Coords,Options,Numerics,Mat,Geometry,Complex,Statistics,JessieCode,Color,Type,EventEmitter,Env,Composition){return JXG.Board=function(container,renderer,id,origin,zoomX,zoomY,unitX,unitY,canvasWidth,canvasHeight,attributes){if(this.BOARD_MODE_NONE=0,this.BOARD_MODE_DRAG=1,this.BOARD_MODE_MOVE_ORIGIN=2,this.BOARD_MODE_ZOOM=17,this.BOARD_QUALITY_LOW=1,this.BOARD_QUALITY_HIGH=2,Type.exists(attributes.document)&&!1!==attributes.document?this.document=attributes.document:void 0!==document&&Type.isObject(document)&&(this.document=document),this.container=container,this.containerObj=Env.isBrowser?this.document.getElementById(this.container):null,Env.isBrowser&&"no"!==renderer.type&&null===this.containerObj)throw new Error("\nJSXGraph: HTML container element '"+container+"' not found.");this.renderer=renderer,this.grids=[],this.options=Type.deepCopy(Options),this.attr=attributes,this.dimension=2,this.jc=new JessieCode,this.jc.use(this),this.origin={},this.origin.usrCoords=[1,0,0],this.origin.scrCoords=[1,origin[0],origin[1]],this.zoomX=zoomX,this.zoomY=zoomY,this.unitX=unitX*this.zoomX,this.unitY=unitY*this.zoomY,this.keepaspectratio=!1,this.canvasWidth=canvasWidth,this.canvasHeight=canvasHeight,Type.exists(id)&&""!==id&&Env.isBrowser&&!Type.exists(this.document.getElementById(id))?this.id=id:this.id=this.generateId(),EventEmitter.eventify(this),this.hooks=[],this.dependentBoards=[],this.inUpdate=!1,this.objects={},this.objectsList=[],this.groups={},this.animationObjects={},this.highlightedObjects={},this.numObjects=0,this.elementsByName={},this.mode=this.BOARD_MODE_NONE,this.updateQuality=this.BOARD_QUALITY_HIGH,this.isSuspendedRedraw=!1,this.calculateSnapSizes(),this.drag_dx=0,this.drag_dy=0,this.drag_position=[0,0],this.mouse={},this.touches=[],this.xmlString="",this.cPos=[],this.touchMoveLast=0,this.touchMoveLastId=1/0,this.positionAccessLast=0,this.downObjects=[],this.attr.showcopyright&&this.renderer.displayCopyright(Const.licenseText,parseInt(this.options.text.fontSize,10)),this.needsFullUpdate=!1,this.reducedUpdate=!1,this.currentCBDef="none",this.geonextCompatibilityMode=!1,this.options.text.useASCIIMathML&&translateASCIIMath?init():this.options.text.useASCIIMathML=!1,this.hasMouseHandlers=!1,this.hasTouchHandlers=!1,this.hasPointerHandlers=!1,this.hasMouseUp=!1,this.hasTouchEnd=!1,this.hasPointerUp=!1,this._drag_offset=[0,0],this._inputDevice="mouse",this._board_touches=[],this.selectingMode=!1,this.isSelecting=!1,this._isScrolling=!1,this._isResizing=!1,this.selectingBox=[[0,0],[0,0]],this.mathLib=Math,this.mathLibJXG=JXG.Math,this.attr.registerevents&&this.addEventHandlers(),this.methodMap={update:"update",fullUpdate:"fullUpdate",on:"on",off:"off",trigger:"trigger",setView:"setBoundingBox",setBoundingBox:"setBoundingBox",migratePoint:"migratePoint",colorblind:"emulateColorblindness",suspendUpdate:"suspendUpdate",unsuspendUpdate:"unsuspendUpdate",clearTraces:"clearTraces",left:"clickLeftArrow",right:"clickRightArrow",up:"clickUpArrow",down:"clickDownArrow",zoomIn:"zoomIn",zoomOut:"zoomOut",zoom100:"zoom100",zoomElements:"zoomElements",remove:"removeObject",removeObject:"removeObject"}},JXG.extend(JXG.Board.prototype,{generateName:function(object){var possibleNames,i,maxNameLength=this.attr.maxnamelength,pre="",post="",indices=[],name="";if(object.type===Const.OBJECT_TYPE_TICKS)return"";for(possibleNames=Type.isPoint(object)?["","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"]:object.type===Const.OBJECT_TYPE_ANGLE?["","α","β","γ","δ","ε","ζ","η","θ","ι","κ","λ","μ","ν","ξ","ο","π","ρ","σ","τ","υ","φ","χ","ψ","ω"]:["","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"],Type.isPoint(object)||object.elementClass===Const.OBJECT_CLASS_LINE||object.type===Const.OBJECT_TYPE_ANGLE||(pre=object.type===Const.OBJECT_TYPE_POLYGON?"P_{":object.elementClass===Const.OBJECT_CLASS_CIRCLE?"k_{":object.elementClass===Const.OBJECT_CLASS_TEXT?"t_{":"s_{",post="}"),i=0;i<maxNameLength;i++)indices[i]=0;for(;indices[maxNameLength-1]<possibleNames.length;){for(indices[0]=1;indices[0]<possibleNames.length;indices[0]++){for(name=pre,i=maxNameLength;i>0;i--)name+=possibleNames[indices[i-1]];if(!Type.exists(this.elementsByName[name+post]))return name+post}for(indices[0]=possibleNames.length,i=1;i<maxNameLength;i++)indices[i-1]===possibleNames.length&&(indices[i-1]=1,indices[i]+=1)}return""},generateId:function(){for(var r=1;Type.exists(JXG.boards["jxgBoard"+r]);)r=Math.round(65535*Math.random());return"jxgBoard"+r},setId:function(obj,type){var randomNumber,num=this.numObjects,elId=obj.id;if(this.numObjects+=1,""===elId||!Type.exists(elId))for(elId=this.id+type+num;Type.exists(this.objects[elId]);)randomNumber=Math.round(65535*Math.random()),elId=this.id+type+num+"-"+randomNumber;return obj.id=elId,this.objects[elId]=obj,obj._pos=this.objectsList.length,this.objectsList[this.objectsList.length]=obj,elId},finalizeAdding:function(obj){!1===Type.evaluate(obj.visProp.visible)&&this.renderer.display(obj,!1)},finalizeLabel:function(obj){obj.hasLabel&&!Type.evaluate(obj.label.visProp.islabel)&&!1===Type.evaluate(obj.label.visProp.visible)&&this.renderer.display(obj.label,!1)},checkFrameRate:function(evt){var handleEvt=!1,time=(new Date).getTime();return Type.exists(evt.pointerId)&&this.touchMoveLastId!==evt.pointerId&&(handleEvt=!0,this.touchMoveLastId=evt.pointerId),!handleEvt&&(time-this.touchMoveLast)*this.attr.maxframerate>=1e3&&(handleEvt=!0),handleEvt&&(this.touchMoveLast=time),handleEvt},getCoordsTopLeftCorner:function(){var cPos,doc,crect,zoom,o,ownerDoc=this.document.ownerDocument||this.document,docElement=ownerDoc.documentElement||this.document.body.parentNode,docBody=ownerDoc.body,container=this.containerObj;if(this.cPos.length>0&&(this.mode===this.BOARD_MODE_DRAG||this.mode===this.BOARD_MODE_MOVE_ORIGIN||(new Date).getTime()-this.positionAccessLast<1e3))return this.cPos;if(this.positionAccessLast=(new Date).getTime(),container.getBoundingClientRect){for(crect=container.getBoundingClientRect(),zoom=1,o=container;o&&Type.exists(o.parentNode);)Type.exists(o.style)&&Type.exists(o.style.zoom)&&""!==o.style.zoom&&(zoom*=parseFloat(o.style.zoom)),o=o.parentNode;return(cPos=[crect.left*zoom,crect.top*zoom])[0]+=Env.getProp(container,"border-left-width"),cPos[1]+=Env.getProp(container,"border-top-width"),"vml"!==this.renderer.type&&(cPos[0]+=Env.getProp(container,"padding-left"),cPos[1]+=Env.getProp(container,"padding-top")),this.cPos=cPos.slice(),this.cPos}return cPos=Env.getOffset(container),doc=this.document.documentElement.ownerDocument,!this.containerObj.currentStyle&&doc.defaultView&&(cPos[0]+=Env.getProp(docElement,"margin-left"),cPos[1]+=Env.getProp(docElement,"margin-top"),cPos[0]+=Env.getProp(docElement,"border-left-width"),cPos[1]+=Env.getProp(docElement,"border-top-width"),cPos[0]+=Env.getProp(docElement,"padding-left"),cPos[1]+=Env.getProp(docElement,"padding-top")),docBody&&(cPos[0]+=Env.getProp(docBody,"left"),cPos[1]+=Env.getProp(docBody,"top")),"object"===("undefined"==typeof google?"undefined":_typeof(google))&&google.translate&&(cPos[0]+=10,cPos[1]+=25),cPos[0]+=Env.getProp(container,"border-left-width"),cPos[1]+=Env.getProp(container,"border-top-width"),"vml"!==this.renderer.type&&(cPos[0]+=Env.getProp(container,"padding-left"),cPos[1]+=Env.getProp(container,"padding-top")),cPos[0]+=this.attr.offsetx,cPos[1]+=this.attr.offsety,this.cPos=cPos.slice(),this.cPos},getMousePosition:function(e,i){var absPos,v,cPos=this.getCoordsTopLeftCorner();return absPos=Env.getPosition(e,i,this.document),Type.exists(this.cssTransMat)||this.updateCSSTransforms(),v=[1,absPos[0]-cPos[0],absPos[1]-cPos[1]],(v=Mat.matVecMult(this.cssTransMat,v))[1]/=v[0],v[2]/=v[0],[v[1],v[2]]},initMoveOrigin:function(x,y){this.drag_dx=x-this.origin.scrCoords[1],this.drag_dy=y-this.origin.scrCoords[2],this.mode=this.BOARD_MODE_MOVE_ORIGIN,this.updateQuality=this.BOARD_QUALITY_LOW},initMoveObject:function(x,y,evt,type){var pEl,el,haspoint,collect=[],offset=[],len=this.objectsList.length,dragEl={visProp:{layer:-1e4}};for(el=0;el<len;el++)haspoint=(pEl=this.objectsList[el]).hasPoint&&pEl.hasPoint(x,y),pEl.visPropCalc.visible&&haspoint&&(pEl.triggerEventHandlers([type+"down","down"],[evt]),this.downObjects.push(pEl)),haspoint&&pEl.isDraggable&&pEl.visPropCalc.visible&&(this.geonextCompatibilityMode&&(Type.isPoint(pEl)||pEl.elementClass===Const.OBJECT_CLASS_TEXT)||!this.geonextCompatibilityMode)&&!Type.evaluate(pEl.visProp.fixed)&&(pEl.visProp.layer>dragEl.visProp.layer||pEl.visProp.layer===dragEl.visProp.layer&&pEl.lastDragTime.getTime()>=dragEl.lastDragTime.getTime())&&(this.attr.ignorelabels&&Type.exists(dragEl.label)&&pEl===dragEl.label||(dragEl=pEl,collect.push(dragEl),Type.exists(dragEl.coords)?offset.push(Statistics.subtract(dragEl.coords.scrCoords.slice(1),[x,y])):offset.push([0,0])));return this.attr.drag.enabled&&collect.length>0&&(this.mode=this.BOARD_MODE_DRAG),this.attr.takefirst?(collect.length=1,this._drag_offset=offset[0]):(collect=collect.slice(-1),this._drag_offset=offset[offset.length-1]),this._drag_offset||(this._drag_offset=[0,0]),"svg"===this.renderer.type&&Type.exists(collect[0])&&Type.evaluate(collect[0].visProp.dragtotopoflayer)&&1===collect.length&&Type.exists(collect[0].rendNode)&&collect[0].rendNode.parentNode.appendChild(collect[0].rendNode),this.previousRotation=0,this.previousScale=1,collect.length>=1&&(collect[0].highlight(!0),this.triggerEventHandlers(["mousehit","hit"],[evt,collect[0]])),collect},moveObject:function(x,y,o,evt,type){var drag,dragScrCoords,newDragScrCoords,newPos=new Coords(Const.COORDS_BY_SCREEN,this.getScrCoordsOfMouse(x,y),this);o&&o.obj&&((drag=o.obj).coords&&(dragScrCoords=drag.coords.scrCoords.slice()),this.drag_position=[newPos.scrCoords[1],newPos.scrCoords[2]],this.drag_position=Statistics.add(this.drag_position,this._drag_offset),Type.exists(drag.coords)?drag.setPositionDirectly(Const.COORDS_BY_SCREEN,this.drag_position):(this.displayInfobox(!1),isNaN(o.targets[0].Xprev+o.targets[0].Yprev)||drag.setPositionDirectly(Const.COORDS_BY_SCREEN,[newPos.scrCoords[1],newPos.scrCoords[2]],[o.targets[0].Xprev,o.targets[0].Yprev]),o.targets[0].Xprev=newPos.scrCoords[1],o.targets[0].Yprev=newPos.scrCoords[2]),Type.exists(drag.coords)&&(drag.prepareUpdate().update(!1).updateRenderer(),this.updateInfobox(drag),drag.prepareUpdate().update(!0).updateRenderer()),drag.coords&&(newDragScrCoords=drag.coords.scrCoords),drag.coords&&dragScrCoords[1]===newDragScrCoords[1]&&dragScrCoords[2]===newDragScrCoords[2]||(drag.triggerEventHandlers([type+"drag","drag"],[evt]),this.update()),drag.highlight(!0),this.triggerEventHandlers(["mousehit","hit"],[evt,drag]),drag.lastDragTime=new Date)},twoFingerMove:function(o,id,evt){var drag;Type.exists(o)&&Type.exists(o.obj)&&((drag=o.obj).elementClass===Const.OBJECT_CLASS_LINE||drag.type===Const.OBJECT_TYPE_POLYGON?this.twoFingerTouchObject(o.targets,drag,id):drag.elementClass===Const.OBJECT_CLASS_CIRCLE&&this.twoFingerTouchCircle(o.targets,drag,id),evt&&drag.triggerEventHandlers(["touchdrag","drag"],[evt]))},twoFingerTouchObject:function(tar,drag,id){var np,op,nd,od,d,alpha,S,t1,t3,t4,t5,ar,i,len,fixEl,moveEl,fix;if(Type.exists(tar[0])&&Type.exists(tar[1])&&!isNaN(tar[0].Xprev+tar[0].Yprev+tar[1].Xprev+tar[1].Yprev)){if(id===tar[0].num?(fixEl=tar[1],moveEl=tar[0]):(fixEl=tar[0],moveEl=tar[1]),fix=new Coords(Const.COORDS_BY_SCREEN,[fixEl.Xprev,fixEl.Yprev],this).usrCoords,op=new Coords(Const.COORDS_BY_SCREEN,[moveEl.Xprev,moveEl.Yprev],this).usrCoords,np=new Coords(Const.COORDS_BY_SCREEN,[moveEl.X,moveEl.Y],this).usrCoords,od=Mat.crossProduct(fix,op),nd=Mat.crossProduct(fix,np),S=Mat.crossProduct(od,nd),Math.abs(S[0])<Mat.eps)return;if(alpha=Geometry.rad(op.slice(1),fix.slice(1),np.slice(1)),(t1=this.create("transform",[alpha,[fix[1],fix[2]]],{type:"rotate"})).update(),Type.evaluate(drag.visProp.scalable)&&(d=Geometry.distance(np,fix)/Geometry.distance(op,fix),t3=this.create("transform",[-fix[1],-fix[2]],{type:"translate"}),t4=this.create("transform",[d,d],{type:"scale"}),t5=this.create("transform",[fix[1],fix[2]],{type:"translate"}),t1.melt(t3).melt(t4).melt(t5)),drag.elementClass===Const.OBJECT_CLASS_LINE)ar=[],drag.point1.draggable()&&ar.push(drag.point1),drag.point2.draggable()&&ar.push(drag.point2),t1.applyOnce(ar);else if(drag.type===Const.OBJECT_TYPE_POLYGON){for(ar=[],len=drag.vertices.length-1,i=0;i<len;++i)drag.vertices[i].draggable()&&ar.push(drag.vertices[i]);t1.applyOnce(ar)}this.update(),drag.highlight(!0)}},twoFingerTouchCircle:function(tar,drag,id){var fixEl,moveEl,np,op,fix,d,alpha,t1,t2,t3,t4;"pointCircle"!==drag.method&&"pointLine"!==drag.method&&Type.exists(tar[0])&&Type.exists(tar[1])&&!isNaN(tar[0].Xprev+tar[0].Yprev+tar[1].Xprev+tar[1].Yprev)&&(id===tar[0].num?(fixEl=tar[1],moveEl=tar[0]):(fixEl=tar[0],moveEl=tar[1]),fix=new Coords(Const.COORDS_BY_SCREEN,[fixEl.Xprev,fixEl.Yprev],this).usrCoords,op=new Coords(Const.COORDS_BY_SCREEN,[moveEl.Xprev,moveEl.Yprev],this).usrCoords,np=new Coords(Const.COORDS_BY_SCREEN,[moveEl.X,moveEl.Y],this).usrCoords,alpha=Geometry.rad(op.slice(1),fix.slice(1),np.slice(1)),t1=this.create("transform",[-fix[1],-fix[2]],{type:"translate"}),t2=this.create("transform",[alpha],{type:"rotate"}),t1.melt(t2),Type.evaluate(drag.visProp.scalable)&&(d=Geometry.distance(fix,np)/Geometry.distance(fix,op),t3=this.create("transform",[d,d],{type:"scale"}),t1.melt(t3)),t4=this.create("transform",[fix[1],fix[2]],{type:"translate"}),t1.melt(t4),drag.center.draggable()&&t1.applyOnce([drag.center]),"twoPoints"===drag.method?drag.point2.draggable()&&t1.applyOnce([drag.point2]):"pointRadius"===drag.method&&Type.isNumber(drag.updateRadius.origin)&&drag.setRadius(drag.radius*d),this.update(drag.center),drag.highlight(!0))},highlightElements:function(x,y,evt,target){var el,pEl,pId,overObjects={},len=this.objectsList.length;for(el=0;el<len;el++)pId=(pEl=this.objectsList[el]).id,Type.exists(pEl.hasPoint)&&pEl.visPropCalc.visible&&pEl.hasPoint(x,y)&&(this.updateInfobox(pEl),Type.exists(this.highlightedObjects[pId])||(overObjects[pId]=pEl,pEl.highlight(),this.triggerEventHandlers(["mousehit","hit"],[evt,pEl,target])),pEl.mouseover?pEl.triggerEventHandlers(["mousemove","move"],[evt]):(pEl.triggerEventHandlers(["mouseover","over"],[evt]),pEl.mouseover=!0));for(el=0;el<len;el++)pId=(pEl=this.objectsList[el]).id,pEl.mouseover&&(overObjects[pId]||(pEl.triggerEventHandlers(["mouseout","out"],[evt]),pEl.mouseover=!1))},saveStartPos:function(obj,targets){var i,len,xy=[];if(obj.type===Const.OBJECT_TYPE_TICKS)xy.push([1,NaN,NaN]);else if(obj.elementClass===Const.OBJECT_CLASS_LINE)xy.push(obj.point1.coords.usrCoords),xy.push(obj.point2.coords.usrCoords);else if(obj.elementClass===Const.OBJECT_CLASS_CIRCLE)xy.push(obj.center.coords.usrCoords),"twoPoints"===obj.method&&xy.push(obj.point2.coords.usrCoords);else if(obj.type===Const.OBJECT_TYPE_POLYGON)for(len=obj.vertices.length-1,i=0;i<len;i++)xy.push(obj.vertices[i].coords.usrCoords);else if(obj.type===Const.OBJECT_TYPE_SECTOR)xy.push(obj.point1.coords.usrCoords),xy.push(obj.point2.coords.usrCoords),xy.push(obj.point3.coords.usrCoords);else if(Type.isPoint(obj)||obj.type===Const.OBJECT_TYPE_GLIDER)xy.push(obj.coords.usrCoords);else if(obj.elementClass===Const.OBJECT_CLASS_CURVE)obj.points.length>0&&xy.push(obj.points[0].usrCoords);else try{xy.push(obj.coords.usrCoords)}catch(e){JXG.debug("JSXGraph+ saveStartPos: obj.coords.usrCoords not available: "+e)}for(len=xy.length,i=0;i<len;i++)targets.Zstart.push(xy[i][0]),targets.Xstart.push(xy[i][1]),targets.Ystart.push(xy[i][2])},mouseOriginMoveStart:function(evt){var r,pos;return(r=this._isRequiredKeyPressed(evt,"pan"))&&(pos=this.getMousePosition(evt),this.initMoveOrigin(pos[0],pos[1])),r},mouseOriginMove:function(evt){var pos,r=this.mode===this.BOARD_MODE_MOVE_ORIGIN;return r&&(pos=this.getMousePosition(evt),this.moveOrigin(pos[0],pos[1],!0)),r},touchStartMoveOriginOneFinger:function(evt){var conditions,pos,touches=evt[JXG.touchProperty];return(conditions=this.attr.pan.enabled&&!this.attr.pan.needtwofingers&&1===touches.length)&&(pos=this.getMousePosition(evt,0),this.initMoveOrigin(pos[0],pos[1])),conditions},touchOriginMove:function(evt){var pos,r=this.mode===this.BOARD_MODE_MOVE_ORIGIN;return r&&(pos=this.getMousePosition(evt,0),this.moveOrigin(pos[0],pos[1],!0)),r},originMoveEnd:function(){this.updateQuality=this.BOARD_QUALITY_HIGH,this.mode=this.BOARD_MODE_NONE},addEventHandlers:function(){if(Env.supportsPointerEvents()?this.addPointerEventHandlers():(this.addMouseEventHandlers(),this.addTouchEventHandlers()),null!==this.containerObj&&(this.containerObj.oncontextmenu=function(e){return Type.exists(e)&&e.preventDefault(),!1}),this.addFullscreenEventHandlers(),this.addKeyboardEventHandlers(),Env.isBrowser){try{this.startResizeObserver()}catch(err){Env.addEvent(window,"resize",this.resizeListener,this),this.startIntersectionObserver()}Env.addEvent(window,"scroll",this.scrollListener,this)}},removeEventHandlers:function(){this.removeMouseEventHandlers(),this.removeTouchEventHandlers(),this.removePointerEventHandlers(),this.removeFullscreenEventHandlers(),this.removeKeyboardEventHandlers(),Env.isBrowser&&(Type.exists(this.resizeObserver)?this.stopResizeObserver():(Env.removeEvent(window,"resize",this.resizeListener,this),this.stopIntersectionObserver()),Env.removeEvent(window,"scroll",this.scrollListener,this))},addPointerEventHandlers:function(){if(!this.hasPointerHandlers&&Env.isBrowser){var moveTarget=this.attr.movetarget||this.containerObj;window.navigator.msPointerEnabled?(Env.addEvent(this.containerObj,"MSPointerDown",this.pointerDownListener,this),Env.addEvent(moveTarget,"MSPointerMove",this.pointerMoveListener,this)):(Env.addEvent(this.containerObj,"pointerdown",this.pointerDownListener,this),Env.addEvent(moveTarget,"pointermove",this.pointerMoveListener,this)),Env.addEvent(this.containerObj,"mousewheel",this.mouseWheelListener,this),Env.addEvent(this.containerObj,"DOMMouseScroll",this.mouseWheelListener,this),null!==this.containerObj&&(this.containerObj.style.touchAction="none"),this.hasPointerHandlers=!0}},addMouseEventHandlers:function(){if(!this.hasMouseHandlers&&Env.isBrowser){var moveTarget=this.attr.movetarget||this.containerObj;Env.addEvent(this.containerObj,"mousedown",this.mouseDownListener,this),Env.addEvent(moveTarget,"mousemove",this.mouseMoveListener,this),Env.addEvent(this.containerObj,"mousewheel",this.mouseWheelListener,this),Env.addEvent(this.containerObj,"DOMMouseScroll",this.mouseWheelListener,this),this.hasMouseHandlers=!0}},addTouchEventHandlers:function(appleGestures){if(!this.hasTouchHandlers&&Env.isBrowser){var moveTarget=this.attr.movetarget||this.containerObj;Env.addEvent(this.containerObj,"touchstart",this.touchStartListener,this),Env.addEvent(moveTarget,"touchmove",this.touchMoveListener,this),this.hasTouchHandlers=!0}},addFullscreenEventHandlers:function(){var i,events=["fullscreenchange","mozfullscreenchange","webkitfullscreenchange","msfullscreenchange"],le=events.length;if(!this.hasFullsceenEventHandlers&&Env.isBrowser){for(i=0;i<le;i++)Env.addEvent(this.document,events[i],this.fullscreenListener,this);this.hasFullsceenEventHandlers=!0}},addKeyboardEventHandlers:function(){this.attr.keyboard.enabled&&!this.hasKeyboardHandlers&&Env.isBrowser&&(Env.addEvent(this.containerObj,"keydown",this.keyDownListener,this),Env.addEvent(this.containerObj,"focusin",this.keyFocusInListener,this),Env.addEvent(this.containerObj,"focusout",this.keyFocusOutListener,this),this.hasKeyboardHandlers=!0)},removeKeyboardEventHandlers:function(){this.hasKeyboardHandlers&&Env.isBrowser&&(Env.removeEvent(this.containerObj,"keydown",this.keyDownListener,this),Env.removeEvent(this.containerObj,"focusin",this.keyFocusInListener,this),Env.removeEvent(this.containerObj,"focusout",this.keyFocusOutListener,this),this.hasKeyboardHandlers=!1)},removeFullscreenEventHandlers:function(){var i,events=["fullscreenchange","mozfullscreenchange","webkitfullscreenchange","msfullscreenchange"],le=events.length;if(this.hasFullsceenEventHandlers&&Env.isBrowser){for(i=0;i<le;i++)Env.removeEvent(this.document,events[i],this.fullscreenListener,this);this.hasFullsceenEventHandlers=!1}},removePointerEventHandlers:function(){if(this.hasPointerHandlers&&Env.isBrowser){var moveTarget=this.attr.movetarget||this.containerObj;window.navigator.msPointerEnabled?(Env.removeEvent(this.containerObj,"MSPointerDown",this.pointerDownListener,this),Env.removeEvent(moveTarget,"MSPointerMove",this.pointerMoveListener,this)):(Env.removeEvent(this.containerObj,"pointerdown",this.pointerDownListener,this),Env.removeEvent(moveTarget,"pointermove",this.pointerMoveListener,this)),Env.removeEvent(this.containerObj,"mousewheel",this.mouseWheelListener,this),Env.removeEvent(this.containerObj,"DOMMouseScroll",this.mouseWheelListener,this),this.hasPointerUp&&(window.navigator.msPointerEnabled?Env.removeEvent(this.document,"MSPointerUp",this.pointerUpListener,this):(Env.removeEvent(this.document,"pointerup",this.pointerUpListener,this),Env.removeEvent(this.document,"pointercancel",this.pointerUpListener,this)),this.hasPointerUp=!1),this.hasPointerHandlers=!1}},removeMouseEventHandlers:function(){if(this.hasMouseHandlers&&Env.isBrowser){var moveTarget=this.attr.movetarget||this.containerObj;Env.removeEvent(this.containerObj,"mousedown",this.mouseDownListener,this),Env.removeEvent(moveTarget,"mousemove",this.mouseMoveListener,this),this.hasMouseUp&&(Env.removeEvent(this.document,"mouseup",this.mouseUpListener,this),this.hasMouseUp=!1),Env.removeEvent(this.containerObj,"mousewheel",this.mouseWheelListener,this),Env.removeEvent(this.containerObj,"DOMMouseScroll",this.mouseWheelListener,this),this.hasMouseHandlers=!1}},removeTouchEventHandlers:function(){if(this.hasTouchHandlers&&Env.isBrowser){var moveTarget=this.attr.movetarget||this.containerObj;Env.removeEvent(this.containerObj,"touchstart",this.touchStartListener,this),Env.removeEvent(moveTarget,"touchmove",this.touchMoveListener,this),this.hasTouchEnd&&(Env.removeEvent(this.document,"touchend",this.touchEndListener,this),this.hasTouchEnd=!1),this.hasTouchHandlers=!1}},clickLeftArrow:function(){return this.moveOrigin(this.origin.scrCoords[1]+.1*this.canvasWidth,this.origin.scrCoords[2]),this},clickRightArrow:function(){return this.moveOrigin(this.origin.scrCoords[1]-.1*this.canvasWidth,this.origin.scrCoords[2]),this},clickUpArrow:function(){return this.moveOrigin(this.origin.scrCoords[1],this.origin.scrCoords[2]-.1*this.canvasHeight),this},clickDownArrow:function(){return this.moveOrigin(this.origin.scrCoords[1],this.origin.scrCoords[2]+.1*this.canvasHeight),this},gestureChangeListener:function(evt){var c,dir1,dir2,angle,factor,dist,dx,dy,theta,cx,cy,bound,isPinch=!1,zx=this.attr.zoom.factorx,zy=this.attr.zoom.factory;return this.mode!==this.BOARD_MODE_ZOOM||(evt.preventDefault(),dist=Geometry.distance([evt.touches[0].clientX,evt.touches[0].clientY],[evt.touches[1].clientX,evt.touches[1].clientY],2),void 0===evt.scale&&(evt.scale=dist/this.prevDist),!!Type.exists(this.prevCoords)&&(dir1=[evt.touches[0].clientX-this.prevCoords[0][0],evt.touches[0].clientY-this.prevCoords[0][1]],dir2=[evt.touches[1].clientX-this.prevCoords[1][0],evt.touches[1].clientY-this.prevCoords[1][1]],dir1[0]*dir1[0]+dir1[1]*dir1[1]<100&&dir2[0]*dir2[0]+dir2[1]*dir2[1]<100||(angle=Geometry.rad(dir1,[0,0],dir2),"pan"!==this.isPreviousGesture&&Math.abs(angle)>.2*Math.PI&&Math.abs(angle)<1.8*Math.PI&&(isPinch=!0),"pan"===this.isPreviousGesture||isPinch||(Math.abs(evt.scale)<.77||Math.abs(evt.scale)>1.3)&&(isPinch=!0),factor=evt.scale/this.prevScale,this.prevScale=evt.scale,this.prevCoords=[[evt.touches[0].clientX,evt.touches[0].clientY],[evt.touches[1].clientX,evt.touches[1].clientY]],c=new Coords(Const.COORDS_BY_SCREEN,this.getMousePosition(evt,0),this),this.attr.pan.enabled&&this.attr.pan.needtwofingers&&!isPinch?(this.isPreviousGesture="pan",this.moveOrigin(c.scrCoords[1],c.scrCoords[2],!0)):this.attr.zoom.enabled&&Math.abs(factor-1)<.5&&((this.attr.zoom.pinchhorizontal||this.attr.zoom.pinchvertical)&&(dx=Math.abs(evt.touches[0].clientX-evt.touches[1].clientX),dy=Math.abs(evt.touches[0].clientY-evt.touches[1].clientY),theta=Math.abs(Math.atan2(dy,dx)),bound=Math.PI*this.attr.zoom.pinchsensitivity/90),this.attr.zoom.pinchhorizontal&&theta<bound?(this.attr.zoom.factorx=factor,this.attr.zoom.factory=1,cx=0,cy=0):this.attr.zoom.pinchvertical&&Math.abs(theta-.5*Math.PI)<bound?(this.attr.zoom.factorx=1,this.attr.zoom.factory=factor,cx=0,cy=0):(this.attr.zoom.factorx=factor,this.attr.zoom.factory=factor,cx=c.usrCoords[1],cy=c.usrCoords[2]),this.zoomIn(cx,cy),this.attr.zoom.factorx=zx,this.attr.zoom.factory=zy)),!1))},gestureStartListener:function(evt){var pos;return evt.preventDefault(),this.prevScale=1,this.prevDist=Geometry.distance([evt.touches[0].clientX,evt.touches[0].clientY],[evt.touches[1].clientX,evt.touches[1].clientY],2),this.prevCoords=[[evt.touches[0].clientX,evt.touches[0].clientY],[evt.touches[1].clientX,evt.touches[1].clientY]],this.isPreviousGesture="none",pos=this.getMousePosition(evt,0),this.initMoveOrigin(pos[0],pos[1]),this.mode=this.BOARD_MODE_ZOOM,!1},_isRequiredKeyPressed:function(evt,action){var obj=this.attr[action];return!!obj.enabled&&!(!(obj.needshift&&evt.shiftKey||!obj.needshift&&!evt.shiftKey)||!(obj.needctrl&&evt.ctrlKey||!obj.needctrl&&!evt.ctrlKey))},_isPointerRegistered:function(evt){var i,len=this._board_touches.length;for(i=0;i<len;i++)if(this._board_touches[i].pointerId===evt.pointerId)return!0;return!1},_pointerStorePosition:function(evt){var i,found;for(i=0,found=!1;i<this._board_touches.length;i++)if(this._board_touches[i].pointerId===evt.pointerId){this._board_touches[i].clientX=evt.clientX,this._board_touches[i].clientY=evt.clientY,found=!0;break}return!found&&this._board_touches.length<2&&this._board_touches.push({pointerId:evt.pointerId,clientX:evt.clientX,clientY:evt.clientY}),this},_pointerRemoveTouches:function(evt){var i;for(i=0;i<this._board_touches.length;i++)if(this._board_touches[i].pointerId===evt.pointerId){this._board_touches.splice(i,1);break}return this},_pointerClearTouches:function(){this._board_touches.length>0&&this.dehighlightAll(),this.updateQuality=this.BOARD_QUALITY_HIGH,this.mode=this.BOARD_MODE_NONE,this._board_touches=[],this.touches=[]},_getPointerInputDevice:function(evt){if(Env.isBrowser){if("touch"===evt.pointerType||window.navigator.msMaxTouchPoints&&window.navigator.msMaxTouchPoints>1)return"touch";if("mouse"===evt.pointerType)return"mouse";if("pen"===evt.pointerType)return"pen"}return"mouse"},pointerDownListener:function(evt,object){var i,j,k,pos,elements,sel,target_obj,type,found,target;if(!object&&this._isPointerRegistered(evt))return!1;if(!object&&evt.isPrimary&&this._pointerClearTouches(),this.hasPointerUp||(window.navigator.msPointerEnabled?Env.addEvent(this.document,"MSPointerUp",this.pointerUpListener,this):(Env.addEvent(this.document,"pointerup",this.pointerUpListener,this),Env.addEvent(this.document,"pointercancel",this.pointerUpListener,this)),this.hasPointerUp=!0),this.hasMouseHandlers&&this.removeMouseEventHandlers(),this.hasTouchHandlers&&this.removeTouchEventHandlers(),this.document.selection&&Type.isFunction(this.document.selection.empty))this.document.selection.empty();else if(window.getSelection&&(sel=window.getSelection()).removeAllRanges)try{sel.removeAllRanges()}catch(e){}if(this._inputDevice=this._getPointerInputDevice(evt),type=this._inputDevice,this.options.precision.hasPoint=this.options.precision[type],pos=this.getMousePosition(evt),this._testForSelection(evt),this.selectingMode)return this._startSelecting(pos),void this.triggerEventHandlers(["touchstartselecting","pointerstartselecting","startselecting"],[evt]);if(this.attr.drag.enabled&&object?(elements=[object],this.mode=this.BOARD_MODE_DRAG):elements=this.initMoveObject(pos[0],pos[1],evt,type),target_obj={num:evt.pointerId,X:pos[0],Y:pos[1],Xprev:NaN,Yprev:NaN,Xstart:[],Ystart:[],Zstart:[]},elements.length>0){for(target=elements[elements.length-1],found=!1,i=0;i<this.touches.length;i++)if(this.touches[i].obj===target){j=i,k=this.touches[i].targets.push(target_obj)-1,found=!0;break}found||(k=0,j=this.touches.push({obj:target,targets:[target_obj]})-1),this.dehighlightAll(),target.highlight(!0),this.saveStartPos(target,this.touches[j].targets[k]),evt&&evt.preventDefault?evt.preventDefault():window.event&&(window.event.returnValue=!1)}return this.touches.length>0&&(evt.preventDefault(),evt.stopPropagation()),!!Env.isBrowser&&("touch"!==this._getPointerInputDevice(evt)?this.mode===this.BOARD_MODE_NONE&&this.mouseOriginMoveStart(evt):(this._pointerStorePosition(evt),evt.touches=this._board_touches,1===evt.touches.length&&this.mode===this.BOARD_MODE_NONE&&this.touchStartMoveOriginOneFinger(evt)||2!==evt.touches.length||this.mode!==this.BOARD_MODE_NONE&&this.mode!==this.BOARD_MODE_MOVE_ORIGIN||(this.mode===this.BOARD_MODE_MOVE_ORIGIN&&this.originMoveEnd(),this.gestureStartListener(evt))),this.triggerEventHandlers(["touchstart","down","pointerdown","MSPointerDown"],[evt]),!1)},pointerMoveListener:function(evt){var i,j,pos,touchTargets,type;if("touch"===this._getPointerInputDevice(evt)&&!this._isPointerRegistered(evt))return this.BOARD_MODE_NONE;if(!this.checkFrameRate(evt))return!1;if(this.mode!==this.BOARD_MODE_DRAG&&(this.dehighlightAll(),this.displayInfobox(!1)),this.mode!==this.BOARD_MODE_NONE&&(evt.preventDefault(),evt.stopPropagation()),this.updateQuality=this.BOARD_QUALITY_LOW,this._inputDevice=this._getPointerInputDevice(evt),type=this._inputDevice,this.options.precision.hasPoint=this.options.precision[type],this.selectingMode)pos=this.getMousePosition(evt),this._moveSelecting(pos),this.triggerEventHandlers(["touchmoveselecting","moveselecting","pointermoveselecting"],[evt,this.mode]);else if(!this.mouseOriginMove(evt))if(this.mode===this.BOARD_MODE_DRAG){for(i=0;i<this.touches.length;i++)for(touchTargets=this.touches[i].targets,j=0;j<touchTargets.length;j++)if(touchTargets[j].num===evt.pointerId){pos=this.getMousePosition(evt),touchTargets[j].X=pos[0],touchTargets[j].Y=pos[1],1===touchTargets.length?this.moveObject(pos[0],pos[1],this.touches[i],evt,type):2===touchTargets.length&&(this.twoFingerMove(this.touches[i],evt.pointerId,evt),touchTargets[j].Xprev=pos[0],touchTargets[j].Yprev=pos[1]);break}}else"touch"===this._getPointerInputDevice(evt)&&(this._pointerStorePosition(evt),2===this._board_touches.length&&(evt.touches=this._board_touches,this.gestureChangeListener(evt))),pos=this.getMousePosition(evt),this.highlightElements(pos[0],pos[1],evt,-1);return this.triggerEventHandlers(["touchmove","move","pointermove","MSPointerMove"],[evt,this.mode]),this.updateQuality=this.BOARD_QUALITY_HIGH,this.mode===this.BOARD_MODE_NONE},pointerUpListener:function(evt){var i,j,found,touchTargets;if(this.triggerEventHandlers(["touchend","up","pointerup","MSPointerUp"],[evt]),this.displayInfobox(!1),evt)for(i=0;i<this.touches.length;i++)for(touchTargets=this.touches[i].targets,j=0;j<touchTargets.length;j++)if(touchTargets[j].num===evt.pointerId){touchTargets.splice(j,1),0===touchTargets.length&&this.touches.splice(i,1);break}if(this.originMoveEnd(),this.update(),this.selectingMode)this._stopSelecting(evt),this.triggerEventHandlers(["touchstopselecting","pointerstopselecting","stopselecting"],[evt]),this.stopSelectionMode();else for(i=this.downObjects.length-1;i>-1;i--){for(found=!1,j=0;j<this.touches.length;j++)this.touches[j].obj.id===this.downObjects[i].id&&(found=!0);found||(this.downObjects[i].triggerEventHandlers(["touchend","up","pointerup","MSPointerUp"],[evt]),this.downObjects.splice(i,1))}return this.hasPointerUp&&(window.navigator.msPointerEnabled?Env.removeEvent(this.document,"MSPointerUp",this.pointerUpListener,this):(Env.removeEvent(this.document,"pointerup",this.pointerUpListener,this),Env.removeEvent(this.document,"pointercancel",this.pointerUpListener,this)),this.hasPointerUp=!1),this._pointerClearTouches(),!0},touchStartListener:function(evt){var i,pos,elements,j,k,obj,found,targets,target,touchTargets,eps=this.options.precision.touch,evtTouches=evt[JXG.touchProperty];for(this.hasTouchEnd||(Env.addEvent(this.document,"touchend",this.touchEndListener,this),this.hasTouchEnd=!0),this.document.selection&&Type.isFunction(this.document.selection.empty)?this.document.selection.empty():window.getSelection&&window.getSelection().removeAllRanges(),this._inputDevice="touch",this.options.precision.hasPoint=this.options.precision.touch,i=0;i<evtTouches.length;i++)evtTouches[i].jxg_isused=!1;for(i=0;i<this.touches.length;i++)for(touchTargets=this.touches[i].targets,j=0;j<touchTargets.length;j++){touchTargets[j].num=-1,eps=this.options.precision.touch;do{for(k=0;k<evtTouches.length;k++)if(Math.abs(Math.pow(evtTouches[k].screenX-touchTargets[j].X,2)+Math.pow(evtTouches[k].screenY-touchTargets[j].Y,2))<eps*eps){touchTargets[j].num=k,touchTargets[j].X=evtTouches[k].screenX,touchTargets[j].Y=evtTouches[k].screenY,evtTouches[k].jxg_isused=!0;break}eps*=2}while(-1===touchTargets[j].num&&eps<this.options.precision.touchMax);-1===touchTargets[j].num&&(JXG.debug("i couldn't find a targettouches for target no "+j+" on "+this.touches[i].obj.name+" ("+this.touches[i].obj.id+"). Removed the target."),JXG.debug("eps = "+eps+", touchMax = "+Options.precision.touchMax),touchTargets.splice(i,1))}for(i=0;i<evtTouches.length;i++)if(!evtTouches[i].jxg_isused){if(pos=this.getMousePosition(evt,i),this.selectingMode)return this._startSelecting(pos),this.triggerEventHandlers(["touchstartselecting","startselecting"],[evt]),evt.preventDefault(),evt.stopPropagation(),this.options.precision.hasPoint=this.options.precision.mouse,this.touches.length>0;if(0!==(elements=this.initMoveObject(pos[0],pos[1],evt,"touch")).length)if(obj=elements[elements.length-1],target={num:i,X:evtTouches[i].screenX,Y:evtTouches[i].screenY,Xprev:NaN,Yprev:NaN,Xstart:[],Ystart:[],Zstart:[]},Type.isPoint(obj)||obj.elementClass===Const.OBJECT_CLASS_TEXT||obj.type===Const.OBJECT_TYPE_TICKS||obj.type===Const.OBJECT_TYPE_IMAGE)targets=[target],this.saveStartPos(obj,targets[0]),this.touches.push({obj:obj,targets:targets}),obj.highlight(!0);else if(obj.elementClass===Const.OBJECT_CLASS_LINE||obj.elementClass===Const.OBJECT_CLASS_CIRCLE||obj.elementClass===Const.OBJECT_CLASS_CURVE||obj.type===Const.OBJECT_TYPE_POLYGON){for(found=!1,j=0;j<this.touches.length;j++)obj.id===this.touches[j].obj.id&&(found=!0,1===this.touches[j].targets.length&&(this.saveStartPos(obj,target),this.touches[j].targets.push(target)),evtTouches[i].jxg_isused=!0);found||(targets=[target],this.saveStartPos(obj,targets[0]),this.touches.push({obj:obj,targets:targets}),obj.highlight(!0))}evtTouches[i].jxg_isused=!0}return this.touches.length>0&&(evt.preventDefault(),evt.stopPropagation()),1===evtTouches.length&&this.mode===this.BOARD_MODE_NONE&&this.touchStartMoveOriginOneFinger(evt)||2!==evtTouches.length||this.mode!==this.BOARD_MODE_NONE&&this.mode!==this.BOARD_MODE_MOVE_ORIGIN||(this.mode===this.BOARD_MODE_MOVE_ORIGIN&&this.originMoveEnd(),this.gestureStartListener(evt)),this.options.precision.hasPoint=this.options.precision.mouse,this.triggerEventHandlers(["touchstart","down"],[evt]),!1},touchMoveListener:function(evt){var i,pos1,pos2,touchTargets,evtTouches=evt[JXG.touchProperty];if(!this.checkFrameRate(evt))return!1;if(this.mode!==this.BOARD_MODE_NONE&&(evt.preventDefault(),evt.stopPropagation()),this.mode!==this.BOARD_MODE_DRAG&&(this.dehighlightAll(),this.displayInfobox(!1)),this._inputDevice="touch",this.options.precision.hasPoint=this.options.precision.touch,this.updateQuality=this.BOARD_QUALITY_LOW,this.selectingMode){for(i=0;i<evtTouches.length;i++)if(!evtTouches[i].jxg_isused){pos1=this.getMousePosition(evt,i),this._moveSelecting(pos1),this.triggerEventHandlers(["touchmoves","moveselecting"],[evt,this.mode]);break}}else if(!this.touchOriginMove(evt))if(this.mode===this.BOARD_MODE_DRAG){for(i=0;i<this.touches.length;i++)if(1===(touchTargets=this.touches[i].targets).length){if(evtTouches[touchTargets[0].num]){if((pos1=this.getMousePosition(evt,touchTargets[0].num))[0]<0||pos1[0]>this.canvasWidth||pos1[1]<0||pos1[1]>this.canvasHeight)return;touchTargets[0].X=pos1[0],touchTargets[0].Y=pos1[1],this.moveObject(pos1[0],pos1[1],this.touches[i],evt,"touch")}}else if(2===touchTargets.length&&touchTargets[0].num>-1&&touchTargets[1].num>-1&&evtTouches[touchTargets[0].num]&&evtTouches[touchTargets[1].num]){if(pos1=this.getMousePosition(evt,touchTargets[0].num),pos2=this.getMousePosition(evt,touchTargets[1].num),pos1[0]<0||pos1[0]>this.canvasWidth||pos1[1]<0||pos1[1]>this.canvasHeight||pos2[0]<0||pos2[0]>this.canvasWidth||pos2[1]<0||pos2[1]>this.canvasHeight)return;touchTargets[0].X=pos1[0],touchTargets[0].Y=pos1[1],touchTargets[1].X=pos2[0],touchTargets[1].Y=pos2[1],this.twoFingerMove(this.touches[i],touchTargets[0].num,evt),this.twoFingerMove(this.touches[i],touchTargets[1].num),touchTargets[0].Xprev=pos1[0],touchTargets[0].Yprev=pos1[1],touchTargets[1].Xprev=pos2[0],touchTargets[1].Yprev=pos2[1]}}else 2===evtTouches.length&&this.gestureChangeListener(evt),pos1=this.getMousePosition(evt,0),this.highlightElements(pos1[0],pos1[1],evt,-1);return this.mode!==this.BOARD_MODE_DRAG&&this.displayInfobox(!1),this.triggerEventHandlers(["touchmove","move"],[evt,this.mode]),this.options.precision.hasPoint=this.options.precision.mouse,this.updateQuality=this.BOARD_QUALITY_HIGH,this.mode===this.BOARD_MODE_NONE},touchEndListener:function(evt){var i,j,k,found,foundNumber,touchTargets,eps=this.options.precision.touch,tmpTouches=[],evtTouches=evt&&evt[JXG.touchProperty];if(this.triggerEventHandlers(["touchend","up"],[evt]),this.displayInfobox(!1),this.selectingMode)this._stopSelecting(evt),this.triggerEventHandlers(["touchstopselecting","stopselecting"],[evt]),this.stopSelectionMode();else if(evtTouches&&evtTouches.length>0){for(i=0;i<this.touches.length;i++)tmpTouches[i]=this.touches[i];for(this.touches.length=0,i=0;i<evtTouches.length;i++)evtTouches[i].jxg_isused=!1;for(i=0;i<tmpTouches.length;i++){for(found=!1,foundNumber=0,touchTargets=tmpTouches[i].targets,j=0;j<touchTargets.length;j++)for(touchTargets[j].found=!1,k=0;k<evtTouches.length;k++)if(Math.abs(Math.pow(evtTouches[k].screenX-touchTargets[j].X,2)+Math.pow(evtTouches[k].screenY-touchTargets[j].Y,2))<eps*eps){touchTargets[j].found=!0,touchTargets[j].num=k,touchTargets[j].X=evtTouches[k].screenX,touchTargets[j].Y=evtTouches[k].screenY,foundNumber+=1;break}if(Type.isPoint(tmpTouches[i].obj)?found=touchTargets[0]&&touchTargets[0].found:tmpTouches[i].obj.elementClass===Const.OBJECT_CLASS_LINE?found=touchTargets[0]&&touchTargets[0].found||touchTargets[1]&&touchTargets[1].found:tmpTouches[i].obj.elementClass===Const.OBJECT_CLASS_CIRCLE&&(found=1===foundNumber||3===foundNumber),found)for(this.touches.push({obj:tmpTouches[i].obj,targets:[]}),j=0;j<touchTargets.length;j++)touchTargets[j].found&&this.touches[this.touches.length-1].targets.push({num:touchTargets[j].num,X:touchTargets[j].screenX,Y:touchTargets[j].screenY,Xprev:NaN,Yprev:NaN,Xstart:touchTargets[j].Xstart,Ystart:touchTargets[j].Ystart,Zstart:touchTargets[j].Zstart});else tmpTouches[i].obj.noHighlight()}}else this.touches.length=0;for(i=this.downObjects.length-1;i>-1;i--){for(found=!1,j=0;j<this.touches.length;j++)this.touches[j].obj.id===this.downObjects[i].id&&(found=!0);found||(this.downObjects[i].triggerEventHandlers(["touchup","up"],[evt]),this.downObjects.splice(i,1))}return evtTouches&&0!==evtTouches.length||(this.hasTouchEnd&&(Env.removeEvent(this.document,"touchend",this.touchEndListener,this),this.hasTouchEnd=!1),this.dehighlightAll(),this.updateQuality=this.BOARD_QUALITY_HIGH,this.originMoveEnd(),this.update()),!0},mouseDownListener:function(evt){var pos,elements,result;if(this.document.selection&&Type.isFunction(this.document.selection.empty)?this.document.selection.empty():window.getSelection&&window.getSelection().removeAllRanges(),!this.hasMouseUp)return Env.addEvent(this.document,"mouseup",this.mouseUpListener,this),this.hasMouseUp=!0,this._inputDevice="mouse",this.options.precision.hasPoint=this.options.precision.mouse,pos=this.getMousePosition(evt),this._testForSelection(evt),this.selectingMode?(this._startSelecting(pos),void this.triggerEventHandlers(["mousestartselecting","startselecting"],[evt])):(0===(elements=this.initMoveObject(pos[0],pos[1],evt,"mouse")).length?(this.mode=this.BOARD_MODE_NONE,result=!0):(this.mouse={obj:null,targets:[{X:pos[0],Y:pos[1],Xprev:NaN,Yprev:NaN}]},this.mouse.obj=elements[elements.length-1],this.dehighlightAll(),this.mouse.obj.highlight(!0),this.mouse.targets[0].Xstart=[],this.mouse.targets[0].Ystart=[],this.mouse.targets[0].Zstart=[],this.saveStartPos(this.mouse.obj,this.mouse.targets[0]),evt&&evt.preventDefault?evt.preventDefault():window.event&&(window.event.returnValue=!1)),this.mode===this.BOARD_MODE_NONE&&(result=this.mouseOriginMoveStart(evt)),this.triggerEventHandlers(["mousedown","down"],[evt]),result)},mouseMoveListener:function(evt){var pos;if(!this.checkFrameRate(evt))return!1;pos=this.getMousePosition(evt),this.updateQuality=this.BOARD_QUALITY_LOW,this.mode!==this.BOARD_MODE_DRAG&&(this.dehighlightAll(),this.displayInfobox(!1)),this.selectingMode?(this._moveSelecting(pos),this.triggerEventHandlers(["mousemoveselecting","moveselecting"],[evt,this.mode])):this.mouseOriginMove(evt)||(this.mode===this.BOARD_MODE_DRAG?this.moveObject(pos[0],pos[1],this.mouse,evt,"mouse"):this.highlightElements(pos[0],pos[1],evt,-1),this.triggerEventHandlers(["mousemove","move"],[evt,this.mode])),this.updateQuality=this.BOARD_QUALITY_HIGH},mouseUpListener:function(evt){var i;if(!1===this.selectingMode&&this.triggerEventHandlers(["mouseup","up"],[evt]),this.updateQuality=this.BOARD_QUALITY_HIGH,this.originMoveEnd(),this.dehighlightAll(),this.update(),this.selectingMode)this._stopSelecting(evt),this.triggerEventHandlers(["mousestopselecting","stopselecting"],[evt]),this.stopSelectionMode();else for(i=0;i<this.downObjects.length;i++)this.downObjects[i].triggerEventHandlers(["mouseup","up"],[evt]);this.downObjects.length=0,this.hasMouseUp&&(Env.removeEvent(this.document,"mouseup",this.mouseUpListener,this),this.hasMouseUp=!1),this.mouse=null},mouseWheelListener:function(evt){if(!this.attr.zoom.wheel||!this._isRequiredKeyPressed(evt,"zoom"))return!0;var wd=(evt=evt||window.event).detail?-evt.detail:evt.wheelDelta/40,pos=new Coords(Const.COORDS_BY_SCREEN,this.getMousePosition(evt),this);return wd>0?this.zoomIn(pos.usrCoords[1],pos.usrCoords[2]):this.zoomOut(pos.usrCoords[1],pos.usrCoords[2]),this.triggerEventHandlers(["mousewheel"],[evt]),evt.preventDefault(),!1},keyDownListener:function(evt){var id,el,res,dir,actPos,id_node=evt.target.id,sX=0,sY=0,dx=Type.evaluate(this.attr.keyboard.dx)/this.unitX,dy=Type.evaluate(this.attr.keyboard.dy)/this.unitY,doZoom=!1,done=!0;return!(!this.attr.keyboard.enabled||""===id_node)&&(id=id_node.replace(this.containerObj.id+"_",""),el=this.select(id),Type.exists(el.coords)&&(actPos=el.coords.usrCoords.slice(1)),(Type.evaluate(this.attr.keyboard.panshift)||Type.evaluate(this.attr.keyboard.panctrl))&&(doZoom=!0),Type.evaluate(this.attr.keyboard.panshift)&&evt.shiftKey||Type.evaluate(this.attr.keyboard.panctrl)&&evt.ctrlKey?38===evt.keyCode?this.clickUpArrow():40===evt.keyCode?this.clickDownArrow():37===evt.keyCode?this.clickLeftArrow():39===evt.keyCode?this.clickRightArrow():done=!1:(Type.exists(el.visProp)&&(Type.exists(el.visProp.snaptogrid)&&el.visProp.snaptogrid&&Type.evaluate(el.visProp.snapsizex)&&Type.evaluate(el.visProp.snapsizey)?(sX=(res=el.getSnapSizes())[0],sY=res[1],dx=Math.max(sX,dx),dy=Math.max(sY,dy)):Type.exists(el.visProp.attracttogrid)&&el.visProp.attracttogrid&&Type.evaluate(el.visProp.attractordistance)&&Type.evaluate(el.visProp.attractorunit)&&(sY=sX=1.1*Type.evaluate(el.visProp.attractordistance),"screen"===Type.evaluate(el.visProp.attractorunit)&&(sX/=this.unitX,sY/=this.unitX),dx=Math.max(sX,dx),dy=Math.max(sY,dy))),38===evt.keyCode?dir=[0,dy]:40===evt.keyCode?dir=[0,-dy]:37===evt.keyCode?dir=[-dx,0]:39===evt.keyCode?dir=[dx,0]:doZoom&&"+"===evt.key?this.zoomIn():doZoom&&"-"===evt.key?this.zoomOut():doZoom&&"o"===evt.key?this.zoom100():done=!1,dir&&el.isDraggable&&el.visPropCalc.visible&&(this.geonextCompatibilityMode&&(Type.isPoint(el)||el.elementClass===Const.OBJECT_CLASS_TEXT)||!this.geonextCompatibilityMode)&&!Type.evaluate(el.visProp.fixed)&&(Type.exists(el.coords)&&(dir[0]+=actPos[0],dir[1]+=actPos[1]),el.setPosition(JXG.COORDS_BY_USER,dir),Type.exists(el.coords)&&this.updateInfobox(el),this.triggerEventHandlers(["hit"],[evt,el]))),this.update(),done&&Type.exists(evt.preventDefault)&&evt.preventDefault(),!0)},keyFocusInListener:function(evt){var id,el,id_node=evt.target.id;if(!this.attr.keyboard.enabled||""===id_node)return!1;id=id_node.replace(this.containerObj.id+"_",""),el=this.select(id),Type.exists(el.highlight)&&el.highlight(!0),Type.exists(el.coords)&&this.updateInfobox(el),this.triggerEventHandlers(["hit"],[evt,el])},keyFocusOutListener:function(evt){if(!this.attr.keyboard.enabled)return!1;this.dehighlightAll(),this.displayInfobox(!1)},updateContainerDims:function(){var w,h,bb,css;w=(bb=this.containerObj.getBoundingClientRect()).width,h=bb.height,window&&window.getComputedStyle&&(css=window.getComputedStyle(this.containerObj,null),w-=parseFloat(css.getPropertyValue("border-left-width"))+parseFloat(css.getPropertyValue("border-right-width")),h-=parseFloat(css.getPropertyValue("border-top-width"))+parseFloat(css.getPropertyValue("border-bottom-width"))),w<=0||h<=0||Type.isNaN(w)||Type.isNaN(h)||(isNaN(this.getBoundingBox()[0])&&this.setBoundingBox(this.attr.boundingbox,this.keepaspectratio,"keep"),Type.exists(this._prevDim)&&this._prevDim.w===w&&this._prevDim.h===h||(this.resizeContainer(w,h,!0),this._prevDim={w:w,h:h}))},startResizeObserver:function(){var that=this;Env.isBrowser&&this.attr.resize&&this.attr.resize.enabled&&(this.resizeObserver=new ResizeObserver((function(entries){that._isResizing||(that._isResizing=!0,window.setTimeout((function(){try{that.updateContainerDims()}catch(err){that.stopResizeObserver()}finally{that._isResizing=!1}}),that.attr.resize.throttle))})),this.resizeObserver.observe(this.containerObj))},stopResizeObserver:function(){Env.isBrowser&&this.attr.resize&&this.attr.resize.enabled&&Type.exists(this.resizeObserver)&&this.resizeObserver.unobserve(this.containerObj)},resizeListener:function(){var that=this;Env.isBrowser&&this.attr.resize&&this.attr.resize.enabled&&(this._isScrolling||this._isResizing||(this._isResizing=!0,window.setTimeout((function(){that.updateContainerDims(),that._isResizing=!1}),this.attr.resize.throttle)))},scrollListener:function(evt){var that=this;Env.isBrowser&&(this._isScrolling||(this._isScrolling=!0,window.setTimeout((function(){that._isScrolling=!1}),66)))},startIntersectionObserver:function(){var that=this;try{this.intersectionObserver=new IntersectionObserver((function(entries){isNaN(that.getBoundingBox()[0])&&that.updateContainerDims()}),{root:null,rootMargin:"0px",threshold:.8}),this.intersectionObserver.observe(that.containerObj)}catch(err){console.log("JSXGraph: IntersectionObserver not available in this browser.")}},stopIntersectionObserver:function(){Type.exists(this.intersectionObserver)&&this.intersectionObserver.unobserve(this.containerObj)},initInfobox:function(){var attr=Type.copyAttributes({},this.options,"infobox");return attr.id=this.id+"_infobox",this.infobox=this.create("text",[0,0,"0,0"],attr),this.infobox.distanceX=-20,this.infobox.distanceY=25,this.infobox.dump=!1,this.displayInfobox(!1),this},updateInfobox:function(el){var x,y,xc,yc,vpinfoboxdigits,vpsi=Type.evaluate(el.visProp.showinfobox);return!Type.evaluate(this.attr.showinfobox)&&"inherit"===vpsi||!vpsi||Type.isPoint(el)&&(xc=el.coords.usrCoords[1],yc=el.coords.usrCoords[2],vpinfoboxdigits=Type.evaluate(el.visProp.infoboxdigits),this.infobox.setCoords(xc+this.infobox.distanceX/this.unitX,yc+this.infobox.distanceY/this.unitY),"string"!=typeof el.infoboxText?("auto"===vpinfoboxdigits?(x=Type.autoDigits(xc),y=Type.autoDigits(yc)):Type.isNumber(vpinfoboxdigits)?(x=Type.toFixed(xc,vpinfoboxdigits),y=Type.toFixed(yc,vpinfoboxdigits)):(x=xc,y=yc),this.highlightInfobox(x,y,el)):this.highlightCustomInfobox(el.infoboxText,el),this.displayInfobox(!0)),this},displayInfobox:function(val){return this.infobox.hiddenByParent===val&&(this.infobox.hiddenByParent=!val,this.infobox.prepareUpdate().updateVisibility(val).updateRenderer()),this},showInfobox:function(val){return this.displayInfobox(val)},highlightInfobox:function(x,y,el){return this.highlightCustomInfobox("("+x+", "+y+")",el),this},highlightCustomInfobox:function(text,el){return this.infobox.setText(text),this},dehighlightAll:function(){var el,pEl,needsDehighlight=!1;for(el in this.highlightedObjects)this.highlightedObjects.hasOwnProperty(el)&&(pEl=this.highlightedObjects[el],(this.hasMouseHandlers||this.hasPointerHandlers)&&pEl.noHighlight(),needsDehighlight=!0);return this.highlightedObjects={},"canvas"===this.renderer.type&&needsDehighlight&&(this.prepareUpdate(),this.renderer.suspendRedraw(this),this.updateRenderer(),this.renderer.unsuspendRedraw()),this},getScrCoordsOfMouse:function(x,y){return[x,y]},getUsrCoordsOfMouse:function(evt){var cPos=this.getCoordsTopLeftCorner(),absPos=Env.getPosition(evt,null,this.document),x=absPos[0]-cPos[0],y=absPos[1]-cPos[1];return new Coords(Const.COORDS_BY_SCREEN,[x,y],this).usrCoords.slice(1)},getAllUnderMouse:function(evt){var elList=this.getAllObjectsUnderMouse(evt);return elList.push(this.getUsrCoordsOfMouse(evt)),elList},getAllObjectsUnderMouse:function(evt){var el,pEl,cPos=this.getCoordsTopLeftCorner(),absPos=Env.getPosition(evt,null,this.document),dx=absPos[0]-cPos[0],dy=absPos[1]-cPos[1],elList=[],len=this.objectsList.length;for(el=0;el<len;el++)(pEl=this.objectsList[el]).visPropCalc.visible&&pEl.hasPoint&&pEl.hasPoint(dx,dy)&&(elList[elList.length]=pEl);return elList},updateCoords:function(){var el,ob,len=this.objectsList.length;for(ob=0;ob<len;ob++)el=this.objectsList[ob],Type.exists(el.coords)&&(Type.evaluate(el.visProp.frozen)?el.coords.screen2usr():el.coords.usr2screen());return this},moveOrigin:function(x,y,diff){var ox,oy,ul,lr;return Type.exists(x)&&Type.exists(y)&&(ox=this.origin.scrCoords[1],oy=this.origin.scrCoords[2],this.origin.scrCoords[1]=x,this.origin.scrCoords[2]=y,diff&&(this.origin.scrCoords[1]-=this.drag_dx,this.origin.scrCoords[2]-=this.drag_dy),ul=new Coords(Const.COORDS_BY_SCREEN,[0,0],this).usrCoords,lr=new Coords(Const.COORDS_BY_SCREEN,[this.canvasWidth,this.canvasHeight],this).usrCoords,(ul[1]<this.maxboundingbox[0]||ul[2]>this.maxboundingbox[1]||lr[1]>this.maxboundingbox[2]||lr[2]<this.maxboundingbox[3])&&(this.origin.scrCoords[1]=ox,this.origin.scrCoords[2]=oy)),this.updateCoords().clearTraces().fullUpdate(),this.triggerEventHandlers(["boundingbox"]),this},addConditions:function(str){var term,m,left,right,name,el,property,functions=[],i=str.indexOf("<data>"),j=str.indexOf("</data>"),xyFun=function(board,el,f,what){return function(){var e,t;t=(e=board.select(el.id)).coords.usrCoords[what],2===what?e.setPositionDirectly(Const.COORDS_BY_USER,[f(),t]):e.setPositionDirectly(Const.COORDS_BY_USER,[t,f()]),e.prepareUpdate().update()}},visFun=function(board,el,f){return function(){var e,v;e=board.select(el.id),v=f(),e.setAttribute({visible:v})}},colFun=function(board,el,f,what){return function(){var e,v;e=board.select(el.id),v=f(),"strokewidth"===what?e.visProp.strokewidth=v:(v=Color.rgba2rgbo(v),e.visProp[what+"color"]=v[0],e.visProp[what+"opacity"]=v[1])}},posFun=function(board,el,f){return function(){board.select(el.id).position=f()}},styleFun=function(board,el,f){return function(){board.select(el.id).setStyle(f())}};if(!(i<0)){for(;i>=0;){if(m=(term=str.slice(i+6,j)).indexOf("="),left=term.slice(0,m),right=term.slice(m+1),m=left.indexOf("."),name=left.slice(0,m),el=this.elementsByName[Type.unescapeHTML(name)],property=left.slice(m+1).replace(/\s+/g,"").toLowerCase(),right=Type.createFunction(right,this,"",!0),Type.exists(this.elementsByName[name]))switch(property){case"x":functions.push(xyFun(this,el,right,2));break;case"y":functions.push(xyFun(this,el,right,1));break;case"visible":functions.push(visFun(this,el,right));break;case"position":functions.push(posFun(this,el,right));break;case"stroke":functions.push(colFun(this,el,right,"stroke"));break;case"style":functions.push(styleFun(this,el,right));break;case"strokewidth":functions.push(colFun(this,el,right,"strokewidth"));break;case"fill":functions.push(colFun(this,el,right,"fill"));break;case"label":break;default:JXG.debug("property '"+property+"' in conditions not yet implemented:"+right)}else JXG.debug("debug conditions: |"+name+"| undefined");i=(str=str.slice(j+7)).indexOf("<data>"),j=str.indexOf("</data>")}this.updateConditions=function(){var i;for(i=0;i<functions.length;i++)functions[i]();return this.prepareUpdate().updateElements(),!0},this.updateConditions()}},updateConditions:function(){return!1},calculateSnapSizes:function(){var p1=new Coords(Const.COORDS_BY_USER,[0,0],this),p2=new Coords(Const.COORDS_BY_USER,[this.options.grid.gridX,this.options.grid.gridY],this),x=p1.scrCoords[1]-p2.scrCoords[1],y=p1.scrCoords[2]-p2.scrCoords[2];for(this.options.grid.snapSizeX=this.options.grid.gridX;Math.abs(x)>25;)this.options.grid.snapSizeX*=2,x/=2;for(this.options.grid.snapSizeY=this.options.grid.gridY;Math.abs(y)>25;)this.options.grid.snapSizeY*=2,y/=2;return this},applyZoom:function(){return this.updateCoords().calculateSnapSizes().clearTraces().fullUpdate(),this},zoomIn:function(x,y){var bb=this.getBoundingBox(),zX=this.attr.zoom.factorx,zY=this.attr.zoom.factory,dX=(bb[2]-bb[0])*(1-1/zX),dY=(bb[1]-bb[3])*(1-1/zY),lr=.5,tr=.5,mi=this.attr.zoom.eps||this.attr.zoom.min||.001;return this.zoomX>this.attr.zoom.max&&zX>1||this.zoomY>this.attr.zoom.max&&zY>1||this.zoomX<mi&&zX<1||this.zoomY<mi&&zY<1?this:(Type.isNumber(x)&&Type.isNumber(y)&&(lr=(x-bb[0])/(bb[2]-bb[0]),tr=(bb[1]-y)/(bb[1]-bb[3])),this.setBoundingBox([bb[0]+dX*lr,bb[1]-dY*tr,bb[2]-dX*(1-lr),bb[3]+dY*(1-tr)],this.keepaspectratio,"update"),this.applyZoom())},zoomOut:function(x,y){var bb=this.getBoundingBox(),zX=this.attr.zoom.factorx,zY=this.attr.zoom.factory,dX=(bb[2]-bb[0])*(1-zX),dY=(bb[1]-bb[3])*(1-zY),lr=.5,tr=.5,mi=this.attr.zoom.eps||this.attr.zoom.min||.001;return this.zoomX<mi||this.zoomY<mi?this:(Type.isNumber(x)&&Type.isNumber(y)&&(lr=(x-bb[0])/(bb[2]-bb[0]),tr=(bb[1]-y)/(bb[1]-bb[3])),this.setBoundingBox([bb[0]+dX*lr,bb[1]-dY*tr,bb[2]-dX*(1-lr),bb[3]+dY*(1-tr)],this.keepaspectratio,"update"),this.applyZoom())},zoom100:function(){var bb,dX,dY;return Type.exists(this.attr.boundingbox)?this.setBoundingBox(this.attr.boundingbox,this.keepaspectratio,"reset"):(dX=((bb=this.getBoundingBox())[2]-bb[0])*(1-this.zoomX)*.5,dY=(bb[1]-bb[3])*(1-this.zoomY)*.5,this.setBoundingBox([bb[0]+dX,bb[1]-dY,bb[2]-dX,bb[3]+dY],this.keepaspectratio,"reset")),this.applyZoom()},zoomAllPoints:function(){var el,borderX,borderY,pEl,minX=0,maxX=0,minY=0,maxY=0,len=this.objectsList.length;for(el=0;el<len;el++)pEl=this.objectsList[el],Type.isPoint(pEl)&&pEl.visPropCalc.visible&&(pEl.coords.usrCoords[1]<minX?minX=pEl.coords.usrCoords[1]:pEl.coords.usrCoords[1]>maxX&&(maxX=pEl.coords.usrCoords[1]),pEl.coords.usrCoords[2]>maxY?maxY=pEl.coords.usrCoords[2]:pEl.coords.usrCoords[2]<minY&&(minY=pEl.coords.usrCoords[2]));return 50,borderX=50/this.unitX,borderY=50/this.unitY,this.setBoundingBox([minX-borderX,maxY+borderY,maxX+borderX,minY-borderY],this.keepaspectratio,"update"),this.applyZoom()},zoomElements:function(elements){var i,box,cx,cy,dx,dy,d,newBBox=[1/0,-1/0,-1/0,1/0];if(!Type.isArray(elements)||0===elements.length)return this;for(i=0;i<elements.length;i++)box=this.select(elements[i]).bounds(),Type.isArray(box)&&(box[0]<newBBox[0]&&(newBBox[0]=box[0]),box[1]>newBBox[1]&&(newBBox[1]=box[1]),box[2]>newBBox[2]&&(newBBox[2]=box[2]),box[3]<newBBox[3]&&(newBBox[3]=box[3]));return Type.isArray(newBBox)&&(cx=.5*(newBBox[0]+newBBox[2]),cy=.5*(newBBox[1]+newBBox[3]),dx=1.5*(newBBox[2]-newBBox[0])*.5,dy=1.5*(newBBox[1]-newBBox[3])*.5,d=Math.max(dx,dy),this.setBoundingBox([cx-d,cy+d,cx+d,cy-d],this.keepaspectratio,"update")),this},setZoom:function(fX,fY){var oX=this.attr.zoom.factorx,oY=this.attr.zoom.factory;return this.attr.zoom.factorx=fX/this.zoomX,this.attr.zoom.factory=fY/this.zoomY,this.zoomIn(),this.attr.zoom.factorx=oX,this.attr.zoom.factory=oY,this},removeObject:function(object,saveMethod){var el,i;if(Type.isArray(object)){for(i=0;i<object.length;i++)this.removeObject(object[i]);return this}if(object=this.select(object),!Type.exists(object)||Type.isString(object))return this;try{for(el in object.childElements)object.childElements.hasOwnProperty(el)&&object.childElements[el].board.removeObject(object.childElements[el]);for(el in object.objects)object.objects.hasOwnProperty(el)&&object.objects[el].board.removeObject(object.objects[el]);if(saveMethod)for(el in this.objects)this.objects.hasOwnProperty(el)&&Type.exists(this.objects[el].childElements)&&Type.exists(this.objects[el].childElements.hasOwnProperty(object.id))&&(delete this.objects[el].childElements[object.id],delete this.objects[el].descendants[object.id]);else if(Type.exists(object.ancestors))for(el in object.ancestors)object.ancestors.hasOwnProperty(el)&&Type.exists(object.ancestors[el].childElements)&&Type.exists(object.ancestors[el].childElements.hasOwnProperty(object.id))&&(delete object.ancestors[el].childElements[object.id],delete object.ancestors[el].descendants[object.id]);if(object._pos>-1)for(this.objectsList.splice(object._pos,1),el=object._pos;el<this.objectsList.length;el++)this.objectsList[el]._pos--;else object.type!==Const.OBJECT_TYPE_TURTLE&&JXG.debug("Board.removeObject: object "+object.id+" not found in list.");delete this.objects[object.id],delete this.elementsByName[object.name],object.visProp&&Type.evaluate(object.visProp.trace)&&object.clearTrace(),Type.exists(object.remove)&&object.remove()}catch(e){JXG.debug(object.id+": Could not be removed: "+e)}return this.update(),this},removeAncestors:function(object){var anc;for(anc in object.ancestors)object.ancestors.hasOwnProperty(anc)&&this.removeAncestors(object.ancestors[anc]);return this.removeObject(object),this},initGeonextBoard:function(){var p1,p2,p3;return p1=this.create("point",[0,0],{id:this.id+"g00e0",name:"Ursprung",withLabel:!1,visible:!1,fixed:!0}),p2=this.create("point",[1,0],{id:this.id+"gX0e0",name:"Punkt_1_0",withLabel:!1,visible:!1,fixed:!0}),p3=this.create("point",[0,1],{id:this.id+"gY0e0",name:"Punkt_0_1",withLabel:!1,visible:!1,fixed:!0}),this.create("line",[p1,p2],{id:this.id+"gXLe0",name:"X-Achse",withLabel:!1,visible:!1}),this.create("line",[p1,p3],{id:this.id+"gYLe0",name:"Y-Achse",withLabel:!1,visible:!1}),this},resizeContainer:function(canvasWidth,canvasHeight,dontset,dontSetBoundingBox){var box;return dontSetBoundingBox||(box=this.getBoundingBox()),this.canvasWidth=parseFloat(canvasWidth),this.canvasHeight=parseFloat(canvasHeight),dontset||(this.containerObj.style.width=this.canvasWidth+"px",this.containerObj.style.height=this.canvasHeight+"px"),this.renderer.resize(this.canvasWidth,this.canvasHeight),dontSetBoundingBox||this.setBoundingBox(box,this.keepaspectratio,"keep"),this},showDependencies:function(){var el,t,c,f,i;for(el in t="<p>\n",this.objects)if(this.objects.hasOwnProperty(el)){for(c in i=0,this.objects[el].childElements)this.objects[el].childElements.hasOwnProperty(c)&&(i+=1);for(c in i>=0&&(t+="<strong>"+this.objects[el].id+":</strong> "),this.objects[el].childElements)this.objects[el].childElements.hasOwnProperty(c)&&(t+=this.objects[el].childElements[c].id+"("+this.objects[el].childElements[c].name+"), ");t+="<p>\n"}return t+="</p>\n",(f=window.open()).document.open(),f.document.write(t),f.document.close(),this},showXML:function(){var f=window.open("");return f.document.open(),f.document.write("<pre>"+Type.escapeHTML(this.xmlString)+"</pre>"),f.document.close(),this},prepareUpdate:function(){var el,pEl,len=this.objectsList.length;for(el=0;el<len;el++)(pEl=this.objectsList[el]).needsUpdate=pEl.needsRegularUpdate||this.needsFullUpdate;for(el in this.groups)this.groups.hasOwnProperty(el)&&((pEl=this.groups[el]).needsUpdate=pEl.needsRegularUpdate||this.needsFullUpdate);return this},updateElements:function(drag){var el,pEl;for(drag=this.select(drag),el=0;el<this.objectsList.length;el++)pEl=this.objectsList[el],this.needsFullUpdate&&pEl.elementClass===Const.OBJECT_CLASS_TEXT&&pEl.updateSize(),pEl.update(!Type.exists(drag)||pEl.id!==drag.id).updateVisibility();for(el in this.groups)this.groups.hasOwnProperty(el)&&this.groups[el].update(drag);return this},updateRenderer:function(){var el,len=this.objectsList.length;if("canvas"===this.renderer.type)this.updateRendererCanvas();else for(el=0;el<len;el++)this.objectsList[el].updateRenderer();return this},updateRendererCanvas:function(){var el,pEl,i,mini,la,olen=this.objectsList.length,layers=this.options.layer,len=this.options.layer.numlayers,last=Number.NEGATIVE_INFINITY;for(i=0;i<len;i++){for(la in mini=Number.POSITIVE_INFINITY,layers)layers.hasOwnProperty(la)&&layers[la]>last&&layers[la]<mini&&(mini=layers[la]);for(last=mini,el=0;el<olen;el++)(pEl=this.objectsList[el]).visProp.layer===mini&&pEl.prepareUpdate().updateRenderer()}return this},addHook:function(hook,m,context){return JXG.deprecated("Board.addHook()","Board.on()"),m=Type.def(m,"update"),context=Type.def(context,this),this.hooks.push([m,hook]),this.on(m,hook,context),this.hooks.length-1},addEvent:JXG.shortcut(JXG.Board.prototype,"on"),removeHook:function(id){return JXG.deprecated("Board.removeHook()","Board.off()"),this.hooks[id]&&(this.off(this.hooks[id][0],this.hooks[id][1]),this.hooks[id]=null),this},removeEvent:JXG.shortcut(JXG.Board.prototype,"off"),updateHooks:function(m){var arg=Array.prototype.slice.call(arguments,0);return JXG.deprecated("Board.updateHooks()","Board.triggerEventHandlers()"),arg[0]=Type.def(arg[0],"update"),this.triggerEventHandlers([arg[0]],arguments),this},addChild:function(board){return Type.exists(board)&&Type.exists(board.containerObj)&&(this.dependentBoards.push(board),this.update()),this},removeChild:function(board){var i;for(i=this.dependentBoards.length-1;i>=0;i--)this.dependentBoards[i]===board&&this.dependentBoards.splice(i,1);return this},update:function(drag){var i,len,b,insert,storeActiveEl;if(this.inUpdate||this.isSuspendedUpdate)return this;for(this.inUpdate=!0,"all"===this.attr.minimizereflow&&this.containerObj&&"vml"!==this.renderer.type&&(storeActiveEl=this.document.activeElement,insert=this.renderer.removeToInsertLater(this.containerObj)),"svg"===this.attr.minimizereflow&&"svg"===this.renderer.type&&(storeActiveEl=this.document.activeElement,insert=this.renderer.removeToInsertLater(this.renderer.svgRoot)),this.prepareUpdate().updateElements(drag).updateConditions(),this.renderer.suspendRedraw(this),this.updateRenderer(),this.renderer.unsuspendRedraw(),this.triggerEventHandlers(["update"],[]),insert&&(insert(),storeActiveEl.focus()),len=this.dependentBoards.length,i=0;i<len;i++)b=this.dependentBoards[i],Type.exists(b)&&b!==this&&(b.updateQuality=this.updateQuality,b.prepareUpdate().updateElements().updateConditions(),b.renderer.suspendRedraw(),b.updateRenderer(),b.renderer.unsuspendRedraw(),b.triggerEventHandlers(["update"],[]));return this.inUpdate=!1,this},fullUpdate:function(){return this.needsFullUpdate=!0,this.update(),this.needsFullUpdate=!1,this},addGrid:function(){return this.create("grid",[]),this},removeGrids:function(){var i;for(i=0;i<this.grids.length;i++)this.removeObject(this.grids[i]);return this.grids.length=0,this.update(),this},create:function(elementType,parents,attributes){var el,i;for(elementType=elementType.toLowerCase(),Type.exists(parents)||(parents=[]),Type.exists(attributes)||(attributes={}),i=0;i<parents.length;i++)!Type.isString(parents[i])||"text"===elementType&&2===i||"solidofrevolution3d"===elementType&&2===i||!("input"!==elementType&&"checkbox"!==elementType&&"button"!==elementType||2!==i&&3!==i)||"curve"===elementType&&i>0||(parents[i]=this.select(parents[i]));if(!Type.isFunction(JXG.elements[elementType]))throw new Error("JSXGraph: create: Unknown element type given: "+elementType);return el=JXG.elements[elementType](this,parents,attributes),Type.exists(el)?(el.prepareUpdate&&el.update&&el.updateRenderer&&el.fullUpdate(),el):(JXG.debug("JSXGraph: create: failure creating "+elementType),el)},createElement:function(){return JXG.deprecated("Board.createElement()","Board.create()"),this.create.apply(this,arguments)},clearTraces:function(){var el;for(el=0;el<this.objectsList.length;el++)this.objectsList[el].clearTrace();return this.numTraces=0,this},suspendUpdate:function(){return this.inUpdate||(this.isSuspendedUpdate=!0),this},unsuspendUpdate:function(){return this.isSuspendedUpdate&&(this.isSuspendedUpdate=!1,this.fullUpdate()),this},setBoundingBox:function(bbox,keepaspectratio,setZoom){var h,w,ux,uy,offX=0,offY=0,dim=Env.getDimensions(this.container,this.document);return Type.isArray(bbox)?(bbox[0]<this.maxboundingbox[0]||bbox[1]>this.maxboundingbox[1]||bbox[2]>this.maxboundingbox[2]||bbox[3]<this.maxboundingbox[3]||(Type.exists(setZoom)||(setZoom="reset"),ux=this.unitX,uy=this.unitY,this.canvasWidth=parseInt(dim.width,10),this.canvasHeight=parseInt(dim.height,10),w=this.canvasWidth,h=this.canvasHeight,keepaspectratio?(this.unitX=w/(bbox[2]-bbox[0]),this.unitY=h/(bbox[1]-bbox[3]),Math.abs(this.unitX)<Math.abs(this.unitY)?(this.unitY=Math.abs(this.unitX)*this.unitY/Math.abs(this.unitY),offY=.5*(h/this.unitY-(bbox[1]-bbox[3]))):(this.unitX=Math.abs(this.unitY)*this.unitX/Math.abs(this.unitX),offX=.5*(w/this.unitX-(bbox[2]-bbox[0]))),this.keepaspectratio=!0):(this.unitX=w/(bbox[2]-bbox[0]),this.unitY=h/(bbox[1]-bbox[3]),this.keepaspectratio=!1),this.moveOrigin(-this.unitX*(bbox[0]-offX),this.unitY*(bbox[1]+offY)),"update"===setZoom?(this.zoomX*=this.unitX/ux,this.zoomY*=this.unitY/uy):"reset"===setZoom&&(this.zoomX=Type.exists(this.attr.zoomx)?this.attr.zoomx:1,this.zoomY=Type.exists(this.attr.zoomy)?this.attr.zoomy:1)),this):this},getBoundingBox:function(){var ul=new Coords(Const.COORDS_BY_SCREEN,[0,0],this).usrCoords,lr=new Coords(Const.COORDS_BY_SCREEN,[this.canvasWidth,this.canvasHeight],this).usrCoords;return[ul[1],ul[2],lr[1],lr[2]]},addAnimation:function(element){var that=this;return this.animationObjects[element.id]=element,this.animationIntervalCode||(this.animationIntervalCode=window.setInterval((function(){that.animate()}),element.board.attr.animationdelay)),this},stopAllAnimation:function(){var el;for(el in this.animationObjects)this.animationObjects.hasOwnProperty(el)&&Type.exists(this.animationObjects[el])&&(this.animationObjects[el]=null,delete this.animationObjects[el]);return window.clearInterval(this.animationIntervalCode),delete this.animationIntervalCode,this},animate:function(){var props,el,o,newCoords,r,p,c,cbtmp,count=0,obj=null;for(el in this.animationObjects)if(this.animationObjects.hasOwnProperty(el)&&Type.exists(this.animationObjects[el])){if(count+=1,(o=this.animationObjects[el]).animationPath&&(newCoords=Type.isFunction(o.animationPath)?o.animationPath((new Date).getTime()-o.animationStart):o.animationPath.pop(),!Type.exists(newCoords)||!Type.isArray(newCoords)&&isNaN(newCoords)?delete o.animationPath:(o.setPositionDirectly(Const.COORDS_BY_USER,newCoords),o.fullUpdate(),obj=o)),o.animationData){for(r in c=0,o.animationData)o.animationData.hasOwnProperty(r)&&(p=o.animationData[r].pop(),Type.exists(p)?(c+=1,(props={})[r]=p,o.setAttribute(props)):delete o.animationData[p]);0===c&&delete o.animationData}Type.exists(o.animationData)||Type.exists(o.animationPath)||(this.animationObjects[el]=null,delete this.animationObjects[el],Type.exists(o.animationCallback)&&(cbtmp=o.animationCallback,o.animationCallback=null,cbtmp()))}return 0===count?(window.clearInterval(this.animationIntervalCode),delete this.animationIntervalCode):this.update(obj),this},migratePoint:function(src,dest,copyName){var child,childId,prop,found,i,srcLabelId,srcHasLabel=!1;for(childId in src=this.select(src),dest=this.select(dest),Type.exists(src.label)&&(srcLabelId=src.label.id,srcHasLabel=!0,this.removeObject(src.label)),src.childElements)if(src.childElements.hasOwnProperty(childId)){for(prop in found=!1,child=src.childElements[childId])child.hasOwnProperty(prop)&&child[prop]===src&&(child[prop]=dest,found=!0);for(found&&delete src.childElements[childId],i=0;i<child.parents.length;i++)child.parents[i]===src.id&&(child.parents[i]=dest.id);dest.addChild(child)}return copyName&&(srcHasLabel&&(delete dest.childElements[srcLabelId],delete dest.descendants[srcLabelId]),dest.label&&this.removeObject(dest.label),delete this.elementsByName[dest.name],dest.name=src.name,srcHasLabel&&dest.createLabel()),this.removeObject(src),Type.exists(dest.name)&&""!==dest.name&&(this.elementsByName[dest.name]=dest),this.fullUpdate(),this},emulateColorblindness:function(deficiency){var e,o;if(Type.exists(deficiency)||(deficiency="none"),this.currentCBDef===deficiency)return this;for(e in this.objects)this.objects.hasOwnProperty(e)&&(o=this.objects[e],"none"!==deficiency?("none"===this.currentCBDef&&(o.visPropOriginal={strokecolor:o.visProp.strokecolor,fillcolor:o.visProp.fillcolor,highlightstrokecolor:o.visProp.highlightstrokecolor,highlightfillcolor:o.visProp.highlightfillcolor}),o.setAttribute({strokecolor:Color.rgb2cb(Type.evaluate(o.visPropOriginal.strokecolor),deficiency),fillcolor:Color.rgb2cb(Type.evaluate(o.visPropOriginal.fillcolor),deficiency),highlightstrokecolor:Color.rgb2cb(Type.evaluate(o.visPropOriginal.highlightstrokecolor),deficiency),highlightfillcolor:Color.rgb2cb(Type.evaluate(o.visPropOriginal.highlightfillcolor),deficiency)})):Type.exists(o.visPropOriginal)&&JXG.extend(o.visProp,o.visPropOriginal));return this.currentCBDef=deficiency,this.update(),this},select:function(str,onlyByIdOrName){var flist,olist,i,l,s=str;if(null===s)return s;if(Type.isString(s)&&""!==s)Type.exists(this.objects[s])?s=this.objects[s]:Type.exists(this.elementsByName[s])?s=this.elementsByName[s]:Type.exists(this.groups[s])&&(s=this.groups[s]);else if(!onlyByIdOrName&&(Type.isFunction(s)||Type.isObject(s)&&!Type.isFunction(s.setAttribute))){for(olist={},l=(flist=Type.filterElements(this.objectsList,s)).length,i=0;i<l;i++)olist[flist[i].id]=flist[i];s=new Composition(olist)}else Type.isObject(s)&&Type.exists(s.id)&&!Type.exists(this.objects[s.id])&&(s=null);return s},hasPoint:function(x,y){var px=x,py=y,bbox=this.getBoundingBox();return Type.exists(x)&&Type.isArray(x.usrCoords)&&(px=x.usrCoords[1],py=x.usrCoords[2]),!!(Type.isNumber(px)&&Type.isNumber(py)&&bbox[0]<px&&px<bbox[2]&&bbox[1]>py&&py>bbox[3])},updateCSSTransforms:function(){var obj=this.containerObj,o=obj,o2=obj;for(this.cssTransMat=Env.getCSSTransformMatrix(o),o=o.offsetParent;o;){for(this.cssTransMat=Mat.matMatMult(Env.getCSSTransformMatrix(o),this.cssTransMat),o2=o2.parentNode;o2!==o;)this.cssTransMat=Mat.matMatMult(Env.getCSSTransformMatrix(o),this.cssTransMat),o2=o2.parentNode||o2.host;o=o.offsetParent}return this.cssTransMat=Mat.inverse(this.cssTransMat),this},startSelectionMode:function(){this.selectingMode=!0,this.selectionPolygon.setAttribute({visible:!0}),this.selectingBox=[[0,0],[0,0]],this._setSelectionPolygonFromBox(),this.selectionPolygon.fullUpdate()},stopSelectionMode:function(){return this.selectingMode=!1,this.selectionPolygon.setAttribute({visible:!1}),[this.selectionPolygon.vertices[0].coords,this.selectionPolygon.vertices[2].coords]},_startSelecting:function(pos){this.isSelecting=!0,this.selectingBox=[[pos[0],pos[1]],[pos[0],pos[1]]],this._setSelectionPolygonFromBox()},_moveSelecting:function(pos){this.isSelecting&&(this.selectingBox[1]=[pos[0],pos[1]],this._setSelectionPolygonFromBox(),this.selectionPolygon.fullUpdate())},_stopSelecting:function(evt){var pos=this.getMousePosition(evt);this.isSelecting=!1,this.selectingBox[1]=[pos[0],pos[1]],this._setSelectionPolygonFromBox()},_setSelectionPolygonFromBox:function(){var A=this.selectingBox[0],B=this.selectingBox[1];this.selectionPolygon.vertices[0].setPositionDirectly(JXG.COORDS_BY_SCREEN,[A[0],A[1]]),this.selectionPolygon.vertices[1].setPositionDirectly(JXG.COORDS_BY_SCREEN,[A[0],B[1]]),this.selectionPolygon.vertices[2].setPositionDirectly(JXG.COORDS_BY_SCREEN,[B[0],B[1]]),this.selectionPolygon.vertices[3].setPositionDirectly(JXG.COORDS_BY_SCREEN,[B[0],A[1]])},_testForSelection:function(evt){this._isRequiredKeyPressed(evt,"selection")&&(Type.exists(this.selectionPolygon)||this._createSelectionPolygon(this.attr),this.startSelectionMode())},_createSelectionPolygon:function(attr){var selectionattr;return Type.exists(this.selectionPolygon)||!0===(selectionattr=Type.copyAttributes(attr,Options,"board","selection")).enabled&&(this.selectionPolygon=this.create("polygon",[[0,0],[0,0],[0,0],[0,0]],selectionattr)),this},__evt__down:function(e){},__evt__mousedown:function(e){},__evt__pendown:function(e){},__evt__pointerdown:function(e){},__evt__touchstart:function(e){},__evt__up:function(e){},__evt__mouseup:function(e){},__evt__pointerup:function(e){},__evt__touchend:function(e){},__evt__move:function(e,mode){},__evt__mousemove:function(e,mode){},__evt__penmove:function(e,mode){},__evt__pointermove:function(e,mode){},__evt__touchmove:function(e,mode){},__evt__hit:function(e,el,target){},__evt__mousehit:function(e,el,target){},__evt__update:function(){},__evt__boundingbox:function(){},__evt__startselecting:function(){},__evt__mousestartselecting:function(){},__evt__pointerstartselecting:function(){},__evt__touchstartselecting:function(){},__evt__stopselecting:function(){},__evt__mousestopselecting:function(){},__evt__pointerstopselecting:function(){},__evt__touchstopselecting:function(){},__evt__moveselecting:function(){},__evt__mousemoveselecting:function(){},__evt__pointermoveselecting:function(){},__evt__touchmoveselecting:function(){},__evt:function(){},toFullscreen:function(id){var wrap_id,wrap_node,inner_node;return id=id||this.container,this._fullscreen_inner_id=id,inner_node=this.document.getElementById(id),wrap_id="fullscreenwrap_"+id,this.document.getElementById(wrap_id)?wrap_node=this.document.getElementById(wrap_id):((wrap_node=document.createElement("div")).classList.add("JXG_wrap_private"),wrap_node.setAttribute("id",wrap_id),inner_node.parentNode.insertBefore(wrap_node,inner_node),wrap_node.appendChild(inner_node)),this._fullscreen_res=Env._getScaleFactors(inner_node),wrap_node.requestFullscreen=wrap_node.requestFullscreen||wrap_node.webkitRequestFullscreen||wrap_node.mozRequestFullScreen||wrap_node.msRequestFullscreen,wrap_node.requestFullscreen&&wrap_node.requestFullscreen(),this},fullscreenListener:function(evt){var res,inner_id,inner_node;if(inner_id=this._fullscreen_inner_id,Type.exists(inner_id)){if(this.document.fullscreenElement=this.document.fullscreenElement||this.document.webkitFullscreenElement||this.document.mozFullscreenElement||this.document.msFullscreenElement,inner_node=this.document.getElementById(inner_id),this.document.fullscreenElement)res=this._fullscreen_res,inner_node._cssFullscreenStore={id:this.document.fullscreenElement.id,isFullscreen:!0,margin:inner_node.style.margin,width:inner_node.style.width,scale:res.scale,vshift:res.vshift},inner_node.style.margin="",inner_node.style.width=res.width+"px",Env.scaleJSXGraphDiv(document.fullscreenElement.id,inner_id,res.scale,res.vshift),this.document.fullscreenElement=null;else if(Type.exists(inner_node._cssFullscreenStore)){try{this.document.styleSheets[this.document.styleSheets.length-1].deleteRule(0)}catch(err){console.log("JSXGraph: Could not remove CSS rules for full screen mode")}inner_node._cssFullscreenStore.isFullscreen=!1,inner_node.style.margin=inner_node._cssFullscreenStore.margin,inner_node.style.width=inner_node._cssFullscreenStore.width}this.updateCSSTransforms()}},createRoulette:function(c1,c2,start_c1,stepsize,direction,time,pointlist){var brd=this;return new function(){var c1dist,alpha=0,Tx=0,Ty=0,t1=start_c1,t2=Numerics.root((function(t){var c1x=c1.X(t1),c1y=c1.Y(t1),c2x=c2.X(t),c2y=c2.Y(t);return(c1x-c2x)*(c1x-c2x)+(c1y-c2y)*(c1y-c2y)}),[0,2*Math.PI]),t1_new=0,t2_new=0,rotation=brd.create("transform",[function(){return alpha}],{type:"rotate"}),rotationLocal=brd.create("transform",[function(){return alpha},function(){return c1.X(t1)},function(){return c1.Y(t1)}],{type:"rotate"}),translate=brd.create("transform",[function(){return Tx},function(){return Ty}],{type:"translate"}),arclen=function(c,a,b){var cpxa=Numerics.D(c.X)(a),cpya=Numerics.D(c.Y)(a),cpxb=Numerics.D(c.X)(b),cpyb=Numerics.D(c.Y)(b),cpxab=Numerics.D(c.X)(.5*(a+b)),cpyab=Numerics.D(c.Y)(.5*(a+b)),fa=Math.sqrt(cpxa*cpxa+cpya*cpya),fb=Math.sqrt(cpxb*cpxb+cpyb*cpyb);return(fa+4*Math.sqrt(cpxab*cpxab+cpyab*cpyab)+fb)*(b-a)/6},exactDist=function(t){return c1dist-arclen(c2,t2,t)},beta=Math.PI/18,beta9=9*beta,interval=null;return this.rolling=function(){var h,g,hp,gp,z;c1dist=arclen(c1,t1,t1_new=t1+direction*stepsize),t2_new=Numerics.root(exactDist,t2),h=new Complex(c1.X(t1_new),c1.Y(t1_new)),g=new Complex(c2.X(t2_new),c2.Y(t2_new)),hp=new Complex(Numerics.D(c1.X)(t1_new),Numerics.D(c1.Y)(t1_new)),gp=new Complex(Numerics.D(c2.X)(t2_new),Numerics.D(c2.Y)(t2_new)),z=Complex.C.div(hp,gp),alpha=Math.atan2(z.imaginary,z.real),z.div(Complex.C.abs(z)),z.mult(g),Tx=h.real-z.real,Ty=h.imaginary-z.imaginary,alpha<-beta&&alpha>-beta9?(alpha=-beta,rotationLocal.applyOnce(pointlist)):alpha>beta&&alpha<beta9?(alpha=beta,rotationLocal.applyOnce(pointlist)):(rotation.applyOnce(pointlist),translate.applyOnce(pointlist),t1=t1_new,t2=t2_new),brd.update()},this.start=function(){return time>0&&(interval=window.setInterval(this.rolling,time)),this},this.stop=function(){return window.clearInterval(interval),this},this}}}),JXG.Board})),define("renderer/svg",["jxg","options","renderer/abstract","base/constants","utils/type","utils/color","utils/base64","math/numerics"],(function(JXG,Options,AbstractRenderer,Const,Type,Color,Base64,Numerics){return JXG.SVGRenderer=function(container,dim){var i;for(this.type="svg",this.isIE=-1!==navigator.appVersion.indexOf("MSIE")||navigator.userAgent.match(/Trident\//),this.svgRoot=null,this.svgNamespace="http://www.w3.org/2000/svg",this.xlinkNamespace="http://www.w3.org/1999/xlink",this.container=container,this.container.style.MozUserSelect="none",this.container.style.userSelect="none",this.container.style.overflow="hidden",""===this.container.style.position&&(this.container.style.position="relative"),this.svgRoot=this.container.ownerDocument.createElementNS(this.svgNamespace,"svg"),this.svgRoot.style.overflow="hidden",this.svgRoot.style.display="block",this.resize(dim.width,dim.height),this.container.appendChild(this.svgRoot),this.defs=this.container.ownerDocument.createElementNS(this.svgNamespace,"defs"),this.svgRoot.appendChild(this.defs),this.filter=this.container.ownerDocument.createElementNS(this.svgNamespace,"filter"),this.filter.setAttributeNS(null,"id",this.container.id+"_f1"),this.filter.setAttributeNS(null,"width","300%"),this.filter.setAttributeNS(null,"height","300%"),this.filter.setAttributeNS(null,"filterUnits","userSpaceOnUse"),this.feOffset=this.container.ownerDocument.createElementNS(this.svgNamespace,"feOffset"),this.feOffset.setAttributeNS(null,"result","offOut"),this.feOffset.setAttributeNS(null,"in","SourceAlpha"),this.feOffset.setAttributeNS(null,"dx","5"),this.feOffset.setAttributeNS(null,"dy","5"),this.filter.appendChild(this.feOffset),this.feGaussianBlur=this.container.ownerDocument.createElementNS(this.svgNamespace,"feGaussianBlur"),this.feGaussianBlur.setAttributeNS(null,"result","blurOut"),this.feGaussianBlur.setAttributeNS(null,"in","offOut"),this.feGaussianBlur.setAttributeNS(null,"stdDeviation","3"),this.filter.appendChild(this.feGaussianBlur),this.feBlend=this.container.ownerDocument.createElementNS(this.svgNamespace,"feBlend"),this.feBlend.setAttributeNS(null,"in","SourceGraphic"),this.feBlend.setAttributeNS(null,"in2","blurOut"),this.feBlend.setAttributeNS(null,"mode","normal"),this.filter.appendChild(this.feBlend),this.defs.appendChild(this.filter),this.layer=[],i=0;i<Options.layer.numlayers;i++)this.layer[i]=this.container.ownerDocument.createElementNS(this.svgNamespace,"g"),this.svgRoot.appendChild(this.layer[i]);this.supportsForeignObject=document.implementation.hasFeature("http://w3.org/TR/SVG11/feature#Extensibility","1.1"),this.supportsForeignObject&&(this.foreignObjLayer=this.container.ownerDocument.createElementNS(this.svgNamespace,"foreignObject"),this.foreignObjLayer.setAttribute("display","none"),this.foreignObjLayer.setAttribute("x",0),this.foreignObjLayer.setAttribute("y",0),this.foreignObjLayer.setAttribute("width","100%"),this.foreignObjLayer.setAttribute("height","100%"),this.foreignObjLayer.setAttribute("id",this.container.id+"_foreignObj"),this.svgRoot.appendChild(this.foreignObjLayer)),this.dashArray=["2, 2","5, 5","10, 10","20, 20","20, 10, 10, 10","20, 5, 10, 5"]},JXG.SVGRenderer.prototype=new AbstractRenderer,JXG.extend(JXG.SVGRenderer.prototype,{_createArrowHead:function(el,idAppendix,type){var node2,node3,v,h,id=el.id+"Triangle";return Type.exists(idAppendix)&&(id+=idAppendix),(node2=this.createPrim("marker",id)).setAttributeNS(null,"stroke",Type.evaluate(el.visProp.strokecolor)),node2.setAttributeNS(null,"stroke-opacity",Type.evaluate(el.visProp.strokeopacity)),node2.setAttributeNS(null,"fill",Type.evaluate(el.visProp.strokecolor)),node2.setAttributeNS(null,"fill-opacity",Type.evaluate(el.visProp.strokeopacity)),node2.setAttributeNS(null,"stroke-width",0),node2.setAttributeNS(null,"orient","auto"),node2.setAttributeNS(null,"markerUnits","strokeWidth"),node3=this.container.ownerDocument.createElementNS(this.svgNamespace,"path"),h=5,"End"===idAppendix?(v=0,2===type?node3.setAttributeNS(null,"d","M 10,0 L 0,5 L 10,10 L 5,5 z"):3===type?node3.setAttributeNS(null,"d","M 0,0 L 3.33,0 L 3.33,10 L 0,10 z"):4===type?(h=3.31,node3.setAttributeNS(null,"d","M 0.00,3.31 C 3.53,3.84 7.13,4.50 10.00,6.63 C 9.33,5.52 8.67,4.42 8.00,3.31 C 8.67,2.21 9.33,1.10 10.00,0.00 C 7.13,2.13 3.53,2.79 0.00,3.31")):5===type?(h=3.28,node3.setAttributeNS(null,"d","M 0.00,3.28 C 3.39,4.19 6.81,5.07 10.00,6.55 C 9.38,5.56 9.00,4.44 9.00,3.28 C 9.00,2.11 9.38,0.99 10.00,0.00 C 6.81,1.49 3.39,2.37 0.00,3.28")):6===type?(h=2.84,node3.setAttributeNS(null,"d","M 0.00,2.84 C 3.39,3.59 6.79,4.35 10.00,5.68 C 9.67,4.73 9.33,3.78 9.00,2.84 C 9.33,1.89 9.67,0.95 10.00,0.00 C 6.79,1.33 3.39,2.09 0.00,2.84")):7===type?(h=5.2,node3.setAttributeNS(null,"d","M 0.00,5.20 C 4.04,5.20 7.99,6.92 10.00,10.39 M 10.00,0.00 C 7.99,3.47 4.04,5.20 0.00,5.20")):node3.setAttributeNS(null,"d","M 10,0 L 0,5 L 10,10 z"),el.elementClass===Const.OBJECT_CLASS_LINE&&(v=2===type?4.9:3===type?3.3:4===type||5===type||6===type?6.66:7===type?0:10)):(v=10,2===type?node3.setAttributeNS(null,"d","M 0,0 L 10,5 L 0,10 L 5,5 z"):3===type?(v=3.3,node3.setAttributeNS(null,"d","M 0,0 L 3.33,0 L 3.33,10 L 0,10 z")):4===type?(h=3.31,node3.setAttributeNS(null,"d","M 10.00,3.31 C 6.47,3.84 2.87,4.50 0.00,6.63 C 0.67,5.52 1.33,4.42 2.00,3.31 C 1.33,2.21 0.67,1.10 0.00,0.00 C 2.87,2.13 6.47,2.79 10.00,3.31")):5===type?(h=3.28,node3.setAttributeNS(null,"d","M 10.00,3.28 C 6.61,4.19 3.19,5.07 0.00,6.55 C 0.62,5.56 1.00,4.44 1.00,3.28 C 1.00,2.11 0.62,0.99 0.00,0.00 C 3.19,1.49 6.61,2.37 10.00,3.28")):6===type?(h=2.84,node3.setAttributeNS(null,"d","M 10.00,2.84 C 6.61,3.59 3.21,4.35 0.00,5.68 C 0.33,4.73 0.67,3.78 1.00,2.84 C 0.67,1.89 0.33,0.95 0.00,0.00 C 3.21,1.33 6.61,2.09 10.00,2.84")):7===type?(h=5.2,node3.setAttributeNS(null,"d","M 10.00,5.20 C 5.96,5.20 2.01,6.92 0.00,10.39 M 0.00,0.00 C 2.01,3.47 5.96,5.20 10.00,5.20")):node3.setAttributeNS(null,"d","M 0,0 L 10,5 L 0,10 z"),el.elementClass===Const.OBJECT_CLASS_LINE&&(v=2===type?5.1:3===type?.02:4===type||5===type||6===type?3.33:7===type?10:.05)),7===type&&(node2.setAttributeNS(null,"fill","none"),node2.setAttributeNS(null,"stroke-width",1)),node2.setAttributeNS(null,"refY",h),node2.setAttributeNS(null,"refX",v),node2.appendChild(node3),node2},_setArrowColor:function(node,color,opacity,el,type){node&&(Type.isString(color)&&(7!==type?this._setAttribute((function(){node.setAttributeNS(null,"stroke",color),node.setAttributeNS(null,"fill",color),node.setAttributeNS(null,"stroke-opacity",opacity),node.setAttributeNS(null,"fill-opacity",opacity)}),el.visPropOld.fillcolor):this._setAttribute((function(){node.setAttributeNS(null,"fill","none"),node.setAttributeNS(null,"stroke",color),node.setAttributeNS(null,"stroke-opacity",opacity)}),el.visPropOld.fillcolor)),this.isIE&&el.rendNode.parentNode.insertBefore(el.rendNode,el.rendNode))},_setArrowWidth:function(node,width,parentNode,size){var s,d;node&&(d=(s=width)*size,node.setAttributeNS(null,"viewBox","0 0 "+10*s+" "+10*s),node.setAttributeNS(null,"markerHeight",d),node.setAttributeNS(null,"markerWidth",d),node.setAttributeNS(null,"display","inherit"),this.isIE&&parentNode.parentNode.insertBefore(parentNode,parentNode))},updateTicks:function(ticks){var i,j,c,node,x,y,len2,str,tickStr="",len=ticks.ticks.length,isReal=!0;for(i=0;i<len;i++){for(x=(c=ticks.ticks[i])[0],y=c[1],len2=x.length,str=" M "+x[0]+" "+y[0],Type.isNumber(x[0])||(isReal=!1),j=1;isReal&&j<len2;++j)Type.isNumber(x[j])?str+=" L "+x[j]+" "+y[j]:isReal=!1;isReal&&(tickStr+=str)}node=ticks.rendNode,Type.exists(node)||(node=this.createPrim("path",ticks.id),this.appendChildPrim(node,Type.evaluate(ticks.visProp.layer)),ticks.rendNode=node),node.setAttributeNS(null,"stroke",Type.evaluate(ticks.visProp.strokecolor)),node.setAttributeNS(null,"fill","none"),node.setAttributeNS(null,"stroke-opacity",Type.evaluate(ticks.visProp.strokeopacity)),node.setAttributeNS(null,"stroke-width",Type.evaluate(ticks.visProp.strokewidth)),this.updatePathPrim(node,tickStr,ticks.board)},displayCopyright:function(str,fontsize){var t,node=this.createPrim("text","licenseText");node.setAttributeNS(null,"x","20px"),node.setAttributeNS(null,"y",2+fontsize+"px"),node.setAttributeNS(null,"style","font-family:Arial,Helvetica,sans-serif; font-size:"+fontsize+"px; fill:#356AA0; opacity:0.3;"),t=this.container.ownerDocument.createTextNode(str),node.appendChild(t),this.appendChildPrim(node,0)},drawInternalText:function(el){var node=this.createPrim("text",el.id);return node.style.whiteSpace="nowrap",el.rendNodeText=this.container.ownerDocument.createTextNode(""),node.appendChild(el.rendNodeText),this.appendChildPrim(node,Type.evaluate(el.visProp.layer)),node},updateInternalText:function(el){var v,content=el.plaintext,ev_ax=el.getAnchorX(),ev_ay=el.getAnchorY();el.rendNode.getAttributeNS(null,"class")!==el.visProp.cssclass&&(el.rendNode.setAttributeNS(null,"class",Type.evaluate(el.visProp.cssclass)),el.needsSizeUpdate=!0),isNaN(el.coords.scrCoords[1]+el.coords.scrCoords[2])||(v=el.coords.scrCoords[1],el.visPropOld.left!==ev_ax+v&&(el.rendNode.setAttributeNS(null,"x",v+"px"),"left"===ev_ax?el.rendNode.setAttributeNS(null,"text-anchor","start"):"right"===ev_ax?el.rendNode.setAttributeNS(null,"text-anchor","end"):"middle"===ev_ax&&el.rendNode.setAttributeNS(null,"text-anchor","middle"),el.visPropOld.left=ev_ax+v),v=el.coords.scrCoords[2],el.visPropOld.top!==ev_ay+v&&(el.rendNode.setAttributeNS(null,"y",v+.5*this.vOffsetText+"px"),"bottom"===ev_ay?el.rendNode.setAttributeNS(null,"dominant-baseline","text-after-edge"):"top"===ev_ay?el.rendNode.setAttributeNS(null,"dy","1.6ex"):"middle"===ev_ay&&el.rendNode.setAttributeNS(null,"dy","0.6ex"),el.visPropOld.top=ev_ay+v)),el.htmlStr!==content&&(el.rendNodeText.data=content,el.htmlStr=content),this.transformImage(el,el.transformations)},updateInternalTextStyle:function(el,strokeColor,strokeOpacity,duration){this.setObjectFillColor(el,strokeColor,strokeOpacity)},drawImage:function(el){var node=this.createPrim("image",el.id);node.setAttributeNS(null,"preserveAspectRatio","none"),this.appendChildPrim(node,Type.evaluate(el.visProp.layer)),el.rendNode=node,this.updateImage(el)},transformImage:function(el,t){var m,node=el.rendNode,str="";t.length>0&&(str+=" matrix("+[(m=this.joinTransforms(el,t))[1][1],m[2][1],m[1][2],m[2][2],m[1][0],m[2][0]].join(",")+") ",node.setAttributeNS(null,"transform",str))},updateImageURL:function(el){var url=Type.evaluate(el.url);return el._src!==url&&(el.imgIsLoaded=!1,el.rendNode.setAttributeNS(this.xlinkNamespace,"xlink:href",url),el._src=url,!0)},updateImageStyle:function(el,doHighlight){var css=Type.evaluate(doHighlight?el.visProp.highlightcssclass:el.visProp.cssclass);el.rendNode.setAttributeNS(null,"class",css)},drawForeignObject:function(el){el.rendNode=this.appendChildPrim(this.createPrim("foreignObject",el.id),Type.evaluate(el.visProp.layer)),this.appendNodesToElement(el,"foreignObject"),this.updateForeignObject(el)},updateForeignObject:function(el){el._useUserSize?el.rendNode.style.overflow="hidden":el.rendNode.style.overflow="visible",this.updateRectPrim(el.rendNode,el.coords.scrCoords[1],el.coords.scrCoords[2]-el.size[1],el.size[0],el.size[1]),el.rendNode.innerHTML=el.content,this._updateVisual(el,{stroke:!0,dash:!0},!0)},appendChildPrim:function(node,level){return Type.exists(level)?level>=Options.layer.numlayers&&(level=Options.layer.numlayers-1):level=0,this.layer[level].appendChild(node),node},createPrim:function(type,id){var node=this.container.ownerDocument.createElementNS(this.svgNamespace,type);return node.setAttributeNS(null,"id",this.container.id+"_"+id),node.style.position="absolute","path"===type&&(node.setAttributeNS(null,"stroke-linecap","round"),node.setAttributeNS(null,"stroke-linejoin","round"),node.setAttributeNS(null,"fill-rule","evenodd")),node},remove:function(shape){Type.exists(shape)&&Type.exists(shape.parentNode)&&shape.parentNode.removeChild(shape)},setLayer:function(el,level){Type.exists(level)?level>=Options.layer.numlayers&&(level=Options.layer.numlayers-1):level=0,this.layer[level].appendChild(el.rendNode)},makeArrows:function(el,a){var node2,ev_fa=a.evFirst,ev_la=a.evLast;el.visPropOld.firstarrow!==ev_fa||el.visPropOld.lastarrow!==ev_la?(ev_fa?(node2=el.rendNodeTriangleStart,Type.exists(node2)?this.defs.appendChild(node2):(node2=this._createArrowHead(el,"End",a.typeFirst),this.defs.appendChild(node2),el.rendNodeTriangleStart=node2,el.rendNode.setAttributeNS(null,"marker-start","url(#"+this.container.id+"_"+el.id+"TriangleEnd)"))):(node2=el.rendNodeTriangleStart,Type.exists(node2)&&this.remove(node2)),ev_la?(node2=el.rendNodeTriangleEnd,Type.exists(node2)?this.defs.appendChild(node2):(node2=this._createArrowHead(el,"Start",a.typeLast),this.defs.appendChild(node2),el.rendNodeTriangleEnd=node2,el.rendNode.setAttributeNS(null,"marker-end","url(#"+this.container.id+"_"+el.id+"TriangleStart)"))):(node2=el.rendNodeTriangleEnd,Type.exists(node2)&&this.remove(node2)),el.visPropOld.firstarrow=ev_fa,el.visPropOld.lastarrow=ev_la):this.isIE&&el.visPropCalc.visible&&(ev_fa||ev_la)&&el.rendNode.parentNode.insertBefore(el.rendNode,el.rendNode)},updateEllipsePrim:function(node,x,y,rx,ry){var huge;huge=2e5,x=Math.abs(x)<huge?x:huge*x/Math.abs(x),y=Math.abs(y)<huge?y:huge*y/Math.abs(y),rx=Math.abs(rx)<huge?rx:huge*rx/Math.abs(rx),ry=Math.abs(ry)<huge?ry:huge*ry/Math.abs(ry),node.setAttributeNS(null,"cx",x),node.setAttributeNS(null,"cy",y),node.setAttributeNS(null,"rx",Math.abs(rx)),node.setAttributeNS(null,"ry",Math.abs(ry))},updateLinePrim:function(node,p1x,p1y,p2x,p2y){var huge;huge=2e5,isNaN(p1x+p1y+p2x+p2y)||(p1x=Math.abs(p1x)<huge?p1x:huge*p1x/Math.abs(p1x),p1y=Math.abs(p1y)<huge?p1y:huge*p1y/Math.abs(p1y),p2x=Math.abs(p2x)<huge?p2x:huge*p2x/Math.abs(p2x),p2y=Math.abs(p2y)<huge?p2y:huge*p2y/Math.abs(p2y),node.setAttributeNS(null,"x1",p1x),node.setAttributeNS(null,"y1",p1y),node.setAttributeNS(null,"x2",p2x),node.setAttributeNS(null,"y2",p2y))},updatePathPrim:function(node,pointString){""===pointString&&(pointString="M 0 0"),node.setAttributeNS(null,"d",pointString)},updatePathStringPoint:function(el,size,type){var s="",scr=el.coords.scrCoords,sqrt32=size*Math.sqrt(3)*.5,s05=.5*size;return"x"===type?s=" M "+(scr[1]-size)+" "+(scr[2]-size)+" L "+(scr[1]+size)+" "+(scr[2]+size)+" M "+(scr[1]+size)+" "+(scr[2]-size)+" L "+(scr[1]-size)+" "+(scr[2]+size):"+"===type?s=" M "+(scr[1]-size)+" "+scr[2]+" L "+(scr[1]+size)+" "+scr[2]+" M "+scr[1]+" "+(scr[2]-size)+" L "+scr[1]+" "+(scr[2]+size):"<>"===type?s=" M "+(scr[1]-size)+" "+scr[2]+" L "+scr[1]+" "+(scr[2]+size)+" L "+(scr[1]+size)+" "+scr[2]+" L "+scr[1]+" "+(scr[2]-size)+" Z ":"^"===type?s=" M "+scr[1]+" "+(scr[2]-size)+" L "+(scr[1]-sqrt32)+" "+(scr[2]+s05)+" L "+(scr[1]+sqrt32)+" "+(scr[2]+s05)+" Z ":"v"===type?s=" M "+scr[1]+" "+(scr[2]+size)+" L "+(scr[1]-sqrt32)+" "+(scr[2]-s05)+" L "+(scr[1]+sqrt32)+" "+(scr[2]-s05)+" Z ":">"===type?s=" M "+(scr[1]+size)+" "+scr[2]+" L "+(scr[1]-s05)+" "+(scr[2]-sqrt32)+" L "+(scr[1]-s05)+" "+(scr[2]+sqrt32)+" Z ":"<"===type&&(s=" M "+(scr[1]-size)+" "+scr[2]+" L "+(scr[1]+s05)+" "+(scr[2]-sqrt32)+" L "+(scr[1]+s05)+" "+(scr[2]+sqrt32)+" Z "),s},updatePathStringPrim:function(el){var i,scr,len,nextSymb=" M ",pStr="";if(el.numberPoints<=0)return"";if(len=Math.min(el.points.length,el.numberPoints),1===el.bezierDegree)for(i=0;i<len;i++)scr=el.points[i].scrCoords,isNaN(scr[1])||isNaN(scr[2])?nextSymb=" M ":(scr[1]=Math.max(Math.min(scr[1],5e3),-5e3),scr[2]=Math.max(Math.min(scr[2],5e3),-5e3),pStr+=nextSymb+scr[1]+" "+scr[2],nextSymb=" L ");else if(3===el.bezierDegree)for(i=0;i<len;)scr=el.points[i].scrCoords,isNaN(scr[1])||isNaN(scr[2])?nextSymb=" M ":(pStr+=nextSymb+scr[1]+" "+scr[2]," C "===nextSymb&&(i+=1,pStr+=" "+(scr=el.points[i].scrCoords)[1]+" "+scr[2],i+=1,pStr+=" "+(scr=el.points[i].scrCoords)[1]+" "+scr[2]),nextSymb=" C "),i+=1;return pStr},updatePathStringBezierPrim:function(el){var i,j,k,scr,lx,ly,len,nextSymb=" M ",pStr="",f=Type.evaluate(el.visProp.strokewidth),isNoPlot="plot"!==Type.evaluate(el.visProp.curvetype);if(el.numberPoints<=0)return"";for(isNoPlot&&el.board.options.curve.RDPsmoothing&&(el.points=Numerics.RamerDouglasPeucker(el.points,.5)),len=Math.min(el.points.length,el.numberPoints),j=1;j<3;j++)for(nextSymb=" M ",i=0;i<len;i++)scr=el.points[i].scrCoords,isNaN(scr[1])||isNaN(scr[2])?nextSymb=" M ":(scr[1]=Math.max(Math.min(scr[1],5e3),-5e3),scr[2]=Math.max(Math.min(scr[2],5e3),-5e3)," M "===nextSymb?pStr+=nextSymb+scr[1]+" "+scr[2]:(k=2*j,pStr+=[nextSymb,lx+.333*(scr[1]-lx)+f*(k*Math.random()-j)," ",ly+.333*(scr[2]-ly)+f*(k*Math.random()-j)," ",lx+.666*(scr[1]-lx)+f*(k*Math.random()-j)," ",ly+.666*(scr[2]-ly)+f*(k*Math.random()-j)," ",scr[1]," ",scr[2]].join("")),nextSymb=" C ",lx=scr[1],ly=scr[2]);return pStr},updatePolygonPrim:function(node,el){var i,scrCoords,pStr="",len=el.vertices.length;for(node.setAttributeNS(null,"stroke","none"),"polygonalchain"===el.elType&&len++,i=0;i<len-1;i++){if(!el.vertices[i].isReal)return void node.setAttributeNS(null,"points","");pStr=pStr+(scrCoords=el.vertices[i].coords.scrCoords)[1]+","+scrCoords[2],i<len-2&&(pStr+=" ")}-1===pStr.indexOf("NaN")&&node.setAttributeNS(null,"points",pStr)},updateRectPrim:function(node,x,y,w,h){node.setAttributeNS(null,"x",x),node.setAttributeNS(null,"y",y),node.setAttributeNS(null,"width",w),node.setAttributeNS(null,"height",h)},setPropertyPrim:function(node,key,val){"stroked"!==key&&node.setAttributeNS(null,key,val)},display:function(el,val){var node;el&&el.rendNode&&(el.visPropOld.visible=val,node=el.rendNode,val?(node.setAttributeNS(null,"display","inline"),node.style.visibility="inherit"):(node.setAttributeNS(null,"display","none"),node.style.visibility="hidden"))},show:function(el){JXG.deprecated("Board.renderer.show()","Board.renderer.display()"),this.display(el,!0)},hide:function(el){JXG.deprecated("Board.renderer.hide()","Board.renderer.display()"),this.display(el,!1)},setBuffering:function(el,type){el.rendNode.setAttribute("buffered-rendering",type)},setDashStyle:function(el){var dashStyle=Type.evaluate(el.visProp.dash),node=el.rendNode;dashStyle>0?node.setAttributeNS(null,"stroke-dasharray",this.dashArray[dashStyle-1]):node.hasAttributeNS(null,"stroke-dasharray")&&node.removeAttributeNS(null,"stroke-dasharray")},setGradient:function(el){var node,node2,node3,fillNode=el.rendNode,ev_g=Type.evaluate(el.visProp.gradient);"linear"===ev_g||"radial"===ev_g?(node=this.createPrim(ev_g+"Gradient",el.id+"_gradient"),node2=this.createPrim("stop",el.id+"_gradient1"),node3=this.createPrim("stop",el.id+"_gradient2"),node.appendChild(node2),node.appendChild(node3),this.defs.appendChild(node),fillNode.setAttributeNS(null,"style","fill:url(#"+this.container.id+"_"+el.id+"_gradient)"),el.gradNode1=node2,el.gradNode2=node3,el.gradNode=node):fillNode.removeAttributeNS(null,"style")},updateGradientAngle:function(node,radians){var f=1,co=Math.cos(radians),si=Math.sin(radians);Math.abs(co)>Math.abs(si)?f/=Math.abs(co):f/=Math.abs(si),co>=0?(node.setAttributeNS(null,"x1",0),node.setAttributeNS(null,"x2",co*f)):(node.setAttributeNS(null,"x1",-co*f),node.setAttributeNS(null,"x2",0)),si>=0?(node.setAttributeNS(null,"y1",0),node.setAttributeNS(null,"y2",si*f)):(node.setAttributeNS(null,"y1",-si*f),node.setAttributeNS(null,"y2",0))},updateGradientCircle:function(node,cx,cy,r,fx,fy,fr){node.setAttributeNS(null,"cx",100*cx+"%"),node.setAttributeNS(null,"cy",100*cy+"%"),node.setAttributeNS(null,"r",100*r+"%"),node.setAttributeNS(null,"fx",100*fx+"%"),node.setAttributeNS(null,"fy",100*fy+"%"),node.setAttributeNS(null,"fr",100*fr+"%")},updateGradient:function(el){var col,op,node2=el.gradNode1,node3=el.gradNode2,ev_g=Type.evaluate(el.visProp.gradient);Type.exists(node2)&&Type.exists(node3)&&(op=(op=Type.evaluate(el.visProp.fillopacity))>0?op:0,col=Type.evaluate(el.visProp.fillcolor),node2.setAttributeNS(null,"style","stop-color:"+col+";stop-opacity:"+op),node3.setAttributeNS(null,"style","stop-color:"+Type.evaluate(el.visProp.gradientsecondcolor)+";stop-opacity:"+Type.evaluate(el.visProp.gradientsecondopacity)),node2.setAttributeNS(null,"offset",100*Type.evaluate(el.visProp.gradientstartoffset)+"%"),node3.setAttributeNS(null,"offset",100*Type.evaluate(el.visProp.gradientendoffset)+"%"),"linear"===ev_g?this.updateGradientAngle(el.gradNode,Type.evaluate(el.visProp.gradientangle)):"radial"===ev_g&&this.updateGradientCircle(el.gradNode,Type.evaluate(el.visProp.gradientcx),Type.evaluate(el.visProp.gradientcy),Type.evaluate(el.visProp.gradientr),Type.evaluate(el.visProp.gradientfx),Type.evaluate(el.visProp.gradientfy),Type.evaluate(el.visProp.gradientfr)))},setObjectTransition:function(el,duration){var transitionStr,i,len,nodes=["rendNode","rendNodeTriangleStart","rendNodeTriangleEnd"];if(void 0===duration&&(duration=Type.evaluate(el.visProp.transitionduration)),duration!==el.visPropOld.transitionduration){for(transitionStr=el.elementClass===Const.OBJECT_CLASS_TEXT&&"html"===Type.evaluate(el.visProp.display)?" color "+duration+"ms, opacity "+duration+"ms":" fill "+duration+"ms, fill-opacity "+duration+"ms, stroke "+duration+"ms, stroke-opacity "+duration+"ms",len=nodes.length,i=0;i<len;++i)el[nodes[i]]&&(el[nodes[i]].style.transition=transitionStr);el.visPropOld.transitionduration=duration}},_setAttribute:function(setFunc,testAttribute){""===testAttribute?setFunc():window.setTimeout(setFunc,1)},setObjectFillColor:function(el,color,opacity,rendNode){var node,c,rgbo,oo,rgba=Type.evaluate(color),o=Type.evaluate(opacity),grad=Type.evaluate(el.visProp.gradient);o=o>0?o:0,el.visPropOld.fillcolor===rgba&&el.visPropOld.fillopacity===o&&null===grad||(Type.exists(rgba)&&!1!==rgba&&(9!==rgba.length?(c=rgba,oo=o):(rgbo=Color.rgba2rgbo(rgba),c=rgbo[0],oo=o*rgbo[1]),node=void 0===rendNode?el.rendNode:rendNode,"none"!==c&&this._setAttribute((function(){node.setAttributeNS(null,"fill",c)}),el.visPropOld.fillcolor),el.type===JXG.OBJECT_TYPE_IMAGE?this._setAttribute((function(){node.setAttributeNS(null,"opacity",oo)}),el.visPropOld.fillopacity):("none"===c?(oo=0,node.setAttributeNS(null,"pointer-events","visibleStroke")):node.setAttributeNS(null,"pointer-events","visiblePainted"),this._setAttribute((function(){node.setAttributeNS(null,"fill-opacity",oo)}),el.visPropOld.fillopacity)),"linear"!==grad&&"radial"!==grad||this.updateGradient(el)),el.visPropOld.fillcolor=rgba,el.visPropOld.fillopacity=o)},setObjectStrokeColor:function(el,color,opacity){var c,rgbo,oo,node,rgba=Type.evaluate(color),o=Type.evaluate(opacity);o=o>0?o:0,el.visPropOld.strokecolor===rgba&&el.visPropOld.strokeopacity===o||(Type.exists(rgba)&&!1!==rgba&&(9!==rgba.length?(c=rgba,oo=o):(rgbo=Color.rgba2rgbo(rgba),c=rgbo[0],oo=o*rgbo[1]),node=el.rendNode,el.elementClass===Const.OBJECT_CLASS_TEXT?"html"===Type.evaluate(el.visProp.display)?this._setAttribute((function(){node.style.color=c,node.style.opacity=oo}),el.visPropOld.strokecolor):this._setAttribute((function(){node.setAttributeNS(null,"style","fill:"+c),node.setAttributeNS(null,"style","fill-opacity:"+oo)}),el.visPropOld.strokecolor):this._setAttribute((function(){node.setAttributeNS(null,"stroke",c),node.setAttributeNS(null,"stroke-opacity",oo)}),el.visPropOld.strokecolor),el.elementClass!==Const.OBJECT_CLASS_CURVE&&el.elementClass!==Const.OBJECT_CLASS_LINE||(Type.evaluate(el.visProp.firstarrow)&&this._setArrowColor(el.rendNodeTriangleStart,c,oo,el,el.visPropCalc.typeFirst),Type.evaluate(el.visProp.lastarrow)&&this._setArrowColor(el.rendNodeTriangleEnd,c,oo,el,el.visPropCalc.typeLast))),el.visPropOld.strokecolor=rgba,el.visPropOld.strokeopacity=o)},setObjectStrokeWidth:function(el,width){var node,w=Type.evaluate(width);isNaN(w)||el.visPropOld.strokewidth===w||(node=el.rendNode,this.setPropertyPrim(node,"stroked","true"),Type.exists(w)&&this.setPropertyPrim(node,"stroke-width",w+"px"),el.visPropOld.strokewidth=w)},setLineCap:function(el){var capStyle=Type.evaluate(el.visProp.linecap);void 0!==capStyle&&""!==capStyle&&el.visPropOld.linecap!==capStyle&&Type.exists(el.rendNode)&&(this.setPropertyPrim(el.rendNode,"stroke-linecap",capStyle),el.visPropOld.linecap=capStyle)},setShadow:function(el){var ev_s=Type.evaluate(el.visProp.shadow);el.visPropOld.shadow!==ev_s&&(Type.exists(el.rendNode)&&(ev_s?el.rendNode.setAttributeNS(null,"filter","url(#"+this.container.id+"_f1)"):el.rendNode.removeAttributeNS(null,"filter")),el.visPropOld.shadow=ev_s)},suspendRedraw:function(){},unsuspendRedraw:function(){},resize:function(w,h){this.svgRoot.setAttribute("width",parseFloat(w)),this.svgRoot.setAttribute("height",parseFloat(h))},createTouchpoints:function(n){var i,na1,na2,node;for(this.touchpoints=[],i=0;i<n;i++)na1="touchpoint1_"+i,node=this.createPrim("path",na1),this.appendChildPrim(node,19),node.setAttributeNS(null,"d","M 0 0"),this.touchpoints.push(node),this.setPropertyPrim(node,"stroked","true"),this.setPropertyPrim(node,"stroke-width","1px"),node.setAttributeNS(null,"stroke","#000000"),node.setAttributeNS(null,"stroke-opacity",1),node.setAttributeNS(null,"display","none"),na2="touchpoint2_"+i,node=this.createPrim("ellipse",na2),this.appendChildPrim(node,19),this.updateEllipsePrim(node,0,0,0,0),this.touchpoints.push(node),this.setPropertyPrim(node,"stroked","true"),this.setPropertyPrim(node,"stroke-width","1px"),node.setAttributeNS(null,"stroke","#000000"),node.setAttributeNS(null,"stroke-opacity",1),node.setAttributeNS(null,"fill","#ffffff"),node.setAttributeNS(null,"fill-opacity",0),node.setAttributeNS(null,"display","none")},showTouchpoint:function(i){this.touchpoints&&i>=0&&2*i<this.touchpoints.length&&(this.touchpoints[2*i].setAttributeNS(null,"display","inline"),this.touchpoints[2*i+1].setAttributeNS(null,"display","inline"))},hideTouchpoint:function(i){this.touchpoints&&i>=0&&2*i<this.touchpoints.length&&(this.touchpoints[2*i].setAttributeNS(null,"display","none"),this.touchpoints[2*i+1].setAttributeNS(null,"display","none"))},updateTouchpoint:function(i,pos){var x,y;this.touchpoints&&i>=0&&2*i<this.touchpoints.length&&(x=pos[0],y=pos[1],this.touchpoints[2*i].setAttributeNS(null,"d","M "+(x-37)+" "+y+" L "+(x+37)+" "+y+" M "+x+" "+(y-37)+" L "+x+" "+(y+37)),this.updateEllipsePrim(this.touchpoints[2*i+1],pos[0],pos[1],25,25))},_getValuesOfDOMElements:function(node){var values=[];if(1===node.nodeType)for(node=node.firstChild;node;)void 0!==node.id&&void 0!==node.value&&values.push([node.id,node.value]),values=values.concat(this._getValuesOfDOMElements(node)),node=node.nextSibling;return values},_getDataUri:function(url,callback){var image=new Image;image.onload=function(){var canvas=document.createElement("canvas");canvas.width=this.naturalWidth,canvas.height=this.naturalHeight,canvas.getContext("2d").drawImage(this,0,0),callback(canvas.toDataURL("image/png")),canvas.remove()},image.src=url},_getImgDataURL:function(svgRoot){var images,len,canvas,ctx,ur,i;if((len=(images=svgRoot.getElementsByTagName("image")).length)>0)for(canvas=document.createElement("canvas"),i=0;i<len;i++){images[i].setAttribute("crossorigin","anonymous"),ctx=canvas.getContext("2d"),canvas.width=images[i].getAttribute("width"),canvas.height=images[i].getAttribute("height");try{ctx.drawImage(images[i],0,0,canvas.width,canvas.height),ur=canvas.toDataURL(),images[i].setAttribute("xlink:href",ur)}catch(err){console.log("CORS problem! Image can not be used",err)}}return!0},dumpToDataURI:function(ignoreTexts){var svg,i,len,svgRoot=this.svgRoot,btoa=window.btoa||Base64.encode,values=[];if(this.container.hasChildNodes()&&Type.exists(this.foreignObjLayer))for(ignoreTexts||this.foreignObjLayer.setAttribute("display","inline");svgRoot.nextSibling;)values=values.concat(this._getValuesOfDOMElements(svgRoot.nextSibling)),this.foreignObjLayer.appendChild(svgRoot.nextSibling);if(this._getImgDataURL(svgRoot),svgRoot.setAttribute("xmlns","http://www.w3.org/2000/svg"),svg=(new XMLSerializer).serializeToString(svgRoot),!0!==ignoreTexts)for(len=values.length,i=0;i<len;i++)svg=svg.replace('id="'+values[i][0]+'"','id="'+values[i][0]+'" value="'+values[i][1]+'"');if((svg.match(/xmlns="http:\/\/www.w3.org\/2000\/svg"/g)||[]).length>1&&(svg=svg.replace(/xmlns="http:\/\/www.w3.org\/2000\/svg"/g,"")),svg=svg.replace(/ /g," "),Type.exists(this.foreignObjLayer)&&this.foreignObjLayer.hasChildNodes()){for(;this.foreignObjLayer.firstChild;)this.container.appendChild(this.foreignObjLayer.firstChild);this.foreignObjLayer.setAttribute("display","none")}return"data:image/svg+xml;base64,"+btoa(unescape(encodeURIComponent(svg)))},dumpToCanvas:function(canvasId,w,h,ignoreTexts){var svg,tmpImg,cv,ctx;return(cv=this.container.ownerDocument.getElementById(canvasId)).width=cv.width,ctx=cv.getContext("2d"),void 0!==w&&void 0!==h&&(cv.style.width=parseFloat(w)+"px",cv.style.height=parseFloat(h)+"px",cv.setAttribute("width",parseFloat(w)),cv.setAttribute("height",parseFloat(h))),tmpImg=new Image,svg=this.dumpToDataURI(ignoreTexts),tmpImg.src=svg,"Promise"in window?new Promise((function(resolve,reject){try{tmpImg.onload=function(){ctx.drawImage(tmpImg,0,0,w,h),resolve()}}catch(e){reject(e)}})):(tmpImg.onload=function(){window.setTimeout((function(){try{ctx.drawImage(tmpImg,0,0,w,h)}catch(err){console.log("screenshots not longer supported on IE")}}),200)},this)},screenshot:function(board,imgId,ignoreTexts){var node,canvas,id,img,button,buttonText,w,h,zbar,zbarDisplay,_copyCanvasToImg,doc=this.container.ownerDocument,parent=this.container.parentNode,bas=board.attr.screenshot,newImg=!1;return"no"===this.type||(w=bas.scale*this.container.getBoundingClientRect().width,h=bas.scale*this.container.getBoundingClientRect().height,void 0===imgId||""===imgId?(newImg=!0,(img=new Image).style.width=w+"px",img.style.height=h+"px"):(newImg=!1,img=doc.getElementById(imgId)),newImg&&((node=doc.createElement("div")).style.cssText=bas.css,node.style.width=w+"px",node.style.height=h+"px",node.style.zIndex=this.container.style.zIndex+120,node.style.position="absolute",node.style.top=this.container.offsetTop+"px",node.style.left=this.container.offsetLeft+"px"),canvas=doc.createElement("canvas"),id=Math.random().toString(36).substr(2,5),canvas.setAttribute("id",id),canvas.setAttribute("width",w),canvas.setAttribute("height",h),canvas.style.width=w+"px",canvas.style.height=w+"px",canvas.style.display="none",parent.appendChild(canvas),newImg&&(button=doc.createElement("span"),buttonText=doc.createTextNode("✖"),button.style.cssText=bas.cssButton,button.appendChild(buttonText),button.onclick=function(){node.parentNode.removeChild(node)},node.appendChild(img),node.appendChild(button),parent.insertBefore(node,this.container.nextSibling)),zbar=doc.getElementById(this.container.id+"_navigationbar"),Type.exists(zbar)&&(zbarDisplay=zbar.style.display,zbar.style.display="none"),_copyCanvasToImg=function(){img.src=canvas.toDataURL("image/png"),parent.removeChild(canvas)},"Promise"in window?this.dumpToCanvas(id,w,h,ignoreTexts).then(_copyCanvasToImg):(this.dumpToCanvas(id,w,h,ignoreTexts),window.setTimeout(_copyCanvasToImg,200)),Type.exists(zbar)&&(zbar.style.display=zbarDisplay)),this}}),JXG.SVGRenderer})),define("renderer/vml",["jxg","renderer/abstract","base/constants","utils/type","utils/color","math/math","math/numerics"],(function(JXG,AbstractRenderer,Const,Type,Color,Mat,Numerics){return JXG.VMLRenderer=function(container){this.type="vml",this.container=container,this.container.style.overflow="hidden",""===this.container.style.position&&(this.container.style.position="relative"),this.container.onselectstart=function(){return!1},this.resolution=10,Type.exists(JXG.vmlStylesheet)||(container.ownerDocument.namespaces.add("jxgvml","urn:schemas-microsoft-com:vml"),JXG.vmlStylesheet=this.container.ownerDocument.createStyleSheet(),JXG.vmlStylesheet.addRule(".jxgvml","behavior:url(#default#VML)"));try{container.ownerDocument.namespaces.jxgvml||container.ownerDocument.namespaces.add("jxgvml","urn:schemas-microsoft-com:vml"),this.createNode=function(tagName){return container.ownerDocument.createElement("<jxgvml:"+tagName+' class="jxgvml">')}}catch(e){this.createNode=function(tagName){return container.ownerDocument.createElement("<"+tagName+' xmlns="urn:schemas-microsoft.com:vml" class="jxgvml">')}}this.dashArray=["Solid","1 1","ShortDash","Dash","LongDash","ShortDashDot","LongDashDot"]},JXG.VMLRenderer.prototype=new AbstractRenderer,JXG.extend(JXG.VMLRenderer.prototype,{_setAttr:function(node,key,val,iFlag){try{8===this.container.ownerDocument.documentMode?node[key]=val:node.setAttribute(key,val,iFlag)}catch(e){JXG.debug("_setAttr: "+key+" "+val+"<br>\n")}},updateTicks:function(ticks){var i,len,c,x,y,r=this.resolution,tickArr=[];for(len=ticks.ticks.length,i=0;i<len;i++)x=(c=ticks.ticks[i])[0],y=c[1],Type.isNumber(x[0])&&Type.isNumber(x[1])&&tickArr.push(" m "+Math.round(r*x[0])+", "+Math.round(r*y[0])+" l "+Math.round(r*x[1])+", "+Math.round(r*y[1])+" ");Type.exists(ticks.rendNode)||(ticks.rendNode=this.createPrim("path",ticks.id),this.appendChildPrim(ticks.rendNode,Type.evaluate(ticks.visProp.layer))),this._setAttr(ticks.rendNode,"stroked","true"),this._setAttr(ticks.rendNode,"strokecolor",Type.evaluate(ticks.visProp.strokecolor),1),this._setAttr(ticks.rendNode,"strokeweight",Type.evaluate(ticks.visProp.strokewidth)),this._setAttr(ticks.rendNodeStroke,"opacity",100*Type.evaluate(ticks.visProp.strokeopacity)+"%"),this.updatePathPrim(ticks.rendNode,tickArr,ticks.board)},displayCopyright:function(str,fontsize){var node,t;(node=this.createNode("textbox")).style.position="absolute",this._setAttr(node,"id",this.container.id+"_licenseText"),node.style.left=20,node.style.top=2,node.style.fontSize=fontsize,node.style.color="#356AA0",node.style.fontFamily="Arial,Helvetica,sans-serif",this._setAttr(node,"opacity","30%"),node.style.filter="progid:DXImageTransform.Microsoft.Matrix(M11='1.0', sizingMethod='auto expand', enabled = false) progid:DXImageTransform.Microsoft.Alpha(opacity = 30, enabled = true)",t=this.container.ownerDocument.createTextNode(str),node.appendChild(t),this.appendChildPrim(node,0)},drawInternalText:function(el){var node;return(node=this.createNode("textbox")).style.position="absolute",el.rendNodeText=this.container.ownerDocument.createTextNode(""),node.appendChild(el.rendNodeText),this.appendChildPrim(node,9),node.style.filter="progid:DXImageTransform.Microsoft.Matrix(M11='1.0', sizingMethod='auto expand', enabled = false) progid:DXImageTransform.Microsoft.Alpha(opacity = 100, enabled = false)",node},updateInternalText:function(el){var v,maxX,maxY,minX,minY,i,content=el.plaintext,m=this.joinTransforms(el,el.transformations),offset=[0,0],node=el.rendNode,p=[],ev_ax=el.getAnchorX(),ev_ay=el.getAnchorY();if(!isNaN(el.coords.scrCoords[1]+el.coords.scrCoords[2])){for("right"===ev_ax?offset[0]=1:"middle"===ev_ax&&(offset[0]=.5),"bottom"===ev_ay?offset[1]=1:"middle"===ev_ay&&(offset[1]=.5),p[0]=Mat.matVecMult(m,[1,el.coords.scrCoords[1]-offset[0]*el.size[0],el.coords.scrCoords[2]+(1-offset[1])*el.size[1]+this.vOffsetText]),p[0][1]/=p[0][0],p[0][2]/=p[0][0],p[1]=Mat.matVecMult(m,[1,el.coords.scrCoords[1]+(1-offset[0])*el.size[0],el.coords.scrCoords[2]+(1-offset[1])*el.size[1]+this.vOffsetText]),p[1][1]/=p[1][0],p[1][2]/=p[1][0],p[2]=Mat.matVecMult(m,[1,el.coords.scrCoords[1]+(1-offset[0])*el.size[0],el.coords.scrCoords[2]-offset[1]*el.size[1]+this.vOffsetText]),p[2][1]/=p[2][0],p[2][2]/=p[2][0],p[3]=Mat.matVecMult(m,[1,el.coords.scrCoords[1]-offset[0]*el.size[0],el.coords.scrCoords[2]-offset[1]*el.size[1]+this.vOffsetText]),p[3][1]/=p[3][0],p[3][2]/=p[3][0],maxX=p[0][1],minX=p[0][1],maxY=p[0][2],minY=p[0][2],i=1;i<4;i++)maxX=Math.max(maxX,p[i][1]),minX=Math.min(minX,p[i][1]),maxY=Math.max(maxY,p[i][2]),minY=Math.min(minY,p[i][2]);v=1===offset[0]?Math.floor(el.board.canvasWidth-maxX):Math.floor(minX),el.visPropOld.left!==ev_ax+v&&(1===offset[0]?(el.rendNode.style.right=v+"px",el.rendNode.style.left="auto"):(el.rendNode.style.left=v+"px",el.rendNode.style.right="auto"),el.visPropOld.left=ev_ax+v),v=1===offset[1]?Math.floor(el.board.canvasHeight-maxY):Math.floor(minY),el.visPropOld.top!==ev_ay+v&&(1===offset[1]?(el.rendNode.style.bottom=v+"px",el.rendNode.style.top="auto"):(el.rendNode.style.top=v+"px",el.rendNode.style.bottom="auto"),el.visPropOld.top=ev_ay+v)}el.htmlStr!==content&&(el.rendNodeText.data=content,el.htmlStr=content),node.filters.item(0).M11=m[1][1],node.filters.item(0).M12=m[1][2],node.filters.item(0).M21=m[2][1],node.filters.item(0).M22=m[2][2],node.filters.item(0).enabled=!0},drawImage:function(el){var node;(node=this.container.ownerDocument.createElement("img")).style.position="absolute",this._setAttr(node,"id",this.container.id+"_"+el.id),this.container.appendChild(node),this.appendChildPrim(node,Type.evaluate(el.visProp.layer)),node.style.filter="progid:DXImageTransform.Microsoft.Matrix(M11='1.0', sizingMethod='auto expand') progid:DXImageTransform.Microsoft.Alpha(opacity = 100, enabled = false)",el.rendNode=node,this.updateImage(el)},transformImage:function(el,t){var m,maxX,maxY,minX,minY,i,node=el.rendNode,p=[];if(t.length>0){for(m=this.joinTransforms(el,t),p[0]=Mat.matVecMult(m,el.coords.scrCoords),p[0][1]/=p[0][0],p[0][2]/=p[0][0],p[1]=Mat.matVecMult(m,[1,el.coords.scrCoords[1]+el.size[0],el.coords.scrCoords[2]]),p[1][1]/=p[1][0],p[1][2]/=p[1][0],p[2]=Mat.matVecMult(m,[1,el.coords.scrCoords[1]+el.size[0],el.coords.scrCoords[2]-el.size[1]]),p[2][1]/=p[2][0],p[2][2]/=p[2][0],p[3]=Mat.matVecMult(m,[1,el.coords.scrCoords[1],el.coords.scrCoords[2]-el.size[1]]),p[3][1]/=p[3][0],p[3][2]/=p[3][0],maxX=p[0][1],minX=p[0][1],maxY=p[0][2],minY=p[0][2],i=1;i<4;i++)maxX=Math.max(maxX,p[i][1]),minX=Math.min(minX,p[i][1]),maxY=Math.max(maxY,p[i][2]),minY=Math.min(minY,p[i][2]);node.style.left=Math.floor(minX)+"px",node.style.top=Math.floor(minY)+"px",node.filters.item(0).M11=m[1][1],node.filters.item(0).M12=m[1][2],node.filters.item(0).M21=m[2][1],node.filters.item(0).M22=m[2][2],node.filters.item(0).enabled=!0}},updateImageURL:function(el){var url=Type.evaluate(el.url);this._setAttr(el.rendNode,"src",url)},appendChildPrim:function(node,level){return Type.exists(level)||(level=0),node.style.zIndex=level,this.container.appendChild(node),node},appendNodesToElement:function(el,type){"shape"!==type&&"path"!==type&&"polygon"!==type||(el.rendNodePath=this.getElementById(el.id+"_path")),el.rendNodeFill=this.getElementById(el.id+"_fill"),el.rendNodeStroke=this.getElementById(el.id+"_stroke"),el.rendNodeShadow=this.getElementById(el.id+"_shadow"),el.rendNode=this.getElementById(el.id)},createPrim:function(type,id){var node,pathNode,fillNode=this.createNode("fill"),strokeNode=this.createNode("stroke"),shadowNode=this.createNode("shadow");return this._setAttr(fillNode,"id",this.container.id+"_"+id+"_fill"),this._setAttr(strokeNode,"id",this.container.id+"_"+id+"_stroke"),this._setAttr(shadowNode,"id",this.container.id+"_"+id+"_shadow"),"circle"===type||"ellipse"===type?((node=this.createNode("oval")).appendChild(fillNode),node.appendChild(strokeNode),node.appendChild(shadowNode)):"polygon"===type||"path"===type||"shape"===type||"line"===type?((node=this.createNode("shape")).appendChild(fillNode),node.appendChild(strokeNode),node.appendChild(shadowNode),pathNode=this.createNode("path"),this._setAttr(pathNode,"id",this.container.id+"_"+id+"_path"),node.appendChild(pathNode)):((node=this.createNode(type)).appendChild(fillNode),node.appendChild(strokeNode),node.appendChild(shadowNode)),node.style.position="absolute",node.style.left="0px",node.style.top="0px",this._setAttr(node,"id",this.container.id+"_"+id),node},remove:function(node){Type.exists(node)&&node.removeNode(!0)},makeArrows:function(el){var nodeStroke,ev_fa=Type.evaluate(el.visProp.firstarrow),ev_la=Type.evaluate(el.visProp.lastarrow);el.visPropOld.firstarrow===ev_fa&&el.visPropOld.lastarrow===ev_la||(ev_fa?(nodeStroke=el.rendNodeStroke,this._setAttr(nodeStroke,"startarrow","block"),this._setAttr(nodeStroke,"startarrowlength","long")):(nodeStroke=el.rendNodeStroke,Type.exists(nodeStroke)&&this._setAttr(nodeStroke,"startarrow","none")),ev_la?(nodeStroke=el.rendNodeStroke,this._setAttr(nodeStroke,"id",this.container.id+"_"+el.id+"stroke"),this._setAttr(nodeStroke,"endarrow","block"),this._setAttr(nodeStroke,"endarrowlength","long")):(nodeStroke=el.rendNodeStroke,Type.exists(nodeStroke)&&this._setAttr(nodeStroke,"endarrow","none")),el.visPropOld.firstarrow=ev_fa,el.visPropOld.lastarrow=ev_la)},updateEllipsePrim:function(node,x,y,rx,ry){node.style.left=Math.floor(x-rx)+"px",node.style.top=Math.floor(y-ry)+"px",node.style.width=Math.floor(2*Math.abs(rx))+"px",node.style.height=Math.floor(2*Math.abs(ry))+"px"},updateLinePrim:function(node,p1x,p1y,p2x,p2y,board){var s,r=this.resolution;isNaN(p1x+p1y+p2x+p2y)||(s=["m ",Math.floor(r*p1x),", ",Math.floor(r*p1y)," l ",Math.floor(r*p2x),", ",Math.floor(r*p2y)],this.updatePathPrim(node,s,board))},updatePathPrim:function(node,pointString,board){var x=board.canvasWidth,y=board.canvasHeight;pointString.length<=0&&(pointString=["m 0,0"]),node.style.width=x,node.style.height=y,this._setAttr(node,"coordsize",[Math.floor(this.resolution*x),Math.floor(this.resolution*y)].join(",")),this._setAttr(node,"path",pointString.join(""))},updatePathStringPoint:function(el,size,type){var s=[],mround=Math.round,scr=el.coords.scrCoords,sqrt32=size*Math.sqrt(3)*.5,s05=.5*size,r=this.resolution;return"x"===type?s.push([" m ",mround(r*(scr[1]-size)),", ",mround(r*(scr[2]-size))," l ",mround(r*(scr[1]+size)),", ",mround(r*(scr[2]+size))," m ",mround(r*(scr[1]+size)),", ",mround(r*(scr[2]-size))," l ",mround(r*(scr[1]-size)),", ",mround(r*(scr[2]+size))].join("")):"+"===type?s.push([" m ",mround(r*(scr[1]-size)),", ",mround(r*scr[2])," l ",mround(r*(scr[1]+size)),", ",mround(r*scr[2])," m ",mround(r*scr[1]),", ",mround(r*(scr[2]-size))," l ",mround(r*scr[1]),", ",mround(r*(scr[2]+size))].join("")):"<>"===type?s.push([" m ",mround(r*(scr[1]-size)),", ",mround(r*scr[2])," l ",mround(r*scr[1]),", ",mround(r*(scr[2]+size))," l ",mround(r*(scr[1]+size)),", ",mround(r*scr[2])," l ",mround(r*scr[1]),", ",mround(r*(scr[2]-size))," x e "].join("")):"^"===type?s.push([" m ",mround(r*scr[1]),", ",mround(r*(scr[2]-size))," l ",mround(r*(scr[1]-sqrt32)),", ",mround(r*(scr[2]+s05))," l ",mround(r*(scr[1]+sqrt32)),", ",mround(r*(scr[2]+s05))," x e "].join("")):"v"===type?s.push([" m ",mround(r*scr[1]),", ",mround(r*(scr[2]+size))," l ",mround(r*(scr[1]-sqrt32)),", ",mround(r*(scr[2]-s05))," l ",mround(r*(scr[1]+sqrt32)),", ",mround(r*(scr[2]-s05))," x e "].join("")):">"===type?s.push([" m ",mround(r*(scr[1]+size)),", ",mround(r*scr[2])," l ",mround(r*(scr[1]-s05)),", ",mround(r*(scr[2]-sqrt32))," l ",mround(r*(scr[1]-s05)),", ",mround(r*(scr[2]+sqrt32))," l ",mround(r*(scr[1]+size)),", ",mround(r*scr[2])].join("")):"<"===type&&s.push([" m ",mround(r*(scr[1]-size)),", ",mround(r*scr[2])," l ",mround(r*(scr[1]+s05)),", ",mround(r*(scr[2]-sqrt32))," l ",mround(r*(scr[1]+s05)),", ",mround(r*(scr[2]+sqrt32))," x e "].join("")),s},updatePathStringPrim:function(el){var i,scr,pStr=[],r=this.resolution,mround=Math.round,nextSymb=" m ",len=Math.min(el.numberPoints,8192);if(el.numberPoints<=0)return"";if(len=Math.min(len,el.points.length),1===el.bezierDegree)for(i=0;i<len;i++)scr=el.points[i].scrCoords,isNaN(scr[1])||isNaN(scr[2])?nextSymb=" m ":(scr[1]>2e4?scr[1]=2e4:scr[1]<-2e4&&(scr[1]=-2e4),scr[2]>2e4?scr[2]=2e4:scr[2]<-2e4&&(scr[2]=-2e4),pStr.push([nextSymb,mround(r*scr[1]),", ",mround(r*scr[2])].join("")),nextSymb=" l ");else if(3===el.bezierDegree)for(i=0;i<len;)scr=el.points[i].scrCoords,isNaN(scr[1])||isNaN(scr[2])?nextSymb=" m ":(pStr.push([nextSymb,mround(r*scr[1]),", ",mround(r*scr[2])].join(""))," c "===nextSymb&&(i+=1,scr=el.points[i].scrCoords,pStr.push([" ",mround(r*scr[1]),", ",mround(r*scr[2])].join("")),i+=1,scr=el.points[i].scrCoords,pStr.push([" ",mround(r*scr[1]),", ",mround(r*scr[2])].join(""))),nextSymb=" c "),i+=1;return pStr.push(" e"),pStr},updatePathStringBezierPrim:function(el){var i,j,k,scr,lx,ly,pStr=[],f=Type.evaluate(el.visProp.strokewidth),r=this.resolution,mround=Math.round,nextSymb=" m ",isNoPlot="plot"!==Type.evaluate(el.visProp.curvetype),len=Math.min(el.numberPoints,8192);if(el.numberPoints<=0)return"";for(isNoPlot&&el.board.options.curve.RDPsmoothing&&(el.points=Numerics.RamerDouglasPeucker(el.points,1)),len=Math.min(len,el.points.length),j=1;j<3;j++)for(nextSymb=" m ",i=0;i<len;i++)scr=el.points[i].scrCoords,isNaN(scr[1])||isNaN(scr[2])?nextSymb=" m ":(scr[1]>2e4?scr[1]=2e4:scr[1]<-2e4&&(scr[1]=-2e4),scr[2]>2e4?scr[2]=2e4:scr[2]<-2e4&&(scr[2]=-2e4)," m "===nextSymb?pStr.push([nextSymb,mround(r*scr[1])," ",mround(r*scr[2])].join("")):(k=2*j,pStr.push([nextSymb,mround(r*(lx+.333*(scr[1]-lx)+f*(k*Math.random()-j)))," ",mround(r*(ly+.333*(scr[2]-ly)+f*(k*Math.random()-j)))," ",mround(r*(lx+.666*(scr[1]-lx)+f*(k*Math.random()-j)))," ",mround(r*(ly+.666*(scr[2]-ly)+f*(k*Math.random()-j)))," ",mround(r*scr[1])," ",mround(r*scr[2])].join(""))),nextSymb=" c ",lx=scr[1],ly=scr[2]);return pStr.push(" e"),pStr},updatePolygonPrim:function(node,el){var i,scr,len=el.vertices.length,r=this.resolution,pStr=[];if(this._setAttr(node,"stroked","false"),scr=el.vertices[0].coords.scrCoords,!isNaN(scr[1]+scr[2])){for(pStr.push(["m ",Math.floor(r*scr[1]),",",Math.floor(r*scr[2])," l "].join("")),i=1;i<len-1;i++){if(!el.vertices[i].isReal)return void this.updatePathPrim(node,"",el.board);if(scr=el.vertices[i].coords.scrCoords,isNaN(scr[1]+scr[2]))return;pStr.push(Math.floor(r*scr[1])+","+Math.floor(r*scr[2])),i<len-2&&pStr.push(", ")}pStr.push(" x e"),this.updatePathPrim(node,pStr,el.board)}},updateRectPrim:function(node,x,y,w,h){node.style.left=Math.floor(x)+"px",node.style.top=Math.floor(y)+"px",w>=0&&(node.style.width=w+"px"),h>=0&&(node.style.height=h+"px")},setPropertyPrim:function(node,key,val){var v,keyVml="";switch(key){case"stroke":keyVml="strokecolor";break;case"stroke-width":keyVml="strokeweight";break;case"stroke-dasharray":keyVml="dashstyle"}""!==keyVml&&(v=Type.evaluate(val),this._setAttr(node,keyVml,v))},display:function(el,val){el&&el.rendNode&&(el.visPropOld.visible=val,el.rendNode.style.visibility=val?"inherit":"hidden")},show:function(el){JXG.deprecated("Board.renderer.show()","Board.renderer.display()"),el&&el.rendNode&&(el.rendNode.style.visibility="inherit")},hide:function(el){JXG.deprecated("Board.renderer.hide()","Board.renderer.display()"),el&&el.rendNode&&(el.rendNode.style.visibility="hidden")},setDashStyle:function(el,visProp){var node;visProp.dash>=0&&(node=el.rendNodeStroke,this._setAttr(node,"dashstyle",this.dashArray[visProp.dash]))},setGradient:function(el){var nodeFill=el.rendNodeFill,ev_g=Type.evaluate(el.visProp.gradient);"linear"===ev_g?(this._setAttr(nodeFill,"type","gradient"),this._setAttr(nodeFill,"color2",Type.evaluate(el.visProp.gradientsecondcolor)),this._setAttr(nodeFill,"opacity2",Type.evaluate(el.visProp.gradientsecondopacity)),this._setAttr(nodeFill,"angle",Type.evaluate(el.visProp.gradientangle))):"radial"===ev_g?(this._setAttr(nodeFill,"type","gradientradial"),this._setAttr(nodeFill,"color2",Type.evaluate(el.visProp.gradientsecondcolor)),this._setAttr(nodeFill,"opacity2",Type.evaluate(el.visProp.gradientsecondopacity)),this._setAttr(nodeFill,"focusposition",100*Type.evaluate(el.visProp.gradientpositionx)+"%,"+100*Type.evaluate(el.visProp.gradientpositiony)+"%"),this._setAttr(nodeFill,"focussize","0,0")):this._setAttr(nodeFill,"type","solid")},setObjectFillColor:function(el,color,opacity){var c,rgbo,oo,rgba=Type.evaluate(color),o=Type.evaluate(opacity),node=el.rendNode;o=o>0?o:0,el.visPropOld.fillcolor===rgba&&el.visPropOld.fillopacity===o||(Type.exists(rgba)&&!1!==rgba&&(9!==rgba.length?(c=rgba,oo=o):(c=(rgbo=Color.rgba2rgbo(rgba))[0],oo=o*rgbo[1]),"none"===c||!1===c?this._setAttr(el.rendNode,"filled","false"):(this._setAttr(el.rendNode,"filled","true"),this._setAttr(el.rendNode,"fillcolor",c),Type.exists(oo)&&el.rendNodeFill&&this._setAttr(el.rendNodeFill,"opacity",100*oo+"%")),el.type===Const.OBJECT_TYPE_IMAGE&&node.filters.length>1&&(node.filters.item(1).opacity=Math.round(100*oo),node.filters.item(1).enabled=!0)),el.visPropOld.fillcolor=rgba,el.visPropOld.fillopacity=o)},setObjectStrokeColor:function(el,color,opacity){var c,rgbo,oo,nodeStroke,rgba=Type.evaluate(color),o=Type.evaluate(opacity),node=el.rendNode;o=o>0?o:0,el.visPropOld.strokecolor===rgba&&el.visPropOld.strokeopacity===o||(Type.exists(rgba)&&!1!==rgba&&(9!==rgba.length?(c=rgba,oo=o):(c=(rgbo=color.rgba2rgbo(rgba))[0],oo=o*rgbo[1]),el.elementClass===Const.OBJECT_CLASS_TEXT?(node.filters.length>1&&(node.filters.item(1).opacity=Math.round(100*oo),node.filters.item(1).enabled=!0),node.style.color=c):(!1!==c&&(this._setAttr(node,"stroked","true"),this._setAttr(node,"strokecolor",c)),nodeStroke=el.rendNodeStroke,Type.exists(oo)&&el.type!==Const.OBJECT_TYPE_IMAGE&&this._setAttr(nodeStroke,"opacity",100*oo+"%"))),el.visPropOld.strokecolor=rgba,el.visPropOld.strokeopacity=o)},setObjectStrokeWidth:function(el,width){var node,w=Type.evaluate(width);isNaN(w)||el.visPropOld.strokewidth===w||(node=el.rendNode,this.setPropertyPrim(node,"stroked","true"),Type.exists(w)&&(this.setPropertyPrim(node,"stroke-width",w),0===w&&Type.exists(el.rendNodeStroke)&&this._setAttr(node,"stroked","false")),el.visPropOld.strokewidth=w)},setShadow:function(el){var nodeShadow=el.rendNodeShadow,ev_s=Type.evaluate(el.visProp.shadow);nodeShadow&&el.visPropOld.shadow!==ev_s&&(ev_s?(this._setAttr(nodeShadow,"On","True"),this._setAttr(nodeShadow,"Offset","3pt,3pt"),this._setAttr(nodeShadow,"Opacity","60%"),this._setAttr(nodeShadow,"Color","#aaaaaa")):this._setAttr(nodeShadow,"On","False"),el.visPropOld.shadow=ev_s)},suspendRedraw:function(){this.container.style.display="none"},unsuspendRedraw:function(){this.container.style.display=""}}),JXG.VMLRenderer})),define("renderer/canvas",["jxg","renderer/abstract","base/constants","utils/env","utils/type","utils/uuid","utils/color","base/coords","math/math","math/geometry","math/numerics"],(function(JXG,AbstractRenderer,Const,Env,Type,UUID,Color,Coords,Mat,Geometry,Numerics){return JXG.CanvasRenderer=function(container,dim){if(this.type="canvas",this.canvasRoot=null,this.suspendHandle=null,this.canvasId=UUID.genUUID(),this.canvasNamespace=null,Env.isBrowser)this.container=container,this.container.style.MozUserSelect="none",this.container.style.userSelect="none",this.container.style.overflow="hidden",""===this.container.style.position&&(this.container.style.position="relative"),this.container.innerHTML=['<canvas id="',this.canvasId,'" width="',dim.width,'px" height="',dim.height,'px"><',"/canvas>"].join(""),this.canvasRoot=this.container.ownerDocument.getElementById(this.canvasId),this.canvasRoot.style.display="block",this.context=this.canvasRoot.getContext("2d");else if(Env.isNode())try{this.canvasId="object"===("undefined"==typeof module?"undefined":_typeof(module))?module.require("canvas"):require("canvas"),this.canvasRoot=new this.canvasId(500,500),this.context=this.canvasRoot.getContext("2d")}catch(err){console.log("Warning: 'canvas' not found. You might need to call 'npm install canvas'")}this.dashArray=[[2,2],[5,5],[10,10],[20,20],[20,10,10,10],[20,5,10,5]]},JXG.CanvasRenderer.prototype=new AbstractRenderer,JXG.extend(JXG.CanvasRenderer.prototype,{_drawPolygon:function(shape,degree,doFill){var i,len=shape.length,context=this.context;if(len>0){if(doFill&&(context.lineWidth=0),context.beginPath(),context.moveTo(shape[0][0],shape[0][1]),1===degree)for(i=1;i<len;i++)context.lineTo(shape[i][0],shape[i][1]);else for(i=1;i<len;i+=3)context.bezierCurveTo(shape[i][0],shape[i][1],shape[i+1][0],shape[i+1][1],shape[i+2][0],shape[i+2][1]);doFill?(context.lineTo(shape[0][0],shape[0][1]),context.closePath(),context.fill()):context.stroke()}},_fill:function(el){var context=this.context;context.save(),this._setColor(el,"fill")&&context.fill(),context.restore()},_rotatePoint:function(angle,x,y){return[x*Math.cos(angle)-y*Math.sin(angle),x*Math.sin(angle)+y*Math.cos(angle)]},_rotateShape:function(shape,angle){var i,rv=[],len=shape.length;if(len<=0)return shape;for(i=0;i<len;i++)rv.push(this._rotatePoint(angle,shape[i][0],shape[i][1]));return rv},updateGradientAngle:function(el,radians){var c1,c2,x1,x2,y1,y2,x1s,x2s,y1s,y2s,dx,dy,f=1,co=Math.cos(-radians),si=Math.sin(-radians),bb=el.getBoundingBox();return Math.abs(co)>Math.abs(si)?f/=Math.abs(co):f/=Math.abs(si),co>=0?(x1=0,x2=co*f):(x1=-co*f,x2=0),si>=0?(y1=0,y2=si*f):(y1=-si*f,y2=0),c1=new Coords(Const.COORDS_BY_USER,[bb[0],bb[1]],el.board),dx=(c2=new Coords(Const.COORDS_BY_USER,[bb[2],bb[3]],el.board)).scrCoords[1]-c1.scrCoords[1],dy=c2.scrCoords[2]-c1.scrCoords[2],x1s=c1.scrCoords[1]+dx*x1,y1s=c1.scrCoords[2]+dy*y1,x2s=c1.scrCoords[1]+dx*x2,y2s=c1.scrCoords[2]+dy*y2,this.context.createLinearGradient(x1s,y1s,x2s,y2s)},updateGradientCircle:function(el,cx,cy,r,fx,fy,fr){var c1,c2,cxs,cys,rs,fxs,fys,frs,dx,dy,bb=el.getBoundingBox();return c1=new Coords(Const.COORDS_BY_USER,[bb[0],bb[1]],el.board),dx=(c2=new Coords(Const.COORDS_BY_USER,[bb[2],bb[3]],el.board)).scrCoords[1]-c1.scrCoords[1],dy=c1.scrCoords[2]-c2.scrCoords[2],cxs=c1.scrCoords[1]+dx*cx,cys=c2.scrCoords[2]+dy*cy,fxs=c1.scrCoords[1]+dx*fx,fys=c2.scrCoords[2]+dy*fy,rs=r*(dx+dy)*.5,frs=fr*(dx+dy)*.5,this.context.createRadialGradient(fxs,fys,frs,cxs,cys,rs)},updateGradient:function(el){var col,op,gradient,ev_g=Type.evaluate(el.visProp.gradient);return op=(op=Type.evaluate(el.visProp.fillopacity))>0?op:0,col=Type.evaluate(el.visProp.fillcolor),"linear"===ev_g?gradient=this.updateGradientAngle(el,Type.evaluate(el.visProp.gradientangle)):"radial"===ev_g&&(gradient=this.updateGradientCircle(el,Type.evaluate(el.visProp.gradientcx),Type.evaluate(el.visProp.gradientcy),Type.evaluate(el.visProp.gradientr),Type.evaluate(el.visProp.gradientfx),Type.evaluate(el.visProp.gradientfy),Type.evaluate(el.visProp.gradientfr))),gradient.addColorStop(Type.evaluate(el.visProp.gradientstartoffset),col),gradient.addColorStop(Type.evaluate(el.visProp.gradientendoffset),Type.evaluate(el.visProp.gradientsecondcolor)),gradient},_setColor:function(el,type,targetType){var hl,sw,rgba,rgbo,c,o,oo,grad,hasColor=!0,ev=el.visProp;return type=type||"stroke",targetType=targetType||type,hl=this._getHighlighted(el),"linear"===(grad=Type.evaluate(el.visProp.gradient))||"radial"===grad?(this.context[targetType+"Style"]=this.updateGradient(el),hasColor):("none"!==(rgba=Type.evaluate(ev[hl+type+"color"]))&&!1!==rgba?(o=(o=Type.evaluate(ev[hl+type+"opacity"]))>0?o:0,9!==rgba.length?(c=rgba,oo=o):(c=(rgbo=Color.rgba2rgbo(rgba))[0],oo=o*rgbo[1]),this.context.globalAlpha=oo,this.context[targetType+"Style"]=c):hasColor=!1,sw=parseFloat(Type.evaluate(ev[hl+"strokewidth"])),"stroke"!==type||isNaN(sw)||(0===sw?this.context.globalAlpha=0:this.context.lineWidth=sw),"stroke"===type&&void 0!==ev.linecap&&""!==ev.linecap&&(this.context.lineCap=ev.linecap),hasColor)},_stroke:function(el){var context=this.context,ev_dash=Type.evaluate(el.visProp.dash);context.save(),ev_dash>0?context.setLineDash&&context.setLineDash(this.dashArray[ev_dash]):this.context.lineDashArray=[],this._setColor(el,"stroke")&&context.stroke(),context.restore()},_translateShape:function(shape,x,y){var i,rv=[],len=shape.length;if(len<=0)return shape;for(i=0;i<len;i++)rv.push([shape[i][0]+x,shape[i][1]+y]);return rv},drawPoint:function(el){var f=Type.evaluate(el.visProp.face),size=Type.evaluate(el.visProp.size),scr=el.coords.scrCoords,sqrt32=size*Math.sqrt(3)*.5,s05=.5*size,stroke05=parseFloat(Type.evaluate(el.visProp.strokewidth))/2,context=this.context;if(el.visPropCalc.visible)switch(f){case"cross":case"x":context.beginPath(),context.moveTo(scr[1]-size,scr[2]-size),context.lineTo(scr[1]+size,scr[2]+size),context.moveTo(scr[1]+size,scr[2]-size),context.lineTo(scr[1]-size,scr[2]+size),context.lineCap="round",context.lineJoin="round",context.closePath(),this._stroke(el);break;case"circle":case"o":context.beginPath(),context.arc(scr[1],scr[2],size+1+stroke05,0,2*Math.PI,!1),context.closePath(),this._fill(el),this._stroke(el);break;case"square":case"[]":if(size<=0)break;context.save(),this._setColor(el,"stroke","fill")&&context.fillRect(scr[1]-size-stroke05,scr[2]-size-stroke05,2*size+3*stroke05,2*size+3*stroke05),context.restore(),context.save(),this._setColor(el,"fill"),context.fillRect(scr[1]-size+stroke05,scr[2]-size+stroke05,2*size-stroke05,2*size-stroke05),context.restore();break;case"plus":case"+":context.beginPath(),context.moveTo(scr[1]-size,scr[2]),context.lineTo(scr[1]+size,scr[2]),context.moveTo(scr[1],scr[2]-size),context.lineTo(scr[1],scr[2]+size),context.lineCap="round",context.lineJoin="round",context.closePath(),this._stroke(el);break;case"diamond":case"<>":context.beginPath(),context.moveTo(scr[1]-size,scr[2]),context.lineTo(scr[1],scr[2]+size),context.lineTo(scr[1]+size,scr[2]),context.lineTo(scr[1],scr[2]-size),context.closePath(),this._fill(el),this._stroke(el);break;case"triangleup":case"a":case"^":context.beginPath(),context.moveTo(scr[1],scr[2]-size),context.lineTo(scr[1]-sqrt32,scr[2]+s05),context.lineTo(scr[1]+sqrt32,scr[2]+s05),context.closePath(),this._fill(el),this._stroke(el);break;case"triangledown":case"v":context.beginPath(),context.moveTo(scr[1],scr[2]+size),context.lineTo(scr[1]-sqrt32,scr[2]-s05),context.lineTo(scr[1]+sqrt32,scr[2]-s05),context.closePath(),this._fill(el),this._stroke(el);break;case"triangleleft":case"<":context.beginPath(),context.moveTo(scr[1]-size,scr[2]),context.lineTo(scr[1]+s05,scr[2]-sqrt32),context.lineTo(scr[1]+s05,scr[2]+sqrt32),context.closePath(),this._fill(el),this._stroke(el);break;case"triangleright":case">":context.beginPath(),context.moveTo(scr[1]+size,scr[2]),context.lineTo(scr[1]-s05,scr[2]-sqrt32),context.lineTo(scr[1]-s05,scr[2]+sqrt32),context.closePath(),this._fill(el),this._stroke(el)}},updatePoint:function(el){this.drawPoint(el)},drawArrows:function(el,scr1,scr2,hl,a){var x1,y1,x2,y2,w0,w,arrowHead,arrowTail,type_fa,type_la,doFill,i,len,d1x,d1y,d2x,d2y,last,ang1,ang2,context=this.context,type=1,degree_fa=1,degree_la=1,ev_fa=a.evFirst,ev_la=a.evLast;if("none"!==Type.evaluate(el.visProp.strokecolor)&&(ev_fa||ev_la)){if(el.elementClass===Const.OBJECT_CLASS_LINE)x1=scr1.scrCoords[1],y1=scr1.scrCoords[2],x2=scr2.scrCoords[1],y2=scr2.scrCoords[2],ang1=ang2=Math.atan2(y2-y1,x2-x1);else{if(x1=el.points[0].scrCoords[1],y1=el.points[0].scrCoords[2],(last=el.points.length-1)<1)return;x2=el.points[el.points.length-1].scrCoords[1],y2=el.points[el.points.length-1].scrCoords[2],d1x=el.points[1].scrCoords[1]-el.points[0].scrCoords[1],d1y=el.points[1].scrCoords[2]-el.points[0].scrCoords[2],d2x=el.points[last].scrCoords[1]-el.points[last-1].scrCoords[1],d2y=el.points[last].scrCoords[2]-el.points[last-1].scrCoords[2],ev_fa&&(ang1=Math.atan2(d1y,d1x)),ev_la&&(ang2=Math.atan2(d2y,d2x))}if(w0=Type.evaluate(el.visProp[hl+"strokewidth"]),ev_fa)if(w=w0*a.sizeFirst,type_fa=type=a.typeFirst,2===type)arrowTail=[[w,.5*-w],[0,0],[w,.5*w],[.5*w,0]];else if(3===type)arrowTail=[[w/3,.5*-w],[0,.5*-w],[0,.5*w],[w/3,.5*w]];else if(4===type)for(w/=10,degree_fa=3,len=(arrowTail=[[10,3.31],[6.47,3.84],[2.87,4.5],[0,6.63],[.67,5.52],[1.33,4.42],[2,3.31],[1.33,2.21],[.67,1.1],[0,0],[2.87,2.13],[6.47,2.79],[10,3.31]]).length,i=0;i<len;i++)arrowTail[i][0]*=-w,arrowTail[i][1]*=w,arrowTail[i][0]+=10*w,arrowTail[i][1]-=3.31*w;else if(5===type)for(w/=10,degree_fa=3,len=(arrowTail=[[10,3.28],[6.61,4.19],[3.19,5.07],[0,6.55],[.62,5.56],[1,4.44],[1,3.28],[1,2.11],[.62,.99],[0,0],[3.19,1.49],[6.61,2.37],[10,3.28]]).length,i=0;i<len;i++)arrowTail[i][0]*=-w,arrowTail[i][1]*=w,arrowTail[i][0]+=10*w,arrowTail[i][1]-=3.28*w;else if(6===type)for(w/=10,degree_fa=3,len=(arrowTail=[[10,2.84],[6.61,3.59],[3.21,4.35],[0,5.68],[.33,4.73],[.67,3.78],[1,2.84],[.67,1.89],[.33,.95],[0,0],[3.21,1.33],[6.61,2.09],[10,2.84]]).length,i=0;i<len;i++)arrowTail[i][0]*=-w,arrowTail[i][1]*=w,arrowTail[i][0]+=10*w,arrowTail[i][1]-=2.84*w;else if(7===type)for(w=w0,degree_fa=3,len=(arrowTail=[[0,10.39],[2.01,6.92],[5.96,5.2],[10,5.2],[5.96,5.2],[2.01,3.47],[0,0]]).length,i=0;i<len;i++)arrowTail[i][0]*=-w,arrowTail[i][1]*=w,arrowTail[i][0]+=10*w,arrowTail[i][1]-=5.2*w;else arrowTail=[[w,.5*-w],[0,0],[w,.5*w]];if(ev_la)if(w=w0*a.sizeLast,type_la=type=a.typeLast,2===type)arrowHead=[[-w,.5*-w],[0,0],[-w,.5*w],[.5*-w,0]];else if(3===type)arrowHead=[[-w/3,.5*-w],[0,.5*-w],[0,.5*w],[-w/3,.5*w]];else if(4===type)for(w/=10,degree_la=3,len=(arrowHead=[[10,3.31],[6.47,3.84],[2.87,4.5],[0,6.63],[.67,5.52],[1.33,4.42],[2,3.31],[1.33,2.21],[.67,1.1],[0,0],[2.87,2.13],[6.47,2.79],[10,3.31]]).length,i=0;i<len;i++)arrowHead[i][0]*=w,arrowHead[i][1]*=w,arrowHead[i][0]-=10*w,arrowHead[i][1]-=3.31*w;else if(5===type)for(w/=10,degree_la=3,len=(arrowHead=[[10,3.28],[6.61,4.19],[3.19,5.07],[0,6.55],[.62,5.56],[1,4.44],[1,3.28],[1,2.11],[.62,.99],[0,0],[3.19,1.49],[6.61,2.37],[10,3.28]]).length,i=0;i<len;i++)arrowHead[i][0]*=w,arrowHead[i][1]*=w,arrowHead[i][0]-=10*w,arrowHead[i][1]-=3.28*w;else if(6===type)for(w/=10,degree_la=3,len=(arrowHead=[[10,2.84],[6.61,3.59],[3.21,4.35],[0,5.68],[.33,4.73],[.67,3.78],[1,2.84],[.67,1.89],[.33,.95],[0,0],[3.21,1.33],[6.61,2.09],[10,2.84]]).length,i=0;i<len;i++)arrowHead[i][0]*=w,arrowHead[i][1]*=w,arrowHead[i][0]-=10*w,arrowHead[i][1]-=2.84*w;else if(7===type)for(w=w0,degree_la=3,len=(arrowHead=[[0,10.39],[2.01,6.92],[5.96,5.2],[10,5.2],[5.96,5.2],[2.01,3.47],[0,0]]).length,i=0;i<len;i++)arrowHead[i][0]*=w,arrowHead[i][1]*=w,arrowHead[i][0]-=10*w,arrowHead[i][1]-=5.2*w;else arrowHead=[[-w,.5*-w],[0,0],[-w,.5*w]];context.save(),this._setColor(el,"stroke","fill")&&(this._setColor(el,"stroke"),ev_fa&&(doFill=7!==type_fa,this._drawPolygon(this._translateShape(this._rotateShape(arrowTail,ang1),x1,y1),degree_fa,doFill)),ev_la&&(doFill=7!==type_la,this._drawPolygon(this._translateShape(this._rotateShape(arrowHead,ang2),x2,y2),degree_la,doFill))),context.restore()}},drawLine:function(el){var c1_org,c2_org,hl,w,arrowData,c1=new Coords(Const.COORDS_BY_USER,el.point1.coords.usrCoords,el.board),c2=new Coords(Const.COORDS_BY_USER,el.point2.coords.usrCoords,el.board),margin=null;el.visPropCalc.visible&&(hl=this._getHighlighted(el),w=Type.evaluate(el.visProp[hl+"strokewidth"]),((arrowData=this.getArrowHeadData(el,w,hl)).evFirst||arrowData.evLast)&&(margin=-4),Geometry.calcStraight(el,c1,c2,margin),this.handleTouchpoints(el,c1,c2,arrowData),c1_org=new Coords(Const.COORDS_BY_USER,c1.usrCoords,el.board),c2_org=new Coords(Const.COORDS_BY_USER,c2.usrCoords,el.board),this.getPositionArrowHead(el,c1,c2,arrowData),this.context.beginPath(),this.context.moveTo(c1.scrCoords[1],c1.scrCoords[2]),this.context.lineTo(c2.scrCoords[1],c2.scrCoords[2]),this._stroke(el),(arrowData.evFirst||arrowData.evLast)&&this.drawArrows(el,c1_org,c2_org,hl,arrowData))},updateLine:function(el){this.drawLine(el)},drawTicks:function(){},updateTicks:function(ticks){var i,c,x,y,len2,j,len=ticks.ticks.length,context=this.context;for(context.beginPath(),i=0;i<len;i++)for(x=(c=ticks.ticks[i])[0],y=c[1],len2=x.length,context.moveTo(x[0],y[0]),j=1;j<len2;++j)context.lineTo(x[j],y[j]);context.lineCap="round",this._stroke(ticks)},drawCurve:function(el){var hl,w,arrowData;Type.evaluate(el.visProp.handdrawing)?this.updatePathStringBezierPrim(el):this.updatePathStringPrim(el),el.numberPoints>1&&(hl=this._getHighlighted(el),w=Type.evaluate(el.visProp[hl+"strokewidth"]),((arrowData=this.getArrowHeadData(el,w,hl)).evFirst||arrowData.evLast)&&this.drawArrows(el,null,null,hl,arrowData))},updateCurve:function(el){this.drawCurve(el)},drawEllipse:function(el){var m1=el.center.coords.scrCoords[1],m2=el.center.coords.scrCoords[2],sX=el.board.unitX,sY=el.board.unitY,rX=2*el.Radius(),rY=2*el.Radius(),aWidth=rX*sX,aHeight=rY*sY,aX=m1-aWidth/2,aY=m2-aHeight/2,hB=aWidth/2*.5522848,vB=aHeight/2*.5522848,eX=aX+aWidth,eY=aY+aHeight,mX=aX+aWidth/2,mY=aY+aHeight/2,context=this.context;rX>0&&rY>0&&!isNaN(m1+m2)&&(context.beginPath(),context.moveTo(aX,mY),context.bezierCurveTo(aX,mY-vB,mX-hB,aY,mX,aY),context.bezierCurveTo(mX+hB,aY,eX,mY-vB,eX,mY),context.bezierCurveTo(eX,mY+vB,mX+hB,eY,mX,eY),context.bezierCurveTo(mX-hB,eY,aX,mY+vB,aX,mY),context.closePath(),this._fill(el),this._stroke(el))},updateEllipse:function(el){return this.drawEllipse(el)},displayCopyright:function(str,fontSize){var context=this.context;context.save(),context.font=fontSize+"px Arial",context.fillStyle="#aaa",context.lineWidth=.5,context.fillText(str,10,2+fontSize),context.restore()},drawInternalText:function(el){var ev_fs=Type.evaluate(el.visProp.fontsize),fontUnit=Type.evaluate(el.visProp.fontunit),ev_ax=el.getAnchorX(),ev_ay=el.getAnchorY(),context=this.context;return context.save(),this._setColor(el,"stroke","fill")&&!isNaN(el.coords.scrCoords[1]+el.coords.scrCoords[2])&&(context.font=(ev_fs>0?ev_fs:0)+fontUnit+" Arial",this.transformImage(el,el.transformations),"left"===ev_ax?context.textAlign="left":"right"===ev_ax?context.textAlign="right":"middle"===ev_ax&&(context.textAlign="center"),"bottom"===ev_ay?context.textBaseline="bottom":"top"===ev_ay?context.textBaseline="top":"middle"===ev_ay&&(context.textBaseline="middle"),context.fillText(el.plaintext,el.coords.scrCoords[1],el.coords.scrCoords[2])),context.restore(),null},updateInternalText:function(el){this.drawInternalText(el)},setObjectStrokeColor:function(el,color,opacity){var c,rgbo,oo,node,rgba=Type.evaluate(color),o=Type.evaluate(opacity);o=o>0?o:0,el.visPropOld.strokecolor===rgba&&el.visPropOld.strokeopacity===o||(Type.exists(rgba)&&!1!==rgba&&(9!==rgba.length?(c=rgba,oo=o):(c=(rgbo=Color.rgba2rgbo(rgba))[0],oo=o*rgbo[1]),node=el.rendNode,el.elementClass===Const.OBJECT_CLASS_TEXT&&"html"===Type.evaluate(el.visProp.display)&&(node.style.color=c,node.style.opacity=oo)),el.visPropOld.strokecolor=rgba,el.visPropOld.strokeopacity=o)},drawImage:function(el){el.rendNode=new Image,el._src="",this.updateImage(el)},updateImage:function(el){var context=this.context,o=Type.evaluate(el.visProp.fillopacity),paintImg=Type.bind((function(){el.imgIsLoaded=!0,el.size[0]<=0||el.size[1]<=0||(context.save(),context.globalAlpha=o,this.transformImage(el,el.transformations),context.drawImage(el.rendNode,el.coords.scrCoords[1],el.coords.scrCoords[2]-el.size[1],el.size[0],el.size[1]),context.restore())}),this);this.updateImageURL(el)?el.rendNode.onload=paintImg:el.imgIsLoaded&&paintImg()},transformImage:function(el,t){var m,len=t.length,ctx=this.context;len>0&&(m=this.joinTransforms(el,t),Math.abs(Numerics.det(m))>=Mat.eps&&ctx.transform(m[1][1],m[2][1],m[1][2],m[2][2],m[1][0],m[2][0]))},updateImageURL:function(el){var url;return url=Type.evaluate(el.url),el._src!==url&&(el.imgIsLoaded=!1,el.rendNode.src=url,el._src=url,!0)},remove:function(shape){Type.exists(shape)&&Type.exists(shape.parentNode)&&shape.parentNode.removeChild(shape)},updatePathStringPrim:function(el){var i,scr,scr1,scr2,len,nextSymb="M",context=this.context;if(!(el.numberPoints<=0)){if(len=Math.min(el.points.length,el.numberPoints),context.beginPath(),1===el.bezierDegree)for(i=0;i<len;i++)scr=el.points[i].scrCoords,isNaN(scr[1])||isNaN(scr[2])?nextSymb="M":(scr[1]>5e3?scr[1]=5e3:scr[1]<-5e3&&(scr[1]=-5e3),scr[2]>5e3?scr[2]=5e3:scr[2]<-5e3&&(scr[2]=-5e3),"M"===nextSymb?context.moveTo(scr[1],scr[2]):context.lineTo(scr[1],scr[2]),nextSymb="L");else if(3===el.bezierDegree)for(i=0;i<len;)scr=el.points[i].scrCoords,isNaN(scr[1])||isNaN(scr[2])?nextSymb="M":("M"===nextSymb?context.moveTo(scr[1],scr[2]):(i+=1,scr1=el.points[i].scrCoords,i+=1,scr2=el.points[i].scrCoords,context.bezierCurveTo(scr[1],scr[2],scr1[1],scr1[2],scr2[1],scr2[2])),nextSymb="C"),i+=1;context.lineCap="round",this._fill(el),this._stroke(el)}},updatePathStringBezierPrim:function(el){var i,j,k,scr,lx,ly,len,nextSymb="M",f=Type.evaluate(el.visProp.strokewidth),isNoPlot="plot"!==Type.evaluate(el.visProp.curvetype),context=this.context;if(!(el.numberPoints<=0)){for(isNoPlot&&el.board.options.curve.RDPsmoothing&&(el.points=Numerics.RamerDouglasPeucker(el.points,.5)),len=Math.min(el.points.length,el.numberPoints),context.beginPath(),j=1;j<3;j++)for(nextSymb="M",i=0;i<len;i++)scr=el.points[i].scrCoords,isNaN(scr[1])||isNaN(scr[2])?nextSymb="M":(scr[1]>5e3?scr[1]=5e3:scr[1]<-5e3&&(scr[1]=-5e3),scr[2]>5e3?scr[2]=5e3:scr[2]<-5e3&&(scr[2]=-5e3),"M"===nextSymb?context.moveTo(scr[1],scr[2]):(k=2*j,context.bezierCurveTo(lx+.333*(scr[1]-lx)+f*(k*Math.random()-j),ly+.333*(scr[2]-ly)+f*(k*Math.random()-j),lx+.666*(scr[1]-lx)+f*(k*Math.random()-j),ly+.666*(scr[2]-ly)+f*(k*Math.random()-j),scr[1],scr[2])),nextSymb="C",lx=scr[1],ly=scr[2]);context.lineCap="round",this._fill(el),this._stroke(el)}},updatePolygonPrim:function(node,el){var scrCoords,i,j,len=el.vertices.length,context=this.context,isReal=!0;if(!(len<=0)&&el.visPropCalc.visible){for("polygonalchain"===el.elType&&len++,context.beginPath(),i=0;!el.vertices[i].isReal&&i<len-1;)i++,isReal=!1;for(scrCoords=el.vertices[i].coords.scrCoords,context.moveTo(scrCoords[1],scrCoords[2]),j=i;j<len-1;j++)el.vertices[j].isReal||(isReal=!1),scrCoords=el.vertices[j].coords.scrCoords,context.lineTo(scrCoords[1],scrCoords[2]);context.closePath(),isReal&&this._fill(el)}},display:function(el,val){el&&el.rendNode&&(el.visPropOld.visible=val,el.rendNode.style.visibility=val?"inherit":"hidden")},show:function(el){JXG.deprecated("Board.renderer.show()","Board.renderer.display()"),Type.exists(el.rendNode)&&(el.rendNode.style.visibility="inherit")},hide:function(el){JXG.deprecated("Board.renderer.hide()","Board.renderer.display()"),Type.exists(el.rendNode)&&(el.rendNode.style.visibility="hidden")},setGradient:function(el){var op;op=(op=Type.evaluate(el.visProp.fillopacity))>0?op:0},setShadow:function(el){el.visPropOld.shadow!==el.visProp.shadow&&(el.visPropOld.shadow=el.visProp.shadow)},highlight:function(obj){return obj.elementClass===Const.OBJECT_CLASS_TEXT&&"html"===Type.evaluate(obj.visProp.display)?this.updateTextStyle(obj,!0):(obj.board.prepareUpdate(),obj.board.renderer.suspendRedraw(obj.board),obj.board.updateRenderer(),obj.board.renderer.unsuspendRedraw()),this},noHighlight:function(obj){return obj.elementClass===Const.OBJECT_CLASS_TEXT&&"html"===Type.evaluate(obj.visProp.display)?this.updateTextStyle(obj,!1):(obj.board.prepareUpdate(),obj.board.renderer.suspendRedraw(obj.board),obj.board.updateRenderer(),obj.board.renderer.unsuspendRedraw()),this},suspendRedraw:function(board){this.context.save(),this.context.clearRect(0,0,this.canvasRoot.width,this.canvasRoot.height),board&&board.attr.showcopyright&&this.displayCopyright(JXG.licenseText,12)},unsuspendRedraw:function(){this.context.restore()},resize:function(w,h){this.container?(this.canvasRoot.style.width=parseFloat(w)+"px",this.canvasRoot.style.height=parseFloat(h)+"px",this.canvasRoot.setAttribute("width",2*parseFloat(w)+"px"),this.canvasRoot.setAttribute("height",2*parseFloat(h)+"px")):(this.canvasRoot.width=2*parseFloat(w),this.canvasRoot.height=2*parseFloat(h)),this.context=this.canvasRoot.getContext("2d"),this.context.scale(2,2)},removeToInsertLater:function(){return function(){}}}),JXG.CanvasRenderer})),define("renderer/no",["jxg","renderer/abstract"],(function(JXG,AbstractRenderer){return JXG.NoRenderer=function(){this.enhancedRendering=!1,this.type="no"},JXG.extend(JXG.NoRenderer.prototype,{drawPoint:function(element){},updatePoint:function(element){},changePointStyle:function(element){},drawLine:function(element){},updateLine:function(element){},drawTicks:function(element){},updateTicks:function(element){},drawCurve:function(element){},updateCurve:function(element){},drawEllipse:function(element){},updateEllipse:function(element){},drawPolygon:function(element){},updatePolygon:function(element){},displayCopyright:function(str,fontsize){},drawInternalText:function(element){},updateInternalText:function(element){},drawText:function(element){},updateText:function(element){},updateTextStyle:function(element,doHighlight){},updateInternalTextStyle:function(element,strokeColor,strokeOpacity){},drawImage:function(element){},updateImage:function(element){},transformImage:function(element,transformations){},updateImageURL:function(element){},appendChildPrim:function(node,level){},appendNodesToElement:function(element,type){},createPrim:function(type,id){return null},remove:function(node){},makeArrows:function(element){},updateEllipsePrim:function(node,x,y,rx,ry){},updateLinePrim:function(node,p1x,p1y,p2x,p2y,board){},updatePathPrim:function(node,pathString,board){},updatePathStringPoint:function(element,size,type){},updatePathStringPrim:function(element){},updatePathStringBezierPrim:function(element){},updatePolygonPrim:function(node,element){},updateRectPrim:function(node,x,y,w,h){},setPropertyPrim:function(node,key,val){},display:function(element,value){element&&(element.visPropOld.visible=value)},show:function(element){},hide:function(element){},setBuffering:function(node,type){},setDashStyle:function(element){},setDraft:function(element){},removeDraft:function(element){},setGradient:function(element){},updateGradient:function(element){},setObjectTransition:function(element,duration){},setObjectFillColor:function(element,color,opacity){},setObjectStrokeColor:function(element,color,opacity){},setObjectStrokeWidth:function(element,width){},setShadow:function(element){},highlight:function(element){},noHighlight:function(element){},suspendRedraw:function(){},unsuspendRedraw:function(){},drawZoomBar:function(board){},getElementById:function(id){return null},resize:function(w,h){},removeToInsertLater:function(){return function(){}}}),JXG.NoRenderer.prototype=new AbstractRenderer,JXG.NoRenderer})),define("jsxgraph",["jxg","utils/env","utils/type","base/board","reader/file","options","renderer/svg","renderer/vml","renderer/canvas","renderer/no"],(function(JXG,Env,Type,Board,FileReader,Options,SVGRenderer,VMLRenderer,CanvasRenderer,NoRenderer){return JXG.JSXGraph={rendererType:(Options.board.renderer="no",Env.supportsVML()&&(Options.board.renderer="vml",document.onmousemove=function(){var t;return document.body&&(t=document.body.scrollLeft,t+=document.body.scrollTop),t}),Env.supportsCanvas()&&(Options.board.renderer="canvas"),Env.supportsSVG()&&(Options.board.renderer="svg"),Env.isNode()&&Env.supportsCanvas()&&(Options.board.renderer="canvas"),(Env.isNode()||"no"===Options.renderer)&&(Options.text.display="internal",Options.infobox.display="internal"),Options.board.renderer),initRenderer:function(box,dim,doc,attrRenderer){var boxid;if(Type.exists(doc)&&!1!==doc||"object"!==("undefined"==typeof document?"undefined":_typeof(document))||(doc=document),"object"===_typeof(doc)&&null!==box)for(boxid=doc.getElementById(box);boxid.firstChild;)boxid.removeChild(boxid.firstChild);else boxid=box;return void 0!==attrRenderer&&"auto"!==attrRenderer||(attrRenderer=this.rendererType),"svg"===attrRenderer?new SVGRenderer(boxid,dim):"vml"===attrRenderer?new VMLRenderer(boxid):"canvas"===attrRenderer?new CanvasRenderer(boxid,dim):new NoRenderer},_setAttributes:function(attributes){var attr=Type.copyAttributes(attributes,Options,"board");return attr.zoom=Type.copyAttributes(attr,Options,"board","zoom"),attr.pan=Type.copyAttributes(attr,Options,"board","pan"),attr.drag=Type.copyAttributes(attr,Options,"board","drag"),attr.keyboard=Type.copyAttributes(attr,Options,"board","keyboard"),attr.selection=Type.copyAttributes(attr,Options,"board","selection"),attr.navbar=Type.copyAttributes(attr.navbar,Options,"navbar"),attr.screenshot=Type.copyAttributes(attr,Options,"board","screenshot"),attr.resize=Type.copyAttributes(attr,Options,"board","resize"),attr.fullscreen=Type.copyAttributes(attr,Options,"board","fullscreen"),attr.movetarget=attributes.moveTarget||attributes.movetarget||Options.board.moveTarget,attr},_fillBoard:function(board,attr,dimensions){board.initInfobox(),board.maxboundingbox=attr.maxboundingbox,board.resizeContainer(dimensions.width,dimensions.height,!0,!0),board._createSelectionPolygon(attr),board.renderer.drawZoomBar(board,attr.navbar),JXG.boards[board.id]=board},_setARIA:function(container,attr){var doc_glob,node_jsx,newNode,parent,id_label,id_description,doc=attr.document||document;"object"===_typeof(doc)&&(doc_glob=(node_jsx=doc.getElementById(container)).ownerDocument,parent=node_jsx.parentNode,id_label=container+"_ARIAlabel",id_description=container+"_ARIAdescription",(newNode=doc_glob.createElement("div")).innerHTML=attr.title,newNode.setAttribute("id",id_label),newNode.style.display="none",parent.insertBefore(newNode,node_jsx),(newNode=doc_glob.createElement("div")).innerHTML=attr.description,newNode.setAttribute("id",id_description),newNode.style.display="none",parent.insertBefore(newNode,node_jsx),node_jsx.setAttribute("aria-labelledby",id_label),node_jsx.setAttribute("aria-describedby",id_description))},_removeARIANodes:function(board){var node,id,doc;"object"===_typeof(doc=board.document||document)&&(id=board.containerObj.getAttribute("aria-labelledby"),(node=doc.getElementById(id))&&node.parentNode&&node.parentNode.removeChild(node),id=board.containerObj.getAttribute("aria-describedby"),(node=doc.getElementById(id))&&node.parentNode&&node.parentNode.removeChild(node))},initBoard:function(box,attributes){var originX,originY,unitX,unitY,renderer,w,h,dimensions,bbox,attr,axattr,axattr_x,axattr_y,board,offX=0,offY=0;return attributes=attributes||{},attr=this._setAttributes(attributes),dimensions=Env.getDimensions(box,attr.document),attr.unitx||attr.unity?(originX=Type.def(attr.originx,150),originY=Type.def(attr.originy,150),unitX=Type.def(attr.unitx,50),unitY=Type.def(attr.unity,50)):((bbox=attr.boundingbox)[0]<attr.maxboundingbox[0]&&(bbox[0]=attr.maxboundingbox[0]),bbox[1]>attr.maxboundingbox[1]&&(bbox[1]=attr.maxboundingbox[1]),bbox[2]>attr.maxboundingbox[2]&&(bbox[2]=attr.maxboundingbox[2]),bbox[3]<attr.maxboundingbox[3]&&(bbox[3]=attr.maxboundingbox[3]),w=parseInt(dimensions.width,10),h=parseInt(dimensions.height,10),Type.exists(bbox)&&attr.keepaspectratio?(unitX=w/(bbox[2]-bbox[0]),unitY=h/(bbox[1]-bbox[3]),Math.abs(unitX)<Math.abs(unitY)?offY=.5*(h/(unitY=Math.abs(unitX)*unitY/Math.abs(unitY))-(bbox[1]-bbox[3])):offX=.5*(w/(unitX=Math.abs(unitY)*unitX/Math.abs(unitX))-(bbox[2]-bbox[0]))):(unitX=w/(bbox[2]-bbox[0]),unitY=h/(bbox[1]-bbox[3])),originX=-unitX*(bbox[0]-offX),originY=unitY*(bbox[1]+offY)),renderer=this.initRenderer(box,dimensions,attr.document,attr.renderer),this._setARIA(box,attr),(board=new Board(box,renderer,attr.id,[originX,originY],attr.zoomfactor*attr.zoomx,attr.zoomfactor*attr.zoomy,unitX,unitY,dimensions.width,dimensions.height,attr)).keepaspectratio=attr.keepaspectratio,this._fillBoard(board,attr,dimensions),board.suspendUpdate(),attr.axis&&(axattr="object"===_typeof(attr.axis)?attr.axis:{},axattr_x=Type.deepCopy(Options.board.defaultAxes.x,axattr),axattr_y=Type.deepCopy(Options.board.defaultAxes.y,axattr),attr.defaultaxes.x&&(axattr_x=Type.deepCopy(axattr_x,attr.defaultaxes.x)),attr.defaultaxes.y&&(axattr_y=Type.deepCopy(axattr_y,attr.defaultaxes.y)),board.defaultAxes={},board.defaultAxes.x=board.create("axis",[[0,0],[1,0]],axattr_x),board.defaultAxes.y=board.create("axis",[[0,0],[0,1]],axattr_y)),attr.grid&&board.create("grid",[],"object"===_typeof(attr.grid)?attr.grid:{}),board.unsuspendUpdate(),board},loadBoardFromFile:function(box,file,format,attributes,callback){var attr,renderer,board,dimensions,encoding;return attributes=attributes||{},attr=this._setAttributes(attributes),dimensions=Env.getDimensions(box,attr.document),renderer=this.initRenderer(box,dimensions,attr.document,attr.renderer),this._setARIA(box,attr),board=new Board(box,renderer,"",[150,150],1,1,50,50,dimensions.width,dimensions.height,attr),this._fillBoard(board,attr,dimensions),encoding=attr.encoding||"iso-8859-1",FileReader.parseFileContent(file,board,format,!0,encoding,callback),board},loadBoardFromString:function(box,string,format,attributes,callback){var attr,renderer,board,dimensions;return attributes=attributes||{},attr=this._setAttributes(attributes),dimensions=Env.getDimensions(box,attr.document),renderer=this.initRenderer(box,dimensions,attr.document),this._setARIA(box,attr),board=new Board(box,renderer,"",[150,150],1,1,50,50,dimensions.width,dimensions.height,attr),this._fillBoard(board,attr,dimensions),FileReader.parseString(string,board,format,!0,callback),board},freeBoard:function(board){var el;for(el in"string"==typeof board&&(board=JXG.boards[board]),this._removeARIANodes(board),board.removeEventHandlers(),board.suspendUpdate(),board.objects)board.objects.hasOwnProperty(el)&&board.objects[el].remove();for(;board.containerObj.firstChild;)board.containerObj.removeChild(board.containerObj.firstChild);for(el in board.objects)board.objects.hasOwnProperty(el)&&delete board.objects[el];delete board.renderer,board.jc.creator.clearCache(),delete board.jc,delete JXG.boards[board.id]},registerElement:function(element,creator){JXG.deprecated("JXG.JSXGraph.registerElement()","JXG.registerElement()"),JXG.registerElement(element,creator)}},Env.isBrowser&&"object"===("undefined"==typeof window?"undefined":_typeof(window))&&"object"===("undefined"==typeof document?"undefined":_typeof(document))&&Env.addEvent(window,"load",(function(){var type,i,j,div,id,board,txt,width,height,maxWidth,aspectRatio,cssClasses,bbox,axis,grid,code,src,request,postpone=!1,scripts=document.getElementsByTagName("script"),init=function(code,type,bbox){var board=JXG.JSXGraph.initBoard(id,{boundingbox:bbox,keepaspectratio:!0,grid:grid,axis:axis,showReload:!0});if(type.toLowerCase().indexOf("script")>-1)board.construct(code);else try{board.jc.parse(code)}catch(e2){JXG.debug(e2)}return board},makeReload=function makeReload(board,code,type,bbox){return function(){var newBoard;JXG.JSXGraph.freeBoard(board),(newBoard=init(code,type,bbox)).reload=makeReload(newBoard,code,type,bbox)}};for(i=0;i<scripts.length;i++)if(type=scripts[i].getAttribute("type",!1),Type.exists(type)&&("text/jessiescript"===type.toLowerCase()||"jessiescript"===type.toLowerCase()||"text/jessiecode"===type.toLowerCase()||"jessiecode"===type.toLowerCase())){if(cssClasses=scripts[i].getAttribute("class",!1)||"",width=scripts[i].getAttribute("width",!1)||"",height=scripts[i].getAttribute("height",!1)||"",maxWidth=scripts[i].getAttribute("maxwidth",!1)||"100%",aspectRatio=scripts[i].getAttribute("aspectratio",!1)||"1/1",bbox=scripts[i].getAttribute("boundingbox",!1)||"-5, 5, 5, -5",id=scripts[i].getAttribute("container",!1),src=scripts[i].getAttribute("src",!1),4!==(bbox=bbox.split(",")).length)bbox=[-5,5,5,-5];else for(j=0;j<bbox.length;j++)bbox[j]=parseFloat(bbox[j]);if(axis=Type.str2Bool(scripts[i].getAttribute("axis",!1)||"false"),grid=Type.str2Bool(scripts[i].getAttribute("grid",!1)||"false"),Type.exists(id))div=document.getElementById(id);else{id="jessiescript_autgen_jxg_"+i,(div=document.createElement("div")).setAttribute("id",id),txt=""!==width?"width:"+width+";":"",txt+=""!==height?"height:"+height+";":"",txt+=""!==maxWidth?"max-width:"+maxWidth+";":"",txt+=""!==aspectRatio?"aspect-ratio:"+aspectRatio+";":"",div.setAttribute("style",txt),div.setAttribute("class","jxgbox "+cssClasses);try{document.body.insertBefore(div,scripts[i])}catch(e){"object"===("undefined"==typeof jQuery?"undefined":_typeof(jQuery))&&jQuery(div).insertBefore(scripts[i])}}code="",Type.exists(src)?(postpone=!0,(request=new XMLHttpRequest).open("GET",src),request.overrideMimeType("text/plain; charset=x-user-defined"),request.addEventListener("load",(function(){if(!(this.status<400))throw new Error("\nJSXGraph: failed to load file",src,":",this.responseText);code=this.responseText+"\n"+code,(board=init(code,type,bbox)).reload=makeReload(board,code,type,bbox)})),request.addEventListener("error",(function(e){throw new Error("\nJSXGraph: failed to load file",src,":",e)})),request.send()):postpone=!1,document.getElementById(id)?(code=(code=scripts[i].innerHTML).replace(/<!\[CDATA\[/g,"").replace(/\]\]>/g,""),scripts[i].innerHTML=code,postpone||((board=init(code,type,bbox)).reload=makeReload(board,code,type,bbox))):JXG.debug("JSXGraph: Apparently the div injection failed. Can't create a board, sorry.")}}),window),JXG.JSXGraph})),define("base/point",["jxg","options","math/math","math/geometry","base/constants","base/element","utils/type","base/coordselement"],(function(JXG,Options,Mat,Geometry,Const,GeometryElement,Type,CoordsElement){return JXG.Point=function(board,coordinates,attributes){this.constructor(board,attributes,Const.OBJECT_TYPE_POINT,Const.OBJECT_CLASS_POINT),this.element=this.board.select(attributes.anchor),this.coordsConstructor(coordinates),this.elType="point",this.id=this.board.setId(this,"P"),this.board.renderer.drawPoint(this),this.board.finalizeAdding(this),this.createGradient(),this.createLabel()},JXG.Point.prototype=new GeometryElement,Type.copyPrototypeMethods(JXG.Point,CoordsElement,"coordsConstructor"),JXG.extend(JXG.Point.prototype,{hasPoint:function(x,y){var r,prec,type,coordsScr=this.coords.scrCoords,unit=Type.evaluate(this.visProp.sizeunit);return Type.isObject(Type.evaluate(this.visProp.precision))?(type=this.board._inputDevice,prec=Type.evaluate(this.visProp.precision[type])):prec=this.board.options.precision.hasPoint,r=parseFloat(Type.evaluate(this.visProp.size)),"user"===unit&&(r*=Math.sqrt(this.board.unitX*this.board.unitY)),(r+=.5*parseFloat(Type.evaluate(this.visProp.strokewidth)))<prec&&(r=prec),Math.abs(coordsScr[1]-x)<r+2&&Math.abs(coordsScr[2]-y)<r+2},update:function(fromParent){return this.needsUpdate?(this.updateCoords(fromParent),Type.evaluate(this.visProp.trace)&&this.cloneToBackground(!0),this):this},updateTransform:function(fromParent){var c,i;if(0===this.transformations.length||null===this.baseElement)return this;for(this===this.baseElement?(c=this.transformations[0].apply(this.baseElement,"self"),this.coords.setCoordinates(Const.COORDS_BY_USER,c)):c=this.transformations[0].apply(this.baseElement),this.coords.setCoordinates(Const.COORDS_BY_USER,c),i=1;i<this.transformations.length;i++)this.coords.setCoordinates(Const.COORDS_BY_USER,this.transformations[i].apply(this));return this},updateRenderer:function(){return this.updateRendererGeneric("updatePoint"),this},bounds:function(){return this.coords.usrCoords.slice(1).concat(this.coords.usrCoords.slice(1))},makeIntersection:function(el1,el2,i,j){var func;el1=this.board.select(el1),el2=this.board.select(el2),func=Geometry.intersectionFunction(this.board,el1,el2,i,j,Type.evaluate(this.visProp.alwaysintersect)),this.addConstraint([func]);try{el1.addChild(this),el2.addChild(this)}catch(e){throw new Error("JSXGraph: Can't create 'intersection' with parent types '"+_typeof(el1)+"' and '"+_typeof(el2)+"'.")}this.type=Const.OBJECT_TYPE_INTERSECTION,this.elType="intersection",this.parents=[el1.id,el2.id,i,j],this.generatePolynomial=function(){var poly1=el1.generatePolynomial(this),poly2=el2.generatePolynomial(this);return 0===poly1.length||0===poly2.length?[]:[poly1[0],poly2[0]]},this.prepareUpdate().update()},setStyle:function(i){return this.visProp.face=["cross","cross","cross","circle","circle","circle","circle","square","square","square","plus","plus","plus"][i],this.visProp.size=[2,3,4,1,2,3,4,2,3,4,2,3,4][i],this.board.renderer.changePointStyle(this),this},normalizeFace:function(s){return JXG.deprecated("Point.normalizeFace()","JXG.normalizePointFace()"),Options.normalizePointFace(s)},face:function(f){JXG.deprecated("Point.face()","Point.setAttribute()"),this.setAttribute({face:f})},size:function(s){JXG.deprecated("Point.size()","Point.setAttribute()"),this.setAttribute({size:s})},isOn:function(el,tol){var arr,crds;return tol=tol||Mat.eps,Type.isPoint(el)?this.Dist(el)<tol:el.elementClass===Const.OBJECT_CLASS_LINE?("segment"!==el.elType||Type.evaluate(this.visProp.alwaysintersect)||(arr=JXG.Math.Geometry.projectCoordsToSegment(this.coords.usrCoords,el.point1.coords.usrCoords,el.point2.coords.usrCoords))[1]>=0&&arr[1]<=1)&&Geometry.distPointLine(this.coords.usrCoords,el.stdform)<tol:el.elementClass===Const.OBJECT_CLASS_CIRCLE?Type.evaluate(el.visProp.hasinnerpoints)?this.Dist(el.center)<el.Radius()+tol:Math.abs(this.Dist(el.center)-el.Radius())<tol:el.elementClass===Const.OBJECT_CLASS_CURVE?(crds=Geometry.projectPointToCurve(this,el,this.board)[0],Geometry.distance(this.coords.usrCoords,crds.usrCoords,3)<tol):el.type===Const.OBJECT_TYPE_POLYGON?!(!Type.evaluate(el.visProp.hasinnerpoints)||!el.pnpoly(this.coords.usrCoords[1],this.coords.usrCoords[2],JXG.COORDS_BY_USER))||(arr=Geometry.projectCoordsToPolygon(this.coords.usrCoords,el),Geometry.distance(this.coords.usrCoords,arr,3)<tol):el.type===Const.OBJECT_TYPE_TURTLE&&(crds=Geometry.projectPointToTurtle(this,el,this.board),Geometry.distance(this.coords.usrCoords,crds.usrCoords,3)<tol)},cloneToBackground:function(){var copy={};return copy.id=this.id+"T"+this.numTraces,this.numTraces+=1,copy.coords=this.coords,copy.visProp=Type.deepCopy(this.visProp,this.visProp.traceattributes,!0),copy.visProp.layer=this.board.options.layer.trace,copy.elementClass=Const.OBJECT_CLASS_POINT,copy.board=this.board,Type.clearVisPropOld(copy),copy.visPropCalc={visible:Type.evaluate(copy.visProp.visible)},this.board.renderer.drawPoint(copy),this.traces[copy.id]=copy.rendNode,this}}),JXG.createPoint=function(board,parents,attributes){var el,attr;if(attr=Type.copyAttributes(attributes,board.options,"point"),!(el=CoordsElement.create(JXG.Point,board,parents,attr)))throw new Error("JSXGraph: Can't create point with parent types '"+_typeof(parents[0])+"' and '"+_typeof(parents[1])+"'.\nPossible parent types: [x,y], [z,x,y], [element,transformation]");return el},JXG.createGlider=function(board,parents,attributes){var el,coords,attr=Type.copyAttributes(attributes,board.options,"glider");return coords=1===parents.length?[0,0]:parents.slice(0,2),(el=board.create("point",coords,attr)).makeGlider(parents[parents.length-1]),el},JXG.createIntersectionPoint=function(board,parents,attributes){var el,el1,el2,func,i,j,attr=Type.copyAttributes(attributes,board.options,"intersection");parents.push(0,0),el1=board.select(parents[0]),el2=board.select(parents[1]),i=parents[2]||0,j=parents[3]||0,el=board.create("point",[0,0,0],attr),func=Geometry.intersectionFunction(board,el1,el2,i,j,el.visProp.alwaysintersect),el.addConstraint([func]);try{el1.addChild(el),el2.addChild(el)}catch(e){throw new Error("JSXGraph: Can't create 'intersection' with parent types '"+_typeof(parents[0])+"' and '"+_typeof(parents[1])+"'.")}return el.type=Const.OBJECT_TYPE_INTERSECTION,el.elType="intersection",el.setParents([el1.id,el2.id]),el.intersectionNumbers=[i,j],el.getParents=function(){return this.parents.concat(this.intersectionNumbers)},el.generatePolynomial=function(){var poly1=el1.generatePolynomial(el),poly2=el2.generatePolynomial(el);return 0===poly1.length||0===poly2.length?[]:[poly1[0],poly2[0]]},el},JXG.createOtherIntersectionPoint=function(board,parents,attributes){var el,el1,el2,other;if(3!==parents.length||!Type.isPoint(parents[2])||parents[0].elementClass!==Const.OBJECT_CLASS_LINE&&parents[0].elementClass!==Const.OBJECT_CLASS_CIRCLE||parents[1].elementClass!==Const.OBJECT_CLASS_LINE&&parents[1].elementClass!==Const.OBJECT_CLASS_CIRCLE)throw new Error("JSXGraph: Can't create 'other intersection point' with parent types '"+_typeof(parents[0])+"', '"+_typeof(parents[1])+"'and '"+_typeof(parents[2])+"'.\nPossible parent types: [circle|line,circle|line,point]");return el1=board.select(parents[0]),el2=board.select(parents[1]),other=board.select(parents[2]),(el=board.create("point",[function(){var c=Geometry.meet(el1.stdform,el2.stdform,0,el1.board);return Math.abs(other.X()-c.usrCoords[1])>Mat.eps||Math.abs(other.Y()-c.usrCoords[2])>Mat.eps||Math.abs(other.Z()-c.usrCoords[0])>Mat.eps?c:Geometry.meet(el1.stdform,el2.stdform,1,el1.board)}],attributes)).type=Const.OBJECT_TYPE_INTERSECTION,el.elType="otherintersection",el.setParents([el1.id,el2.id,other]),el1.addChild(el),el2.addChild(el),el.generatePolynomial=function(){var poly1=el1.generatePolynomial(el),poly2=el2.generatePolynomial(el);return 0===poly1.length||0===poly2.length?[]:[poly1[0],poly2[0]]},el},JXG.createPolePoint=function(board,parents,attributes){var el,el1,el2,firstParentIsConic,secondParentIsConic,firstParentIsLine,secondParentIsLine;if(parents.length>1&&(firstParentIsConic=parents[0].type===Const.OBJECT_TYPE_CONIC||parents[0].elementClass===Const.OBJECT_CLASS_CIRCLE,secondParentIsConic=parents[1].type===Const.OBJECT_TYPE_CONIC||parents[1].elementClass===Const.OBJECT_CLASS_CIRCLE,firstParentIsLine=parents[0].elementClass===Const.OBJECT_CLASS_LINE,secondParentIsLine=parents[1].elementClass===Const.OBJECT_CLASS_LINE),2!==parents.length||!(firstParentIsConic&&secondParentIsLine||firstParentIsLine&&secondParentIsConic))throw new Error("JSXGraph: Can't create 'pole point' with parent types '"+_typeof(parents[0])+"' and '"+_typeof(parents[1])+"'.\nPossible parent type: [conic|circle,line], [line,conic|circle]");return secondParentIsLine?(el1=board.select(parents[0]),el2=board.select(parents[1])):(el1=board.select(parents[1]),el2=board.select(parents[0])),(el=board.create("point",[function(){var q=el1.quadraticform,s=el2.stdform.slice(0,3);return[JXG.Math.Numerics.det([s,q[1],q[2]]),JXG.Math.Numerics.det([q[0],s,q[2]]),JXG.Math.Numerics.det([q[0],q[1],s])]}],attributes)).elType="polepoint",el.setParents([el1.id,el2.id]),el1.addChild(el),el2.addChild(el),el},JXG.registerElement("point",JXG.createPoint),JXG.registerElement("glider",JXG.createGlider),JXG.registerElement("intersection",JXG.createIntersectionPoint),JXG.registerElement("otherintersection",JXG.createOtherIntersectionPoint),JXG.registerElement("polepoint",JXG.createPolePoint),{Point:JXG.Point,createPoint:JXG.createPoint,createGlider:JXG.createGlider,createIntersection:JXG.createIntersectionPoint,createOtherIntersection:JXG.createOtherIntersectionPoint,createPolePoint:JXG.createPolePoint}})),define("base/line",["jxg","math/math","math/geometry","math/numerics","math/statistics","base/constants","base/coords","base/element","utils/type","base/point"],(function(JXG,Mat,Geometry,Numerics,Statistics,Const,Coords,GeometryElement,Type,Point){return JXG.Line=function(board,p1,p2,attributes){this.constructor(board,attributes,Const.OBJECT_TYPE_LINE,Const.OBJECT_CLASS_LINE),this.point1=this.board.select(p1),this.point2=this.board.select(p2),this.ticks=[],this.defaultTicks=null,this.parentPolygon=null,this.id=this.board.setId(this,"L"),this.board.renderer.drawLine(this),this.board.finalizeAdding(this),this.elType="line",this.point1._is_new?(this.addChild(this.point1),delete this.point1._is_new):this.point1.addChild(this),this.point2._is_new?(this.addChild(this.point2),delete this.point2._is_new):this.point2.addChild(this),this.inherits.push(this.point1,this.point2),this.updateStdform(),this.createLabel(),this.methodMap=JXG.deepCopy(this.methodMap,{point1:"point1",point2:"point2",getSlope:"getSlope",getRise:"getRise",getYIntersect:"getRise",getAngle:"getAngle",L:"L",length:"L"})},JXG.Line.prototype=new GeometryElement,JXG.extend(JXG.Line.prototype,{hasPoint:function(x,y){var s,vnew,p1c,p2c,d,pos,i,prec,type,c=[],v=[1,x,y],sw=Type.evaluate(this.visProp.strokewidth);return Type.isObject(Type.evaluate(this.visProp.precision))?(type=this.board._inputDevice,prec=Type.evaluate(this.visProp.precision[type])):prec=this.board.options.precision.hasPoint,prec+=.5*sw,c[0]=this.stdform[0]-this.stdform[1]*this.board.origin.scrCoords[1]/this.board.unitX+this.stdform[2]*this.board.origin.scrCoords[2]/this.board.unitY,c[1]=this.stdform[1]/this.board.unitX,c[2]=this.stdform[2]/-this.board.unitY,s=Geometry.distPointLine(v,c),!(isNaN(s)||s>prec)&&(!(!Type.evaluate(this.visProp.straightfirst)||!Type.evaluate(this.visProp.straightlast))||(p1c=this.point1.coords,p2c=this.point2.coords,vnew=[0,c[1],c[2]],vnew=Mat.crossProduct(vnew,v),(vnew=Mat.crossProduct(vnew,c))[1]/=vnew[0],vnew[2]/=vnew[0],vnew[0]=1,vnew=new Coords(Const.COORDS_BY_SCREEN,vnew.slice(1),this.board).usrCoords,d=p1c.distance(Const.COORDS_BY_USER,p2c),p1c=p1c.usrCoords.slice(0),p2c=p2c.usrCoords.slice(0),d<Mat.eps?pos=0:(d===Number.POSITIVE_INFINITY&&(d=1/Mat.eps,Math.abs(p2c[0])<Mat.eps?(d/=Geometry.distance([0,0,0],p2c),p2c=[1,p1c[1]+p2c[1]*d,p1c[2]+p2c[2]*d]):(d/=Geometry.distance([0,0,0],p1c),p1c=[1,p2c[1]+p1c[1]*d,p2c[2]+p1c[2]*d])),d=p2c[i=1]-p1c[i],Math.abs(d)<Mat.eps&&(d=p2c[i=2]-p1c[i]),pos=(vnew[i]-p1c[i])/d),!(!Type.evaluate(this.visProp.straightfirst)&&pos<0)&&!(!Type.evaluate(this.visProp.straightlast)&&pos>1)))},update:function(){var funps;return this.needsUpdate?(this.constrained&&(Type.isFunction(this.funps)?(funps=this.funps())&&funps.length&&2===funps.length&&(this.point1=funps[0],this.point2=funps[1]):(Type.isFunction(this.funp1)&&(funps=this.funp1(),Type.isPoint(funps)?this.point1=funps:funps&&funps.length&&2===funps.length&&this.point1.setPositionDirectly(Const.COORDS_BY_USER,funps)),Type.isFunction(this.funp2)&&(funps=this.funp2(),Type.isPoint(funps)?this.point2=funps:funps&&funps.length&&2===funps.length&&this.point2.setPositionDirectly(Const.COORDS_BY_USER,funps)))),this.updateSegmentFixedLength(),this.updateStdform(),Type.evaluate(this.visProp.trace)&&this.cloneToBackground(!0),this):this},updateSegmentFixedLength:function(){var d,dnew,d1,d2,drag1,drag2,x,y;return this.hasFixedLength?(d=this.point1.Dist(this.point2),dnew=this.fixedLength(),d1=this.fixedLengthOldCoords[0].distance(Const.COORDS_BY_USER,this.point1.coords),d2=this.fixedLengthOldCoords[1].distance(Const.COORDS_BY_USER,this.point2.coords),(d1>Mat.eps||d2>Mat.eps||d!==dnew)&&(drag1=this.point1.isDraggable&&this.point1.type!==Const.OBJECT_TYPE_GLIDER&&!Type.evaluate(this.point1.visProp.fixed),drag2=this.point2.isDraggable&&this.point2.type!==Const.OBJECT_TYPE_GLIDER&&!Type.evaluate(this.point2.visProp.fixed),d>Mat.eps?d1>d2&&drag2||d1<=d2&&drag2&&!drag1?(this.point2.setPositionDirectly(Const.COORDS_BY_USER,[this.point1.X()+(this.point2.X()-this.point1.X())*dnew/d,this.point1.Y()+(this.point2.Y()-this.point1.Y())*dnew/d]),this.point2.fullUpdate()):(d1<=d2&&drag1||d1>d2&&drag1&&!drag2)&&(this.point1.setPositionDirectly(Const.COORDS_BY_USER,[this.point2.X()+(this.point1.X()-this.point2.X())*dnew/d,this.point2.Y()+(this.point1.Y()-this.point2.Y())*dnew/d]),this.point1.fullUpdate()):(x=Math.random()-.5,y=Math.random()-.5,d=Math.sqrt(x*x+y*y),drag2?(this.point2.setPositionDirectly(Const.COORDS_BY_USER,[this.point1.X()+x*dnew/d,this.point1.Y()+y*dnew/d]),this.point2.fullUpdate()):drag1&&(this.point1.setPositionDirectly(Const.COORDS_BY_USER,[this.point2.X()+x*dnew/d,this.point2.Y()+y*dnew/d]),this.point1.fullUpdate())),this.fixedLengthOldCoords[0].setCoordinates(Const.COORDS_BY_USER,this.point1.coords.usrCoords),this.fixedLengthOldCoords[1].setCoordinates(Const.COORDS_BY_USER,this.point2.coords.usrCoords)),this):this},updateStdform:function(){var v=Mat.crossProduct(this.point1.coords.usrCoords,this.point2.coords.usrCoords);this.stdform[0]=v[0],this.stdform[1]=v[1],this.stdform[2]=v[2],this.stdform[3]=0,this.normalize()},updateRenderer:function(){return this.needsUpdate?(this.visPropCalc.visible&&(this.isReal=!isNaN(this.point1.coords.usrCoords[1]+this.point1.coords.usrCoords[2]+this.point2.coords.usrCoords[1]+this.point2.coords.usrCoords[2])&&Mat.innerProduct(this.stdform,this.stdform,3)>=Mat.eps*Mat.eps,this.isReal||this.updateVisibility(!1)),this.visPropCalc.visible&&this.board.renderer.updateLine(this),this.hasLabel&&this.visPropCalc.visible&&this.label&&this.label.visPropCalc.visible&&this.isReal&&(this.label.update(),this.board.renderer.updateText(this.label)),this.setDisplayRendNode(),this.needsUpdate=!1,this):this},generatePolynomial:function(p){var u1=this.point1.symbolic.x,u2=this.point1.symbolic.y,v1=this.point2.symbolic.x,v2=this.point2.symbolic.y,w1=p.symbolic.x,w2=p.symbolic.y;return[["(",u2,")*(",w1,")-(",u2,")*(",v1,")+(",w2,")*(",v1,")-(",u1,")*(",w2,")+(",u1,")*(",v2,")-(",w1,")*(",v2,")"].join("")]},getRise:function(){return Math.abs(this.stdform[2])>=Mat.eps?-this.stdform[0]/this.stdform[2]:1/0},getSlope:function(){return Math.abs(this.stdform[2])>=Mat.eps?-this.stdform[1]/this.stdform[2]:1/0},getAngle:function(){return Math.atan2(-this.stdform[1],this.stdform[2])},setStraight:function(straightFirst,straightLast){return this.visProp.straightfirst=straightFirst,this.visProp.straightlast=straightLast,this.board.renderer.updateLine(this),this},getTextAnchor:function(){return new Coords(Const.COORDS_BY_USER,[.5*(this.point2.X()+this.point1.X()),.5*(this.point2.Y()+this.point1.Y())],this.board)},setLabelRelativeCoords:function(relCoords){Type.exists(this.label)&&(this.label.relativeCoords=new Coords(Const.COORDS_BY_SCREEN,[relCoords[0],-relCoords[1]],this.board))},getLabelAnchor:function(){var x,y,fs=0,c1=new Coords(Const.COORDS_BY_USER,this.point1.coords.usrCoords,this.board),c2=new Coords(Const.COORDS_BY_USER,this.point2.coords.usrCoords,this.board),ev_sf=Type.evaluate(this.visProp.straightfirst),ev_sl=Type.evaluate(this.visProp.straightlast);if((ev_sf||ev_sl)&&Geometry.calcStraight(this,c1,c2,0),c1=c1.scrCoords,c2=c2.scrCoords,!Type.exists(this.label))return new Coords(Const.COORDS_BY_SCREEN,[NaN,NaN],this.board);switch(Type.evaluate(this.label.visProp.position)){case"lft":case"llft":case"ulft":c1[1]<=c2[1]?(x=c1[1],y=c1[2]):(x=c2[1],y=c2[2]);break;case"rt":case"lrt":case"urt":c1[1]>c2[1]?(x=c1[1],y=c1[2]):(x=c2[1],y=c2[2]);break;default:x=.5*(c1[1]+c2[1]),y=.5*(c1[2]+c2[2])}return(ev_sf||ev_sl)&&(Type.exists(this.label)&&(fs=Type.evaluate(this.label.visProp.fontsize)),Math.abs(x)<Mat.eps?x=fs:this.board.canvasWidth+Mat.eps>x&&x>this.board.canvasWidth-fs-Mat.eps&&(x=this.board.canvasWidth-fs),Mat.eps+fs>y&&y>-Mat.eps?y=fs:this.board.canvasHeight+Mat.eps>y&&y>this.board.canvasHeight-fs-Mat.eps&&(y=this.board.canvasHeight-fs)),new Coords(Const.COORDS_BY_SCREEN,[x,y],this.board)},cloneToBackground:function(){var r,s,er,copy={};return copy.id=this.id+"T"+this.numTraces,copy.elementClass=Const.OBJECT_CLASS_LINE,this.numTraces++,copy.point1=this.point1,copy.point2=this.point2,copy.stdform=this.stdform,copy.board=this.board,copy.visProp=Type.deepCopy(this.visProp,this.visProp.traceattributes,!0),copy.visProp.layer=this.board.options.layer.trace,Type.clearVisPropOld(copy),copy.visPropCalc={visible:Type.evaluate(copy.visProp.visible)},s=this.getSlope(),r=this.getRise(),copy.getSlope=function(){return s},copy.getRise=function(){return r},er=this.board.renderer.enhancedRendering,this.board.renderer.enhancedRendering=!0,this.board.renderer.drawLine(copy),this.board.renderer.enhancedRendering=er,this.traces[copy.id]=copy.rendNode,this},addTransform:function(transform){var i,list=Type.isArray(transform)?transform:[transform],len=list.length;for(i=0;i<len;i++)this.point1.transformations.push(list[i]),this.point2.transformations.push(list[i]);return this},snapToGrid:function(pos){var c1,c2,dc,ticks,x,y,sX,sY;return Type.evaluate(this.visProp.snaptogrid)?this.parents.length<3?(this.point1.handleSnapToGrid(!0,!0),this.point2.handleSnapToGrid(!0,!0)):Type.exists(pos)&&(sX=Type.evaluate(this.visProp.snapsizex),sY=Type.evaluate(this.visProp.snapsizey),x=(c1=new Coords(Const.COORDS_BY_SCREEN,[pos.Xprev,pos.Yprev],this.board)).usrCoords[1],y=c1.usrCoords[2],sX<=0&&this.board.defaultAxes&&this.board.defaultAxes.x.defaultTicks&&(sX=(ticks=this.board.defaultAxes.x.defaultTicks).ticksDelta*(Type.evaluate(ticks.visProp.minorticks)+1)),sY<=0&&this.board.defaultAxes&&this.board.defaultAxes.y.defaultTicks&&(sY=(ticks=this.board.defaultAxes.y.defaultTicks).ticksDelta*(Type.evaluate(ticks.visProp.minorticks)+1)),sX>0&&sY>0&&(c2=Geometry.projectPointToLine({coords:c1},this,this.board),dc=Statistics.subtract([1,Math.round(x/sX)*sX,Math.round(y/sY)*sY],c2.usrCoords),this.board.create("transform",dc.slice(1),{type:"translate"}).applyOnce([this.point1,this.point2]))):(this.point1.handleSnapToGrid(!1,!0),this.point2.handleSnapToGrid(!1,!0)),this},snapToPoints:function(){var forceIt=Type.evaluate(this.visProp.snaptopoints);return this.parents.length<3&&(this.point1.handleSnapToPoints(forceIt),this.point2.handleSnapToPoints(forceIt)),this},X:function(t){var x,b=this.stdform[2];return x=Math.abs(this.point1.coords.usrCoords[0])>Mat.eps?this.point1.coords.usrCoords[1]:this.point2.coords.usrCoords[1],t=2*(t-.5),(1-Math.abs(t))*x-t*b},Y:function(t){var y,a=this.stdform[1];return y=Math.abs(this.point1.coords.usrCoords[0])>Mat.eps?this.point1.coords.usrCoords[2]:this.point2.coords.usrCoords[2],t=2*(t-.5),(1-Math.abs(t))*y+t*a},Z:function(t){var z=Math.abs(this.point1.coords.usrCoords[0])>Mat.eps?this.point1.coords.usrCoords[0]:this.point2.coords.usrCoords[0];return t=2*(t-.5),(1-Math.abs(t))*z},L:function(){return this.point1.Dist(this.point2)},minX:function(){return 0},maxX:function(){return 1},bounds:function(){var p1c=this.point1.coords.usrCoords,p2c=this.point2.coords.usrCoords;return[Math.min(p1c[1],p2c[1]),Math.max(p1c[2],p2c[2]),Math.max(p1c[1],p2c[1]),Math.min(p1c[2],p2c[2])]},remove:function(){this.removeAllTicks(),GeometryElement.prototype.remove.call(this)}}),JXG.createLine=function(board,parents,attributes){var ps,el,p1,p2,i,attr,isDraggable,c=[],doTransform=!1,constrained=!1;if(2===parents.length){if(Type.isArray(parents[0])&&parents[0].length>1)attr=Type.copyAttributes(attributes,board.options,"line","point1"),p1=board.create("point",parents[0],attr);else if(Type.isString(parents[0])||Type.isPoint(parents[0]))p1=board.select(parents[0]);else if(Type.isFunction(parents[0])&&Type.isPoint(parents[0]()))p1=parents[0](),constrained=!0;else if(Type.isFunction(parents[0])&&parents[0]().length&&parents[0]().length>=2)attr=Type.copyAttributes(attributes,board.options,"line","point1"),p1=Point.createPoint(board,parents[0](),attr),constrained=!0;else{if(!Type.isObject(parents[0])||!Type.isTransformationOrArray(parents[1]))throw new Error("JSXGraph: Can't create line with parent types '"+_typeof(parents[0])+"' and '"+_typeof(parents[1])+"'.\nPossible parent types: [point,point], [[x1,y1],[x2,y2]], [a,b,c]");doTransform=!0,attr=Type.copyAttributes(attributes,board.options,"line","point1"),p1=board.create("point",[parents[0].point1,parents[1]],attr)}if(doTransform)attr=Type.copyAttributes(attributes,board.options,"line","point2"),p2=board.create("point",[parents[0].point2,parents[1]],attr);else if(Type.isArray(parents[1])&&parents[1].length>1)attr=Type.copyAttributes(attributes,board.options,"line","point2"),p2=board.create("point",parents[1],attr);else if(Type.isString(parents[1])||Type.isPoint(parents[1]))p2=board.select(parents[1]);else if(Type.isFunction(parents[1])&&Type.isPoint(parents[1]()))p2=parents[1](),constrained=!0;else{if(!(Type.isFunction(parents[1])&&parents[1]().length&&parents[1]().length>=2))throw new Error("JSXGraph: Can't create line with parent types '"+_typeof(parents[0])+"' and '"+_typeof(parents[1])+"'.\nPossible parent types: [point,point], [[x1,y1],[x2,y2]], [a,b,c]");attr=Type.copyAttributes(attributes,board.options,"line","point2"),p2=Point.createPoint(board,parents[1](),attr),constrained=!0}attr=Type.copyAttributes(attributes,board.options,"line"),el=new JXG.Line(board,p1,p2,attr),constrained?(el.constrained=!0,el.funp1=parents[0],el.funp2=parents[1]):doTransform||(el.isDraggable=!0),el.setParents([p1.id,p2.id])}else if(3===parents.length){for(isDraggable=!0,i=0;i<3;i++)if(Type.isNumber(parents[i]))c[i]=Type.createFunction(parents[i]);else{if(!Type.isFunction(parents[i]))throw new Error("JSXGraph: Can't create line with parent types '"+_typeof(parents[0])+"' and '"+_typeof(parents[1])+"' and '"+_typeof(parents[2])+"'.\nPossible parent types: [point,point], [[x1,y1],[x2,y2]], [a,b,c]");c[i]=parents[i],isDraggable=!1}attr=Type.copyAttributes(attributes,board.options,"line","point1"),p1=isDraggable?board.create("point",[c[2]()*c[2]()+c[1]()*c[1](),c[2]()-c[1]()*c[0]()+c[2](),-c[1]()-c[2]()*c[0]()-c[1]()],attr):board.create("point",[function(){return.5*(c[2]()*c[2]()+c[1]()*c[1]())},function(){return.5*(c[2]()-c[1]()*c[0]()+c[2]())},function(){return.5*(-c[1]()-c[2]()*c[0]()-c[1]())}],attr),attr=Type.copyAttributes(attributes,board.options,"line","point2"),p2=isDraggable?board.create("point",[c[2]()*c[2]()+c[1]()*c[1](),-c[1]()*c[0]()+c[2](),-c[2]()*c[0]()-c[1]()],attr):board.create("point",[function(){return c[2]()*c[2]()+c[1]()*c[1]()},function(){return-c[1]()*c[0]()+c[2]()},function(){return-c[2]()*c[0]()-c[1]()}],attr),p1.prepareUpdate().update(),p2.prepareUpdate().update(),attr=Type.copyAttributes(attributes,board.options,"line"),(el=new JXG.Line(board,p1,p2,attr)).isDraggable=isDraggable,el.setParents([p1,p2])}else if(1===parents.length&&Type.isFunction(parents[0])&&2===parents[0]().length&&Type.isPoint(parents[0]()[0])&&Type.isPoint(parents[0]()[1]))ps=parents[0](),attr=Type.copyAttributes(attributes,board.options,"line"),(el=new JXG.Line(board,ps[0],ps[1],attr)).constrained=!0,el.funps=parents[0],el.setParents(ps);else{if(!(1===parents.length&&Type.isFunction(parents[0])&&3===parents[0]().length&&Type.isNumber(parents[0]()[0])&&Type.isNumber(parents[0]()[1])&&Type.isNumber(parents[0]()[2])))throw new Error("JSXGraph: Can't create line with parent types '"+_typeof(parents[0])+"' and '"+_typeof(parents[1])+"'.\nPossible parent types: [point,point], [[x1,y1],[x2,y2]], [a,b,c]");ps=parents[0],attr=Type.copyAttributes(attributes,board.options,"line","point1"),p1=board.create("point",[function(){var c=ps();return[.5*(c[2]*c[2]+c[1]*c[1]),.5*(c[2]-c[1]*c[0]+c[2]),.5*(-c[1]-c[2]*c[0]-c[1])]}],attr),attr=Type.copyAttributes(attributes,board.options,"line","point2"),p2=board.create("point",[function(){var c=ps();return[c[2]*c[2]+c[1]*c[1],-c[1]*c[0]+c[2],-c[2]*c[0]-c[1]]}],attr),attr=Type.copyAttributes(attributes,board.options,"line"),(el=new JXG.Line(board,p1,p2,attr)).constrained=!0,el.funps=parents[0],el.setParents([p1,p2])}return el},JXG.registerElement("line",JXG.createLine),JXG.createSegment=function(board,parents,attributes){var el,attr;if(attributes.straightFirst=!1,attributes.straightLast=!1,attr=Type.copyAttributes(attributes,board.options,"segment"),el=board.create("line",parents.slice(0,2),attr),3===parents.length){if(el.hasFixedLength=!0,Type.isNumber(parents[2]))el.fixedLength=function(){return parents[2]};else{if(!Type.isFunction(parents[2]))throw new Error("JSXGraph: Can't create segment with third parent type '"+_typeof(parents[2])+"'.\nPossible third parent types: number or function");el.fixedLength=parents[2]}el.getParents=function(){return this.parents.concat(this.fixedLength())},el.fixedLengthOldCoords=[],el.fixedLengthOldCoords[0]=new Coords(Const.COORDS_BY_USER,el.point1.coords.usrCoords.slice(1,3),board),el.fixedLengthOldCoords[1]=new Coords(Const.COORDS_BY_USER,el.point2.coords.usrCoords.slice(1,3),board)}return el.elType="segment",el},JXG.registerElement("segment",JXG.createSegment),JXG.createArrow=function(board,parents,attributes){var el,attr;return attributes.straightFirst=!1,attributes.straightLast=!1,attr=Type.copyAttributes(attributes,board.options,"arrow"),(el=board.create("line",parents,attr)).type=Const.OBJECT_TYPE_VECTOR,el.elType="arrow",el},JXG.registerElement("arrow",JXG.createArrow),JXG.createAxis=function(board,parents,attributes){var attr,attr_ticks,el,els,dist;if(!Type.isArray(parents[0])&&!Type.isPoint(parents[0])||!Type.isArray(parents[1])&&!Type.isPoint(parents[1]))throw new Error("JSXGraph: Can't create axis with parent types '"+_typeof(parents[0])+"' and '"+_typeof(parents[1])+"'.\nPossible parent types: [point,point], [[x1,y1],[x2,y2]]");for(els in attr=Type.copyAttributes(attributes,board.options,"axis"),(el=board.create("line",parents,attr)).type=Const.OBJECT_TYPE_AXIS,el.isDraggable=!1,el.point1.isDraggable=!1,el.point2.isDraggable=!1,el.ancestors)el.ancestors.hasOwnProperty(els)&&(el.ancestors[els].type=Const.OBJECT_TYPE_AXISPOINT);return attr_ticks=Type.copyAttributes(attributes,board.options,"axis","ticks"),dist=Type.exists(attr_ticks.ticksdistance)?attr_ticks.ticksdistance:Type.isArray(attr_ticks.ticks)?attr_ticks.ticks:1,el.defaultTicks=board.create("ticks",[el,dist],attr_ticks),el.defaultTicks.dump=!1,el.elType="axis",el.subs={ticks:el.defaultTicks},el.inherits.push(el.defaultTicks),el},JXG.registerElement("axis",JXG.createAxis),JXG.createTangent=function(board,parents,attributes){var p,c,j,el,tangent;if(1===parents.length)p=parents[0],c=p.slideObject;else{if(2!==parents.length)throw new Error("JSXGraph: Can't create tangent with parent types '"+_typeof(parents[0])+"' and '"+_typeof(parents[1])+"'.\nPossible parent types: [glider], [point,line|curve|circle|conic]");if(Type.isPoint(parents[0]))p=parents[0],c=parents[1];else{if(!Type.isPoint(parents[1]))throw new Error("JSXGraph: Can't create tangent with parent types '"+_typeof(parents[0])+"' and '"+_typeof(parents[1])+"'.\nPossible parent types: [glider], [point,line|curve|circle|conic]");c=parents[0],p=parents[1]}}if(c.elementClass===Const.OBJECT_CLASS_LINE?(tangent=board.create("line",[c.point1,c.point2],attributes)).glider=p:c.elementClass===Const.OBJECT_CLASS_CURVE&&c.type!==Const.OBJECT_TYPE_CONIC?"plot"!==Type.evaluate(c.visProp.curvetype)?(tangent=board.create("line",[function(){var g=c.X,f=c.Y;return-p.X()*Numerics.D(f)(p.position)+p.Y()*Numerics.D(g)(p.position)},function(){return Numerics.D(c.Y)(p.position)},function(){return-Numerics.D(c.X)(p.position)}],attributes),p.addChild(tangent),tangent.glider=p):(tangent=board.create("line",[function(){var p1,p2,t,A,B,C,D,dx,dy,d,i=Math.floor(p.position);if(1===c.bezierDegree)i===c.numberPoints-1&&i--;else{if(3!==c.bezierDegree)return 0;i=3*Math.floor(p.position*(c.numberPoints-1)/3),t=(p.position*(c.numberPoints-1)-i)/3,i>=c.numberPoints-1&&(i=c.numberPoints-4,t=1)}return i<0?1:(1===c.bezierDegree?(p1=c.points[i].usrCoords,p2=c.points[i+1].usrCoords):(A=c.points[i].usrCoords,B=c.points[i+1].usrCoords,C=c.points[i+2].usrCoords,D=c.points[i+3].usrCoords,dx=(1-t)*(1-t)*(B[1]-A[1])+2*(1-t)*t*(C[1]-B[1])+t*t*(D[1]-C[1]),dy=(1-t)*(1-t)*(B[2]-A[2])+2*(1-t)*t*(C[2]-B[2])+t*t*(D[2]-C[2]),dx/=d=Math.sqrt(dx*dx+dy*dy),dy/=d,p2=[1,(p1=p.coords.usrCoords)[1]+dx,p1[2]+dy]),p1[2]*p2[1]-p1[1]*p2[2])},function(){var p1,p2,t,A,B,C,D,dx,dy,d,i=Math.floor(p.position);if(1===c.bezierDegree)i===c.numberPoints-1&&i--;else{if(3!==c.bezierDegree)return 0;i=3*Math.floor(p.position*(c.numberPoints-1)/3),t=(p.position*(c.numberPoints-1)-i)/3,i>=c.numberPoints-1&&(i=c.numberPoints-4,t=1)}return i<0?0:(1===c.bezierDegree?(p1=c.points[i].usrCoords,p2=c.points[i+1].usrCoords):(A=c.points[i].usrCoords,B=c.points[i+1].usrCoords,C=c.points[i+2].usrCoords,D=c.points[i+3].usrCoords,dx=(1-t)*(1-t)*(B[1]-A[1])+2*(1-t)*t*(C[1]-B[1])+t*t*(D[1]-C[1]),dy=(1-t)*(1-t)*(B[2]-A[2])+2*(1-t)*t*(C[2]-B[2])+t*t*(D[2]-C[2]),dx/=d=Math.sqrt(dx*dx+dy*dy),dy/=d,p2=[1,(p1=p.coords.usrCoords)[1]+dx,p1[2]+dy]),p2[2]-p1[2])},function(){var p1,p2,t,A,B,C,D,dx,dy,d,i=Math.floor(p.position);if(1===c.bezierDegree)i===c.numberPoints-1&&i--;else{if(3!==c.bezierDegree)return 0;i=3*Math.floor(p.position*(c.numberPoints-1)/3),t=(p.position*(c.numberPoints-1)-i)/3,i>=c.numberPoints-1&&(i=c.numberPoints-4,t=1)}return i<0?0:(1===c.bezierDegree?(p1=c.points[i].usrCoords,p2=c.points[i+1].usrCoords):(A=c.points[i].usrCoords,B=c.points[i+1].usrCoords,C=c.points[i+2].usrCoords,D=c.points[i+3].usrCoords,dx=(1-t)*(1-t)*(B[1]-A[1])+2*(1-t)*t*(C[1]-B[1])+t*t*(D[1]-C[1]),dy=(1-t)*(1-t)*(B[2]-A[2])+2*(1-t)*t*(C[2]-B[2])+t*t*(D[2]-C[2]),dx/=d=Math.sqrt(dx*dx+dy*dy),dy/=d,p2=[1,(p1=p.coords.usrCoords)[1]+dx,p1[2]+dy]),p1[1]-p2[1])}],attributes),p.addChild(tangent),tangent.glider=p):c.type===Const.OBJECT_TYPE_TURTLE?(tangent=board.create("line",[function(){var i=Math.floor(p.position);for(j=0;j<c.objects.length;j++)if((el=c.objects[j]).type===Const.OBJECT_TYPE_CURVE){if(i<el.numberPoints)break;i-=el.numberPoints}return i===el.numberPoints-1&&i--,i<0?1:el.Y(i)*el.X(i+1)-el.X(i)*el.Y(i+1)},function(){var i=Math.floor(p.position);for(j=0;j<c.objects.length;j++)if((el=c.objects[j]).type===Const.OBJECT_TYPE_CURVE){if(i<el.numberPoints)break;i-=el.numberPoints}return i===el.numberPoints-1&&i--,i<0?0:el.Y(i+1)-el.Y(i)},function(){var i=Math.floor(p.position);for(j=0;j<c.objects.length;j++)if((el=c.objects[j]).type===Const.OBJECT_TYPE_CURVE){if(i<el.numberPoints)break;i-=el.numberPoints}return i===el.numberPoints-1&&i--,i<0?0:el.X(i)-el.X(i+1)}],attributes),p.addChild(tangent),tangent.glider=p):c.elementClass!==Const.OBJECT_CLASS_CIRCLE&&c.type!==Const.OBJECT_TYPE_CONIC||(tangent=board.create("line",[function(){return Mat.matVecMult(c.quadraticform,p.coords.usrCoords)[0]},function(){return Mat.matVecMult(c.quadraticform,p.coords.usrCoords)[1]},function(){return Mat.matVecMult(c.quadraticform,p.coords.usrCoords)[2]}],attributes),p.addChild(tangent),tangent.glider=p),!Type.exists(tangent))throw new Error("JSXGraph: Couldn't create tangent with the given parents.");return tangent.elType="tangent",tangent.type=Const.OBJECT_TYPE_TANGENT,tangent.setParents(parents),tangent},JXG.createRadicalAxis=function(board,parents,attributes){var el,el1,el2;if(2!==parents.length||parents[0].elementClass!==Const.OBJECT_CLASS_CIRCLE||parents[1].elementClass!==Const.OBJECT_CLASS_CIRCLE)throw new Error("JSXGraph: Can't create 'radical axis' with parent types '"+_typeof(parents[0])+"' and '"+_typeof(parents[1])+"'.\nPossible parent type: [circle,circle]");return el1=board.select(parents[0]),el2=board.select(parents[1]),(el=board.create("line",[function(){var a=el1.stdform,b=el2.stdform;return Mat.matVecMult(Mat.transpose([a.slice(0,3),b.slice(0,3)]),[b[3],-a[3]])}],attributes)).elType="radicalaxis",el.setParents([el1.id,el2.id]),el1.addChild(el),el2.addChild(el),el},JXG.createPolarLine=function(board,parents,attributes){var el,el1,el2,firstParentIsConic,secondParentIsConic,firstParentIsPoint,secondParentIsPoint;if(parents.length>1&&(firstParentIsConic=parents[0].type===Const.OBJECT_TYPE_CONIC||parents[0].elementClass===Const.OBJECT_CLASS_CIRCLE,secondParentIsConic=parents[1].type===Const.OBJECT_TYPE_CONIC||parents[1].elementClass===Const.OBJECT_CLASS_CIRCLE,firstParentIsPoint=Type.isPoint(parents[0]),secondParentIsPoint=Type.isPoint(parents[1])),2!==parents.length||!(firstParentIsConic&&secondParentIsPoint||firstParentIsPoint&&secondParentIsConic))throw new Error("JSXGraph: Can't create 'polar line' with parent types '"+_typeof(parents[0])+"' and '"+_typeof(parents[1])+"'.\nPossible parent type: [conic|circle,point], [point,conic|circle]");return secondParentIsPoint?(el1=board.select(parents[0]),el2=board.select(parents[1])):(el1=board.select(parents[1]),el2=board.select(parents[0])),(el=board.create("tangent",[el1,el2],attributes)).elType="polarline",el},JXG.registerElement("tangent",JXG.createTangent),JXG.registerElement("polar",JXG.createTangent),JXG.registerElement("radicalaxis",JXG.createRadicalAxis),JXG.registerElement("polarline",JXG.createPolarLine),{Line:JXG.Line,createLine:JXG.createLine,createTangent:JXG.createTangent,createPolar:JXG.createTangent,createSegment:JXG.createSegment,createAxis:JXG.createAxis,createArrow:JXG.createArrow,createRadicalAxis:JXG.createRadicalAxis,createPolarLine:JXG.createPolarLine}})),define("base/group",["jxg","base/constants","math/math","math/geometry","utils/type"],(function(JXG,Const,Mat,Geometry,Type){return JXG.Group=function(board,id,name,objects,attributes){var number,objArray,i,obj;for(this.board=board,this.objects={},number=this.board.numObjects,this.board.numObjects+=1,""!==id&&Type.exists(id)?this.id=id:this.id=this.board.id+"Group"+number,this.board.groups[this.id]=this,this.type=Const.OBJECT_TYPE_POINT,this.elementClass=Const.OBJECT_CLASS_POINT,""!==name&&Type.exists(name)?this.name=name:this.name="group_"+this.board.generateName(this),delete this.type,this.coords={},this.needsRegularUpdate=attributes.needsregularupdate,this.rotationCenter="centroid",this.scaleCenter=null,this.rotationPoints=[],this.translationPoints=[],this.scalePoints=[],this.scaleDirections={},this.parents=[],objArray=Type.isArray(objects)?objects:Array.prototype.slice.call(arguments,3),i=0;i<objArray.length;i++)obj=this.board.select(objArray[i]),!Type.evaluate(obj.visProp.fixed)&&Type.exists(obj.coords)&&this.addPoint(obj);this.methodMap={ungroup:"ungroup",add:"addPoint",addPoint:"addPoint",addPoints:"addPoints",addGroup:"addGroup",remove:"removePoint",removePoint:"removePoint",setAttribute:"setAttribute",setProperty:"setAttribute"}},JXG.extend(JXG.Group.prototype,{ungroup:function(){var el,p,i;for(el in this.objects)this.objects.hasOwnProperty(el)&&(p=this.objects[el].point,Type.isArray(p.groups)&&(i=Type.indexOf(p.groups,this.id))>=0&&delete p.groups[i]);return this.objects={},this},addParents:function(parents){var i,len,par;for(len=(par=Type.isArray(parents)?parents:arguments).length,i=0;i<len;++i)Type.isId(this.board,par[i])?this.parents.push(par[i]):Type.exists(par[i].id)&&this.parents.push(par[i].id);this.parents=Type.uniqueArray(this.parents)},setParents:function(parents){return this.parents=[],this.addParents(parents),this},getParents:function(){return Type.isArray(this.parents)?this.parents:[]},_updateCoordsCache:function(el){var obj;""!==el&&Type.exists(this.objects[el])&&(obj=this.objects[el].point,this.coords[obj.id]={usrCoords:obj.coords.usrCoords.slice(0)})},update:function(){var drag,el,actionCenter,desc,s,sx,sy,alpha,t,center,obj=null;if(!this.needsUpdate)return this;if("nothing"===(drag=this._update_find_drag_type()).action)return this._updateCoordsCache(drag.id),this;if(obj=this.objects[drag.id].point,"translation"===drag.action)t=[obj.coords.usrCoords[1]-this.coords[drag.id].usrCoords[1],obj.coords.usrCoords[2]-this.coords[drag.id].usrCoords[2]];else if("rotation"===drag.action||"scaling"===drag.action){if(actionCenter="rotation"===drag.action?"rotationCenter":"scaleCenter",Type.isPoint(this[actionCenter]))center=this[actionCenter].coords.usrCoords.slice(1);else if("centroid"===this[actionCenter])center=this._update_centroid_center();else if(Type.isArray(this[actionCenter]))center=this[actionCenter];else{if(!Type.isFunction(this[actionCenter]))return this;center=this[actionCenter]()}if("rotation"===drag.action)alpha=Geometry.rad(this.coords[drag.id].usrCoords.slice(1),center,this.objects[drag.id].point),(t=this.board.create("transform",[alpha,center[0],center[1]],{type:"rotate"})).update();else{if("scaling"!==drag.action)return this;if(s=Geometry.distance(this.coords[drag.id].usrCoords.slice(1),center),Math.abs(s)<Mat.eps)return this;s=Geometry.distance(obj.coords.usrCoords.slice(1),center)/s,sx=this.scaleDirections[drag.id].indexOf("x")>=0?s:1,sy=this.scaleDirections[drag.id].indexOf("y")>=0?s:1,(t=this.board.create("transform",[1,0,0,center[0]*(1-sx),sx,0,center[1]*(1-sy),0,sy],{type:"generic"})).update()}}for(el in this._update_apply_transformation(drag,t),this.needsUpdate=!1,this.objects)if(this.objects.hasOwnProperty(el))for(desc in this.objects[el].descendants)this.objects[el].descendants.hasOwnProperty(desc)&&(this.objects[el].descendants.needsUpdate=this.objects[el].descendants.needsRegularUpdate||this.board.needsFullUpdate);for(el in this.board.updateElements(drag),this.objects)this.objects.hasOwnProperty(el)&&this._updateCoordsCache(el);return this},_update_find_drag_type:function(){var el,obj,dragObjId,action="nothing",changed=[];for(el in this.objects)this.objects.hasOwnProperty(el)&&(obj=this.objects[el].point).coords.distance(Const.COORDS_BY_USER,this.coords[el])>Mat.eps&&changed.push(obj.id);return 0===changed.length?{action:action,id:"",changed:changed}:(dragObjId=changed[0],obj=this.objects[dragObjId].point,changed.length>1?action="translation":Type.isInArray(this.rotationPoints,obj)&&Type.exists(this.rotationCenter)?action="rotation":Type.isInArray(this.scalePoints,obj)&&Type.exists(this.scaleCenter)?action="scaling":Type.isInArray(this.translationPoints,obj)&&(action="translation"),{action:action,id:dragObjId,changed:changed})},_update_centroid_center:function(){var center,len,el;for(el in center=[0,0],len=0,this.coords)this.coords.hasOwnProperty(el)&&(center[0]+=this.coords[el].usrCoords[1],center[1]+=this.coords[el].usrCoords[2],++len);return len>0&&(center[0]/=len,center[1]/=len),center},_update_apply_transformation:function(drag,t){var el,obj;for(el in this.objects)this.objects.hasOwnProperty(el)&&(Type.exists(this.board.objects[el])?(obj=this.objects[el].point).id!==drag.id?"translation"===drag.action?Type.isInArray(drag.changed,obj.id)||obj.coords.setCoordinates(Const.COORDS_BY_USER,[this.coords[el].usrCoords[1]+t[0],this.coords[el].usrCoords[2]+t[1]]):"rotation"!==drag.action&&"scaling"!==drag.action||t.applyOnce([obj]):"rotation"!==drag.action&&"scaling"!==drag.action||obj.coords.setCoordinates(Const.COORDS_BY_USER,Mat.matVecMult(t.matrix,this.coords[obj.id].usrCoords)):delete this.objects[el])},addPoint:function(object){return this.objects[object.id]={point:this.board.select(object)},this._updateCoordsCache(object.id),this.translationPoints.push(object),object.groups.push(this.id),object.groups=Type.uniqueArray(object.groups),this},addPoints:function(objects){var p;for(p=0;p<objects.length;p++)this.addPoint(objects[p]);return this},addGroup:function(group){var el;for(el in group.objects)group.objects.hasOwnProperty(el)&&this.addPoint(group.objects[el].point);return this},removePoint:function(point){return delete this.objects[point.id],this},setRotationCenter:function(object){return this.rotationCenter=object,this},setRotationPoints:function(objects){return this._setActionPoints("rotation",objects)},addRotationPoint:function(point){return this._addActionPoint("rotation",point)},removeRotationPoint:function(point){return this._removeActionPoint("rotation",point)},setTranslationPoints:function(objects){return this._setActionPoints("translation",objects)},addTranslationPoint:function(point){return this._addActionPoint("translation",point)},removeTranslationPoint:function(point){return this._removeActionPoint("translation",point)},setScaleCenter:function(object){return this.scaleCenter=object,this},setScalePoints:function(objects,direction){var objs,i,len;for(len=(objs=Type.isArray(objects)?objects:arguments).length,i=0;i<len;++i)this.scaleDirections[this.board.select(objs[i]).id]=direction||"xy";return this._setActionPoints("scale",objects)},addScalePoint:function(point,direction){return this._addActionPoint("scale",point),this.scaleDirections[this.board.select(point).id]=direction||"xy",this},removeScalePoint:function(point){return this._removeActionPoint("scale",point)},_setActionPoints:function(action,objects){var objs,i,len;for(len=(objs=Type.isArray(objects)?objects:arguments).length,this[action+"Points"]=[],i=0;i<len;++i)this._addActionPoint(action,objs[i]);return this},_addActionPoint:function(action,point){return this[action+"Points"].push(this.board.select(point)),this},_removeActionPoint:function(action,point){var idx=this[action+"Points"].indexOf(this.board.select(point));return idx>-1&&this[action+"Points"].splice(idx,1),this},setProperty:function(){JXG.deprecated("Group.setProperty","Group.setAttribute()"),this.setAttribute.apply(this,arguments)},setAttribute:function(){var el;for(el in this.objects)this.objects.hasOwnProperty(el)&&this.objects[el].point.setAttribute.apply(this.objects[el].point,arguments);return this}}),JXG.createGroup=function(board,parents,attributes){var attr=Type.copyAttributes(attributes,board.options,"group"),g=new JXG.Group(board,attr.id,attr.name,parents,attr);return g.elType="group",g.setParents(parents),g},JXG.registerElement("group",JXG.createGroup),{Group:JXG.Group,createGroup:JXG.createGroup}})),define("element/conic",["jxg","base/constants","base/coords","math/math","math/numerics","math/geometry","utils/type"],(function(JXG,Const,Coords,Mat,Numerics,Geometry,Type){return JXG.createEllipse=function(board,parents,attributes){var polarForm,curve,M,C,majorAxis,i,hasPointOrg,F=[],attr_foci=Type.copyAttributes(attributes,board.options,"conic","foci"),attr_center=Type.copyAttributes(attributes,board.options,"conic","center"),attr_curve=Type.copyAttributes(attributes,board.options,"conic");for(i=0;i<2;i++)if(parents[i].length>1)F[i]=board.create("point",parents[i],attr_foci);else if(Type.isPoint(parents[i]))F[i]=board.select(parents[i]);else if(Type.isFunction(parents[i])&&Type.isPoint(parents[i]()))F[i]=parents[i]();else{if(!Type.isString(parents[i]))throw new Error("JSXGraph: Can't create Ellipse with parent types '"+_typeof(parents[0])+"' and '"+_typeof(parents[1])+"'.\nPossible parent types: [point,point,point], [point,point,number|function]");F[i]=board.select(parents[i])}if(Type.isNumber(parents[2]))majorAxis=Type.createFunction(parents[2],board);else if(Type.isFunction(parents[2])&&Type.isNumber(parents[2]()))majorAxis=parents[2];else{if(Type.isPoint(parents[2]))C=board.select(parents[2]);else if(parents[2].length>1)C=board.create("point",parents[2],attr_foci);else if(Type.isFunction(parents[2])&&Type.isPoint(parents[2]()))C=parents[2]();else{if(!Type.isString(parents[2]))throw new Error("JSXGraph: Can't create Ellipse with parent types '"+_typeof(parents[0])+"' and '"+_typeof(parents[1])+"' and '"+_typeof(parents[2])+"'.\nPossible parent types: [point,point,point], [point,point,number|function]");C=board.select(parents[2])}majorAxis=function(){return C.Dist(F[0])+C.Dist(F[1])}}for(Type.exists(parents[4])||(parents[4]=2*Math.PI),Type.exists(parents[3])||(parents[3]=0),M=board.create("point",[function(){return.5*(F[0].X()+F[1].X())},function(){return.5*(F[0].Y()+F[1].Y())}],attr_center),(curve=board.create("curve",[function(x){return 0},function(x){return 0},parents[3],parents[4]],attr_curve)).majorAxis=majorAxis,hasPointOrg=curve.hasPoint,polarForm=function(phi,suspendUpdate){var r,rr,ax,ay,bx,by,axbx,ayby,f;suspendUpdate||(rr=(r=majorAxis())*r,ax=F[0].X(),ay=F[0].Y(),axbx=ax-(bx=F[1].X()),ayby=ay-(by=F[1].Y()),f=(rr-ax*ax-ay*ay+bx*bx+by*by)/(2*r),curve.quadraticform=[[f*f-bx*bx-by*by,f*axbx/r+bx,f*ayby/r+by],[f*axbx/r+bx,axbx*axbx/rr-1,axbx*ayby/rr],[f*ayby/r+by,axbx*ayby/rr,ayby*ayby/rr-1]])},curve.X=function(phi,suspendUpdate){var r=majorAxis(),c=F[1].Dist(F[0]),b=.5*(c*c-r*r)/(c*Math.cos(phi)-r),beta=Math.atan2(F[1].Y()-F[0].Y(),F[1].X()-F[0].X());return suspendUpdate||polarForm(0,suspendUpdate),F[0].X()+Math.cos(beta+phi)*b},curve.Y=function(phi,suspendUpdate){var r=majorAxis(),c=F[1].Dist(F[0]),b=.5*(c*c-r*r)/(c*Math.cos(phi)-r),beta=Math.atan2(F[1].Y()-F[0].Y(),F[1].X()-F[0].X());return F[0].Y()+Math.sin(beta+phi)*b},curve.midpoint=curve.center=M,curve.type=Const.OBJECT_TYPE_CONIC,curve.subs={center:curve.center},curve.inherits.push(curve.center,F[0],F[1]),Type.isPoint(C)&&curve.inherits.push(C),curve.hasPoint=function(x,y){var ac,bc,r,p;return Type.evaluate(this.visProp.hasinnerpoints)?(ac=F[0].coords,bc=F[1].coords,r=this.majorAxis(),(p=new Coords(Const.COORDS_BY_SCREEN,[x,y],this.board)).distance(Const.COORDS_BY_USER,ac)+p.distance(Const.COORDS_BY_USER,bc)<=r):hasPointOrg.apply(this,arguments)},M.addChild(curve),i=0;i<2;i++)Type.isPoint(F[i])&&F[i].addChild(curve);return Type.isPoint(C)&&C.addChild(curve),curve.setParents(parents),curve},JXG.createHyperbola=function(board,parents,attributes){var polarForm,curve,M,C,majorAxis,i,F=[],attr_foci=Type.copyAttributes(attributes,board.options,"conic","foci"),attr_center=Type.copyAttributes(attributes,board.options,"conic","center"),attr_curve=Type.copyAttributes(attributes,board.options,"conic");for(i=0;i<2;i++)if(parents[i].length>1)F[i]=board.create("point",parents[i],attr_foci);else if(Type.isPoint(parents[i]))F[i]=board.select(parents[i]);else if(Type.isFunction(parents[i])&&Type.isPoint(parents[i]()))F[i]=parents[i]();else{if(!Type.isString(parents[i]))throw new Error("JSXGraph: Can't create Hyperbola with parent types '"+_typeof(parents[0])+"' and '"+_typeof(parents[1])+"'.\nPossible parent types: [point,point,point], [point,point,number|function]");F[i]=board.select(parents[i])}if(Type.isNumber(parents[2]))majorAxis=Type.createFunction(parents[2],board);else if(Type.isFunction(parents[2])&&Type.isNumber(parents[2]()))majorAxis=parents[2];else{if(Type.isPoint(parents[2]))C=board.select(parents[2]);else if(parents[2].length>1)C=board.create("point",parents[2],attr_foci);else if(Type.isFunction(parents[2])&&Type.isPoint(parents[2]()))C=parents[2]();else{if(!Type.isString(parents[2]))throw new Error("JSXGraph: Can't create Hyperbola with parent types '"+_typeof(parents[0])+"' and '"+_typeof(parents[1])+"' and '"+_typeof(parents[2])+"'.\nPossible parent types: [point,point,point], [point,point,number|function]");C=board.select(parents[2])}majorAxis=function(){return C.Dist(F[0])-C.Dist(F[1])}}for(Type.exists(parents[4])||(parents[4]=1.0001*Math.PI),Type.exists(parents[3])||(parents[3]=-1.0001*Math.PI),M=board.create("point",[function(){return.5*(F[0].X()+F[1].X())},function(){return.5*(F[0].Y()+F[1].Y())}],attr_center),(curve=board.create("curve",[function(x){return 0},function(x){return 0},parents[3],parents[4]],attr_curve)).majorAxis=majorAxis,polarForm=function(phi,suspendUpdate){var r,rr,ax,ay,bx,by,axbx,ayby,f;suspendUpdate||(rr=(r=majorAxis())*r,ax=F[0].X(),ay=F[0].Y(),axbx=ax-(bx=F[1].X()),ayby=ay-(by=F[1].Y()),f=(rr-ax*ax-ay*ay+bx*bx+by*by)/(2*r),curve.quadraticform=[[f*f-bx*bx-by*by,f*axbx/r+bx,f*ayby/r+by],[f*axbx/r+bx,axbx*axbx/rr-1,axbx*ayby/rr],[f*ayby/r+by,axbx*ayby/rr,ayby*ayby/rr-1]])},curve.X=function(phi,suspendUpdate){var r=majorAxis(),c=F[1].Dist(F[0]),b=.5*(c*c-r*r)/(c*Math.cos(phi)+r),beta=Math.atan2(F[1].Y()-F[0].Y(),F[1].X()-F[0].X());return suspendUpdate||polarForm(0,suspendUpdate),F[0].X()+Math.cos(beta+phi)*b},curve.Y=function(phi,suspendUpdate){var r=majorAxis(),c=F[1].Dist(F[0]),b=.5*(c*c-r*r)/(c*Math.cos(phi)+r),beta=Math.atan2(F[1].Y()-F[0].Y(),F[1].X()-F[0].X());return F[0].Y()+Math.sin(beta+phi)*b},curve.midpoint=curve.center=M,curve.subs={center:curve.center},curve.inherits.push(curve.center,F[0],F[1]),Type.isPoint(C)&&curve.inherits.push(C),curve.type=Const.OBJECT_TYPE_CONIC,M.addChild(curve),i=0;i<2;i++)Type.isPoint(F[i])&&F[i].addChild(curve);return Type.isPoint(C)&&C.addChild(curve),curve.setParents(parents),curve},JXG.createParabola=function(board,parents,attributes){var polarForm,curve,M,attr_line,F1=parents[0],l=parents[1],attr_foci=Type.copyAttributes(attributes,board.options,"conic","foci"),attr_center=Type.copyAttributes(attributes,board.options,"conic","center"),attr_curve=Type.copyAttributes(attributes,board.options,"conic");if(parents[0].length>1)F1=board.create("point",parents[0],attr_foci);else if(Type.isPoint(parents[0]))F1=board.select(parents[0]);else if(Type.isFunction(parents[0])&&Type.isPoint(parents[0]()))F1=parents[0]();else{if(!Type.isString(parents[0]))throw new Error("JSXGraph: Can't create Parabola with parent types '"+_typeof(parents[0])+"' and '"+_typeof(parents[1])+"'.\nPossible parent types: [point,line]");F1=board.select(parents[0])}return Type.isArray(l)&&2===l.length&&(attr_line=Type.copyAttributes(attributes,board.options,"conic","line"),l=board.create("line",l,attr_line)),Type.exists(parents[3])||(parents[3]=2*Math.PI),Type.exists(parents[2])||(parents[2]=0),M=board.create("point",[function(){return Geometry.projectPointToLine(F1,l,board).usrCoords}],attr_center),(curve=board.create("curve",[function(x){return 0},function(x){return 0},parents[2],parents[3]],attr_curve)).midpoint=curve.center=M,curve.subs={center:curve.center},curve.inherits.push(curve.center),polarForm=function(t,suspendUpdate){var a,b,c,ab,px,py;suspendUpdate||(a=l.stdform[1],b=l.stdform[2],c=l.stdform[0],ab=a*a+b*b,px=F1.X(),py=F1.Y(),curve.quadraticform=[[c*c-ab*(px*px+py*py),c*a+ab*px,c*b+ab*py],[c*a+ab*px,-b*b,a*b],[c*b+ab*py,a*b,-a*a]])},curve.X=function(phi,suspendUpdate){var a,beta=l.getAngle(),d=Geometry.distPointLine(F1.coords.usrCoords,l.stdform),A=l.point1.coords.usrCoords,B=l.point2.coords.usrCoords,M=F1.coords.usrCoords;return 0===A[0]?A=[1,B[1]+l.stdform[2],B[2]-l.stdform[1]]:0===B[0]&&(B=[1,A[1]+l.stdform[2],A[2]-l.stdform[1]]),a=((B[1]-A[1])*(M[2]-A[2])-(B[2]-A[2])*(M[1]-A[1])>=0?1:-1)*d/(1-Math.sin(phi)),suspendUpdate||polarForm(0,suspendUpdate),F1.X()+Math.cos(phi+beta)*a},curve.Y=function(phi,suspendUpdate){var a,beta=l.getAngle(),d=Geometry.distPointLine(F1.coords.usrCoords,l.stdform),A=l.point1.coords.usrCoords,B=l.point2.coords.usrCoords,M=F1.coords.usrCoords;return 0===A[0]?A=[1,B[1]+l.stdform[2],B[2]-l.stdform[1]]:0===B[0]&&(B=[1,A[1]+l.stdform[2],A[2]-l.stdform[1]]),a=((B[1]-A[1])*(M[2]-A[2])-(B[2]-A[2])*(M[1]-A[1])>=0?1:-1)*d/(1-Math.sin(phi)),F1.Y()+Math.sin(phi+beta)*a},curve.type=Const.OBJECT_TYPE_CONIC,M.addChild(curve),Type.isPoint(F1)&&(F1.addChild(curve),curve.inherits.push(F1)),l.addChild(curve),curve.setParents(parents),curve},JXG.createConic=function(board,parents,attributes){var polarForm,curve,fitConic,degconic,sym,eigen,a,b,c,c1,c2,i,definingMat,givenByPoints,rotationMatrix=[[1,0,0],[0,1,0],[0,0,1]],M=[[1,0,0],[0,1,0],[0,0,1]],points=[],p=[],attr_point=Type.copyAttributes(attributes,board.options,"conic","point"),attr_center=Type.copyAttributes(attributes,board.options,"conic","center"),attr_curve=Type.copyAttributes(attributes,board.options,"conic");if(5===parents.length)givenByPoints=!0;else{if(6!==parents.length)throw new Error("JSXGraph: Can't create generic Conic with "+parents.length+" parameters.");givenByPoints=!1}if(givenByPoints)for(i=0;i<5;i++)if(parents[i].length>1)points[i]=board.create("point",parents[i],attr_point);else if(Type.isPoint(parents[i]))points[i]=board.select(parents[i]);else if(Type.isFunction(parents[i])&&Type.isPoint(parents[i]()))points[i]=parents[i]();else{if(!Type.isString(parents[i]))throw new Error("JSXGraph: Can't create Conic section with parent types '"+_typeof(parents[i])+"'.\nPossible parent types: [point,point,point,point,point], [a00,a11,a22,a01,a02,a12]");points[i]=board.select(parents[i])}else(definingMat=[[0,0,0],[0,0,0],[0,0,0]])[0][0]=Type.isFunction(parents[2])?function(){return parents[2]()}:function(){return parents[2]},definingMat[0][1]=Type.isFunction(parents[4])?function(){return parents[4]()}:function(){return parents[4]},definingMat[0][2]=Type.isFunction(parents[5])?function(){return parents[5]()}:function(){return parents[5]},definingMat[1][1]=Type.isFunction(parents[0])?function(){return parents[0]()}:function(){return parents[0]},definingMat[1][2]=Type.isFunction(parents[3])?function(){return parents[3]()}:function(){return parents[3]},definingMat[2][2]=Type.isFunction(parents[1])?function(){return parents[1]()}:function(){return parents[1]};if(sym=function(A){var i,j;for(i=0;i<3;i++)for(j=i;j<3;j++)A[i][j]+=A[j][i];for(i=0;i<3;i++)for(j=0;j<i;j++)A[i][j]=A[j][i];return A},degconic=function(v,w){var i,j,mat=[[0,0,0],[0,0,0],[0,0,0]];for(i=0;i<3;i++)for(j=0;j<3;j++)mat[i][j]=v[i]*w[j];return sym(mat)},fitConic=function(A,B,p){var i,j,pBp,pAp,Mv,mat=[[0,0,0],[0,0,0],[0,0,0]];for(Mv=Mat.matVecMult(B,p),pBp=Mat.innerProduct(p,Mv),Mv=Mat.matVecMult(A,p),pAp=Mat.innerProduct(p,Mv),i=0;i<3;i++)for(j=0;j<3;j++)mat[i][j]=pBp*A[i][j]-pAp*B[i][j];return mat},curve=board.create("curve",[function(x){return 0},function(x){return 0},0,2*Math.PI],attr_curve),polarForm=function(phi,suspendUpdate){var i,j,len,v;if(!suspendUpdate){if(givenByPoints){for(i=0;i<5;i++)p[i]=points[i].coords.usrCoords;c1=degconic(Mat.crossProduct(p[0],p[1]),Mat.crossProduct(p[2],p[3])),c2=degconic(Mat.crossProduct(p[0],p[2]),Mat.crossProduct(p[1],p[3])),M=fitConic(c1,c2,p[4])}else for(i=0;i<3;i++)for(j=i;j<3;j++)M[i][j]=definingMat[i][j](),j>i&&(M[j][i]=M[i][j]);for(curve.quadraticform=M,(eigen=Numerics.Jacobi(M))[0][0][0]<0&&(eigen[0][0][0]*=-1,eigen[0][1][1]*=-1,eigen[0][2][2]*=-1),i=0;i<3;i++){for(len=0,j=0;j<3;j++)len+=eigen[1][j][i]*eigen[1][j][i];len=Math.sqrt(len)}rotationMatrix=eigen[1],c=Math.sqrt(Math.abs(eigen[0][0][0])),a=Math.sqrt(Math.abs(eigen[0][1][1])),b=Math.sqrt(Math.abs(eigen[0][2][2]))}return eigen[0][1][1]<=0&&eigen[0][2][2]<=0?v=Mat.matVecMult(rotationMatrix,[1/c,Math.cos(phi)/a,Math.sin(phi)/b]):eigen[0][1][1]<=0&&eigen[0][2][2]>0?v=Mat.matVecMult(rotationMatrix,[Math.cos(phi)/c,1/a,Math.sin(phi)/b]):eigen[0][2][2]<0&&(v=Mat.matVecMult(rotationMatrix,[Math.sin(phi)/c,Math.cos(phi)/a,1/b])),Type.exists(v)?(v[1]/=v[0],v[2]/=v[0],v[0]=1):v=[1,NaN,NaN],v},curve.X=function(phi,suspendUpdate){return polarForm(phi,suspendUpdate)[1]},curve.Y=function(phi,suspendUpdate){return polarForm(phi,suspendUpdate)[2]},curve.midpoint=board.create("point",[function(){var m=curve.quadraticform;return[m[1][1]*m[2][2]-m[1][2]*m[1][2],m[1][2]*m[0][2]-m[2][2]*m[0][1],m[0][1]*m[1][2]-m[1][1]*m[0][2]]}],attr_center),curve.type=Const.OBJECT_TYPE_CONIC,curve.center=curve.midpoint,curve.subs={center:curve.center},curve.inherits.push(curve.center),curve.inherits=curve.inherits.concat(points),givenByPoints){for(i=0;i<5;i++)Type.isPoint(points[i])&&points[i].addChild(curve);curve.setParents(parents)}return curve.addChild(curve.center),curve},JXG.registerElement("ellipse",JXG.createEllipse),JXG.registerElement("hyperbola",JXG.createHyperbola),JXG.registerElement("parabola",JXG.createParabola),JXG.registerElement("conic",JXG.createConic),{createEllipse:JXG.createEllipse,createHyperbola:JXG.createHyperbola,createParabola:JXG.createParabola,createConic:JXG.createConic}})),define("base/circle",["jxg","base/element","base/coords","base/constants","element/conic","parser/geonext","utils/type"],(function(JXG,GeometryElement,Coords,Const,Conic,GeonextParser,Type){return JXG.Circle=function(board,method,par1,par2,attributes){this.constructor(board,attributes,Const.OBJECT_TYPE_CIRCLE,Const.OBJECT_CLASS_CIRCLE),this.method=method,this.midpoint=this.board.select(par1),this.center=this.board.select(par1),this.point2=null,this.radius=0,this.line=null,this.circle=null,this.points=[],"twoPoints"===method?(this.point2=board.select(par2),this.radius=this.Radius()):"pointRadius"===method?(this.gxtterm=par2,this.updateRadius=Type.createFunction(par2,this.board,null,!0),this.updateRadius()):"pointLine"===method?(this.line=board.select(par2),this.radius=this.line.point1.coords.distance(Const.COORDS_BY_USER,this.line.point2.coords)):"pointCircle"===method&&(this.circle=board.select(par2),this.radius=this.circle.Radius()),this.id=this.board.setId(this,"C"),this.board.renderer.drawEllipse(this),this.board.finalizeAdding(this),this.createGradient(),this.elType="circle",this.createLabel(),Type.exists(this.center._is_new)?(this.addChild(this.center),delete this.center._is_new):this.center.addChild(this),"pointRadius"===method?this.notifyParents(par2):"pointLine"===method?this.line.addChild(this):"pointCircle"===method?this.circle.addChild(this):"twoPoints"===method&&(Type.exists(this.point2._is_new)?(this.addChild(this.point2),delete this.point2._is_new):this.point2.addChild(this)),this.methodMap=Type.deepCopy(this.methodMap,{setRadius:"setRadius",getRadius:"getRadius",Area:"Area",area:"Area",radius:"Radius",center:"center",line:"line",point2:"point2"})},JXG.Circle.prototype=new GeometryElement,JXG.extend(JXG.Circle.prototype,{hasPoint:function(x,y){var prec,type,dx,dy,dist,mp=this.center.coords.usrCoords,p=new Coords(Const.COORDS_BY_SCREEN,[x,y],this.board),r=this.Radius();return Type.isObject(Type.evaluate(this.visProp.precision))?(type=this.board._inputDevice,prec=Type.evaluate(this.visProp.precision[type])):prec=this.board.options.precision.hasPoint,dx=mp[1]-p.usrCoords[1],dy=mp[2]-p.usrCoords[2],dist=Math.sqrt(dx*dx+dy*dy),prec+=.5*Type.evaluate(this.visProp.strokewidth),prec/=Math.sqrt(this.board.unitX*this.board.unitY),Type.evaluate(this.visProp.hasinnerpoints)?dist<r+prec:Math.abs(dist-r)<prec},generatePolynomial:function(p){var m1=this.center.symbolic.x,m2=this.center.symbolic.y,g1=p.symbolic.x,g2=p.symbolic.y,rsq=this.generateRadiusSquared();return""===rsq?[]:["(("+g1+")-("+m1+"))^2 + (("+g2+")-("+m2+"))^2 - ("+rsq+")"]},generateRadiusSquared:function(){var m1,m2,p1,p2,rsq="";return"twoPoints"===this.method?(m1=this.center.symbolic.x,m2=this.center.symbolic.y,rsq="(("+(p1=this.point2.symbolic.x)+")-("+m1+"))^2 + (("+(p2=this.point2.symbolic.y)+")-("+m2+"))^2"):"pointRadius"===this.method?Type.isNumber(this.radius)&&(rsq=(this.radius*this.radius).toString()):"pointLine"===this.method?(p1=this.line.point1.symbolic.x,p2=this.line.point1.symbolic.y,rsq="(("+p1+")-("+this.line.point2.symbolic.x+"))^2 + (("+p2+")-("+this.line.point2.symbolic.y+"))^2"):"pointCircle"===this.method&&(rsq=this.circle.Radius()),rsq},update:function(){var x,y,z,r,c,i;if(this.needsUpdate)for(Type.evaluate(this.visProp.trace)&&this.cloneToBackground(!0),"pointLine"===this.method?this.radius=this.line.point1.coords.distance(Const.COORDS_BY_USER,this.line.point2.coords):"pointCircle"===this.method?this.radius=this.circle.Radius():"pointRadius"===this.method&&(this.radius=this.updateRadius()),this.updateStdform(),this.updateQuadraticform(),z=this.center.coords.usrCoords[0],x=this.center.coords.usrCoords[1]/z,y=this.center.coords.usrCoords[2]/z,z/=z,r=this.Radius(),c=.551915024494,this.numberPoints=13,this.dataX=[x+r,x+r,x+r*c,x,x-r*c,x-r,x-r,x-r,x-r*c,x,x+r*c,x+r,x+r],this.dataY=[y,y+r*c,y+r,y+r,y+r,y+r*c,y,y-r*c,y-r,y-r,y-r,y-r*c,y],this.bezierDegree=3,i=0;i<this.numberPoints;i++)this.points[i]=new Coords(Const.COORDS_BY_USER,[this.dataX[i],this.dataY[i]],this.board);return this},updateQuadraticform:function(){var m=this.center,mX=m.X(),mY=m.Y(),r=this.Radius();this.quadraticform=[[mX*mX+mY*mY-r*r,-mX,-mY],[-mX,1,0],[-mY,0,1]]},updateStdform:function(){this.stdform[3]=.5,this.stdform[4]=this.Radius(),this.stdform[1]=-this.center.coords.usrCoords[1],this.stdform[2]=-this.center.coords.usrCoords[2],isFinite(this.stdform[4])||(this.stdform[0]=Type.exists(this.point2)?-(this.stdform[1]*this.point2.coords.usrCoords[1]+this.stdform[2]*this.point2.coords.usrCoords[2]):0),this.normalize()},updateRenderer:function(){return this.needsUpdate?(this.visPropCalc.visible&&(this.isReal=!isNaN(this.center.coords.usrCoords[1]+this.center.coords.usrCoords[2]+this.Radius())&&this.center.isReal,this.isReal||this.updateVisibility(!1)),this.visPropCalc.visible&&this.board.renderer.updateEllipse(this),this.hasLabel&&this.visPropCalc.visible&&this.label&&this.label.visPropCalc.visible&&this.isReal&&(this.label.update(),this.board.renderer.updateText(this.label)),this.setDisplayRendNode(),this.needsUpdate=!1,this):this},notifyParents:function(contentStr){Type.isString(contentStr)&&GeonextParser.findDependencies(this,contentStr,this.board)},setRadius:function(r){return this.updateRadius=Type.createFunction(r,this.board,null,!0),this.board.update(),this},Radius:function(value){return Type.exists(value)?(this.setRadius(value),this.Radius()):"twoPoints"===this.method?Type.cmpArrays(this.point2.coords.usrCoords,[0,0,0])||Type.cmpArrays(this.center.coords.usrCoords,[0,0,0])?NaN:this.center.Dist(this.point2):"pointLine"===this.method||"pointCircle"===this.method?this.radius:"pointRadius"===this.method?this.updateRadius():NaN},getRadius:function(){return JXG.deprecated("Circle.getRadius()","Circle.Radius()"),this.Radius()},getTextAnchor:function(){return this.center.coords},getLabelAnchor:function(){var x,y,r=this.Radius(),c=this.center.coords.usrCoords,SQRTH=.7071067811865476;switch(Type.evaluate(this.visProp.label.position)){case"lft":x=c[1]-r,y=c[2];break;case"llft":x=c[1]-SQRTH*r,y=c[2]-SQRTH*r;break;case"rt":x=c[1]+r,y=c[2];break;case"lrt":x=c[1]+SQRTH*r,y=c[2]-SQRTH*r;break;case"urt":x=c[1]+SQRTH*r,y=c[2]+SQRTH*r;break;case"top":x=c[1],y=c[2]+r;break;case"bot":x=c[1],y=c[2]-r;break;default:x=c[1]-SQRTH*r,y=c[2]+SQRTH*r}return new Coords(Const.COORDS_BY_USER,[x,y],this.board)},cloneToBackground:function(){var er,r=this.Radius(),copy={id:this.id+"T"+this.numTraces,elementClass:Const.OBJECT_CLASS_CIRCLE,center:{coords:this.center.coords},Radius:function(){return r},getRadius:function(){return r},board:this.board,visProp:Type.deepCopy(this.visProp,this.visProp.traceattributes,!0)};return copy.visProp.layer=this.board.options.layer.trace,this.numTraces++,Type.clearVisPropOld(copy),copy.visPropCalc={visible:Type.evaluate(copy.visProp.visible)},er=this.board.renderer.enhancedRendering,this.board.renderer.enhancedRendering=!0,this.board.renderer.drawEllipse(copy),this.board.renderer.enhancedRendering=er,this.traces[copy.id]=copy.rendNode,this},addTransform:function(transform){var i,list=Type.isArray(transform)?transform:[transform],len=list.length;for(i=0;i<len;i++)this.center.transformations.push(list[i]),"twoPoints"===this.method&&this.point2.transformations.push(list[i]);return this},snapToGrid:function(){var forceIt=Type.evaluate(this.visProp.snaptogrid);return this.center.handleSnapToGrid(forceIt,!0),"twoPoints"===this.method&&this.point2.handleSnapToGrid(forceIt,!0),this},snapToPoints:function(){var forceIt=Type.evaluate(this.visProp.snaptopoints);return this.center.handleSnapToPoints(forceIt),"twoPoints"===this.method&&this.point2.handleSnapToPoints(forceIt),this},X:function(t){return this.Radius()*Math.cos(2*t*Math.PI)+this.center.coords.usrCoords[1]},Y:function(t){return this.Radius()*Math.sin(2*t*Math.PI)+this.center.coords.usrCoords[2]},Z:function(t){return 1},minX:function(){return 0},maxX:function(){return 1},Area:function(){var r=this.Radius();return r*r*Math.PI},bounds:function(){var uc=this.center.coords.usrCoords,r=this.Radius();return[uc[1]-r,uc[2]+r,uc[1]+r,uc[2]-r]},getParents:function(){return 1===this.parents.length?this.parents.concat(this.radius):this.parents}}),JXG.createCircle=function(board,parents,attributes){var el,p,i,attr,obj,point_style=["center","point2"];if(p=[],obj=board.select(parents[0]),Type.isObject(obj)&&obj.elementClass===Const.OBJECT_CLASS_CIRCLE&&Type.isTransformationOrArray(parents[1]))return attr=Type.copyAttributes(attributes,board.options,"circle"),(el=Conic.createEllipse(board,[obj.center,obj.center,function(){return 2*obj.Radius()}],attr)).addTransform(parents[1]),el;for(i=0;i<parents.length;i++)if(Type.isPointType(board,parents[i])){if(!1===(p=p.concat(Type.providePoints(board,[parents[i]],attributes,"circle",[point_style[i]])))[p.length-1])throw new Error("JSXGraph: Can't create circle from this type. Please provide a point type.")}else p.push(parents[i]);if(attr=Type.copyAttributes(attributes,board.options,"circle"),2===p.length&&Type.isPoint(p[0])&&Type.isPoint(p[1]))el=new JXG.Circle(board,"twoPoints",p[0],p[1],attr);else if((Type.isNumber(p[0])||Type.isFunction(p[0])||Type.isString(p[0]))&&Type.isPoint(p[1]))el=new JXG.Circle(board,"pointRadius",p[1],p[0],attr);else if((Type.isNumber(p[1])||Type.isFunction(p[1])||Type.isString(p[1]))&&Type.isPoint(p[0]))el=new JXG.Circle(board,"pointRadius",p[0],p[1],attr);else if(p[0].elementClass===Const.OBJECT_CLASS_CIRCLE&&Type.isPoint(p[1]))el=new JXG.Circle(board,"pointCircle",p[1],p[0],attr);else if(p[1].elementClass===Const.OBJECT_CLASS_CIRCLE&&Type.isPoint(p[0]))el=new JXG.Circle(board,"pointCircle",p[0],p[1],attr);else if(p[0].elementClass===Const.OBJECT_CLASS_LINE&&Type.isPoint(p[1]))el=new JXG.Circle(board,"pointLine",p[1],p[0],attr);else if(p[1].elementClass===Const.OBJECT_CLASS_LINE&&Type.isPoint(p[0]))el=new JXG.Circle(board,"pointLine",p[0],p[1],attr);else{if(!(3===parents.length&&Type.isPoint(p[0])&&Type.isPoint(p[1])&&Type.isPoint(p[2])))throw new Error("JSXGraph: Can't create circle with parent types '"+_typeof(parents[0])+"' and '"+_typeof(parents[1])+"'.\nPossible parent types: [point,point], [point,number], [point,function], [point,circle], [point,point,point], [circle,transformation]");if(!JXG.elements.circumcircle)throw new Error("JSXGraph: Can't create circle with three points. Please include the circumcircle element (element/composition).");el=JXG.elements.circumcircle(board,p,attr)}for(el.isDraggable=!0,el.setParents(p),el.elType="circle",i=0;i<p.length;i++)Type.isPoint(p[i])&&el.inherits.push(p[i]);return el},JXG.registerElement("circle",JXG.createCircle),{Circle:JXG.Circle,createCircle:JXG.createCircle}})),define("base/polygon",["jxg","base/constants","base/coords","math/statistics","math/geometry","utils/type","base/element"],(function(JXG,Const,Coords,Statistics,Geometry,Type,GeometryElement){return JXG.Polygon=function(board,vertices,attributes){this.constructor(board,attributes,Const.OBJECT_TYPE_POLYGON,Const.OBJECT_CLASS_AREA);var i,l,len,j,p,attr_line=Type.copyAttributes(attributes,board.options,"polygon","borders");for(this.withLines=attributes.withlines,this.attr_line=attr_line,this.vertices=[],i=0;i<vertices.length;i++)this.vertices[i]=this.board.select(vertices[i]);if(this.vertices.length>0&&this.vertices[this.vertices.length-1].id!==this.vertices[0].id&&this.vertices.push(this.vertices[0]),this.borders=[],this.withLines)for(len=this.vertices.length-1,j=0;j<len;j++)i=(j+1)%len,attr_line.id=attr_line.ids&&attr_line.ids[i],attr_line.name=attr_line.names&&attr_line.names[i],attr_line.strokecolor=Type.isArray(attr_line.colors)&&attr_line.colors[i%attr_line.colors.length]||attr_line.strokecolor,attr_line.visible=Type.exists(attributes.borders.visible)?attributes.borders.visible:attributes.visible,!1===attr_line.strokecolor&&(attr_line.strokecolor="none"),(l=board.create("segment",[this.vertices[i],this.vertices[i+1]],attr_line)).dump=!1,this.borders[i]=l,l.parentPolygon=this;for(this.inherits.push(this.vertices,this.borders),this.id=this.board.setId(this,"Py"),i=0;i<this.vertices.length-1;i++)p=this.board.select(this.vertices[i]),Type.exists(p._is_new)?(this.addChild(p),delete p._is_new):p.addChild(this);this.board.renderer.drawPolygon(this),this.board.finalizeAdding(this),this.createGradient(),this.elType="polygon",this.createLabel(),this.methodMap=JXG.deepCopy(this.methodMap,{borders:"borders",vertices:"vertices",A:"Area",Area:"Area",Perimeter:"Perimeter",L:"Perimeter",Length:"Perimeter",boundingBox:"boundingBox",bounds:"bounds",addPoints:"addPoints",insertPoints:"insertPoints",removePoints:"removePoints"})},JXG.Polygon.prototype=new GeometryElement,JXG.extend(JXG.Polygon.prototype,{pnpoly:function(x_in,y_in,coord_type){var i,j,len,x,y,crds,v=this.vertices,isIn=!1;for(coord_type===Const.COORDS_BY_USER?(x=(crds=new Coords(Const.COORDS_BY_USER,[x_in,y_in],this.board)).scrCoords[1],y=crds.scrCoords[2]):(x=x_in,y=y_in),i=0,j=(len=this.vertices.length)-2;i<len-1;j=i++)v[i].coords.scrCoords[2]>y!=v[j].coords.scrCoords[2]>y&&x<(v[j].coords.scrCoords[1]-v[i].coords.scrCoords[1])*(y-v[i].coords.scrCoords[2])/(v[j].coords.scrCoords[2]-v[i].coords.scrCoords[2])+v[i].coords.scrCoords[1]&&(isIn=!isIn);return isIn},hasPoint:function(x,y){var i,len;if(Type.evaluate(this.visProp.hasinnerpoints)&&this.pnpoly(x,y))return!0;for(len=this.borders.length,i=0;i<len;i++)if(this.borders[i].hasPoint(x,y))return!0;return!1},updateRenderer:function(){var i,len;if(!this.needsUpdate)return this;if(this.visPropCalc.visible){for(len=this.vertices.length,this.isReal=!0,i=0;i<len;++i)if(!this.vertices[i].isReal){this.isReal=!1;break}this.isReal||this.updateVisibility(!1)}return this.visPropCalc.visible&&this.board.renderer.updatePolygon(this),this.hasLabel&&this.visPropCalc.visible&&this.label&&this.label.visPropCalc.visible&&this.isReal&&(this.label.update(),this.board.renderer.updateText(this.label)),this.setDisplayRendNode(),this.needsUpdate=!1,this},getTextAnchor:function(){var a,b,x,y,i;if(0===this.vertices.length)return new Coords(Const.COORDS_BY_USER,[1,0,0],this.board);for(x=a=this.vertices[0].X(),y=b=this.vertices[0].Y(),i=0;i<this.vertices.length;i++)this.vertices[i].X()<a&&(a=this.vertices[i].X()),this.vertices[i].X()>x&&(x=this.vertices[i].X()),this.vertices[i].Y()>b&&(b=this.vertices[i].Y()),this.vertices[i].Y()<y&&(y=this.vertices[i].Y());return new Coords(Const.COORDS_BY_USER,[.5*(a+x),.5*(b+y)],this.board)},getLabelAnchor:JXG.shortcut(JXG.Polygon.prototype,"getTextAnchor"),cloneToBackground:function(){var er,copy={};return copy.id=this.id+"T"+this.numTraces,this.numTraces++,copy.vertices=this.vertices,copy.visProp=Type.deepCopy(this.visProp,this.visProp.traceattributes,!0),copy.visProp.layer=this.board.options.layer.trace,copy.board=this.board,Type.clearVisPropOld(copy),copy.visPropCalc={visible:Type.evaluate(copy.visProp.visible)},er=this.board.renderer.enhancedRendering,this.board.renderer.enhancedRendering=!0,this.board.renderer.drawPolygon(copy),this.board.renderer.enhancedRendering=er,this.traces[copy.id]=copy.rendNode,this},hideElement:function(borderless){var i;if(JXG.deprecated("Element.hideElement()","Element.setDisplayRendNode()"),this.visPropCalc.visible=!1,this.board.renderer.display(this,!1),!borderless)for(i=0;i<this.borders.length;i++)this.borders[i].hideElement();this.hasLabel&&Type.exists(this.label)&&(this.label.hiddenByParent=!0,this.label.visPropCalc.visible&&this.label.hideElement())},showElement:function(borderless){var i;if(JXG.deprecated("Element.showElement()","Element.setDisplayRendNode()"),this.visPropCalc.visible=!0,this.board.renderer.display(this,!0),!borderless)for(i=0;i<this.borders.length;i++)this.borders[i].showElement().updateRenderer();return Type.exists(this.label)&&this.hasLabel&&this.label.hiddenByParent&&(this.label.hiddenByParent=!1,this.label.visPropCalc.visible||this.label.showElement().updateRenderer()),this},Area:function(){return Math.abs(Geometry.signedPolygon(this.vertices,!0))},Perimeter:function(){var i,len=this.vertices.length,val=0;for(i=1;i<len;++i)val+=this.vertices[i].Dist(this.vertices[i-1]);return val},boundingBox:function(){var i,v,box=[0,0,0,0],le=this.vertices.length-1;if(0===le)return box;for(box[0]=this.vertices[0].X(),box[2]=box[0],box[1]=this.vertices[0].Y(),box[3]=box[1],i=1;i<le;++i)(v=this.vertices[i].X())<box[0]?box[0]=v:v>box[2]&&(box[2]=v),(v=this.vertices[i].Y())>box[1]?box[1]=v:v<box[3]&&(box[3]=v);return box},bounds:function(){return this.boundingBox()},remove:function(){var i;for(i=0;i<this.borders.length;i++)this.board.removeObject(this.borders[i]);GeometryElement.prototype.remove.call(this)},findPoint:function(p){var i;if(!Type.isPoint(p))return-1;for(i=0;i<this.vertices.length;i++)if(this.vertices[i].id===p.id)return i;return-1},addPoints:function(p){var args=Array.prototype.slice.call(arguments);return this.insertPoints.apply(this,[this.vertices.length-2].concat(args))},insertPoints:function(idx,p){var i,le;if(0===arguments.length)return this;if(idx<-1||idx>this.vertices.length-2)return this;for(le=arguments.length-1,i=1;i<le+1;i++)this.vertices.splice(idx+i,0,Type.providePoints(this.board,[arguments[i]],{},"polygon",["vertices"])[0]);if(-1===idx&&(this.vertices[this.vertices.length-1]=this.vertices[0]),this.withLines)for(idx<0?this.borders[this.borders.length-1].point2=this.vertices[this.vertices.length-1]:this.borders[idx].point2=this.vertices[idx+1],i=idx+1;i<idx+1+le;i++)this.borders.splice(i,0,this.board.create("segment",[this.vertices[i],this.vertices[i+1]],this.attr_line));return this.board.update(),this},removePoints:function(p){var i,j,idx,nvertices=[],nborders=[],nidx=[],partition=[];for(this.vertices=this.vertices.slice(0,this.vertices.length-1),i=0;i<arguments.length;i++)idx=arguments[i],Type.isPoint(idx)&&(idx=this.findPoint(idx)),Type.isNumber(idx)&&idx>-1&&idx<this.vertices.length&&-1===Type.indexOf(nidx,idx)&&nidx.push(idx);for(i=0;i<nidx.length;i++)this.vertices[nidx[i]].removeChild(this);for(nidx=nidx.sort(),nvertices=this.vertices.slice(),nborders=this.borders.slice(),this.withLines&&partition.push([nidx[nidx.length-1]]),i=nidx.length-1;i>-1;i--)nvertices[nidx[i]]=-1,this.withLines&&nidx[i]-1>nidx[i-1]&&(partition[partition.length-1][1]=nidx[i],partition.push([nidx[i-1]]));for(this.withLines&&(partition[partition.length-1][1]=nidx[0]),this.vertices=[],i=0;i<nvertices.length;i++)Type.isPoint(nvertices[i])&&this.vertices.push(nvertices[i]);if(this.vertices[this.vertices.length-1].id!==this.vertices[0].id&&this.vertices.push(this.vertices[0]),this.withLines){for(i=0;i<partition.length;i++){for(j=partition[i][1]-1;j<partition[i][0]+1;j++)j<0?(j=0,this.board.removeObject(this.borders[nborders.length-1]),nborders[nborders.length-1]=-1):j>nborders.length-1&&(j=nborders.length-1),this.board.removeObject(this.borders[j]),nborders[j]=-1;0!==partition[i][1]&&partition[i][0]!==nvertices.length-1&&(nborders[partition[i][0]-1]=this.board.create("segment",[nvertices[Math.max(partition[i][1]-1,0)],nvertices[Math.min(partition[i][0]+1,this.vertices.length-1)]],this.attr_line))}for(this.borders=[],i=0;i<nborders.length;i++)-1!==nborders[i]&&this.borders.push(nborders[i]);partition[0][1]!==this.vertices.length-1&&0!==partition[partition.length-1][1]||this.borders.push(this.board.create("segment",[this.vertices[0],this.vertices[this.vertices.length-2]],this.attr_line))}return this.board.update(),this},getParents:function(){return this.setParents(this.vertices),this.parents},getAttributes:function(){var i,attr=GeometryElement.prototype.getAttributes.call(this);if(this.withLines)for(attr.lines=attr.lines||{},attr.lines.ids=[],attr.lines.colors=[],i=0;i<this.borders.length;i++)attr.lines.ids.push(this.borders[i].id),attr.lines.colors.push(this.borders[i].visProp.strokecolor);return attr},snapToGrid:function(){var i,force;for(force=!!Type.evaluate(this.visProp.snaptogrid),i=0;i<this.vertices.length;i++)this.vertices[i].handleSnapToGrid(force,!0)},setPositionDirectly:function(method,coords,oldcoords){var dc,i,len,c=new Coords(method,coords,this.board),oldc=new Coords(method,oldcoords,this.board);for(len=this.vertices.length-1,i=0;i<len;i++)if(!this.vertices[i].draggable())return this;return dc=Statistics.subtract(c.usrCoords,oldc.usrCoords),this.board.create("transform",dc.slice(1),{type:"translate"}).applyOnce(this.vertices.slice(0,-1)),this},sutherlandHodgman:function(polygon){var lenIn,inputList,i,j,S,E,cross,clip=JXG.Math.Geometry.sortVertices(this.vertices),subject=JXG.Math.Geometry.sortVertices(polygon.vertices),lenClip=clip.length-1,lenSubject=subject.length-1,outputList=[],isInside=function(c1,c2,c3){return(c2[1]-c1[1])*(c3[2]-c1[2])-(c2[2]-c1[2])*(c3[1]-c1[1])>=0};for(i=0;i<lenSubject;i++)outputList.push(subject[i]);for(i=0;i<lenClip;i++)for(inputList=outputList.slice(0),outputList=[],S=inputList[(lenIn=inputList.length)-1],j=0;j<lenIn;j++)E=inputList[j],isInside(clip[i],clip[i+1],E)?(isInside(clip[i],clip[i+1],S)||((cross=JXG.Math.Geometry.meetSegmentSegment(S,E,clip[i],clip[i+1]))[0][1]/=cross[0][0],cross[0][2]/=cross[0][0],cross[0][0]=1,outputList.push(cross[0])),outputList.push(E)):isInside(clip[i],clip[i+1],S)&&((cross=JXG.Math.Geometry.meetSegmentSegment(S,E,clip[i],clip[i+1]))[0][1]/=cross[0][0],cross[0][2]/=cross[0][0],cross[0][0]=1,outputList.push(cross[0])),S=E;return outputList},intersect:function(polygon){return this.sutherlandHodgman(polygon)}}),JXG.createPolygon=function(board,parents,attributes){var el,i,le,obj,attr,attr_points,points=[],is_transform=!1;if(Type.copyAttributes(attributes,board.options,"polygon"),null===(obj=board.select(parents[0]))&&(obj=parents[0]),Type.isObject(obj)&&obj.type===Const.OBJECT_TYPE_POLYGON&&Type.isTransformationOrArray(parents[1]))for(is_transform=!0,le=obj.vertices.length-1,attr_points=Type.copyAttributes(attributes,board.options,"polygon","vertices"),i=0;i<le;i++)attr_points.withlabel&&(attr_points.name=""===obj.vertices[i].name?"":obj.vertices[i].name+"'"),points.push(board.create("point",[obj.vertices[i],parents[1]],attr_points));else if(!1===(points=Type.providePoints(board,parents,attributes,"polygon",["vertices"])))throw new Error("JSXGraph: Can't create polygon / polygonalchain with parent types other than 'point' and 'coordinate arrays' or a function returning an array of coordinates. Alternatively, a polygon and a transformation can be supplied");if(attr=Type.copyAttributes(attributes,board.options,"polygon"),(el=new JXG.Polygon(board,points,attr)).isDraggable=!0,is_transform)for(el.prepareUpdate().update().updateVisibility().updateRenderer(),le=obj.vertices.length-1,i=0;i<le;i++)points[i].prepareUpdate().update().updateVisibility().updateRenderer();return el},JXG.createRegularPolygon=function(board,parents,attributes){var el,i,n,rot,len,pointsExist,attr,p=[];if(n=parents[(len=parents.length)-1],Type.isNumber(n)&&(3!==parents.length||n<3))throw new Error("JSXGraph: A regular polygon needs two point types and a number > 2 as input.");if(Type.isNumber(board.select(n))?(len--,pointsExist=!1):(n=len,pointsExist=!0),!1===(p=Type.providePoints(board,parents.slice(0,len),attributes,"regularpolygon",["vertices"])))throw new Error("JSXGraph: Can't create regular polygon with parent types other than 'point' and 'coordinate arrays' or a function returning an array of coordinates");for(attr=Type.copyAttributes(attributes,board.options,"regularpolygon","vertices"),i=2;i<n;i++)rot=board.create("transform",[Math.PI*(2-(n-2)/n),p[i-1]],{type:"rotate"}),pointsExist?(p[i].addTransform(p[i-2],rot),p[i].fullUpdate()):(Type.isArray(attr.ids)&&attr.ids.length>=n-2&&(attr.id=attr.ids[i-2]),p[i]=board.create("point",[p[i-2],rot],attr),p[i].type=Const.OBJECT_TYPE_CAS,p[i].isDraggable=!0,p[i].visProp.fixed=!1);return attr=Type.copyAttributes(attributes,board.options,"regularpolygon"),(el=board.create("polygon",p,attr)).elType="regularpolygon",el},JXG.createPolygonalChain=function(board,parents,attributes){var attr,el;return attr=Type.copyAttributes(attributes,board.options,"polygonalchain"),(el=board.create("polygon",parents,attr)).elType="polygonalchain",el.vertices.pop(),board.removeObject(el.borders[el.borders.length-1]),el.borders.pop(),el},JXG.registerElement("polygon",JXG.createPolygon),JXG.registerElement("regularpolygon",JXG.createRegularPolygon),JXG.registerElement("polygonalchain",JXG.createPolygonalChain),{Polygon:JXG.Polygon,createPolygon:JXG.createPolygon,createRegularPolygon:JXG.createRegularPolygon}})),define("base/curve",["jxg","base/constants","base/coords","base/element","math/math","math/numerics","math/plot","math/geometry","parser/geonext","utils/type","math/qdt"],(function(JXG,Const,Coords,GeometryElement,Mat,Numerics,Plot,Geometry,GeonextParser,Type,QDT){return JXG.Curve=function(board,parents,attributes){this.constructor(board,attributes,Const.OBJECT_TYPE_CURVE,Const.OBJECT_CLASS_CURVE),this.points=[],this.numberPoints=Type.evaluate(this.visProp.numberpointshigh),this.bezierDegree=1,this.dataX=null,this.dataY=null,this.ticks=[],this.qdt=null,Type.exists(parents[0])?this.varname=parents[0]:this.varname="x",this.xterm=parents[1],this.yterm=parents[2],this.generateTerm(this.varname,this.xterm,this.yterm,parents[3],parents[4]),this.updateCurve(),this.id=this.board.setId(this,"G"),this.board.renderer.drawCurve(this),this.board.finalizeAdding(this),this.createGradient(),this.elType="curve",this.createLabel(),Type.isString(this.xterm)&&this.notifyParents(this.xterm),Type.isString(this.yterm)&&this.notifyParents(this.yterm),this.methodMap=Type.deepCopy(this.methodMap,{generateTerm:"generateTerm",setTerm:"generateTerm",move:"moveTo",moveTo:"moveTo"})},JXG.Curve.prototype=new GeometryElement,JXG.extend(JXG.Curve.prototype,{minX:function(){return"polar"===Type.evaluate(this.visProp.curvetype)?0:new Coords(Const.COORDS_BY_SCREEN,[.1*-this.board.canvasWidth,0],this.board,!1).usrCoords[1]},maxX:function(){return"polar"===Type.evaluate(this.visProp.curvetype)?2*Math.PI:new Coords(Const.COORDS_BY_SCREEN,[1.1*this.board.canvasWidth,0],this.board,!1).usrCoords[1]},X:function(t){return NaN},Y:function(t){return NaN},Z:function(t){return 1},hasPoint:function(x,y,start){var t,checkPoint,len,invMat,c,i,tX,tY,points,qdt,prec,type,ux2,uy2,ev_ct,mi,res=[],steps=Type.evaluate(this.visProp.numberpointslow),d=(this.maxX()-this.minX())/steps,dist=1/0;if(Type.isObject(Type.evaluate(this.visProp.precision))?(type=this.board._inputDevice,prec=Type.evaluate(this.visProp.precision[type])):prec=this.board.options.precision.hasPoint,x=(checkPoint=new Coords(Const.COORDS_BY_SCREEN,[x,y],this.board,!1)).usrCoords[1],y=checkPoint.usrCoords[2],prec+=.5*Type.evaluate(this.visProp.strokewidth),prec*=prec,ux2=this.board.unitX*this.board.unitX,uy2=this.board.unitY*this.board.unitY,mi=this.minX(),this.maxX(),Type.exists(this._visibleArea)&&(mi=this._visibleArea[0],d=(this._visibleArea[1]-mi)/steps),"parameter"===(ev_ct=Type.evaluate(this.visProp.curvetype))||"polar"===ev_ct)for(this.transformations.length>0&&(this.updateTransformMatrix(),invMat=Mat.inverse(this.transformMat),x=(c=Mat.matVecMult(invMat,[1,x,y]))[1],y=c[2]),i=0,t=mi;i<steps;i++){if((dist=(x-(tX=this.X(t,true)))*(x-tX)*ux2+(y-(tY=this.Y(t,true)))*(y-tY)*uy2)<=prec)return!0;t+=d}else if("plot"===ev_ct||"functiongraph"===ev_ct){for((!Type.exists(start)||start<0)&&(start=0),Type.exists(this.qdt)&&Type.evaluate(this.visProp.useqdt)&&3!==this.bezierDegree?len=(points=(qdt=this.qdt.query(new Coords(Const.COORDS_BY_USER,[x,y],this.board))).points).length:(points=this.points,len=this.numberPoints-1),i=start;i<len;i++)if(3===this.bezierDegree?res.push(Geometry.projectCoordsToBeziersegment([1,x,y],this,i)):qdt?(points[i].prev&&(res=Geometry.projectCoordsToSegment([1,x,y],points[i].prev.usrCoords,points[i].usrCoords)),points[i].next&&points[i+1]!==points[i].next&&(res=Geometry.projectCoordsToSegment([1,x,y],points[i].usrCoords,points[i].next.usrCoords))):res=Geometry.projectCoordsToSegment([1,x,y],points[i].usrCoords,points[i+1].usrCoords),res[1]>=0&&res[1]<=1&&(x-res[0][1])*(x-res[0][1])*ux2+(y-res[0][2])*(y-res[0][2])*uy2<=prec)return!0;return!1}return dist<prec},allocatePoints:function(){var i,len;if(len=this.numberPoints,this.points.length<this.numberPoints)for(i=this.points.length;i<len;i++)this.points[i]=new Coords(Const.COORDS_BY_USER,[0,0],this.board,!1)},update:function(){return this.needsUpdate&&(Type.evaluate(this.visProp.trace)&&this.cloneToBackground(!0),this.updateCurve()),this},updateRenderer:function(){return this.needsUpdate?(this.visPropCalc.visible&&(this.isReal=Plot.checkReal(this.points),this.isReal||this.updateVisibility(!1)),this.visPropCalc.visible&&this.board.renderer.updateCurve(this),this.hasLabel&&this.visPropCalc.visible&&this.label&&this.label.visPropCalc.visible&&this.isReal&&(this.label.update(),this.board.renderer.updateText(this.label)),this.setDisplayRendNode(),this.needsUpdate=!1,this):this},updateDataArray:function(){},updateCurve:function(){var len,mi,ma,x,y,i,version=this.visProp.plotversion,suspendUpdate=!1;if(this.updateTransformMatrix(),this.updateDataArray(),mi=this.minX(),ma=this.maxX(),Type.exists(this.dataX))for(this.numberPoints=this.dataX.length,len=this.numberPoints,this.allocatePoints(),i=0;i<len;i++)x=i,Type.exists(this.dataY)?(y=i,this.points[i].setCoordinates(Const.COORDS_BY_USER,[this.dataX[i],this.dataY[i]],!1)):(y=this.X(x),this.points[i].setCoordinates(Const.COORDS_BY_USER,[this.dataX[i],this.Y(y,suspendUpdate)],!1)),this.points[i]._t=i,suspendUpdate=!0;else if(Type.evaluate(this.visProp.doadvancedplot)?1===version||Type.evaluate(this.visProp.doadvancedplotold)?Plot.updateParametricCurveOld(this,mi,ma):2===version?Plot.updateParametricCurve_v2(this,mi,ma):3===version?Plot.updateParametricCurve_v3(this,mi,ma):4===version?Plot.updateParametricCurve_v4(this,mi,ma):Plot.updateParametricCurve_v2(this,mi,ma):(this.board.updateQuality===this.board.BOARD_QUALITY_HIGH?this.numberPoints=Type.evaluate(this.visProp.numberpointshigh):this.numberPoints=Type.evaluate(this.visProp.numberpointslow),this.allocatePoints(),Plot.updateParametricCurveNaive(this,mi,ma,this.numberPoints)),len=this.numberPoints,Type.evaluate(this.visProp.useqdt)&&this.board.updateQuality===this.board.BOARD_QUALITY_HIGH)for(this.qdt=new QDT(this.board.getBoundingBox()),i=0;i<this.points.length;i++)this.qdt.insert(this.points[i]),i>0&&(this.points[i].prev=this.points[i-1]),i<len-1&&(this.points[i].next=this.points[i+1]);for("plot"!==Type.evaluate(this.visProp.curvetype)&&Type.evaluate(this.visProp.rdpsmoothing)&&(this.points=Numerics.RamerDouglasPeucker(this.points,.2),this.numberPoints=this.points.length),len=this.numberPoints,i=0;i<len;i++)this.updateTransform(this.points[i]);return this},updateTransformMatrix:function(){var t,i,len=this.transformations.length;for(this.transformMat=[[1,0,0],[0,1,0],[0,0,1]],i=0;i<len;i++)(t=this.transformations[i]).update(),this.transformMat=Mat.matMatMult(t.matrix,this.transformMat);return this},updateTransform:function(p){var c;return this.transformations.length>0&&(c=Mat.matVecMult(this.transformMat,p.usrCoords),p.setCoordinates(Const.COORDS_BY_USER,c,!1,!0)),p},addTransform:function(transform){var i,list=Type.isArray(transform)?transform:[transform],len=list.length;for(i=0;i<len;i++)this.transformations.push(list[i]);return this},interpolationFunctionFromArray:function(which){var data="data"+which,that=this;return function(t,suspendedUpdate){var i,j,t0,t1,arr=that[data],len=arr.length,f=[];if(isNaN(t))return NaN;if(t<0)return Type.isFunction(arr[0])?arr[0]():arr[0];if(3===that.bezierDegree){if(t>=(len-1)/3)return Type.isFunction(arr[arr.length-1])?arr[arr.length-1]():arr[arr.length-1];for(i=3*Math.floor(t),t1=1-(t0=t%1),j=0;j<4;j++)Type.isFunction(arr[i+j])?f[j]=arr[i+j]():f[j]=arr[i+j];return t1*t1*(t1*f[0]+3*t0*f[1])+(3*t1*f[2]+t0*f[3])*t0*t0}if((i=t>len-2?len-2:parseInt(Math.floor(t),10))===t)return Type.isFunction(arr[i])?arr[i]():arr[i];for(j=0;j<2;j++)Type.isFunction(arr[i+j])?f[j]=arr[i+j]():f[j]=arr[i+j];return f[0]+(f[1]-f[0])*(t-i)}},generateTerm:function(varname,xterm,yterm,mi,ma){var fx,fy;Type.isArray(xterm)?(this.dataX=xterm,this.numberPoints=this.dataX.length,this.X=this.interpolationFunctionFromArray.apply(this,["X"]),this.visProp.curvetype="plot",this.isDraggable=!0):(this.X=Type.createFunction(xterm,this.board,varname),Type.isString(xterm)?this.visProp.curvetype="functiongraph":(Type.isFunction(xterm)||Type.isNumber(xterm))&&(this.visProp.curvetype="parameter"),this.isDraggable=!0),Type.isArray(yterm)?(this.dataY=yterm,this.Y=this.interpolationFunctionFromArray.apply(this,["Y"])):this.Y=Type.createFunction(yterm,this.board,varname),Type.isFunction(xterm)&&Type.isArray(yterm)&&(fx=Type.createFunction(yterm[0],this.board,""),fy=Type.createFunction(yterm[1],this.board,""),this.X=function(phi){return xterm(phi)*Math.cos(phi)+fx()},this.Y=function(phi){return xterm(phi)*Math.sin(phi)+fy()},this.visProp.curvetype="polar"),Type.exists(mi)&&(this.minX=Type.createFunction(mi,this.board,"")),Type.exists(ma)&&(this.maxX=Type.createFunction(ma,this.board,""))},notifyParents:function(contentStr){var fstr,dep,obj,isJessieCode=!1;for(fstr in obj={xterm:1,yterm:1})if(obj.hasOwnProperty(fstr)&&this.hasOwnProperty(fstr)&&this[fstr].origin)for(dep in isJessieCode=!0,this[fstr].origin.deps)this[fstr].origin.deps.hasOwnProperty(dep)&&this[fstr].origin.deps[dep].addChild(this);isJessieCode||GeonextParser.findDependencies(this,contentStr,this.board)},getLabelAnchor:function(){var c,x,y,ax=.05*this.board.canvasWidth,ay=.05*this.board.canvasHeight,bx=.95*this.board.canvasWidth,by=.95*this.board.canvasHeight;switch(Type.evaluate(this.visProp.label.position)){case"ulft":x=ax,y=ay;break;case"llft":x=ax,y=by;break;case"rt":x=bx,y=.5*by;break;case"lrt":x=bx,y=by;break;case"urt":x=bx,y=ay;break;case"top":x=.5*bx,y=ay;break;case"bot":x=.5*bx,y=by;break;default:x=ax,y=.5*by}return c=new Coords(Const.COORDS_BY_SCREEN,[x,y],this.board,!1),Geometry.projectCoordsToCurve(c.usrCoords[1],c.usrCoords[2],0,this,this.board)[0]},cloneToBackground:function(){var er,copy={id:this.id+"T"+this.numTraces,elementClass:Const.OBJECT_CLASS_CURVE,points:this.points.slice(0),bezierDegree:this.bezierDegree,numberPoints:this.numberPoints,board:this.board,visProp:Type.deepCopy(this.visProp,this.visProp.traceattributes,!0)};return copy.visProp.layer=this.board.options.layer.trace,copy.visProp.curvetype=this.visProp.curvetype,this.numTraces++,Type.clearVisPropOld(copy),copy.visPropCalc={visible:Type.evaluate(copy.visProp.visible)},er=this.board.renderer.enhancedRendering,this.board.renderer.enhancedRendering=!0,this.board.renderer.drawCurve(copy),this.board.renderer.enhancedRendering=er,this.traces[copy.id]=copy.rendNode,this},bounds:function(){var i,bezier,up,minX=1/0,maxX=-1/0,minY=1/0,maxY=-1/0,l=this.points.length;if(3===this.bezierDegree){for(i=0;i<l;i++)this.points[i].X=Type.bind((function(){return this.usrCoords[1]}),this.points[i]),this.points[i].Y=Type.bind((function(){return this.usrCoords[2]}),this.points[i]);return up=(bezier=Numerics.bezier(this.points))[3](),minX=Numerics.fminbr((function(t){return bezier[0](t)}),[0,up]),maxX=Numerics.fminbr((function(t){return-bezier[0](t)}),[0,up]),minY=Numerics.fminbr((function(t){return bezier[1](t)}),[0,up]),maxY=Numerics.fminbr((function(t){return-bezier[1](t)}),[0,up]),minX=bezier[0](minX),maxX=bezier[0](maxX),minY=bezier[1](minY),[minX,maxY=bezier[1](maxY),maxX,minY]}for(i=0;i<l;i++)minX>this.points[i].usrCoords[1]&&(minX=this.points[i].usrCoords[1]),maxX<this.points[i].usrCoords[1]&&(maxX=this.points[i].usrCoords[1]),minY>this.points[i].usrCoords[2]&&(minY=this.points[i].usrCoords[2]),maxY<this.points[i].usrCoords[2]&&(maxY=this.points[i].usrCoords[2]);return[minX,maxY,maxX,minY]},getParents:function(){var p=[this.xterm,this.yterm,this.minX(),this.maxX()];return 0!==this.parents.length&&(p=this.parents),p},moveTo:function(where){var p,delta=[];return this.points.length>0&&!Type.evaluate(this.visProp.fixed)&&(p=this.points[0],delta=3===where.length?[where[0]-p.usrCoords[0],where[1]-p.usrCoords[1],where[2]-p.usrCoords[2]]:[where[0]-p.usrCoords[1],where[1]-p.usrCoords[2]],this.setPosition(Const.COORDS_BY_USER,delta)),this},getTransformationSource:function(){var isTransformed,curve_org;return Type.exists(this._transformationSource)&&(curve_org=this._transformationSource).elementClass===Const.OBJECT_CLASS_CURVE&&(isTransformed=!0),[isTransformed,curve_org]}}),JXG.createCurve=function(board,parents,attributes){var obj,cu,attr=Type.copyAttributes(attributes,board.options,"curve");return obj=board.select(parents[0],!0),Type.isObject(obj)&&(obj.type===Const.OBJECT_TYPE_CURVE||obj.type===Const.OBJECT_TYPE_ANGLE||obj.type===Const.OBJECT_TYPE_ARC||obj.type===Const.OBJECT_TYPE_CONIC||obj.type===Const.OBJECT_TYPE_SECTOR)&&Type.isTransformationOrArray(parents[1])?(obj.type===Const.OBJECT_TYPE_SECTOR?attr=Type.copyAttributes(attributes,board.options,"sector"):obj.type===Const.OBJECT_TYPE_ARC?attr=Type.copyAttributes(attributes,board.options,"arc"):obj.type===Const.OBJECT_TYPE_ANGLE?(Type.exists(attributes.withLabel)||(attributes.withLabel=!1),attr=Type.copyAttributes(attributes,board.options,"angle")):attr=Type.copyAttributes(attributes,board.options,"curve"),attr=Type.copyAttributes(attr,board.options,"curve"),(cu=new JXG.Curve(board,["x",[],[]],attr)).updateDataArray=function(){var i,le=obj.numberPoints;for(this.bezierDegree=obj.bezierDegree,this.dataX=[],this.dataY=[],i=0;i<le;i++)this.dataX.push(obj.points[i].usrCoords[1]),this.dataY.push(obj.points[i].usrCoords[2]);return this},cu.addTransform(parents[1]),obj.addChild(cu),cu.setParents([obj]),cu._transformationSource=obj,cu):(attr=Type.copyAttributes(attributes,board.options,"curve"),new JXG.Curve(board,["x"].concat(parents),attr))},JXG.registerElement("curve",JXG.createCurve),JXG.createFunctiongraph=function(board,parents,attributes){var attr,par=["x","x"].concat(parents);return(attr=Type.copyAttributes(attributes,board.options,"curve")).curvetype="functiongraph",new JXG.Curve(board,par,attr)},JXG.registerElement("functiongraph",JXG.createFunctiongraph),JXG.registerElement("plot",JXG.createFunctiongraph),JXG.createSpline=function(board,parents,attributes){var el,funcs,ret;return funcs=function(){var D,x=[],y=[];return[function(t,suspended){var i,j,c;if(!suspended){if(x=[],y=[],2===parents.length&&Type.isArray(parents[0])&&Type.isArray(parents[1])&&parents[0].length===parents[1].length)for(i=0;i<parents[0].length;i++)Type.isFunction(parents[0][i])?x.push(parents[0][i]()):x.push(parents[0][i]),Type.isFunction(parents[1][i])?y.push(parents[1][i]()):y.push(parents[1][i]);else for(i=0;i<parents.length;i++)if(Type.isPoint(parents[i]))x.push(parents[i].X()),y.push(parents[i].Y());else if(Type.isArray(parents[i])&&2===parents[i].length)for(j=0;j<parents.length;j++)Type.isFunction(parents[j][0])?x.push(parents[j][0]()):x.push(parents[j][0]),Type.isFunction(parents[j][1])?y.push(parents[j][1]()):y.push(parents[j][1]);else Type.isFunction(parents[i])&&2===parents[i]().length&&(c=parents[i](),x.push(c[0]),y.push(c[1]));D=Numerics.splineDef(x,y)}return Numerics.splineEval(t,x,y,D)},function(){return x[0]},function(){return x[x.length-1]}]},(attributes=Type.copyAttributes(attributes,board.options,"curve")).curvetype="functiongraph",ret=funcs(),(el=new JXG.Curve(board,["x","x",ret[0],ret[1],ret[2]],attributes)).setParents(parents),el.elType="spline",el},JXG.registerElement("spline",JXG.createSpline),JXG.createCardinalSpline=function(board,parents,attributes){var el,getPointLike,points,tau,type,p,q,i,le,splineArr,errStr="\nPossible parent types: [points:array, tau:number|function, type:string]";if(!Type.exists(parents[0])||!Type.isArray(parents[0]))throw new Error("JSXGraph: JXG.createCardinalSpline: argument 1 'points' has to be array of points or coordinate pairs"+errStr);if(!Type.exists(parents[1])||!Type.isNumber(parents[1])&&!Type.isFunction(parents[1]))throw new Error("JSXGraph: JXG.createCardinalSpline: argument 2 'tau' has to be number between [0,1] or function'"+errStr);if(!Type.exists(parents[2])||!Type.isString(parents[2]))throw new Error("JSXGraph: JXG.createCardinalSpline: argument 3 'type' has to be string 'uniform' or 'centripetal'"+errStr);if(attributes=Type.copyAttributes(attributes,board.options,"curve"),(attributes=Type.copyAttributes(attributes,board.options,"cardinalspline")).curvetype="parameter",p=parents[0],q=[],!attributes.isarrayofcoordinates&&2===p.length&&Type.isArray(p[0])&&Type.isArray(p[1])&&p[0].length===p[1].length)for(i=0;i<p[0].length;i++)q[i]=[],Type.isFunction(p[0][i])?q[i].push(p[0][i]()):q[i].push(p[0][i]),Type.isFunction(p[1][i])?q[i].push(p[1][i]()):q[i].push(p[1][i]);else for(i=0;i<p.length;i++)Type.isString(p[i])?q.push(board.select(p[i])):Type.isPoint(p[i])?q.push(p[i]):Type.isArray(p[i])&&2===p[i].length?(q[i]=[],Type.isFunction(p[i][0])?q[i].push(p[i][0]()):q[i].push(p[i][0]),Type.isFunction(p[i][1])?q[i].push(p[i][1]()):q[i].push(p[i][1])):Type.isFunction(p[i])&&2===p[i]().length&&q.push(parents[i]());if(!0===attributes.createpoints)points=Type.providePoints(board,q,attributes,"cardinalspline",["points"]);else for(points=[],getPointLike=function(ii){return{X:function(){return q[ii][0]},Y:function(){return q[ii][1]},Dist:function(p){var dx=this.X()-p.X(),dy=this.Y()-p.Y();return Math.sqrt(dx*dx+dy*dy)}}},i=0;i<q.length;i++)Type.isPoint(q[i])?points.push(q[i]):points.push(getPointLike(i));for(tau=parents[1],type=parents[2],splineArr=["x"].concat(Numerics.CardinalSpline(points,tau,type)),el=new JXG.Curve(board,splineArr,attributes),le=points.length,el.setParents(points),i=0;i<le;i++)p=points[i],Type.isPoint(p)&&(Type.exists(p._is_new)?(el.addChild(p),delete p._is_new):p.addChild(el));return el.elType="cardinalspline",el},JXG.registerElement("cardinalspline",JXG.createCardinalSpline),JXG.createMetapostSpline=function(board,parents,attributes){var el,getPointLike,points,controls,p,q,i,le,errStr="\nPossible parent types: [points:array, controls:object";if(!Type.exists(parents[0])||!Type.isArray(parents[0]))throw new Error("JSXGraph: JXG.createMetapostSpline: argument 1 'points' has to be array of points or coordinate pairs"+errStr);if(!Type.exists(parents[1])||!Type.isObject(parents[1]))throw new Error("JSXGraph: JXG.createMetapostSpline: argument 2 'controls' has to be a JavaScript object'"+errStr);if(attributes=Type.copyAttributes(attributes,board.options,"curve"),(attributes=Type.copyAttributes(attributes,board.options,"metapostspline")).curvetype="parameter",p=parents[0],q=[],!attributes.isarrayofcoordinates&&2===p.length&&Type.isArray(p[0])&&Type.isArray(p[1])&&p[0].length===p[1].length)for(i=0;i<p[0].length;i++)q[i]=[],Type.isFunction(p[0][i])?q[i].push(p[0][i]()):q[i].push(p[0][i]),Type.isFunction(p[1][i])?q[i].push(p[1][i]()):q[i].push(p[1][i]);else for(i=0;i<p.length;i++)Type.isString(p[i])?q.push(board.select(p[i])):Type.isPoint(p[i])?q.push(p[i]):Type.isArray(p[i])&&2===p[i].length?(q[i]=[],Type.isFunction(p[i][0])?q[i].push(p[i][0]()):q[i].push(p[i][0]),Type.isFunction(p[i][1])?q[i].push(p[i][1]()):q[i].push(p[i][1])):Type.isFunction(p[i])&&2===p[i]().length&&q.push(parents[i]());if(!0===attributes.createpoints)points=Type.providePoints(board,q,attributes,"metapostspline",["points"]);else for(points=[],getPointLike=function(ii){return{X:function(){return q[ii][0]},Y:function(){return q[ii][1]}}},i=0;i<q.length;i++)Type.isPoint(q[i])?points.push(q[i]):points.push(getPointLike);for(controls=parents[1],(el=new JXG.Curve(board,["t",[],[],0,p.length-1],attributes)).updateDataArray=function(){var res,i,len=points.length,p=[];for(i=0;i<len;i++)p.push([points[i].X(),points[i].Y()]);res=JXG.Math.Metapost.curve(p,controls),this.dataX=res[0],this.dataY=res[1]},el.bezierDegree=3,le=points.length,el.setParents(points),i=0;i<le;i++)Type.isPoint(points[i])&&points[i].addChild(el);return el.elType="metapostspline",el},JXG.registerElement("metapostspline",JXG.createMetapostSpline),JXG.createRiemannsum=function(board,parents,attributes){var n,type,f,par,c,attr;if((attr=Type.copyAttributes(attributes,board.options,"riemannsum")).curvetype="plot",f=parents[0],n=Type.createFunction(parents[1],board,""),!Type.exists(n))throw new Error("JSXGraph: JXG.createRiemannsum: argument '2' n has to be number or function.\nPossible parent types: [function,n:number|function,type,start:number|function,end:number|function]");if(type=Type.createFunction(parents[2],board,"",!1),!Type.exists(type))throw new Error("JSXGraph: JXG.createRiemannsum: argument 3 'type' has to be string or function.\nPossible parent types: [function,n:number|function,type,start:number|function,end:number|function]");return par=[[0],[0]].concat(parents.slice(3)),(c=board.create("curve",par,attr)).sum=0,c.Value=function(){return this.sum},c.updateDataArray=function(){var u=Numerics.riemann(f,n(),type(),this.minX(),this.maxX());this.dataX=u[0],this.dataY=u[1],this.sum=u[2]},c},JXG.registerElement("riemannsum",JXG.createRiemannsum),JXG.createTracecurve=function(board,parents,attributes){var c,glider,tracepoint,attr;if(2!==parents.length)throw new Error("JSXGraph: Can't create trace curve with given parent'\nPossible parent types: [glider, point]");if(glider=board.select(parents[0]),tracepoint=board.select(parents[1]),glider.type!==Const.OBJECT_TYPE_GLIDER||!Type.isPoint(tracepoint))throw new Error("JSXGraph: Can't create trace curve with parent types '"+_typeof(parents[0])+"' and '"+_typeof(parents[1])+"'.\nPossible parent types: [glider, point]");return(attr=Type.copyAttributes(attributes,board.options,"tracecurve")).curvetype="plot",(c=board.create("curve",[[0],[0]],attr)).updateDataArray=function(){var i,step,t,el,pEl,x,y,from,savetrace,le=attr.numberpoints,savePos=glider.position,slideObj=glider.slideObject,mi=slideObj.minX();for(step=(slideObj.maxX()-mi)/le,this.dataX=[],this.dataY=[],slideObj.elementClass!==Const.OBJECT_CLASS_CURVE&&le++,i=0;i<le;i++){for(el in t=mi+i*step,x=slideObj.X(t)/slideObj.Z(t),y=slideObj.Y(t)/slideObj.Z(t),glider.setPositionDirectly(Const.COORDS_BY_USER,[x,y]),from=!1,this.board.objects)if(this.board.objects.hasOwnProperty(el)&&((pEl=this.board.objects[el])===glider&&(from=!0),from&&pEl.needsRegularUpdate&&(savetrace=pEl.visProp.trace,pEl.visProp.trace=!1,pEl.needsUpdate=!0,pEl.update(!0),pEl.visProp.trace=savetrace,pEl===tracepoint)))break;this.dataX[i]=tracepoint.X(),this.dataY[i]=tracepoint.Y()}for(el in glider.position=savePos,from=!1,this.board.objects)if(this.board.objects.hasOwnProperty(el)&&((pEl=this.board.objects[el])===glider&&(from=!0),from&&pEl.needsRegularUpdate&&(savetrace=pEl.visProp.trace,pEl.visProp.trace=!1,pEl.needsUpdate=!0,pEl.update(!0),pEl.visProp.trace=savetrace,pEl===tracepoint)))break},c},JXG.registerElement("tracecurve",JXG.createTracecurve),JXG.createStepfunction=function(board,parents,attributes){var c,attr;if(2!==parents.length)throw new Error("JSXGraph: Can't create step function with given parent'\nPossible parent types: [array, array|function]");return attr=Type.copyAttributes(attributes,board.options,"stepfunction"),(c=board.create("curve",parents,attr)).updateDataArray=function(){var i,j=0,len=this.xterm.length;if(this.dataX=[],this.dataY=[],0!==len)for(this.dataX[j]=this.xterm[0],this.dataY[j]=this.yterm[0],++j,i=1;i<len;++i)this.dataX[j]=this.xterm[i],this.dataY[j]=this.dataY[j-1],++j,this.dataX[j]=this.xterm[i],this.dataY[j]=this.yterm[i],++j},c},JXG.registerElement("stepfunction",JXG.createStepfunction),JXG.createDerivative=function(board,parents,attributes){var c,curve,dx,dy,attr;if(1!==parents.length&&parents[0].class!==Const.OBJECT_CLASS_CURVE)throw new Error("JSXGraph: Can't create derivative curve with given parent'\nPossible parent types: [curve]");return attr=Type.copyAttributes(attributes,board.options,"curve"),curve=parents[0],dx=Numerics.D(curve.X),dy=Numerics.D(curve.Y),(c=board.create("curve",[function(t){return curve.X(t)},function(t){return dy(t)/dx(t)},curve.minX(),curve.maxX()],attr)).setParents(curve),c},JXG.registerElement("derivative",JXG.createDerivative),JXG.createCurveIntersection=function(board,parents,attributes){var c;if(2!==parents.length)throw new Error("JSXGraph: Can't create curve intersection with given parent'\nPossible parent types: [array, array|function]");return(c=board.create("curve",[[],[]],attributes)).updateDataArray=function(){var a=JXG.Math.Clip.intersection(parents[0],parents[1],this.board);this.dataX=a[0],this.dataY=a[1]},c},JXG.createCurveUnion=function(board,parents,attributes){var c;if(2!==parents.length)throw new Error("JSXGraph: Can't create curve union with given parent'\nPossible parent types: [array, array|function]");return(c=board.create("curve",[[],[]],attributes)).updateDataArray=function(){var a=JXG.Math.Clip.union(parents[0],parents[1],this.board);this.dataX=a[0],this.dataY=a[1]},c},JXG.createCurveDifference=function(board,parents,attributes){var c;if(2!==parents.length)throw new Error("JSXGraph: Can't create curve difference with given parent'\nPossible parent types: [array, array|function]");return(c=board.create("curve",[[],[]],attributes)).updateDataArray=function(){var a=JXG.Math.Clip.difference(parents[0],parents[1],this.board);this.dataX=a[0],this.dataY=a[1]},c},JXG.registerElement("curvedifference",JXG.createCurveDifference),JXG.registerElement("curveintersection",JXG.createCurveIntersection),JXG.registerElement("curveunion",JXG.createCurveUnion),JXG.createBoxPlot=function(board,parents,attributes){var box,i,len,attr=Type.copyAttributes(attributes,board.options,"boxplot");if(3!==parents.length)throw new Error("JSXGraph: Can't create box plot with given parent'\nPossible parent types: [array, number|function, number|function] containing quantiles, axis, width");if(parents[0].length<5)throw new Error("JSXGraph: Can't create box plot with given parent[0]'\nparent[0] has to conatin at least 5 quantiles.");for(box=board.create("curve",[[],[]],attr),len=parents[0].length,box.Q=[],i=0;i<len;i++)box.Q[i]=Type.createFunction(parents[0][i],board,null,!0);return box.x=Type.createFunction(parents[1],board,null,!0),box.w=Type.createFunction(parents[2],board,null,!0),box.updateDataArray=function(){var v1,v2,l1,l2,r1,r2,w2,dir,x;w2=Type.evaluate(this.visProp.smallwidth),dir=Type.evaluate(this.visProp.dir),l1=(x=this.x())-.5*this.w(),l2=x-.5*this.w()*w2,r1=x+.5*this.w(),v1=[x,l2,r2=x+.5*this.w()*w2,x,x,l1,l1,r1,r1,x,NaN,l1,r1,NaN,x,x,l2,r2,x],v2=[this.Q[0](),this.Q[0](),this.Q[0](),this.Q[0](),this.Q[1](),this.Q[1](),this.Q[3](),this.Q[3](),this.Q[1](),this.Q[1](),NaN,this.Q[2](),this.Q[2](),NaN,this.Q[3](),this.Q[4](),this.Q[4](),this.Q[4](),this.Q[4]()],"vertical"===dir?(this.dataX=v1,this.dataY=v2):(this.dataX=v2,this.dataY=v1)},box},JXG.registerElement("boxplot",JXG.createBoxPlot),{Curve:JXG.Curve,createCardinalSpline:JXG.createCardinalSpline,createCurve:JXG.createCurve,createCurveDifference:JXG.createCurveDifference,createCurveIntersection:JXG.createCurveIntersection,createCurveUnion:JXG.createCurveUnion,createDerivative:JXG.createDerivative,createFunctiongraph:JXG.createFunctiongraph,createMetapostSpline:JXG.createMetapostSpline,createPlot:JXG.createFunctiongraph,createSpline:JXG.createSpline,createRiemannsum:JXG.createRiemannsum,createStepfunction:JXG.createStepfunction,createTracecurve:JXG.createTracecurve}})),define("element/arc",["jxg","math/geometry","math/math","base/coords","base/circle","utils/type","base/constants"],(function(JXG,Geometry,Mat,Coords,Circle,Type,Const){return JXG.createArc=function(board,parents,attributes){var el,attr,points;if(!1===(points=Type.providePoints(board,parents,attributes,"arc",["center","radiusPoint","anglePoint"]))||points.length<3)throw new Error("JSXGraph: Can't create Arc with parent types '"+_typeof(parents[0])+"' and '"+_typeof(parents[1])+"' and '"+_typeof(parents[2])+"'.\nPossible parent types: [point,point,point], [arc, transformation]");return attr=Type.copyAttributes(attributes,board.options,"arc"),(el=board.create("curve",[[0],[0]],attr)).elType="arc",el.setParents(points),el.type=Const.OBJECT_TYPE_ARC,el.center=points[0],el.radiuspoint=points[1],el.point2=el.radiuspoint,el.anglepoint=points[2],el.point3=el.anglepoint,Type.exists(el.center._is_new)?(el.addChild(el.center),delete el.center._is_new):el.center.addChild(el),Type.exists(el.radiuspoint._is_new)?(el.addChild(el.radiuspoint),delete el.radiuspoint._is_new):el.radiuspoint.addChild(el),Type.exists(el.anglepoint._is_new)?(el.addChild(el.anglepoint),delete el.anglepoint._is_new):el.anglepoint.addChild(el),el.useDirection=attr.usedirection,el.updateDataArray=function(){var ar,phi,p0c,p1c,p2c,sgn=1,A=this.radiuspoint,B=this.center,C=this.anglepoint,ev_s=Type.evaluate(this.visProp.selection);phi=Geometry.rad(A,B,C),("minor"===ev_s&&phi>Math.PI||"major"===ev_s&&phi<Math.PI)&&(sgn=-1),this.useDirection&&(p0c=points[1].coords.usrCoords,p1c=points[3].coords.usrCoords,p2c=points[2].coords.usrCoords,(p0c[1]-p2c[1])*(p0c[2]-p1c[2])-(p0c[2]-p2c[2])*(p0c[1]-p1c[1])<0?(this.radiuspoint=points[1],this.anglepoint=points[2]):(this.radiuspoint=points[2],this.anglepoint=points[1])),A=A.coords.usrCoords,B=B.coords.usrCoords,C=C.coords.usrCoords,ar=Geometry.bezierArc(A,B,C,!1,sgn),this.dataX=ar[0],this.dataY=ar[1],this.bezierDegree=3,this.updateStdform(),this.updateQuadraticform()},el.Radius=function(){return this.radiuspoint.Dist(this.center)},el.getRadius=function(){return JXG.deprecated("Arc.getRadius()","Arc.Radius()"),this.Radius()},el.Value=function(){return this.Radius()*Geometry.rad(this.radiuspoint,this.center,this.anglepoint)},el.hasPoint=function(x,y){var dist,checkPoint,has,invMat,c,prec,type,r=this.Radius();return Type.evaluate(this.visProp.hasinnerpoints)?this.hasPointSector(x,y):(Type.isObject(Type.evaluate(this.visProp.precision))?(type=this.board._inputDevice,prec=Type.evaluate(this.visProp.precision[type])):prec=this.board.options.precision.hasPoint,prec/=Math.min(this.board.unitX,this.board.unitY),checkPoint=new Coords(Const.COORDS_BY_SCREEN,[x,y],this.board),this.transformations.length>0&&(this.updateTransformMatrix(),invMat=Mat.inverse(this.transformMat),c=Mat.matVecMult(invMat,checkPoint.usrCoords),checkPoint=new Coords(Const.COORDS_BY_USER,c,this.board)),dist=this.center.coords.distance(Const.COORDS_BY_USER,checkPoint),(has=Math.abs(dist-r)<prec)&&(has=Geometry.coordsOnArc(this,checkPoint)),has)},el.hasPointSector=function(x,y){var checkPoint=new Coords(Const.COORDS_BY_SCREEN,[x,y],this.board),r=this.Radius(),has=this.center.coords.distance(Const.COORDS_BY_USER,checkPoint)<r;return has&&(has=Geometry.coordsOnArc(this,checkPoint)),has},el.getTextAnchor=function(){return this.center.coords},el.getLabelAnchor=function(){var coords,vec,vecx,vecy,len,angle=Geometry.rad(this.radiuspoint,this.center,this.anglepoint),dx=10/this.board.unitX,dy=10/this.board.unitY,p2c=this.point2.coords.usrCoords,pmc=this.center.coords.usrCoords,bxminusax=p2c[1]-pmc[1],byminusay=p2c[2]-pmc[2],ev_s=Type.evaluate(this.visProp.selection),l_vp=this.label?this.label.visProp:this.visProp.label;return("minor"===ev_s&&angle>Math.PI||"major"===ev_s&&angle<Math.PI)&&(angle=-(2*Math.PI-angle)),vecx=(coords=new Coords(Const.COORDS_BY_USER,[pmc[1]+Math.cos(.5*angle)*bxminusax-Math.sin(.5*angle)*byminusay,pmc[2]+Math.sin(.5*angle)*bxminusax+Math.cos(.5*angle)*byminusay],this.board)).usrCoords[1]-pmc[1],vecy=coords.usrCoords[2]-pmc[2],vecx=vecx*((len=Math.sqrt(vecx*vecx+vecy*vecy))+dx)/len,vecy=vecy*(len+dy)/len,vec=[pmc[1]+vecx,pmc[2]+vecy],l_vp.position=Geometry.calcLabelQuadrant(Geometry.rad([1,0],[0,0],vec)),new Coords(Const.COORDS_BY_USER,vec,this.board)},el.updateQuadraticform=Circle.Circle.prototype.updateQuadraticform,el.updateStdform=Circle.Circle.prototype.updateStdform,el.methodMap=JXG.deepCopy(el.methodMap,{getRadius:"getRadius",radius:"Radius",center:"center",radiuspoint:"radiuspoint",anglepoint:"anglepoint",Value:"Value"}),el.prepareUpdate().update(),el},JXG.registerElement("arc",JXG.createArc),JXG.createSemicircle=function(board,parents,attributes){var el,mp,attr,points;if(!1===(points=Type.providePoints(board,parents,attributes,"point"))||2!==points.length)throw new Error("JSXGraph: Can't create Semicircle with parent types '"+_typeof(parents[0])+"' and '"+_typeof(parents[1])+"'.\nPossible parent types: [point,point]");return attr=Type.copyAttributes(attributes,board.options,"semicircle","center"),(mp=board.create("midpoint",points,attr)).dump=!1,attr=Type.copyAttributes(attributes,board.options,"semicircle"),(el=board.create("arc",[mp,points[1],points[0]],attr)).elType="semicircle",el.setParents([points[0].id,points[1].id]),el.subs={midpoint:mp},el.inherits.push(mp),el.midpoint=el.center=mp,el},JXG.registerElement("semicircle",JXG.createSemicircle),JXG.createCircumcircleArc=function(board,parents,attributes){var el,mp,attr,points;if(!1===(points=Type.providePoints(board,parents,attributes,"point"))||3!==points.length)throw new Error("JSXGraph: create Circumcircle Arc with parent types '"+_typeof(parents[0])+"' and '"+_typeof(parents[1])+"' and '"+_typeof(parents[2])+"'.\nPossible parent types: [point,point,point]");return attr=Type.copyAttributes(attributes,board.options,"circumcirclearc","center"),(mp=board.create("circumcenter",points,attr)).dump=!1,(attr=Type.copyAttributes(attributes,board.options,"circumcirclearc")).usedirection=!0,(el=board.create("arc",[mp,points[0],points[2],points[1]],attr)).elType="circumcirclearc",el.setParents([points[0].id,points[1].id,points[2].id]),el.subs={center:mp},el.inherits.push(mp),el.center=mp,el},JXG.registerElement("circumcirclearc",JXG.createCircumcircleArc),JXG.createMinorArc=function(board,parents,attributes){return attributes.selection="minor",JXG.createArc(board,parents,attributes)},JXG.registerElement("minorarc",JXG.createMinorArc),JXG.createMajorArc=function(board,parents,attributes){return attributes.selection="major",JXG.createArc(board,parents,attributes)},JXG.registerElement("majorarc",JXG.createMajorArc),{createArc:JXG.createArc,createSemicircle:JXG.createSemicircle,createCircumcircleArc:JXG.createCircumcircleArc,createMinorArc:JXG.createMinorArc,createMajorArc:JXG.createMajorArc}})),define("element/sector",["jxg","math/geometry","math/math","math/statistics","base/coords","base/constants","utils/type"],(function(JXG,Geometry,Mat,Statistics,Coords,Const,Type){return JXG.createSector=function(board,parents,attributes){var el,attr,i,s,v,points,type="invalid";if(parents[0].elementClass===Const.OBJECT_CLASS_LINE&&parents[1].elementClass===Const.OBJECT_CLASS_LINE&&(Type.isArray(parents[2])||Type.isNumber(parents[2]))&&(Type.isArray(parents[3])||Type.isNumber(parents[3]))&&(Type.isNumber(parents[4])||Type.isFunction(parents[4])||Type.isString(parents[4])))type="2lines";else{if(!1===(points=Type.providePoints(board,parents,attributes,"sector",["center","radiusPoint","anglePoint"])))throw new Error("JSXGraph: Can't create Sector with parent types '"+_typeof(parents[0])+"' and '"+_typeof(parents[1])+"' and '"+_typeof(parents[2])+"'.");type="3points"}if(attr=Type.copyAttributes(attributes,board.options,"sector"),(el=board.create("curve",[[0],[0]],attr)).type=Const.OBJECT_TYPE_SECTOR,el.elType="sector",el.autoRadius=function(){var r1=20/el.board.unitX,r2=1/0,r3=50/el.board.unitX;return Type.isPoint(el.center)&&(r2=.3333*el.center.Dist(el.point2)),Math.max(r1,Math.min(r2,r3))},"2lines"===type)el.Radius=function(){var r=Type.evaluate(parents[4]);return"auto"===r?this.autoRadius():r},el.line1=board.select(parents[0]),el.line2=board.select(parents[1]),el.line1.addChild(el),el.line2.addChild(el),el.setParents(parents),el.point1={visProp:{}},el.point2={visProp:{}},el.point3={visProp:{}},s=Geometry.meetLineLine(el.line1.stdform,el.line2.stdform,0,board),Type.isArray(parents[2])?(2===parents[2].length&&(parents[2]=[1].concat(parents[2])),v=Geometry.projectPointToLine({coords:{usrCoords:parents[2]}},el.line1,board),v=Statistics.subtract(v.usrCoords,s.usrCoords),el.direction1=Mat.innerProduct(v,[0,el.line1.stdform[2],-el.line1.stdform[1]],3)>=0?1:-1):el.direction1=parents[2]>=0?1:-1,Type.isArray(parents[3])?(2===parents[3].length&&(parents[3]=[1].concat(parents[3])),v=Geometry.projectPointToLine({coords:{usrCoords:parents[3]}},el.line2,board),v=Statistics.subtract(v.usrCoords,s.usrCoords),el.direction2=Mat.innerProduct(v,[0,el.line2.stdform[2],-el.line2.stdform[1]],3)>=0?1:-1):el.direction2=parents[3]>=0?1:-1,el.updateDataArray=function(){var r,l1,l2,A,C,ar,B=[0,0,0];if(l1=this.line1,l2=this.line2,B=Mat.crossProduct(l1.stdform,l2.stdform),Math.abs(B[0])>Mat.eps*Mat.eps&&(B[1]/=B[0],B[2]/=B[0],B[0]/=B[0]),r=this.direction1*this.Radius(),A=Statistics.add(B,[0,r*l1.stdform[2],-r*l1.stdform[1]]),r=this.direction2*this.Radius(),C=Statistics.add(B,[0,r*l2.stdform[2],-r*l2.stdform[1]]),this.point2.coords=new Coords(Const.COORDS_BY_USER,A,el.board),this.point1.coords=new Coords(Const.COORDS_BY_USER,B,el.board),this.point3.coords=new Coords(Const.COORDS_BY_USER,C,el.board),Math.abs(A[0])<Mat.eps||Math.abs(B[0])<Mat.eps||Math.abs(C[0])<Mat.eps)return this.dataX=[NaN],void(this.dataY=[NaN]);ar=Geometry.bezierArc(A,B,C,!0,1),this.dataX=ar[0],this.dataY=ar[1],this.bezierDegree=3},el.methodMap=JXG.deepCopy(el.methodMap,{radius:"Radius",getRadius:"Radius",setRadius:"setRadius"});else if("3points"===type){for(el.point1=points[0],el.point2=points[1],el.point3=points[2],i=0;i<3;i++)Type.exists(points[i]._is_new)?(el.addChild(points[i]),delete points[i]._is_new):points[i].addChild(el);el.useDirection=attributes.usedirection,el.setParents(points),Type.exists(points[3])&&(el.point4=points[3],el.point4.addChild(el)),el.methodMap=JXG.deepCopy(el.methodMap,{arc:"arc",center:"center",radiuspoint:"radiuspoint",anglepoint:"anglepoint",radius:"Radius",getRadius:"Radius",setRadius:"setRadius"}),el.updateDataArray=function(){var ar,p0c,p1c,p2c,phi,A=this.point2,B=this.point1,C=this.point3,sgn=1,vp_s=Type.evaluate(this.visProp.selection);if(!A.isReal||!B.isReal||!C.isReal)return this.dataX=[NaN],void(this.dataY=[NaN]);phi=Geometry.rad(A,B,C),("minor"===vp_s&&phi>Math.PI||"major"===vp_s&&phi<Math.PI)&&(sgn=-1),this.useDirection&&Type.exists(this.point4)&&(p0c=this.point2.coords.usrCoords,p1c=this.point4.coords.usrCoords,p2c=this.point3.coords.usrCoords,(p0c[1]-p2c[1])*(p0c[2]-p1c[2])-(p0c[2]-p2c[2])*(p0c[1]-p1c[1])>=0&&(C=this.point2,A=this.point3)),A=A.coords.usrCoords,B=B.coords.usrCoords,C=C.coords.usrCoords,ar=Geometry.bezierArc(A,B,C,!0,sgn),this.dataX=ar[0],this.dataY=ar[1],this.bezierDegree=3},el.Radius=function(){return this.point2.Dist(this.point1)},(attr=Type.copyAttributes(attributes,board.options,"sector","arc")).withLabel=!1,attr.name+="_arc",el.arc=board.create("arc",[el.point1,el.point2,el.point3],attr),el.addChild(el.arc)}return el.center=el.point1,el.radiuspoint=el.point2,el.anglepoint=el.point3,el.hasPointCurve=function(x,y){var angle,alpha,beta,prec,type,has,checkPoint=new Coords(Const.COORDS_BY_SCREEN,[x,y],this.board),r=this.Radius(),dist=this.center.coords.distance(Const.COORDS_BY_USER,checkPoint),vp_s=Type.evaluate(this.visProp.selection);return Type.isObject(Type.evaluate(this.visProp.precision))?(type=this.board._inputDevice,prec=Type.evaluate(this.visProp.precision[type])):prec=this.board.options.precision.hasPoint,prec/=Math.min(this.board.unitX,this.board.unitY),(has=Math.abs(dist-r)<prec)&&(angle=Geometry.rad(this.point2,this.center,checkPoint.usrCoords.slice(1)),alpha=0,beta=Geometry.rad(this.point2,this.center,this.point3),("minor"===vp_s&&beta>Math.PI||"major"===vp_s&&beta<Math.PI)&&(alpha=beta,beta=2*Math.PI),(angle<alpha||angle>beta)&&(has=!1)),has},el.hasPointSector=function(x,y){var angle,alpha,beta,checkPoint=new Coords(Const.COORDS_BY_SCREEN,[x,y],this.board),r=this.Radius(),has=this.point1.coords.distance(Const.COORDS_BY_USER,checkPoint)<r,vp_s=Type.evaluate(this.visProp.selection);return has&&(angle=Geometry.rad(this.radiuspoint,this.center,checkPoint.usrCoords.slice(1)),alpha=0,beta=Geometry.rad(this.radiuspoint,this.center,this.anglepoint),("minor"===vp_s&&beta>Math.PI||"major"===vp_s&&beta<Math.PI)&&(alpha=beta,beta=2*Math.PI),(angle<alpha||angle>beta)&&(has=!1)),has},el.hasPoint=function(x,y){return Type.evaluate(this.visProp.highlightonsector)||Type.evaluate(this.visProp.hasinnerpoints)?this.hasPointSector(x,y):this.hasPointCurve(x,y)},el.getTextAnchor=function(){return this.point1.coords},el.getLabelAnchor=function(){var coords,vec,vecx,vecy,len,angle=Geometry.rad(this.point2,this.point1,this.point3),dx=13/this.board.unitX,dy=13/this.board.unitY,p2c=this.point2.coords.usrCoords,pmc=this.point1.coords.usrCoords,bxminusax=p2c[1]-pmc[1],byminusay=p2c[2]-pmc[2],vp_s=Type.evaluate(this.visProp.selection),l_vp=this.label?this.label.visProp:this.visProp.label;return("minor"===vp_s&&angle>Math.PI||"major"===vp_s&&angle<Math.PI)&&(angle=-(2*Math.PI-angle)),vecx=(coords=new Coords(Const.COORDS_BY_USER,[pmc[1]+Math.cos(.5*angle)*bxminusax-Math.sin(.5*angle)*byminusay,pmc[2]+Math.sin(.5*angle)*bxminusax+Math.cos(.5*angle)*byminusay],this.board)).usrCoords[1]-pmc[1],vecy=coords.usrCoords[2]-pmc[2],vecx=vecx*((len=Math.sqrt(vecx*vecx+vecy*vecy))+dx)/len,vecy=vecy*(len+dy)/len,vec=[pmc[1]+vecx,pmc[2]+vecy],l_vp.position=Geometry.calcLabelQuadrant(Geometry.rad([1,0],[0,0],vec)),new Coords(Const.COORDS_BY_USER,vec,this.board)},el.setRadius=function(val){el.Radius=function(){var r=Type.evaluate(val);return"auto"===r?this.autoRadius():r}},el.getRadius=function(){return JXG.deprecated("Sector.getRadius()","Sector.Radius()"),this.Radius()},"3points"===type&&(el.setPositionDirectly=function(method,coords,oldcoords){var dc,c=new Coords(method,coords,this.board),oldc=new Coords(method,oldcoords,this.board);return el.point1.draggable()&&el.point2.draggable()&&el.point3.draggable()?(dc=Statistics.subtract(c.usrCoords,oldc.usrCoords),this.board.create("transform",dc.slice(1),{type:"translate"}).applyOnce([el.point1,el.point2,el.point3]),this):this}),el.prepareUpdate().update(),el},JXG.registerElement("sector",JXG.createSector),JXG.createCircumcircleSector=function(board,parents,attributes){var el,mp,attr,points;if(!1===(points=Type.providePoints(board,parents,attributes,"point")))throw new Error("JSXGraph: Can't create circumcircle sector with parent types '"+_typeof(parents[0])+"' and '"+_typeof(parents[1])+"' and '"+_typeof(parents[2])+"'.");return(mp=board.create("circumcenter",points.slice(0,3),attr)).dump=!1,attr=Type.copyAttributes(attributes,board.options,"circumcirclesector"),(el=board.create("sector",[mp,points[0],points[2],points[1]],attr)).elType="circumcirclesector",el.setParents(points),el.center=mp,el.subs={center:mp},el},JXG.registerElement("circumcirclesector",JXG.createCircumcircleSector),JXG.createMinorSector=function(board,parents,attributes){return attributes.selection="minor",JXG.createSector(board,parents,attributes)},JXG.registerElement("minorsector",JXG.createMinorSector),JXG.createMajorSector=function(board,parents,attributes){return attributes.selection="major",JXG.createSector(board,parents,attributes)},JXG.registerElement("majorsector",JXG.createMajorSector),JXG.createAngle=function(board,parents,attributes){var el,radius,attr,attrsub,i,points,type="invalid";if(parents[0].elementClass===Const.OBJECT_CLASS_LINE&&parents[1].elementClass===Const.OBJECT_CLASS_LINE&&(Type.isArray(parents[2])||Type.isNumber(parents[2]))&&(Type.isArray(parents[3])||Type.isNumber(parents[3])))type="2lines";else{if(!1===(points=Type.providePoints(board,parents,attributes,"point")))throw new Error("JSXGraph: Can't create angle with parent types '"+_typeof(parents[0])+"' and '"+_typeof(parents[1])+"' and '"+_typeof(parents[2])+"'.");type="3points"}if(attr=Type.copyAttributes(attributes,board.options,"angle"),Type.exists(attr.name)&&""!==attr.name||(attr.name=board.generateName({type:Const.OBJECT_TYPE_ANGLE})),radius=Type.exists(attr.radius)?attr.radius:0,"2lines"===type?(parents.push(radius),(el=board.create("sector",parents,attr)).updateDataArraySector=el.updateDataArray,el.setAngle=function(val){},el.free=function(val){}):((el=board.create("sector",[points[1],points[0],points[2]],attr)).arc.visProp.priv=!0,el.point=el.point2=el.radiuspoint=points[0],el.pointsquare=el.point3=el.anglepoint=points[2],el.Radius=function(){var r=Type.evaluate(radius);return"auto"===r?el.autoRadius():r},el.updateDataArraySector=function(){var ar,phi,A=this.point2,B=this.point1,C=this.point3,r=this.Radius(),d=B.Dist(A),sgn=1,vp_s=Type.evaluate(this.visProp.selection);phi=Geometry.rad(A,B,C),("minor"===vp_s&&phi>Math.PI||"major"===vp_s&&phi<Math.PI)&&(sgn=-1),A=A.coords.usrCoords,B=B.coords.usrCoords,C=C.coords.usrCoords,A=[1,B[1]+(A[1]-B[1])*r/d,B[2]+(A[2]-B[2])*r/d],C=[1,B[1]+(C[1]-B[1])*r/d,B[2]+(C[2]-B[2])*r/d],ar=Geometry.bezierArc(A,B,C,!0,sgn),this.dataX=ar[0],this.dataY=ar[1],this.bezierDegree=3},el.setAngle=function(val){var t1,t2,val2,p=this.anglepoint,q=this.radiuspoint;return p.draggable()&&(t1=this.board.create("transform",[val,this.center],{type:"rotate"}),p.addTransform(q,t1),t1.update(),p.moveTo(Mat.matVecMult(t1.matrix,q.coords.usrCoords)),val2=Type.isFunction(val)?function(){return 2*Math.PI-val()}:function(){return 2*Math.PI-val},t2=this.board.create("transform",[val2,this.center],{type:"rotate"}),p.coords.on("update",(function(){t2.update(),q.moveTo(Mat.matVecMult(t2.matrix,p.coords.usrCoords))})),p.setParents(q)),this},el.free=function(){var p=this.anglepoint;return p.transformations.length>0&&(p.transformations.pop(),p.isDraggable=!0,p.parents=[],p.coords.off("update")),this},el.setParents(points)),Type.exists(el.visProp.text)&&el.label.setText(Type.evaluate(el.visProp.text)),el.elType="angle",el.type=Const.OBJECT_TYPE_ANGLE,el.subs={},el.updateDataArraySquare=function(){var A,B,C,d1,d2,v,l1,l2,r=this.Radius();"2lines"===type&&this.updateDataArraySector(),A=this.point2,B=this.point1,C=this.point3,A=A.coords.usrCoords,B=B.coords.usrCoords,C=C.coords.usrCoords,d1=Geometry.distance(A,B,3),d2=Geometry.distance(C,B,3),A=[1,B[1]+(A[1]-B[1])*r/d1,B[2]+(A[2]-B[2])*r/d1],C=[1,B[1]+(C[1]-B[1])*r/d2,B[2]+(C[2]-B[2])*r/d2],v=Mat.crossProduct(C,B),l1=[-A[1]*v[1]-A[2]*v[2],A[0]*v[1],A[0]*v[2]],v=Mat.crossProduct(A,B),l2=[-C[1]*v[1]-C[2]*v[2],C[0]*v[1],C[0]*v[2]],(v=Mat.crossProduct(l1,l2))[1]/=v[0],v[2]/=v[0],this.dataX=[B[1],A[1],v[1],C[1],B[1]],this.dataY=[B[2],A[2],v[2],C[2],B[2]],this.bezierDegree=1},el.updateDataArrayNone=function(){this.dataX=[NaN],this.dataY=[NaN],this.bezierDegree=1},el.updateDataArray=function(){var type=Type.evaluate(this.visProp.type),deg=Geometry.trueAngle(this.point2,this.point1,this.point3),vp_s=Type.evaluate(this.visProp.selection);("minor"===vp_s&°>180||"major"===vp_s&°<180)&&(deg=360-deg),Math.abs(deg-90)<Type.evaluate(this.visProp.orthosensitivity)+Mat.eps&&(type=Type.evaluate(this.visProp.orthotype)),"none"===type?this.updateDataArrayNone():"square"===type?this.updateDataArraySquare():"sector"===type?this.updateDataArraySector():"sectordot"===type&&(this.updateDataArraySector(),this.dot.visProp.visible||this.dot.setAttribute({visible:!0})),(!this.visProp.visible||"sectordot"!==type&&this.dot.visProp.visible)&&this.dot.setAttribute({visible:!1})},attrsub=Type.copyAttributes(attributes,board.options,"angle","dot"),el.dot=board.create("point",[function(){var A,B,r,d,a2,co,si,mat,vp_s;return Type.exists(el.dot)&&!el.dot.visProp.visible?[0,0]:(A=el.point2.coords.usrCoords,B=el.point1.coords.usrCoords,r=el.Radius(),d=Geometry.distance(A,B,3),a2=Geometry.rad(el.point2,el.point1,el.point3),("minor"===(vp_s=Type.evaluate(el.visProp.selection))&&a2>Math.PI||"major"===vp_s&&a2<Math.PI)&&(a2=-(2*Math.PI-a2)),a2*=.5,co=Math.cos(a2),si=Math.sin(a2),A=[1,B[1]+(A[1]-B[1])*r/d,B[2]+(A[2]-B[2])*r/d],mat=[[1,0,0],[B[1]-.5*B[1]*co+.5*B[2]*si,.5*co,.5*-si],[B[2]-.5*B[1]*si-.5*B[2]*co,.5*si,.5*co]],Mat.matVecMult(mat,A))}],attrsub),el.dot.dump=!1,el.subs.dot=el.dot,"2lines"===type)for(i=0;i<2;i++)board.select(parents[i]).addChild(el.dot);else for(i=0;i<3;i++)board.select(points[i]).addChild(el.dot);return el.getLabelAnchor=function(){var vec,A,B,r,d,a2,co,si,mat,dx=12,vp_s=Type.evaluate(el.visProp.selection),l_vp=this.label?this.label.visProp:this.visProp.label;return Type.exists(this.label.visProp.fontSize)&&(dx=Type.evaluate(this.label.visProp.fontSize)),dx/=this.board.unitX,A=el.point2.coords.usrCoords,B=el.point1.coords.usrCoords,r=el.Radius(),d=Geometry.distance(A,B,3),a2=Geometry.rad(el.point2,el.point1,el.point3),("minor"===vp_s&&a2>Math.PI||"major"===vp_s&&a2<Math.PI)&&(a2=-(2*Math.PI-a2)),a2*=.5,co=Math.cos(a2),si=Math.sin(a2),A=[1,B[1]+(A[1]-B[1])*r/d,B[2]+(A[2]-B[2])*r/d],mat=[[1,0,0],[B[1]-.5*B[1]*co+.5*B[2]*si,.5*co,.5*-si],[B[2]-.5*B[1]*si-.5*B[2]*co,.5*si,.5*co]],(vec=Mat.matVecMult(mat,A))[1]/=vec[0],vec[2]/=vec[0],vec[0]/=vec[0],d=Geometry.distance(vec,B,3),vec=[vec[0],B[1]+(vec[1]-B[1])*(r+dx)/d,B[2]+(vec[2]-B[2])*(r+dx)/d],l_vp.position=Geometry.calcLabelQuadrant(Geometry.rad([1,0],[0,0],vec)),new Coords(Const.COORDS_BY_USER,vec,this.board)},el.Value=function(){return Geometry.rad(this.point2,this.point1,this.point3)},el.methodMap=Type.deepCopy(el.methodMap,{Value:"Value",setAngle:"setAngle",free:"free"}),el},JXG.registerElement("angle",JXG.createAngle),JXG.createNonreflexAngle=function(board,parents,attributes){var el;return attributes.selection="minor",(el=JXG.createAngle(board,parents,attributes)).Value=function(){var v=Geometry.rad(this.point2,this.point1,this.point3);return v<Math.PI?v:2*Math.PI-v},el},JXG.registerElement("nonreflexangle",JXG.createNonreflexAngle),JXG.createReflexAngle=function(board,parents,attributes){var el;return attributes.selection="major",(el=JXG.createAngle(board,parents,attributes)).Value=function(){var v=Geometry.rad(this.point2,this.point1,this.point3);return v>=Math.PI?v:2*Math.PI-v},el},JXG.registerElement("reflexangle",JXG.createReflexAngle),{createSector:JXG.createSector,createCircumcircleSector:JXG.createCircumcircleSector,createMinorSector:JXG.createMinorSector,createMajorSector:JXG.createMajorSector,createAngle:JXG.createAngle,createReflexAngle:JXG.createReflexAngle,createNonreflexAngle:JXG.createNonreflexAngle}})),define("base/transformation",["jxg","base/constants","math/math","utils/type"],(function(JXG,Const,Mat,Type){return JXG.Transformation=function(board,type,params){this.elementClass=Const.OBJECT_CLASS_OTHER,this.type=Const.OBJECT_TYPE_TRANSFORMATION,this.matrix=[[1,0,0],[0,1,0],[0,0,1]],this.board=board,this.isNumericMatrix=!1,this.setMatrix(board,type,params),this.methodMap={apply:"apply",applyOnce:"applyOnce",bindTo:"bindTo",bind:"bindTo",melt:"melt"}},JXG.Transformation.prototype={},JXG.extend(JXG.Transformation.prototype,{update:function(){return this},setMatrix:function(board,type,params){var i;for(this.isNumericMatrix=!0,i=0;i<params.length;i++)if("number"!=typeof params[i]){this.isNumericMatrix=!1;break}if("translate"===type){if(2!==params.length)throw new Error("JSXGraph: translate transformation needs 2 parameters.");this.evalParam=Type.createEvalFunction(board,params,2),this.update=function(){this.matrix[1][0]=this.evalParam(0),this.matrix[2][0]=this.evalParam(1)}}else if("scale"===type){if(2!==params.length)throw new Error("JSXGraph: scale transformation needs 2 parameters.");this.evalParam=Type.createEvalFunction(board,params,2),this.update=function(){this.matrix[1][1]=this.evalParam(0),this.matrix[2][2]=this.evalParam(1)}}else if("reflect"===type)params.length<4&&(params[0]=board.select(params[0])),2===params.length&&(params[1]=board.select(params[1])),4===params.length&&(this.evalParam=Type.createEvalFunction(board,params,4)),this.update=function(){var x,y,z,xoff,yoff,d,v,p;1===params.length?v=params[0].stdform:2===params.length?v=Mat.crossProduct(params[1].coords.usrCoords,params[0].coords.usrCoords):4===params.length&&(v=Mat.crossProduct([1,this.evalParam(2),this.evalParam(3)],[1,this.evalParam(0),this.evalParam(1)])),x=v[1],y=v[2],d=(p=[-(z=v[0])*x,-z*y,x*x+y*y])[2],xoff=p[0]/p[2],yoff=p[1]/p[2],x=-v[2],y=v[1],this.matrix[1][1]=(x*x-y*y)/d,this.matrix[1][2]=2*x*y/d,this.matrix[2][1]=this.matrix[1][2],this.matrix[2][2]=-this.matrix[1][1],this.matrix[1][0]=xoff*(1-this.matrix[1][1])-yoff*this.matrix[1][2],this.matrix[2][0]=yoff*(1-this.matrix[2][2])-xoff*this.matrix[2][1]};else if("rotate"===type)3===params.length?this.evalParam=Type.createEvalFunction(board,params,3):params.length>0&¶ms.length<=2&&(this.evalParam=Type.createEvalFunction(board,params,1),2!==params.length||Type.isArray(params[1])||(params[1]=board.select(params[1]))),this.update=function(){var x,y,beta=this.evalParam(0),co=Math.cos(beta),si=Math.sin(beta);this.matrix[1][1]=co,this.matrix[1][2]=-si,this.matrix[2][1]=si,this.matrix[2][2]=co,params.length>1&&(3===params.length?(x=this.evalParam(1),y=this.evalParam(2)):Type.isArray(params[1])?(x=params[1][0],y=params[1][1]):(x=params[1].X(),y=params[1].Y()),this.matrix[1][0]=x*(1-co)+y*si,this.matrix[2][0]=y*(1-co)-x*si)};else if("shear"===type){if(2!==params.length)throw new Error("JSXGraph: shear transformation needs 2 parameters.");this.evalParam=Type.createEvalFunction(board,params,2),this.update=function(){this.matrix[1][2]=this.evalParam(0),this.matrix[2][1]=this.evalParam(1)}}else if("generic"===type){if(9!==params.length)throw new Error("JSXGraph: generic transformation needs 9 parameters.");this.evalParam=Type.createEvalFunction(board,params,9),this.update=function(){this.matrix[0][0]=this.evalParam(0),this.matrix[0][1]=this.evalParam(1),this.matrix[0][2]=this.evalParam(2),this.matrix[1][0]=this.evalParam(3),this.matrix[1][1]=this.evalParam(4),this.matrix[1][2]=this.evalParam(5),this.matrix[2][0]=this.evalParam(6),this.matrix[2][1]=this.evalParam(7),this.matrix[2][2]=this.evalParam(8)}}},apply:function(p,self){return this.update(),Type.exists(self)?Mat.matVecMult(this.matrix,p.initialCoords.usrCoords):Mat.matVecMult(this.matrix,p.coords.usrCoords)},applyOnce:function(p){var c,len,i;for(Type.isArray(p)||(p=[p]),len=p.length,i=0;i<len;i++)this.update(),c=Mat.matVecMult(this.matrix,p[i].coords.usrCoords),p[i].coords.setCoordinates(Const.COORDS_BY_USER,c)},bindTo:function(p){var i,len;if(Type.isArray(p))for(len=p.length,i=0;i<len;i++)p[i].transformations.push(this);else p.transformations.push(this)},setProperty:function(term){JXG.deprecated("Transformation.setProperty()","Transformation.setAttribute()")},setAttribute:function(term){},melt:function(t){var i,len,len0,k,s,j,res=[];for(len=t.matrix.length,len0=this.matrix[0].length,i=0;i<len;i++)res[i]=[];for(this.update(),t.update(),i=0;i<len;i++)for(j=0;j<len0;j++){for(s=0,k=0;k<len;k++)s+=t.matrix[i][k]*this.matrix[k][j];res[i][j]=s}return this.update=function(){var len=this.matrix.length,len0=this.matrix[0].length;for(i=0;i<len;i++)for(j=0;j<len0;j++)this.matrix[i][j]=res[i][j]},this},getParents:function(){var p=[[].concat.apply([],this.matrix)];return 0!==this.parents.length&&(p=this.parents),p}}),JXG.createTransform=function(board,parents,attributes){return new JXG.Transformation(board,attributes.type,parents)},JXG.registerElement("transform",JXG.createTransform),{Transformation:JXG.Transformation,createTransform:JXG.createTransform}})),define("element/composition",["jxg","math/math","math/geometry","math/numerics","base/coords","utils/type","base/constants","base/point","base/line","base/circle","base/transformation","base/composition","base/curve","base/polygon"],(function(JXG,Mat,Geometry,Numerics,Coords,Type,Const,Point,Line,Circle,Transform,Composition,Curve,Polygon){return JXG.createOrthogonalProjection=function(board,parents,attributes){var l,p,t,attr;if(parents[0]=board.select(parents[0]),parents[1]=board.select(parents[1]),Type.isPointType(board,parents[0])&&parents[1].elementClass===Const.OBJECT_CLASS_LINE)p=Type.providePoints(board,[parents[0]],attributes,"point")[0],l=parents[1];else{if(!Type.isPointType(board,parents[1])||parents[0].elementClass!==Const.OBJECT_CLASS_LINE)throw new Error("JSXGraph: Can't create perpendicular point with parent types '"+_typeof(parents[0])+"' and '"+_typeof(parents[1])+"'.\nPossible parent types: [point,line]");p=Type.providePoints(board,[parents[1]],attributes,"point")[0],l=parents[0]}return attr=Type.copyAttributes(attributes,board.options,"orthogonalprojection"),t=board.create("point",[function(){return Geometry.projectPointToLine(p,l,board)}],attr),Type.exists(p._is_new)?(t.addChild(p),delete p._is_new):p.addChild(t),l.addChild(t),t.elType="orthogonalprojection",t.setParents([p.id,t.id]),t.update(),t.generatePolynomial=function(){var a1=l.point1.symbolic.x,a2=l.point1.symbolic.y,b1=l.point2.symbolic.x,b2=l.point2.symbolic.y,p1=p.symbolic.x,p2=p.symbolic.y,t1=t.symbolic.x,t2=t.symbolic.y;return["("+a2+")*("+t1+")-("+a2+")*("+b1+")+("+t2+")*("+b1+")-("+a1+")*("+t2+")+("+a1+")*("+b2+")-("+t1+")*("+b2+")","("+p2+")*("+a2+")-("+p2+")*("+b2+")-("+t2+")*("+a2+")+("+t2+")*("+b2+")+("+p1+")*("+a1+")-("+p1+")*("+b1+")-("+t1+")*("+a1+")+("+t1+")*("+b1+")"]},t},JXG.createPerpendicular=function(board,parents,attributes){var p,l,pd,attr;if(parents[0]=board.select(parents[0]),parents[1]=board.select(parents[1]),Type.isPointType(board,parents[0])&&parents[1].elementClass===Const.OBJECT_CLASS_LINE)l=parents[1],p=Type.providePoints(board,[parents[0]],attributes,"point")[0];else{if(!Type.isPointType(board,parents[1])||parents[0].elementClass!==Const.OBJECT_CLASS_LINE)throw new Error("JSXGraph: Can't create perpendicular with parent types '"+_typeof(parents[0])+"' and '"+_typeof(parents[1])+"'.\nPossible parent types: [line,point]");l=parents[0],p=Type.providePoints(board,[parents[1]],attributes,"point")[0]}return attr=Type.copyAttributes(attributes,board.options,"perpendicular"),(pd=Line.createLine(board,[function(){return l.stdform[2]*p.X()-l.stdform[1]*p.Y()},function(){return-l.stdform[2]*p.Z()},function(){return l.stdform[1]*p.Z()}],attr)).elType="perpendicular",pd.setParents([l.id,p.id]),Type.exists(p._is_new)?(pd.addChild(p),delete p._is_new):p.addChild(pd),l.addChild(pd),pd},JXG.createPerpendicularPoint=function(board,parents,attributes){var l,p,t;if(parents[0]=board.select(parents[0]),parents[1]=board.select(parents[1]),Type.isPointType(board,parents[0])&&parents[1].elementClass===Const.OBJECT_CLASS_LINE)p=Type.providePoints(board,[parents[0]],attributes,"point")[0],l=parents[1];else{if(!Type.isPointType(board,parents[1])||parents[0].elementClass!==Const.OBJECT_CLASS_LINE)throw new Error("JSXGraph: Can't create perpendicular point with parent types '"+_typeof(parents[0])+"' and '"+_typeof(parents[1])+"'.\nPossible parent types: [point,line]");p=Type.providePoints(board,[parents[1]],attributes,"point")[0],l=parents[0]}return t=board.create("point",[function(){return Geometry.perpendicular(l,p,board)[0]}],attributes),Type.exists(p._is_new)?(t.addChild(p),delete p._is_new):p.addChild(t),l.addChild(t),t.elType="perpendicularpoint",t.setParents([p.id,l.id]),t.update(),t.generatePolynomial=function(){var a1=l.point1.symbolic.x,a2=l.point1.symbolic.y,b1=l.point2.symbolic.x,b2=l.point2.symbolic.y,p1=p.symbolic.x,p2=p.symbolic.y,t1=t.symbolic.x,t2=t.symbolic.y;return["("+a2+")*("+t1+")-("+a2+")*("+b1+")+("+t2+")*("+b1+")-("+a1+")*("+t2+")+("+a1+")*("+b2+")-("+t1+")*("+b2+")","("+p2+")*("+a2+")-("+p2+")*("+b2+")-("+t2+")*("+a2+")+("+t2+")*("+b2+")+("+p1+")*("+a1+")-("+p1+")*("+b1+")-("+t1+")*("+a1+")+("+t1+")*("+b1+")"]},t},JXG.createPerpendicularSegment=function(board,parents,attributes){var p,l,pd,t,attr;if(parents[0]=board.select(parents[0]),parents[1]=board.select(parents[1]),Type.isPointType(board,parents[0])&&parents[1].elementClass===Const.OBJECT_CLASS_LINE)l=parents[1],p=Type.providePoints(board,[parents[0]],attributes,"point")[0];else{if(!Type.isPointType(board,parents[1])||parents[0].elementClass!==Const.OBJECT_CLASS_LINE)throw new Error("JSXGraph: Can't create perpendicular with parent types '"+_typeof(parents[0])+"' and '"+_typeof(parents[1])+"'.\nPossible parent types: [line,point]");l=parents[0],p=Type.providePoints(board,[parents[1]],attributes,"point")[0]}return attr=Type.copyAttributes(attributes,board.options,"perpendicularsegment","point"),(t=JXG.createPerpendicularPoint(board,[l,p],attr)).dump=!1,Type.exists(attributes.layer)||(attributes.layer=board.options.layer.line),attr=Type.copyAttributes(attributes,board.options,"perpendicularsegment"),(pd=Line.createLine(board,[function(){return Geometry.perpendicular(l,p,board)[1]?[t,p]:[p,t]}],attr)).point=t,Type.exists(p._is_new)?(pd.addChild(p),delete p._is_new):p.addChild(pd),l.addChild(pd),pd.elType="perpendicularsegment",pd.setParents([p.id,l.id]),pd.subs={point:t},pd.inherits.push(t),pd},JXG.createMidpoint=function(board,parents,attributes){var a,b,t,i,attr;for(i=0;i<parents.length;++i)parents[i]=board.select(parents[i]);if(2===parents.length&&Type.isPointType(board,parents[0])&&Type.isPointType(board,parents[1]))parents=Type.providePoints(board,parents,attributes,"point"),a=parents[0],b=parents[1];else{if(1!==parents.length||parents[0].elementClass!==Const.OBJECT_CLASS_LINE)throw new Error("JSXGraph: Can't create midpoint.\nPossible parent types: [point,point], [line]");a=parents[0].point1,b=parents[0].point2}return attr=Type.copyAttributes(attributes,board.options,"midpoint"),t=board.create("point",[function(){var x=a.coords.usrCoords[1]+b.coords.usrCoords[1];return isNaN(x)||Math.abs(a.coords.usrCoords[0])<Mat.eps||Math.abs(b.coords.usrCoords[0])<Mat.eps?NaN:.5*x},function(){var y=a.coords.usrCoords[2]+b.coords.usrCoords[2];return isNaN(y)||Math.abs(a.coords.usrCoords[0])<Mat.eps||Math.abs(b.coords.usrCoords[0])<Mat.eps?NaN:.5*y}],attr),Type.exists(a._is_new)?(t.addChild(a),delete a._is_new):a.addChild(t),Type.exists(b._is_new)?(t.addChild(b),delete b._is_new):b.addChild(t),t.elType="midpoint",t.setParents([a.id,b.id]),t.prepareUpdate().update(),t.generatePolynomial=function(){var a1=a.symbolic.x,a2=a.symbolic.y,b1=b.symbolic.x,b2=b.symbolic.y,t1=t.symbolic.x,t2=t.symbolic.y;return["("+a2+")*("+t1+")-("+a2+")*("+b1+")+("+t2+")*("+b1+")-("+a1+")*("+t2+")+("+a1+")*("+b2+")-("+t1+")*("+b2+")","("+a1+")^2 - 2*("+a1+")*("+t1+")+("+a2+")^2-2*("+a2+")*("+t2+")-("+b1+")^2+2*("+b1+")*("+t1+")-("+b2+")^2+2*("+b2+")*("+t2+")"]},t},JXG.createParallelPoint=function(board,parents,attributes){var a,b,c,p,i;for(i=0;i<parents.length;++i)parents[i]=board.select(parents[i]);if(3===parents.length&&Type.isPointType(board,parents[0])&&Type.isPointType(board,parents[1])&&Type.isPointType(board,parents[2]))parents=Type.providePoints(board,parents,attributes,"point"),a=parents[0],b=parents[1],c=parents[2];else if(Type.isPointType(board,parents[0])&&parents[1].elementClass===Const.OBJECT_CLASS_LINE)c=Type.providePoints(board,[parents[0]],attributes,"point")[0],a=parents[1].point1,b=parents[1].point2;else{if(!Type.isPointType(board,parents[1])||parents[0].elementClass!==Const.OBJECT_CLASS_LINE)throw new Error("JSXGraph: Can't create parallel point with parent types '"+_typeof(parents[0])+"', '"+_typeof(parents[1])+"' and '"+_typeof(parents[2])+"'.\nPossible parent types: [line,point], [point,point,point]");c=Type.providePoints(board,[parents[1]],attributes,"point")[0],a=parents[0].point1,b=parents[0].point2}return p=board.create("point",[function(){return c.coords.usrCoords[1]+b.coords.usrCoords[1]-a.coords.usrCoords[1]},function(){return c.coords.usrCoords[2]+b.coords.usrCoords[2]-a.coords.usrCoords[2]}],attributes),Type.exists(a._is_new)?(p.addChild(a),delete a._is_new):a.addChild(p),Type.exists(b._is_new)?(p.addChild(b),delete b._is_new):b.addChild(p),Type.exists(c._is_new)?(p.addChild(c),delete c._is_new):c.addChild(p),p.elType="parallelpoint",p.setParents([a.id,b.id,c.id]),p.prepareUpdate().update(),p.generatePolynomial=function(){var a1=a.symbolic.x,a2=a.symbolic.y,b1=b.symbolic.x,b2=b.symbolic.y,c1=c.symbolic.x,c2=c.symbolic.y,t1=p.symbolic.x,t2=p.symbolic.y;return["("+b2+")*("+t1+")-("+b2+")*("+c1+")-("+a2+")*("+t1+")+("+a2+")*("+c1+")-("+t2+")*("+b1+")+("+t2+")*("+a1+")+("+c2+")*("+b1+")-("+c2+")*("+a1+")","("+t2+")*("+a1+")-("+t2+")*("+c1+")-("+b2+")*("+a1+")+("+b2+")*("+c1+")-("+t1+")*("+a2+")+("+t1+")*("+c2+")+("+b1+")*("+a2+")-("+b1+")*("+c2+")"]},p},JXG.createParallel=function(board,parents,attributes){var p,pp,pl,li,i,attr,ty=1;for(i=0;i<parents.length;++i)parents[i]=board.select(parents[i]);return p=null,3===parents.length?(p=(parents=Type.providePoints(board,parents,attributes,"point"))[2],ty=0):Type.isPointType(board,parents[0])?(p=Type.providePoints(board,[parents[0]],attributes,"point")[0],li=function(){return parents[1].stdform}):Type.isPointType(board,parents[1])&&(p=Type.providePoints(board,[parents[1]],attributes,"point")[0],li=function(){return parents[0].stdform}),Type.exists(attributes.layer)||(attributes.layer=board.options.layer.line),attr=Type.copyAttributes(attributes,board.options,"parallel","point"),(pp=1===ty?board.create("point",[function(){return Mat.crossProduct([1,0,0],li())}],attr):board.create("parallelpoint",parents,attr)).isDraggable=!0,attr=Type.copyAttributes(attributes,board.options,"parallel"),(pl=board.create("line",[p,pp],attr)).elType="parallel",pl.subs={point:pp},pl.inherits.push(pp),pl.setParents([parents[0].id,parents[1].id]),3===parents.length&&pl.addParents(parents[2].id),pl.point=pp,pl},JXG.createArrowParallel=function(board,parents,attributes){var p;try{return attributes.firstArrow=!1,attributes.lastArrow=!0,(p=JXG.createParallel(board,parents,attributes).setAttribute({straightFirst:!1,straightLast:!1})).elType="arrowparallel",p}catch(e){throw new Error("JSXGraph: Can't create arrowparallel with parent types '"+_typeof(parents[0])+"' and '"+_typeof(parents[1])+"'.\nPossible parent types: [line,point], [point,point,point]")}},JXG.createNormal=function(board,parents,attributes){var p,c,l,i,g,f,attr,pp,attrp;for(i=0;i<parents.length;++i)parents[i]=board.select(parents[i]);if(1===parents.length)p=parents[0],c=p.slideObject;else{if(2!==parents.length)throw new Error("JSXGraph: Can't create normal with parent types '"+_typeof(parents[0])+"' and '"+_typeof(parents[1])+"'.\nPossible parent types: [point,line], [point,circle], [glider]");if(Type.isPointType(board,parents[0]))p=Type.providePoints(board,[parents[0]],attributes,"point")[0],c=parents[1];else{if(!Type.isPointType(board,parents[1]))throw new Error("JSXGraph: Can't create normal with parent types '"+_typeof(parents[0])+"' and '"+_typeof(parents[1])+"'.\nPossible parent types: [point,line], [point,circle], [glider]");c=parents[0],p=Type.providePoints(board,[parents[1]],attributes,"point")[0]}}if(attr=Type.copyAttributes(attributes,board.options,"normal"),c.elementClass===Const.OBJECT_CLASS_LINE)attrp=Type.copyAttributes(attributes,board.options,"normal","point"),pp=board.create("point",[function(){var p=Mat.crossProduct([1,0,0],c.stdform);return[p[0],-p[2],p[1]]}],attrp),pp.isDraggable=!0,(l=board.create("line",[p,pp],attr)).point=pp,l.subs={point:pp},l.inherits.push(pp);else if(c.elementClass===Const.OBJECT_CLASS_CIRCLE)l=board.create("line",[c.midpoint,p],attr);else if(c.elementClass===Const.OBJECT_CLASS_CURVE)"plot"!==Type.evaluate(c.visProp.curvetype)?(g=c.X,f=c.Y,l=board.create("line",[function(){return-p.X()*Numerics.D(g)(p.position)-p.Y()*Numerics.D(f)(p.position)},function(){return Numerics.D(g)(p.position)},function(){return Numerics.D(f)(p.position)}],attr)):l=board.create("line",[function(){var p1,p2,t,A,B,C,D,dx,dy,d,i=Math.floor(p.position),lbda=p.position-i;if(1===c.bezierdegree)i===c.numberPoints-1&&(i-=1,lbda=1);else{if(3!==c.bezierDegree)return 0;i=3*Math.floor(p.position*(c.numberPoints-1)/3),t=(p.position*(c.numberPoints-1)-i)/3,i>=c.numberPoints-1&&(i=c.numberPoints-4,t=1)}return i<0?1:1===c.bezierDegree?(c.Y(i)+lbda*(c.Y(i+1)-c.Y(i)))*(c.Y(i)-c.Y(i+1))-(c.X(i)+lbda*(c.X(i+1)-c.X(i)))*(c.X(i+1)-c.X(i)):(A=c.points[i].usrCoords,B=c.points[i+1].usrCoords,C=c.points[i+2].usrCoords,D=c.points[i+3].usrCoords,dx=(1-t)*(1-t)*(B[1]-A[1])+2*(1-t)*t*(C[1]-B[1])+t*t*(D[1]-C[1]),dy=(1-t)*(1-t)*(B[2]-A[2])+2*(1-t)*t*(C[2]-B[2])+t*t*(D[2]-C[2]),dx/=d=Math.sqrt(dx*dx+dy*dy),dy/=d,p2=[1,(p1=p.coords.usrCoords)[1]-dy,p1[2]+dx],p1[2]*p2[1]-p1[1]*p2[2])},function(){var p1,t,A,B,C,D,dx,dy,d,i=Math.floor(p.position);if(1===c.bezierdegree)i===c.numberPoints-1&&(i-=1);else{if(3!==c.bezierDegree)return 0;i=3*Math.floor(p.position*(c.numberPoints-1)/3),t=(p.position*(c.numberPoints-1)-i)/3,i>=c.numberPoints-1&&(i=c.numberPoints-4,t=1)}return i<0?0:1===c.bezierDegree?c.X(i+1)-c.X(i):(A=c.points[i].usrCoords,B=c.points[i+1].usrCoords,C=c.points[i+2].usrCoords,D=c.points[i+3].usrCoords,dx=(1-t)*(1-t)*(B[1]-A[1])+2*(1-t)*t*(C[1]-B[1])+t*t*(D[1]-C[1]),dy=(1-t)*(1-t)*(B[2]-A[2])+2*(1-t)*t*(C[2]-B[2])+t*t*(D[2]-C[2]),dx/=d=Math.sqrt(dx*dx+dy*dy),dy/=d,[1,(p1=p.coords.usrCoords)[1]-dy,p1[2]+dx][2]-p1[2])},function(){var p1,p2,t,A,B,C,D,dx,dy,d,i=Math.floor(p.position);if(1===c.bezierdegree)i===c.numberPoints-1&&(i-=1);else{if(3!==c.bezierDegree)return 0;i=3*Math.floor(p.position*(c.numberPoints-1)/3),t=(p.position*(c.numberPoints-1)-i)/3,i>=c.numberPoints-1&&(i=c.numberPoints-4,t=1)}return i<0?0:1===c.bezierDegree?c.Y(i+1)-c.Y(i):(A=c.points[i].usrCoords,B=c.points[i+1].usrCoords,C=c.points[i+2].usrCoords,D=c.points[i+3].usrCoords,dx=(1-t)*(1-t)*(B[1]-A[1])+2*(1-t)*t*(C[1]-B[1])+t*t*(D[1]-C[1]),dy=(1-t)*(1-t)*(B[2]-A[2])+2*(1-t)*t*(C[2]-B[2])+t*t*(D[2]-C[2]),dx/=d=Math.sqrt(dx*dx+dy*dy),dy/=d,p2=[1,(p1=p.coords.usrCoords)[1]-dy,p1[2]+dx],p1[1]-p2[1])}],attr);else{if(c.type!==Const.OBJECT_TYPE_TURTLE)throw new Error("JSXGraph: Can't create normal with parent types '"+_typeof(parents[0])+"' and '"+_typeof(parents[1])+"'.\nPossible parent types: [point,line], [point,circle], [glider]");l=board.create("line",[function(){var el,j,i=Math.floor(p.position),lbda=p.position-i;for(j=0;j<c.objects.length;j++)if((el=c.objects[j]).type===Const.OBJECT_TYPE_CURVE){if(i<el.numberPoints)break;i-=el.numberPoints}return i===el.numberPoints-1&&(i-=1,lbda=1),i<0?1:(el.Y(i)+lbda*(el.Y(i+1)-el.Y(i)))*(el.Y(i)-el.Y(i+1))-(el.X(i)+lbda*(el.X(i+1)-el.X(i)))*(el.X(i+1)-el.X(i))},function(){var el,j,i=Math.floor(p.position);for(j=0;j<c.objects.length;j++)if((el=c.objects[j]).type===Const.OBJECT_TYPE_CURVE){if(i<el.numberPoints)break;i-=el.numberPoints}return i===el.numberPoints-1&&(i-=1),i<0?0:el.X(i+1)-el.X(i)},function(){var el,j,i=Math.floor(p.position);for(j=0;j<c.objects.length;j++)if((el=c.objects[j]).type===Const.OBJECT_TYPE_CURVE){if(i<el.numberPoints)break;i-=el.numberPoints}return i===el.numberPoints-1&&(i-=1),i<0?0:el.Y(i+1)-el.Y(i)}],attr)}return l.elType="normal",l.setParents(parents),Type.exists(p._is_new)?(l.addChild(p),delete p._is_new):p.addChild(l),c.addChild(l),l},JXG.createBisector=function(board,parents,attributes){var p,l,i,attr;if(parents=Type.providePoints(board,parents,attributes,"point"),Type.isPoint(parents[0])&&Type.isPoint(parents[1])&&Type.isPoint(parents[2])){for((attr=Type.copyAttributes(attributes,board.options,"bisector","point")).snapToGrid=!1,(p=board.create("point",[function(){return Geometry.angleBisector(parents[0],parents[1],parents[2],board)}],attr)).dump=!1,i=0;i<3;i++)Type.exists(parents[i]._is_new)?(p.addChild(parents[i]),delete parents[i]._is_new):parents[i].addChild(p);return Type.exists(attributes.layer)||(attributes.layer=board.options.layer.line),attr=Type.copyAttributes(attributes,board.options,"bisector"),(l=Line.createLine(board,[parents[1],p],attr)).point=p,l.elType="bisector",l.setParents(parents),l.subs={point:p},l.inherits.push(p),l}throw new Error("JSXGraph: Can't create angle bisector with parent types '"+_typeof(parents[0])+"' and '"+_typeof(parents[1])+"'.\nPossible parent types: [point,point,point]")},JXG.createAngularBisectorsOfTwoLines=function(board,parents,attributes){var g1,g2,attr,ret,l1=board.select(parents[0]),l2=board.select(parents[1]);if(l1.elementClass!==Const.OBJECT_CLASS_LINE||l2.elementClass!==Const.OBJECT_CLASS_LINE)throw new Error("JSXGraph: Can't create angle bisectors of two lines with parent types '"+_typeof(parents[0])+"' and '"+_typeof(parents[1])+"'.\nPossible parent types: [line,line]");return Type.exists(attributes.layer)||(attributes.layer=board.options.layer.line),attr=Type.copyAttributes(attributes,board.options,"bisectorlines","line1"),g1=board.create("line",[function(){var d1=Math.sqrt(l1.stdform[1]*l1.stdform[1]+l1.stdform[2]*l1.stdform[2]),d2=Math.sqrt(l2.stdform[1]*l2.stdform[1]+l2.stdform[2]*l2.stdform[2]);return l1.stdform[0]/d1-l2.stdform[0]/d2},function(){var d1=Math.sqrt(l1.stdform[1]*l1.stdform[1]+l1.stdform[2]*l1.stdform[2]),d2=Math.sqrt(l2.stdform[1]*l2.stdform[1]+l2.stdform[2]*l2.stdform[2]);return l1.stdform[1]/d1-l2.stdform[1]/d2},function(){var d1=Math.sqrt(l1.stdform[1]*l1.stdform[1]+l1.stdform[2]*l1.stdform[2]),d2=Math.sqrt(l2.stdform[1]*l2.stdform[1]+l2.stdform[2]*l2.stdform[2]);return l1.stdform[2]/d1-l2.stdform[2]/d2}],attr),Type.exists(attributes.layer)||(attributes.layer=board.options.layer.line),attr=Type.copyAttributes(attributes,board.options,"bisectorlines","line2"),g2=board.create("line",[function(){var d1=Math.sqrt(l1.stdform[1]*l1.stdform[1]+l1.stdform[2]*l1.stdform[2]),d2=Math.sqrt(l2.stdform[1]*l2.stdform[1]+l2.stdform[2]*l2.stdform[2]);return l1.stdform[0]/d1+l2.stdform[0]/d2},function(){var d1=Math.sqrt(l1.stdform[1]*l1.stdform[1]+l1.stdform[2]*l1.stdform[2]),d2=Math.sqrt(l2.stdform[1]*l2.stdform[1]+l2.stdform[2]*l2.stdform[2]);return l1.stdform[1]/d1+l2.stdform[1]/d2},function(){var d1=Math.sqrt(l1.stdform[1]*l1.stdform[1]+l1.stdform[2]*l1.stdform[2]),d2=Math.sqrt(l2.stdform[1]*l2.stdform[1]+l2.stdform[2]*l2.stdform[2]);return l1.stdform[2]/d1+l2.stdform[2]/d2}],attr),ret=new Composition({line1:g1,line2:g2}),g1.dump=!1,g2.dump=!1,ret.elType="bisectorlines",ret.setParents([l1.id,l2.id]),ret.subs={line1:g1,line2:g2},ret},JXG.createCircumcenter=function(board,parents,attributes){var p,i,a,b,c;if(parents=Type.providePoints(board,parents,attributes,"point"),Type.isPoint(parents[0])&&Type.isPoint(parents[1])&&Type.isPoint(parents[2])){for(a=parents[0],b=parents[1],c=parents[2],p=Point.createPoint(board,[function(){return Geometry.circumcenter(a,b,c,board)}],attributes),i=0;i<3;i++)Type.exists(parents[i]._is_new)?(p.addChild(parents[i]),delete parents[i]._is_new):parents[i].addChild(p);return p.elType="circumcenter",p.setParents(parents),p.generatePolynomial=function(){var a1=a.symbolic.x,a2=a.symbolic.y,b1=b.symbolic.x,b2=b.symbolic.y,c1=c.symbolic.x,c2=c.symbolic.y,t1=p.symbolic.x,t2=p.symbolic.y;return[["((",t1,")-(",a1,"))^2+((",t2,")-(",a2,"))^2-((",t1,")-(",b1,"))^2-((",t2,")-(",b2,"))^2"].join(""),["((",t1,")-(",a1,"))^2+((",t2,")-(",a2,"))^2-((",t1,")-(",c1,"))^2-((",t2,")-(",c2,"))^2"].join("")]},p}throw new Error("JSXGraph: Can't create circumcircle midpoint with parent types '"+_typeof(parents[0])+"', '"+_typeof(parents[1])+"' and '"+_typeof(parents[2])+"'.\nPossible parent types: [point,point,point]")},JXG.createIncenter=function(board,parents,attributes){var p,A,B,C,i;if(!((parents=Type.providePoints(board,parents,attributes,"point")).length>=3&&Type.isPoint(parents[0])&&Type.isPoint(parents[1])&&Type.isPoint(parents[2])))throw new Error("JSXGraph: Can't create incenter with parent types '"+_typeof(parents[0])+"', '"+_typeof(parents[1])+"' and '"+_typeof(parents[2])+"'.\nPossible parent types: [point,point,point]");for(A=parents[0],B=parents[1],C=parents[2],p=board.create("point",[function(){var a,b,c;return a=Math.sqrt((B.X()-C.X())*(B.X()-C.X())+(B.Y()-C.Y())*(B.Y()-C.Y())),b=Math.sqrt((A.X()-C.X())*(A.X()-C.X())+(A.Y()-C.Y())*(A.Y()-C.Y())),c=Math.sqrt((B.X()-A.X())*(B.X()-A.X())+(B.Y()-A.Y())*(B.Y()-A.Y())),new Coords(Const.COORDS_BY_USER,[(a*A.X()+b*B.X()+c*C.X())/(a+b+c),(a*A.Y()+b*B.Y()+c*C.Y())/(a+b+c)],board)}],attributes),i=0;i<3;i++)Type.exists(parents[i]._is_new)?(p.addChild(parents[i]),delete parents[i]._is_new):parents[i].addChild(p);return p.elType="incenter",p.setParents(parents),p},JXG.createCircumcircle=function(board,parents,attributes){var p,c,attr,i;if(!1===(parents=Type.providePoints(board,parents,attributes,"point")))throw new Error("JSXGraph: Can't create circumcircle with parent types '"+_typeof(parents[0])+"', '"+_typeof(parents[1])+"' and '"+_typeof(parents[2])+"'.\nPossible parent types: [point,point,point]");try{for(attr=Type.copyAttributes(attributes,board.options,"circumcircle","center"),(p=JXG.createCircumcenter(board,parents,attr)).dump=!1,Type.exists(attributes.layer)||(attributes.layer=board.options.layer.circle),attr=Type.copyAttributes(attributes,board.options,"circumcircle"),(c=Circle.createCircle(board,[p,parents[0]],attr)).elType="circumcircle",c.setParents(parents),c.subs={center:p},c.inherits.push(c),i=0;i<3;i++)Type.exists(parents[i]._is_new)?(c.addChild(parents[i]),delete parents[i]._is_new):parents[i].addChild(c)}catch(e){throw new Error("JSXGraph: Can't create circumcircle with parent types '"+_typeof(parents[0])+"', '"+_typeof(parents[1])+"' and '"+_typeof(parents[2])+"'.\nPossible parent types: [point,point,point]")}return c},JXG.createIncircle=function(board,parents,attributes){var i,p,c,attr;if(!1===(parents=Type.providePoints(board,parents,attributes,"point")))throw new Error("JSXGraph: Can't create circumcircle with parent types '"+_typeof(parents[0])+"', '"+_typeof(parents[1])+"' and '"+_typeof(parents[2])+"'.\nPossible parent types: [point,point,point]");try{for(attr=Type.copyAttributes(attributes,board.options,"incircle","center"),(p=JXG.createIncenter(board,parents,attr)).dump=!1,Type.exists(attributes.layer)||(attributes.layer=board.options.layer.circle),attr=Type.copyAttributes(attributes,board.options,"incircle"),(c=Circle.createCircle(board,[p,function(){var a=Math.sqrt((parents[1].X()-parents[2].X())*(parents[1].X()-parents[2].X())+(parents[1].Y()-parents[2].Y())*(parents[1].Y()-parents[2].Y())),b=Math.sqrt((parents[0].X()-parents[2].X())*(parents[0].X()-parents[2].X())+(parents[0].Y()-parents[2].Y())*(parents[0].Y()-parents[2].Y())),c=Math.sqrt((parents[1].X()-parents[0].X())*(parents[1].X()-parents[0].X())+(parents[1].Y()-parents[0].Y())*(parents[1].Y()-parents[0].Y())),s=(a+b+c)/2;return Math.sqrt((s-a)*(s-b)*(s-c)/s)}],attr)).elType="incircle",c.setParents(parents),i=0;i<3;i++)Type.exists(parents[i]._is_new)?(c.addChild(parents[i]),delete parents[i]._is_new):parents[i].addChild(c);c.center=p,c.subs={center:c.center},c.inherits.push(p)}catch(e){throw new Error("JSXGraph: Can't create circumcircle with parent types '"+_typeof(parents[0])+"', '"+_typeof(parents[1])+"' and '"+_typeof(parents[2])+"'.\nPossible parent types: [point,point,point]")}return c},JXG.createReflection=function(board,parents,attributes){var l,org,r,r_c,t,i,attr,attr2,errStr="\nPossible parent types: [point|line|curve|polygon|circle|arc|sector, line]";for(i=0;i<parents.length;++i)parents[i]=board.select(parents[i]);if(attr=Type.copyAttributes(attributes,board.options,"reflection"),Type.isPoint(parents[0]))org=Type.providePoints(board,[parents[0]],attr2)[0];else{if(parents[0].elementClass!==Const.OBJECT_CLASS_CURVE&&parents[0].elementClass!==Const.OBJECT_CLASS_LINE&&parents[0].type!==Const.OBJECT_TYPE_POLYGON&&parents[0].elementClass!==Const.OBJECT_CLASS_CIRCLE)throw new Error("JSXGraph: Can't create reflection element with parent types '"+_typeof(parents[0])+"' and '"+_typeof(parents[1])+"'."+errStr);org=parents[0]}if(parents[1].elementClass!==Const.OBJECT_CLASS_LINE)throw new Error("JSXGraph: Can't create reflected element with parent types '"+_typeof(parents[0])+"' and '"+_typeof(parents[1])+"'."+errStr);if(l=parents[1],t=Transform.createTransform(board,[l],{type:"reflect"}),Type.isPoint(org))r=Point.createPoint(board,[org,t],attr);else if(org.elementClass===Const.OBJECT_CLASS_CURVE)r=Curve.createCurve(board,[org,t],attr);else if(org.elementClass===Const.OBJECT_CLASS_LINE)r=Line.createLine(board,[org,t],attr);else if(org.type===Const.OBJECT_TYPE_POLYGON)r=Polygon.createPolygon(board,[org,t],attr);else{if(org.elementClass!==Const.OBJECT_CLASS_CIRCLE)throw new Error("JSXGraph: Can't create reflected element with parent types '"+_typeof(parents[0])+"' and '"+_typeof(parents[1])+"'."+errStr);"euclidean"===attr.type.toLowerCase()?(attr2=Type.copyAttributes(attributes,board.options,"reflection","center"),(r_c=Point.createPoint(board,[org.center,t],attr2)).prepareUpdate().update().updateVisibility(Type.evaluate(r_c.visProp.visible)).updateRenderer(),r=Circle.createCircle(board,[r_c,function(){return org.Radius()}],attr)):r=Circle.createCircle(board,[org,t],attr)}return Type.exists(org._is_new)&&(r.addChild(org),delete org._is_new),l.addChild(r),r.elType="reflection",r.addParents(l),r.prepareUpdate().update(),Type.isPoint(r)&&(r.generatePolynomial=function(){var a1=l.point1.symbolic.x,a2=l.point1.symbolic.y,b1=l.point2.symbolic.x,b2=l.point2.symbolic.y,p1=org.symbolic.x,p2=org.symbolic.y,r1=r.symbolic.x,r2=r.symbolic.y;return[["((",r2,")-(",p2,"))*((",a2,")-(",b2,"))+((",a1,")-(",b1,"))*((",r1,")-(",p1,"))"].join(""),["((",r1,")-(",a1,"))^2+((",r2,")-(",a2,"))^2-((",p1,")-(",a1,"))^2-((",p2,")-(",a2,"))^2"].join("")]}),r},JXG.createMirrorElement=function(board,parents,attributes){var org,i,m,r,r_c,t,attr,attr2,errStr="\nPossible parent types: [point|line|curve|polygon|circle|arc|sector, point]";for(i=0;i<parents.length;++i)parents[i]=board.select(parents[i]);if(attr=Type.copyAttributes(attributes,board.options,"mirrorelement"),Type.isPoint(parents[0]))org=Type.providePoints(board,[parents[0]],attr)[0];else{if(parents[0].elementClass!==Const.OBJECT_CLASS_CURVE&&parents[0].elementClass!==Const.OBJECT_CLASS_LINE&&parents[0].type!==Const.OBJECT_TYPE_POLYGON&&parents[0].elementClass!==Const.OBJECT_CLASS_CIRCLE)throw new Error("JSXGraph: Can't create mirror element with parent types '"+_typeof(parents[0])+"' and '"+_typeof(parents[1])+"'."+errStr);org=parents[0]}if(!Type.isPoint(parents[1]))throw new Error("JSXGraph: Can't create mirror element with parent types '"+_typeof(parents[0])+"' and '"+_typeof(parents[1])+"'."+errStr);if(attr2=Type.copyAttributes(attributes,board.options,"mirrorelement","point"),m=Type.providePoints(board,[parents[1]],attr2)[0],t=Transform.createTransform(board,[Math.PI,m],{type:"rotate"}),Type.isPoint(org))r=Point.createPoint(board,[org,t],attr);else if(org.elementClass===Const.OBJECT_CLASS_CURVE)r=Curve.createCurve(board,[org,t],attr);else if(org.elementClass===Const.OBJECT_CLASS_LINE)r=Line.createLine(board,[org,t],attr);else if(org.type===Const.OBJECT_TYPE_POLYGON)r=Polygon.createPolygon(board,[org,t],attr);else{if(org.elementClass!==Const.OBJECT_CLASS_CIRCLE)throw new Error("JSXGraph: Can't create mirror element with parent types '"+_typeof(parents[0])+"' and '"+_typeof(parents[1])+"'."+errStr);"euclidean"===attr.type.toLowerCase()?(attr2=Type.copyAttributes(attributes,board.options,"mirrorelement","center"),(r_c=Point.createPoint(board,[org.center,t],attr2)).prepareUpdate().update().updateVisibility(Type.evaluate(r_c.visProp.visible)).updateRenderer(),r=Circle.createCircle(board,[r_c,function(){return org.Radius()}],attr)):r=Circle.createCircle(board,[org,t],attr)}return Type.exists(org._is_new)&&(r.addChild(org),delete org._is_new),m.addChild(r),r.elType="mirrorelement",r.addParents(m),r.prepareUpdate().update(),r},JXG.createMirrorPoint=function(board,parents,attributes){var el=JXG.createMirrorElement(board,parents,attributes);return el.elType="mirrorpoint",el},JXG.createIntegral=function(board,parents,attributes){var interval,curve,attr,start,end,startx,starty,endx,endy,pa_on_curve,pa_on_axis,pb_on_curve,pb_on_axis,p,t=null;if(Type.isArray(parents[0])&&parents[1].elementClass===Const.OBJECT_CLASS_CURVE)interval=parents[0],curve=parents[1];else{if(!Type.isArray(parents[1])||parents[0].elementClass!==Const.OBJECT_CLASS_CURVE)throw new Error("JSXGraph: Can't create integral with parent types '"+_typeof(parents[0])+"' and '"+_typeof(parents[1])+"'.\nPossible parent types: [[number|function,number|function],curve]");interval=parents[1],curve=parents[0]}return(attr=Type.copyAttributes(attributes,board.options,"integral")).withLabel=!1,p=board.create("curve",[[0],[0]],attr),start=interval[0],end=interval[1],Type.isFunction(start)?(starty=function(){return curve.Y(startx())},start=(startx=start)()):(startx=start,starty=curve.Y(start)),Type.isFunction(end)?(endy=function(){return curve.Y(endx())},end=(endx=end)()):(endx=end,endy=curve.Y(end)),attr=Type.copyAttributes(attributes,board.options,"integral","curveLeft"),pa_on_curve=board.create("glider",[startx,starty,curve],attr),Type.isFunction(startx)&&pa_on_curve.hideElement(),attr=Type.copyAttributes(attributes,board.options,"integral","baseLeft"),pa_on_axis=board.create("point",[function(){return"y"===Type.evaluate(p.visProp.axis)?0:pa_on_curve.X()},function(){return"y"===Type.evaluate(p.visProp.axis)?pa_on_curve.Y():0}],attr),attr=Type.copyAttributes(attributes,board.options,"integral","curveRight"),pb_on_curve=board.create("glider",[endx,endy,curve],attr),Type.isFunction(endx)&&pb_on_curve.hideElement(),attr=Type.copyAttributes(attributes,board.options,"integral","baseRight"),pb_on_axis=board.create("point",[function(){return"y"===Type.evaluate(p.visProp.axis)?0:pb_on_curve.X()},function(){return"y"===Type.evaluate(p.visProp.axis)?pb_on_curve.Y():0}],attr),!1!==(attr=Type.copyAttributes(attributes,board.options,"integral")).withlabel&&"y"!==attr.axis&&(attr=Type.copyAttributes(attributes,board.options,"integral","label"),attr=Type.copyAttributes(attr,board.options,"label"),(t=board.create("text",[function(){var off=new Coords(Const.COORDS_BY_SCREEN,[Type.evaluate(this.visProp.offset[0])+this.board.origin.scrCoords[1],0],this.board,!1),bb=this.board.getBoundingBox(),dx=.1*(bb[2]-bb[0]),x=pb_on_curve.X();return x<bb[0]?x=bb[0]+dx:x>bb[2]&&(x=bb[2]-dx),x+off.usrCoords[1]},function(){var off=new Coords(Const.COORDS_BY_SCREEN,[0,Type.evaluate(this.visProp.offset[1])+this.board.origin.scrCoords[2]],this.board,!1),bb=this.board.getBoundingBox(),dy=.1*(bb[1]-bb[3]),y=pb_on_curve.Y();return y>bb[1]?y=bb[1]-dy:y<bb[3]&&(y=bb[3]+dy),y+off.usrCoords[2]},function(){var Int=Numerics.NewtonCotes([pa_on_axis.X(),pb_on_axis.X()],curve.Y);return"∫ = "+Type.toFixed(Int,4)}],attr)).dump=!1,pa_on_curve.addChild(t),pb_on_curve.addChild(t)),pa_on_curve.dump=!1,pa_on_axis.dump=!1,pb_on_curve.dump=!1,pb_on_axis.dump=!1,p.elType="integral",p.setParents([curve.id,interval]),p.subs={curveLeft:pa_on_curve,baseLeft:pa_on_axis,curveRight:pb_on_curve,baseRight:pb_on_axis},p.inherits.push(pa_on_curve,pa_on_axis,pb_on_curve,pb_on_axis),attr.withLabel&&(p.subs.label=t,p.inherits.push(t)),p.Value=function(){return Numerics.I([pa_on_axis.X(),pb_on_axis.X()],curve.Y)},p.updateDataArray=function(){var x,y,i,left,right,lowx,upx,lowy,upy;if("y"===Type.evaluate(this.visProp.axis)){for(pa_on_curve.Y()<pb_on_curve.Y()?(lowx=pa_on_curve.X(),lowy=pa_on_curve.Y(),upx=pb_on_curve.X(),upy=pb_on_curve.Y()):(lowx=pb_on_curve.X(),lowy=pb_on_curve.Y(),upx=pa_on_curve.X(),upy=pa_on_curve.Y()),left=Math.min(lowx,upx),right=Math.max(lowx,upx),x=[0,lowx],y=[lowy,lowy],i=0;i<curve.numberPoints;i++)lowy<=curve.points[i].usrCoords[2]&&left<=curve.points[i].usrCoords[1]&&curve.points[i].usrCoords[2]<=upy&&curve.points[i].usrCoords[1]<=right&&(x.push(curve.points[i].usrCoords[1]),y.push(curve.points[i].usrCoords[2]));x.push(upx),y.push(upy),x.push(0),y.push(upy),x.push(0),y.push(lowy)}else{for(pa_on_axis.X()<pb_on_axis.X()?(left=pa_on_axis.X(),right=pb_on_axis.X()):(left=pb_on_axis.X(),right=pa_on_axis.X()),x=[left,left],y=[0,curve.Y(left)],i=0;i<curve.numberPoints;i++)left<=curve.points[i].usrCoords[1]&&curve.points[i].usrCoords[1]<=right&&(x.push(curve.points[i].usrCoords[1]),y.push(curve.points[i].usrCoords[2]));x.push(right),y.push(curve.Y(right)),x.push(right),y.push(0),x.push(left),y.push(0)}this.dataX=x,this.dataY=y},pa_on_curve.addChild(p),pb_on_curve.addChild(p),pa_on_axis.addChild(p),pb_on_axis.addChild(p),p.baseLeft=pa_on_axis,p.baseRight=pb_on_axis,p.curveLeft=pa_on_curve,p.curveRight=pb_on_curve,p.methodMap=JXG.deepCopy(p.methodMap,{curveLeft:"curveLeft",baseLeft:"baseLeft",curveRight:"curveRight",baseRight:"baseRight",Value:"Value"}),p.label=t,p},JXG.createGrid=function(board,parents,attributes){var c,attr;return attr=Type.copyAttributes(attributes,board.options,"grid"),(c=board.create("curve",[[null],[null]],attr)).elType="grid",c.type=Const.OBJECT_TYPE_GRID,c.updateDataArray=function(){var start,end,i,topLeft,bottomRight,gridX=Type.evaluate(this.visProp.gridx),gridY=Type.evaluate(this.visProp.gridy);for(topLeft=Type.isArray(this.visProp.topleft)?new Coords(Type.evaluate(this.visProp.tltype)||Const.COORDS_BY_USER,this.visProp.topleft,board):new Coords(Const.COORDS_BY_SCREEN,[0,0],board),bottomRight=Type.isArray(this.visProp.bottomright)?new Coords(Type.evaluate(this.visProp.brtype)||Const.COORDS_BY_USER,this.visProp.bottomright,board):new Coords(Const.COORDS_BY_SCREEN,[board.canvasWidth,board.canvasHeight],board),board.options.grid.hasGrid=!0,c.dataX=[],c.dataY=[],start=Math.floor(topLeft.usrCoords[2]/gridY)*gridY,end=Math.ceil(bottomRight.usrCoords[2]/gridY)*gridY,topLeft.usrCoords[2]<bottomRight.usrCoords[2]&&(start=Math.ceil(bottomRight.usrCoords[2]/gridY)*gridY,end=Math.floor(topLeft.usrCoords[2]/gridY)*gridY),i=start;i>end-gridY;i-=gridY)c.dataX.push(topLeft.usrCoords[1],bottomRight.usrCoords[1],NaN),c.dataY.push(i,i,NaN);for(start=Math.ceil(topLeft.usrCoords[1]/gridX)*gridX,end=Math.floor(bottomRight.usrCoords[1]/gridX)*gridX,topLeft.usrCoords[1]>bottomRight.usrCoords[1]&&(start=Math.floor(bottomRight.usrCoords[1]/gridX)*gridX,end=Math.ceil(topLeft.usrCoords[1]/gridX)*gridX),i=start;i<end+gridX;i+=gridX)c.dataX.push(i,i,NaN),c.dataY.push(topLeft.usrCoords[2],bottomRight.usrCoords[2],NaN)},c.hasPoint=function(){return!1},board.grids.push(c),c},JXG.createInequality=function(board,parents,attributes){var f,a,attr;if(attr=Type.copyAttributes(attributes,board.options,"inequality"),parents[0].elementClass===Const.OBJECT_CLASS_LINE)(a=board.create("curve",[[],[]],attr)).hasPoint=function(){return!1},a.updateDataArray=function(){var i1,i2,h,bb=board.getBoundingBox(),factor=attr.inverse?-1:1,w=1.5*Math.max(bb[2]-bb[0],bb[1]-bb[3]),dp={coords:{usrCoords:[1,(bb[0]+bb[2])/2,attr.inverse?bb[1]:bb[3]]}},slope1=parents[0].stdform.slice(1),slope2=slope1;h=1.5*Math.max(Geometry.perpendicular(parents[0],dp,board)[0].distance(Const.COORDS_BY_USER,dp.coords),w),h*=factor,dp={coords:{usrCoords:[1,(bb[0]+bb[2])/2,(bb[1]+bb[3])/2]}},i1=[1,(dp=Math.abs(Mat.innerProduct(dp.coords.usrCoords,parents[0].stdform,3))>=Mat.eps?Geometry.perpendicular(parents[0],dp,board)[0].usrCoords:dp.coords.usrCoords)[1]+slope1[1]*w,dp[2]-slope1[0]*w],i2=[1,dp[1]-slope2[1]*w,dp[2]+slope2[0]*w],this.dataX=[i1[1],i1[1]+slope1[0]*h,i2[1]+slope2[0]*h,i2[1],i1[1]],this.dataY=[i1[2],i1[2]+slope1[1]*h,i2[2]+slope2[1]*h,i2[2],i1[2]]};else if(parents[0].elementClass===Const.OBJECT_CLASS_CURVE&&"functiongraph"===parents[0].visProp.curvetype)(a=board.create("curve",[[],[]],attr)).updateDataArray=function(){var infty,first,last,len,i,curve_mi,curve_ma,firstx,lastx,bbox=this.board.getBoundingBox(),points=[],mi=parents[0].minX(),ma=parents[0].maxX(),enlarge=.3*(bbox[1]-bbox[3]);if(infty=Type.evaluate(this.visProp.inverse)?1:3,this.dataX=[],this.dataY=[],0!==(len=parents[0].points.length))for(bbox[1]+=enlarge,bbox[3]-=enlarge,last=-1;last<len-1;){for(i=last+1,first=len;i<len;i++)if(parents[0].points[i].isReal()){first=i;break}if(first>=len)break;for(i=first,last=len-1;i<len-1;i++)if(!parents[0].points[i+1].isReal()){last=i;break}for(firstx=parents[0].points[first].usrCoords[1],lastx=parents[0].points[last].usrCoords[1],curve_mi=bbox[0]<mi?mi:bbox[0],curve_ma=bbox[2]>ma?ma:bbox[2],curve_mi=0===first?curve_mi:Math.max(curve_mi,firstx),curve_ma=last===len-1?curve_ma:Math.min(curve_ma,lastx),curve_ma=last===len-1?ma:lastx,(points=[]).push([1,curve_mi=0===first?mi:firstx,bbox[infty]]),points.push([1,curve_mi,parents[0].points[first].usrCoords[2]]),i=first;i<=last;i++)points.push(parents[0].points[i].usrCoords);for(points.push([1,curve_ma,parents[0].points[last].usrCoords[2]]),points.push([1,curve_ma,bbox[infty]]),points.push(points[0]),i=0;i<points.length;i++)this.dataX.push(points[i][1]),this.dataY.push(points[i][2]);last<len-1&&(this.dataX.push(NaN),this.dataY.push(NaN))}},a.hasPoint=function(){return!1};else if(f=Type.createFunction(parents[0]),!Type.exists(f))throw new Error("JSXGraph: Can't create area with the given parents.\nPossible parent types: [line], [function]");return a.addParents(parents[0]),a},JXG.registerElement("arrowparallel",JXG.createArrowParallel),JXG.registerElement("bisector",JXG.createBisector),JXG.registerElement("bisectorlines",JXG.createAngularBisectorsOfTwoLines),JXG.registerElement("msector",JXG.createMsector),JXG.registerElement("circumcircle",JXG.createCircumcircle),JXG.registerElement("circumcirclemidpoint",JXG.createCircumcenter),JXG.registerElement("circumcenter",JXG.createCircumcenter),JXG.registerElement("incenter",JXG.createIncenter),JXG.registerElement("incircle",JXG.createIncircle),JXG.registerElement("integral",JXG.createIntegral),JXG.registerElement("midpoint",JXG.createMidpoint),JXG.registerElement("mirrorelement",JXG.createMirrorElement),JXG.registerElement("mirrorpoint",JXG.createMirrorPoint),JXG.registerElement("normal",JXG.createNormal),JXG.registerElement("orthogonalprojection",JXG.createOrthogonalProjection),JXG.registerElement("parallel",JXG.createParallel),JXG.registerElement("parallelpoint",JXG.createParallelPoint),JXG.registerElement("perpendicular",JXG.createPerpendicular),JXG.registerElement("perpendicularpoint",JXG.createPerpendicularPoint),JXG.registerElement("perpendicularsegment",JXG.createPerpendicularSegment),JXG.registerElement("reflection",JXG.createReflection),JXG.registerElement("grid",JXG.createGrid),JXG.registerElement("inequality",JXG.createInequality),{createArrowParallel:JXG.createArrowParallel,createBisector:JXG.createBisector,createAngularBisectorOfTwoLines:JXG.createAngularBisectorsOfTwoLines,createCircumcircle:JXG.createCircumcircle,createCircumcenter:JXG.createCircumcenter,createIncenter:JXG.createIncenter,createIncircle:JXG.createIncircle,createIntegral:JXG.createIntegral,createMidpoint:JXG.createMidpoint,createMirrorElement:JXG.createMirrorElement,createMirrorPoint:JXG.createMirrorPoint,createNormal:JXG.createNormal,createOrthogonalProjection:JXG.createOrthogonalProjection,createParallel:JXG.createParallel,createParallelPoint:JXG.createParallelPoint,createPerpendicular:JXG.createPerpendicular,createPerpendicularPoint:JXG.createPerpendicularPoint,createPerpendicularSegmen:JXG.createPerpendicularSegment,createReflection:JXG.createReflection,createGrid:JXG.createGrid,createInequality:JXG.createInequality}})),define("element/locus",["jxg","math/symbolic","utils/type"],(function(JXG,Symbolic,Type){return JXG.createLocus=function(board,parents,attributes){var c,p;if(!Type.isArray(parents)||1!==parents.length||!Type.isPoint(parents[0]))throw new Error("JSXGraph: Can't create locus with parent of type other than point.\nPossible parent types: [point]");return p=parents[0],(c=board.create("curve",[[null],[null]],attributes)).dontCallServer=!1,c.elType="locus",c.setParents([p.id]),c.updateDataArray=function(){var spe,cb,data;c.board.mode>0||(spe=Symbolic.generatePolynomials(board,p,!0).join("|"))!==c.spe&&(c.spe=spe,(cb=function(x,y,eq,t){var equations;c.dataX=x,c.dataY=y,c.eq=eq,c.ctime=t,c.generatePolynomial=(equations=eq,function(point){var i,x="("+point.symbolic.x+")",y="("+point.symbolic.y+")",res=[];for(i=0;i<equations.length;i++)res[i]=equations[i].replace(/\*\*/g,"^").replace(/x/g,x).replace(/y/g,y);return res})})((data=Symbolic.geometricLocusByGroebnerBase(board,p,cb)).datax,data.datay,data.polynomial,data.exectime))},c},JXG.registerElement("locus",JXG.createLocus),{createLocus:JXG.createLocus}})),define("base/image",["jxg","base/constants","base/coords","base/element","math/math","utils/type","base/coordselement"],(function(JXG,Const,Coords,GeometryElement,Mat,Type,CoordsElement){return JXG.Image=function(board,coords,attributes,url,size){this.constructor(board,attributes,Const.OBJECT_TYPE_IMAGE,Const.OBJECT_CLASS_OTHER),this.element=this.board.select(attributes.anchor),this.coordsConstructor(coords),this.W=Type.createFunction(size[0],this.board,""),this.H=Type.createFunction(size[1],this.board,""),this.usrSize=[this.W(),this.H()],this.size=[Math.abs(this.usrSize[0]*board.unitX),Math.abs(this.usrSize[1]*board.unitY)],this.url=url,this.elType="image",this.span=[this.coords.usrCoords.slice(0),[this.coords.usrCoords[0],this.W(),0],[this.coords.usrCoords[0],0,this.H()]],this.id=this.board.setId(this,"Im"),this.board.renderer.drawImage(this),this.board.finalizeAdding(this),this.methodMap=JXG.deepCopy(this.methodMap,{addTransformation:"addTransform",trans:"addTransform"})},JXG.Image.prototype=new GeometryElement,Type.copyPrototypeMethods(JXG.Image,CoordsElement,"coordsConstructor"),JXG.extend(JXG.Image.prototype,{hasPoint:function(x,y){var dx,dy,r,type,prec,c,v,p,dot,len=this.transformations.length;return Type.isObject(Type.evaluate(this.visProp.precision))?(type=this.board._inputDevice,prec=Type.evaluate(this.visProp.precision[type])):prec=this.board.options.precision.hasPoint,0===len?(dx=x-this.coords.scrCoords[1],dy=this.coords.scrCoords[2]-y,dx>=-(r=prec)&&dx-this.size[0]<=r&&dy>=-r&&dy-this.size[1]<=r):(v=[(c=(c=new Coords(Const.COORDS_BY_SCREEN,[x,y],this.board)).usrCoords)[0]-this.span[0][0],c[1]-this.span[0][1],c[2]-this.span[0][2]],0<=(p=(dot=Mat.innerProduct)(v,this.span[1]))&&p<=dot(this.span[1],this.span[1])&&0<=(p=dot(v,this.span[2]))&&p<=dot(this.span[2],this.span[2]))},update:function(fromParent){return this.needsUpdate?(this.updateCoords(fromParent),this.updateSize(),this.updateSpan(),this):this},updateRenderer:function(){return this.updateRendererGeneric("updateImage")},updateSize:function(){return this.usrSize=[this.W(),this.H()],this.size=[Math.abs(this.usrSize[0]*this.board.unitX),Math.abs(this.usrSize[1]*this.board.unitY)],this},updateSpan:function(){var i,j,len=this.transformations.length,v=[];if(0===len)this.span=[[this.Z(),this.X(),this.Y()],[this.Z(),this.W(),0],[this.Z(),0,this.H()]];else{for(v[0]=[this.Z(),this.X(),this.Y()],v[1]=[this.Z(),this.X()+this.W(),this.Y()],v[2]=[this.Z(),this.X(),this.Y()+this.H()],i=0;i<len;i++)for(j=0;j<3;j++)v[j]=Mat.matVecMult(this.transformations[i].matrix,v[j]);for(j=0;j<3;j++)v[j][1]/=v[j][0],v[j][2]/=v[j][0],v[j][0]/=v[j][0];for(j=1;j<3;j++)v[j][0]-=v[0][0],v[j][1]-=v[0][1],v[j][2]-=v[0][2];this.span=v}return this},addTransform:function(transform){var i;if(Type.isArray(transform))for(i=0;i<transform.length;i++)this.transformations.push(transform[i]);else this.transformations.push(transform);return this},getParents:function(){var p=[this.url,[this.Z(),this.X(),this.Y()],this.usrSize];return 0!==this.parents.length&&(p=this.parents),p},setSize:function(width,height){return this.W=Type.createFunction(width,this.board,""),this.H=Type.createFunction(height,this.board,""),this},W:function(){},H:function(){}}),JXG.createImage=function(board,parents,attributes){var attr,im,url=parents[0],coords=parents[1],size=parents[2];if(attr=Type.copyAttributes(attributes,board.options,"image"),!(im=CoordsElement.create(JXG.Image,board,coords,attr,url,size)))throw new Error("JSXGraph: Can't create image with parent types '"+_typeof(parents[0])+"' and '"+_typeof(parents[1])+"'.\nPossible parent types: [x,y], [z,x,y], [element,transformation]");return 0!==attr.rotate&&im.addRotation(attr.rotate),im},JXG.registerElement("image",JXG.createImage),{Image:JXG.Image,createImage:JXG.createImage}})),define("element/slider",["jxg","math/math","base/constants","base/coords","utils/type","base/point"],(function(JXG,Mat,Const,Coords,Type,Point){return JXG.createSlider=function(board,parents,attributes){var pos0,pos1,smin,start,smax,sdiff,p1,p2,l1,ti,startx,starty,p3,l2,t,withText,withTicks,snapWidth,sw,s,attr;return withTicks=(attr=Type.copyAttributes(attributes,board.options,"slider")).withticks,withText=attr.withlabel,snapWidth=attr.snapwidth,attr=Type.copyAttributes(attributes,board.options,"slider","point1"),p1=board.create("point",parents[0],attr),attr=Type.copyAttributes(attributes,board.options,"slider","point2"),p2=board.create("point",parents[1],attr),attr=Type.copyAttributes(attributes,board.options,"slider","baseline"),(l1=board.create("segment",[p1,p2],attr)).updateStdform(),pos0=p1.coords.usrCoords.slice(1),pos1=p2.coords.usrCoords.slice(1),smin=parents[2][0],start=parents[2][1],smax=parents[2][2],sdiff=smax-smin,s=-1===(sw=Type.evaluate(snapWidth))?start:Math.round(start/sw)*sw,startx=pos0[0]+(pos1[0]-pos0[0])*(s-smin)/(smax-smin),starty=pos0[1]+(pos1[1]-pos0[1])*(s-smin)/(smax-smin),(attr=Type.copyAttributes(attributes,board.options,"slider")).withLabel=!1,(p3=board.create("glider",[startx,starty,l1],attr)).setAttribute({snapwidth:snapWidth}),attr=Type.copyAttributes(attributes,board.options,"slider","highline"),l2=board.create("segment",[p1,p3],attr),p3.Value=function(){var sdiff=this._smax-this._smin,ev_sw=Type.evaluate(this.visProp.snapwidth);return-1===ev_sw?this.position*sdiff+this._smin:Math.round((this.position*sdiff+this._smin)/ev_sw)*ev_sw},p3.methodMap=Type.deepCopy(p3.methodMap,{Value:"Value",setValue:"setValue",smax:"_smax",smin:"_smin",setMax:"setMax",setMin:"setMin"}),p3._smax=smax,p3._smin=smin,p3.setMax=function(val){return this._smax=val,this},p3.setValue=function(val){var sdiff=this._smax-this._smin;return Math.abs(sdiff)>Mat.eps?this.position=(val-this._smin)/sdiff:this.position=0,this.position=Math.max(0,Math.min(1,this.position)),this},p3.setMin=function(val){return this._smin=val,this},withText&&(attr=Type.copyAttributes(attributes,board.options,"slider","label"),t=board.create("text",[function(){return.05*(p2.X()-p1.X())+p2.X()},function(){return.05*(p2.Y()-p1.Y())+p2.Y()},function(){var n,d=Type.evaluate(p3.visProp.digits),sl=Type.evaluate(p3.visProp.suffixlabel),ul=Type.evaluate(p3.visProp.unitlabel),pl=Type.evaluate(p3.visProp.postlabel);return 2===d&&2!==Type.evaluate(p3.visProp.precision)&&(d=Type.evaluate(p3.visProp.precision)),n=null!==sl?sl:p3.name&&""!==p3.name?p3.name+" = ":"",n+=Type.toFixed(p3.Value(),d),null!==ul&&(n+=ul),null!==pl&&(n+=pl),n}],attr),p3.label=t,p3.visProp.withlabel=!0,p3.hasLabel=!0),p3.point1=p1,p3.point2=p2,p3.baseline=l1,p3.highline=l2,withTicks&&(attr=Type.copyAttributes(attributes,board.options,"slider","ticks"),Type.exists(attr.generatelabeltext)||(attr.generateLabelText=function(tick,zero,value){var dFull=p3.point1.Dist(p3.point2),smin=p3._smin,smax=p3._smax,val=this.getDistanceFromZero(zero,tick)*(smax-smin)/dFull+smin;return dFull<Mat.eps||Math.abs(val)<Mat.eps?"0":this.formatLabelText(val)}),2,ti=board.create("ticks",[p3.baseline,p3.point1.Dist(p1)/2,function(tick){var dFull=p3.point1.Dist(p3.point2),d=p3.point1.coords.distance(Const.COORDS_BY_USER,tick);return dFull<Mat.eps?0:d/dFull*sdiff+smin}],attr),p3.ticks=ti),p3.remove=function(){withText&&board.removeObject(t),board.removeObject(l2),board.removeObject(l1),board.removeObject(p2),board.removeObject(p1),Point.Point.prototype.remove.call(p3)},p1.dump=!1,p2.dump=!1,l1.dump=!1,l2.dump=!1,withText&&(t.dump=!1),p3.elType="slider",p3.parents=parents,p3.subs={point1:p1,point2:p2,baseLine:l1,highLine:l2},p3.inherits.push(p1,p2,l1,l2),withTicks&&(ti.dump=!1,p3.subs.ticks=ti,p3.inherits.push(ti)),p3.getParents=function(){return[this.point1.coords.usrCoords.slice(1),this.point2.coords.usrCoords.slice(1),[this._smin,this.position*(this._smax-this._smin)+this._smin,this._smax]]},p3.baseline.on("up",(function(evt){var pos,c;Type.evaluate(p3.visProp.moveonup)&&!Type.evaluate(p3.visProp.fixed)&&(pos=l1.board.getMousePosition(evt,0),c=new Coords(Const.COORDS_BY_SCREEN,pos,this.board),p3.moveTo([c.usrCoords[1],c.usrCoords[2]]))})),p3.prepareUpdate().update(),board.isSuspendedUpdate||(p3.updateVisibility().updateRenderer(),p3.baseline.updateVisibility().updateRenderer(),p3.highline.updateVisibility().updateRenderer(),withTicks&&p3.ticks.updateVisibility().updateRenderer()),p3},JXG.registerElement("slider",JXG.createSlider),{createSlider:JXG.createSlider}})),define("element/measure",["jxg","utils/type","base/element"],(function(JXG,Type,GeometryElement){return JXG.createTapemeasure=function(board,parents,attributes){var pos0,pos1,attr,withTicks,withText,digits,li,p1,p2,n,ti;return pos0=parents[0],pos1=parents[1],attr=Type.copyAttributes(attributes,board.options,"tapemeasure","point1"),p1=board.create("point",pos0,attr),attr=Type.copyAttributes(attributes,board.options,"tapemeasure","point2"),p2=board.create("point",pos1,attr),p1.setAttribute({ignoredSnapToPoints:[p2]}),p2.setAttribute({ignoredSnapToPoints:[p1]}),attr=Type.copyAttributes(attributes,board.options,"tapemeasure"),withTicks=attr.withticks,withText=attr.withlabel,2===(digits=attr.digits)&&2!==attr.precision&&(digits=attr.precision),withText&&(attr.withlabel=!0),li=board.create("segment",[p1,p2],attr),withText&&(n=attributes.name&&""!==attributes.name?attributes.name+" = ":"",li.label.setText((function(){return n+Type.toFixed(p1.Dist(p2),digits)}))),withTicks&&(attr=Type.copyAttributes(attributes,board.options,"tapemeasure","ticks"),ti=board.create("ticks",[li,.1],attr),li.inherits.push(ti)),li.remove=function(){withTicks&&li.removeTicks(ti),board.removeObject(p2),board.removeObject(p1),GeometryElement.prototype.remove.call(this)},li.Value=function(){return p1.Dist(p2)},p1.dump=!1,p2.dump=!1,li.elType="tapemeasure",li.getParents=function(){return[[p1.X(),p1.Y()],[p2.X(),p2.Y()]]},li.subs={point1:p1,point2:p2},withTicks&&(ti.dump=!1),li.methodMap=JXG.deepCopy(li.methodMap,{Value:"Value"}),li.prepareUpdate().update(),board.isSuspendedUpdate||(li.updateVisibility().updateRenderer(),li.point1.updateVisibility().updateRenderer(),li.point2.updateVisibility().updateRenderer()),li},JXG.registerElement("tapemeasure",JXG.createTapemeasure),{createTapemeasure:JXG.createTapemeasure}})),define("parser/datasource",["jxg","utils/type"],(function(JXG,Type){return JXG.DataSource=function(){return this.data=[],this.columnHeaders=[],this.rowHeaders=[],this},JXG.extend(JXG.DataSource.prototype,{loadFromArray:function(table,columnHeader,rowHeader){var i,j,cell;if(Type.isArray(columnHeader)&&(this.columnHeaders=columnHeader,columnHeader=!1),Type.isArray(rowHeader)&&(this.rowHeaders=rowHeader,rowHeader=!1),this.data=[],columnHeader&&(this.columnHeaders=[]),rowHeader&&(this.rowHeaders=[]),Type.exists(table)){for(this.data=[],i=0;i<table.length;i++)for(this.data[i]=[],j=0;j<table[i].length;j++)cell=table[i][j],parseFloat(cell).toString()===cell?this.data[i][j]=parseFloat(cell):this.data[i][j]="-"!==cell?cell:NaN;if(columnHeader&&(this.columnHeaders=this.data[0].slice(1),this.data=this.data.slice(1)),rowHeader)for(this.rowHeaders=[],i=0;i<this.data.length;i++)this.rowHeaders.push(this.data[i][0]),this.data[i]=this.data[i].slice(1)}return this},loadFromTable:function(table,columnHeader,rowHeader){var row,i,j,col,cell;if(Type.isArray(columnHeader)&&(this.columnHeaders=columnHeader,columnHeader=!1),Type.isArray(rowHeader)&&(this.rowHeaders=rowHeader,rowHeader=!1),this.data=[],columnHeader&&(this.columnHeaders=[]),rowHeader&&(this.rowHeaders=[]),table=document.getElementById(table),Type.exists(table)){for(row=table.getElementsByTagName("tr"),this.data=[],i=0;i<row.length;i++)for(col=row[i].getElementsByTagName("td"),this.data[i]=[],j=0;j<col.length;j++)cell=col[j].innerHTML,parseFloat(cell).toString()===cell?this.data[i][j]=parseFloat(cell):this.data[i][j]="-"!==cell?cell:NaN;if(columnHeader&&(this.columnHeaders=this.data[0].slice(1),this.data=this.data.slice(1)),rowHeader)for(this.rowHeaders=[],i=0;i<this.data.length;i++)this.rowHeaders.push(this.data[i][0]),this.data[i]=this.data[i].slice(1)}return this},addColumn:function(name,pos,data){throw new Error("not implemented")},addRow:function(name,pos,data){throw new Error("not implemented")},getColumn:function(col){var i,result=[];if(Type.isString(col))for(i=0;i<this.columnHeaders.length;i++)if(col===this.columnHeaders[i]){col=i;break}for(i=0;i<this.data.length;i++)this.data[i].length>col&&(result[i]=parseFloat(this.data[i][col]));return result},getRow:function(row){var result,i;if(Type.isString(row))for(i=0;i<this.rowHeaders.length;i++)if(row===this.rowHeaders[i]){row=i;break}for(result=[],i=0;i<this.data[row].length;i++)result[i]=this.data[row][i];return result}}),JXG.DataSource})),define("base/chart",["jxg","math/numerics","math/statistics","base/constants","base/coords","base/element","parser/datasource","utils/color","utils/type","utils/env","base/curve","base/point","base/text","base/polygon","element/sector","base/transformation","base/line","base/circle"],(function(JXG,Numerics,Statistics,Const,Coords,GeometryElement,DataSource,Color,Type,Env,Curve,Point,Text,Polygon,Sector,Transform,Line,Circle){return JXG.Chart=function(board,parents,attributes){var x,y,i,c,style,len;if(this.constructor(board,attributes),!Type.isArray(parents)||0===parents.length)throw new Error("JSXGraph: Can't create a chart without data");if(this.elements=[],Type.isNumber(parents[0]))for(y=parents,x=[],i=0;i<y.length;i++)x[i]=i+1;else if(1===parents.length&&Type.isArray(parents[0]))for(y=parents[0],x=[],len=Type.evaluate(y).length,i=0;i<len;i++)x[i]=i+1;else 2===parents.length&&(len=Math.min(parents[0].length,parents[1].length),x=parents[0].slice(0,len),y=parents[1].slice(0,len));if(Type.isArray(y)&&0===y.length)throw new Error("JSXGraph: Can't create charts without data.");for(style=attributes.chartstyle.replace(/ /g,"").split(","),i=0;i<style.length;i++){switch(style[i]){case"bar":c=this.drawBar(board,x,y,attributes);break;case"line":c=this.drawLine(board,x,y,attributes);break;case"fit":c=this.drawFit(board,x,y,attributes);break;case"spline":c=this.drawSpline(board,x,y,attributes);break;case"pie":c=this.drawPie(board,y,attributes);break;case"point":c=this.drawPoints(board,x,y,attributes);break;case"radar":c=this.drawRadar(board,parents,attributes)}this.elements.push(c)}return this.id=this.board.setId(this,"Chart"),this.elements},JXG.Chart.prototype=new GeometryElement,JXG.extend(JXG.Chart.prototype,{drawLine:function(board,x,y,attributes){return attributes.fillcolor="none",attributes.highlightfillcolor="none",board.create("curve",[x,y],attributes)},drawSpline:function(board,x,y,attributes){return attributes.fillColor="none",attributes.highlightfillcolor="none",board.create("spline",[x,y],attributes)},drawFit:function(board,x,y,attributes){var deg=attributes.degree;return deg=Math.max(parseInt(deg,10),1)||1,attributes.fillcolor="none",attributes.highlightfillcolor="none",board.create("functiongraph",[Numerics.regressionPolynomial(deg,x,y)],attributes)},drawBar:function(board,x,y,attributes){var i,text,w,xp0,xp1,xp2,yp,colors,attr,attrSub,pols=[],p=[],makeXpFun=function(i,f){return function(){return x[i]()-f*w}},hiddenPoint={fixed:!0,withLabel:!1,visible:!1,name:""};if((attr=Type.copyAttributes(attributes,board.options,"chart"))&&attr.width)w=attr.width;else{if(x.length<=1)w=1;else for(w=x[1]-x[0],i=1;i<x.length-1;i++)w=x[i+1]-x[i]<w?x[i+1]-x[i]:w;w*=.8}for(attrSub=Type.copyAttributes(attributes,board.options,"chart","label"),i=0;i<x.length;i++)Type.isFunction(x[i])?(xp0=makeXpFun(i,-.5),xp1=makeXpFun(i,0),xp2=makeXpFun(i,.5)):(xp0=x[i]-.5*w,xp1=x[i],xp2=x[i]+.5*w),yp=Type.isFunction(y[i])?y[i]():y[i],yp=y[i],"horizontal"===attr.dir?(p[0]=board.create("point",[0,xp0],hiddenPoint),p[1]=board.create("point",[yp,xp0],hiddenPoint),p[2]=board.create("point",[yp,xp2],hiddenPoint),p[3]=board.create("point",[0,xp2],hiddenPoint),Type.exists(attr.labels)&&Type.exists(attr.labels[i])&&(attrSub.anchorY="middle",(text=board.create("text",[yp,xp1,attr.labels[i]],attrSub)).visProp.anchorx=function(txt){return function(){return txt.X()>=0?"left":"right"}}(text))):(p[0]=board.create("point",[xp0,0],hiddenPoint),p[1]=board.create("point",[xp0,yp],hiddenPoint),p[2]=board.create("point",[xp2,yp],hiddenPoint),p[3]=board.create("point",[xp2,0],hiddenPoint),Type.exists(attr.labels)&&Type.exists(attr.labels[i])&&(attrSub.anchorX="middle",(text=board.create("text",[xp1,yp,attr.labels[i]],attrSub)).visProp.anchory=function(txt){return function(){return txt.Y()>=0?"bottom":"top"}}(text))),Type.isArray(attr.colors)&&(colors=attr.colors,attr.fillcolor=colors[i%colors.length]),pols[i]=board.create("polygon",p,attr),Type.exists(attr.labels)&&Type.exists(attr.labels[i])&&(pols[i].text=text);return pols},drawPoints:function(board,x,y,attributes){var i,points=[],infoboxArray=attributes.infoboxarray;for(attributes.fixed=!0,attributes.name="",i=0;i<x.length;i++)attributes.infoboxtext=!!infoboxArray&&infoboxArray[i%infoboxArray.length],points[i]=board.create("point",[x[i],y[i]],attributes);return points},drawPie:function(board,y,attributes){var i,center,p=[],sector=[],colorArray=(Statistics.sum(y),attributes.colors),highlightColorArray=attributes.highlightcolors,labelArray=attributes.labels,r=attributes.radius||4,radius=r,cent=attributes.center||[0,0],xc=cent[0],yc=cent[1],makeRadPointFun=function(j,fun,xc){return function(){var s,i,rad,t=0;for(i=0;i<=j;i++)t+=parseFloat(Type.evaluate(y[i]));for(s=t,i=j+1;i<y.length;i++)s+=parseFloat(Type.evaluate(y[i]));return rad=0!==s?2*Math.PI*t/s:0,radius()*Math[fun](rad)+xc}},highlightHandleLabel=function(f,s){var dx=-this.point1.coords.usrCoords[1]+this.point2.coords.usrCoords[1],dy=-this.point1.coords.usrCoords[2]+this.point2.coords.usrCoords[2];Type.exists(this.label)&&(this.label.rendNode.style.fontSize=s*Type.evaluate(this.label.visProp.fontsize)+"px",this.label.fullUpdate()),this.point2.coords=new Coords(Const.COORDS_BY_USER,[this.point1.coords.usrCoords[1]+dx*f,this.point1.coords.usrCoords[2]+dy*f],this.board),this.fullUpdate()},highlightFun=function(){this.highlighted||(this.highlighted=!0,this.board.highlightedObjects[this.id]=this,this.board.renderer.highlight(this),highlightHandleLabel.call(this,1.1,2))},noHighlightFun=function(){this.highlighted&&(this.highlighted=!1,this.board.renderer.noHighlight(this),highlightHandleLabel.call(this,.9090909,1))},hiddenPoint={fixed:!0,withLabel:!1,visible:!1,name:""};if(!Type.isArray(labelArray))for(labelArray=[],i=0;i<y.length;i++)labelArray[i]="";for(Type.isFunction(r)||(radius=function(){return r}),attributes.highlightonsector=attributes.highlightonsector||!1,attributes.straightfirst=!1,attributes.straightlast=!1,center=board.create("point",[xc,yc],hiddenPoint),p[0]=board.create("point",[function(){return radius()+xc},function(){return yc}],hiddenPoint),i=0;i<y.length;i++)p[i+1]=board.create("point",[makeRadPointFun(i,"cos",xc),makeRadPointFun(i,"sin",yc)],hiddenPoint),attributes.name=labelArray[i],attributes.withlabel=""!==attributes.name,attributes.fillcolor=colorArray&&colorArray[i%colorArray.length],attributes.labelcolor=colorArray&&colorArray[i%colorArray.length],attributes.highlightfillcolor=highlightColorArray&&highlightColorArray[i%highlightColorArray.length],sector[i]=board.create("sector",[center,p[i],p[i+1]],attributes),attributes.highlightonsector&&(sector[i].hasPoint=sector[i].hasPointSector),attributes.highlightbysize&&(sector[i].highlight=highlightFun,sector[i].noHighlight=noHighlightFun);return{sectors:sector,points:p,midpoint:center}},drawRadar:function(board,parents,attributes){var i,j,paramArray,numofparams,maxes,mins,la,pdata,ssa,esa,ssratio,esratio,sshifts,eshifts,starts,ends,labelArray,colorArray,radius,myAtts,cent,xc,yc,center,start_angle,rad,p,line,t,xcoord,ycoord,polygons,circles,lxoff,lyoff,cla,clabelArray,ncircles,pcircles,dr,sw,data,len=parents.length,get_anchor=function(){var x1,x2,y1,y2,relCoords=Type.evaluate(this.visProp.label.offset).slice(0);return x1=this.point1.X(),x2=this.point2.X(),y1=this.point1.Y(),y2=this.point2.Y(),x2<x1&&(relCoords[0]=-relCoords[0]),y2<y1&&(relCoords[1]=-relCoords[1]),this.setLabelRelativeCoords(relCoords),new Coords(Const.COORDS_BY_USER,[this.point2.X(),this.point2.Y()],this.board)},get_transform=function(angle,i){var t,tscale,trot;return t=board.create("transform",[-(starts[i]-sshifts[i]),0],{type:"translate"}),tscale=board.create("transform",[radius/(ends[i]+eshifts[i]-(starts[i]-sshifts[i])),1],{type:"scale"}),t.melt(tscale),trot=board.create("transform",[angle],{type:"rotate"}),t.melt(trot),t};if(len<=0)throw new Error("JSXGraph radar chart: no data");if(paramArray=attributes.paramarray,!Type.exists(paramArray))throw new Error("JSXGraph radar chart: need paramArray attribute");if((numofparams=paramArray.length)<=1)throw new Error("JSXGraph radar chart: need more than one param in paramArray");for(i=0;i<len;i++)if(numofparams!==parents[i].length)throw new Error("JSXGraph radar chart: use data length equal to number of params ("+parents[i].length+" != "+numofparams+")");for(maxes=[],mins=[],j=0;j<numofparams;j++)maxes[j]=parents[0][j],mins[j]=maxes[j];for(i=1;i<len;i++)for(j=0;j<numofparams;j++)parents[i][j]>maxes[j]&&(maxes[j]=parents[i][j]),parents[i][j]<mins[j]&&(mins[j]=parents[i][j]);for(la=[],pdata=[],i=0;i<len;i++)la[i]="",pdata[i]=[];for(ssa=[],esa=[],ssratio=attributes.startshiftratio||0,esratio=attributes.endshiftratio||0,i=0;i<numofparams;i++)ssa[i]=(maxes[i]-mins[i])*ssratio,esa[i]=(maxes[i]-mins[i])*esratio;if(sshifts=attributes.startshiftarray||ssa,eshifts=attributes.endshiftarray||esa,starts=attributes.startarray||mins,Type.exists(attributes.start))for(i=0;i<numofparams;i++)starts[i]=attributes.start;if(ends=attributes.endarray||maxes,Type.exists(attributes.end))for(i=0;i<numofparams;i++)ends[i]=attributes.end;if(sshifts.length!==numofparams)throw new Error("JSXGraph radar chart: start shifts length is not equal to number of parameters");if(eshifts.length!==numofparams)throw new Error("JSXGraph radar chart: end shifts length is not equal to number of parameters");if(starts.length!==numofparams)throw new Error("JSXGraph radar chart: starts length is not equal to number of parameters");if(ends.length!==numofparams)throw new Error("JSXGraph radar chart: snds length is not equal to number of parameters");for(labelArray=attributes.labelarray||la,colorArray=attributes.colors,attributes.highlightcolors,radius=attributes.radius||10,sw=attributes.strokewidth||1,Type.exists(attributes.highlightonsector)||(attributes.highlightonsector=!1),myAtts={name:attributes.name,id:attributes.id,strokewidth:sw,polystrokewidth:attributes.polystrokewidth||sw,strokecolor:attributes.strokecolor||"black",straightfirst:!1,straightlast:!1,fillcolor:attributes.fillColor||"#FFFF88",fillopacity:attributes.fillOpacity||.4,highlightfillcolor:attributes.highlightFillColor||"#FF7400",highlightstrokecolor:attributes.highlightStrokeColor||"black",gradient:attributes.gradient||"none"},xc=(cent=attributes.center||[0,0])[0],yc=cent[1],center=board.create("point",[xc,yc],{name:"",fixed:!0,withlabel:!1,visible:!1}),Math.PI/2-Math.PI/numofparams,rad=start_angle=attributes.startangle||0,p=[],line=[],i=0;i<numofparams;i++)for(rad+=2*Math.PI/numofparams,xcoord=radius*Math.cos(rad)+xc,ycoord=radius*Math.sin(rad)+yc,p[i]=board.create("point",[xcoord,ycoord],{name:"",fixed:!0,withlabel:!1,visible:!1}),line[i]=board.create("line",[center,p[i]],{name:paramArray[i],strokeColor:myAtts.strokecolor,strokeWidth:myAtts.strokewidth,strokeOpacity:1,straightFirst:!1,straightLast:!1,withLabel:!0,highlightStrokeColor:myAtts.highlightstrokecolor}),line[i].getLabelAnchor=get_anchor,t=get_transform(rad,i),j=0;j<parents.length;j++)data=parents[j][i],pdata[j][i]=board.create("point",[data,0],{name:"",fixed:!0,withlabel:!1,visible:!1}),pdata[j][i].addTransform(pdata[j][i],t);for(polygons=[],i=0;i<len;i++)for(myAtts.labelcolor=colorArray&&colorArray[i%colorArray.length],myAtts.strokecolor=colorArray&&colorArray[i%colorArray.length],myAtts.fillcolor=colorArray&&colorArray[i%colorArray.length],polygons[i]=board.create("polygon",pdata[i],{withLines:!0,withLabel:!1,fillColor:myAtts.fillcolor,fillOpacity:myAtts.fillopacity,highlightFillColor:myAtts.highlightfillcolor}),j=0;j<numofparams;j++)polygons[i].borders[j].setAttribute("strokecolor:"+colorArray[i%colorArray.length]),polygons[i].borders[j].setAttribute("strokewidth:"+myAtts.polystrokewidth);switch(attributes.legendposition||"none"){case"right":lxoff=attributes.legendleftoffset||2,lyoff=attributes.legendtopoffset||1,this.legend=board.create("legend",[xc+radius+lxoff,yc+radius-lyoff],{labels:labelArray,colors:colorArray});break;case"none":break;default:JXG.debug("Unknown legend position")}if(circles=[],attributes.showcircles){for(cla=[],i=0;i<6;i++)cla[i]=20*i;if(cla[0]="0",(ncircles=(clabelArray=attributes.circlelabelarray||cla).length)<2)throw new Error("JSXGraph radar chart: too less circles in circleLabelArray");for(pcircles=[],t=get_transform(start_angle+Math.PI/numofparams,0),myAtts.fillcolor="none",myAtts.highlightfillcolor="none",myAtts.strokecolor=attributes.strokecolor||"black",myAtts.strokewidth=attributes.circlestrokewidth||.5,myAtts.layer=0,dr=(ends[0]-starts[0])/(ncircles-1),i=0;i<ncircles;i++)pcircles[i]=board.create("point",[starts[0]+i*dr,0],{name:clabelArray[i],size:0,fixed:!0,withLabel:!0,visible:!0}),pcircles[i].addTransform(pcircles[i],t),circles[i]=board.create("circle",[center,pcircles[i]],myAtts)}return this.rendNode=polygons[0].rendNode,{circles:circles,lines:line,points:pdata,midpoint:center,polygons:polygons}},updateRenderer:function(){return this},update:function(){return this.needsUpdate&&this.updateDataArray(),this},updateDataArray:function(){return this}}),JXG.createChart=function(board,parents,attributes){var data,row,i,j,col,w,x,showRows,attr,originalWidth,name,strokeColor,fillColor,hStrokeColor,hFillColor,len,charts=[],table=Env.isBrowser?board.document.getElementById(parents[0]):null;if(1===parents.length&&Type.isString(parents[0])){if(Type.exists(table)){if(attr=Type.copyAttributes(attributes,board.options,"chart"),data=(table=(new DataSource).loadFromTable(parents[0],attr.withheaders,attr.withheaders)).data,col=table.columnHeaders,row=table.rowHeaders,originalWidth=attr.width,name=attr.name,strokeColor=attr.strokecolor,fillColor=attr.fillcolor,hStrokeColor=attr.highlightstrokecolor,hFillColor=attr.highlightfillcolor,board.suspendUpdate(),len=data.length,showRows=[],attr.rows&&Type.isArray(attr.rows)){for(i=0;i<len;i++)for(j=0;j<attr.rows.length;j++)if(attr.rows[j]===i||attr.withheaders&&attr.rows[j]===row[i]){showRows.push(data[i]);break}}else showRows=data;for(len=showRows.length,i=0;i<len;i++){if(x=[],attr.chartstyle&&-1!==attr.chartstyle.indexOf("bar")){for(w=originalWidth||.8,x.push(1-w/2+(i+.5)*w/len),j=1;j<showRows[i].length;j++)x.push(x[j-1]+1);attr.width=w/len}name&&name.length===len?attr.name=name[i]:attr.withheaders&&(attr.name=col[i]),strokeColor&&strokeColor.length===len?attr.strokecolor=strokeColor[i]:attr.strokecolor=Color.hsv2rgb((i+1)/len*360,.9,.6),fillColor&&fillColor.length===len?attr.fillcolor=fillColor[i]:attr.fillcolor=Color.hsv2rgb((i+1)/len*360,.9,1),hStrokeColor&&hStrokeColor.length===len?attr.highlightstrokecolor=hStrokeColor[i]:attr.highlightstrokecolor=Color.hsv2rgb((i+1)/len*360,.9,1),hFillColor&&hFillColor.length===len?attr.highlightfillcolor=hFillColor[i]:attr.highlightfillcolor=Color.hsv2rgb((i+1)/len*360,.9,.6),attr.chartstyle&&-1!==attr.chartstyle.indexOf("bar")?charts.push(new JXG.Chart(board,[x,showRows[i]],attr)):charts.push(new JXG.Chart(board,[showRows[i]],attr))}board.unsuspendUpdate()}return charts}return attr=Type.copyAttributes(attributes,board.options,"chart"),new JXG.Chart(board,parents,attr)},JXG.registerElement("chart",JXG.createChart),JXG.Legend=function(board,coords,attributes){var attr;if(this.constructor(),attr=Type.copyAttributes(attributes,board.options,"legend"),this.board=board,this.coords=new Coords(Const.COORDS_BY_USER,coords,this.board),this.myAtts={},this.label_array=attr.labelarray||attr.labels,this.color_array=attr.colorarray||attr.colors,this.lines=[],this.myAtts.strokewidth=attr.strokewidth||5,this.myAtts.straightfirst=!1,this.myAtts.straightlast=!1,this.myAtts.withlabel=!0,this.myAtts.fixed=!0,this.style=attr.legendstyle||attr.style,"vertical"!==this.style)throw new Error("JSXGraph: Unknown legend style: "+this.style);this.drawVerticalLegend(board,attr)},JXG.Legend.prototype=new GeometryElement,JXG.Legend.prototype.drawVerticalLegend=function(board,attributes){var i,line_length=attributes.linelength||1,offy=(attributes.rowheight||20)/this.board.unitY,getLabelAnchor=function(){return this.setLabelRelativeCoords(this.visProp.label.offset),new Coords(Const.COORDS_BY_USER,[this.point2.X(),this.point2.Y()],this.board)};for(i=0;i<this.label_array.length;i++)this.myAtts.name=this.label_array[i],this.myAtts.strokecolor=this.color_array[i%this.color_array.length],this.myAtts.highlightstrokecolor=this.color_array[i%this.color_array.length],this.myAtts.label={offset:[10,0],strokeColor:this.color_array[i%this.color_array.length],strokeWidth:this.myAtts.strokewidth},this.lines[i]=board.create("line",[[this.coords.usrCoords[1],this.coords.usrCoords[2]-i*offy],[this.coords.usrCoords[1]+line_length,this.coords.usrCoords[2]-i*offy]],this.myAtts),this.lines[i].getLabelAnchor=getLabelAnchor,this.lines[i].prepareUpdate().update().updateVisibility(Type.evaluate(this.lines[i].visProp.visible)).updateRenderer()},JXG.createLegend=function(board,parents,attributes){var start_from=[0,0];if(!Type.exists(parents)||2!==parents.length)throw new Error("JSXGraph: Legend element needs two numbers as parameters");return start_from=parents,new JXG.Legend(board,start_from,attributes)},JXG.registerElement("legend",JXG.createLegend),{Chart:JXG.Chart,Legend:JXG.Legend,createChart:JXG.createChart,createLegend:JXG.createLegend}})),define("base/turtle",["jxg","base/constants","base/element","utils/type"],(function(JXG,Const,GeometryElement,Type){return JXG.Turtle=function(board,parents,attributes){var x,y,dir;return this.constructor(board,attributes,Const.OBJECT_TYPE_TURTLE,Const.OBJECT_CLASS_OTHER),this.turtleIsHidden=!1,this.board=board,this.visProp.curveType="plot",this._attributes=Type.copyAttributes(this.visProp,board.options,"turtle"),delete this._attributes.id,x=0,y=0,dir=90,0!==parents.length&&(3===parents.length?(x=parents[0],y=parents[1],dir=parents[2]):2===parents.length?Type.isArray(parents[0])?(x=parents[0][0],y=parents[0][1],dir=parents[1]):(x=parents[0],y=parents[1]):(x=parents[0][0],y=parents[0][1])),this.init(x,y,dir),this.methodMap=Type.deepCopy(this.methodMap,{forward:"forward",fd:"forward",back:"back",bk:"back",right:"right",rt:"right",left:"left",lt:"left",penUp:"penUp",pu:"penUp",penDown:"penDown",pd:"penDown",clearScreen:"clearScreen",cs:"clearScreen",clean:"clean",setPos:"setPos",home:"home",hideTurtle:"hideTurtle",ht:"hideTurtle",showTurtle:"showTurtle",st:"showTurtle",penSize:"setPenSize",penColor:"setPenColor",pushTurtle:"pushTurtle",push:"pushTurtle",popTurtle:"popTurtle",pop:"popTurtle",lookTo:"lookTo",pos:"pos",moveTo:"moveTo",X:"X",Y:"Y"}),this},JXG.Turtle.prototype=new GeometryElement,JXG.extend(JXG.Turtle.prototype,{init:function(x,y,dir){var hiddenPointAttr={fixed:!0,name:"",visible:!1,withLabel:!1};this.arrowLen=20/Math.sqrt(this.board.unitX*this.board.unitX+this.board.unitY*this.board.unitY),this.pos=[x,y],this.isPenDown=!0,this.dir=90,this.stack=[],this.objects=[],this.curve=this.board.create("curve",[[this.pos[0]],[this.pos[1]]],this._attributes),this.objects.push(this.curve),this.turtle=this.board.create("point",this.pos,hiddenPointAttr),this.objects.push(this.turtle),this.turtle2=this.board.create("point",[this.pos[0],this.pos[1]+this.arrowLen],hiddenPointAttr),this.objects.push(this.turtle2),this.visProp.arrow.lastArrow=!0,this.visProp.arrow.straightFirst=!1,this.visProp.arrow.straightLast=!1,this.arrow=this.board.create("line",[this.turtle,this.turtle2],this.visProp.arrow),this.objects.push(this.arrow),this.subs={arrow:this.arrow},this.inherits.push(this.arrow),this.right(90-dir),this.board.update()},forward:function(len){if(0===len)return this;var t,dx=len*Math.cos(this.dir*Math.PI/180),dy=len*Math.sin(this.dir*Math.PI/180);return this.turtleIsHidden||((t=this.board.create("transform",[dx,dy],{type:"translate"})).applyOnce(this.turtle),t.applyOnce(this.turtle2)),this.isPenDown&&this.curve.dataX.length>=8192&&(this.curve=this.board.create("curve",[[this.pos[0]],[this.pos[1]]],this._attributes),this.objects.push(this.curve)),this.pos[0]+=dx,this.pos[1]+=dy,this.isPenDown&&(this.curve.dataX.push(this.pos[0]),this.curve.dataY.push(this.pos[1])),this.board.update(),this},back:function(len){return this.forward(-len)},right:function(angle){(this.dir-=angle,this.dir%=360,this.turtleIsHidden)||this.board.create("transform",[-angle*Math.PI/180,this.turtle],{type:"rotate"}).applyOnce(this.turtle2);return this.board.update(),this},left:function(angle){return this.right(-angle)},penUp:function(){return this.isPenDown=!1,this},penDown:function(){return this.isPenDown=!0,this.curve=this.board.create("curve",[[this.pos[0]],[this.pos[1]]],this._attributes),this.objects.push(this.curve),this},clean:function(){var i,el;for(i=0;i<this.objects.length;i++)(el=this.objects[i]).type===Const.OBJECT_TYPE_CURVE&&(this.board.removeObject(el),this.objects.splice(i,1));return this.curve=this.board.create("curve",[[this.pos[0]],[this.pos[1]]],this._attributes),this.objects.push(this.curve),this.board.update(),this},clearScreen:function(){var i,el,len=this.objects.length;for(i=0;i<len;i++)el=this.objects[i],this.board.removeObject(el);return this.init(0,0,90),this},setPos:function(x,y){return Type.isArray(x)?this.pos=x:this.pos=[x,y],this.turtleIsHidden||(this.turtle.setPositionDirectly(Const.COORDS_BY_USER,[x,y]),this.turtle2.setPositionDirectly(Const.COORDS_BY_USER,[x,y+this.arrowLen]),this.board.create("transform",[-(this.dir-90)*Math.PI/180,this.turtle],{type:"rotate"}).applyOnce(this.turtle2)),this.curve=this.board.create("curve",[[this.pos[0]],[this.pos[1]]],this._attributes),this.objects.push(this.curve),this.board.update(),this},setPenSize:function(size){return this.curve=this.board.create("curve",[[this.pos[0]],[this.pos[1]]],this.copyAttr("strokeWidth",size)),this.objects.push(this.curve),this},setPenColor:function(color){return this.curve=this.board.create("curve",[[this.pos[0]],[this.pos[1]]],this.copyAttr("strokeColor",color)),this.objects.push(this.curve),this},setHighlightPenColor:function(color){return this.curve=this.board.create("curve",[[this.pos[0]],[this.pos[1]]],this.copyAttr("highlightStrokeColor",color)),this.objects.push(this.curve),this},setAttribute:function(attributes){var i,el,tmp,len=this.objects.length;for(i=0;i<len;i++)(el=this.objects[i]).type===Const.OBJECT_TYPE_CURVE&&el.setAttribute(attributes);return tmp=this.visProp.id,this.visProp=Type.deepCopy(this.curve.visProp),this.visProp.id=tmp,this._attributes=Type.deepCopy(this.visProp),delete this._attributes.id,this},copyAttr:function(key,val){return this._attributes[key.toLowerCase()]=val,this._attributes},showTurtle:function(){return this.turtleIsHidden=!1,this.arrow.setAttribute({visible:!0}),this.visProp.arrow.visible=!1,this.setPos(this.pos[0],this.pos[1]),this.board.update(),this},hideTurtle:function(){return this.turtleIsHidden=!0,this.arrow.setAttribute({visible:!1}),this.visProp.arrow.visible=!1,this.board.update(),this},home:function(){return this.pos=[0,0],this.setPos(this.pos[0],this.pos[1]),this},pushTurtle:function(){return this.stack.push([this.pos[0],this.pos[1],this.dir]),this},popTurtle:function(){var status=this.stack.pop();return this.pos[0]=status[0],this.pos[1]=status[1],this.dir=status[2],this.setPos(this.pos[0],this.pos[1]),this},lookTo:function(target){var ax,ay,bx,by,beta;return Type.isArray(target)?(ax=this.pos[0],ay=this.pos[1],bx=target[0],by=target[1],beta=Math.atan2(by-ay,bx-ax),this.right(this.dir-180*beta/Math.PI)):Type.isNumber(target)&&this.right(this.dir-target),this},moveTo:function(target){var dx,dy,t;return Type.isArray(target)&&(dx=target[0]-this.pos[0],dy=target[1]-this.pos[1],this.turtleIsHidden||((t=this.board.create("transform",[dx,dy],{type:"translate"})).applyOnce(this.turtle),t.applyOnce(this.turtle2)),this.isPenDown&&this.curve.dataX.length>=8192&&(this.curve=this.board.create("curve",[[this.pos[0]],[this.pos[1]]],this._attributes),this.objects.push(this.curve)),this.pos[0]=target[0],this.pos[1]=target[1],this.isPenDown&&(this.curve.dataX.push(this.pos[0]),this.curve.dataY.push(this.pos[1])),this.board.update()),this},fd:function(len){return this.forward(len)},bk:function(len){return this.back(len)},lt:function(angle){return this.left(angle)},rt:function(angle){return this.right(angle)},pu:function(){return this.penUp()},pd:function(){return this.penDown()},ht:function(){return this.hideTurtle()},st:function(){return this.showTurtle()},cs:function(){return this.clearScreen()},push:function(){return this.pushTurtle()},pop:function(){return this.popTurtle()},evalAt:function(t,co){var i,j,el,tc,len=this.objects.length;for(i=0,j=0;i<len;i++)if((el=this.objects[i]).elementClass===Const.OBJECT_CLASS_CURVE){if(j<=t&&t<j+el.numberPoints)return tc=t-j,el[co](tc);j+=el.numberPoints}return this[co]()},X:function(t){return Type.exists(t)?this.evalAt(t,"X"):this.pos[0]},Y:function(t){return Type.exists(t)?this.evalAt(t,"Y"):this.pos[1]},Z:function(t){return 1},minX:function(){return 0},maxX:function(){var i,len=this.objects.length,np=0;for(i=0;i<len;i++)this.objects[i].elementClass===Const.OBJECT_CLASS_CURVE&&(np+=this.objects[i].numberPoints);return np},hasPoint:function(x,y){var i,el;for(i=0;i<this.objects.length;i++)if((el=this.objects[i]).type===Const.OBJECT_TYPE_CURVE&&el.hasPoint(x,y))return!0;return!1}}),JXG.createTurtle=function(board,parents,attributes){var attr;return parents=parents||[],attr=Type.copyAttributes(attributes,board.options,"turtle"),new JXG.Turtle(board,parents,attr)},JXG.registerElement("turtle",JXG.createTurtle),{Turtle:JXG.Turtle,createTurtle:JXG.createTurtle}})),define("base/ticks",["jxg","math/math","math/geometry","math/numerics","base/constants","base/element","base/coords","utils/type","base/text"],(function(JXG,Mat,Geometry,Numerics,Const,GeometryElement,Coords,Type,Text){return JXG.Ticks=function(line,ticks,attributes){if(this.constructor(line.board,attributes,Const.OBJECT_TYPE_TICKS,Const.OBJECT_CLASS_OTHER),this.line=line,this.board=this.line.board,this.ticksFunction=null,this.fixedTicks=null,this.equidistant=!1,this.labelsData=[],Type.isFunction(ticks))throw this.ticksFunction=ticks,new Error("Function arguments are no longer supported.");Type.isArray(ticks)?this.fixedTicks=ticks:((Math.abs(ticks)<Mat.eps||ticks<0)&&(ticks=attributes.defaultdistance),this.ticksFunction=this.makeTicksFunction(ticks),this.equidistant=!0),this.minTicksDistance=attributes.minticksdistance,this.ticks=[],this.ticksDelta=1,this.labels=[],this.labelData=[],this.labelCounter=0,this.id=this.line.addTicks(this),this.elType="ticks",this.inherits.push(this.labels),this.board.setId(this,"Ti")},JXG.Ticks.prototype=new GeometryElement,JXG.extend(JXG.Ticks.prototype,{makeTicksFunction:function(ticks){return function(){var delta,b,dist;return Type.evaluate(this.visProp.insertticks)?((dist=(b=this.getLowerAndUpperBounds(this.getZeroCoordinates(),"ticksdistance")).upper-b.lower)<=6*(delta=Math.pow(10,Math.floor(Math.log(.6*dist)/Math.LN10)))&&(delta*=.5),delta):ticks}},hasPoint:function(x,y){var i,t,r,type,len=this.ticks&&this.ticks.length||0;if(Type.isObject(Type.evaluate(this.visProp.precision))?(type=this.board._inputDevice,r=Type.evaluate(this.visProp.precision[type])):r=this.board.options.precision.hasPoint,r+=.5*Type.evaluate(this.visProp.strokewidth),!Type.evaluate(this.line.visProp.scalable)||this.line.elementClass===Const.OBJECT_CLASS_CURVE)return!1;if(0!==this.line.stdform[1]&&0!==this.line.stdform[2]&&this.line.type!==Const.OBJECT_TYPE_AXIS)return!1;for(i=0;i<len;i++)if((t=this.ticks[i])[2]&&!(0===this.line.stdform[1]&&Math.abs(t[0][0]-this.line.point1.coords.scrCoords[1])<Mat.eps||0===this.line.stdform[2]&&Math.abs(t[1][0]-this.line.point1.coords.scrCoords[2])<Mat.eps)&&(Math.abs(t[0][0]-t[0][1])>=1||Math.abs(t[1][0]-t[1][1])>=1))if(0===this.line.stdform[1]){if(Math.abs(y-.5*(t[1][0]+t[1][1]))<2*r&&t[0][0]-r<x&&x<t[0][1]+r)return!0}else if(0===this.line.stdform[2]&&Math.abs(x-.5*(t[0][0]+t[0][1]))<2*r&&t[1][0]-r<y&&y<t[1][1]+r)return!0;return!1},setPositionDirectly:function(method,coords,oldcoords){var dx,dy,c=new Coords(method,coords,this.board),oldc=new Coords(method,oldcoords,this.board),bb=this.board.getBoundingBox();return this.line.type===Const.OBJECT_TYPE_AXIS&&Type.evaluate(this.line.visProp.scalable)?(Math.abs(this.line.stdform[1])<Mat.eps&&Math.abs(c.usrCoords[1]*oldc.usrCoords[1])>Mat.eps?(dx=oldc.usrCoords[1]/c.usrCoords[1],bb[0]*=dx,bb[2]*=dx,this.board.setBoundingBox(bb,this.board.keepaspectratio,"update")):Math.abs(this.line.stdform[2])<Mat.eps&&Math.abs(c.usrCoords[2]*oldc.usrCoords[2])>Mat.eps&&(dy=oldc.usrCoords[2]/c.usrCoords[2],bb[3]*=dy,bb[1]*=dy,this.board.setBoundingBox(bb,this.board.keepaspectratio,"update")),this):this},calculateTicksCoordinates:function(){var coordsZero,bounds,r_max,bb;if(!(this.line.elementClass===Const.OBJECT_CLASS_LINE&&(this.setTicksSizeVariables(),Math.abs(this.dx)<Mat.eps&&Math.abs(this.dy)<Mat.eps)))return coordsZero=this.getZeroCoordinates(),bounds=this.line.elementClass===Const.OBJECT_CLASS_LINE?this.getLowerAndUpperBounds(coordsZero):{lower:this.line.minX(),upper:this.line.maxX()},"polar"===Type.evaluate(this.visProp.type)&&(bb=this.board.getBoundingBox(),r_max=Math.max(Math.sqrt(bb[0]*bb[0]+bb[1]*bb[1]),Math.sqrt(bb[2]*bb[2]+bb[3]*bb[3])),bounds.upper=r_max),this.ticks=[],this.labelsData=[],this.equidistant?this.generateEquidistantTicks(coordsZero,bounds):this.generateFixedTicks(coordsZero,bounds),this},setTicksSizeVariables:function(pos){var d,mi,ma,len,distMaj=.5*Type.evaluate(this.visProp.majorheight),distMin=.5*Type.evaluate(this.visProp.minorheight);Type.exists(pos)?(mi=this.line.minX(),ma=this.line.maxX(),(len=this.line.points.length)<2?(this.dxMaj=0,this.dyMaj=0):Mat.relDif(pos,mi)<Mat.eps?(this.dxMaj=this.line.points[0].usrCoords[2]-this.line.points[1].usrCoords[2],this.dyMaj=this.line.points[1].usrCoords[1]-this.line.points[0].usrCoords[1]):Mat.relDif(pos,ma)<Mat.eps?(this.dxMaj=this.line.points[len-2].usrCoords[2]-this.line.points[len-1].usrCoords[2],this.dyMaj=this.line.points[len-1].usrCoords[1]-this.line.points[len-2].usrCoords[1]):(this.dxMaj=-Numerics.D(this.line.Y)(pos),this.dyMaj=Numerics.D(this.line.X)(pos))):(this.dxMaj=this.line.stdform[1],this.dyMaj=this.line.stdform[2]),this.dxMin=this.dxMaj,this.dyMin=this.dyMaj,this.dx=this.dxMaj,this.dy=this.dyMaj,d=Math.sqrt(this.dxMaj*this.dxMaj*this.board.unitX*this.board.unitX+this.dyMaj*this.dyMaj*this.board.unitY*this.board.unitY),this.dxMaj*=distMaj/d*this.board.unitX,this.dyMaj*=distMaj/d*this.board.unitY,this.dxMin*=distMin/d*this.board.unitX,this.dyMin*=distMin/d*this.board.unitY,this.minStyle=Type.evaluate(this.visProp.minorheight)<0?"infinite":"finite",this.majStyle=Type.evaluate(this.visProp.majorheight)<0?"infinite":"finite"},getZeroCoordinates:function(){var c1x,c1y,c1z,c2x,c2y,c2z,mi,ma,ev_a=Type.evaluate(this.visProp.anchor);return this.line.elementClass===Const.OBJECT_CLASS_LINE?this.line.type===Const.OBJECT_TYPE_AXIS?Geometry.projectPointToLine({coords:{usrCoords:[1,0,0]}},this.line,this.board):(c1z=this.line.point1.coords.usrCoords[0],c1x=this.line.point1.coords.usrCoords[1],c1y=this.line.point1.coords.usrCoords[2],c2z=this.line.point2.coords.usrCoords[0],c2x=this.line.point2.coords.usrCoords[1],c2y=this.line.point2.coords.usrCoords[2],"right"===ev_a?this.line.point2.coords:"middle"===ev_a?new Coords(Const.COORDS_BY_USER,[.5*(c1z+c2z),.5*(c1x+c2x),.5*(c1y+c2y)],this.board):Type.isNumber(ev_a)?new Coords(Const.COORDS_BY_USER,[c1z+(c2z-c1z)*ev_a,c1x+(c2x-c1x)*ev_a,c1y+(c2y-c1y)*ev_a],this.board):this.line.point1.coords):(mi=this.line.minX(),ma=this.line.maxX(),"right"===ev_a?ma:"middle"===ev_a?.5*(mi+ma):Type.isNumber(ev_a)?mi*(1-ev_a)+ma*ev_a:mi)},getLowerAndUpperBounds:function(coordsZero,type){var lowerBound,upperBound,fA,lA,point1,point2,isPoint1inBoard,isPoint2inBoard,dZeroPoint1,dZeroPoint2,ev_sf=Type.evaluate(this.line.visProp.straightfirst),ev_sl=Type.evaluate(this.line.visProp.straightlast),ev_i=Type.evaluate(this.visProp.includeboundaries);return this.line.elementClass===Const.OBJECT_CLASS_CURVE?{lower:this.line.minX(),upper:this.line.maxX()}:(point1=new Coords(Const.COORDS_BY_USER,this.line.point1.coords.usrCoords,this.board),point2=new Coords(Const.COORDS_BY_USER,this.line.point2.coords.usrCoords,this.board),isPoint1inBoard=Math.abs(point1.usrCoords[0])>=Mat.eps&&point1.scrCoords[1]>=0&&point1.scrCoords[1]<=this.board.canvasWidth&&point1.scrCoords[2]>=0&&point1.scrCoords[2]<=this.board.canvasHeight,isPoint2inBoard=Math.abs(point2.usrCoords[0])>=Mat.eps&&point2.scrCoords[1]>=0&&point2.scrCoords[1]<=this.board.canvasWidth&&point2.scrCoords[2]>=0&&point2.scrCoords[2]<=this.board.canvasHeight,Type.exists(type)||"tickdistance"===type?Geometry.calcStraight(this.line,point1,point2,Type.evaluate(this.line.visProp.margin)):Geometry.calcLineDelimitingPoints(this.line,point1,point2),fA=Type.evaluate(this.line.visProp.firstarrow),lA=Type.evaluate(this.line.visProp.lastarrow),(fA||lA)&&(this.board.renderer.getPositionArrowHead(this.line,point1,point2,Type.evaluate(this.line.visProp.strokewidth)),fA&&point1.setCoordinates(Const.COORDS_BY_SCREEN,[point1.scrCoords[1],point1.scrCoords[2]]),lA&&point2.setCoordinates(Const.COORDS_BY_SCREEN,[point2.scrCoords[1],point2.scrCoords[2]])),(dZeroPoint1=this.getDistanceFromZero(coordsZero,point1))<(dZeroPoint2=this.getDistanceFromZero(coordsZero,point2))?(lowerBound=dZeroPoint1,ev_sf||!isPoint1inBoard||ev_i||(lowerBound+=Mat.eps),upperBound=dZeroPoint2,ev_sl||!isPoint2inBoard||ev_i||(upperBound-=Mat.eps)):dZeroPoint2<dZeroPoint1?(lowerBound=dZeroPoint2,ev_sl||!isPoint2inBoard||ev_i||(lowerBound+=Mat.eps),upperBound=dZeroPoint1,ev_sf||!isPoint1inBoard||ev_i||(upperBound-=Mat.eps)):(lowerBound=0,upperBound=0),{lower:lowerBound,upper:upperBound})},getDistanceFromZero:function(zero,point){var p1,p2,dirLine,dirPoint,distance;return p1=this.line.point1.coords,p2=this.line.point2.coords,distance=zero.distance(Const.COORDS_BY_USER,point),dirLine=[p2.usrCoords[0]-p1.usrCoords[0],p2.usrCoords[1]-p1.usrCoords[1],p2.usrCoords[2]-p1.usrCoords[2]],dirPoint=[point.usrCoords[0]-zero.usrCoords[0],point.usrCoords[1]-zero.usrCoords[1],point.usrCoords[2]-zero.usrCoords[2]],Mat.innerProduct(dirLine,dirPoint,3)<0&&(distance*=-1),distance},generateEquidistantTicks:function(coordsZero,bounds){var tickPosition,deltas,eps2=Mat.eps,ticksDelta=this.equidistant?this.ticksFunction(1):this.ticksDelta,ev_it=Type.evaluate(this.visProp.insertticks),ev_mt=Type.evaluate(this.visProp.minorticks);if(this.line.elementClass===Const.OBJECT_CLASS_LINE&&(deltas=this.getXandYdeltas()),ticksDelta*=Type.evaluate(this.visProp.scale),ev_it&&this.minTicksDistance>Mat.eps?(ticksDelta=this.adjustTickDistance(ticksDelta,coordsZero,deltas),ticksDelta/=ev_mt+1):ev_it||(ticksDelta/=ev_mt+1),this.ticksDelta=ticksDelta,!(ticksDelta<Mat.eps)){for(tickPosition=0,Type.evaluate(this.visProp.drawzero)||(tickPosition=ticksDelta);tickPosition<=bounds.upper+eps2&&(tickPosition>=bounds.lower-eps2&&this.processTickPosition(coordsZero,tickPosition,ticksDelta,deltas),tickPosition+=ticksDelta,!(bounds.upper-tickPosition>1e4*ticksDelta)););for(tickPosition=-ticksDelta;tickPosition>=bounds.lower-eps2&&(tickPosition<=bounds.upper+eps2&&this.processTickPosition(coordsZero,tickPosition,ticksDelta,deltas),!((tickPosition-=ticksDelta)-bounds.lower>1e4*ticksDelta)););}},adjustTickDistance:function(ticksDelta,coordsZero,deltas){var nx,ny,distScr,sgn=1,ev_minti=Type.evaluate(this.visProp.minorticks);if(this.line.elementClass===Const.OBJECT_CLASS_CURVE)return ticksDelta;if(this.getLowerAndUpperBounds(coordsZero,"ticksdistance"),nx=coordsZero.usrCoords[1]+deltas.x*ticksDelta,ny=coordsZero.usrCoords[2]+deltas.y*ticksDelta,distScr=coordsZero.distance(Const.COORDS_BY_SCREEN,new Coords(Const.COORDS_BY_USER,[nx,ny],this.board)),0===ticksDelta)return 0;for(;distScr/(ev_minti+1)<this.minTicksDistance;)ticksDelta*=1===sgn?2:5,sgn*=-1,nx=coordsZero.usrCoords[1]+deltas.x*ticksDelta,ny=coordsZero.usrCoords[2]+deltas.y*ticksDelta,distScr=coordsZero.distance(Const.COORDS_BY_SCREEN,new Coords(Const.COORDS_BY_USER,[nx,ny],this.board));return ticksDelta},processTickPosition:function(coordsZero,tickPosition,ticksDelta,deltas){var x,y,tickCoords,ti,labelVal=null;this.line.elementClass===Const.OBJECT_CLASS_LINE?(x=coordsZero.usrCoords[1]+tickPosition*deltas.x,y=coordsZero.usrCoords[2]+tickPosition*deltas.y):(x=this.line.X(coordsZero+tickPosition),y=this.line.Y(coordsZero+tickPosition)),tickCoords=new Coords(Const.COORDS_BY_USER,[x,y],this.board),this.line.elementClass===Const.OBJECT_CLASS_CURVE&&(labelVal=coordsZero+tickPosition,this.setTicksSizeVariables(labelVal)),tickCoords.major=Math.round(tickPosition/ticksDelta)%(Type.evaluate(this.visProp.minorticks)+1)==0,3===(ti=this.createTickPath(tickCoords,tickCoords.major)).length&&(this.ticks.push(ti),tickCoords.major&&Type.evaluate(this.visProp.drawlabels)?this.labelsData.push(this.generateLabelData(this.generateLabelText(tickCoords,coordsZero,labelVal),tickCoords,this.ticks.length)):this.labelsData.push(null))},generateFixedTicks:function(coordsZero,bounds){var tickCoords,labelText,i,ti,x,y,fixedTick,deltas,eps2=Mat.eps,hasLabelOverrides=Type.isArray(this.visProp.labels),ev_dl=Type.evaluate(this.visProp.drawlabels);for(this.line.elementClass===Const.OBJECT_CLASS_LINE&&(deltas=this.getXandYdeltas()),i=0;i<this.fixedTicks.length;i++)this.line.elementClass===Const.OBJECT_CLASS_LINE?(fixedTick=this.fixedTicks[i],x=coordsZero.usrCoords[1]+fixedTick*deltas.x,y=coordsZero.usrCoords[2]+fixedTick*deltas.y):(fixedTick=coordsZero+this.fixedTicks[i],x=this.line.X(fixedTick),y=this.line.Y(fixedTick)),tickCoords=new Coords(Const.COORDS_BY_USER,[x,y],this.board),this.line.elementClass===Const.OBJECT_CLASS_CURVE&&this.setTicksSizeVariables(fixedTick),3===(ti=this.createTickPath(tickCoords,!0)).length&&fixedTick>=bounds.lower-eps2&&fixedTick<=bounds.upper+eps2&&(this.ticks.push(ti),ev_dl&&(hasLabelOverrides||Type.exists(this.visProp.labels[i]))?(labelText=hasLabelOverrides?Type.evaluate(this.visProp.labels[i]):fixedTick,this.labelsData.push(this.generateLabelData(this.generateLabelText(tickCoords,coordsZero,labelText),tickCoords,i))):this.labelsData.push(null))},getXandYdeltas:function(){var point1UsrCoords,point2UsrCoords,distP1P2=this.line.point1.Dist(this.line.point2);return this.line.type===Const.OBJECT_TYPE_AXIS?(point1UsrCoords=this.line.point1.coords.usrCoords,point2UsrCoords=this.line.point2.coords.usrCoords,(point1UsrCoords[1]>point2UsrCoords[1]||Math.abs(point1UsrCoords[1]-point2UsrCoords[1])<Mat.eps&&point1UsrCoords[2]>point2UsrCoords[2])&&(point1UsrCoords=this.line.point2.coords.usrCoords,point2UsrCoords=this.line.point1.coords.usrCoords)):(point1UsrCoords=this.line.point1.coords.usrCoords,point2UsrCoords=this.line.point2.coords.usrCoords),{x:(point2UsrCoords[1]-point1UsrCoords[1])/distP1P2,y:(point2UsrCoords[2]-point1UsrCoords[2])/distP1P2}},_isInsideCanvas:function(x,y,m){var cw=this.board.canvasWidth,ch=this.board.canvasHeight;return void 0===m&&(m=0),x[0]>=m&&x[0]<=cw-m&&y[0]>=m&&y[0]<=ch-m||x[1]>=m&&x[1]<=cw-m&&y[1]>=m&&y[1]<=ch-m},createTickPath:function(coords,major){var c,lineStdForm,intersection,dxs,dys,dxr,dyr,alpha,style,i,r,bb,full,delta,x=[-2e6,-2e6],y=[-2e6,-2e6];if(c=coords.scrCoords,major?(dxs=this.dxMaj,dys=this.dyMaj,style=this.majStyle):(dxs=this.dxMin,dys=this.dyMin,style=this.minStyle),lineStdForm=[-dys*c[1]-dxs*c[2],dys,dxs],major&&"polar"===Type.evaluate(this.visProp.type)){if(bb=this.board.getBoundingBox(),delta=(full=2*Math.PI)/180,c=coords.usrCoords,(r=Math.sqrt(c[1]*c[1]+c[2]*c[2]))<Math.max(Math.sqrt(bb[0]*bb[0]+bb[1]*bb[1]),Math.sqrt(bb[2]*bb[2]+bb[3]*bb[3]))){for(x=[],y=[],i=0;i<=full;i+=delta)x.push(this.board.origin.scrCoords[1]+r*Math.cos(i)*this.board.unitX),y.push(this.board.origin.scrCoords[2]+r*Math.sin(i)*this.board.unitY);return[x,y,major]}}else if("infinite"===style?(intersection=Geometry.meetLineBoard(lineStdForm,this.board),x[0]=intersection[0].scrCoords[1],x[1]=intersection[1].scrCoords[1],y[0]=intersection[0].scrCoords[2],y[1]=intersection[1].scrCoords[2]):(alpha=">"===Type.evaluate(this.visProp.face)?Math.PI/4:"<"===Type.evaluate(this.visProp.face)?-Math.PI/4:0,dxr=Math.cos(alpha)*dxs-Math.sin(alpha)*dys,dyr=Math.sin(alpha)*dxs+Math.cos(alpha)*dys,x[0]=c[1]+dxr*Type.evaluate(this.visProp.tickendings[0]),y[0]=c[2]-dyr*Type.evaluate(this.visProp.tickendings[0]),x[1]=c[1],y[1]=c[2],alpha=-alpha,dxr=Math.cos(alpha)*dxs-Math.sin(alpha)*dys,dyr=Math.sin(alpha)*dxs+Math.cos(alpha)*dys,x[2]=c[1]-dxr*Type.evaluate(this.visProp.tickendings[1]),y[2]=c[2]+dyr*Type.evaluate(this.visProp.tickendings[1])),this._isInsideCanvas(x,y))return[x,y,major];return[]},formatLabelText:function(value){var labelText,digits,ev_s=Type.evaluate(this.visProp.scalesymbol);return Type.isNumber(value)?(((labelText=(Math.round(1e13*value)/1e13).toString()).length>Type.evaluate(this.visProp.maxlabellength)||-1!==labelText.indexOf("e"))&&(digits=Type.evaluate(this.visProp.digits),3!==Type.evaluate(this.visProp.precision)&&3===digits&&(digits=Type.evaluate(this.visProp.precision)),labelText=value.toExponential(digits).toString()),Type.evaluate(this.visProp.beautifulscientificticklabels)&&(labelText=this.beautifyScientificNotationLabel(labelText)),labelText.indexOf(".")>-1&&-1===labelText.indexOf("e")&&(labelText=(labelText=labelText.replace(/0+$/,"")).replace(/\.$/,""))):labelText=value.toString(),ev_s.length>0&&("1"===labelText?labelText=ev_s:"-1"===labelText?labelText="-"+ev_s:"0"!==labelText&&(labelText+=ev_s)),Type.evaluate(this.visProp.useunicodeminus)&&(labelText=labelText.replace(/-/g,"−")),labelText},beautifyScientificNotationLabel:function(labelText){return-1===labelText.indexOf("e")?labelText:(parseFloat(labelText.substring(0,labelText.indexOf("e")))+labelText.substring(labelText.indexOf("e"))).replace(/e(.*)$/g,(function(match,$1){var temp="•10";return temp+=$1.replace(/-/g,"⁻").replace(/\+/g,"").replace(/0/g,"⁰").replace(/1/g,"¹").replace(/2/g,"²").replace(/3/g,"³").replace(/4/g,"⁴").replace(/5/g,"⁵").replace(/6/g,"⁶").replace(/7/g,"⁷").replace(/8/g,"⁸").replace(/9/g,"⁹")}))},generateLabelText:function(tick,zero,value){var distance;if(!Type.exists(value)){if(distance=this.getDistanceFromZero(zero,tick),Math.abs(distance)<Mat.eps)return"0";value=distance/Type.evaluate(this.visProp.scale)}return this.formatLabelText(value)},generateLabelData:function(labelText,tick,tickNumber){var xa,ya,m,fs;return fs=Type.evaluate(this.visProp.label.fontsize),xa=[tick.scrCoords[1],tick.scrCoords[1]],ya=[tick.scrCoords[2],tick.scrCoords[2]],m=void 0===fs?12:fs,m*=.5,this._isInsideCanvas(xa,ya,m)?(xa=Type.evaluate(this.visProp.label.offset[0]),ya=Type.evaluate(this.visProp.label.offset[1]),{x:tick.usrCoords[1]+xa/this.board.unitX,y:tick.usrCoords[2]+ya/this.board.unitY,t:labelText,i:tickNumber}):null},update:function(){return this.needsUpdate&&0!==this.board.canvasWidth&&0!==this.board.canvasHeight&&this.calculateTicksCoordinates(),this},updateRenderer:function(){return this.needsUpdate?(this.visPropCalc.visible&&this.board.renderer.updateTicks(this),this.updateRendererLabels(),this.setDisplayRendNode(),this.needsUpdate=!1,this):this},updateRendererLabels:function(){var i,j,lenData,lenLabels,attr,label,ld,visible;for(lenData=this.labelsData.length,lenLabels=this.labels.length,i=0,j=0;i<lenData;i++)null!==this.labelsData[i]&&(ld=this.labelsData[i],j<lenLabels?((label=this.labels[j]).setText(ld.t),label.setCoords(ld.x,ld.y),j++):(this.labelCounter+=1,attr={isLabel:!0,layer:this.board.options.layer.line,highlightStrokeColor:this.board.options.text.strokeColor,highlightStrokeWidth:this.board.options.text.strokeWidth,highlightStrokeOpacity:this.board.options.text.strokeOpacity,priv:this.visProp.priv},(attr=Type.deepCopy(attr,this.visProp.label)).id=this.id+ld.i+"Label"+this.labelCounter,label=Text.createText(this.board,[ld.x,ld.y,ld.t],attr),this.addChild(label),label.setParents(this),label.isDraggable=!1,label.dump=!1,this.labels.push(label)),"inherit"===(visible=Type.evaluate(this.visProp.label.visible))&&(visible=this.visPropCalc.visible),label.prepareUpdate().updateVisibility(visible).updateRenderer(),label.distanceX=Type.evaluate(this.visProp.label.offset[0]),label.distanceY=Type.evaluate(this.visProp.label.offset[1]));for(j=lenData=j;j<lenLabels;j++)this.board.renderer.display(this.labels[j],!1),this.labels[j].visProp.visible=this.labels[j].visPropCalc.visible=!1;return this},hideElement:function(){var i;for(JXG.deprecated("Element.hideElement()","Element.setDisplayRendNode()"),this.visPropCalc.visible=!1,this.board.renderer.display(this,!1),i=0;i<this.labels.length;i++)Type.exists(this.labels[i])&&this.labels[i].hideElement();return this},showElement:function(){var i;for(JXG.deprecated("Element.showElement()","Element.setDisplayRendNode()"),this.visPropCalc.visible=!0,this.board.renderer.display(this,!1),i=0;i<this.labels.length;i++)Type.exists(this.labels[i])&&this.labels[i].showElement();return this}}),JXG.createTicks=function(board,parents,attributes){var el,dist,attr=Type.copyAttributes(attributes,board.options,"ticks");if(dist=parents.length<2?attr.ticksdistance:parents[1],parents[0].elementClass!==Const.OBJECT_CLASS_LINE&&parents[0].elementClass!==Const.OBJECT_CLASS_CURVE)throw new Error("JSXGraph: Can't create Ticks with parent types '"+_typeof(parents[0])+"'.");return el=new JXG.Ticks(parents[0],dist,attr),Type.isFunction(attr.generatelabelvalue)&&(el.generateLabelText=attr.generatelabelvalue),Type.isFunction(attr.generatelabeltext)&&(el.generateLabelText=attr.generatelabeltext),el.setParents(parents[0]),el.isDraggable=!0,el.fullUpdate(parents[0].visPropCalc.visible),el},JXG.createHatchmark=function(board,parents,attributes){var num,i,base,width,el,pos=[],attr=Type.copyAttributes(attributes,board.options,"hatch");if(parents[0].elementClass!==Const.OBJECT_CLASS_LINE&&parents[0].elementClass!==Const.OBJECT_CLASS_CURVE||"number"!=typeof parents[1])throw new Error("JSXGraph: Can't create Hatch mark with parent types '"+_typeof(parents[0])+"' and '"+_typeof(parents[1])+" and ''"+_typeof(parents[2])+"'.");for(base=.5*-(((num=parents[1])-1)*(width=attr.ticksdistance)),i=0;i<num;i++)pos[i]=base+i*width;return(el=board.create("ticks",[parents[0],pos],attr)).elType="hatch",el},JXG.registerElement("ticks",JXG.createTicks),JXG.registerElement("hash",JXG.createHatchmark),JXG.registerElement("hatch",JXG.createHatchmark),{Ticks:JXG.Ticks,createTicks:JXG.createTicks,createHashmark:JXG.createHatchmark,createHatchmark:JXG.createHatchmark}})),define("parser/ca",["jxg","base/constants","base/text","math/math","math/geometry","math/statistics","utils/type","utils/env"],(function(JXG,Const,Text,Mat,Geometry,Statistics,Type,Env){return JXG.CA=function(node,createNode,parser){this.node=node,this.createNode=createNode,this.parser=parser},JXG.extend(JXG.CA.prototype,{findMapNode:function(mapname,node){var i,len,ret;if("op_assign"===node.value&&node.children[0].value===mapname)return node.children[1];if(node.children)for(len=node.children.length,i=0;i<len;++i)if(null!==(ret=this.findMapNode(mapname,node.children[i])))return ret;return null},setMath:function(node){var i,len;if(("node_op"!=node.type||"op_add"!=node.value&&"op_sub"!=node.value&&"op_mul"!=node.value&&"op_div"!=node.value&&"op_neg"!=node.value&&"op_execfun"!=node.value&&"op_exp"!=node.value)&&"node_var"!=node.type&&"node_const"!=node.type||(node.isMath=!0),node.children)for(len=node.children.length,i=0;i<len;++i)this.setMath(node.children[i])},deriveElementary:function(node,varname){var newNode,fun=node.children[0].value,arg=node.children[1];switch(fun){case"abs":newNode=this.createNode("node_op","op_div",arg[0],this.createNode("node_op","op_execfun",this.createNode("node_var","sqrt"),[this.createNode("node_op","op_mul",Type.deepCopy(arg[0]),Type.deepCopy(arg[0]))]));break;case"sqrt":newNode=this.createNode("node_op","op_div",this.createNode("node_const",1),this.createNode("node_op","op_mul",this.createNode("node_const",2),this.createNode(node.type,node.value,Type.deepCopy(node.children[0]),Type.deepCopy(node.children[1]))));break;case"sin":newNode=this.createNode("node_op","op_execfun",this.createNode("node_var","cos"),Type.deepCopy(arg));break;case"cos":newNode=this.createNode("node_op","op_neg",this.createNode("node_op","op_execfun",this.createNode("node_var","sin"),Type.deepCopy(arg)));break;case"tan":newNode=this.createNode("node_op","op_div",this.createNode("node_const",1),this.createNode("node_op","op_exp",this.createNode("node_op","op_execfun",this.createNode("node_var","cos"),Type.deepCopy(arg)),this.createNode("node_const",2)));break;case"cot":newNode=this.createNode("node_op","op_neg",this.createNode("node_op","op_div",this.createNode("node_const",1),this.createNode("node_op","op_exp",this.createNode("node_op","op_execfun",this.createNode("node_var","sin"),Type.deepCopy(arg)),this.createNode("node_const",2))));break;case"exp":newNode=this.createNode(node.type,node.value,Type.deepCopy(node.children[0]),Type.deepCopy(node.children[1]));break;case"pow":newNode=this.createNode("node_op","op_mul",this.createNode("node_op","op_execfun",Type.deepCopy(node.children[0]),Type.deepCopy(node.children[1])),this.createNode("node_op","op_add",this.createNode("node_op","op_mul",this.derivative(node.children[1][0],varname),this.createNode("node_op","op_div",Type.deepCopy(node.children[1][1]),Type.deepCopy(node.children[1][0]))),this.createNode("node_op","op_mul",this.derivative(node.children[1][1],varname),this.createNode("node_op","op_execfun",this.createNode("node_var","log"),[Type.deepCopy(node.children[1][0])]))));break;case"log":case"ln":newNode=this.createNode("node_op","op_div",this.createNode("node_const",1),Type.deepCopy(arg[0]));break;case"log2":case"lb":case"ld":newNode=this.createNode("node_op","op_mul",this.createNode("node_op","op_div",this.createNode("node_const",1),Type.deepCopy(arg[0])),this.createNode("node_const",1.4426950408889634));break;case"log10":case"lg":newNode=this.createNode("node_op","op_mul",this.createNode("node_op","op_div",this.createNode("node_const",1),Type.deepCopy(arg[0])),this.createNode("node_const",.43429448190325176));break;case"asin":newNode=this.createNode("node_op","op_div",this.createNode("node_const",1),this.createNode("node_op","op_execfun",this.createNode("node_var","sqrt"),[this.createNode("node_op","op_sub",this.createNode("node_const",1),this.createNode("node_op","op_mul",Type.deepCopy(arg[0]),Type.deepCopy(arg[0])))]));break;case"acos":newNode=this.createNode("node_op","op_neg",this.createNode("node_op","op_div",this.createNode("node_const",1),this.createNode("node_op","op_execfun",this.createNode("node_var","sqrt"),[this.createNode("node_op","op_sub",this.createNode("node_const",1),this.createNode("node_op","op_mul",Type.deepCopy(arg[0]),Type.deepCopy(arg[0])))])));break;case"atan":newNode=this.createNode("node_op","op_div",this.createNode("node_const",1),this.createNode("node_op","op_add",this.createNode("node_const",1),this.createNode("node_op","op_mul",Type.deepCopy(arg[0]),Type.deepCopy(arg[0]))));break;case"acot":newNode=this.createNode("node_op","op_neg",this.createNode("node_op","op_div",this.createNode("node_const",1),this.createNode("node_op","op_add",this.createNode("node_const",1),this.createNode("node_op","op_mul",Type.deepCopy(arg[0]),Type.deepCopy(arg[0])))));break;case"sinh":newNode=this.createNode("node_op","op_execfun",this.createNode("node_var","cosh"),[Type.deepCopy(arg[0])]);break;case"cosh":newNode=this.createNode("node_op","op_execfun",this.createNode("node_var","sinh"),[Type.deepCopy(arg[0])]);break;case"tanh":newNode=this.createNode("node_op","op_sub",this.createNode("node_const",1),this.createNode("node_op","op_exp",this.createNode("node_op","op_execfun",this.createNode("node_var","tanh"),[Type.deepCopy(arg[0])]),this.createNode("node_const",2)));break;case"asinh":newNode=this.createNode("node_op","op_div",this.createNode("node_const",1),this.createNode("node_op","op_execfun",this.createNode("node_var","sqrt"),[this.createNode("node_op","op_add",this.createNode("node_op","op_mul",Type.deepCopy(arg[0]),Type.deepCopy(arg[0])),this.createNode("node_const",1))]));break;case"acosh":newNode=this.createNode("node_op","op_div",this.createNode("node_const",1),this.createNode("node_op","op_execfun",this.createNode("node_var","sqrt"),[this.createNode("node_op","op_sub",this.createNode("node_op","op_mul",Type.deepCopy(arg[0]),Type.deepCopy(arg[0])),this.createNode("node_const",1))]));break;case"atanh":newNode=this.createNode("node_op","op_div",this.createNode("node_const",1),this.createNode("node_op","op_sub",this.createNode("node_const",1),this.createNode("node_op","op_mul",Type.deepCopy(arg[0]),Type.deepCopy(arg[0]))));break;default:throw newNode=this.createNode("node_const",0),console.log('Derivative of "'+fun+'" not yet implemented'),new Error("Error("+this.line+"): ")}return newNode},derivative:function(node,varname){var newNode;switch(node.type){case"node_op":switch(node.value){case"op_execfun":newNode="pow"==node.children[0].value?this.deriveElementary(node,varname):0===node.children[1].length?this.createNode("node_const",0):this.createNode("node_op","op_mul",this.deriveElementary(node,varname),this.derivative(node.children[1][0],varname));break;case"op_div":newNode=this.createNode("node_op","op_div",this.createNode("node_op","op_sub",this.createNode("node_op","op_mul",this.derivative(node.children[0],varname),Type.deepCopy(node.children[1])),this.createNode("node_op","op_mul",Type.deepCopy(node.children[0]),this.derivative(node.children[1],varname))),this.createNode("node_op","op_mul",Type.deepCopy(node.children[1]),Type.deepCopy(node.children[1])));break;case"op_mul":newNode=this.createNode("node_op","op_add",this.createNode("node_op","op_mul",Type.deepCopy(node.children[0]),this.derivative(node.children[1],varname)),this.createNode("node_op","op_mul",this.derivative(node.children[0],varname),Type.deepCopy(node.children[1])));break;case"op_neg":newNode=this.createNode("node_op","op_neg",this.derivative(node.children[0],varname));break;case"op_add":case"op_sub":newNode=this.createNode("node_op",node.value,this.derivative(node.children[0],varname),this.derivative(node.children[1],varname));break;case"op_exp":newNode=this.createNode("node_op","op_mul",Type.deepCopy(node),this.createNode("node_op","op_add",this.createNode("node_op","op_mul",this.derivative(node.children[0],varname),this.createNode("node_op","op_div",Type.deepCopy(node.children[1]),Type.deepCopy(node.children[0]))),this.createNode("node_op","op_mul",this.derivative(node.children[1],varname),this.createNode("node_op","op_execfun",this.createNode("node_var","log"),[Type.deepCopy(node.children[0])]))))}break;case"node_var":newNode=node.value===varname?this.createNode("node_const",1):this.createNode("node_const",0);break;case"node_const":newNode=this.createNode("node_const",0)}return newNode},expandDerivatives:function(node,parent,ast){var len,i,j,mapNode,codeNode,node2,newNode,mapName,varname,vArray,order;if(0,!node)return 0;for(this.line=node.line,this.col=node.col,len=node.children.length,i=0;i<len;++i)if(node.children[i]&&node.children[i].type)node.children[i]=this.expandDerivatives(node.children[i],node,ast);else if(Type.isArray(node.children[i]))for(j=0;j<node.children[i].length;++j)node.children[i][j]&&node.children[i][j].type&&(node.children[i][j]=this.expandDerivatives(node.children[i][j],node,ast));if("node_op"===node.type)if("op_execfun"===node.value)if(node.children[0]&&"D"===node.children[0].value){if("node_var"==node.children[1][0].type?(mapName=node.children[1][0].value,vArray=(mapNode=this.findMapNode(mapName,ast)).children[0],varname=node.children[1].length>=2?node.children[1][1].value:mapNode.children[0][0],codeNode=mapNode.children[1]):(codeNode=node.children[1][0],vArray=["x"],varname=node.children[1].length>=2?node.children[1][1].value:"x"),newNode=codeNode,(order=node.children[1].length>=3?node.children[1][2].value:1)>=1)for(;order>=1;)newNode=this.derivative(newNode,varname),newNode=this.removeTrivialNodes(newNode),order--;node2="node_op"==parent.type&&"op_assign"==parent.value?this.createNode("node_op","op_map",vArray,newNode):newNode,this.setMath(node2),node.type=node2.type,node.value=node2.value,node.children[0]=node2.children[0],node.children[1]=node2.children[1]}return node},removeTrivialNodes:function(node){var i,len,n0,n1,swap;if(Type.isArray(node))for(len=node.length,i=0;i<len;++i)node[i]=this.removeTrivialNodes(node[i]);if("node_op"!=node.type||!node.children)return node;for(len=node.children.length,i=0;i<len;++i){this.mayNotBeSimplified=!1;do{node.children[i]=this.removeTrivialNodes(node.children[i])}while(this.mayNotBeSimplified)}switch(node.value){case"op_map":if(n0=node.children[0],"node_var"==(n1=node.children[1]).type)for(i=0;i<n0.length;++i)if(n0[i]==n1.value){n1.isMath=!0;break}break;case"op_add":if(n0=node.children[0],n1=node.children[1],"node_const"==n0.type&&0===n0.value)return n1;if("node_const"==n1.type&&0===n1.value)return n0;if("node_const"==n0.type&&"node_const"==n1.type)return n0.value+=n1.value,n0;break;case"op_mul":if(n0=node.children[0],n1=node.children[1],"node_const"==n0.type&&1==n0.value)return n1;if("node_const"==n1.type&&1==n1.value)return n0;if("node_const"==n0.type&&0===n0.value)return n0;if("node_const"==n1.type&&0===n1.value)return n1;if("node_const"==n1.type&&0===n1.value)return n1;if("node_op"==n0.type&&"op_neg"==n0.value&&"node_op"==n1.type&&"op_neg"==n1.value)return node.children=[n0.children[0],n1.children[0]],this.mayNotBeSimplified=!0,node;if("op_neg"==n0.value&&"op_neg"!=n1.value)return node.type="node_op",node.value="op_neg",node.children=[this.createNode("node_op","op_mul",n0.children[0],n1)],this.mayNotBeSimplified=!0,node;if("op_neg"!=n0.value&&"op_neg"==n1.value)return node.type="node_op",node.value="op_neg",node.children=[this.createNode("node_op","op_mul",n0,n1.children[0])],this.mayNotBeSimplified=!0,node;if("op_div"==n0.value&&"node_const"==n0.children[0].type&&1==n0.children[0].value)return node.type="node_op",node.value="op_div",node.children=[n1,n0.children[1]],this.mayNotBeSimplified=!0,node;if("op_div"==n1.value&&"node_const"==n1.children[0].type&&1==n1.children[0].value)return node.type="node_op",node.value="op_div",node.children=[n0,n1.children[1]],this.mayNotBeSimplified=!0,node;if("node_const"!=n0.type&&"node_const"==n1.type)return node.children=[n1,n0],this.mayNotBeSimplified=!0,node;if("node_const"!=n0.type&&"node_op"==n1.type&&"op_neg"==n1.value&&"node_const"==n1.children[0].type)return node.children=[n1,n0],this.mayNotBeSimplified=!0,node;if("node_op"==n0.type&&"op_execfun"!=n0.value&&("node_var"==n1.type||"node_op"==n1.type&&"op_execfun"==n1.value))return node.children=[n1,n0],this.mayNotBeSimplified=!0,node;if("node_op"!=n0.type&&"node_op"==n1.type&&"op_neg"==n1.value&&"node_var"==n1.children[0].type)return node.children=[n1,n0],this.mayNotBeSimplified=!0,node;if("node_const"!=n0.type&&"node_op"==n1.type&&("op_mul"==n1.value||"op_div"==n1.value)&&"node_const"==n1.children[0].type)return swap=n1.children[0],n1.children[0]=n0,node.children=[swap,n1],this.mayNotBeSimplified=!0,node;if("node_const"!=n1.type&&"node_op"==n0.type&&"op_mul"==n0.value&&"node_const"==n0.children[0].type)return node.children=[n0.children[0],this.createNode("node_op","op_mul",n0.children[1],n1)],this.mayNotBeSimplified=!0,node;if("node_const"==n0.type&&"node_const"==n1.type)return n0.value*=n1.value,n0;if("node_const"==n0.type&&"node_op"==n1.type&&("op_mul"==n1.value||"op_div"==n1.value)&&"node_const"==n1.children[0].type)return n1.children[0].value*=n0.value,n1;if(n0.hash=this.parser.compile(n0),n1.hash=this.parser.compile(n1),n0.hash===n1.hash)return node.value="op_exp",node.children[1]=this.createNode("node_const",2),node;if("node_const"==n0.type&&"node_op"==n1.type&&("op_mul"==n1.value||"op_div"==n1.value)&&"node_const"==n1.children[0].type)return n1.children[0].value*=n0.value,n1;if("node_op"==n1.type&&"op_exp"==n1.value&&(n0.hash||(n0.hash=this.parser.compile(n0)),n1.children[0].hash||(n1.children[0].hash=this.parser.compile(n1.children[0])),n0.hash===n1.children[0].hash))return n1.children[1]=this.createNode("node_op","op_add",n1.children[1],this.createNode("node_const",1)),this.mayNotBeSimplified=!0,n1;if("node_op"==n0.type&&"op_exp"==n0.value&&"node_op"==n1.type&&"op_exp"==n1.value&&(n0.children[0].hash=this.parser.compile(n0.children[0]),n1.children[0].hash=this.parser.compile(n1.children[0]),n0.children[0].hash===n1.children[0].hash))return n0.children[1]=this.createNode("node_op","op_add",n0.children[1],n1.children[1]),this.mayNotBeSimplified=!0,n0;break;case"op_sub":if(n0=node.children[0],n1=node.children[1],"node_const"==n0.type&&0===n0.value)return node.value="op_neg",node.children[0]=n1,node;if("node_const"==n1.type&&0===n1.value)return n0;if("node_const"==n0.type&&"node_const"==n1.type&&n0.value==n1.value)return this.createNode("node_const",0);if("node_var"==n0.type&&"node_var"==n1.type&&n0.value==n1.value)return this.createNode("node_const",0);if("node_const"==n0.type&&"node_const"==n1.type)return n0.value-=n1.value,n0;if("node_op"==n0.type&&"op_mul"==n0.value&&"node_op"==n1.type&&"op_mul"==n1.value&&(n0.children[1].hash=this.parser.compile(n0.children[1]),n1.children[1].hash=this.parser.compile(n1.children[1]),n0.children[1].hash===n1.children[1].hash))return node.value="op_mul",node.children=[this.createNode("node_op","op_sub",n0.children[0],n1.children[0]),n0.children[1]],this.mayNotBeSimplified=!0,node;if("node_op"==n0.type&&"op_mul"==n0.value&&(n0.children[1].hash=this.parser.compile(n0.children[1]),n1.hash=this.parser.compile(n1),n0.children[1].hash===n1.hash))return node.value="op_mul",node.children=[this.createNode("node_op","op_sub",n0.children[0],this.createNode("node_const",1)),n1],this.mayNotBeSimplified=!0,node;if("node_op"==n1.type&&"op_mul"==n1.value&&(n1.children[1].hash=this.parser.compile(n1.children[1]),n0.hash=this.parser.compile(n0),n1.children[1].hash===n0.hash))return node.value="op_mul",node.children=[this.createNode("node_op","op_sub",this.createNode("node_const",1),n1.children[0]),n0],this.mayNotBeSimplified=!0,node;break;case"op_neg":if("node_const"==(n0=node.children[0]).type&&0===n0.value)return n0;if("node_op"==n0.type&&"op_neg"==n0.value)return n0.children[0];break;case"op_div":if(n0=node.children[0],n1=node.children[1],"node_const"==n0.type&&"node_const"==n1.type&&n0.value==n1.value&&0!==n0.value)return n0.value=1,n0;if("node_const"==n0.type&&0===n0.value&&"node_const"==n1.type&&0!==n1.value)return n0.value=0,n0;if("node_const"==n0.type&&0===n0.value&&("node_op"==n1.type||"node_var"==n1.type))return node.type="node_const",node.value=0,node;if("node_var"==n0.type&&"node_var"==n1.type&&n0.value==n1.value)return this.createNode("node_const",1);if("node_const"==n0.type&&0!==n0.value&&"node_const"==n1.type&&0===n1.value)return n0.value>0?n0.value=1/0:n0.value=-1/0,n0;if("node_op"==n0.type&&"op_neg"==n0.value&&"node_op"==n1.type&&"op_neg"==n1.value)return node.children=[n0.children[0],n1.children[0]],this.mayNotBeSimplified=!0,node;if("op_neg"==n0.value&&"op_neg"!=n1.value)return node.type="node_op",node.value="op_neg",node.children=[this.createNode("node_op","op_div",n0.children[0],n1)],this.mayNotBeSimplified=!0,node;if("op_neg"!=n0.value&&"op_neg"==n1.value)return node.type="node_op",node.value="op_neg",node.children=[this.createNode("node_op","op_div",n0,n1.children[0])],this.mayNotBeSimplified=!0,node;if("node_op"==n0.type&&"op_exp"==n0.value&&(n1.hash||(n1.hash=this.parser.compile(n1)),n0.children[0].hash||(n0.children[0].hash=this.parser.compile(n0.children[0])),n1.hash===n0.children[0].hash))return n0.children[1]=this.createNode("node_op","op_sub",n0.children[1],this.createNode("node_const",1)),this.mayNotBeSimplified=!0,n0;if("node_const"!=n1.type&&"node_op"==n0.type&&"op_mul"==n0.value&&"node_const"==n0.children[0].type)return node.value="op_mul",node.children=[n0.children[0],this.createNode("node_op","op_div",n0.children[1],n1)],this.mayNotBeSimplified=!0,node;if("node_op"==n0.type&&"op_exp"==n0.value&&"node_op"==n1.type&&"op_exp"==n1.value&&(n0.children[0].hash=this.parser.compile(n0.children[0]),n1.children[0].hash=this.parser.compile(n1.children[0]),n0.children[0].hash===n1.children[0].hash))return n0.children[1]=this.createNode("node_op","op_sub",n0.children[1],n1.children[1]),this.mayNotBeSimplified=!0,n0;break;case"op_exp":if(n0=node.children[0],"node_const"==(n1=node.children[1]).type&&0===n1.value)return n1.value=1,n1;if("node_const"==n1.type&&1==n1.value)return n0;if("node_const"==n0.type&&1==n0.value)return n0;if("node_const"==n0.type&&0===n0.value&&"node_const"==n1.type&&0!==n1.value)return n0;if("node_op"==n0.type&&"op_exp"==n0.value)return node.children=[n0.children[0],this.createNode("node_op","op_mul",n0.children[1],n1)],node}switch(node.value){case"op_add":if(n0=node.children[0],n1=node.children[1],"node_const"==n0.type&&"node_const"==n1.type&&n0.value==n1.value)return n0.value+=n1.value,n0;if("node_var"==n0.type&&"node_var"==n1.type&&n0.value==n1.value)return node.children[0]=this.createNode("node_const",2),node.value="op_mul",node;if("node_op"==n0.type&&"op_neg"==n0.value)return node.value="op_sub",node.children[0]=n1,node.children[1]=n0.children[0],this.mayNotBeSimplified=!0,node;if("node_op"==n1.type&&"op_neg"==n1.value)return node.value="op_sub",node.children[1]=n1.children[0],this.mayNotBeSimplified=!0,node;if("node_op"==n0.type&&"op_mul"==n0.value&&"node_op"==n1.type&&"op_mul"==n1.value&&(n0.children[1].hash=this.parser.compile(n0.children[1]),n1.children[1].hash=this.parser.compile(n1.children[1]),n0.children[1].hash===n1.children[1].hash))return node.value="op_mul",node.children=[this.createNode("node_op","op_add",n0.children[0],n1.children[0]),n0.children[1]],this.mayNotBeSimplified=!0,node;if("node_op"==n0.type&&"op_mul"==n0.value&&(n0.children[1].hash=this.parser.compile(n0.children[1]),n1.hash=this.parser.compile(n1),n0.children[1].hash===n1.hash))return node.value="op_mul",node.children=[this.createNode("node_op","op_add",n0.children[0],this.createNode("node_const",1)),n1],this.mayNotBeSimplified=!0,node;if("node_op"==n1.type&&"op_mul"==n1.value&&(n1.children[1].hash=this.parser.compile(n1.children[1]),n0.hash=this.parser.compile(n0),n1.children[1].hash===n0.hash))return node.value="op_mul",node.children=[this.createNode("node_op","op_add",this.createNode("node_const",1),n1.children[0]),n0],this.mayNotBeSimplified=!0,node;break;case"op_sub":if(n0=node.children[0],"node_op"==(n1=node.children[1]).type&&"op_neg"==n1.value)return node.value="op_add",node.children[1]=n1.children[0],this.mayNotBeSimplified=!0,node;break;case"op_execfun":return this.simplifyElementary(node)}return node},simplifyElementary:function(node){var fun=node.children[0].value,arg=node.children[1];if(0==arg.length)return node;switch(fun){case"sin":case"tan":if("node_const"==arg[0].type&&0===arg[0].value)return node.type="node_const",node.value=0,node;if("node_var"==arg[0].type&&"PI"==arg[0].value)return node.type="node_const",node.value=0,node;if("node_op"==arg[0].type&&"op_mul"==arg[0].value&&"node_const"==arg[0].children[0].type&&arg[0].children[0].value%1==0&&"node_var"==arg[0].children[1].type&&"PI"==arg[0].children[1].value)return node.type="node_const",node.value=0,node;break;case"cos":if("node_const"==arg[0].type&&0===arg[0].value)return node.type="node_const",node.value=1,node;if("node_var"==arg[0].type&&"PI"==arg[0].value)return node.type="node_op",node.value="op_neg",node.children=[this.createNode("node_const",1)],node;break;case"exp":if("node_const"==arg[0].type&&0===arg[0].value)return node.type="node_const",node.value=1,node;break;case"pow":if("node_const"==arg[1].type&&0===arg[1].value)return node.type="node_const",node.value=1,node}return node}}),JXG.CA})),define("utils/dump",["jxg","utils/type"],(function(JXG,Type){return JXG.Dump={addMarkers:function(board,markers,values){var e,l,i;for(e in Type.isArray(markers)||(markers=[markers]),Type.isArray(values)||(values=[values]),l=Math.min(markers.length,values.length),markers.length=l,values.length=l,board.objects)if(board.objects.hasOwnProperty(e))for(i=0;i<l;i++)board.objects[e][markers[i]]=values[i]},deleteMarkers:function(board,markers){var e,l,i;for(e in Type.isArray(markers)||(markers=[markers]),l=markers.length,markers.length=l,board.objects)if(board.objects.hasOwnProperty(e))for(i=0;i<l;i++)delete board.objects[e][markers[i]]},str:function(s){return"string"==typeof s&&"function"!==s.substr(0,7)&&(s='"'+s+'"'),s},minimizeObject:function(instance,s){var p,pl,i,def={},copy=Type.deepCopy(instance),defaults=[];for(i=1;i<arguments.length;i++)defaults.push(arguments[i]);for(def=Type.deepCopy(def,JXG.Options.elements,!0),i=defaults.length;i>0;i--)def=Type.deepCopy(def,defaults[i-1],!0);for(p in def)def.hasOwnProperty(p)&&(pl=p.toLowerCase(),"object"!==_typeof(def[p])&&def[p]===copy[pl]&&delete copy[pl]);return copy},prepareAttributes:function(board,obj){var a,s;for(s in a=this.minimizeObject(obj.getAttributes(),JXG.Options[obj.elType]),obj.subs)obj.subs.hasOwnProperty(s)&&(a[s]=this.minimizeObject(obj.subs[s].getAttributes(),JXG.Options[obj.elType][s],JXG.Options[obj.subs[s].elType]),a[s].id=obj.subs[s].id,a[s].name=obj.subs[s].name);return a.id=obj.id,a.name=obj.name,a},setBoundingBox:function(methods,board,boardVarName){return methods.push({obj:boardVarName,method:"setBoundingBox",params:[board.getBoundingBox(),board.keepaspectratio]}),methods},dump:function(board){var e,obj,element,s,props=[],elementList=[],len=board.objectsList.length;for(this.addMarkers(board,"dumped",!1),e=0;e<len;e++)if(element={},!(obj=board.objectsList[e]).dumped&&obj.dump){for(element.type=obj.getType(),element.parents=obj.getParents().slice(),"point"===element.type&&1===element.parents[0]&&(element.parents=element.parents.slice(1)),s=0;s<element.parents.length;s++)Type.isString(element.parents[s])&&"'"!==element.parents[s][0]&&'"'!==element.parents[s][0]?element.parents[s]='"'+element.parents[s]+'"':Type.isArray(element.parents[s])&&(element.parents[s]="["+element.parents[s].toString()+"]");element.attributes=this.prepareAttributes(board,obj),"glider"===element.type&&obj.onPolygon&&props.push({obj:obj.id,prop:"onPolygon",val:!0}),elementList.push(element)}return this.deleteMarkers(board,"dumped"),{elements:elementList,props:props,methods:[]}},arrayToParamStr:function(a,converter){var i,s=[];for(i=0;i<a.length;i++)s.push(converter.call(this,a[i]));return s.join(", ")},toJCAN:function(obj){var i,list,prop;switch(_typeof(obj)){case"object":if(obj){if(list=[],Type.isArray(obj)){for(i=0;i<obj.length;i++)list.push(this.toJCAN(obj[i]));return"["+list.join(",")+"]"}for(prop in obj)obj.hasOwnProperty(prop)&&list.push(prop+": "+this.toJCAN(obj[prop]));return"<<"+list.join(", ")+">> "}return"null";case"string":return"'"+obj.replace(/\\/g,"\\\\").replace(/(["'])/g,"\\$1")+"'";case"number":case"boolean":return obj.toString();case"null":return"null"}},toJessie:function(board){var i,elements,id,dump=this.dump(board),script=[];for(dump.methods=this.setBoundingBox(dump.methods,board,"$board"),elements=dump.elements,i=0;i<elements.length;i++)elements[i].attributes.name.length>0&&script.push("// "+elements[i].attributes.name),script.push("s"+i+" = "+elements[i].type+"("+elements[i].parents.join(", ")+") "+this.toJCAN(elements[i].attributes).replace(/\n/,"\\n")+";"),"axis"===elements[i].type&&(id=elements[i].attributes.id,null===board.objects[id].defaultTicks&&script.push("s"+i+".removeAllTicks();")),script.push("");for(i=0;i<dump.methods.length;i++)script.push(dump.methods[i].obj+"."+dump.methods[i].method+"("+this.arrayToParamStr(dump.methods[i].params,this.toJCAN)+");"),script.push("");for(i=0;i<dump.props.length;i++)script.push(dump.props[i].obj+"."+dump.props[i].prop+" = "+this.toJCAN(dump.props[i].val)+";"),script.push("");return script.join("\n")},toJavaScript:function(board){var i,elements,id,dump=this.dump(board),script=[];for(dump.methods=this.setBoundingBox(dump.methods,board,"board"),elements=dump.elements,i=0;i<elements.length;i++)script.push('board.create("'+elements[i].type+'", ['+elements[i].parents.join(", ")+"], "+Type.toJSON(elements[i].attributes)+");"),"axis"===elements[i].type&&(id=elements[i].attributes.id,null===board.objects[id].defaultTicks&&script.push('board.objects["'+id+'"].removeTicks(board.objects["'+id+'"].defaultTicks);'));for(i=0;i<dump.methods.length;i++)script.push(dump.methods[i].obj+"."+dump.methods[i].method+"("+this.arrayToParamStr(dump.methods[i].params,Type.toJSON)+");"),script.push("");for(i=0;i<dump.props.length;i++)script.push(dump.props[i].obj+"."+dump.props[i].prop+" = "+Type.toJSON(dump.props[i].val)+";"),script.push("");return script.join("\n")}},JXG.Dump})),define("element/comb",["jxg","utils/type","base/point"],(function(JXG,Type,Point){return JXG.createComb=function(board,parents,attributes){var p1,p2,c,attr,parent_types;if(2!==parents.length)throw parent_types=parents.map((function(parent){return"'"+_typeof(parent)+"'"})),new Error("JSXGraph: Can't create comb with parent types "+parent_types.join(", ")+".\nPossible parent types: [point,point], [[x1,y1],[x2,y2]]");if(Type.isArray(parents[0])&&parents[0].length>1)attr=Type.copyAttributes(attributes,board.options,"comb","point1"),p1=board.create("point",parents[0],attr);else if(Type.isString(parents[0])||Type.isPoint(parents[0]))p1=board.select(parents[0]);else if(Type.isFunction(parents[0])&&Type.isPoint(parents[0]()))p1=parents[0]();else{if(!(Type.isFunction(parents[0])&&parents[0]().length&&parents[0]().length>=2))throw new Error("JSXGraph: Can't create comb with parent types '"+_typeof(parents[0])+"' and '"+_typeof(parents[1])+"'.\nPossible parent types: [point,point], [[x1,y1],[x2,y2]]");attr=Type.copyAttributes(attributes,board.options,"comb","point1"),p1=Point.createPoint(board,parents[0](),attr)}if(Type.isArray(parents[1])&&parents[1].length>1)attr=Type.copyAttributes(attributes,board.options,"comb","point2"),p2=board.create("point",parents[1],attr);else if(Type.isString(parents[1])||Type.isPoint(parents[1]))p2=board.select(parents[1]);else if(Type.isFunction(parents[1])&&Type.isPoint(parents[1]()))p2=parents[1]();else{if(!(Type.isFunction(parents[1])&&parents[1]().length&&parents[1]().length>=2))throw new Error("JSXGraph: Can't create comb with parent types '"+_typeof(parents[0])+"' and '"+_typeof(parents[1])+"'.\nPossible parent types: [point,point], [[x1,y1],[x2,y2]]");attr=Type.copyAttributes(attributes,board.options,"comb","point2"),p2=Point.createPoint(board,parents[1](),attr)}return attr=Type.copyAttributes(attributes,board.options,"comb"),Type.merge(attr,Type.copyAttributes(attributes,board.options,"comb","curve")),(c=board.create("curve",[[0],[0]],attr)).updateDataArray=function(){var cs,sn,dx,dy,x,y,f,ds,angle,width,s=0,max_s=p1.Dist(p2),p1_inner=p1,p2_inner=p2;for(ds=Type.evaluate(c.visProp.frequency),angle=-Type.evaluate(c.visProp.angle),width=Type.evaluate(c.visProp.width),Type.evaluate(c.visProp.reverse)&&(p1_inner=p2,p2_inner=p1,angle=-angle),cs=Math.cos(angle),sn=Math.sin(angle),dx=(p2_inner.X()-p1_inner.X())/max_s,dy=(p2_inner.Y()-p1_inner.Y())/max_s,cs*=width/Math.abs(sn),sn*=width/Math.abs(sn),this.dataX=[],this.dataY=[];s<max_s;)x=p1_inner.X()+dx*s,y=p1_inner.Y()+dy*s,sn*=f=Math.min(cs,max_s-s)/Math.abs(cs),cs*=f,this.dataX.push(x),this.dataY.push(y),this.dataX.push(x+dx*cs+dy*sn),this.dataY.push(y-dx*sn+dy*cs),this.dataX.push(NaN),this.dataY.push(NaN),s+=ds},c},JXG.registerElement("comb",JXG.createComb),{createComb:JXG.createComb}})),define("element/slopetriangle",["jxg","utils/type","base/constants","base/polygon"],(function(JXG,Type,Const,Polygon){var priv_removeSlopeTriangle=function(){Polygon.Polygon.prototype.remove.call(this),this.board.removeObject(this.toppoint),this.board.removeObject(this.glider),this.board.removeObject(this.baseline),this.board.removeObject(this.basepoint),this.board.removeObject(this.label),this._isPrivateTangent&&this.board.removeObject(this.tangent)},priv_Value=function(){return this.tangent.getSlope()};return JXG.createSlopeTriangle=function(board,parents,attributes){var el,tangent,tglide,glider,toppoint,baseline,basepoint,label,attr,isPrivateTangent=!1;if(1===parents.length&&parents[0].type===Const.OBJECT_TYPE_TANGENT)tangent=parents[0],tglide=tangent.glider;else if(1===parents.length&&parents[0].type===Const.OBJECT_TYPE_GLIDER)tglide=parents[0],attr=Type.copyAttributes(attributes,board.options,"slopetriangle","tangent"),tangent=board.create("tangent",[tglide],attr),isPrivateTangent=!0;else{if(2!==parents.length||parents[0].elementClass!==Const.OBJECT_CLASS_LINE||!Type.isPoint(parents[1]))throw new Error("JSXGraph: Can't create slope triangle with parent types '"+_typeof(parents[0])+"'.");tangent=parents[0],tglide=parents[1]}return attr=Type.copyAttributes(attributes,board.options,"slopetriangle","basepoint"),basepoint=board.create("point",[function(){return[tglide.X()+1,tglide.Y()]}],attr),attr=Type.copyAttributes(attributes,board.options,"slopetriangle","baseline"),baseline=board.create("line",[tglide,basepoint],attr),attr=Type.copyAttributes(attributes,board.options,"slopetriangle","glider"),glider=board.create("glider",[tglide.X()+1,tglide.Y(),baseline],attr),attr=Type.copyAttributes(attributes,board.options,"slopetriangle","toppoint"),toppoint=board.create("point",[function(){return[glider.X(),glider.Y()+(glider.X()-tglide.X())*tangent.getSlope()]}],attr),(attr=Type.copyAttributes(attributes,board.options,"slopetriangle")).borders=Type.copyAttributes(attr.borders,board.options,"slopetriangle","borders"),(el=board.create("polygon",[tglide,glider,toppoint],attr)).Value=priv_Value,el.tangent=tangent,el._isPrivateTangent=isPrivateTangent,el.borders[2].setArrow(!1,!1),attr=Type.copyAttributes(attributes,board.options,"slopetriangle","label"),(label=board.create("text",[function(){return glider.X()+.1},function(){return.5*(glider.Y()+toppoint.Y())},function(){return""}],attr))._setText((function(){return Type.toFixed(el.Value(),Type.evaluate(label.visProp.digits))})),label.fullUpdate(),el.glider=glider,el.basepoint=basepoint,el.baseline=baseline,el.toppoint=toppoint,el.label=label,el.subs={glider:glider,basePoint:basepoint,baseLine:baseline,topPoint:toppoint,label:label},el.inherits.push(glider,basepoint,baseline,toppoint,label),el.methodMap=JXG.deepCopy(el.methodMap,{tangent:"tangent",glider:"glider",basepoint:"basepoint",baseline:"baseline",toppoint:"toppoint",label:"label",Value:"Value",V:"Value"}),el.remove=priv_removeSlopeTriangle,el},JXG.registerElement("slopetriangle",JXG.createSlopeTriangle),{createSlopeTriangle:JXG.createSlopeTriangle}})),define("element/checkbox",["jxg","utils/env","utils/type"],(function(JXG,Env,Type){var priv_CheckboxChangeEventHandler=function(){this._value=this.rendNodeCheckbox.checked,this.board.update()};return JXG.createCheckbox=function(board,parents,attributes){var t,par,attr=Type.copyAttributes(attributes,board.options,"checkbox");return par=[parents[0],parents[1],'<span style="display:inline"><input type="checkbox" /><label for=""></label></span>'],(t=board.create("text",par,attr)).type=Type.OBJECT_TYPE_CHECKBOX,t.rendNodeCheckbox=t.rendNode.childNodes[0].childNodes[0],t.rendNodeLabel=t.rendNode.childNodes[0].childNodes[1],t.rendNodeTag=t.rendNodeCheckbox,t.rendNodeTag.disabled=!!attr.disabled,t.rendNodeLabel.innerHTML=parents[2],t.rendNodeCheckbox.id=t.rendNode.id+"_checkbox",t.rendNodeLabel.id=t.rendNode.id+"_label",t.rendNodeLabel.setAttribute("for",t.rendNodeCheckbox.id),t.visPropOld.fontsize="0px",board.renderer.updateTextStyle(t,!1),t.rendNodeCheckbox.checked=attr.checked,t._value=attr.checked,t.Value=function(){return this._value},t.update=function(){return this.needsUpdate&&(JXG.Text.prototype.update.call(this),this._value=this.rendNodeCheckbox.checked),this},Env.addEvent(t.rendNodeCheckbox,"change",priv_CheckboxChangeEventHandler,t),t},JXG.registerElement("checkbox",JXG.createCheckbox),{createCheckbox:JXG.createCheckbox}})),define("element/input",["jxg","utils/env","utils/type"],(function(JXG,Env,Type){var priv_InputInputEventHandler=function(evt){this._value=this.rendNodeInput.value,this.board.update()};return JXG.createInput=function(board,parents,attributes){var t,par,attr=Type.copyAttributes(attributes,board.options,"input");return par=[parents[0],parents[1],'<span style="display:inline; white-space:nowrap; padding:0px;"><span></span><input type="text" maxlength="'+attr.maxlength+'" style="width:100%"/></span>'],(t=board.create("text",par,attr)).type=Type.OBJECT_TYPE_INPUT,t.rendNodeLabel=t.rendNode.childNodes[0].childNodes[0],t.rendNodeInput=t.rendNode.childNodes[0].childNodes[1],t.rendNodeLabel.innerHTML=parents[3],t.rendNodeInput.value=parents[2],t.rendNodeTag=t.rendNodeInput,t.rendNodeTag.disabled=!!attr.disabled,t.rendNodeLabel.id=t.rendNode.id+"_label",t.rendNodeInput.id=t.rendNode.id+"_input",t._value=parents[2],t.update=function(){return this.needsUpdate&&(JXG.Text.prototype.update.call(this),this._value=this.rendNodeInput.value),this},t.Value=function(){return this._value},t.set=function(val){return this._value=val,this.rendNodeInput.value=val,this},Env.addEvent(t.rendNodeInput,"input",priv_InputInputEventHandler,t),Env.addEvent(t.rendNodeInput,"mousedown",(function(evt){Type.exists(evt.stopPropagation)&&evt.stopPropagation()}),t),Env.addEvent(t.rendNodeInput,"touchstart",(function(evt){Type.exists(evt.stopPropagation)&&evt.stopPropagation()}),t),Env.addEvent(t.rendNodeInput,"pointerdown",(function(evt){Type.exists(evt.stopPropagation)&&evt.stopPropagation()}),t),t.visPropOld.fontsize="0px",board.renderer.updateTextStyle(t,!1),t},JXG.registerElement("input",JXG.createInput),{createInput:JXG.createInput}})),define("element/button",["jxg","utils/env","utils/type"],(function(JXG,Env,Type){var priv_ButtonClickEventHandler=function(){this._handler&&this._handler(),this.board.update()};return JXG.createButton=function(board,parents,attributes){var t,par,attr=Type.copyAttributes(attributes,board.options,"button");return par=[parents[0],parents[1],'<button type="button" style="width:100%;"></button>'],(t=board.create("text",par,attr)).type=Type.OBJECT_TYPE_BUTTON,t.rendNodeButton=t.rendNode.childNodes[0],t.rendNodeButton.id=t.rendNode.id+"_button",t.rendNodeButton.innerHTML=parents[2],t.rendNodeTag=t.rendNodeButton,t.rendNodeTag.disabled=!!attr.disabled,t.visPropOld.fontsize="0px",board.renderer.updateTextStyle(t,!1),parents[3]&&(Type.isString(parents[3])?(t._jc=new JXG.JessieCode,t._jc.use(board),t._handler=function(){t._jc.parse(parents[3])}):t._handler=parents[3]),Env.addEvent(t.rendNodeButton,"click",priv_ButtonClickEventHandler,t),Env.addEvent(t.rendNodeButton,"mousedown",(function(evt){Type.exists(evt.stopPropagation)&&evt.stopPropagation()}),t),Env.addEvent(t.rendNodeButton,"touchstart",(function(evt){Type.exists(evt.stopPropagation)&&evt.stopPropagation()}),t),Env.addEvent(t.rendNodeButton,"pointerdown",(function(evt){Type.exists(evt.stopPropagation)&&evt.stopPropagation()}),t),t},JXG.registerElement("button",JXG.createButton),{createButton:JXG.createButton}})),define("base/foreignobject",["jxg","base/constants","base/coords","base/element","math/math","utils/type","base/coordselement"],(function(JXG,Const,Coords,GeometryElement,Mat,Type,CoordsElement){return JXG.ForeignObject=function(board,coords,attributes,content,size){this.constructor(board,attributes,Const.OBJECT_TYPE_FOREIGNOBJECT,Const.OBJECT_CLASS_OTHER),this.element=this.board.select(attributes.anchor),this.coordsConstructor(coords),this._useUserSize=!1,this.size=[1,1],Type.exists(size)&&size.length>0&&(this._useUserSize=!0,this.W=Type.createFunction(size[0],this.board,""),this.H=Type.createFunction(size[1],this.board,""),this.usrSize=[this.W(),this.H()]),this.content=content,this.elType="foreignobject",this.id=this.board.setId(this,"Im"),this.board.renderer.drawForeignObject(this),this.board.finalizeAdding(this),this.methodMap=JXG.deepCopy(this.methodMap,{addTransformation:"addTransform",trans:"addTransform"})},JXG.ForeignObject.prototype=new GeometryElement,Type.copyPrototypeMethods(JXG.ForeignObject,CoordsElement,"coordsConstructor"),JXG.extend(JXG.ForeignObject.prototype,{hasPoint:function(x,y){var dx,dy,r,type,prec,c,v,p,dot,len=this.transformations.length;return Type.isObject(Type.evaluate(this.visProp.precision))?(type=this.board._inputDevice,prec=Type.evaluate(this.visProp.precision[type])):prec=this.board.options.precision.hasPoint,0===len?(dx=x-this.coords.scrCoords[1],dy=this.coords.scrCoords[2]-y,dx>=-(r=prec)&&dx-this.size[0]<=r&&dy>=-r&&dy-this.size[1]<=r):(v=[(c=(c=new Coords(Const.COORDS_BY_SCREEN,[x,y],this.board)).usrCoords)[0]-this.span[0][0],c[1]-this.span[0][1],c[2]-this.span[0][2]],0<=(p=(dot=Mat.innerProduct)(v,this.span[1]))&&p<=dot(this.span[1],this.span[1])&&0<=(p=dot(v,this.span[2]))&&p<=dot(this.span[2],this.span[2]))},update:function(fromParent){return this.needsUpdate?(this.updateCoords(fromParent),this.updateSize(),this):this},updateRenderer:function(){return this.updateRendererGeneric("updateForeignObject")},updateSize:function(){var bb=[0,0];return this._useUserSize?(this.usrSize=[this.W(),this.H()],this.size=[Math.abs(this.usrSize[0]*this.board.unitX),Math.abs(this.usrSize[1]*this.board.unitY)]):this.rendNode.hasChildNodes()&&(bb=this.rendNode.childNodes[0].getBoundingClientRect(),this.size=[bb.width,bb.height]),this},updateSpan:function(){var i,j,len=this.transformations.length,v=[];if(0===len)this.span=[[this.Z(),this.X(),this.Y()],[this.Z(),this.W(),0],[this.Z(),0,this.H()]];else{for(v[0]=[this.Z(),this.X(),this.Y()],v[1]=[this.Z(),this.X()+this.W(),this.Y()],v[2]=[this.Z(),this.X(),this.Y()+this.H()],i=0;i<len;i++)for(j=0;j<3;j++)v[j]=Mat.matVecMult(this.transformations[i].matrix,v[j]);for(j=0;j<3;j++)v[j][1]/=v[j][0],v[j][2]/=v[j][0],v[j][0]/=v[j][0];for(j=1;j<3;j++)v[j][0]-=v[0][0],v[j][1]-=v[0][1],v[j][2]-=v[0][2];this.span=v}return this},addTransform:function(transform){var i;if(Type.isArray(transform))for(i=0;i<transform.length;i++)this.transformations.push(transform[i]);else this.transformations.push(transform);return this},getParents:function(){var p=[this.url,[this.Z(),this.X(),this.Y()],this.usrSize];return 0!==this.parents.length&&(p=this.parents),p},setSize:function(width,height){return this.W=Type.createFunction(width,this.board,""),this.H=Type.createFunction(height,this.board,""),this._useUserSize=!0,this},W:function(){},H:function(){}}),JXG.createForeignObject=function(board,parents,attributes){var attr,fo,content=parents[0],coords=parents[1],size=[];if(parents.length>=2&&(size=parents[2]),attr=Type.copyAttributes(attributes,board.options,"foreignobject"),!(fo=CoordsElement.create(JXG.ForeignObject,board,coords,attr,content,size)))throw new Error("JSXGraph: Can't create foreignObject with parent types '"+_typeof(parents[0])+"' and '"+_typeof(parents[1])+"'.\nPossible parent types: [string, [x, y], [w, h]], [string, [x, y]], [element,transformation]");return fo},JXG.registerElement("foreignobject",JXG.createForeignObject),JXG.registerElement("fo",JXG.createForeignObject),{ForeignObject:JXG.ForeignObject,createForeignobject:JXG.createForeignObject}})),define("options3d",["jxg","options"],(function(JXG,Options){return JXG.extend(Options,{infobox:{strokeColor:"black"},axes3d:{axesPosition:"center",xAxis:{visible:!0,point2:{name:"x"}},yAxis:{visible:!0,point2:{name:"y"}},zAxis:{visible:!0,point2:{name:"z"}},xPlaneRear:{visible:!0,layer:0,mesh3d:{layer:1}},yPlaneRear:{visible:!0,layer:0,mesh3d:{layer:1}},zPlaneRear:{visible:!0,layer:0,mesh3d:{layer:1}},xPlaneFront:{visible:!1,layer:0,mesh3d:{layer:1}},yPlaneFront:{visible:!1,layer:0,mesh3d:{layer:1}},zPlaneFront:{visible:!1,layer:0,mesh3d:{layer:1}},xPlaneRearYAxis:{visible:"inherit",strokeColor:"#888888",strokeWidth:1},xPlaneRearZAxis:{visible:"inherit",strokeColor:"#888888",strokeWidth:1},xPlaneFrontYAxis:{visible:"inherit",strokeColor:"#888888",strokeWidth:1},xPlaneFrontZAxis:{visible:"inherit",strokeColor:"#888888",strokeWidth:1},yPlaneRearXAxis:{visible:"inherit",strokeColor:"#888888",strokeWidth:1},yPlaneRearZAxis:{visible:"inherit",strokeColor:"#888888",strokeWidth:1},yPlaneFrontXAxis:{visible:"inherit",strokeColor:"#888888",strokeWidth:1},yPlaneFrontZAxis:{visible:"inherit",strokeColor:"#888888",strokeWidth:1},zPlaneRearXAxis:{visible:"inherit",strokeColor:"#888888",strokeWidth:1},zPlaneRearYAxis:{visible:"inherit",strokeColor:"#888888",strokeWidth:1},zPlaneFrontXAxis:{visible:"inherit",strokeColor:"#888888",strokeWidth:1},zPlaneFrontYAxis:{visible:"inherit",strokeColor:"#888888",strokeWidth:1}},axis3d:{highlight:!1,strokecolor:"black",strokeWidth:1,tabindex:null,point1:{visible:!1,name:""},point2:{visible:!1,name:"",label:{visible:!0}}},mesh3d:{strokeWidth:1,strokeColor:"#9a9a9a",strokeOpacity:.6,highlight:!1,fillColor:"#9a9a9a",fillOpacity:.1,tabindex:null,visible:"inherit"},line3d:{strokeWidth:1,strokeColor:"black",fixed:!0,tabindex:null,gradient:"linear",gradientSecondColor:"#ffffff",point1:{visible:!1,name:""},point2:{visible:!1,name:""}},plane3d:{strokeWidth:0,strokeColor:"black",strokeOpacity:1,highlight:!1,tabindex:null,gradient:"linear",gradientSecondColor:"#ffffff",gradientAngle:Math.PI,fillColor:"#a7a7a7",fillOpacity:.6},point3d:{strokeWidth:0,gradient:"radial",gradientSecondColor:"#555555",fillColor:"yellow",highlightStrokeColor:"#555555"},surface3d:{highlight:!1,tabindex:-1,strokeWidth:1,stepsU:30,stepsV:30},view3d:{needsRegularUpdate:!0}}),JXG.Options})),define("3d/threed",["jxg"],(function(JXG){return JXG.ThreeD={},JXG.ThreeD})),define("3d/view3d",["jxg","options","base/constants","utils/type","math/math","base/element","3d/threed"],(function(JXG,Options,Const,Type,Mat,GeometryElement,ThreeD){return ThreeD.View3D=function(board,parents,attributes){var bbox3d,coords,size;this.constructor(board,attributes,Const.OBJECT_TYPE_VIEW3D,Const.OBJECT_CLASS_CURVE),bbox3d=parents[2],coords=parents[0],size=parents[1],this.D3={},this.D3.objects={},this.D3.objectsList=[],this.D3.defaultAxes=null,this.D3.matrix=[[1,0,0,0],[0,1,0,0],[0,0,1,0]],this.D3.bbox3d=bbox3d,this.D3.coords=coords,this.D3.size=size,this.D3.r=-1,this.timeoutAzimuth=null,this.id=this.board.setId(this,"V"),this.board.finalizeAdding(this),this.elType="view3d",this.methodMap=Type.deepCopy(this.methodMap,{})},ThreeD.View3D.prototype=new GeometryElement,JXG.extend(ThreeD.View3D.prototype,{create:function(elementType,parents,attributes){var el,prefix=[];return elementType.indexOf("3d")>0&&(!0,prefix.push(this)),el=this.board.create(elementType,prefix.concat(parents),attributes),this.add(el),el},add:function(el){this.D3.objects[el.id]=el,this.D3.objectsList.push(el)},update:function(){var e,r,a,f,mat,D3=this.D3;return Type.exists(D3.el_slide)&&Type.exists(D3.az_slide)&&this.needsUpdate?(e=D3.el_slide.Value(),r=D3.r,a=D3.az_slide.Value(),f=r*Math.sin(e),mat=[[1,0,0],[0,1,0],[0,0,1]],D3.matrix=[[1,0,0,0],[0,1,0,0],[0,0,1,0]],D3.matrix[1][1]=r*Math.cos(a),D3.matrix[1][2]=-r*Math.sin(a),D3.matrix[2][1]=f*Math.sin(a),D3.matrix[2][2]=f*Math.cos(a),D3.matrix[2][3]=Math.cos(e),mat[1][1]=D3.size[0]/(D3.bbox3d[0][1]-D3.bbox3d[0][0]),mat[2][2]=D3.size[1]/(D3.bbox3d[1][1]-D3.bbox3d[1][0]),mat[1][0]=D3.coords[0]-mat[1][1]*D3.bbox3d[0][0],mat[2][0]=D3.coords[1]-mat[2][2]*D3.bbox3d[1][0],D3.matrix=Mat.matMatMult(mat,D3.matrix),this):this},updateRenderer:function(){return this.needsUpdate=!1,this},project3DTo2D:function(x,y,z){var vec;return vec=3===arguments.length?[1,x,y,z]:3===x.length?[1].concat(x):x,Mat.matVecMult(this.D3.matrix,vec)},project2DTo3DPlane:function(point,normal,foot){var mat,rhs,d,le,n=normal.slice(1),sol=[1,0,0,0];foot=foot||[1,0,0,0],le=Mat.norm(n,3),d=Mat.innerProduct(foot.slice(1),n,3)/le,(mat=this.D3.matrix.slice(0,3)).push([0].concat(n)),rhs=point.coords.usrCoords.concat([d]);try{1===mat[2][3]&&(mat[2][1]=mat[2][2]=.001*Mat.eps),sol=Mat.Numerics.Gauss(mat,rhs)}catch(err){sol=[0,NaN,NaN,NaN]}return sol},project3DToCube:function(c3d){var cube=this.D3.bbox3d;return c3d[1]<cube[0][0]&&(c3d[1]=cube[0][0]),c3d[1]>cube[0][1]&&(c3d[1]=cube[0][1]),c3d[2]<cube[1][0]&&(c3d[2]=cube[1][0]),c3d[2]>cube[1][1]&&(c3d[2]=cube[1][1]),c3d[3]<cube[2][0]&&(c3d[3]=cube[2][0]),c3d[3]>cube[2][1]&&(c3d[3]=cube[2][1]),c3d},intersectionLineCube:function(p,d,r){var rnew,i,r0,r1;for(rnew=r,i=0;i<3;i++)0!==d[i]&&(r0=(this.D3.bbox3d[i][0]-p[i])/d[i],r1=(this.D3.bbox3d[i][1]-p[i])/d[i],rnew=r<0?Math.max(rnew,Math.min(r0,r1)):Math.min(rnew,Math.max(r0,r1)));return rnew},isInCube:function(q){return q[0]>this.D3.bbox3d[0][0]-Mat.eps&&q[0]<this.D3.bbox3d[0][1]+Mat.eps&&q[1]>this.D3.bbox3d[1][0]-Mat.eps&&q[1]<this.D3.bbox3d[1][1]+Mat.eps&&q[2]>this.D3.bbox3d[2][0]-Mat.eps&&q[2]<this.D3.bbox3d[2][1]+Mat.eps},intersectionPlanePlane:function(plane1,plane2,d){var p,dir,r,q,ret=[[],[]];return d=d||plane2.D3.d,p=Mat.Geometry.meet3Planes(plane1.D3.normal,plane1.D3.d,plane2.D3.normal,d,Mat.crossProduct(plane1.D3.normal,plane2.D3.normal),0),dir=Mat.Geometry.meetPlanePlane(plane1.D3.dir1,plane1.D3.dir2,plane2.D3.dir1,plane2.D3.dir2),r=this.intersectionLineCube(p,dir,1/0),q=Mat.axpy(r,dir,p),this.isInCube(q)&&(ret[0]=q),r=this.intersectionLineCube(p,dir,-1/0),q=Mat.axpy(r,dir,p),this.isInCube(q)&&(ret[1]=q),ret},getMesh:function(X,Y,Z,interval_u,interval_v){var i_u,i_v,u,v,c2d,delta_u,delta_v,p=[0,0,0],steps_u=interval_u[2],steps_v=interval_v[2],dataX=[],dataY=[];for(delta_u=(Type.evaluate(interval_u[1])-Type.evaluate(interval_u[0]))/steps_u,delta_v=(Type.evaluate(interval_v[1])-Type.evaluate(interval_v[0]))/steps_v,i_u=0;i_u<=steps_u;i_u++){for(u=interval_u[0]+delta_u*i_u,i_v=0;i_v<=steps_v;i_v++)v=interval_v[0]+delta_v*i_v,p[0]=X(u,v),p[1]=Y(u,v),p[2]=Z(u,v),c2d=this.project3DTo2D(p),dataX.push(c2d[1]),dataY.push(c2d[2]);dataX.push(NaN),dataY.push(NaN)}for(i_v=0;i_v<=steps_v;i_v++){for(v=interval_v[0]+delta_v*i_v,i_u=0;i_u<=steps_u;i_u++)u=interval_u[0]+delta_u*i_u,p[0]=X(u,v),p[1]=Y(u,v),p[2]=Z(u,v),c2d=this.project3DTo2D(p),dataX.push(c2d[1]),dataY.push(c2d[2]);dataX.push(NaN),dataY.push(NaN)}return[dataX,dataY]},animateAzimuth:function(){var s=this.D3.az_slide._smin,sdiff=this.D3.az_slide._smax-s,newVal=this.D3.az_slide.Value()+.1;this.D3.az_slide.position=(newVal-s)/sdiff,this.D3.az_slide.position>1&&(this.D3.az_slide.position=0),this.board.update(),this.timeoutAzimuth=setTimeout(function(){this.animateAzimuth()}.bind(this),200)},stopAzimuth:function(){clearTimeout(this.timeoutAzimuth),this.timeoutAzimuth=null}}),ThreeD.createView3D=function(board,parents,attributes){var view,attr,x,y,w,h,coords=parents[0],size=parents[1];return attr=Type.copyAttributes(attributes,board.options,"view3d"),(view=new ThreeD.View3D(board,parents,attr)).defaultAxes=view.create("axes3d",parents,attributes),x=coords[0],y=coords[1],w=size[0],h=size[1],view.D3.az_slide=board.create("slider",[[x-1,y-2],[x+w+1,y-2],[0,1,2*Math.PI]],{style:6,name:"az",point1:{frozen:!0},point2:{frozen:!0}}),view.D3.el_slide=board.create("slider",[[x-1,y],[x-1,y+h],[0,.3,Math.PI/2]],{style:6,name:"el",point1:{frozen:!0},point2:{frozen:!0}}),view.board.highlightInfobox=function(x,y,el){var d;Type.exists(el.D3)?"auto"===(d=Type.evaluate(el.visProp.infoboxdigits))?view.board.highlightCustomInfobox("("+Type.autoDigits(el.D3.X())+" | "+Type.autoDigits(el.D3.Y())+" | "+Type.autoDigits(el.D3.Z())+")",el):view.board.highlightCustomInfobox("("+Type.toFixed(el.D3.X(),d)+" | "+Type.toFixed(el.D3.Y(),d)+" | "+Type.toFixed(el.D3.Z(),d)+")",el):view.board.highlightCustomInfobox("("+x+", "+y+")",el)},view},JXG.registerElement("view3d",ThreeD.createView3D),ThreeD.View3D})),define("3d/box3d",["jxg","utils/type","math/math","math/geometry","3d/view3d"],(function(JXG,Type,Mat,Geometry,ThreeD){ThreeD.createAxes=function(board,parents,attributes){var i,j,k,i1,i2,attr,pos,dir,from,to,vec1,vec2,range1,range2,na,na_parent,ticks_attr,view=parents[0],directions=["x","y","z"],sides=["Rear","Front"],rear=[0,0,0],front=[0,0,0],axes={};if(Type.exists(view.D3))for(i=0;i<directions.length;i++)rear[i]=view.D3.bbox3d[i][0],front[i]=view.D3.bbox3d[i][1];else for(i=0;i<directions.length;i++)rear[i]=parents[1][i],front[i]=parents[2][1];for(pos=(attr=Type.copyAttributes(attributes,board.options,"axes3d")).axesposition,i=0;i<directions.length;i++)na=(dir=directions[i])+"Axis","center"===pos?(from=[0,0,0],(to=[0,0,0])[i]=front[i],axes[na]=view.create("axis3d",[from,to],attr[na.toLowerCase()])):(na+="Border",from=rear.slice(),to=front.slice(),2===i?(from[1]=front[1],to[0]=rear[0]):(from[i]=front[i],to[2]=rear[2]),to[i]=front[i],attr[na.toLowerCase()].lastArrow=!1,axes[na]=view.create("axis3d",[from,to],attr[na.toLowerCase()]),ticks_attr={visible:!0,minorTicks:0,tickEndings:[0,1],drawLabels:!1},2===i&&(ticks_attr.tickEndings=[1,0]),axes[na+"Ticks"]=view.create("ticks",[axes[na],1],ticks_attr));for(axes.O=board.create("intersection",[axes[directions[0]+"Axis"],axes[directions[1]+"Axis"]],{name:"",visible:!1,withLabel:!1}),i=0;i<directions.length;i++)for(i1=(i+1)%3,i2=(i+2)%3,dir=directions[i],j=0;j<sides.length;j++)(from=[0,0,0])[i]=0===j?rear[i]:front[i],vec2=[0,0,0],(vec1=[0,0,0])[i1]=1,vec2[i2]=1,range1=[rear[i1],front[i1]],range2=[rear[i2],front[i2]],na=dir+"Plane"+sides[j],attr=Type.copyAttributes(attributes,board.options,"axes3d",na),axes[na]=view.create("plane3d",[from,vec1,vec2,range1,range2],attr),axes[na].D3.elType="axisplane3d";for(i=0;i<directions.length;i++)for(dir=directions[i],j=0;j<sides.length;j++)for(k=1;k<=2;k++)na=dir+"Plane"+sides[j]+directions[i1=(i+k)%3].toUpperCase()+"Axis",na_parent=dir+"Plane"+sides[j],(from=[0,0,0])[i]=(to=[0,0,0])[i]=0===j?rear[i]:front[i],from[i1]=rear[i1],to[i1]=front[i1],attr=Type.copyAttributes(attributes,board.options,"axes3d",na),axes[na]=view.create("axis3d",[from,to],attr),axes[na_parent].addChild(axes[na]),axes[na_parent].inherits.push(axes[na]);return axes},JXG.registerElement("axes3d",ThreeD.createAxes),ThreeD.createAxis=function(board,parents,attributes){var attr,el_start,el_end,xx,yy,zz,view=parents[0],start=parents[1],end=parents[2];return attr=Type.copyAttributes(attributes.point1,board.options,"axis3d","point1"),el_start=board.create("point",[(xx=start[0],yy=start[1],zz=start[2],function(){return view.project3DTo2D(xx,yy,zz)[1]}),function(xx,yy,zz){return function(){return view.project3DTo2D(xx,yy,zz)[2]}}(start[0],start[1],start[2])],attr),attr=Type.copyAttributes(attributes.point2,board.options,"axis3d","point2"),el_end=board.create("point",[function(xx,yy,zz){return function(){return view.project3DTo2D(xx,yy,zz)[1]}}(end[0],end[1],end[2]),function(xx,yy,zz){return function(){return view.project3DTo2D(xx,yy,zz)[2]}}(end[0],end[1],end[2])],attr),attr=Type.copyAttributes(attributes,board.options,"axis3d"),board.create("arrow",[el_start,el_end],attr)},JXG.registerElement("axis3d",ThreeD.createAxis),ThreeD.createMesh=function(board,parents,attr){var el,view=parents[0],point=parents[1],vec1=parents[2],range1=parents[3],vec2=parents[4],range2=parents[5];return(el=board.create("curve",[[],[]],attr)).updateDataArray=function(){var l1,l2,res,i,s1=range1[0],e1=range1[1],s2=range2[0],e2=range2[1],v1=[0,0,0],v2=[0,0,0],q=[0,0,0];for(this.dataX=[],this.dataY=[],i=0;i<3;i++)q[i]=Type.evaluate(point[i]),v1[i]=Type.evaluate(vec1[i]),v2[i]=Type.evaluate(vec2[i]);for(l1=JXG.Math.norm(v1,3),l2=JXG.Math.norm(v2,3),i=0;i<3;i++)v1[i]/=l1,v2[i]/=l2;res=view.getMesh((function(u,v){return q[0]+u*v1[0]+v*v2[0]}),(function(u,v){return q[1]+u*v1[1]+v*v2[1]}),(function(u,v){return q[2]+u*v1[2]+v*v2[2]}),[Math.ceil(s1),Math.floor(e1),(Math.ceil(e1)-Math.floor(s1))/1],[Math.ceil(s2),Math.floor(e2),(Math.ceil(e2)-Math.floor(s2))/1]),this.dataX=res[0],this.dataY=res[1]},el},JXG.registerElement("mesh3d",ThreeD.createMesh)})),define("3d/curve3d",["jxg","utils/type","3d/view3d"],(function(JXG,Type,ThreeD){ThreeD.createCurve=function(board,parents,attr){var D3,el,view=parents[0];return(D3={elType:"curve3D",X:parents[1],Y:parents[2],Z:parents[3]}).F=[D3.X,D3.Y,D3.Z],(el=board.create("curve",[[],[]],attr)).D3=D3,Type.isFunction(el.D3.X)?(el.D3.range=parents[4],el.updateDataArray=function(){var c2d,t,i,steps=Type.evaluate(this.visProp.numberpointshigh),s=Type.evaluate(this.D3.range[0]),e=Type.evaluate(this.D3.range[1]),delta=(e-s)/(steps-1),p=[0,0,0];for(this.dataX=[],this.dataY=[],t=s;t<=e;t+=delta){for(i=0;i<3;i++)p[i]=this.D3.F[i](t);c2d=view.project3DTo2D(p),this.dataX.push(c2d[1]),this.dataY.push(c2d[2])}}):Type.isArray(el.D3.X)&&(el.updateDataArray=function(){var i,c2d,le=this.D3.X.length;for(this.dataX=[],this.dataY=[],i=0;i<le;i++)c2d=view.project3DTo2D([this.D3.X[i],this.D3.Y[i],this.D3.Z[i]]),this.dataX.push(c2d[1]),this.dataY.push(c2d[2])}),el},JXG.registerElement("curve3d",ThreeD.createCurve)})),define("3d/linspace3d",["jxg","utils/type","math/math","math/geometry","3d/view3d"],(function(JXG,Type,Mat,Geometry,ThreeD){ThreeD.createLine=function(board,parents,attributes){var attr,D3,point,point1,point2,el,view=parents[0];return D3={elType:"line3d",range:parents[3]||[-1/0,1/0]},point=Type.isPoint(parents[1])?parents[1]:view.create("point3d",parents[1],{visible:!1,name:"",withLabel:!1}),D3.point=point,Type.isPoint(parents[2])&&Type.exists(parents[2].D3)?(point1=point,point2=parents[2],D3.direction=function(){return[point2.D3.X()-point.D3.X(),point2.D3.Y()-point.D3.Y(),point2.D3.Z()-point.D3.Z()]},D3.range=[0,1]):(Type.isFunction(parents[2])?D3.direction=parents[2]:3===parents[2].length?D3.direction=[1].concat(parents[2]):4===parents[2].length&&(D3.direction=parents[2]),D3.getPointCoords=function(r){var i,p=[],d=[];if(p.push(point.D3.X()),p.push(point.D3.Y()),p.push(point.D3.Z()),Type.isFunction(D3.direction))d=D3.direction();else for(i=1;i<4;i++)d.push(Type.evaluate(D3.direction[i]));return Math.abs(r)===1/0&&(r=view.intersectionLineCube(p,d,r)),[p[0]+d[0]*r,p[1]+d[1]*r,p[2]+d[2]*r]},attr=Type.copyAttributes(attributes,board.options,"line3d","point1"),point1=view.create("point3d",[function(){return D3.getPointCoords(Type.evaluate(D3.range[0]))}],attr),attr=Type.copyAttributes(attributes,board.options,"line3d","point2"),point2=view.create("point3d",[function(){return D3.getPointCoords(Type.evaluate(D3.range[1]))}],attr)),attr=Type.copyAttributes(attributes,board.options,"line3d"),(el=view.create("segment",[point1,point2],attr)).point1=point1,el.point2=point2,point1.addChild(el),point2.addChild(el),el.D3=D3,el},JXG.registerElement("line3d",ThreeD.createLine),ThreeD.createPlane=function(board,parents,attributes){var attr,D3,point,el,grid,view=parents[0],vec1=parents[2],vec2=parents[3];return D3={elType:"plane3d",dir1:[],dir2:[],range1:parents[4],range2:parents[5],vec1:vec1,vec2:vec2},point=Type.isPoint(parents[1])?parents[1]:view.create("point3d",parents[1],{visible:!1,name:"",withLabel:!1}),D3.point=point,D3.updateNormal=function(){var i;for(i=0;i<3;i++)D3.dir1[i]=Type.evaluate(D3.vec1[i]),D3.dir2[i]=Type.evaluate(D3.vec2[i]);D3.normal=Mat.crossProduct(D3.dir1,D3.dir2),D3.d=Mat.innerProduct(D3.point.D3.coords.slice(1),D3.normal,3)},D3.updateNormal(),attr=Type.copyAttributes(attributes,board.options,"plane3d"),(el=board.create("curve",[[],[]],attr)).D3=D3,el.updateDataArray=function(){var s1,e1,s2,e2,c2d,l1,l2,d,i,j,a,b,pos,pos_akt,planes=["xPlaneRear","yPlaneRear","zPlaneRear"],points=[],v1=[0,0,0],v2=[0,0,0],q=[0,0,0],p=[0,0,0];if(this.dataX=[],this.dataY=[],this.D3.updateNormal(),"axisplane3d"===this.D3.elType||!view.defaultAxes||D3.range1&&D3.range2){for(s1=Type.evaluate(this.D3.range1[0]),e1=Type.evaluate(this.D3.range1[1]),s2=Type.evaluate(this.D3.range2[0]),e2=Type.evaluate(this.D3.range2[1]),q=this.D3.point.D3.coords.slice(1),v1=this.D3.dir1.slice(),v2=this.D3.dir2.slice(),l1=Mat.norm(v1,3),l2=Mat.norm(v2,3),i=0;i<3;i++)v1[i]/=l1,v2[i]/=l2;for(j=0;j<4;j++){switch(j){case 0:a=s1,b=s2;break;case 1:a=e1,b=s2;break;case 2:a=e1,b=e2;break;case 3:a=s1,b=e2}for(i=0;i<3;i++)p[i]=q[i]+a*v1[i]+b*v2[i];c2d=view.project3DTo2D(p),this.dataX.push(c2d[1]),this.dataY.push(c2d[2])}this.dataX.push(this.dataX[0]),this.dataY.push(this.dataY[0])}else{for(j=0;j<planes.length;j++){if(3===(p=view.intersectionPlanePlane(this,view.defaultAxes[planes[j]]))[0].length&&3===p[1].length){for(i=0;i<points.length&&!(Geometry.distance(p[0],points[i][0],3)<Mat.eps&&Geometry.distance(p[1],points[i][1],3)<Mat.eps||Geometry.distance(p[0],points[i][1],3)<Mat.eps&&Geometry.distance(p[1],points[i][0],3)<Mat.eps);i++);i===points.length&&points.push(p.slice())}if((p=[0,0,0])[j]=view.D3.bbox3d[j][1],d=Mat.innerProduct(p,view.defaultAxes[planes[j]].D3.normal,3),3===(p=view.intersectionPlanePlane(this,view.defaultAxes[planes[j]],d))[0].length&&3===p[1].length){for(i=0;i<points.length&&!(Geometry.distance(p[0],points[i][0],3)<Mat.eps&&Geometry.distance(p[1],points[i][1],3)<Mat.eps||Geometry.distance(p[0],points[i][1],3)<Mat.eps&&Geometry.distance(p[1],points[i][0],3)<Mat.eps);i++);i===points.length&&points.push(p.slice())}}0,pos=0,i=0;do{for(3===(p=points[pos][i]).length&&(c2d=view.project3DTo2D(p),this.dataX.push(c2d[1]),this.dataY.push(c2d[2])),i=(i+1)%2,p=points[pos][i],pos_akt=pos,j=0;j<points.length;j++){if(j!==pos&&Geometry.distance(p,points[j][0])<Mat.eps){pos=j,i=0;break}if(j!==pos&&Geometry.distance(p,points[j][1])<Mat.eps){pos=j,i=1;break}}if(pos===pos_akt){console.log("Error: update plane3d: did not find next",pos);break}}while(0!==pos);c2d=view.project3DTo2D(points[0][0]),this.dataX.push(c2d[1]),this.dataY.push(c2d[2])}},attr=Type.copyAttributes(attributes.mesh3d,board.options,"mesh3d"),D3.range1&&D3.range2&&(grid=view.create("mesh3d",[point.D3.coords.slice(1),vec1,D3.range1,vec2,D3.range2],attr),el.grid=grid,el.inherits.push(grid)),el},JXG.registerElement("plane3d",ThreeD.createPlane)})),define("3d/point3d",["jxg","base/constants","math/math","math/geometry","utils/type","3d/view3d"],(function(JXG,Const,Mat,Geometry,Type,ThreeD){ThreeD.createPoint=function(board,parents,attributes){var attr,update2D,D3,i,c2d,el,view=parents[0];if(attr=Type.copyAttributes(attributes,board.options,"point3d"),D3={elType:"point3d",coords:[1,0,0,0],X:function(){return this.coords[1]},Y:function(){return this.coords[2]},Z:function(){return this.coords[3]}},parents.length>2&&Type.exists(parents[parents.length-1].D3)?D3.slide=parents.pop():D3.slide=null,2===parents.length)D3.F=parents[1],D3.coords=[1].concat(Type.evaluate(D3.F));else if(4===parents.length)for(D3.F=parents.slice(1),i=0;i<3;i++)D3.coords[i+1]=Type.evaluate(D3.F[i]);return D3.updateCoords=function(){var res,i;if(Type.isFunction(this.F))res=Type.evaluate(this.F),this.coords=[1,res[0],res[1],res[2]];else for(this.coords[0]=1,i=0;i<3;i++)Type.isFunction(this.F[i])&&(this.coords[i+1]=Type.evaluate(this.F[i]));return this},D3.updateCoords(),c2d=view.project3DTo2D(D3.coords),(el=board.create("point",c2d,attr)).D3=D3,el.D3.c2d=el.coords.usrCoords.slice(),update2D=el.update,el.D3.slide&&(el._minFunc=function(n,m,x,con){var surface=el.D3.slide.D3,c3d=[1,surface.X(x[0],x[1]),surface.Y(x[0],x[1]),surface.Z(x[0],x[1])],c2d=view.project3DTo2D(c3d);return con[0]=el.X()-c2d[1],con[1]=el.Y()-c2d[2],con[0]*con[0]+con[1]*con[1]},el.projectCoords2Surface=function(){var c3d,c2d,x=[0,0],surface=this.D3.slide.D3;Type.exists(this.D3.params)&&(x=this.D3.params.slice()),Mat.Nlp.FindMinimum(this._minFunc,2,2,x,5,1e-6,0,200),c3d=[1,surface.X(x[0],x[1]),surface.Y(x[0],x[1]),surface.Z(x[0],x[1])],c2d=view.project3DTo2D(c3d),this.D3.params=x,this.D3.coords=c3d,this.coords.setCoordinates(Const.COORDS_BY_USER,c2d),this.D3.c2d=c2d}),el.update=function(drag){var c3d,foot;return this.needsUpdate?(this.draggable()&&0!==Geometry.distance(this.D3.c2d,this.coords.usrCoords)?this.D3.slide?this.projectCoords2Surface():(foot=[1,0,0,this.D3.coords[3]],0!==(c3d=view.project2DTo3DPlane(el,[1,0,0,1],foot))[0]&&(this.D3.coords=view.project3DToCube(c3d))):(this.D3.updateCoords(),el.coords.setCoordinates(Const.COORDS_BY_USER,view.project3DTo2D([1,this.D3.X(),this.D3.Y(),this.D3.Z()]))),this.D3.c2d=el.coords.usrCoords.slice(),update2D.apply(this,[drag]),this):this},el},JXG.registerElement("point3d",ThreeD.createPoint)})),define("3d/surface3d",["jxg","utils/type","3d/view3d"],(function(JXG,Type,ThreeD){ThreeD.createParametricSurface=function(board,parents,attributes){var attr,D3,el,view=parents[0];return D3={elType:"surface3d",X:parents[1],Y:parents[2],Z:parents[3],range_u:parents[4],range_v:parents[5]},attr=Type.copyAttributes(attributes,board.options,"surface3d"),(el=board.create("curve",[[],[]],attr)).updateDataArray=function(){var steps_u=Type.evaluate(this.visProp.stepsu),steps_v=Type.evaluate(this.visProp.stepsv),r_u=Type.evaluate(this.D3.range_u),r_v=Type.evaluate(this.D3.range_v),res=view.getMesh(this.D3.X,this.D3.Y,this.D3.Z,r_u.concat([steps_u]),r_v.concat([steps_v]));this.dataX=res[0],this.dataY=res[1]},el.D3=D3,el},JXG.registerElement("parametricsurface3d",ThreeD.createParametricSurface),ThreeD.createFunctiongraph=function(board,parents,attributes){var view=parents[0],Z=parents[1],range_u=parents[2],range_v=parents[3];return view.create("parametricsurface3d",[function(u,v){return u},function(u,v){return v},Z,range_u,range_v],attributes)},JXG.registerElement("functiongraph3d",ThreeD.createFunctiongraph)})),define("../build/core.deps.js",["jxg","utils/env","base/constants","utils/type","utils/xml","utils/event","utils/expect","math/math","math/probfuncs","math/ia","math/extrapolate","math/qdt","math/numerics","math/nlp","math/plot","math/metapost","math/statistics","math/symbolic","math/geometry","math/clip","math/poly","math/complex","renderer/abstract","reader/file","parser/geonext","base/board","options","jsxgraph","base/element","base/coords","base/coordselement","base/point","base/line","base/group","base/circle","element/conic","base/polygon","base/curve","element/arc","element/sector","base/composition","element/composition","element/locus","base/text","base/image","element/slider","element/measure","base/chart","base/transformation","base/turtle","utils/color","base/ticks","utils/zip","utils/base64","utils/uuid","utils/encoding","server/server","parser/datasource","parser/jessiecode","parser/ca","utils/dump","renderer/svg","renderer/vml","renderer/canvas","renderer/no","element/comb","element/slopetriangle","element/checkbox","element/input","element/button","base/foreignobject","options3d","3d/box3d","3d/curve3d","3d/linspace3d","3d/point3d","3d/surface3d","3d/threed","3d/view3d"],(function(JXG,Env){return Env.isBrowser?window.JXG=JXG:Env.isNode()&&"object"===("undefined"==typeof module?"undefined":_typeof(module))?module.exports=JXG:Env.isWebWorker()&&(self.JXG=JXG),JXG})),require("../build/core.deps.js")}()); -/** - * UTF-8 Decoder by Bjoern Hoehrmann - * - * Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de> - * - * 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. - */ -!function(t,e){"function"==typeof define&&define.amd?define("qtype_stack/jsxgraphcore-lazy",[],e):"object"==typeof module&&module.exports?module.exports=e():t.returnExports=e()}(this,function(){var requirejs,require,define;return function(t){function e(t,e){return v.call(t,e)}function i(t,e){var i,r,s,o,n,a,h,l,c,d,u,p,f=e&&e.split("/"),m=g.map,b=m&&m["*"]||{};if(t){for(t=t.split("/"),n=t.length-1,g.nodeIdCompat&&C.test(t[n])&&(t[n]=t[n].replace(C,"")),"."===t[0].charAt(0)&&f&&(p=f.slice(0,f.length-1),t=p.concat(t)),c=0;c<t.length;c++)if("."===(u=t[c]))t.splice(c,1),c-=1;else if(".."===u){if(0===c||1===c&&".."===t[2]||".."===t[c-1])continue;c>0&&(t.splice(c-1,2),c-=2)}t=t.join("/")}if((f||b)&&m){for(i=t.split("/"),c=i.length;c>0;c-=1){if(r=i.slice(0,c).join("/"),f)for(d=f.length;d>0;d-=1)if((s=m[f.slice(0,d).join("/")])&&(s=s[r])){o=s,a=c;break}if(o)break;!h&&b&&b[r]&&(h=b[r],l=c)}!o&&h&&(o=h,a=l),o&&(i.splice(0,a,o),t=i.join("/"))}return t}function r(e,i){return function(){var r=y.call(arguments,0);return"string"!=typeof r[0]&&1===r.length&&r.push(null),d.apply(t,r.concat([e,i]))}}function s(t){return function(e){return i(e,t)}}function o(t){return function(e){f[t]=e}}function n(i){if(e(m,i)){var r=m[i];delete m[i],b[i]=!0,c.apply(t,r)}if(!e(f,i)&&!e(b,i))throw new Error("No "+i);return f[i]}function a(t){var e,i=t?t.indexOf("!"):-1;return i>-1&&(e=t.substring(0,i),t=t.substring(i+1,t.length)),[e,t]}function h(t){return t?a(t):[]}function l(t){return function(){return g&&g.config&&g.config[t]||{}}}var c,d,u,p,f={},m={},g={},b={},v=Object.prototype.hasOwnProperty,y=[].slice,C=/\.js$/;u=function(t,e){var r,o=a(t),h=o[0],l=e[1];return t=o[1],h&&(h=i(h,l),r=n(h)),h?t=r&&r.normalize?r.normalize(t,s(l)):i(t,l):(t=i(t,l),o=a(t),h=o[0],t=o[1],h&&(r=n(h))),{f:h?h+"!"+t:t,n:t,pr:h,p:r}},p={require:function(t){return r(t)},exports:function(t){var e=f[t];return void 0!==e?e:f[t]={}},module:function(t){return{id:t,uri:"",exports:f[t],config:l(t)}}},c=function(i,s,a,l){var c,d,g,v,y,C,_,P=[],E=typeof a;if(l=l||i,C=h(l),"undefined"===E||"function"===E){for(s=!s.length&&a.length?["require","exports","module"]:s,y=0;y<s.length;y+=1)if(v=u(s[y],C),"require"===(d=v.f))P[y]=p.require(i);else if("exports"===d)P[y]=p.exports(i),_=!0;else if("module"===d)c=P[y]=p.module(i);else if(e(f,d)||e(m,d)||e(b,d))P[y]=n(d);else{if(!v.p)throw new Error(i+" missing "+d);v.p.load(v.n,r(l,!0),o(d),{}),P[y]=f[d]}g=a?a.apply(f[i],P):void 0,i&&(c&&c.exports!==t&&c.exports!==f[i]?f[i]=c.exports:g===t&&_||(f[i]=g))}else i&&(f[i]=a)},requirejs=require=d=function(e,i,r,s,o){if("string"==typeof e)return p[e]?p[e](i):n(u(e,h(i)).f);if(!e.splice){if(g=e,g.deps&&d(g.deps,g.callback),!i)return;i.splice?(e=i,i=r,r=null):e=t}return i=i||function(){},"function"==typeof r&&(r=s,s=o),s?c(t,e,i,r):setTimeout(function(){c(t,e,i,r)},4),d},d.config=function(t){return d(t)},requirejs._defined=f,define=function(t,i,r){if("string"!=typeof t)throw new Error("See almond README: incorrect module build, no module name");i.splice||(r=i,i=[]),e(f,t)||e(m,t)||(m[t]=[t,i,r])},define.amd={jQuery:!0}}(),define("../node_modules/almond/almond",function(){}),define("jxg",[],function(){"use strict";var t={};return"object"!=typeof JXG||JXG.extend||(t=JXG),t.extend=function(t,e,i,r){var s,o;i=i||!1,r=r||!1;for(s in e)(!i||i&&e.hasOwnProperty(s))&&(o=r?s.toLowerCase():s,t[o]=e[s])},t.defineConstant=function(t,e,i){Object.defineProperty(t,e,{value:i,writable:!1,enumerable:!0,configurable:!1})},t.extendConstants=function(t,e,i,r){var s,o;i=i||!1,r=r||!1;for(s in e)(!i||i&&extension.hasOwnProperty(s))&&(o=r?s.toUpperCase():s,this.defineConstant(t,o,e[s]))},t.extend(t,{boards:{},readers:{},elements:{},registerElement:function(t,e){t=t.toLowerCase(),this.elements[t]=e},registerReader:function(t,e){var i,r;for(i=0;i<e.length;i++)r=e[i].toLowerCase(),"function"!=typeof this.readers[r]&&(this.readers[r]=t)},shortcut:function(t,e){return function(){return t[e].apply(this,arguments)}},getRef:function(e,i){return t.deprecated("JXG.getRef()","Board.select()"),e.select(i)},getReference:function(e,i){return t.deprecated("JXG.getReference()","Board.select()"),e.select(i)},getBoardByContainerId:function(t){var e;for(e in JXG.boards)if(JXG.boards.hasOwnProperty(e)&&JXG.boards[e].container===t)return JXG.boards[e];return null},deprecated:function(e,i){var r=e+" is deprecated.";i&&(r+=" Please use "+i+" instead."),t.warn(r)},warn:function(t){"object"==typeof window&&window.console&&console.warn?console.warn("WARNING:",t):"object"==typeof document&&document.getElementById("warning")&&(document.getElementById("debug").innerHTML+="WARNING: "+t+"<br />")},debugInt:function(t){var e,i;for(e=0;e<arguments.length;e++)i=arguments[e],"object"==typeof window&&window.console&&console.log?console.log(i):"object"==typeof document&&document.getElementById("debug")&&(document.getElementById("debug").innerHTML+=i+"<br/>")},debugWST:function(e){var i=new Error;t.debugInt.apply(this,arguments),i&&i.stack&&(t.debugInt("stacktrace"),t.debugInt(i.stack.split("\n").slice(1).join("\n")))},debugLine:function(e){var i=new Error;t.debugInt.apply(this,arguments),i&&i.stack&&t.debugInt("Called from",i.stack.split("\n").slice(2,3).join("\n"))},debug:function(e){t.debugInt.apply(this,arguments)}}),t}),define("base/constants",["jxg"],function(t){"use strict";var e;return e={version:"1.2.1",licenseText:"JSXGraph v1.2.1 Copyright (C) see https://jsxgraph.org",COORDS_BY_USER:1,COORDS_BY_SCREEN:2,OBJECT_TYPE_ARC:1,OBJECT_TYPE_ARROW:2,OBJECT_TYPE_AXIS:3,OBJECT_TYPE_AXISPOINT:4,OBJECT_TYPE_TICKS:5,OBJECT_TYPE_CIRCLE:6,OBJECT_TYPE_CONIC:7,OBJECT_TYPE_CURVE:8,OBJECT_TYPE_GLIDER:9,OBJECT_TYPE_IMAGE:10,OBJECT_TYPE_LINE:11,OBJECT_TYPE_POINT:12,OBJECT_TYPE_SLIDER:13,OBJECT_TYPE_CAS:14,OBJECT_TYPE_GXTCAS:15,OBJECT_TYPE_POLYGON:16,OBJECT_TYPE_SECTOR:17,OBJECT_TYPE_TEXT:18,OBJECT_TYPE_ANGLE:19,OBJECT_TYPE_INTERSECTION:20,OBJECT_TYPE_TURTLE:21,OBJECT_TYPE_VECTOR:22,OBJECT_TYPE_OPROJECT:23,OBJECT_TYPE_GRID:24,OBJECT_TYPE_TANGENT:25,OBJECT_TYPE_HTMLSLIDER:26,OBJECT_TYPE_CHECKBOX:27,OBJECT_TYPE_INPUT:28,OBJECT_TYPE_BUTTON:29,OBJECT_TYPE_TRANSFORMATION:30,OBJECT_CLASS_POINT:1,OBJECT_CLASS_LINE:2,OBJECT_CLASS_CIRCLE:3,OBJECT_CLASS_CURVE:4,OBJECT_CLASS_AREA:5,OBJECT_CLASS_OTHER:6,OBJECT_CLASS_TEXT:7,GENTYPE_ABC:1,GENTYPE_AXIS:2,GENTYPE_MID:3,GENTYPE_REFLECTION:4,GENTYPE_MIRRORELEMENT:5,GENTYPE_REFLECTION_ON_LINE:4,GENTYPE_REFLECTION_ON_POINT:5,GENTYPE_TANGENT:6,GENTYPE_PARALLEL:7,GENTYPE_BISECTORLINES:8,GENTYPE_BOARDIMG:9,GENTYPE_BISECTOR:10,GENTYPE_NORMAL:11,GENTYPE_POINT:12,GENTYPE_GLIDER:13,GENTYPE_INTERSECTION:14,GENTYPE_CIRCLE:15,GENTYPE_CIRCLE2POINTS:16,GENTYPE_LINE:17,GENTYPE_TRIANGLE:18,GENTYPE_QUADRILATERAL:19,GENTYPE_TEXT:20,GENTYPE_POLYGON:21,GENTYPE_REGULARPOLYGON:22,GENTYPE_SECTOR:23,GENTYPE_ANGLE:24,GENTYPE_PLOT:25,GENTYPE_SLIDER:26,GENTYPE_TRUNCATE:27,GENTYPE_JCODE:28,GENTYPE_MOVEMENT:29,GENTYPE_COMBINED:30,GENTYPE_RULER:31,GENTYPE_SLOPETRIANGLE:32,GENTYPE_PERPSEGMENT:33,GENTYPE_LABELMOVEMENT:34,GENTYPE_VECTOR:35,GENTYPE_NONREFLEXANGLE:36,GENTYPE_REFLEXANGLE:37,GENTYPE_PATH:38,GENTYPE_DERIVATIVE:39,GENTYPE_DELETE:41,GENTYPE_COPY:42,GENTYPE_MIRROR:43,GENTYPE_ROTATE:44,GENTYPE_ABLATION:45,GENTYPE_MIGRATE:46,GENTYPE_VECTORCOPY:47,GENTYPE_POLYGONCOPY:48,GENTYPE_CTX_TYPE_G:51,GENTYPE_CTX_TYPE_P:52,GENTYPE_CTX_TRACE:53,GENTYPE_CTX_VISIBILITY:54,GENTYPE_CTX_CCVISIBILITY:55,GENTYPE_CTX_MPVISIBILITY:56,GENTYPE_CTX_WITHLABEL:57,GENTYPE_CTX_LABEL:58,GENTYPE_CTX_FIXED:59,GENTYPE_CTX_STROKEWIDTH:60,GENTYPE_CTX_LABELSIZE:61,GENTYPE_CTX_SIZE:62,GENTYPE_CTX_FACE:63,GENTYPE_CTX_STRAIGHT:64,GENTYPE_CTX_ARROW:65,GENTYPE_CTX_COLOR:66,GENTYPE_CTX_RADIUS:67,GENTYPE_CTX_COORDS:68,GENTYPE_CTX_TEXT:69,GENTYPE_CTX_ANGLERADIUS:70,GENTYPE_CTX_DOTVISIBILITY:71,GENTYPE_CTX_FILLOPACITY:72,GENTYPE_CTX_PLOT:73,GENTYPE_CTX_SCALE:74,GENTYPE_CTX_INTVAL:75,GENTYPE_CTX_POINT1:76,GENTYPE_CTX_POINT2:77,GENTYPE_CTX_LABELSTICKY:78,GENTYPE_CTX_TYPE_I:79,GENTYPE_CTX_HASINNERPOINTS:80,GENTYPE_CTX_SNAPWIDTH:81,GENTYPE_CTX_SNAPTOGRID:82},t.extendConstants(t,e),e}),define("utils/type",["jxg","base/constants"],function(t,e){"use strict";return t.extend(t,{isId:function(t,e){return"string"==typeof e&&!!t.objects[e]},isName:function(t,e){return"string"==typeof e&&!!t.elementsByName[e]},isGroup:function(t,e){return"string"==typeof e&&!!t.groups[e]},isString:function(t){return"string"==typeof t},isNumber:function(t){return"number"==typeof t||"[Object Number]"===Object.prototype.toString.call(t)},isFunction:function(t){return"function"==typeof t},isArray:function(t){return Array.isArray?Array.isArray(t):null!==t&&"object"==typeof t&&"function"==typeof t.splice&&"function"==typeof t.join},isObject:function(t){return"object"==typeof t&&!this.isArray(t)},isPoint:function(t){return null!==t&&"object"==typeof t&&t.elementClass===e.OBJECT_CLASS_POINT},isPointType:function(t,e){var i,r;return!!this.isArray(e)||(!!(this.isFunction(e)&&(i=e(),this.isArray(i)&&i.length>1))||(r=t.select(e),this.isPoint(r)))},isTransformationOrArray:function(t){if(null!==t){if(this.isArray(t)&&t.length>0)return this.isTransformationOrArray(t[0]);if("object"==typeof t)return t.type===e.OBJECT_TYPE_TRANSFORMATION}return!1},exists:function(t){return function(t,e){var i=!(void 0===t||null===t);return e=e||!1,e?i&&""!==t:i}}(),isEmpty:function(t){return 0===Object.keys(t).length},def:function(t,e){return this.exists(t)?t:e},str2Bool:function(t){return!this.exists(t)||("boolean"==typeof t?t:!!this.isString(t)&&"true"===t.toLowerCase())},createEvalFunction:function(e,i,r){var s,o=[];for(s=0;s<r;s++)o[s]=t.createFunction(i[s],e,"",!0);return function(t){return o[t]()}},createFunction:function(t,e,i,r){var s=null;return this.exists(r)&&!r||!this.isString(t)?this.isFunction(t)?s=t:this.isNumber(t)?s=function(){return t}:this.isString(t)&&(s=function(){return t}):s=e.jc.snippet(t,!0,i,!0),null!==s&&(s.origin=t),s},providePoints:function(t,e,i,r,s){var o,n,a,h,l,c=0,d=[];for(this.isArray(e)||(e=[e]),a=e.length,this.exists(s)&&(c=s.length),0===c&&(h=this.copyAttributes(i,t.options,r)),o=0;o<a;++o)if(c>0&&(n=Math.min(o,c-1),h=this.copyAttributes(i,t.options,r,s[n])),this.isArray(e[o])&&e[o].length>1?d.push(t.create("point",e[o],h)):this.isFunction(e[o])?(l=e[o](),this.isArray(l)&&l.length>1&&d.push(t.create("point",[e[o]],h))):d.push(t.select(e[o])),!this.isPoint(d[o]))return!1;return d},bind:function(t,e){return function(){return t.apply(e,arguments)}},evaluate:function(t){return this.isFunction(t)?t():t},indexOf:function(t,e,i){var r,s=this.exists(i);if(Array.indexOf&&!s)return t.indexOf(e);for(r=0;r<t.length;r++)if(s&&t[r][i]===e||!s&&t[r]===e)return r;return-1},eliminateDuplicates:function(t){var e,i=t.length,r=[],s={};for(e=0;e<i;e++)s[t[e]]=0;for(e in s)s.hasOwnProperty(e)&&r.push(e);return r},swap:function(t,e,i){var r;return r=t[e],t[e]=t[i],t[i]=r,t},uniqueArray:function(e){var i,r,s,o=[];if(0===e.length)return[];for(i=0;i<e.length;i++)if(s=this.isArray(e[i]),this.exists(e[i]))for(r=i+1;r<e.length;r++)s&&t.cmpArrays(e[i],e[r])?e[i]=[]:s||e[i]!==e[r]||(e[i]="");else e[i]="";for(r=0,i=0;i<e.length;i++)s=this.isArray(e[i]),s||""===e[i]?s&&0!==e[i].length&&(o[r]=e[i].slice(0),r++):(o[r]=e[i],r++);return e=o,o},isInArray:function(e,i){return t.indexOf(e,i)>-1},coordsArrayToMatrix:function(t,e){var i,r=[],s=[];for(i=0;i<t.length;i++)e?(r.push(t[i].usrCoords[1]),s.push(t[i].usrCoords[2])):s.push([t[i].usrCoords[1],t[i].usrCoords[2]]);return e&&(s=[r,s]),s},cmpArrays:function(t,e){var i;if(t===e)return!0;if(t.length!==e.length)return!1;for(i=0;i<t.length;i++)if(this.isArray(t[i])&&this.isArray(e[i])){if(!this.cmpArrays(t[i],e[i]))return!1}else if(t[i]!==e[i])return!1;return!0},removeElementFromArray:function(t,e){var i;for(i=0;i<t.length;i++)if(t[i]===e)return t.splice(i,1),t;return t},trunc:function(e,i){return i=t.def(i,0),this.toFixed(e,i)},_decimalAdjust:function(t,e,i){return void 0===i||0==+i?Math[t](e):(e=+e,i=+i,isNaN(e)||"number"!=typeof i||i%1!=0?NaN:(e=e.toString().split("e"),e=Math[t](+(e[0]+"e"+(e[1]?+e[1]-i:-i))),e=e.toString().split("e"),+(e[0]+"e"+(e[1]?+e[1]+i:i))))},_round10:function(t,e){return this._decimalAdjust("round",t,e)},_floor10:function(t,e){return this._decimalAdjust("floor",t,e)},_ceil10:function(t,e){return this._decimalAdjust("ceil",t,e)},toFixed:function(t,e){return this._round10(t,-e).toFixed(e)},autoDigits:function(t){var e=Math.abs(t);return e>.1?this.toFixed(t,2):e>=.01?this.toFixed(t,4):e>=1e-4?this.toFixed(t,6):t},keys:function(t,e){var i,r=[];for(i in t)e?t.hasOwnProperty(i)&&r.push(i):r.push(i);return r},clone:function(t){var e={};return e.prototype=t,e},cloneAndCopy:function(t,e){var i,r=function(){};r.prototype=t;for(i in e)r[i]=e[i];return r},merge:function(t,e){var i,r;for(i in e)if(e.hasOwnProperty(i))if(this.isArray(e[i]))for(t[i]||(t[i]=[]),r=0;r<e[i].length;r++)"object"==typeof e[i][r]?t[i][r]=this.merge(t[i][r],e[i][r]):t[i][r]=e[i][r];else"object"==typeof e[i]?(t[i]||(t[i]={}),t[i]=this.merge(t[i],e[i])):t[i]=e[i];return t},deepCopy:function(t,e,i){var r,s,o,n;if(i=i||!1,"object"!=typeof t||null===t)return t;if(this.isArray(t))for(r=[],s=0;s<t.length;s++)o=t[s],"object"==typeof o?this.exists(o.board)?r[s]=o.id:r[s]=this.deepCopy(o):r[s]=o;else{r={};for(s in t)t.hasOwnProperty(s)&&(n=i?s.toLowerCase():s,o=t[s],null!==o&&"object"==typeof o?this.exists(o.board)?r[n]=o.id:r[n]=this.deepCopy(o):r[n]=o);for(s in e)e.hasOwnProperty(s)&&(n=i?s.toLowerCase():s,o=e[s],"object"==typeof o?this.isArray(o)||!this.exists(r[n])?r[n]=this.deepCopy(o):r[n]=this.deepCopy(r[n],o,i):r[n]=o)}return r},copyAttributes:function(e,i,r){var s,o,n,a,h,l={circle:1,curve:1,image:1,line:1,point:1,polygon:1,text:1,ticks:1,integral:1};for(n=arguments.length,s=n<3||l[r]?t.deepCopy(i.elements,null,!0):{},n<4&&this.exists(r)&&this.exists(i.layer[r])&&(s.layer=i.layer[r]),a=i,h=!0,o=2;o<n;o++){if(!this.exists(a[arguments[o]])){h=!1;break}a=a[arguments[o]]}for(h&&(s=t.deepCopy(s,a,!0)),a=e,h=!0,o=3;o<n;o++){if(!this.exists(a[arguments[o]])){h=!1;break}a=a[arguments[o]]}for(h&&this.extend(s,a,null,!0),a=i,h=!0,o=2;o<n;o++){if(!this.exists(a[arguments[o]])){h=!1;break}a=a[arguments[o]]}return h&&this.exists(a.label)&&(s.label=t.deepCopy(a.label,s.label)),s.label=t.deepCopy(i.label,s.label),s},copyPrototypeMethods:function(t,e,i){var r;t.prototype[i]=e.prototype.constructor;for(r in e.prototype)e.prototype.hasOwnProperty(r)&&(t.prototype[r]=e.prototype[r])},toJSON:function(e,i){var r,s,o,n;if(i=t.def(i,!1),JSON.stringify&&!i)try{return JSON.stringify(e)}catch(t){}switch(typeof e){case"object":if(e){if(r=[],this.isArray(e)){for(o=0;o<e.length;o++)r.push(t.toJSON(e[o],i));return"["+r.join(",")+"]"}for(s in e)if(e.hasOwnProperty(s)){try{n=t.toJSON(e[s],i)}catch(t){n=""}i?r.push(s+":"+n):r.push('"'+s+'":'+n)}return"{"+r.join(",")+"} "}return"null";case"string":return"'"+e.replace(/(["'])/g,"\\$1")+"'";case"number":case"boolean":return e.toString()}return"0"},clearVisPropOld:function(t){return t.visPropOld={cssclass:"",cssdefaultstyle:"",cssstyle:"",fillcolor:"",fillopacity:"",firstarrow:!1,fontsize:-1,lastarrow:!1,left:-1e5,linecap:"",shadow:!1,strokecolor:"",strokeopacity:"",strokewidth:"",transitionduration:0,top:-1e5,visible:null},t},isInObject:function(t,e){var i;for(i in t)if(t.hasOwnProperty(i)&&t[i]===e)return!0;return!1},escapeHTML:function(t){return t.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")},unescapeHTML:function(t){return t.replace(/<\/?[^>]+>/gi,"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")},capitalize:function(t){return t.charAt(0).toUpperCase()+t.substring(1).toLowerCase()},trimNumber:function(t){return t=t.replace(/^0+/,""),t=t.replace(/0+$/,""),"."!==t[t.length-1]&&","!==t[t.length-1]||(t=t.slice(0,-1)),"."!==t[0]&&","!==t[0]||(t="0"+t),t},filterElements:function(t,e){var i,r,s,o,n,a,h,l=t.length,c=[];if("function"!=typeof e&&"object"!=typeof e)return c;for(i=0;i<l;i++){if(h=!0,s=t[i],"object"==typeof e){for(r in e)if(e.hasOwnProperty(r)&&(o=r.toLowerCase(),n="function"==typeof s[r]?s[r]():s[r],a=s.visProp&&"function"==typeof s.visProp[o]?s.visProp[o]():s.visProp&&s.visProp[o],!(h="function"==typeof e[r]?e[r](n)||e[r](a):n===e[r]||a===e[r])))break}else"function"==typeof e&&(h=e(s));h&&c.push(s)}return c},trim:function(t){return t.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,"")},sanitizeHTML:function(t,e){return"function"==typeof html_sanitize&&e?html_sanitize(t,function(){},function(t){return t}):(t&&(t=t.replace(/</g,"<").replace(/>/g,">")),t)},evalSlider:function(t){return t&&t.type===e.OBJECT_TYPE_GLIDER&&"function"==typeof t.Value?t.Value():t}}),t}),define("utils/env",["jxg","utils/type"],function(t,e){"use strict";return t.extendConstants(t,{touchProperty:"touches"}),t.extend(t,{isTouchEvent:function(e){return t.exists(e[t.touchProperty])},isPointerEvent:function(e){return t.exists(e.pointerId)},isMouseEvent:function(e){return!t.isTouchEvent(e)&&!t.isPointerEvent(e)},getNumberOfTouchPoints:function(e){var i=-1;return t.isTouchEvent(e)&&(i=e[t.touchProperty].length),i},isFirstTouch:function(e){var i=t.getNumberOfTouchPoints(e);return t.isPointerEvent(e)?e.isPrimary:1===i},isBrowser:"object"==typeof window&&"object"==typeof document,supportsES6:function(){try{return new Function("(a = 0) => a"),!0}catch(t){return!1}},supportsVML:function(){return this.isBrowser&&!!document.namespaces},supportsSVG:function(){return this.isBrowser&&document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure","1.1")},supportsCanvas:function(){var t,e=!1;if(this.isNode())try{t="object"==typeof module?module.require("canvas"):require("canvas"),e=!!t}catch(t){}return e||this.isBrowser&&!!document.createElement("canvas").getContext},isNode:function(){return!this.isBrowser&&("object"==typeof module&&!!module.exports||"object"==typeof global&&global.requirejsVars&&!global.requirejsVars.isBrowser)},isWebWorker:function(){return!this.isBrowser&&"object"==typeof self&&"function"==typeof self.postMessage},supportsPointerEvents:function(){return!!(this.isBrowser&&window.navigator&&(window.PointerEvent||window.navigator.pointerEnabled||window.navigator.msPointerEnabled))},isTouchDevice:function(){return this.isBrowser&&void 0!==window.ontouchstart},isAndroid:function(){return e.exists(navigator)&&navigator.userAgent.toLowerCase().indexOf("android")>-1},isWebkitAndroid:function(){return this.isAndroid()&&navigator.userAgent.indexOf(" AppleWebKit/")>-1},isApple:function(){return e.exists(navigator)&&(navigator.userAgent.indexOf("iPad")>-1||navigator.userAgent.indexOf("iPhone")>-1)},isWebkitApple:function(){return this.isApple()&&navigator.userAgent.search(/Mobile\/[0-9A-Za-z\.]*Safari/)>-1},isMetroApp:function(){return"object"==typeof window&&window.clientInformation&&window.clientInformation.appVersion&&window.clientInformation.appVersion.indexOf("MSAppHost")>-1},isMozilla:function(){return e.exists(navigator)&&navigator.userAgent.toLowerCase().indexOf("mozilla")>-1&&-1===navigator.userAgent.toLowerCase().indexOf("apple")},isFirefoxOS:function(){return e.exists(navigator)&&-1===navigator.userAgent.toLowerCase().indexOf("android")&&-1===navigator.userAgent.toLowerCase().indexOf("apple")&&navigator.userAgent.toLowerCase().indexOf("mobile")>-1&&navigator.userAgent.toLowerCase().indexOf("mozilla")>-1},ieVersion:function(){var t,e,i=3;if("object"!=typeof document)return 0;t=document.createElement("div"),e=t.getElementsByTagName("i");do{t.innerHTML="\x3c!--[if gt IE "+ ++i+"]><i></i><![endif]--\x3e"}while(e[0]);return i>4?i:void 0}(),getDimensions:function(t,i){var r,s,o,n,a,h,l,c,d,u=/\d+(\.\d*)?px/;if(!this.isBrowser||null===t)return{width:500,height:500};if(i=i||document,r=i.getElementById(t),!e.exists(r))throw new Error("\nJSXGraph: HTML container element '"+t+"' not found.");return"none"!==(s=r.style.display)&&null!==s?r.clientWidth>0&&r.clientHeight>0?{width:r.clientWidth,height:r.clientHeight}:(d=window.getComputedStyle?window.getComputedStyle(r):r.style,{width:u.test(d.width)?parseFloat(d.width):0,height:u.test(d.height)?parseFloat(d.height):0}):(o=r.style,n=o.visibility,a=o.position,h=o.display,o.visibility="hidden",o.position="absolute",o.display="block",l=r.clientWidth,c=r.clientHeight,o.display=h,o.position=a,o.visibility=n,{width:l,height:c})},addEvent:function(t,i,r,s){var o=function(){return r.apply(s,arguments)};o.origin=r,s["x_internal"+i]=s["x_internal"+i]||[],s["x_internal"+i].push(o),e.exists(t)&&e.exists(t.addEventListener)&&t.addEventListener(i,o,!1),e.exists(t)&&e.exists(t.attachEvent)&&t.attachEvent("on"+i,o)},removeEvent:function(i,r,s,o){var n;if(!e.exists(o))return void t.debug("no such owner");if(!e.exists(o["x_internal"+r]))return void t.debug("no such type: "+r);if(!e.isArray(o["x_internal"+r]))return void t.debug("owner[x_internal + "+r+"] is not an array");if(-1===(n=e.indexOf(o["x_internal"+r],s,"origin")))return void t.debug("removeEvent: no such event function in internal list: "+s);try{e.exists(i)&&e.exists(i.removeEventListener)&&i.removeEventListener(r,o["x_internal"+r][n],!1),e.exists(i)&&e.exists(i.detachEvent)&&i.detachEvent("on"+r,o["x_internal"+r][n])}catch(e){t.debug("event not registered in browser: ("+r+" -- "+s+")")}o["x_internal"+r].splice(n,1)},removeAllEvents:function(e,i,r){var s,o;if(r["x_internal"+i]){for(o=r["x_internal"+i].length,s=o-1;s>=0;s--)t.removeEvent(e,i,r["x_internal"+i][s].origin,r);r["x_internal"+i].length>0&&t.debug("removeAllEvents: Not all events could be removed.")}},getPosition:function(i,r,s){var o,n,a,h=0,l=0;if(i||(i=window.event),s=s||document,a=i[t.touchProperty],e.exists(a)&&0===a.length&&(a=i.changedTouches),e.exists(r)&&e.exists(a))if(-1===r){for(n=a.length,o=0;o<n;o++)if(a[o]){i=a[o];break}}else i=a[r];return i.clientX&&(h=i.clientX,l=i.clientY),[h,l]},getOffset:function(t){var e,i=t,r=t,s=i.offsetLeft-i.scrollLeft,o=i.offsetTop-i.scrollTop;for(e=this.getCSSTransform([s,o],i),s=e[0],o=e[1],i=i.offsetParent;i;){for(s+=i.offsetLeft,o+=i.offsetTop,i.offsetParent&&(s+=i.clientLeft-i.scrollLeft,o+=i.clientTop-i.scrollTop),e=this.getCSSTransform([s,o],i),s=e[0],o=e[1],r=r.parentNode;r!==i;)s+=r.clientLeft-r.scrollLeft,o+=r.clientTop-r.scrollTop,e=this.getCSSTransform([s,o],r),s=e[0],o=e[1],r=r.parentNode;i=i.offsetParent}return[s,o]},getStyle:function(e,i){var r,s=e.ownerDocument;return s.defaultView&&s.defaultView.getComputedStyle?r=s.defaultView.getComputedStyle(e,null).getPropertyValue(i):e.currentStyle&&t.ieVersion>=9?r=e.currentStyle[i]:e.style&&(i=i.replace(/-([a-z]|[0-9])/gi,function(t,e){return e.toUpperCase()}),r=e.style[i]),r},getProp:function(t,e){var i=parseInt(this.getStyle(t,e),10);return isNaN(i)?0:i},getCSSTransform:function(t,i){var r,s,o,n,a,h,l,c,d=["transform","webkitTransform","MozTransform","msTransform","oTransform"];for(h=d.length,r=0,o="";r<h;r++)if(e.exists(i.style[d[r]])){o=i.style[d[r]];break}if(""!==o&&(a=o.indexOf("("))>0){for(h=o.length,n=o.substring(a+1,h-1),c=n.split(","),s=0,l=c.length;s<l;s++)c[s]=parseFloat(c[s]);0===o.indexOf("matrix")?(t[0]+=c[4],t[1]+=c[5]):0===o.indexOf("translateX")?t[0]+=c[0]:0===o.indexOf("translateY")?t[1]+=c[0]:0===o.indexOf("translate")&&(t[0]+=c[0],t[1]+=c[1])}return e.exists(i.style.zoom)&&""!==(o=i.style.zoom)&&(t[0]*=parseFloat(o),t[1]*=parseFloat(o)),t},getCSSTransformMatrix:function(t){var i,r,s,o,n,a,h,l,c,d=t.ownerDocument,u=["transform","webkitTransform","MozTransform","msTransform","oTransform"],p=[[1,0,0],[0,1,0],[0,0,1]];if(d.defaultView&&d.defaultView.getComputedStyle)c=d.defaultView.getComputedStyle(t,null),s=c.getPropertyValue("-webkit-transform")||c.getPropertyValue("-moz-transform")||c.getPropertyValue("-ms-transform")||c.getPropertyValue("-o-transform")||c.getPropertyValue("transform");else for(a=u.length,i=0,s="";i<a;i++)if(e.exists(t.style[u[i]])){s=t.style[u[i]];break}if(""!==s&&(n=s.indexOf("("))>0){for(a=s.length,o=s.substring(n+1,a-1),l=o.split(","),r=0,h=l.length;r<h;r++)l[r]=parseFloat(l[r]);0===s.indexOf("matrix")?p=[[1,0,0],[0,l[0],l[1]],[0,l[2],l[3]]]:0===s.indexOf("scaleX")?p[1][1]=l[0]:0===s.indexOf("scaleY")?p[2][2]=l[0]:0===s.indexOf("scale")&&(p[1][1]=l[0],p[2][2]=l[1])}return e.exists(t.style.zoom)&&""!==(s=t.style.zoom)&&(p[1][1]*=parseFloat(s),p[2][2]*=parseFloat(s)),p},timedChunk:function(t,e,i,r){var s=t.concat(),o=function(){var n=+new Date;do{e.call(i,s.shift())}while(s.length>0&&+new Date-n<300);s.length>0?window.setTimeout(o,1):r(t)};window.setTimeout(o,1)},scaleJSXGraphDiv:function(t,e,i,r){var s,o,n=document.styleSheets.length,a=[":-webkit-full-screen",":-moz-full-screen",":fullscreen",":-ms-fullscreen"],h=a.length,l="{margin:0 auto;transform:matrix("+i+",0,0,"+i+",0,"+r+");}",c=new RegExp(".*"+t+":.*full.*screen.*"+e+".*auto;.*transform:.*matrix");for(0===n&&(s=document.createElement("style"),s.appendChild(document.createTextNode("")),document.body.appendChild(s),n=document.styleSheets.length),document.styleSheets[n-1].cssRules.length>0&&c.test(document.styleSheets[n-1].cssRules[0].cssText)&&document.styleSheets[n-1].deleteRule&&document.styleSheets[n-1].deleteRule(0),o=0;o<h;o++)try{document.styleSheets[n-1].insertRule(t+a[o]+" "+e+l,0);break}catch(t){console.log('JXG.scaleJSXGraphDiv: Could not add CSS rule "'+a[o]+'".'),console.log("One possible reason could be that the id of the JSXGraph container does not start with a letter.")}},toFullscreen:function(t,e,i){var r=document.getElementById(t),s=document.getElementById(e),o=parseInt(s.style.height,10),n=window.screen.width/parseInt(s.style.width,10),a=window.screen.height/parseInt(s.style.height,10),h=.5*(window.screen.height-o);i=i||Math.min(n,a),window.matchMedia&&window.matchMedia("(orientation:landscape)").matches&&window.screen.width<window.screen.height&&(n=window.screen.height/parseInt(s.style.width,10),a=window.screen.width/parseInt(s.style.height,10),i=Math.min(n,a),h=.5*(window.screen.width-o)),i*=.85,this.scaleJSXGraphDiv("#"+t,"#"+e,i,h),r.requestFullscreen=r.requestFullscreen||r.webkitRequestFullscreen||r.mozRequestFullScreen||r.msRequestFullscreen,r.requestFullscreen&&r.requestFullscreen()}}),t}),define("utils/xml",["jxg","utils/type"],function(t,e){"use strict";return t.XML={cleanWhitespace:function(t){for(var i=t.firstChild;e.exists(i);)3!==i.nodeType||/\S/.test(i.nodeValue)?1===i.nodeType&&this.cleanWhitespace(i):t.removeChild(i),i=i.nextSibling},parse:function(t){var e,i,r;return r="function"==typeof DOMParser||"object"==typeof DOMParser?DOMParser:function(){this.parseFromString=function(t){var e;return"function"==typeof ActiveXObject&&(e=new ActiveXObject("MSXML.DomDocument"),e.loadXML(t)),e}},e=new r,i=e.parseFromString(t,"text/xml"),this.cleanWhitespace(i),i}},t.XML}),define("utils/event",["jxg","utils/type"],function(t,e){"use strict";return t.EventEmitter={eventHandlers:{},suspended:{},trigger:function(t,e){var i,r,s,o,n,a;for(n=t.length,r=0;r<n;r++)if(o=this.eventHandlers[t[r]],!this.suspended[t[r]]){if(this.suspended[t[r]]=!0,o)for(a=o.length,i=0;i<a;i++)s=o[i],s.handler.apply(s.context,e);this.suspended[t[r]]=!1}return this},on:function(t,i,r){return e.isArray(this.eventHandlers[t])||(this.eventHandlers[t]=[]),r=e.def(r,this),this.eventHandlers[t].push({handler:i,context:r}),this},off:function(t,i){var r;return t&&e.isArray(this.eventHandlers[t])?(i?(r=e.indexOf(this.eventHandlers[t],i,"handler"),r>-1&&this.eventHandlers[t].splice(r,1),0===this.eventHandlers[t].length&&delete this.eventHandlers[t]):delete this.eventHandlers[t],this):this},eventify:function(t){t.eventHandlers={},t.on=this.on,t.off=this.off,t.triggerEventHandlers=this.trigger,t.trigger=this.trigger,t.suspended={}}},t.EventEmitter}),define("math/math",["jxg","utils/type"],function(t,e){"use strict";var i=function(t){var e,i;return t.memo?t.memo:(e={},i=Array.prototype.join,t.memo=function(){var r=i.call(arguments);return void 0!==e[r]?e[r]:e[r]=t.apply(this,arguments)},t.memo)};return t.Math={eps:1e-6,relDif:function(t,e){var i=Math.abs(t),r=Math.abs(e);return r=Math.max(i,r),0===r?0:Math.abs(t-e)/r},mod:function(t,e){return t-Math.floor(t/e)*e},vector:function(t,e){var i,r;for(e=e||0,i=[],r=0;r<t;r++)i[r]=e;return i},matrix:function(t,e,i){var r,s,o;for(i=i||0,e=e||t,r=[],s=0;s<t;s++)for(r[s]=[],o=0;o<e;o++)r[s][o]=i;return r},identity:function(t,e){var i,r;for(void 0===e&&"number"!=typeof e&&(e=t),i=this.matrix(t,e),r=0;r<Math.min(t,e);r++)i[r][r]=1;return i},frustum:function(t,e,i,r,s,o){var n=this.matrix(4,4);return n[0][0]=2*s/(e-t),n[0][1]=0,n[0][2]=(e+t)/(e-t),n[0][3]=0,n[1][0]=0,n[1][1]=2*s/(r-i),n[1][2]=(r+i)/(r-i),n[1][3]=0,n[2][0]=0,n[2][1]=0,n[2][2]=-(o+s)/(o-s),n[2][3]=-o*s*2/(o-s),n[3][0]=0,n[3][1]=0,n[3][2]=-1,n[3][3]=0,n},projection:function(t,e,i,r){var s=i*Math.tan(t/2),o=s*e;return this.frustum(-o,o,-s,s,i,r)},matVecMult:function(t,e){var i,r,s,o=t.length,n=e.length,a=[];if(3===n)for(i=0;i<o;i++)a[i]=t[i][0]*e[0]+t[i][1]*e[1]+t[i][2]*e[2];else for(i=0;i<o;i++){for(r=0,s=0;s<n;s++)r+=t[i][s]*e[s];a[i]=r}return a},matMatMult:function(t,e){var i,r,s,o,n=t.length,a=n>0?e[0].length:0,h=e.length,l=this.matrix(n,a);for(i=0;i<n;i++)for(r=0;r<a;r++){for(s=0,o=0;o<h;o++)s+=t[i][o]*e[o][r];l[i][r]=s}return l},transpose:function(t){var e,i,r,s,o;for(s=t.length,o=t.length>0?t[0].length:0,e=this.matrix(o,s),i=0;i<o;i++)for(r=0;r<s;r++)e[i][r]=t[r][i];return e},inverse:function(t){var e,i,r,s,o,n,a,h=t.length,l=[],c=[],d=[];for(e=0;e<h;e++){for(l[e]=[],i=0;i<h;i++)l[e][i]=t[e][i];c[e]=e}for(i=0;i<h;i++){for(o=Math.abs(l[i][i]),n=i,e=i+1;e<h;e++)Math.abs(l[e][i])>o&&(o=Math.abs(l[e][i]),n=e);if(o<=this.eps)return[];if(n>i){for(r=0;r<h;r++)a=l[i][r],l[i][r]=l[n][r],l[n][r]=a;a=c[i],c[i]=c[n],c[n]=a}for(s=1/l[i][i],e=0;e<h;e++)l[e][i]*=s;for(l[i][i]=s,r=0;r<h;r++)if(r!==i){for(e=0;e<h;e++)e!==i&&(l[e][r]-=l[e][i]*l[i][r]);l[i][r]=-s*l[i][r]}}for(e=0;e<h;e++){for(r=0;r<h;r++)d[c[r]]=l[e][r];for(r=0;r<h;r++)l[e][r]=d[r]}return l},innerProduct:function(t,i,r){var s,o=0;for(void 0!==r&&e.isNumber(r)||(r=t.length),s=0;s<r;s++)o+=t[s]*i[s];return o},crossProduct:function(t,e){return[t[1]*e[2]-t[2]*e[1],t[2]*e[0]-t[0]*e[2],t[0]*e[1]-t[1]*e[0]]},norm:function(t,i){var r,s=0;for(void 0!==i&&e.isNumber(i)||(i=t.length),r=0;r<i;r++)s+=t[r]*t[r];return Math.sqrt(s)},factorial:i(function(t){return t<0?NaN:(t=Math.floor(t),0===t||1===t?1:t*this.factorial(t-1))}),binomial:i(function(t,e){var i,r;if(e>t||e<0)return NaN;if(e=Math.round(e),t=Math.round(t),0===e||e===t)return 1;for(i=1,r=0;r<e;r++)i*=t-r,i/=r+1;return i}),cosh:Math.cosh||function(t){return.5*(Math.exp(t)+Math.exp(-t))},sinh:Math.sinh||function(t){return.5*(Math.exp(t)-Math.exp(-t))},cot:function(t){return 1/Math.tan(t)},acot:function(t){return(t>=0?.5:-.5)*Math.PI-Math.atan(t)},nthroot:function(t,e){var i=1/e;return e<=0||Math.floor(e)!==e?NaN:0===t?0:t>0?Math.exp(i*Math.log(t)):e%2==1?-Math.exp(i*Math.log(-t)):NaN},cbrt:Math.cbrt||function(t){return this.nthroot(t,3)},pow:function(t,e){return 0===t?0===e?1:0:Math.floor(e)===e?Math.pow(t,e):t>0?Math.exp(e*Math.log(t)):NaN},ratpow:function(t,e,i){var r;return 0===e?1:0===i?NaN:(r=this.gcd(e,i),this.nthroot(this.pow(t,e/r),i/r))},log10:function(t){return Math.log(t)/Math.log(10)},log2:function(t){return Math.log(t)/Math.log(2)},log:function(t,i){return void 0!==i&&e.isNumber(i)?Math.log(t)/Math.log(i):Math.log(t)},sign:Math.sign||function(t){return t=+t,0===t||isNaN(t)?t:t>0?1:-1},squampow:function(t,e){var i;if(Math.floor(e)===e){for(i=1,e<0&&(t=1/t,e*=-1);0!==e;)1&e&&(i*=t),e>>=1,t*=t;return i}return this.pow(t,e)},gcd:function(t,i){if(t=Math.abs(t),i=Math.abs(i),!e.isNumber(t)||!e.isNumber(i))return NaN;if(i>t){var r=t;t=i,i=r}for(;;){if(0===(t%=i))return i;if(0===(i%=t))return t}},lcm:function(t,i){var r;return e.isNumber(t)&&e.isNumber(i)?(r=t*i,0!==r?r/this.gcd(t,i):0):NaN},normalize:function(t){var e,i,r=2*t[3],s=t[4]/r;return t[5]=s,t[6]=-t[1]/r,t[7]=-t[2]/r,isFinite(s)?Math.abs(s)>=1?(t[0]=(t[6]*t[6]+t[7]*t[7]-s*s)/(2*s),t[1]=-t[6]/s,t[2]=-t[7]/s,t[3]=1/(2*s),t[4]=1):(i=s<=0?-1:1,t[0]=i*(t[6]*t[6]+t[7]*t[7]-s*s)*.5,t[1]=-i*t[6], -t[2]=-i*t[7],t[3]=i/2,t[4]=i*s):(e=Math.sqrt(t[1]*t[1]+t[2]*t[2]),t[0]/=e,t[1]/=e,t[2]/=e,t[3]=0,t[4]=1),t},toGL:function(t){var e,i,r;if(e="function"==typeof Float32Array?new Float32Array(16):new Array(16),4!==t.length&&4!==t[0].length)return e;for(i=0;i<4;i++)for(r=0;r<4;r++)e[i+4*r]=t[i][r];return e}},t.Math}),define("base/coords",["jxg","base/constants","utils/event","utils/type","math/math"],function(t,e,i,r,s){"use strict";return t.Coords=function(t,e,s,o){this.board=s,this.usrCoords=[],this.scrCoords=[],this.emitter=!r.exists(o)||o,this.emitter&&i.eventify(this),this.setCoordinates(t,e,!1,!0)},t.extend(t.Coords.prototype,{normalizeUsrCoords:function(){Math.abs(this.usrCoords[0])>s.eps&&(this.usrCoords[1]/=this.usrCoords[0],this.usrCoords[2]/=this.usrCoords[0],this.usrCoords[0]=1)},usr2screen:function(t){var e=Math.round,i=this.board,r=this.usrCoords,s=i.origin.scrCoords;!0===t?(this.scrCoords[0]=e(r[0]),this.scrCoords[1]=e(r[0]*s[1]+r[1]*i.unitX),this.scrCoords[2]=e(r[0]*s[2]-r[2]*i.unitY)):(this.scrCoords[0]=r[0],this.scrCoords[1]=r[0]*s[1]+r[1]*i.unitX,this.scrCoords[2]=r[0]*s[2]-r[2]*i.unitY)},screen2usr:function(){var t=this.board.origin.scrCoords,e=this.scrCoords,i=this.board;this.usrCoords[0]=1,this.usrCoords[1]=(e[1]-t[1])/i.unitX,this.usrCoords[2]=(t[2]-e[2])/i.unitY},distance:function(t,i){var r,o,n=0,a=this.usrCoords,h=this.scrCoords;if(t===e.COORDS_BY_USER){if(r=i.usrCoords,o=a[0]-r[0],(n=o*o)>s.eps*s.eps)return Number.POSITIVE_INFINITY;o=a[1]-r[1],n+=o*o,o=a[2]-r[2],n+=o*o}else r=i.scrCoords,o=h[1]-r[1],n+=o*o,o=h[2]-r[2],n+=o*o;return Math.sqrt(n)},setCoordinates:function(t,i,r,s){var o=this.usrCoords,n=this.scrCoords,a=[o[0],o[1],o[2]],h=[n[0],n[1],n[2]];return t===e.COORDS_BY_USER?(2===i.length?(o[0]=1,o[1]=i[0],o[2]=i[1]):(o[0]=i[0],o[1]=i[1],o[2]=i[2],this.normalizeUsrCoords()),this.usr2screen(r)):(2===i.length?(n[1]=i[0],n[2]=i[1]):(n[1]=i[1],n[2]=i[2]),this.screen2usr()),!this.emitter||s||h[1]===n[1]&&h[2]===n[2]||this.triggerEventHandlers(["update"],[a,h]),this},copy:function(t,e){return void 0===e&&(e=0),this[t].slice(e)},isReal:function(){return!isNaN(this.usrCoords[1]+this.usrCoords[2])&&Math.abs(this.usrCoords[0])>s.eps},__evt__update:function(t,e){},__evt:function(){}}),t.Coords}),define("utils/expect",["jxg","utils/type","base/constants","base/coords"],function(t,e,i,r){"use strict";var s={each:function(t,i,r){var s,o,n=[];if(e.exists(t.length))for(o=t.length,s=0;s<o;s++)n.push(i.call(this,t[s],r));return n},coords:function(t,e){var s=t;return t&&t.elementClass===i.OBJECT_CLASS_POINT?s=t.coords:t.usrCoords&&t.scrCoords&&t.usr2screen&&(s=t),e&&(s=new r(i.COORDS_BY_USER,s.usrCoords,s.board)),s},coordsArray:function(t,i){var r;return r=e.isArray(t)?t:this.coords(t).usrCoords,r.length<3&&r.unshift(1),i&&(r=[r[0],r[1],r[2]]),r}};return t.Expect=s,s}),define("math/ia",["jxg","math/math","utils/type"],function(t,e,i){"use strict";t.Math.DoubleBits=function(){var t,e,i,r,s,o,n,a,h=new Float64Array(1),l=new Uint32Array(h.buffer);void 0!==Float64Array&&(h[0]=1,!0,1072693248===l[1]?(t=function(t){return h[0]=t,[l[0],l[1]]},e=function(t,e){return l[0]=t,l[1]=e,h[0]},i=function(t){return h[0]=t,l[0]},r=function(t){return h[0]=t,l[1]},this.doubleBits=t,this.pack=e,this.lo=i,this.hi=r):1072693248===l[0]&&(s=function(t){return h[0]=t,[l[1],l[0]]},o=function(t,e){return l[1]=t,l[0]=e,h[0]},n=function(t){return h[0]=t,l[1]},a=function(t){return h[0]=t,l[0]},this.doubleBits=s,this.pack=o,this.lo=n,this.hi=a))},t.extend(t.Math.DoubleBits.prototype,{sign:function(t){return this.hi(t)>>>31},exponent:function(t){return(this.hi(t)<<1>>>21)-1023},fraction:function(t){var e=this.lo(t),i=this.hi(t),r=1048575&i;return 2146435072&i&&(r+=1<<20),[e,r]},denormalized:function(t){return!(2146435072&this.hi(t))}});var r=new t.Math.DoubleBits,s=function(t,i){if(void 0!==t&&void 0!==i){if(e.IntervalArithmetic.isInterval(t)){if(!e.IntervalArithmetic.isSingleton(t))throw new TypeError("JXG.Math.IntervalArithmetic: interval `lo` must be a singleton");this.lo=t.lo}else this.lo=t;if(e.IntervalArithmetic.isInterval(i)){if(!e.IntervalArithmetic.isSingleton(i))throw new TypeError("JXG.Math.IntervalArithmetic: interval `hi` must be a singleton");this.hi=i.hi}else this.hi=i}else{if(void 0!==t)return Array.isArray(t)?new s(t[0],t[1]):new s(t,t);this.lo=this.hi=0}};return t.extend(s.prototype,{print:function(){console.log("[",this.lo,this.hi,"]")},set:function(t,e){return this.lo=t,this.hi=e,this},bounded:function(t,i){return this.set(e.IntervalArithmetic.prev(t),e.IntervalArithmetic.next(i))},boundedSingleton:function(t){return this.bounded(t,t)},assign:function(t,e){if("number"!=typeof t||"number"!=typeof e)throw new TypeError("JXG.Math.Interval#assign: arguments must be numbers");return isNaN(t)||isNaN(e)||t>e?this.setEmpty():this.set(t,e)},setEmpty:function(){return this.set(Number.POSITIVE_INFINITY,Number.NEGATIVE_INFINITY)},setWhole:function(){return this.set(Number.NEGATIVE_INFINITY,Number.POSITIVE_INFINITY)},open:function(t,i){return this.assign(e.IntervalArithmetic.next(t),e.IntervalArithmetic.prev(i))},halfOpenLeft:function(t,i){return this.assign(e.IntervalArithmetic.next(t),i)},halfOpenRight:function(t,i){return this.assign(t,e.IntervalArithmetic.prev(i))},toArray:function(){return[this.lo,this.hi]},clone:function(){return(new s).set(this.lo,this.hi)}}),t.Math.IntervalArithmetic={Interval:function(t,e){return new s(t,e)},isInterval:function(t){return null!==t&&"object"==typeof t&&"number"==typeof t.lo&&"number"==typeof t.hi},isSingleton:function(t){return t.lo===t.hi},add:function(t,e){return i.isNumber(t)&&(t=this.Interval(t)),i.isNumber(e)&&(e=this.Interval(e)),new s(this.addLo(t.lo,e.lo),this.addHi(t.hi,e.hi))},sub:function(t,e){return i.isNumber(t)&&(t=this.Interval(t)),i.isNumber(e)&&(e=this.Interval(e)),new s(this.subLo(t.lo,e.hi),this.subHi(t.hi,e.lo))},mul:function(t,e){var r,o,n,a,h;return i.isNumber(t)&&(t=this.Interval(t)),i.isNumber(e)&&(e=this.Interval(e)),this.isEmpty(t)||this.isEmpty(e)?this.EMPTY.clone():(r=t.lo,o=t.hi,n=e.lo,a=e.hi,h=new s,r<0?o>0?n<0?a>0?(h.lo=Math.min(this.mulLo(r,a),this.mulLo(o,n)),h.hi=Math.max(this.mulHi(r,n),this.mulHi(o,a))):(h.lo=this.mulLo(o,n),h.hi=this.mulHi(r,n)):a>0?(h.lo=this.mulLo(r,a),h.hi=this.mulHi(o,a)):(h.lo=0,h.hi=0):n<0?a>0?(h.lo=this.mulLo(r,a),h.hi=this.mulHi(r,n)):(h.lo=this.mulLo(o,a),h.hi=this.mulHi(r,n)):a>0?(h.lo=this.mulLo(r,a),h.hi=this.mulHi(o,n)):(h.lo=0,h.hi=0):o>0?n<0?a>0?(h.lo=this.mulLo(o,n),h.hi=this.mulHi(o,a)):(h.lo=this.mulLo(o,n),h.hi=this.mulHi(r,a)):a>0?(h.lo=this.mulLo(r,n),h.hi=this.mulHi(o,a)):(h.lo=0,h.hi=0):(h.lo=0,h.hi=0),h)},div:function(t,e){return i.isNumber(t)&&(t=this.Interval(t)),i.isNumber(e)&&(e=this.Interval(e)),this.isEmpty(t)||this.isEmpty(e)?this.EMPTY.clone():this.zeroIn(e)?0!==e.lo?0!==e.hi?this.divZero(t):this.divNegative(t,e.lo):0!==e.hi?this.divPositive(t,e.hi):this.EMPTY.clone():this.divNonZero(t,e)},positive:function(t){return new s(t.lo,t.hi)},negative:function(t){return i.isNumber(t)?new s(-t):new s(-t.hi,-t.lo)},isEmpty:function(t){return t.lo>t.hi},isWhole:function(t){return t.lo===-1/0&&t.hi===1/0},zeroIn:function(t){return this.hasValue(t,0)},hasValue:function(t,e){return!this.isEmpty(t)&&(t.lo<=e&&e<=t.hi)},hasInterval:function(t,e){return!!this.isEmpty(t)||!this.isEmpty(e)&&e.lo<=t.lo&&t.hi<=e.hi},intervalsOverlap:function(t,e){return!this.isEmpty(t)&&!this.isEmpty(e)&&(t.lo<=e.lo&&e.lo<=t.hi||e.lo<=t.lo&&t.lo<=e.hi)},divNonZero:function(t,e){var i=t.lo,r=t.hi,o=e.lo,n=e.hi,a=new s;return r<0?n<0?(a.lo=this.divLo(r,o),a.hi=this.divHi(i,n)):(a.lo=this.divLo(i,o),a.hi=this.divHi(r,n)):i<0?n<0?(a.lo=this.divLo(r,n),a.hi=this.divHi(i,n)):(a.lo=this.divLo(i,o),a.hi=this.divHi(r,o)):n<0?(a.lo=this.divLo(r,n),a.hi=this.divHi(i,o)):(a.lo=this.divLo(i,n),a.hi=this.divHi(r,o)),a},divPositive:function(t,e){return 0===t.lo&&0===t.hi?t:this.zeroIn(t)?this.WHOLE:t.hi<0?new s(Number.NEGATIVE_INFINITY,this.divHi(t.hi,e)):new s(this.divLo(t.lo,e),Number.POSITIVE_INFINITY)},divNegative:function(t,e){return 0===t.lo&&0===t.hi?t:this.zeroIn(t)?this.WHOLE:t.hi<0?new s(this.divLo(t.hi,e),Number.POSITIVE_INFINITY):new s(Number.NEGATIVE_INFINITY,this.divHi(t.lo,e))},divZero:function(t){return 0===t.lo&&0===t.hi?t:this.WHOLE},fmod:function(t,e){var r,o;return i.isNumber(t)&&(t=this.Interval(t)),i.isNumber(e)&&(e=this.Interval(e)),this.isEmpty(t)||this.isEmpty(e)?this.EMPTY.clone():(r=t.lo<0?e.lo:e.hi,o=t.lo/r,o=o<0?Math.ceil(o):Math.floor(o),this.sub(t,this.mul(e,new s(o))))},multiplicativeInverse:function(t){return i.isNumber(t)&&(t=this.Interval(t)),this.isEmpty(t)?this.EMPTY.clone():this.zeroIn(t)?0!==t.lo?0!==t.hi?this.WHOLE:new s(Number.NEGATIVE_INFINITY,this.divHi(1,t.lo)):0!==t.hi?new s(this.divLo(1,t.hi),Number.POSITIVE_INFINITY):this.EMPTY.clone():new s(this.divLo(1,t.hi),this.divHi(1,t.lo))},pow:function(t,e){var r,o;if(i.isNumber(t)&&(t=this.Interval(t)),this.isEmpty(t))return this.EMPTY.clone();if(this.isInterval(e)){if(!this.isSingleton(e))return this.EMPTY.clone();e=e.lo}return 0===e?0===t.lo&&0===t.hi?this.EMPTY.clone():this.ONE.clone():e<0?this.pow(this.multiplicativeInverse(t),-e):e%1==0?t.hi<0?(r=this.powLo(-t.hi,e),o=this.powHi(-t.lo,e),1==(1&e)?new s(-o,-r):new s(r,o)):t.lo<0?1==(1&e)?new s(-this.powLo(-t.lo,e),this.powHi(t.hi,e)):new s(0,this.powHi(Math.max(-t.lo,t.hi),e)):new s(this.powLo(t.lo,e),this.powHi(t.hi,e)):(console.warn("power is not an integer, you should use nth-root instead, returning an empty interval"),this.EMPTY.clone())},sqrt:function(t){return i.isNumber(t)&&(t=this.Interval(t)),this.nthRoot(t,2)},nthRoot:function(t,e){var r,o,n,a,h;if(i.isNumber(t)&&(t=this.Interval(t)),this.isEmpty(t)||e<0)return this.EMPTY.clone();if(this.isInterval(e)){if(!this.isSingleton(e))return this.EMPTY.clone();e=e.lo}return r=1/e,t.hi<0?e%1==0&&1==(1&e)?(o=this.powHi(-t.lo,r),n=this.powLo(-t.hi,r),new s(-o,-n)):this.EMPTY.clone():t.lo<0?(a=this.powHi(t.hi,r),e%1==0&&1==(1&e)?(h=-this.powHi(-t.lo,r),new s(h,a)):new s(0,a)):new s(this.powLo(t.lo,r),this.powHi(t.hi,r))},exp:function(t){return i.isNumber(t)&&(t=this.Interval(t)),this.isEmpty(t)?this.EMPTY.clone():new s(this.expLo(t.lo),this.expHi(t.hi))},log:function(t){var e;return i.isNumber(t)&&(t=this.Interval(t)),this.isEmpty(t)?this.EMPTY.clone():(e=t.lo<=0?Number.NEGATIVE_INFINITY:this.logLo(t.lo),new s(e,this.logHi(t.hi)))},ln:function(t){return this.log(t)},log10:function(t){return this.isEmpty(t)?this.EMPTY.clone():this.div(this.log(t),this.log(new s(10,10)))},log2:function(t){return this.isEmpty(t)?this.EMPTY.clone():this.div(this.log(t),this.log(new s(2,2)))},hull:function(t,e){var i=this.isEmpty(t),r=this.isEmpty(e);return i&&r?this.EMPTY.clone():i?e.clone():r?t.clone():new s(Math.min(t.lo,e.lo),Math.max(t.hi,e.hi))},intersection:function(t,e){var i,r;return this.isEmpty(t)||this.isEmpty(e)?this.EMPTY.clone():(i=Math.max(t.lo,e.lo),r=Math.min(t.hi,e.hi),i<=r?new s(i,r):this.EMPTY.clone())},union:function(t,e){if(!this.intervalsOverlap(t,e))throw new Error("Interval#unions do not overlap");return new s(Math.min(t.lo,e.lo),Math.max(t.hi,e.hi))},difference:function(t,e){if(this.isEmpty(t)||this.isWhole(e))return this.EMPTY.clone();if(this.intervalsOverlap(t,e)){if(t.lo<e.lo&&e.hi<t.hi)throw new Error("Interval.difference: difference creates multiple intervals");return e.lo<=t.lo&&e.hi===1/0||e.hi>=t.hi&&e.lo===-1/0?this.EMPTY.clone():e.lo<=t.lo?(new s).halfOpenLeft(e.hi,t.hi):(new s).halfOpenRight(t.lo,e.lo)}return t.clone()},width:function(t){return this.isEmpty(t)?0:this.subHi(t.hi,t.lo)},abs:function(t){return i.isNumber(t)&&(t=this.Interval(t)),this.isEmpty(t)?this.EMPTY.clone():t.lo>=0?t.clone():t.hi<=0?this.negative(t):new s(0,Math.max(-t.lo,t.hi))},max:function(t,e){var i=this.isEmpty(t),r=this.isEmpty(e);return i&&r?this.EMPTY.clone():i?e.clone():r?t.clone():new s(Math.max(t.lo,e.lo),Math.max(t.hi,e.hi))},min:function(t,e){var i=this.isEmpty(t),r=this.isEmpty(e);return i&&r?this.EMPTY.clone():i?e.clone():r?t.clone():new s(Math.min(t.lo,e.lo),Math.min(t.hi,e.hi))},onlyInfinity:function(t){return!isFinite(t.lo)&&t.lo===t.hi},_handleNegative:function(t){var e;return t.lo<0&&(t.lo===-1/0?(t.lo=0,t.hi=1/0):(e=Math.ceil(-t.lo/this.piTwiceLow),t.lo+=this.piTwiceLow*e,t.hi+=this.piTwiceLow*e)),t},cos:function(t){var e,i,r,o,n,a,h,l;return this.isEmpty(t)||this.onlyInfinity(t)?this.EMPTY.clone():(e=(new s).set(t.lo,t.hi),this._handleNegative(e),i=this.PI_TWICE,r=this.fmod(e,i),this.width(r)>=i.lo?new s(-1,1):r.lo>=this.piHigh?(o=this.cos(this.sub(r,this.PI)),this.negative(o)):(n=r.lo,a=r.hi,h=this.cosLo(a),l=this.cosHi(n),a<=this.piLow?new s(h,l):a<=i.lo?new s(-1,Math.max(h,l)):new s(-1,1)))},sin:function(t){return this.isEmpty(t)||this.onlyInfinity(t)?this.EMPTY.clone():this.cos(this.sub(t,this.PI_HALF))},tan:function(t){var e,i,r;return this.isEmpty(t)||this.onlyInfinity(t)?this.EMPTY.clone():(e=(new s).set(t.lo,t.hi),this._handleNegative(e),r=this.PI,i=this.fmod(e,r),i.lo>=this.piHalfLow&&(i=this.sub(i,r)),i.lo<=-this.piHalfLow||i.hi>=this.piHalfLow?this.WHOLE.clone():new s(this.tanLo(i.lo),this.tanHi(i.hi)))},asin:function(t){var e,i;return this.isEmpty(t)||t.hi<-1||t.lo>1?this.EMPTY.clone():(e=t.lo<=-1?-this.piHalfHigh:this.asinLo(t.lo),i=t.hi>=1?this.piHalfHigh:this.asinHi(t.hi),new s(e,i))},acos:function(t){var e,i;return this.isEmpty(t)||t.hi<-1||t.lo>1?this.EMPTY.clone():(e=t.hi>=1?0:this.acosLo(t.hi),i=t.lo<=-1?this.piHigh:this.acosHi(t.lo),new s(e,i))},atan:function(t){return this.isEmpty(t)?this.EMPTY.clone():new s(this.atanLo(t.lo),this.atanHi(t.hi))},sinh:function(t){return this.isEmpty(t)?this.EMPTY.clone():new s(this.sinhLo(t.lo),this.sinhHi(t.hi))},cosh:function(t){return this.isEmpty(t)?this.EMPTY.clone():t.hi<0?new s(this.coshLo(t.hi),this.coshHi(t.lo)):t.lo>=0?new s(this.coshLo(t.lo),this.coshHi(t.hi)):new s(1,this.coshHi(-t.lo>t.hi?t.lo:t.hi))},tanh:function(t){return this.isEmpty(t)?this.EMPTY.clone():new s(this.tanhLo(t.lo),this.tanhHi(t.hi))},equal:function(t,e){return this.isEmpty(t)?this.isEmpty(e):!this.isEmpty(e)&&t.lo===e.lo&&t.hi===e.hi},notEqual:function(t,e){return this.isEmpty(t)?!this.isEmpty(e):this.isEmpty(e)||t.hi<e.lo||t.lo>e.hi},lt:function(t,e){return i.isNumber(t)&&(t=this.Interval(t)),i.isNumber(e)&&(e=this.Interval(e)),!this.isEmpty(t)&&!this.isEmpty(e)&&t.hi<e.lo},gt:function(t,e){return i.isNumber(t)&&(t=this.Interval(t)),i.isNumber(e)&&(e=this.Interval(e)),!this.isEmpty(t)&&!this.isEmpty(e)&&t.lo>e.hi},leq:function(t,e){return i.isNumber(t)&&(t=this.Interval(t)),i.isNumber(e)&&(e=this.Interval(e)),!this.isEmpty(t)&&!this.isEmpty(e)&&t.hi<=e.lo},geq:function(t,e){return i.isNumber(t)&&(t=this.Interval(t)),i.isNumber(e)&&(e=this.Interval(e)),!this.isEmpty(t)&&!this.isEmpty(e)&&t.lo>=e.hi},piLow:3.141592653589793,piHigh:3.1415926535897936,piHalfLow:1.5707963267948966,piHalfHigh:1.5707963267948968,piTwiceLow:6.283185307179586,piTwiceHigh:6.283185307179587,identity:function(t){return t},_prev:function(t){return t===1/0?t:this.nextafter(t,-1/0)},_next:function(t){return t===-1/0?t:this.nextafter(t,1/0)},prev:function(t){return this._prev(t)},next:function(t){return this._next(t)},toInteger:function(t){return t<0?Math.ceil(t):Math.floor(t)},addLo:function(t,e){return this.prev(t+e)},addHi:function(t,e){return this.next(t+e)},subLo:function(t,e){return this.prev(t-e)},subHi:function(t,e){return this.next(t-e)},mulLo:function(t,e){return this.prev(t*e)},mulHi:function(t,e){return this.next(t*e)},divLo:function(t,e){return this.prev(t/e)},divHi:function(t,e){return this.next(t/e)},intLo:function(t){return this.toInteger(this.prev(t))},intHi:function(t){return this.toInteger(this.next(t))},logLo:function(t){return this.prev(Math.log(t))},logHi:function(t){return this.next(Math.log(t))},expLo:function(t){return this.prev(Math.exp(t))},expHi:function(t){return this.next(Math.exp(t))},sinLo:function(t){return this.prev(Math.sin(t))},sinHi:function(t){return this.next(Math.sin(t))},cosLo:function(t){return this.prev(Math.cos(t))},cosHi:function(t){return this.next(Math.cos(t))},tanLo:function(t){return this.prev(Math.tan(t))},tanHi:function(t){return this.next(Math.tan(t))},asinLo:function(t){return this.prev(Math.asin(t))},asinHi:function(t){return this.next(Math.asin(t))},acosLo:function(t){return this.prev(Math.acos(t))},acosHi:function(t){return this.next(Math.acos(t))},atanLo:function(t){return this.prev(Math.atan(t))},atanHi:function(t){return this.next(Math.atan(t))},sinhLo:function(t){return this.prev(e.sinh(t))},sinhHi:function(t){return this.next(e.sinh(t))},coshLo:function(t){return this.prev(e.cosh(t))},coshHi:function(t){return this.next(e.cosh(t))},tanhLo:function(t){return this.prev(e.tanh(t))},tanhHi:function(t){return this.next(e.tanh(t))},sqrtLo:function(t){return this.prev(Math.sqrt(t))},sqrtHi:function(t){return this.next(Math.sqrt(t))},powLo:function(t,e){var i;if(e%1!=0)return this.prev(Math.pow(t,e));for(i=1==(1&e)?t:1,e>>=1;e>0;)t=this.mulLo(t,t),1==(1&e)&&(i=this.mulLo(t,i)),e>>=1;return i},powHi:function(t,e){var i;if(e%1!=0)return this.next(Math.pow(t,e));for(i=1==(1&e)?t:1,e>>=1;e>0;)t=this.mulHi(t,t),1==(1&e)&&(i=this.mulHi(t,i)),e>>=1;return i},disable:function(){this.next=this.prev=this.identity},enable:function(){this.prev=function(t){return this._prev(t)},this.next=function(t){return this._next(t)}},SMALLEST_DENORM:Math.pow(2,-1074),UINT_MAX:-1>>>0,nextafter:function(t,e){var i,s;return isNaN(t)||isNaN(e)?NaN:t===e?t:0===t?e<0?-this.SMALLEST_DENORM:this.SMALLEST_DENORM:(s=r.hi(t),i=r.lo(t),e>t==t>0?i===this.UINT_MAX?(s+=1,i=0):i+=1:0===i?(i=this.UINT_MAX,s-=1):i-=1,r.pack(i,s))}},t.Math.IntervalArithmetic.PI=new s(e.IntervalArithmetic.piLow,e.IntervalArithmetic.piHigh),t.Math.IntervalArithmetic.PI_HALF=new s(e.IntervalArithmetic.piHalfLow,e.IntervalArithmetic.piHalfHigh),t.Math.IntervalArithmetic.PI_TWICE=new s(e.IntervalArithmetic.piTwiceLow,e.IntervalArithmetic.piTwiceHigh),t.Math.IntervalArithmetic.ZERO=new s(0),t.Math.IntervalArithmetic.ONE=new s(1),t.Math.IntervalArithmetic.WHOLE=(new s).setWhole(),t.Math.IntervalArithmetic.EMPTY=(new s).setEmpty(),t.Math.IntervalArithmetic}),define("math/extrapolate",["math/math"],function(t){"use strict";return t.Extrapolate={upper:15,infty:1e4,wynnEps:function(t,e,i){var r,s,o,n,a,h;if(i[e]=t,0===e)h=t;else{for(n=0,s=e;s>0;s--)o=n,n=i[s-1],a=i[s]-n,Math.abs(a)<=1e-15?i[s-1]=1e20:(r=1,i[s-1]=o*r+1/a);h=i[e%2]}return h},aitken:function(t,e,i){var r,s,o,n,a,h;if(i[e]=t,e<2)r=t;else{for(n=e/2,a=1;a<=n;a++)h=e-2*a,s=i[h+2]-2*i[h+1]+i[h],Math.abs(s)<1e-15?i[h]=1e20:(o=i[h]-i[h+1],i[h]-=o*o/s);r=i[e%2]}return r},brezinski:function(t,e,i){var r,s,o,n,a,h,l,c;if(i[e]=t,e<3)r=t;else{for(h=e/3,c=e,l=1;l<=h;l++)c-=3,o=i[c+1]-i[c],n=i[c+2]-i[c+1],a=i[c+3]-i[c+2],s=a*(n-o)-o*(a-n),Math.abs(s)<1e-15?i[c]=1e20:i[c]=i[c+1]-o*n*(a-n)/s;r=i[e%3]}return r},iteration:function(t,e,i,r,s){var o,n,a,h,l=NaN,c=[],d="finite",u=e;for(s=s||0,o=1;o<=this.upper;o++){if(u=0===s?e/(o+1):.5*u,n=i(t+u,!0),a=this[r](n,o-1,c),isNaN(a)){d="NaN";break}if(0!==n&&a/n>this.infty){l=a,d="infinite";break}if(h=a-l,Math.abs(h)<1e-7)break;l=a}return[l,d,1-(o-1)/this.upper]},levin:function(t,e,i,r,s,o){var n,a,h,l;if(l=1/(r+e),s[e]=t/i,o[e]=1/i,e>0&&(s[e-1]=s[e]-s[e-1],o[e-1]=o[e]-o[e-1],e>1))for(h=(r+e-1)*l,n=2;n<=e;n++)a=(r+e-n)*Math.pow(h,n-2)*l,s[e-n]=s[e-n+1]-a*s[e-n],o[e-n]=o[e-n+1]-a*o[e-n],l*=h;return Math.abs(o[0])<1e-15?1e20:s[0]/o[0]},iteration_levin:function(t,e,i,r){var s,o,n,a,h,l,c,d=NaN,u=[],p=[],f="finite",m=e,g="u";for(r=r||0,a=i(t+e,!0),s=1;s<=this.upper;s++){if(m=0===r?e/(s+1):.5*m,o=i(t+m,!0),h=o-a,g=Math.abs(h)<1?"u":"t",c="u"===g?(1+s)*h:h,a=o,n=this.levin(o,s-1,c,1,u,p),l=n-d,isNaN(n)){f="NaN";break}if(0!==o&&n/o>this.infty){d=n,f="infinite";break}if(Math.abs(l)<1e-7)break;d=n}return[d,f,1-(s-1)/this.upper]},limit:function(t,e,i){return this.iteration_levin(t,e,i,0)}},t.Extrapolate}),define("math/qdt",["math/math","utils/type"],function(t,e){"use strict";var i=function(t){this.capacity=10,this.points=[],this.xlb=t[0],this.xub=t[2],this.ylb=t[3],this.yub=t[1],this.northWest=null,this.northEast=null,this.southEast=null,this.southWest=null};return e.extend(i.prototype,{contains:function(t,e){return this.xlb<t&&t<=this.xub&&this.ylb<e&&e<=this.yub},insert:function(t){return!!this.contains(t.usrCoords[1],t.usrCoords[2])&&(this.points.length<this.capacity?(this.points.push(t),!0):(null===this.northWest&&this.subdivide(),!!this.northWest.insert(t)||(!!this.northEast.insert(t)||(!!this.southEast.insert(t)||!!this.southWest.insert(t)))))},subdivide:function(){var t,e=this.points.length,r=this.xlb+(this.xub-this.xlb)/2,s=this.ylb+(this.yub-this.ylb)/2;for(this.northWest=new i([this.xlb,this.yub,r,s]),this.northEast=new i([r,this.yub,this.xub,s]),this.southEast=new i([this.xlb,s,r,this.ylb]),this.southWest=new i([r,s,this.xub,this.ylb]),t=0;t<e;t+=1)this.northWest.insert(this.points[t]),this.northEast.insert(this.points[t]),this.southEast.insert(this.points[t]),this.southWest.insert(this.points[t])},_query:function(t,e){var i;if(this.contains(t,e)){if(null===this.northWest)return this;if(i=this.northWest._query(t,e))return i;if(i=this.northEast._query(t,e))return i;if(i=this.southEast._query(t,e))return i;if(i=this.southWest._query(t,e))return i}return!1},query:function(t,i){var r,s;return e.exists(i)?(r=t,s=i):(r=t.usrCoords[1],s=t.usrCoords[2]),this._query(r,s)}}),t.Quadtree=i,i}),define("math/numerics",["jxg","utils/type","math/math"],function(t,e,i){"use strict";var r={rk4:{s:4,A:[[0,0,0,0],[.5,0,0,0],[0,.5,0,0],[0,0,1,0]],b:[1/6,1/3,1/3,1/6],c:[0,.5,.5,1]},heun:{s:2,A:[[0,0],[1,0]],b:[.5,.5],c:[0,1]},euler:{s:1,A:[[0]],b:[1],c:[0]}};return i.Numerics={Gauss:function(t,r){var s,o,n,a,h,l=i.eps,c=t.length>0?t[0].length:0;if(c!==r.length||c!==t.length)throw new Error("JXG.Math.Numerics.Gauss: Dimensions don't match. A must be a square matrix and b must be of the same length as A.");for(a=[],h=r.slice(0,c),s=0;s<c;s++)a[s]=t[s].slice(0,c);for(o=0;o<c;o++){for(s=c-1;s>o;s--)if(Math.abs(a[s][o])>l)if(Math.abs(a[o][o])<l)e.swap(a,s,o),e.swap(h,s,o);else for(a[s][o]/=a[o][o],h[s]-=a[s][o]*h[o],n=o+1;n<c;n++)a[s][n]-=a[s][o]*a[o][n];if(Math.abs(a[o][o])<l)throw new Error("JXG.Math.Numerics.Gauss(): The given matrix seems to be singular.")}return this.backwardSolve(a,h,!0),h},backwardSolve:function(t,e,i){var r,s,o,n,a;for(r=i?e:e.slice(0,e.length),s=t.length,o=t.length>0?t[0].length:0,n=s-1;n>=0;n--){for(a=o-1;a>n;a--)r[n]-=t[n][a]*r[a];r[n]/=t[n][n]}return r},gaussBareiss:function(t){var e,r,s,o,n,a,h,l,c,d=i.eps;if((h=t.length)<=0)return 0;for(t[0].length<h&&(h=t[0].length),l=[],o=0;o<h;o++)l[o]=t[o].slice(0,h);for(r=1,s=1,e=0;e<h-1;e++){if(a=l[e][e],Math.abs(a)<d){for(o=e+1;o<h&&!(Math.abs(l[o][e])>=d);o++);if(o===h)return 0;for(n=e;n<h;n++)c=l[o][n],l[o][n]=l[e][n],l[e][n]=c;s=-s,a=l[e][e]}for(o=e+1;o<h;o++)for(n=e+1;n<h;n++)c=a*l[o][n]-l[o][e]*l[e][n],l[o][n]=c/r;r=a}return s*l[h-1][h-1]},det:function(t){return 2===t.length&&2===t[0].length?t[0][0]*t[1][1]-t[1][0]*t[0][1]:this.gaussBareiss(t)},Jacobi:function(t){var e,r,s,o,n,a,h,l,c,d=i.eps*i.eps,u=0,p=t.length,f=[[0,0,0],[0,0,0],[0,0,0]],m=[[0,0,0],[0,0,0],[0,0,0]],g=0;for(e=0;e<p;e++){for(r=0;r<p;r++)f[e][r]=0,m[e][r]=t[e][r],u+=Math.abs(m[e][r]);f[e][e]=1}if(1===p)return[m,f];if(u<=0)return[m,f];u/=p*p;do{for(l=0,c=0,r=1;r<p;r++)for(e=0;e<r;e++)if(o=Math.abs(m[e][r]),o>c&&(c=o),l+=o,o>=d){for(o=.5*Math.atan2(2*m[e][r],m[e][e]-m[r][r]),n=Math.sin(o),a=Math.cos(o),s=0;s<p;s++)h=m[s][e],m[s][e]=a*h+n*m[s][r],m[s][r]=-n*h+a*m[s][r],h=f[s][e],f[s][e]=a*h+n*f[s][r],f[s][r]=-n*h+a*f[s][r];for(m[e][e]=a*m[e][e]+n*m[r][e],m[r][r]=-n*m[e][r]+a*m[r][r],m[e][r]=0,s=0;s<p;s++)m[e][s]=m[s][e],m[r][s]=m[s][r]}g+=1}while(Math.abs(l)/u>d&&g<2e3);return[m,f]},NewtonCotes:function(t,i,r){var s,o,n,a=0,h=r&&e.isNumber(r.number_of_nodes)?r.number_of_nodes:28,l={trapez:!0,simpson:!0,milne:!0},c=r&&r.integration_type&&l.hasOwnProperty(r.integration_type)&&l[r.integration_type]?r.integration_type:"milne",d=(t[1]-t[0])/h;switch(c){case"trapez":for(a=.5*(i(t[0])+i(t[1])),s=t[0],o=0;o<h-1;o++)s+=d,a+=i(s);a*=d;break;case"simpson":if(h%2>0)throw new Error("JSXGraph: INT_SIMPSON requires config.number_of_nodes dividable by 2.");for(n=h/2,a=i(t[0])+i(t[1]),s=t[0],o=0;o<n-1;o++)s+=2*d,a+=2*i(s);for(s=t[0]-d,o=0;o<n;o++)s+=2*d,a+=4*i(s);a*=d/3;break;default:if(h%4>0)throw new Error("JSXGraph: Error in INT_MILNE: config.number_of_nodes must be a multiple of 4");for(n=.25*h,a=7*(i(t[0])+i(t[1])),s=t[0],o=0;o<n-1;o++)s+=4*d,a+=14*i(s);for(s=t[0]-3*d,o=0;o<n;o++)s+=4*d,a+=32*(i(s)+i(s+2*d));for(s=t[0]-2*d,o=0;o<n;o++)s+=4*d,a+=12*i(s);a*=2*d/45}return a},Romberg:function(t,i,r){var s,o,n,a,h,l,c,d,u=[],p=0,f=1/0,m=r&&e.isNumber(r.max_iterations)?r.max_iterations:20,g=r&&e.isNumber(r.eps)?r.eps:r.eps||1e-7;for(s=t[0],o=t[1],n=o-s,h=1,u[0]=.5*n*(i(s)+i(o)),l=0;l<m;++l){for(a=0,n*=.5,h*=2,d=1,c=1;c<h;c+=2)a+=i(s+c*n);for(u[l+1]=.5*u[l]+a*n,p=u[l+1],c=l-1;c>=0;--c)d*=4,u[c]=u[c+1]+(u[c+1]-u[c])/(d-1),p=u[c];if(Math.abs(p-f)<g*Math.abs(p))break;f=p}return p},GaussLegendre:function(t,i,r){var s,o,n,a,h,l,c,d,u=0,p=[],f=[],m=r&&e.isNumber(r.n)?r.n:12;if(m>18&&(m=18),p[2]=[.5773502691896257],f[2]=[1],p[4]=[.33998104358485626,.8611363115940526],f[4]=[.6521451548625461,.34785484513745385],p[6]=[.2386191860831969,.6612093864662645,.932469514203152],f[6]=[.46791393457269104,.3607615730481386,.17132449237917036],p[8]=[.1834346424956498,.525532409916329,.7966664774136267,.9602898564975363],f[8]=[.362683783378362,.31370664587788727,.22238103445337448,.10122853629037626],p[10]=[.14887433898163122,.4333953941292472,.6794095682990244,.8650633666889845,.9739065285171717],f[10]=[.29552422471475287,.26926671930999635,.21908636251598204,.1494513491505806,.06667134430868814],p[12]=[.1252334085114689,.3678314989981802,.5873179542866175,.7699026741943047,.9041172563704749,.9815606342467192],f[12]=[.24914704581340277,.2334925365383548,.20316742672306592,.16007832854334622,.10693932599531843,.04717533638651183],p[14]=[.10805494870734367,.31911236892788974,.5152486363581541,.6872929048116855,.827201315069765,.9284348836635735,.9862838086968123],f[14]=[.2152638534631578,.2051984637212956,.18553839747793782,.15720316715819355,.12151857068790319,.08015808715976021,.03511946033175186],p[16]=[.09501250983763744,.2816035507792589,.45801677765722737,.6178762444026438,.755404408355003,.8656312023878318,.9445750230732326,.9894009349916499],f[16]=[.1894506104550685,.18260341504492358,.16915651939500254,.14959598881657674,.12462897125553388,.09515851168249279,.062253523938647894,.027152459411754096],p[18]=[.0847750130417353,.2518862256915055,.41175116146284263,.5597708310739475,.6916870430603532,.8037049589725231,.8926024664975557,.9558239495713977,.9915651684209309],f[18]=[.1691423829631436,.16427648374583273,.15468467512626524,.14064291467065065,.12255520671147846,.10094204410628717,.07642573025488905,.0497145488949698,.02161601352648331],p[3]=[0,.7745966692414834],f[3]=[.8888888888888888,.5555555555555556],p[5]=[0,.5384693101056831,.906179845938664],f[5]=[.5688888888888889,.47862867049936647,.23692688505618908],p[7]=[0,.4058451513773972,.7415311855993945,.9491079123427585],f[7]=[.4179591836734694,.3818300505051189,.27970539148927664,.1294849661688697],p[9]=[0,.3242534234038089,.6133714327005904,.8360311073266358,.9681602395076261],f[9]=[.3302393550012598,.31234707704000286,.26061069640293544,.1806481606948574,.08127438836157441],p[11]=[0,.26954315595234496,.5190961292068118,.7301520055740494,.8870625997680953,.978228658146057],f[11]=[.2729250867779006,.26280454451024665,.23319376459199048,.18629021092773426,.1255803694649046,.05566856711617366],p[13]=[0,.2304583159551348,.44849275103644687,.6423493394403402,.8015780907333099,.9175983992229779,.9841830547185881],f[13]=[.2325515532308739,.22628318026289723,.2078160475368885,.17814598076194574,.13887351021978725,.09212149983772845,.04048400476531588],p[15]=[0,.20119409399743451,.3941513470775634,.5709721726085388,.7244177313601701,.8482065834104272,.937273392400706,.9879925180204854],f[15]=[.2025782419255613,.19843148532711158,.1861610000155622,.16626920581699392,.13957067792615432,.10715922046717194,.07036604748810812,.03075324199611727],p[17]=[0,.17848418149584785,.3512317634538763,.5126905370864769,.6576711592166907,.7815140038968014,.8802391537269859,.9506755217687678,.9905754753144174],f[17]=[.17944647035620653,.17656270536699264,.16800410215645004,.15404576107681028,.13513636846852548,.11188384719340397,.08503614831717918,.0554595293739872,.02414830286854793],s=t[0],o=t[1],a=m+1>>1,c=p[m],d=f[m],l=.5*(o-s),h=.5*(o+s),!0&m)for(u=d[0]*i(h),n=1;n<a;++n)u+=d[n]*(i(h+l*c[n])+i(h-l*c[n]));else for(u=0,n=0;n<a;++n)u+=d[n]*(i(h+l*c[n])+i(h-l*c[n]));return l*u},_rescale_error:function(t,e,i){var r,s;return t=Math.abs(t),0!==i&&0!==t&&(r=Math.pow(200*t/i,1.5),t=r<1?i*r:i),e>2.0041683600089728e-294&&(s=1.1102230246251565e-14*e)>t&&(t=s),t},_gaussKronrod:function(t,e,i,r,s,o,n){var a,h,l,c,d,u,p,f,m,g=t[0],b=t[1],v=.5*(g+b),y=.5*(b-g),C=Math.abs(y),_=e(v),P=0,E=_*o[i-1],x=Math.abs(E),S=0,w=0,O=0,T=[],N=[];for(i%2==0&&(P=_*s[i/2-1]),a=Math.floor((i-1)/2),l=0;l<a;l++)c=2*l+1,d=y*r[c],u=e(v-d),p=e(v+d),f=u+p,T[c]=u,N[c]=p,P+=s[l]*f,E+=o[c]*f,x+=o[c]*(Math.abs(u)+Math.abs(p));for(a=Math.floor(i/2),l=0;l<a;l++)m=2*l,d=y*r[m],u=e(v-d),p=e(v+d),T[m]=u,N[m]=p,E+=o[m]*(u+p),x+=o[m]*(Math.abs(u)+Math.abs(p));for(w=.5*E,S=o[i-1]*Math.abs(_-w),l=0;l<i-1;l++)S+=o[l]*(Math.abs(T[l]-w)+Math.abs(N[l]-w));return O=(E-P)*y,E*=y,x*=C,S*=C,h=E,n.abserr=this._rescale_error(O,x,S),n.resabs=x,n.resasc=S,h},GaussKronrod15:function(t,e,i){var r=[.9914553711208126,.9491079123427585,.8648644233597691,.7415311855993945,.5860872354676911,.4058451513773972,.20778495500789848,0],s=[.1294849661688697,.27970539148927664,.3818300505051189,.4179591836734694],o=[.022935322010529224,.06309209262997856,.10479001032225019,.14065325971552592,.1690047266392679,.19035057806478542,.20443294007529889,.20948214108472782];return this._gaussKronrod(t,e,8,r,s,o,i)},GaussKronrod21:function(t,e,i){var r=[.9956571630258081,.9739065285171717,.9301574913557082,.8650633666889845,.7808177265864169,.6794095682990244,.5627571346686047,.4333953941292472,.2943928627014602,.14887433898163122,0],s=[.06667134430868814,.1494513491505806,.21908636251598204,.26926671930999635,.29552422471475287],o=[.011694638867371874,.032558162307964725,.054755896574351995,.07503967481091996,.0931254545836976,.10938715880229764,.12349197626206584,.13470921731147334,.14277593857706009,.14773910490133849,.1494455540029169];return this._gaussKronrod(t,e,11,r,s,o,i)},GaussKronrod31:function(t,e,i){var r=[.9980022986933971,.9879925180204854,.9677390756791391,.937273392400706,.8972645323440819,.8482065834104272,.790418501442466,.7244177313601701,.650996741297417,.5709721726085388,.4850818636402397,.3941513470775634,.29918000715316884,.20119409399743451,.1011420669187175,0],s=[.03075324199611727,.07036604748810812,.10715922046717194,.13957067792615432,.16626920581699392,.1861610000155622,.19843148532711158,.2025782419255613],o=[.005377479872923349,.015007947329316122,.02546084732671532,.03534636079137585,.04458975132476488,.05348152469092809,.06200956780067064,.06985412131872826,.07684968075772038,.08308050282313302,.08856444305621176,.09312659817082532,.09664272698362368,.09917359872179196,.10076984552387559,.10133000701479154];return this._gaussKronrod(t,e,16,r,s,o,i)},_workspace:function(t,e){return{limit:e,size:0,nrmax:0,i:0,alist:[t[0]],blist:[t[1]],rlist:[0],elist:[0],order:[0],level:[0],qpsrt:function(){var t,e,i,r,s,o=this.size-1,n=this.limit,a=this.nrmax,h=this.order[a];if(o<2)return this.order[0]=0,this.order[1]=1,void(this.i=h);for(t=this.elist[h];a>0&&t>this.elist[this.order[a-1]];)this.order[a]=this.order[a-1],a--;for(s=o<n/2+2?o:n-o+1,i=a+1;i<s&&t<this.elist[this.order[i]];)this.order[i-1]=this.order[i],i++;for(this.order[i-1]=h,e=this.elist[o], -r=s-1;r>i-2&&e>=this.elist[this.order[r]];)this.order[r+1]=this.order[r],r--;this.order[r+1]=o,h=this.order[a],this.i=h,this.nrmax=a},set_initial_result:function(t,e){this.size=1,this.rlist[0]=t,this.elist[0]=e},update:function(t,e,i,r,s,o,n,a){var h=this.i,l=this.size,c=this.level[this.i]+1;a>r?(this.alist[h]=s,this.rlist[h]=n,this.elist[h]=a,this.level[h]=c,this.alist[l]=t,this.blist[l]=e,this.rlist[l]=i,this.elist[l]=r,this.level[l]=c):(this.blist[h]=e,this.rlist[h]=i,this.elist[h]=r,this.level[h]=c,this.alist[l]=s,this.blist[l]=o,this.rlist[l]=n,this.elist[l]=a,this.level[l]=c),this.size++,c>this.maximum_level&&(this.maximum_level=c),this.qpsrt()},retrieve:function(){var t=this.i;return{a:this.alist[t],b:this.blist[t],r:this.rlist[t],e:this.elist[t]}},sum_results:function(){var t,e=this.size,i=0;for(t=0;t<e;t++)i+=this.rlist[t];return i},subinterval_too_small:function(t,e,i){var r=1.0000000000000222*(Math.abs(e)+2.2250738585072014e-305);return Math.abs(t)<=r&&Math.abs(i)<=r}}},Qag:function(r,s,o){var n,a,h,l,c,d,u,p,f,m,g,b,v,y,C,_,P,E,x,S,w=this._workspace(r,1e3),O=o&&e.isNumber(o.limit)?o.limit:15,T=o&&e.isNumber(o.epsrel)?o.epsrel:1e-7,N=o&&e.isNumber(o.epsabs)?o.epsabs:1e-7,M=o&&e.isFunction(o.q)?o.q:this.GaussKronrod15,A={},R=0,L=0,k=0,B=0,I=0,Y=0,D=0,j=0,X=0,G=0;if(O>w.limit&&t.warn("iteration limit exceeds available workspace"),N<=0&&(T<50*i.eps||T<5e-29)&&t.warn("tolerance cannot be acheived with given epsabs and epsrel"),h=M.apply(this,[r,s,A]),l=A.abserr,c=A.resabs,d=A.resasc,w.set_initial_result(h,l),u=Math.max(N,T*Math.abs(h)),p=1.1102230246251565e-14*c,l<=p&&l>u)return h,t.warn("cannot reach tolerance because of roundoff error on first attempt"),-1/0;if(l<=u&&l!==d||0===l)return h;if(1===O)return h,t.warn("a maximum of one iteration was insufficient"),-1/0;n=h,a=l,R=1;do{I=0,Y=0,D=0,j=0,X=0,G=0,x=w.retrieve(),v=x.a,y=x.b,C=x.r,_=x.e,f=v,m=.5*(v+y),g=m,b=y,I=M.apply(this,[[f,m],s,A]),j=A.abserr,P=A.resasc,Y=M.apply(this,[[g,b],s,A]),X=A.abserr,E=A.resasc,D=I+Y,G=j+X,a+=G-_,n+=D-C,P!==j&&E!==X&&(S=C-D,Math.abs(S)<=1e-5*Math.abs(D)&&G>=.99*_&&L++,R>=10&&G>_&&k++),u=Math.max(N,T*Math.abs(n)),a>u&&((L>=6||k>=20)&&(B=2),w.subinterval_too_small(f,g,b)&&(B=3)),w.update(f,m,I,j,g,b,Y,X),x=w.retrieve(),v=x.a_i,y=x.b_i,C=x.r_i,_=x.e_i,R++}while(R<O&&!B&&a>u);return w.sum_results()},I:function(t,e){return this.Qag(t,e,{q:this.GaussKronrod15,limit:15,epsrel:1e-7,epsabs:1e-7})},Newton:function(t,r,s){var o,n=0,a=i.eps,h=t.apply(s,[r]);for(e.isArray(r)&&(r=r[0]);n<50&&Math.abs(h)>a;)o=this.D(t,s)(r),Math.abs(o)>a?r-=h/o:r+=.2*Math.random()-1,h=t.apply(s,[r]),n+=1;return r},root:function(t,e,i){return this.chandrupatla(t,e,i)},generalizedNewton:function(t,e,r,s){var o,n,a,h,l,c,d,u,p,f,m,g,b,v,y=0;for(this.generalizedNewton.t1memo?(o=this.generalizedNewton.t1memo,n=this.generalizedNewton.t2memo):(o=r,n=s),u=t.X(o)-e.X(n),p=t.Y(o)-e.Y(n),f=u*u+p*p,m=this.D(t.X,t),g=this.D(e.X,e),b=this.D(t.Y,t),v=this.D(e.Y,e);f>i.eps&&y<10;)a=m(o),h=-g(n),l=b(o),c=-v(n),d=a*c-h*l,o-=(c*u-h*p)/d,n-=(a*p-l*u)/d,u=t.X(o)-e.X(n),p=t.Y(o)-e.Y(n),f=u*u+p*p,y+=1;return this.generalizedNewton.t1memo=o,this.generalizedNewton.t2memo=n,Math.abs(o)<Math.abs(n)?[t.X(o),t.Y(o)]:[e.X(n),e.Y(n)]},Neville:function(t){var e=[],r=function(r){return function(s,o){var n,a,h,l=i.binomial,c=t.length,d=c-1,u=0,p=0;if(!o)for(h=1,n=0;n<c;n++)e[n]=l(d,n)*h,h*=-1;for(a=s,n=0;n<c;n++){if(0===a)return t[n][r]();h=e[n]/a,a-=1,u+=t[n][r]()*h,p+=h}return u/p}};return[r("X"),r("Y"),0,function(){return t.length-1}]},splineDef:function(t,e){var i,r,s,o=Math.min(t.length,e.length),n=[],a=[],h=[],l=[],c=[],d=[];if(2===o)return[0,0];for(r=0;r<o;r++)i={X:t[r],Y:e[r]},h.push(i);for(h.sort(function(t,e){return t.X-e.X}),r=0;r<o;r++)t[r]=h[r].X,e[r]=h[r].Y;for(r=0;r<o-1;r++)l.push(t[r+1]-t[r]);for(r=0;r<o-2;r++)c.push(6*(e[r+2]-e[r+1])/l[r+1]-6*(e[r+1]-e[r])/l[r]);for(n.push(2*(l[0]+l[1])),a.push(c[0]),r=0;r<o-3;r++)s=l[r+1]/n[r],n.push(2*(l[r+1]+l[r+2])-s*l[r+1]),a.push(c[r+1]-s*a[r]);for(d[o-3]=a[o-3]/n[o-3],r=o-4;r>=0;r--)d[r]=(a[r]-l[r+1]*d[r+1])/n[r];for(r=o-3;r>=0;r--)d[r+1]=d[r];return d[0]=0,d[o-1]=0,d},splineEval:function(t,i,r,s){var o,n,a,h,l,c,d,u=Math.min(i.length,r.length),p=1,f=!1,m=[];for(e.isArray(t)?(p=t.length,f=!0):t=[t],o=0;o<p;o++){if(t[o]<i[0]||i[o]>i[u-1])return NaN;for(n=1;n<u&&!(t[o]<=i[n]);n++);n-=1,a=r[n],h=(r[n+1]-r[n])/(i[n+1]-i[n])-(i[n+1]-i[n])/6*(s[n+1]+2*s[n]),l=s[n]/2,c=(s[n+1]-s[n])/(6*(i[n+1]-i[n])),d=t[o]-i[n],m.push(a+(h+(l+c*d)*d)*d)}return f?m:m[0]},generatePolynomialTerm:function(t,e,i,r){var s,o=[];for(s=e;s>=0;s--)o=o.concat(["(",t[s].toPrecision(r),")"]),s>1?o=o.concat(["*",i,"<sup>",s,"<","/sup> + "]):1===s&&(o=o.concat(["*",i," + "]));return o.join("")},lagrangePolynomial:function(t){var e=[],i=function(i,r){var s,o,n,a,h=t.length,l=0,c=0;if(!r)for(s=0;s<h;s++){for(e[s]=1,n=t[s].X(),o=0;o<h;o++)o!==s&&(e[s]*=n-t[o].X());e[s]=1/e[s]}for(s=0;s<h;s++){if(n=t[s].X(),i===n)return t[s].Y();a=e[s]/(i-n),c+=a,l+=a*t[s].Y()}return l/c};return i.getTerm=function(){return""},i},_initCubicPoly:function(t,e,i,r){return[t,i,-3*t+3*e-2*i-r,2*t-2*e+i+r]},CardinalSpline:function(t,r,s){var o,n,a,h,l=[],c=this;return h=e.isFunction(r)?r:function(){return r},void 0===s&&(s="uniform"),n=function(e){return function(r,n){var d,u,p,f,m,g,b,v,y,C;if(t.length<2)return NaN;if(!n)for(a=h(),p={X:function(){return 2*t[0].X()-t[1].X()},Y:function(){return 2*t[0].Y()-t[1].Y()},Dist:function(t){var e=this.X()-t.X(),i=this.Y()-t.Y();return Math.sqrt(e*e+i*i)}},f={X:function(){return 2*t[t.length-1].X()-t[t.length-2].X()},Y:function(){return 2*t[t.length-1].Y()-t[t.length-2].Y()},Dist:function(t){var e=this.X()-t.X(),i=this.Y()-t.Y();return Math.sqrt(e*e+i*i)}},o=[p].concat(t,[f]),C=o.length,l[e]=[],d=0;d<C-3;d++)"centripetal"===s?(b=o[d].Dist(o[d+1]),v=o[d+2].Dist(o[d+1]),y=o[d+3].Dist(o[d+2]),b=Math.sqrt(b),v=Math.sqrt(v),y=Math.sqrt(y),v<i.eps&&(v=1),b<i.eps&&(b=v),y<i.eps&&(y=v),m=(o[d+1][e]()-o[d][e]())/b-(o[d+2][e]()-o[d][e]())/(v+b)+(o[d+2][e]()-o[d+1][e]())/v,g=(o[d+2][e]()-o[d+1][e]())/v-(o[d+3][e]()-o[d+1][e]())/(y+v)+(o[d+3][e]()-o[d+2][e]())/y,m*=v,g*=v,l[e][d]=c._initCubicPoly(o[d+1][e](),o[d+2][e](),a*m,a*g)):l[e][d]=c._initCubicPoly(o[d+1][e](),o[d+2][e](),a*(o[d+2][e]()-o[d][e]()),a*(o[d+3][e]()-o[d+1][e]()));return isNaN(r)?NaN:(C=t.length,r<=0?t[0][e]():r>=C?t[C-1][e]():(d=Math.floor(r))===r?t[d][e]():(r-=d,u=l[e][d],void 0===u?NaN:((u[3]*r+u[2])*r+u[1])*r+u[0]))}},[n("X"),n("Y"),0,function(){return t.length-1}]},CatmullRomSpline:function(t,e){return this.CardinalSpline(t,.5,e)},regressionPolynomial:function(t,r,s){var o,n,a,h,l,c,d="";if(e.isPoint(t)&&e.isFunction(t.Value))n=function(){return t.Value()};else if(e.isFunction(t))n=t;else{if(!e.isNumber(t))throw new Error("JSXGraph: Can't create regressionPolynomial from degree of type'"+typeof t+"'.");n=function(){return t}}if(3===arguments.length&&e.isArray(r)&&e.isArray(s))l=0;else if(2===arguments.length&&e.isArray(r)&&r.length>0&&e.isPoint(r[0]))l=1;else{if(!(2===arguments.length&&e.isArray(r)&&r.length>0&&r[0].usrCoords&&r[0].scrCoords))throw new Error("JSXGraph: Can't create regressionPolynomial. Wrong parameters.");l=2}return c=function(t,c){var u,p,f,m,g,b,v,y,C,_=r.length;if(C=Math.floor(n()),!c){if(1===l)for(a=[],h=[],u=0;u<_;u++)a[u]=r[u].X(),h[u]=r[u].Y();if(2===l)for(a=[],h=[],u=0;u<_;u++)a[u]=r[u].usrCoords[1],h[u]=r[u].usrCoords[2];if(0===l)for(a=[],h=[],u=0;u<_;u++)e.isFunction(r[u])?a.push(r[u]()):a.push(r[u]),e.isFunction(s[u])?h.push(s[u]()):h.push(s[u]);for(f=[],p=0;p<_;p++)f.push([1]);for(u=1;u<=C;u++)for(p=0;p<_;p++)f[p][u]=f[p][u-1]*a[p];g=h,m=i.transpose(f),b=i.matMatMult(m,f),v=i.matVecMult(m,g),o=i.Numerics.Gauss(b,v),d=i.Numerics.generatePolynomialTerm(o,C,"x",3)}for(y=o[C],u=C-1;u>=0;u--)y=y*t+o[u];return y},c.getTerm=function(){return d},c},bezier:function(t){var e,i,r=function(r){return function(s,o){var n=3*Math.floor(s),a=s%1,h=1-a;return o||(i=3*Math.floor((t.length-1)/3),e=Math.floor(i/3)),s<0?t[0][r]():s>=e?t[i][r]():isNaN(s)?NaN:h*h*(h*t[n][r]()+3*a*t[n+1][r]())+(3*h*t[n+2][r]()+a*t[n+3][r]())*a*a}};return[r("X"),r("Y"),0,function(){return Math.floor(t.length/3)}]},bspline:function(t,e){var i,r=function(t,e){var i,r=[];for(i=0;i<t+e+1;i++)r[i]=i<e?0:i<=t?i-e+1:t-e+2;return r},s=function(t,e,i,r){var s,o,n,a,h,l=[];for(e[r]<=t&&t<e[r+1]?l[r]=1:l[r]=0,s=2;s<=i;s++)for(o=r-s+1;o<=r;o++)n=o<=r-s+1||o<0?0:l[o],a=o>=r?0:l[o+1],h=e[o+s-1]-e[o],l[o]=0===h?0:(t-e[o])/h*n,0!==(h=e[o+s]-e[o+1])&&(l[o]+=(e[o+s]-t)/h*a);return l},o=function(o){return function(n,a){var h,l,c,d=[],u=t.length,p=u-1,f=e;if(p<=0)return NaN;if(p+2<=f&&(f=p+1),n<=0)return t[0][o]();if(n>=p-f+2)return t[p][o]();for(c=Math.floor(n)+f-1,i=r(p,f),d=s(n,i,f,c),h=0,l=c-f+1;l<=c;l++)l<u&&l>=0&&(h+=t[l][o]()*d[l]);return h}};return[o("X"),o("Y"),0,function(){return t.length-1}]},D:function(t,i){return e.exists(i)?function(e,r){var s=1e-5;return(t.apply(i,[e+s,r])-t.apply(i,[e-s,r]))/2e-5}:function(e,i){var r=1e-5;return(t(e+r,i)-t(e-r,i))/2e-5}},_riemannValue:function(t,e,i,r){var s,o,n,a;if(r<0&&("trapezoidal"!==i&&(t+=r),r*=-1,"lower"===i?i="upper":"upper"===i&&(i="lower")),a=.01*r,"right"===i)s=e(t+r);else if("middle"===i)s=e(t+.5*r);else if("left"===i||"trapezoidal"===i)s=e(t);else if("lower"===i){for(s=e(t),n=t+a;n<=t+r;n+=a)(o=e(n))<s&&(s=o);o=e(t+r),o<s&&(s=o)}else if("upper"===i){for(s=e(t),n=t+a;n<=t+r;n+=a)(o=e(n))>s&&(s=o);o=e(t+r),o>s&&(s=o)}else s="random"===i?e(t+r*Math.random()):"simpson"===i?(e(t)+4*e(t+.5*r)+e(t+r))/6:e(t);return s},riemann:function(t,i,r,s,o){var n,a,h,l,c,d,u,p=[],f=[],m=0,g=s,b=0;if(e.isArray(t)?(c=t[0],l=t[1]):l=t,(i=Math.floor(i))<=0)return[p,f,b];for(a=(o-s)/i,n=0;n<i;n++)h=this._riemannValue(g,l,r,a),p[m]=g,f[m]=h,m+=1,g+=a,"trapezoidal"===r&&(h=l(g)),p[m]=g,f[m]=h,m+=1;for(n=0;n<i;n++)h=c?this._riemannValue(g,c,r,-a):0,p[m]=g,f[m]=h,m+=1,g-=a,"trapezoidal"===r&&c&&(h=c(g)),p[m]=g,f[m]=h,"trapezoidal"!==r?(d=h,u=f[2*(i-1)-2*n]):(u=.5*(l(g+a)+l(g)),d=c?.5*(c(g+a)+c(g)):0),b+=(u-d)*a,m+=1,p[m]=g,f[m]=f[2*(i-1)-2*n],m+=1;return[p,f,b]},riemannsum:function(e,i,r,s,o){return t.deprecated("Numerics.riemannsum()","Numerics.riemann()"),this.riemann(e,i,r,s,o)[2]},rungeKutta:function(t,i,s,o,n){var a,h,l,c,d,u,p=[],f=[],m=(s[1]-s[0])/o,g=s[0],b=i.length,v=[],y=0;for(e.isString(t)&&(t=r[t]||r.euler),u=t.s,a=0;a<b;a++)p[a]=i[a];for(h=0;h<o;h++){for(v[y]=[],a=0;a<b;a++)v[y][a]=p[a];for(y+=1,c=[],l=0;l<u;l++){for(a=0;a<b;a++)f[a]=0;for(d=0;d<l;d++)for(a=0;a<b;a++)f[a]+=t.A[l][d]*m*c[d][a];for(a=0;a<b;a++)f[a]+=p[a];c.push(n(g+t.c[l]*m,f))}for(a=0;a<b;a++)f[a]=0;for(d=0;d<u;d++)for(a=0;a<b;a++)f[a]+=t.b[d]*c[d][a];for(a=0;a<b;a++)p[a]=p[a]+m*f[a];g+=m}return v},maxIterationsRoot:80,maxIterationsMinimize:500,findBracket:function(t,i,r){var s,o,n,a,h,l,c,d,u,p;if(e.isArray(i))return i;for(s=i,n=t.call(r,s),o=0===s?1:s,a=[s-.1*o,s+.1*o,s-1,s+1,s-.5*o,s+.5*o,s-.6*o,s+.6*o,s-1*o,s+1*o,s-2*o,s+2*o,s-5*o,s+5*o,s-10*o,s+10*o,s-50*o,s+50*o,s-100*o,s+100*o],p=a.length,u=0;u<p&&(h=a[u],l=t.call(r,h),!(n*l<=0));u++);return h<s&&(c=s,s=h,h=c,d=n,n=l,l=d),[s,n,h,l]},fzero:function(t,r,s){var o,n,a,h,l,c,d,u,p,f,m,g,b,v,y,C=i.eps,_=this.maxIterationsRoot,P=0;if(e.isArray(r)){if(r.length<2)throw new Error("JXG.Math.Numerics.fzero: length of array x0 has to be at least two.");o=r[0],h=t.call(s,o),n=r[1],l=t.call(s,n)}else d=this.findBracket(t,r,s),o=d[0],h=d[1],n=d[2],l=d[3];if(Math.abs(h)<=C)return o;if(Math.abs(l)<=C)return n;if(h*l>0)return e.isArray(r)?this.fminbr(t,[o,n],s):this.Newton(t,o,s);for(a=o,c=h;P<_;){if(u=n-o,Math.abs(c)<Math.abs(l)&&(o=n,n=a,a=o,h=l,l=c,c=h),g=2*C*Math.abs(n)+.5*C,y=.5*(a-n),Math.abs(y)<=g||Math.abs(l)<=C)return n;Math.abs(u)>=g&&Math.abs(h)>Math.abs(l)&&(f=a-n,o===a?(p=l/h,b=f*p,v=1-p):(v=h/c,p=l/c,m=l/h,b=m*(f*v*(v-p)-(n-o)*(p-1)),v=(v-1)*(p-1)*(m-1)),b>0?v=-v:b=-b,b<.75*f*v-.5*Math.abs(g*v)&&b<Math.abs(u*v*.5)&&(y=b/v)),Math.abs(y)<g&&(y=y>0?g:-g),o=n,h=l,n+=y,l=t.call(s,n),(l>0&&c>0||l<0&&c<0)&&(a=o,c=h),P++}return n},chandrupatla:function(t,r,s){var o,n,a,h,l,c,d,u,p,f,m,g,b,v,y,C,_,P,E,x,S,w,O,T,N,M,A=0,R=this.maxIterationsRoot,L=1+.001*Math.random(),k=.5*L,B=i.eps;if(e.isArray(r)){if(r.length<2)throw new Error("JXG.Math.Numerics.fzero: length of array x0 has to be at least two.");o=r[0],n=t.call(s,o),a=r[1],h=t.call(s,a)}else l=this.findBracket(t,r,s),o=l[0],n=l[1],a=l[2],h=l[3];if(n*h>0)return e.isArray(r)?this.fminbr(t,[o,a],s):this.Newton(t,o,s);c=o,d=a,f=n,m=h;do{if(p=c+k*(d-c),b=t.call(s,p),Math.sign(b)===Math.sign(f)?(u=c,c=p,g=f,f=b):(u=d,d=c,g=m,m=f),c=p,f=b,v=c,y=f,Math.abs(m)<Math.abs(f)&&(v=d,y=m),C=2*B*Math.abs(v)+5e-6,(_=C/Math.abs(d-c))>.5||0===y)break;P=(c-d)/(u-d),E=(f-m)/(g-m),x=1-Math.sqrt(1-P),S=Math.sqrt(P),x<E&&E<S?(w=(u-c)/(d-c),O=f/(m-f),T=g/(m-g),N=f/(g-f),M=m/(g-m),k=O*T+N*M*w):k=.5*L,k<_&&(k=_),k>1-_&&(k=1-_),A++}while(A<=R);return v},fminbr:function(t,r,s){var o,n,a,h,l,c,d,u,p,f,m,g,b,v,y,C,_=.5*(3-Math.sqrt(5)),P=i.eps,E=i.eps,x=this.maxIterationsMinimize,S=0;if(!e.isArray(r)||r.length<2)throw new Error("JXG.Math.Numerics.fminbr: length of array x0 has to be at least two.");for(o=r[0],n=r[1],h=o+_*(n-o),d=t.call(s,h),a=h,l=h,c=d,u=d;S<x;){if(p=n-o,f=.5*(o+n),m=E*Math.abs(a)+P/3,Math.abs(a-f)+.5*p<=2*m)return a;g=_*(a<f?n-a:o-a),Math.abs(a-l)>=m&&(y=(a-l)*(c-d),v=(a-h)*(c-u),b=(a-h)*v-(a-l)*y,v=2*(v-y),v>0?b=-b:v=-v,Math.abs(b)<Math.abs(g*v)&&b>v*(o-a+2*m)&&b<v*(n-a-2*m)&&(g=b/v)),Math.abs(g)<m&&(g=g>0?m:-m),y=a+g,C=t.call(s,y),C<=c?(y<a?n=a:o=a,h=l,l=a,a=y,d=u,u=c,c=C):(y<a?o=y:n=y,C<=u||l===a?(h=l,l=y,d=u,u=C):(C<=d||h===a||h===l)&&(h=y,d=C)),S+=1}return a},RamerDouglasPeucker:function(t,e){var r,s,o,n=[],a=[],h=function(t,e,r){var s,o,n,a,h,l,c,d,u,p,f,m=0,g=e;if(r-e<2)return[-1,0];if(n=t[e].scrCoords,a=t[r].scrCoords,isNaN(n[1])||isNaN(n[2]))return[NaN,e];if(isNaN(a[1])||isNaN(a[2]))return[NaN,r];for(o=e+1;o<r;o++){if(h=t[o].scrCoords,isNaN(h[1])||isNaN(h[2]))return[NaN,o];l=h[1]-n[1],c=h[2]-n[2],d=a[1]-n[1],u=a[2]-n[2],l=l===1/0?1e4:l,c=c===1/0?1e4:c,d=d===1/0?1e4:d,u=u===1/0?1e4:u,l=l===-1/0?-1e4:l,c=c===-1/0?-1e4:c,d=d===-1/0?-1e4:d,u=u===-1/0?-1e4:u,p=d*d+u*u,p>=i.eps?(f=(l*d+c*u)/p,f<0?f=0:f>1&&(f=1),l-=f*d,c-=f*u,s=l*l+c*c):(f=0,s=l*l+c*c),s>m&&(m=s,g=o)}return[Math.sqrt(m),g]},l=function(t,e,i,r,s){var o=h(t,e,i),n=o[1];if(isNaN(o[0])){l(t,e,n-1,r,s),s.push(t[n]);do{++n}while(n<=i&&isNaN(t[n].scrCoords[1]+t[n].scrCoords[2]));n<=i&&s.push(t[n]),l(t,n+1,i,r,s)}else o[0]>r?(l(t,e,n,r,s),l(t,n,i,r,s)):s.push(t[i])};for(o=t.length,r=0;;){for(;r<o&&isNaN(t[r].scrCoords[1]+t[r].scrCoords[2]);)r+=1;for(s=r+1;s<o&&!isNaN(t[s].scrCoords[1]+t[s].scrCoords[2]);)s+=1;if(s--,r<o&&s>r&&(a=[],a[0]=t[r],l(t,r,s,e,a),n=n.concat(a)),r>=o)break;s<o-1&&n.push(t[s+1]),r=s+1}return n},RamerDouglasPeuker:function(e,i){return t.deprecated("Numerics.RamerDouglasPeuker()","Numerics.RamerDouglasPeucker()"),this.RamerDouglasPeucker(e,i)},Visvalingam:function(e,i){var r,s,o,n,a,h,l,c,d,u=[],p=[],f=[];if((s=e.length)<=2)return e;for(u[0]={used:!0,lft:null,node:null},a=0,r=1;r<s-1;r++)o=Math.abs(t.Math.Numerics.det([e[r-1].usrCoords,e[r].usrCoords,e[r+1].usrCoords])),isNaN(o)||(d={v:o,idx:r},p.push(d),u[r]={used:!0,lft:a,node:d},u[a].rt=r,a=r);for(u[s-1]={used:!0,rt:null,lft:a,node:null},u[a].rt=s-1,n=-1/0;p.length>i;)p.sort(function(t,e){return e.v-t.v}),r=p.pop().idx,u[r].used=!1,n=u[r].node.v,a=u[r].lft,h=u[r].rt,u[a].rt=h,u[h].lft=a,l=u[a].lft,null!==l&&(o=Math.abs(t.Math.Numerics.det([e[l].usrCoords,e[a].usrCoords,e[h].usrCoords])),u[a].node.v=o>=n?o:n),null!==(c=u[h].rt)&&(o=Math.abs(t.Math.Numerics.det([e[a].usrCoords,e[h].usrCoords,e[c].usrCoords])),u[h].node.v=o>=n?o:n);r=0,f=[e[r]];do{r=u[r].rt,f.push(e[r])}while(null!==u[r].rt);return f}},i.Numerics}),define("math/statistics",["jxg","math/math","utils/type"],function(t,e,i){"use strict";return e.Statistics={sum:function(t){var e,i=t.length,r=0;for(e=0;e<i;e++)r+=t[e];return r},prod:function(t){var e,i=t.length,r=1;for(e=0;e<i;e++)r*=t[e];return r},mean:function(t){return t.length>0?this.sum(t)/t.length:0},median:function(t){var e,i;return t.length>0?(ArrayBuffer.isView(t)?(e=new Float64Array(t),e.sort()):(e=t.slice(0),e.sort(function(t,e){return t-e})),i=e.length,1&i?e[parseInt(.5*i,10)]:.5*(e[.5*i-1]+e[.5*i])):0},variance:function(t){var e,i,r,s=t.length;if(s>1){for(e=this.mean(t),i=0,r=0;r<s;r++)i+=(t[r]-e)*(t[r]-e);return i/(t.length-1)}return 0},sd:function(t){return Math.sqrt(this.variance(t))},weightedMean:function(t,e){if(t.length!==e.length)throw new Error("JSXGraph error (Math.Statistics.weightedMean): Array dimension mismatch.");return t.length>0?this.mean(this.multiply(t,e)):0},max:function(t){return Math.max.apply(this,t)},min:function(t){return Math.min.apply(this,t)},range:function(t){return[this.min(t),this.max(t)]},abs:function(t){var e,r,s;if(i.isArray(t))if(t.map)s=t.map(Math.abs);else for(r=t.length,s=[],e=0;e<r;e++)s[e]=Math.abs(t[e]);else s=ArrayBuffer.isView(t)?t.map(Math.abs):Math.abs(t);return s},add:function(t,e){var r,s,o=[];if(t=i.evalSlider(t),e=i.evalSlider(e),i.isArray(t)&&i.isNumber(e))for(s=t.length,r=0;r<s;r++)o[r]=t[r]+e;else if(i.isNumber(t)&&i.isArray(e))for(s=e.length,r=0;r<s;r++)o[r]=t+e[r];else if(i.isArray(t)&&i.isArray(e))for(s=Math.min(t.length,e.length),r=0;r<s;r++)o[r]=t[r]+e[r];else o=t+e;return o},div:function(t,e){var r,s,o=[];if(t=i.evalSlider(t),e=i.evalSlider(e),i.isArray(t)&&i.isNumber(e))for(s=t.length,r=0;r<s;r++)o[r]=t[r]/e;else if(i.isNumber(t)&&i.isArray(e))for(s=e.length,r=0;r<s;r++)o[r]=t/e[r];else if(i.isArray(t)&&i.isArray(e))for(s=Math.min(t.length,e.length),r=0;r<s;r++)o[r]=t[r]/e[r];else o=t/e;return o},divide:function(){t.deprecated("Statistics.divide()","Statistics.div()"),e.Statistics.div.apply(e.Statistics,arguments)},mod:function(t,r,s){var o,n,a=[],h=function(t,e){return t%e};if(s=i.def(s,!1),s&&(h=e.mod),t=i.evalSlider(t),r=i.evalSlider(r),i.isArray(t)&&i.isNumber(r))for(n=t.length,o=0;o<n;o++)a[o]=h(t[o],r);else if(i.isNumber(t)&&i.isArray(r))for(n=r.length,o=0;o<n;o++)a[o]=h(t,r[o]);else if(i.isArray(t)&&i.isArray(r))for(n=Math.min(t.length,r.length),o=0;o<n;o++)a[o]=h(t[o],r[o]);else a=h(t,r);return a},multiply:function(t,e){var r,s,o=[];if(t=i.evalSlider(t),e=i.evalSlider(e),i.isArray(t)&&i.isNumber(e))for(s=t.length,r=0;r<s;r++)o[r]=t[r]*e;else if(i.isNumber(t)&&i.isArray(e))for(s=e.length,r=0;r<s;r++)o[r]=t*e[r];else if(i.isArray(t)&&i.isArray(e))for(s=Math.min(t.length,e.length),r=0;r<s;r++)o[r]=t[r]*e[r];else o=t*e;return o},subtract:function(t,e){var r,s,o=[];if(t=i.evalSlider(t),e=i.evalSlider(e),i.isArray(t)&&i.isNumber(e))for(s=t.length,r=0;r<s;r++)o[r]=t[r]-e;else if(i.isNumber(t)&&i.isArray(e))for(s=e.length,r=0;r<s;r++)o[r]=t-e[r];else if(i.isArray(t)&&i.isArray(e))for(s=Math.min(t.length,e.length),r=0;r<s;r++)o[r]=t[r]-e[r];else o=t-e;return o},TheilSenRegression:function(t){var i,r,s=[],o=[],n=[];for(i=0;i<t.length;i++){for(o.length=0,r=0;r<t.length;r++)Math.abs(t[r].usrCoords[1]-t[i].usrCoords[1])>e.eps&&(o[r]=(t[r].usrCoords[2]-t[i].usrCoords[2])/(t[r].usrCoords[1]-t[i].usrCoords[1]));s[i]=this.median(o),n.push(t[i].usrCoords[2]-s[i]*t[i].usrCoords[1])}return[this.median(n),this.median(s),-1]},generateGaussian:function(t,e){var i,r,s;if(this.hasSpare)return this.hasSpare=!1,this.spare*e+t;do{i=2*Math.random()-1,r=2*Math.random()-1,s=i*i+r*r}while(s>=1||0===s);return s=Math.sqrt(-2*Math.log(s)/s),this.spare=r*s,this.hasSpare=!0,t+e*i*s}},e.Statistics}),define("math/geometry",["jxg","base/constants","base/coords","math/math","math/numerics","utils/type","utils/expect"],function(t,e,i,r,s,o,n){"use strict";return r.Geometry={},t.extend(r.Geometry,{angle:function(e,i,r){var s,o,n,a,h=[],l=[],c=[];return t.deprecated("Geometry.angle()","Geometry.rad()"),e.coords?(h[0]=e.coords.usrCoords[1],h[1]=e.coords.usrCoords[2]):(h[0]=e[0],h[1]=e[1]),i.coords?(l[0]=i.coords.usrCoords[1],l[1]=i.coords.usrCoords[2]):(l[0]=i[0],l[1]=i[1]),r.coords?(c[0]=r.coords.usrCoords[1],c[1]=r.coords.usrCoords[2]):(c[0]=r[0],c[1]=r[1]),s=h[0]-l[0],o=h[1]-l[1],n=c[0]-l[0],a=c[1]-l[1],Math.atan2(s*a-o*n,s*n+o*a)},trueAngle:function(t,e,i){return 57.29577951308232*this.rad(t,e,i)},rad:function(t,e,i){var r,s,o,n,a,h,l;return t.coords?(r=t.coords.usrCoords[1],s=t.coords.usrCoords[2]):(r=t[0],s=t[1]),e.coords?(o=e.coords.usrCoords[1],n=e.coords.usrCoords[2]):(o=e[0],n=e[1]),i.coords?(a=i.coords.usrCoords[1],h=i.coords.usrCoords[2]):(a=i[0],h=i[1]),l=Math.atan2(h-n,a-o)-Math.atan2(s-n,r-o),l<0&&(l+=6.283185307179586),l},angleBisector:function(t,r,s,n){var a,h,l,c,d,u=t.coords.usrCoords,p=r.coords.usrCoords,f=s.coords.usrCoords;return o.exists(n)||(n=t.board),0===p[0]?new i(e.COORDS_BY_USER,[1,.5*(u[1]+f[1]),.5*(u[2]+f[2])],n):(c=u[1]-p[1],d=u[2]-p[2],a=Math.atan2(d,c),c=f[1]-p[1],d=f[2]-p[2],h=Math.atan2(d,c),l=.5*(a+h),a>h&&(l+=Math.PI),c=Math.cos(l)+p[1],d=Math.sin(l)+p[2],new i(e.COORDS_BY_USER,[1,c,d],n))},reflection:function(t,r,s){var n,a,h,l,c,d,u,p=r.coords.usrCoords,f=t.point1.coords.usrCoords,m=t.point2.coords.usrCoords;return o.exists(s)||(s=r.board),c=m[1]-f[1],d=m[2]-f[2],n=p[1]-f[1],a=p[2]-f[2],u=(c*a-d*n)/(c*c+d*d),h=p[1]+2*u*d,l=p[2]-2*u*c,new i(e.COORDS_BY_USER,[h,l],s)},rotation:function(t,r,s,n){var a,h,l,c,d,u,p=r.coords.usrCoords,f=t.coords.usrCoords;return o.exists(n)||(n=r.board),a=p[1]-f[1],h=p[2]-f[2],l=Math.cos(s),c=Math.sin(s),d=a*l-h*c+f[1],u=a*c+h*l+f[2],new i(e.COORDS_BY_USER,[d,u],n)},perpendicular:function(t,s,n){var a,h,l,c,d,u=t.point1.coords.usrCoords,p=t.point2.coords.usrCoords,f=s.coords.usrCoords;return o.exists(n)||(n=s.board),s===t.point1?(a=u[1]+p[2]-u[2],h=u[2]-p[1]+u[1],d=u[0]*p[0],Math.abs(d)<r.eps&&(a=p[2],h=-p[1]),c=[d,a,h],l=!0):s===t.point2?(a=p[1]+u[2]-p[2],h=p[2]-u[1]+p[1],d=u[0]*p[0],Math.abs(d)<r.eps&&(a=u[2],h=-u[1]),c=[d,a,h],l=!1):Math.abs(r.innerProduct(f,t.stdform,3))<r.eps?(a=f[1]+p[2]-f[2],h=f[2]-p[1]+f[1],d=p[0],Math.abs(d)<r.eps&&(a=p[2],h=-p[1]),l=!0,Math.abs(d)>r.eps&&Math.abs(a-f[1])<r.eps&&Math.abs(h-f[2])<r.eps&&(a=f[1]+u[2]-f[2],h=f[2]-u[1]+f[1],l=!1),c=[d,a,h]):(c=[0,t.stdform[1],t.stdform[2]],c=r.crossProduct(c,f),c=r.crossProduct(c,t.stdform),l=!0),[new i(e.COORDS_BY_USER,c,n),l]},circumcenterMidpoint:function(){t.deprecated("Geometry.circumcenterMidpoint()","Geometry.circumcenter()"),this.circumcenter.apply(this,arguments)},circumcenter:function(t,s,n,a){var h,l,c,d,u=t.coords.usrCoords,p=s.coords.usrCoords,f=n.coords.usrCoords;return o.exists(a)||(a=t.board),h=[p[0]-u[0],-p[2]+u[2],p[1]-u[1]],l=[.5*(u[0]+p[0]),.5*(u[1]+p[1]),.5*(u[2]+p[2])],c=r.crossProduct(h,l),h=[f[0]-p[0],-f[2]+p[2],f[1]-p[1]],l=[.5*(p[0]+f[0]),.5*(p[1]+f[1]),.5*(p[2]+f[2])],d=r.crossProduct(h,l),new i(e.COORDS_BY_USER,r.crossProduct(c,d),a)},distance:function(t,e,i){var r,s=0;for(i||(i=Math.min(t.length,e.length)),r=0;r<i;r++)s+=(t[r]-e[r])*(t[r]-e[r]);return Math.sqrt(s)},affineDistance:function(t,e,i){var s;return s=this.distance(t,e,i),s>r.eps&&(Math.abs(t[0])<r.eps||Math.abs(e[0])<r.eps)?1/0:s},sortVertices:function(t){for(var e,i=n.each(t,n.coordsArray),r=i.length,s=null;i[0][0]===i[r-1][0]&&i[0][1]===i[r-1][1]&&i[0][2]===i[r-1][2];)s=i.pop(),r--;return e=i[0],i.sort(function(t,i){return(t[2]===e[2]&&t[1]===e[1]?-1/0:Math.atan2(t[2]-e[2],t[1]-e[1]))-(i[2]===e[2]&&i[1]===e[1]?-1/0:Math.atan2(i[2]-e[2],i[1]-e[1]))}),null!==s&&i.push(s),i},signedTriangle:function(t,e,i){var r=n.coordsArray(t),s=n.coordsArray(e),o=n.coordsArray(i);return.5*((s[1]-r[1])*(o[2]-r[2])-(s[2]-r[2])*(o[1]-r[1]))},signedPolygon:function(t,e){var i,r,s=0,o=n.each(t,n.coordsArray);for(void 0===e&&(e=!0),e?o.unshift(o[o.length-1]):o=this.sortVertices(o),r=o.length,i=1;i<r;i++)s+=o[i-1][1]*o[i][2]-o[i][1]*o[i-1][2];return.5*s},GrahamScan:function(t){var e,i=1,r=n.each(t,n.coordsArray),s=r.length;for(r=this.sortVertices(r),s=r.length,e=2;e<s;e++){for(;this.signedTriangle(r[i-1],r[i],r[e])<=0;){if(i>1)i-=1;else if(e===s-1)break;e+=1}i+=1,r=o.swap(r,i,e)}return r.slice(0,i)},calcStraight:function(t,i,s,n){var a,h,l,c,d,u,p,f,m,g;if(o.exists(n)||(n=10),u=o.evaluate(t.visProp.straightfirst),p=o.evaluate(t.visProp.straightlast),Math.abs(i.scrCoords[0])<r.eps&&(u=!0),Math.abs(s.scrCoords[0])<r.eps&&(p=!0),(u||p)&&(f=[],f[0]=t.stdform[0]-t.stdform[1]*t.board.origin.scrCoords[1]/t.board.unitX+t.stdform[2]*t.board.origin.scrCoords[2]/t.board.unitY,f[1]=t.stdform[1]/t.board.unitX,f[2]=-t.stdform[2]/t.board.unitY,!isNaN(f[0]+f[1]+f[2]))){if(a=!1,h=!1,a=!u&&Math.abs(i.usrCoords[0])>=r.eps&&i.scrCoords[1]>=0&&i.scrCoords[1]<=t.board.canvasWidth&&i.scrCoords[2]>=0&&i.scrCoords[2]<=t.board.canvasHeight,h=!p&&Math.abs(s.usrCoords[0])>=r.eps&&s.scrCoords[1]>=0&&s.scrCoords[1]<=t.board.canvasWidth&&s.scrCoords[2]>=0&&s.scrCoords[2]<=t.board.canvasHeight,l=this.meetLineBoard(f,t.board,n),c=l[0],d=l[1],!a&&!h){if(!u&&p&&!this.isSameDirection(i,s,c)&&!this.isSameDirection(i,s,d))return;if(u&&!p&&!this.isSameDirection(s,i,c)&&!this.isSameDirection(s,i,d))return}a?h||(g=this.isSameDir(i,s,c,d)?d:c):h?m=this.isSameDir(i,s,c,d)?c:d:this.isSameDir(i,s,c,d)?(m=c,g=d):(g=c,m=d),m&&i.setCoordinates(e.COORDS_BY_USER,m.usrCoords),g&&s.setCoordinates(e.COORDS_BY_USER,g.usrCoords)}},calcLineDelimitingPoints:function(t,i,s){var n,a,h,l,c,d,u,p,f,m,g=!1,b=!1;if(d=o.evaluate(t.visProp.straightfirst),u=o.evaluate(t.visProp.straightlast),Math.abs(i.scrCoords[0])<r.eps&&(d=!0),Math.abs(s.scrCoords[0])<r.eps&&(u=!0),p=[],p[0]=t.stdform[0]-t.stdform[1]*t.board.origin.scrCoords[1]/t.board.unitX+t.stdform[2]*t.board.origin.scrCoords[2]/t.board.unitY,p[1]=t.stdform[1]/t.board.unitX,p[2]=-t.stdform[2]/t.board.unitY,!isNaN(p[0]+p[1]+p[2])){if(g=!d,b=!u,a=t.board.getBoundingBox(),h=t.getSlope(),h>=0?(l=this.projectPointToLine({coords:{usrCoords:[1,a[2],a[1]]}},t,t.board),c=this.projectPointToLine({coords:{usrCoords:[1,a[0],a[3]]}},t,t.board)):(l=this.projectPointToLine({coords:{usrCoords:[1,a[0],a[1]]}},t,t.board),c=this.projectPointToLine({coords:{usrCoords:[1,a[2],a[3]]}},t,t.board)),!g&&!b){if(!d&&!u){if(n=i.distance(e.COORDS_BY_USER,s),Math.abs(i.distance(e.COORDS_BY_USER,l)+l.distance(e.COORDS_BY_USER,s)-n)>r.eps)return;if(Math.abs(i.distance(e.COORDS_BY_USER,c)+c.distance(e.COORDS_BY_USER,s)-n)>r.eps)return}if(!d&&u&&!this.isSameDirection(i,s,l)&&!this.isSameDirection(i,s,c))return;if(d&&!u&&!this.isSameDirection(s,i,l)&&!this.isSameDirection(s,i,c))return}g?b||(m=this.isSameDir(i,s,l,c)?c:l):b?f=this.isSameDir(i,s,l,c)?l:c:this.isSameDir(i,s,l,c)?(f=l,m=c):(m=l,f=c),f&&i.setCoordinates(e.COORDS_BY_USER,f.usrCoords),m&&s.setCoordinates(e.COORDS_BY_USER,m.usrCoords)}},calcLabelQuadrant:function(t){var e;return t<0&&(t+=2*Math.PI),e=Math.floor((t+Math.PI/8)/(Math.PI/4))%8,["rt","urt","top","ulft","lft","llft","lrt"][e]},isSameDir:function(t,e,i,s){var o=e.usrCoords[1]-t.usrCoords[1],n=e.usrCoords[2]-t.usrCoords[2],a=s.usrCoords[1]-i.usrCoords[1],h=s.usrCoords[2]-i.usrCoords[2];return Math.abs(e.usrCoords[0])<r.eps&&(o=e.usrCoords[1],n=e.usrCoords[2]),Math.abs(t.usrCoords[0])<r.eps&&(o=-t.usrCoords[1],n=-t.usrCoords[2]),o*a+n*h>=0},isSameDirection:function(t,e,i){var s,o,n,a,h=!1;return s=e.usrCoords[1]-t.usrCoords[1],o=e.usrCoords[2]-t.usrCoords[2],n=i.usrCoords[1]-t.usrCoords[1],a=i.usrCoords[2]-t.usrCoords[2],Math.abs(s)<r.eps&&(s=0),Math.abs(o)<r.eps&&(o=0),Math.abs(n)<r.eps&&(n=0),Math.abs(a)<r.eps&&(a=0),s>=0&&n>=0?h=o>=0&&a>=0||o<=0&&a<=0:s<=0&&n<=0&&(h=o>=0&&a>=0||o<=0&&a<=0),h},intersectionFunction:function(t,r,s,n,a,h){var l=this;return r.elementClass===e.OBJECT_CLASS_CURVE&&s.elementClass===e.OBJECT_CLASS_CURVE?function(){return l.meetCurveCurve(r,s,n,a,r.board)}:r.elementClass===e.OBJECT_CLASS_CURVE&&s.elementClass===e.OBJECT_CLASS_LINE||s.elementClass===e.OBJECT_CLASS_CURVE&&r.elementClass===e.OBJECT_CLASS_LINE?function(){return l.meetCurveLine(r,s,n,r.board,h)}:r.elementClass===e.OBJECT_CLASS_LINE&&s.elementClass===e.OBJECT_CLASS_LINE?function(){var t,a,c=o.evaluate(r.visProp.straightfirst),d=o.evaluate(r.visProp.straightlast),u=o.evaluate(s.visProp.straightfirst),p=o.evaluate(s.visProp.straightlast);return o.evaluate(h)||c&&d&&u&&p?l.meet(r.stdform,s.stdform,n,r.board):(t=l.meetSegmentSegment(r.point1.coords.usrCoords,r.point2.coords.usrCoords,s.point1.coords.usrCoords,s.point2.coords.usrCoords,r.board),a=!c&&t[1]<0||!d&&t[1]>1||!u&&t[2]<0||!p&&t[2]>1?[0,NaN,NaN]:t[0],new i(e.COORDS_BY_USER,a,r.board))}:function(){return l.meet(r.stdform,s.stdform,n,r.board)}},meet:function(t,e,i,s){var o=r.eps;return Math.abs(t[3])<o&&Math.abs(e[3])<o?this.meetLineLine(t,e,i,s):Math.abs(t[3])>=o&&Math.abs(e[3])<o?this.meetLineCircle(e,t,i,s):Math.abs(t[3])<o&&Math.abs(e[3])>=o?this.meetLineCircle(t,e,i,s):this.meetCircleCircle(t,e,i,s)},meetLineBoard:function(t,s,n){var a,h,l,c,d=[];for(o.exists(n)||(n=0),d[0]=r.crossProduct(t,[n,0,1]),d[1]=r.crossProduct(t,[n,1,0]),d[2]=r.crossProduct(t,[-n-s.canvasHeight,0,1]),d[3]=r.crossProduct(t,[-n-s.canvasWidth,1,0]),l=0;l<4;l++)if(Math.abs(d[l][0])>r.eps){for(c=2;c>0;c--)d[l][c]/=d[l][0];d[l][0]=1}return Math.abs(d[1][0])<r.eps?(a=d[0],h=d[2]):Math.abs(d[0][0])<r.eps?(a=d[1],h=d[3]):d[1][2]<0?(a=d[0],h=d[3][2]>s.canvasHeight?d[2]:d[3]):d[1][2]>s.canvasHeight?(a=d[2],h=d[3][2]<0?d[0]:d[3]):(a=d[1],h=d[3][2]<0?d[0]:d[3][2]>s.canvasHeight?d[2]:d[3]),a=new i(e.COORDS_BY_SCREEN,a.slice(1),s),h=new i(e.COORDS_BY_SCREEN,h.slice(1),s),[a,h]},meetLineLine:function(t,s,o,n){var a=isNaN(t[5]+s[5])?[0,0,0]:r.crossProduct(t,s);return new i(e.COORDS_BY_USER,a,n)},meetLineCircle:function(t,s,o,n){var a,h,l,c,d,u,p,f,m,g;return s[4]<r.eps?Math.abs(r.innerProduct([1,s[6],s[7]],t,3))<r.eps?new i(e.COORDS_BY_USER,s.slice(6,8),n):new i(e.COORDS_BY_USER,[NaN,NaN],n):(l=s[0],h=s.slice(1,3),a=s[3],c=t[0],d=t.slice(1,3),u=a,p=h[0]*d[1]-h[1]*d[0],f=a*c*c-(h[0]*d[0]+h[1]*d[1])*c+l,m=p*p-4*u*f,m>-r.eps*r.eps?(m=Math.sqrt(Math.abs(m)),g=[(-p+m)/(2*u),(-p-m)/(2*u)],0===o?new i(e.COORDS_BY_USER,[-g[0]*-d[1]-c*d[0],-g[0]*d[0]-c*d[1]],n):new i(e.COORDS_BY_USER,[-g[1]*-d[1]-c*d[0],-g[1]*d[0]-c*d[1]],n)):new i(e.COORDS_BY_USER,[0,0,0],n))},meetCircleCircle:function(t,s,o,n){var a;return t[4]<r.eps?Math.abs(this.distance(t.slice(6,2),s.slice(6,8))-s[4])<r.eps?new i(e.COORDS_BY_USER,t.slice(6,8),n):new i(e.COORDS_BY_USER,[0,0,0],n):s[4]<r.eps?Math.abs(this.distance(s.slice(6,2),t.slice(6,8))-t[4])<r.eps?new i(e.COORDS_BY_USER,s.slice(6,8),n):new i(e.COORDS_BY_USER,[0,0,0],n):(a=[s[3]*t[0]-t[3]*s[0],s[3]*t[1]-t[3]*s[1],s[3]*t[2]-t[3]*s[2],0,1,1/0,1/0,1/0],a=r.normalize(a),this.meetLineCircle(a,t,o,n))},meetCurveCurve:function(t,r,n,a,h,l){var c;return c=o.exists(l)&&"newton"===l?s.generalizedNewton(t,r,n,a):3===t.bezierDegree&&3===r.bezierDegree?this.meetBezierCurveRedBlueSegments(t,r,n):this.meetCurveRedBlueSegments(t,r,n),new i(e.COORDS_BY_USER,c,h)},meetCurveLine:function(t,i,r,s,n){var a,h;return o.exists(s)||(s=t.board),t.elementClass===e.OBJECT_CLASS_CURVE?(a=t,h=i):(a=i,h=t),this.meetCurveLineDiscrete(a,h,r,s,!n)},meetCurveLineContinuous:function(t,o,n,a,h){var l,c,d,u,p,f,m,g,b,v,y,C,_,P,E=r.eps,x=r.eps;for(u=this.meetCurveLineDiscrete(t,o,n,a,h),p=u.usrCoords[1],f=u.usrCoords[2],c=function(e){var i,r;return e>t.maxX()||e<t.minX()?1/0:(i=p-t.X(e),r=f-t.Y(e),i*i+r*r)},d=function(e){var i=o.stdform[0]+o.stdform[1]*t.X(e)+o.stdform[2]*t.Y(e);return i*i},g=50,b=(t.maxX()-t.minX())/g,v=t.minX(),_=1e-4,C=NaN,y=0;y<g&&(l=s.root(c,[Math.max(v,t.minX()),Math.min(v+b,t.maxX())]),!((P=Math.abs(c(l)))<=_&&(_=P,C=l,_<E)));y++)v+=b;return l=C,l=s.root(d,[Math.max(l-b,t.minX()),Math.min(l+b,t.maxX())]),P=d(l),m=isNaN(P)||Math.abs(P)>x?0:1,new i(e.COORDS_BY_USER,[m,t.X(l),t.Y(l)],a)},meetCurveLineContinuousOld:function(o,n,a,h){var l,c,d,u,p,f,m,g,b,v,y,C,_=10*r.eps;if(t.deprecated("Geometry.meetCurveLineContinuousOld()","Geometry.meetCurveLineContinuous()"),u=function(t){var e=n.stdform[0]+n.stdform[1]*o.X(t)+n.stdform[2]*o.Y(t);return e*e},this.meetCurveLineContinuous.t1memo?(b=this.meetCurveLineContinuous.t1memo,l=s.root(u,b)):(b=o.minX(),v=o.maxX(),l=s.root(u,[b,v])),this.meetCurveLineContinuous.t1memo=l,y=o.X(l),C=o.Y(l), -1===a){if(this.meetCurveLineContinuous.t2memo&&(b=this.meetCurveLineContinuous.t2memo),c=s.root(u,b),!(Math.abs(c-l)>.1&&Math.abs(y-o.X(c))>.1&&Math.abs(C-o.Y(c))>.1))for(m=20,g=(o.maxX()-o.minX())/m,f=o.minX(),d=0;d<m&&(c=s.root(u,[f,f+g]),!(Math.abs(u(c))<=_&&Math.abs(c-l)>.1&&Math.abs(y-o.X(c))>.1&&Math.abs(C-o.Y(c))>.1));d++)f+=g;l=c,this.meetCurveLineContinuous.t2memo=l}return p=Math.abs(u(l))>_?NaN:1,new i(e.COORDS_BY_USER,[p,o.X(l),o.Y(l)],h)},meetCurveLineDiscrete:function(t,s,n,a,h){var l,c,d,u,p,f,m,g=s.point1.coords.usrCoords,b=s.point2.coords.usrCoords,v=0,y=t.numberPoints,C=o.evaluate(s.visProp.straightfirst),_=o.evaluate(s.visProp.straightlast);for(f=new i(e.COORDS_BY_USER,[0,NaN,NaN],a),0===g[0]?g=[1,b[1]+s.stdform[2],b[2]-s.stdform[1]]:0===b[0]&&(b=[1,g[1]+s.stdform[2],g[2]-s.stdform[1]]),u=t.points[0].usrCoords,l=1;l<y;l++)if(d=u.slice(0),u=t.points[l].usrCoords,this.distance(d,u)>r.eps)for(3===t.bezierDegree?(m=this.meetBeziersegmentBeziersegment([t.points[l-1].usrCoords.slice(1),t.points[l].usrCoords.slice(1),t.points[l+1].usrCoords.slice(1),t.points[l+2].usrCoords.slice(1)],[g.slice(1),b.slice(1)],h),l+=2):m=[this.meetSegmentSegment(d,u,g,b)],c=0;c<m.length;c++)if(p=m[c],0<=p[1]&&p[1]<=1){if(v===n)return h&&(!C&&p[2]<0||!_&&p[2]>1)?f:f=new i(e.COORDS_BY_USER,p[0],a);v+=1}return f},meetCurveRedBlueSegments:function(t,e,i){var r,s,o,n,a,h,l,c,d,u=0,p=e.numberPoints,f=t.numberPoints;if(p<=1||f<=1)return[0,NaN,NaN];for(r=1;r<f;r++)for(o=t.points[r-1].usrCoords,n=t.points[r].usrCoords,c=Math.min(o[1],n[1]),d=Math.max(o[1],n[1]),h=e.points[0].usrCoords,s=1;s<p;s++)if(a=h,h=e.points[s].usrCoords,Math.min(a[1],h[1])<d&&Math.max(a[1],h[1])>c&&(l=this.meetSegmentSegment(o,n,a,h),l[1]>=0&&l[2]>=0&&(l[1]<1&&l[2]<1||r===f-1&&1===l[1]||s===p-1&&1===l[2]))){if(u===i)return l[0];u++}return[0,NaN,NaN]},meetSegmentSegment:function(t,e,i,s){var o,n,a,h=r.crossProduct(t,e),l=r.crossProduct(i,s),c=r.crossProduct(h,l),d=c[0];return Math.abs(d)<r.eps?[c,1/0,1/0]:(a=[i[1]-t[1],i[2]-t[2]],o=(a[0]*(s[2]-i[2])-a[1]*(s[1]-i[1]))/d,n=(a[0]*(e[2]-t[2])-a[1]*(e[1]-t[1]))/d,[c,o,n])},_bezierSplit:function(t){var e,i,r,s,o,n;return e=[.5*(t[0][0]+t[1][0]),.5*(t[0][1]+t[1][1])],i=[.5*(t[1][0]+t[2][0]),.5*(t[1][1]+t[2][1])],r=[.5*(t[2][0]+t[3][0]),.5*(t[2][1]+t[3][1])],s=[.5*(e[0]+i[0]),.5*(e[1]+i[1])],o=[.5*(i[0]+r[0]),.5*(i[1]+r[1])],n=[.5*(s[0]+o[0]),.5*(s[1]+o[1])],[[t[0],e,s,n],[n,o,r,t[3]]]},_bezierBbox:function(t){var e=[];return 4===t.length?(e[0]=Math.min(t[0][0],t[1][0],t[2][0],t[3][0]),e[1]=Math.max(t[0][1],t[1][1],t[2][1],t[3][1]),e[2]=Math.max(t[0][0],t[1][0],t[2][0],t[3][0]),e[3]=Math.min(t[0][1],t[1][1],t[2][1],t[3][1])):(e[0]=Math.min(t[0][0],t[1][0]),e[1]=Math.max(t[0][1],t[1][1]),e[2]=Math.max(t[0][0],t[1][0]),e[3]=Math.min(t[0][1],t[1][1])),e},_bezierOverlap:function(t,e){return t[2]>=e[0]&&t[0]<=e[2]&&t[1]>=e[3]&&t[3]<=e[1]},_bezierListConcat:function(t,e,i,r){var s,n=o.exists(r),a=0,h=e.length,l=t.length;for(l>0&&h>0&&(1===t[l-1][1]&&0===e[0][1]||n&&1===t[l-1][2]&&0===e[0][2])&&(a=1),s=a;s<h;s++)n&&(e[s][2]*=.5,e[s][2]+=r),e[s][1]*=.5,e[s][1]+=i,t.push(e[s])},_bezierMeetSubdivision:function(t,e,i){var r,s,o,n,a,h,l,c,d,u,p,f,m=[];return s=this._bezierBbox(e),r=this._bezierBbox(t),this._bezierOverlap(s,r)?i<5?(o=this._bezierSplit(t),h=o[0],l=o[1],o=this._bezierSplit(e),n=o[0],a=o[1],this._bezierListConcat(m,this._bezierMeetSubdivision(h,n,i+1),0,0),this._bezierListConcat(m,this._bezierMeetSubdivision(h,a,i+1),0,.5),this._bezierListConcat(m,this._bezierMeetSubdivision(l,n,i+1),.5,0),this._bezierListConcat(m,this._bezierMeetSubdivision(l,a,i+1),.5,.5),m):(p=[1].concat(t[0]),f=[1].concat(t[3]),d=[1].concat(e[0]),u=[1].concat(e[3]),c=this.meetSegmentSegment(p,f,d,u),c[1]>=0&&c[2]>=0&&c[1]<=1&&c[2]<=1?[c]:[]):[]},_bezierLineMeetSubdivision:function(t,e,i,r){var s,o,n,a,h,l,c,d,u,p,f=[];return s=this._bezierBbox(e),o=this._bezierBbox(t),r&&!this._bezierOverlap(o,s)?[]:i<5?(n=this._bezierSplit(t),a=n[0],h=n[1],this._bezierListConcat(f,this._bezierLineMeetSubdivision(a,e,i+1),0),this._bezierListConcat(f,this._bezierLineMeetSubdivision(h,e,i+1),.5),f):(u=[1].concat(t[0]),p=[1].concat(t[3]),c=[1].concat(e[0]),d=[1].concat(e[1]),l=this.meetSegmentSegment(u,p,c,d),l[1]>=0&&l[1]<=1&&(!r||l[2]>=0&&l[2]<=1)?[l]:[])},meetBeziersegmentBeziersegment:function(t,e,i){var r,s,o;for(r=4===t.length&&4===e.length?this._bezierMeetSubdivision(t,e,0):this._bezierLineMeetSubdivision(t,e,0,i),r.sort(function(t,e){return 1e7*(t[1]-e[1])+(t[2]-e[2])}),s=[],o=0;o<r.length;o++)0!==o&&r[o][1]===r[o-1][1]&&r[o][2]===r[o-1][2]||s.push(r[o]);return s},meetBezierCurveRedBlueSegments:function(t,e,i){var r,s,o,n,a,h,l,c=e.numberPoints,d=t.numberPoints,u=[];if(c<4||d<4)return[0,NaN,NaN];for(s=0;s<d-3;s+=3)for(r=t.points,n=[[r[s].usrCoords[1],r[s].usrCoords[2]],[r[s+1].usrCoords[1],r[s+1].usrCoords[2]],[r[s+2].usrCoords[1],r[s+2].usrCoords[2]],[r[s+3].usrCoords[1],r[s+3].usrCoords[2]]],h=this._bezierBbox(n),o=0;o<c-3;o+=3)if(r=e.points,a=[[r[o].usrCoords[1],r[o].usrCoords[2]],[r[o+1].usrCoords[1],r[o+1].usrCoords[2]],[r[o+2].usrCoords[1],r[o+2].usrCoords[2]],[r[o+3].usrCoords[1],r[o+3].usrCoords[2]]],l=this._bezierBbox(a),this._bezierOverlap(h,l)&&(u=u.concat(this.meetBeziersegmentBeziersegment(n,a)),u.length>i))return u[i][0];return u.length>i?u[i][0]:[0,NaN,NaN]},bezierSegmentEval:function(t,e){var i,r,s,o=1-t;return r=0,s=0,i=o*o*o,r+=i*e[0][0],s+=i*e[0][1],i=3*t*o*o,r+=i*e[1][0],s+=i*e[1][1],i=3*t*t*o,r+=i*e[2][0],s+=i*e[2][1],i=t*t*t,r+=i*e[3][0],s+=i*e[3][1],[1,r,s]},bezierArc:function(t,e,i,s,o){var n,a,h,l,c,d,u,p,f,m,g,b,v,y,C,_,P,E=.5*Math.PI,x=e[1],S=e[2],w=e[0],O=[],T=[];for(c=this.distance(e,t),x/=w,S/=w,d=this.rad(t.slice(1),e.slice(1),i.slice(1)),-1===o&&(d=2*Math.PI-d),n=t,n[1]/=n[0],n[2]/=n[0],n[0]/=n[0],l=n.slice(0),s?(O=[x,x+.333*(n[1]-x),x+.666*(n[1]-x),n[1]],T=[S,S+.333*(n[2]-S),S+.666*(n[2]-S),n[2]]):(O=[n[1]],T=[n[2]]);d>r.eps;)d>E?(u=E,d-=E):(u=d,d=0),p=Math.cos(o*u),f=Math.sin(o*u),P=[[1,0,0],[x*(1-p)+S*f,p,-f],[S*(1-p)-x*f,f,p]],C=r.matVecMult(P,n),l=[C[0]/C[0],C[1]/C[0],C[2]/C[0]],m=n[1]-x,g=n[2]-S,b=l[1]-x,v=l[2]-S,_=Math.sqrt((m+b)*(m+b)+(g+v)*(g+v)),y=Math.abs(v-g)>r.eps?(m+b)*(c/_-.5)/(v-g)*8/3:(g+v)*(c/_-.5)/(m-b)*8/3,a=[1,n[1]-y*g,n[2]+y*m],h=[1,l[1]+y*v,l[2]-y*b],O=O.concat([a[1],h[1],l[1]]),T=T.concat([a[2],h[2],l[2]]),n=l.slice(0);return s&&(O=O.concat([l[1]+.333*(x-l[1]),l[1]+.666*(x-l[1]),x]),T=T.concat([l[2]+.333*(S-l[2]),l[2]+.666*(S-l[2]),S])),[O,T]},projectPointToCircle:function(t,s,n){var a,h,l,c,d,u=s.center.coords.usrCoords;return o.exists(n)||(n=t.board),o.isPoint(t)?(a=t.coords.distance(e.COORDS_BY_USER,s.center.coords),h=t.coords.usrCoords):(a=t.distance(e.COORDS_BY_USER,s.center.coords),h=t.usrCoords),Math.abs(a)<r.eps&&(a=r.eps),d=s.Radius()/a,l=u[1]+d*(h[1]-u[1]),c=u[2]+d*(h[2]-u[2]),new i(e.COORDS_BY_USER,[l,c],n)},projectPointToLine:function(t,s,n){var a,h=[0,s.stdform[1],s.stdform[2]];return o.exists(n)||(n=o.exists(t.coords)?t.board:s.board),a=o.exists(t.coords)?t.coords.usrCoords:t.usrCoords,h=r.crossProduct(h,a),new i(e.COORDS_BY_USER,r.crossProduct(h,s.stdform),n)},projectCoordsToSegment:function(t,e,i){var s,o,n=[i[1]-e[1],i[2]-e[2]],a=[t[1]-e[1],t[2]-e[2]];return Math.abs(n[0])<r.eps&&Math.abs(n[1])<r.eps?[e,0]:(s=r.innerProduct(a,n),o=r.innerProduct(n,n),s/=o,[[1,s*n[0]+e[1],s*n[1]+e[2]],s])},projectCoordsToBeziersegment:function(e,i,r){var s,o=function(t){var s=[1,i.X(r+t),i.Y(r+t)];return s[1]-=e[1],s[2]-=e[2],s[1]*s[1]+s[2]*s[2]};return s=t.Math.Numerics.fminbr(o,[0,1]),[[1,i.X(s+r),i.Y(s+r)],s]},projectPointToCurve:function(t,e,i){o.exists(i)||(i=t.board);var r=t.X(),s=t.Y(),n=t.position||0,a=this.projectCoordsToCurve(r,s,n,e,i);return t.position=a[1],a[0]},projectCoordsToCurve:function(t,r,n,a,h){var l,c,d,u,p,f,m,g,b,v,y,C,_,P,E,x,S,w,O,T,N,M=Number.POSITIVE_INFINITY;if(o.exists(h)||(h=a.board),"plot"===o.evaluate(a.visProp.curvetype)){if(n=0,p=M,l=0===a.numberPoints?[0,1,1]:[a.Z(0),a.X(0),a.Y(0)],a.numberPoints>1)for(g=[1,t,r],3===a.bezierDegree?u=0:y=[a.Z(0),a.X(0),a.Y(0)],d=0;d<a.numberPoints-1;d++)3===a.bezierDegree?_=this.projectCoordsToBeziersegment(g,a,u):(C=[a.Z(d+1),a.X(d+1),a.Y(d+1)],_=this.projectCoordsToSegment(g,y,C)),m=_[1],b=_[0],0<=m&&m<=1?(f=this.distance(b,g),v=d+m):m<0?(b=y,f=this.distance(y,g),v=d):m>1&&d===a.numberPoints-2&&(b=C,f=this.distance(b,g),v=a.numberPoints-1),f<p&&(p=f,n=v,l=b),3===a.bezierDegree?(u++,d+=2):y=C;c=new i(e.COORDS_BY_USER,l,h)}else{for(P=function(e){var i,s;return e<a.minX()||e>a.maxX()?NaN:(i=t-a.X(e),s=r-a.Y(e),i*i+s*s)},S=P(n),O=50,w=(a.maxX()-a.minX())/O,E=a.minX(),d=0;d<O;d++)x=P(E),(x<S||isNaN(S))&&(n=E,S=x),E+=w;n=s.fminbr(P,[n-w,n+w]),T=a.minX(),N=a.maxX(),n=n<T?T:n,n=n>N?N:n,c=new i(e.COORDS_BY_USER,[a.X(n),a.Y(n)],h)}return[a.updateTransform(c),n]},projectCoordsToPolygon:function(e,i){var r,s,o,n,a=i.vertices.length,h=1/0;for(r=0;r<a;r++)o=t.Math.Geometry.projectCoordsToSegment(e,i.vertices[r].coords.usrCoords,i.vertices[(r+1)%a].coords.usrCoords),s=t.Math.Geometry.distance(o[0],e,3),0<=o[1]&&o[1]<=1&&s<h&&(n=o[0].slice(0),h=s);return n},projectPointToTurtle:function(t,r,s){var n,a,h,l,c,d,u,p,f=0,m=0,g=Number.POSITIVE_INFINITY,b=r.objects.length;for(o.exists(s)||(s=t.board),c=0;c<b;c++)u=r.objects[c],u.elementClass===e.OBJECT_CLASS_CURVE&&(n=this.projectPointToCurve(t,u),d=this.distance(n.usrCoords,t.coords.usrCoords),d<g&&(h=n.usrCoords[1],l=n.usrCoords[2],a=t.position,g=d,p=u,m=f),f+=u.numberPoints);return n=new i(e.COORDS_BY_USER,[h,l],s),t.position=a+m,p.updateTransform(n)},projectPointToPoint:function(t,e){return e.coords},projectPointToBoard:function(t,e){var i,s,o,n=e||t.board,a=[[1,1,0,0,3,0,1],[-1,2,1,0,1,2,1],[-1,1,2,2,1,2,3],[1,2,3,0,3,2,3]],h=t.coords||t,l=n.getBoundingBox();for(i=0;i<4;i++)o=a[i],o[0]*h.usrCoords[o[1]]<o[0]*l[o[2]]&&(s=r.crossProduct([1,l[o[3]],l[o[4]]],[1,l[o[5]],l[o[6]]]),s[3]=0,s=r.normalize(s),h=this.projectPointToLine({coords:h},{stdform:s},n));return h},distPointLine:function(t,e){var i,s=e[1],o=e[2],n=e[0];return Math.abs(s)+Math.abs(o)<r.eps?Number.POSITIVE_INFINITY:(i=s*t[1]+o*t[2]+n,s*=s,o*=o,Math.abs(i)/Math.sqrt(s+o))},reuleauxPolygon:function(t,e){var i,s=2*Math.PI,o=s/e,n=(e-1)/2,a=0,h=function(h,l){return function(c,d){var u=(c%s+s)%s,p=Math.floor(u/o)%e;return d||(a=t[0].Dist(t[n]),i=r.Geometry.rad([t[0].X()+1,t[0].Y()],t[0],t[n%e])),isNaN(p)?p:(u=.5*u+p*o*.5+i,t[p][h]()+a*Math[l](u))}};return[h("X","cos"),h("Y","sin"),0,s]}}),r.Geometry}),define("math/plot",["jxg","base/constants","base/coords","math/math","math/extrapolate","math/numerics","math/statistics","math/geometry","math/ia","utils/type"],function(t,e,i,r,s,o,n,a,h,l){"use strict";return r.Plot={checkReal:function(t){var e,i,s=!1,o=t.length;for(e=0;e<o;e++)if(i=t[e].usrCoords,!isNaN(i[1])&&!isNaN(i[2])&&Math.abs(i[0])>r.eps){s=!0;break}return s},updateParametricCurveNaive:function(t,i,r,s){var o,n,a=!1,h=(r-i)/s;for(o=0;o<s;o++)n=i+o*h,t.points[o].setCoordinates(e.COORDS_BY_USER,[t.X(n,a),t.Y(n,a)],!1),t.points[o]._t=n,a=!0;return t},isSegmentOutside:function(t,e,i,r,s){return e<0&&r<0||e>s.canvasHeight&&r>s.canvasHeight||t<0&&i<0||t>s.canvasWidth&&i>s.canvasWidth},isDistOK:function(t,e,i,r){return Math.abs(t)<i&&Math.abs(e)<r&&!isNaN(t+e)},isSegmentDefined:function(t,e,i,r){return!(isNaN(t+e)&&isNaN(i+r))},updateParametricCurveOld:function(s,o,n){var a,h,l,c,d,u,p,f,m,g,b,v=!1,y=new i(e.COORDS_BY_USER,[0,0],s.board,!1),C=[],_=[],P=[],E=[],x=!1,S=0;for(t.deprecated("Curve.updateParametricCurveOld()"),s.board.updateQuality===s.board.BOARD_QUALITY_LOW?(m=15,g=10,b=10):(m=21,g=.7,b=.7),E[0]=n-o,a=1;a<m;a++)E[a]=.5*E[a-1];a=1,C[0]=1,_[0]=0,h=o,y.setCoordinates(e.COORDS_BY_USER,[s.X(h,v),s.Y(h,v)],!1),v=!0,d=y.scrCoords[1],u=y.scrCoords[2],h=n,y.setCoordinates(e.COORDS_BY_USER,[s.X(h,v),s.Y(h,v)],!1),l=y.scrCoords[1],c=y.scrCoords[2],P[0]=[l,c],p=1,f=0,s.points=[],s.points[S++]=new i(e.COORDS_BY_SCREEN,[d,u],s.board,!1);do{for(x=this.isDistOK(l-d,c-u,g,b)||this.isSegmentOutside(d,u,l,c,s.board);f<m&&(!x||f<6)&&(f<=7||this.isSegmentDefined(d,u,l,c));)C[p]=a,_[p]=f,P[p]=[l,c],p+=1,a=2*a-1,f++,h=o+a*E[f],y.setCoordinates(e.COORDS_BY_USER,[s.X(h,v),s.Y(h,v)],!1,!0),l=y.scrCoords[1],c=y.scrCoords[2],x=this.isDistOK(l-d,c-u,g,b)||this.isSegmentOutside(d,u,l,c,s.board);S>1&&function(t,e,i){var s,o,n=i[1]-t[1],a=i[2]-t[2],h=e[0]-t[1],l=e[1]-t[2],c=h*h+l*l;return c>=r.eps&&(s=(n*h+a*l)/c)>0&&(s<=1?(n-=s*h,a-=s*l):(n-=h,a-=l)),o=n*n+a*a,Math.sqrt(o)}(s.points[S-2].scrCoords,[l,c],s.points[S-1].scrCoords)<.015&&(S-=1),s.points[S]=new i(e.COORDS_BY_SCREEN,[l,c],s.board,!1),s.points[S]._t=h,S+=1,d=l,u=c,h,p-=1,l=P[p][0],c=P[p][1],f=_[p]+1,a=2*C[p]}while(p>0&&S<5e5);return s.numberPoints=s.points.length,s},_insertPoint_v2:function(t,e,i){var r=!isNaN(this._lastCrds[1]+this._lastCrds[2]),s=!isNaN(e.scrCoords[1]+e.scrCoords[2]),o=t.board.canvasWidth,n=t.board.canvasHeight;(!(s=s&&e.scrCoords[1]>-500&&e.scrCoords[2]>-500&&e.scrCoords[1]<o+500&&e.scrCoords[2]<n+500)&&r||s&&(!r||Math.abs(e.scrCoords[1]-this._lastCrds[1])>.7||Math.abs(e.scrCoords[2]-this._lastCrds[2])>.7))&&(e._t=i,t.points.push(e),this._lastCrds=e.copy("scrCoords"))},_borderCase:function(t,r,s,o,n,a,h,l){var c,d,u,p,f,m,g,b,v,y,C,_=null,P=!1;if(l<=1){d=new i(e.COORDS_BY_USER,[0,0],t.board,!1),p=0;do{if(isNaN(r[1]+r[2])&&!isNaN(o[1]+o[2]))f=n,m=h,g=a;else if(isNaN(s[1]+s[2])&&!isNaN(o[1]+o[2]))f=a,m=h,g=n;else if(isNaN(o[1]+o[2])&&!isNaN(s[1]+s[2]))f=h,m=a,g=a+(a-h);else{if(!isNaN(o[1]+o[2])||isNaN(r[1]+r[2]))return!1;f=h,m=n,g=n-(h-n)}c=.5*(f+m),d.setCoordinates(e.COORDS_BY_USER,[t.X(c,!0),t.Y(c,!0)],!1),u=d.usrCoords,P=isNaN(u[1]+u[2]),P?f=c:(g=m,m=c),++p}while(P&&p<30);if(p<30&&(_=u.slice(),o=u.slice(),m=c),b=t.X(m,!0),y=t.X(g,!0),(b-y)/(m-g),v=t.Y(m,!0),C=t.Y(g,!0),(v-C)/(m-g),null!==_)return this._insertPoint_v2(t,new i(e.COORDS_BY_USER,_,t.board,!1)),!0}return!1},_plotRecursive_v2:function(t,r,s,o,n,a,h){var l,c,d,u,p,f,m=0,g=new i(e.COORDS_BY_USER,[0,0],t.board,!1);if(!(t.numberPoints>65536))return a<this.nanLevel&&this._isUndefined(t,r,s,o,n)?this:a<this.nanLevel&&this._isOutside(r,s,o,n,t.board)?this:(l=.5*(s+n),g.setCoordinates(e.COORDS_BY_USER,[t.X(l,!0),t.Y(l,!0)],!1),c=g.scrCoords,this._borderCase(t,r,o,c,s,n,l,a)?this:(d=this._triangleDists(r,o,c),u=a<this.smoothLevel&&d[3]<h,p=a<this.jumpLevel&&(d[2]>.99*d[0]||d[1]>.99*d[0]||d[0]===1/0||d[1]===1/0||d[2]===1/0),f=a<this.smoothLevel+2&&d[0]<.5*(d[1]+d[2]),f&&(m=0,u=!1),--a,p?this._insertPoint_v2(t,new i(e.COORDS_BY_SCREEN,[NaN,NaN],t.board,!1),l):a<=m||u?this._insertPoint_v2(t,g,l):(this._plotRecursive_v2(t,r,s,c,l,a,h),this._insertPoint_v2(t,g,l),this._plotRecursive_v2(t,c,l,o,n,a,h)),this))},updateParametricCurve_v2:function(t,r,s){var o,n,a,h,c,d,u,p,f,m=!1,g=new i(e.COORDS_BY_USER,[0,0],t.board,!1),b=new i(e.COORDS_BY_USER,[0,0],t.board,!1);return t.board.updateQuality===t.board.BOARD_QUALITY_LOW?(c=l.evaluate(t.visProp.recursiondepthlow)||13,d=2,this.smoothLevel=c-6,this.jumpLevel=3):(c=l.evaluate(t.visProp.recursiondepthhigh)||17,d=2,this.smoothLevel=c-9,this.jumpLevel=2),this.nanLevel=c-4,t.points=[],"x"===this.xterm?(p=t.board.getBoundingBox(),u=.3*(p[2]-p[0]),.3*(p[1]-p[3]),o=Math.max(r,p[0]-u),n=Math.min(s,p[2]+u)):(o=r,n=s),g.setCoordinates(e.COORDS_BY_USER,[t.X(o,m),t.Y(o,m)],!1),m=!0,b.setCoordinates(e.COORDS_BY_USER,[t.X(n,m),t.Y(n,m)],!1),f=this._findStartPoint(t,g.scrCoords,o,b.scrCoords,n),g.setCoordinates(e.COORDS_BY_SCREEN,f[0],!1),o=f[1],f=this._findStartPoint(t,b.scrCoords,n,g.scrCoords,o),b.setCoordinates(e.COORDS_BY_SCREEN,f[0],!1),n=f[1],this._visibleArea=[o,n],a=g.copy("scrCoords"),h=b.copy("scrCoords"),g._t=o,t.points.push(g),this._lastCrds=g.copy("scrCoords"),this._plotRecursive_v2(t,a,o,h,n,c,d),b._t=n,t.points.push(b),t.numberPoints=t.points.length,t},_insertLimesPoint:function(t,s,o,n,a){var h,l,c;Math.abs(this._lastUsrCrds[1])===1/0&&Math.abs(a.left_x)===1/0||Math.abs(this._lastUsrCrds[2])===1/0&&Math.abs(a.left_y)===1/0||(h=new i(e.COORDS_BY_USER,[a.left_x,a.left_y],t.board),h._t=o,t.points.push(h),isNaN(a.left_x)||isNaN(a.left_y)||isNaN(a.right_x)||isNaN(a.right_y)||!(Math.abs(a.left_x-a.right_x)>r.eps||Math.abs(a.left_y-a.right_y)>r.eps)||(l=new i(e.COORDS_BY_SCREEN,s,t.board),l._t=o,t.points.push(l)),c=new i(e.COORDS_BY_USER,[a.right_x,a.right_y],t.board),c._t=o,t.points.push(c),this._lastScrCrds=c.copy("scrCoords"),this._lastUsrCrds=c.copy("usrCoords"))},_insertPoint:function(t,r,s,o,n){var a,h=!isNaN(this._lastScrCrds[1]+this._lastScrCrds[2]),c=!isNaN(r[1]+r[2]),d=t.board.canvasWidth,u=t.board.canvasHeight;if(l.exists(n))return void this._insertLimesPoint(t,r,s,o,n);c=c&&r[1]>-500&&r[2]>-500&&r[1]<d+500&&r[2]<u+500,(h||c)&&(c&&h&&Math.abs(r[1]-this._lastScrCrds[1])<.8&&Math.abs(r[2]-this._lastScrCrds[2])<.8||Math.abs(r[1])===1/0&&Math.abs(this._lastUsrCrds[1])===1/0||Math.abs(r[2])===1/0&&Math.abs(this._lastUsrCrds[2])===1/0||(a=new i(e.COORDS_BY_SCREEN,r,t.board),a._t=s,t.points.push(a),this._lastScrCrds=a.copy("scrCoords"),this._lastUsrCrds=a.copy("usrCoords")))},_triangleDists:function(t,e,i){var r,s,o,n,h;return r=[t[0]*e[0],.5*(t[1]+e[1]),.5*(t[2]+e[2])],s=a.distance(t,e,3),o=a.distance(t,i,3),n=a.distance(i,e,3),h=a.distance(i,r,3),[s,o,n,h]},_isUndefined:function(t,r,s,o,n){var a,h,l;if(!isNaN(r[1]+r[2])||!isNaN(o[1]+o[2]))return!1;for(l=new i(e.COORDS_BY_USER,[0,0],t.board,!1),h=0;h<20;++h)if(a=s+Math.random()*(n-s),l.setCoordinates(e.COORDS_BY_USER,[t.X(a,!0),t.Y(a,!0)],!1),!isNaN(l.scrCoords[0]+l.scrCoords[1]+l.scrCoords[2]))return!1;return!0},_isOutside:function(t,e,i,r,s){var o=s.canvasWidth,n=s.canvasHeight;return!!(t[1]<-500&&i[1]<-500||t[2]<-500&&i[2]<-500||t[1]>o+500&&i[1]>o+500||t[2]>n+500&&i[2]>n+500)},_isOutsidePoint:function(t,e){var i=e.canvasWidth,r=e.canvasHeight;return!!(t[1]<-500||t[2]<-500||t[1]>i+500||t[2]>r+500)},_findStartPoint:function(t,r,s,n,a){var h,l,c,d,u,p,f,m,g,b,v,y,C=new i(e.COORDS_BY_USER,[0,0],t.board,!1),_=t.board.getBoundingBox();if(!this._isOutsidePoint(r,t.board))return[r,s];for(f=.3*(_[2]-_[0]),m=.3*(_[1]-_[3]),_[0]-=f,_[1]+=m,_[2]+=f,_[3]-=m,l=(a-s)/40,c=s+l,p=!1,g=function(e){return t.X(e,!0)-_[0]},v=function(e){return t.Y(e,!0)-_[1]},b=function(e){return t.X(e,!0)-_[2]},y=function(e){return t.Y(e,!0)-_[3]},h=0;h<40;++h){if(u=_[0],d=o.root(g,[c-l,c],t),Math.abs(t.X(d,!0)-u)<.01){p=!0;break}if(u=_[1],d=o.root(v,[c-l,c],t),Math.abs(t.Y(d,!0)-u)<.01){p=!0;break}if(u=_[2],d=o.root(b,[c-l,c],t),Math.abs(t.X(d,!0)-u)<.01){p=!0;break}if(u=_[3],d=o.root(y,[c-l,c],t),Math.abs(t.Y(d,!0)-u)<.01){p=!0;break}c+=l}return p?(C.setCoordinates(e.COORDS_BY_USER,[t.X(d,!0),t.Y(d,!0)],!1),[C.scrCoords,d]):(console.log("TODO _findStartPoint",t.Y.toString(),c),C.setCoordinates(e.COORDS_BY_USER,[t.X(s,!0),t.Y(s,!0)],!1),[C.scrCoords,s])},_getBorderPos:function(t,s,o,n,a,h,l){var c,d,u,p,f,m,g=!1;if(d=new i(e.COORDS_BY_USER,[0,0],t.board,!1),p=0,isNaN(o[1]+o[2])&&!isNaN(a[1]+a[2]))m=s,f=n,h;else if(isNaN(l[1]+l[2])&&!isNaN(a[1]+a[2]))m=h,f=n,s;else if(isNaN(a[1]+a[2])&&!isNaN(l[1]+l[2]))m=n,f=h,h+(h-n);else{if(!isNaN(a[1]+a[2])||isNaN(o[1]+o[2]))return!1;m=n,f=s,s-(n-s)}do{c=.5*(f+m),d.setCoordinates(e.COORDS_BY_USER,[t.X(c,!0),t.Y(c,!0)],!1),u=d.usrCoords,g=isNaN(u[1]+u[2]),g?m=c:(f,f=c),++p}while(p<30&&Math.abs(f-m)>r.eps);return c},_getCuspPos:function(t,e,i){var r=[t.X(e,!0),t.Y(e,!0)],s=[t.X(i,!0),t.Y(i,!0)],n=function(e){var i=[t.X(e,!0),t.Y(e,!0)];return-(Math.sqrt((r[0]-i[0])*(r[0]-i[0])+(r[1]-i[1])*(r[1]-i[1]))+Math.sqrt((s[0]-i[0])*(s[0]-i[0])+(s[1]-i[1])*(s[1]-i[1])))};return o.fminbr(n,[e,i],t)},_getJumpPos:function(t,e,i){var s=function(e){var i=r.eps*r.eps,s=[t.X(e,!0),t.Y(e,!0)],o=[t.X(e+i,!0),t.Y(e+i,!0)];return-Math.abs((o[1]-s[1])/(o[0]-s[0]))};return o.fminbr(s,[e,i],t)},_getLimits:function(t,e){var i,r,o,n,a,h=2/(t.maxX()-t.minX());return i=s.limit(e,-h,t.X),r=i[0],"infinite"===i[1]&&(r=Math.sign(r)*(1/0)),i=s.limit(e,-h,t.Y),n=i[0],"infinite"===i[1]&&(n=Math.sign(n)*(1/0)),i=s.limit(e,h,t.X),o=i[0],"infinite"===i[1]&&(o=Math.sign(o)*(1/0)),i=s.limit(e,h,t.Y),a=i[0],"infinite"===i[1]&&(a=Math.sign(a)*(1/0)),{left_x:r,left_y:n,right_x:o,right_y:a,t:e}},_getLimes:function(t,e,i,r,s,o,n,a,h){var l;return"border"===a?l=this._getBorderPos(t,e,i,r,s,o,n):"cusp"===a?l=this._getCuspPos(t,e,o):"jump"===a&&(l=this._getJumpPos(t,e,o)),this._getLimits(t,l)},_plotNonRecursive:function(t,e,i,r,s,o){var n,a,h,l,c,d,u,p,f,m,g,b=null,v=!1,y="",C=[],_=0;for(p=t.board.origin.scrCoords,C[_++]=[e,i,r,s,o,1/0];_>0;){if(g=C[--_],e=g[0],i=g[1],r=g[2],s=g[3],f=g[4],m=g[5],v=!1,y="",b=null,t.points.length>65536)return;if(f<this.nanLevel){if(this._isUndefined(t,e,i,r,s))continue;if(this._isOutside(e,i,r,s,t.board))continue}n=.5*(i+s),d=t.X(n,!0),u=t.Y(n,!0),a=[1,p[1]+d*t.board.unitX,p[2]-u*t.board.unitY],h=this._triangleDists(e,r,a),l=isNaN(e[1]+e[2]),c=isNaN(r[1]+r[2]),l&&!c||!l&&c?y="border":h[0]>.66*m||h[0]<this.cusp_threshold*(h[1]+h[2])||h[1]>5*h[2]||h[2]>5*h[1]?y="cusp":(h[2]>this.jump_threshold*h[0]||h[1]>this.jump_threshold*h[0]||h[0]===1/0||h[1]===1/0||h[2]===1/0)&&(y="jump"),v=""===y&&f<this.smoothLevel&&h[3]<this.smooth_threshold,f<this.testLevel&&!v&&(""===y?v=!0:b=this._getLimes(t,i,e,n,a,s,r,y,f)),null!==b?(a=[1,NaN,NaN],this._insertPoint(t,a,n,f,b)):f<=0||v?this._insertPoint(t,a,n,f,null):(C[_++]=[a,n,r,s,f-1,h[0]],C[_++]=[e,i,a,n,f-1,h[0]])}return this},updateParametricCurve:function(t,r,s){var o,n,a,h,c,d,u,p,f=!1,m=new i(e.COORDS_BY_USER,[0,0],t.board,!1),g=new i(e.COORDS_BY_USER,[0,0],t.board,!1);return c=t.board.updateQuality===t.board.BOARD_QUALITY_LOW?l.evaluate(t.visProp.recursiondepthlow)||14:l.evaluate(t.visProp.recursiondepthhigh)||17,this.smoothLevel=7,this.nanLevel=c-4,this.testLevel=4,this.cusp_threshold=.5,this.jump_threshold=.99,this.smooth_threshold=2,t.points=[],"x"===t.xterm?(u=t.board.getBoundingBox(),d=.3*(u[2]-u[0]),o=Math.max(r,u[0]-d),n=Math.min(s,u[2]+d)):(o=r,n=s),m.setCoordinates(e.COORDS_BY_USER,[t.X(o,f),t.Y(o,f)],!1),f=!0,g.setCoordinates(e.COORDS_BY_USER,[t.X(n,f),t.Y(n,f)],!1),p=this._findStartPoint(t,m.scrCoords,o,g.scrCoords,n),m.setCoordinates(e.COORDS_BY_SCREEN,p[0],!1),o=p[1],p=this._findStartPoint(t,g.scrCoords,n,m.scrCoords,o),g.setCoordinates(e.COORDS_BY_SCREEN,p[0],!1),n=p[1],this._visibleArea=[o,n],a=m.copy("scrCoords"),h=g.copy("scrCoords"),m._t=o,t.points.push(m),this._lastScrCrds=m.copy("scrCoords"),this._lastUsrCrds=m.copy("usrCoords"),this._plotNonRecursive(t,a,o,h,n,c),g._t=n,t.points.push(g),t.numberPoints=t.points.length,t},_criticalInterval:function(t,e,i){var r,s,o,a,h,l,c,d=!1,u=!1,p=!1,f=0,m=[],g=[],b=[];for(c=n.abs(t),a=n.median(c),a<1e-7?(a=1e-7,u=!0):a*=this.criticalThreshold,r=0;r<e;r++)c[r]>a?(b.push({i:r,v:t[r],group:f}),d||(d=!0)):d&&(b.length>0&&m.push(b.slice(0)),b=[],d=!1,f++);for(d&&b.length>1&&m.push(b.slice(0)),u&&0===m.length&&(p=!0),s=0;s<m.length;s++)if(g[s]="point",!((o=m[s].length)<64)){for(l=0,h=Math.sign(m[s][0].v),r=1;r<o;r++)Math.sign(m[s][r].v)!==h&&(l++,h=Math.sign(m[s][r].v));6*l>o&&(g[s]="interval")}return{smooth:p,groups:m,types:g}},Component:function(){this.left_isNaN=!1,this.right_isNaN=!1,this.left_t=null,this.right_t=null,this.t_values=[],this.x_values=[],this.y_values=[],this.len=0},findComponents:function(t,e,i,r){var s,o,n,a,h,l,c=[],d=0,u=0,p=0,f=!1,m=!1;for(n=(i-e)/r,c[d]=new this.Component,l=c[d],s=0,o=e;s<=r;s++,o+=n)a=t.X(o,m),h=t.Y(o,m),isNaN(a)||isNaN(h)?++p>1&&f&&(l.right_isNaN=!0,l.right_t=o-n,l.len=u,f=!1,d++,c[d]=new this.Component,l=c[d],p=0):(f||(f=!0,u=0,p>0&&(l.left_t=o-n,l.left_isNaN=!0)),p=0,l.t_values[u]=o,l.x_values[u]=a,l.y_values[u]=h,u++),0===s&&(m=!0);return f?l.len=u:c.pop(),c},getPointType:function(t,e,i,r,s,o,n){var a=s[0],h=o[0],l=r.length,c={idx:e,t:i,x:a[e],y:h[e],type:"other"};return e<5?(c.type="borderleft",c.idx=0,c.t=r[0],c.x=a[0],c.y=h[0],c):e>n-6?(c.type="borderright",c.idx=l-1,c.t=r[l-1],c.x=a[l-1],c.y=h[l-1],c):c},newtonApprox:function(t,e,i,r,s){var o,n=0;for(o=r;o>0;o--)n=(n+s[o][t])*(e-(o-1)*i)/o;return n+s[0][t]},thiele:function(t,e,i,r,s){var o,n=0;for(o=s;o>1;o--)n=(t-i[r+o])/(e[o][r+1]-e[o-2][r+1]+n);return e[0][r+1]+(t-i[r+1])/(e[1][r+1]+n)},differenceMethodExperiments:function(t,e){var i,r,s,o,n,a,h,l,c,d,u,p=t.t_values,f=t.x_values,m=t.y_values,g=[],b=[],v=[],y=[],C=[],_=[],P=[],E=[],x=0,S=[];for(n=p[1]-p[0],C.push([]),_.push([]),P.push([]),E.push([]),s=m.length,i=0;i<s;i++)C[0][i]=f[i],_[0][i]=m[i],P[0][i]=f[i],E[0][i]=m[i];for(C.push([]),_.push([]),P.push([]),E.push([]),a=n,s=m.length-1,i=0;i<s;i++)g[i]=f[i+1]-f[i],b[i]=m[i+1]-m[i],v[i]=g[i],y[i]=b[i],C[1][i]=g[i],_[1][i]=b[i],P[1][i]=a/g[i],E[1][i]=a/b[i];for(s--,o=Math.min(8,m.length-1),r=1;r<o;r++){for(C.push([]),_.push([]),P.push([]),E.push([]),a*=n,i=0;i<s;i++)g[i]=g[i+1]-g[i],b[i]=b[i+1]-b[i],C[r+1][i]=g[i],_[r+1][i]=b[i],P[r+1][i]=a/(P[r][i+1]-P[r][i])+P[r-1][i+1],E[r+1][i]=a/(E[r][i+1]-E[r][i])+E[r-1][i+1];if(!1===(u=this._criticalPoints(b,s,r))){console.log("Polynomial of degree",r),u=[];break}if(u.length>0&&++x>1&&r%2==0)break;s--}for(i=0;i<u.length;i++){for(l=-1/0,c=0;c<u[i].length;c++)(d=Math.abs(u[i][c].v))>l&&(l=d,h=c);h=Math.floor(u[i][h].i+r/2),S.push(this.getPointType(e,h,p,f,m,v,y,s+1))}return[S,C,_,P,E]},getCenterOfCriticalInterval:function(t,e,i){var r,s,o,n,a,h=0,l=0,c=i[1]-i[0],d=[];for(r=-1/0,d=[],s=0;s<t.length;s++)n=Math.abs(t[s].v),n>r?(d=[s],r=n,o=s):r===n&&d.push(s);if(d.length>0&&(a=d.reduce(function(t,e){return t+e},0)/d.length,o=Math.floor(a),a+=t[0].i),r<1/0){for(s=0;s<t.length;s++)h+=Math.abs(t[s].v)*t[s].i,l+=Math.abs(t[s].v);a=h/l}return a+=e/2,[t[o].i+e/2,a,i[Math.floor(a)]+c*(a-Math.floor(a))]},differenceMethod:function(t,e){var i,r,s,o,n,a,h,l,c,d,u=t.t_values,p=t.x_values,f=t.y_values,m=[],g=[],b=0,v=-1,y=-1,C=[],_=[];for(s=f.length,m.push(new Float64Array(p)),g.push(new Float64Array(f)),s--,o=Math.min(12,s),r=0;r<o&&(m.push(new Float64Array(s)),g.push(new Float64Array(s)),m[r+1]=m[r].map(function(t,e,i){return i[e+1]-t}),g[r+1]=g[r].map(function(t,e,i){return i[e+1]-t}),l=this._criticalInterval(g[r+1],s,r),!0===l.smooth&&(y=r,C=[]),h=this._criticalInterval(m[r+1],s,r),-1===v&&!0===h.smooth&&(v=r),!(y>=0));r++){if(l.groups.length>0&&++b>2&&(r+1)%2==0){C=l.groups,d=l.types;break}s--}for(i=0;i<C.length;i++)"interval"!==d[i]&&(a=this.getCenterOfCriticalInterval(C[i],r+1,u),n=l[0],n=Math.floor(a[1]),c=a[2],_.push(this.getPointType(e,n,c,u,m,g,s+1)));return[_,m,g,v,y]},_insertPoint_v4:function(t,r,s,o){var n,a=null;t.points.length>0&&(a=t.points[t.points.length-1].scrCoords),n=new i(e.COORDS_BY_USER,r,t.board),null!==a&&Math.abs(n.scrCoords[1]-a[1])<.8&&Math.abs(n.scrCoords[2]-a[2])<.8||(n._t=s,t.points.push(n))},getInterval:function(e,i,r){var s,o;return h.disable(),s=h.Interval(i,r),e.board.mathLib=h,e.board.mathLibJXG=h,e.X(s,!0),o=e.Y(s,!0),e.board.mathLib=Math,e.board.mathLibJXG=t.Math,o},sign:function(t){return t<0?-1:t>0?1:0},handleBorder:function(t,e,i,r,s){var o,n,a,h,c,d,u,p,f,m,g,b,v=i.idx;for(b=e.t_values[1]-e.t_values[0],"borderleft"===i.type?(o=e.left_isNaN?e.left_t:i.t-b,n=o,a=n+b):"borderright"===i.type?(o=e.right_isNaN?e.right_t:i.t+b,a=o,n=a-b):console.log("No bordercase!!!"),m=this.findComponents(t,n,a,32),"borderleft"===i.type&&(n=m[0].left_t,a=m[0].t_values[0],b=m[0].t_values[1]-m[0].t_values[0],n=null===n?a-b:n,o=n,h=this.getInterval(t,n,a),l.isObject(h)&&(u=h.lo,p=h.hi,c=t.X(o,!0),d=s[1][v]<0?p:u,this._insertPoint_v4(t,[1,c,d],o))),g=m[0].t_values.length,f=0;f<g;f++)o=m[0].t_values[f],c=m[0].x_values[f],d=m[0].y_values[f],this._insertPoint_v4(t,[1,c,d],o);"borderright"===i.type&&(n=m[0].t_values[g-1],a=m[0].right_t,b=m[0].t_values[1]-m[0].t_values[0],a=null===a?n+b:a,o=a,h=this.getInterval(t,n,a),l.isObject(h)&&(u=h.lo,p=h.hi,c=t.X(o,!0),d=s[1][v]>0?p:u,this._insertPoint_v4(t,[1,c,d],o)))},_recurse_v4:function(t,e,i,r,s){var o,n,a,h,l,c,d,u,p,f,m,g,b;for(n=e.t_values[i.idx-2],a=e.t_values[i.idx+2],l=this.findComponents(t,n,a,64),d=0;d<l.length;d++){for(c=l[d],h=this.differenceMethod(c,t),u=h[0],f=h[1],m=h[2],g=0,p=0;p<=u.length;p++){for(b=p===u.length?c.len:u[p].idx,o=g;o<b;o++)isNaN(c.x_values[o])||isNaN(c.y_values[o])||this._insertPoint_v4(t,[1,c.x_values[o],c.y_values[o]],c.t_values[o]);p<u.length&&(this.handleSingularity(t,c,u[p],f,m),g=u[p].idx+1)}b=c.len,d<l.length-1&&this._insertPoint_v4(t,[1,NaN,NaN],c.right_t)}return this},handleSingularity:function(t,e,i,r,s){var o,n,a,h,c,d,u,p,f,m=i.idx;o=i.t,n=e.t_values[m-5],a=e.t_values[m+5],h=this.getInterval(t,n,a),l.isObject(h)?(d=h.lo,u=h.hi):s[0][m-1]<s[0][m+1]?(d=s[0][m-1],u=s[0][m+1]):(d=s[0][m+1],u=s[0][m-1]),c=t.X(o,!0),p=(s[0][m-3]-s[0][m-5])/(e.t_values[m-3]-e.t_values[m-5]),f=(s[0][m+3]-s[0][m+5])/(e.t_values[m+3]-e.t_values[m+5]),p<-100?(this._insertPoint_v4(t,[1,c,d],o,!0),f<=100&&this._insertPoint_v4(t,[1,NaN,NaN],o)):p>100?(this._insertPoint_v4(t,[1,c,u],o),f>=-100&&this._insertPoint_v4(t,[1,NaN,NaN],o)):Math.abs(s[0][m-1]-s[0][m+1])*t.board.unitY>=2?this._insertPoint_v4(t,[1,NaN,NaN],o):(d===-1/0&&(this._insertPoint_v4(t,[1,c,d],o,!0),this._insertPoint_v4(t,[1,NaN,NaN],o)),u===1/0&&(this._insertPoint_v4(t,[1,NaN,NaN],o),this._insertPoint_v4(t,[1,c,u],o,!0))),f<-100?this._insertPoint_v4(t,[1,c,u],o):f>100&&this._insertPoint_v4(t,[1,c,d],o)},steps:1021,criticalThreshold:1e3,plot_v4:function(t,e,i,r){var s,n,a,h,c,d,u,p,f,m,g,b,v,y,C,_,P,E=(i-e)/r,x=function(e){return t.Y(e,!0)},S=function(e){return-t.Y(e,!0)},w=.5*E;for(a=this.findComponents(t,e,i,r),h=0;h<a.length;h++){for(c=a[h],f=this.differenceMethod(c,t),d=f[0],m=f[1],g=f[2],f[3],f[4],0!==d.length&&"borderleft"===d[0].type||d.unshift({idx:0,t:c.t_values[0],x:c.x_values[0],y:c.y_values[0],type:"borderleft"}),"borderright"!==d[d.length-1].type&&(n=c.t_values.length,d.push({idx:n-1,t:c.t_values[n-1],x:c.x_values[n-1],y:c.y_values[n-1],type:"borderright"})),p=0,u=0;u<=d.length;u++){for(n=u===d.length?c.len:d[u].idx-1,C=0,_=0,s=p;s<n-2;s++)this._insertPoint_v4(t,[1,c.x_values[s],c.y_values[s]],c.t_values[s]),Math.max(0,s-2),s>=p+3&&s<n-3&&g.length>3&&Math.abs(g[2][s])>.2*Math.abs(g[0][s])?(b=c.t_values[s],w=.25*E,P=this.getInterval(t,b,b+E),l.isObject(P)?g[2][s]>0?this._insertPoint_v4(t,[1,b+w,P.lo],b+w):this._insertPoint_v4(t,[1,b+E-w,P.hi],b+E-w):(v=o.fminbr(x,[b,b+E]),y=o.fminbr(S,[b,b+E]),v<y?(this._insertPoint_v4(t,[1,t.X(v,!0),t.Y(v,!0)],v),this._insertPoint_v4(t,[1,t.X(y,!0),t.Y(y,!0)],y)):(this._insertPoint_v4(t,[1,t.X(y,!0),t.Y(y,!0)],y),this._insertPoint_v4(t,[1,t.X(v,!0),t.Y(v,!0)],v))),_++):C++;u<d.length&&(s=d[u].idx,"borderleft"===d[u].type||"borderright"===d[u].type?this.handleBorder(t,c,d[u],m,g):this._recurse_v4(t,c,d[u],m,g),p=d[u].idx+1+1)}n=c.len,h<a.length-1&&this._insertPoint_v4(t,[1,NaN,NaN],c.right_t)}},updateParametricCurve_v4:function(t,e,i){var r,s,o,n;"x"===t.xterm?(n=t.board.getBoundingBox(),o=.3*(n[2]-n[0]),r=Math.max(e,n[0]-o),s=Math.min(i,n[2]+o)):(r=e,s=i),t.points=[],this.plot_v4(t,r,s,this.steps),t.numberPoints=t.points.length}},r.Plot}),define("math/metapost",["utils/type","math/math"],function(t,e){"use strict";return e.Metapost={MP_ENDPOINT:0,MP_EXPLICIT:1,MP_GIVEN:2,MP_CURL:3,MP_OPEN:4,MP_END_CYCLE:5,UNITY:1,FRACTION_ONE:1,FRACTION_THREE:3,ONE_EIGHTY_DEG:Math.PI,THREE_SIXTY_DEG:2*Math.PI,EPS_SQ:1e-5*1e-5,make_choices:function(t){var e,i,r,s,o,n,a,h,l,c,d,u,p,f,m;a=t[0];do{if(!a)break;n=a.next,a.rtype>this.MP_EXPLICIT&&(a.x-n.x)*(a.x-n.x)+(a.y-n.y)*(a.y-n.y)<this.EPS_SQ&&(a.rtype=this.MP_EXPLICIT,a.ltype===this.MP_OPEN&&(a.ltype=this.MP_CURL,a.set_left_curl(this.UNITY)),n.ltype=this.MP_EXPLICIT,n.rtype===this.MP_OPEN&&(n.rtype=this.MP_CURL,n.set_right_curl(this.UNITY)),a.rx=a.x,n.lx=a.x,a.ry=a.y,n.ly=a.y),a=n}while(a!==t[0]);for(i=t[0];;){if(i.ltype!==this.MP_OPEN||i.rtype!==this.MP_OPEN)break;if((i=i.next)===t[0]){i.ltype=this.MP_END_CYCLE;break}}for(a=i;;){if(!a)break;if(n=a.next,a.rtype>=this.MP_GIVEN){for(;n.ltype===this.MP_OPEN&&n.rtype===this.MP_OPEN;)n=n.next;for(r=0,h=a,o=t.length,u=[],p=[],f=[],m=[null];;)if(c=h.next,u.push(c.x-h.x),p.push(c.y-h.y),f.push(this.mp_pyth_add(u[r],p[r])),r>0&&(d=p[r-1]/f[r-1], -l=u[r-1]/f[r-1],m.push(Math.atan2(p[r]*l-u[r]*d,u[r]*l+p[r]*d))),r++,h=c,h===n&&(o=r),r>=o&&h.ltype!==this.MP_END_CYCLE)break;r===o?m.push(0):m.push(m[1]),n.ltype===this.MP_OPEN&&(s=n.rx-n.x,e=n.ry-n.y,s*s+e*e<this.EPS_SQ?(n.ltype=this.MP_CURL,n.set_left_curl(this.UNITY)):(n.ltype=this.MP_GIVEN,n.set_left_given(Math.atan2(e,s)))),a.rtype===this.MP_OPEN&&a.ltype===this.MP_EXPLICIT&&(s=a.x-a.lx,e=a.y-a.ly,s*s+e*e<this.EPS_SQ?(a.rtype=this.MP_CURL,a.set_right_curl(this.UNITY)):(a.rtype=this.MP_GIVEN,a.set_right_given(Math.atan2(e,s)))),this.mp_solve_choices(a,n,o,u,p,f,m)}else a.rtype===this.MP_ENDPOINT&&(a.rx=a.x,a.ry=a.y,n.lx=n.x,n.ly=n.y);if((a=n)===i)break}},mp_solve_choices:function(t,e,i,r,s,o,n){var a,h,l,c,d,u,p,f,m,g,b,v,y,C,_,P,E,x,S,w,O,T,N,M,A,R;for(d=o.length+1,g=new Array(d),m=new Array(d),l=new Array(d),_=new Array(d),A=0;A<d;A++)_[A]=l[A]=m[A]=g[A]=0;for(p=0,f=t,v=0;;){if(y=f.next,0===p)if(f.rtype===this.MP_GIVEN){if(y.ltype===this.MP_GIVEN)return a=Math.atan2(s[0],r[0]),S=this.mp_n_sin_cos(t.right_given()-a),w=S[0],O=S[1],T=this.mp_n_sin_cos(e.left_given()-a),N=T[0],M=T[1],void this.mp_set_controls(t,e,r[0],s[0],O,w,-M,N);l[0]=f.right_given()-Math.atan2(s[0],r[0]),l[0]=this.reduce_angle(l[0]),g[0]=0,m[0]=0}else if(f.rtype===this.MP_CURL){if(y.ltype===this.MP_CURL)return t.rtype=this.MP_EXPLICIT,e.ltype=this.MP_EXPLICIT,b=Math.abs(e.left_tension()),P=Math.abs(t.right_tension()),C=this.UNITY/(3*P),t.rx=t.x+r[0]*C,t.ry=t.y+s[0]*C,C=this.UNITY/(3*b),e.lx=e.x-r[0]*C,void(e.ly=e.y-s[0]*C);x=f.right_curl(),b=Math.abs(y.left_tension()),P=Math.abs(f.right_tension()),g[0]=this.mp_curl_ratio(x,P,b),l[0]=-n[1]*g[0],m[0]=0}else f.rtype===this.MP_OPEN&&(g[0]=0,l[0]=0,m[0]=this.FRACTION_ONE);else if(f.ltype===this.MP_END_CYCLE||f.ltype===this.MP_OPEN){if(a=this.UNITY/(3*Math.abs(v.right_tension())-this.UNITY),E=o[p]*(this.FRACTION_THREE-this.UNITY/Math.abs(v.right_tension())),c=this.UNITY/(3*Math.abs(y.left_tension())-this.UNITY),u=o[p-1]*(this.FRACTION_THREE-this.UNITY/Math.abs(y.left_tension())),x=this.FRACTION_ONE-g[p-1]*a,E*=x,b=Math.abs(f.left_tension()),P=Math.abs(f.right_tension()),b<P?E*=Math.pow(b/P,2):b>P&&(u*=Math.pow(P/b,2)),C=u/(u+E),g[p]=C*c,h=-n[p+1]*g[p],v.rtype===this.MP_CURL?(m[p]=0,l[p]=h-n[1]*(this.FRACTION_ONE-C)):(C=(this.FRACTION_ONE-C)/x,h-=n[p]*C,C*=a,l[p]=h-l[p-1]*C,m[p]=-m[p-1]*C),f.ltype===this.MP_END_CYCLE){for(a=0,c=this.FRACTION_ONE;;)if(p-=1,0===p&&(p=i),a=l[p]-a*g[p],c=m[p]-c*g[p],p===i)break;for(a/=this.FRACTION_ONE-c,_[i]=a,l[0]=a,R=1;R<i;R++)l[R]=l[R]+a*m[R];break}}else{if(f.ltype===this.MP_CURL){x=f.left_curl(),b=Math.abs(f.left_tension()),P=Math.abs(v.right_tension()),C=this.mp_curl_ratio(x,b,P),_[i]=-l[i-1]*C/(this.FRACTION_ONE-C*g[i-1]);break}if(f.ltype===this.MP_GIVEN){_[i]=f.left_given()-Math.atan2(s[i-1],r[i-1]),_[i]=this.reduce_angle(_[i]);break}}v=f,f=y,p+=1}for(p=i-1;p>-1;p--)_[p]=l[p]-_[p+1]*g[p];for(f=t,p=0;;)if(y=f.next,S=this.mp_n_sin_cos(_[p]),w=S[0],O=S[1],T=this.mp_n_sin_cos(-n[p+1]-_[p+1]),N=T[0],M=T[1],this.mp_set_controls(f,y,r[p],s[p],O,w,M,N),p++,f=y,p===i)break},mp_n_sin_cos:function(t){return[Math.cos(t),Math.sin(t)]},mp_set_controls:function(t,e,i,r,s,o,n,a){var h,l,c,d,u;c=Math.abs(e.left_tension()),h=Math.abs(t.right_tension()),u=this.mp_velocity(s,o,n,a,h),l=this.mp_velocity(n,a,s,o,c),(t.right_tension()<0||e.left_tension()<0)&&(s>=0&&n>=0||s<=0&&n<=0)&&(d=Math.abs(s)*a+Math.abs(n)*o)>0&&(d*=1.00024414062,t.right_tension()<0&&this.mp_ab_vs_cd(Math.abs(n),this.FRACTION_ONE,u,d)<0&&(u=Math.abs(n)/d),e.left_tension()<0&&this.mp_ab_vs_cd(Math.abs(s),this.FRACTION_ONE,l,d)<0&&(l=Math.abs(s)/d)),t.rx=t.x+(i*o-r*s)*u,t.ry=t.y+(r*o+i*s)*u,e.lx=e.x-(i*a+r*n)*l,e.ly=e.y-(r*a-i*n)*l,t.rtype=this.MP_EXPLICIT,e.ltype=this.MP_EXPLICIT},mp_pyth_add:function(t,e){return Math.sqrt(t*t+e*e)},mp_curl_ratio:function(t,e,i){var r=1/e,s=1/i;return Math.min(4,((3-r)*r*r*t+s*s*s)/(r*r*r*t+(3-s)*s*s))},mp_ab_vs_cd:function(t,e,i,r){return t*e==i*r?0:t*e>i*r?1:-1},mp_velocity:function(t,e,i,r,s){return Math.min(4,(2+Math.sqrt(2)*(t-i/16)*(i-t/16)*(e-r))/(1.5*s*(2+(Math.sqrt(5)-1)*e+(3-Math.sqrt(5))*r)))},reduce_angle:function(t){return Math.abs(t)>this.ONE_EIGHTY_DEG&&(t>0?t-=this.THREE_SIXTY_DEG:t+=this.THREE_SIXTY_DEG),t},makeknots:function(t,e,i){var r,s,o=[];for(e=e||1,s=t.length,r=0;r<s;r++)o.push({x:t[r][0],y:t[r][1],ltype:this.MP_OPEN,rtype:this.MP_OPEN,ly:e,ry:e,lx:e,rx:e,left_curl:function(){return this.lx||0},right_curl:function(){return this.rx||0},left_tension:function(){return this.ly||(this.ly=1),this.ly},right_tension:function(){return this.ry||(this.ry=1),this.ry},set_right_curl:function(t){this.rx=t||0},set_left_curl:function(t){this.lx=t||0}});for(s=o.length,r=0;r<s;r++)o[r].next=o[r+1]||o[r],o[r].set_right_given=o[r].set_right_curl,o[r].set_left_given=o[r].set_left_curl,o[r].right_given=o[r].right_curl,o[r].left_given=o[r].left_curl;return o[s-1].next=o[0],i||(o[s-1].rtype=this.MP_ENDPOINT,o[s-1].ltype=this.MP_CURL,o[0].rtype=this.MP_CURL),o},curve:function(e,i){var r,s,o,n,a=[],h=[];i=i||{tension:1,direction:{},curl:{},isClosed:!1},r=this.makeknots(e,t.evaluate(i.tension),i.isClosed),s=r.length;for(o in i.direction)i.direction.hasOwnProperty(o)&&(n=t.evaluate(i.direction[o]),t.isArray(n)?(!1!==n[0]&&(r[o].lx=n[0]*Math.PI/180,r[o].ltype=this.MP_GIVEN),!1!==n[1]&&(r[o].rx=n[1]*Math.PI/180,r[o].rtype=this.MP_GIVEN)):(r[o].lx=n*Math.PI/180,r[o].rx=n*Math.PI/180,r[o].ltype=r[o].rtype=this.MP_GIVEN));for(o in i.curl)i.curl.hasOwnProperty(o)&&(n=t.evaluate(i.curl[o]),0===parseInt(o,10)?(r[o].rtype=this.MP_CURL,r[o].set_right_curl(n)):parseInt(o,10)===s-1&&(r[o].ltype=this.MP_CURL,r[o].set_left_curl(n)));for(this.make_choices(r),o=0;o<s-1;o++)a.push(r[o].x),a.push(r[o].rx),a.push(r[o+1].lx),h.push(r[o].y),h.push(r[o].ry),h.push(r[o+1].ly);return a.push(r[s-1].x),h.push(r[s-1].y),i.isClosed&&(a.push(r[s-1].rx),h.push(r[s-1].ry),a.push(r[0].lx),h.push(r[0].ly),a.push(r[0].x),h.push(r[0].y)),[a,h]}},e.Metapost}),define("utils/zip",["jxg"],function(t){"use strict";var e=[0,128,64,192,32,160,96,224,16,144,80,208,48,176,112,240,8,136,72,200,40,168,104,232,24,152,88,216,56,184,120,248,4,132,68,196,36,164,100,228,20,148,84,212,52,180,116,244,12,140,76,204,44,172,108,236,28,156,92,220,60,188,124,252,2,130,66,194,34,162,98,226,18,146,82,210,50,178,114,242,10,138,74,202,42,170,106,234,26,154,90,218,58,186,122,250,6,134,70,198,38,166,102,230,22,150,86,214,54,182,118,246,14,142,78,206,46,174,110,238,30,158,94,222,62,190,126,254,1,129,65,193,33,161,97,225,17,145,81,209,49,177,113,241,9,137,73,201,41,169,105,233,25,153,89,217,57,185,121,249,5,133,69,197,37,165,101,229,21,149,85,213,53,181,117,245,13,141,77,205,45,173,109,237,29,157,93,221,61,189,125,253,3,131,67,195,35,163,99,227,19,147,83,211,51,179,115,243,11,139,75,203,43,171,107,235,27,155,91,219,59,187,123,251,7,135,71,199,39,167,103,231,23,151,87,215,55,183,119,247,15,143,79,207,47,175,111,239,31,159,95,223,63,191,127,255],i=[3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,0,0],r=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,99,99],s=[1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577],o=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13],n=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],a=256;return t.Util=t.Util||{},t.Util.Unzip=function(h){function l(){return Y+=8,B<k?h[B++]:-1}function c(){I=1}function d(){var t;try{return Y++,t=1&I,I>>=1,0===I&&(I=l(),t=1&I,I=I>>1|128),t}catch(t){throw t}}function u(t){var i=0,r=t;try{for(;r--;)i=i<<1|d();t&&(i=e[i]>>8-t)}catch(t){throw t}return i}function p(){R=0}function f(t){x++,A[R++]=t,T.push(String.fromCharCode(t)),32768===R&&(R=0)}function m(){this.b0=0,this.b1=0,this.jump=null,this.jumppos=-1}function g(){for(;;){if(U[F]>=O)return-1;if(w[U[F]]===F)return U[F]++;U[F]++}}function b(){var t,e=G[X];if(17===F)return-1;if(X++,F++,(t=g())>=0)e.b0=t;else if(e.b0=32768,b())return-1;if((t=g())>=0)e.b1=t,e.jump=null;else if(e.b1=32768,e.jump=G[X],e.jumppos=X,b())return-1;return F--,0}function v(t,e,i,r){var s;for(G=t,X=0,w=i,O=e,s=0;s<17;s++)U[s]=0;return F=0,b()?-1:0}function y(t){for(var e,i,r=0,s=t[r];;)if(d()){if(!(32768&s.b1))return s.b1;for(s=s.jump,e=t.length,i=0;i<e;i++)if(t[i]===s){r=i;break}}else{if(!(32768&s.b0))return s.b0;r++,s=t[r]}}function C(){var a,h,g,b,C,_,P,E,x,S,w,O,T,N,M,L,k;do{if(a=d(),0===(g=u(2)))for(c(),S=l(),S|=l()<<8,O=l(),O|=l()<<8,65535&(S^~O)&&t.debug("BlockLen checksum mismatch\n");S--;)h=l(),f(h);else if(1===g)for(;;)if(C=e[u(7)]>>1,C>23?(C=C<<1|d(),C>199?(C-=128,C=C<<1|d()):(C-=48)>143&&(C+=136)):C+=256,C<256)f(C);else{if(256===C)break;for(C-=257,x=u(r[C])+i[C],C=e[u(5)]>>3,o[C]>8?(w=u(8),w|=u(o[C]-8)<<8):w=u(o[C]),w+=s[C],C=0;C<x;C++)h=A[R-w&32767],f(h)}else if(2===g){for(P=new Array(320),N=257+u(5),M=1+u(5),L=4+u(4),C=0;C<19;C++)P[C]=0;for(C=0;C<L;C++)P[n[C]]=u(3);for(x=j.length,b=0;b<x;b++)j[b]=new m;if(v(j,19,P,0))return p(),1;for(T=N+M,b=0,k=-1;b<T;)if(k++,(C=y(j))<16)P[b++]=C;else if(16===C){if(C=3+u(2),b+C>T)return p(),1;for(_=b?P[b-1]:0;C--;)P[b++]=_}else{if(C=17===C?3+u(3):11+u(7),b+C>T)return p(),1;for(;C--;)P[b++]=0}for(x=D.length,b=0;b<x;b++)D[b]=new m;if(v(D,N,P,0))return p(),1;for(x=D.length,b=0;b<x;b++)j[b]=new m;for(E=[],b=N;b<P.length;b++)E[b-N]=P[b];if(v(j,M,E,0))return p(),1;for(;;)if((C=y(D))>=256){if(0===(C-=256))break;for(C-=1,x=u(r[C])+i[C],C=y(j),o[C]>8?(w=u(8),w|=u(o[C]-8)<<8):w=u(o[C]),w+=s[C];x--;)h=A[R-w&32767],f(h)}else f(C)}}while(!a);return p(),c(),0}function _(){var t,e,i,r,s,o,n,h,c=[];try{if(T=[],L=!1,c[0]=l(),c[1]=l(),120===c[0]&&218===c[1]&&(C(),M[N]=[T.join(""),"geonext.gxt"],N++),31===c[0]&&139===c[1]&&(P(),M[N]=[T.join(""),"file"],N++),80===c[0]&&75===c[1]){if(L=!0,c[2]=l(),c[3]=l(),3===c[2]&&4===c[3]){for(c[0]=l(),c[1]=l(),E=l(),E|=l()<<8,h=l(),h|=l()<<8,l(),l(),l(),l(),n=l(),n|=l()<<8,n|=l()<<16,n|=l()<<24,o=l(),o|=l()<<8,o|=l()<<16,o|=l()<<24,s=l(),s|=l()<<8,s|=l()<<16,s|=l()<<24,r=l(),r|=l()<<8,i=l(),i|=l()<<8,t=0,J=[];r--;)e=l(),"/"===e|":"===e?t=0:t<a-1&&(J[t++]=String.fromCharCode(e));for(S||(S=J),t=0;t<i;)e=l(),t++;if(x=0,8===h&&(C(),M[N]=new Array(2),M[N][0]=T.join(""),M[N][1]=J.join(""),N++),P())return!1}return!0}}catch(t){throw t}return!1}function P(){var t,e,i,r,s,o=[];if(8&E&&(o[0]=l(),o[1]=l(),o[2]=l(),o[3]=l(),80===o[0]&&75===o[1]&&7===o[2]&&8===o[3]?(t=l(),t|=l()<<8,t|=l()<<16,t|=l()<<24):t=o[0]|o[1]<<8|o[2]<<16|o[3]<<24,e=l(),e|=l()<<8,e|=l()<<16,e|=l()<<24,i=l(),i|=l()<<8,i|=l()<<16,i|=l()<<24),L&&_())return!1;if(o[0]=l(),8!==o[0])return!0;if(E=l(),l(),l(),l(),l(),l(),l(),4&E)for(o[0]=l(),o[2]=l(),F=o[0]+256*o[1],r=0;r<F;r++)l();if(8&E)for(r=0,J=[],s=l();s;)"7"!==s&&":"!==s||(r=0),r<a-1&&(J[r++]=s),s=l();if(16&E)for(s=l();s;)s=l();return 2&E&&(l(),l()),C(),t=l(),t|=l()<<8,t|=l()<<16,t|=l()<<24,i=l(),i|=l()<<8,i|=l()<<16,i|=l()<<24,L&&_(),!1}var E,x,S,w,O,T=[],N=0,M=[],A=new Array(32768),R=0,L=!1,k=h.length,B=0,I=1,Y=0,D=new Array(288),j=new Array(32),X=0,G=null,F=(new Array(64),new Array(64),0),U=new Array(17),J=[];U[0]=0,t.Util.Unzip.prototype.unzipFile=function(t){var e;for(this.unzip(),e=0;e<M.length;e++)if(M[e][1]===t)return M[e][0];return""},t.Util.Unzip.prototype.unzip=function(){return _(),M}},t.Util}),define("utils/encoding",["jxg"],function(t){"use strict";var e=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3,11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,0,12,24,36,60,96,84,12,12,12,48,72,12,12,12,12,12,12,12,12,12,12,12,12,12,0,12,12,12,12,12,0,12,0,12,12,12,24,12,12,12,12,12,24,12,24,12,12,12,12,12,12,12,12,12,24,12,12,12,12,12,24,12,12,12,12,12,12,12,24,12,12,12,12,12,12,12,12,12,36,12,36,12,12,12,36,12,12,12,12,12,36,12,36,12,12,12,36,12,12,12,12,12,12,12,12,12,12];return t.Util=t.Util||{},t.Util.UTF8={encode:function(t){var e,i,r="",s=t.length;if(t=t.replace(/\r\n/g,"\n"),"function"==typeof unescape&&"function"==typeof encodeURIComponent)return unescape(encodeURIComponent(t));for(e=0;e<s;e++)i=t.charCodeAt(e),i<128?r+=String.fromCharCode(i):i>127&&i<2048?(r+=String.fromCharCode(i>>6|192),r+=String.fromCharCode(63&i|128)):(r+=String.fromCharCode(i>>12|224),r+=String.fromCharCode(i>>6&63|128),r+=String.fromCharCode(63&i|128));return r},decode:function(t){var i,r,s,o=0,n=0,a=0,h=[],l=t.length,c=[];for(i=0;i<l;i++)r=t.charCodeAt(i),s=e[r],n=0!==a?63&r|n<<6:255>>s&r,0===(a=e[256+a+s])&&(n>65535?h.push(55232+(n>>10),56320+(1023&n)):h.push(n),++o%1e4==0&&(c.push(String.fromCharCode.apply(null,h)),h=[]));return c.push(String.fromCharCode.apply(null,h)),c.join("")},asciiCharCodeAt:function(t,e){var i=t.charCodeAt(e);if(i>255)switch(i){case 8364:i=128;break;case 8218:i=130;break;case 402:i=131;break;case 8222:i=132;break;case 8230:i=133;break;case 8224:i=134;break;case 8225:i=135;break;case 710:i=136;break;case 8240:i=137;break;case 352:i=138;break;case 8249:i=139;break;case 338:i=140;break;case 381:i=142;break;case 8216:i=145;break;case 8217:i=146;break;case 8220:i=147;break;case 8221:i=148;break;case 8226:i=149;break;case 8211:i=150;break;case 8212:i=151;break;case 732:i=152;break;case 8482:i=153;break;case 353:i=154;break;case 8250:i=155;break;case 339:i=156;break;case 382:i=158;break;case 376:i=159}return i}},t.Util.UTF8}),define("utils/base64",["jxg","utils/encoding"],function(t,e){"use strict";function i(t,e){return 255&t.charCodeAt(e)}function r(t,e){return s.indexOf(t.charAt(e))}var s="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";return t.Util=t.Util||{},t.Util.Base64={encode:function(t){var r,o,n,a,h,l=[];for(h=e.encode(t),n=h.length,a=n%3,r=0;r<n-a;r+=3)o=i(h,r)<<16|i(h,r+1)<<8|i(h,r+2),l.push(s.charAt(o>>18),s.charAt(o>>12&63),s.charAt(o>>6&63),s.charAt(63&o));switch(a){case 1:o=i(h,n-1),l.push(s.charAt(o>>2),s.charAt(o<<4&63),"=","=");break;case 2:o=i(h,n-2)<<8|i(h,n-1),l.push(s.charAt(o>>10),s.charAt(o>>4&63),s.charAt(o<<2&63),"=")}return l.join("")},decode:function(t,i){var s,o,n,a,h,l,c=[],d=[];if(s=t.replace(/[^A-Za-z0-9\+\/=]/g,""),(n=s.length)%4!=0)throw new Error("JSXGraph/utils/base64: Can't decode string (invalid input length).");for("="===s.charAt(n-1)&&(a=1,"="===s.charAt(n-2)&&(a=2),n-=4),o=0;o<n;o+=4)h=r(s,o)<<18|r(s,o+1)<<12|r(s,o+2)<<6|r(s,o+3),d.push(h>>16,h>>8&255,255&h),o%1e4==0&&(c.push(String.fromCharCode.apply(null,d)),d=[]);switch(a){case 1:h=r(s,n)<<12|r(s,n+1)<<6|r(s,n+2),d.push(h>>10,h>>2&255);break;case 2:h=r(s,o)<<6|r(s,o+1),d.push(h>>4)}return c.push(String.fromCharCode.apply(null,d)),l=c.join(""),i&&(l=e.decode(l)),l},decodeAsArray:function(t){var e,i=this.decode(t),r=[],s=i.length;for(e=0;e<s;e++)r[e]=i.charCodeAt(e);return r}},t.Util.Base64}),define("server/server",["jxg","utils/zip","utils/base64","utils/type"],function(t,e,i,r){"use strict";return t.Server={modules:{},runningCalls:{},handleError:function(e){t.debug("error occured, server says: "+e.message)},callServer:function(s,o,n,a){var h,l,c,d,u,p,f;a=a||!1,d="";for(f in n)n.hasOwnProperty(f)&&(d+="&"+escape(f)+"="+escape(n[f]));p=r.toJSON(n);do{u=s+Math.floor(4096*Math.random())}while(r.exists(this.runningCalls[u]));return this.runningCalls[u]={action:s},r.exists(n.module)&&(this.runningCalls[u].module=n.module),h=t.serverBase+"JXGServer.py",l="action="+escape(s)+"&id="+u+"&dataJSON="+escape(i.encode(p)),this.cbp=function(t){var s,n,a,h,l,c,d,u;if(s=new e.Unzip(i.decodeAsArray(t)).unzip(),r.isArray(s)&&s.length>0&&(s=s[0][0]),r.exists(s))if(n=window.JSON&&window.JSON.parse?window.JSON.parse(s):new Function("return "+s)(),"error"===n.type)this.handleError(n);else if("response"===n.type){for(c=n.id,d=0;d<n.fields.length;d++)a=n.fields[d],h=a.namespace+("object"==typeof new Function("return "+a.namespace)()?".":".prototype.")+a.name+" = "+a.value,new Function(h)();for(d=0;d<n.handler.length;d++){for(a=n.handler[d],l=[],u=0;u<a.parameters.length;u++)l[u]='"'+a.parameters[u]+'": '+a.parameters[u];h="if(typeof JXG.Server.modules."+this.runningCalls[c].module+' == "undefined")JXG.Server.modules.'+this.runningCalls[c].module+" = {};",h+="JXG.Server.modules."+this.runningCalls[c].module+"."+a.name+"_cb = "+a.callback+";",h+="JXG.Server.modules."+this.runningCalls[c].module+"."+a.name+" = function ("+a.parameters.join(",")+', __JXGSERVER_CB__, __JXGSERVER_SYNC) {if(typeof __JXGSERVER_CB__ == "undefined") __JXGSERVER_CB__ = JXG.Server.modules.'+this.runningCalls[c].module+"."+a.name+"_cb;var __JXGSERVER_PAR__ = {"+l.join(",")+', "module": "'+this.runningCalls[c].module+'", "handler": "'+a.name+'" };JXG.Server.callServer("exec", __JXGSERVER_CB__, __JXGSERVER_PAR__, __JXGSERVER_SYNC);};',new Function(h)()}delete this.runningCalls[c],o(n.data)}},this.cb=t.bind(this.cbp,this),window.XMLHttpRequest?(c=new XMLHttpRequest,c.overrideMimeType("text/plain; charset=iso-8859-1")):c=new ActiveXObject("Microsoft.XMLHTTP"),!(!c||(c.open("POST",h,!a),c.setRequestHeader("Content-type","application/x-www-form-urlencoded"),a||(c.onreadystatechange=function(t){return function(){return 4===c.readyState&&200===c.status&&(t(c.responseText),!0)}}(this.cb)),c.send(l),!a))&&(this.cb(c.responseText),!0)},loadModule_cb:function(e){var i;for(i=0;i<e.length;i++)t.debug(e[i].name+": "+e[i].value)},loadModule:function(e){return t.Server.callServer("load",t.Server.loadModule_cb,{module:e},!0)}},t.Server.load=t.Server.loadModule,t.Server}),define("math/symbolic",["base/constants","base/coords","math/math","math/geometry","server/server","utils/type"],function(t,e,i,r,s,o){"use strict";return i.Symbolic={generateSymbolicCoordinatesPartial:function(t,e,i,r){var s,n,a,h=e.ancestors,l=0,c=function(t){return"underscore"===r?i+"_{"+t+"}":"brace"===r?i+"["+t+"]":i+t};t.listOfFreePoints=[],t.listOfDependantPoints=[];for(n in h)if(h.hasOwnProperty(n)&&(s=0,o.isPoint(h[n]))){for(a in h[n].ancestors)h[n].ancestors.hasOwnProperty(a)&&s++;0===s?(h[n].symbolic.x=h[n].coords.usrCoords[1],h[n].symbolic.y=h[n].coords.usrCoords[2],t.listOfFreePoints.push(h[n])):(l+=1,h[n].symbolic.x=c(l),l+=1,h[n].symbolic.y=c(l),t.listOfDependantPoints.push(h[n]))}return o.isPoint(e)&&(e.symbolic.x="x",e.symbolic.y="y"),l},clearSymbolicCoordinates:function(t){var e=function(t){var e,i=t&&t.length||0;for(e=0;e<i;e++)o.isPoint(t[e])&&(t[e].symbolic.x="",t[e].symbolic.y="")};e(t.listOfFreePoints),e(t.listOfDependantPoints),delete t.listOfFreePoints,delete t.listOfDependantPoints},generatePolynomials:function(t,e,i){var r,s,n,a,h=e.ancestors,l=[],c=[];i&&this.generateSymbolicCoordinatesPartial(t,e,"u","brace"),h[e.id]=e;for(r in h)if(h.hasOwnProperty(r)&&(a=0,l=[],o.isPoint(h[r]))){for(s in h[r].ancestors)h[r].ancestors.hasOwnProperty(s)&&a++;if(a>0)for(l=h[r].generatePolynomial(),n=0;n<l.length;n++)c.push(l[n])}return i&&this.clearSymbolicCoordinates(t),c},geometricLocusByGroebnerBase:function(n,a){var h,l,c,d,u,p,f,m,g,b,v,y,C,_=n.options.locus,P={},E=this.generateSymbolicCoordinatesPartial(n,a,"u","brace"),x=new e(t.COORDS_BY_USR,[0,0],n),S=new e(t.COORDS_BY_USR,[n.canvasWidth,n.canvasHeight],n),w=1,O=0,T=0,N=0;if(void 0===s.modules.geoloci&&s.loadModule("geoloci"),void 0===s.modules.geoloci)throw new Error("JSXGraph: Unable to load JXG.Server module 'geoloci.py'.");if(f=x.usrCoords[1],m=S.usrCoords[1],g=S.usrCoords[2],b=x.usrCoords[2],_.translateToOrigin&&n.listOfFreePoints.length>0){for(d=void 0!==_.toOrigin&&null!==_.toOrigin&&o.isInArray(n.listOfFreePoints,_.toOrigin.id)?_.toOrigin:n.listOfFreePoints[0],O=d.symbolic.x,T=d.symbolic.y,p=0;p<n.listOfFreePoints.length;p++)n.listOfFreePoints[p].symbolic.x-=O,n.listOfFreePoints[p].symbolic.y-=T;if(f-=O,m-=O,g-=T,b-=T,_.translateTo10&&n.listOfFreePoints.length>1){for(u=void 0!==_.to10&&null!==_.to10&&_.to10.id!==_.toOrigin.id&&o.isInArray(n.listOfFreePoints,_.to10.id)?_.to10:n.listOfFreePoints[0].id===d.id?n.listOfFreePoints[1]:n.listOfFreePoints[0],N=r.rad([1,0],[0,0],[u.symbolic.x,u.symbolic.y]),v=Math.cos(-N),y=Math.sin(-N),p=0;p<n.listOfFreePoints.length;p++)C=n.listOfFreePoints[p].symbolic.x,n.listOfFreePoints[p].symbolic.x=v*n.listOfFreePoints[p].symbolic.x-y*n.listOfFreePoints[p].symbolic.y,n.listOfFreePoints[p].symbolic.y=y*C+v*n.listOfFreePoints[p].symbolic.y;if(u.symbolic.y=0,C=f,f=v*f-y*g,g=y*C+v*g,C=m,m=v*m-y*b,b=y*C+v*b,_.stretch&&Math.abs(u.symbolic.x)>i.eps){for(w=u.symbolic.x,p=0;p<n.listOfFreePoints.length;p++)n.listOfFreePoints[p].symbolic.x/=w,n.listOfFreePoints[p].symbolic.y/=w;for(p=0;p<n.objectsList.length;p++)n.objectsList[p].elementClass===t.OBJECT_CLASS_CIRCLE&&"pointRadius"===n.objectsList[p].method&&(P[p]=n.objectsList[p].radius,n.objectsList[p].radius/=w);f/=w,m/=w,g/=w,b/=w,u.symbolic.x=1}}for(p=0;p<n.listOfFreePoints.length;p++)C=n.listOfFreePoints[p].symbolic.x,Math.abs(C)<i.eps&&(n.listOfFreePoints[p].symbolic.x=0),Math.abs(C-Math.round(C))<i.eps&&(n.listOfFreePoints[p].symbolic.x=Math.round(C)),C=n.listOfFreePoints[p].symbolic.y,Math.abs(C)<i.eps&&(n.listOfFreePoints[p].symbolic.y=0),Math.abs(C-Math.round(C))<i.eps&&(n.listOfFreePoints[p].symbolic.y=Math.round(C))}h=this.generatePolynomials(n,a),l=h.join(","),this.cbp=function(t){c=t},this.cb=o.bind(this.cbp,this),s.modules.geoloci.lociCoCoA(f,m,g,b,E,l,w,N,O,T,this.cb,!0),this.clearSymbolicCoordinates(n);for(p in P)P.hasOwnProperty(p)&&(n.objects[p].radius=P[p]);return c}},i.Symbolic}),define("math/clip",["jxg","base/constants","base/coords","math/math","math/geometry","utils/type"],function(t,e,i,r,s,o){"use strict";return r.Clip={makeDoublyLinkedList:function(t){var e,i=t.length;if(i>0){for(e=0;e<i;e++)t[e]._next=t[(e+1)%i],t[e]._prev=t[(i+e-1)%i];t[i-1]._end=!0}return t},det:function(t,e,i){return(t[1]-i[1])*(e[2]-i[2])-(e[1]-i[1])*(t[2]-i[2])},windingNumber:function(t,e){var i,s,o,n,a,h=0,l=e.length,c=t[1],d=t[2];if(0===l)return 0;if(isNaN(c)||isNaN(d))return 1;if(e[0].coords.usrCoords[1]===c&&e[0].coords.usrCoords[2]===d)return 1;for(a=0;a<l;a++)if(i=e[a].coords.usrCoords,s=e[(a+1)%l].coords.usrCoords,!(0===i[0]||0===s[0]||isNaN(i[1])||isNaN(s[1])||isNaN(i[2])||isNaN(s[2]))){if(s[2]===d){if(s[1]===c)return 1;if(i[2]===d&&s[1]>c==i[1]<c)return 0}if(i[2]<d!=s[2]<d)if(n=2*(s[2]>i[2]?1:0)-1,i[1]>=c)if(s[1]>c)h+=n;else{if(0===(o=this.det(i,s,t)))return 0;o>0==s[2]>i[2]&&(h+=n)}else s[1]>c&&(o=this.det(i,s,t))>0+r.eps==s[2]>i[2]&&(h+=n)}return h},Vertex:function(t,i,r,s,o,n){this.pos=i,this.intersection=!0,this.coords=t,this.elementClass=e.OBJECT_CLASS_POINT,this.data={alpha:r,path:s,pathname:o,done:!1,type:n,revtype:n,link:null,idx:0},this.neighbour=null,this.entry_exit=!1},_addToList:function(t,i,s){var o=t.length,n=r.eps*r.eps;o>0&&Math.abs(t[o-1].coords.usrCoords[0]-i.usrCoords[0])<n&&Math.abs(t[o-1].coords.usrCoords[1]-i.usrCoords[1])<n&&Math.abs(t[o-1].coords.usrCoords[2]-i.usrCoords[2])<n||t.push({pos:s,intersection:!1,coords:i,elementClass:e.OBJECT_CLASS_POINT})},sortIntersections:function(t){var e,i,r,s,o,n,a=[],h=t.length;for(e=0;e<h;e++)if(t[e].sort(function(t,e){return t.data.alpha>e.data.alpha?1:-1}),t[e].length>0){for(o=t[e].length-1,r=t[e][0],s=r.data.path[r.pos],n=s._next,e===h-1&&(s._end=!1),0===r.data.alpha&&"T"===r.data.type?(s.intersection=!0,s.data=r.data,s.neighbour=r.neighbour,s.neighbour.neighbour=s,s.entry_exit=!1,t[e][0]=s):(r._prev=s,r._prev._next=r),i=1;i<=o;i++)r=t[e][i],r._prev=t[e][i-1],r._prev._next=r;r=t[e][o],r._next=n,r._next._prev=r,e===h-1&&(r._end=!0),a=a.concat(t[e])}return a},_inbetween:function(t,e,i){var s,o=r.eps*r.eps,n=i[1]-e[1],a=i[2]-e[2],h=t[1]-e[1],l=t[2]-e[2];return 0===n&&0===a&&0===h&&0===l||(s=Math.abs(h)<o&&Math.abs(n)<o?l/a:h/n,Math.abs(s)<o&&(s=0),s)},_print_array:function(t){var e;for(e=0;e<t.length;e++)console.log(e,t[e].coords.usrCoords,t[e].data.type)},_print_list:function(t){for(var e,i=0;i<100&&(e=t.data?t.data.alpha:"-",console.log("\t",t.coords.usrCoords,"\n\t\tis:",t.intersection,"end:",t._end,e,"\n\t\t-:",t._prev.coords.usrCoords,"\n\t\t+:",t._next.coords.usrCoords,"\n\t\tn:",t.intersection?t.neighbour.coords.usrCoords:"-"),!t._end);)t=t._next,i++},_noOverlap:function(t,e,i,s){var o,n,a,h,l,c=r.eps*r.eps,d=!1;for(o=0;o<3;o++)if(n=Math.min(t[o],e[o]),a=Math.max(t[o],e[o]),h=Math.min(i[o],s[o]),l=Math.max(i[o],s[o]),a<h-c||n>l+c){d=!0;break}return d},findIntersections:function(t,o,n){var a,h,l,c,d,u,p,f,m,g,b,v=[],y=r.eps,C=t.length,_=o.length,P=[],E=[],x=[],S=[];for(h=0;h<_;h++)S.push([]);for(a=0;a<C;a++)for(x.push([]),c=t[a].coords.usrCoords,d=t[(a+1)%C].coords.usrCoords,h=0;h<_;h++)if(u=o[h].coords.usrCoords,p=o[(h+1)%_].coords.usrCoords,!this._noOverlap(c,d,u,p)&&(v=s.meetSegmentSegment(c,d,u,p),v[1]>-y&&v[1]<1-y&&v[2]>-y&&v[2]<1-y||v[1]===1/0&&v[2]===1/0&&r.norm(v[0],3)<y)){if(l=new i(e.COORDS_BY_USER,v[0],n),m="X",Math.abs(v[1])<y||Math.abs(v[2])<y)m="T",Math.abs(v[1])<y&&(v[1]=0),Math.abs(v[2])<y&&(v[2]=0),l=0===v[1]?new i(e.COORDS_BY_USER,c,n):new i(e.COORDS_BY_USER,u,n);else if(v[1]===1/0&&v[2]===1/0&&r.norm(v[0],3)<y){f=this._inbetween(c,u,p),f>=0&&f<1&&(m="T",l=new i(e.COORDS_BY_USER,c,n),v[1]=0,v[2]=f,g=new this.Vertex(l,a,v[1],t,"S",m),b=new this.Vertex(l,h,v[2],o,"C",m),g.neighbour=b,b.neighbour=g,x[a].push(g),S[h].push(b)),f=this._inbetween(u,c,d),s.distance(c,u,3)>r.eps&&f>=0&&f<1&&(m="T",l=new i(e.COORDS_BY_USER,u,n),v[1]=f,v[2]=0,g=new this.Vertex(l,a,v[1],t,"S",m),b=new this.Vertex(l,h,v[2],o,"C",m),g.neighbour=b,b.neighbour=g,x[a].push(g),S[h].push(b));continue}g=new this.Vertex(l,a,v[1],t,"S",m),b=new this.Vertex(l,h,v[2],o,"C",m),g.neighbour=b,b.neighbour=g,x[a].push(g),S[h].push(b)}for(P=this.sortIntersections(x),a=0;a<P.length;a++)P[a].data.idx=a,P[a].neighbour.data.idx=a;return E=this.sortIntersections(S),[P,E]},_getPosition:function(t,e,i,r){var s=this.det(t,e,i),o=this.det(t,i,r);return this.det(e,i,r)>=0?s>0&&o>0?"left":"right":s<0&&o<0?"right":"left"},_classifyDegenerateIntersections:function(t){var e,i,r,s,o,n,a;for(a=0;;){if(t.intersection&&"T"===t.data.type&&(e=t._next.coords.usrCoords,i=t._prev.coords.usrCoords,o=t.neighbour,s=t.neighbour._prev.coords.usrCoords,r=t.neighbour._next.coords.usrCoords,t._next.intersection&&t._next.neighbour===o._next?t._prev.intersection&&t._prev.neighbour===o._prev?t.delayedStatus=["on","on"]:(n=this._getPosition(s,i,t.coords.usrCoords,e),t.delayedStatus="right"===n?["left","on"]:["right","on"]):t._next.intersection&&t._next.neighbour===o._prev&&(t._prev.intersection&&t._prev.neighbour===o._next?t.delayedStatus=["on","on"]:(n=this._getPosition(r,i,t.coords.usrCoords,e),t.delayedStatus="right"===n?["left","on"]:["right","on"])),t._prev.intersection&&t._prev.neighbour===o._prev?t._next.intersection&&t._next.neighbour===o._next||(n=this._getPosition(r,i,t.coords.usrCoords,e),t.delayedStatus="right"===n?["on","left"]:["on","right"]):t._prev.intersection&&t._prev.neighbour===o._next&&(t._next.intersection&&t._next.neighbour===o._prev||(n=this._getPosition(s,i,t.coords.usrCoords,e),t.delayedStatus="right"===n?["on","left"]:["on","right"])),t._next.intersection&&(t._next.neighbour===o._prev||t._next.neighbour===o._next)||t._prev.intersection&&(t._prev.neighbour===o._prev||t._prev.neighbour===o._next)||(n=this._getPosition(s,i,t.coords.usrCoords,e),n!==this._getPosition(r,i,t.coords.usrCoords,e)?(t.data.type="X",t.data.revtype="X"):(t.data.type="B",t.data.revtype="B")),a++),t._end||a>1e3)break;t=t._next}},_handleIntersectionChains:function(t){for(var e,i=0,r="Null",s=!1,o=!1;;){if(!0===t.intersection&&("T"===t.data.type&&("on"!==t.delayedStatus[0]&&"on"===t.delayedStatus[1]?(s=!0,e=t,r=t.delayedStatus[0]):"on"===t.delayedStatus[0]&&"on"===t.delayedStatus[1]?(t.data.type="B",t.data.revtype="B"):"on"===t.delayedStatus[0]&&"on"!==t.delayedStatus[1]&&s&&(s=!1,r===t.delayedStatus[1]?(t.data.type="B",t.data.revtype="B",e.data.type="B",e.data.revtype="B"):(t.data.type="X",t.data.revtype="B",e.data.type="B",e.data.revtype="X"),e.data.link=t,t.data.link=e)),i++),t._end&&(o=!0),o&&!s)break;if(i>1e3){console.log("Intersection chain: SAFETY EXIT!!!!");break}t=t._next}},_handleFullyDegenerateCase:function(t,s,o){var n,a,h,l,c,d,u,p,f,m,g,b,v,y,C=[t,s];for(h=0;h<2;h++){for(n=C[h],g=n.length,f=0,y=!0;f<g;f++)if(!n[f].intersection){y=!1;break}if(y)for(a=C[(h+1)%2],b=a.length,f=0;f<g;f++){for(d=n[f].coords.usrCoords,u=n[(f+1)%g].coords.usrCoords,l=[.5*(d[0]+u[0]),.5*(d[1]+u[1]),.5*(d[2]+u[2])],m=0,v=!1;m<b;m++)if(Math.abs(this.det(a[m].coords.usrCoords,a[(m+1)%b].coords.usrCoords,l))<r.eps){v=!0;break}if(!v){c=new i(e.COORDS_BY_USER,l,o),p={pos:f,intersection:!1,coords:c,elementClass:e.OBJECT_CLASS_POINT},n[f]._next=p,p._prev=n[f],n[(f+1)%g]._prev=p,p._next=n[(f+1)%g],n[f]._end&&(n[f]._end=!1,p._end=!0);break}}}},markEntryExit:function(t,e){var i,r,s,o;for(this._classifyDegenerateIntersections(t[0]),this._handleIntersectionChains(t[0]),r=t[0];r.intersection&&!r._end;)r=r._next;for(i=0===this.windingNumber(r.coords.usrCoords,e)?"entry":"exit",s=r,o=0;;){if(!0===r.intersection&&"X"===r.data.type&&(r.entry_exit=i,i="entry"===i?"exit":"entry",null===r.data.link||r.data.link.entry_exit||(r.data.link.entry_exit=r.entry_exit)),!0===r.intersection&&"X"!==r.data.type&&(r.entry_exit||null===r.data.link||(r.entry_exit=r.data.link.entry_exit)),(r=r._next)===s||o>1e3)break;o++}for(s=r,o=0;;){if((r=r._next)===s||o>1e3)break;o++}},_isCrossing:function(t,e){return e=e||!1,t.intersection&&"X"===(e?t.data.revtype:t.data.type)},tracing:function(t,e,i){var r,s,o,n,a=0,h=0,l=[];for(n="difference"===i||"union"===i;h<e.length&&a<1e4;)if(s=e[h],!s.data.done&&this._isCrossing(s,n)){l.length>0&&l.push([NaN,NaN]),o=s.data.idx,r=t;do{if(l.push(s),s.data.done=!0,"intersection"===i&&"entry"===s.entry_exit||"union"===i&&"exit"===s.entry_exit||"difference"===i&&r===t==("exit"===s.entry_exit)){s=s._next;do{a++,l.push(s),this._isCrossing(s,n)||(s=s._next)}while(!this._isCrossing(s,n)&&a<1e4)}else{s=s._prev;do{a++,l.push(s),this._isCrossing(s,!0)||(s=s._prev)}while(!this._isCrossing(s,!0)&&a<1e4)}if(s.data.done=!0,!s.neighbour)return console.log("BREAK!!!!!!!!!!!!!!!!!",a),[[0],[0]];if(s=s.neighbour,s.data.done){l.push(s);break}r=s.data.path}while(("S"!==s.data.pathname||s.data.idx!==o)&&a<1e4);h++}else h++;return this._getCoordsArrays(l,!1)},isEmptyCase:function(t,e,i,r,s){return"intersection"===i&&(0===t.length||0===e.length)||("union"===i&&(0===t.length||0===e.length)||"difference"===i&&(0===t.length||0===e.length))},_getCoordsArrays:function(t,e){var i,r=[],s=[],o=t.length;for(i=0;i<o;i++)t[i].coords?(r.push(t[i].coords.usrCoords[1]),s.push(t[i].coords.usrCoords[2])):(r.push(t[i][0]),s.push(t[i][1]));return e&&o>0&&(t[0].coords?(r.push(t[0].coords.usrCoords[1]),s.push(t[0].coords.usrCoords[2])):(r.push(t[0][0]),s.push(t[0][1]))),[r,s]},handleEmptyIntersection:function(t,e,i){var r,o,n=!1,a=[];if(0===t.length)return a="union"===i?e:[],this._getCoordsArrays(a,!0);if(0===e.length)return a="intersection"===i?[]:t,this._getCoordsArrays(a,!0);if("union"===i)return a=a.concat(t),a.push(t[0]),a.push([NaN,NaN]),a=a.concat(e),a.push(e[0]),this._getCoordsArrays(a,!1);if(t.length>0)for(r=t[0];r.intersection&&(r=r._next,!r._end););if(e.length>0)for(o=e[0];o.intersection&&(o=o._next,!o._end););return 0===this.windingNumber(r.coords.usrCoords,e)?0!==this.windingNumber(o.coords.usrCoords,t)?("difference"===i&&(a=a.concat(t),a.push(t[0]),s.signedPolygon(t)*s.signedPolygon(e)>0&&a.reverse(),a.push([NaN,NaN])),a=a.concat(e),a.push(e[0]),n=!1):"difference"===i&&(a=a.concat(t),n=!0):"intersection"===i&&(a=a.concat(t),n=!0),this._getCoordsArrays(a,n)},_countCrossingIntersections:function(t){var e,i=t.length,r=0;for(e=0;e<i;e++)"X"===t[e].data.type&&r++;return r},greinerHormann:function(t,n,a,h){var l,c,d,u,p=[],f=[],m=[],g=[],b=[],v=[] -;if(t.elementClass===e.OBJECT_CLASS_CURVE&&o.exists(t.points))for(u=t.points.length,l=0;l<u;l++)this._addToList(p,t.points[l],l);else if(t.type===e.OBJECT_TYPE_POLYGON)for(l=0;l<t.vertices.length;l++)this._addToList(p,t.vertices[l].coords,l);else if(t.elementClass===e.OBJECT_CLASS_CIRCLE)for(c=t.Radius(),d=2*Math.PI/359,l=0;l<=359;l++)this._addToList(p,new i(e.COORDS_BY_USER,[t.center.coords.usrCoords[0],t.center.coords.usrCoords[1]+Math.cos(l*d)*c,t.center.coords.usrCoords[2]+Math.sin(l*d)*c],h),l);else if(o.isArray(t))for(u=t.length,l=0;l<u;l++)o.exists(t[l].coords)?this._addToList(p,t[l].coords,l):o.isArray(t[l])?this._addToList(p,new i(e.COORDS_BY_USER,t[l],h),l):o.exists(t[l].usrCoords)&&this._addToList(p,t[l],l);if(u=p.length,u>0&&s.distance(p[0].coords.usrCoords,p[u-1].coords.usrCoords,3)<r.eps&&p.pop(),n.elementClass===e.OBJECT_CLASS_CURVE&&o.exists(n.points))for(u=n.points.length,l=0;l<u;l++)this._addToList(f,n.points[l],l);else if(n.type===e.OBJECT_TYPE_POLYGON)for(l=0;l<n.vertices.length;l++)this._addToList(f,n.vertices[l].coords,l);else if(n.elementClass===e.OBJECT_CLASS_CIRCLE)for(c=n.Radius(),d=2*Math.PI/359,l=0;l<=359;l++)this._addToList(f,new i(e.COORDS_BY_USER,[n.center.coords.usrCoords[0],n.center.coords.usrCoords[1]+Math.cos(l*d)*c,n.center.coords.usrCoords[2]+Math.sin(l*d)*c],h),l);else if(o.isArray(n))for(u=n.length,l=0;l<u;l++)o.exists(n[l].coords)?this._addToList(f,n[l].coords,l):o.isArray(n[l])?this._addToList(f,new i(e.COORDS_BY_USER,n[l],h),l):o.exists(n[l].usrCoords)&&this._addToList(f,n[l],l);return u=f.length,u>0&&s.distance(f[0].coords.usrCoords,f[u-1].coords.usrCoords,3)<r.eps*r.eps&&f.pop(),this.isEmptyCase(p,f,a,b,v)?[b,v]:(this.makeDoublyLinkedList(p),this.makeDoublyLinkedList(f),g=this.findIntersections(p,f,h),m=g[0],this._handleFullyDegenerateCase(p,f,h),this.markEntryExit(p,f),this.markEntryExit(f,p),0===this._countCrossingIntersections(m)?this.handleEmptyIntersection(p,f,a):this.tracing(p,m,a))},union:function(t,e,i){return this.greinerHormann(t,e,"union",i)},intersection:function(t,e,i){return this.greinerHormann(t,e,"intersection",i)},difference:function(t,e,i){return this.greinerHormann(t,e,"difference",i)}},t.extend(r.Clip,{}),r.Clip}),define("math/poly",["jxg","math/math","utils/type"],function(t,e,i){"use strict";return e.Poly={},e.Poly.Ring=function(t){this.vars=t},t.extend(e.Poly.Ring.prototype,{}),e.Poly.Monomial=function(t,e,r){var s;if(!i.exists(t))throw new Error("JSXGraph error: In JXG.Math.Poly.monomial missing parameter 'ring'.");for(i.isArray(r)||(r=[]),r=r.slice(0,t.vars.length),s=r.length;s<t.vars.length;s++)r.push(0);this.ring=t,this.coefficient=e||0,this.exponents=i.deepCopy(r)},t.extend(e.Poly.Monomial.prototype,{copy:function(){return new e.Poly.Monomial(this.ring,this.coefficient,this.exponents)},print:function(){var t,e=[];for(t=0;t<this.ring.vars.length;t++)e.push(this.ring.vars[t]+"^"+this.exponents[t]);return this.coefficient+"*"+e.join("*")}}),e.Poly.Polynomial=function(t,e){var r;if(!i.exists(t))throw new Error("JSXGraph error: In JXG.Math.Poly.polynomial missing parameter 'ring'.");r=i.exists(e)&&i.isString(e)?void 0:[],this.ring=t,this.monomials=r},t.extend(e.Poly.Polynomial.prototype,{findSignature:function(t){var e;for(e=0;e<this.monomials.length;e++)if(i.cmpArrays(this.monomials[e].exponents,t))return e;return-1},addSubMonomial:function(t,e){var i;i=this.findSignature(t.exponents),i>-1?this.monomials[i].coefficient+=e*t.coefficient:(t.coefficient*=e,this.monomials.push(t))},add:function(t){var e;if(!i.exists(t)||t.ring!==this.ring)throw new Error("JSXGraph error: In JXG.Math.Poly.polynomial.add either summand is undefined or rings don't match.");if(i.isArray(t.exponents))this.addSubMonomial(t,1);else for(e=0;e<t.monomials.length;e++)this.addSubMonomial(t.monomials[e],1)},sub:function(t){var e;if(!i.exists(t)||t.ring!==this.ring)throw new Error("JSXGraph error: In JXG.Math.Poly.polynomial.sub either summand is undefined or rings don't match.");if(i.isArray(t.exponents))this.addSubMonomial(t,-1);else for(e=0;e<t.monomials.length;e++)this.addSubMonomial(t.monomials[e],-1)},copy:function(){var t,i;for(i=new e.Poly.Polynomial(this.ring),t=0;t<this.monomials.length;t++)i.monomials.push(this.monomials[t].copy());return i},print:function(){var t,e=[];for(t=0;t<this.monomials.length;t++)e.push("("+this.monomials[t].print()+")");return e.join("+")}}),e.Poly}),define("math/complex",["jxg","utils/type"],function(t,e){"use strict";return t.Complex=function(t,e){this.isComplex=!0,t&&t.isComplex&&(e=t.imaginary,t=t.real),this.real=t||0,this.imaginary=e||0,this.absval=0,this.angle=0},t.extend(t.Complex.prototype,{toString:function(){return this.real+" + "+this.imaginary+"i"},add:function(t){return e.isNumber(t)?this.real+=t:(this.real+=t.real,this.imaginary+=t.imaginary),this},sub:function(t){return e.isNumber(t)?this.real-=t:(this.real-=t.real,this.imaginary-=t.imaginary),this},mult:function(t){var i,r;return e.isNumber(t)?(this.real*=t,this.imaginary*=t):(i=this.real,r=this.imaginary,this.real=i*t.real-r*t.imaginary,this.imaginary=i*t.imaginary+r*t.real),this},div:function(t){var i,r,s;if(e.isNumber(t)){if(Math.abs(t)<Math.eps)return this.real=1/0,this.imaginary=1/0,this;this.real/=t,this.imaginary/=t}else{if(Math.abs(t.real)<Math.eps&&Math.abs(t.imaginary)<Math.eps)return this.real=1/0,this.imaginary=1/0,this;i=t.real*t.real+t.imaginary*t.imaginary,s=this.real,r=this.imaginary,this.real=(s*t.real+r*t.imaginary)/i,this.imaginary=(r*t.real-s*t.imaginary)/i}return this},conj:function(){return this.imaginary*=-1,this}}),t.C={},t.C.add=function(e,i){var r=new t.Complex(e);return r.add(i),r},t.C.sub=function(e,i){var r=new t.Complex(e);return r.sub(i),r},t.C.mult=function(e,i){var r=new t.Complex(e);return r.mult(i),r},t.C.div=function(e,i){var r=new t.Complex(e);return r.div(i),r},t.C.conj=function(e){var i=new t.Complex(e);return i.conj(),i},t.C.abs=function(e){var i=new t.Complex(e);return i.conj(),i.mult(e),Math.sqrt(i.real)},t.Complex.C=t.C,t.Complex}),define("utils/color",["jxg","utils/type","math/math"],function(t,e,i){"use strict";var r={aliceblue:"f0f8ff",antiquewhite:"faebd7",aqua:"00ffff",aquamarine:"7fffd4",azure:"f0ffff",beige:"f5f5dc",bisque:"ffe4c4",black:"000000",blanchedalmond:"ffebcd",blue:"0000ff",blueviolet:"8a2be2",brown:"a52a2a",burlywood:"deb887",cadetblue:"5f9ea0",chartreuse:"7fff00",chocolate:"d2691e",coral:"ff7f50",cornflowerblue:"6495ed",cornsilk:"fff8dc",crimson:"dc143c",cyan:"00ffff",darkblue:"00008b",darkcyan:"008b8b",darkgoldenrod:"b8860b",darkgray:"a9a9a9",darkgreen:"006400",darkkhaki:"bdb76b",darkmagenta:"8b008b",darkolivegreen:"556b2f",darkorange:"ff8c00",darkorchid:"9932cc",darkred:"8b0000",darksalmon:"e9967a",darkseagreen:"8fbc8f",darkslateblue:"483d8b",darkslategray:"2f4f4f",darkturquoise:"00ced1",darkviolet:"9400d3",deeppink:"ff1493",deepskyblue:"00bfff",dimgray:"696969",dodgerblue:"1e90ff",feldspar:"d19275",firebrick:"b22222",floralwhite:"fffaf0",forestgreen:"228b22",fuchsia:"ff00ff",gainsboro:"dcdcdc",ghostwhite:"f8f8ff",gold:"ffd700",goldenrod:"daa520",gray:"808080",green:"008000",greenyellow:"adff2f",honeydew:"f0fff0",hotpink:"ff69b4",indianred:"cd5c5c",indigo:"4b0082",ivory:"fffff0",khaki:"f0e68c",lavender:"e6e6fa",lavenderblush:"fff0f5",lawngreen:"7cfc00",lemonchiffon:"fffacd",lightblue:"add8e6",lightcoral:"f08080",lightcyan:"e0ffff",lightgoldenrodyellow:"fafad2",lightgrey:"d3d3d3",lightgreen:"90ee90",lightpink:"ffb6c1",lightsalmon:"ffa07a",lightseagreen:"20b2aa",lightskyblue:"87cefa",lightslateblue:"8470ff",lightslategray:"778899",lightsteelblue:"b0c4de",lightyellow:"ffffe0",lime:"00ff00",limegreen:"32cd32",linen:"faf0e6",magenta:"ff00ff",maroon:"800000",mediumaquamarine:"66cdaa",mediumblue:"0000cd",mediumorchid:"ba55d3",mediumpurple:"9370d8",mediumseagreen:"3cb371",mediumslateblue:"7b68ee",mediumspringgreen:"00fa9a",mediumturquoise:"48d1cc",mediumvioletred:"c71585",midnightblue:"191970",mintcream:"f5fffa",mistyrose:"ffe4e1",moccasin:"ffe4b5",navajowhite:"ffdead",navy:"000080",oldlace:"fdf5e6",olive:"808000",olivedrab:"6b8e23",orange:"ffa500",orangered:"ff4500",orchid:"da70d6",palegoldenrod:"eee8aa",palegreen:"98fb98",paleturquoise:"afeeee",palevioletred:"d87093",papayawhip:"ffefd5",peachpuff:"ffdab9",peru:"cd853f",pink:"ffc0cb",plum:"dda0dd",powderblue:"b0e0e6",purple:"800080",red:"ff0000",rosybrown:"bc8f8f",royalblue:"4169e1",saddlebrown:"8b4513",salmon:"fa8072",sandybrown:"f4a460",seagreen:"2e8b57",seashell:"fff5ee",sienna:"a0522d",silver:"c0c0c0",skyblue:"87ceeb",slateblue:"6a5acd",slategray:"708090",snow:"fffafa",springgreen:"00ff7f",steelblue:"4682b4",tan:"d2b48c",teal:"008080",thistle:"d8bfd8",tomato:"ff6347",turquoise:"40e0d0",violet:"ee82ee",violetred:"d02090",wheat:"f5deb3",white:"ffffff",whitesmoke:"f5f5f5",yellow:"ffff00",yellowgreen:"9acd32"},s=[{re:/^\s*rgba\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*([\d\.]{1,3})\s*\)\s*$/,example:["rgba(123, 234, 45, 0.5)","rgba(255,234,245,1.0)"],process:function(t){return[parseInt(t[1],10),parseInt(t[2],10),parseInt(t[3],10)]}},{re:/^\s*rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)\s*$/,example:["rgb(123, 234, 45)","rgb(255,234,245)"],process:function(t){return[parseInt(t[1],10),parseInt(t[2],10),parseInt(t[3],10)]}},{re:/^(\w{2})(\w{2})(\w{2})$/,example:["#00ff00","336699"],process:function(t){return[parseInt(t[1],16),parseInt(t[2],16),parseInt(t[3],16)]}},{re:/^(\w{1})(\w{1})(\w{1})$/,example:["#fb0","f0f"],process:function(t){return[parseInt(t[1]+t[1],16),parseInt(t[2]+t[2],16),parseInt(t[3]+t[3],16)]}}];return t.rgbParser=function(t,i,o){var n,a,h,l,c,d,u,p,f,m,g=t;if(!e.exists(t))return[];if(e.exists(i)&&e.exists(o)&&(g=[t,i,o]),n=g,m=!1,e.isArray(n)){for(d=0;d<3;d++)m=m||/\./.test(g[d].toString());for(d=0;d<3;d++)m=m&&g[d]>=0&&g[d]<=1;return m?[Math.ceil(255*g[0]),Math.ceil(255*g[1]),Math.ceil(255*g[2])]:g}for("string"==typeof g&&(n=g),"#"===n.charAt(0)&&(n=n.substr(1,6)),n=n.replace(/ /g,"").toLowerCase(),n=r[n]||n,d=0;d<s.length;d++)h=s[d].re,l=s[d].process,(c=h.exec(n))&&(a=l(c),u=a[0],p=a[1],f=a[2]);return isNaN(u)||isNaN(p)||isNaN(f)?[]:(u=u<0||isNaN(u)?0:u>255?255:u,p=p<0||isNaN(p)?0:p>255?255:p,f=f<0||isNaN(f)?0:f>255?255:f,[u,p,f])},t.rgb2css=function(e,i,r){var s;return s=t.rgbParser(e,i,r),"rgb("+s[0]+", "+s[1]+", "+s[2]+")"},t.rgb2hex=function(e,i,r){var s,o,n;return s=t.rgbParser(e,i,r),o=s[1],n=s[2],s=s[0],s=s.toString(16),o=o.toString(16),n=n.toString(16),1===s.length&&(s="0"+s),1===o.length&&(o="0"+o),1===n.length&&(n="0"+n),"#"+s+o+n},t.hex2rgb=function(e){return t.deprecated("JXG.hex2rgb()","JXG.rgb2css()"),t.rgb2css(e)},t.hsv2rgb=function(t,e,r){var s,o,n,a,h,l,c,d,u;if(t=(t%360+360)%360,0===e){if(!(isNaN(t)||t<i.eps))return"#ffffff";s=r,o=r,n=r}else switch(l=t>=360?0:t,l/=60,h=Math.floor(l),a=l-h,c=r*(1-e),d=r*(1-e*a),u=r*(1-e*(1-a)),h){case 0:s=r,o=u,n=c;break;case 1:s=d,o=r,n=c;break;case 2:s=c,o=r,n=u;break;case 3:s=c,o=d,n=r;break;case 4:s=u,o=c,n=r;break;case 5:s=r,o=c,n=d}return s=Math.round(255*s).toString(16),s=2===s.length?s:1===s.length?"0"+s:"00",o=Math.round(255*o).toString(16),o=2===o.length?o:1===o.length?"0"+o:"00",n=Math.round(255*n).toString(16),n=2===n.length?n:1===n.length?"0"+n:"00",["#",s,o,n].join("")},t.rgb2hsv=function(e,i,r){var s,o,n,a,h,l,c,d,u,p,f,m,g;return s=t.rgbParser(e,i,r),o=s[1],n=s[2],s=s[0],a=s/255,h=o/255,l=n/255,m=Math.max(s,o,n),g=Math.min(s,o,n),c=m/255,d=g/255,f=c,p=0,f>0&&(p=(f-d)/f),u=1/(c-d),p>0&&(m===s?u*=h-l:u=m===o?2+(l-a)*u:4+(a-h)*u),u*=60,u<0&&(u+=360),m===g&&(u=0),[u,p,f]},t.rgb2LMS=function(e,i,r){var s,o,n,a,h,l,c,d=[[.05059983,.08585369,.0095242],[.01893033,.08925308,.01370054],[.00292202,.00975732,.07145979]];return s=t.rgbParser(e,i,r),o=s[1],n=s[2],s=s[0],s=Math.pow(s,.476190476),o=Math.pow(o,.476190476),n=Math.pow(n,.476190476),a=s*d[0][0]+o*d[0][1]+n*d[0][2],h=s*d[1][0]+o*d[1][1]+n*d[1][2],l=s*d[2][0]+o*d[2][1]+n*d[2][2],c=[a,h,l],c.l=a,c.m=h,c.s=l,c},t.LMS2rgb=function(t,e,i){var r,s,o,n,a=[[30.830854,-29.832659,1.610474],[-6.481468,17.715578,-2.532642],[-.37569,-1.199062,14.273846]],h=function(t){for(var e=127,i=64;i>0;){if(Math.pow(e,.476190476)>t)e-=i;else{if(Math.pow(e+1,.476190476)>t)return e;e+=i}i/=2}return 254===e&&13.994955247<t?255:e};return r=t*a[0][0]+e*a[0][1]+i*a[0][2],s=t*a[1][0]+e*a[1][1]+i*a[1][2],o=t*a[2][0]+e*a[2][1]+i*a[2][2],r=h(r),s=h(s),o=h(o),n=[r,s,o],n.r=r,n.g=s,n.b=o,n},t.rgba2rgbo=function(t){var e;return 9===t.length&&"#"===t.charAt(0)?(e=parseInt(t.substr(7,2).toUpperCase(),16)/255,t=t.substr(0,7)):e=1,[t,e]},t.rgbo2rgba=function(t,e){var i;return"none"===t?t:(i=Math.round(255*e).toString(16),1===i.length&&(i="0"+i),t+i)},t.rgb2bw=function(e){var i,r,s,o="0123456789ABCDEF";return"none"===e?e:(s=t.rgbParser(e),i=Math.floor(.3*s[0]+.59*s[1]+.11*s[2]),r=o.charAt(i>>4&15)+o.charAt(15&i),e="#"+r+r+r)},t.rgb2cb=function(e,i){var r,s,o,n,a,h,l,c,d,u,p,f,m,g="0123456789ABCDEF";if("none"===e)return e;switch(a=t.rgb2LMS(e),s=a[0],o=a[1],n=a[2],i=i.toLowerCase()){case"protanopia":l=-.06150039994295001,c=.08277001656812001,d=-.013200141220000003,u=.05858939668799999,p=-.07934519995360001,f=.013289415272000003,m=.6903216543277437,h=n/o,s=h<m?-(c*o+d*n)/l:-(p*o+f*n)/u;break;case"tritanopia":l=-.00058973116217,c=.007690316482,d=-.01011703519052,u=.025495080838999994,p=-.0422740347,f=.017005316784,m=.8349489908460004,h=o/s,n=h<m?-(l*s+c*o)/d:-(u*s+p*o)/f;break;default:l=-.06150039994295001,c=.08277001656812001,d=-.013200141220000003,u=.05858939668799999,p=-.07934519995360001,f=.013289415272000003,m=.5763833686400911,h=n/s,o=h<m?-(l*s+d*n)/c:-(u*s+f*n)/p}return r=t.LMS2rgb(s,o,n),h=g.charAt(r[0]>>4&15)+g.charAt(15&r[0]),e="#"+h,h=g.charAt(r[1]>>4&15)+g.charAt(15&r[1]),e+=h,h=g.charAt(r[2]>>4&15)+g.charAt(15&r[2]),e+=h},t.autoHighlight=function(e){var i=t.rgba2rgbo(e),r=i[0],s=i[1];return"#"===e.charAt(0)?(s*=s<.3?1.8:.4,t.rgbo2rgba(r,s)):e},t.contrast=function(e,i,r,s){var o,n,a,h,l;return i=i||"#000000",r=r||"#ffffff",s=s||7,o=t.rgbParser(e),n=t.rgbParser("#000000"),a=.2126*Math.pow(o[0]/255,2.2)+.7152*Math.pow(o[1]/255,2.2)+.0722*Math.pow(o[2]/255,2.2),h=.2126*Math.pow(n[0]/255,2.2)+.7152*Math.pow(n[1]/255,2.2)+.0722*Math.pow(n[2]/255,2.2),l=a>h?Math.floor((a+.05)/(h+.05)):Math.floor((h+.05)/(a+.05)),l-=1,l>s?i:r},t}),define("options",["jxg","base/constants","math/math","utils/color","utils/type"],function(t,e,i,r,s){"use strict";return t.Options={jc:{enabled:!0,compile:!0},board:{boundingBox:[-5,5,5,-5],maxBoundingBox:[-1/0,1/0,1/0,-1/0],zoomFactor:1,zoomX:1,zoomY:1,title:"",description:"",showCopyright:!0,axis:!1,defaultAxes:{x:{name:"x",ticks:{label:{visible:"inherit",anchorX:"middle",anchorY:"top",fontSize:12,offset:[0,-3]},drawZero:!1,visible:"inherit"}},y:{name:"y",ticks:{label:{visible:"inherit",anchorX:"right",anchorY:"middle",fontSize:12,offset:[-6,0]},tickEndings:[1,0],drawZero:!1,visible:"inherit"}}},showNavigation:!0,showZoom:!0,showReload:!1,showScreenshot:!1,screenshot:{scale:1,type:"png",symbol:"⌘",css:"background-color:#eeeeee; opacity:1.0; border:2px solid black; border-radius:10px; text-align:center",cssButton:"padding: 4px 10px; border: solid #356AA0 1px; border-radius: 5px; position: absolute; right: 2ex; top: 2ex; background-color: rgba(255, 255, 255, 0.3);"},showFullscreen:!1,fullscreen:{symbol:"⛶"},showClearTraces:!1,keepAspectRatio:!1,ignoreLabels:!0,maxNameLength:1,document:!1,takeFirst:!1,takeSizeFromFile:!1,renderer:"auto",animationDelay:35,maxFrameRate:40,registerEvents:!0,minimizeReflow:"svg",offsetX:0,offsetY:0,zoom:{enabled:!0,factorX:1.25,factorY:1.25,wheel:!0,needShift:!0,min:1e-4,max:1e4,pinchHorizontal:!0,pinchVertical:!0,pinchSensitivity:7},pan:{needShift:!0,needTwoFingers:!1,enabled:!0},drag:{enabled:!0},selection:{enabled:!1,name:"selectionPolygon",needShift:!1,needCtrl:!0,withLines:!1,vertices:{visible:!1},fillColor:"#ffff00",visible:!1},showInfobox:!0},navbar:{strokeColor:"#333333",fillColor:"transparent",highlightFillColor:"#aaaaaa",padding:"2px",position:"absolute",fontSize:"14px",cursor:"pointer",zIndex:"100",right:"5px",bottom:"5px"},elements:{strokeColor:"#0000ff",highlightStrokeColor:"#C3D9FF",fillColor:"red",highlightFillColor:"none",strokeOpacity:1,highlightStrokeOpacity:1,fillOpacity:1,highlightFillOpacity:1,gradient:null,gradientSecondColor:"#ffffff",gradientSecondOpacity:1,gradientStartOffset:0,gradientEndOffset:1,gradientAngle:0,gradientCX:.5,gradientCY:.5,gradientR:.5,gradientFX:.5,gradientFY:.5,gradientFR:0,transitionDuration:100,strokeWidth:2,highlightStrokeWidth:2,fixed:!1,frozen:!1,withLabel:!1,visible:!0,priv:!1,layer:0,dash:0,shadow:!1,trace:!1,traceAttributes:{},highlight:!0,needsRegularUpdate:!0,snapToGrid:!1,scalable:!0,dragToTopOfLayer:!1,precision:"inherit",draft:{draft:!1,strokeColor:"#565656",fillColor:"#565656",strokeOpacity:.8,fillOpacity:.8,strokeWidth:1},isLabel:!1},ticks:{generateLabelText:null,generateLabelValue:null,drawLabels:!1,label:{},beautifulScientificTickLabels:!1,useUnicodeMinus:!0,anchor:"left",drawZero:!1,insertTicks:!1,minTicksDistance:10,minorHeight:4,majorHeight:10,tickEndings:[1,1],minorTicks:4,scale:1,scaleSymbol:"",labels:[],maxLabelLength:5,precision:3,ticksDistance:1,face:"|",strokeOpacity:1,strokeWidth:1,strokeColor:"black",highlightStrokeColor:"#888888",fillColor:"none",highlightFillColor:"none",visible:"inherit",includeBoundaries:!1,type:"linear"},hatch:{drawLabels:!1,drawZero:!0,majorHeight:20,anchor:"middle",face:"|",strokeWidth:2,strokeColor:"blue",ticksDistance:.2},precision:{touch:15,touchMax:100,mouse:4,pen:4,epsilon:1e-4,hasPoint:4},layer:{numlayers:20,unused9:19,unused8:18,unused7:17,unused6:16,unused5:15,unused4:14,unused3:13,unused2:12,unused1:11,unused0:10,text:9,point:9,glider:9,arc:8,line:7,circle:6,curve:5,turtle:5,polygon:3,sector:3,angle:3,integral:3,axis:2,ticks:2,grid:1,image:0,trace:0},angle:{withLabel:!0,radius:.5,type:"sector",orthoType:"square",orthoSensitivity:1,fillColor:"#FF7F00",highlightFillColor:"#FF7F00",strokeColor:"#FF7F00",fillOpacity:.3,highlightFillOpacity:.3,radiuspoint:{withLabel:!1,visible:!1,name:""},pointsquare:{withLabel:!1,visible:!1,name:""},dot:{visible:!1,strokeColor:"none",fillColor:"black",size:2,face:"o",withLabel:!1,name:""},label:{position:"top",offset:[0,0],strokeColor:"#0000FF"},arc:{visible:!1,fillColor:"none"}},arc:{selection:"auto",hasInnerPoints:!1,label:{anchorX:"auto",anchorY:"auto"},firstArrow:!1,lastArrow:!1,fillColor:"none",highlightFillColor:"none",strokeColor:"#0000ff",highlightStrokeColor:"#C3D9FF",useDirection:!1,center:{},radiusPoint:{},anglePoint:{}},arrow:{firstArrow:!1,lastArrow:{type:1,highlightSize:6,size:6}},axis:{name:"",needsRegularUpdate:!1,strokeWidth:1,lastArrow:{type:1,highlightSize:8,size:8},strokeColor:"#666666",highlightStrokeWidth:1,highlightStrokeColor:"#888888",withTicks:!0,straightFirst:!0,straightLast:!0,margin:-4,withLabel:!1,scalable:!1,ticks:{label:{offset:[4,-9],parse:!1,needsRegularUpdate:!1,display:"internal",visible:"inherit",layer:9},visible:"inherit",needsRegularUpdate:!1,strokeWidth:1,strokeColor:"#666666",highlightStrokeColor:"#888888",drawLabels:!0,drawZero:!1,insertTicks:!0,minTicksDistance:5,minorHeight:10,majorHeight:-1,tickEndings:[0,1],minorTicks:4,ticksDistance:1,strokeOpacity:.25},point1:{needsRegularUpdate:!1,visible:!1},point2:{needsRegularUpdate:!1,visible:!1},label:{position:"lft",offset:[10,10]}},bisector:{strokeColor:"#000000",point:{visible:!1,fixed:!1,withLabel:!1,name:""}},bisectorlines:{line1:{strokeColor:"black"},line2:{strokeColor:"black"}},button:{disabled:!1,display:"html"},cardinalspline:{createPoints:!0,isArrayOfCoordinates:!1,points:{strokeOpacity:.05,fillOpacity:.05,highlightStrokeOpacity:1,highlightFillOpacity:1,withLabel:!1,name:"",fixed:!1}},chart:{chartStyle:"line",colors:["#B02B2C","#3F4C6B","#C79810","#D15600","#FFFF88","#C3D9FF","#4096EE","#008C00"],highlightcolors:null,fillcolor:null,highlightonsector:!1,highlightbysize:!1,fillOpacity:.6,withLines:!1,label:{}},checkbox:{disabled:!1,checked:!1,display:"html"},circle:{hasInnerPoints:!1,fillColor:"none",highlightFillColor:"none",strokeColor:"#0000ff",highlightStrokeColor:"#C3D9FF",center:{visible:!1,withLabel:!1,fixed:!1,name:""},label:{position:"urt"}},circumcircle:{fillColor:"none",highlightFillColor:"none",strokeColor:"#0000ff",highlightStrokeColor:"#C3D9FF",center:{visible:!1,fixed:!1,withLabel:!1,name:""}},circumcirclearc:{fillColor:"none",highlightFillColor:"none",strokeColor:"#0000ff",highlightStrokeColor:"#C3D9FF",center:{visible:!1,withLabel:!1,fixed:!1,name:""}},circumcirclesector:{useDirection:!0,fillColor:"#00FF00",highlightFillColor:"#00FF00",fillOpacity:.3,highlightFillOpacity:.3,strokeColor:"#0000ff",highlightStrokeColor:"#C3D9FF",point:{visible:!1,fixed:!1,withLabel:!1,name:""}},conic:{fillColor:"none",highlightFillColor:"none",strokeColor:"#0000ff",highlightStrokeColor:"#C3D9FF",foci:{fixed:!1,visible:!1,withLabel:!1,name:""},center:{visible:!1,withLabel:!1,name:""},point:{withLabel:!1,name:""},line:{visible:!1}},curve:{strokeWidth:1,strokeColor:"#0000ff",fillColor:"none",fixed:!0,useQDT:!1,handDrawing:!1,curveType:null,RDPsmoothing:!1,numberPointsHigh:1600,numberPointsLow:400,doAdvancedPlot:!0,recursionDepthHigh:17,recursionDepthLow:15,doAdvancedPlotOld:!1,plotVersion:2,label:{position:"lft"}},glider:{label:{}},grid:{needsRegularUpdate:!1,hasGrid:!1,gridX:1,gridY:1,strokeColor:"#C0C0C0",strokeOpacity:.5,strokeWidth:1,dash:0,snapToGrid:!1,snapSizeX:10,snapSizeY:10},group:{needsRegularUpdate:!0},htmlslider:{widthRange:100,widthOut:34,step:.01,frozen:!0,isLabel:!1,strokeColor:"black",display:"html",anchorX:"left",anchorY:"middle",withLabel:!1},image:{imageString:null,fillOpacity:1,highlightFillOpacity:.6,cssClass:"JXGimage",highlightCssClass:"JXGimageHighlight",rotate:0,snapSizeX:1,snapSizeY:1,attractors:[]},incircle:{fillColor:"none",highlightFillColor:"none",strokeColor:"#0000ff",highlightStrokeColor:"#C3D9FF",center:{visible:!1,fixed:!1,withLabel:!1,name:""}},inequality:{fillColor:"red",fillOpacity:.2,strokeColor:"none",inverse:!1},infobox:{fontSize:12,isLabel:!1,strokeColor:"#bbbbbb",display:"html",anchorX:"left",anchorY:"middle",cssClass:"JXGinfobox",rotate:0,visible:!0,parse:!1,transitionDuration:0,needsRegularUpdate:!1},integral:{axis:"x",withLabel:!0,fixed:!0,strokeWidth:0,strokeOpacity:0,fillColor:"red",fillOpacity:.4,highlightFillColor:"red",highlightFillOpacity:.2,curveLeft:{visible:!0,withLabel:!1,color:"red",fillOpacity:.8,layer:9},baseLeft:{visible:!1,fixed:!1,withLabel:!1,name:""},curveRight:{visible:!0,withLabel:!1,color:"red",fillOpacity:.8,layer:9},baseRight:{visible:!1,fixed:!1,withLabel:!1,name:""},label:{fontSize:20}},input:{disabled:!1,maxlength:524288,display:"html"},intersection:{alwaysIntersect:!0},label:{visible:"inherit",strokeColor:"black",strokeOpacity:1,highlightStrokeOpacity:.666666,highlightStrokeColor:"black",fixed:!0,position:"urt",offset:[10,10],autoPosition:!1},legend:{style:"vertical",labels:["1","2","3","4","5","6","7","8"],colors:["#B02B2C","#3F4C6B","#C79810","#D15600","#FFFF88","#C3D9FF","#4096EE","#008C00"],rowHeight:20,strokeWidth:5},line:{firstArrow:!1,lastArrow:!1,margin:0,straightFirst:!0,straightLast:!0,fillColor:"none",highlightFillColor:"none",strokeColor:"#0000ff",highlightStrokeColor:"#888888",withTicks:!1,point1:{visible:!1,withLabel:!1,fixed:!1,name:""},point2:{visible:!1,withLabel:!1,fixed:!1,name:""},ticks:{drawLabels:!0,label:{offset:[4,-9]},drawZero:!1,insertTicks:!1,minTicksDistance:50,minorHeight:4,majorHeight:-1,minorTicks:4,defaultDistance:1,strokeOpacity:.3,visible:"inherit"},label:{position:"llft"},snapToGrid:!1,snapSizeX:1,snapSizeY:1,touchFirstPoint:!1,touchLastPoint:!1,lineCap:"butt"},locus:{translateToOrigin:!1,translateTo10:!1,stretch:!1,toOrigin:null,to10:null},metapostspline:{createPoints:!0,isArrayOfCoordinates:!1,points:{strokeOpacity:.05,fillOpacity:.05,highlightStrokeOpacity:1,highlightFillOpacity:1,withLabel:!1,name:"",fixed:!1}},mirrorelement:{fixed:!0,point:{},center:{},type:"Euclidean"},normal:{strokeColor:"#000000",point:{visible:!1,fixed:!1,withLabel:!1,name:""}},orthogonalprojection:{},parallel:{strokeColor:"#000000",point:{visible:!1,fixed:!1,withLabel:!1,name:""},label:{position:"llft"}},perpendicular:{strokeColor:"#000000",straightFirst:!0,straightLast:!0},perpendicularsegment:{strokeColor:"#000000",straightFirst:!1,straightLast:!1,point:{visible:!1,fixed:!0,withLabel:!1,name:""}},point:{withLabel:!0,label:{},style:5,face:"o",size:3,sizeUnit:"screen",fillColor:"#ff0000",highlightFillColor:"#EEEEEE",strokeWidth:2,strokeColor:"#ff0000",highlightStrokeColor:"#C3D9FF",zoom:!1,showInfobox:"inherit",infoboxDigits:"auto",draft:!1,attractors:[],attractorUnit:"user",attractorDistance:0,snatchDistance:0,snapToGrid:!1,snapSizeX:1,snapSizeY:1,snapToPoints:!1,ignoredSnapToPoints:[]},polygon:{hasInnerPoints:!1,fillColor:"#00FF00",highlightFillColor:"#00FF00",fillOpacity:.3,highlightFillOpacity:.3,withLines:!0,borders:{withLabel:!1,strokeWidth:1,highlightStrokeWidth:1,layer:5,label:{position:"top"},visible:"inherit"},vertices:{layer:9,withLabel:!1,name:"",strokeColor:"#ff0000",fillColor:"#ff0000",fixed:!1,visible:"inherit"},label:{offset:[0,0]}},polygonalchain:{fillColor:"none",highlightFillColor:"none"},prescribedangle:{anglePoint:{size:2,visible:!1,withLabel:!1}},reflection:{fixed:!0,center:{},type:"Euclidean"},regularpolygon:{hasInnerPoints:!1,fillColor:"#00FF00",highlightFillColor:"#00FF00",fillOpacity:.3,highlightFillOpacity:.3,withLines:!0,borders:{withLabel:!1,strokeWidth:1,highlightStrokeWidth:1,layer:5,label:{position:"top"}},vertices:{layer:9,withLabel:!0,strokeColor:"#ff0000",fillColor:"#ff0000",fixed:!1},label:{offset:[0,0]}},riemannsum:{withLabel:!1,fillOpacity:.3,fillColor:"#ffff00"},sector:{fillColor:"#00FF00",highlightFillColor:"#00FF00",fillOpacity:.3,highlightFillOpacity:.3,highlightOnSector:!1,highlightStrokeWidth:0,selection:"auto",arc:{visible:!1,fillColor:"none"},radiusPoint:{visible:!1,withLabel:!1},center:{visible:!1,withLabel:!1},anglePoint:{visible:!1,withLabel:!1},label:{offset:[0,0],anchorX:"auto",anchorY:"auto"}},segment:{label:{position:"top"}},semicircle:{center:{visible:!1,withLabel:!1,fixed:!1,name:""}},slider:{snapWidth:-1,precision:2,firstArrow:!1,lastArrow:!1,withTicks:!0,withLabel:!0,suffixLabel:null,unitLabel:null,postLabel:null,layer:9,showInfobox:!1,name:"",visible:!0,strokeColor:"#000000",highlightStrokeColor:"#888888",fillColor:"#ffffff",highlightFillColor:"none",size:6,point1:{needsRegularUpdate:!1,showInfobox:!1,withLabel:!1,visible:!1,fixed:!0,name:""},point2:{needsRegularUpdate:!1,showInfobox:!1,withLabel:!1,visible:!1,fixed:!0,name:""},baseline:{needsRegularUpdate:!1,visible:"inherit",fixed:!0,scalable:!1,name:"",strokeWidth:1,strokeColor:"#000000",highlightStrokeColor:"#888888"},ticks:{needsRegularUpdate:!1,fixed:!0,drawLabels:!1,precision:2,includeBoundaries:1,drawZero:!0,label:{offset:[-4,-14],display:"internal"},minTicksDistance:30,insertTicks:!0,minorHeight:4,majorHeight:5,minorTicks:0,defaultDistance:1,strokeOpacity:1,strokeWidth:1,tickEndings:[0,1],strokeColor:"#000000",visible:"inherit"},highline:{strokeWidth:3,visible:"inherit",fixed:!0,name:"",strokeColor:"#000000",highlightStrokeColor:"#888888"},label:{visible:"inherit",strokeColor:"#000000"},moveOnUp:!0},comb:{frequency:.2,width:.4,angle:Math.PI/3,reverse:!1,point1:{visible:!1,withLabel:!1,fixed:!1,name:""},point2:{visible:!1,withLabel:!1,fixed:!1,name:""},curve:{strokeWidth:1,strokeColor:"#000000",fillColor:"none"}},slopetriangle:{fillColor:"red",fillOpacity:.4,highlightFillColor:"red",highlightFillOpacity:.3,borders:{lastArrow:{type:1,size:6}},glider:{fixed:!0,visible:!1,withLabel:!1},baseline:{visible:!1,withLabel:!1,name:""},basepoint:{visible:!1,withLabel:!1,name:""},tangent:{visible:!1,withLabel:!1,name:""},topPoint:{visible:!1,withLabel:!1,name:""},label:{visible:!0}},stepfunction:{},tapemeasure:{strokeColor:"#000000",strokeWidth:2,highlightStrokeColor:"#000000",withTicks:!0,withLabel:!0,precision:2,point1:{visible:"inherit",strokeColor:"#000000",fillColor:"#ffffff",fillOpacity:0,highlightFillOpacity:.1,size:6,snapToPoints:!0,attractorUnit:"screen",attractorDistance:20,showInfobox:!1,withLabel:!1,name:""},point2:{visible:"inherit",strokeColor:"#000000",fillColor:"#ffffff",fillOpacity:0,highlightFillOpacity:.1,size:6,snapToPoints:!0,attractorUnit:"screen",attractorDistance:20,showInfobox:!1,withLabel:!1,name:""},ticks:{drawLabels:!1,drawZero:!0,insertTicks:!0,minorHeight:8,majorHeight:16,minorTicks:4,tickEndings:[0,1],defaultDistance:.1,strokeOpacity:1,strokeWidth:1,strokeColor:"#000000",visible:"inherit"},label:{position:"top"}},text:{fontSize:12,digits:2,parse:!0,useCaja:!1,isLabel:!1,strokeColor:"black",highlightStrokeColor:"black",highlightStrokeOpacity:.666666,cssDefaultStyle:"font-family: Arial, Helvetica, Geneva, sans-serif;",highlightCssDefaultStyle:"font-family: Arial, Helvetica, Geneva, sans-serif;",cssStyle:"",highlightCssStyle:"",useASCIIMathML:!1,useMathJax:!1,display:"html",anchor:null,anchorX:"left",anchorY:"middle",cssClass:"JXGtext",highlightCssClass:"JXGtext",dragArea:"all",withLabel:!1,rotate:0,visible:!0,snapSizeX:1,snapSizeY:1,attractors:[]},tracecurve:{strokeColor:"#000000",fillColor:"none",numberPoints:100},turtle:{strokeWidth:1,fillColor:"none",strokeColor:"#000000",arrow:{strokeWidth:2,withLabel:!1,strokeColor:"#ff0000",lastArrow:!0}},shortcuts:{color:["strokeColor","fillColor"],opacity:["strokeOpacity","fillOpacity"],highlightColor:["highlightStrokeColor","highlightFillColor"],highlightOpacity:["highlightStrokeOpacity","highlightFillOpacity"],strokeWidth:["strokeWidth","highlightStrokeWidth"]}},t.Validator=function(){var e,r=function(t){return/^[0-9]+px$/.test(t)},o=function(t){return"html"===t||"internal"===t},n=function(t){return s.isString(t)},a=function(e){return s.exists(t.normalizePointFace(e))},h=function(t){return Math.abs(t-Math.round(t))<i.eps},l=function(t){return h(t)&&t>=0},c=function(t){return h(t)&&t>0},d=function(t){return"vml"===t||"svg"===t||"canvas"===t||"no"===t},u=function(t){return t>0},p=function(t){return t>=0},f={},m={attractorDistance:p,color:n,defaultDistance:s.isNumber,display:o,doAdvancedPlot:!1,draft:!1,drawLabels:!1,drawZero:!1,face:a,factor:s.isNumber,fillColor:n,fillOpacity:s.isNumber,firstArrow:!1,fontSize:h,dash:h,gridX:s.isNumber,gridY:s.isNumber,hasGrid:!1,highlightFillColor:n,highlightFillOpacity:s.isNumber,highlightStrokeColor:n,highlightStrokeOpacity:s.isNumber,insertTicks:!1,lastArrow:!1,layer:l,majorHeight:h,minorHeight:h,minorTicks:p,minTicksDistance:c,numberPointsHigh:c,numberPointsLow:c,opacity:s.isNumber,radius:s.isNumber,RDPsmoothing:!1,renderer:d,right:r,showCopyright:!1,showInfobox:!1,showNavigation:!1,size:p,snapSizeX:u,snapSizeY:u,snapWidth:s.isNumber,snapToGrid:!1,snatchDistance:p,straightFirst:!1,straightLast:!1,stretch:!1,strokeColor:n,strokeOpacity:s.isNumber,strokeWidth:p,takeFirst:!1,takeSizeFromFile:!1,to10:!1,toOrigin:!1,translateTo10:!1,translateToOrigin:!1,useASCIIMathML:!1,useDirection:!1,useMathJax:!1,withLabel:!1,withTicks:!1,zoom:!1};for(e in m)m.hasOwnProperty(e)&&(f[e.toLowerCase()]=m[e]);return f}(),t.normalizePointFace=function(t){return{cross:"x",x:"x",circle:"o",o:"o",square:"[]","[]":"[]",plus:"+","+":"+",diamond:"<>","<>":"<>",triangleup:"^",a:"^","^":"^",triangledown:"v",v:"v",triangleleft:"<","<":"<",triangleright:">",">":">"}[t]},t.useStandardOptions=function(i){var r,s,o,n,a=t.Options,h=i.hasGrid;i.options.grid.hasGrid=a.grid.hasGrid,i.options.grid.gridX=a.grid.gridX,i.options.grid.gridY=a.grid.gridY,i.options.grid.gridColor=a.grid.gridColor,i.options.grid.gridOpacity=a.grid.gridOpacity,i.options.grid.gridDash=a.grid.gridDash,i.options.grid.snapToGrid=a.grid.snapToGrid,i.options.grid.snapSizeX=a.grid.SnapSizeX,i.options.grid.snapSizeY=a.grid.SnapSizeY,i.takeSizeFromFile=a.takeSizeFromFile,n=function(t,e){t.visProp.fillcolor=e.fillColor,t.visProp.highlightfillcolor=e.highlightFillColor,t.visProp.strokecolor=e.strokeColor, -t.visProp.highlightstrokecolor=e.highlightStrokeColor};for(r in i.objects)if(i.objects.hasOwnProperty(r))if(o=i.objects[r],o.elementClass===e.OBJECT_CLASS_POINT)n(o,a.point);else if(o.elementClass===e.OBJECT_CLASS_LINE)for(n(o,a.line),s=0;s<o.ticks.length;s++)o.ticks[s].majorTicks=a.line.ticks.majorTicks,o.ticks[s].minTicksDistance=a.line.ticks.minTicksDistance,o.ticks[s].visProp.minorheight=a.line.ticks.minorHeight,o.ticks[s].visProp.majorheight=a.line.ticks.majorHeight;else o.elementClass===e.OBJECT_CLASS_CIRCLE?n(o,a.circle):o.type===e.OBJECT_TYPE_ANGLE?n(o,a.angle):o.type===e.OBJECT_TYPE_ARC?n(o,a.arc):o.type===e.OBJECT_TYPE_POLYGON?n(o,a.polygon):o.type===e.OBJECT_TYPE_CONIC?n(o,a.conic):o.type===e.OBJECT_TYPE_CURVE?n(o,a.curve):o.type===e.OBJECT_TYPE_SECTOR&&(o.arc.visProp.fillcolor=a.sector.fillColor,o.arc.visProp.highlightfillcolor=a.sector.highlightFillColor,o.arc.visProp.fillopacity=a.sector.fillOpacity,o.arc.visProp.highlightfillopacity=a.sector.highlightFillOpacity);i.fullUpdate(),h&&!i.hasGrid?i.removeGrids(i):!h&&i.hasGrid&&i.create("grid",[])},t.useBlackWhiteOptions=function(e){var i=t.Options;i.point.fillColor=r.rgb2bw(i.point.fillColor),i.point.highlightFillColor=r.rgb2bw(i.point.highlightFillColor),i.point.strokeColor=r.rgb2bw(i.point.strokeColor),i.point.highlightStrokeColor=r.rgb2bw(i.point.highlightStrokeColor),i.line.fillColor=r.rgb2bw(i.line.fillColor),i.line.highlightFillColor=r.rgb2bw(i.line.highlightFillColor),i.line.strokeColor=r.rgb2bw(i.line.strokeColor),i.line.highlightStrokeColor=r.rgb2bw(i.line.highlightStrokeColor),i.circle.fillColor=r.rgb2bw(i.circle.fillColor),i.circle.highlightFillColor=r.rgb2bw(i.circle.highlightFillColor),i.circle.strokeColor=r.rgb2bw(i.circle.strokeColor),i.circle.highlightStrokeColor=r.rgb2bw(i.circle.highlightStrokeColor),i.arc.fillColor=r.rgb2bw(i.arc.fillColor),i.arc.highlightFillColor=r.rgb2bw(i.arc.highlightFillColor),i.arc.strokeColor=r.rgb2bw(i.arc.strokeColor),i.arc.highlightStrokeColor=r.rgb2bw(i.arc.highlightStrokeColor),i.polygon.fillColor=r.rgb2bw(i.polygon.fillColor),i.polygon.highlightFillColor=r.rgb2bw(i.polygon.highlightFillColor),i.sector.fillColor=r.rgb2bw(i.sector.fillColor),i.sector.highlightFillColor=r.rgb2bw(i.sector.highlightFillColor),i.curve.strokeColor=r.rgb2bw(i.curve.strokeColor),i.grid.gridColor=r.rgb2bw(i.grid.gridColor),t.useStandardOptions(e)},t.Options.normalizePointFace=t.normalizePointFace,t.Options}),define("renderer/abstract",["jxg","options","base/coords","base/constants","math/math","math/geometry","utils/type","utils/env"],function(t,e,i,r,s,o,n,a){"use strict";return t.AbstractRenderer=function(){this.vOffsetText=0,this.enhancedRendering=!0,this.container=null,this.type="",this.supportsForeignObject=!1},t.extend(t.AbstractRenderer.prototype,{_updateVisual:function(t,e,i){(i||this.enhancedRendering)&&(e=e||{},this.setObjectTransition(t),n.evaluate(t.visProp.draft)?this.setDraft(t):(e.stroke||(t.highlighted?(this.setObjectStrokeColor(t,t.visProp.highlightstrokecolor,t.visProp.highlightstrokeopacity),this.setObjectStrokeWidth(t,t.visProp.highlightstrokewidth)):(this.setObjectStrokeColor(t,t.visProp.strokecolor,t.visProp.strokeopacity),this.setObjectStrokeWidth(t,t.visProp.strokewidth))),e.fill||(t.highlighted?this.setObjectFillColor(t,t.visProp.highlightfillcolor,t.visProp.highlightfillopacity):this.setObjectFillColor(t,t.visProp.fillcolor,t.visProp.fillopacity)),e.dash||this.setDashStyle(t,t.visProp),e.shadow||this.setShadow(t),e.gradient||this.setShadow(t)))},_getHighlighted:function(t){var e=!1;return n.exists(t.board)&&n.exists(t.board.highlightedObjects)||(e=!0),!e&&n.exists(t.board.highlightedObjects[t.id])?"highlight":""},drawPoint:function(t){var i,r=e.normalizePointFace(n.evaluate(t.visProp.face));i="o"===r?"ellipse":"[]"===r?"rect":"path",t.rendNode=this.appendChildPrim(this.createPrim(i,t.id),n.evaluate(t.visProp.layer)),this.appendNodesToElement(t,i),this._updateVisual(t,{dash:!0,shadow:!0},!0),this.updatePoint(t)},updatePoint:function(t){var i,r=n.evaluate(t.visProp.size),s=e.normalizePointFace(n.evaluate(t.visProp.face)),o=n.evaluate(t.visProp.sizeunit),a=n.evaluate(t.visProp.zoom);isNaN(t.coords.scrCoords[2]+t.coords.scrCoords[1])||("user"===o&&(r*=Math.sqrt(t.board.unitX*t.board.unitY)),r*=t.board&&a?Math.sqrt(t.board.zoomX*t.board.zoomY):1,i=0===r?0:r+1,"o"===s?this.updateEllipsePrim(t.rendNode,t.coords.scrCoords[1],t.coords.scrCoords[2],i,i):"[]"===s?this.updateRectPrim(t.rendNode,t.coords.scrCoords[1]-r,t.coords.scrCoords[2]-r,2*r,2*r):this.updatePathPrim(t.rendNode,this.updatePathStringPoint(t,r,s),t.board),this._updateVisual(t,{dash:!1,shadow:!1}),this.setShadow(t))},changePointStyle:function(t){var e=this.getElementById(t.id);n.exists(e)&&this.remove(e),this.drawPoint(t),n.clearVisPropOld(t),t.visPropCalc.visible||this.display(t,!1),n.evaluate(t.visProp.draft)&&this.setDraft(t)},drawLine:function(t){t.rendNode=this.appendChildPrim(this.createPrim("line",t.id),n.evaluate(t.visProp.layer)),this.appendNodesToElement(t,"lines"),this.updateLine(t)},getArrowHeadData:function(t,e,i){var r,o,a,h,l=s.eps,c=0,d=0,u=0,p=0,f=n.evaluate(t.visProp.firstarrow),m=n.evaluate(t.visProp.lastarrow);return(f||m)&&(n.exists(f.type)&&(r=n.evaluate(f.type)),n.exists(m.type)&&(o=n.evaluate(m.type)),f&&(h=6,n.exists(f.size)&&(h=n.evaluate(f.size)),""!==i&&n.exists(f[i+"size"])&&(h=n.evaluate(f[i+"size"])),a=e*h,2===r?(a*=.5,l+=e*h):3===r?(a=e*h/3,l+=e):4===r||5===r||6===r?(a=e*h/1.5,l+=e*h):l+=e*h,c+=a,u=h),m&&(h=6,n.exists(m.size)&&(h=n.evaluate(m.size)),""!==i&&n.exists(m[i+"size"])&&(h=n.evaluate(m[i+"size"])),a=e*h,2===o?(a*=.5,l+=e*h):3===o?(a=e*h/3,l+=e):4===o||5===o||6===o?(a=e*h/1.5,l+=e*h):l+=e*h,d+=a,p=h)),{evFirst:f,evLast:m,offFirst:c,offLast:d,sizeFirst:u,sizeLast:p,showFirst:1,showLast:1,minLen:l,strokeWidth:e}},getPositionArrowHead:function(t,e,i,s){var o,n,a,h,l;return(s.evFirst||s.evLast)&&(n=a=h=l=0,o=e.distance(r.COORDS_BY_SCREEN,i),s.evFirst&&"vml"!==t.board.renderer.type&&(o>=s.minLen?(n=(i.scrCoords[1]-e.scrCoords[1])*s.offFirst/o,a=(i.scrCoords[2]-e.scrCoords[2])*s.offFirst/o):s.showFirst=0),s.evLast&&"vml"!==t.board.renderer.type&&(o>=s.minLen?(h=(i.scrCoords[1]-e.scrCoords[1])*s.offLast/o,l=(i.scrCoords[2]-e.scrCoords[2])*s.offLast/o):s.showLast=0),e.setCoordinates(r.COORDS_BY_SCREEN,[e.scrCoords[1]+n,e.scrCoords[2]+a],!1,!0),i.setCoordinates(r.COORDS_BY_SCREEN,[i.scrCoords[1]-h,i.scrCoords[2]-l],!1,!0)),this},handleTouchpoints:function(t,e,i,s){var o,a,h,l,c,d,u;return(s.evFirst||s.evLast)&&(h=l=c=d=u=0,o=n.evaluate(t.point1.visProp.size)+n.evaluate(t.point1.visProp.strokewidth),a=n.evaluate(t.point2.visProp.size)+n.evaluate(t.point2.visProp.strokewidth),o+a,s.evFirst&&n.evaluate(t.visProp.touchfirstpoint)&&(h=e.distance(r.COORDS_BY_SCREEN,i),l=(i.scrCoords[1]-e.scrCoords[1])*o/h,c=(i.scrCoords[2]-e.scrCoords[2])*o/h),s.evLast&&n.evaluate(t.visProp.touchlastpoint)&&(h=e.distance(r.COORDS_BY_SCREEN,i),d=(i.scrCoords[1]-e.scrCoords[1])*a/h,u=(i.scrCoords[2]-e.scrCoords[2])*a/h),e.setCoordinates(r.COORDS_BY_SCREEN,[e.scrCoords[1]+l,e.scrCoords[2]+c],!1,!0),i.setCoordinates(r.COORDS_BY_SCREEN,[i.scrCoords[1]-d,i.scrCoords[2]-u],!1,!0)),this},updateLineEndings:function(t,e){var s,a,h=null;return s=new i(r.COORDS_BY_USER,t.point1.coords.usrCoords,t.board),a=new i(r.COORDS_BY_USER,t.point2.coords.usrCoords,t.board),h=n.evaluate(t.visProp.margin),o.calcStraight(t,s,a,h),this.handleTouchpoints(t,s,a,e),this.getPositionArrowHead(t,s,a,e),this.updateLinePrim(t.rendNode,s.scrCoords[1],s.scrCoords[2],a.scrCoords[1],a.scrCoords[2],t.board),this},updatePathEndings:function(t,e){return n.evaluate(t.visProp.handdrawing)?this.updatePathPrim(t.rendNode,this.updatePathStringBezierPrim(t),t.board):this.updatePathPrim(t.rendNode,this.updatePathStringPrim(t),t.board),this.shortenPath(t.rendNode,e.offFirst,e.offLast),this},setArrowSize:function(t,e){return e.evFirst&&this._setArrowWidth(t.rendNodeTriangleStart,e.showFirst*e.strokeWidth,t.rendNode,e.sizeFirst),e.evLast&&this._setArrowWidth(t.rendNodeTriangleEnd,e.showLast*e.strokeWidth,t.rendNode,e.sizeLast),this},updatePathWithArrowHeads:function(t,e){var i,s,o=t.visProp,a=e?"highlight":"";i=e&&o.highlightstrokewidth?Math.max(n.evaluate(o.highlightstrokewidth),n.evaluate(o.strokewidth)):n.evaluate(o.strokewidth),s=this.getArrowHeadData(t,i,a),this.makeArrows(t),t.elementClass===r.OBJECT_CLASS_LINE?this.updateLineEndings(t,s):t.elementClass===r.OBJECT_CLASS_CURVE&&this.updatePathEndings(t,s),this.setArrowSize(t,s)},updateLine:function(t){this._updateVisual(t),this.updatePathWithArrowHeads(t),this.setLineCap(t)},setLineCap:function(t){},drawTicks:function(t){t.rendNode=this.appendChildPrim(this.createPrim("path",t.id),n.evaluate(t.visProp.layer)),this.appendNodesToElement(t,"path")},updateTicks:function(t){},drawCurve:function(t){t.rendNode=this.appendChildPrim(this.createPrim("path",t.id),n.evaluate(t.visProp.layer)),this.appendNodesToElement(t,"path"),t.numberPoints>1&&this.makeArrows(t),this._updateVisual(t,{shadow:!0},!0),this.updateCurve(t)},updateCurve:function(t){this.updatePathWithArrowHeads(t),this._updateVisual(t)},drawEllipse:function(t){t.rendNode=this.appendChildPrim(this.createPrim("ellipse",t.id),n.evaluate(t.visProp.layer)),this.appendNodesToElement(t,"ellipse"),this.updateEllipse(t)},updateEllipse:function(t){this._updateVisual(t);var e=t.Radius();e>0&&Math.abs(t.center.coords.usrCoords[0])>s.eps&&!isNaN(e+t.center.coords.scrCoords[1]+t.center.coords.scrCoords[2])&&e*t.board.unitX<2e6&&this.updateEllipsePrim(t.rendNode,t.center.coords.scrCoords[1],t.center.coords.scrCoords[2],e*t.board.unitX,e*t.board.unitY)},drawPolygon:function(t){t.rendNode=this.appendChildPrim(this.createPrim("polygon",t.id),n.evaluate(t.visProp.layer)),this.appendNodesToElement(t,"polygon"),this.updatePolygon(t)},updatePolygon:function(t){this._updateVisual(t,{stroke:!0,dash:!0}),this.updatePolygonPrim(t.rendNode,t)},displayCopyright:function(t,e){},drawInternalText:function(t){},updateInternalText:function(t){},drawText:function(t){var e,i,r,s;"html"===n.evaluate(t.visProp.display)&&a.isBrowser&&"no"!==this.type?(e=this.container.ownerDocument.createElement("div"),e.style.position="absolute",e.className=n.evaluate(t.visProp.cssclass),r=n.evaluate(t.visProp.layer),n.exists(r)||(r=0),i=""===this.container.style.zIndex?0:parseInt(this.container.style.zIndex,10),e.style.zIndex=i+r,this.container.appendChild(e),e.setAttribute("id",this.container.id+"_"+t.id)):e=this.drawInternalText(t),t.rendNode=e,t.htmlStr="",t.visProp.islabel&&n.exists(t.visProp.anchor)?(s=n.evaluate(t.visProp.anchor.visProp.visible),t.prepareUpdate().updateVisibility(s)):t.prepareUpdate().updateVisibility(),this.updateText(t)},updateText:function(e){var i,r,s,o,a,h=e.plaintext;if(e.visPropCalc.visible)if(this.updateTextStyle(e,!1),"html"===n.evaluate(e.visProp.display)&&"no"!==this.type){if(isNaN(e.coords.scrCoords[1]+e.coords.scrCoords[2])||(r=e.coords.scrCoords[1],r=Math.abs(r)<1e6?r:1e6,o=e.getAnchorX(),i="right"===o?Math.floor(e.board.canvasWidth-r):"middle"===o?Math.floor(r-.5*e.size[0]):Math.floor(r),e.visPropOld.left!==o+i&&("right"===o?(e.rendNode.style.right=i+"px",e.rendNode.style.left="auto"):(e.rendNode.style.left=i+"px",e.rendNode.style.right="auto"),e.visPropOld.left=o+i),r=e.coords.scrCoords[2]+this.vOffsetText,r=Math.abs(r)<1e6?r:1e6,a=e.getAnchorY(),i="bottom"===a?Math.floor(e.board.canvasHeight-r):"middle"===a?Math.floor(r-.5*e.size[1]):Math.floor(r),e.visPropOld.top!==a+i&&("bottom"===a?(e.rendNode.style.top="auto",e.rendNode.style.bottom=i+"px"):(e.rendNode.style.bottom="auto",e.rendNode.style.top=i+"px"),e.visPropOld.top=a+i)),e.htmlStr!==h){try{e.rendNode.innerHTML=h}catch(t){s=e.rendNode.parentNode,e.rendNode.parentNode.removeChild(e.rendNode),e.rendNode.innerHTML=h,s.appendChild(e.rendNode)}if(e.htmlStr=h,n.evaluate(e.visProp.usemathjax))try{MathJax.typeset?MathJax.typeset([e.rendNode]):MathJax.Hub.Queue(["Typeset",MathJax.Hub,e.rendNode])}catch(e){t.debug("MathJax (not yet) loaded")}else if(n.evaluate(e.visProp.useasciimathml))try{AMprocessNode(e.rendNode,!1)}catch(e){t.debug("AsciiMathML (not yet) loaded")}}this.transformImage(e,e.transformations)}else this.updateInternalText(e)},_css2js:function(t){var e,i,r,s,o,a=[],h=n.trim(t).replace(/;$/,"").split(";");for(i=h.length,e=0;e<i;++e)""!==n.trim(h[e])&&(o=h[e].split(":"),r=n.trim(o[0].replace(/-([a-z])/gi,function(t,e){return e.toUpperCase()})),s=n.trim(o[1]),a.push({key:r,val:s}));return a},updateTextStyle:function(t,e){var i,r,s,o,h,l,c,d,u,p=t.visProp,f=a.isBrowser?p.display:"internal",m=["rendNode","rendNodeTag","rendNodeLabel"],g=m.length,b=["cssdefaultstyle","cssstyle"],v=b.length;if(e?(s=p.highlightstrokecolor,r=p.highlightstrokeopacity,o=p.highlightcssclass):(s=p.strokecolor,r=p.strokeopacity,o=p.cssclass),"no"!==this.type&&("html"===f||"canvas"!==this.type)){for(d=0;d<v;d++)if(""!==(u=n.evaluate(p[(e?"highlight":"")+b[d]]))&&t.visPropOld[b[d]]!==u){for(l=this._css2js(u),h=0;h<g;h++)if(n.exists(t[m[h]]))for(c in l)l.hasOwnProperty(c)&&(t[m[h]].style[l[c].key]=l[c].val);t.visPropOld[b[d]]=u}if(i=n.evaluate(p.fontsize),t.visPropOld.fontsize!==i){t.needsSizeUpdate=!0;try{for(h=0;h<g;h++)n.exists(t[m[h]])&&(t[m[h]].style.fontSize=i+"px")}catch(e){for(h=0;h<g;h++)n.exists(t[m[h]])&&(t[m[h]].style.fontSize=i)}t.visPropOld.fontsize=i}}return this.setObjectTransition(t),"html"===f&&"no"!==this.type?(t.visPropOld.cssclass!==o&&(t.rendNode.className=o,t.visPropOld.cssclass=o,t.needsSizeUpdate=!0),this.setObjectStrokeColor(t,s,r)):this.updateInternalTextStyle(t,s,r),this},updateInternalTextStyle:function(t,e,i){this.setObjectStrokeColor(t,e,i)},drawImage:function(t){},updateImage:function(t){this.updateRectPrim(t.rendNode,t.coords.scrCoords[1],t.coords.scrCoords[2]-t.size[1],t.size[0],t.size[1]),this.updateImageURL(t),this.transformImage(t,t.transformations),this._updateVisual(t,{stroke:!0,dash:!0},!0)},joinTransforms:function(t,e){var i,r=t.board.origin.scrCoords[1],o=t.board.origin.scrCoords[2],n=t.board.unitX,a=t.board.unitY,h=e.length,l=[[1,0,0],[-r/n,1/n,0],[o/a,0,-1/a]];for(i=0;i<h;i++)l=s.matMatMult(e[i].matrix,l);return l=s.matMatMult([[1,0,0],[r,n,0],[o,0,-a]],l)},transformImage:function(t,e){},updateImageURL:function(t){},updateImageStyle:function(t,e){t.rendNode.className=n.evaluate(e?t.visProp.highlightcssclass:t.visProp.cssclass)},appendChildPrim:function(t,e){},appendNodesToElement:function(t,e){},createPrim:function(t,e){return null},remove:function(t){},makeArrows:function(t){},_setArrowWidth:function(t,e,i){},updateEllipsePrim:function(t,e,i,r,s){},updateLinePrim:function(t,e,i,r,s,o){},updatePathPrim:function(t,e,i){},updatePathStringPoint:function(t,e,i){},updatePathStringPrim:function(t){},updatePathStringBezierPrim:function(t){},updatePolygonPrim:function(t,e){},updateRectPrim:function(t,e,i,r,s){},setPropertyPrim:function(t,e,i){},display:function(t,e){t&&(t.visPropOld.visible=e)},show:function(t){},hide:function(t){},setBuffering:function(t,e){},setDashStyle:function(t){},setDraft:function(t){if(n.evaluate(t.visProp.draft)){var e=t.board.options.elements.draft.color,i=t.board.options.elements.draft.opacity;this.setObjectTransition(t),t.type===r.OBJECT_TYPE_POLYGON?this.setObjectFillColor(t,e,i):(t.elementClass===r.OBJECT_CLASS_POINT?this.setObjectFillColor(t,e,i):this.setObjectFillColor(t,"none",0),this.setObjectStrokeColor(t,e,i),this.setObjectStrokeWidth(t,t.board.options.elements.draft.strokeWidth))}},removeDraft:function(t){this.setObjectTransition(t),t.type===r.OBJECT_TYPE_POLYGON?this.setObjectFillColor(t,t.visProp.fillcolor,t.visProp.fillopacity):(t.type===r.OBJECT_CLASS_POINT&&this.setObjectFillColor(t,t.visProp.fillcolor,t.visProp.fillopacity),this.setObjectStrokeColor(t,t.visProp.strokecolor,t.visProp.strokeopacity),this.setObjectStrokeWidth(t,t.visProp.strokewidth))},setGradient:function(t){},updateGradient:function(t){},setObjectTransition:function(t,e){},setObjectFillColor:function(t,e,i){},setObjectStrokeColor:function(t,e,i){},setObjectStrokeWidth:function(t,e){},setShadow:function(t){},highlight:function(t){var e,i,s=t.visProp;if(this.setObjectTransition(t),!s.draft){if(t.type===r.OBJECT_TYPE_POLYGON)for(this.setObjectFillColor(t,s.highlightfillcolor,s.highlightfillopacity),e=0;e<t.borders.length;e++)this.setObjectStrokeColor(t.borders[e],t.borders[e].visProp.highlightstrokecolor,t.borders[e].visProp.highlightstrokeopacity);else t.elementClass===r.OBJECT_CLASS_TEXT?this.updateTextStyle(t,!0):t.type===r.OBJECT_TYPE_IMAGE?(this.updateImageStyle(t,!0),this.setObjectFillColor(t,s.highlightfillcolor,s.highlightfillopacity)):(this.setObjectStrokeColor(t,s.highlightstrokecolor,s.highlightstrokeopacity),this.setObjectFillColor(t,s.highlightfillcolor,s.highlightfillopacity));s.highlightstrokewidth&&(i=Math.max(n.evaluate(s.highlightstrokewidth),n.evaluate(s.strokewidth)),this.setObjectStrokeWidth(t,i),t.elementClass!==r.OBJECT_CLASS_LINE&&t.elementClass!==r.OBJECT_CLASS_CURVE||this.updatePathWithArrowHeads(t,!0))}return this},noHighlight:function(t){var e,i,s=t.visProp;if(this.setObjectTransition(t),!n.evaluate(t.visProp.draft)){if(t.type===r.OBJECT_TYPE_POLYGON)for(this.setObjectFillColor(t,s.fillcolor,s.fillopacity),e=0;e<t.borders.length;e++)this.setObjectStrokeColor(t.borders[e],t.borders[e].visProp.strokecolor,t.borders[e].visProp.strokeopacity);else t.elementClass===r.OBJECT_CLASS_TEXT?this.updateTextStyle(t,!1):t.type===r.OBJECT_TYPE_IMAGE?(this.updateImageStyle(t,!1),this.setObjectFillColor(t,s.fillcolor,s.fillopacity)):(this.setObjectStrokeColor(t,s.strokecolor,s.strokeopacity),this.setObjectFillColor(t,s.fillcolor,s.fillopacity));i=n.evaluate(s.strokewidth),this.setObjectStrokeWidth(t,i),t.elementClass!==r.OBJECT_CLASS_LINE&&t.elementClass!==r.OBJECT_CLASS_CURVE||this.updatePathWithArrowHeads(t,!1)}return this},suspendRedraw:function(){},unsuspendRedraw:function(){},drawZoomBar:function(t,e){var i,r,s=function(t){t||(t=window.event),t.stopPropagation?t.stopPropagation():t.cancelBubble=!0},o=function(e,o){var h;h=i.createElement("span"),r.appendChild(h),h.appendChild(i.createTextNode(e)),h.style.paddingLeft="7px",h.style.paddingRight="7px",void 0!==h.classList&&h.classList.add("JXG_navigation_button"),a.addEvent(h,"click",function(e){return n.bind(o,t)(),!1},t),a.addEvent(h,"mouseup",s,t),a.addEvent(h,"mousedown",s,t),a.addEvent(h,"touchend",s,t),a.addEvent(h,"touchstart",s,t)};a.isBrowser&&"no"!==this.type&&(i=t.containerObj.ownerDocument,r=i.createElement("div"),r.setAttribute("id",t.containerObj.id+"_navigationbar"),r.style.color=e.strokecolor,r.style.backgroundColor=e.fillcolor,r.style.padding=e.padding,r.style.position=e.position,r.style.fontSize=e.fontsize,r.style.cursor=e.cursor,r.style.zIndex=e.zindex,t.containerObj.appendChild(r),r.style.right=e.right,r.style.bottom=e.bottom,void 0!==r.classList&&r.classList.add("JXG_navigation"),t.attr.showfullscreen&&o(t.attr.fullscreen.symbol,function(){t.toFullscreen()}),t.attr.showscreenshot&&o(t.attr.screenshot.symbol,function(){window.setTimeout(function(){t.renderer.screenshot(t,"",!1)},330)}),t.attr.showreload&&o("↻",function(){t.reload()}),t.attr.showcleartraces&&o("⊗",function(){t.clearTraces()}),t.attr.shownavigation&&(t.attr.showzoom&&(o("–",t.zoomOut),o("o",t.zoom100),o("+",t.zoomIn)),o("←",t.clickLeftArrow),o("↓",t.clickUpArrow),o("↑",t.clickDownArrow),o("→",t.clickRightArrow)))},getElementById:function(t){return n.exists(this.container)?this.container.ownerDocument.getElementById(this.container.id+"_"+t):""},removeToInsertLater:function(t){var e=t.parentNode,i=t.nextSibling;if(null!==e)return e.removeChild(t),function(){i?e.insertBefore(t,i):e.appendChild(t)}},resize:function(t,e){},createTouchpoints:function(t){},showTouchpoint:function(t){},hideTouchpoint:function(t){},updateTouchpoint:function(t,e){},dumpToDataURI:function(t){},dumpToCanvas:function(t,e,i,r){},screenshot:function(t){},shortenPath:function(t,e,i){},setLayer:function(t,e){}}),t.AbstractRenderer}),define("reader/file",["jxg","utils/env","utils/type","utils/encoding","utils/base64"],function(t,e,i,r,s){"use strict";return t.FileReader={handleRemoteFile:function(e,o,n,a,h,l){var c=!1;try{c=new XMLHttpRequest,"raw"===n.toLowerCase()?c.overrideMimeType("text/plain; charset="+h):c.overrideMimeType("text/xml; charset="+h)}catch(t){try{c=new ActiveXObject("Msxml2.XMLHTTP")}catch(t){try{c=new ActiveXObject("Microsoft.XMLHTTP")}catch(t){c=!1}}}if(!c)return void t.debug("AJAX not activated!");c.open("GET",e,a),"raw"===n.toLowerCase()?this.cbp=function(){var t=c;4===t.readyState&&o(t.responseText)}:this.cbp=function(){var t=c,e="";4===t.readyState&&(!i.exists(t.responseStream)||"PK"!==t.responseText.slice(0,2)&&31!==r.asciiCharCodeAt(t.responseText.slice(0,1),0)?(e=t.responseText,console.log(e)):e=s.decode(jxgBinFileReader(t)),this.parseString(e,o,n,l))},this.cb=i.bind(this.cbp,this),c.onreadystatechange=this.cb;try{c.send(null)}catch(t){throw new Error("JSXGraph: A problem occurred while trying to read remote file '"+e+"'.")}},handleLocalFile:function(t,e,r,s,o,n){i.exists(s)||(s=!0),"raw"===r.toLowerCase()?this.cbp=function(t){e(t.target.result)}:this.cbp=function(t){var i=t.target.result;this.parseString(i,e,r,n)},this.cb=i.bind(this.cbp,this);var a=new FileReader;a.onload=this.cb,"raw"===r.toLowerCase()?a.readAsText(t):a.readAsText(t,o)},parseFileContent:function(t,e,r,s,o,n){i.isString(t)||void 0===FileReader?this.handleRemoteFile(t,e,r,s,o,n):this.handleLocalFile(t,e,r,s,o,n)},parseString:function(e,r,s,o){var n,a;if(s=s.toLowerCase(),n=t.readers[s],!i.exists(n))throw new Error("JSXGraph: There is no reader available for '"+s+"'.");a=new n(r,e),a.read(),i.isFunction(o)&&o(r)}},!e.isMetroApp()&&e.isBrowser&&"object"==typeof navigator&&/msie/i.test(navigator.userAgent)&&!/opera/i.test(navigator.userAgent)&&document&&document.write&&document.write('<script type="text/vbscript">\nFunction Base64Encode(inData)\n Const Base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"\n Dim cOut, sOut, I\n For I = 1 To LenB(inData) Step 3\n Dim nGroup, pOut, sGroup\n nGroup = &H10000 * AscB(MidB(inData, I, 1)) + _\n &H100 * MyASC(MidB(inData, I + 1, 1)) + MyASC(MidB(inData, I + 2, 1))\n nGroup = Oct(nGroup)\n nGroup = String(8 - Len(nGroup), "0") & nGroup\n pOut = Mid(Base64, CLng("&o" & Mid(nGroup, 1, 2)) + 1, 1) + _\n Mid(Base64, CLng("&o" & Mid(nGroup, 3, 2)) + 1, 1) + _\n Mid(Base64, CLng("&o" & Mid(nGroup, 5, 2)) + 1, 1) + _\n Mid(Base64, CLng("&o" & Mid(nGroup, 7, 2)) + 1, 1)\n sOut = sOut + pOut\n Next\n Select Case LenB(inData) Mod 3\n Case 1: \'8 bit final\n sOut = Left(sOut, Len(sOut) - 2) + "=="\n Case 2: \'16 bit final\n sOut = Left(sOut, Len(sOut) - 1) + "="\n End Select\n Base64Encode = sOut\nEnd Function\n\nFunction MyASC(OneChar)\n If OneChar = "" Then MyASC = 0 Else MyASC = AscB(OneChar)\nEnd Function\n\nFunction jxgBinFileReader(xhr)\n Dim byteString\n Dim b64String\n Dim i\n byteString = xhr.responseBody\n ReDim byteArray(LenB(byteString))\n For i = 1 To LenB(byteString)\n byteArray(i-1) = AscB(MidB(byteString, i, 1))\n Next\n b64String = Base64Encode(byteString)\n jxgBinFileReader = b64String\nEnd Function\n<\/script>\n'),t.FileReader}),define("parser/geonext",["jxg","base/constants","utils/type"],function(t,e,i){"use strict";return t.GeonextParser={replacePow:function(t){var e,i,r,s,o,n,a,h,l,c,d,u;for(t=t.replace(/(\s*)\^(\s*)/g,"^"),c=t.indexOf("^"),s=-1;c>=0&&c<t.length-1;){if(s===c)throw new Error("JSXGraph: Error while parsing expression '"+t+"'");if(s=c,l=t.slice(0,c),d=t.slice(c+1),")"===l.charAt(l.length-1)){for(e=1,i=l.length-2;i>=0&&e>0;)r=l.charAt(i),")"===r?e++:"("===r&&(e-=1),i-=1;if(0!==e)throw new Error("JSXGraph: Missing '(' in expression");for(o="",a=l.substring(0,i+1),h=i;h>=0&&a.substr(h,1).match(/([\w\.]+)/);)o=RegExp.$1+o,h-=1;o+=l.substring(i+1,l.length),o=o.replace(/([\(\)\+\*\%\^\-\/\]\[])/g,"\\$1")}else o="[\\w\\.]+";if(d.match(/^([\w\.]*\()/)){for(e=1,i=RegExp.$1.length;i<d.length&&e>0;)r=d.charAt(i),")"===r?e-=1:"("===r&&(e+=1),i+=1;if(0!==e)throw new Error("JSXGraph: Missing ')' in expression");n=d.substring(0,i),n=n.replace(/([\(\)\+\*\%\^\-\/\[\]])/g,"\\$1")}else n="[\\w\\.]+";u=new RegExp("("+o+")\\^("+n+")"),t=t.replace(u,"pow($1,$2)"),c=t.indexOf("^")}return t},replaceIf:function(t){var e,i,r,s,o,n,a,h,l,c="",d=null,u=null,p=null;if((r=t.indexOf("If("))<0)return t;for(t=t.replace(/""/g,"0");r>=0;){for(e=t.slice(0,r),i=t.slice(r+3),o=1,s=0,n=-1,a=-1;s<i.length&&o>0;)h=i.charAt(s),")"===h?o-=1:"("===h?o+=1:","===h&&1===o&&(n<0?n=s:a=s),s+=1;if(l=i.slice(0,s-1),i=i.slice(s),n<0)return"";if(a<0)return"";d=l.slice(0,n),u=l.slice(n+1,a),p=l.slice(a+1),d=this.replaceIf(d),u=this.replaceIf(u),p=this.replaceIf(p),c+=e+"(("+d+")?("+u+"):("+p+"))",t=i,d=null,u=null,r=t.indexOf("If(")}return c+=i},replaceNameById:function(t,e,i){var r,s,o,n,a=0,h=["X","Y","L","V"],l=function(t){return i?"$('"+t+"')":t};for(n=0;n<h.length;n++)for(a=t.indexOf(h[n]+"(");a>=0;)a>=0&&(r=t.indexOf(")",a+2))>=0&&(s=t.slice(a+2,r),s=s.replace(/\\(['"])?/g,"$1"),(o=e.elementsByName[s])&&(t=t.slice(0,a+2)+(i?"$('":"")+l(o.id)+t.slice(r))),r=t.indexOf(")",a+2),a=t.indexOf(h[n]+"(",r);for(a=t.indexOf("Dist(");a>=0;)a>=0&&(r=t.indexOf(",",a+5))>=0&&(s=t.slice(a+5,r),s=s.replace(/\\(['"])?/g,"$1"),(o=e.elementsByName[s])&&(t=t.slice(0,a+5)+l(o.id)+t.slice(r))),r=t.indexOf(",",a+5),a=t.indexOf(",",r),r=t.indexOf(")",a+1),r>=0&&(s=t.slice(a+1,r),s=s.replace(/\\(['"])?/g,"$1"),(o=e.elementsByName[s])&&(t=t.slice(0,a+1)+l(o.id)+t.slice(r))),r=t.indexOf(")",a+1),a=t.indexOf("Dist(",r);for(h=["Deg","Rad"],n=0;n<h.length;n++)for(a=t.indexOf(h[n]+"(");a>=0;)a>=0&&(r=t.indexOf(",",a+4))>=0&&(s=t.slice(a+4,r),s=s.replace(/\\(['"])?/g,"$1"),(o=e.elementsByName[s])&&(t=t.slice(0,a+4)+l(o.id)+t.slice(r))),r=t.indexOf(",",a+4),a=t.indexOf(",",r),r=t.indexOf(",",a+1),r>=0&&(s=t.slice(a+1,r),s=s.replace(/\\(['"])?/g,"$1"),(o=e.elementsByName[s])&&(t=t.slice(0,a+1)+l(o.id)+t.slice(r))),r=t.indexOf(",",a+1),a=t.indexOf(",",r),r=t.indexOf(")",a+1),r>=0&&(s=t.slice(a+1,r),s=s.replace(/\\(['"])?/g,"$1"),(o=e.elementsByName[s])&&(t=t.slice(0,a+1)+l(o.id)+t.slice(r))),r=t.indexOf(")",a+1),a=t.indexOf(h[n]+"(",r);return t},replaceIdByObj:function(t){var e=/(X|Y|L)\(([\w_]+)\)/g;return t=t.replace(e,"$('$2').$1()"),e=/(V)\(([\w_]+)\)/g,t=t.replace(e,"$('$2').Value()"),e=/(Dist)\(([\w_]+),([\w_]+)\)/g,t=t.replace(e,"dist($('$2'), $('$3'))"),e=/(Deg)\(([\w_]+),([ \w\[\w_]+),([\w_]+)\)/g,t=t.replace(e,"deg($('$2'),$('$3'),$('$4'))"),e=/Rad\(([\w_]+),([\w_]+),([\w_]+)\)/g,t=t.replace(e,"rad($('$1'),$('$2'),$('$3'))"),e=/N\((.+)\)/g,t=t.replace(e,"($1)")},geonext2JS:function(t,e){var i,r,s,o=["Abs","ACos","ASin","ATan","Ceil","Cos","Exp","Factorial","Floor","Log","Max","Min","Random","Round","Sin","Sqrt","Tan","Trunc"],n=["abs","acos","asin","atan","ceil","cos","exp","factorial","floor","log","max","min","random","round","sin","sqrt","tan","ceil"];for(t=t.replace(/</g,"<"),t=t.replace(/>/g,">"),t=t.replace(/&/g,"&"),r=t,r=this.replaceNameById(r,e),r=this.replaceIf(r),r=this.replacePow(r),r=this.replaceIdByObj(r),s=0;s<o.length;s++)i=new RegExp(["(\\W|^)(",o[s],")"].join(""),"ig"),r=r.replace(i,["$1",n[s]].join(""));return r=r.replace(/True/g,"true"),r=r.replace(/False/g,"false"),r=r.replace(/fasle/g,"false"),r=r.replace(/Pi/g,"PI"),r=r.replace(/"/g,"'")},findDependencies:function(t,r,s){var o,n,a,h;i.exists(s)||(s=t.board),o=s.elementsByName;for(n in o)o.hasOwnProperty(n)&&n!==t.name&&(o[n].elementClass===e.OBJECT_CLASS_TEXT?i.evaluate(o[n].visProp.islabel)||(h=n.replace(/\[/g,"\\["),h=h.replace(/\]/g,"\\]"),a=new RegExp("\\(([\\w\\[\\]'_ ]+,)*("+h+")(,[\\w\\[\\]'_ ]+)*\\)","g"),r.search(a)>=0&&o[n].addChild(t)):(h=n.replace(/\[/g,"\\["),h=h.replace(/\]/g,"\\]"),a=new RegExp("\\(([\\w\\[\\]'_ ]+,)*("+h+")(,[\\w\\[\\]'_ ]+)*\\)","g"),r.search(a)>=0&&o[n].addChild(t)))},gxt2jc:function(t,e){var i;return t=t.replace(/</g,"<"),t=t.replace(/>/g,">"),t=t.replace(/&/g,"&"),i=t,i=this.replaceNameById(i,e,!0),i=i.replace(/True/g,"true"),i=i.replace(/False/g,"false"),i=i.replace(/fasle/g,"false")}},t.GeonextParser}),define("base/element",["jxg","base/constants","base/coords","math/math","math/statistics","options","parser/geonext","utils/event","utils/color","utils/type"],function(t,e,i,r,s,o,n,a,h,l){"use strict";return t.GeometryElement=function(t,i,r,s){var o,n,h;if(this.needsUpdate=!0,this.isDraggable=!1,this.isReal=!0,this.childElements={},this.hasLabel=!1,this.highlighted=!1,this.notExistingParents={},this.traces={},this.numTraces=0,this.transformations=[],this.baseElement=null,this.descendants={},this.ancestors={},this.parents=[],this.symbolic={},this.rendNode=null,this.elType="",this.dump=!0,this.subs={},this.inherits=[],this._pos=-1,this.stdform=[1,0,0,0,1,1,0,0],this.methodMap={setLabel:"setLabel",label:"label",setName:"setName",getName:"getName",addTransform:"addTransform",setProperty:"setAttribute",setAttribute:"setAttribute",addChild:"addChild",animate:"animate",on:"on",off:"off",trigger:"trigger",addTicks:"addTicks",removeTicks:"removeTicks",removeAllTicks:"removeAllTicks"},this.quadraticform=[[1,0,0],[0,1,0],[0,0,1]],this.visProp={},this.visPropCalc={visible:!1},a.eventify(this),this.mouseover=!1,this.lastDragTime=new Date,arguments.length>0){this.board=t,this.type=r,this._org_type=r,this.elementClass=s||e.OBJECT_CLASS_OTHER,this.id=i.id,o=i.name,l.exists(o)||(o=this.board.generateName(this)),""!==o&&(this.board.elementsByName[o]=this),this.name=o,this.needsRegularUpdate=i.needsregularupdate,l.clearVisPropOld(this),h=this.resolveShortcuts(i);for(n in h)h.hasOwnProperty(n)&&this._set(n,h[n]);this.visProp.draft=h.draft&&h.draft.draft}},t.extend(t.GeometryElement.prototype,{addChild:function(t){var e,i;this.childElements[t.id]=t,this.addDescendants(t),t.ancestors[this.id]=this;for(e in this.descendants)if(this.descendants.hasOwnProperty(e)){this.descendants[e].ancestors[this.id]=this;for(i in this.ancestors)this.ancestors.hasOwnProperty(i)&&(this.descendants[e].ancestors[this.ancestors[i].id]=this.ancestors[i])}for(e in this.ancestors)if(this.ancestors.hasOwnProperty(e))for(i in this.descendants)this.descendants.hasOwnProperty(i)&&(this.ancestors[e].descendants[this.descendants[i].id]=this.descendants[i]);return this},addDescendants:function(t){var e;this.descendants[t.id]=t;for(e in t.childElements)t.childElements.hasOwnProperty(e)&&this.addDescendants(t.childElements[e]);return this},addParents:function(t){var e,i,r;for(r=l.isArray(t)?t:arguments,i=r.length,e=0;e<i;++e)l.exists(r[e])&&(l.isId(this.board,r[e])?this.parents.push(r[e]):l.exists(r[e].id)&&this.parents.push(r[e].id));this.parents=l.uniqueArray(this.parents)},setParents:function(t){this.parents=[],this.addParents(t)},removeChild:function(t){return delete this.childElements[t.id],this.removeDescendants(t),delete t.ancestors[this.id],this},removeDescendants:function(t){var e;delete this.descendants[t.id];for(e in t.childElements)t.childElements.hasOwnProperty(e)&&this.removeDescendants(t.childElements[e]);return this},countChildren:function(){var t,e,i=0;e=this.childElements;for(t in e)e.hasOwnProperty(t)&&t.indexOf("Label")<0&&i++;return i},getName:function(){return this.name},addTransform:function(t){return this},draggable:function(){return this.isDraggable&&!l.evaluate(this.visProp.fixed)&&this.type!==e.OBJECT_TYPE_GLIDER},setPosition:function(t,i){var r,s,o,n,a=[];if(!l.exists(this.parents))return this;for(o=this.parents.length,s=0;s<o;++s)if(r=this.board.select(this.parents[s]),l.isPoint(r)){if(!r.draggable())return this;a.push(r)}for(3===i.length&&(i=i.slice(1)),n=this.board.create("transform",i,{type:"translate"}),o=a.length, -o>0?n.applyOnce(a):this.transformations.length>0&&this.transformations[this.transformations.length-1].isNumericMatrix?this.transformations[this.transformations.length-1].melt(n):this.addTransform(n),s=0;s<o;++s)a[s].type===e.OBJECT_TYPE_GLIDER&&a[s].updateGlider();return this},setPositionDirectly:function(t,r,o){var n=new i(t,r,this.board,!1),a=new i(t,o,this.board,!1),h=s.subtract(n.usrCoords,a.usrCoords);return this.setPosition(e.COORDS_BY_USER,h),this},generatePolynomial:function(){return[]},animate:function(t,e,i){i=i||{};var r,s,o,n=this.board.attr.animationdelay,a=Math.ceil(e/n),c=this,d=function(t,e,i,r){var s,n;if(t=parseFloat(t),e=parseFloat(e),!isNaN(t)&&!isNaN(e))for(n=(e-t)/a,c.animationData[i]=[],o=0;o<a;o++)s=t+(o+1)*n,c.animationData[i][a-o-1]=r?Math.floor(s):s};this.animationData={};for(r in t)if(t.hasOwnProperty(r))switch(s=r.toLowerCase()){case"strokecolor":case"fillcolor":!function(t,e,i){var r,s,n,l,d;for(r=h.rgb2hsv(t),s=h.rgb2hsv(e),n=(s[0]-r[0])/a,l=(s[1]-r[1])/a,d=(s[2]-r[2])/a,c.animationData[i]=[],o=0;o<a;o++)c.animationData[i][a-o-1]=h.hsv2rgb(r[0]+(o+1)*n,r[1]+(o+1)*l,r[2]+(o+1)*d)}(this.visProp[s],t[r],s);break;case"size":if(!l.isPoint(this))break;d(this.visProp[s],t[r],s,!0);break;case"strokeopacity":case"strokewidth":case"fillopacity":d(this.visProp[s],t[r],s,!1)}return this.animationCallback=i.callback,this.board.addAnimation(this),this},update:function(){return l.evaluate(this.visProp.trace)&&this.cloneToBackground(),this},updateRenderer:function(){return this},fullUpdate:function(t){return this.prepareUpdate().update().updateVisibility(t).updateRenderer()},setDisplayRendNode:function(t){var e,i,r,s,o;if(void 0===t&&(t=this.visPropCalc.visible),t===this.visPropOld.visible)return this;for(this.board.renderer.display(this,t),i=this.inherits.length,r=0;r<i;r++)if(o=this.inherits[r],l.isArray(o))for(s=o.length,e=0;e<s;e++)l.exists(o[e])&&l.exists(o[e].rendNode)&&"inherit"===l.evaluate(o[e].visProp.visible)&&o[e].setDisplayRendNode(t);else l.exists(o)&&l.exists(o.rendNode)&&"inherit"===l.evaluate(o.visProp.visible)&&o.setDisplayRendNode(t);return this.hasLabel&&l.exists(this.label)&&l.exists(this.label.rendNode)&&"inherit"===l.evaluate(this.label.visProp.visible)&&this.label.setDisplayRendNode(t),this},hideElement:function(){return t.deprecated("Element.hideElement()","Element.setDisplayRendNode()"),this.visPropCalc.visible=this.visProp.visible=!1,this.board.renderer.display(this,!1),l.exists(this.label)&&this.hasLabel&&(this.label.hiddenByParent=!0,this.label.visPropCalc.visible&&this.label.hideElement()),this},showElement:function(){return t.deprecated("Element.showElement()","Element.setDisplayRendNode()"),this.visPropCalc.visible=this.visProp.visible=!0,this.board.renderer.display(this,!0),l.exists(this.label)&&this.hasLabel&&this.label.hiddenByParent&&(this.label.hiddenByParent=!1,this.label.visPropCalc.visible||this.label.showElement().updateRenderer()),this},updateVisibility:function(t){var e,i,r,s,o,n;if(this.needsUpdate){for(void 0!==t?this.visPropCalc.visible=t:(n=l.evaluate(this.visProp.visible),l.exists(this.hiddenByParent)&&this.hiddenByParent&&(n=!1),"inherit"!==n&&(this.visPropCalc.visible=n)),i=this.inherits.length,r=0;r<i;r++)if(o=this.inherits[r],l.isArray(o))for(s=o.length,e=0;e<s;e++)l.exists(o[e])&&"inherit"===l.evaluate(o[e].visProp.visible)&&o[e].prepareUpdate().updateVisibility(this.visPropCalc.visible);else l.exists(o)&&"inherit"===l.evaluate(o.visProp.visible)&&o.prepareUpdate().updateVisibility(this.visPropCalc.visible);l.exists(this.label)&&l.exists(this.label.visProp)&&l.evaluate(this.label.visProp.visible)&&this.label.prepareUpdate().updateVisibility(this.visPropCalc.visible)}return this},_set:function(t,e){var i;if(t=t.toLocaleLowerCase(),this.visProp.hasOwnProperty(t)&&t.indexOf("color")>=0&&l.isString(e)&&9===e.length&&"#"===e.charAt(0))e=h.rgba2rgbo(e),this.visProp[t]=e[0],this.visProp[t.replace("color","opacity")]=e[1];else if(null===e||!l.isObject(e)||l.exists(e.id)||l.exists(e.name))this.visProp[t]=e;else{this.visProp[t]={};for(i in e)e.hasOwnProperty(i)&&(this.visProp[t][i.toLocaleLowerCase()]=e[i])}},resolveShortcuts:function(t){var e,i;for(e in o.shortcuts)if(o.shortcuts.hasOwnProperty(e)&&l.exists(t[e]))for(i=0;i<o.shortcuts[e].length;i++)l.exists(t[o.shortcuts[e][i]])||(t[o.shortcuts[e][i]]=t[e]);return t},setLabel:function(t){this.hasLabel||this.setAttribute({withlabel:!0}),this.setLabelText(t)},setLabelText:function(t){return l.exists(this.label)&&(t=t.replace(/</g,"<").replace(/>/g,">"),this.label.setText(t)),this},setName:function(t){t=t.replace(/</g,"<").replace(/>/g,">"),"slider"!==this.elType&&this.setLabelText(t),this.setAttribute({name:t})},setProperty:function(){t.deprecated("setProperty()","setAttribute()"),this.setAttribute.apply(this,arguments)},setAttribute:function(i){var r,s,o,n,a,c,d,u,p,f={};for(r=0;r<arguments.length;r++)c=arguments[r],l.isString(c)?(u=c.split(":"),f[l.trim(u[0])]=l.trim(u[1])):l.isArray(c)?f[c[0]]=c[1]:t.extend(f,c);f=this.resolveShortcuts(f);for(r in f)if(f.hasOwnProperty(r)){if(n=r.replace(/\s+/g,"").toLowerCase(),a=f[r],l.isObject(a)&&l.exists(this.visProp[n])){if(this.visProp[n]=l.merge(this.visProp[n],a),this.type===e.OBJECT_TYPE_TICKS&&l.exists(this.labels))for(o=this.labels.length,s=0;s<o;s++)this.labels[s].setAttribute(a);else if(l.exists(this[n]))if(l.isArray(this[n]))for(s=0;s<this[n].length;s++)this[n][s].setAttribute(a);else this[n].setAttribute(a);continue}switch(p=this.visProp[n],n){case"name":p=this.name,delete this.board.elementsByName[this.name],this.name=a,this.board.elementsByName[this.name]=this;break;case"needsregularupdate":this.needsRegularUpdate=!("false"===a||!1===a),this.board.renderer.setBuffering(this,this.needsRegularUpdate?"auto":"static");break;case"labelcolor":a=h.rgba2rgbo(a),d=a[1],a=a[0],0===d&&l.exists(this.label)&&this.hasLabel&&this.label.hideElement(),l.exists(this.label)&&this.hasLabel&&(this.label.visProp.strokecolor=a,this.board.renderer.setObjectStrokeColor(this.label,a,d)),this.elementClass===e.OBJECT_CLASS_TEXT&&(this.visProp.strokecolor=a,this.visProp.strokeopacity=d,this.board.renderer.setObjectStrokeColor(this,a,d));break;case"infoboxtext":l.isString(a)?this.infoboxText=a:this.infoboxText=!1;break;case"visible":this.visProp.visible="false"!==a&&("true"===a||a),this.setDisplayRendNode(l.evaluate(this.visProp.visible)),l.evaluate(this.visProp.visible)&&l.exists(this.updateSize)&&this.updateSize();break;case"face":l.isPoint(this)&&(this.visProp.face=a,this.board.renderer.changePointStyle(this));break;case"trace":"false"===a||!1===a?(this.clearTrace(),this.visProp.trace=!1):this.visProp.trace="pause"!==a;break;case"gradient":this.visProp.gradient=a,this.board.renderer.setGradient(this);break;case"gradientsecondcolor":a=h.rgba2rgbo(a),this.visProp.gradientsecondcolor=a[0],this.visProp.gradientsecondopacity=a[1],this.board.renderer.updateGradient(this);break;case"gradientsecondopacity":this.visProp.gradientsecondopacity=a,this.board.renderer.updateGradient(this);break;case"withlabel":this.visProp.withlabel=a,l.evaluate(a)?(this.label||this.createLabel(),this.label.setAttribute({visible:"inherit"})):this.label&&this.hasLabel&&this.label.setAttribute({visible:!1}),this.hasLabel=a;break;case"radius":this.type!==e.OBJECT_TYPE_ANGLE&&this.type!==e.OBJECT_TYPE_SECTOR||this.setRadius(a);break;case"rotate":(this.elementClass===e.OBJECT_CLASS_TEXT&&"internal"===l.evaluate(this.visProp.display)||this.type===e.OBJECT_TYPE_IMAGE)&&this.addRotation(a);break;case"ticksdistance":this.type===e.OBJECT_TYPE_TICKS&&l.isNumber(a)&&(this.ticksFunction=this.makeTicksFunction(a));break;case"generatelabelvalue":this.type===e.OBJECT_TYPE_TICKS&&l.isFunction(a)&&(this.generateLabelValue=a);break;case"onpolygon":this.type===e.OBJECT_TYPE_GLIDER&&(this.onPolygon=!!a);break;case"disabled":l.exists(this.rendNodeTag)&&(this.rendNodeTag.disabled=!!a);break;case"checked":l.exists(this.rendNodeTag)&&(this.rendNodeCheckbox.checked=!!a);break;case"maxlength":l.exists(this.rendNodeTag)&&(this.rendNodeTag.maxlength=!!a);break;case"layer":this.board.renderer.setLayer(this,l.evaluate(a)),this._set(n,a);break;default:l.exists(this.visProp[n])&&(!t.Validator[n]||t.Validator[n]&&t.Validator[n](a)||t.Validator[n]&&l.isFunction(a)&&t.Validator[n](a()))&&(a=(!a.toLowerCase||"false"!==a.toLowerCase())&&a,this._set(n,a))}this.triggerEventHandlers(["attribute:"+n],[p,a,this])}return this.triggerEventHandlers(["attribute"],[f,this]),l.evaluate(this.visProp.needsregularupdate)?this.board.update(this):this.board.fullUpdate(),this},getProperty:function(){t.deprecated("getProperty()","getAttribute()"),this.getProperty.apply(this,arguments)},getAttribute:function(t){var e;switch(t=t.toLowerCase()){case"needsregularupdate":e=this.needsRegularUpdate;break;case"labelcolor":e=this.label.visProp.strokecolor;break;case"infoboxtext":e=this.infoboxText;break;case"withlabel":e=this.hasLabel;break;default:e=this.visProp[t]}return e},setDash:function(t){return this.setAttribute({dash:t}),this},prepareUpdate:function(){return this.needsUpdate=!0,this},remove:function(){return this.board.renderer.remove(this.board.renderer.getElementById(this.id)),this.hasLabel&&this.board.renderer.remove(this.board.renderer.getElementById(this.label.id)),this},getTextAnchor:function(){return new i(e.COORDS_BY_USER,[0,0],this.board)},getLabelAnchor:function(){return new i(e.COORDS_BY_USER,[0,0],this.board)},setArrow:function(t,i){return this.visProp.firstarrow=t,this.visProp.lastarrow=i,i&&(this.type=e.OBJECT_TYPE_VECTOR,this.elType="arrow"),this.prepareUpdate().update().updateVisibility().updateRenderer(),this},createGradient:function(){var t=l.evaluate(this.visProp.gradient);"linear"!==t&&"radial"!==t||this.board.renderer.setGradient(this)},createLabel:function(){var e,i=this;return t.elements.text?(e=l.deepCopy(this.visProp.label,null),e.id=this.id+"Label",e.isLabel=!0,e.anchor=this,e.priv=this.visProp.priv,this.visProp.withlabel&&(this.label=t.elements.text(this.board,[0,0,function(){return l.isFunction(i.name)?i.name():i.name}],e),this.label.needsUpdate=!0,this.label.dump=!1,this.label.fullUpdate(),this.hasLabel=!0)):t.debug("JSXGraph: Can't create label: text element is not available. Make sure you include base/text"),this},highlight:function(t){return t=l.def(t,!1),!l.evaluate(this.visProp.highlight)||this.highlighted&&!t||(this.highlighted=!0,this.board.highlightedObjects[this.id]=this,this.board.renderer.highlight(this)),this},noHighlight:function(){return this.highlighted&&(this.highlighted=!1,delete this.board.highlightedObjects[this.id],this.board.renderer.noHighlight(this)),this},clearTrace:function(){var t;for(t in this.traces)this.traces.hasOwnProperty(t)&&this.board.renderer.remove(this.traces[t]);return this.numTraces=0,this},cloneToBackground:function(){return this},bounds:function(){return[0,0,0,0]},normalize:function(){return this.stdform=r.normalize(this.stdform),this},toJSON:function(){var t,e,i=['{"name":',this.name];i.push(', "id":'+this.id),t=[];for(e in this.visProp)this.visProp.hasOwnProperty(e)&&l.exists(this.visProp[e])&&t.push('"'+e+'":'+this.visProp[e]);return i.push(', "visProp":{'+t.toString()+"}"),i.push("}"),i.join("")},addRotation:function(t){var i,r,s,o,n,a=this;return(this.elementClass===e.OBJECT_CLASS_TEXT&&"internal"===l.evaluate(this.visProp.display)||this.type===e.OBJECT_TYPE_IMAGE)&&0!==t&&(i=this.board.create("transform",[function(){return-a.X()},function(){return-a.Y()}],{type:"translate"}),r=this.board.create("transform",[function(){return a.X()},function(){return a.Y()}],{type:"translate"}),s=this.board.create("transform",[function(){return a.board.unitX/a.board.unitY},function(){return 1}],{type:"scale"}),o=this.board.create("transform",[function(){return a.board.unitY/a.board.unitX},function(){return 1}],{type:"scale"}),n=this.board.create("transform",[function(){return l.evaluate(t)*Math.PI/180}],{type:"rotate"}),i.bindTo(this),s.bindTo(this),n.bindTo(this),o.bindTo(this),r.bindTo(this)),this},highlightStrokeColor:function(e){return t.deprecated("highlightStrokeColor()","setAttribute()"),this.setAttribute({highlightStrokeColor:e}),this},strokeColor:function(e){return t.deprecated("strokeColor()","setAttribute()"),this.setAttribute({strokeColor:e}),this},strokeWidth:function(e){return t.deprecated("strokeWidth()","setAttribute()"),this.setAttribute({strokeWidth:e}),this},fillColor:function(e){return t.deprecated("fillColor()","setAttribute()"),this.setAttribute({fillColor:e}),this},highlightFillColor:function(e){return t.deprecated("highlightFillColor()","setAttribute()"),this.setAttribute({highlightFillColor:e}),this},labelColor:function(e){return t.deprecated("labelColor()","setAttribute()"),this.setAttribute({labelColor:e}),this},dash:function(e){return t.deprecated("dash()","setAttribute()"),this.setAttribute({dash:e}),this},visible:function(e){return t.deprecated("visible()","setAttribute()"),this.setAttribute({visible:e}),this},shadow:function(e){return t.deprecated("shadow()","setAttribute()"),this.setAttribute({shadow:e}),this},getType:function(){return this.elType},getParents:function(){return l.isArray(this.parents)?this.parents:[]},snapToGrid:function(){return this},snapToPoints:function(){return this},getAttributes:function(){var t,e=l.deepCopy(this.visProp),i=[],r=i.length;for(e.id=this.id,e.name=this.name,t=0;t<r;t++)delete e[i[t]];return e},hasPoint:function(t,e){return!1},addTicks:function(t){return""!==t.id&&l.exists(t.id)||(t.id=this.id+"_ticks_"+(this.ticks.length+1)),this.board.renderer.drawTicks(t),this.ticks.push(t),t.id},removeAllTicks:function(){var t;if(l.exists(this.ticks)){for(t=this.ticks.length;t>0;t--)this.removeTicks(this.ticks[t-1]);this.ticks=[],this.board.update()}},removeTicks:function(t){var e,i;if(l.exists(this.defaultTicks)&&this.defaultTicks===t&&(this.defaultTicks=null),l.exists(this.ticks))for(e=this.ticks.length;e>0;e--)if(this.ticks[e-1]===t){if(this.board.removeObject(this.ticks[e-1]),this.ticks[e-1].ticks)for(i=0;i<this.ticks[e-1].ticks.length;i++)l.exists(this.ticks[e-1].labels[i])&&this.board.removeObject(this.ticks[e-1].labels[i]);delete this.ticks[e-1];break}},handleSnapToGrid:function(t,i){var r,s,o,n,a=!1,h=l.evaluate(this.visProp.snapsizex),c=l.evaluate(this.visProp.snapsizey);return l.exists(this.coords)?(a=l.evaluate(this.visProp.snaptogrid)||!0===t,a&&(r=this.coords.usrCoords[1],s=this.coords.usrCoords[2],h<=0&&this.board.defaultAxes&&this.board.defaultAxes.x.defaultTicks&&(o=this.board.defaultAxes.x.defaultTicks,h=o.ticksDelta*(l.evaluate(o.visProp.minorticks)+1)),c<=0&&this.board.defaultAxes&&this.board.defaultAxes.y.defaultTicks&&(o=this.board.defaultAxes.y.defaultTicks,c=o.ticksDelta*(l.evaluate(o.visProp.minorticks)+1)),h>0&&c>0&&(n=this.board.getBoundingBox(),r=Math.round(r/h)*h,s=Math.round(s/c)*c,i||(r<n[0]?r+=h:r>n[2]&&(r-=h),s<n[3]?s+=c:s>n[1]&&(s-=c)),this.coords.setCoordinates(e.COORDS_BY_USER,[r,s]))),this):this},getBoundingBox:function(){var t,i,r,s,o,n=[1/0,1/0,-1/0,-1/0];if(this.type===e.OBJECT_TYPE_POLYGON){if((i=this.vertices.length-1)<=0)return n;for(t=0;t<i;t++)r=this.vertices[t].X(),n[0]=r<n[0]?r:n[0],n[2]=r>n[2]?r:n[2],r=this.vertices[t].Y(),n[1]=r<n[1]?r:n[1],n[3]=r>n[3]?r:n[3]}else if(this.elementClass===e.OBJECT_CLASS_CIRCLE)s=this.center.X(),o=this.center.Y(),n=[s-this.radius,o+this.radius,s+this.radius,o-this.radius];else if(this.elementClass===e.OBJECT_CLASS_CURVE){if(0===(i=this.vertices.length))return n;for(t=0;t<i;t++)r=this.points[t].coords.usrCoords[1],n[0]=r<n[0]?r:n[0],n[2]=r>n[2]?r:n[2],r=this.points[t].coords.usrCoords[1],n[1]=r<n[1]?r:n[1],n[3]=r>n[3]?r:n[3]}return n},addEvent:t.shortcut(t.GeometryElement.prototype,"on"),removeEvent:t.shortcut(t.GeometryElement.prototype,"off"),__evt__over:function(t){},__evt__mouseover:function(t){},__evt__out:function(t){},__evt__mouseout:function(t){},__evt__move:function(t){},__evt__mousemove:function(t){},__evt__drag:function(t){},__evt__mousedrag:function(t){},__evt__pendrag:function(t){},__evt__touchdrag:function(t){},__evt__down:function(t){},__evt__mousedown:function(t){},__evt__pendown:function(t){},__evt__touchdown:function(t){},__evt__up:function(t){},__evt__mouseup:function(t){},__evt__penup:function(t){},__evt__touchup:function(t){},__evt__attribute:function(t,e){},__evt__attribute_:function(t,e,i){},__evt:function(){}}),t.GeometryElement}),define("base/transformation",["jxg","base/constants","math/math","utils/type"],function(t,e,i,r){"use strict";return t.Transformation=function(t,i,r){this.elementClass=e.OBJECT_CLASS_OTHER,this.type=e.OBJECT_TYPE_TRANSFORMATION,this.matrix=[[1,0,0],[0,1,0],[0,0,1]],this.board=t,this.isNumericMatrix=!1,this.setMatrix(t,i,r),this.methodMap={apply:"apply",applyOnce:"applyOnce",bindTo:"bindTo",bind:"bind",melt:"melt"}},t.Transformation.prototype={},t.extend(t.Transformation.prototype,{update:function(){return this},setMatrix:function(t,e,s){var o;for(this.isNumericMatrix=!0,o=0;o<s.length;o++)if("number"!=typeof s[o]){this.isNumericMatrix=!1;break}if("translate"===e){if(2!==s.length)throw new Error("JSXGraph: translate transformation needs 2 parameters.");this.evalParam=r.createEvalFunction(t,s,2),this.update=function(){this.matrix[1][0]=this.evalParam(0),this.matrix[2][0]=this.evalParam(1)}}else if("scale"===e){if(2!==s.length)throw new Error("JSXGraph: scale transformation needs 2 parameters.");this.evalParam=r.createEvalFunction(t,s,2),this.update=function(){this.matrix[1][1]=this.evalParam(0),this.matrix[2][2]=this.evalParam(1)}}else if("reflect"===e)s.length<4&&(s[0]=t.select(s[0])),2===s.length&&(s[1]=t.select(s[1])),4===s.length&&(this.evalParam=r.createEvalFunction(t,s,4)),this.update=function(){var t,e,r,o,n,a,h,l;1===s.length?h=s[0].stdform:2===s.length?h=i.crossProduct(s[1].coords.usrCoords,s[0].coords.usrCoords):4===s.length&&(h=i.crossProduct([1,this.evalParam(2),this.evalParam(3)],[1,this.evalParam(0),this.evalParam(1)])),t=h[1],e=h[2],r=h[0],l=[-r*t,-r*e,t*t+e*e],a=l[2],o=l[0]/l[2],n=l[1]/l[2],t=-h[2],e=h[1],this.matrix[1][1]=(t*t-e*e)/a,this.matrix[1][2]=2*t*e/a,this.matrix[2][1]=this.matrix[1][2],this.matrix[2][2]=-this.matrix[1][1],this.matrix[1][0]=o*(1-this.matrix[1][1])-n*this.matrix[1][2],this.matrix[2][0]=n*(1-this.matrix[2][2])-o*this.matrix[2][1]};else if("rotate"===e)3===s.length?this.evalParam=r.createEvalFunction(t,s,3):s.length>0&&s.length<=2&&(this.evalParam=r.createEvalFunction(t,s,1),2!==s.length||r.isArray(s[1])||(s[1]=t.select(s[1]))),this.update=function(){var t,e,i=this.evalParam(0),o=Math.cos(i),n=Math.sin(i);this.matrix[1][1]=o,this.matrix[1][2]=-n,this.matrix[2][1]=n,this.matrix[2][2]=o,s.length>1&&(3===s.length?(t=this.evalParam(1),e=this.evalParam(2)):r.isArray(s[1])?(t=s[1][0],e=s[1][1]):(t=s[1].X(),e=s[1].Y()),this.matrix[1][0]=t*(1-o)+e*n,this.matrix[2][0]=e*(1-o)-t*n)};else if("shear"===e){if(2!==s.length)throw new Error("JSXGraph: shear transformation needs 2 parameters.");this.evalParam=r.createEvalFunction(t,s,2),this.update=function(){this.matrix[1][2]=this.evalParam(0),this.matrix[2][1]=this.evalParam(1)}}else if("generic"===e){if(9!==s.length)throw new Error("JSXGraph: generic transformation needs 9 parameters.");this.evalParam=r.createEvalFunction(t,s,9),this.update=function(){this.matrix[0][0]=this.evalParam(0),this.matrix[0][1]=this.evalParam(1),this.matrix[0][2]=this.evalParam(2),this.matrix[1][0]=this.evalParam(3),this.matrix[1][1]=this.evalParam(4),this.matrix[1][2]=this.evalParam(5),this.matrix[2][0]=this.evalParam(6),this.matrix[2][1]=this.evalParam(7),this.matrix[2][2]=this.evalParam(8)}}},apply:function(t,e){return this.update(),r.exists(e)?i.matVecMult(this.matrix,t.initialCoords.usrCoords):i.matVecMult(this.matrix,t.coords.usrCoords)},applyOnce:function(t){var s,o,n;for(r.isArray(t)||(t=[t]),o=t.length,n=0;n<o;n++)this.update(),s=i.matVecMult(this.matrix,t[n].coords.usrCoords),t[n].coords.setCoordinates(e.COORDS_BY_USER,s)},bindTo:function(t){var e,i;if(r.isArray(t))for(i=t.length,e=0;e<i;e++)t[e].transformations.push(this);else t.transformations.push(this)},setProperty:function(e){t.deprecated("Transformation.setProperty()","Transformation.setAttribute()")},setAttribute:function(t){},melt:function(t){var e,i,r,s,o,n,a=[];for(i=t.matrix.length,r=this.matrix[0].length,e=0;e<i;e++)a[e]=[];for(this.update(),t.update(),e=0;e<i;e++)for(n=0;n<r;n++){for(o=0,s=0;s<i;s++)o+=t.matrix[e][s]*this.matrix[s][n];a[e][n]=o}return this.update=function(){var t=this.matrix.length,i=this.matrix[0].length;for(e=0;e<t;e++)for(n=0;n<i;n++)this.matrix[e][n]=a[e][n]},this},getParents:function(){var t=[[].concat.apply([],this.matrix)];return 0!==this.parents.length&&(t=this.parents),t}}),t.createTransform=function(e,i,r){return new t.Transformation(e,r.type,i)},t.registerElement("transform",t.createTransform),{Transformation:t.Transformation,createTransform:t.createTransform}}),define("base/coordselement",["jxg","options","math/math","math/geometry","math/numerics","math/statistics","base/coords","base/constants","base/element","parser/geonext","utils/type","base/transformation"],function(t,e,i,r,s,o,n,a,h,l,c,d){"use strict";return t.CoordsElement=function(t,e){var i;for(c.exists(t)||(t=[1,0,0]),i=0;i<t.length;++i)t[i]=parseFloat(t[i]);this.coords=new n(a.COORDS_BY_USER,t,this.board),this.initialCoords=new n(a.COORDS_BY_USER,t,this.board),this.position=null,this.onPolygon=!1,this.slideObject=null,this.slideObjects=[],this.needsUpdateFromParent=!0,this.updateConstraint=function(){return this},this.groups=[],this.Xjc=null,this.Yjc=null,this.methodMap=c.deepCopy(this.methodMap,{move:"moveTo",moveTo:"moveTo",moveAlong:"moveAlong",visit:"visit",glide:"makeGlider",makeGlider:"makeGlider",intersect:"makeIntersection",makeIntersection:"makeIntersection",X:"X",Y:"Y",free:"free",setPosition:"setGliderPosition",setGliderPosition:"setGliderPosition",addConstraint:"addConstraint",dist:"Dist",onPolygon:"onPolygon"}),c.exists(this.element)&&this.addAnchor(t,e),this.isDraggable=!0},t.extend(t.CoordsElement.prototype,{updateCoords:function(t){return this.needsUpdate?(c.exists(t)||(t=!1),this.type===a.OBJECT_TYPE_GLIDER&&(t?this.updateGliderFromParent():this.updateGlider()),c.evaluate(this.visProp.frozen)||this.updateConstraint(),this.updateTransform(),this):this},updateGlider:function(){var t,e,s,o,h,l,d,u,p,f,m,g,b,v,y,C,_,P,E,x,S,w=2*Math.PI,O=!1,T=this.slideObject,N=[];if(this.needsUpdateFromParent=!1,T.elementClass===a.OBJECT_CLASS_CIRCLE)c.evaluate(this.visProp.isgeonext)&&(w=1),C=r.projectPointToCircle(this,T,this.board),_=r.rad([T.center.X()+1,T.center.Y()],T.center,this)/w;else if(T.elementClass===a.OBJECT_CLASS_LINE){if(this.onPolygon){if(e=T.point1.coords.usrCoords,s=T.point2.coords.usrCoords,t=1,o=s[t]-e[t],Math.abs(o)<i.eps&&(t=2,o=s[t]-e[t]),d=r.projectPointToLine(this,T,this.board),u=(d.usrCoords[t]-e[t])/o,l=T.parentPolygon,u<0){for(t=0;t<l.borders.length;t++)if(T===l.borders[t]){T=l.borders[(t-1+l.borders.length)%l.borders.length];break}}else if(u>1)for(t=0;t<l.borders.length;t++)if(T===l.borders[t]){T=l.borders[(t+1+l.borders.length)%l.borders.length];break}T.id!==this.slideObject.id&&(this.slideObject=T)}e=T.point1.coords,s=T.point2.coords,o=e.distance(a.COORDS_BY_USER,s),o<i.eps?(C=e,O=!0,_=0):(C=r.projectPointToLine(this,T,this.board),e=e.usrCoords.slice(0),s=s.usrCoords.slice(0),Math.abs(s[0])<i.eps?(t=1,o=s[t],Math.abs(o)<i.eps&&(t=2,o=s[t]),o=(C.usrCoords[t]-e[t])/o,p=o>=0?1:-1,o=Math.abs(o),_=p*o/(o+1)):Math.abs(e[0])<i.eps?(t=1,o=e[t],Math.abs(o)<i.eps&&(t=2,o=e[t]),o=(C.usrCoords[t]-s[t])/o,_=o<0?(1-2*o)/(1-o):1/(o+1)):(t=1,o=s[t]-e[t],Math.abs(o)<i.eps&&(t=2,o=s[t]-e[t]),_=(C.usrCoords[t]-e[t])/o)),P=c.evaluate(this.visProp.snapwidth),c.evaluate(P)>0&&Math.abs(this._smax-this._smin)>=i.eps&&(_=Math.max(Math.min(_,1),0),h=_*(this._smax-this._smin)+this._smin,h=Math.round(h/P)*P,_=(h-this._smin)/(this._smax-this._smin),this.update(!0)),e=T.point1.coords,!c.evaluate(T.visProp.straightfirst)&&Math.abs(e.usrCoords[0])>i.eps&&_<0&&(C=e,O=!0,_=0),s=T.point2.coords,!c.evaluate(T.visProp.straightlast)&&Math.abs(s.usrCoords[0])>i.eps&&_>1&&(C=s,O=!0,_=1)}else if(T.type===a.OBJECT_TYPE_TURTLE)this.updateConstraint(),C=r.projectPointToTurtle(this,T,this.board),_=this.position;else if(T.elementClass===a.OBJECT_CLASS_CURVE)if(T.type===a.OBJECT_TYPE_ARC||T.type===a.OBJECT_TYPE_SECTOR)C=r.projectPointToCircle(this,T,this.board),g=r.rad(T.radiuspoint,T.center,this),f=0,m=r.rad(T.radiuspoint,T.center,T.anglepoint),_=g,P=c.evaluate(T.visProp.selection),("minor"===P&&m>Math.PI||"major"===P&&m<Math.PI)&&(f=m,m=2*Math.PI),(g<f||g>m)&&(_=m,(g<f&&g>.5*f||g>m&&g>.5*m+Math.PI)&&(_=f),this.needsUpdateFromParent=!0,this.updateGliderFromParent()),w=m-f,this.visProp.isgeonext&&(w=1),Math.abs(w)>i.eps&&(_/=w);else if(this.updateConstraint(),T.transformations.length>0){for(S=!1,E=T.getTransformationSource(),E[0]&&(S=E[0],N.push(T),N.push(E[1]));E[0]&&c.exists(E[1]._transformationSource);)E=E[1].getTransformationSource(),N.push(E[1]);if(x=this.coords.usrCoords,S){for(t=0;t<N.length;t++)N[t].updateTransformMatrix(),y=i.inverse(N[t].transformMat),x=i.matVecMult(y,x);for(b=new n(a.COORDS_BY_USER,x,this.board).usrCoords,v=r.projectCoordsToCurve(b[1],b[2],this.position||0,N[N.length-1],this.board),x=v[0].usrCoords,t=N.length-2;t>=0;t--)x=i.matVecMult(N[t].transformMat,x);v[0]=new n(a.COORDS_BY_USER,x,this.board)}else T.updateTransformMatrix(),y=i.inverse(T.transformMat),x=i.matVecMult(y,x),b=new n(a.COORDS_BY_USER,x,this.board).usrCoords,v=r.projectCoordsToCurve(b[1],b[2],this.position||0,T,this.board);C=v[0],_=v[1]}else C=r.projectPointToCurve(this,T,this.board),_=this.position;else c.isPoint(T)&&(C=r.projectPointToPoint(this,T,this.board),_=this.position);this.coords.setCoordinates(a.COORDS_BY_USER,C.usrCoords,O),this.position=_},updateGliderFromParent:function(){var t,e,s,o,h,l,d,u,p,f,m,g,b=this.slideObject,v=[],y=2*Math.PI;if(!this.needsUpdateFromParent)return void(this.needsUpdateFromParent=!0);if(b.elementClass===a.OBJECT_CLASS_CIRCLE)s=b.Radius(),c.evaluate(this.visProp.isgeonext)&&(y=1),h=[b.center.X()+s*Math.cos(this.position*y),b.center.Y()+s*Math.sin(this.position*y)];else if(b.elementClass===a.OBJECT_CLASS_LINE)t=b.point1.coords.usrCoords,e=b.point2.coords.usrCoords,0===t[0]&&0===t[1]&&0===t[2]||0===e[0]&&0===e[1]&&0===e[2]?h=[0,0,0]:Math.abs(e[0])<i.eps?(o=Math.min(Math.abs(this.position),1-i.eps),o/=1-o,this.position<0&&(o=-o),h=[t[0]+o*e[0],t[1]+o*e[1],t[2]+o*e[2]]):Math.abs(t[0])<i.eps?(o=Math.max(this.position,i.eps),o=Math.min(o,2-i.eps),o=o>1?(o-1)/(o-2):(1-o)/o,h=[e[0]+o*t[0],e[1]+o*t[1],e[2]+o*t[2]]):(o=this.position,h=[t[0]+o*(e[0]-t[0]),t[1]+o*(e[1]-t[1]),t[2]+o*(e[2]-t[2])]);else if(b.type===a.OBJECT_TYPE_TURTLE)this.coords.setCoordinates(a.COORDS_BY_USER,[b.Z(this.position),b.X(this.position),b.Y(this.position)]),this.updateConstraint(),h=r.projectPointToTurtle(this,b,this.board).usrCoords;else if(b.elementClass===a.OBJECT_CLASS_CURVE){for(u=!1,l=b.getTransformationSource(),l[0]&&(u=l[0],v.push(b),v.push(l[1]));l[0]&&c.exists(l[1]._transformationSource);)l=l[1].getTransformationSource(),v.push(l[1]);if(u?this.coords.setCoordinates(a.COORDS_BY_USER,[v[v.length-1].Z(this.position),v[v.length-1].X(this.position),v[v.length-1].Y(this.position)]):this.coords.setCoordinates(a.COORDS_BY_USER,[b.Z(this.position),b.X(this.position),b.Y(this.position)]),b.type===a.OBJECT_TYPE_ARC||b.type===a.OBJECT_TYPE_SECTOR)p=r.rad([b.center.X()+1,b.center.Y()],b.center,b.radiuspoint),f=0,g=r.rad(b.radiuspoint,b.center,b.anglepoint),("minor"===b.visProp.selection&&g>Math.PI||"major"===b.visProp.selection&&g<Math.PI)&&(f=g,g=2*Math.PI),y=g-f,c.evaluate(this.visProp.isgeonext)&&(y=1),m=this.position*y,(m<f||m>g)&&(m=g,(m<f&&m>.5*f||m>g&&m>.5*g+Math.PI)&&(m=f),this.position=m,Math.abs(y)>i.eps&&(this.position/=y)),s=b.Radius(),h=[b.center.X()+s*Math.cos(this.position*y+p),b.center.Y()+s*Math.sin(this.position*y+p)];else if(this.updateConstraint(),u)for(h=r.projectPointToCurve(this,v[v.length-1],this.board).usrCoords,d=v.length-2;d>=0;d--)h=new n(a.COORDS_BY_USER,i.matVecMult(v[d].transformMat,h),this.board).usrCoords;else h=r.projectPointToCurve(this,b,this.board).usrCoords}else c.isPoint(b)&&(h=r.projectPointToPoint(this,b,this.board).usrCoords);this.coords.setCoordinates(a.COORDS_BY_USER,h,!1)},updateRendererGeneric:function(t){return this.needsUpdate?(this.visPropCalc.visible&&(this.isReal=!isNaN(this.coords.usrCoords[1]+this.coords.usrCoords[2]),this.isReal=Math.abs(this.coords.usrCoords[0])>i.eps&&this.isReal,this.isReal||this.updateVisibility(!1)),this.visPropCalc.visible&&this.board.renderer[t](this),this.hasLabel&&this.visPropCalc.visible&&this.label&&this.label.visPropCalc.visible&&this.isReal&&(this.label.update(),this.board.renderer.updateText(this.label)),this.setDisplayRendNode(),this.needsUpdate=!1,this):this},X:function(){return this.coords.usrCoords[1]},Y:function(){return this.coords.usrCoords[2]},Z:function(){return this.coords.usrCoords[0]},XEval:function(){return this.coords.usrCoords[1]},YEval:function(){return this.coords.usrCoords[2]},ZEval:function(){return this.coords.usrCoords[0]},Dist:function(t){return this.isReal&&t.isReal?this.coords.distance(a.COORDS_BY_USER,t.coords):NaN},snapToGrid:function(t){return this.handleSnapToGrid(t)},handleSnapToPoints:function(t){var e,i,s,o,n,h,l,d,u=0,p=1/0,f=null,m=c.evaluate(this.visProp.ignoredsnaptopoints),g=!1;if(o=this.board.objectsList.length,m&&(l=m.length),c.evaluate(this.visProp.snaptopoints)||t){for(n=c.evaluate(this.visProp.attractorunit),h=c.evaluate(this.visProp.attractordistance),e=0;e<o;e++){if(i=this.board.objectsList[e],m){for(g=!1,d=0;d<l;d++)if(i===this.board.select(m[d])){g=!0;break}if(g)continue}c.isPoint(i)&&i!==this&&i.visPropCalc.visible&&(s=r.projectPointToPoint(this,i,this.board),(u="screen"===n?s.distance(a.COORDS_BY_SCREEN,this.coords):s.distance(a.COORDS_BY_USER,this.coords))<h&&u<p&&(p=u,f=s))}null!==f&&this.coords.setCoordinates(a.COORDS_BY_USER,f.usrCoords)}return this},snapToPoints:function(t){return this.handleSnapToPoints(t)},handleAttractors:function(){var t,e,i,s,o=0,h=c.evaluate(this.visProp.attractorunit),l=c.evaluate(this.visProp.attractordistance),d=c.evaluate(this.visProp.snatchdistance),u=c.evaluate(this.visProp.attractors),p=u.length;if(0!==l){for(t=0;t<p;t++)if(e=this.board.select(u[t]),c.exists(e)&&e!==this){if(c.isPoint(e)?i=r.projectPointToPoint(this,e,this.board):e.elementClass===a.OBJECT_CLASS_LINE?(s=r.projectCoordsToSegment(this.coords.usrCoords,e.point1.coords.usrCoords,e.point2.coords.usrCoords),i=!c.evaluate(e.visProp.straightfirst)&&s[1]<0?e.point1.coords:!c.evaluate(e.visProp.straightlast)&&s[1]>1?e.point2.coords:new n(a.COORDS_BY_USER,s[0],this.board)):e.elementClass===a.OBJECT_CLASS_CIRCLE?i=r.projectPointToCircle(this,e,this.board):e.elementClass===a.OBJECT_CLASS_CURVE?i=r.projectPointToCurve(this,e,this.board):e.type===a.OBJECT_TYPE_TURTLE&&(i=r.projectPointToTurtle(this,e,this.board)),(o="screen"===h?i.distance(a.COORDS_BY_SCREEN,this.coords):i.distance(a.COORDS_BY_USER,this.coords))<l){this.type===a.OBJECT_TYPE_GLIDER&&this.slideObject===e||this.makeGlider(e);break}e===this.slideObject&&o>=d&&this.popSlideObject()}return this}},setPositionDirectly:function(t,e){var r,s,h,l,d=this.coords;if(this.relativeCoords)return s=new n(t,e,this.board),c.evaluate(this.visProp.islabel)?(h=o.subtract(s.scrCoords,d.scrCoords),this.relativeCoords.scrCoords[1]+=h[1],this.relativeCoords.scrCoords[2]+=h[2]):(h=o.subtract(s.usrCoords,d.usrCoords),this.relativeCoords.usrCoords[1]+=h[1],this.relativeCoords.usrCoords[2]+=h[2]),this;for(this.coords.setCoordinates(t,e),this.handleSnapToGrid(),this.handleSnapToPoints(),this.handleAttractors(),r=this.transformations.length-1;r>=0;r--)t===a.COORDS_BY_SCREEN?l=new n(t,e,this.board).usrCoords:(2===e.length&&(e=[1].concat(e)),l=e), -this.initialCoords.setCoordinates(a.COORDS_BY_USER,i.matVecMult(i.inverse(this.transformations[r].matrix),l));return this.prepareUpdate().update(),this.board.isSuspendedUpdate&&this.type===a.OBJECT_TYPE_GLIDER&&this.updateGlider(),this},setPositionByTransform:function(t,e){var i;return e=new n(t,e,this.board),i=this.board.create("transform",e.usrCoords.slice(1),{type:"translate"}),this.transformations.length>0&&this.transformations[this.transformations.length-1].isNumericMatrix?this.transformations[this.transformations.length-1].melt(i):this.addTransform(this,i),this.prepareUpdate().update(),this},setPosition:function(t,e){return this.setPositionDirectly(t,e)},setGliderPosition:function(t){return this.type===a.OBJECT_TYPE_GLIDER&&(this.position=t,this.board.update()),this},makeGlider:function(e){var i,r,s,o=this.board.select(e),n=!1;if(o.type===a.OBJECT_TYPE_POLYGON){for(i=Number.MAX_VALUE,r=0;r<o.borders.length;r++)(s=t.Math.Geometry.distPointLine(this.coords.usrCoords,o.borders[r].stdform))<i&&(i=s,e=o.borders[r]);o=this.board.select(e),n=!0}if(!c.exists(o))throw new Error("JSXGraph: slide object undefined.");if(o.type===a.OBJECT_TYPE_TICKS)throw new Error("JSXGraph: gliders on ticks are not possible.");return this.slideObject=this.board.select(e),this.slideObjects.push(this.slideObject),this.addParents(e),this.type=a.OBJECT_TYPE_GLIDER,this.elType="glider",this.visProp.snapwidth=-1,this.slideObject.addChild(this),this.isDraggable=!0,this.onPolygon=n,this.generatePolynomial=function(){return this.slideObject.generatePolynomial(this)},this.updateGlider(),this.needsUpdateFromParent=!0,this.updateGliderFromParent(),this},popSlideObject:function(){this.slideObjects.length>0&&(this.slideObjects.pop(),this.slideObject.removeChild(this),0===this.slideObjects.length?(this.type=this._org_type,this.type===a.OBJECT_TYPE_POINT?this.elType="point":this.elementClass===a.OBJECT_CLASS_TEXT?this.elType="text":this.type===a.OBJECT_TYPE_IMAGE&&(this.elType="image"),this.slideObject=null):this.slideObject=this.slideObjects[this.slideObjects.length-1])},free:function(){var t,e;if(this.type!==a.OBJECT_TYPE_GLIDER){if(this.transformations.length=0,this.updateConstraint=function(){return this},this.isDraggable)return;this.isDraggable=!0,this.elementClass===a.OBJECT_CLASS_POINT&&(this.type=a.OBJECT_TYPE_POINT,this.elType="point"),this.XEval=function(){return this.coords.usrCoords[1]},this.YEval=function(){return this.coords.usrCoords[2]},this.ZEval=function(){return this.coords.usrCoords[0]},this.Xjc=null,this.Yjc=null}for(t in this.board.objects)this.board.objects.hasOwnProperty(t)&&(e=this.board.objects[t],e.descendants&&(delete e.descendants[this.id],delete e.childElements[this.id],this.hasLabel&&(delete e.descendants[this.label.id],delete e.childElements[this.label.id])));this.ancestors={},this.slideObject=null,this.slideObjects=[],this.elementClass===a.OBJECT_CLASS_POINT?(this.type=a.OBJECT_TYPE_POINT,this.elType="point"):this.elementClass===a.OBJECT_CLASS_TEXT?(this.type=this._org_type,this.elType="text"):this.elementClass===a.OBJECT_CLASS_OTHER&&(this.type=this._org_type,this.elType="image")},addConstraint:function(t){var e,i,r=[],s=["X","Y"];for(this.elementClass===a.OBJECT_CLASS_POINT&&(this.type=a.OBJECT_TYPE_CAS),this.isDraggable=!1,e=0;e<t.length;e++)i=t[e],c.isString(i)?(r[e]=this.board.jc.snippet(i,!0,null,!0),2===t.length&&(this[s[e]+"jc"]=t[e])):c.isFunction(i)?r[e]=i:c.isNumber(i)?r[e]=function(t){return function(){return t}}(i):c.isObject(i)&&c.isFunction(i.Value)&&(r[e]=function(t){return function(){return t.Value()}}(i)),r[e].origin=i;return 1===t.length?this.updateConstraint=function(){var t=r[0]();c.isArray(t)?this.coords.setCoordinates(a.COORDS_BY_USER,t):this.coords=t}:2===t.length?(this.XEval=r[0],this.YEval=r[1],this.setParents([r[0].origin,r[1].origin]),this.updateConstraint=function(){this.coords.setCoordinates(a.COORDS_BY_USER,[this.XEval(),this.YEval()])}):(this.ZEval=r[0],this.XEval=r[1],this.YEval=r[2],this.setParents([r[0].origin,r[1].origin,r[2].origin]),this.updateConstraint=function(){this.coords.setCoordinates(a.COORDS_BY_USER,[this.ZEval(),this.XEval(),this.YEval()])}),this.prepareUpdate().update(),this.board.isSuspendedUpdate||(this.updateVisibility().updateRenderer(),this.hasLabel&&this.label.fullUpdate()),this},addAnchor:function(t,e){this.relativeCoords=e?new n(a.COORDS_BY_SCREEN,t.slice(0,2),this.board):new n(a.COORDS_BY_USER,t,this.board),this.element.addChild(this),e&&this.addParents(this.element),this.XEval=function(){var t,e,i,r;return c.evaluate(this.visProp.islabel)?(r=c.evaluate(this.visProp.offset),t=parseFloat(r[0]),i=this.element.getLabelAnchor(),e=new n(a.COORDS_BY_SCREEN,[t+this.relativeCoords.scrCoords[1]+i.scrCoords[1],0],this.board),e.usrCoords[1]):(i=this.element.getTextAnchor(),this.relativeCoords.usrCoords[1]+i.usrCoords[1])},this.YEval=function(){var t,e,i,r;return c.evaluate(this.visProp.islabel)?(r=c.evaluate(this.visProp.offset),t=-parseFloat(r[1]),i=this.element.getLabelAnchor(),e=new n(a.COORDS_BY_SCREEN,[0,t+this.relativeCoords.scrCoords[2]+i.scrCoords[2]],this.board),e.usrCoords[2]):(i=this.element.getTextAnchor(),this.relativeCoords.usrCoords[2]+i.usrCoords[2])},this.ZEval=c.createFunction(1,this.board,""),this.updateConstraint=function(){this.coords.setCoordinates(a.COORDS_BY_USER,[this.ZEval(),this.XEval(),this.YEval()])},this.updateConstraint()},updateTransform:function(){var t;if(0===this.transformations.length)return this;for(t=0;t<this.transformations.length;t++)this.transformations[t].update();return this},addTransform:function(t,e){var i,r=c.isArray(e)?e:[e],s=r.length;for(0===this.transformations.length&&(this.baseElement=t),i=0;i<s;i++)this.transformations.push(r[i]);return this},startAnimation:function(t,e,i){var r=this;return i=i||250,this.type!==a.OBJECT_TYPE_GLIDER||c.exists(this.intervalCode)||(this.intervalCode=window.setInterval(function(){r._anim(t,e)},i),c.exists(this.intervalCount)||(this.intervalCount=0)),this},stopAnimation:function(){return c.exists(this.intervalCode)&&(window.clearInterval(this.intervalCode),delete this.intervalCode),this},moveAlong:function(t,e,i){i=i||{};var r,o,n,h,l,d=[],u=[],p=this.board.attr.animationdelay,f=e/p,m=function(e,i){return function(){return t[e][i]}};if(c.isArray(t)){for(n=t.length,r=0;r<n;r++)c.isPoint(t[r])?u[r]=t[r]:u[r]={elementClass:a.OBJECT_CLASS_POINT,X:m(r,0),Y:m(r,1)};if(0===(e=e||0))return this.setPosition(a.COORDS_BY_USER,[u[u.length-1].X(),u[u.length-1].Y()]),this.board.update(this);if(!c.exists(i.interpolate)||i.interpolate)for(o=s.Neville(u),r=0;r<f;r++)d[r]=[],d[r][0]=o[0]((f-r)/f*o[3]()),d[r][1]=o[1]((f-r)/f*o[3]());else{for(n=t.length-1,r=0;r<f;++r)h=Math.floor(r/f*n),l=r/f*n-h,d[r]=[],d[r][0]=(1-l)*u[h].X()+l*u[h+1].X(),d[r][1]=(1-l)*u[h].Y()+l*u[h+1].Y();d.push([u[n].X(),u[n].Y()]),d.reverse()}this.animationPath=d}else c.isFunction(t)&&(this.animationPath=t,this.animationStart=(new Date).getTime());return this.animationCallback=i.callback,this.board.addAnimation(this),this},moveTo:function(t,e,r){r=r||{},t=new n(a.COORDS_BY_USER,t,this.board);var s,o=this.board.attr.animationdelay,h=Math.ceil(e/o),l=[],d=this.coords.usrCoords[1],u=this.coords.usrCoords[2],p=t.usrCoords[1]-d,f=t.usrCoords[2]-u,m=function(t){return r.effect&&"<>"===r.effect?Math.pow(Math.sin(t/h*Math.PI/2),2):t/h};if(!c.exists(e)||0===e||Math.abs(t.usrCoords[0]-this.coords.usrCoords[0])>i.eps)return this.setPosition(a.COORDS_BY_USER,t.usrCoords),this.board.update(this);if(!c.exists(r.callback)&&Math.abs(p)<i.eps&&Math.abs(f)<i.eps)return this;for(s=h;s>=0;s--)l[h-s]=[t.usrCoords[0],d+p*m(s),u+f*m(s)];return this.animationPath=l,this.animationCallback=r.callback,this.board.addAnimation(this),this},visit:function(t,e,i){t=new n(a.COORDS_BY_USER,t,this.board);var r,s,o,h=this.board.attr.animationdelay,l=[],d=this.coords.usrCoords[1],u=this.coords.usrCoords[2],p=t.usrCoords[1]-d,f=t.usrCoords[2]-u,m=function(t){var e=t<o/2?2*t/o:2*(o-t)/o;return i.effect&&"<>"===i.effect?Math.pow(Math.sin(e*Math.PI/2),2):e};for(c.isNumber(i)?i={repeat:i}:(i=i||{},c.exists(i.repeat)||(i.repeat=1)),o=Math.ceil(e/(h*i.repeat)),s=0;s<i.repeat;s++)for(r=o;r>=0;r--)l[s*(o+1)+o-r]=[t.usrCoords[0],d+p*m(r),u+f*m(r)];return this.animationPath=l,this.animationCallback=i.callback,this.board.addAnimation(this),this},_anim:function(t,e){var i,s,o,n,h,l,c,d;return this.intervalCount+=1,this.intervalCount>e&&(this.intervalCount=0),this.slideObject.elementClass===a.OBJECT_CLASS_LINE?(c=this.slideObject.point1.coords.scrCoords,d=this.slideObject.point2.coords.scrCoords,i=Math.round((d[1]-c[1])*this.intervalCount/e),s=Math.round((d[2]-c[2])*this.intervalCount/e),t>0?n=this.slideObject.point1:(n=this.slideObject.point2,i*=-1,s*=-1),this.coords.setCoordinates(a.COORDS_BY_SCREEN,[n.coords.scrCoords[1]+i,n.coords.scrCoords[2]+s])):this.slideObject.elementClass===a.OBJECT_CLASS_CURVE?(h=t>0?Math.round(this.intervalCount/e*this.board.canvasWidth):Math.round((e-this.intervalCount)/e*this.board.canvasWidth),this.coords.setCoordinates(a.COORDS_BY_SCREEN,[h,0]),this.coords=r.projectPointToCurve(this,this.slideObject,this.board)):this.slideObject.elementClass===a.OBJECT_CLASS_CIRCLE&&(o=2*Math.PI,o*=t<0?this.intervalCount/e:e-this.intervalCount,l=this.slideObject.Radius(),this.coords.setCoordinates(a.COORDS_BY_USER,[this.slideObject.center.coords.usrCoords[1]+l*Math.cos(o),this.slideObject.center.coords.usrCoords[2]+l*Math.sin(o)])),this.board.update(this),this},getTextAnchor:function(){return this.coords},getLabelAnchor:function(){return this.coords},getParents:function(){var t=[this.Z(),this.X(),this.Y()];return 0!==this.parents.length&&(t=this.parents),this.type===a.OBJECT_TYPE_GLIDER&&(t=[this.X(),this.Y(),this.slideObject.id]),t}}),t.CoordsElement.create=function(t,e,i,r,s,o){var n,a,h=!1;for(a=0;a<i.length;a++)(c.isFunction(i[a])||c.isString(i[a]))&&(h=!0);if(h)n=new t(e,[0,0],r,s,o),n.addConstraint(i);else if(c.isNumber(i[0])&&c.isNumber(i[1]))n=new t(e,i,r,s,o),c.exists(r.slideobject)?n.makeGlider(r.slideobject):n.baseElement=n,n.isDraggable=!0;else{if(!c.isObject(i[0])||!c.isTransformationOrArray(i[1]))return!1;n=new t(e,[0,0],r,s,o),n.addTransform(i[0],i[1]),n.isDraggable=!1}return n.handleSnapToGrid(),n.handleSnapToPoints(),n.handleAttractors(),n.addParents(i),n},t.CoordsElement}),define("base/text",["jxg","base/constants","base/element","parser/geonext","utils/env","utils/type","math/math","math/geometry","base/coordselement"],function(t,e,i,r,s,o,n,a,h){"use strict";var l={HTMLSliderInputEventHandler:function(){this._val=parseFloat(this.rendNodeRange.value),this.rendNodeOut.value=this.rendNodeRange.value,this.board.update()}};return t.Text=function(t,i,r,s){this.constructor(t,r,e.OBJECT_TYPE_TEXT,e.OBJECT_CLASS_TEXT),this.element=this.board.select(r.anchor),this.coordsConstructor(i,o.evaluate(this.visProp.islabel)),this.content="",this.plaintext="",this.plaintextOld=null,this.orgText="",this.needsSizeUpdate=!1,this.hiddenByParent=!1,this.size=[1,1],this.id=this.board.setId(this,"T"),this._setUpdateText(s),this.updateText(),this.board.renderer.drawText(this),this.board.finalizeAdding(this),o.isString(this.content)&&this.notifyParents(this.content),this.elType="text",this.methodMap=o.deepCopy(this.methodMap,{setText:"setTextJessieCode",move:"setCoords"})},t.Text.prototype=new i,o.copyPrototypeMethods(t.Text,h,"coordsConstructor"),t.extend(t.Text.prototype,{hasPoint:function(t,e){var i,r,s,a,h,l,c,d;return o.isObject(o.evaluate(this.visProp.precision))?(c=this.board._inputDevice,d=o.evaluate(this.visProp.precision[c])):d=this.board.options.precision.hasPoint,this.transformations.length>0&&(i=n.matVecMult(n.inverse(this.board.renderer.joinTransforms(this,this.transformations)),[1,t,e]),t=i[1],e=i[2]),h=this.getAnchorX(),i="right"===h?this.coords.scrCoords[1]-this.size[0]:"middle"===h?this.coords.scrCoords[1]-.5*this.size[0]:this.coords.scrCoords[1],r=i+this.size[0],l=this.getAnchorY(),a="top"===l?this.coords.scrCoords[2]+this.size[1]:"middle"===l?this.coords.scrCoords[2]+.5*this.size[1]:this.coords.scrCoords[2],s=a-this.size[1],"all"===o.evaluate(this.visProp.dragarea)?t>=i-d&&t<r+d&&e>=s-d&&e<=a+d:e>=s-d&&e<=a+d&&(t>=i-d&&t<=i+2*d||t>=r-2*d&&t<=r+d)},_setUpdateText:function(t){var e,i,r=o.evaluate(this.visProp.parse),s=o.evaluate(this.visProp.usemathjax);this.orgText=t,o.isFunction(t)?this.updateText=function(){i=t().toString(),this.plaintext=r&&!s?this.replaceSub(this.replaceSup(this.convertGeonext2CSS(i))):i}:o.isString(t)&&!r?this.updateText=function(){this.plaintext=t}:(o.isNumber(t)?this.content=o.toFixed(t,o.evaluate(this.visProp.digits)):o.evaluate(this.visProp.useasciimathml)?this.content="'`"+t+"`'":this.content=s?"'"+t+"'":this.generateTerm(t,!0,!0),e=this.board.jc.snippet(this.content,!0,"",!1),this.updateText=function(){this.plaintext=e()})},_setText:function(t){return this._setUpdateText(t),this.updateText(),this.fullUpdate(),this.board.infobox&&this.id===this.board.infobox.id||this.updateSize(),this},setTextJessieCode:function(t){var e;return this.visProp.castext=t,e=o.isFunction(t)?function(){return o.sanitizeHTML(t())}:o.isNumber(t)?t:o.sanitizeHTML(t),this._setText(e)},setText:function(t){return this._setText(t)},updateSize:function(){var t,e,i,r=o.evaluate(this.visProp.display);return s.isBrowser&&"no"!==this.board.renderer.type?(i=this.rendNode,"html"===r||"vml"===this.board.renderer.type?o.exists(i.offsetWidth)?(e=this,window.setTimeout(function(){e.size=[i.offsetWidth,i.offsetHeight],e.needsUpdate=!0,e.updateRenderer()},0)):this.size=this.crudeSizeEstimate():"internal"===r&&("svg"===this.board.renderer.type?(e=this,window.setTimeout(function(){try{t=i.getBBox(),e.size=[t.width,t.height],e.needsUpdate=!0,e.updateRenderer()}catch(t){}},0)):"canvas"===this.board.renderer.type&&(this.size=this.crudeSizeEstimate())),this):this},crudeSizeEstimate:function(){var t=parseFloat(o.evaluate(this.visProp.fontsize));return[t*this.plaintext.length*.45,.9*t]},utf8_decode:function(t){return t.replace(/&#x(\w+);/g,function(t,e){return String.fromCharCode(parseInt(e,16))})},replaceSub:function(t){if(!t.indexOf)return t;for(var e,i=t.indexOf("_{");i>=0;)t=t.substr(0,i)+t.substr(i).replace(/_\{/,"<sub>"),e=t.substr(i).indexOf("}"),e>=0&&(t=t.substr(0,e)+t.substr(e).replace(/\}/,"</sub>")),i=t.indexOf("_{");for(i=t.indexOf("_");i>=0;)t=t.substr(0,i)+t.substr(i).replace(/_(.?)/,"<sub>$1</sub>"),i=t.indexOf("_");return t},replaceSup:function(t){if(!t.indexOf)return t;for(var e,i=t.indexOf("^{");i>=0;)t=t.substr(0,i)+t.substr(i).replace(/\^\{/,"<sup>"),e=t.substr(i).indexOf("}"),e>=0&&(t=t.substr(0,e)+t.substr(e).replace(/\}/,"</sup>")),i=t.indexOf("^{");for(i=t.indexOf("^");i>=0;)t=t.substr(0,i)+t.substr(i).replace(/\^(.?)/,"<sup>$1</sup>"),i=t.indexOf("^");return t},getSize:function(){return this.size},setCoords:function(t,i){var r,s,n;return o.isArray(t)&&t.length>1&&(i=t[1],t=t[0]),o.evaluate(this.visProp.islabel)&&o.exists(this.element)?(r=this.element.getLabelAnchor(),s=(t-r.usrCoords[1])*this.board.unitX,n=-(i-r.usrCoords[2])*this.board.unitY,this.relativeCoords.setCoordinates(e.COORDS_BY_SCREEN,[s,n])):this.coords.setCoordinates(e.COORDS_BY_USER,[t,i]),this.fullUpdate(),this},update:function(t){return this.needsUpdate?(this.updateCoords(t),this.updateText(),"internal"===o.evaluate(this.visProp.display)&&o.isString(this.plaintext)&&(this.plaintext=this.utf8_decode(this.plaintext)),this.checkForSizeUpdate(),this.needsSizeUpdate&&this.updateSize(),this):this},checkForSizeUpdate:function(){this.board.infobox&&this.id===this.board.infobox.id?this.needsSizeUpdate=!1:(this.needsSizeUpdate=this.plaintextOld!==this.plaintext,this.needsSizeUpdate&&(this.plaintextOld=this.plaintext))},updateRenderer:function(){return o.evaluate(this.visProp.autoposition)&&this.setAutoPosition().updateConstraint(),this.updateRendererGeneric("updateText")},expandShortMath:function(t){var e=/([\)0-9\.])\s*([\(a-zA-Z_])/g;return t.replace(e,"$1*$2")},generateTerm:function(t,e,i){var s,n,a,h,l='""';if(t=t||"",t=t.replace(/\r/g,""),t=t.replace(/\n/g,""),t=t.replace(/"/g,"'"),t=t.replace(/'/g,"\\'"),t=t.replace(/&arc;/g,"∠"),t=t.replace(/<arc\s*\/>/g,"∠"),t=t.replace(/<arc\s*\/>/g,"∠"),t=t.replace(/<sqrt\s*\/>/g,"√"),t=t.replace(/<value>/g,"<value>"),t=t.replace(/<\/value>/g,"</value>"),a=t.indexOf("<value>"),h=t.indexOf("</value>"),a>=0)for(;a>=0;)l+=' + "'+this.replaceSub(this.replaceSup(t.slice(0,a)))+'"',n=t.slice(a+7,h),n=n.replace(/\s+/g,""),!0===e&&(n=this.expandShortMath(n)),s=i?n:r.geonext2JS(n,this.board),s=s.replace(/\\"/g,"'"),s=s.replace(/\\'/g,"'"),s.indexOf("toFixed")<0&&o.isNumber(o.bind(this.board.jc.snippet(s,!0,"",!1),this)())?l+="+("+s+").toFixed("+o.evaluate(this.visProp.digits)+")":l+="+("+s+")",t=t.slice(h+8),a=t.indexOf("<value>"),h=t.indexOf("</value>");return l+=' + "'+this.replaceSub(this.replaceSup(t))+'"',l=this.convertGeonext2CSS(l),l=l.replace(/&/g,"&"),l=l.replace(/"/g,"'")},convertGeonext2CSS:function(t){return o.isString(t)&&(t=t.replace(/<overline>/g,"<span style=text-decoration:overline>"),t=t.replace(/<overline>/g,"<span style=text-decoration:overline>"),t=t.replace(/<\/overline>/g,"</span>"),t=t.replace(/<\/overline>/g,"</span>"),t=t.replace(/<arrow>/g,"<span style=text-decoration:overline>"),t=t.replace(/<arrow>/g,"<span style=text-decoration:overline>"),t=t.replace(/<\/arrow>/g,"</span>"),t=t.replace(/<\/arrow>/g,"</span>")),t},notifyParents:function(t){var e,i=null;t=t.replace(/<value>/g,"<value>"),t=t.replace(/<\/value>/g,"</value>");do{e=/<value>([\w\s\*\/\^\-\+\(\)\[\],<>=!]+)<\/value>/,null!==(i=e.exec(t))&&(r.findDependencies(this,i[1],this.board),t=t.substr(i.index),t=t.replace(e,""))}while(null!==i);return this},getParents:function(){var t;return t=void 0!==this.relativeCoords?[this.relativeCoords.usrCoords[1],this.relativeCoords.usrCoords[2],this.orgText]:[this.Z(),this.X(),this.Y(),this.orgText],0!==this.parents.length&&(t=this.parents),t},bounds:function(){var t=this.coords.usrCoords;return o.evaluate(this.visProp.islabel)||0===this.board.unitY||0===this.board.unitX?[0,0,0,0]:[t[1],t[2]+this.size[1]/this.board.unitY,t[1]+this.size[0]/this.board.unitX,t[2]]},getAnchorX:function(){var t=o.evaluate(this.visProp.anchorx);if("auto"===t)switch(this.visProp.position){case"top":case"bot":return"middle";case"rt":case"lrt":case"urt":return"left";case"lft":case"llft":case"ulft":default:return"right"}return t},getAnchorY:function(){var t=o.evaluate(this.visProp.anchory);if("auto"===t)switch(this.visProp.position){case"top":case"ulft":case"urt":return"bottom";case"bot":case"lrt":case"llft":return"top";case"rt":case"lft":default:return"middle"}return t},getNumberofConflicts:function(t,e,i,r){var s,o,n,a,h=0;for(a=this.board.options.precision.hasPoint,this.board.options.precision.hasPoint=.5*Math.max(i,r),s=0,n=this.board.objectsList.length;s<n;s++)o=this.board.objectsList[s],o.visPropCalc.visible&&"axis"!==o.elType&&"ticks"!==o.elType&&o!==this.board.infobox&&o!==this&&o.hasPoint(t,e)&&h++;return this.board.options.precision.hasPoint=a,h},setAutoPosition:function(){var t,e,i,r,s,n,h,l,c,d,u,p,f,m,g,b,v=this.size[0],y=this.size[1],C=1/0,_=2*Math.PI/12;if(this===this.board.infobox||!o.evaluate(this.visProp.islabel)||!this.element)return this;if(o.evaluate(this.visProp.anchorx),o.evaluate(this.visProp.anchory),d=o.evaluate(this.visProp.offset),s=this.element.getLabelAnchor(),i=s.scrCoords[1],r=s.scrCoords[2],f=d[0],m=d[1],0===(c=this.getNumberofConflicts(i+f,r-m,v,y)))return this;for(u=a.distance([0,0],[f,m],2),n=Math.atan2(m,f),l=n,C=c,p=1,h=n+_;p<12&&(g=Math.cos(h),b=Math.sin(h),t=i+u*g,e=r-u*b,c=this.getNumberofConflicts(t,e,v,y),c<C&&(C=c,l=h),0!==C);p++)h+=_;return u=a.distance([0,0],d,2),g=Math.cos(l),b=Math.sin(l),this.visProp.offset=[u*g,u*b],this.visProp.anchorx=g<-.2?"right":g>.2?"left":"middle",this}}),t.createText=function(e,i,r){var s,n=o.copyAttributes(r,e.options,"text"),a=i.slice(0,-1),l=i[i.length-1];if(n.anchor=n.parent||n.anchor,!(s=h.create(t.Text,e,a,n,l)))throw new Error("JSXGraph: Can't create text with parent types '"+typeof i[0]+"' and '"+typeof i[1]+"'.\nPossible parent types: [x,y], [z,x,y], [element,transformation]");return 0!==n.rotate&&"internal"===n.display&&s.addRotation(n.rotate),s},t.registerElement("text",t.createText),t.createHTMLSlider=function(e,i,r){var n,a,h=o.copyAttributes(r,e.options,"htmlslider");if(2!==i.length||2!==i[0].length||3!==i[1].length)throw new Error("JSXGraph: Can't create htmlslider with parent types '"+typeof i[0]+"' and '"+typeof i[1]+"'.\nPossible parents are: [[x,y], [min, start, max]]");h.anchor=h.parent||h.anchor,h.fixed=h.fixed||!0,a=[i[0][0],i[0][1],'<form style="display:inline"><input type="range" /><span></span><input type="text" /></form>'],n=t.createText(e,a,h),n.type=o.OBJECT_TYPE_HTMLSLIDER,n.rendNodeForm=n.rendNode.childNodes[0],n.rendNodeRange=n.rendNodeForm.childNodes[0],n.rendNodeRange.min=i[1][0],n.rendNodeRange.max=i[1][2],n.rendNodeRange.step=h.step,n.rendNodeRange.value=i[1][1],n.rendNodeLabel=n.rendNodeForm.childNodes[1],n.rendNodeLabel.id=n.rendNode.id+"_label",h.withlabel&&(n.rendNodeLabel.innerHTML=n.name+"="),n.rendNodeOut=n.rendNodeForm.childNodes[2],n.rendNodeOut.value=i[1][1];try{n.rendNodeForm.id=n.rendNode.id+"_form",n.rendNodeRange.id=n.rendNode.id+"_range",n.rendNodeOut.id=n.rendNode.id+"_out"}catch(e){t.debug(e)}return n.rendNodeRange.style.width=h.widthrange+"px",n.rendNodeRange.style.verticalAlign="middle",n.rendNodeOut.style.width=h.widthout+"px",n._val=i[1][1],t.supportsVML()?s.addEvent(n.rendNodeForm,"change",l.HTMLSliderInputEventHandler,n):s.addEvent(n.rendNodeForm,"input",l.HTMLSliderInputEventHandler,n),n.Value=function(){return this._val},n},t.registerElement("htmlslider",t.createHTMLSlider),{Text:t.Text,createText:t.createText,createHTMLSlider:t.createHTMLSlider}}),define("utils/uuid",["jxg"],function(t){"use strict";var e="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",i=e.split("");return t.Util=t.Util||{},t.Util.genUUID=function(){var t,e,r=[],s=0;for(e=0;e<36;e++)8===e||13===e||18===e||23===e?r[e]="-":14===e?r[e]="4":(s<=2&&(s=33554432+16777216*Math.random()|0),t=15&s,s>>=4,r[e]=i[19===e?3&t|8:t]);return r.join("")},t.Util}),define("parser/jessiecode",["jxg","base/constants","base/text","math/math","math/ia","math/geometry","math/statistics","utils/type","utils/uuid","utils/env"],function(JXG,Const,Text,Mat,Interval,Geometry,Statistics,Type,UUID,Env){Object.create||(Object.create=function(t,e){function i(){}if("object"!=typeof t&&"function"!=typeof t)throw new TypeError("Object prototype may only be an Object: "+t);if(null===t)throw new Error("This browser's implementation of Object.create is a shim and doesn't support 'null' as the first argument.");if(void 0!==e)throw new Error("This browser's implementation of Object.create is a shim and doesn't support a second argument.");return i.prototype=t,new i});var priv={modules:{math:Mat,"math/geometry":Geometry,"math/statistics":Statistics,"math/numerics":Mat.Numerics}};JXG.JessieCode=function(t,e){this.scope={id:0,hasChild:!0,args:[],locals:{},context:null,previous:null},this.scopes=[],this.scopes.push(this.scope),this.dpstack=[[]],this.pscope=0,this.propstack=[{}],this.propscope=0,this.lhs=[],this.isLHS=!1,this.warnLog="jcwarn",this.$log=[],this.builtIn=this.defineBuiltIn(),this.board=null,this.lineToElement={},this.parCurLine=1,this.parCurColumn=0,this.line=1,this.col=1,JXG.CA&&(this.CA=new JXG.CA(this.node,this.createNode,this)),this.code="","string"==typeof t&&this.parse(t,e)},JXG.extend(JXG.JessieCode.prototype,{node:function(t,e,i){return{type:t,value:e,children:i}},createNode:function(t,e,i){var r,s=this.node(t,e,[]);for(r=2;r<arguments.length;r++)s.children.push(arguments[r]);return"node_const"==s.type&&Type.isNumber(s.value)&&(s.isMath=!0),s.line=this.parCurLine,s.col=this.parCurColumn,s},pushScope:function(t){var e={args:t,locals:{},context:null,previous:this.scope};return this.scope.hasChild=!0,this.scope=e,e.id=this.scopes.push(e)-1,e},popScope:function(){var t=this.scope.previous;return this.scope=null!==t?t:this.scope,this.scope},getElementById:function(t){return this.board.objects[t]},log:function(){this.$log.push(arguments),"object"==typeof console&&console.log&&console.log.apply(console,arguments)},creator:function(){var t,e={};return t=function(t){var i;return"function"==typeof e[this.board.id+t]?i=e[this.board.id+t]:(i=function(e){return function(i,r){var s;return s=Type.exists(r)?r:{name:0!==e.lhs[e.scope]?e.lhs[e.scope]:""},e.board.create(t,i,s)}}(this),i.creator=!0,e[this.board.id+t]=i),i},t.clearCache=function(){e={}},t}(),letvar:function(t,e){this.builtIn[t]&&this._warn('"'+t+'" is a predefined value.'),this.scope.locals[t]=e},isLocalVariable:function(t){for(var e=this.scope;null!==e;){if(Type.exists(e.locals[t]))return e;e=e.previous}return null},isParameter:function(t){for(var e=this.scope;null!==e;){if(Type.indexOf(e.args,t)>-1)return e;e=e.previous}return null},isCreator:function(t){return!!JXG.elements[t]},isMathMethod:function(t){return"E"!==t&&!!Math[t]},isBuiltIn:function(t){return!!this.builtIn[t]},getvar:function(t,e){var i;return e=Type.def(e,!1),i=this.isLocalVariable(t),null!==i?i.locals[t]:this.isCreator(t)?this.creator(t):this.isBuiltIn(t)?this.builtIn[t]:this.isMathMethod(t)?Math[t]:e||(i=this.board.select(t))===t?void 0:i},resolve:function(t){for(var e=this.scope;null!==e;){if(Type.exists(e.locals[t]))return e.locals[t];e=e.previous}},getvarJS:function(t,e,i){var r,s="";return e=Type.def(e,!1),i=Type.def(i,!1),null!==this.isParameter(t)?t:null===this.isLocalVariable(t)||i?this.isCreator(t)?"(function () { var a = Array.prototype.slice.call(arguments, 0), props = "+(i?"a.pop()":"{}")+"; return $jc$.board.create.apply($jc$.board, ['"+t+"'].concat([a, props])); })":(i&&this._error("Syntax error (attribute values are allowed with element creators only)"),this.isBuiltIn(t)?(s=this.builtIn[t].src||this.builtIn[t],Type.isNumber(s)?s:s.match(/board\.select/)?s:(t=s.split(".").pop(),Type.exists(this.board.mathLib)&&(r=new RegExp("^Math."+t),null!==r.exec(s))?s.replace(r,"$jc$.board.mathLib."+t):Type.exists(this.board.mathLibJXG)?(r=new RegExp("^JXG.Math."),null!==r.exec(s)?s.replace(r,"$jc$.board.mathLibJXG."):s):s)):this.isMathMethod(t)?"$jc$.board.mathLib."+t:e?"":(Type.isId(this.board,t)?(s="$jc$.board.objects['"+t+"']","slider"===this.board.objects[t].elType&&(s+=".Value()")):Type.isName(this.board,t)?(s="$jc$.board.elementsByName['"+t+"']","slider"===this.board.elementsByName[t].elType&&(s+=".Value()")):Type.isGroup(this.board,t)&&(s="$jc$.board.groups['"+t+"']"),s)):"$jc$.resolve('"+t+"')"},makeMap:function(t){return t.isMap=!0,t},functionCodeJS:function(t){var e=t.children[0].join(", "),i="",r="";return"op_map"===t.value&&(i="{ return ",r=" }"),"function ("+e+") {\nvar $oldscope$ = $jc$.scope;\n$jc$.scope = $jc$.scopes["+this.scope.id+"];\nvar r = (function () "+i+this.compile(t.children[1],!0)+r+")();\n$jc$.scope = $oldscope$;\nreturn r;\n}"},defineFunction:function(node){var fun,i,list=node.children[0],scope=this.pushScope(list);if(this.board.options.jc.compile){for(this.isLHS=!1,i=0;i<list.length;i++)scope.locals[list[i]]=list[i];this.replaceNames(node.children[1]),fun=function($jc$){var fun,str="var f = "+$jc$.functionCodeJS(node)+"; f;";try{return fun=eval(str)}catch(t){return $jc$._warn("error compiling function\n\n"+str+"\n\n"+t.toString()),function(){}}}(this),this.popScope()}else fun=function(t,e,i){return function(){var r,s;for(s=e.scope,e.scope=e.scopes[i],r=0;r<t.length;r++)e.scope.locals[t[r]]=arguments[r];return r=e.execute(node.children[1]),e.scope=s,r}}(list,this,scope.id);return fun.node=node,fun.scope=scope,fun.toJS=fun.toString,fun.toString=function(t){return function(){return t.compile(t.replaceIDs(Type.deepCopy(node)))}}(this),fun.deps={},this.collectDependencies(node.children[1],fun.deps),fun},mergeAttributes:function(t){var e,i={};for(e=0;e<arguments.length;e++)i=Type.deepCopy(i,arguments[e],!0);return i},setProp:function(t,e,i){var r,s,o={};t.elementClass!==Const.OBJECT_CLASS_POINT||"X"!==e&&"Y"!==e?t.elementClass!==Const.OBJECT_CLASS_TEXT||"X"!==e&&"Y"!==e?t.type&&t.elementClass&&t.visProp?Type.exists(t[t.methodMap[e]])&&"function"!=typeof t[t.methodMap[e]]?t[t.methodMap[e]]=i:(o[e]=i,t.setAttribute(o)):t[e]=i:("number"==typeof i?t[e]=function(){return i}:"function"==typeof i?(t.isDraggable=!1,t[e]=i):"string"==typeof i&&(t.isDraggable=!1,t[e]=Type.createFunction(i,this.board,null,!0),t[e+"jc"]=i),t[e].origin=i,this.board.update()):(e=e.toLowerCase(),t.isDraggable&&"number"==typeof i?(r="x"===e?i:t.X(),s="y"===e?i:t.Y(),t.setPosition(Const.COORDS_BY_USER,[r,s])):!t.isDraggable||"function"!=typeof i&&"string"!=typeof i?t.isDraggable||(r="x"===e?i:t.XEval.origin,s="y"===e?i:t.YEval.origin,t.addConstraint([r,s])):(r="x"===e?i:t.coords.usrCoords[1],s="y"===e?i:t.coords.usrCoords[2],t.addConstraint([r,s])),this.board.update())},_genericParse:function(t,e,i,r){var s,o,n,a,h=t.replace(/\r\n/g,"\n").split("\n"),l=[];r||(this.code+=t+"\n"),Text&&(o=Text.Text.prototype.setText,Text.Text.prototype.setText=Text.Text.prototype.setTextJessieCode);try{for(Type.exists(i)||(i=!1),s=0;s<h.length;s++)i&&(h[s]=JXG.GeonextParser.geonext2JS(h[s],this.board)),l.push(h[s]);switch(t=l.join("\n"),n=parser.parse(t),this.CA&&(n=this.CA.expandDerivatives(n,null,n),n=this.CA.removeTrivialNodes(n)),e){case"parse":a=this.execute(n);break;case"manipulate":a=this.compile(n);break;case"getAst":a=n;break;default:a=!1}}catch(t){throw t}finally{Text&&(Text.Text.prototype.setText=o)}return a},parse:function(t,e,i){return this._genericParse(t,"parse",e,i)},manipulate:function(t,e,i){return this._genericParse(t,"manipulate",e,i)},getAST:function(t,e,i){return this._genericParse(t,"getAst",e,i)},snippet:function(t,e,i,r){var s;return e=Type.def(e,!0),i=Type.def(i,""),r=Type.def(r,!1),s=(e?" function ("+i+") { return ":"")+t+(e?"; }":"")+";",this.parse(s,r,!0)},replaceIDs:function(t){var e,i;if(t.replaced&&(i=this.board.objects[t.children[1][0].value],Type.exists(i)&&""!==i.name&&(t.type="node_var",t.value=i.name,t.children.length=0,delete t.replaced)),t.children)for(e=t.children.length;e>0;e--)Type.exists(t.children[e-1])&&(t.children[e-1]=this.replaceIDs(t.children[e-1]));return t},replaceNames:function(t){var e,i;if(i=t.value,"node_op"===t.type&&"op_lhs"===i&&1===t.children.length?this.isLHS=!0:"node_var"===t.type&&(this.isLHS?this.letvar(i,!0):!Type.exists(this.getvar(i,!0))&&Type.exists(this.board.elementsByName[i])&&(t=this.createReplacementNode(t))),t.children)for(e=t.children.length;e>0;e--)Type.exists(t.children[e-1])&&(t.children[e-1]=this.replaceNames(t.children[e-1]));return"node_op"===t.type&&"op_lhs"===t.value&&1===t.children.length&&(this.isLHS=!1),t},createReplacementNode:function(t){var e=t.value,i=this.board.elementsByName[e];return t=this.createNode("node_op","op_execfun",this.createNode("node_var","$"),[this.createNode("node_str",i.id)]),t.replaced=!0,t},collectDependencies:function(t,e){var i,r,s,o;if(Type.isArray(t))for(o=t.length,i=0;i<o;i++)this.collectDependencies(t[i],e);else if(r=t.value,"node_var"===t.type&&(s=this.getvar(r))&&s.visProp&&s.type&&s.elementClass&&s.id&&(e[s.id]=s),"node_op"===t.type&&"op_execfun"===t.value&&t.children.length>1&&"$"===t.children[0].value&&t.children[1].length>0&&(s=t.children[1][0].value,e[s]=this.board.objects[s]),t.children)for(i=t.children.length;i>0;i--)Type.exists(t.children[i-1])&&this.collectDependencies(t.children[i-1],e)},resolveProperty:function(t,e,i){return i=Type.def(i,!1),t&&t.methodMap&&(Type.exists(t.subs)&&Type.exists(t.subs[e])?t=t.subs:Type.exists(t.methodMap[e])?e=t.methodMap[e]:(t=t.visProp,e=e.toLowerCase())),Type.isFunction(t)&&this._error("Accessing function properties is not allowed."),Type.exists(t)||this._error(t+" is not an object"), -Type.exists(t[e])||this._error("unknown property "+e),i&&"function"==typeof t[e]?function(){return t[e].apply(t,arguments)}:t[e]},getLHS:function(t){var e;if("node_var"===t.type)e={o:this.scope.locals,what:t.value};else if("node_op"===t.type&&"op_property"===t.value)e={o:this.execute(t.children[0]),what:t.children[1]};else{if("node_op"!==t.type||"op_extvalue"!==t.value)throw new Error("Syntax error: Invalid left-hand side of assignment.");e={o:this.execute(t.children[0]),what:this.execute(t.children[1])}}return e},getLHSCompiler:function(t,e){var i;if("node_var"===t.type)i=t.value;else if("node_op"===t.type&&"op_property"===t.value)i=[this.compile(t.children[0],e),"'"+t.children[1]+"'"];else{if("node_op"!==t.type||"op_extvalue"!==t.value)throw new Error("Syntax error: Invalid left-hand side of assignment.");i=[this.compile(t.children[0],e),"node_const"===t.children[1].type?t.children[1].value:this.compile(t.children[1],e)]}return i},execute:function(t){var e,i,r,s,o,n,a,h,l,c,d=[];if(e=0,!t)return e;switch(this.line=t.line,this.col=t.col,t.type){case"node_op":switch(t.value){case"op_none":t.children[0]&&this.execute(t.children[0]),t.children[1]&&(e=this.execute(t.children[1]));break;case"op_assign":i=this.getLHS(t.children[0]),this.lhs[this.scope.id]=i[1],i.o.type&&i.o.elementClass&&i.o.methodMap&&"label"===i.what&&this._error("Left-hand side of assignment is read-only."),e=this.execute(t.children[1]),i.o!==this.scope.locals||Type.isArray(i.o)&&"number"==typeof i.what?this.setProp(i.o,i.what,e):this.letvar(i.what,e),this.lhs[this.scope.id]=0;break;case"op_if":this.execute(t.children[0])&&(e=this.execute(t.children[1]));break;case"op_conditional":case"op_if_else":e=this.execute(t.children[0])?this.execute(t.children[1]):this.execute(t.children[2]);break;case"op_while":for(;this.execute(t.children[0]);)this.execute(t.children[1]);break;case"op_do":do{this.execute(t.children[0])}while(this.execute(t.children[1]));break;case"op_for":for(this.execute(t.children[0]);this.execute(t.children[1]);this.execute(t.children[2]))this.execute(t.children[3]);break;case"op_proplst":t.children[0]&&this.execute(t.children[0]),t.children[1]&&this.execute(t.children[1]);break;case"op_emptyobject":e={};break;case"op_proplst_val":this.propstack.push({}),this.propscope++,this.execute(t.children[0]),e=this.propstack[this.propscope],this.propstack.pop(),this.propscope--;break;case"op_prop":this.propstack[this.propscope][t.children[0]]=this.execute(t.children[1]);break;case"op_array":for(e=[],o=t.children[0].length,r=0;r<o;r++)e.push(this.execute(t.children[0][r]));break;case"op_extvalue":e=this.execute(t.children[0]),r=this.execute(t.children[1]),e="number"==typeof r&&Math.abs(Math.round(r)-r)<Mat.eps?e[r]:void 0;break;case"op_return":if(0!==this.scope)return this.execute(t.children[0]);this._error("Unexpected return.");break;case"op_map":t.children[1].isMath||"node_var"===t.children[1].type||this._error("execute: In a map only function calls and mathematical expressions are allowed."),h=this.defineFunction(t),h.isMap=!0,e=h;break;case"op_function":h=this.defineFunction(t),h.isMap=!1,e=h;break;case"op_execfun":if(this.dpstack.push([]),this.pscope++,n=t.children[1],Type.exists(t.children[2]))if(t.children[3])for(a=t.children[2],l={},r=0;r<a.length;r++)l=Type.deepCopy(l,this.execute(a[r]),!0);else l=this.execute(t.children[2]);for(h=this.execute(t.children[0]),c=h&&h.sc?h.sc:this,!h.creator&&Type.exists(t.children[2])&&this._error("Unexpected value. Only element creators are allowed to have a value after the function call."),r=0;r<n.length;r++)d[r]=this.execute(n[r]),this.dpstack[this.pscope].push({line:t.children[1][r].line,col:t.children[1][r].ecol});if("function"!=typeof h||h.creator)if("function"==typeof h&&h.creator){s=this.line;try{for(e=h(d,l),e.jcLineStart=s,e.jcLineEnd=t.eline,r=s;r<=t.line;r++)this.lineToElement[r]=e;e.debugParents=this.dpstack[this.pscope]}catch(t){this._error(t.toString())}}else this._error("Function '"+h+"' is undefined.");else e=h.apply(c,d);this.dpstack.pop(),this.pscope--;break;case"op_property":s=this.execute(t.children[0]),i=t.children[1],e=this.resolveProperty(s,i,!1),Type.exists(e)&&(e.sc=s);break;case"op_use":this._warn("Use of the 'use' operator is deprecated."),this.use(t.children[0].toString());break;case"op_delete":this._warn("Use of the 'delete' operator is deprecated. Please use the remove() function."),i=this.getvar(t.children[0]),e=this.del(i);break;case"op_equ":e=this.execute(t.children[0])==this.execute(t.children[1]);break;case"op_neq":e=this.execute(t.children[0])!=this.execute(t.children[1]);break;case"op_approx":e=Math.abs(this.execute(t.children[0])-this.execute(t.children[1]))<Mat.eps;break;case"op_grt":e=this.execute(t.children[0])>this.execute(t.children[1]);break;case"op_lot":e=this.execute(t.children[0])<this.execute(t.children[1]);break;case"op_gre":e=this.execute(t.children[0])>=this.execute(t.children[1]);break;case"op_loe":e=this.execute(t.children[0])<=this.execute(t.children[1]);break;case"op_or":e=this.execute(t.children[0])||this.execute(t.children[1]);break;case"op_and":e=this.execute(t.children[0])&&this.execute(t.children[1]);break;case"op_not":e=!this.execute(t.children[0]);break;case"op_add":e=this.add(this.execute(t.children[0]),this.execute(t.children[1]));break;case"op_sub":e=this.sub(this.execute(t.children[0]),this.execute(t.children[1]));break;case"op_div":e=this.div(this.execute(t.children[0]),this.execute(t.children[1]));break;case"op_mod":e=this.mod(this.execute(t.children[0]),this.execute(t.children[1]),!0);break;case"op_mul":e=this.mul(this.execute(t.children[0]),this.execute(t.children[1]));break;case"op_exp":e=this.pow(this.execute(t.children[0]),this.execute(t.children[1]));break;case"op_neg":e=this.neg(this.execute(t.children[0]))}break;case"node_var":e=this.getvar(t.value);break;case"node_const":e=Number(t.value);break;case"node_const_bool":e=t.value;break;case"node_str":e=t.value.replace(/\\(.)/,"$1")}return e},compile:function(t,e){var i,r,s,o="";if(Type.exists(e)||(e=!1),!t)return o;switch(t.type){case"node_op":switch(t.value){case"op_none":t.children[0]&&(o=this.compile(t.children[0],e)),t.children[1]&&(o+=this.compile(t.children[1],e));break;case"op_assign":e?(i=this.getLHSCompiler(t.children[0],e),Type.isArray(i)?o="$jc$.setProp("+i[0]+", "+i[1]+", "+this.compile(t.children[1],e)+");\n":(this.isLocalVariable(i)!==this.scope&&(this.scope.locals[i]=!0),o="$jc$.scopes["+this.scope.id+"].locals['"+i+"'] = "+this.compile(t.children[1],e)+";\n")):(i=this.compile(t.children[0]),o=i+" = "+this.compile(t.children[1],e)+";\n");break;case"op_if":o=" if ("+this.compile(t.children[0],e)+") "+this.compile(t.children[1],e);break;case"op_if_else":o=" if ("+this.compile(t.children[0],e)+")"+this.compile(t.children[1],e),o+=" else "+this.compile(t.children[2],e);break;case"op_conditional":o="(("+this.compile(t.children[0],e)+")?("+this.compile(t.children[1],e),o+="):("+this.compile(t.children[2],e)+"))";break;case"op_while":o=" while ("+this.compile(t.children[0],e)+") {\n"+this.compile(t.children[1],e)+"}\n";break;case"op_do":o=" do {\n"+this.compile(t.children[0],e)+"} while ("+this.compile(t.children[1],e)+");\n";break;case"op_for":o=" for ("+this.compile(t.children[0],e)+this.compile(t.children[1],e)+"; "+this.compile(t.children[2],e).slice(0,-2)+") {\n"+this.compile(t.children[3],e)+"\n}\n";break;case"op_proplst":t.children[0]&&(o=this.compile(t.children[0],e)+", "),o+=this.compile(t.children[1],e);break;case"op_prop":o=t.children[0]+": "+this.compile(t.children[1],e);break;case"op_emptyobject":o=e?"{}":"<< >>";break;case"op_proplst_val":o=this.compile(t.children[0],e);break;case"op_array":for(s=[],r=0;r<t.children[0].length;r++)s.push(this.compile(t.children[0][r],e));o="["+s.join(", ")+"]";break;case"op_extvalue":o=this.compile(t.children[0],e)+"["+this.compile(t.children[1],e)+"]";break;case"op_return":o=" return "+this.compile(t.children[0],e)+";\n";break;case"op_map":t.children[1].isMath||"node_var"===t.children[1].type||this._error("compile: In a map only function calls and mathematical expressions are allowed."),s=t.children[0],o=e?" $jc$.makeMap(function ("+s.join(", ")+") { return "+this.compile(t.children[1],e)+"; })":"map ("+s.join(", ")+") -> "+this.compile(t.children[1],e);break;case"op_function":s=t.children[0],this.pushScope(s),o=e?this.functionCodeJS(t):" function ("+s.join(", ")+") "+this.compile(t.children[1],e),this.popScope();break;case"op_execfunmath":console.log("TODO"),o="-1";break;case"op_execfun":if(t.children[2]){for(s=[],r=0;r<t.children[2].length;r++)s.push(this.compile(t.children[2][r],e));e&&(i="$jc$.mergeAttributes("+s.join(", ")+")")}for(t.children[0].withProps=!!t.children[2],s=[],r=0;r<t.children[1].length;r++)s.push(this.compile(t.children[1][r],e));o=this.compile(t.children[0],e)+"("+s.join(", ")+(t.children[2]&&e?", "+i:"")+")"+(t.children[2]&&!e?i:""),e&&"$"===t.children[0].value&&(o="$jc$.board.objects["+this.compile(t.children[1][0],e)+"]");break;case"op_property":o=e&&"X"!==t.children[1]&&"Y"!==t.children[1]?"$jc$.resolveProperty("+this.compile(t.children[0],e)+", '"+t.children[1]+"', true)":this.compile(t.children[0],e)+"."+t.children[1];break;case"op_use":this._warn("Use of the 'use' operator is deprecated."),o=e?"$jc$.use('":"use('",o+=t.children[0].toString()+"');";break;case"op_delete":this._warn("Use of the 'delete' operator is deprecated. Please use the remove() function."),o=e?"$jc$.del(":"remove(",o+=this.compile(t.children[0],e)+")";break;case"op_equ":o="("+this.compile(t.children[0],e)+" == "+this.compile(t.children[1],e)+")";break;case"op_neq":o="("+this.compile(t.children[0],e)+" != "+this.compile(t.children[1],e)+")";break;case"op_approx":o="("+this.compile(t.children[0],e)+" ~= "+this.compile(t.children[1],e)+")";break;case"op_grt":o=e?"$jc$.gt("+this.compile(t.children[0],e)+", "+this.compile(t.children[1],e)+")":"("+this.compile(t.children[0],e)+" > "+this.compile(t.children[1],e)+")";break;case"op_lot":o=e?"$jc$.lt("+this.compile(t.children[0],e)+", "+this.compile(t.children[1],e)+")":"("+this.compile(t.children[0],e)+" < "+this.compile(t.children[1],e)+")";break;case"op_gre":o=e?"$jc$.geq("+this.compile(t.children[0],e)+", "+this.compile(t.children[1],e)+")":"("+this.compile(t.children[0],e)+" >= "+this.compile(t.children[1],e)+")";break;case"op_loe":o=e?"$jc$.leq("+this.compile(t.children[0],e)+", "+this.compile(t.children[1],e)+")":"("+this.compile(t.children[0],e)+" <= "+this.compile(t.children[1],e)+")";break;case"op_or":o="("+this.compile(t.children[0],e)+" || "+this.compile(t.children[1],e)+")";break;case"op_and":o="("+this.compile(t.children[0],e)+" && "+this.compile(t.children[1],e)+")";break;case"op_not":o="!("+this.compile(t.children[0],e)+")";break;case"op_add":o=e?"$jc$.add("+this.compile(t.children[0],e)+", "+this.compile(t.children[1],e)+")":"("+this.compile(t.children[0],e)+" + "+this.compile(t.children[1],e)+")";break;case"op_sub":o=e?"$jc$.sub("+this.compile(t.children[0],e)+", "+this.compile(t.children[1],e)+")":"("+this.compile(t.children[0],e)+" - "+this.compile(t.children[1],e)+")";break;case"op_div":o=e?"$jc$.div("+this.compile(t.children[0],e)+", "+this.compile(t.children[1],e)+")":"("+this.compile(t.children[0],e)+" / "+this.compile(t.children[1],e)+")";break;case"op_mod":o=e?"$jc$.mod("+this.compile(t.children[0],e)+", "+this.compile(t.children[1],e)+", true)":"("+this.compile(t.children[0],e)+" % "+this.compile(t.children[1],e)+")";break;case"op_mul":o=e?"$jc$.mul("+this.compile(t.children[0],e)+", "+this.compile(t.children[1],e)+")":"("+this.compile(t.children[0],e)+" * "+this.compile(t.children[1],e)+")";break;case"op_exp":o=e?"$jc$.pow("+this.compile(t.children[0],e)+", "+this.compile(t.children[1],e)+")":"("+this.compile(t.children[0],e)+"^"+this.compile(t.children[1],e)+")";break;case"op_neg":o=e?"$jc$.neg("+this.compile(t.children[0],e)+")":"(-"+this.compile(t.children[0],e)+")"}break;case"node_var":o=e?this.getvarJS(t.value,!1,t.withProps):t.value;break;case"node_const":case"node_const_bool":o=t.value;break;case"node_str":o="'"+t.value+"'"}return t.needsBrackets&&(o="{\n"+o+"}\n"),o},X:function(t){return t.X()},Y:function(t){return t.Y()},V:function(t){return t.Value()},L:function(t){return t.L()},dist:function(t,e){return Type.exists(t)&&Type.exists(t.Dist)||this._error("Error: Can't calculate distance."),t.Dist(e)},add:function(t,e){var i,r,s;if(t=Type.evalSlider(t),e=Type.evalSlider(e),Interval.isInterval(t)||Interval.isInterval(e))s=Interval.add(t,e);else if(Type.isArray(t)&&Type.isArray(e))for(r=Math.min(t.length,e.length),s=[],i=0;i<r;i++)s[i]=t[i]+e[i];else Type.isNumber(t)&&Type.isNumber(e)?s=t+e:Type.isString(t)||Type.isString(e)?s=t.toString()+e.toString():this._error("Operation + not defined on operands "+typeof t+" and "+typeof e);return s},sub:function(t,e){var i,r,s;if(t=Type.evalSlider(t),e=Type.evalSlider(e),Interval.isInterval(t)||Interval.isInterval(e))s=Interval.sub(t,e);else if(Type.isArray(t)&&Type.isArray(e))for(r=Math.min(t.length,e.length),s=[],i=0;i<r;i++)s[i]=t[i]-e[i];else Type.isNumber(t)&&Type.isNumber(e)?s=t-e:this._error("Operation - not defined on operands "+typeof t+" and "+typeof e);return s},neg:function(t){var e,i,r;if(t=Type.evalSlider(t),Interval.isInterval(t))r=Interval.negative(t);else if(Type.isArray(t))for(i=t.length,r=[],e=0;e<i;e++)r[e]=-t[e];else Type.isNumber(t)?r=-t:this._error("Unary operation - not defined on operand "+typeof t);return r},mul:function(t,e){var i,r,s;if(t=Type.evalSlider(t),e=Type.evalSlider(e),Type.isArray(t)&&Type.isNumber(e)&&(i=t,t=e,e=t),Interval.isInterval(t)||Interval.isInterval(e))s=Interval.mul(t,e);else if(Type.isArray(t)&&Type.isArray(e))r=Math.min(t.length,e.length),s=Mat.innerProduct(t,e,r);else if(Type.isNumber(t)&&Type.isArray(e))for(r=e.length,s=[],i=0;i<r;i++)s[i]=t*e[i];else Type.isNumber(t)&&Type.isNumber(e)?s=t*e:this._error("Operation * not defined on operands "+typeof t+" and "+typeof e);return s},div:function(t,e){var i,r,s;if(t=Type.evalSlider(t),e=Type.evalSlider(e),Interval.isInterval(t)||Interval.isInterval(e))s=Interval.div(t,e);else if(Type.isArray(t)&&Type.isNumber(e))for(r=t.length,s=[],i=0;i<r;i++)s[i]=t[i]/e;else Type.isNumber(t)&&Type.isNumber(e)?s=t/e:this._error("Operation * not defined on operands "+typeof t+" and "+typeof e);return s},mod:function(t,e){var i,r,s;if(t=Type.evalSlider(t),e=Type.evalSlider(e),Interval.isInterval(t)||Interval.isInterval(e))return Interval.fmod(t,e);if(Type.isArray(t)&&Type.isNumber(e))for(r=t.length,s=[],i=0;i<r;i++)s[i]=Mat.mod(t[i],e,!0);else Type.isNumber(t)&&Type.isNumber(e)?s=Mat.mod(t,e,!0):this._error("Operation * not defined on operands "+typeof t+" and "+typeof e);return s},pow:function(t,e){return t=Type.evalSlider(t),e=Type.evalSlider(e),Interval.isInterval(t)||Interval.isInterval(e)?Interval.pow(t,e):Mat.pow(t,e)},lt:function(t,e){return Interval.isInterval(t)||Interval.isInterval(e)?Interval.lt(t,e):t<e},leq:function(t,e){return Interval.isInterval(t)||Interval.isInterval(e)?Interval.leq(t,e):t<=e},gt:function(t,e){return Interval.isInterval(t)||Interval.isInterval(e)?Interval.gt(t,e):t>e},geq:function(t,e){return Interval.isInterval(t)||Interval.isInterval(e)?Intervalt.geq(t,e):t>=e},DDD:function(t){console.log("Dummy derivative function. This should never appear!")},ifthen:function(t,e,i){return t?e:i},del:function(t){"object"==typeof t&&JXG.exists(t.type)&&JXG.exists(t.elementClass)&&this.board.removeObject(t)},use:function(t){var e,i,r=!1;if("string"==typeof t){for(e in JXG.boards)if(JXG.boards.hasOwnProperty(e)&&JXG.boards[e].container===t){i=JXG.boards[e],r=!0;break}}else i=t,r=!0;r?(this.board=i,this.builtIn.$board=i,this.builtIn.$board.src="$jc$.board"):this._error("Board '"+t+"' not found!")},findSymbol:function(t,e){var i,r;for(e=Type.def(e,-1),r=-1===e?this.scope:this.scopes[e];null!==r;){for(i in r.locals)if(r.locals.hasOwnProperty(i)&&r.locals[i]===t)return[i,r];r=r.previous}return[]},importModule:function(t){return priv.modules[t.toLowerCase()]},defineBuiltIn:function(){var t=this,e={PI:Math.PI,EULER:Math.E,X:t.X,Y:t.Y,V:t.V,L:t.L,dist:t.dist,rad:Geometry.rad,deg:Geometry.trueAngle,factorial:Mat.factorial,trunc:Type.trunc,log:Mat.log,ln:Math.log,log10:Mat.log10,lg:Mat.log10,log2:Mat.log2,lb:Mat.log2,ld:Mat.log2,cosh:Mat.cosh,sinh:Mat.sinh,cot:Mat.cot,acot:Mat.acot,nthroot:Mat.nthroot,cbrt:Mat.cbrt,pow:Mat.pow,ratpow:Mat.ratpow,gcd:Mat.gcd,lcm:Mat.lcm,binomial:Mat.binomial,IfThen:t.ifthen,import:t.importModule,use:t.use,remove:t.del,$:t.getElementById,$board:t.board,$log:t.log,D:t.DDD};return e.rad.sc=Geometry,e.deg.sc=Geometry,e.factorial.sc=Mat,e.X.src="$jc$.X",e.Y.src="$jc$.Y",e.V.src="$jc$.V",e.L.src="$jc$.L",e.dist.src="$jc$.dist",e.rad.src="JXG.Math.Geometry.rad",e.deg.src="JXG.Math.Geometry.trueAngle",e.factorial.src="JXG.Math.factorial",e.trunc.src="JXG.trunc",e.log.src="JXG.Math.log",e.ln.src="Math.log",e.log10.src="JXG.Math.log10",e.lg.src="JXG.Math.log10",e.log2.src="JXG.Math.log2",e.lb.src="JXG.Math.log2",e.ld.src="JXG.Math.log2",e.cosh.src="JXG.Math.cosh",e.sinh.src="JXG.Math.sinh",e.cot.src="JXG.Math.cot",e.acot.src="JXG.Math.acot",e.nthroot.src="JXG.Math.nthroot",e.cbrt.src="JXG.Math.cbrt",e.pow.src="JXG.Math.pow",e.ratpow.src="JXG.Math.ratpow",e.gcd.src="JXG.Math.gcd",e.lcm.src="JXG.Math.lcm",e.binomial.src="JXG.Math.binomial",e.import.src="$jc$.importModule",e.use.src="$jc$.use",e.remove.src="$jc$.del",e.IfThen.src="$jc$.ifthen",e.$.src="(function (n) { return $jc$.board.select(n); })",e.$board&&(e.$board.src="$jc$.board"),e.$log.src="$jc$.log",e},_debug:function(t){"object"==typeof console?console.log(t):Env.isBrowser&&document&&null!==document.getElementById("debug")&&(document.getElementById("debug").innerHTML+=t+"<br />")},_error:function(t){var e=new Error("Error("+this.line+"): "+t);throw e.line=this.line,e},_warn:function(t){"object"==typeof console?console.log("Warning("+this.line+"): "+t):Env.isBrowser&&document&&null!==document.getElementById(this.warnLog)&&(document.getElementById(this.warnLog).innerHTML+="Warning("+this.line+"): "+t+"<br />")},_log:function(t){"object"!=typeof window&&"object"==typeof self&&self.postMessage?self.postMessage({type:"log",msg:"Log: "+t.toString()}):console.log("Log: ",arguments)}});var parser=function(){function t(){this.yy={}}var e=function(t,e,i,r){for(i=i||{},r=t.length;r--;i[t[r]]=e);return i},i=[2,14],r=[1,13],s=[1,37],o=[1,14],n=[1,15],a=[1,21],h=[1,16],l=[1,17],c=[1,33],d=[1,18],u=[1,19],p=[1,12],f=[1,59],m=[1,60],g=[1,58],b=[1,46],v=[1,48],y=[1,49],C=[1,50],_=[1,51],P=[1,52],E=[1,53],x=[1,54],S=[1,45],w=[1,38],O=[1,39],T=[5,7,8,14,15,16,17,19,20,21,23,26,27,50,51,58,65,74,75,76,77,78,79,80,82,91,93],N=[5,7,8,12,14,15,16,17,19,20,21,23,26,27,50,51,58,65,74,75,76,77,78,79,80,82,91,93],M=[8,10,16,32,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,57,64,65,66,83,86],A=[2,48],R=[1,72],L=[10,16,32,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,57,66,83,86],k=[1,78],B=[8,10,16,32,34,35,37,41,42,43,45,46,47,48,50,51,53,54,55,57,64,65,66,83,86],I=[1,82],Y=[8,10,16,32,34,35,37,39,45,46,47,48,50,51,53,54,55,57,64,65,66,83,86],D=[1,83],j=[1,84],X=[1,85],G=[8,10,16,32,34,35,37,39,41,42,43,50,51,53,54,55,57,64,65,66,83,86],F=[1,89],U=[1,90],J=[1,91],z=[1,92],H=[1,97],V=[8,10,16,32,34,35,37,39,41,42,43,45,46,47,48,53,54,55,57,64,65,66,83,86],$=[1,103],q=[1,104],W=[8,10,16,32,34,35,37,39,41,42,43,45,46,47,48,50,51,57,64,65,66,83,86],Z=[1,105],Q=[1,106],K=[1,107],tt=[1,126],et=[1,139],it=[83,86],rt=[1,149],st=[10,66,86],ot=[8,10,16,20,32,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,57,64,65,66,82,83,86],nt=[1,166],at=[10,86],ht={trace:function(){},yy:{},symbols_:{error:2,Program:3,StatementList:4,EOF:5,IfStatement:6,IF:7,"(":8,Expression:9,")":10,Statement:11,ELSE:12,LoopStatement:13,WHILE:14,FOR:15,";":16,DO:17,UnaryStatement:18,USE:19,IDENTIFIER:20,DELETE:21,ReturnStatement:22,RETURN:23,EmptyStatement:24,StatementBlock:25,"{":26,"}":27,ExpressionStatement:28,AssignmentExpression:29,ConditionalExpression:30,LeftHandSideExpression:31,"=":32,LogicalORExpression:33,"?":34,":":35,LogicalANDExpression:36,"||":37,EqualityExpression:38,"&&":39,RelationalExpression:40,"==":41,"!=":42,"~=":43,AdditiveExpression:44,"<":45,">":46,"<=":47,">=":48,MultiplicativeExpression:49,"+":50,"-":51,UnaryExpression:52,"*":53,"/":54,"%":55,ExponentExpression:56,"^":57,"!":58,MemberExpression:59,CallExpression:60,PrimaryExpression:61,FunctionExpression:62,MapExpression:63,".":64,"[":65,"]":66,BasicLiteral:67,ObjectLiteral:68,ArrayLiteral:69,NullLiteral:70,BooleanLiteral:71,StringLiteral:72,NumberLiteral:73,NULL:74,TRUE:75,FALSE:76,STRING:77,NUMBER:78,NAN:79,INFINITY:80,ElementList:81,"<<":82,">>":83,PropertyList:84,Property:85,",":86,PropertyName:87,Arguments:88,AttributeList:89,Attribute:90,FUNCTION:91,ParameterDefinitionList:92,MAP:93,"->":94,$accept:0,$end:1},terminals_:{2:"error",5:"EOF",7:"IF",8:"(",10:")",12:"ELSE",14:"WHILE",15:"FOR",16:";",17:"DO",19:"USE",20:"IDENTIFIER",21:"DELETE",23:"RETURN",26:"{",27:"}",32:"=",34:"?",35:":",37:"||",39:"&&",41:"==",42:"!=",43:"~=",45:"<",46:">",47:"<=",48:">=",50:"+",51:"-",53:"*",54:"/",55:"%",57:"^",58:"!",64:".",65:"[",66:"]",74:"NULL",75:"TRUE",76:"FALSE",77:"STRING",78:"NUMBER",79:"NAN",80:"INFINITY",82:"<<",83:">>",86:",",91:"FUNCTION",93:"MAP",94:"->"},productions_:[0,[3,2],[6,5],[6,7],[13,5],[13,9],[13,7],[18,2],[18,2],[22,2],[22,3],[24,1],[25,3],[4,2],[4,0],[11,1],[11,1],[11,1],[11,1],[11,1],[11,1],[11,1],[28,2],[9,1],[29,1],[29,3],[30,1],[30,5],[33,1],[33,3],[36,1],[36,3],[38,1],[38,3],[38,3],[38,3],[40,1],[40,3],[40,3],[40,3],[40,3],[44,1],[44,3],[44,3],[49,1],[49,3],[49,3],[49,3],[56,1],[56,3],[52,1],[52,2],[52,2],[52,2],[31,1],[31,1],[59,1],[59,1],[59,1],[59,3],[59,4],[61,1],[61,1],[61,1],[61,1],[61,3],[67,1],[67,1],[67,1],[67,1],[70,1],[71,1],[71,1],[72,1],[73,1],[73,1],[73,1],[69,2],[69,3],[68,2],[68,3],[84,1],[84,3],[85,3],[87,1],[87,1],[87,1],[60,2],[60,3],[60,2],[60,4],[60,3],[88,2],[88,3],[89,1],[89,3],[90,1],[90,1],[81,1],[81,3],[62,4],[62,5],[63,6],[92,1],[92,3]],performAction:function(t,e,i,r,s,o,n){var a=o.length-1;switch(s){case 1:return o[a-1];case 2:this.$=lt.createNode(ct(n[a-4]),"node_op","op_if",o[a-2],o[a]);break;case 3:this.$=lt.createNode(ct(n[a-6]),"node_op","op_if_else",o[a-4],o[a-2],o[a]);break;case 4:this.$=lt.createNode(ct(n[a-4]),"node_op","op_while",o[a-2],o[a]);break;case 5:this.$=lt.createNode(ct(n[a-8]),"node_op","op_for",o[a-6],o[a-4],o[a-2],o[a]);break;case 6:this.$=lt.createNode(ct(n[a-6]),"node_op","op_do",o[a-5],o[a-2]);break;case 7:this.$=lt.createNode(ct(n[a-1]),"node_op","op_use",o[a]);break;case 8:this.$=lt.createNode(ct(n[a-1]),"node_op","op_delete",o[a]);break;case 9:this.$=lt.createNode(ct(n[a-1]),"node_op","op_return",void 0);break;case 10:this.$=lt.createNode(ct(n[a-2]),"node_op","op_return",o[a-1]);break;case 11:case 14:this.$=lt.createNode(ct(n[a]),"node_op","op_none");break;case 12:this.$=o[a-1],this.$.needsBrackets=!0;break;case 13:this.$=lt.createNode(ct(n[a-1]),"node_op","op_none",o[a-1],o[a]);break;case 15:case 16:case 17:case 18:case 19:case 20:case 21:case 23:case 24:case 26:case 28:case 30:case 32:case 36:case 41:case 44:case 48:case 50:case 52:case 54:case 55:case 56:case 58:case 62:case 81:case 84:case 85:case 86:this.$=o[a];break;case 22:case 65:case 93:this.$=o[a-1];break;case 25:this.$=lt.createNode(ct(n[a-2]),"node_op","op_assign",o[a-2],o[a]),this.$.isMath=!1;break;case 27:this.$=lt.createNode(ct(n[a-4]),"node_op","op_conditional",o[a-4],o[a-2],o[a]),this.$.isMath=!1;break;case 29:this.$=lt.createNode(ct(n[a-2]),"node_op","op_or",o[a-2],o[a]),this.$.isMath=!1;break;case 31:this.$=lt.createNode(ct(n[a-2]),"node_op","op_and",o[a-2],o[a]),this.$.isMath=!1;break;case 33:this.$=lt.createNode(ct(n[a-2]),"node_op","op_equ",o[a-2],o[a]),this.$.isMath=!1;break;case 34:this.$=lt.createNode(ct(n[a-2]),"node_op","op_neq",o[a-2],o[a]),this.$.isMath=!1;break;case 35:this.$=lt.createNode(ct(n[a-2]),"node_op","op_approx",o[a-2],o[a]),this.$.isMath=!1;break;case 37:this.$=lt.createNode(ct(n[a-2]),"node_op","op_lot",o[a-2],o[a]),this.$.isMath=!1;break;case 38:this.$=lt.createNode(ct(n[a-2]),"node_op","op_grt",o[a-2],o[a]),this.$.isMath=!1;break;case 39:this.$=lt.createNode(ct(n[a-2]),"node_op","op_loe",o[a-2],o[a]),this.$.isMath=!1;break;case 40:this.$=lt.createNode(ct(n[a-2]),"node_op","op_gre",o[a-2],o[a]),this.$.isMath=!1;break;case 42:this.$=lt.createNode(ct(n[a-2]),"node_op","op_add",o[a-2],o[a]),this.$.isMath=!0;break;case 43:this.$=lt.createNode(ct(n[a-2]),"node_op","op_sub",o[a-2],o[a]),this.$.isMath=!0;break;case 45:this.$=lt.createNode(ct(n[a-2]),"node_op","op_mul",o[a-2],o[a]),this.$.isMath=!0;break;case 46:this.$=lt.createNode(ct(n[a-2]),"node_op","op_div",o[a-2],o[a]),this.$.isMath=!0;break;case 47:this.$=lt.createNode(ct(n[a-2]),"node_op","op_mod",o[a-2],o[a]),this.$.isMath=!0;break;case 49:this.$=lt.createNode(ct(n[a-2]),"node_op","op_exp",o[a-2],o[a]),this.$.isMath=!0;break;case 51:this.$=lt.createNode(ct(n[a-1]),"node_op","op_not",o[a]),this.$.isMath=!1;break;case 53:this.$=lt.createNode(ct(n[a-1]),"node_op","op_neg",o[a]),this.$.isMath=!0;break;case 57:case 63:case 64:case 66:case 67:case 68:case 97:this.$=o[a],this.$.isMath=!1;break;case 59:case 91:this.$=lt.createNode(ct(n[a-2]),"node_op","op_property",o[a-2],o[a]),this.$.isMath=!0;break;case 60:case 90:this.$=lt.createNode(ct(n[a-3]),"node_op","op_extvalue",o[a-3],o[a-1]),this.$.isMath=!0;break;case 61:this.$=lt.createNode(ct(n[a]),"node_var",o[a]);break;case 69:this.$=o[a],this.$.isMath=!0;break;case 70:this.$=lt.createNode(ct(n[a]),"node_const",null);break;case 71:this.$=lt.createNode(ct(n[a]),"node_const_bool",!0);break;case 72:this.$=lt.createNode(ct(n[a]),"node_const_bool",!1);break;case 73:this.$=lt.createNode(ct(n[a]),"node_str",o[a].substring(1,o[a].length-1));break;case 74:this.$=lt.createNode(ct(n[a]),"node_const",parseFloat(o[a]));break;case 75:this.$=lt.createNode(ct(n[a]),"node_const",NaN);break;case 76:this.$=lt.createNode(ct(n[a]),"node_const",1/0);break;case 77:this.$=lt.createNode(ct(n[a-1]),"node_op","op_array",[]);break;case 78:this.$=lt.createNode(ct(n[a-2]),"node_op","op_array",o[a-1]);break;case 79:this.$=lt.createNode(ct(n[a-1]),"node_op","op_emptyobject",{});break;case 80:this.$=lt.createNode(ct(n[a-2]),"node_op","op_proplst_val",o[a-1]);break;case 82:this.$=lt.createNode(ct(n[a-2]),"node_op","op_proplst",o[a-2],o[a]);break;case 83:this.$=lt.createNode(ct(n[a-2]),"node_op","op_prop",o[a-2],o[a]);break;case 87:case 89:this.$=lt.createNode(ct(n[a-1]),"node_op","op_execfun",o[a-1],o[a]),this.$.isMath=!0;break;case 88:this.$=lt.createNode(ct(n[a-2]),"node_op","op_execfun",o[a-2],o[a-1],o[a],!0),this.$.isMath=!1;break;case 92:this.$=[];break;case 94:case 98:case 103:this.$=[o[a]];break;case 95:case 99:case 104:this.$=o[a-2].concat(o[a]);break;case 96:this.$=lt.createNode(ct(n[a]),"node_var",o[a]),this.$.isMath=!0;break;case 100:this.$=lt.createNode(ct(n[a-3]),"node_op","op_function",[],o[a]),this.$.isMath=!1;break;case 101:this.$=lt.createNode(ct(n[a-4]),"node_op","op_function",o[a-2],o[a]),this.$.isMath=!1;break;case 102:this.$=lt.createNode(ct(n[a-5]),"node_op","op_map",o[a-3],o[a])}},table:[e([5,7,8,14,15,16,17,19,20,21,23,26,50,51,58,65,74,75,76,77,78,79,80,82,91,93],i,{3:1,4:2}),{1:[3]},{5:[1,3],6:6,7:r,8:s,9:20,11:4,13:7,14:o,15:n,16:a,17:h,18:8,19:l,20:c,21:d,22:9,23:u,24:11,25:5,26:p,28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:f,51:m,52:56,56:57,58:g,59:26,60:27,61:29,62:30,63:31,65:b,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:v,75:y,76:C,77:_,78:P,79:E,80:x,82:S,91:w,93:O},{1:[2,1]},e(T,[2,13]),e(N,[2,15]),e(N,[2,16]),e(N,[2,17]),e(N,[2,18]),e(N,[2,19]),e(N,[2,20]),e(N,[2,21]),e([7,8,14,15,16,17,19,20,21,23,26,27,50,51,58,65,74,75,76,77,78,79,80,82,91,93],i,{4:61}),{8:[1,62]},{8:[1,63]},{8:[1,64]},{6:6,7:r,8:s,9:20,11:65,13:7,14:o,15:n,16:a,17:h,18:8,19:l,20:c,21:d,22:9,23:u,24:11,25:5,26:p,28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:f,51:m,52:56,56:57,58:g,59:26,60:27,61:29,62:30,63:31,65:b,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:v,75:y,76:C,77:_,78:P,79:E,80:x,82:S,91:w,93:O},{20:[1,66]},{20:[1,67]},{8:s,9:69,16:[1,68],20:c,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:f,51:m,52:56,56:57,58:g,59:26,60:27,61:29,62:30,63:31,65:b,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:v,75:y,76:C,77:_,78:P,79:E,80:x,82:S,91:w,93:O},{16:[1,70]},e(N,[2,11]),e(M,[2,23]),e(M,[2,24]),e([8,10,16,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,64,65,66,83,86],A,{32:[1,71],57:R}),e([8,10,16,32,35,39,41,42,43,45,46,47,48,50,51,53,54,55,57,64,65,66,83,86],[2,26],{34:[1,73],37:[1,74]}),e(L,[2,54],{88:77,8:k,64:[1,75],65:[1,76]}),e(L,[2,55],{88:79,8:k,64:[1,81],65:[1,80]}),e(B,[2,28],{39:I}),e(M,[2,56]),e(M,[2,57]),e(M,[2,58]),e(Y,[2,30],{41:D,42:j,43:X}),e(M,[2,61]),e(M,[2,62]),e(M,[2,63]),e(M,[2,64]),{8:s,9:86,20:c,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:f,51:m,52:56,56:57,58:g,59:26,60:27,61:29,62:30,63:31,65:b,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:v,75:y,76:C,77:_,78:P,79:E,80:x,82:S,91:w,93:O},{8:[1,87]},{8:[1,88]},e(G,[2,32],{45:F,46:U,47:J,48:z}),e(M,[2,66]),e(M,[2,67]),e(M,[2,68]),e(M,[2,69]),{20:H,72:98,73:99,77:_,78:P,79:E,80:x,83:[1,93],84:94,85:95,87:96},{8:s,20:c,29:102,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:f,51:m,52:56,56:57,58:g,59:26,60:27,61:29,62:30,63:31,65:b,66:[1,100],67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:v,75:y,76:C,77:_,78:P,79:E,80:x,81:101,82:S,91:w,93:O},e(V,[2,36],{50:$,51:q}),e(M,[2,70]),e(M,[2,71]),e(M,[2,72]),e(M,[2,73]),e(M,[2,74]),e(M,[2,75]),e(M,[2,76]),e(W,[2,41],{53:Z,54:Q,55:K}),e(M,[2,44]),e(M,[2,50]),{8:s,20:c,31:109,50:f,51:m,52:108,56:57,58:g,59:26,60:27,61:29,62:30,63:31,65:b,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:v,75:y,76:C,77:_,78:P,79:E,80:x,82:S,91:w,93:O},{8:s,20:c,31:109,50:f,51:m,52:110,56:57,58:g,59:26,60:27,61:29,62:30,63:31,65:b,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:v,75:y,76:C,77:_,78:P,79:E,80:x,82:S,91:w,93:O},{8:s,20:c,31:109,50:f,51:m,52:111,56:57,58:g,59:26,60:27,61:29,62:30,63:31,65:b,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:v,75:y,76:C,77:_,78:P,79:E,80:x,82:S,91:w,93:O},{6:6,7:r,8:s,9:20,11:4,13:7,14:o,15:n,16:a,17:h,18:8,19:l,20:c,21:d,22:9,23:u,24:11,25:5,26:p,27:[1,112],28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:f,51:m,52:56,56:57,58:g,59:26,60:27,61:29,62:30,63:31,65:b,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:v,75:y,76:C,77:_,78:P,79:E,80:x,82:S,91:w,93:O},{8:s,9:113,20:c,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:f,51:m,52:56,56:57,58:g,59:26,60:27,61:29,62:30,63:31,65:b,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:v,75:y,76:C,77:_,78:P,79:E,80:x,82:S,91:w,93:O},{8:s,9:114,20:c,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:f,51:m,52:56,56:57,58:g,59:26,60:27,61:29,62:30,63:31,65:b,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:v,75:y,76:C,77:_,78:P,79:E,80:x,82:S,91:w,93:O},{8:s,9:115,20:c,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:f,51:m,52:56,56:57,58:g,59:26,60:27,61:29,62:30,63:31,65:b,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:v,75:y,76:C,77:_,78:P,79:E,80:x,82:S,91:w,93:O},{14:[1,116]},e(N,[2,7]),e(N,[2,8]),e(N,[2,9]),{16:[1,117]},e(N,[2,22]),{8:s,20:c,29:118,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:f,51:m,52:56,56:57,58:g,59:26,60:27,61:29,62:30,63:31,65:b,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:v,75:y,76:C,77:_,78:P,79:E,80:x,82:S,91:w,93:O},{8:s,20:c,31:109,50:f,51:m,52:119,56:57,58:g,59:26,60:27,61:29,62:30,63:31,65:b,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:v,75:y,76:C,77:_,78:P,79:E,80:x,82:S,91:w,93:O},{8:s,20:c,29:120,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:f,51:m,52:56,56:57,58:g,59:26,60:27,61:29,62:30,63:31,65:b,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:v,75:y,76:C,77:_,78:P,79:E,80:x,82:S,91:w,93:O},{8:s,20:c,31:109,36:121,38:32,40:40,44:47,49:55,50:f,51:m,52:56,56:57,58:g,59:26, -60:27,61:29,62:30,63:31,65:b,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:v,75:y,76:C,77:_,78:P,79:E,80:x,82:S,91:w,93:O},{20:[1,122]},{8:s,9:123,20:c,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:f,51:m,52:56,56:57,58:g,59:26,60:27,61:29,62:30,63:31,65:b,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:v,75:y,76:C,77:_,78:P,79:E,80:x,82:S,91:w,93:O},e(M,[2,87],{89:124,90:125,68:127,20:tt,82:S}),{8:s,10:[1,128],20:c,29:102,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:f,51:m,52:56,56:57,58:g,59:26,60:27,61:29,62:30,63:31,65:b,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:v,75:y,76:C,77:_,78:P,79:E,80:x,81:129,82:S,91:w,93:O},e(M,[2,89]),{8:s,9:130,20:c,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:f,51:m,52:56,56:57,58:g,59:26,60:27,61:29,62:30,63:31,65:b,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:v,75:y,76:C,77:_,78:P,79:E,80:x,82:S,91:w,93:O},{20:[1,131]},{8:s,20:c,31:109,38:132,40:40,44:47,49:55,50:f,51:m,52:56,56:57,58:g,59:26,60:27,61:29,62:30,63:31,65:b,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:v,75:y,76:C,77:_,78:P,79:E,80:x,82:S,91:w,93:O},{8:s,20:c,31:109,40:133,44:47,49:55,50:f,51:m,52:56,56:57,58:g,59:26,60:27,61:29,62:30,63:31,65:b,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:v,75:y,76:C,77:_,78:P,79:E,80:x,82:S,91:w,93:O},{8:s,20:c,31:109,40:134,44:47,49:55,50:f,51:m,52:56,56:57,58:g,59:26,60:27,61:29,62:30,63:31,65:b,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:v,75:y,76:C,77:_,78:P,79:E,80:x,82:S,91:w,93:O},{8:s,20:c,31:109,40:135,44:47,49:55,50:f,51:m,52:56,56:57,58:g,59:26,60:27,61:29,62:30,63:31,65:b,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:v,75:y,76:C,77:_,78:P,79:E,80:x,82:S,91:w,93:O},{10:[1,136]},{10:[1,137],20:et,92:138},{20:et,92:140},{8:s,20:c,31:109,44:141,49:55,50:f,51:m,52:56,56:57,58:g,59:26,60:27,61:29,62:30,63:31,65:b,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:v,75:y,76:C,77:_,78:P,79:E,80:x,82:S,91:w,93:O},{8:s,20:c,31:109,44:142,49:55,50:f,51:m,52:56,56:57,58:g,59:26,60:27,61:29,62:30,63:31,65:b,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:v,75:y,76:C,77:_,78:P,79:E,80:x,82:S,91:w,93:O},{8:s,20:c,31:109,44:143,49:55,50:f,51:m,52:56,56:57,58:g,59:26,60:27,61:29,62:30,63:31,65:b,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:v,75:y,76:C,77:_,78:P,79:E,80:x,82:S,91:w,93:O},{8:s,20:c,31:109,44:144,49:55,50:f,51:m,52:56,56:57,58:g,59:26,60:27,61:29,62:30,63:31,65:b,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:v,75:y,76:C,77:_,78:P,79:E,80:x,82:S,91:w,93:O},e(M,[2,79]),{83:[1,145],86:[1,146]},e(it,[2,81]),{35:[1,147]},{35:[2,84]},{35:[2,85]},{35:[2,86]},e(M,[2,77]),{66:[1,148],86:rt},e(st,[2,98]),{8:s,20:c,31:109,49:150,50:f,51:m,52:56,56:57,58:g,59:26,60:27,61:29,62:30,63:31,65:b,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:v,75:y,76:C,77:_,78:P,79:E,80:x,82:S,91:w,93:O},{8:s,20:c,31:109,49:151,50:f,51:m,52:56,56:57,58:g,59:26,60:27,61:29,62:30,63:31,65:b,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:v,75:y,76:C,77:_,78:P,79:E,80:x,82:S,91:w,93:O},{8:s,20:c,31:109,50:f,51:m,52:152,56:57,58:g,59:26,60:27,61:29,62:30,63:31,65:b,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:v,75:y,76:C,77:_,78:P,79:E,80:x,82:S,91:w,93:O},{8:s,20:c,31:109,50:f,51:m,52:153,56:57,58:g,59:26,60:27,61:29,62:30,63:31,65:b,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:v,75:y,76:C,77:_,78:P,79:E,80:x,82:S,91:w,93:O},{8:s,20:c,31:109,50:f,51:m,52:154,56:57,58:g,59:26,60:27,61:29,62:30,63:31,65:b,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:v,75:y,76:C,77:_,78:P,79:E,80:x,82:S,91:w,93:O},e(M,[2,51]),e([8,10,16,32,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,64,65,66,83,86],A,{57:R}),e(M,[2,52]),e(M,[2,53]),e([5,7,8,10,12,14,15,16,17,19,20,21,23,26,27,32,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,57,58,64,65,66,74,75,76,77,78,79,80,82,83,86,91,93],[2,12]),{10:[1,155]},{10:[1,156]},{16:[1,157]},{8:[1,158]},e(N,[2,10]),e(M,[2,25]),e(M,[2,49]),{35:[1,159]},e(B,[2,29],{39:I}),e(M,[2,59]),{66:[1,160]},e([8,10,16,32,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,57,64,65,66,83],[2,88],{86:[1,161]}),e(M,[2,94]),e(M,[2,96]),e(M,[2,97]),e(ot,[2,92]),{10:[1,162],86:rt},{66:[1,163]},e(M,[2,91]),e(Y,[2,31],{41:D,42:j,43:X}),e(G,[2,33],{45:F,46:U,47:J,48:z}),e(G,[2,34],{45:F,46:U,47:J,48:z}),e(G,[2,35],{45:F,46:U,47:J,48:z}),e(M,[2,65]),{25:164,26:p},{10:[1,165],86:nt},e(at,[2,103]),{10:[1,167],86:nt},e(V,[2,37],{50:$,51:q}),e(V,[2,38],{50:$,51:q}),e(V,[2,39],{50:$,51:q}),e(V,[2,40],{50:$,51:q}),e(M,[2,80]),{20:H,72:98,73:99,77:_,78:P,79:E,80:x,85:168,87:96},{8:s,20:c,29:169,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:f,51:m,52:56,56:57,58:g,59:26,60:27,61:29,62:30,63:31,65:b,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:v,75:y,76:C,77:_,78:P,79:E,80:x,82:S,91:w,93:O},e(M,[2,78]),{8:s,20:c,29:170,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:f,51:m,52:56,56:57,58:g,59:26,60:27,61:29,62:30,63:31,65:b,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:v,75:y,76:C,77:_,78:P,79:E,80:x,82:S,91:w,93:O},e(W,[2,42],{53:Z,54:Q,55:K}),e(W,[2,43],{53:Z,54:Q,55:K}),e(M,[2,45]),e(M,[2,46]),e(M,[2,47]),{6:6,7:r,8:s,9:20,11:171,13:7,14:o,15:n,16:a,17:h,18:8,19:l,20:c,21:d,22:9,23:u,24:11,25:5,26:p,28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:f,51:m,52:56,56:57,58:g,59:26,60:27,61:29,62:30,63:31,65:b,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:v,75:y,76:C,77:_,78:P,79:E,80:x,82:S,91:w,93:O},{6:6,7:r,8:s,9:20,11:172,13:7,14:o,15:n,16:a,17:h,18:8,19:l,20:c,21:d,22:9,23:u,24:11,25:5,26:p,28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:f,51:m,52:56,56:57,58:g,59:26,60:27,61:29,62:30,63:31,65:b,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:v,75:y,76:C,77:_,78:P,79:E,80:x,82:S,91:w,93:O},{8:s,9:173,20:c,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:f,51:m,52:56,56:57,58:g,59:26,60:27,61:29,62:30,63:31,65:b,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:v,75:y,76:C,77:_,78:P,79:E,80:x,82:S,91:w,93:O},{8:s,9:174,20:c,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:f,51:m,52:56,56:57,58:g,59:26,60:27,61:29,62:30,63:31,65:b,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:v,75:y,76:C,77:_,78:P,79:E,80:x,82:S,91:w,93:O},{8:s,20:c,29:175,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:f,51:m,52:56,56:57,58:g,59:26,60:27,61:29,62:30,63:31,65:b,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:v,75:y,76:C,77:_,78:P,79:E,80:x,82:S,91:w,93:O},e(M,[2,60]),{20:tt,68:127,82:S,90:176},e(ot,[2,93]),e(M,[2,90]),e(M,[2,100]),{25:177,26:p},{20:[1,178]},{94:[1,179]},e(it,[2,82]),e(it,[2,83]),e(st,[2,99]),e(T,[2,2],{12:[1,180]}),e(N,[2,4]),{16:[1,181]},{10:[1,182]},e(M,[2,27]),e(M,[2,95]),e(M,[2,101]),e(at,[2,104]),{8:s,9:183,20:c,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:f,51:m,52:56,56:57,58:g,59:26,60:27,61:29,62:30,63:31,65:b,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:v,75:y,76:C,77:_,78:P,79:E,80:x,82:S,91:w,93:O},{6:6,7:r,8:s,9:20,11:184,13:7,14:o,15:n,16:a,17:h,18:8,19:l,20:c,21:d,22:9,23:u,24:11,25:5,26:p,28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:f,51:m,52:56,56:57,58:g,59:26,60:27,61:29,62:30,63:31,65:b,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:v,75:y,76:C,77:_,78:P,79:E,80:x,82:S,91:w,93:O},{8:s,9:185,20:c,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:f,51:m,52:56,56:57,58:g,59:26,60:27,61:29,62:30,63:31,65:b,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:v,75:y,76:C,77:_,78:P,79:E,80:x,82:S,91:w,93:O},{16:[1,186]},e(M,[2,102]),e(N,[2,3]),{10:[1,187]},e(N,[2,6]),{6:6,7:r,8:s,9:20,11:188,13:7,14:o,15:n,16:a,17:h,18:8,19:l,20:c,21:d,22:9,23:u,24:11,25:5,26:p,28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:f,51:m,52:56,56:57,58:g,59:26,60:27,61:29,62:30,63:31,65:b,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:v,75:y,76:C,77:_,78:P,79:E,80:x,82:S,91:w,93:O},e(N,[2,5])],defaultActions:{3:[2,1],97:[2,84],98:[2,85],99:[2,86]},parseError:function(t,e){if(!e.recoverable){var i=new Error(t);throw i.hash=e,i}this.trace(t)},parse:function(t){var e=this,i=[0],r=[null],s=[],o=this.table,n="",a=0,h=0,l=0,c=s.slice.call(arguments,1),d=Object.create(this.lexer),u={yy:{}};for(var p in this.yy)Object.prototype.hasOwnProperty.call(this.yy,p)&&(u.yy[p]=this.yy[p]);d.setInput(t,u.yy),u.yy.lexer=d,u.yy.parser=this,void 0===d.yylloc&&(d.yylloc={});var f=d.yylloc;s.push(f);var m=d.options&&d.options.ranges;"function"==typeof u.yy.parseError?this.parseError=u.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;for(var g,b,v,y,C,_,P,E,x,S=function(){var t;return t=d.lex()||1,"number"!=typeof t&&(t=e.symbols_[t]||t),t},w={};;){if(v=i[i.length-1],this.defaultActions[v]?y=this.defaultActions[v]:(null!==g&&void 0!==g||(g=S()),y=o[v]&&o[v][g]),void 0===y||!y.length||!y[0]){var O="";x=[];for(_ in o[v])this.terminals_[_]&&_>2&&x.push("'"+this.terminals_[_]+"'");O=d.showPosition?"Parse error on line "+(a+1)+":\n"+d.showPosition()+"\nExpecting "+x.join(", ")+", got '"+(this.terminals_[g]||g)+"'":"Parse error on line "+(a+1)+": Unexpected "+(1==g?"end of input":"'"+(this.terminals_[g]||g)+"'"),this.parseError(O,{text:d.match,token:this.terminals_[g]||g,line:d.yylineno,loc:f,expected:x})}if(y[0]instanceof Array&&y.length>1)throw new Error("Parse Error: multiple actions possible at state: "+v+", token: "+g);switch(y[0]){case 1:i.push(g),r.push(d.yytext),s.push(d.yylloc),i.push(y[1]),g=null,b?(g=b,b=null):(h=d.yyleng,n=d.yytext,a=d.yylineno,f=d.yylloc,l>0&&l--);break;case 2:if(P=this.productions_[y[1]][1],w.$=r[r.length-P],w._$={first_line:s[s.length-(P||1)].first_line,last_line:s[s.length-1].last_line,first_column:s[s.length-(P||1)].first_column,last_column:s[s.length-1].last_column},m&&(w._$.range=[s[s.length-(P||1)].range[0],s[s.length-1].range[1]]),void 0!==(C=this.performAction.apply(w,[n,h,a,u.yy,y[1],r,s].concat(c))))return C;P&&(i=i.slice(0,-1*P*2),r=r.slice(0,-1*P),s=s.slice(0,-1*P)),i.push(this.productions_[y[1]][0]),r.push(w.$),s.push(w._$),E=o[i[i.length-2]][i[i.length-1]],i.push(E);break;case 3:return!0}}return!0}},lt={node:function(t,e,i){return{type:t,value:e,children:i}},createNode:function(t,e,i,r){var s,o=this.node(e,i,[]);for(s=3;s<arguments.length;s++)o.children.push(arguments[s]);return o.line=t[0],o.col=t[1],o.eline=t[2],o.ecol=t[3],o}},ct=function(t){return[t.first_line,t.first_column,t.last_line,t.last_column]},dt=function(){return{EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)},setInput:function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,i=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var r=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),i.length-1&&(this.yylineno-=i.length-1);var s=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:i?(i.length===r.length?this.yylloc.first_column:0)+r[r.length-i.length].length-i[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[s[0],s[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(t){this.unput(this.match.slice(t))},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},test_match:function(t,e){var i,r,s;if(this.options.backtrack_lexer&&(s={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(s.yylloc.range=this.yylloc.range.slice(0))),r=t[0].match(/(?:\r\n?|\n).*/g),r&&(this.yylineno+=r.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:r?r[r.length-1].length-r[r.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],i=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),i)return i;if(this._backtrack){for(var o in s)this[o]=s[o];return!1}return!1},next:function(){if(this.done)return this.EOF;this._input||(this.done=!0);var t,e,i,r;this._more||(this.yytext="",this.match="");for(var s=this._currentRules(),o=0;o<s.length;o++)if((i=this._input.match(this.rules[s[o]]))&&(!e||i[0].length>e[0].length)){if(e=i,r=o,this.options.backtrack_lexer){if(!1!==(t=this.test_match(i,s[o])))return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,s[r]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){var t=this.next();return t||this.lex()},begin:function(t){this.conditionStack.push(t)},popState:function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(t){return t=this.conditionStack.length-1-Math.abs(t||0),t>=0?this.conditionStack[t]:"INITIAL"},pushState:function(t){this.begin(t)},stateStackSize:function(){return this.conditionStack.length},options:{},performAction:function(t,e,i,r){switch(i){case 0:break;case 1:case 2:return 78;case 3:case 4:return 77;case 5:case 6:break;case 7:return 7;case 8:return 12;case 9:return 14;case 10:return 17;case 11:return 15;case 12:return 91;case 13:return 93;case 14:return 19;case 15:return 23;case 16:return 21;case 17:return 75;case 18:return 76;case 19:return 74;case 20:return 80;case 21:return 94;case 22:return 82;case 23:return 83;case 24:return 26;case 25:return 27;case 26:return 16;case 27:return"#";case 28:return 34;case 29:return 35;case 30:return 79;case 31:return 64;case 32:return 65;case 33:return 66;case 34:return 8;case 35:return 10;case 36:return 58;case 37:return 57;case 38:return 53;case 39:return 54;case 40:return 55;case 41:return 50;case 42:return 51;case 43:return 47;case 44:return 45;case 45:return 48;case 46:return 46;case 47:return 41;case 48:return 43;case 49:return 42;case 50:return 39;case 51:return 37;case 52:return 32;case 53:return 86;case 54:return 5;case 55:return 20;case 56:return"INVALID"}},rules:[/^(?:\s+)/,/^(?:[0-9]+\.[0-9]*|[0-9]*\.[0-9]+\b)/,/^(?:[0-9]+)/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:\/\/.*)/,/^(?:\/\*(.|\n|\r)*?\*\/)/,/^(?:if\b)/,/^(?:else\b)/,/^(?:while\b)/,/^(?:do\b)/,/^(?:for\b)/,/^(?:function\b)/,/^(?:map\b)/,/^(?:use\b)/,/^(?:return\b)/,/^(?:delete\b)/,/^(?:true\b)/,/^(?:false\b)/,/^(?:null\b)/,/^(?:Infinity\b)/,/^(?:->)/,/^(?:<<)/,/^(?:>>)/,/^(?:\{)/,/^(?:\})/,/^(?:;)/,/^(?:#)/,/^(?:\?)/,/^(?::)/,/^(?:NaN\b)/,/^(?:\.)/,/^(?:\[)/,/^(?:\])/,/^(?:\()/,/^(?:\))/,/^(?:!)/,/^(?:\^)/,/^(?:\*)/,/^(?:\/)/,/^(?:%)/,/^(?:\+)/,/^(?:-)/,/^(?:<=)/,/^(?:<)/,/^(?:>=)/,/^(?:>)/,/^(?:==)/,/^(?:~=)/,/^(?:!=)/,/^(?:&&)/,/^(?:\|\|)/,/^(?:=)/,/^(?:,)/,/^(?:$)/,/^(?:[A-Za-z_\$][A-Za-z0-9_]*)/,/^(?:.)/],conditions:{INITIAL:{rules:[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56],inclusive:!0}}}}();return ht.lexer=dt,t.prototype=ht,ht.Parser=t,new t}();return void 0!==require&&"undefined"!=typeof exports&&(exports.parser=parser,exports.Parser=parser.Parser,exports.parse=function(){return parser.parse.apply(parser,arguments)},exports.main=function(t){t[1]||(console.log("Usage: "+t[0]+" FILE"),process.exit(1));var e=require("fs").readFileSync(require("path").normalize(t[1]),"utf8");return exports.parser.parse(e)},"undefined"!=typeof module&&require.main===module&&exports.main(process.argv.slice(1))),parser.yy.parseError=parser.parseError,JXG.JessieCode}),define("base/point",["jxg","options","math/math","math/geometry","math/numerics","base/coords","base/constants","base/element","parser/geonext","utils/type","base/transformation","base/coordselement"],function(t,e,i,r,s,o,n,a,h,l,c,d){"use strict";return t.Point=function(t,e,i){this.constructor(t,i,n.OBJECT_TYPE_POINT,n.OBJECT_CLASS_POINT),this.element=this.board.select(i.anchor),this.coordsConstructor(e),this.elType="point",this.id=this.board.setId(this,"P"),this.board.renderer.drawPoint(this),this.board.finalizeAdding(this),this.createLabel()},t.Point.prototype=new a,l.copyPrototypeMethods(t.Point,d,"coordsConstructor"),t.extend(t.Point.prototype,{hasPoint:function(t,e){var i,r,s,o=this.coords.scrCoords,n=l.evaluate(this.visProp.sizeunit);return l.isObject(l.evaluate(this.visProp.precision))?(s=this.board._inputDevice,r=l.evaluate(this.visProp.precision[s])):r=this.board.options.precision.hasPoint,i=parseFloat(l.evaluate(this.visProp.size)),"user"===n&&(i*=Math.sqrt(this.board.unitX*this.board.unitY)),i+=.5*parseFloat(l.evaluate(this.visProp.strokewidth)),i<r&&(i=r),Math.abs(o[1]-t)<i+2&&Math.abs(o[2]-e)<i+2},update:function(t){return this.needsUpdate?(this.updateCoords(t),l.evaluate(this.visProp.trace)&&this.cloneToBackground(!0),this):this},updateTransform:function(){var t,e;if(0===this.transformations.length||null===this.baseElement)return this;for(t=this===this.baseElement?this.transformations[0].apply(this.baseElement,"self"):this.transformations[0].apply(this.baseElement),this.coords.setCoordinates(n.COORDS_BY_USER,t),e=1;e<this.transformations.length;e++)this.coords.setCoordinates(n.COORDS_BY_USER,this.transformations[e].apply(this));return this},updateRenderer:function(){return this.updateRendererGeneric("updatePoint"),this},bounds:function(){return this.coords.usrCoords.slice(1).concat(this.coords.usrCoords.slice(1))},makeIntersection:function(t,e,i,s){var o;t=this.board.select(t),e=this.board.select(e),o=r.intersectionFunction(this.board,t,e,i,s,l.evaluate(this.visProp.alwaysintersect)),this.addConstraint([o]);try{t.addChild(this),e.addChild(this)}catch(i){throw new Error("JSXGraph: Can't create 'intersection' with parent types '"+typeof t+"' and '"+typeof e+"'.")}this.type=n.OBJECT_TYPE_INTERSECTION,this.elType="intersection",this.parents=[t.id,e.id,i,s],this.generatePolynomial=function(){var i=t.generatePolynomial(this),r=e.generatePolynomial(this);return 0===i.length||0===r.length?[]:[i[0],r[0]]},this.prepareUpdate().update()},setStyle:function(t){var e=["cross","cross","cross","circle","circle","circle","circle","square","square","square","plus","plus","plus"],i=[2,3,4,1,2,3,4,2,3,4,2,3,4];return this.visProp.face=e[t],this.visProp.size=i[t],this.board.renderer.changePointStyle(this),this},normalizeFace:function(i){return t.deprecated("Point.normalizeFace()","JXG.normalizePointFace()"),e.normalizePointFace(i)},face:function(e){t.deprecated("Point.face()","Point.setAttribute()"),this.setAttribute({face:e})},size:function(e){t.deprecated("Point.size()","Point.setAttribute()"),this.setAttribute({size:e})},cloneToBackground:function(){var t={};return t.id=this.id+"T"+this.numTraces,this.numTraces+=1,t.coords=this.coords,t.visProp=l.deepCopy(this.visProp,this.visProp.traceattributes,!0),t.visProp.layer=this.board.options.layer.trace,t.elementClass=n.OBJECT_CLASS_POINT,t.board=this.board,l.clearVisPropOld(t),t.visPropCalc={visible:l.evaluate(t.visProp.visible)},this.board.renderer.drawPoint(t),this.traces[t.id]=t.rendNode,this}}),t.createPoint=function(e,i,r){var s,o;if(o=l.copyAttributes(r,e.options,"point"),!(s=d.create(t.Point,e,i,o)))throw new Error("JSXGraph: Can't create point with parent types '"+typeof i[0]+"' and '"+typeof i[1]+"'.\nPossible parent types: [x,y], [z,x,y], [element,transformation]");return s},t.createGlider=function(t,e,i){var r,s,o=l.copyAttributes(i,t.options,"glider");return s=1===e.length?[0,0]:e.slice(0,2),r=t.create("point",s,o),r.makeGlider(e[e.length-1]),r},t.createIntersectionPoint=function(t,e,i){var s,o,a,h,c,d,u=l.copyAttributes(i,t.options,"intersection");e.push(0,0),o=t.select(e[0]),a=t.select(e[1]),c=e[2]||0,d=e[3]||0,s=t.create("point",[0,0,0],u),h=r.intersectionFunction(t,o,a,c,d,s.visProp.alwaysintersect),s.addConstraint([h]);try{o.addChild(s),a.addChild(s)}catch(t){throw new Error("JSXGraph: Can't create 'intersection' with parent types '"+typeof e[0]+"' and '"+typeof e[1]+"'.")}return s.type=n.OBJECT_TYPE_INTERSECTION,s.elType="intersection",s.setParents([o.id,a.id]),s.intersectionNumbers=[c,d],s.getParents=function(){return this.parents.concat(this.intersectionNumbers)},s.generatePolynomial=function(){var t=o.generatePolynomial(s),e=a.generatePolynomial(s);return 0===t.length||0===e.length?[]:[t[0],e[0]]},s},t.createOtherIntersectionPoint=function(t,e,s){var o,a,h,c;if(3!==e.length||!l.isPoint(e[2])||e[0].elementClass!==n.OBJECT_CLASS_LINE&&e[0].elementClass!==n.OBJECT_CLASS_CIRCLE||e[1].elementClass!==n.OBJECT_CLASS_LINE&&e[1].elementClass!==n.OBJECT_CLASS_CIRCLE)throw new Error("JSXGraph: Can't create 'other intersection point' with parent types '"+typeof e[0]+"', '"+typeof e[1]+"'and '"+typeof e[2]+"'.\nPossible parent types: [circle|line,circle|line,point]");return a=t.select(e[0]),h=t.select(e[1]),c=t.select(e[2]),o=t.create("point",[function(){var t=r.meet(a.stdform,h.stdform,0,a.board);return Math.abs(c.X()-t.usrCoords[1])>i.eps||Math.abs(c.Y()-t.usrCoords[2])>i.eps||Math.abs(c.Z()-t.usrCoords[0])>i.eps?t:r.meet(a.stdform,h.stdform,1,a.board)}],s),o.type=n.OBJECT_TYPE_INTERSECTION,o.elType="otherintersection",o.setParents([a.id,h.id,c]),a.addChild(o),h.addChild(o),o.generatePolynomial=function(){var t=a.generatePolynomial(o),e=h.generatePolynomial(o);return 0===t.length||0===e.length?[]:[t[0],e[0]]},o},t.createPolePoint=function(e,i,r){var s,o,a,h,l,c,d;if(i.length>1&&(h=i[0].type===n.OBJECT_TYPE_CONIC||i[0].elementClass===n.OBJECT_CLASS_CIRCLE,l=i[1].type===n.OBJECT_TYPE_CONIC||i[1].elementClass===n.OBJECT_CLASS_CIRCLE,c=i[0].elementClass===n.OBJECT_CLASS_LINE,d=i[1].elementClass===n.OBJECT_CLASS_LINE),2!==i.length||!(h&&d||c&&l))throw new Error("JSXGraph: Can't create 'pole point' with parent types '"+typeof i[0]+"' and '"+typeof i[1]+"'.\nPossible parent type: [conic|circle,line], [line,conic|circle]");return d?(o=e.select(i[0]),a=e.select(i[1])):(o=e.select(i[1]),a=e.select(i[0])),s=e.create("point",[function(){var e=o.quadraticform,i=a.stdform.slice(0,3);return[t.Math.Numerics.det([i,e[1],e[2]]),t.Math.Numerics.det([e[0],i,e[2]]),t.Math.Numerics.det([e[0],e[1],i])]}],r),s.elType="polepoint",s.setParents([o.id,a.id]),o.addChild(s),a.addChild(s),s},t.registerElement("point",t.createPoint),t.registerElement("glider",t.createGlider),t.registerElement("intersection",t.createIntersectionPoint),t.registerElement("otherintersection",t.createOtherIntersectionPoint),t.registerElement("polepoint",t.createPolePoint),{Point:t.Point,createPoint:t.createPoint,createGlider:t.createGlider,createIntersection:t.createIntersectionPoint,createOtherIntersection:t.createOtherIntersectionPoint,createPolePoint:t.createPolePoint}}),define("base/line",["jxg","math/math","math/geometry","math/numerics","math/statistics","base/constants","base/coords","base/element","utils/type","base/point"],function(t,e,i,r,s,o,n,a,h,l){"use strict";return t.Line=function(e,i,r,s){this.constructor(e,s,o.OBJECT_TYPE_LINE,o.OBJECT_CLASS_LINE),this.point1=this.board.select(i),this.point2=this.board.select(r),this.ticks=[],this.defaultTicks=null,this.parentPolygon=null,this.id=this.board.setId(this,"L"),this.board.renderer.drawLine(this),this.board.finalizeAdding(this),this.elType="line",this.point1.addChild(this),this.point2.addChild(this),this.inherits.push(this.point1,this.point2),this.updateStdform(),this.createLabel(),this.methodMap=t.deepCopy(this.methodMap,{point1:"point1",point2:"point2",getSlope:"getSlope",getRise:"getRise",getYIntersect:"getRise",getAngle:"getAngle",L:"L",length:"L"})},t.Line.prototype=new a,t.extend(t.Line.prototype,{hasPoint:function(t,r){var s,a,l,c,d,u,p,f,m,g=[],b=[1,t,r],v=h.evaluate(this.visProp.strokewidth);return h.isObject(h.evaluate(this.visProp.precision))?(m=this.board._inputDevice,f=h.evaluate(this.visProp.precision[m])):f=this.board.options.precision.hasPoint,f+=.5*v,g[0]=this.stdform[0]-this.stdform[1]*this.board.origin.scrCoords[1]/this.board.unitX+this.stdform[2]*this.board.origin.scrCoords[2]/this.board.unitY,g[1]=this.stdform[1]/this.board.unitX,g[2]=this.stdform[2]/-this.board.unitY,s=i.distPointLine(b,g),!(isNaN(s)||s>f)&&(!(!h.evaluate(this.visProp.straightfirst)||!h.evaluate(this.visProp.straightlast))||(l=this.point1.coords,c=this.point2.coords,a=[0,g[1],g[2]],a=e.crossProduct(a,b),a=e.crossProduct(a,g),a[1]/=a[0],a[2]/=a[0],a[0]=1,a=new n(o.COORDS_BY_SCREEN,a.slice(1),this.board).usrCoords,d=l.distance(o.COORDS_BY_USER,c),l=l.usrCoords.slice(0),c=c.usrCoords.slice(0),d<e.eps?u=0:(d===Number.POSITIVE_INFINITY&&(d=1/e.eps,Math.abs(c[0])<e.eps?(d/=i.distance([0,0,0],c),c=[1,l[1]+c[1]*d,l[2]+c[2]*d]):(d/=i.distance([0,0,0],l),l=[1,c[1]+l[1]*d,c[2]+l[2]*d])),p=1,d=c[p]-l[p],Math.abs(d)<e.eps&&(p=2,d=c[p]-l[p]),u=(a[p]-l[p])/d),!(!h.evaluate(this.visProp.straightfirst)&&u<0)&&!(!h.evaluate(this.visProp.straightlast)&&u>1)))},update:function(){var t;return this.needsUpdate?(this.constrained&&(h.isFunction(this.funps)?(t=this.funps())&&t.length&&2===t.length&&(this.point1=t[0],this.point2=t[1]):(h.isFunction(this.funp1)&&(t=this.funp1(),h.isPoint(t)?this.point1=t:t&&t.length&&2===t.length&&this.point1.setPositionDirectly(o.COORDS_BY_USER,t)),h.isFunction(this.funp2)&&(t=this.funp2(),h.isPoint(t)?this.point2=t:t&&t.length&&2===t.length&&this.point2.setPositionDirectly(o.COORDS_BY_USER,t)))),this.updateSegmentFixedLength(),this.updateStdform(),h.evaluate(this.visProp.trace)&&this.cloneToBackground(!0),this):this},updateSegmentFixedLength:function(){var t,i,r,s,n,a,l,c;return this.hasFixedLength?(t=this.point1.Dist(this.point2),i=this.fixedLength(),r=this.fixedLengthOldCoords[0].distance(o.COORDS_BY_USER,this.point1.coords),s=this.fixedLengthOldCoords[1].distance(o.COORDS_BY_USER,this.point2.coords),(r>e.eps||s>e.eps||t!==i)&&(n=this.point1.isDraggable&&this.point1.type!==o.OBJECT_TYPE_GLIDER&&!h.evaluate(this.point1.visProp.fixed),a=this.point2.isDraggable&&this.point2.type!==o.OBJECT_TYPE_GLIDER&&!h.evaluate(this.point2.visProp.fixed),t>e.eps?r>s&&a||r<=s&&a&&!n?(this.point2.setPositionDirectly(o.COORDS_BY_USER,[this.point1.X()+(this.point2.X()-this.point1.X())*i/t,this.point1.Y()+(this.point2.Y()-this.point1.Y())*i/t]),this.point2.fullUpdate()):(r<=s&&n||r>s&&n&&!a)&&(this.point1.setPositionDirectly(o.COORDS_BY_USER,[this.point2.X()+(this.point1.X()-this.point2.X())*i/t,this.point2.Y()+(this.point1.Y()-this.point2.Y())*i/t]),this.point1.fullUpdate()):(l=Math.random()-.5,c=Math.random()-.5,t=Math.sqrt(l*l+c*c),a?(this.point2.setPositionDirectly(o.COORDS_BY_USER,[this.point1.X()+l*i/t,this.point1.Y()+c*i/t]),this.point2.fullUpdate()):n&&(this.point1.setPositionDirectly(o.COORDS_BY_USER,[this.point2.X()+l*i/t,this.point2.Y()+c*i/t]),this.point1.fullUpdate())),this.fixedLengthOldCoords[0].setCoordinates(o.COORDS_BY_USER,this.point1.coords.usrCoords),this.fixedLengthOldCoords[1].setCoordinates(o.COORDS_BY_USER,this.point2.coords.usrCoords)),this):this},updateStdform:function(){var t=e.crossProduct(this.point1.coords.usrCoords,this.point2.coords.usrCoords);this.stdform[0]=t[0],this.stdform[1]=t[1],this.stdform[2]=t[2],this.stdform[3]=0,this.normalize()},updateRenderer:function(){return this.needsUpdate?(this.visPropCalc.visible&&(this.isReal=!isNaN(this.point1.coords.usrCoords[1]+this.point1.coords.usrCoords[2]+this.point2.coords.usrCoords[1]+this.point2.coords.usrCoords[2])&&e.innerProduct(this.stdform,this.stdform,3)>=e.eps*e.eps,this.isReal||this.updateVisibility(!1)),this.visPropCalc.visible&&this.board.renderer.updateLine(this),this.hasLabel&&this.visPropCalc.visible&&this.label&&this.label.visPropCalc.visible&&this.isReal&&(this.label.update(),this.board.renderer.updateText(this.label)),this.setDisplayRendNode(),this.needsUpdate=!1,this):this},generatePolynomial:function(t){var e=this.point1.symbolic.x,i=this.point1.symbolic.y,r=this.point2.symbolic.x,s=this.point2.symbolic.y,o=t.symbolic.x,n=t.symbolic.y;return[["(",i,")*(",o,")-(",i,")*(",r,")+(",n,")*(",r,")-(",e,")*(",n,")+(",e,")*(",s,")-(",o,")*(",s,")"].join("")]},getRise:function(){return Math.abs(this.stdform[2])>=e.eps?-this.stdform[0]/this.stdform[2]:1/0},getSlope:function(){return Math.abs(this.stdform[2])>=e.eps?-this.stdform[1]/this.stdform[2]:1/0},getAngle:function(){return Math.atan2(-this.stdform[1],this.stdform[2])},setStraight:function(t,e){return this.visProp.straightfirst=t,this.visProp.straightlast=e,this.board.renderer.updateLine(this),this},getTextAnchor:function(){return new n(o.COORDS_BY_USER,[.5*(this.point2.X()+this.point1.X()),.5*(this.point2.Y()+this.point1.Y())],this.board)},setLabelRelativeCoords:function(t){h.exists(this.label)&&(this.label.relativeCoords=new n(o.COORDS_BY_SCREEN,[t[0],-t[1]],this.board))},getLabelAnchor:function(){var t,r,s=0,a=new n(o.COORDS_BY_USER,this.point1.coords.usrCoords,this.board),l=new n(o.COORDS_BY_USER,this.point2.coords.usrCoords,this.board),c=h.evaluate(this.visProp.straightfirst),d=h.evaluate(this.visProp.straightlast);if((c||d)&&i.calcStraight(this,a,l,0),a=a.scrCoords,l=l.scrCoords,!h.exists(this.label))return new n(o.COORDS_BY_SCREEN,[NaN,NaN],this.board);switch(h.evaluate(this.label.visProp.position)){case"lft":case"llft":case"ulft":a[1]<=l[1]?(t=a[1],r=a[2]):(t=l[1],r=l[2]);break;case"rt":case"lrt":case"urt":a[1]>l[1]?(t=a[1],r=a[2]):(t=l[1],r=l[2]);break;default:t=.5*(a[1]+l[1]),r=.5*(a[2]+l[2])}return(c||d)&&(h.exists(this.label)&&(s=h.evaluate(this.label.visProp.fontsize)),Math.abs(t)<e.eps?t=s:this.board.canvasWidth+e.eps>t&&t>this.board.canvasWidth-s-e.eps&&(t=this.board.canvasWidth-s),e.eps+s>r&&r>-e.eps?r=s:this.board.canvasHeight+e.eps>r&&r>this.board.canvasHeight-s-e.eps&&(r=this.board.canvasHeight-s)),new n(o.COORDS_BY_SCREEN,[t,r],this.board)},cloneToBackground:function(){var t,e,i,r={};return r.id=this.id+"T"+this.numTraces,r.elementClass=o.OBJECT_CLASS_LINE,this.numTraces++,r.point1=this.point1,r.point2=this.point2,r.stdform=this.stdform,r.board=this.board, -r.visProp=h.deepCopy(this.visProp,this.visProp.traceattributes,!0),r.visProp.layer=this.board.options.layer.trace,h.clearVisPropOld(r),r.visPropCalc={visible:h.evaluate(r.visProp.visible)},e=this.getSlope(),t=this.getRise(),r.getSlope=function(){return e},r.getRise=function(){return t},i=this.board.renderer.enhancedRendering,this.board.renderer.enhancedRendering=!0,this.board.renderer.drawLine(r),this.board.renderer.enhancedRendering=i,this.traces[r.id]=r.rendNode,this},addTransform:function(t){var e,i=h.isArray(t)?t:[t],r=i.length;for(e=0;e<r;e++)this.point1.transformations.push(i[e]),this.point2.transformations.push(i[e]);return this},snapToGrid:function(t){var e,r,a,l,c,d,u,p,f;return h.evaluate(this.visProp.snaptogrid)?this.parents.length<3?(this.point1.handleSnapToGrid(!0,!0),this.point2.handleSnapToGrid(!0,!0)):h.exists(t)&&(p=h.evaluate(this.visProp.snapsizex),f=h.evaluate(this.visProp.snapsizey),e=new n(o.COORDS_BY_SCREEN,[t.Xprev,t.Yprev],this.board),d=e.usrCoords[1],u=e.usrCoords[2],p<=0&&this.board.defaultAxes&&this.board.defaultAxes.x.defaultTicks&&(c=this.board.defaultAxes.x.defaultTicks,p=c.ticksDelta*(h.evaluate(c.visProp.minorticks)+1)),f<=0&&this.board.defaultAxes&&this.board.defaultAxes.y.defaultTicks&&(c=this.board.defaultAxes.y.defaultTicks,f=c.ticksDelta*(h.evaluate(c.visProp.minorticks)+1)),p>0&&f>0&&(r=i.projectPointToLine({coords:e},this,this.board),a=s.subtract([1,Math.round(d/p)*p,Math.round(u/f)*f],r.usrCoords),l=this.board.create("transform",a.slice(1),{type:"translate"}),l.applyOnce([this.point1,this.point2]))):(this.point1.handleSnapToGrid(!1,!0),this.point2.handleSnapToGrid(!1,!0)),this},snapToPoints:function(){var t=h.evaluate(this.visProp.snaptopoints);return this.parents.length<3&&(this.point1.handleSnapToPoints(t),this.point2.handleSnapToPoints(t)),this},X:function(t){var i,r=this.stdform[2];return i=Math.abs(this.point1.coords.usrCoords[0])>e.eps?this.point1.coords.usrCoords[1]:this.point2.coords.usrCoords[1],t=2*(t-.5),(1-Math.abs(t))*i-t*r},Y:function(t){var i,r=this.stdform[1];return i=Math.abs(this.point1.coords.usrCoords[0])>e.eps?this.point1.coords.usrCoords[2]:this.point2.coords.usrCoords[2],t=2*(t-.5),(1-Math.abs(t))*i+t*r},Z:function(t){var i=Math.abs(this.point1.coords.usrCoords[0])>e.eps?this.point1.coords.usrCoords[0]:this.point2.coords.usrCoords[0];return t=2*(t-.5),(1-Math.abs(t))*i},L:function(){return this.point1.Dist(this.point2)},minX:function(){return 0},maxX:function(){return 1},bounds:function(){var t=this.point1.coords.usrCoords,e=this.point2.coords.usrCoords;return[Math.min(t[1],e[1]),Math.max(t[2],e[2]),Math.max(t[1],e[1]),Math.min(t[2],e[2])]},remove:function(){this.removeAllTicks(),a.prototype.remove.call(this)}}),t.createLine=function(e,i,r){var s,o,n,a,c,d,u,p=[],f=!1,m=!1;if(2===i.length){if(h.isArray(i[0])&&i[0].length>1)d=h.copyAttributes(r,e.options,"line","point1"),n=e.create("point",i[0],d);else if(h.isString(i[0])||h.isPoint(i[0]))n=e.select(i[0]);else if(h.isFunction(i[0])&&h.isPoint(i[0]()))n=i[0](),m=!0;else if(h.isFunction(i[0])&&i[0]().length&&i[0]().length>=2)d=h.copyAttributes(r,e.options,"line","point1"),n=l.createPoint(e,i[0](),d),m=!0;else{if(!h.isObject(i[0])||!h.isTransformationOrArray(i[1]))throw new Error("JSXGraph: Can't create line with parent types '"+typeof i[0]+"' and '"+typeof i[1]+"'.\nPossible parent types: [point,point], [[x1,y1],[x2,y2]], [a,b,c]");f=!0,d=h.copyAttributes(r,e.options,"line","point1"),n=e.create("point",[i[0].point1,i[1]],d)}if(f)d=h.copyAttributes(r,e.options,"line","point2"),a=e.create("point",[i[0].point2,i[1]],d);else if(h.isArray(i[1])&&i[1].length>1)d=h.copyAttributes(r,e.options,"line","point2"),a=e.create("point",i[1],d);else if(h.isString(i[1])||h.isPoint(i[1]))a=e.select(i[1]);else if(h.isFunction(i[1])&&h.isPoint(i[1]()))a=i[1](),m=!0;else{if(!(h.isFunction(i[1])&&i[1]().length&&i[1]().length>=2))throw new Error("JSXGraph: Can't create line with parent types '"+typeof i[0]+"' and '"+typeof i[1]+"'.\nPossible parent types: [point,point], [[x1,y1],[x2,y2]], [a,b,c]");d=h.copyAttributes(r,e.options,"line","point2"),a=l.createPoint(e,i[1](),d),m=!0}d=h.copyAttributes(r,e.options,"line"),o=new t.Line(e,n,a,d),m?(o.constrained=!0,o.funp1=i[0],o.funp2=i[1]):f||(o.isDraggable=!0),o.setParents([n.id,a.id])}else if(3===i.length){for(u=!0,c=0;c<3;c++)if(h.isNumber(i[c]))p[c]=h.createFunction(i[c]);else{if(!h.isFunction(i[c]))throw new Error("JSXGraph: Can't create line with parent types '"+typeof i[0]+"' and '"+typeof i[1]+"' and '"+typeof i[2]+"'.\nPossible parent types: [point,point], [[x1,y1],[x2,y2]], [a,b,c]");p[c]=i[c],u=!1}d=h.copyAttributes(r,e.options,"line","point1"),n=u?e.create("point",[p[2]()*p[2]()+p[1]()*p[1](),p[2]()-p[1]()*p[0]()+p[2](),-p[1]()-p[2]()*p[0]()-p[1]()],d):e.create("point",[function(){return.5*(p[2]()*p[2]()+p[1]()*p[1]())},function(){return.5*(p[2]()-p[1]()*p[0]()+p[2]())},function(){return.5*(-p[1]()-p[2]()*p[0]()-p[1]())}],d),d=h.copyAttributes(r,e.options,"line","point2"),a=u?e.create("point",[p[2]()*p[2]()+p[1]()*p[1](),-p[1]()*p[0]()+p[2](),-p[2]()*p[0]()-p[1]()],d):e.create("point",[function(){return p[2]()*p[2]()+p[1]()*p[1]()},function(){return-p[1]()*p[0]()+p[2]()},function(){return-p[2]()*p[0]()-p[1]()}],d),n.prepareUpdate().update(),a.prepareUpdate().update(),d=h.copyAttributes(r,e.options,"line"),o=new t.Line(e,n,a,d),o.isDraggable=u,o.setParents([n,a])}else if(1===i.length&&h.isFunction(i[0])&&2===i[0]().length&&h.isPoint(i[0]()[0])&&h.isPoint(i[0]()[1]))s=i[0](),d=h.copyAttributes(r,e.options,"line"),o=new t.Line(e,s[0],s[1],d),o.constrained=!0,o.funps=i[0],o.setParents(s);else{if(!(1===i.length&&h.isFunction(i[0])&&3===i[0]().length&&h.isNumber(i[0]()[0])&&h.isNumber(i[0]()[1])&&h.isNumber(i[0]()[2])))throw new Error("JSXGraph: Can't create line with parent types '"+typeof i[0]+"' and '"+typeof i[1]+"'.\nPossible parent types: [point,point], [[x1,y1],[x2,y2]], [a,b,c]");s=i[0],d=h.copyAttributes(r,e.options,"line","point1"),n=e.create("point",[function(){var t=s();return[.5*(t[2]*t[2]+t[1]*t[1]),.5*(t[2]-t[1]*t[0]+t[2]),.5*(-t[1]-t[2]*t[0]-t[1])]}],d),d=h.copyAttributes(r,e.options,"line","point2"),a=e.create("point",[function(){var t=s();return[t[2]*t[2]+t[1]*t[1],-t[1]*t[0]+t[2],-t[2]*t[0]-t[1]]}],d),d=h.copyAttributes(r,e.options,"line"),o=new t.Line(e,n,a,d),o.constrained=!0,o.funps=i[0],o.setParents([n,a])}return o},t.registerElement("line",t.createLine),t.createSegment=function(t,e,i){var r,s;if(i.straightFirst=!1,i.straightLast=!1,s=h.copyAttributes(i,t.options,"segment"),r=t.create("line",e.slice(0,2),s),3===e.length){if(r.hasFixedLength=!0,h.isNumber(e[2]))r.fixedLength=function(){return e[2]};else{if(!h.isFunction(e[2]))throw new Error("JSXGraph: Can't create segment with third parent type '"+typeof e[2]+"'.\nPossible third parent types: number or function");r.fixedLength=e[2]}r.getParents=function(){return this.parents.concat(this.fixedLength())},r.fixedLengthOldCoords=[],r.fixedLengthOldCoords[0]=new n(o.COORDS_BY_USER,r.point1.coords.usrCoords.slice(1,3),t),r.fixedLengthOldCoords[1]=new n(o.COORDS_BY_USER,r.point2.coords.usrCoords.slice(1,3),t)}return r.elType="segment",r},t.registerElement("segment",t.createSegment),t.createArrow=function(t,e,i){var r,s;return i.straightFirst=!1,i.straightLast=!1,s=h.copyAttributes(i,t.options,"arrow"),r=t.create("line",e,s),r.type=o.OBJECT_TYPE_VECTOR,r.elType="arrow",r},t.registerElement("arrow",t.createArrow),t.createAxis=function(t,e,i){var r,s,n,a,l;if(!h.isArray(e[0])&&!h.isPoint(e[0])||!h.isArray(e[1])&&!h.isPoint(e[1]))throw new Error("JSXGraph: Can't create axis with parent types '"+typeof e[0]+"' and '"+typeof e[1]+"'.\nPossible parent types: [point,point], [[x1,y1],[x2,y2]]");r=h.copyAttributes(i,t.options,"axis"),n=t.create("line",e,r),n.type=o.OBJECT_TYPE_AXIS,n.isDraggable=!1,n.point1.isDraggable=!1,n.point2.isDraggable=!1;for(a in n.ancestors)n.ancestors.hasOwnProperty(a)&&(n.ancestors[a].type=o.OBJECT_TYPE_AXISPOINT);return s=h.copyAttributes(i,t.options,"axis","ticks"),l=h.exists(s.ticksdistance)?s.ticksdistance:h.isArray(s.ticks)?s.ticks:1,n.defaultTicks=t.create("ticks",[n,l],s),n.defaultTicks.dump=!1,n.elType="axis",n.subs={ticks:n.defaultTicks},n.inherits.push(n.defaultTicks),n},t.registerElement("axis",t.createAxis),t.createTangent=function(t,i,s){var n,a,l,c,d;if(1===i.length)n=i[0],a=n.slideObject;else{if(2!==i.length)throw new Error("JSXGraph: Can't create tangent with parent types '"+typeof i[0]+"' and '"+typeof i[1]+"'.\nPossible parent types: [glider], [point,line|curve|circle|conic]");if(h.isPoint(i[0]))n=i[0],a=i[1];else{if(!h.isPoint(i[1]))throw new Error("JSXGraph: Can't create tangent with parent types '"+typeof i[0]+"' and '"+typeof i[1]+"'.\nPossible parent types: [glider], [point,line|curve|circle|conic]");a=i[0],n=i[1]}}if(a.elementClass===o.OBJECT_CLASS_LINE?(d=t.create("line",[a.point1,a.point2],s),d.glider=n):a.elementClass===o.OBJECT_CLASS_CURVE&&a.type!==o.OBJECT_TYPE_CONIC?"plot"!==h.evaluate(a.visProp.curvetype)?(d=t.create("line",[function(){var t=a.X,e=a.Y;return-n.X()*r.D(e)(n.position)+n.Y()*r.D(t)(n.position)},function(){return r.D(a.Y)(n.position)},function(){return-r.D(a.X)(n.position)}],s),n.addChild(d),d.glider=n):(d=t.create("line",[function(){var t,e,i=Math.floor(n.position);return i===a.numberPoints-1&&i--,i<0?1:(t=a.points[i].usrCoords,e=a.points[i+1].usrCoords,t[2]*e[1]-t[1]*e[2])},function(){var t,e,i=Math.floor(n.position);return i===a.numberPoints-1&&i--,i<0?0:(t=a.points[i].usrCoords,e=a.points[i+1].usrCoords,e[2]-t[2])},function(){var t,e,i=Math.floor(n.position);return i===a.numberPoints-1&&i--,i<0?0:(t=a.points[i].usrCoords,e=a.points[i+1].usrCoords,t[1]-e[1])}],s),n.addChild(d),d.glider=n):a.type===o.OBJECT_TYPE_TURTLE?(d=t.create("line",[function(){var t=Math.floor(n.position);for(l=0;l<a.objects.length;l++)if(c=a.objects[l],c.type===o.OBJECT_TYPE_CURVE){if(t<c.numberPoints)break;t-=c.numberPoints}return t===c.numberPoints-1&&t--,t<0?1:c.Y(t)*c.X(t+1)-c.X(t)*c.Y(t+1)},function(){var t=Math.floor(n.position);for(l=0;l<a.objects.length;l++)if(c=a.objects[l],c.type===o.OBJECT_TYPE_CURVE){if(t<c.numberPoints)break;t-=c.numberPoints}return t===c.numberPoints-1&&t--,t<0?0:c.Y(t+1)-c.Y(t)},function(){var t=Math.floor(n.position);for(l=0;l<a.objects.length;l++)if(c=a.objects[l],c.type===o.OBJECT_TYPE_CURVE){if(t<c.numberPoints)break;t-=c.numberPoints}return t===c.numberPoints-1&&t--,t<0?0:c.X(t)-c.X(t+1)}],s),n.addChild(d),d.glider=n):a.elementClass!==o.OBJECT_CLASS_CIRCLE&&a.type!==o.OBJECT_TYPE_CONIC||(d=t.create("line",[function(){return e.matVecMult(a.quadraticform,n.coords.usrCoords)[0]},function(){return e.matVecMult(a.quadraticform,n.coords.usrCoords)[1]},function(){return e.matVecMult(a.quadraticform,n.coords.usrCoords)[2]}],s),n.addChild(d),d.glider=n),!h.exists(d))throw new Error("JSXGraph: Couldn't create tangent with the given parents.");return d.elType="tangent",d.type=o.OBJECT_TYPE_TANGENT,d.setParents(i),d},t.createRadicalAxis=function(t,i,r){var s,n,a;if(2!==i.length||i[0].elementClass!==o.OBJECT_CLASS_CIRCLE||i[1].elementClass!==o.OBJECT_CLASS_CIRCLE)throw new Error("JSXGraph: Can't create 'radical axis' with parent types '"+typeof i[0]+"' and '"+typeof i[1]+"'.\nPossible parent type: [circle,circle]");return n=t.select(i[0]),a=t.select(i[1]),s=t.create("line",[function(){var t=n.stdform,i=a.stdform;return e.matVecMult(e.transpose([t.slice(0,3),i.slice(0,3)]),[i[3],-t[3]])}],r),s.elType="radicalaxis",s.setParents([n.id,a.id]),n.addChild(s),a.addChild(s),s},t.createPolarLine=function(t,e,i){var r,s,n,a,l,c,d;if(e.length>1&&(a=e[0].type===o.OBJECT_TYPE_CONIC||e[0].elementClass===o.OBJECT_CLASS_CIRCLE,l=e[1].type===o.OBJECT_TYPE_CONIC||e[1].elementClass===o.OBJECT_CLASS_CIRCLE,c=h.isPoint(e[0]),d=h.isPoint(e[1])),2!==e.length||!(a&&d||c&&l))throw new Error("JSXGraph: Can't create 'polar line' with parent types '"+typeof e[0]+"' and '"+typeof e[1]+"'.\nPossible parent type: [conic|circle,point], [point,conic|circle]");return d?(s=t.select(e[0]),n=t.select(e[1])):(s=t.select(e[1]),n=t.select(e[0])),r=t.create("tangent",[s,n],i),r.elType="polarline",r},t.registerElement("tangent",t.createTangent),t.registerElement("polar",t.createTangent),t.registerElement("radicalaxis",t.createRadicalAxis),t.registerElement("polarline",t.createPolarLine),{Line:t.Line,createLine:t.createLine,createTangent:t.createTangent,createPolar:t.createTangent,createSegment:t.createSegment,createAxis:t.createAxis,createArrow:t.createArrow,createRadicalAxis:t.createRadicalAxis,createPolarLine:t.createPolarLine}}),define("base/curve",["jxg","base/constants","base/coords","base/element","math/math","math/numerics","math/plot","math/geometry","parser/geonext","utils/type","math/qdt"],function(t,e,i,r,s,o,n,a,h,l,c){"use strict";return t.Curve=function(t,i,r){this.constructor(t,r,e.OBJECT_TYPE_CURVE,e.OBJECT_CLASS_CURVE),this.points=[],this.numberPoints=l.evaluate(this.visProp.numberpointshigh),this.bezierDegree=1,this.dataX=null,this.dataY=null,this.ticks=[],this.qdt=null,l.exists(i[0])?this.varname=i[0]:this.varname="x",this.xterm=i[1],this.yterm=i[2],this.generateTerm(this.varname,this.xterm,this.yterm,i[3],i[4]),this.updateCurve(),this.id=this.board.setId(this,"G"),this.board.renderer.drawCurve(this),this.board.finalizeAdding(this),this.createGradient(),this.elType="curve",this.createLabel(),l.isString(this.xterm)&&this.notifyParents(this.xterm),l.isString(this.yterm)&&this.notifyParents(this.yterm),this.methodMap=l.deepCopy(this.methodMap,{generateTerm:"generateTerm",setTerm:"generateTerm",move:"moveTo",moveTo:"moveTo"})},t.Curve.prototype=new r,t.extend(t.Curve.prototype,{minX:function(){var t;return"polar"===l.evaluate(this.visProp.curvetype)?0:(t=new i(e.COORDS_BY_SCREEN,[.1*-this.board.canvasWidth,0],this.board,!1),t.usrCoords[1])},maxX:function(){var t;return"polar"===l.evaluate(this.visProp.curvetype)?2*Math.PI:(t=new i(e.COORDS_BY_SCREEN,[1.1*this.board.canvasWidth,0],this.board,!1),t.usrCoords[1])},X:function(t){return NaN},Y:function(t){return NaN},Z:function(t){return 1},hasPoint:function(t,r,o){var n,h,c,d,u,p,f,m,g,b,v,y,C,_,P,E,x,S=[],w=l.evaluate(this.visProp.numberpointslow),O=(this.maxX()-this.minX())/w,T=1/0;if(l.isObject(l.evaluate(this.visProp.precision))?(y=this.board._inputDevice,v=l.evaluate(this.visProp.precision[y])):v=this.board.options.precision.hasPoint,h=new i(e.COORDS_BY_SCREEN,[t,r],this.board,!1),t=h.usrCoords[1],r=h.usrCoords[2],v+=.5*l.evaluate(this.visProp.strokewidth),v*=v,C=this.board.unitX*this.board.unitX,_=this.board.unitY*this.board.unitY,E=this.minX(),x=this.maxX(),l.exists(this._visibleArea)&&(E=this._visibleArea[0],x=this._visibleArea[1],O=(x-E)/w),"parameter"===(P=l.evaluate(this.visProp.curvetype))||"polar"===P)for(this.transformations.length>0&&(this.updateTransformMatrix(),d=s.inverse(this.transformMat),u=s.matVecMult(d,[1,t,r]),t=u[1],r=u[2]),p=0,n=E;p<w;p++){if(f=this.X(n,!0),m=this.Y(n,!0),(T=(t-f)*(t-f)*C+(r-m)*(r-m)*_)<=v)return!0;n+=O}else if("plot"===P||"functiongraph"===P){for((!l.exists(o)||o<0)&&(o=0),l.exists(this.qdt)&&l.evaluate(this.visProp.useqdt)&&3!==this.bezierDegree?(b=this.qdt.query(new i(e.COORDS_BY_USER,[t,r],this.board)),g=b.points,c=g.length):(g=this.points,c=this.numberPoints-1),p=o;p<c;p++)if(3===this.bezierDegree?S.push(a.projectCoordsToBeziersegment([1,t,r],this,p)):b?(g[p].prev&&(S=a.projectCoordsToSegment([1,t,r],g[p].prev.usrCoords,g[p].usrCoords)),g[p].next&&g[p+1]!==g[p].next&&(S=a.projectCoordsToSegment([1,t,r],g[p].usrCoords,g[p].next.usrCoords))):S=a.projectCoordsToSegment([1,t,r],g[p].usrCoords,g[p+1].usrCoords),S[1]>=0&&S[1]<=1&&(t-S[0][1])*(t-S[0][1])*C+(r-S[0][2])*(r-S[0][2])*_<=v)return!0;return!1}return T<v},allocatePoints:function(){var t,r;if(r=this.numberPoints,this.points.length<this.numberPoints)for(t=this.points.length;t<r;t++)this.points[t]=new i(e.COORDS_BY_USER,[0,0],this.board,!1)},update:function(){return this.needsUpdate&&(l.evaluate(this.visProp.trace)&&this.cloneToBackground(!0),this.updateCurve()),this},updateRenderer:function(){return this.needsUpdate?(this.visPropCalc.visible&&(this.isReal=n.checkReal(this.points),this.isReal||this.updateVisibility(!1)),this.visPropCalc.visible&&this.board.renderer.updateCurve(this),this.hasLabel&&this.visPropCalc.visible&&this.label&&this.label.visPropCalc.visible&&this.isReal&&(this.label.update(),this.board.renderer.updateText(this.label)),this.setDisplayRendNode(),this.needsUpdate=!1,this):this},updateDataArray:function(){},updateCurve:function(){var t,i,r,s,a,h,d=this.visProp.plotversion,u=!1;if(this.updateTransformMatrix(),this.updateDataArray(),i=this.minX(),r=this.maxX(),l.exists(this.dataX))for(this.numberPoints=this.dataX.length,t=this.numberPoints,this.allocatePoints(),h=0;h<t;h++)s=h,l.exists(this.dataY)?(a=h,this.points[h].setCoordinates(e.COORDS_BY_USER,[this.dataX[h],this.dataY[h]],!1)):(a=this.X(s),this.points[h].setCoordinates(e.COORDS_BY_USER,[this.dataX[h],this.Y(a,u)],!1)),this.points[h]._t=h,u=!0;else if(l.evaluate(this.visProp.doadvancedplot)?1===d||l.evaluate(this.visProp.doadvancedplotold)?n.updateParametricCurveOld(this,i,r):2===d?n.updateParametricCurve_v2(this,i,r):4===d?n.updateParametricCurve_v4(this,i,r):n.updateParametricCurve(this,i,r):(this.board.updateQuality===this.board.BOARD_QUALITY_HIGH?this.numberPoints=l.evaluate(this.visProp.numberpointshigh):this.numberPoints=l.evaluate(this.visProp.numberpointslow),this.allocatePoints(),n.updateParametricCurveNaive(this,i,r,this.numberPoints)),t=this.numberPoints,l.evaluate(this.visProp.useqdt)&&this.board.updateQuality===this.board.BOARD_QUALITY_HIGH)for(this.qdt=new c(this.board.getBoundingBox()),h=0;h<this.points.length;h++)this.qdt.insert(this.points[h]),h>0&&(this.points[h].prev=this.points[h-1]),h<t-1&&(this.points[h].next=this.points[h+1]);for("plot"!==l.evaluate(this.visProp.curvetype)&&l.evaluate(this.visProp.rdpsmoothing)&&(this.points=o.RamerDouglasPeucker(this.points,.2),this.numberPoints=this.points.length),t=this.numberPoints,h=0;h<t;h++)this.updateTransform(this.points[h]);return this},updateTransformMatrix:function(){var t,e,i=this.transformations.length;for(this.transformMat=[[1,0,0],[0,1,0],[0,0,1]],e=0;e<i;e++)t=this.transformations[e],t.update(),this.transformMat=s.matMatMult(t.matrix,this.transformMat);return this},updateTransform:function(t){var i;return this.transformations.length>0&&(i=s.matVecMult(this.transformMat,t.usrCoords),t.setCoordinates(e.COORDS_BY_USER,i,!1,!0)),t},addTransform:function(t){var e,i=l.isArray(t)?t:[t],r=i.length;for(e=0;e<r;e++)this.transformations.push(i[e]);return this},interpolationFunctionFromArray:function(t){var e="data"+t,i=this;return function(t,r){var s,o,n,a,h,c=i[e],d=c.length,u=[];if(isNaN(t))return NaN;if(t<0)return l.isFunction(c[0])?c[0]():c[0];if(3===i.bezierDegree){if(h=(d-1)/3,t>=h)return l.isFunction(c[c.length-1])?c[c.length-1]():c[c.length-1];for(s=3*Math.floor(t),n=t%1,a=1-n,o=0;o<4;o++)l.isFunction(c[s+o])?u[o]=c[s+o]():u[o]=c[s+o];return a*a*(a*u[0]+3*n*u[1])+(3*a*u[2]+n*u[3])*n*n}if((s=t>d-2?d-2:parseInt(Math.floor(t),10))===t)return l.isFunction(c[s])?c[s]():c[s];for(o=0;o<2;o++)l.isFunction(c[s+o])?u[o]=c[s+o]():u[o]=c[s+o];return u[0]+(u[1]-u[0])*(t-s)}},generateTerm:function(t,e,i,r,s){var o,n;l.isArray(e)?(this.dataX=e,this.numberPoints=this.dataX.length,this.X=this.interpolationFunctionFromArray.apply(this,["X"]),this.visProp.curvetype="plot",this.isDraggable=!0):(this.X=l.createFunction(e,this.board,t),l.isString(e)?this.visProp.curvetype="functiongraph":(l.isFunction(e)||l.isNumber(e))&&(this.visProp.curvetype="parameter"),this.isDraggable=!0),l.isArray(i)?(this.dataY=i,this.Y=this.interpolationFunctionFromArray.apply(this,["Y"])):this.Y=l.createFunction(i,this.board,t),l.isFunction(e)&&l.isArray(i)&&(o=l.createFunction(i[0],this.board,""),n=l.createFunction(i[1],this.board,""),this.X=function(t){return e(t)*Math.cos(t)+o()},this.Y=function(t){return e(t)*Math.sin(t)+n()},this.visProp.curvetype="polar"),l.exists(r)&&(this.minX=l.createFunction(r,this.board,"")),l.exists(s)&&(this.maxX=l.createFunction(s,this.board,""))},notifyParents:function(t){var e,i,r,s=!1;r={xterm:1,yterm:1};for(e in r)if(r.hasOwnProperty(e)&&this.hasOwnProperty(e)&&this[e].origin){s=!0;for(i in this[e].origin.deps)this[e].origin.deps.hasOwnProperty(i)&&this[e].origin.deps[i].addChild(this)}s||h.findDependencies(this,t,this.board)},getLabelAnchor:function(){var t,r,s,o=.05*this.board.canvasWidth,n=.05*this.board.canvasHeight,h=.95*this.board.canvasWidth,c=.95*this.board.canvasHeight;switch(l.evaluate(this.visProp.label.position)){case"ulft":r=o,s=n;break;case"llft":r=o,s=c;break;case"rt":r=h,s=.5*c;break;case"lrt":r=h,s=c;break;case"urt":r=h,s=n;break;case"top":r=.5*h,s=n;break;case"bot":r=.5*h,s=c;break;default:r=o,s=.5*c}return t=new i(e.COORDS_BY_SCREEN,[r,s],this.board,!1),a.projectCoordsToCurve(t.usrCoords[1],t.usrCoords[2],0,this,this.board)[0]},cloneToBackground:function(){var t,i={id:this.id+"T"+this.numTraces,elementClass:e.OBJECT_CLASS_CURVE,points:this.points.slice(0),bezierDegree:this.bezierDegree,numberPoints:this.numberPoints,board:this.board,visProp:l.deepCopy(this.visProp,this.visProp.traceattributes,!0)};return i.visProp.layer=this.board.options.layer.trace,i.visProp.curvetype=this.visProp.curvetype,this.numTraces++,l.clearVisPropOld(i),i.visPropCalc={visible:l.evaluate(i.visProp.visible)},t=this.board.renderer.enhancedRendering,this.board.renderer.enhancedRendering=!0,this.board.renderer.drawCurve(i),this.board.renderer.enhancedRendering=t,this.traces[i.id]=i.rendNode,this},bounds:function(){var t,e,i,r=1/0,s=-1/0,n=1/0,a=-1/0,h=this.points.length;if(3===this.bezierDegree){for(t=0;t<h;t++)this.points[t].X=l.bind(function(){return this.usrCoords[1]},this.points[t]),this.points[t].Y=l.bind(function(){return this.usrCoords[2]},this.points[t]);return e=o.bezier(this.points),i=e[3](),r=o.fminbr(function(t){return e[0](t)},[0,i]),s=o.fminbr(function(t){return-e[0](t)},[0,i]),n=o.fminbr(function(t){return e[1](t)},[0,i]),a=o.fminbr(function(t){return-e[1](t)},[0,i]),r=e[0](r),s=e[0](s),n=e[1](n),a=e[1](a),[r,a,s,n]}for(t=0;t<h;t++)r>this.points[t].usrCoords[1]&&(r=this.points[t].usrCoords[1]),s<this.points[t].usrCoords[1]&&(s=this.points[t].usrCoords[1]),n>this.points[t].usrCoords[2]&&(n=this.points[t].usrCoords[2]),a<this.points[t].usrCoords[2]&&(a=this.points[t].usrCoords[2]);return[r,a,s,n]},getParents:function(){var t=[this.xterm,this.yterm,this.minX(),this.maxX()];return 0!==this.parents.length&&(t=this.parents),t},moveTo:function(t){var i,r=[];return this.points.length>0&&!l.evaluate(this.visProp.fixed)&&(i=this.points[0],r=3===t.length?[t[0]-i.usrCoords[0],t[1]-i.usrCoords[1],t[2]-i.usrCoords[2]]:[t[0]-i.usrCoords[1],t[1]-i.usrCoords[2]],this.setPosition(e.COORDS_BY_USER,r)),this},getTransformationSource:function(){var t,i;return l.exists(this._transformationSource)&&(i=this._transformationSource,i.elementClass===e.OBJECT_CLASS_CURVE&&(t=!0)),[t,i]}}),t.createCurve=function(i,r,s){var o,n,a=l.copyAttributes(s,i.options,"curve");return o=i.select(r[0],!0),l.isObject(o)&&(o.type===e.OBJECT_TYPE_CURVE||o.type===e.OBJECT_TYPE_ANGLE||o.type===e.OBJECT_TYPE_ARC||o.type===e.OBJECT_TYPE_CONIC||o.type===e.OBJECT_TYPE_SECTOR)&&l.isTransformationOrArray(r[1])?(o.type===e.OBJECT_TYPE_SECTOR?a=l.copyAttributes(s,i.options,"sector"):o.type===e.OBJECT_TYPE_ARC?a=l.copyAttributes(s,i.options,"arc"):o.type===e.OBJECT_TYPE_ANGLE?(l.exists(s.withLabel)||(s.withLabel=!1),a=l.copyAttributes(s,i.options,"angle")):a=l.copyAttributes(s,i.options,"curve"),a=l.copyAttributes(a,i.options,"curve"),n=new t.Curve(i,["x",[],[]],a),n.updateDataArray=function(){var t,e=o.numberPoints;for(this.bezierDegree=o.bezierDegree,this.dataX=[],this.dataY=[],t=0;t<e;t++)this.dataX.push(o.points[t].usrCoords[1]),this.dataY.push(o.points[t].usrCoords[2]);return this},n.addTransform(r[1]),o.addChild(n),n.setParents([o]),n._transformationSource=o,n):(a=l.copyAttributes(s,i.options,"curve"),new t.Curve(i,["x"].concat(r),a))},t.registerElement("curve",t.createCurve),t.createFunctiongraph=function(e,i,r){var s,o=["x","x"].concat(i);return s=l.copyAttributes(r,e.options,"curve"),s.curvetype="functiongraph",new t.Curve(e,o,s)},t.registerElement("functiongraph",t.createFunctiongraph),t.registerElement("plot",t.createFunctiongraph),t.createSpline=function(e,i,r){var s,n,a;return n=function(){var t,e=[],r=[];return[function(s,n){var a,h,c;if(!n){if(e=[],r=[],2===i.length&&l.isArray(i[0])&&l.isArray(i[1])&&i[0].length===i[1].length)for(a=0;a<i[0].length;a++)l.isFunction(i[0][a])?e.push(i[0][a]()):e.push(i[0][a]),l.isFunction(i[1][a])?r.push(i[1][a]()):r.push(i[1][a]);else for(a=0;a<i.length;a++)if(l.isPoint(i[a]))e.push(i[a].X()),r.push(i[a].Y());else if(l.isArray(i[a])&&2===i[a].length)for(h=0;h<i.length;h++)l.isFunction(i[h][0])?e.push(i[h][0]()):e.push(i[h][0]),l.isFunction(i[h][1])?r.push(i[h][1]()):r.push(i[h][1]);else l.isFunction(i[a])&&2===i[a]().length&&(c=i[a](),e.push(c[0]),r.push(c[1]));t=o.splineDef(e,r)}return o.splineEval(s,e,r,t)},function(){return e[0]},function(){return e[e.length-1]}]},r=l.copyAttributes(r,e.options,"curve"),r.curvetype="functiongraph",a=n(),s=new t.Curve(e,["x","x",a[0],a[1],a[2]],r),s.setParents(i),s.elType="spline",s},t.registerElement("spline",t.createSpline),t.createCardinalSpline=function(e,i,r){var s,n,a,h,c,d,u,p,f,m="\nPossible parent types: [points:array, tau:number|function, type:string]";if(!l.exists(i[0])||!l.isArray(i[0]))throw new Error("JSXGraph: JXG.createCardinalSpline: argument 1 'points' has to be array of points or coordinate pairs"+m);if(!l.exists(i[1])||!l.isNumber(i[1])&&!l.isFunction(i[1]))throw new Error("JSXGraph: JXG.createCardinalSpline: argument 2 'tau' has to be number between [0,1] or function'"+m);if(!l.exists(i[2])||!l.isString(i[2]))throw new Error("JSXGraph: JXG.createCardinalSpline: argument 3 'type' has to be string 'uniform' or 'centripetal'"+m);if(r=l.copyAttributes(r,e.options,"curve"),r=l.copyAttributes(r,e.options,"cardinalspline"),r.curvetype="parameter",c=i[0],d=[],!r.isarrayofcoordinates&&2===c.length&&l.isArray(c[0])&&l.isArray(c[1])&&c[0].length===c[1].length)for(u=0;u<c[0].length;u++)d[u]=[],l.isFunction(c[0][u])?d[u].push(c[0][u]()):d[u].push(c[0][u]),l.isFunction(c[1][u])?d[u].push(c[1][u]()):d[u].push(c[1][u]);else for(u=0;u<c.length;u++)l.isString(c[u])?d.push(e.select(c[u])):l.isPoint(c[u])?d.push(c[u]):l.isArray(c[u])&&2===c[u].length?(d[u]=[],l.isFunction(c[u][0])?d[u].push(c[u][0]()):d[u].push(c[u][0]),l.isFunction(c[u][1])?d[u].push(c[u][1]()):d[u].push(c[u][1])):l.isFunction(c[u])&&2===c[u]().length&&d.push(i[u]());if(!0===r.createpoints)n=l.providePoints(e,d,r,"cardinalspline",["points"]);else for(n=[],u=0;u<d.length;u++)l.isPoint(d[u])?n.push(d[u]):n.push(function(t){return{X:function(){return d[t][0]},Y:function(){return d[t][1]},Dist:function(t){var e=this.X()-t.X(),i=this.Y()-t.Y();return Math.sqrt(e*e+i*i)}}}(u));for(a=i[1],h=i[2],f=["x"].concat(o.CardinalSpline(n,a,h)),s=new t.Curve(e,f,r),p=n.length,s.setParents(n),u=0;u<p;u++)l.isPoint(n[u])&&n[u].addChild(s);return s.elType="cardinalspline",s},t.registerElement("cardinalspline",t.createCardinalSpline),t.createMetapostSpline=function(e,i,r){var s,o,n,a,h,c,d,u="\nPossible parent types: [points:array, controls:object";if(!l.exists(i[0])||!l.isArray(i[0]))throw new Error("JSXGraph: JXG.createMetapostSpline: argument 1 'points' has to be array of points or coordinate pairs"+u);if(!l.exists(i[1])||!l.isObject(i[1]))throw new Error("JSXGraph: JXG.createMetapostSpline: argument 2 'controls' has to be a JavaScript object'"+u);if(r=l.copyAttributes(r,e.options,"curve"),r=l.copyAttributes(r,e.options,"metapostspline"),r.curvetype="parameter",a=i[0],h=[],!r.isarrayofcoordinates&&2===a.length&&l.isArray(a[0])&&l.isArray(a[1])&&a[0].length===a[1].length)for(c=0;c<a[0].length;c++)h[c]=[],l.isFunction(a[0][c])?h[c].push(a[0][c]()):h[c].push(a[0][c]),l.isFunction(a[1][c])?h[c].push(a[1][c]()):h[c].push(a[1][c]);else for(c=0;c<a.length;c++)l.isString(a[c])?h.push(e.select(a[c])):l.isPoint(a[c])?h.push(a[c]):l.isArray(a[c])&&2===a[c].length?(h[c]=[],l.isFunction(a[c][0])?h[c].push(a[c][0]()):h[c].push(a[c][0]),l.isFunction(a[c][1])?h[c].push(a[c][1]()):h[c].push(a[c][1])):l.isFunction(a[c])&&2===a[c]().length&&h.push(i[c]());if(!0===r.createpoints)o=l.providePoints(e,h,r,"metapostspline",["points"]);else for(o=[],c=0;c<h.length;c++)l.isPoint(h[c])?o.push(h[c]):o.push(function(t){return{X:function(){return h[t][0]},Y:function(){return h[t][1]}}}(c));for(n=i[1],s=new t.Curve(e,["t",[],[],0,a.length-1],r),s.updateDataArray=function(){var e,i,r=o.length,s=[];for(i=0;i<r;i++)s.push([o[i].X(),o[i].Y()]);e=t.Math.Metapost.curve(s,n),this.dataX=e[0],this.dataY=e[1]},s.bezierDegree=3,d=o.length,s.setParents(o),c=0;c<d;c++)l.isPoint(o[c])&&o[c].addChild(s);return s.elType="metapostspline",s},t.registerElement("metapostspline",t.createMetapostSpline),t.createRiemannsum=function(t,e,i){var r,s,n,a,h,c;if(c=l.copyAttributes(i,t.options,"riemannsum"),c.curvetype="plot",n=e[0],r=l.createFunction(e[1],t,""),!l.exists(r))throw new Error("JSXGraph: JXG.createRiemannsum: argument '2' n has to be number or function.\nPossible parent types: [function,n:number|function,type,start:number|function,end:number|function]");if(s=l.createFunction(e[2],t,"",!1),!l.exists(s))throw new Error("JSXGraph: JXG.createRiemannsum: argument 3 'type' has to be string or function.\nPossible parent types: [function,n:number|function,type,start:number|function,end:number|function]");return a=[[0],[0]].concat(e.slice(3)),h=t.create("curve",a,c),h.sum=0,h.Value=function(){return this.sum},h.updateDataArray=function(){var t=o.riemann(n,r(),s(),this.minX(),this.maxX());this.dataX=t[0],this.dataY=t[1],this.sum=t[2]},h},t.registerElement("riemannsum",t.createRiemannsum),t.createTracecurve=function(t,i,r){var s,o,n,a;if(2!==i.length)throw new Error("JSXGraph: Can't create trace curve with given parent'\nPossible parent types: [glider, point]");if(o=t.select(i[0]),n=t.select(i[1]),o.type!==e.OBJECT_TYPE_GLIDER||!l.isPoint(n))throw new Error("JSXGraph: Can't create trace curve with parent types '"+typeof i[0]+"' and '"+typeof i[1]+"'.\nPossible parent types: [glider, point]");return a=l.copyAttributes(r,t.options,"tracecurve"),a.curvetype="plot",s=t.create("curve",[[0],[0]],a),s.updateDataArray=function(){var t,i,r,s,h,l,c,d,u,p=a.numberpoints,f=o.position,m=o.slideObject,g=m.minX(),b=m.maxX();for(i=(b-g)/p,this.dataX=[],this.dataY=[],m.elementClass!==e.OBJECT_CLASS_CURVE&&p++,t=0;t<p;t++){r=g+t*i,l=m.X(r)/m.Z(r),c=m.Y(r)/m.Z(r),o.setPositionDirectly(e.COORDS_BY_USER,[l,c]),d=!1;for(s in this.board.objects)if(this.board.objects.hasOwnProperty(s)&&(h=this.board.objects[s],h===o&&(d=!0),d&&h.needsRegularUpdate&&(u=h.visProp.trace,h.visProp.trace=!1,h.needsUpdate=!0,h.update(!0),h.visProp.trace=u,h===n)))break;this.dataX[t]=n.X(),this.dataY[t]=n.Y()}o.position=f,d=!1;for(s in this.board.objects)if(this.board.objects.hasOwnProperty(s)&&(h=this.board.objects[s],h===o&&(d=!0),d&&h.needsRegularUpdate&&(u=h.visProp.trace,h.visProp.trace=!1,h.needsUpdate=!0,h.update(!0),h.visProp.trace=u,h===n)))break},s},t.registerElement("tracecurve",t.createTracecurve),t.createStepfunction=function(t,e,i){var r,s;if(2!==e.length)throw new Error("JSXGraph: Can't create step function with given parent'\nPossible parent types: [array, array|function]");return s=l.copyAttributes(i,t.options,"stepfunction"),r=t.create("curve",e,s),r.updateDataArray=function(){var t,e=0,i=this.xterm.length;if(this.dataX=[],this.dataY=[],0!==i)for(this.dataX[e]=this.xterm[0],this.dataY[e]=this.yterm[0],++e,t=1;t<i;++t)this.dataX[e]=this.xterm[t],this.dataY[e]=this.dataY[e-1],++e,this.dataX[e]=this.xterm[t],this.dataY[e]=this.yterm[t],++e},r},t.registerElement("stepfunction",t.createStepfunction),t.createDerivative=function(t,i,r){var s,n,a,h,c -;if(1!==i.length&&i[0].class!==e.OBJECT_CLASS_CURVE)throw new Error("JSXGraph: Can't create derivative curve with given parent'\nPossible parent types: [curve]");return c=l.copyAttributes(r,t.options,"curve"),n=i[0],a=o.D(n.X),h=o.D(n.Y),s=t.create("curve",[function(t){return n.X(t)},function(t){return h(t)/a(t)},n.minX(),n.maxX()],c),s.setParents(n),s},t.registerElement("derivative",t.createDerivative),{Curve:t.Curve,createCurve:t.createCurve,createFunctiongraph:t.createFunctiongraph,createPlot:t.createPlot,createSpline:t.createSpline,createRiemannsum:t.createRiemannsum,createTracecurve:t.createTracecurve,createStepfunction:t.createStepfunction}}),define("element/conic",["jxg","base/constants","base/coords","math/math","math/numerics","math/geometry","utils/type","base/point","base/curve"],function(t,e,i,r,s,o,n,a,h){"use strict";return t.createEllipse=function(t,r,s){var o,a,h,l,c,d,u,p=[],f=n.copyAttributes(s,t.options,"conic","foci"),m=n.copyAttributes(s,t.options,"conic","center"),g=n.copyAttributes(s,t.options,"conic");for(d=0;d<2;d++)if(r[d].length>1)p[d]=t.create("point",r[d],f);else if(n.isPoint(r[d]))p[d]=t.select(r[d]);else if(n.isFunction(r[d])&&n.isPoint(r[d]()))p[d]=r[d]();else{if(!n.isString(r[d]))throw new Error("JSXGraph: Can't create Ellipse with parent types '"+typeof r[0]+"' and '"+typeof r[1]+"'.\nPossible parent types: [point,point,point], [point,point,number|function]");p[d]=t.select(r[d])}if(n.isNumber(r[2]))c=n.createFunction(r[2],t);else if(n.isFunction(r[2])&&n.isNumber(r[2]()))c=r[2];else{if(n.isPoint(r[2]))l=t.select(r[2]);else if(r[2].length>1)l=t.create("point",r[2],f);else if(n.isFunction(r[2])&&n.isPoint(r[2]()))l=r[2]();else{if(!n.isString(r[2]))throw new Error("JSXGraph: Can't create Ellipse with parent types '"+typeof r[0]+"' and '"+typeof r[1]+"' and '"+typeof r[2]+"'.\nPossible parent types: [point,point,point], [point,point,number|function]");l=t.select(r[2])}c=function(){return l.Dist(p[0])+l.Dist(p[1])}}for(n.exists(r[4])||(r[4]=2*Math.PI),n.exists(r[3])||(r[3]=0),h=t.create("point",[function(){return.5*(p[0].X()+p[1].X())},function(){return.5*(p[0].Y()+p[1].Y())}],m),a=t.create("curve",[function(t){return 0},function(t){return 0},r[3],r[4]],g),a.majorAxis=c,u=a.hasPoint,o=function(t,e){var i,r,s,o,n,h,l,d,u;e||(i=c(),r=i*i,s=p[0].X(),o=p[0].Y(),n=p[1].X(),h=p[1].Y(),l=s-n,d=o-h,u=(r-s*s-o*o+n*n+h*h)/(2*i),a.quadraticform=[[u*u-n*n-h*h,u*l/i+n,u*d/i+h],[u*l/i+n,l*l/r-1,l*d/r],[u*d/i+h,l*d/r,d*d/r-1]])},a.X=function(t,e){var i=c(),r=p[1].Dist(p[0]),s=.5*(r*r-i*i)/(r*Math.cos(t)-i),n=Math.atan2(p[1].Y()-p[0].Y(),p[1].X()-p[0].X());return e||o(t,e),p[0].X()+Math.cos(n+t)*s},a.Y=function(t,e){var i=c(),r=p[1].Dist(p[0]),s=.5*(r*r-i*i)/(r*Math.cos(t)-i),o=Math.atan2(p[1].Y()-p[0].Y(),p[1].X()-p[0].X());return p[0].Y()+Math.sin(o+t)*s},a.midpoint=a.center=h,a.type=e.OBJECT_TYPE_CONIC,a.subs={center:a.center},a.inherits.push(a.center,p[0],p[1]),n.isPoint(l)&&a.inherits.push(l),a.hasPoint=function(t,r){var s,o,a,h;return n.evaluate(this.visProp.hasinnerpoints)?(s=p[0].coords,o=p[1].coords,a=this.majorAxis(),h=new i(e.COORDS_BY_SCREEN,[t,r],this.board),h.distance(e.COORDS_BY_USER,s)+h.distance(e.COORDS_BY_USER,o)<=a):u.apply(this,arguments)},h.addChild(a),d=0;d<2;d++)n.isPoint(p[d])&&p[d].addChild(a);return n.isPoint(l)&&l.addChild(a),a.setParents(r),a},t.createHyperbola=function(t,i,r){var s,o,a,h,l,c,d=[],u=n.copyAttributes(r,t.options,"conic","foci"),p=n.copyAttributes(r,t.options,"conic","center"),f=n.copyAttributes(r,t.options,"conic");for(c=0;c<2;c++)if(i[c].length>1)d[c]=t.create("point",i[c],u);else if(n.isPoint(i[c]))d[c]=t.select(i[c]);else if(n.isFunction(i[c])&&n.isPoint(i[c]()))d[c]=i[c]();else{if(!n.isString(i[c]))throw new Error("JSXGraph: Can't create Hyperbola with parent types '"+typeof i[0]+"' and '"+typeof i[1]+"'.\nPossible parent types: [point,point,point], [point,point,number|function]");d[c]=t.select(i[c])}if(n.isNumber(i[2]))l=n.createFunction(i[2],t);else if(n.isFunction(i[2])&&n.isNumber(i[2]()))l=i[2];else{if(n.isPoint(i[2]))h=t.select(i[2]);else if(i[2].length>1)h=t.create("point",i[2],u);else if(n.isFunction(i[2])&&n.isPoint(i[2]()))h=i[2]();else{if(!n.isString(i[2]))throw new Error("JSXGraph: Can't create Hyperbola with parent types '"+typeof i[0]+"' and '"+typeof i[1]+"' and '"+typeof i[2]+"'.\nPossible parent types: [point,point,point], [point,point,number|function]");h=t.select(i[2])}l=function(){return h.Dist(d[0])-h.Dist(d[1])}}for(n.exists(i[4])||(i[4]=1.0001*Math.PI),n.exists(i[3])||(i[3]=-1.0001*Math.PI),a=t.create("point",[function(){return.5*(d[0].X()+d[1].X())},function(){return.5*(d[0].Y()+d[1].Y())}],p),o=t.create("curve",[function(t){return 0},function(t){return 0},i[3],i[4]],f),o.majorAxis=l,s=function(t,e){var i,r,s,n,a,h,c,u,p;e||(i=l(),r=i*i,s=d[0].X(),n=d[0].Y(),a=d[1].X(),h=d[1].Y(),c=s-a,u=n-h,p=(r-s*s-n*n+a*a+h*h)/(2*i),o.quadraticform=[[p*p-a*a-h*h,p*c/i+a,p*u/i+h],[p*c/i+a,c*c/r-1,c*u/r],[p*u/i+h,c*u/r,u*u/r-1]])},o.X=function(t,e){var i=l(),r=d[1].Dist(d[0]),o=.5*(r*r-i*i)/(r*Math.cos(t)+i),n=Math.atan2(d[1].Y()-d[0].Y(),d[1].X()-d[0].X());return e||s(t,e),d[0].X()+Math.cos(n+t)*o},o.Y=function(t,e){var i=l(),r=d[1].Dist(d[0]),s=.5*(r*r-i*i)/(r*Math.cos(t)+i),o=Math.atan2(d[1].Y()-d[0].Y(),d[1].X()-d[0].X());return d[0].Y()+Math.sin(o+t)*s},o.midpoint=o.center=a,o.subs={center:o.center},o.inherits.push(o.center,d[0],d[1]),n.isPoint(h)&&o.inherits.push(h),o.type=e.OBJECT_TYPE_CONIC,a.addChild(o),c=0;c<2;c++)n.isPoint(d[c])&&d[c].addChild(o);return n.isPoint(h)&&h.addChild(o),o.setParents(i),o},t.createParabola=function(t,i,r){var s,a,h,l,c=i[0],d=i[1],u=n.copyAttributes(r,t.options,"conic","foci"),p=n.copyAttributes(r,t.options,"conic","center"),f=n.copyAttributes(r,t.options,"conic");if(i[0].length>1)c=t.create("point",i[0],u);else if(n.isPoint(i[0]))c=t.select(i[0]);else if(n.isFunction(i[0])&&n.isPoint(i[0]()))c=i[0]();else{if(!n.isString(i[0]))throw new Error("JSXGraph: Can't create Parabola with parent types '"+typeof i[0]+"' and '"+typeof i[1]+"'.\nPossible parent types: [point,line]");c=t.select(i[0])}return n.isArray(d)&&2==d.length&&(l=n.copyAttributes(r,t.options,"conic","line"),d=t.create("line",d,l)),n.exists(i[3])||(i[3]=10),n.exists(i[2])||(i[2]=-10),h=t.create("point",[function(){return o.projectPointToLine(c,d,t).usrCoords}],p),a=t.create("curve",[function(t){return 0},function(t){return 0},i[2],i[3]],f),a.midpoint=a.center=h,a.subs={center:a.center},a.inherits.push(a.center),s=function(t,e){var i,r,s,o,n,h;e||(i=d.stdform[1],r=d.stdform[2],s=d.stdform[0],o=i*i+r*r,n=c.X(),h=c.Y(),a.quadraticform=[[s*s-o*(n*n+h*h),s*i+o*n,s*r+o*h],[s*i+o*n,-r*r,i*r],[s*r+o*h,i*r,-i*i]])},a.X=function(t,e){var i,r,n=d.getAngle(),a=o.distPointLine(c.coords.usrCoords,d.stdform),h=d.point1.coords.usrCoords,l=d.point2.coords.usrCoords,u=c.coords.usrCoords;return 0===h[0]?h=[1,l[1]+d.stdform[2],l[2]-d.stdform[1]]:0===l[0]&&(l=[1,h[1]+d.stdform[2],h[2]-d.stdform[1]]),r=(l[1]-h[1])*(u[2]-h[2])-(l[2]-h[2])*(u[1]-h[1])>=0?1:-1,i=r*a/(1-Math.sin(t)),e||s(t,e),c.X()+Math.cos(t+n)*i},a.Y=function(t,e){var i,r,s=d.getAngle(),n=o.distPointLine(c.coords.usrCoords,d.stdform),a=d.point1.coords.usrCoords,h=d.point2.coords.usrCoords,l=c.coords.usrCoords;return 0===a[0]?a=[1,h[1]+d.stdform[2],h[2]-d.stdform[1]]:0===h[0]&&(h=[1,a[1]+d.stdform[2],a[2]-d.stdform[1]]),r=(h[1]-a[1])*(l[2]-a[2])-(h[2]-a[2])*(l[1]-a[1])>=0?1:-1,i=r*n/(1-Math.sin(t)),c.Y()+Math.sin(t+s)*i},a.type=e.OBJECT_TYPE_CONIC,h.addChild(a),n.isPoint(c)&&(c.addChild(a),a.inherits.push(c)),d.addChild(a),a.setParents(i),a},t.createConic=function(t,i,o){var a,h,l,c,d,u,p,f,m,g,b,v,y,C,_=[[1,0,0],[0,1,0],[0,0,1]],P=[[1,0,0],[0,1,0],[0,0,1]],E=[],x=[],S=n.copyAttributes(o,t.options,"conic","point"),w=n.copyAttributes(o,t.options,"conic","center"),O=n.copyAttributes(o,t.options,"conic");if(5===i.length)C=!0;else{if(6!==i.length)throw new Error("JSXGraph: Can't create generic Conic with "+i.length+" parameters.");C=!1}if(C)for(v=0;v<5;v++)if(i[v].length>1)E[v]=t.create("point",i[v],S);else if(n.isPoint(i[v]))E[v]=t.select(i[v]);else if(n.isFunction(i[v])&&n.isPoint(i[v]()))E[v]=i[v]();else{if(!n.isString(i[v]))throw new Error("JSXGraph: Can't create Conic section with parent types '"+typeof i[v]+"'.\nPossible parent types: [point,point,point,point,point], [a00,a11,a22,a01,a02,a12]");E[v]=t.select(i[v])}else y=[[0,0,0],[0,0,0],[0,0,0]],y[0][0]=n.isFunction(i[2])?function(){return i[2]()}:function(){return i[2]},y[0][1]=n.isFunction(i[4])?function(){return i[4]()}:function(){return i[4]},y[0][2]=n.isFunction(i[5])?function(){return i[5]()}:function(){return i[5]},y[1][1]=n.isFunction(i[0])?function(){return i[0]()}:function(){return i[0]},y[1][2]=n.isFunction(i[3])?function(){return i[3]()}:function(){return i[3]},y[2][2]=n.isFunction(i[1])?function(){return i[1]()}:function(){return i[1]};if(d=function(t){var e,i;for(e=0;e<3;e++)for(i=e;i<3;i++)t[e][i]+=t[i][e];for(e=0;e<3;e++)for(i=0;i<e;i++)t[e][i]=t[i][e];return t},c=function(t,e){var i,r,s=[[0,0,0],[0,0,0],[0,0,0]];for(i=0;i<3;i++)for(r=0;r<3;r++)s[i][r]=t[i]*e[r];return d(s)},l=function(t,e,i){var s,o,n,a,h,l=[[0,0,0],[0,0,0],[0,0,0]];for(h=r.matVecMult(e,i),n=r.innerProduct(i,h),h=r.matVecMult(t,i),a=r.innerProduct(i,h),s=0;s<3;s++)for(o=0;o<3;o++)l[s][o]=n*t[s][o]-a*e[s][o];return l},h=t.create("curve",[function(t){return 0},function(t){return 0},0,2*Math.PI],O),a=function(t,e){var i,o,a,d;if(!e){if(C){for(i=0;i<5;i++)x[i]=E[i].coords.usrCoords;g=c(r.crossProduct(x[0],x[1]),r.crossProduct(x[2],x[3])),b=c(r.crossProduct(x[0],x[2]),r.crossProduct(x[1],x[3])),P=l(g,b,x[4])}else for(i=0;i<3;i++)for(o=i;o<3;o++)P[i][o]=y[i][o](),o>i&&(P[o][i]=P[i][o]);for(h.quadraticform=P,u=s.Jacobi(P),u[0][0][0]<0&&(u[0][0][0]*=-1,u[0][1][1]*=-1,u[0][2][2]*=-1),i=0;i<3;i++){for(a=0,o=0;o<3;o++)a+=u[1][o][i]*u[1][o][i];a=Math.sqrt(a)}_=u[1],m=Math.sqrt(Math.abs(u[0][0][0])),p=Math.sqrt(Math.abs(u[0][1][1])),f=Math.sqrt(Math.abs(u[0][2][2]))}return u[0][1][1]<=0&&u[0][2][2]<=0?d=r.matVecMult(_,[1/m,Math.cos(t)/p,Math.sin(t)/f]):u[0][1][1]<=0&&u[0][2][2]>0?d=r.matVecMult(_,[Math.cos(t)/m,1/p,Math.sin(t)/f]):u[0][2][2]<0&&(d=r.matVecMult(_,[Math.sin(t)/m,Math.cos(t)/p,1/f])),n.exists(d)?(d[1]/=d[0],d[2]/=d[0],d[0]=1):d=[1,NaN,NaN],d},h.X=function(t,e){return a(t,e)[1]},h.Y=function(t,e){return a(t,e)[2]},h.midpoint=t.create("point",[function(){var t=h.quadraticform;return[t[1][1]*t[2][2]-t[1][2]*t[1][2],t[1][2]*t[0][2]-t[2][2]*t[0][1],t[0][1]*t[1][2]-t[1][1]*t[0][2]]}],w),h.type=e.OBJECT_TYPE_CONIC,h.center=h.midpoint,h.subs={center:h.center},h.inherits.push(h.center),h.inherits=h.inherits.concat(E),C){for(v=0;v<5;v++)n.isPoint(E[v])&&E[v].addChild(h);h.setParents(i)}return h.addChild(h.center),h},t.registerElement("ellipse",t.createEllipse),t.registerElement("hyperbola",t.createHyperbola),t.registerElement("parabola",t.createParabola),t.registerElement("conic",t.createConic),{createEllipse:t.createEllipse,createHyperbola:t.createHyperbola,createParabola:t.createParabola,createConic:t.createConic}}),define("base/circle",["jxg","base/element","base/coords","base/constants","element/conic","parser/geonext","utils/type"],function(t,e,i,r,s,o,n){"use strict";return t.Circle=function(t,e,i,s,o){this.constructor(t,o,r.OBJECT_TYPE_CIRCLE,r.OBJECT_CLASS_CIRCLE),this.method=e,this.midpoint=this.board.select(i),this.center=this.board.select(i),this.point2=null,this.radius=0,this.line=null,this.circle=null,"twoPoints"===e?(this.point2=t.select(s),this.radius=this.Radius()):"pointRadius"===e?(this.gxtterm=s,this.updateRadius=n.createFunction(s,this.board,null,!0),this.updateRadius()):"pointLine"===e?(this.line=t.select(s),this.radius=this.line.point1.coords.distance(r.COORDS_BY_USER,this.line.point2.coords)):"pointCircle"===e&&(this.circle=t.select(s),this.radius=this.circle.Radius()),this.id=this.board.setId(this,"C"),this.board.renderer.drawEllipse(this),this.board.finalizeAdding(this),this.createGradient(),this.elType="circle",this.createLabel(),this.center.addChild(this),"pointRadius"===e?this.notifyParents(s):"pointLine"===e?this.line.addChild(this):"pointCircle"===e?this.circle.addChild(this):"twoPoints"===e&&this.point2.addChild(this),this.methodMap=n.deepCopy(this.methodMap,{setRadius:"setRadius",getRadius:"getRadius",Area:"Area",area:"Area",radius:"Radius",center:"center",line:"line",point2:"point2"})},t.Circle.prototype=new e,t.extend(t.Circle.prototype,{hasPoint:function(t,e){var s,o,a,h,l,c=this.center.coords.usrCoords,d=new i(r.COORDS_BY_SCREEN,[t,e],this.board),u=this.Radius();return n.isObject(n.evaluate(this.visProp.precision))?(o=this.board._inputDevice,s=n.evaluate(this.visProp.precision[o])):s=this.board.options.precision.hasPoint,a=c[1]-d.usrCoords[1],h=c[2]-d.usrCoords[2],l=Math.sqrt(a*a+h*h),s+=.5*n.evaluate(this.visProp.strokewidth),s/=Math.sqrt(this.board.unitX*this.board.unitY),n.evaluate(this.visProp.hasinnerpoints)?l<u+s:Math.abs(l-u)<s},generatePolynomial:function(t){var e=this.center.symbolic.x,i=this.center.symbolic.y,r=t.symbolic.x,s=t.symbolic.y,o=this.generateRadiusSquared();return""===o?[]:["(("+r+")-("+e+"))^2 + (("+s+")-("+i+"))^2 - ("+o+")"]},generateRadiusSquared:function(){var t,e,i,r,s,o,a="";return"twoPoints"===this.method?(t=this.center.symbolic.x,e=this.center.symbolic.y,i=this.point2.symbolic.x,r=this.point2.symbolic.y,a="(("+i+")-("+t+"))^2 + (("+r+")-("+e+"))^2"):"pointRadius"===this.method?n.isNumber(this.radius)&&(a=(this.radius*this.radius).toString()):"pointLine"===this.method?(i=this.line.point1.symbolic.x,r=this.line.point1.symbolic.y,s=this.line.point2.symbolic.x,o=this.line.point2.symbolic.y,a="(("+i+")-("+s+"))^2 + (("+r+")-("+o+"))^2"):"pointCircle"===this.method&&(a=this.circle.Radius()),a},update:function(){return this.needsUpdate&&(n.evaluate(this.visProp.trace)&&this.cloneToBackground(!0),"pointLine"===this.method?this.radius=this.line.point1.coords.distance(r.COORDS_BY_USER,this.line.point2.coords):"pointCircle"===this.method?this.radius=this.circle.Radius():"pointRadius"===this.method&&(this.radius=this.updateRadius()),this.updateStdform(),this.updateQuadraticform()),this},updateQuadraticform:function(){var t=this.center,e=t.X(),i=t.Y(),r=this.Radius();this.quadraticform=[[e*e+i*i-r*r,-e,-i],[-e,1,0],[-i,0,1]]},updateStdform:function(){this.stdform[3]=.5,this.stdform[4]=this.Radius(),this.stdform[1]=-this.center.coords.usrCoords[1],this.stdform[2]=-this.center.coords.usrCoords[2],isFinite(this.stdform[4])||(this.stdform[0]=n.exists(this.point2)?-(this.stdform[1]*this.point2.coords.usrCoords[1]+this.stdform[2]*this.point2.coords.usrCoords[2]):0),this.normalize()},updateRenderer:function(){return this.needsUpdate?(this.visPropCalc.visible&&(this.isReal=!isNaN(this.center.coords.usrCoords[1]+this.center.coords.usrCoords[2]+this.Radius())&&this.center.isReal,this.isReal||this.updateVisibility(!1)),this.visPropCalc.visible&&this.board.renderer.updateEllipse(this),this.hasLabel&&this.visPropCalc.visible&&this.label&&this.label.visPropCalc.visible&&this.isReal&&(this.label.update(),this.board.renderer.updateText(this.label)),this.setDisplayRendNode(),this.needsUpdate=!1,this):this},notifyParents:function(t){n.isString(t)&&o.findDependencies(this,t,this.board)},setRadius:function(t){return this.updateRadius=n.createFunction(t,this.board,null,!0),this.board.update(),this},Radius:function(t){return n.exists(t)?(this.setRadius(t),this.Radius()):"twoPoints"===this.method?n.cmpArrays(this.point2.coords.usrCoords,[0,0,0])||n.cmpArrays(this.center.coords.usrCoords,[0,0,0])?NaN:this.center.Dist(this.point2):"pointLine"===this.method||"pointCircle"===this.method?this.radius:"pointRadius"===this.method?this.updateRadius():NaN},getRadius:function(){return t.deprecated("Circle.getRadius()","Circle.Radius()"),this.Radius()},getTextAnchor:function(){return this.center.coords},getLabelAnchor:function(){var t,e,s=this.Radius(),o=this.center.coords.usrCoords;switch(n.evaluate(this.visProp.label.position)){case"lft":t=o[1]-s,e=o[2];break;case"llft":t=o[1]-Math.sqrt(.5)*s,e=o[2]-Math.sqrt(.5)*s;break;case"rt":t=o[1]+s,e=o[2];break;case"lrt":t=o[1]+Math.sqrt(.5)*s,e=o[2]-Math.sqrt(.5)*s;break;case"urt":t=o[1]+Math.sqrt(.5)*s,e=o[2]+Math.sqrt(.5)*s;break;case"top":t=o[1],e=o[2]+s;break;case"bot":t=o[1],e=o[2]-s;break;default:t=o[1]-Math.sqrt(.5)*s,e=o[2]+Math.sqrt(.5)*s}return new i(r.COORDS_BY_USER,[t,e],this.board)},cloneToBackground:function(){var t,e=this.Radius(),i={id:this.id+"T"+this.numTraces,elementClass:r.OBJECT_CLASS_CIRCLE,center:{coords:this.center.coords},Radius:function(){return e},getRadius:function(){return e},board:this.board,visProp:n.deepCopy(this.visProp,this.visProp.traceattributes,!0)};return i.visProp.layer=this.board.options.layer.trace,this.numTraces++,n.clearVisPropOld(i),i.visPropCalc={visible:n.evaluate(i.visProp.visible)},t=this.board.renderer.enhancedRendering,this.board.renderer.enhancedRendering=!0,this.board.renderer.drawEllipse(i),this.board.renderer.enhancedRendering=t,this.traces[i.id]=i.rendNode,this},addTransform:function(t){var e,i=n.isArray(t)?t:[t],r=i.length;for(e=0;e<r;e++)this.center.transformations.push(i[e]),"twoPoints"===this.method&&this.point2.transformations.push(i[e]);return this},snapToGrid:function(){var t=n.evaluate(this.visProp.snaptogrid);return this.center.handleSnapToGrid(t,!0),"twoPoints"===this.method&&this.point2.handleSnapToGrid(t,!0),this},snapToPoints:function(){var t=n.evaluate(this.visProp.snaptopoints);return this.center.handleSnapToPoints(t),"twoPoints"===this.method&&this.point2.handleSnapToPoints(t),this},X:function(t){return this.Radius()*Math.cos(2*t*Math.PI)+this.center.coords.usrCoords[1]},Y:function(t){return this.Radius()*Math.sin(2*t*Math.PI)+this.center.coords.usrCoords[2]},Z:function(t){return 1},minX:function(){return 0},maxX:function(){return 1},Area:function(){var t=this.Radius();return t*t*Math.PI},bounds:function(){var t=this.center.coords.usrCoords,e=this.Radius();return[t[1]-e,t[2]+e,t[1]+e,t[2]-e]},getParents:function(){return 1===this.parents.length?this.parents.concat(this.radius):this.parents}}),t.createCircle=function(e,i,o){var a,h,l,c,d;if(h=[],d=e.select(i[0]),n.isObject(d)&&d.elementClass===r.OBJECT_CLASS_CIRCLE&&n.isTransformationOrArray(i[1]))return c=n.copyAttributes(o,e.options,"circle"),a=s.createEllipse(e,[d.center,d.center,function(){return 2*d.Radius()}],c),a.addTransform(i[1]),a;for(l=0;l<i.length;l++)if(n.isPointType(e,i[l])){if(h=h.concat(n.providePoints(e,[i[l]],o,"circle",["center"])),!1===h[h.length-1])throw new Error("JSXGraph: Can't create circle from this type. Please provide a point type.")}else h.push(i[l]);if(c=n.copyAttributes(o,e.options,"circle"),2===h.length&&n.isPoint(h[0])&&n.isPoint(h[1]))a=new t.Circle(e,"twoPoints",h[0],h[1],c);else if((n.isNumber(h[0])||n.isFunction(h[0])||n.isString(h[0]))&&n.isPoint(h[1]))a=new t.Circle(e,"pointRadius",h[1],h[0],c);else if((n.isNumber(h[1])||n.isFunction(h[1])||n.isString(h[1]))&&n.isPoint(h[0]))a=new t.Circle(e,"pointRadius",h[0],h[1],c);else if(h[0].elementClass===r.OBJECT_CLASS_CIRCLE&&n.isPoint(h[1]))a=new t.Circle(e,"pointCircle",h[1],h[0],c);else if(h[1].elementClass===r.OBJECT_CLASS_CIRCLE&&n.isPoint(h[0]))a=new t.Circle(e,"pointCircle",h[0],h[1],c);else if(h[0].elementClass===r.OBJECT_CLASS_LINE&&n.isPoint(h[1]))a=new t.Circle(e,"pointLine",h[1],h[0],c);else if(h[1].elementClass===r.OBJECT_CLASS_LINE&&n.isPoint(h[0]))a=new t.Circle(e,"pointLine",h[0],h[1],c);else{if(!(3===i.length&&n.isPoint(h[0])&&n.isPoint(h[1])&&n.isPoint(h[2])))throw new Error("JSXGraph: Can't create circle with parent types '"+typeof i[0]+"' and '"+typeof i[1]+"'.\nPossible parent types: [point,point], [point,number], [point,function], [point,circle], [point,point,point], [circle,transformation]");if(!t.elements.circumcircle)throw new Error("JSXGraph: Can't create circle with three points. Please include the circumcircle element (element/composition).");a=t.elements.circumcircle(e,h,c)}for(a.isDraggable=!0,a.setParents(h),a.elType="circle",l=0;l<h.length;l++)n.isPoint(h[l])&&a.inherits.push(h[l]);return a},t.registerElement("circle",t.createCircle),{Circle:t.Circle,createCircle:t.createCircle}}),define("base/composition",["jxg","utils/type"],function(t,e){"use strict";return t.Composition=function(t){var i,r=this,s=["setAttribute","setParents","prepareUpdate","updateRenderer","update","fullUpdate","highlight","noHighlight"];for(i=0;i<s.length;i++)this[s[i]]=function(t){return function(){var i;for(i in r.elements)r.elements.hasOwnProperty(i)&&e.exists(r.elements[i][t])&&r.elements[i][t].apply(r.elements[i],arguments);return r}}(s[i]);this.elements={},this.objects=this.elements,this.elementsByName={},this.objectsList=[],this.groups={},this.methodMap={setAttribute:"setAttribute",setProperty:"setAttribute",setParents:"setParents",add:"add",remove:"remove",select:"select"};for(i in t)t.hasOwnProperty(i)&&this.add(i,t[i]);this.dump=!0,this.subs={}},t.extend(t.Composition.prototype,{add:function(t,i){return!(e.exists(this[t])||!e.exists(i))&&(e.exists(i.id)?this.elements[i.id]=i:this.elements[t]=i,e.exists(i.name)&&(this.elementsByName[i.name]=i),i.on("attribute:name",this.nameListener,this),this.objectsList.push(i),this[t]=i,this.methodMap[t]=i,!0)},remove:function(t){var e,i=!1;for(e in this.elements)if(this.elements.hasOwnProperty(e)&&this.elements[e].id===this[t].id){i=!0;break}return i&&(delete this.elements[this[t].id],delete this[t]),i},nameListener:function(t,e,i){delete this.elementsByName[t],this.elementsByName[e]=i},select:function(i){return e.exists(t.Board)?t.Board.prototype.select.call(this,i):new t.Composition},getParents:function(){return this.parents},getType:function(){return this.elType},getAttributes:function(){var t,e={};for(t in this.subs)this.subs.hasOwnProperty(t)&&(e[t]=this.subs[t].visProp);return this.attr}}),t.Composition}),define("base/polygon",["jxg","base/constants","base/coords","math/statistics","math/geometry","utils/type","base/element","base/line","base/transformation"],function(t,e,i,r,s,o,n,a,h){"use strict";return t.Polygon=function(i,r,s){this.constructor(i,s,e.OBJECT_TYPE_POLYGON,e.OBJECT_CLASS_AREA);var n,a,h,l,c=o.copyAttributes(s,i.options,"polygon","borders");for(this.withLines=s.withlines,this.attr_line=c,this.vertices=[],n=0;n<r.length;n++)this.vertices[n]=this.board.select(r[n]);if(this.vertices.length>0&&this.vertices[this.vertices.length-1].id!==this.vertices[0].id&&this.vertices.push(this.vertices[0]),this.borders=[],this.withLines)for(h=this.vertices.length-1,l=0;l<h;l++)n=(l+1)%h,c.id=c.ids&&c.ids[n],c.name=c.names&&c.names[n],c.strokecolor=o.isArray(c.colors)&&c.colors[n%c.colors.length]||c.strokecolor,c.visible=o.exists(s.borders.visible)?s.borders.visible:s.visible,!1===c.strokecolor&&(c.strokecolor="none"),a=i.create("segment",[this.vertices[n],this.vertices[n+1]],c),a.dump=!1,this.borders[n]=a,a.parentPolygon=this;for(this.inherits.push(this.vertices,this.borders),this.id=this.board.setId(this,"Py"),n=0;n<this.vertices.length-1;n++)this.board.select(this.vertices[n]).addChild(this);this.board.renderer.drawPolygon(this),this.board.finalizeAdding(this),this.createGradient(),this.elType="polygon",this.createLabel(),this.methodMap=t.deepCopy(this.methodMap,{borders:"borders",vertices:"vertices",A:"Area",Area:"Area",Perimeter:"Perimeter",L:"Perimeter",Length:"Perimeter",boundingBox:"boundingBox",bounds:"bounds",addPoints:"addPoints",insertPoints:"insertPoints",removePoints:"removePoints"})},t.Polygon.prototype=new n,t.extend(t.Polygon.prototype,{hasPoint:function(t,e){var i,r,s,n=!1;if(o.evaluate(this.visProp.hasinnerpoints)){for(s=this.vertices.length,i=0,r=s-2;i<s-1;r=i++)this.vertices[i].coords.scrCoords[2]>e!=this.vertices[r].coords.scrCoords[2]>e&&t<(this.vertices[r].coords.scrCoords[1]-this.vertices[i].coords.scrCoords[1])*(e-this.vertices[i].coords.scrCoords[2])/(this.vertices[r].coords.scrCoords[2]-this.vertices[i].coords.scrCoords[2])+this.vertices[i].coords.scrCoords[1]&&(n=!n);if(n)return!0}for(s=this.borders.length,i=0;i<s;i++)if(this.borders[i].hasPoint(t,e)){n=!0;break}return n},updateRenderer:function(){var t,e;if(!this.needsUpdate)return this;if(this.visPropCalc.visible){for(e=this.vertices.length,this.isReal=!0,t=0;t<e;++t)if(!this.vertices[t].isReal){this.isReal=!1;break}this.isReal||this.updateVisibility(!1)}return this.visPropCalc.visible&&this.board.renderer.updatePolygon(this),this.hasLabel&&this.visPropCalc.visible&&this.label&&this.label.visPropCalc.visible&&this.isReal&&(this.label.update(),this.board.renderer.updateText(this.label)),this.setDisplayRendNode(),this.needsUpdate=!1,this},getTextAnchor:function(){var t,r,s,o,n;if(0===this.vertices.length)return new i(e.COORDS_BY_USER,[1,0,0],this.board);for(t=this.vertices[0].X(),r=this.vertices[0].Y(),s=t,o=r,n=0;n<this.vertices.length;n++)this.vertices[n].X()<t&&(t=this.vertices[n].X()),this.vertices[n].X()>s&&(s=this.vertices[n].X()),this.vertices[n].Y()>r&&(r=this.vertices[n].Y()),this.vertices[n].Y()<o&&(o=this.vertices[n].Y());return new i(e.COORDS_BY_USER,[.5*(t+s),.5*(r+o)],this.board)},getLabelAnchor:t.shortcut(t.Polygon.prototype,"getTextAnchor"),cloneToBackground:function(){var t,e={};return e.id=this.id+"T"+this.numTraces,this.numTraces++,e.vertices=this.vertices,e.visProp=o.deepCopy(this.visProp,this.visProp.traceattributes,!0),e.visProp.layer=this.board.options.layer.trace,e.board=this.board,o.clearVisPropOld(e),e.visPropCalc={visible:o.evaluate(e.visProp.visible)},t=this.board.renderer.enhancedRendering,this.board.renderer.enhancedRendering=!0,this.board.renderer.drawPolygon(e),this.board.renderer.enhancedRendering=t,this.traces[e.id]=e.rendNode,this},hideElement:function(e){var i;if(t.deprecated("Element.hideElement()","Element.setDisplayRendNode()"),this.visPropCalc.visible=!1,this.board.renderer.display(this,!1),!e)for(i=0;i<this.borders.length;i++)this.borders[i].hideElement();this.hasLabel&&o.exists(this.label)&&(this.label.hiddenByParent=!0,this.label.visPropCalc.visible&&this.label.hideElement())},showElement:function(e){var i;if(t.deprecated("Element.showElement()","Element.setDisplayRendNode()"),this.visPropCalc.visible=!0,this.board.renderer.display(this,!0),!e)for(i=0;i<this.borders.length;i++)this.borders[i].showElement().updateRenderer();return o.exists(this.label)&&this.hasLabel&&this.label.hiddenByParent&&(this.label.hiddenByParent=!1,this.label.visPropCalc.visible||this.label.showElement().updateRenderer()),this},Area:function(){return Math.abs(s.signedPolygon(this.vertices,!0))},Perimeter:function(){var t,e=this.vertices.length,i=0;for(t=1;t<e;++t)i+=this.vertices[t].Dist(this.vertices[t-1]);return i},boundingBox:function(){var t,e,i=[0,0,0,0],r=this.vertices.length-1;if(0===r)return i;for(i[0]=this.vertices[0].X(),i[2]=i[0],i[1]=this.vertices[0].Y(),i[3]=i[1],t=1;t<r;++t)e=this.vertices[t].X(),e<i[0]?i[0]=e:e>i[2]&&(i[2]=e),e=this.vertices[t].Y(),e>i[1]?i[1]=e:e<i[3]&&(i[3]=e);return i},bounds:function(){return this.boundingBox()},remove:function(){var t;for(t=0;t<this.borders.length;t++)this.board.removeObject(this.borders[t]);n.prototype.remove.call(this)},findPoint:function(t){var e;if(!o.isPoint(t))return-1;for(e=0;e<this.vertices.length;e++)if(this.vertices[e].id===t.id)return e;return-1},addPoints:function(t){var e=Array.prototype.slice.call(arguments);return this.insertPoints.apply(this,[this.vertices.length-2].concat(e))},insertPoints:function(t,e){var i,r,s=[];if(0===arguments.length)return this;if(t<0||t>this.vertices.length-2)return this;for(i=1;i<arguments.length;i++)o.isPoint(arguments[i])&&s.push(arguments[i]);if(r=this.vertices.slice(0,t+1).concat(s),this.vertices=r.concat(this.vertices.slice(t+1)),this.withLines){for(r=this.borders.slice(0,t),this.board.removeObject(this.borders[t]),i=0;i<s.length;i++)r.push(this.board.create("segment",[this.vertices[t+i],this.vertices[t+i+1]],this.attr_line));r.push(this.board.create("segment",[this.vertices[t+s.length],this.vertices[t+s.length+1]],this.attr_line)),this.borders=r.concat(this.borders.slice(t+1))}return this.board.update(),this},removePoints:function(t){var e,i,r,s=[],n=[],a=[],h=[];for(this.vertices=this.vertices.slice(0,this.vertices.length-1),e=0;e<arguments.length;e++)r=arguments[e],o.isPoint(r)&&(r=this.findPoint(r)),o.isNumber(r)&&r>-1&&r<this.vertices.length&&-1===o.indexOf(a,r)&&a.push(r);for(e=0;e<a.length;e++)this.vertices[a[e]].removeChild(this);for(a=a.sort(),s=this.vertices.slice(),n=this.borders.slice(),this.withLines&&h.push([a[a.length-1]]),e=a.length-1;e>-1;e--)s[a[e]]=-1,this.withLines&&a[e]-1>a[e-1]&&(h[h.length-1][1]=a[e],h.push([a[e-1]]));for(this.withLines&&(h[h.length-1][1]=a[0]),this.vertices=[],e=0;e<s.length;e++)o.isPoint(s[e])&&this.vertices.push(s[e]);if(this.vertices[this.vertices.length-1].id!==this.vertices[0].id&&this.vertices.push(this.vertices[0]),this.withLines){for(e=0;e<h.length;e++){for(i=h[e][1]-1;i<h[e][0]+1;i++)i<0?(i=0,this.board.removeObject(this.borders[n.length-1]),n[n.length-1]=-1):i>n.length-1&&(i=n.length-1),this.board.removeObject(this.borders[i]),n[i]=-1;0!==h[e][1]&&h[e][0]!==s.length-1&&(n[h[e][0]-1]=this.board.create("segment",[s[Math.max(h[e][1]-1,0)],s[Math.min(h[e][0]+1,this.vertices.length-1)]],this.attr_line))}for(this.borders=[],e=0;e<n.length;e++)-1!==n[e]&&this.borders.push(n[e]);h[0][1]!==this.vertices.length-1&&0!==h[h.length-1][1]||this.borders.push(this.board.create("segment",[this.vertices[0],this.vertices[this.vertices.length-2]],this.attr_line))}return this.board.update(),this},getParents:function(){return this.setParents(this.vertices),this.parents},getAttributes:function(){var t,e=n.prototype.getAttributes.call(this);if(this.withLines)for(e.lines=e.lines||{},e.lines.ids=[],e.lines.colors=[],t=0;t<this.borders.length;t++)e.lines.ids.push(this.borders[t].id),e.lines.colors.push(this.borders[t].visProp.strokecolor);return e},snapToGrid:function(){var t,e;for(e=!!o.evaluate(this.visProp.snaptogrid),t=0;t<this.vertices.length;t++)this.vertices[t].handleSnapToGrid(e,!0)},setPositionDirectly:function(t,e,s){var o,n,a,h,l=new i(t,e,this.board),c=new i(t,s,this.board);for(h=this.vertices.length-1,a=0;a<h;a++)if(!this.vertices[a].draggable())return this;return o=r.subtract(l.usrCoords,c.usrCoords),n=this.board.create("transform",o.slice(1),{type:"translate"}),n.applyOnce(this.vertices.slice(0,-1)),this},sutherlandHodgman:function(e){var i,r,s,o,n,a,h,l=t.Math.Geometry.sortVertices(this.vertices),c=t.Math.Geometry.sortVertices(e.vertices),d=l.length-1,u=c.length-1,p=[],f=function(t,e,i){return(e[1]-t[1])*(i[2]-t[2])-(e[2]-t[2])*(i[1]-t[1])>=0};for(s=0;s<u;s++)p.push(c[s]);for(s=0;s<d;s++)for(r=p.slice(0),i=r.length,p=[],n=r[i-1],o=0;o<i;o++)a=r[o],f(l[s],l[s+1],a)?(f(l[s],l[s+1],n)||(h=t.Math.Geometry.meetSegmentSegment(n,a,l[s],l[s+1]),h[0][1]/=h[0][0],h[0][2]/=h[0][0],h[0][0]=1,p.push(h[0])),p.push(a)):f(l[s],l[s+1],n)&&(h=t.Math.Geometry.meetSegmentSegment(n,a,l[s],l[s+1]),h[0][1]/=h[0][0],h[0][2]/=h[0][0],h[0][0]=1,p.push(h[0])),n=a;return p},intersect:function(t){return this.sutherlandHodgman(t)}}),t.createPolygon=function(i,r,s){var n,a,h,l,c,d,u=[],p=!1;if(c=o.copyAttributes(s,i.options,"polygon"),l=i.select(r[0]),o.isObject(l)&&l.type===e.OBJECT_TYPE_POLYGON&&o.isTransformationOrArray(r[1]))for(p=!0,h=l.vertices.length-1,d=o.copyAttributes(s,i.options,"polygon","vertices"),a=0;a<h;a++)d.withlabel&&(d.name=""===l.vertices[a].name?"":l.vertices[a].name+"'"),u.push(i.create("point",[l.vertices[a],r[1]],d));else if(!1===(u=o.providePoints(i,r,s,"polygon",["vertices"])))throw new Error("JSXGraph: Can't create polygon with parent types other than 'point' and 'coordinate arrays' or a function returning an array of coordinates. Alternatively, a polygon and a transformation can be supplied");if(c=o.copyAttributes(s,i.options,"polygon"),n=new t.Polygon(i,u,c),n.isDraggable=!0,p)for(h=l.vertices.length-1, -a=0;a<h;a++)u[a].prepareUpdate().update().updateVisibility(o.evaluate(n.visProp.visible)).updateRenderer();return n},t.createRegularPolygon=function(t,i,r){var s,n,a,h,l,c,d,u=[];if(l=i.length,a=i[l-1],o.isNumber(a)&&(3!==i.length||a<3))throw new Error("JSXGraph: A regular polygon needs two point types and a number > 2 as input.");if(o.isNumber(t.select(a))?(l--,c=!1):(a=l,c=!0),!1===(u=o.providePoints(t,i.slice(0,l),r,"regularpolygon",["vertices"])))throw new Error("JSXGraph: Can't create regular polygon with parent types other than 'point' and 'coordinate arrays' or a function returning an array of coordinates");for(d=o.copyAttributes(r,t.options,"regularpolygon","vertices"),n=2;n<a;n++)h=t.create("transform",[Math.PI*(2-(a-2)/a),u[n-1]],{type:"rotate"}),c?(u[n].addTransform(u[n-2],h),u[n].fullUpdate()):(o.isArray(d.ids)&&d.ids.length>=a-2&&(d.id=d.ids[n-2]),u[n]=t.create("point",[u[n-2],h],d),u[n].type=e.OBJECT_TYPE_CAS,u[n].isDraggable=!0,u[n].visProp.fixed=!1);return d=o.copyAttributes(r,t.options,"regularpolygon"),s=t.create("polygon",u,d),s.elType="regularpolygon",s},t.createPolygonalChain=function(t,e,i){var r,s;return r=o.copyAttributes(i,t.options,"polygonalchain"),s=t.create("polygon",e,r),s.elType="polygonalchain",s.vertices.pop(),t.removeObject(s.borders[s.borders.length-1]),s.borders.pop(),s},t.registerElement("polygon",t.createPolygon),t.registerElement("regularpolygon",t.createRegularPolygon),t.registerElement("polygonalchain",t.createPolygonalChain),{Polygon:t.Polygon,createPolygon:t.createPolygon,createRegularPolygon:t.createRegularPolygon}}),define("element/composition",["jxg","math/math","math/geometry","math/numerics","base/coords","utils/type","base/constants","base/point","base/line","base/circle","base/transformation","base/composition","base/curve","base/polygon"],function(t,e,i,r,s,o,n,a,h,l,c,d,u,p){"use strict";return t.createOrthogonalProjection=function(t,e,r){var s,a,h,l;if(e[0]=t.select(e[0]),e[1]=t.select(e[1]),o.isPointType(t,e[0])&&e[1].elementClass===n.OBJECT_CLASS_LINE)a=o.providePoints(t,[e[0]],r,"point")[0],s=e[1];else{if(!o.isPointType(t,e[1])||e[0].elementClass!==n.OBJECT_CLASS_LINE)throw new Error("JSXGraph: Can't create perpendicular point with parent types '"+typeof e[0]+"' and '"+typeof e[1]+"'.\nPossible parent types: [point,line]");a=o.providePoints(t,[e[1]],r,"point")[0],s=e[0]}return l=o.copyAttributes(r,t.options,"orthogonalprojection"),h=t.create("point",[function(){return i.projectPointToLine(a,s,t)}],l),a.addChild(h),s.addChild(h),h.elType="orthogonalprojection",h.setParents([a.id,h.id]),h.update(),h.generatePolynomial=function(){var t=s.point1.symbolic.x,e=s.point1.symbolic.y,i=s.point2.symbolic.x,r=s.point2.symbolic.y,o=a.symbolic.x,n=a.symbolic.y,l=h.symbolic.x,c=h.symbolic.y;return["("+e+")*("+l+")-("+e+")*("+i+")+("+c+")*("+i+")-("+t+")*("+c+")+("+t+")*("+r+")-("+l+")*("+r+")","("+n+")*("+e+")-("+n+")*("+r+")-("+c+")*("+e+")+("+c+")*("+r+")+("+o+")*("+t+")-("+o+")*("+i+")-("+l+")*("+t+")+("+l+")*("+i+")"]},h},t.createPerpendicular=function(t,e,i){var r,s,a,l;if(e[0]=t.select(e[0]),e[1]=t.select(e[1]),o.isPointType(t,e[0])&&e[1].elementClass===n.OBJECT_CLASS_LINE)s=e[1],r=o.providePoints(t,[e[0]],i,"point")[0];else{if(!o.isPointType(t,e[1])||e[0].elementClass!==n.OBJECT_CLASS_LINE)throw new Error("JSXGraph: Can't create perpendicular with parent types '"+typeof e[0]+"' and '"+typeof e[1]+"'.\nPossible parent types: [line,point]");s=e[0],r=o.providePoints(t,[e[1]],i,"point")[0]}return l=o.copyAttributes(i,t.options,"perpendicular"),a=h.createLine(t,[function(){return s.stdform[2]*r.X()-s.stdform[1]*r.Y()},function(){return-s.stdform[2]*r.Z()},function(){return s.stdform[1]*r.Z()}],l),a.elType="perpendicular",a.setParents([s.id,r.id]),a},t.createPerpendicularPoint=function(t,e,r){var s,a,h;if(e[0]=t.select(e[0]),e[1]=t.select(e[1]),o.isPointType(t,e[0])&&e[1].elementClass===n.OBJECT_CLASS_LINE)a=o.providePoints(t,[e[0]],r,"point")[0],s=e[1];else{if(!o.isPointType(t,e[1])||e[0].elementClass!==n.OBJECT_CLASS_LINE)throw new Error("JSXGraph: Can't create perpendicular point with parent types '"+typeof e[0]+"' and '"+typeof e[1]+"'.\nPossible parent types: [point,line]");a=o.providePoints(t,[e[1]],r,"point")[0],s=e[0]}return h=t.create("point",[function(){return i.perpendicular(s,a,t)[0]}],r),a.addChild(h),s.addChild(h),h.elType="perpendicularpoint",h.setParents([a.id,s.id]),h.update(),h.generatePolynomial=function(){var t=s.point1.symbolic.x,e=s.point1.symbolic.y,i=s.point2.symbolic.x,r=s.point2.symbolic.y,o=a.symbolic.x,n=a.symbolic.y,l=h.symbolic.x,c=h.symbolic.y;return["("+e+")*("+l+")-("+e+")*("+i+")+("+c+")*("+i+")-("+t+")*("+c+")+("+t+")*("+r+")-("+l+")*("+r+")","("+n+")*("+e+")-("+n+")*("+r+")-("+c+")*("+e+")+("+c+")*("+r+")+("+o+")*("+t+")-("+o+")*("+i+")-("+l+")*("+t+")+("+l+")*("+i+")"]},h},t.createPerpendicularSegment=function(e,r,s){var a,l,c,d,u;if(r[0]=e.select(r[0]),r[1]=e.select(r[1]),o.isPointType(e,r[0])&&r[1].elementClass===n.OBJECT_CLASS_LINE)l=r[1],a=o.providePoints(e,[r[0]],s,"point")[0];else{if(!o.isPointType(e,r[1])||r[0].elementClass!==n.OBJECT_CLASS_LINE)throw new Error("JSXGraph: Can't create perpendicular with parent types '"+typeof r[0]+"' and '"+typeof r[1]+"'.\nPossible parent types: [line,point]");l=r[0],a=o.providePoints(e,[r[1]],s,"point")[0]}return u=o.copyAttributes(s,e.options,"perpendicularsegment","point"),d=t.createPerpendicularPoint(e,[l,a],u),d.dump=!1,o.exists(s.layer)||(s.layer=e.options.layer.line),u=o.copyAttributes(s,e.options,"perpendicularsegment"),c=h.createLine(e,[function(){return i.perpendicular(l,a,e)[1]?[d,a]:[a,d]}],u),c.point=d,c.elType="perpendicularsegment",c.setParents([a.id,l.id]),c.subs={point:d},c.inherits.push(d),c},t.createMidpoint=function(t,i,r){var s,a,h,l,c;for(l=0;l<i.length;++l)i[l]=t.select(i[l]);if(2===i.length&&o.isPointType(t,i[0])&&o.isPointType(t,i[1]))i=o.providePoints(t,i,r,"point"),s=i[0],a=i[1];else{if(1!==i.length||i[0].elementClass!==n.OBJECT_CLASS_LINE)throw new Error("JSXGraph: Can't create midpoint.\nPossible parent types: [point,point], [line]");s=i[0].point1,a=i[0].point2}return c=o.copyAttributes(r,t.options,"midpoint"),h=t.create("point",[function(){var t=s.coords.usrCoords[1]+a.coords.usrCoords[1];return isNaN(t)||Math.abs(s.coords.usrCoords[0])<e.eps||Math.abs(a.coords.usrCoords[0])<e.eps?NaN:.5*t},function(){var t=s.coords.usrCoords[2]+a.coords.usrCoords[2];return isNaN(t)||Math.abs(s.coords.usrCoords[0])<e.eps||Math.abs(a.coords.usrCoords[0])<e.eps?NaN:.5*t}],c),s.addChild(h),a.addChild(h),h.elType="midpoint",h.setParents([s.id,a.id]),h.prepareUpdate().update(),h.generatePolynomial=function(){var t=s.symbolic.x,e=s.symbolic.y,i=a.symbolic.x,r=a.symbolic.y,o=h.symbolic.x,n=h.symbolic.y;return["("+e+")*("+o+")-("+e+")*("+i+")+("+n+")*("+i+")-("+t+")*("+n+")+("+t+")*("+r+")-("+o+")*("+r+")","("+t+")^2 - 2*("+t+")*("+o+")+("+e+")^2-2*("+e+")*("+n+")-("+i+")^2+2*("+i+")*("+o+")-("+r+")^2+2*("+r+")*("+n+")"]},h},t.createParallelPoint=function(t,e,i){var r,s,a,h,l;for(l=0;l<e.length;++l)e[l]=t.select(e[l]);if(3===e.length&&o.isPointType(t,e[0])&&o.isPointType(t,e[1])&&o.isPointType(t,e[2]))e=o.providePoints(t,e,i,"point"),r=e[0],s=e[1],a=e[2];else if(o.isPointType(t,e[0])&&e[1].elementClass===n.OBJECT_CLASS_LINE)a=o.providePoints(t,[e[0]],i,"point")[0],r=e[1].point1,s=e[1].point2;else{if(!o.isPointType(t,e[1])||e[0].elementClass!==n.OBJECT_CLASS_LINE)throw new Error("JSXGraph: Can't create parallel point with parent types '"+typeof e[0]+"', '"+typeof e[1]+"' and '"+typeof e[2]+"'.\nPossible parent types: [line,point], [point,point,point]");a=o.providePoints(t,[e[1]],i,"point")[0],r=e[0].point1,s=e[0].point2}return h=t.create("point",[function(){return a.coords.usrCoords[1]+s.coords.usrCoords[1]-r.coords.usrCoords[1]},function(){return a.coords.usrCoords[2]+s.coords.usrCoords[2]-r.coords.usrCoords[2]}],i),r.addChild(h),s.addChild(h),a.addChild(h),h.elType="parallelpoint",h.setParents([r.id,s.id,a.id]),h.prepareUpdate().update(),h.generatePolynomial=function(){var t=r.symbolic.x,e=r.symbolic.y,i=s.symbolic.x,o=s.symbolic.y,n=a.symbolic.x,l=a.symbolic.y,c=h.symbolic.x,d=h.symbolic.y;return["("+o+")*("+c+")-("+o+")*("+n+")-("+e+")*("+c+")+("+e+")*("+n+")-("+d+")*("+i+")+("+d+")*("+t+")+("+l+")*("+i+")-("+l+")*("+t+")","("+d+")*("+t+")-("+d+")*("+n+")-("+o+")*("+t+")+("+o+")*("+n+")-("+c+")*("+e+")+("+c+")*("+l+")+("+i+")*("+e+")-("+i+")*("+l+")"]},h},t.createParallel=function(t,i,r){var s,n,a,h,l,c;for(l=0;l<i.length;++l)i[l]=t.select(i[l]);return s=null,3===i.length?(i=o.providePoints(t,i,r,"point"),s=i[2],h=function(){return e.crossProduct(i[0].coords.usrCoords,i[1].coords.usrCoords)}):o.isPointType(t,i[0])?(s=o.providePoints(t,[i[0]],r,"point")[0],h=function(){return i[1].stdform}):o.isPointType(t,i[1])&&(s=o.providePoints(t,[i[1]],r,"point")[0],h=function(){return i[0].stdform}),o.exists(r.layer)||(r.layer=t.options.layer.line),c=o.copyAttributes(r,t.options,"parallel","point"),n=t.create("point",[function(){return e.crossProduct([1,0,0],h())}],c),n.isDraggable=!0,c=o.copyAttributes(r,t.options,"parallel"),a=t.create("line",[s,n],c),a.elType="parallel",a.subs={point:n},a.inherits.push(n),a.setParents([i[0].id,i[1].id]),3===i.length&&a.addParents(i[2].id),a.point=n,a},t.createArrowParallel=function(e,i,r){var s;try{return r.firstArrow=!1,r.lastArrow=!0,s=t.createParallel(e,i,r).setAttribute({straightFirst:!1,straightLast:!1}),s.elType="arrowparallel",s}catch(t){throw new Error("JSXGraph: Can't create arrowparallel with parent types '"+typeof i[0]+"' and '"+typeof i[1]+"'.\nPossible parent types: [line,point], [point,point,point]")}},t.createNormal=function(t,i,s){var a,h,l,c,d,u,p,f,m;for(c=0;c<i.length;++c)i[c]=t.select(i[c]);if(1===i.length)a=i[0],h=a.slideObject;else{if(2!==i.length)throw new Error("JSXGraph: Can't create normal with parent types '"+typeof i[0]+"' and '"+typeof i[1]+"'.\nPossible parent types: [point,line], [point,circle], [glider]");if(o.isPointType(t,i[0]))a=o.providePoints(t,[i[0]],s,"point")[0],h=i[1];else{if(!o.isPointType(t,i[1]))throw new Error("JSXGraph: Can't create normal with parent types '"+typeof i[0]+"' and '"+typeof i[1]+"'.\nPossible parent types: [point,line], [point,circle], [glider]");h=i[0],a=o.providePoints(t,[i[1]],s,"point")[0]}}if(p=o.copyAttributes(s,t.options,"normal"),h.elementClass===n.OBJECT_CLASS_LINE)m=o.copyAttributes(s,t.options,"normal","point"),f=t.create("point",[function(){var t=e.crossProduct([1,0,0],h.stdform);return[t[0],-t[2],t[1]]}],m),f.isDraggable=!0,l=t.create("line",[a,f],p),l.point=f,l.subs={point:f},l.inherits.push(f);else if(h.elementClass===n.OBJECT_CLASS_CIRCLE)l=t.create("line",[h.midpoint,a],p);else if(h.elementClass===n.OBJECT_CLASS_CURVE)"plot"!==o.evaluate(h.visProp.curvetype)?(d=h.X,u=h.Y,l=t.create("line",[function(){return-a.X()*r.D(d)(a.position)-a.Y()*r.D(u)(a.position)},function(){return r.D(d)(a.position)},function(){return r.D(u)(a.position)}],p)):l=t.create("line",[function(){var t=Math.floor(a.position),e=a.position-t;return t===h.numberPoints-1&&(t-=1,e=1),t<0?1:(h.Y(t)+e*(h.Y(t+1)-h.Y(t)))*(h.Y(t)-h.Y(t+1))-(h.X(t)+e*(h.X(t+1)-h.X(t)))*(h.X(t+1)-h.X(t))},function(){var t=Math.floor(a.position);return t===h.numberPoints-1&&(t-=1),t<0?0:h.X(t+1)-h.X(t)},function(){var t=Math.floor(a.position);return t===h.numberPoints-1&&(t-=1),t<0?0:h.Y(t+1)-h.Y(t)}],p);else{if(h.type!==n.OBJECT_TYPE_TURTLE)throw new Error("JSXGraph: Can't create normal with parent types '"+typeof i[0]+"' and '"+typeof i[1]+"'.\nPossible parent types: [point,line], [point,circle], [glider]");l=t.create("line",[function(){var t,e,i=Math.floor(a.position),r=a.position-i;for(e=0;e<h.objects.length;e++)if(t=h.objects[e],t.type===n.OBJECT_TYPE_CURVE){if(i<t.numberPoints)break;i-=t.numberPoints}return i===t.numberPoints-1&&(i-=1,r=1),i<0?1:(t.Y(i)+r*(t.Y(i+1)-t.Y(i)))*(t.Y(i)-t.Y(i+1))-(t.X(i)+r*(t.X(i+1)-t.X(i)))*(t.X(i+1)-t.X(i))},function(){var t,e,i=Math.floor(a.position);for(e=0;e<h.objects.length;e++)if(t=h.objects[e],t.type===n.OBJECT_TYPE_CURVE){if(i<t.numberPoints)break;i-=t.numberPoints}return i===t.numberPoints-1&&(i-=1),i<0?0:t.X(i+1)-t.X(i)},function(){var t,e,i=Math.floor(a.position);for(e=0;e<h.objects.length;e++)if(t=h.objects[e],t.type===n.OBJECT_TYPE_CURVE){if(i<t.numberPoints)break;i-=t.numberPoints}return i===t.numberPoints-1&&(i-=1),i<0?0:t.Y(i+1)-t.Y(i)}],p)}return l.elType="normal",l.setParents(i),l},t.createBisector=function(t,e,r){var s,n,a,l;if(e=o.providePoints(t,e,r,"point"),o.isPoint(e[0])&&o.isPoint(e[1])&&o.isPoint(e[2])){for(l=o.copyAttributes(r,t.options,"bisector","point"),l.snapToGrid=!1,s=t.create("point",[function(){return i.angleBisector(e[0],e[1],e[2],t)}],l),s.dump=!1,a=0;a<3;a++)e[a].addChild(s);return o.exists(r.layer)||(r.layer=t.options.layer.line),l=o.copyAttributes(r,t.options,"bisector"),n=h.createLine(t,[e[1],s],l),n.point=s,n.elType="bisector",n.setParents(e),n.subs={point:s},n.inherits.push(s),n}throw new Error("JSXGraph: Can't create angle bisector with parent types '"+typeof e[0]+"' and '"+typeof e[1]+"'.\nPossible parent types: [point,point,point]")},t.createAngularBisectorsOfTwoLines=function(t,e,i){var r,s,a,h,l=t.select(e[0]),c=t.select(e[1]);if(l.elementClass!==n.OBJECT_CLASS_LINE||c.elementClass!==n.OBJECT_CLASS_LINE)throw new Error("JSXGraph: Can't create angle bisectors of two lines with parent types '"+typeof e[0]+"' and '"+typeof e[1]+"'.\nPossible parent types: [line,line]");return o.exists(i.layer)||(i.layer=t.options.layer.line),a=o.copyAttributes(i,t.options,"bisectorlines","line1"),r=t.create("line",[function(){var t=Math.sqrt(l.stdform[1]*l.stdform[1]+l.stdform[2]*l.stdform[2]),e=Math.sqrt(c.stdform[1]*c.stdform[1]+c.stdform[2]*c.stdform[2]);return l.stdform[0]/t-c.stdform[0]/e},function(){var t=Math.sqrt(l.stdform[1]*l.stdform[1]+l.stdform[2]*l.stdform[2]),e=Math.sqrt(c.stdform[1]*c.stdform[1]+c.stdform[2]*c.stdform[2]);return l.stdform[1]/t-c.stdform[1]/e},function(){var t=Math.sqrt(l.stdform[1]*l.stdform[1]+l.stdform[2]*l.stdform[2]),e=Math.sqrt(c.stdform[1]*c.stdform[1]+c.stdform[2]*c.stdform[2]);return l.stdform[2]/t-c.stdform[2]/e}],a),o.exists(i.layer)||(i.layer=t.options.layer.line),a=o.copyAttributes(i,t.options,"bisectorlines","line2"),s=t.create("line",[function(){var t=Math.sqrt(l.stdform[1]*l.stdform[1]+l.stdform[2]*l.stdform[2]),e=Math.sqrt(c.stdform[1]*c.stdform[1]+c.stdform[2]*c.stdform[2]);return l.stdform[0]/t+c.stdform[0]/e},function(){var t=Math.sqrt(l.stdform[1]*l.stdform[1]+l.stdform[2]*l.stdform[2]),e=Math.sqrt(c.stdform[1]*c.stdform[1]+c.stdform[2]*c.stdform[2]);return l.stdform[1]/t+c.stdform[1]/e},function(){var t=Math.sqrt(l.stdform[1]*l.stdform[1]+l.stdform[2]*l.stdform[2]),e=Math.sqrt(c.stdform[1]*c.stdform[1]+c.stdform[2]*c.stdform[2]);return l.stdform[2]/t+c.stdform[2]/e}],a),h=new d({line1:r,line2:s}),r.dump=!1,s.dump=!1,h.elType="bisectorlines",h.setParents([l.id,c.id]),h.subs={line1:r,line2:s},h},t.createCircumcenter=function(t,e,r){var s,n,h,l,c;if(e=o.providePoints(t,e,r,"point"),o.isPoint(e[0])&&o.isPoint(e[1])&&o.isPoint(e[2])){for(h=e[0],l=e[1],c=e[2],s=a.createPoint(t,[function(){return i.circumcenter(h,l,c,t)}],r),n=0;n<3;n++)e[n].addChild(s);return s.elType="circumcenter",s.setParents(e),s.generatePolynomial=function(){var t=h.symbolic.x,e=h.symbolic.y,i=l.symbolic.x,r=l.symbolic.y,o=c.symbolic.x,n=c.symbolic.y,a=s.symbolic.x,d=s.symbolic.y;return[["((",a,")-(",t,"))^2+((",d,")-(",e,"))^2-((",a,")-(",i,"))^2-((",d,")-(",r,"))^2"].join(""),["((",a,")-(",t,"))^2+((",d,")-(",e,"))^2-((",a,")-(",o,"))^2-((",d,")-(",n,"))^2"].join("")]},s}throw new Error("JSXGraph: Can't create circumcircle midpoint with parent types '"+typeof e[0]+"', '"+typeof e[1]+"' and '"+typeof e[2]+"'.\nPossible parent types: [point,point,point]")},t.createIncenter=function(t,e,i){var r,a,h,l;if(e=o.providePoints(t,e,i,"point"),!(e.length>=3&&o.isPoint(e[0])&&o.isPoint(e[1])&&o.isPoint(e[2])))throw new Error("JSXGraph: Can't create incenter with parent types '"+typeof e[0]+"', '"+typeof e[1]+"' and '"+typeof e[2]+"'.\nPossible parent types: [point,point,point]");return a=e[0],h=e[1],l=e[2],r=t.create("point",[function(){var e,i,r;return e=Math.sqrt((h.X()-l.X())*(h.X()-l.X())+(h.Y()-l.Y())*(h.Y()-l.Y())),i=Math.sqrt((a.X()-l.X())*(a.X()-l.X())+(a.Y()-l.Y())*(a.Y()-l.Y())),r=Math.sqrt((h.X()-a.X())*(h.X()-a.X())+(h.Y()-a.Y())*(h.Y()-a.Y())),new s(n.COORDS_BY_USER,[(e*a.X()+i*h.X()+r*l.X())/(e+i+r),(e*a.Y()+i*h.Y()+r*l.Y())/(e+i+r)],t)}],i),r.elType="incenter",r.setParents(e),r},t.createCircumcircle=function(e,i,r){var s,n,a;if(!1===(i=o.providePoints(e,i,r,"point")))throw new Error("JSXGraph: Can't create circumcircle with parent types '"+typeof i[0]+"', '"+typeof i[1]+"' and '"+typeof i[2]+"'.\nPossible parent types: [point,point,point]");try{a=o.copyAttributes(r,e.options,"circumcircle","center"),s=t.createCircumcenter(e,i,a),s.dump=!1,o.exists(r.layer)||(r.layer=e.options.layer.circle),a=o.copyAttributes(r,e.options,"circumcircle"),n=l.createCircle(e,[s,i[0]],a),n.elType="circumcircle",n.setParents(i),n.subs={center:s},n.inherits.push(n)}catch(t){throw new Error("JSXGraph: Can't create circumcircle with parent types '"+typeof i[0]+"', '"+typeof i[1]+"' and '"+typeof i[2]+"'.\nPossible parent types: [point,point,point]")}return n},t.createIncircle=function(e,i,r){var s,n,a;if(!1===(i=o.providePoints(e,i,r,"point")))throw new Error("JSXGraph: Can't create circumcircle with parent types '"+typeof i[0]+"', '"+typeof i[1]+"' and '"+typeof i[2]+"'.\nPossible parent types: [point,point,point]");try{a=o.copyAttributes(r,e.options,"incircle","center"),s=t.createIncenter(e,i,a),s.dump=!1,o.exists(r.layer)||(r.layer=e.options.layer.circle),a=o.copyAttributes(r,e.options,"incircle"),n=l.createCircle(e,[s,function(){var t=Math.sqrt((i[1].X()-i[2].X())*(i[1].X()-i[2].X())+(i[1].Y()-i[2].Y())*(i[1].Y()-i[2].Y())),e=Math.sqrt((i[0].X()-i[2].X())*(i[0].X()-i[2].X())+(i[0].Y()-i[2].Y())*(i[0].Y()-i[2].Y())),r=Math.sqrt((i[1].X()-i[0].X())*(i[1].X()-i[0].X())+(i[1].Y()-i[0].Y())*(i[1].Y()-i[0].Y())),s=(t+e+r)/2;return Math.sqrt((s-t)*(s-e)*(s-r)/s)}],a),n.elType="incircle",n.setParents(i),n.center=s,n.subs={center:n.center},n.inherits.push(s)}catch(t){throw new Error("JSXGraph: Can't create circumcircle with parent types '"+typeof i[0]+"', '"+typeof i[1]+"' and '"+typeof i[2]+"'.\nPossible parent types: [point,point,point]")}return n},t.createReflection=function(t,e,i){var r,s,d,f,m,g,b,v,y="\nPossible parent types: [point|line|curve|polygon|circle|arc|sector, line]";for(g=0;g<e.length;++g)e[g]=t.select(e[g]);if(b=o.copyAttributes(i,t.options,"reflection"),o.isPoint(e[0]))s=o.providePoints(t,[e[0]],v)[0];else{if(e[0].elementClass!==n.OBJECT_CLASS_CURVE&&e[0].elementClass!==n.OBJECT_CLASS_LINE&&e[0].type!==n.OBJECT_TYPE_POLYGON&&e[0].elementClass!==n.OBJECT_CLASS_CIRCLE)throw new Error("JSXGraph: Can't create reflection element with parent types '"+typeof e[0]+"' and '"+typeof e[1]+"'."+y);s=e[0]}if(e[1].elementClass!==n.OBJECT_CLASS_LINE)throw new Error("JSXGraph: Can't create reflected element with parent types '"+typeof e[0]+"' and '"+typeof e[1]+"'."+y);if(r=e[1],m=c.createTransform(t,[r],{type:"reflect"}),o.isPoint(s))d=a.createPoint(t,[s,m],b);else if(s.elementClass===n.OBJECT_CLASS_CURVE)d=u.createCurve(t,[s,m],b);else if(s.elementClass===n.OBJECT_CLASS_LINE)d=h.createLine(t,[s,m],b);else if(s.type===n.OBJECT_TYPE_POLYGON)d=p.createPolygon(t,[s,m],b);else{if(s.elementClass!==n.OBJECT_CLASS_CIRCLE)throw new Error("JSXGraph: Can't create reflected element with parent types '"+typeof e[0]+"' and '"+typeof e[1]+"'."+y);"euclidean"===b.type.toLowerCase()?(v=o.copyAttributes(i,t.options,"reflection","center"),f=a.createPoint(t,[s.center,m],v),d=l.createCircle(t,[f,function(){return s.Radius()}],b)):d=l.createCircle(t,[s,m],b)}return r.addChild(d),d.elType="reflection",d.addParents(r),d.prepareUpdate().update(),o.isPoint(d)&&(d.generatePolynomial=function(){var t=r.point1.symbolic.x,e=r.point1.symbolic.y,i=r.point2.symbolic.x,o=r.point2.symbolic.y,n=s.symbolic.x,a=s.symbolic.y,h=d.symbolic.x,l=d.symbolic.y;return[["((",l,")-(",a,"))*((",e,")-(",o,"))+((",t,")-(",i,"))*((",h,")-(",n,"))"].join(""),["((",h,")-(",t,"))^2+((",l,")-(",e,"))^2-((",n,")-(",t,"))^2-((",a,")-(",e,"))^2"].join("")]}),d},t.createMirrorElement=function(t,e,i){var r,s,d,f,m,g,b,v,y="\nPossible parent types: [point|line|curve|polygon|circle|arc|sector, point]";for(s=0;s<e.length;++s)e[s]=t.select(e[s]);if(b=o.copyAttributes(i,t.options,"mirrorelement"),o.isPoint(e[0]))r=o.providePoints(t,[e[0]],b)[0];else{if(e[0].elementClass!==n.OBJECT_CLASS_CURVE&&e[0].elementClass!==n.OBJECT_CLASS_LINE&&e[0].type!==n.OBJECT_TYPE_POLYGON&&e[0].elementClass!==n.OBJECT_CLASS_CIRCLE)throw new Error("JSXGraph: Can't create mirror element with parent types '"+typeof e[0]+"' and '"+typeof e[1]+"'."+y);r=e[0]}if(!o.isPoint(e[1]))throw new Error("JSXGraph: Can't create mirror element with parent types '"+typeof e[0]+"' and '"+typeof e[1]+"'."+y);if(v=o.copyAttributes(i,t.options,"mirrorelement","point"),d=o.providePoints(t,[e[1]],v)[0],g=c.createTransform(t,[Math.PI,d],{type:"rotate"}),o.isPoint(r))f=a.createPoint(t,[r,g],b);else if(r.elementClass===n.OBJECT_CLASS_CURVE)f=u.createCurve(t,[r,g],b);else if(r.elementClass===n.OBJECT_CLASS_LINE)f=h.createLine(t,[r,g],b);else if(r.type===n.OBJECT_TYPE_POLYGON)f=p.createPolygon(t,[r,g],b);else{if(r.elementClass!==n.OBJECT_CLASS_CIRCLE)throw new Error("JSXGraph: Can't create mirror element with parent types '"+typeof e[0]+"' and '"+typeof e[1]+"'."+y);"euclidean"===b.type.toLowerCase()?(v=o.copyAttributes(i,t.options,"mirrorelement","center"),m=a.createPoint(t,[r.center,g],v),f=l.createCircle(t,[m,function(){return r.Radius()}],b)):f=l.createCircle(t,[r,g],b)}return d.addChild(f),f.elType="mirrorelement",f.addParents(d),f.prepareUpdate().update(),f},t.createMirrorPoint=function(e,i,r){var s=t.createMirrorElement(e,i,r);return s.elType="mirrorpoint",s},t.createIntegral=function(e,i,a){var h,l,c,d,u,p,f,m,g,b,v,y,C,_,P=null;if(o.isArray(i[0])&&i[1].elementClass===n.OBJECT_CLASS_CURVE)h=i[0],l=i[1];else{if(!o.isArray(i[1])||i[0].elementClass!==n.OBJECT_CLASS_CURVE)throw new Error("JSXGraph: Can't create integral with parent types '"+typeof i[0]+"' and '"+typeof i[1]+"'.\nPossible parent types: [[number|function,number|function],curve]");h=i[1],l=i[0]}return c=o.copyAttributes(a,e.options,"integral"),c.withLabel=!1,_=e.create("curve",[[0],[0]],c),d=h[0],u=h[1],o.isFunction(d)?(p=d,f=function(){return l.Y(p())},d=p()):(p=d,f=l.Y(d)),o.isFunction(u)?(m=u,g=function(){return l.Y(m())},u=m()):(m=u,g=l.Y(u)),c=o.copyAttributes(a,e.options,"integral","curveLeft"),b=e.create("glider",[p,f,l],c),o.isFunction(p)&&b.hideElement(),c=o.copyAttributes(a,e.options,"integral","baseLeft"),v=e.create("point",[function(){return"y"===o.evaluate(_.visProp.axis)?0:b.X()},function(){return"y"===o.evaluate(_.visProp.axis)?b.Y():0}],c),c=o.copyAttributes(a,e.options,"integral","curveRight"),y=e.create("glider",[m,g,l],c),o.isFunction(m)&&y.hideElement(),c=o.copyAttributes(a,e.options,"integral","baseRight"),C=e.create("point",[function(){return"y"===o.evaluate(_.visProp.axis)?0:y.X()},function(){return"y"===o.evaluate(_.visProp.axis)?y.Y():0}],c),c=o.copyAttributes(a,e.options,"integral"),!1!==c.withlabel&&"y"!==c.axis&&(c=o.copyAttributes(a,e.options,"integral","label"),c=o.copyAttributes(c,e.options,"label"),P=e.create("text",[function(){var t=new s(n.COORDS_BY_SCREEN,[o.evaluate(this.visProp.offset[0])+this.board.origin.scrCoords[1],0],this.board,!1),e=this.board.getBoundingBox(),i=.1*(e[2]-e[0]),r=y.X();return r<e[0]?r=e[0]+i:r>e[2]&&(r=e[2]-i),r+t.usrCoords[1]},function(){var t=new s(n.COORDS_BY_SCREEN,[0,o.evaluate(this.visProp.offset[1])+this.board.origin.scrCoords[2]],this.board,!1),e=this.board.getBoundingBox(),i=.1*(e[1]-e[3]),r=y.Y();return r>e[1]?r=e[1]-i:r<e[3]&&(r=e[3]+i),r+t.usrCoords[2]},function(){var t=r.NewtonCotes([v.X(),C.X()],l.Y);return"∫ = "+o.toFixed(t,4)}],c),P.dump=!1,b.addChild(P),y.addChild(P)),b.dump=!1,v.dump=!1,y.dump=!1,C.dump=!1,_.elType="integral",_.setParents([l.id,h]),_.subs={curveLeft:b,baseLeft:v,curveRight:y,baseRight:C},_.inherits.push(b,v,y,C),c.withLabel&&(_.subs.label=P,_.inherits.push(P)),_.Value=function(){return r.I([v.X(),C.X()],l.Y)},_.updateDataArray=function(){var t,e,i,r,s,n,a,h,c;if("y"===o.evaluate(this.visProp.axis)){for(b.Y()<y.Y()?(n=b.X(),h=b.Y(),a=y.X(),c=y.Y()):(n=y.X(),h=y.Y(),a=b.X(),c=b.Y()),r=Math.min(n,a),s=Math.max(n,a),t=[0,n],e=[h,h],i=0;i<l.numberPoints;i++)h<=l.points[i].usrCoords[2]&&r<=l.points[i].usrCoords[1]&&l.points[i].usrCoords[2]<=c&&l.points[i].usrCoords[1]<=s&&(t.push(l.points[i].usrCoords[1]),e.push(l.points[i].usrCoords[2]));t.push(a),e.push(c),t.push(0),e.push(c),t.push(0),e.push(h)}else{for(v.X()<C.X()?(r=v.X(),s=C.X()):(r=C.X(),s=v.X()),t=[r,r],e=[0,l.Y(r)],i=0;i<l.numberPoints;i++)r<=l.points[i].usrCoords[1]&&l.points[i].usrCoords[1]<=s&&(t.push(l.points[i].usrCoords[1]),e.push(l.points[i].usrCoords[2]));t.push(s),e.push(l.Y(s)),t.push(s),e.push(0),t.push(r),e.push(0)}this.dataX=t,this.dataY=e},b.addChild(_),y.addChild(_),v.addChild(_),C.addChild(_),_.baseLeft=v,_.baseRight=C,_.curveLeft=b,_.curveRight=y,_.methodMap=t.deepCopy(_.methodMap,{curveLeft:"curveLeft",baseLeft:"baseLeft",curveRight:"curveRight",baseRight:"baseRight",Value:"Value"}),_.label=P,_},t.createGrid=function(t,e,i){var r,a;return a=o.copyAttributes(i,t.options,"grid"),r=t.create("curve",[[null],[null]],a),r.elType="grid",r.type=n.OBJECT_TYPE_GRID,r.updateDataArray=function(){var e,i,a,h,l,c=o.evaluate(this.visProp.gridx),d=o.evaluate(this.visProp.gridy);for(h=o.isArray(this.visProp.topleft)?new s(o.evaluate(this.visProp.tltype)||n.COORDS_BY_USER,this.visProp.topleft,t):new s(n.COORDS_BY_SCREEN,[0,0],t),l=o.isArray(this.visProp.bottomright)?new s(o.evaluate(this.visProp.brtype)||n.COORDS_BY_USER,this.visProp.bottomright,t):new s(n.COORDS_BY_SCREEN,[t.canvasWidth,t.canvasHeight],t),t.options.grid.hasGrid=!0,r.dataX=[],r.dataY=[],e=Math.floor(h.usrCoords[2]/d)*d,i=Math.ceil(l.usrCoords[2]/d)*d,h.usrCoords[2]<l.usrCoords[2]&&(e=Math.ceil(l.usrCoords[2]/d)*d,i=Math.floor(h.usrCoords[2]/d)*d),a=e;a>i-d;a-=d)r.dataX.push(h.usrCoords[1],l.usrCoords[1],NaN),r.dataY.push(a,a,NaN);for(e=Math.ceil(h.usrCoords[1]/c)*c,i=Math.floor(l.usrCoords[1]/c)*c,h.usrCoords[1]>l.usrCoords[1]&&(e=Math.floor(l.usrCoords[1]/c)*c,i=Math.ceil(h.usrCoords[1]/c)*c),a=e;a<i+c;a+=c)r.dataX.push(a,a,NaN),r.dataY.push(h.usrCoords[2],l.usrCoords[2],NaN)},r.hasPoint=function(){return!1},t.grids.push(r),r},t.createInequality=function(t,r,s){var a,h,l;if(l=o.copyAttributes(s,t.options,"inequality"),r[0].elementClass===n.OBJECT_CLASS_LINE)h=t.create("curve",[[],[]],l),h.hasPoint=function(){return!1},h.updateDataArray=function(){var s,o,a,h=t.getBoundingBox(),c=l.inverse?-1:1,d=1.5*Math.max(h[2]-h[0],h[1]-h[3]),u={coords:{usrCoords:[1,(h[0]+h[2])/2,l.inverse?h[1]:h[3]]}},p=r[0].stdform.slice(1),f=p;a=1.5*Math.max(i.perpendicular(r[0],u,t)[0].distance(n.COORDS_BY_USER,u.coords),d),a*=c,u={coords:{usrCoords:[1,(h[0]+h[2])/2,(h[1]+h[3])/2]}},u=Math.abs(e.innerProduct(u.coords.usrCoords,r[0].stdform,3))>=e.eps?i.perpendicular(r[0],u,t)[0].usrCoords:u.coords.usrCoords,s=[1,u[1]+p[1]*d,u[2]-p[0]*d],o=[1,u[1]-f[1]*d,u[2]+f[0]*d],this.dataX=[s[1],s[1]+p[0]*a,o[1]+f[0]*a,o[1],s[1]],this.dataY=[s[2],s[2]+p[1]*a,o[2]+f[1]*a,o[2],s[2]]};else if(r[0].elementClass===n.OBJECT_CLASS_CURVE&&"functiongraph"===r[0].visProp.curvetype)h=t.create("curve",[[],[]],l),h.updateDataArray=function(){var t,e,i,s,n,a,h,l,c,d=this.board.getBoundingBox(),u=[],p=r[0].minX(),f=r[0].maxX(),m=.3*(d[1]-d[3]);if(t=o.evaluate(this.visProp.inverse)?1:3,this.dataX=[],this.dataY=[],0!=(s=r[0].points.length))for(d[1]+=m,d[3]-=m,i=-1;i<s-1;){for(n=i+1,e=s;n<s;n++)if(r[0].points[n].isReal()){e=n;break}if(e>=s)break;for(n=e,i=s-1;n<s-1;n++)if(!r[0].points[n+1].isReal()){i=n;break}for(l=r[0].points[e].usrCoords[1],c=r[0].points[i].usrCoords[1],a=d[0]<p?p:d[0],h=d[2]>f?f:d[2],a=0===e?a:Math.max(a,l),h=i===s-1?h:Math.min(h,c),a=0===e?p:l,h=i===s-1?f:c,u=[],u.push([1,a,d[t]]),u.push([1,a,r[0].points[e].usrCoords[2]]),n=e;n<=i;n++)u.push(r[0].points[n].usrCoords);for(u.push([1,h,r[0].points[i].usrCoords[2]]),u.push([1,h,d[t]]),u.push(u[0]),n=0;n<u.length;n++)this.dataX.push(u[n][1]),this.dataY.push(u[n][2]);i<s-1&&(this.dataX.push(NaN),this.dataY.push(NaN))}},h.hasPoint=function(){return!1};else if(a=o.createFunction(r[0]),!o.exists(a))throw new Error("JSXGraph: Can't create area with the given parents.\nPossible parent types: [line], [function]");return h.addParents(r[0]),h},t.registerElement("arrowparallel",t.createArrowParallel),t.registerElement("bisector",t.createBisector),t.registerElement("bisectorlines",t.createAngularBisectorsOfTwoLines),t.registerElement("msector",t.createMsector),t.registerElement("circumcircle",t.createCircumcircle),t.registerElement("circumcirclemidpoint",t.createCircumcenter),t.registerElement("circumcenter",t.createCircumcenter),t.registerElement("incenter",t.createIncenter),t.registerElement("incircle",t.createIncircle),t.registerElement("integral",t.createIntegral),t.registerElement("midpoint",t.createMidpoint),t.registerElement("mirrorelement",t.createMirrorElement),t.registerElement("mirrorpoint",t.createMirrorPoint),t.registerElement("normal",t.createNormal),t.registerElement("orthogonalprojection",t.createOrthogonalProjection),t.registerElement("parallel",t.createParallel),t.registerElement("parallelpoint",t.createParallelPoint),t.registerElement("perpendicular",t.createPerpendicular),t.registerElement("perpendicularpoint",t.createPerpendicularPoint),t.registerElement("perpendicularsegment",t.createPerpendicularSegment),t.registerElement("reflection",t.createReflection),t.registerElement("grid",t.createGrid),t.registerElement("inequality",t.createInequality),{createArrowParallel:t.createArrowParallel,createBisector:t.createBisector,createAngularBisectorOfTwoLines:t.createAngularBisectorsOfTwoLines,createCircumcircle:t.createCircumcircle,createCircumcenter:t.createCircumcenter,createIncenter:t.createIncenter,createIncircle:t.createIncircle,createIntegral:t.createIntegral,createMidpoint:t.createMidpoint,createMirrorElement:t.createMirrorElement,createMirrorPoint:t.createMirrorPoint,createNormal:t.createNormal,createOrthogonalProjection:t.createOrthogonalProjection,createParallel:t.createParallel,createParallelPoint:t.createParallelPoint,createPerpendicular:t.createPerpendicular,createPerpendicularPoint:t.createPerpendicularPoint,createPerpendicularSegmen:t.createPerpendicularSegment,createReflection:t.createReflection,createGrid:t.createGrid,createInequality:t.createInequality}}),define("base/board",["jxg","base/constants","base/coords","options","math/numerics","math/math","math/geometry","math/complex","math/statistics","parser/jessiecode","parser/geonext","utils/color","utils/type","utils/event","utils/env","base/transformation","base/point","base/line","base/text","element/composition","base/composition"],function(t,e,i,r,s,o,n,a,h,l,c,d,u,p,f,m,g,b,v,y,C){"use strict";return t.Board=function(i,s,o,n,a,h,c,d,m,g,b){if(this.BOARD_MODE_NONE=0,this.BOARD_MODE_DRAG=1,this.BOARD_MODE_MOVE_ORIGIN=2,this.BOARD_QUALITY_LOW=1,this.BOARD_QUALITY_HIGH=2,this.BOARD_MODE_ZOOM=17,u.exists(b.document)&&!1!==b.document?this.document=b.document:void 0!==document&&u.isObject(document)&&(this.document=document),this.container=i,this.containerObj=f.isBrowser?this.document.getElementById(this.container):null,f.isBrowser&&"no"!==s.type&&null===this.containerObj)throw new Error("\nJSXGraph: HTML container element '"+i+"' not found.");this.renderer=s,this.grids=[],this.options=u.deepCopy(r),this.attr=b,this.dimension=2,this.jc=new l,this.jc.use(this),this.origin={},this.origin.usrCoords=[1,0,0],this.origin.scrCoords=[1,n[0],n[1]],this.zoomX=a,this.zoomY=h,this.unitX=c*this.zoomX, -this.unitY=d*this.zoomY,this.keepaspectratio=!1,this.canvasWidth=m,this.canvasHeight=g,u.exists(o)&&""!==o&&f.isBrowser&&!u.exists(this.document.getElementById(o))?this.id=o:this.id=this.generateId(),p.eventify(this),this.hooks=[],this.dependentBoards=[],this.inUpdate=!1,this.objects={},this.objectsList=[],this.groups={},this.animationObjects={},this.highlightedObjects={},this.numObjects=0,this.elementsByName={},this.mode=this.BOARD_MODE_NONE,this.updateQuality=this.BOARD_QUALITY_HIGH,this.isSuspendedRedraw=!1,this.calculateSnapSizes(),this.drag_dx=0,this.drag_dy=0,this.drag_position=[0,0],this.mouse={},this.touches=[],this.xmlString="",this.cPos=[],this.touchMoveLast=0,this.positionAccessLast=0,this.downObjects=[],this.attr.showcopyright&&this.renderer.displayCopyright(e.licenseText,parseInt(this.options.text.fontSize,10)),this.needsFullUpdate=!1,this.reducedUpdate=!1,this.currentCBDef="none",this.geonextCompatibilityMode=!1,this.options.text.useASCIIMathML&&translateASCIIMath?init():this.options.text.useASCIIMathML=!1,this.hasMouseHandlers=!1,this.hasTouchHandlers=!1,this.hasPointerHandlers=!1,this.hasMouseUp=!1,this.hasTouchEnd=!1,this.hasPointerUp=!1,this._drag_offset=[0,0],this._inputDevice="mouse",this._board_touches=[],this.selectingMode=!1,this.isSelecting=!1,this.selectingBox=[[0,0],[0,0]],this.mathLib=Math,this.mathLibJXG=t.Math,this.attr.registerevents&&this.addEventHandlers(),this.methodMap={update:"update",fullUpdate:"fullUpdate",on:"on",off:"off",trigger:"trigger",setView:"setBoundingBox",setBoundingBox:"setBoundingBox",migratePoint:"migratePoint",colorblind:"emulateColorblindness",suspendUpdate:"suspendUpdate",unsuspendUpdate:"unsuspendUpdate",clearTraces:"clearTraces",left:"clickLeftArrow",right:"clickRightArrow",up:"clickUpArrow",down:"clickDownArrow",zoomIn:"zoomIn",zoomOut:"zoomOut",zoom100:"zoom100",zoomElements:"zoomElements",remove:"removeObject",removeObject:"removeObject"}},t.extend(t.Board.prototype,{generateName:function(t){var i,r,s=this.attr.maxnamelength,o="",n="",a=[],h="";if(t.type===e.OBJECT_TYPE_TICKS)return"";for(i=u.isPoint(t)?["","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"]:t.type===e.OBJECT_TYPE_ANGLE?["","α","β","γ","δ","ε","ζ","η","θ","ι","κ","λ","μ","ν","ξ","ο","π","ρ","σ","τ","υ","φ","χ","ψ","ω"]:["","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"],u.isPoint(t)||t.elementClass===e.OBJECT_CLASS_LINE||t.type===e.OBJECT_TYPE_ANGLE||(o=t.type===e.OBJECT_TYPE_POLYGON?"P_{":t.elementClass===e.OBJECT_CLASS_CIRCLE?"k_{":t.elementClass===e.OBJECT_CLASS_TEXT?"t_{":"s_{",n="}"),r=0;r<s;r++)a[r]=0;for(;a[s-1]<i.length;){for(a[0]=1;a[0]<i.length;a[0]++){for(h=o,r=s;r>0;r--)h+=i[a[r-1]];if(!u.exists(this.elementsByName[h+n]))return h+n}for(a[0]=i.length,r=1;r<s;r++)a[r-1]===i.length&&(a[r-1]=1,a[r]+=1)}return""},generateId:function(){for(var e=1;u.exists(t.boards["jxgBoard"+e]);)e=Math.round(65535*Math.random());return"jxgBoard"+e},setId:function(t,e){var i,r=this.numObjects,s=t.id;if(this.numObjects+=1,""===s||!u.exists(s))for(s=this.id+e+r;u.exists(this.objects[s]);)i=Math.round(65535*Math.random()),s=this.id+e+r+"-"+i;return t.id=s,this.objects[s]=t,t._pos=this.objectsList.length,this.objectsList[this.objectsList.length]=t,s},finalizeAdding:function(t){!1===u.evaluate(t.visProp.visible)&&this.renderer.display(t,!1)},finalizeLabel:function(t){t.hasLabel&&!u.evaluate(t.label.visProp.islabel)&&!1===u.evaluate(t.label.visProp.visible)&&this.renderer.display(t.label,!1)},checkFrameRate:function(t){var e=(new Date).getTime();return!((e-this.touchMoveLast)*this.attr.maxframerate<1e3)&&(this.touchMoveLast=e,!0)},getCoordsTopLeftCorner:function(){var t,e,i,r,s,o=this.document.documentElement||this.document.body.parentNode,n=this.document.body,a=this.containerObj;if(this.cPos.length>0&&(this.mode===this.BOARD_MODE_DRAG||this.mode===this.BOARD_MODE_MOVE_ORIGIN||(new Date).getTime()-this.positionAccessLast<1e3))return this.cPos;if(this.positionAccessLast=(new Date).getTime(),a.getBoundingClientRect){for(i=a.getBoundingClientRect(),r=1,s=a;s&&u.exists(s.parentNode);)u.exists(s.style)&&u.exists(s.style.zoom)&&""!==s.style.zoom&&(r*=parseFloat(s.style.zoom)),s=s.parentNode;return t=[i.left*r,i.top*r],t[0]+=f.getProp(a,"border-left-width"),t[1]+=f.getProp(a,"border-top-width"),"vml"!==this.renderer.type&&(t[0]+=f.getProp(a,"padding-left"),t[1]+=f.getProp(a,"padding-top")),this.cPos=t.slice(),this.cPos}return t=f.getOffset(a),e=this.document.documentElement.ownerDocument,!this.containerObj.currentStyle&&e.defaultView&&(t[0]+=f.getProp(o,"margin-left"),t[1]+=f.getProp(o,"margin-top"),t[0]+=f.getProp(o,"border-left-width"),t[1]+=f.getProp(o,"border-top-width"),t[0]+=f.getProp(o,"padding-left"),t[1]+=f.getProp(o,"padding-top")),n&&(t[0]+=f.getProp(n,"left"),t[1]+=f.getProp(n,"top")),"object"==typeof google&&google.translate&&(t[0]+=10,t[1]+=25),t[0]+=f.getProp(a,"border-left-width"),t[1]+=f.getProp(a,"border-top-width"),"vml"!==this.renderer.type&&(t[0]+=f.getProp(a,"padding-left"),t[1]+=f.getProp(a,"padding-top")),t[0]+=this.attr.offsetx,t[1]+=this.attr.offsety,this.cPos=t.slice(),this.cPos},getMousePosition:function(t,e){var i,r,s=this.getCoordsTopLeftCorner();return i=f.getPosition(t,e,this.document),u.exists(this.cssTransMat)||this.updateCSSTransforms(),r=[1,i[0]-s[0],i[1]-s[1]],r=o.matVecMult(this.cssTransMat,r),r[1]/=r[0],r[2]/=r[0],[r[1],r[2]]},initMoveOrigin:function(t,e){this.drag_dx=t-this.origin.scrCoords[1],this.drag_dy=e-this.origin.scrCoords[2],this.mode=this.BOARD_MODE_MOVE_ORIGIN,this.updateQuality=this.BOARD_QUALITY_LOW},initMoveObject:function(t,i,r,s){var o,n,a,l=[],c=[],d=this.objectsList.length,p={visProp:{layer:-1e4}};for(n=0;n<d;n++)o=this.objectsList[n],a=o.hasPoint&&o.hasPoint(t,i),o.visPropCalc.visible&&a&&(o.triggerEventHandlers([s+"down","down"],[r]),this.downObjects.push(o)),a&&o.isDraggable&&o.visPropCalc.visible&&(this.geonextCompatibilityMode&&(u.isPoint(o)||o.elementClass===e.OBJECT_CLASS_TEXT)||!this.geonextCompatibilityMode)&&!u.evaluate(o.visProp.fixed)&&(o.visProp.layer>p.visProp.layer||o.visProp.layer===p.visProp.layer&&o.lastDragTime.getTime()>=p.lastDragTime.getTime())&&(this.attr.ignorelabels&&u.exists(p.label)&&o===p.label||(p=o,l.push(p),u.exists(p.coords)?c.push(h.subtract(p.coords.scrCoords.slice(1),[t,i])):c.push([0,0])));return this.attr.drag.enabled&&l.length>0&&(this.mode=this.BOARD_MODE_DRAG),this.attr.takefirst?(l.length=1,this._drag_offset=c[0]):(l=l.slice(-1),this._drag_offset=c[c.length-1]),this._drag_offset||(this._drag_offset=[0,0]),"svg"===this.renderer.type&&u.exists(l[0])&&u.evaluate(l[0].visProp.dragtotopoflayer)&&1===l.length&&u.exists(l[0].rendNode)&&l[0].rendNode.parentNode.appendChild(l[0].rendNode),this.previousRotation=0,this.previousScale=1,l.length>=1&&(l[0].highlight(!0),this.triggerEventHandlers(["mousehit","hit"],[r,l[0]])),l},moveObject:function(t,r,s,o,n){var a,l,c,d=new i(e.COORDS_BY_SCREEN,this.getScrCoordsOfMouse(t,r),this);s&&s.obj&&(a=s.obj,a.coords&&(l=a.coords.scrCoords.slice()),this.drag_position=[d.scrCoords[1],d.scrCoords[2]],this.drag_position=h.add(this.drag_position,this._drag_offset),u.exists(a.coords)?a.setPositionDirectly(e.COORDS_BY_SCREEN,this.drag_position):(this.displayInfobox(!1),isNaN(s.targets[0].Xprev+s.targets[0].Yprev)||a.setPositionDirectly(e.COORDS_BY_SCREEN,[d.scrCoords[1],d.scrCoords[2]],[s.targets[0].Xprev,s.targets[0].Yprev]),s.targets[0].Xprev=d.scrCoords[1],s.targets[0].Yprev=d.scrCoords[2]),u.exists(a.coords)&&(a.prepareUpdate().update(!1).updateRenderer(),this.updateInfobox(a),a.prepareUpdate().update(!0).updateRenderer()),a.coords&&(c=a.coords.scrCoords),a.coords&&l[1]===c[1]&&l[2]===c[2]||(a.triggerEventHandlers([n+"drag","drag"],[o]),this.update()),a.highlight(!0),this.triggerEventHandlers(["mousehit","hit"],[o,a]),a.lastDragTime=new Date)},twoFingerMove:function(t,r,s,o){var n,a,h;u.exists(s)&&u.exists(s.obj)&&(h=s.obj,n=new i(e.COORDS_BY_SCREEN,this.getScrCoordsOfMouse(t[0],t[1]),this),a=new i(e.COORDS_BY_SCREEN,this.getScrCoordsOfMouse(r[0],r[1]),this),h.elementClass===e.OBJECT_CLASS_LINE||h.type===e.OBJECT_TYPE_POLYGON?this.twoFingerTouchObject(n,a,s,h,o):h.elementClass===e.OBJECT_CLASS_CIRCLE&&this.twoFingerTouchCircle(n,a,s,h),h.triggerEventHandlers(["touchdrag","drag"],[o]),s.targets[0].Xprev=n.scrCoords[1],s.targets[0].Yprev=n.scrCoords[2],s.targets[1].Xprev=a.scrCoords[1],s.targets[1].Yprev=a.scrCoords[2])},twoFingerTouchObject:function(t,r,s,a,h){var l,c,d,p,f,m,g,b,v,y,C,_,P,E,x,S,w,O,T;if(u.exists(s.targets[0])&&u.exists(s.targets[1])&&!isNaN(s.targets[0].Xprev+s.targets[0].Yprev+s.targets[1].Xprev+s.targets[1].Yprev)){if(l=t.usrCoords,c=r.usrCoords,d=new i(e.COORDS_BY_SCREEN,[s.targets[0].Xprev,s.targets[0].Yprev],this).usrCoords,p=new i(e.COORDS_BY_SCREEN,[s.targets[1].Xprev,s.targets[1].Yprev],this).usrCoords,m=[1,.5*(d[1]+p[1]),.5*(d[2]+p[2])],f=[1,.5*(l[1]+c[1]),.5*(l[2]+c[2])],b=o.crossProduct(d,p),g=o.crossProduct(l,c),C=o.crossProduct(b,g),Math.abs(C[0])<o.eps)return;if(C[1]/=C[0],C[2]/=C[0],u.exists(h.rotation)&&"pointermove"!==h.type?(y=h.rotation-this.previousRotation,this.previousRotation=h.rotation,y*=-.017453292519943295):y=n.rad(m.slice(1),C.slice(1),f.slice(1)),_=this.create("transform",[y,C[1],C[2]],{type:"rotate"}),_.update(),m=o.matVecMult(_.matrix,m),m[1]/=m[0],m[2]/=m[0],P=this.create("transform",[f[1]-m[1],f[2]-m[2]],{type:"translate"}),P.update(),_.melt(P),u.evaluate(a.visProp.scalable)&&(u.exists(h.scale)?(v=h.scale/this.previousScale,this.previousScale=h.scale):v=n.distance(l,c)/n.distance(d,p),E=this.create("transform",[-f[1],-f[2]],{type:"translate"}),x=this.create("transform",[v,v],{type:"scale"}),S=this.create("transform",[f[1],f[2]],{type:"translate"}),_.melt(E).melt(x).melt(S)),a.elementClass===e.OBJECT_CLASS_LINE)w=[],a.point1.draggable()&&w.push(a.point1),a.point2.draggable()&&w.push(a.point2),_.applyOnce(w);else if(a.type===e.OBJECT_TYPE_POLYGON){for(w=[],T=a.vertices.length-1,O=0;O<T;++O)a.vertices[O].draggable()&&w.push(a.vertices[O]);_.applyOnce(w)}this.update(),a.highlight(!0)}},twoFingerTouchCircle:function(t,r,s,o){var a,h,l,c,d,p,f,m,g,b,v;"pointCircle"!==o.method&&"pointLine"!==o.method&&u.exists(s.targets[0])&&u.exists(s.targets[1])&&!isNaN(s.targets[0].Xprev+s.targets[0].Yprev+s.targets[1].Xprev+s.targets[1].Yprev)&&(a=t.usrCoords,h=r.usrCoords,l=new i(e.COORDS_BY_SCREEN,[s.targets[0].Xprev,s.targets[0].Yprev],this).usrCoords,c=new i(e.COORDS_BY_SCREEN,[s.targets[1].Xprev,s.targets[1].Yprev],this).usrCoords,f=this.create("transform",[a[1]-l[1],a[2]-l[2]],{type:"translate"}),p=n.rad(c.slice(1),a.slice(1),h.slice(1)),m=this.create("transform",[-a[1],-a[2]],{type:"translate"}),g=this.create("transform",[p],{type:"rotate"}),f.melt(m).melt(g),u.evaluate(o.visProp.scalable)&&(d=n.distance(a,h)/n.distance(l,c),b=this.create("transform",[d,d],{type:"scale"}),f.melt(b)),v=this.create("transform",[a[1],a[2]],{type:"translate"}),f.melt(v),o.center.draggable()&&f.applyOnce([o.center]),"twoPoints"===o.method?o.point2.draggable()&&f.applyOnce([o.point2]):"pointRadius"===o.method&&u.isNumber(o.updateRadius.origin)&&o.setRadius(o.radius*d),this.update(o.center),o.highlight(!0))},highlightElements:function(t,e,i,r){var s,o,n,a={},h=this.objectsList.length;for(s=0;s<h;s++)o=this.objectsList[s],n=o.id,u.exists(o.hasPoint)&&o.visPropCalc.visible&&o.hasPoint(t,e)&&(this.updateInfobox(o),u.exists(this.highlightedObjects[n])||(a[n]=o,o.highlight(),this.triggerEventHandlers(["mousehit","hit"],[i,o,r])),o.mouseover?o.triggerEventHandlers(["mousemove","move"],[i]):(o.triggerEventHandlers(["mouseover","over"],[i]),o.mouseover=!0));for(s=0;s<h;s++)o=this.objectsList[s],n=o.id,o.mouseover&&(a[n]||(o.triggerEventHandlers(["mouseout","out"],[i]),o.mouseover=!1))},saveStartPos:function(i,r){var s,o,n=[];if(i.type===e.OBJECT_TYPE_TICKS)n.push([1,NaN,NaN]);else if(i.elementClass===e.OBJECT_CLASS_LINE)n.push(i.point1.coords.usrCoords),n.push(i.point2.coords.usrCoords);else if(i.elementClass===e.OBJECT_CLASS_CIRCLE)n.push(i.center.coords.usrCoords),"twoPoints"===i.method&&n.push(i.point2.coords.usrCoords);else if(i.type===e.OBJECT_TYPE_POLYGON)for(o=i.vertices.length-1,s=0;s<o;s++)n.push(i.vertices[s].coords.usrCoords);else if(i.type===e.OBJECT_TYPE_SECTOR)n.push(i.point1.coords.usrCoords),n.push(i.point2.coords.usrCoords),n.push(i.point3.coords.usrCoords);else if(u.isPoint(i)||i.type===e.OBJECT_TYPE_GLIDER)n.push(i.coords.usrCoords);else if(i.elementClass===e.OBJECT_CLASS_CURVE)i.points.length>0&&n.push(i.points[0].usrCoords);else try{n.push(i.coords.usrCoords)}catch(e){t.debug("JSXGraph+ saveStartPos: obj.coords.usrCoords not available: "+e)}for(o=n.length,s=0;s<o;s++)r.Zstart.push(n[s][0]),r.Xstart.push(n[s][1]),r.Ystart.push(n[s][2])},mouseOriginMoveStart:function(t){var e,i;return e=this._isRequiredKeyPressed(t,"pan"),e&&(i=this.getMousePosition(t),this.initMoveOrigin(i[0],i[1])),e},mouseOriginMove:function(t){var e,i=this.mode===this.BOARD_MODE_MOVE_ORIGIN;return i&&(e=this.getMousePosition(t),this.moveOrigin(e[0],e[1],!0)),i},touchOriginMoveStart:function(e){var i,r,s=e[t.touchProperty];return i=this.attr.pan.enabled&&!this.attr.pan.needtwofingers&&1===s.length,i&&(r=this.getMousePosition(e,0),this.initMoveOrigin(r[0],r[1])),i},touchOriginMove:function(t){var e,i=this.mode===this.BOARD_MODE_MOVE_ORIGIN;return i&&(e=this.getMousePosition(t,0),this.moveOrigin(e[0],e[1],!0)),i},originMoveEnd:function(){this.updateQuality=this.BOARD_QUALITY_HIGH,this.mode=this.BOARD_MODE_NONE},addEventHandlers:function(){f.supportsPointerEvents()?this.addPointerEventHandlers():(this.addMouseEventHandlers(),this.addTouchEventHandlers()),null!==this.containerObj&&(this.containerObj.oncontextmenu=function(t){return u.exists(t)&&t.preventDefault(),!1}),this.addFullscreenEventHandlers()},addPointerEventHandlers:function(){!this.hasPointerHandlers&&f.isBrowser&&(window.navigator.msPointerEnabled?(f.addEvent(this.containerObj,"MSPointerDown",this.pointerDownListener,this),f.addEvent(this.containerObj,"MSPointerMove",this.pointerMoveListener,this)):(f.addEvent(this.containerObj,"pointerdown",this.pointerDownListener,this),f.addEvent(this.containerObj,"pointermove",this.pointerMoveListener,this)),f.addEvent(this.containerObj,"mousewheel",this.mouseWheelListener,this),f.addEvent(this.containerObj,"DOMMouseScroll",this.mouseWheelListener,this),null!==this.containerObj&&(this.containerObj.style.touchAction="none"),this.hasPointerHandlers=!0)},addMouseEventHandlers:function(){!this.hasMouseHandlers&&f.isBrowser&&(f.addEvent(this.containerObj,"mousedown",this.mouseDownListener,this),f.addEvent(this.containerObj,"mousemove",this.mouseMoveListener,this),f.addEvent(this.containerObj,"mousewheel",this.mouseWheelListener,this),f.addEvent(this.containerObj,"DOMMouseScroll",this.mouseWheelListener,this),this.hasMouseHandlers=!0)},addTouchEventHandlers:function(t){!this.hasTouchHandlers&&f.isBrowser&&(f.addEvent(this.containerObj,"touchstart",this.touchStartListener,this),f.addEvent(this.containerObj,"touchmove",this.touchMoveListener,this),this.hasTouchHandlers=!0)},addFullscreenEventHandlers:function(){var t,e=["fullscreenchange","mozfullscreenchange","webkitfullscreenchange","msfullscreenchange"],i=e.length;for(t=0;t<i;t++)f.addEvent(this.document,e[t],this.fullscreenListener,this);this.hasFullsceenEventHandlers=!0},removeFullscreenEventHandlers:function(){var t,e=["fullscreenchange","mozfullscreenchange","webkitfullscreenchange","msfullscreenchange"],i=e.length;if(this.hasFullsceenEventHandlers&&f.isBrowser)for(t=0;t<i;t++)f.removeEvent(this.document,e[t],this.fullscreenListener,this)},removePointerEventHandlers:function(){this.hasPointerHandlers&&f.isBrowser&&(window.navigator.msPointerEnabled?(f.removeEvent(this.containerObj,"MSPointerDown",this.pointerDownListener,this),f.removeEvent(this.containerObj,"MSPointerMove",this.pointerMoveListener,this)):(f.removeEvent(this.containerObj,"pointerdown",this.pointerDownListener,this),f.removeEvent(this.containerObj,"pointermove",this.pointerMoveListener,this)),f.removeEvent(this.containerObj,"mousewheel",this.mouseWheelListener,this),f.removeEvent(this.containerObj,"DOMMouseScroll",this.mouseWheelListener,this),this.hasPointerUp&&(window.navigator.msPointerEnabled?f.removeEvent(this.document,"MSPointerUp",this.pointerUpListener,this):f.removeEvent(this.document,"pointerup",this.pointerUpListener,this),this.hasPointerUp=!1),this.hasPointerHandlers=!1)},removeMouseEventHandlers:function(){this.hasMouseHandlers&&f.isBrowser&&(f.removeEvent(this.containerObj,"mousedown",this.mouseDownListener,this),f.removeEvent(this.containerObj,"mousemove",this.mouseMoveListener,this),this.hasMouseUp&&(f.removeEvent(this.document,"mouseup",this.mouseUpListener,this),this.hasMouseUp=!1),f.removeEvent(this.containerObj,"mousewheel",this.mouseWheelListener,this),f.removeEvent(this.containerObj,"DOMMouseScroll",this.mouseWheelListener,this),this.hasMouseHandlers=!1)},removeTouchEventHandlers:function(){this.hasTouchHandlers&&f.isBrowser&&(f.removeEvent(this.containerObj,"touchstart",this.touchStartListener,this),f.removeEvent(this.containerObj,"touchmove",this.touchMoveListener,this),this.hasTouchEnd&&(f.removeEvent(this.document,"touchend",this.touchEndListener,this),this.hasTouchEnd=!1),this.hasTouchHandlers=!1)},removeEventHandlers:function(){this.removeMouseEventHandlers(),this.removeTouchEventHandlers(),this.removePointerEventHandlers(),this.removeFullscreenEventHandlers()},clickLeftArrow:function(){return this.moveOrigin(this.origin.scrCoords[1]+.1*this.canvasWidth,this.origin.scrCoords[2]),this},clickRightArrow:function(){return this.moveOrigin(this.origin.scrCoords[1]-.1*this.canvasWidth,this.origin.scrCoords[2]),this},clickUpArrow:function(){return this.moveOrigin(this.origin.scrCoords[1],this.origin.scrCoords[2]-.1*this.canvasHeight),this},clickDownArrow:function(){return this.moveOrigin(this.origin.scrCoords[1],this.origin.scrCoords[2]+.1*this.canvasHeight),this},gestureChangeListener:function(t){var r,s,o,a,h,l,c,d,p,f,m=[],g=[],b=!1,v=this.attr.zoom.factorx,y=this.attr.zoom.factory;return this.mode!==this.BOARD_MODE_ZOOM||(t.preventDefault(),a=n.distance([t.touches[0].clientX,t.touches[0].clientY],[t.touches[1].clientX,t.touches[1].clientY],2),void 0===t.scale&&(t.scale=a/this.prevDist),!!u.exists(this.prevCoords)&&(m=[t.touches[0].clientX-this.prevCoords[0][0],t.touches[0].clientY-this.prevCoords[0][1]],g=[t.touches[1].clientX-this.prevCoords[1][0],t.touches[1].clientY-this.prevCoords[1][1]],!(m[0]*m[0]+m[1]*m[1]<100&&g[0]*g[0]+g[1]*g[1]<100)&&(s=n.rad(m,[0,0],g),"pan"!==this.isPreviousGesture&&Math.abs(s)>.2*Math.PI&&Math.abs(s)<1.8*Math.PI&&(b=!0),"pan"===this.isPreviousGesture||b||(Math.abs(t.scale)<.77||Math.abs(t.scale)>1.3)&&(b=!0),o=t.scale/this.prevScale,this.prevScale=t.scale,this.prevCoords=[[t.touches[0].clientX,t.touches[0].clientY],[t.touches[1].clientX,t.touches[1].clientY]],r=new i(e.COORDS_BY_SCREEN,this.getMousePosition(t,0),this),this.attr.pan.enabled&&this.attr.pan.needtwofingers&&!b?(this.isPreviousGesture="pan",this.moveOrigin(r.scrCoords[1],r.scrCoords[2],!0)):this.attr.zoom.enabled&&Math.abs(o-1)<.5&&((this.attr.zoom.pinchhorizontal||this.attr.zoom.pinchvertical)&&(h=Math.abs(t.touches[0].clientX-t.touches[1].clientX),l=Math.abs(t.touches[0].clientY-t.touches[1].clientY),c=Math.abs(Math.atan2(l,h)),f=Math.PI*this.attr.zoom.pinchsensitivity/90),this.attr.zoom.pinchhorizontal&&c<f?(this.attr.zoom.factorx=o,this.attr.zoom.factory=1,d=0,p=0):this.attr.zoom.pinchvertical&&Math.abs(c-.5*Math.PI)<f?(this.attr.zoom.factorx=1,this.attr.zoom.factory=o,d=0,p=0):(this.attr.zoom.factorx=o,this.attr.zoom.factory=o,d=r.usrCoords[1],p=r.usrCoords[2]),this.zoomIn(d,p),this.attr.zoom.factorx=v,this.attr.zoom.factory=y),!1)))},gestureStartListener:function(t){var e;return t.preventDefault(),this.prevScale=1,this.prevDist=n.distance([t.touches[0].clientX,t.touches[0].clientY],[t.touches[1].clientX,t.touches[1].clientY],2),this.prevCoords=[[t.touches[0].clientX,t.touches[0].clientY],[t.touches[1].clientX,t.touches[1].clientY]],this.isPreviousGesture="none",e=this.getMousePosition(t,0),this.initMoveOrigin(e[0],e[1]),this.mode=this.BOARD_MODE_ZOOM,!1},_isRequiredKeyPressed:function(t,e){var i=this.attr[e];return!!i.enabled&&!(!(i.needshift&&t.shiftKey||!i.needshift&&!t.shiftKey)||!(i.needctrl&&t.ctrlKey||!i.needctrl&&!t.ctrlKey))},_isPointerEventAlreadyThere:function(t){var e;for(e=0;e<this._board_touches.length;e++)if(this._board_touches[e].pointerId===t.pointerId)return!0;return!1},_pointerIsTouchRegistered:function(t){var e,i=this._board_touches.length;for(e=0;e<i;e++)if(this._board_touches[e].pointerId===t.pointerId)return!0;return!1},_pointerAddBoardTouches:function(t){var e,i;for(e=0,i=!1;e<this._board_touches.length;e++)if(this._board_touches[e].pointerId===t.pointerId){this._board_touches[e].clientX=t.clientX,this._board_touches[e].clientY=t.clientY,i=!0;break}return i||this._board_touches.push({pointerId:t.pointerId,clientX:t.clientX,clientY:t.clientY}),this},_pointerRemoveBoardTouches:function(t){var e;for(e=0;e<this._board_touches.length;e++)if(this._board_touches[e].pointerId===t.pointerId){this._board_touches.splice(e,1);break}return this},_getPointerInputDevice:function(t){if(f.isBrowser){if("touch"===t.pointerType||window.navigator.msMaxTouchPoints&&window.navigator.msMaxTouchPoints>1)return"touch";if("mouse"===t.pointerType)return"mouse";if("pen"===t.pointerType)return"pen"}return"mouse"},pointerDownListener:function(t,e){var i,r,s,o,n,a,h,l,c="mouse";if(!e&&this._isPointerEventAlreadyThere(t))return!1;if(this.hasPointerUp||(window.navigator.msPointerEnabled?f.addEvent(this.document,"MSPointerUp",this.pointerUpListener,this):f.addEvent(this.document,"pointerup",this.pointerUpListener,this),this.hasPointerUp=!0),this.hasMouseHandlers&&this.removeMouseEventHandlers(),this.hasTouchHandlers&&this.removeTouchEventHandlers(),this.document.selection&&u.isFunction(this.document.selection.empty))this.document.selection.empty();else if(window.getSelection&&(a=window.getSelection(),a.removeAllRanges))try{a.removeAllRanges()}catch(t){}if(this._inputDevice=this._getPointerInputDevice(t),c=this._inputDevice,this.options.precision.hasPoint=this.options.precision[c],o=this.getMousePosition(t),this._testForSelection(t),this.selectingMode)return this._startSelecting(o),void this.triggerEventHandlers(["touchstartselecting","pointerstartselecting","startselecting"],[t]);if(this.attr.drag.enabled&&e?(n=[e],this.mode=this.BOARD_MODE_DRAG):n=this.initMoveObject(o[0],o[1],t,c),n.length>0){for(l=n[n.length-1],h=!1,i=0;i<this.touches.length;i++)if(this.touches[i].obj===l){r=i,s=this.touches[i].targets.push({num:t.pointerId,X:o[0],Y:o[1],Xprev:NaN,Yprev:NaN,Xstart:[],Ystart:[],Zstart:[]})-1,h=!0;break}h||(s=0,r=this.touches.push({obj:l,targets:[{num:t.pointerId,X:o[0],Y:o[1],Xprev:NaN,Yprev:NaN,Xstart:[],Ystart:[],Zstart:[]}]})-1),this.dehighlightAll(),l.highlight(!0),this.saveStartPos(l,this.touches[r].targets[s]),t&&t.preventDefault?t.preventDefault():window.event&&(window.event.returnValue=!1)}return this.touches.length>0&&(t.preventDefault(),t.stopPropagation()),f.isBrowser&&"touch"!==this._getPointerInputDevice(t)?this.mode===this.BOARD_MODE_NONE&&this.mouseOriginMoveStart(t):(this._pointerAddBoardTouches(t),t.touches=this._board_touches,this.mode===this.BOARD_MODE_NONE&&this.touchOriginMoveStart(t)||this.mode!==this.BOARD_MODE_NONE&&this.mode!==this.BOARD_MODE_MOVE_ORIGIN||2!=t.touches.length||(this.mode===this.BOARD_MODE_MOVE_ORIGIN&&this.originMoveEnd(),this.gestureStartListener(t))),this.triggerEventHandlers(["touchstart","down","pointerdown","MSPointerDown"],[t]),!1},pointerOutListener:function(t){return(t.target===this.containerObj||"svg"===this.renderer.type&&t.target===this.renderer.foreignObjLayer)&&this.pointerUpListener(t),this.mode===this.BOARD_MODE_NONE},pointerMoveListener:function(t){var e,i,r,s="mouse";if("touch"===this._getPointerInputDevice(t)&&!this._pointerIsTouchRegistered(t))return this.BOARD_MODE_NONE;if(!this.checkFrameRate(t))return!1;if(this.mode!==this.BOARD_MODE_DRAG&&(this.dehighlightAll(),this.displayInfobox(!1)),this.mode!==this.BOARD_MODE_NONE&&(t.preventDefault(),t.stopPropagation()),this.updateQuality=this.BOARD_QUALITY_LOW,this._inputDevice=this._getPointerInputDevice(t),s=this._inputDevice,this.options.precision.hasPoint=this.options.precision[s],this.selectingMode)r=this.getMousePosition(t),this._moveSelecting(r),this.triggerEventHandlers(["touchmoveselecting","moveselecting","pointermoveselecting"],[t,this.mode]);else if(!this.mouseOriginMove(t))if(this.mode===this.BOARD_MODE_DRAG){for(e=0;e<this.touches.length;e++)for(i=0;i<this.touches[e].targets.length;i++)if(this.touches[e].targets[i].num===t.pointerId){1===this.touches[e].targets.length?(this.touches[e].targets[i].X=t.pageX,this.touches[e].targets[i].Y=t.pageY,r=this.getMousePosition(t),this.moveObject(r[0],r[1],this.touches[e],t,s)):2===this.touches[e].targets.length&&(this.touches[e].targets[i].X=t.pageX,this.touches[e].targets[i].Y=t.pageY,this.twoFingerMove(this.getMousePosition({clientX:this.touches[e].targets[0].X,clientY:this.touches[e].targets[0].Y}),this.getMousePosition({clientX:this.touches[e].targets[1].X,clientY:this.touches[e].targets[1].Y}),this.touches[e],t));break}}else"touch"===this._getPointerInputDevice(t)&&(this._pointerAddBoardTouches(t),2===this._board_touches.length&&(t.touches=this._board_touches,this.gestureChangeListener(t))),r=this.getMousePosition(t),this.highlightElements(r[0],r[1],t,-1);return this.triggerEventHandlers(["touchmove","move","pointermove","MSPointerMove"],[t,this.mode]),this.updateQuality=this.BOARD_QUALITY_HIGH,this.mode===this.BOARD_MODE_NONE},pointerUpListener:function(t){var e,i,r;if(this.triggerEventHandlers(["touchend","up","pointerup","MSPointerUp"],[t]),this.displayInfobox(!1),t)for(e=0;e<this.touches.length;e++)for(i=0;i<this.touches[e].targets.length;i++)if(this.touches[e].targets[i].num===t.pointerId){this.touches[e].targets.splice(i,1),0===this.touches[e].targets.length&&this.touches.splice(e,1);break}if(this.selectingMode)this._stopSelecting(t),this.triggerEventHandlers(["touchstopselecting","pointerstopselecting","stopselecting"],[t]);else for(e=this.downObjects.length-1;e>-1;e--){for(r=!1,i=0;i<this.touches.length;i++)this.touches[i].obj.id===this.downObjects[e].id&&(r=!0);r||(this.downObjects[e].triggerEventHandlers(["touchend","up","pointerup","MSPointerUp"],[t]),this.downObjects[e].snapToGrid(),this.downObjects[e].snapToPoints(),this.downObjects.splice(e,1))}return this._pointerRemoveBoardTouches(t),0===this._board_touches.length&&(this.hasPointerUp&&(window.navigator.msPointerEnabled?f.removeEvent(this.document,"MSPointerUp",this.pointerUpListener,this):f.removeEvent(this.document,"pointerup",this.pointerUpListener,this),this.hasPointerUp=!1),this.dehighlightAll(),this.updateQuality=this.BOARD_QUALITY_HIGH,this.mode=this.BOARD_MODE_NONE,this.originMoveEnd(),this.update()),!0},touchStartListener:function(i){var s,o,n,a,h,l,c,d,p,m=this.options.precision.touch,g=i[t.touchProperty];for(this.hasTouchEnd||(f.addEvent(this.document,"touchend",this.touchEndListener,this),this.hasTouchEnd=!0),this.document.selection&&u.isFunction(this.document.selection.empty)?this.document.selection.empty():window.getSelection&&window.getSelection().removeAllRanges(),this._inputDevice="touch",this.options.precision.hasPoint=this.options.precision.touch,s=0;s<g.length;s++)g[s].jxg_isused=!1;for(s=0;s<this.touches.length;s++)for(a=0;a<this.touches[s].targets.length;a++){this.touches[s].targets[a].num=-1,m=this.options.precision.touch;do{for(h=0;h<g.length;h++)if(Math.abs(Math.pow(g[h].screenX-this.touches[s].targets[a].X,2)+Math.pow(g[h].screenY-this.touches[s].targets[a].Y,2))<m*m){this.touches[s].targets[a].num=h,this.touches[s].targets[a].X=g[h].screenX,this.touches[s].targets[a].Y=g[h].screenY,g[h].jxg_isused=!0;break}m*=2}while(-1===this.touches[s].targets[a].num&&m<this.options.precision.touchMax);-1===this.touches[s].targets[a].num&&(t.debug("i couldn't find a targettouches for target no "+a+" on "+this.touches[s].obj.name+" ("+this.touches[s].obj.id+"). Removed the target."),t.debug("eps = "+m+", touchMax = "+r.precision.touchMax),this.touches[s].targets.splice(s,1))}for(s=0;s<g.length;s++)if(!g[s].jxg_isused){if(o=this.getMousePosition(i,s),this.selectingMode)return this._startSelecting(o),this.triggerEventHandlers(["touchstartselecting","startselecting"],[i]),i.preventDefault(),i.stopPropagation(),this.options.precision.hasPoint=this.options.precision.mouse,this.touches.length>0;if(n=this.initMoveObject(o[0],o[1],i,"touch"),0!==n.length)if(l=n[n.length-1],u.isPoint(l)||l.elementClass===e.OBJECT_CLASS_TEXT||l.type===e.OBJECT_TYPE_TICKS||l.type===e.OBJECT_TYPE_IMAGE)d=[{num:s,X:g[s].screenX,Y:g[s].screenY,Xprev:NaN,Yprev:NaN,Xstart:[],Ystart:[],Zstart:[]}],this.saveStartPos(l,d[0]),this.touches.push({obj:l,targets:d}),l.highlight(!0);else if(l.elementClass===e.OBJECT_CLASS_LINE||l.elementClass===e.OBJECT_CLASS_CIRCLE||l.elementClass===e.OBJECT_CLASS_CURVE||l.type===e.OBJECT_TYPE_POLYGON){for(c=!1,a=0;a<this.touches.length;a++)l.id===this.touches[a].obj.id&&(c=!0,1===this.touches[a].targets.length&&(p={num:s,X:g[s].screenX,Y:g[s].screenY,Xprev:NaN,Yprev:NaN,Xstart:[],Ystart:[],Zstart:[]},this.saveStartPos(l,p),this.touches[a].targets.push(p)),g[s].jxg_isused=!0);c||(d=[{num:s,X:g[s].screenX,Y:g[s].screenY,Xprev:NaN,Yprev:NaN,Xstart:[],Ystart:[],Zstart:[]}],this.saveStartPos(l,d[0]),this.touches.push({obj:l,targets:d}),l.highlight(!0))}g[s].jxg_isused=!0}return this.touches.length>0&&(i.preventDefault(),i.stopPropagation()),this.mode===this.BOARD_MODE_NONE&&this.touchOriginMoveStart(i)||2!==g.length||this.mode!==this.BOARD_MODE_NONE&&this.mode!==this.BOARD_MODE_MOVE_ORIGIN||(this.mode===this.BOARD_MODE_MOVE_ORIGIN&&this.originMoveEnd(),this.gestureStartListener(i)),this.options.precision.hasPoint=this.options.precision.mouse,this.triggerEventHandlers(["touchstart","down"],[i]),!1},touchMoveListener:function(e){var i,r,s,o=e[t.touchProperty];if(!this.checkFrameRate(e))return!1;if(this.mode!==this.BOARD_MODE_NONE&&(e.preventDefault(),e.stopPropagation()),this.mode!==this.BOARD_MODE_DRAG&&(this.dehighlightAll(),this.displayInfobox(!1)),this._inputDevice="touch",this.options.precision.hasPoint=this.options.precision.touch,this.updateQuality=this.BOARD_QUALITY_LOW,this.selectingMode){for(i=0;i<o.length;i++)if(!o[i].jxg_isused){r=this.getMousePosition(e,i),this._moveSelecting(r),this.triggerEventHandlers(["touchmoves","moveselecting"],[e,this.mode]);break}}else if(!this.touchOriginMove(e))if(this.mode===this.BOARD_MODE_DRAG){for(i=0;i<this.touches.length;i++)if(1===this.touches[i].targets.length){if(o[this.touches[i].targets[0].num]){if(r=this.getMousePosition(e,this.touches[i].targets[0].num),r[0]<0||r[0]>this.canvasWidth||r[1]<0||r[1]>this.canvasHeight)return;this.touches[i].targets[0].X=o[this.touches[i].targets[0].num].screenX,this.touches[i].targets[0].Y=o[this.touches[i].targets[0].num].screenY,this.moveObject(r[0],r[1],this.touches[i],e,"touch")}}else if(2===this.touches[i].targets.length&&this.touches[i].targets[0].num>-1&&this.touches[i].targets[1].num>-1&&o[this.touches[i].targets[0].num]&&o[this.touches[i].targets[1].num]){if(r=this.getMousePosition(e,this.touches[i].targets[0].num),s=this.getMousePosition(e,this.touches[i].targets[1].num),r[0]<0||r[0]>this.canvasWidth||r[1]<0||r[1]>this.canvasHeight||s[0]<0||s[0]>this.canvasWidth||s[1]<0||s[1]>this.canvasHeight)return;this.touches[i].targets[0].X=o[this.touches[i].targets[0].num].screenX,this.touches[i].targets[0].Y=o[this.touches[i].targets[0].num].screenY, -this.touches[i].targets[1].X=o[this.touches[i].targets[1].num].screenX,this.touches[i].targets[1].Y=o[this.touches[i].targets[1].num].screenY,this.twoFingerMove(r,s,this.touches[i],e)}}else 2===o.length&&this.gestureChangeListener(e),r=this.getMousePosition(e,0),this.highlightElements(r[0],r[1],e,-1);return this.mode!==this.BOARD_MODE_DRAG&&this.displayInfobox(!1),this.triggerEventHandlers(["touchmove","move"],[e,this.mode]),this.options.precision.hasPoint=this.options.precision.mouse,this.updateQuality=this.BOARD_QUALITY_HIGH,this.mode===this.BOARD_MODE_NONE},touchEndListener:function(i){var r,s,o,n,a,h=this.options.precision.touch,l=[],c=i&&i[t.touchProperty];if(this.triggerEventHandlers(["touchend","up"],[i]),this.displayInfobox(!1),this.selectingMode)this._stopSelecting(i),this.triggerEventHandlers(["touchstopselecting","stopselecting"],[i]);else if(c&&c.length>0){for(r=0;r<this.touches.length;r++)l[r]=this.touches[r];for(this.touches.length=0,r=0;r<c.length;r++)c[r].jxg_isused=!1;for(r=0;r<l.length;r++){for(n=!1,a=0,s=0;s<l[r].targets.length;s++)for(l[r].targets[s].found=!1,o=0;o<c.length;o++)if(Math.abs(Math.pow(c[o].screenX-l[r].targets[s].X,2)+Math.pow(c[o].screenY-l[r].targets[s].Y,2))<h*h){l[r].targets[s].found=!0,l[r].targets[s].num=o,l[r].targets[s].X=c[o].screenX,l[r].targets[s].Y=c[o].screenY,a+=1;break}if(u.isPoint(l[r].obj)?n=l[r].targets[0]&&l[r].targets[0].found:l[r].obj.elementClass===e.OBJECT_CLASS_LINE?n=l[r].targets[0]&&l[r].targets[0].found||l[r].targets[1]&&l[r].targets[1].found:l[r].obj.elementClass===e.OBJECT_CLASS_CIRCLE&&(n=1===a||3===a),n)for(this.touches.push({obj:l[r].obj,targets:[]}),s=0;s<l[r].targets.length;s++)l[r].targets[s].found&&this.touches[this.touches.length-1].targets.push({num:l[r].targets[s].num,X:l[r].targets[s].screenX,Y:l[r].targets[s].screenY,Xprev:NaN,Yprev:NaN,Xstart:l[r].targets[s].Xstart,Ystart:l[r].targets[s].Ystart,Zstart:l[r].targets[s].Zstart});else l[r].obj.noHighlight()}}else this.touches.length=0;for(r=this.downObjects.length-1;r>-1;r--){for(n=!1,s=0;s<this.touches.length;s++)this.touches[s].obj.id===this.downObjects[r].id&&(n=!0);n||(this.downObjects[r].triggerEventHandlers(["touchup","up"],[i]),this.downObjects[r].snapToGrid(),this.downObjects[r].snapToPoints(),this.downObjects.splice(r,1))}return c&&0!==c.length||(this.hasTouchEnd&&(f.removeEvent(this.document,"touchend",this.touchEndListener,this),this.hasTouchEnd=!1),this.dehighlightAll(),this.updateQuality=this.BOARD_QUALITY_HIGH,this.originMoveEnd(),this.update()),!0},mouseDownListener:function(t){var e,i,r;if(this.document.selection&&u.isFunction(this.document.selection.empty)?this.document.selection.empty():window.getSelection&&window.getSelection().removeAllRanges(),!this.hasMouseUp)return f.addEvent(this.document,"mouseup",this.mouseUpListener,this),this.hasMouseUp=!0,this._inputDevice="mouse",this.options.precision.hasPoint=this.options.precision.mouse,e=this.getMousePosition(t),this._testForSelection(t),this.selectingMode?(this._startSelecting(e),void this.triggerEventHandlers(["mousestartselecting","startselecting"],[t])):(i=this.initMoveObject(e[0],e[1],t,"mouse"),0===i.length?(this.mode=this.BOARD_MODE_NONE,r=!0):(this.mouse={obj:null,targets:[{X:e[0],Y:e[1],Xprev:NaN,Yprev:NaN}]},this.mouse.obj=i[i.length-1],this.dehighlightAll(),this.mouse.obj.highlight(!0),this.mouse.targets[0].Xstart=[],this.mouse.targets[0].Ystart=[],this.mouse.targets[0].Zstart=[],this.saveStartPos(this.mouse.obj,this.mouse.targets[0]),t&&t.preventDefault?t.preventDefault():window.event&&(window.event.returnValue=!1)),this.mode===this.BOARD_MODE_NONE&&(r=this.mouseOriginMoveStart(t)),this.triggerEventHandlers(["mousedown","down"],[t]),r)},mouseMoveListener:function(t){var e;if(!this.checkFrameRate(t))return!1;e=this.getMousePosition(t),this.updateQuality=this.BOARD_QUALITY_LOW,this.mode!==this.BOARD_MODE_DRAG&&(this.dehighlightAll(),this.displayInfobox(!1)),this.selectingMode?(this._moveSelecting(e),this.triggerEventHandlers(["mousemoveselecting","moveselecting"],[t,this.mode])):this.mouseOriginMove(t)||(this.mode===this.BOARD_MODE_DRAG?this.moveObject(e[0],e[1],this.mouse,t,"mouse"):this.highlightElements(e[0],e[1],t,-1),this.triggerEventHandlers(["mousemove","move"],[t,this.mode])),this.updateQuality=this.BOARD_QUALITY_HIGH},mouseUpListener:function(t){var e;if(!1===this.selectingMode&&this.triggerEventHandlers(["mouseup","up"],[t]),this.updateQuality=this.BOARD_QUALITY_HIGH,this.mouse&&this.mouse.obj&&(this.mouse.obj.snapToGrid(this.mouse.targets[0]),this.mouse.obj.snapToPoints()),this.originMoveEnd(),this.dehighlightAll(),this.update(),this.selectingMode)this._stopSelecting(t),this.triggerEventHandlers(["mousestopselecting","stopselecting"],[t]);else for(e=0;e<this.downObjects.length;e++)this.downObjects[e].triggerEventHandlers(["mouseup","up"],[t]);this.downObjects.length=0,this.hasMouseUp&&(f.removeEvent(this.document,"mouseup",this.mouseUpListener,this),this.hasMouseUp=!1),this.mouse=null},mouseWheelListener:function(t){if(!this.attr.zoom.wheel||!this._isRequiredKeyPressed(t,"zoom"))return!0;t=t||window.event;var r=t.detail?-t.detail:t.wheelDelta/40,s=new i(e.COORDS_BY_SCREEN,this.getMousePosition(t),this);return r>0?this.zoomIn(s.usrCoords[1],s.usrCoords[2]):this.zoomOut(s.usrCoords[1],s.usrCoords[2]),this.triggerEventHandlers(["mousewheel"],[t]),t.preventDefault(),!1},initInfobox:function(){var t=u.copyAttributes({},this.options,"infobox");return t.id=this.id+"_infobox",this.infobox=this.create("text",[0,0,"0,0"],t),this.infobox.distanceX=-20,this.infobox.distanceY=25,this.infobox.dump=!1,this.displayInfobox(!1),this},updateInfobox:function(t){var e,i,r,s,o,n=u.evaluate(t.visProp.showinfobox);return!u.evaluate(this.attr.showinfobox)&&"inherit"===n||!n?this:(u.isPoint(t)&&(r=t.coords.usrCoords[1],s=t.coords.usrCoords[2],o=u.evaluate(t.visProp.infoboxdigits),this.infobox.setCoords(r+this.infobox.distanceX/this.unitX,s+this.infobox.distanceY/this.unitY),"string"!=typeof t.infoboxText?("auto"===o?(e=u.autoDigits(r),i=u.autoDigits(s)):u.isNumber(o)?(e=u.toFixed(r,o),i=u.toFixed(s,o)):(e=r,i=s),this.highlightInfobox(e,i,t)):this.highlightCustomInfobox(t.infoboxText,t),this.displayInfobox(!0)),this)},displayInfobox:function(t){return this.infobox.hiddenByParent==t&&(this.infobox.hiddenByParent=!t,this.infobox.prepareUpdate().updateVisibility(t).updateRenderer()),this},showInfobox:function(t){return this.displayInfobox(t)},highlightInfobox:function(t,e,i){return this.highlightCustomInfobox("("+t+", "+e+")",i),this},highlightCustomInfobox:function(t,e){return this.infobox.setText(t),this},dehighlightAll:function(){var t,e,i=!1;for(t in this.highlightedObjects)this.highlightedObjects.hasOwnProperty(t)&&(e=this.highlightedObjects[t],(this.hasMouseHandlers||this.hasPointerHandlers)&&e.noHighlight(),i=!0);return this.highlightedObjects={},"canvas"===this.renderer.type&&i&&(this.prepareUpdate(),this.renderer.suspendRedraw(this),this.updateRenderer(),this.renderer.unsuspendRedraw()),this},getScrCoordsOfMouse:function(t,e){return[t,e]},getUsrCoordsOfMouse:function(t){var r=this.getCoordsTopLeftCorner(),s=f.getPosition(t,null,this.document),o=s[0]-r[0],n=s[1]-r[1];return new i(e.COORDS_BY_SCREEN,[o,n],this).usrCoords.slice(1)},getAllUnderMouse:function(t){var e=this.getAllObjectsUnderMouse(t);return e.push(this.getUsrCoordsOfMouse(t)),e},getAllObjectsUnderMouse:function(t){var e,i,r=this.getCoordsTopLeftCorner(),s=f.getPosition(t,null,this.document),o=s[0]-r[0],n=s[1]-r[1],a=[],h=this.objectsList.length;for(e=0;e<h;e++)i=this.objectsList[e],i.visPropCalc.visible&&i.hasPoint&&i.hasPoint(o,n)&&(a[a.length]=i);return a},updateCoords:function(){var t,e,i=this.objectsList.length;for(e=0;e<i;e++)t=this.objectsList[e],u.exists(t.coords)&&(u.evaluate(t.visProp.frozen)?t.coords.screen2usr():t.coords.usr2screen());return this},moveOrigin:function(t,r,s){var o,n,a,h;return u.exists(t)&&u.exists(r)&&(o=this.origin.scrCoords[1],n=this.origin.scrCoords[2],this.origin.scrCoords[1]=t,this.origin.scrCoords[2]=r,s&&(this.origin.scrCoords[1]-=this.drag_dx,this.origin.scrCoords[2]-=this.drag_dy),a=new i(e.COORDS_BY_SCREEN,[0,0],this).usrCoords,h=new i(e.COORDS_BY_SCREEN,[this.canvasWidth,this.canvasHeight],this).usrCoords,(a[1]<this.maxboundingbox[0]||a[2]>this.maxboundingbox[1]||h[1]>this.maxboundingbox[2]||h[2]<this.maxboundingbox[3])&&(this.origin.scrCoords[1]=o,this.origin.scrCoords[2]=n)),this.updateCoords().clearTraces().fullUpdate(),this.triggerEventHandlers(["boundingbox"]),this},addConditions:function(i){var r,s,o,n,a,h,l,c=[],p="var el, x, y, c, rgbo;\n",f=i.indexOf("<data>"),m=i.indexOf("</data>"),g=function(t,i,r,s){return function(){var o,n;o=t.select(i.id),n=o.coords.usrCoords[s],2===s?o.setPositionDirectly(e.COORDS_BY_USER,[r(),n]):o.setPositionDirectly(e.COORDS_BY_USER,[n,r()]),o.prepareUpdate().update()}},b=function(t,e,i,r){return function(){var s,o;s=t.select(e.id),o=i(),"strokewidth"===r?s.visProp.strokewidth=o:(o=d.rgba2rgbo(o),s.visProp[r+"color"]=o[0],s.visProp[r+"opacity"]=o[1])}};if(!(f<0)){for(;f>=0;){if(r=i.slice(f+6,m),s=r.indexOf("="),o=r.slice(0,s),n=r.slice(s+1),s=o.indexOf("."),a=o.slice(0,s),h=this.elementsByName[u.unescapeHTML(a)],l=o.slice(s+1).replace(/\s+/g,"").toLowerCase(),n=u.createFunction(n,this,"",!0),u.exists(this.elementsByName[a]))switch(p+='el = this.objects["'+h.id+'"];\n',l){case"x":c.push(g(this,h,n,2));break;case"y":c.push(g(this,h,n,1));break;case"visible":c.push(function(t,e,i){return function(){var r,s;r=t.select(e.id),s=i(),r.setAttribute({visible:s})}}(this,h,n));break;case"position":c.push(function(t,e,i){return function(){t.select(e.id).position=i()}}(this,h,n));break;case"stroke":c.push(b(this,h,n,"stroke"));break;case"style":c.push(function(t,e,i){return function(){t.select(e.id).setStyle(i())}}(this,h,n));break;case"strokewidth":c.push(b(this,h,n,"strokewidth"));break;case"fill":c.push(b(this,h,n,"fill"));break;case"label":break;default:t.debug("property '"+l+"' in conditions not yet implemented:"+n)}else t.debug("debug conditions: |"+a+"| undefined");i=i.slice(m+7),f=i.indexOf("<data>"),m=i.indexOf("</data>")}this.updateConditions=function(){var t;for(t=0;t<c.length;t++)c[t]();return this.prepareUpdate().updateElements(),!0},this.updateConditions()}},updateConditions:function(){return!1},calculateSnapSizes:function(){var t=new i(e.COORDS_BY_USER,[0,0],this),r=new i(e.COORDS_BY_USER,[this.options.grid.gridX,this.options.grid.gridY],this),s=t.scrCoords[1]-r.scrCoords[1],o=t.scrCoords[2]-r.scrCoords[2];for(this.options.grid.snapSizeX=this.options.grid.gridX;Math.abs(s)>25;)this.options.grid.snapSizeX*=2,s/=2;for(this.options.grid.snapSizeY=this.options.grid.gridY;Math.abs(o)>25;)this.options.grid.snapSizeY*=2,o/=2;return this},applyZoom:function(){return this.updateCoords().calculateSnapSizes().clearTraces().fullUpdate(),this},zoomIn:function(t,e){var i=this.getBoundingBox(),r=this.attr.zoom.factorx,s=this.attr.zoom.factory,o=(i[2]-i[0])*(1-1/r),n=(i[1]-i[3])*(1-1/s),a=.5,h=.5,l=this.attr.zoom.eps||this.attr.zoom.min||.001;return this.zoomX>this.attr.zoom.max&&r>1||this.zoomY>this.attr.zoom.max&&s>1||this.zoomX<l&&r<1||this.zoomY<l&&s<1?this:(u.isNumber(t)&&u.isNumber(e)&&(a=(t-i[0])/(i[2]-i[0]),h=(i[1]-e)/(i[1]-i[3])),this.setBoundingBox([i[0]+o*a,i[1]-n*h,i[2]-o*(1-a),i[3]+n*(1-h)],!1),this.zoomX*=r,this.zoomY*=s,this.applyZoom())},zoomOut:function(t,e){var i=this.getBoundingBox(),r=this.attr.zoom.factorx,s=this.attr.zoom.factory,o=(i[2]-i[0])*(1-r),n=(i[1]-i[3])*(1-s),a=.5,h=.5,l=this.attr.zoom.eps||this.attr.zoom.min||.001;return this.zoomX<l||this.zoomY<l?this:(u.isNumber(t)&&u.isNumber(e)&&(a=(t-i[0])/(i[2]-i[0]),h=(i[1]-e)/(i[1]-i[3])),this.setBoundingBox([i[0]+o*a,i[1]-n*h,i[2]-o*(1-a),i[3]+n*(1-h)],!1),this.zoomX/=r,this.zoomY/=s,this.applyZoom())},zoom100:function(){var t=this.getBoundingBox(),e=(t[2]-t[0])*(1-this.zoomX)*.5,i=(t[1]-t[3])*(1-this.zoomY)*.5;return this.setBoundingBox([t[0]+e,t[1]-i,t[2]-e,t[3]+i],!1),this.zoomX=1,this.zoomY=1,this.applyZoom()},zoomAllPoints:function(){var t,e,i,r,s,o=0,n=0,a=0,h=0,l=this.objectsList.length;for(t=0;t<l;t++)s=this.objectsList[t],u.isPoint(s)&&s.visPropCalc.visible&&(s.coords.usrCoords[1]<o?o=s.coords.usrCoords[1]:s.coords.usrCoords[1]>n&&(n=s.coords.usrCoords[1]),s.coords.usrCoords[2]>h?h=s.coords.usrCoords[2]:s.coords.usrCoords[2]<a&&(a=s.coords.usrCoords[2]));return e=50,i=e/this.unitX,r=e/this.unitY,this.zoomX=1,this.zoomY=1,this.setBoundingBox([o-i,h+r,n+i,a-r],!0),this.applyZoom()},zoomElements:function(t){var e,i,r,s,o,n,a,h,l=[1/0,-1/0,-1/0,1/0];if(!u.isArray(t)||0===t.length)return this;for(e=0;e<t.length;e++)i=this.select(t[e]),r=i.bounds(),u.isArray(r)&&(r[0]<l[0]&&(l[0]=r[0]),r[1]>l[1]&&(l[1]=r[1]),r[2]>l[2]&&(l[2]=r[2]),r[3]<l[3]&&(l[3]=r[3]));return u.isArray(l)&&(this.zoomX=1,this.zoomY=1,s=.5*(l[0]+l[2]),o=.5*(l[1]+l[3]),n=1.5*(l[2]-l[0])*.5,a=1.5*(l[1]-l[3])*.5,h=Math.max(n,a),this.setBoundingBox([s-h,o+h,s+h,o-h],!0)),this},zoomElementsOld:function(t){var e,i,r,s,o=[0,0,0,0],n=[1,-1,-1,1];if(!u.isArray(t)||0===t.length)return this;for(e=0;e<t.length;e++)if(r=this.select(t[e]),s=r.bounds(),u.isArray(s))if(u.isArray(o))for(i=0;i<4;i++)n[i]*s[i]<n[i]*o[i]&&(o[i]=s[i]);else o=s;if(u.isArray(o)){for(i=0;i<4;i++)o[i]-=n[i];this.zoomX=1,this.zoomY=1,this.setBoundingBox(o,!0)}return this},setZoom:function(t,e){var i=this.attr.zoom.factorx,r=this.attr.zoom.factory;return this.attr.zoom.factorx=t/this.zoomX,this.attr.zoom.factory=e/this.zoomY,this.zoomIn(),this.attr.zoom.factorx=i,this.attr.zoom.factory=r,this},removeObject:function(i,r){var s,o;if(u.isArray(i)){for(o=0;o<i.length;o++)this.removeObject(i[o]);return this}if(i=this.select(i),!u.exists(i)||u.isString(i))return this;try{for(s in i.childElements)i.childElements.hasOwnProperty(s)&&i.childElements[s].board.removeObject(i.childElements[s]);for(s in i.objects)i.objects.hasOwnProperty(s)&&i.objects[s].board.removeObject(i.objects[s]);if(r)for(s in this.objects)this.objects.hasOwnProperty(s)&&u.exists(this.objects[s].childElements)&&u.exists(this.objects[s].childElements.hasOwnProperty(i.id))&&(delete this.objects[s].childElements[i.id],delete this.objects[s].descendants[i.id]);else if(u.exists(i.ancestors))for(s in i.ancestors)i.ancestors.hasOwnProperty(s)&&u.exists(i.ancestors[s].childElements)&&u.exists(i.ancestors[s].childElements.hasOwnProperty(i.id))&&(delete i.ancestors[s].childElements[i.id],delete i.ancestors[s].descendants[i.id]);if(i._pos>-1)for(this.objectsList.splice(i._pos,1),s=i._pos;s<this.objectsList.length;s++)this.objectsList[s]._pos--;else i.type!==e.OBJECT_TYPE_TURTLE&&t.debug("Board.removeObject: object "+i.id+" not found in list.");delete this.objects[i.id],delete this.elementsByName[i.name],i.visProp&&u.evaluate(i.visProp.trace)&&i.clearTrace(),u.exists(i.remove)&&i.remove()}catch(e){t.debug(i.id+": Could not be removed: "+e)}return this.update(),this},removeAncestors:function(t){var e;for(e in t.ancestors)t.ancestors.hasOwnProperty(e)&&this.removeAncestors(t.ancestors[e]);return this.removeObject(t),this},initGeonextBoard:function(){var t,e,i;return t=this.create("point",[0,0],{id:this.id+"g00e0",name:"Ursprung",withLabel:!1,visible:!1,fixed:!0}),e=this.create("point",[1,0],{id:this.id+"gX0e0",name:"Punkt_1_0",withLabel:!1,visible:!1,fixed:!0}),i=this.create("point",[0,1],{id:this.id+"gY0e0",name:"Punkt_0_1",withLabel:!1,visible:!1,fixed:!0}),this.create("line",[t,e],{id:this.id+"gXLe0",name:"X-Achse",withLabel:!1,visible:!1}),this.create("line",[t,i],{id:this.id+"gYLe0",name:"Y-Achse",withLabel:!1,visible:!1}),this},resizeContainer:function(t,e,i,r){var s;return r||(s=this.getBoundingBox()),this.canvasWidth=parseInt(t,10),this.canvasHeight=parseInt(e,10),i||(this.containerObj.style.width=this.canvasWidth+"px",this.containerObj.style.height=this.canvasHeight+"px"),this.renderer.resize(this.canvasWidth,this.canvasHeight),r||this.setBoundingBox(s,this.keepaspectratio),this},showDependencies:function(){var t,e,i,r,s;e="<p>\n";for(t in this.objects)if(this.objects.hasOwnProperty(t)){s=0;for(i in this.objects[t].childElements)this.objects[t].childElements.hasOwnProperty(i)&&(s+=1);s>=0&&(e+="<strong>"+this.objects[t].id+":</strong> ");for(i in this.objects[t].childElements)this.objects[t].childElements.hasOwnProperty(i)&&(e+=this.objects[t].childElements[i].id+"("+this.objects[t].childElements[i].name+"), ");e+="<p>\n"}return e+="</p>\n",r=window.open(),r.document.open(),r.document.write(e),r.document.close(),this},showXML:function(){var t=window.open("");return t.document.open(),t.document.write("<pre>"+u.escapeHTML(this.xmlString)+"</pre>"),t.document.close(),this},prepareUpdate:function(){var t,e,i=this.objectsList.length;for(t=0;t<i;t++)e=this.objectsList[t],e.needsUpdate=e.needsRegularUpdate||this.needsFullUpdate;for(t in this.groups)this.groups.hasOwnProperty(t)&&(e=this.groups[t],e.needsUpdate=e.needsRegularUpdate||this.needsFullUpdate);return this},updateElements:function(t){var e,i;for(t=this.select(t),e=0;e<this.objectsList.length;e++)i=this.objectsList[e],i.update(!u.exists(t)||i.id!==t.id).updateVisibility();for(e in this.groups)this.groups.hasOwnProperty(e)&&this.groups[e].update(t);return this},updateRenderer:function(){var t,e=this.objectsList.length;if("canvas"===this.renderer.type)this.updateRendererCanvas();else for(t=0;t<e;t++)this.objectsList[t].updateRenderer();return this},updateRendererCanvas:function(){var t,e,i,r,s,o=this.objectsList.length,n=this.options.layer,a=this.options.layer.numlayers,h=Number.NEGATIVE_INFINITY;for(i=0;i<a;i++){r=Number.POSITIVE_INFINITY;for(s in n)n.hasOwnProperty(s)&&n[s]>h&&n[s]<r&&(r=n[s]);for(h=r,t=0;t<o;t++)e=this.objectsList[t],e.visProp.layer===r&&e.prepareUpdate().updateRenderer()}return this},addHook:function(e,i,r){return t.deprecated("Board.addHook()","Board.on()"),i=u.def(i,"update"),r=u.def(r,this),this.hooks.push([i,e]),this.on(i,e,r),this.hooks.length-1},addEvent:t.shortcut(t.Board.prototype,"on"),removeHook:function(e){return t.deprecated("Board.removeHook()","Board.off()"),this.hooks[e]&&(this.off(this.hooks[e][0],this.hooks[e][1]),this.hooks[e]=null),this},removeEvent:t.shortcut(t.Board.prototype,"off"),updateHooks:function(e){var i=Array.prototype.slice.call(arguments,0);return t.deprecated("Board.updateHooks()","Board.triggerEventHandlers()"),i[0]=u.def(i[0],"update"),this.triggerEventHandlers([i[0]],arguments),this},addChild:function(t){return u.exists(t)&&u.exists(t.containerObj)&&(this.dependentBoards.push(t),this.update()),this},removeChild:function(t){var e;for(e=this.dependentBoards.length-1;e>=0;e--)this.dependentBoards[e]===t&&this.dependentBoards.splice(e,1);return this},update:function(t){var e,i,r,s;if(this.inUpdate||this.isSuspendedUpdate)return this;for(this.inUpdate=!0,"all"===this.attr.minimizereflow&&this.containerObj&&"vml"!==this.renderer.type&&(s=this.renderer.removeToInsertLater(this.containerObj)),"svg"===this.attr.minimizereflow&&"svg"===this.renderer.type&&(s=this.renderer.removeToInsertLater(this.renderer.svgRoot)),this.prepareUpdate().updateElements(t).updateConditions(),this.renderer.suspendRedraw(this),this.updateRenderer(),this.renderer.unsuspendRedraw(),this.triggerEventHandlers(["update"],[]),s&&s(),i=this.dependentBoards.length,e=0;e<i;e++)r=this.dependentBoards[e],u.exists(r)&&r!==this&&(r.updateQuality=this.updateQuality,r.prepareUpdate().updateElements().updateConditions(),r.renderer.suspendRedraw(),r.updateRenderer(),r.renderer.unsuspendRedraw(),r.triggerEventHandlers(["update"],[]));return this.inUpdate=!1,this},fullUpdate:function(){return this.needsFullUpdate=!0,this.update(),this.needsFullUpdate=!1,this},addGrid:function(){return this.create("grid",[]),this},removeGrids:function(){var t;for(t=0;t<this.grids.length;t++)this.removeObject(this.grids[t]);return this.grids.length=0,this.update(),this},create:function(e,i,r){var s,o;for(e=e.toLowerCase(),u.exists(i)||(i=[]),u.exists(r)||(r={}),o=0;o<i.length;o++)u.isString(i[o])&&("text"!==e||2!==o)&&("input"!==e&&"checkbox"!==e&&"button"!==e||2!==o&&3!==o)&&(i[o]=this.select(i[o]));if(!u.isFunction(t.elements[e]))throw new Error("JSXGraph: create: Unknown element type given: "+e);return s=t.elements[e](this,i,r),u.exists(s)?(s.prepareUpdate&&s.update&&s.updateRenderer&&s.fullUpdate(),s):(t.debug("JSXGraph: create: failure creating "+e),s)},createElement:function(){return t.deprecated("Board.createElement()","Board.create()"),this.create.apply(this,arguments)},clearTraces:function(){var t;for(t=0;t<this.objectsList.length;t++)this.objectsList[t].clearTrace();return this.numTraces=0,this},suspendUpdate:function(){return this.inUpdate||(this.isSuspendedUpdate=!0),this},unsuspendUpdate:function(){return this.isSuspendedUpdate&&(this.isSuspendedUpdate=!1,this.fullUpdate()),this},setBoundingBox:function(t,e){var i,r,s=f.getDimensions(this.container,this.document);return u.isArray(t)?t[0]<this.maxboundingbox[0]||t[1]>this.maxboundingbox[1]||t[2]>this.maxboundingbox[2]||t[3]<this.maxboundingbox[3]?this:(this.plainBB=t,this.canvasWidth=parseInt(s.width,10),this.canvasHeight=parseInt(s.height,10),r=this.canvasWidth,i=this.canvasHeight,e?(this.unitX=r/(t[2]-t[0]),this.unitY=i/(t[1]-t[3]),Math.abs(this.unitX)<Math.abs(this.unitY)?this.unitY=Math.abs(this.unitX)*this.unitY/Math.abs(this.unitY):this.unitX=Math.abs(this.unitY)*this.unitX/Math.abs(this.unitX),this.keepaspectratio=!0):(this.unitX=r/(t[2]-t[0]),this.unitY=i/(t[1]-t[3]),this.keepaspectratio=!1),this.moveOrigin(-this.unitX*t[0],this.unitY*t[1]),this):this},getBoundingBox:function(){var t=new i(e.COORDS_BY_SCREEN,[0,0],this).usrCoords,r=new i(e.COORDS_BY_SCREEN,[this.canvasWidth,this.canvasHeight],this).usrCoords;return[t[1],t[2],r[1],r[2]]},addAnimation:function(t){var e=this;return this.animationObjects[t.id]=t,this.animationIntervalCode||(this.animationIntervalCode=window.setInterval(function(){e.animate()},t.board.attr.animationdelay)),this},stopAllAnimation:function(){var t;for(t in this.animationObjects)this.animationObjects.hasOwnProperty(t)&&u.exists(this.animationObjects[t])&&(this.animationObjects[t]=null,delete this.animationObjects[t]);return window.clearInterval(this.animationIntervalCode),delete this.animationIntervalCode,this},animate:function(){var t,i,r,s,o,n,a,h,l=0,c=null;for(i in this.animationObjects)if(this.animationObjects.hasOwnProperty(i)&&u.exists(this.animationObjects[i])){if(l+=1,r=this.animationObjects[i],r.animationPath&&(s=u.isFunction(r.animationPath)?r.animationPath((new Date).getTime()-r.animationStart):r.animationPath.pop(),!u.exists(s)||!u.isArray(s)&&isNaN(s)?delete r.animationPath:(r.setPositionDirectly(e.COORDS_BY_USER,s),r.fullUpdate(),c=r)),r.animationData){a=0;for(o in r.animationData)r.animationData.hasOwnProperty(o)&&(n=r.animationData[o].pop(),u.exists(n)?(a+=1,t={},t[o]=n,r.setAttribute(t)):delete r.animationData[n]);0===a&&delete r.animationData}u.exists(r.animationData)||u.exists(r.animationPath)||(this.animationObjects[i]=null,delete this.animationObjects[i],u.exists(r.animationCallback)&&(h=r.animationCallback,r.animationCallback=null,h()))}return 0===l?(window.clearInterval(this.animationIntervalCode),delete this.animationIntervalCode):this.update(c),this},migratePoint:function(t,e,i){var r,s,o,n,a,h,l=!1;t=this.select(t),e=this.select(e),u.exists(t.label)&&(h=t.label.id,l=!0,this.removeObject(t.label));for(s in t.childElements)if(t.childElements.hasOwnProperty(s)){r=t.childElements[s],n=!1;for(o in r)r.hasOwnProperty(o)&&r[o]===t&&(r[o]=e,n=!0);for(n&&delete t.childElements[s],a=0;a<r.parents.length;a++)r.parents[a]===t.id&&(r.parents[a]=e.id);e.addChild(r)}return i&&(l&&(delete e.childElements[h],delete e.descendants[h]),e.label&&this.removeObject(e.label),delete this.elementsByName[e.name],e.name=t.name,l&&e.createLabel()),this.removeObject(t),u.exists(e.name)&&""!==e.name&&(this.elementsByName[e.name]=e),this.fullUpdate(),this},emulateColorblindness:function(e){var i,r;if(u.exists(e)||(e="none"),this.currentCBDef===e)return this;for(i in this.objects)this.objects.hasOwnProperty(i)&&(r=this.objects[i],"none"!==e?("none"===this.currentCBDef&&(r.visPropOriginal={strokecolor:r.visProp.strokecolor,fillcolor:r.visProp.fillcolor,highlightstrokecolor:r.visProp.highlightstrokecolor,highlightfillcolor:r.visProp.highlightfillcolor}),r.setAttribute({strokecolor:d.rgb2cb(u.evaluate(r.visPropOriginal.strokecolor),e),fillcolor:d.rgb2cb(u.evaluate(r.visPropOriginal.fillcolor),e),highlightstrokecolor:d.rgb2cb(u.evaluate(r.visPropOriginal.highlightstrokecolor),e),highlightfillcolor:d.rgb2cb(u.evaluate(r.visPropOriginal.highlightfillcolor),e)})):u.exists(r.visPropOriginal)&&t.extend(r.visProp,r.visPropOriginal));return this.currentCBDef=e,this.update(),this},select:function(t,e){var i,r,s,o,n=t;if(null===n)return n;if(u.isString(n)&&""!==n)u.exists(this.objects[n])?n=this.objects[n]:u.exists(this.elementsByName[n])?n=this.elementsByName[n]:u.exists(this.groups[n])&&(n=this.groups[n]);else if(!e&&(u.isFunction(n)||u.isObject(n)&&!u.isFunction(n.setAttribute))){for(i=u.filterElements(this.objectsList,n),r={},o=i.length,s=0;s<o;s++)r[i[s].id]=i[s];n=new C(r)}else u.isObject(n)&&u.exists(n.id)&&!u.exists(this.objects[n.id])&&(n=null);return n},hasPoint:function(t,e){var i=t,r=e,s=this.getBoundingBox();return u.exists(t)&&u.isArray(t.usrCoords)&&(i=t.usrCoords[1],r=t.usrCoords[2]),!!(u.isNumber(i)&&u.isNumber(r)&&s[0]<i&&i<s[2]&&s[1]>r&&r>s[3])},updateCSSTransforms:function(){var t=this.containerObj,e=t,i=t;for(this.cssTransMat=f.getCSSTransformMatrix(e),e=e.offsetParent;e;){for(this.cssTransMat=o.matMatMult(f.getCSSTransformMatrix(e),this.cssTransMat),i=i.parentNode;i!==e;)this.cssTransMat=o.matMatMult(f.getCSSTransformMatrix(e),this.cssTransMat),i=i.parentNode;e=e.offsetParent}return this.cssTransMat=o.inverse(this.cssTransMat),this},startSelectionMode:function(){this.selectingMode=!0,this.selectionPolygon.setAttribute({visible:!0}),this.selectingBox=[[0,0],[0,0]],this._setSelectionPolygonFromBox(),this.selectionPolygon.fullUpdate()},stopSelectionMode:function(){return this.selectingMode=!1,this.selectionPolygon.setAttribute({visible:!1}),[this.selectionPolygon.vertices[0].coords,this.selectionPolygon.vertices[2].coords]},_startSelecting:function(t){this.isSelecting=!0,this.selectingBox=[[t[0],t[1]],[t[0],t[1]]],this._setSelectionPolygonFromBox()},_moveSelecting:function(t){this.isSelecting&&(this.selectingBox[1]=[t[0],t[1]],this._setSelectionPolygonFromBox(),this.selectionPolygon.fullUpdate())},_stopSelecting:function(t){var e=this.getMousePosition(t);this.isSelecting=!1,this.selectingBox[1]=[e[0],e[1]],this._setSelectionPolygonFromBox()},_setSelectionPolygonFromBox:function(){var e=this.selectingBox[0],i=this.selectingBox[1];this.selectionPolygon.vertices[0].setPositionDirectly(t.COORDS_BY_SCREEN,[e[0],e[1]]),this.selectionPolygon.vertices[1].setPositionDirectly(t.COORDS_BY_SCREEN,[e[0],i[1]]),this.selectionPolygon.vertices[2].setPositionDirectly(t.COORDS_BY_SCREEN,[i[0],i[1]]),this.selectionPolygon.vertices[3].setPositionDirectly(t.COORDS_BY_SCREEN,[i[0],e[1]])},_testForSelection:function(t){this._isRequiredKeyPressed(t,"selection")&&(u.exists(this.selectionPolygon)||this._createSelectionPolygon(this.attr),this.startSelectionMode())},_createSelectionPolygon:function(t){var e;return u.exists(this.selectionPolygon)||(e=u.copyAttributes(t,r,"board","selection"),!0===e.enabled&&(this.selectionPolygon=this.create("polygon",[[0,0],[0,0],[0,0],[0,0]],e))),this},__evt__down:function(t){},__evt__mousedown:function(t){},__evt__pendown:function(t){},__evt__pointerdown:function(t){},__evt__touchstart:function(t){},__evt__up:function(t){},__evt__mouseup:function(t){},__evt__pointerup:function(t){},__evt__touchend:function(t){},__evt__move:function(t,e){},__evt__mousemove:function(t,e){},__evt__penmove:function(t,e){},__evt__pointermove:function(t,e){},__evt__touchmove:function(t,e){},__evt__hit:function(t,e,i){},__evt__mousehit:function(t,e,i){},__evt__update:function(){},__evt__boundingbox:function(){},__evt__startselecting:function(){},__evt__mousestartselecting:function(){},__evt__pointerstartselecting:function(){},__evt__touchstartselecting:function(){},__evt__stopselecting:function(){},__evt__mousestopselecting:function(){},__evt__pointerstopselecting:function(){},__evt__touchstopselecting:function(){},__evt__moveselecting:function(){},__evt__mousemoveselecting:function(){},__evt__pointermoveselecting:function(){},__evt__touchmoveselecting:function(){},__evt:function(){},toFullscreen:function(){var t,e=this.container,i="fullscreenwrap_"+e,r=document.createElement("div");return this.document.getElementById(i)||(r.classList.add("JXG_wrap_private"),r.setAttribute("id",i),t=this.containerObj,t.parentNode.insertBefore(r,t),r.appendChild(t)),f.toFullscreen(i,e),this},fullscreenListener:function(t){this.updateCSSTransforms()},createRoulette:function(t,e,i,r,o,n,h){var l=this;return new function(){var c,d=0,u=0,p=0,f=i,m=s.root(function(i){var r=t.X(f),s=t.Y(f),o=e.X(i),n=e.Y(i);return(r-o)*(r-o)+(s-n)*(s-n)},[0,2*Math.PI]),g=0,b=0,v=l.create("transform",[function(){return d}],{type:"rotate"}),y=l.create("transform",[function(){return d},function(){return t.X(f)},function(){return t.Y(f)}],{type:"rotate"}),C=l.create("transform",[function(){return u},function(){return p}],{type:"translate"}),_=function(t,e,i){var r=s.D(t.X)(e),o=s.D(t.Y)(e),n=s.D(t.X)(i),a=s.D(t.Y)(i),h=s.D(t.X)(.5*(e+i)),l=s.D(t.Y)(.5*(e+i)),c=Math.sqrt(r*r+o*o),d=Math.sqrt(n*n+a*a);return(c+4*Math.sqrt(h*h+l*l)+d)*(i-e)/6},P=function(t){return c-_(e,m,t)},E=Math.PI/18,x=9*E,S=null;return this.rolling=function(){var i,n,S,w,O;g=f+o*r,c=_(t,f,g),b=s.root(P,m),i=new a(t.X(g),t.Y(g)),n=new a(e.X(b),e.Y(b)),S=new a(s.D(t.X)(g),s.D(t.Y)(g)),w=new a(s.D(e.X)(b),s.D(e.Y)(b)),O=a.C.div(S,w),d=Math.atan2(O.imaginary,O.real),O.div(a.C.abs(O)),O.mult(n),u=i.real-O.real,p=i.imaginary-O.imaginary,d<-E&&d>-x?(d=-E,y.applyOnce(h)):d>E&&d<x?(d=E,y.applyOnce(h)):(v.applyOnce(h),C.applyOnce(h),f=g,m=b),l.update()},this.start=function(){return n>0&&(S=window.setInterval(this.rolling,n)),this},this.stop=function(){return window.clearInterval(S),this},this}}}),t.Board}),define("renderer/svg",["jxg","options","renderer/abstract","base/constants","utils/type","utils/color","utils/base64","math/numerics"],function(t,e,i,r,s,o,n,a){"use strict";return t.SVGRenderer=function(t,i){var r;for(this.type="svg",this.isIE=-1!==navigator.appVersion.indexOf("MSIE")||navigator.userAgent.match(/Trident\//),this.svgRoot=null,this.svgNamespace="http://www.w3.org/2000/svg",this.xlinkNamespace="http://www.w3.org/1999/xlink",this.container=t,this.container.style.MozUserSelect="none",this.container.style.userSelect="none",this.container.style.overflow="hidden",""===this.container.style.position&&(this.container.style.position="relative"),this.svgRoot=this.container.ownerDocument.createElementNS(this.svgNamespace,"svg"),this.svgRoot.style.overflow="hidden",this.resize(i.width,i.height),this.container.appendChild(this.svgRoot),this.defs=this.container.ownerDocument.createElementNS(this.svgNamespace,"defs"),this.svgRoot.appendChild(this.defs),this.filter=this.container.ownerDocument.createElementNS(this.svgNamespace,"filter"),this.filter.setAttributeNS(null,"id",this.container.id+"_f1"),this.filter.setAttributeNS(null,"width","300%"),this.filter.setAttributeNS(null,"height","300%"),this.filter.setAttributeNS(null,"filterUnits","userSpaceOnUse"),this.feOffset=this.container.ownerDocument.createElementNS(this.svgNamespace,"feOffset"),this.feOffset.setAttributeNS(null,"result","offOut"),this.feOffset.setAttributeNS(null,"in","SourceAlpha"),this.feOffset.setAttributeNS(null,"dx","5"),this.feOffset.setAttributeNS(null,"dy","5"),this.filter.appendChild(this.feOffset),this.feGaussianBlur=this.container.ownerDocument.createElementNS(this.svgNamespace,"feGaussianBlur"),this.feGaussianBlur.setAttributeNS(null,"result","blurOut"), -this.feGaussianBlur.setAttributeNS(null,"in","offOut"),this.feGaussianBlur.setAttributeNS(null,"stdDeviation","3"),this.filter.appendChild(this.feGaussianBlur),this.feBlend=this.container.ownerDocument.createElementNS(this.svgNamespace,"feBlend"),this.feBlend.setAttributeNS(null,"in","SourceGraphic"),this.feBlend.setAttributeNS(null,"in2","blurOut"),this.feBlend.setAttributeNS(null,"mode","normal"),this.filter.appendChild(this.feBlend),this.defs.appendChild(this.filter),this.layer=[],r=0;r<e.layer.numlayers;r++)this.layer[r]=this.container.ownerDocument.createElementNS(this.svgNamespace,"g"),this.svgRoot.appendChild(this.layer[r]);this.supportsForeignObject=document.implementation.hasFeature("http://w3.org/TR/SVG11/feature#Extensibility","1.1"),this.supportsForeignObject&&(this.foreignObjLayer=this.container.ownerDocument.createElementNS(this.svgNamespace,"foreignObject"),this.foreignObjLayer.setAttribute("x",0),this.foreignObjLayer.setAttribute("y",0),this.foreignObjLayer.setAttribute("width","100%"),this.foreignObjLayer.setAttribute("height","100%"),this.foreignObjLayer.setAttribute("id",this.container.id+"_foreignObj"),this.svgRoot.appendChild(this.foreignObjLayer)),this.dashArray=["2, 2","5, 5","10, 10","20, 20","20, 10, 10, 10","20, 5, 10, 5"]},t.SVGRenderer.prototype=new i,t.extend(t.SVGRenderer.prototype,{_createArrowHead:function(e,i){var o,n,a,h,l=e.id+"Triangle",c=null,d=s.evaluate(e.visProp.firstarrow),u=s.evaluate(e.visProp.lastarrow);return s.exists(i)&&(l+=i),o=this.createPrim("marker",l),o.setAttributeNS(null,"stroke",s.evaluate(e.visProp.strokecolor)),o.setAttributeNS(null,"stroke-opacity",s.evaluate(e.visProp.strokeopacity)),o.setAttributeNS(null,"fill",s.evaluate(e.visProp.strokecolor)),o.setAttributeNS(null,"fill-opacity",s.evaluate(e.visProp.strokeopacity)),o.setAttributeNS(null,"stroke-width",0),o.setAttributeNS(null,"orient","auto"),o.setAttributeNS(null,"markerUnits","strokeWidth"),n=this.container.ownerDocument.createElementNS(this.svgNamespace,"path"),h=5,"End"===i?(t.exists(d.type)&&(c=s.evaluate(d.type)),a=0,2===c?n.setAttributeNS(null,"d","M 10,0 L 0,5 L 10,10 L 5,5 z"):3===c?n.setAttributeNS(null,"d","M 0,0 L 3.33,0 L 3.33,10 L 0,10 z"):4===c?(h=3.31,n.setAttributeNS(null,"d","M 0.00,3.31 C 3.53,3.84 7.13,4.50 10.00,6.63 C 9.33,5.52 8.67,4.42 8.00,3.31 C 8.67,2.21 9.33,1.10 10.00,0.00 C 7.13,2.13 3.53,2.79 0.00,3.31")):5===c?(h=3.28,n.setAttributeNS(null,"d","M 0.00,3.28 C 3.39,4.19 6.81,5.07 10.00,6.55 C 9.38,5.56 9.00,4.44 9.00,3.28 C 9.00,2.11 9.38,0.99 10.00,0.00 C 6.81,1.49 3.39,2.37 0.00,3.28")):6===c?(h=2.84,n.setAttributeNS(null,"d","M 0.00,2.84 C 3.39,3.59 6.79,4.35 10.00,5.68 C 9.67,4.73 9.33,3.78 9.00,2.84 C 9.33,1.89 9.67,0.95 10.00,0.00 C 6.79,1.33 3.39,2.09 0.00,2.84")):n.setAttributeNS(null,"d","M 10,0 L 0,5 L 10,10 z"),e.elementClass===r.OBJECT_CLASS_LINE&&(a=2===c?4.9:3===c?3.3:4===c||5===c||6===c?6.66:10)):(t.exists(u.type)&&(c=s.evaluate(u.type)),a=10,2===c?n.setAttributeNS(null,"d","M 0,0 L 10,5 L 0,10 L 5,5 z"):3===c?(a=3.3,n.setAttributeNS(null,"d","M 0,0 L 3.33,0 L 3.33,10 L 0,10 z")):4===c?(h=3.31,n.setAttributeNS(null,"d","M 10.00,3.31 C 6.47,3.84 2.87,4.50 0.00,6.63 C 0.67,5.52 1.33,4.42 2.00,3.31 C 1.33,2.21 0.67,1.10 0.00,0.00 C 2.87,2.13 6.47,2.79 10.00,3.31")):5===c?(h=3.28,n.setAttributeNS(null,"d","M 10.00,3.28 C 6.61,4.19 3.19,5.07 0.00,6.55 C 0.62,5.56 1.00,4.44 1.00,3.28 C 1.00,2.11 0.62,0.99 0.00,0.00 C 3.19,1.49 6.61,2.37 10.00,3.28")):6===c?(h=2.84,n.setAttributeNS(null,"d","M 10.00,2.84 C 6.61,3.59 3.21,4.35 0.00,5.68 C 0.33,4.73 0.67,3.78 1.00,2.84 C 0.67,1.89 0.33,0.95 0.00,0.00 C 3.21,1.33 6.61,2.09 10.00,2.84")):n.setAttributeNS(null,"d","M 0,0 L 10,5 L 0,10 z"),e.elementClass===r.OBJECT_CLASS_LINE&&(a=2===c?5.1:3===c?.02:4===c||5===c||6===c?3.33:.05)),o.setAttributeNS(null,"refY",h),o.setAttributeNS(null,"refX",a),o.appendChild(n),o},_setArrowColor:function(t,e,i,r){t&&(s.isString(e)&&this._setAttribute(function(){t.setAttributeNS(null,"stroke",e),t.setAttributeNS(null,"fill",e),t.setAttributeNS(null,"stroke-opacity",i),t.setAttributeNS(null,"fill-opacity",i)},r.visPropOld.fillcolor),this.isIE&&r.rendNode.parentNode.insertBefore(r.rendNode,r.rendNode))},_setArrowWidth:function(t,e,i,r){var s,o;t&&(s=e,o=s*r,t.setAttributeNS(null,"viewBox","0 0 "+10*s+" "+10*s),t.setAttributeNS(null,"markerHeight",o),t.setAttributeNS(null,"markerWidth",o),t.setAttributeNS(null,"display","inherit"),this.isIE&&i.parentNode.insertBefore(i,i))},shortenPath:function(t,e,i){var r,o;if((0!==e||0!==i)&&s.exists(t.getTotalLength))try{r=t.getTotalLength(),o=r-e-i,t.style.strokeDasharray=o+" "+e+" "+o+" "+i,t.style.strokeDashoffset=o}catch(t){}},updateTicks:function(t){var e,i,r,o,n,a,h,l,c="",d=t.ticks.length,u=!0;for(e=0;e<d;e++){for(r=t.ticks[e],n=r[0],a=r[1],h=n.length,l=" M "+n[0]+" "+a[0],s.isNumber(n[0])||(u=!1),i=1;u&&i<h;++i)s.isNumber(n[i])?l+=" L "+n[i]+" "+a[i]:u=!1;u&&(c+=l)}o=t.rendNode,s.exists(o)||(o=this.createPrim("path",t.id),this.appendChildPrim(o,s.evaluate(t.visProp.layer)),t.rendNode=o),o.setAttributeNS(null,"stroke",s.evaluate(t.visProp.strokecolor)),o.setAttributeNS(null,"fill","none"),o.setAttributeNS(null,"stroke-opacity",s.evaluate(t.visProp.strokeopacity)),o.setAttributeNS(null,"stroke-width",s.evaluate(t.visProp.strokewidth)),this.updatePathPrim(o,c,t.board)},displayCopyright:function(t,e){var i,r=this.createPrim("text","licenseText");r.setAttributeNS(null,"x","20px"),r.setAttributeNS(null,"y",2+e+"px"),r.setAttributeNS(null,"style","font-family:Arial,Helvetica,sans-serif; font-size:"+e+"px; fill:#356AA0; opacity:0.3;"),i=this.container.ownerDocument.createTextNode(t),r.appendChild(i),this.appendChildPrim(r,0)},drawInternalText:function(t){var e=this.createPrim("text",t.id);return e.style.whiteSpace="nowrap",t.rendNodeText=this.container.ownerDocument.createTextNode(""),e.appendChild(t.rendNodeText),this.appendChildPrim(e,s.evaluate(t.visProp.layer)),e},updateInternalText:function(t){var e,i=t.plaintext,r=t.getAnchorX(),o=t.getAnchorY();t.rendNode.getAttributeNS(null,"class")!==t.visProp.cssclass&&(t.rendNode.setAttributeNS(null,"class",s.evaluate(t.visProp.cssclass)),t.needsSizeUpdate=!0),isNaN(t.coords.scrCoords[1]+t.coords.scrCoords[2])||(e=t.coords.scrCoords[1],t.visPropOld.left!==r+e&&(t.rendNode.setAttributeNS(null,"x",e+"px"),"left"===r?t.rendNode.setAttributeNS(null,"text-anchor","start"):"right"===r?t.rendNode.setAttributeNS(null,"text-anchor","end"):"middle"===r&&t.rendNode.setAttributeNS(null,"text-anchor","middle"),t.visPropOld.left=r+e),e=t.coords.scrCoords[2],t.visPropOld.top!==o+e&&(t.rendNode.setAttributeNS(null,"y",e+.5*this.vOffsetText+"px"),"bottom"===o?t.rendNode.setAttributeNS(null,"dominant-baseline","text-after-edge"):"top"===o?t.rendNode.setAttributeNS(null,"dy","1.6ex"):"middle"===o&&t.rendNode.setAttributeNS(null,"dy","0.6ex"),t.visPropOld.top=o+e)),t.htmlStr!==i&&(t.rendNodeText.data=i,t.htmlStr=i),this.transformImage(t,t.transformations)},updateInternalTextStyle:function(t,e,i,r){this.setObjectFillColor(t,e,i)},drawImage:function(t){var e=this.createPrim("image",t.id);e.setAttributeNS(null,"preserveAspectRatio","none"),this.appendChildPrim(e,s.evaluate(t.visProp.layer)),t.rendNode=e,this.updateImage(t)},transformImage:function(t,e){var i,r,s=t.rendNode,o="";e.length>0&&(r=this.joinTransforms(t,e),i=[r[1][1],r[2][1],r[1][2],r[2][2],r[1][0],r[2][0]].join(","),o+=" matrix("+i+") ",s.setAttributeNS(null,"transform",o))},updateImageURL:function(t){var e=s.evaluate(t.url);return t._src!==e&&(t.imgIsLoaded=!1,t.rendNode.setAttributeNS(this.xlinkNamespace,"xlink:href",e),t._src=e,!0)},updateImageStyle:function(t,e){var i=s.evaluate(e?t.visProp.highlightcssclass:t.visProp.cssclass);t.rendNode.setAttributeNS(null,"class",i)},appendChildPrim:function(t,i){return s.exists(i)?i>=e.layer.numlayers&&(i=e.layer.numlayers-1):i=0,this.layer[i].appendChild(t),t},createPrim:function(t,e){var i=this.container.ownerDocument.createElementNS(this.svgNamespace,t);return i.setAttributeNS(null,"id",this.container.id+"_"+e),i.style.position="absolute","path"===t&&(i.setAttributeNS(null,"stroke-linecap","round"),i.setAttributeNS(null,"stroke-linejoin","round")),i},remove:function(t){s.exists(t)&&s.exists(t.parentNode)&&t.parentNode.removeChild(t)},setLayer:function(t,i){s.exists(i)?i>=e.layer.numlayers&&(i=e.layer.numlayers-1):i=0,this.layer[i].appendChild(t.rendNode)},makeArrows:function(t){var e,i=s.evaluate(t.visProp.firstarrow),r=s.evaluate(t.visProp.lastarrow);if(t.visPropOld.firstarrow===i&&t.visPropOld.lastarrow===r)return void(this.isIE&&t.visPropCalc.visible&&(i||r)&&t.rendNode.parentNode.insertBefore(t.rendNode,t.rendNode));i?(e=t.rendNodeTriangleStart,s.exists(e)?this.defs.appendChild(e):(e=this._createArrowHead(t,"End"),this.defs.appendChild(e),t.rendNodeTriangleStart=e,t.rendNode.setAttributeNS(null,"marker-start","url(#"+this.container.id+"_"+t.id+"TriangleEnd)"))):(e=t.rendNodeTriangleStart,s.exists(e)&&this.remove(e)),r?(e=t.rendNodeTriangleEnd,s.exists(e)?this.defs.appendChild(e):(e=this._createArrowHead(t,"Start"),this.defs.appendChild(e),t.rendNodeTriangleEnd=e,t.rendNode.setAttributeNS(null,"marker-end","url(#"+this.container.id+"_"+t.id+"TriangleStart)"))):(e=t.rendNodeTriangleEnd,s.exists(e)&&this.remove(e)),t.visPropOld.firstarrow=i,t.visPropOld.lastarrow=r},updateEllipsePrim:function(t,e,i,r,s){var o=1e6;o=2e5,e=Math.abs(e)<o?e:o*e/Math.abs(e),i=Math.abs(i)<o?i:o*i/Math.abs(i),r=Math.abs(r)<o?r:o*r/Math.abs(r),s=Math.abs(s)<o?s:o*s/Math.abs(s),t.setAttributeNS(null,"cx",e),t.setAttributeNS(null,"cy",i),t.setAttributeNS(null,"rx",Math.abs(r)),t.setAttributeNS(null,"ry",Math.abs(s))},updateLinePrim:function(t,e,i,r,s){var o=1e6;o=2e5,isNaN(e+i+r+s)||(e=Math.abs(e)<o?e:o*e/Math.abs(e),i=Math.abs(i)<o?i:o*i/Math.abs(i),r=Math.abs(r)<o?r:o*r/Math.abs(r),s=Math.abs(s)<o?s:o*s/Math.abs(s),t.setAttributeNS(null,"x1",e),t.setAttributeNS(null,"y1",i),t.setAttributeNS(null,"x2",r),t.setAttributeNS(null,"y2",s))},updatePathPrim:function(t,e){""===e&&(e="M 0 0"),t.setAttributeNS(null,"d",e)},updatePathStringPoint:function(t,e,i){var r="",s=t.coords.scrCoords,o=e*Math.sqrt(3)*.5,n=.5*e;return"x"===i?r=" M "+(s[1]-e)+" "+(s[2]-e)+" L "+(s[1]+e)+" "+(s[2]+e)+" M "+(s[1]+e)+" "+(s[2]-e)+" L "+(s[1]-e)+" "+(s[2]+e):"+"===i?r=" M "+(s[1]-e)+" "+s[2]+" L "+(s[1]+e)+" "+s[2]+" M "+s[1]+" "+(s[2]-e)+" L "+s[1]+" "+(s[2]+e):"<>"===i?r=" M "+(s[1]-e)+" "+s[2]+" L "+s[1]+" "+(s[2]+e)+" L "+(s[1]+e)+" "+s[2]+" L "+s[1]+" "+(s[2]-e)+" Z ":"^"===i?r=" M "+s[1]+" "+(s[2]-e)+" L "+(s[1]-o)+" "+(s[2]+n)+" L "+(s[1]+o)+" "+(s[2]+n)+" Z ":"v"===i?r=" M "+s[1]+" "+(s[2]+e)+" L "+(s[1]-o)+" "+(s[2]-n)+" L "+(s[1]+o)+" "+(s[2]-n)+" Z ":">"===i?r=" M "+(s[1]+e)+" "+s[2]+" L "+(s[1]-n)+" "+(s[2]-o)+" L "+(s[1]-n)+" "+(s[2]+o)+" Z ":"<"===i&&(r=" M "+(s[1]-e)+" "+s[2]+" L "+(s[1]+n)+" "+(s[2]-o)+" L "+(s[1]+n)+" "+(s[2]+o)+" Z "),r},updatePathStringPrim:function(t){var e,i,r,s=" M ",o="";if(t.numberPoints<=0)return"";if(r=Math.min(t.points.length,t.numberPoints),1===t.bezierDegree)for(e=0;e<r;e++)i=t.points[e].scrCoords,isNaN(i[1])||isNaN(i[2])?s=" M ":(i[1]=Math.max(Math.min(i[1],5e3),-5e3),i[2]=Math.max(Math.min(i[2],5e3),-5e3),o+=s+i[1]+" "+i[2],s=" L ");else if(3===t.bezierDegree)for(e=0;e<r;)i=t.points[e].scrCoords,isNaN(i[1])||isNaN(i[2])?s=" M ":(o+=s+i[1]+" "+i[2]," C "===s&&(e+=1,i=t.points[e].scrCoords,o+=" "+i[1]+" "+i[2],e+=1,i=t.points[e].scrCoords,o+=" "+i[1]+" "+i[2]),s=" C "),e+=1;return o},updatePathStringBezierPrim:function(t){var e,i,r,o,n,h,l,c=" M ",d="",u=s.evaluate(t.visProp.strokewidth),p="plot"!==s.evaluate(t.visProp.curvetype);if(t.numberPoints<=0)return"";for(p&&t.board.options.curve.RDPsmoothing&&(t.points=a.RamerDouglasPeucker(t.points,.5)),l=Math.min(t.points.length,t.numberPoints),i=1;i<3;i++)for(c=" M ",e=0;e<l;e++)o=t.points[e].scrCoords,isNaN(o[1])||isNaN(o[2])?c=" M ":(o[1]=Math.max(Math.min(o[1],5e3),-5e3),o[2]=Math.max(Math.min(o[2],5e3),-5e3)," M "===c?d+=c+o[1]+" "+o[2]:(r=2*i,d+=[c,n+.333*(o[1]-n)+u*(r*Math.random()-i)," ",h+.333*(o[2]-h)+u*(r*Math.random()-i)," ",n+.666*(o[1]-n)+u*(r*Math.random()-i)," ",h+.666*(o[2]-h)+u*(r*Math.random()-i)," ",o[1]," ",o[2]].join("")),c=" C ",n=o[1],h=o[2]);return d},updatePolygonPrim:function(t,e){var i,r,s="",o=e.vertices.length;for(t.setAttributeNS(null,"stroke","none"),"polygonalchain"===e.elType&&o++,i=0;i<o-1;i++){if(!e.vertices[i].isReal)return void t.setAttributeNS(null,"points","");r=e.vertices[i].coords.scrCoords,s=s+r[1]+","+r[2],i<o-2&&(s+=" ")}-1===s.indexOf("NaN")&&t.setAttributeNS(null,"points",s)},updateRectPrim:function(t,e,i,r,s){t.setAttributeNS(null,"x",e),t.setAttributeNS(null,"y",i),t.setAttributeNS(null,"width",r),t.setAttributeNS(null,"height",s)},setPropertyPrim:function(t,e,i){"stroked"!==e&&t.setAttributeNS(null,e,i)},display:function(t,e){var i;t&&t.rendNode&&(t.visPropOld.visible=e,i=t.rendNode,e?(i.setAttributeNS(null,"display","inline"),i.style.visibility="inherit"):(i.setAttributeNS(null,"display","none"),i.style.visibility="hidden"))},show:function(e){t.deprecated("Board.renderer.show()","Board.renderer.display()"),this.display(e,!0)},hide:function(e){t.deprecated("Board.renderer.hide()","Board.renderer.display()"),this.display(e,!1)},setBuffering:function(t,e){t.rendNode.setAttribute("buffered-rendering",e)},setDashStyle:function(t){var e=s.evaluate(t.visProp.dash),i=t.rendNode;e>0?i.setAttributeNS(null,"stroke-dasharray",this.dashArray[e-1]):i.hasAttributeNS(null,"stroke-dasharray")&&i.removeAttributeNS(null,"stroke-dasharray")},setGradient:function(t){var e,i,r,o=t.rendNode,n=s.evaluate(t.visProp.gradient);"linear"===n||"radial"===n?(e=this.createPrim(n+"Gradient",t.id+"_gradient"),i=this.createPrim("stop",t.id+"_gradient1"),r=this.createPrim("stop",t.id+"_gradient2"),e.appendChild(i),e.appendChild(r),this.defs.appendChild(e),o.setAttributeNS(null,"style","fill:url(#"+this.container.id+"_"+t.id+"_gradient)"),t.gradNode1=i,t.gradNode2=r,t.gradNode=e):o.removeAttributeNS(null,"style")},updateGradientAngle:function(t,e){var i=1,r=Math.cos(e),s=Math.sin(e);Math.abs(r)>Math.abs(s)?i/=Math.abs(r):i/=Math.abs(s),r>=0?(t.setAttributeNS(null,"x1",0),t.setAttributeNS(null,"x2",r*i)):(t.setAttributeNS(null,"x1",-r*i),t.setAttributeNS(null,"x2",0)),s>=0?(t.setAttributeNS(null,"y1",0),t.setAttributeNS(null,"y2",s*i)):(t.setAttributeNS(null,"y1",-s*i),t.setAttributeNS(null,"y2",0))},updateGradientCircle:function(t,e,i,r,s,o,n){t.setAttributeNS(null,"cx",100*e+"%"),t.setAttributeNS(null,"cy",100*i+"%"),t.setAttributeNS(null,"r",100*r+"%"),t.setAttributeNS(null,"fx",100*s+"%"),t.setAttributeNS(null,"fy",100*o+"%"),t.setAttributeNS(null,"fr",100*n+"%")},updateGradient:function(t){var e,i,r=t.gradNode1,o=t.gradNode2,n=s.evaluate(t.visProp.gradient);s.exists(r)&&s.exists(o)&&(i=s.evaluate(t.visProp.fillopacity),i=i>0?i:0,e=s.evaluate(t.visProp.fillcolor),r.setAttributeNS(null,"style","stop-color:"+e+";stop-opacity:"+i),o.setAttributeNS(null,"style","stop-color:"+s.evaluate(t.visProp.gradientsecondcolor)+";stop-opacity:"+s.evaluate(t.visProp.gradientsecondopacity)),r.setAttributeNS(null,"offset",100*s.evaluate(t.visProp.gradientstartoffset)+"%"),o.setAttributeNS(null,"offset",100*s.evaluate(t.visProp.gradientendoffset)+"%"),"linear"===n?this.updateGradientAngle(t.gradNode,s.evaluate(t.visProp.gradientangle)):"radial"===n&&this.updateGradientCircle(t.gradNode,s.evaluate(t.visProp.gradientcx),s.evaluate(t.visProp.gradientcy),s.evaluate(t.visProp.gradientr),s.evaluate(t.visProp.gradientfx),s.evaluate(t.visProp.gradientfy),s.evaluate(t.visProp.gradientfr)))},setObjectTransition:function(t,e){var i,o,n,a,h=["rendNode","rendNodeTriangleStart","rendNodeTriangleEnd"];if(void 0===e&&(e=s.evaluate(t.visProp.transitionduration)),e!==t.visPropOld.transitionduration){for(o=t.elementClass===r.OBJECT_CLASS_TEXT&&"html"===s.evaluate(t.visProp.display)?" color "+e+"ms, opacity "+e+"ms":" fill "+e+"ms, fill-opacity "+e+"ms, stroke "+e+"ms, stroke-opacity "+e+"ms",a=h.length,n=0;n<a;++n)t[h[n]]&&(i=t[h[n]],i.style.transition=o);t.visPropOld.transitionduration=e}},_setAttribute:function(t,e){""===e?t():window.setTimeout(t,1)},setObjectFillColor:function(e,i,r,n){var a,h,l,c,d=s.evaluate(i),u=s.evaluate(r),p=s.evaluate(e.visProp.gradient);u=u>0?u:0,e.visPropOld.fillcolor===d&&e.visPropOld.fillopacity===u&&null===p||(s.exists(d)&&!1!==d&&(9!==d.length?(h=d,c=u):(l=o.rgba2rgbo(d),h=l[0],c=u*l[1]),a=void 0===n?e.rendNode:n,"none"!==h&&this._setAttribute(function(){a.setAttributeNS(null,"fill",h)},e.visPropOld.fillcolor),e.type===t.OBJECT_TYPE_IMAGE?this._setAttribute(function(){a.setAttributeNS(null,"opacity",c)},e.visPropOld.fillopacity):("none"===h&&(c=0),this._setAttribute(function(){a.setAttributeNS(null,"fill-opacity",c)},e.visPropOld.fillopacity)),"linear"!==p&&"radial"!==p||this.updateGradient(e)),e.visPropOld.fillcolor=d,e.visPropOld.fillopacity=u)},setObjectStrokeColor:function(t,e,i){var n,a,h,l,c=s.evaluate(e),d=s.evaluate(i);d=d>0?d:0,t.visPropOld.strokecolor===c&&t.visPropOld.strokeopacity===d||(s.exists(c)&&!1!==c&&(9!==c.length?(n=c,h=d):(a=o.rgba2rgbo(c),n=a[0],h=d*a[1]),l=t.rendNode,t.elementClass===r.OBJECT_CLASS_TEXT?"html"===s.evaluate(t.visProp.display)?this._setAttribute(function(){l.style.color=n,l.style.opacity=h},t.visPropOld.strokecolor):this._setAttribute(function(){l.setAttributeNS(null,"style","fill:"+n),l.setAttributeNS(null,"style","fill-opacity:"+h)},t.visPropOld.strokecolor):this._setAttribute(function(){l.setAttributeNS(null,"stroke",n),l.setAttributeNS(null,"stroke-opacity",h)},t.visPropOld.strokecolor),t.elementClass!==r.OBJECT_CLASS_CURVE&&t.elementClass!==r.OBJECT_CLASS_LINE||(s.evaluate(t.visProp.firstarrow)&&this._setArrowColor(t.rendNodeTriangleStart,n,h,t),s.evaluate(t.visProp.lastarrow)&&this._setArrowColor(t.rendNodeTriangleEnd,n,h,t))),t.visPropOld.strokecolor=c,t.visPropOld.strokeopacity=d)},setObjectStrokeWidth:function(t,e){var i,r=s.evaluate(e);isNaN(r)||t.visPropOld.strokewidth===r||(i=t.rendNode,this.setPropertyPrim(i,"stroked","true"),s.exists(r)&&this.setPropertyPrim(i,"stroke-width",r+"px"),t.visPropOld.strokewidth=r)},setLineCap:function(t){var e=s.evaluate(t.visProp.linecap);void 0!==e&&""!==e&&t.visPropOld.linecap!==e&&s.exists(t.rendNode)&&(this.setPropertyPrim(t.rendNode,"stroke-linecap",e),t.visPropOld.linecap=e)},setShadow:function(t){var e=s.evaluate(t.visProp.shadow);t.visPropOld.shadow!==e&&(s.exists(t.rendNode)&&(e?t.rendNode.setAttributeNS(null,"filter","url(#"+this.container.id+"_f1)"):t.rendNode.removeAttributeNS(null,"filter")),t.visPropOld.shadow=e)},suspendRedraw:function(){},unsuspendRedraw:function(){},resize:function(t,e){this.svgRoot.style.width=parseFloat(t)+"px",this.svgRoot.style.height=parseFloat(e)+"px",this.svgRoot.setAttribute("width",parseFloat(t)),this.svgRoot.setAttribute("height",parseFloat(e))},createTouchpoints:function(t){var e,i,r,s;for(this.touchpoints=[],e=0;e<t;e++)i="touchpoint1_"+e,s=this.createPrim("path",i),this.appendChildPrim(s,19),s.setAttributeNS(null,"d","M 0 0"),this.touchpoints.push(s),this.setPropertyPrim(s,"stroked","true"),this.setPropertyPrim(s,"stroke-width","1px"),s.setAttributeNS(null,"stroke","#000000"),s.setAttributeNS(null,"stroke-opacity",1),s.setAttributeNS(null,"display","none"),r="touchpoint2_"+e,s=this.createPrim("ellipse",r),this.appendChildPrim(s,19),this.updateEllipsePrim(s,0,0,0,0),this.touchpoints.push(s),this.setPropertyPrim(s,"stroked","true"),this.setPropertyPrim(s,"stroke-width","1px"),s.setAttributeNS(null,"stroke","#000000"),s.setAttributeNS(null,"stroke-opacity",1),s.setAttributeNS(null,"fill","#ffffff"),s.setAttributeNS(null,"fill-opacity",0),s.setAttributeNS(null,"display","none")},showTouchpoint:function(t){this.touchpoints&&t>=0&&2*t<this.touchpoints.length&&(this.touchpoints[2*t].setAttributeNS(null,"display","inline"),this.touchpoints[2*t+1].setAttributeNS(null,"display","inline"))},hideTouchpoint:function(t){this.touchpoints&&t>=0&&2*t<this.touchpoints.length&&(this.touchpoints[2*t].setAttributeNS(null,"display","none"),this.touchpoints[2*t+1].setAttributeNS(null,"display","none"))},updateTouchpoint:function(t,e){var i,r;this.touchpoints&&t>=0&&2*t<this.touchpoints.length&&(i=e[0],r=e[1],this.touchpoints[2*t].setAttributeNS(null,"d","M "+(i-37)+" "+r+" L "+(i+37)+" "+r+" M "+i+" "+(r-37)+" L "+i+" "+(r+37)),this.updateEllipsePrim(this.touchpoints[2*t+1],e[0],e[1],25,25))},_getValuesOfDOMElements:function(t){var e=[];if(1===t.nodeType)for(t=t.firstChild;t;)void 0!==t.id&&void 0!==t.value&&e.push([t.id,t.value]),e=e.concat(this._getValuesOfDOMElements(t)),t=t.nextSibling;return e},_getDataUri:function(t,e){var i=new Image;i.onload=function(){var t=document.createElement("canvas");t.width=this.naturalWidth,t.height=this.naturalHeight,t.getContext("2d").drawImage(this,0,0),e(t.toDataURL("image/png")),t.remove()},i.src=t},_getImgDataURL:function(t){var e,i,r,s,o,n;if(e=t.getElementsByTagName("image"),(i=e.length)>0)for(r=document.createElement("canvas"),n=0;n<i;n++){e[n].setAttribute("crossorigin","anonymous"),s=r.getContext("2d"),r.width=e[n].getAttribute("width"),r.height=e[n].getAttribute("height");try{s.drawImage(e[n],0,0,r.width,r.height),o=r.toDataURL(),e[n].setAttribute("xlink:href",o)}catch(t){console.log("CORS problem! Image can not be used",t)}}return!0},dumpToDataURI:function(t){var e,i,r,o,a,h=this.svgRoot,l=window.btoa||n.encode,c=[];if(this.container.hasChildNodes()&&s.exists(this.foreignObjLayer)){for(;h.nextSibling;)c=c.concat(this._getValuesOfDOMElements(h.nextSibling)),this.foreignObjLayer.appendChild(h.nextSibling);!0===t&&(r=this.container.ownerDocument,i=r.createElement("div"),i.appendChild(this.foreignObjLayer))}if(this._getImgDataURL(h),h.setAttribute("xmlns","http://www.w3.org/2000/svg"),e=(new XMLSerializer).serializeToString(h),!0!==t)for(a=c.length,o=0;o<a;o++)e=e.replace('id="'+c[o][0]+'"','id="'+c[o][0]+'" value="'+c[o][1]+'"');if((e.match(/xmlns=\"http:\/\/www.w3.org\/2000\/svg\"/g)||[]).length>1&&(e=e.replace(/xmlns=\"http:\/\/www.w3.org\/2000\/svg\"/g,"")),e=e.replace(/ /g," "),s.exists(this.foreignObjLayer)&&this.foreignObjLayer.hasChildNodes())for(!0===t&&h.appendChild(this.foreignObjLayer);this.foreignObjLayer.firstChild;)this.container.appendChild(this.foreignObjLayer.firstChild);return"data:image/svg+xml;base64,"+l(unescape(encodeURIComponent(e)))},dumpToCanvas:function(t,e,i,r){var s,o,n,a;return n=document.getElementById(t),n.width=n.width,a=n.getContext("2d"),void 0!==e&&void 0!==i&&(n.style.width=parseFloat(e)+"px",n.style.height=parseFloat(i)+"px",n.setAttribute("width",parseFloat(e)),n.setAttribute("height",parseFloat(i))),o=new Image,s=this.dumpToDataURI(r),o.src=s,"Promise"in window?new Promise(function(t,r){try{o.onload=function(){a.drawImage(o,0,0,e,i),t()}}catch(t){r(t)}}):(o.onload=function(){window.setTimeout(function(){try{a.drawImage(o,0,0,e,i)}catch(t){console.log("screenshots not longer supported on IE")}},200)},this)},screenshot:function(t,e,i){var r,o,n,a,h,l,c,d,u,p,f,m=this.container.ownerDocument,g=this.container.parentNode,b=t.attr.screenshot,v=!1;return"no"===this.type?this:(c=b.scale*parseFloat(this.container.style.width),d=b.scale*parseFloat(this.container.style.height),void 0===e||""===e?(v=!0,a=new Image,a.style.width=c+"px",a.style.height=d+"px"):(v=!1,a=m.getElementById(e)),v&&(r=m.createElement("div"),r.style.cssText=b.css,r.style.width=c+"px",r.style.height=d+"px",r.style.zIndex=this.container.style.zIndex+120,r.style.position="absolute",r.style.top=this.container.offsetTop+"px",r.style.left=this.container.offsetLeft+"px"),o=m.createElement("canvas"),n=Math.random().toString(36).substr(2,5),o.setAttribute("id",n),o.setAttribute("width",c),o.setAttribute("height",d),o.style.width=c+"px",o.style.height=c+"px",o.style.display="none",g.appendChild(o),v&&(h=m.createElement("span"),l=m.createTextNode("✖"),h.style.cssText=b.cssButton,h.appendChild(l),h.onclick=function(){r.parentNode.removeChild(r)},r.appendChild(a),r.appendChild(h),g.insertBefore(r,this.container.nextSibling)),u=document.getElementById(this.container.id+"_navigationbar"),s.exists(u)&&(p=u.style.display,u.style.display="none"),f=function(){a.src=o.toDataURL("image/png"),g.removeChild(o)},"Promise"in window?this.dumpToCanvas(n,c,d,i).then(f):(this.dumpToCanvas(n,c,d,i),window.setTimeout(f,200)),s.exists(u)&&(u.style.display=p),this)}}),t.SVGRenderer}),define("renderer/vml",["jxg","renderer/abstract","base/constants","utils/type","utils/color","math/math","math/numerics"],function(t,e,i,r,s,o,n){"use strict";return t.VMLRenderer=function(e){this.type="vml",this.container=e,this.container.style.overflow="hidden",""===this.container.style.position&&(this.container.style.position="relative"),this.container.onselectstart=function(){return!1},this.resolution=10,r.exists(t.vmlStylesheet)||(e.ownerDocument.namespaces.add("jxgvml","urn:schemas-microsoft-com:vml"),t.vmlStylesheet=this.container.ownerDocument.createStyleSheet(),t.vmlStylesheet.addRule(".jxgvml","behavior:url(#default#VML)"));try{e.ownerDocument.namespaces.jxgvml||e.ownerDocument.namespaces.add("jxgvml","urn:schemas-microsoft-com:vml"),this.createNode=function(t){return e.ownerDocument.createElement("<jxgvml:"+t+' class="jxgvml">')}}catch(t){this.createNode=function(t){return e.ownerDocument.createElement("<"+t+' xmlns="urn:schemas-microsoft.com:vml" class="jxgvml">')}}this.dashArray=["Solid","1 1","ShortDash","Dash","LongDash","ShortDashDot","LongDashDot"]},t.VMLRenderer.prototype=new e,t.extend(t.VMLRenderer.prototype,{_setAttr:function(e,i,r,s){try{8===this.container.ownerDocument.documentMode?e[i]=r:e.setAttribute(i,r,s)}catch(e){t.debug("_setAttr: "+i+" "+r+"<br>\n")}},updateTicks:function(t){var e,i,s,o,n,a=this.resolution,h=[];for(i=t.ticks.length,e=0;e<i;e++)s=t.ticks[e],o=s[0],n=s[1],r.isNumber(o[0])&&r.isNumber(o[1])&&h.push(" m "+Math.round(a*o[0])+", "+Math.round(a*n[0])+" l "+Math.round(a*o[1])+", "+Math.round(a*n[1])+" ");r.exists(t.rendNode)||(t.rendNode=this.createPrim("path",t.id),this.appendChildPrim(t.rendNode,r.evaluate(t.visProp.layer))),this._setAttr(t.rendNode,"stroked","true"),this._setAttr(t.rendNode,"strokecolor",r.evaluate(t.visProp.strokecolor),1),this._setAttr(t.rendNode,"strokeweight",r.evaluate(t.visProp.strokewidth)),this._setAttr(t.rendNodeStroke,"opacity",100*r.evaluate(t.visProp.strokeopacity)+"%"),this.updatePathPrim(t.rendNode,h,t.board)},displayCopyright:function(t,e){var i,r;i=this.createNode("textbox"),i.style.position="absolute",this._setAttr(i,"id",this.container.id+"_licenseText"),i.style.left=20,i.style.top=2,i.style.fontSize=e,i.style.color="#356AA0",i.style.fontFamily="Arial,Helvetica,sans-serif",this._setAttr(i,"opacity","30%"),i.style.filter="progid:DXImageTransform.Microsoft.Matrix(M11='1.0', sizingMethod='auto expand', enabled = false) progid:DXImageTransform.Microsoft.Alpha(opacity = 30, enabled = true)",r=this.container.ownerDocument.createTextNode(t),i.appendChild(r),this.appendChildPrim(i,0)},drawInternalText:function(t){var e;return e=this.createNode("textbox"),e.style.position="absolute",t.rendNodeText=this.container.ownerDocument.createTextNode(""),e.appendChild(t.rendNodeText),this.appendChildPrim(e,9),e.style.filter="progid:DXImageTransform.Microsoft.Matrix(M11='1.0', sizingMethod='auto expand', enabled = false) progid:DXImageTransform.Microsoft.Alpha(opacity = 100, enabled = false)",e},updateInternalText:function(t){var e,i,r,s,n,a,h=t.plaintext,l=this.joinTransforms(t,t.transformations),c=[0,0],d=t.rendNode,u=[],p=t.getAnchorX(),f=t.getAnchorY();if(!isNaN(t.coords.scrCoords[1]+t.coords.scrCoords[2])){for("right"===p?c[0]=1:"middle"===p&&(c[0]=.5),"bottom"===f?c[1]=1:"middle"===f&&(c[1]=.5),u[0]=o.matVecMult(l,[1,t.coords.scrCoords[1]-c[0]*t.size[0],t.coords.scrCoords[2]+(1-c[1])*t.size[1]+this.vOffsetText]),u[0][1]/=u[0][0],u[0][2]/=u[0][0],u[1]=o.matVecMult(l,[1,t.coords.scrCoords[1]+(1-c[0])*t.size[0],t.coords.scrCoords[2]+(1-c[1])*t.size[1]+this.vOffsetText]),u[1][1]/=u[1][0],u[1][2]/=u[1][0],u[2]=o.matVecMult(l,[1,t.coords.scrCoords[1]+(1-c[0])*t.size[0],t.coords.scrCoords[2]-c[1]*t.size[1]+this.vOffsetText]),u[2][1]/=u[2][0],u[2][2]/=u[2][0],u[3]=o.matVecMult(l,[1,t.coords.scrCoords[1]-c[0]*t.size[0],t.coords.scrCoords[2]-c[1]*t.size[1]+this.vOffsetText]),u[3][1]/=u[3][0],u[3][2]/=u[3][0],i=u[0][1],s=u[0][1],r=u[0][2],n=u[0][2],a=1;a<4;a++)i=Math.max(i,u[a][1]),s=Math.min(s,u[a][1]),r=Math.max(r,u[a][2]),n=Math.min(n,u[a][2]);e=1===c[0]?Math.floor(t.board.canvasWidth-i):Math.floor(s),t.visPropOld.left!==p+e&&(1===c[0]?(t.rendNode.style.right=e+"px",t.rendNode.style.left="auto"):(t.rendNode.style.left=e+"px",t.rendNode.style.right="auto"),t.visPropOld.left=p+e),e=1===c[1]?Math.floor(t.board.canvasHeight-r):Math.floor(n),t.visPropOld.top!==f+e&&(1===c[1]?(t.rendNode.style.bottom=e+"px",t.rendNode.style.top="auto"):(t.rendNode.style.top=e+"px",t.rendNode.style.bottom="auto"),t.visPropOld.top=f+e)}t.htmlStr!==h&&(t.rendNodeText.data=h,t.htmlStr=h),d.filters.item(0).M11=l[1][1],d.filters.item(0).M12=l[1][2],d.filters.item(0).M21=l[2][1],d.filters.item(0).M22=l[2][2],d.filters.item(0).enabled=!0},drawImage:function(t){var e;e=this.container.ownerDocument.createElement("img"),e.style.position="absolute",this._setAttr(e,"id",this.container.id+"_"+t.id),this.container.appendChild(e),this.appendChildPrim(e,r.evaluate(t.visProp.layer)),e.style.filter="progid:DXImageTransform.Microsoft.Matrix(M11='1.0', sizingMethod='auto expand') progid:DXImageTransform.Microsoft.Alpha(opacity = 100, enabled = false)",t.rendNode=e,this.updateImage(t)},transformImage:function(t,e){var i,r,s,n,a,h,l=t.rendNode,c=[];if(e.length>0){for(i=this.joinTransforms(t,e),c[0]=o.matVecMult(i,t.coords.scrCoords),c[0][1]/=c[0][0],c[0][2]/=c[0][0],c[1]=o.matVecMult(i,[1,t.coords.scrCoords[1]+t.size[0],t.coords.scrCoords[2]]),c[1][1]/=c[1][0],c[1][2]/=c[1][0],c[2]=o.matVecMult(i,[1,t.coords.scrCoords[1]+t.size[0],t.coords.scrCoords[2]-t.size[1]]),c[2][1]/=c[2][0],c[2][2]/=c[2][0],c[3]=o.matVecMult(i,[1,t.coords.scrCoords[1],t.coords.scrCoords[2]-t.size[1]]),c[3][1]/=c[3][0],c[3][2]/=c[3][0],r=c[0][1],n=c[0][1],s=c[0][2],a=c[0][2],h=1;h<4;h++)r=Math.max(r,c[h][1]),n=Math.min(n,c[h][1]),s=Math.max(s,c[h][2]),a=Math.min(a,c[h][2]);l.style.left=Math.floor(n)+"px",l.style.top=Math.floor(a)+"px",l.filters.item(0).M11=i[1][1],l.filters.item(0).M12=i[1][2],l.filters.item(0).M21=i[2][1],l.filters.item(0).M22=i[2][2],l.filters.item(0).enabled=!0}},updateImageURL:function(t){var e=r.evaluate(t.url);this._setAttr(t.rendNode,"src",e)},appendChildPrim:function(t,e){return r.exists(e)||(e=0),t.style.zIndex=e,this.container.appendChild(t),t},appendNodesToElement:function(t,e){"shape"!==e&&"path"!==e&&"polygon"!==e||(t.rendNodePath=this.getElementById(t.id+"_path")),t.rendNodeFill=this.getElementById(t.id+"_fill"),t.rendNodeStroke=this.getElementById(t.id+"_stroke"),t.rendNodeShadow=this.getElementById(t.id+"_shadow"),t.rendNode=this.getElementById(t.id)},createPrim:function(t,e){var i,r,s=this.createNode("fill"),o=this.createNode("stroke"),n=this.createNode("shadow");return this._setAttr(s,"id",this.container.id+"_"+e+"_fill"),this._setAttr(o,"id",this.container.id+"_"+e+"_stroke"),this._setAttr(n,"id",this.container.id+"_"+e+"_shadow"),"circle"===t||"ellipse"===t?(i=this.createNode("oval"),i.appendChild(s),i.appendChild(o),i.appendChild(n)):"polygon"===t||"path"===t||"shape"===t||"line"===t?(i=this.createNode("shape"),i.appendChild(s),i.appendChild(o),i.appendChild(n),r=this.createNode("path"),this._setAttr(r,"id",this.container.id+"_"+e+"_path"),i.appendChild(r)):(i=this.createNode(t),i.appendChild(s),i.appendChild(o),i.appendChild(n)),i.style.position="absolute",i.style.left="0px",i.style.top="0px",this._setAttr(i,"id",this.container.id+"_"+e),i},remove:function(t){r.exists(t)&&t.removeNode(!0)},makeArrows:function(t){var e,i=r.evaluate(t.visProp.firstarrow),s=r.evaluate(t.visProp.lastarrow) -;t.visPropOld.firstarrow===i&&t.visPropOld.lastarrow===s||(i?(e=t.rendNodeStroke,this._setAttr(e,"startarrow","block"),this._setAttr(e,"startarrowlength","long")):(e=t.rendNodeStroke,r.exists(e)&&this._setAttr(e,"startarrow","none")),s?(e=t.rendNodeStroke,this._setAttr(e,"id",this.container.id+"_"+t.id+"stroke"),this._setAttr(e,"endarrow","block"),this._setAttr(e,"endarrowlength","long")):(e=t.rendNodeStroke,r.exists(e)&&this._setAttr(e,"endarrow","none")),t.visPropOld.firstarrow=i,t.visPropOld.lastarrow=s)},updateEllipsePrim:function(t,e,i,r,s){t.style.left=Math.floor(e-r)+"px",t.style.top=Math.floor(i-s)+"px",t.style.width=Math.floor(2*Math.abs(r))+"px",t.style.height=Math.floor(2*Math.abs(s))+"px"},updateLinePrim:function(t,e,i,r,s,o){var n,a=this.resolution;isNaN(e+i+r+s)||(n=["m ",Math.floor(a*e),", ",Math.floor(a*i)," l ",Math.floor(a*r),", ",Math.floor(a*s)],this.updatePathPrim(t,n,o))},updatePathPrim:function(t,e,i){var r=i.canvasWidth,s=i.canvasHeight;e.length<=0&&(e=["m 0,0"]),t.style.width=r,t.style.height=s,this._setAttr(t,"coordsize",[Math.floor(this.resolution*r),Math.floor(this.resolution*s)].join(",")),this._setAttr(t,"path",e.join(""))},updatePathStringPoint:function(t,e,i){var r=[],s=Math.round,o=t.coords.scrCoords,n=e*Math.sqrt(3)*.5,a=.5*e,h=this.resolution;return"x"===i?r.push([" m ",s(h*(o[1]-e)),", ",s(h*(o[2]-e))," l ",s(h*(o[1]+e)),", ",s(h*(o[2]+e))," m ",s(h*(o[1]+e)),", ",s(h*(o[2]-e))," l ",s(h*(o[1]-e)),", ",s(h*(o[2]+e))].join("")):"+"===i?r.push([" m ",s(h*(o[1]-e)),", ",s(h*o[2])," l ",s(h*(o[1]+e)),", ",s(h*o[2])," m ",s(h*o[1]),", ",s(h*(o[2]-e))," l ",s(h*o[1]),", ",s(h*(o[2]+e))].join("")):"<>"===i?r.push([" m ",s(h*(o[1]-e)),", ",s(h*o[2])," l ",s(h*o[1]),", ",s(h*(o[2]+e))," l ",s(h*(o[1]+e)),", ",s(h*o[2])," l ",s(h*o[1]),", ",s(h*(o[2]-e))," x e "].join("")):"^"===i?r.push([" m ",s(h*o[1]),", ",s(h*(o[2]-e))," l ",s(h*(o[1]-n)),", ",s(h*(o[2]+a))," l ",s(h*(o[1]+n)),", ",s(h*(o[2]+a))," x e "].join("")):"v"===i?r.push([" m ",s(h*o[1]),", ",s(h*(o[2]+e))," l ",s(h*(o[1]-n)),", ",s(h*(o[2]-a))," l ",s(h*(o[1]+n)),", ",s(h*(o[2]-a))," x e "].join("")):">"===i?r.push([" m ",s(h*(o[1]+e)),", ",s(h*o[2])," l ",s(h*(o[1]-a)),", ",s(h*(o[2]-n))," l ",s(h*(o[1]-a)),", ",s(h*(o[2]+n))," l ",s(h*(o[1]+e)),", ",s(h*o[2])].join("")):"<"===i&&r.push([" m ",s(h*(o[1]-e)),", ",s(h*o[2])," l ",s(h*(o[1]+a)),", ",s(h*(o[2]-n))," l ",s(h*(o[1]+a)),", ",s(h*(o[2]+n))," x e "].join("")),r},updatePathStringPrim:function(t){var e,i,r=[],s=this.resolution,o=Math.round,n=" m ",a=Math.min(t.numberPoints,8192);if(t.numberPoints<=0)return"";if(a=Math.min(a,t.points.length),1===t.bezierDegree)for(e=0;e<a;e++)i=t.points[e].scrCoords,isNaN(i[1])||isNaN(i[2])?n=" m ":(i[1]>2e4?i[1]=2e4:i[1]<-2e4&&(i[1]=-2e4),i[2]>2e4?i[2]=2e4:i[2]<-2e4&&(i[2]=-2e4),r.push([n,o(s*i[1]),", ",o(s*i[2])].join("")),n=" l ");else if(3===t.bezierDegree)for(e=0;e<a;)i=t.points[e].scrCoords,isNaN(i[1])||isNaN(i[2])?n=" m ":(r.push([n,o(s*i[1]),", ",o(s*i[2])].join(""))," c "===n&&(e+=1,i=t.points[e].scrCoords,r.push([" ",o(s*i[1]),", ",o(s*i[2])].join("")),e+=1,i=t.points[e].scrCoords,r.push([" ",o(s*i[1]),", ",o(s*i[2])].join(""))),n=" c "),e+=1;return r.push(" e"),r},updatePathStringBezierPrim:function(t){var e,i,s,o,a,h,l=[],c=r.evaluate(t.visProp.strokewidth),d=this.resolution,u=Math.round,p=" m ",f="plot"!==r.evaluate(t.visProp.curvetype),m=Math.min(t.numberPoints,8192);if(t.numberPoints<=0)return"";for(f&&t.board.options.curve.RDPsmoothing&&(t.points=n.RamerDouglasPeucker(t.points,1)),m=Math.min(m,t.points.length),i=1;i<3;i++)for(p=" m ",e=0;e<m;e++)o=t.points[e].scrCoords,isNaN(o[1])||isNaN(o[2])?p=" m ":(o[1]>2e4?o[1]=2e4:o[1]<-2e4&&(o[1]=-2e4),o[2]>2e4?o[2]=2e4:o[2]<-2e4&&(o[2]=-2e4)," m "===p?l.push([p,u(d*o[1])," ",u(d*o[2])].join("")):(s=2*i,l.push([p,u(d*(a+.333*(o[1]-a)+c*(s*Math.random()-i)))," ",u(d*(h+.333*(o[2]-h)+c*(s*Math.random()-i)))," ",u(d*(a+.666*(o[1]-a)+c*(s*Math.random()-i)))," ",u(d*(h+.666*(o[2]-h)+c*(s*Math.random()-i)))," ",u(d*o[1])," ",u(d*o[2])].join(""))),p=" c ",a=o[1],h=o[2]);return l.push(" e"),l},updatePolygonPrim:function(t,e){var i,r,s=e.vertices.length,o=this.resolution,n=[];if(this._setAttr(t,"stroked","false"),r=e.vertices[0].coords.scrCoords,!isNaN(r[1]+r[2])){for(n.push(["m ",Math.floor(o*r[1]),",",Math.floor(o*r[2])," l "].join("")),i=1;i<s-1;i++){if(!e.vertices[i].isReal)return void this.updatePathPrim(t,"",e.board);if(r=e.vertices[i].coords.scrCoords,isNaN(r[1]+r[2]))return;n.push(Math.floor(o*r[1])+","+Math.floor(o*r[2])),i<s-2&&n.push(", ")}n.push(" x e"),this.updatePathPrim(t,n,e.board)}},updateRectPrim:function(t,e,i,r,s){t.style.left=Math.floor(e)+"px",t.style.top=Math.floor(i)+"px",r>=0&&(t.style.width=r+"px"),s>=0&&(t.style.height=s+"px")},setPropertyPrim:function(t,e,i){var s,o="";switch(e){case"stroke":o="strokecolor";break;case"stroke-width":o="strokeweight";break;case"stroke-dasharray":o="dashstyle"}""!==o&&(s=r.evaluate(i),this._setAttr(t,o,s))},display:function(t,e){t&&t.rendNode&&(t.visPropOld.visible=e,t.rendNode.style.visibility=e?"inherit":"hidden")},show:function(e){t.deprecated("Board.renderer.show()","Board.renderer.display()"),e&&e.rendNode&&(e.rendNode.style.visibility="inherit")},hide:function(e){t.deprecated("Board.renderer.hide()","Board.renderer.display()"),e&&e.rendNode&&(e.rendNode.style.visibility="hidden")},setDashStyle:function(t,e){var i;e.dash>=0&&(i=t.rendNodeStroke,this._setAttr(i,"dashstyle",this.dashArray[e.dash]))},setGradient:function(t){var e=t.rendNodeFill,i=r.evaluate(t.visProp.gradient);"linear"===i?(this._setAttr(e,"type","gradient"),this._setAttr(e,"color2",r.evaluate(t.visProp.gradientsecondcolor)),this._setAttr(e,"opacity2",r.evaluate(t.visProp.gradientsecondopacity)),this._setAttr(e,"angle",r.evaluate(t.visProp.gradientangle))):"radial"===i?(this._setAttr(e,"type","gradientradial"),this._setAttr(e,"color2",r.evaluate(t.visProp.gradientsecondcolor)),this._setAttr(e,"opacity2",r.evaluate(t.visProp.gradientsecondopacity)),this._setAttr(e,"focusposition",100*r.evaluate(t.visProp.gradientpositionx)+"%,"+100*r.evaluate(t.visProp.gradientpositiony)+"%"),this._setAttr(e,"focussize","0,0")):this._setAttr(e,"type","solid")},setObjectFillColor:function(t,e,o){var n,a,h,l=r.evaluate(e),c=r.evaluate(o),d=t.rendNode;c=c>0?c:0,t.visPropOld.fillcolor===l&&t.visPropOld.fillopacity===c||(r.exists(l)&&!1!==l&&(9!==l.length?(n=l,h=c):(a=s.rgba2rgbo(l),n=a[0],h=c*a[1]),"none"===n||!1===n?this._setAttr(t.rendNode,"filled","false"):(this._setAttr(t.rendNode,"filled","true"),this._setAttr(t.rendNode,"fillcolor",n),r.exists(h)&&t.rendNodeFill&&this._setAttr(t.rendNodeFill,"opacity",100*h+"%")),t.type===i.OBJECT_TYPE_IMAGE&&d.filters.length>1&&(d.filters.item(1).opacity=Math.round(100*h),d.filters.item(1).enabled=!0)),t.visPropOld.fillcolor=l,t.visPropOld.fillopacity=c)},setObjectStrokeColor:function(t,e,s){var o,n,a,h,l=r.evaluate(e),c=r.evaluate(s),d=t.rendNode;c=c>0?c:0,t.visPropOld.strokecolor===l&&t.visPropOld.strokeopacity===c||(r.exists(l)&&!1!==l&&(9!==l.length?(o=l,a=c):(n=e.rgba2rgbo(l),o=n[0],a=c*n[1]),t.elementClass===i.OBJECT_CLASS_TEXT?(d.filters.length>1&&(d.filters.item(1).opacity=Math.round(100*a),d.filters.item(1).enabled=!0),d.style.color=o):(!1!==o&&(this._setAttr(d,"stroked","true"),this._setAttr(d,"strokecolor",o)),h=t.rendNodeStroke,r.exists(a)&&t.type!==i.OBJECT_TYPE_IMAGE&&this._setAttr(h,"opacity",100*a+"%"))),t.visPropOld.strokecolor=l,t.visPropOld.strokeopacity=c)},setObjectStrokeWidth:function(t,e){var i,s=r.evaluate(e);isNaN(s)||t.visPropOld.strokewidth===s||(i=t.rendNode,this.setPropertyPrim(i,"stroked","true"),r.exists(s)&&(this.setPropertyPrim(i,"stroke-width",s),0===s&&r.exists(t.rendNodeStroke)&&this._setAttr(i,"stroked","false")),t.visPropOld.strokewidth=s)},setShadow:function(t){var e=t.rendNodeShadow,i=r.evaluate(t.visProp.shadow);e&&t.visPropOld.shadow!==i&&(i?(this._setAttr(e,"On","True"),this._setAttr(e,"Offset","3pt,3pt"),this._setAttr(e,"Opacity","60%"),this._setAttr(e,"Color","#aaaaaa")):this._setAttr(e,"On","False"),t.visPropOld.shadow=i)},suspendRedraw:function(){this.container.style.display="none"},unsuspendRedraw:function(){this.container.style.display=""}}),t.VMLRenderer}),define("renderer/canvas",["jxg","renderer/abstract","base/constants","utils/env","utils/type","utils/uuid","utils/color","base/coords","math/math","math/geometry","math/numerics"],function(t,e,i,r,s,o,n,a,h,l,c){"use strict";return t.CanvasRenderer=function(t,e){this.type="canvas",this.canvasRoot=null,this.suspendHandle=null,this.canvasId=o.genUUID(),this.canvasNamespace=null,r.isBrowser?(this.container=t,this.container.style.MozUserSelect="none",this.container.style.userSelect="none",this.container.style.overflow="hidden",""===this.container.style.position&&(this.container.style.position="relative"),this.container.innerHTML=['<canvas id="',this.canvasId,'" width="',e.width,'px" height="',e.height,'px"><',"/canvas>"].join(""),this.canvasRoot=this.container.ownerDocument.getElementById(this.canvasId),this.context=this.canvasRoot.getContext("2d")):r.isNode()&&(this.canvasId="object"==typeof module?module.require("canvas"):require("canvas"),this.canvasRoot=new this.canvasId(500,500),this.context=this.canvasRoot.getContext("2d")),this.dashArray=[[2,2],[5,5],[10,10],[20,20],[20,10,10,10],[20,5,10,5]]},t.CanvasRenderer.prototype=new e,t.extend(t.CanvasRenderer.prototype,{_drawFilledPolygon:function(t,e){var i,r=t.length,s=this.context;if(r>0){if(s.beginPath(),s.moveTo(t[0][0],t[0][1]),1==e)for(i=1;i<r;i++)s.lineTo(t[i][0],t[i][1]);else for(i=1;i<r;i+=3)s.bezierCurveTo(t[i][0],t[i][1],t[i+1][0],t[i+1][1],t[i+2][0],t[i+2][1]);s.lineTo(t[0][0],t[0][1]),s.closePath(),s.fill(),s.stroke()}},_fill:function(t){var e=this.context;e.save(),this._setColor(t,"fill")&&e.fill(),e.restore()},_rotatePoint:function(t,e,i){return[e*Math.cos(t)-i*Math.sin(t),e*Math.sin(t)+i*Math.cos(t)]},_rotateShape:function(t,e){var i,r=[],s=t.length;if(s<=0)return t;for(i=0;i<s;i++)r.push(this._rotatePoint(e,t[i][0],t[i][1]));return r},updateGradientAngle:function(t,e){var r,s,o,n,h,l,c,d,u,p,f,m,g=1,b=Math.cos(-e),v=Math.sin(-e),y=t.getBoundingBox();return Math.abs(b)>Math.abs(v)?g/=Math.abs(b):g/=Math.abs(v),b>=0?(o=0,n=b*g):(o=-b*g,n=0),v>=0?(h=0,l=v*g):(h=-v*g,l=0),r=new a(i.COORDS_BY_USER,[y[0],y[1]],t.board),s=new a(i.COORDS_BY_USER,[y[2],y[3]],t.board),f=s.scrCoords[1]-r.scrCoords[1],m=s.scrCoords[2]-r.scrCoords[2],c=r.scrCoords[1]+f*o,u=r.scrCoords[2]+m*h,d=r.scrCoords[1]+f*n,p=r.scrCoords[2]+m*l,this.context.createLinearGradient(c,u,d,p)},updateGradientCircle:function(t,e,r,s,o,n,h){var l,c,d,u,p,f,m,g,b,v,y=t.getBoundingBox();return l=new a(i.COORDS_BY_USER,[y[0],y[1]],t.board),c=new a(i.COORDS_BY_USER,[y[2],y[3]],t.board),b=c.scrCoords[1]-l.scrCoords[1],v=l.scrCoords[2]-c.scrCoords[2],d=l.scrCoords[1]+b*e,u=c.scrCoords[2]+v*r,f=l.scrCoords[1]+b*o,m=c.scrCoords[2]+v*n,p=s*(b+v)*.5,g=h*(b+v)*.5,this.context.createRadialGradient(f,m,g,d,u,p)},updateGradient:function(t){var e,i,r,o=s.evaluate(t.visProp.gradient);return i=s.evaluate(t.visProp.fillopacity),i=i>0?i:0,e=s.evaluate(t.visProp.fillcolor),"linear"===o?r=this.updateGradientAngle(t,s.evaluate(t.visProp.gradientangle)):"radial"===o&&(r=this.updateGradientCircle(t,s.evaluate(t.visProp.gradientcx),s.evaluate(t.visProp.gradientcy),s.evaluate(t.visProp.gradientr),s.evaluate(t.visProp.gradientfx),s.evaluate(t.visProp.gradientfy),s.evaluate(t.visProp.gradientfr))),r.addColorStop(s.evaluate(t.visProp.gradientstartoffset),e),r.addColorStop(s.evaluate(t.visProp.gradientendoffset),s.evaluate(t.visProp.gradientsecondcolor)),r},_setColor:function(t,e,i){var r,o,a,h,l,c,d,u,p=!0,f=t.visProp;return e=e||"stroke",i=i||e,r=this._getHighlighted(t),"linear"===(u=s.evaluate(t.visProp.gradient))||"radial"===u?(this.context[i+"Style"]=this.updateGradient(t),p):(a=s.evaluate(f[r+e+"color"]),"none"!==a&&!1!==a?(c=s.evaluate(f[r+e+"opacity"]),c=c>0?c:0,9!==a.length?(l=a,d=c):(h=n.rgba2rgbo(a),l=h[0],d=c*h[1]),this.context.globalAlpha=d,this.context[i+"Style"]=l):p=!1,o=parseFloat(s.evaluate(f[r+"strokewidth"])),"stroke"!==e||isNaN(o)||(0===o?this.context.globalAlpha=0:this.context.lineWidth=o),"stroke"===e&&void 0!==f.linecap&&""!==f.linecap&&(this.context.lineCap=f.linecap),p)},_stroke:function(t){var e=this.context,i=s.evaluate(t.visProp.dash);e.save(),i>0?e.setLineDash&&e.setLineDash(this.dashArray[i]):this.context.lineDashArray=[],this._setColor(t,"stroke")&&e.stroke(),e.restore()},_translateShape:function(t,e,i){var r,s=[],o=t.length;if(o<=0)return t;for(r=0;r<o;r++)s.push([t[r][0]+e,t[r][1]+i]);return s},drawPoint:function(t){var e=s.evaluate(t.visProp.face),i=s.evaluate(t.visProp.size),r=t.coords.scrCoords,o=i*Math.sqrt(3)*.5,n=.5*i,a=parseFloat(s.evaluate(t.visProp.strokewidth))/2,h=this.context;if(t.visPropCalc.visible)switch(e){case"cross":case"x":h.beginPath(),h.moveTo(r[1]-i,r[2]-i),h.lineTo(r[1]+i,r[2]+i),h.moveTo(r[1]+i,r[2]-i),h.lineTo(r[1]-i,r[2]+i),h.lineCap="round",h.lineJoin="round",h.closePath(),this._stroke(t);break;case"circle":case"o":h.beginPath(),h.arc(r[1],r[2],i+1+a,0,2*Math.PI,!1),h.closePath(),this._fill(t),this._stroke(t);break;case"square":case"[]":if(i<=0)break;h.save(),this._setColor(t,"stroke","fill")&&h.fillRect(r[1]-i-a,r[2]-i-a,2*i+3*a,2*i+3*a),h.restore(),h.save(),this._setColor(t,"fill"),h.fillRect(r[1]-i+a,r[2]-i+a,2*i-a,2*i-a),h.restore();break;case"plus":case"+":h.beginPath(),h.moveTo(r[1]-i,r[2]),h.lineTo(r[1]+i,r[2]),h.moveTo(r[1],r[2]-i),h.lineTo(r[1],r[2]+i),h.lineCap="round",h.lineJoin="round",h.closePath(),this._stroke(t);break;case"diamond":case"<>":h.beginPath(),h.moveTo(r[1]-i,r[2]),h.lineTo(r[1],r[2]+i),h.lineTo(r[1]+i,r[2]),h.lineTo(r[1],r[2]-i),h.closePath(),this._fill(t),this._stroke(t);break;case"triangleup":case"a":case"^":h.beginPath(),h.moveTo(r[1],r[2]-i),h.lineTo(r[1]-o,r[2]+n),h.lineTo(r[1]+o,r[2]+n),h.closePath(),this._fill(t),this._stroke(t);break;case"triangledown":case"v":h.beginPath(),h.moveTo(r[1],r[2]+i),h.lineTo(r[1]-o,r[2]-n),h.lineTo(r[1]+o,r[2]-n),h.closePath(),this._fill(t),this._stroke(t);break;case"triangleleft":case"<":h.beginPath(),h.moveTo(r[1]-i,r[2]),h.lineTo(r[1]+n,r[2]-o),h.lineTo(r[1]+n,r[2]+o),h.closePath(),this.fill(t),this._stroke(t);break;case"triangleright":case">":h.beginPath(),h.moveTo(r[1]+i,r[2]),h.lineTo(r[1]-n,r[2]-o),h.lineTo(r[1]-n,r[2]+o),h.closePath(),this._fill(t),this._stroke(t)}},updatePoint:function(t){this.drawPoint(t)},drawArrows:function(t,e,r,o){var n,a,h,l,c,d,u,p,f,m,g,b,v,y,C,_,P,E=this.context,x=6,S=1,w=1,O=1,T=s.evaluate(t.visProp.firstarrow),N=s.evaluate(t.visProp.lastarrow);if("none"!==s.evaluate(t.visProp.strokecolor)&&(T||N)){if(t.elementClass===i.OBJECT_CLASS_LINE)n=e.scrCoords[1],a=e.scrCoords[2],h=r.scrCoords[1],l=r.scrCoords[2],_=P=Math.atan2(l-a,h-n);else{if(n=t.points[0].scrCoords[1],a=t.points[0].scrCoords[2],(C=t.points.length-1)<1)return;h=t.points[t.points.length-1].scrCoords[1],l=t.points[t.points.length-1].scrCoords[2],g=t.points[1].scrCoords[1]-t.points[0].scrCoords[1],b=t.points[1].scrCoords[2]-t.points[0].scrCoords[2],v=t.points[C].scrCoords[1]-t.points[C-1].scrCoords[1],y=t.points[C].scrCoords[2]-t.points[C-1].scrCoords[2],T&&(_=Math.atan2(b,g)),N&&(P=Math.atan2(y,v))}if(c=s.evaluate(t.visProp[o+"strokewidth"]),T)if(x=6,s.exists(T.size)&&(x=s.evaluate(T.size)),""!==o&&s.exists(T[o+"size"])&&(x=s.evaluate(T[o+"size"])),d=c*x,s.exists(T.type)&&(S=s.evaluate(T.type)),2===S)p=[[d,.5*-d],[0,0],[d,.5*d],[.5*d,0]];else if(3===S)p=[[d/3,.5*-d],[0,.5*-d],[0,.5*d],[d/3,.5*d]];else if(4===S)for(d/=10,w=3,p=[[10,3.31],[6.47,3.84],[2.87,4.5],[0,6.63],[.67,5.52],[1.33,4.42],[2,3.31],[1.33,2.21],[.67,1.1],[0,0],[2.87,2.13],[6.47,2.79],[10,3.31]],m=p.length,f=0;f<m;f++)p[f][0]*=-d,p[f][1]*=d,p[f][0]+=10*d,p[f][1]-=3.31*d;else if(5===S)for(d/=10,w=3,p=[[10,3.28],[6.61,4.19],[3.19,5.07],[0,6.55],[.62,5.56],[1,4.44],[1,3.28],[1,2.11],[.62,.99],[0,0],[3.19,1.49],[6.61,2.37],[10,3.28]],m=p.length,f=0;f<m;f++)p[f][0]*=-d,p[f][1]*=d,p[f][0]+=10*d,p[f][1]-=3.28*d;else if(6===S)for(d/=10,w=3,p=[[10,2.84],[6.61,3.59],[3.21,4.35],[0,5.68],[.33,4.73],[.67,3.78],[1,2.84],[.67,1.89],[.33,.95],[0,0],[3.21,1.33],[6.61,2.09],[10,2.84]],m=p.length,f=0;f<m;f++)p[f][0]*=-d,p[f][1]*=d,p[f][0]+=10*d,p[f][1]-=2.84*d;else p=[[d,.5*-d],[0,0],[d,.5*d]];if(N)if(x=6,s.exists(N.size)&&(x=s.evaluate(N.size)),""!==o&&s.exists(N[o+"size"])&&(x=s.evaluate(N[o+"size"])),d=c*x,s.exists(N.type)&&(S=s.evaluate(N.type)),2===S)u=[[-d,.5*-d],[0,0],[-d,.5*d],[.5*-d,0]];else if(3===S)u=[[-d/3,.5*-d],[0,.5*-d],[0,.5*d],[-d/3,.5*d]];else if(4===S)for(d/=10,O=3,u=[[10,3.31],[6.47,3.84],[2.87,4.5],[0,6.63],[.67,5.52],[1.33,4.42],[2,3.31],[1.33,2.21],[.67,1.1],[0,0],[2.87,2.13],[6.47,2.79],[10,3.31]],m=u.length,f=0;f<m;f++)u[f][0]*=d,u[f][1]*=d,u[f][0]-=10*d,u[f][1]-=3.31*d;else if(5===S)for(d/=10,O=3,u=[[10,3.28],[6.61,4.19],[3.19,5.07],[0,6.55],[.62,5.56],[1,4.44],[1,3.28],[1,2.11],[.62,.99],[0,0],[3.19,1.49],[6.61,2.37],[10,3.28]],m=u.length,f=0;f<m;f++)u[f][0]*=d,u[f][1]*=d,u[f][0]-=10*d,u[f][1]-=3.28*d;else if(6===S)for(d/=10,O=3,u=[[10,2.84],[6.61,3.59],[3.21,4.35],[0,5.68],[.33,4.73],[.67,3.78],[1,2.84],[.67,1.89],[.33,.95],[0,0],[3.21,1.33],[6.61,2.09],[10,2.84]],m=u.length,f=0;f<m;f++)u[f][0]*=d,u[f][1]*=d,u[f][0]-=10*d,u[f][1]-=2.84*d;else u=[[-d,.5*-d],[0,0],[-d,.5*d]];E.save(),this._setColor(t,"stroke","fill")&&(this._setColor(t,"stroke"),T&&this._drawFilledPolygon(this._translateShape(this._rotateShape(p,_),n,a),w),N&&this._drawFilledPolygon(this._translateShape(this._rotateShape(u,P),h,l),O)),E.restore()}},drawLine:function(t){var e,r,o,n,h,c=new a(i.COORDS_BY_USER,t.point1.coords.usrCoords,t.board),d=new a(i.COORDS_BY_USER,t.point2.coords.usrCoords,t.board),u=null;t.visPropCalc.visible&&(o=this._getHighlighted(t),n=s.evaluate(t.visProp[o+"strokewidth"]),h=this.getArrowHeadData(t,n,o),(h.evFirst||h.evLast)&&(u=-4),l.calcStraight(t,c,d,u),e=new a(i.COORDS_BY_USER,c.usrCoords,t.board),r=new a(i.COORDS_BY_USER,d.usrCoords,t.board),this.getPositionArrowHead(t,c,d,h),this.context.beginPath(),this.context.moveTo(c.scrCoords[1],c.scrCoords[2]),this.context.lineTo(d.scrCoords[1],d.scrCoords[2]),this._stroke(t),(h.evFirst||h.evLast)&&this.drawArrows(t,e,r,o))},updateLine:function(t){this.drawLine(t)},drawTicks:function(){},updateTicks:function(t){var e,i,r,s,o,n,a=t.ticks.length,h=this.context;for(h.beginPath(),e=0;e<a;e++)for(i=t.ticks[e],r=i[0],s=i[1],o=r.length,h.moveTo(r[0],s[0]),n=1;n<o;++n)h.lineTo(r[n],s[n]);h.lineCap="round",this._stroke(t)},drawCurve:function(t){var e;s.evaluate(t.visProp.handdrawing)?this.updatePathStringBezierPrim(t):this.updatePathStringPrim(t),t.numberPoints>1&&(e=this._getHighlighted(t),this.drawArrows(t,null,null,e))},updateCurve:function(t){this.drawCurve(t)},drawEllipse:function(t){var e=t.center.coords.scrCoords[1],i=t.center.coords.scrCoords[2],r=t.board.unitX,s=t.board.unitY,o=2*t.Radius(),n=2*t.Radius(),a=o*r,h=n*s,l=e-a/2,c=i-h/2,d=a/2*.5522848,u=h/2*.5522848,p=l+a,f=c+h,m=l+a/2,g=c+h/2,b=this.context;o>0&&n>0&&!isNaN(e+i)&&(b.beginPath(),b.moveTo(l,g),b.bezierCurveTo(l,g-u,m-d,c,m,c),b.bezierCurveTo(m+d,c,p,g-u,p,g),b.bezierCurveTo(p,g+u,m+d,f,m,f),b.bezierCurveTo(m-d,f,l,g+u,l,g),b.closePath(),this._fill(t),this._stroke(t))},updateEllipse:function(t){return this.drawEllipse(t)},displayCopyright:function(t,e){var i=this.context;i.save(),i.font=e+"px Arial",i.fillStyle="#aaa",i.lineWidth=.5,i.fillText(t,10,2+e),i.restore()},drawInternalText:function(t){var e=s.evaluate(t.visProp.fontsize),i=t.getAnchorX(),r=t.getAnchorY(),o=this.context;return o.save(),this._setColor(t,"stroke","fill")&&!isNaN(t.coords.scrCoords[1]+t.coords.scrCoords[2])&&(o.font=(e>0?e:0)+"px Arial",this.transformImage(t,t.transformations),"left"===i?o.textAlign="left":"right"===i?o.textAlign="right":"middle"===i&&(o.textAlign="center"),"bottom"===r?o.textBaseline="bottom":"top"===r?o.textBaseline="top":"middle"===r&&(o.textBaseline="middle"),o.fillText(t.plaintext,t.coords.scrCoords[1],t.coords.scrCoords[2])),o.restore(),null},updateInternalText:function(t){this.drawInternalText(t)},setObjectStrokeColor:function(t,e,r){var o,a,h,l,c=s.evaluate(e),d=s.evaluate(r);d=d>0?d:0,t.visPropOld.strokecolor===c&&t.visPropOld.strokeopacity===d||(s.exists(c)&&!1!==c&&(9!==c.length?(o=c,h=d):(a=n.rgba2rgbo(c),o=a[0],h=d*a[1]),l=t.rendNode,t.elementClass===i.OBJECT_CLASS_TEXT&&"html"===s.evaluate(t.visProp.display)&&(l.style.color=o,l.style.opacity=h)),t.visPropOld.strokecolor=c,t.visPropOld.strokeopacity=d)},drawImage:function(t){t.rendNode=new Image,t._src="",this.updateImage(t)},updateImage:function(t){var e=this.context,i=s.evaluate(t.visProp.fillopacity),r=s.bind(function(){t.imgIsLoaded=!0,t.size[0]<=0||t.size[1]<=0||(e.save(),e.globalAlpha=i,this.transformImage(t,t.transformations),e.drawImage(t.rendNode,t.coords.scrCoords[1],t.coords.scrCoords[2]-t.size[1],t.size[0],t.size[1]),e.restore())},this);this.updateImageURL(t)?t.rendNode.onload=r:t.imgIsLoaded&&r()},transformImage:function(t,e){var i,r=e.length,s=this.context;r>0&&(i=this.joinTransforms(t,e),Math.abs(c.det(i))>=h.eps&&s.transform(i[1][1],i[2][1],i[1][2],i[2][2],i[1][0],i[2][0]))},updateImageURL:function(t){var e;return e=s.evaluate(t.url),t._src!==e&&(t.imgIsLoaded=!1,t.rendNode.src=e,t._src=e,!0)},remove:function(t){s.exists(t)&&s.exists(t.parentNode)&&t.parentNode.removeChild(t)},updatePathStringPrim:function(t){var e,i,r,s,o,n="M",a=this.context;if(!(t.numberPoints<=0)){if(o=Math.min(t.points.length,t.numberPoints),a.beginPath(),1===t.bezierDegree)for(e=0;e<o;e++)i=t.points[e].scrCoords,isNaN(i[1])||isNaN(i[2])?n="M":(i[1]>5e3?i[1]=5e3:i[1]<-5e3&&(i[1]=-5e3),i[2]>5e3?i[2]=5e3:i[2]<-5e3&&(i[2]=-5e3),"M"===n?a.moveTo(i[1],i[2]):a.lineTo(i[1],i[2]),n="L");else if(3===t.bezierDegree)for(e=0;e<o;)i=t.points[e].scrCoords,isNaN(i[1])||isNaN(i[2])?n="M":("M"===n?a.moveTo(i[1],i[2]):(e+=1,r=t.points[e].scrCoords,e+=1,s=t.points[e].scrCoords,a.bezierCurveTo(i[1],i[2],r[1],r[2],s[1],s[2])),n="C"),e+=1;a.lineCap="round",this._fill(t),this._stroke(t)}},updatePathStringBezierPrim:function(t){var e,i,r,o,n,a,h,l="M",d=s.evaluate(t.visProp.strokewidth),u="plot"!==s.evaluate(t.visProp.curvetype),p=this.context;if(!(t.numberPoints<=0)){for(u&&t.board.options.curve.RDPsmoothing&&(t.points=c.RamerDouglasPeucker(t.points,.5)),h=Math.min(t.points.length,t.numberPoints),p.beginPath(),i=1;i<3;i++)for(l="M",e=0;e<h;e++)o=t.points[e].scrCoords,isNaN(o[1])||isNaN(o[2])?l="M":(o[1]>5e3?o[1]=5e3:o[1]<-5e3&&(o[1]=-5e3),o[2]>5e3?o[2]=5e3:o[2]<-5e3&&(o[2]=-5e3),"M"===l?p.moveTo(o[1],o[2]):(r=2*i,p.bezierCurveTo(n+.333*(o[1]-n)+d*(r*Math.random()-i),a+.333*(o[2]-a)+d*(r*Math.random()-i),n+.666*(o[1]-n)+d*(r*Math.random()-i),a+.666*(o[2]-a)+d*(r*Math.random()-i),o[1],o[2])),l="C",n=o[1],a=o[2]);p.lineCap="round",this._fill(t),this._stroke(t)}},updatePolygonPrim:function(t,e){var i,r,s,o=e.vertices.length,n=this.context,a=!0;if(!(o<=0)&&e.visPropCalc.visible){for("polygonalchain"===e.elType&&o++,n.beginPath(),r=0;!e.vertices[r].isReal&&r<o-1;)r++,a=!1;for(i=e.vertices[r].coords.scrCoords,n.moveTo(i[1],i[2]),s=r;s<o-1;s++)e.vertices[s].isReal||(a=!1),i=e.vertices[s].coords.scrCoords,n.lineTo(i[1],i[2]);n.closePath(),a&&this._fill(e)}},display:function(t,e){t&&t.rendNode&&(t.visPropOld.visible=e,t.rendNode.style.visibility=e?"inherit":"hidden")},show:function(e){t.deprecated("Board.renderer.show()","Board.renderer.display()"),s.exists(e.rendNode)&&(e.rendNode.style.visibility="inherit")},hide:function(e){t.deprecated("Board.renderer.hide()","Board.renderer.display()"),s.exists(e.rendNode)&&(e.rendNode.style.visibility="hidden")},setGradient:function(t){var e;e=s.evaluate(t.visProp.fillopacity),e=e>0?e:0,s.evaluate(t.visProp.fillcolor)},setShadow:function(t){t.visPropOld.shadow!==t.visProp.shadow&&(t.visPropOld.shadow=t.visProp.shadow)},highlight:function(t){return t.elementClass===i.OBJECT_CLASS_TEXT&&"html"===s.evaluate(t.visProp.display)?this.updateTextStyle(t,!0):(t.board.prepareUpdate(),t.board.renderer.suspendRedraw(t.board),t.board.updateRenderer(),t.board.renderer.unsuspendRedraw()),this},noHighlight:function(t){return t.elementClass===i.OBJECT_CLASS_TEXT&&"html"===s.evaluate(t.visProp.display)?this.updateTextStyle(t,!1):(t.board.prepareUpdate(),t.board.renderer.suspendRedraw(t.board),t.board.updateRenderer(),t.board.renderer.unsuspendRedraw()),this},suspendRedraw:function(e){this.context.save(),this.context.clearRect(0,0,this.canvasRoot.width,this.canvasRoot.height),e&&e.attr.showcopyright&&this.displayCopyright(t.licenseText,12)},unsuspendRedraw:function(){this.context.restore()},resize:function(t,e){this.container?(this.canvasRoot.style.width=parseFloat(t)+"px",this.canvasRoot.style.height=parseFloat(e)+"px",this.canvasRoot.setAttribute("width",2*parseFloat(t)+"px"),this.canvasRoot.setAttribute("height",2*parseFloat(e)+"px")):(this.canvasRoot.width=2*parseFloat(t),this.canvasRoot.height=2*parseFloat(e)),this.context=this.canvasRoot.getContext("2d"),this.context.scale(2,2)},removeToInsertLater:function(){return function(){}}}),t.CanvasRenderer}),define("renderer/no",["jxg","renderer/abstract"],function(t,e){"use strict";return t.NoRenderer=function(){this.enhancedRendering=!1,this.type="no"},t.extend(t.NoRenderer.prototype,{drawPoint:function(t){},updatePoint:function(t){},changePointStyle:function(t){},drawLine:function(t){},updateLine:function(t){},drawTicks:function(t){},updateTicks:function(t){},drawCurve:function(t){},updateCurve:function(t){},drawEllipse:function(t){},updateEllipse:function(t){},drawPolygon:function(t){},updatePolygon:function(t){},displayCopyright:function(t,e){},drawInternalText:function(t){},updateInternalText:function(t){},drawText:function(t){},updateText:function(t){},updateTextStyle:function(t,e){},updateInternalTextStyle:function(t,e,i){},drawImage:function(t){},updateImage:function(t){},transformImage:function(t,e){},updateImageURL:function(t){},appendChildPrim:function(t,e){},appendNodesToElement:function(t,e){},createPrim:function(t,e){return null},remove:function(t){},makeArrows:function(t){},updateEllipsePrim:function(t,e,i,r,s){},updateLinePrim:function(t,e,i,r,s,o){},updatePathPrim:function(t,e,i){},updatePathStringPoint:function(t,e,i){},updatePathStringPrim:function(t){},updatePathStringBezierPrim:function(t){},updatePolygonPrim:function(t,e){},updateRectPrim:function(t,e,i,r,s){},setPropertyPrim:function(t,e,i){},display:function(t,e){t&&(t.visPropOld.visible=e)},show:function(t){},hide:function(t){},setBuffering:function(t,e){},setDashStyle:function(t){},setDraft:function(t){},removeDraft:function(t){},setGradient:function(t){},updateGradient:function(t){},setObjectTransition:function(t,e){},setObjectFillColor:function(t,e,i){},setObjectStrokeColor:function(t,e,i){},setObjectStrokeWidth:function(t,e){},setShadow:function(t){},highlight:function(t){},noHighlight:function(t){},suspendRedraw:function(){},unsuspendRedraw:function(){},drawZoomBar:function(t){},getElementById:function(t){return null},resize:function(t,e){},removeToInsertLater:function(){return function(){}}}),t.NoRenderer.prototype=new e,t.NoRenderer}),define("jsxgraph",["jxg","utils/env","utils/type","base/board","reader/file","options","renderer/svg","renderer/vml","renderer/canvas","renderer/no"],function(t,e,i,r,s,o,n,a,h,l){"use strict";return t.JSXGraph={rendererType:function(){return o.board.renderer="no",e.supportsVML()&&(o.board.renderer="vml",document.onmousemove=function(){var t;return document.body&&(t=document.body.scrollLeft,t+=document.body.scrollTop),t}),e.supportsCanvas()&&(o.board.renderer="canvas"),e.supportsSVG()&&(o.board.renderer="svg"),e.isNode()&&e.supportsCanvas()&&(o.board.renderer="canvas"),(e.isNode()||"no"===o.renderer)&&(o.text.display="internal",o.infobox.display="internal"),o.board.renderer}(),initRenderer:function(t,e,r,s){var o;if(i.exists(r)&&!1!==r||"object"!=typeof document||(r=document),"object"==typeof r&&null!==t)for(o=r.getElementById(t);o.firstChild;)o.removeChild(o.firstChild);else o=t;return void 0!==s&&"auto"!==s||(s=this.rendererType),"svg"===s?new n(o,e):"vml"===s?new a(o):"canvas"===s?new h(o,e):new l},_setAttributes:function(t){var e=i.copyAttributes(t,o,"board");return e.zoom=i.copyAttributes(e,o,"board","zoom"),e.pan=i.copyAttributes(e,o,"board","pan"),e.drag=i.copyAttributes(e,o,"board","drag"),e.selection=i.copyAttributes(e,o,"board","selection"),e.navbar=i.copyAttributes(e.navbar,o,"navbar"),e},_fillBoard:function(e,i,r){e.initInfobox(),e.maxboundingbox=i.maxboundingbox,e.resizeContainer(r.width,r.height,!0,!0),e._createSelectionPolygon(i),e.renderer.drawZoomBar(e,i.navbar),t.boards[e.id]=e},_setARIA:function(t,e){var i,r,s,o,n,a=e.document||document;"object"==typeof a&&(i=a.getElementById(t),s=i.parentNode,o=t+"_ARIAlabel",n=t+"_ARIAdescription",r=a.createElement("div"),r.innerHTML=e.title,r.setAttribute("id",o),r.style.display="none",s.insertBefore(r,i),r=a.createElement("div"),r.innerHTML=e.description,r.setAttribute("id",n),r.style.display="none",s.insertBefore(r,i),i.setAttribute("aria-labelledby",o),i.setAttribute("aria-describedby",n))},_removeARIANodes:function(t){var e,i,r;"object"==typeof(r=t.document||document)&&(i=t.containerObj.getAttribute("aria-labelledby"),e=document.getElementById(i),e&&e.parentNode&&e.parentNode.removeChild(e),i=t.containerObj.getAttribute("aria-describedby"),(e=document.getElementById(i))&&e.parentNode&&e.parentNode.removeChild(e))},initBoard:function(t,s){var n,a,h,l,c,d,u,p,f,m,g,b,v,y;return s=s||{},m=this._setAttributes(s),p=e.getDimensions(t,m.document),m.unitx||m.unity?(n=i.def(m.originx,150),a=i.def(m.originy,150),h=i.def(m.unitx,50),l=i.def(m.unity,50)):(f=m.boundingbox,f[0]<m.maxboundingbox[0]&&(f[0]=m.maxboundingbox[0]),f[1]>m.maxboundingbox[1]&&(f[1]=m.maxboundingbox[1]),f[2]>m.maxboundingbox[2]&&(f[2]=m.maxboundingbox[2]),f[3]<m.maxboundingbox[3]&&(f[3]=m.maxboundingbox[3]),d=parseInt(p.width,10),u=parseInt(p.height,10),i.exists(f)&&m.keepaspectratio?(h=d/(f[2]-f[0]),l=u/(f[1]-f[3]),Math.abs(h)<Math.abs(l)?l=Math.abs(h)*l/Math.abs(l):h=Math.abs(l)*h/Math.abs(h)):(h=d/(f[2]-f[0]),l=u/(f[1]-f[3])),n=-h*f[0],a=l*f[1]),c=this.initRenderer(t,p,m.document,m.renderer),this._setARIA(t,m),y=new r(t,c,m.id,[n,a],m.zoomfactor*m.zoomx,m.zoomfactor*m.zoomy,h,l,p.width,p.height,m),y.keepaspectratio=m.keepaspectratio,this._fillBoard(y,m,p),y.suspendUpdate(),m.axis&&(g="object"==typeof m.axis?m.axis:{},b=i.deepCopy(o.board.defaultAxes.x,g),v=i.deepCopy(o.board.defaultAxes.y,g),m.defaultaxes.x&&(b=i.deepCopy(b,m.defaultaxes.x)),m.defaultaxes.y&&(v=i.deepCopy(v,m.defaultaxes.y)),y.defaultAxes={},y.defaultAxes.x=y.create("axis",[[0,0],[1,0]],b),y.defaultAxes.y=y.create("axis",[[0,0],[0,1]],v)),m.grid&&y.create("grid",[],"object"==typeof m.grid?m.grid:{}),y.unsuspendUpdate(),y},loadBoardFromFile:function(t,i,o,n,a){var h,l,c,d,u;return n=n||{},h=this._setAttributes(n),d=e.getDimensions(t,h.document),l=this.initRenderer(t,d,h.document,h.renderer),this._setARIA(t,h),c=new r(t,l,"",[150,150],1,1,50,50,d.width,d.height,h),this._fillBoard(c,h,d),u=h.encoding||"iso-8859-1",s.parseFileContent(i,c,o,!0,u,a),c},loadBoardFromString:function(t,i,o,n,a){var h,l,c,d;return n=n||{},h=this._setAttributes(n),d=e.getDimensions(t,h.document),l=this.initRenderer(t,d,h.document),this._setARIA(t,h),c=new r(t,l,"",[150,150],1,1,50,50,d.width,d.height,h),this._fillBoard(c,h,d),s.parseString(i,c,o,!0,a),c},freeBoard:function(e){var i;"string"==typeof e&&(e=t.boards[e]),this._removeARIANodes(e),e.removeEventHandlers(),e.suspendUpdate();for(i in e.objects)e.objects.hasOwnProperty(i)&&e.objects[i].remove();for(;e.containerObj.firstChild;)e.containerObj.removeChild(e.containerObj.firstChild);for(i in e.objects)e.objects.hasOwnProperty(i)&&delete e.objects[i];delete e.renderer,e.jc.creator.clearCache(),delete e.jc,delete t.boards[e.id]},registerElement:function(e,i){t.deprecated("JXG.JSXGraph.registerElement()","JXG.registerElement()"), -t.registerElement(e,i)}},e.isBrowser&&"object"==typeof window&&"object"==typeof document&&e.addEvent(window,"load",function(){var e,r,s,o,n,a,h,l,c,d,u,p,f=document.getElementsByTagName("script"),m=function(e,i,r){var s=t.JSXGraph.initBoard(n,{boundingbox:r,keepaspectratio:!0,grid:u,axis:d,showReload:!0});if(i.toLowerCase().indexOf("script")>-1)s.construct(e);else try{s.jc.parse(e)}catch(e){t.debug(e)}return s},g=function(e,i,r,s){return function(){var o;t.JSXGraph.freeBoard(e),o=m(i,r,s),o.reload=g(o,i,r,s)}};for(r=0;r<f.length;r++)if(e=f[r].getAttribute("type",!1),i.exists(e)&&("text/jessiescript"===e.toLowerCase()||"jessiescript"===e.toLowerCase()||"text/jessiecode"===e.toLowerCase()||"jessiecode"===e.toLowerCase())){if(h=f[r].getAttribute("width",!1)||"500px",l=f[r].getAttribute("height",!1)||"500px",c=f[r].getAttribute("boundingbox",!1)||"-5, 5, 5, -5",n=f[r].getAttribute("container",!1),c=c.split(","),4!==c.length)c=[-5,5,5,-5];else for(s=0;s<c.length;s++)c[s]=parseFloat(c[s]);if(d=i.str2Bool(f[r].getAttribute("axis",!1)||"false"),u=i.str2Bool(f[r].getAttribute("grid",!1)||"false"),i.exists(n))o=document.getElementById(n);else{n="jessiescript_autgen_jxg_"+r,o=document.createElement("div"),o.setAttribute("id",n),o.setAttribute("style","width:"+h+"; height:"+l+"; float:left"),o.setAttribute("class","jxgbox");try{document.body.insertBefore(o,f[r])}catch(t){"object"==typeof jQuery&&jQuery(o).insertBefore(f[r])}}document.getElementById(n)?(p=f[r].innerHTML,p=p.replace(/<!\[CDATA\[/g,"").replace(/\]\]>/g,""),f[r].innerHTML=p,a=m(p,e,c),a.reload=g(a,p,e,c)):t.debug("JSXGraph: Apparently the div injection failed. Can't create a board, sorry.")}},window),t.JSXGraph}),define("base/group",["jxg","base/constants","math/math","math/geometry","utils/type"],function(t,e,i,r,s){"use strict";return t.Group=function(t,i,r,o,n){var a,h,l,c;for(this.board=t,this.objects={},a=this.board.numObjects,this.board.numObjects+=1,""!==i&&s.exists(i)?this.id=i:this.id=this.board.id+"Group"+a,this.board.groups[this.id]=this,this.type=e.OBJECT_TYPE_POINT,this.elementClass=e.OBJECT_CLASS_POINT,""!==r&&s.exists(r)?this.name=r:this.name="group_"+this.board.generateName(this),delete this.type,this.coords={},this.needsRegularUpdate=n.needsregularupdate,this.rotationCenter="centroid",this.scaleCenter=null,this.rotationPoints=[],this.translationPoints=[],this.scalePoints=[],this.scaleDirections={},this.parents=[],h=s.isArray(o)?o:Array.prototype.slice.call(arguments,3),l=0;l<h.length;l++)c=this.board.select(h[l]),!s.evaluate(c.visProp.fixed)&&s.exists(c.coords)&&this.addPoint(c);this.methodMap={ungroup:"ungroup",add:"addPoint",addPoint:"addPoint",addPoints:"addPoints",addGroup:"addGroup",remove:"removePoint",removePoint:"removePoint",setAttribute:"setAttribute",setProperty:"setAttribute"}},t.extend(t.Group.prototype,{ungroup:function(){var t,e,i;for(t in this.objects)this.objects.hasOwnProperty(t)&&(e=this.objects[t].point,s.isArray(e.groups)&&(i=s.indexOf(e.groups,this.id))>=0&&delete e.groups[i]);return this.objects={},this},addParents:function(t){var e,i,r;for(r=s.isArray(t)?t:arguments,i=r.length,e=0;e<i;++e)s.isId(this.board,r[e])?this.parents.push(r[e]):s.exists(r[e].id)&&this.parents.push(r[e].id);this.parents=s.uniqueArray(this.parents)},setParents:function(t){this.parents=[],this.addParents(t)},getParents:function(){return s.isArray(this.parents)?this.parents:[]},_updateCoordsCache:function(t){var e;""!==t&&s.exists(this.objects[t])&&(e=this.objects[t].point,this.coords[e.id]={usrCoords:e.coords.usrCoords.slice(0)})},update:function(t){var e,o,n,a,h,l,c,d,u,p=null;if(!this.needsUpdate)return this;if(t=this._update_find_drag_type(),"nothing"===t.action)return this._updateCoordsCache(t.id),this;if(p=this.objects[t.id].point,"translation"===t.action)d=[p.coords.usrCoords[1]-this.coords[t.id].usrCoords[1],p.coords.usrCoords[2]-this.coords[t.id].usrCoords[2]];else if("rotation"===t.action||"scaling"===t.action){if(o="rotation"===t.action?"rotationCenter":"scaleCenter",s.isPoint(this[o]))u=this[o].coords.usrCoords.slice(1);else if("centroid"===this[o])u=this._update_centroid_center();else if(s.isArray(this[o]))u=this[o];else{if(!s.isFunction(this[o]))return this;u=this[o]()}if("rotation"===t.action)c=r.rad(this.coords[t.id].usrCoords.slice(1),u,this.objects[t.id].point),d=this.board.create("transform",[c,u[0],u[1]],{type:"rotate"}),d.update();else{if("scaling"!==t.action)return this;if(a=r.distance(this.coords[t.id].usrCoords.slice(1),u),Math.abs(a)<i.eps)return this;a=r.distance(p.coords.usrCoords.slice(1),u)/a,h=this.scaleDirections[t.id].indexOf("x")>=0?a:1,l=this.scaleDirections[t.id].indexOf("y")>=0?a:1,d=this.board.create("transform",[1,0,0,u[0]*(1-h),h,0,u[1]*(1-l),0,l],{type:"generic"}),d.update()}}this._update_apply_transformation(t,d),this.needsUpdate=!1;for(e in this.objects)if(this.objects.hasOwnProperty(e))for(n in this.objects[e].descendants)this.objects[e].descendants.hasOwnProperty(n)&&(this.objects[e].descendants.needsUpdate=this.objects[e].descendants.needsRegularUpdate||this.board.needsFullUpdate);this.board.updateElements(t);for(e in this.objects)this.objects.hasOwnProperty(e)&&this._updateCoordsCache(e);return this},_update_find_drag_type:function(){var t,r,o,n="nothing",a=[];for(t in this.objects)this.objects.hasOwnProperty(t)&&(r=this.objects[t].point,r.coords.distance(e.COORDS_BY_USER,this.coords[t])>i.eps&&a.push(r.id));return 0===a.length?{action:n,id:"",changed:a}:(o=a[0],r=this.objects[o].point,a.length>1?n="translation":s.isInArray(this.rotationPoints,r)&&s.exists(this.rotationCenter)?n="rotation":s.isInArray(this.scalePoints,r)&&s.exists(this.scaleCenter)?n="scaling":s.isInArray(this.translationPoints,r)&&(n="translation"),{action:n,id:o,changed:a})},_update_centroid_center:function(){var t,e,i;t=[0,0],e=0;for(i in this.coords)this.coords.hasOwnProperty(i)&&(t[0]+=this.coords[i].usrCoords[1],t[1]+=this.coords[i].usrCoords[2],++e);return e>0&&(t[0]/=e,t[1]/=e),t},_update_apply_transformation:function(t,r){var o,n;for(o in this.objects)this.objects.hasOwnProperty(o)&&(s.exists(this.board.objects[o])?(n=this.objects[o].point,n.id!==t.id?"translation"===t.action?s.isInArray(t.changed,n.id)||n.coords.setCoordinates(e.COORDS_BY_USER,[this.coords[o].usrCoords[1]+r[0],this.coords[o].usrCoords[2]+r[1]]):"rotation"!==t.action&&"scaling"!==t.action||r.applyOnce([n]):"rotation"!==t.action&&"scaling"!==t.action||n.coords.setCoordinates(e.COORDS_BY_USER,i.matVecMult(r.matrix,this.coords[n.id].usrCoords))):delete this.objects[o])},addPoint:function(t){return this.objects[t.id]={point:this.board.select(t)},this._updateCoordsCache(t.id),this.translationPoints.push(t),t.groups.push(this.id),t.groups=s.uniqueArray(t.groups),this},addPoints:function(t){var e;for(e=0;e<t.length;e++)this.addPoint(t[e]);return this},addGroup:function(t){var e;for(e in t.objects)t.objects.hasOwnProperty(e)&&this.addPoint(t.objects[e].point);return this},removePoint:function(t){return delete this.objects[t.id],this},setRotationCenter:function(t){return this.rotationCenter=t,this},setRotationPoints:function(t){return this._setActionPoints("rotation",t)},addRotationPoint:function(t){return this._addActionPoint("rotation",t)},removeRotationPoint:function(t){return this._removeActionPoint("rotation",t)},setTranslationPoints:function(t){return this._setActionPoints("translation",t)},addTranslationPoint:function(t){return this._addActionPoint("translation",t)},removeTranslationPoint:function(t){return this._removeActionPoint("translation",t)},setScaleCenter:function(t){return this.scaleCenter=t,this},setScalePoints:function(t,e){var i,r,o;for(i=s.isArray(t)?t:arguments,o=i.length,r=0;r<o;++r)this.scaleDirections[this.board.select(i[r]).id]=e||"xy";return this._setActionPoints("scale",t)},addScalePoint:function(t,e){return this._addActionPoint("scale",t),this.scaleDirections[this.board.select(t).id]=e||"xy",this},removeScalePoint:function(t){return this._removeActionPoint("scale",t)},_setActionPoints:function(t,e){var i,r,o;for(i=s.isArray(e)?e:arguments,o=i.length,this[t+"Points"]=[],r=0;r<o;++r)this._addActionPoint(t,i[r]);return this},_addActionPoint:function(t,e){return this[t+"Points"].push(this.board.select(e)),this},_removeActionPoint:function(t,e){var i=this[t+"Points"].indexOf(this.board.select(e));return i>-1&&this[t+"Points"].splice(i,1),this},setProperty:function(){t.deprecated("Group.setProperty","Group.setAttribute()"),this.setAttribute.apply(this,arguments)},setAttribute:function(){var t;for(t in this.objects)this.objects.hasOwnProperty(t)&&this.objects[t].point.setAttribute.apply(this.objects[t].point,arguments);return this}}),t.createGroup=function(e,i,r){var o=s.copyAttributes(r,e.options,"group"),n=new t.Group(e,o.id,o.name,i,o);return n.elType="group",n.setParents(i),n},t.registerElement("group",t.createGroup),{Group:t.Group,createGroup:t.createGroup}}),define("element/arc",["jxg","math/geometry","math/math","base/coords","base/circle","utils/type","base/constants"],function(t,e,i,r,s,o,n){"use strict";return t.createArc=function(a,h,l){var c,d,u;if(!1===(u=o.providePoints(a,h,l,"arc",["center","radiuspoint","anglepoint"]))||u.length<3)throw new Error("JSXGraph: Can't create Arc with parent types '"+typeof h[0]+"' and '"+typeof h[1]+"' and '"+typeof h[2]+"'.\nPossible parent types: [point,point,point], [arc, transformation]");return d=o.copyAttributes(l,a.options,"arc"),c=a.create("curve",[[0],[0]],d),c.elType="arc",c.setParents(u),c.type=n.OBJECT_TYPE_ARC,c.center=u[0],c.radiuspoint=u[1],c.point2=c.radiuspoint,c.anglepoint=u[2],c.point3=c.anglepoint,c.center.addChild(c),c.radiuspoint.addChild(c),c.anglepoint.addChild(c),c.useDirection=d.usedirection,c.updateDataArray=function(){var t,i,r,s,n,a,h=1,l=this.radiuspoint,c=this.center,d=this.anglepoint,p=o.evaluate(this.visProp.selection);i=e.rad(l,c,d),("minor"===p&&i>Math.PI||"major"===p&&i<Math.PI)&&(h=-1),this.useDirection&&(s=u[1].coords.usrCoords,n=u[3].coords.usrCoords,a=u[2].coords.usrCoords,r=(s[1]-a[1])*(s[2]-n[2])-(s[2]-a[2])*(s[1]-n[1]),r<0?(this.radiuspoint=u[1],this.anglepoint=u[2]):(this.radiuspoint=u[2],this.anglepoint=u[1])),l=l.coords.usrCoords,c=c.coords.usrCoords,d=d.coords.usrCoords,t=e.bezierArc(l,c,d,!1,h),this.dataX=t[0],this.dataY=t[1],this.bezierDegree=3,this.updateStdform(),this.updateQuadraticform()},c.Radius=function(){return this.radiuspoint.Dist(this.center)},c.getRadius=function(){return t.deprecated("Arc.getRadius()","Arc.Radius()"),this.Radius()},c.Value=function(){return this.Radius()*e.rad(this.radiuspoint,this.center,this.anglepoint)},c.hasPoint=function(t,s){var a,h,l,c,d,u,p,f,m,g,b=this.Radius(),v=o.evaluate(this.visProp.selection);return o.evaluate(this.visProp.hasinnerpoints)?this.hasPointSector(t,s):(o.isObject(o.evaluate(this.visProp.precision))?(g=this.board._inputDevice,m=o.evaluate(this.visProp.precision[g])):m=this.board.options.precision.hasPoint,m/=Math.min(this.board.unitX,this.board.unitY),h=new r(n.COORDS_BY_SCREEN,[t,s],this.board),this.transformations.length>0&&(this.updateTransformMatrix(),p=i.inverse(this.transformMat),f=i.matVecMult(p,h.usrCoords),h=new r(n.COORDS_BY_USER,f,this.board)),a=this.center.coords.distance(n.COORDS_BY_USER,h),l=Math.abs(a-b)<m,l&&(c=e.rad(this.radiuspoint,this.center,h.usrCoords.slice(1)),d=0,u=e.rad(this.radiuspoint,this.center,this.anglepoint),("minor"===v&&u>Math.PI||"major"===v&&u<Math.PI)&&(d=u,u=2*Math.PI),(c<d||c>u)&&(l=!1)),l)},c.hasPointSector=function(t,i){var s,a,h,l=new r(n.COORDS_BY_SCREEN,[t,i],this.board),c=this.Radius(),d=this.center.coords.distance(n.COORDS_BY_USER,l),u=d<c,p=o.evaluate(this.visProp.selection);return u&&(s=e.rad(this.radiuspoint,this.center,l.usrCoords.slice(1)),a=0,h=e.rad(this.radiuspoint,this.center,this.anglepoint),("minor"===p&&h>Math.PI||"major"===p&&h<Math.PI)&&(a=h,h=2*Math.PI),(s<a||s>h)&&(u=!1)),u},c.getTextAnchor=function(){return this.center.coords},c.getLabelAnchor=function(){var t,i,s,a,h,l=e.rad(this.radiuspoint,this.center,this.anglepoint),c=10/this.board.unitX,d=10/this.board.unitY,u=this.point2.coords.usrCoords,p=this.center.coords.usrCoords,f=u[1]-p[1],m=u[2]-p[2],g=o.evaluate(this.visProp.selection),b=this.label?this.label.visProp:this.visProp.label;return("minor"===g&&l>Math.PI||"major"===g&&l<Math.PI)&&(l=-(2*Math.PI-l)),t=new r(n.COORDS_BY_USER,[p[1]+Math.cos(.5*l)*f-Math.sin(.5*l)*m,p[2]+Math.sin(.5*l)*f+Math.cos(.5*l)*m],this.board),s=t.usrCoords[1]-p[1],a=t.usrCoords[2]-p[2],h=Math.sqrt(s*s+a*a),s=s*(h+c)/h,a=a*(h+d)/h,i=[p[1]+s,p[2]+a],b.position=e.calcLabelQuadrant(e.rad([1,0],[0,0],i)),new r(n.COORDS_BY_USER,i,this.board)},c.updateQuadraticform=s.Circle.prototype.updateQuadraticform,c.updateStdform=s.Circle.prototype.updateStdform,c.methodMap=t.deepCopy(c.methodMap,{getRadius:"getRadius",radius:"Radius",center:"center",radiuspoint:"radiuspoint",anglepoint:"anglepoint",Value:"Value"}),c.prepareUpdate().update(),c},t.registerElement("arc",t.createArc),t.createSemicircle=function(t,e,i){var r,s,n,a;if(!1===(a=o.providePoints(t,e,i,"point"))||2!==a.length)throw new Error("JSXGraph: Can't create Semicircle with parent types '"+typeof e[0]+"' and '"+typeof e[1]+"'.\nPossible parent types: [point,point]");return n=o.copyAttributes(i,t.options,"semicircle","center"),s=t.create("midpoint",a,n),s.dump=!1,n=o.copyAttributes(i,t.options,"semicircle"),r=t.create("arc",[s,a[1],a[0]],n),r.elType="semicircle",r.setParents([a[0].id,a[1].id]),r.subs={midpoint:s},r.inherits.push(s),r.midpoint=r.center=s,r},t.registerElement("semicircle",t.createSemicircle),t.createCircumcircleArc=function(t,e,i){var r,s,n,a;if(!1===(a=o.providePoints(t,e,i,"point"))||3!==a.length)throw new Error("JSXGraph: create Circumcircle Arc with parent types '"+typeof e[0]+"' and '"+typeof e[1]+"' and '"+typeof e[2]+"'.\nPossible parent types: [point,point,point]");return n=o.copyAttributes(i,t.options,"circumcirclearc","center"),s=t.create("circumcenter",a,n),s.dump=!1,n=o.copyAttributes(i,t.options,"circumcirclearc"),n.usedirection=!0,r=t.create("arc",[s,a[0],a[2],a[1]],n),r.elType="circumcirclearc",r.setParents([a[0].id,a[1].id,a[2].id]),r.subs={center:s},r.inherits.push(s),r.center=s,r},t.registerElement("circumcirclearc",t.createCircumcircleArc),t.createMinorArc=function(e,i,r){return r.selection="minor",t.createArc(e,i,r)},t.registerElement("minorarc",t.createMinorArc),t.createMajorArc=function(e,i,r){return r.selection="major",t.createArc(e,i,r)},t.registerElement("majorarc",t.createMajorArc),{createArc:t.createArc,createSemicircle:t.createSemicircle,createCircumcircleArc:t.createCircumcircleArc,createMinorArc:t.createMinorArc,createMajorArc:t.createMajorArc}}),define("element/sector",["jxg","math/geometry","math/math","math/statistics","base/coords","base/constants","utils/type","base/point","base/curve","base/transformation","element/composition"],function(t,e,i,r,s,o,n,a,h,l,c){"use strict";return t.createSector=function(a,h,l){var c,d,u,p,f,m="invalid",g=["center","radiuspoint","anglepoint"];if(h[0].elementClass===o.OBJECT_CLASS_LINE&&h[1].elementClass===o.OBJECT_CLASS_LINE&&(n.isArray(h[2])||n.isNumber(h[2]))&&(n.isArray(h[3])||n.isNumber(h[3]))&&(n.isNumber(h[4])||n.isFunction(h[4])))m="2lines";else{if(!1===(f=n.providePoints(a,h,l,"sector",g)))throw new Error("JSXGraph: Can't create Sector with parent types '"+typeof h[0]+"' and '"+typeof h[1]+"' and '"+typeof h[2]+"'.");m="3points"}return d=n.copyAttributes(l,a.options,"sector"),c=a.create("curve",[[0],[0]],d),c.type=o.OBJECT_TYPE_SECTOR,c.elType="sector","2lines"===m?(c.Radius=function(){return n.evaluate(h[4])},c.line1=a.select(h[0]),c.line2=a.select(h[1]),c.line1.addChild(c),c.line2.addChild(c),c.setParents(h),c.point1={visProp:{}},c.point2={visProp:{}},c.point3={visProp:{}},u=e.meetLineLine(c.line1.stdform,c.line2.stdform,0,a),n.isArray(h[2])?(2===h[2].length&&(h[2]=[1].concat(h[2])),p=e.projectPointToLine({coords:{usrCoords:h[2]}},c.line1,a),p=r.subtract(p.usrCoords,u.usrCoords),c.direction1=i.innerProduct(p,[0,c.line1.stdform[2],-c.line1.stdform[1]],3)>=0?1:-1):c.direction1=h[2]>=0?1:-1,n.isArray(h[3])?(2===h[3].length&&(h[3]=[1].concat(h[3])),p=e.projectPointToLine({coords:{usrCoords:h[3]}},c.line2,a),p=r.subtract(p.usrCoords,u.usrCoords),c.direction2=i.innerProduct(p,[0,c.line2.stdform[2],-c.line2.stdform[1]],3)>=0?1:-1):c.direction2=h[3]>=0?1:-1,c.updateDataArray=function(){var t,n,a,h,l=[0,0,0],d=[0,0,0],u=[0,0,0];if(n=this.line1,a=this.line2,d=i.crossProduct(n.stdform,a.stdform),Math.abs(d[0])>i.eps*i.eps&&(d[1]/=d[0],d[2]/=d[0],d[0]/=d[0]),t=this.direction1*this.Radius(),l=r.add(d,[0,t*n.stdform[2],-t*n.stdform[1]]),t=this.direction2*this.Radius(),u=r.add(d,[0,t*a.stdform[2],-t*a.stdform[1]]),this.point2.coords=new s(o.COORDS_BY_USER,l,c.board),this.point1.coords=new s(o.COORDS_BY_USER,d,c.board),this.point3.coords=new s(o.COORDS_BY_USER,u,c.board),Math.abs(l[0])<i.eps||Math.abs(d[0])<i.eps||Math.abs(u[0])<i.eps)return this.dataX=[NaN],void(this.dataY=[NaN]);h=e.bezierArc(l,d,u,!0,1),this.dataX=h[0],this.dataY=h[1],this.bezierDegree=3},c.methodMap=t.deepCopy(c.methodMap,{radius:"getRadius",getRadius:"getRadius",setRadius:"setRadius"}),c.prepareUpdate().update()):"3points"===m&&(c.point1=f[0],c.point2=f[1],c.point3=f[2],c.point1.addChild(c),c.point2.addChild(c),c.point3.addChild(c),c.useDirection=l.usedirection,c.setParents(f),n.exists(f[3])&&(c.point4=f[3],c.point4.addChild(c)),c.methodMap=t.deepCopy(c.methodMap,{arc:"arc",center:"center",radiuspoint:"radiuspoint",anglepoint:"anglepoint",radius:"getRadius",getRadius:"getRadius",setRadius:"setRadius"}),c.updateDataArray=function(){var t,i,r,s,o,a=this.point2,h=this.point1,l=this.point3,c=1,d=n.evaluate(this.visProp.selection);if(!a.isReal||!h.isReal||!l.isReal)return this.dataX=[NaN],void(this.dataY=[NaN]);o=e.rad(a,h,l),("minor"===d&&o>Math.PI||"major"===d&&o<Math.PI)&&(c=-1),this.useDirection&&n.exists(this.point4)&&(i=this.point2.coords.usrCoords,r=this.point4.coords.usrCoords,s=this.point3.coords.usrCoords,(i[1]-s[1])*(i[2]-r[2])-(i[2]-s[2])*(i[1]-r[1])>=0&&(l=this.point2,a=this.point3)),a=a.coords.usrCoords,h=h.coords.usrCoords,l=l.coords.usrCoords,t=e.bezierArc(a,h,l,!0,c),this.dataX=t[0],this.dataY=t[1],this.bezierDegree=3},c.Radius=function(){return this.point2.Dist(this.point1)},d=n.copyAttributes(l,a.options,"sector","arc"),d.withLabel=!1,d.name+="_arc",c.arc=a.create("arc",[c.point1,c.point2,c.point3],d),c.addChild(c.arc)),c.center=c.point1,c.radiuspoint=c.point2,c.anglepoint=c.point3,c.hasPointCurve=function(t,i){var r,a,h,l,c,d,u=new s(o.COORDS_BY_SCREEN,[t,i],this.board),p=this.Radius(),f=this.center.coords.distance(o.COORDS_BY_USER,u),m=n.evaluate(this.visProp.selection);return n.isObject(n.evaluate(this.visProp.precision))?(c=this.board._inputDevice,l=n.evaluate(this.visProp.precision[c])):l=this.board.options.precision.hasPoint,l/=Math.min(this.board.unitX,this.board.unitY),d=Math.abs(f-p)<l,d&&(r=e.rad(this.point2,this.center,u.usrCoords.slice(1)),a=0,h=e.rad(this.point2,this.center,this.point3),("minor"===m&&h>Math.PI||"major"===m&&h<Math.PI)&&(a=h,h=2*Math.PI),(r<a||r>h)&&(d=!1)),d},c.hasPointSector=function(t,i){var r,a,h,l=new s(o.COORDS_BY_SCREEN,[t,i],this.board),c=this.Radius(),d=this.point1.coords.distance(o.COORDS_BY_USER,l),u=d<c,p=n.evaluate(this.visProp.selection);return u&&(r=e.rad(this.radiuspoint,this.center,l.usrCoords.slice(1)),a=0,h=e.rad(this.radiuspoint,this.center,this.anglepoint),("minor"===p&&h>Math.PI||"major"===p&&h<Math.PI)&&(a=h,h=2*Math.PI),(r<a||r>h)&&(u=!1)),u},c.hasPoint=function(t,e){return n.evaluate(this.visProp.highlightonsector)||n.evaluate(this.visProp.hasinnerpoints)?this.hasPointSector(t,e):this.hasPointCurve(t,e)},c.getTextAnchor=function(){return this.point1.coords},c.getLabelAnchor=function(){var t,i,r,a,h,l=e.rad(this.point2,this.point1,this.point3),c=13/this.board.unitX,d=13/this.board.unitY,u=this.point2.coords.usrCoords,p=this.point1.coords.usrCoords,f=u[1]-p[1],m=u[2]-p[2],g=n.evaluate(this.visProp.selection),b=this.label?this.label.visProp:this.visProp.label;return("minor"===g&&l>Math.PI||"major"===g&&l<Math.PI)&&(l=-(2*Math.PI-l)),t=new s(o.COORDS_BY_USER,[p[1]+Math.cos(.5*l)*f-Math.sin(.5*l)*m,p[2]+Math.sin(.5*l)*f+Math.cos(.5*l)*m],this.board),r=t.usrCoords[1]-p[1],a=t.usrCoords[2]-p[2],h=Math.sqrt(r*r+a*a),r=r*(h+c)/h,a=a*(h+d)/h,i=[p[1]+r,p[2]+a],b.position=e.calcLabelQuadrant(e.rad([1,0],[0,0],i)),new s(o.COORDS_BY_USER,i,this.board)},c.setRadius=function(t){c.Radius=function(){return n.evaluate(t)}},c.getRadius=function(){return t.deprecated("Sector.getRadius()","Sector.Radius()"),this.Radius()},"3points"===m&&(c.setPositionDirectly=function(t,e,i){var o,n,a=new s(t,e,this.board),h=new s(t,i,this.board);return c.point1.draggable()&&c.point2.draggable()&&c.point3.draggable()?(o=r.subtract(a.usrCoords,h.usrCoords),n=this.board.create("transform",o.slice(1),{type:"translate"}),n.applyOnce([c.point1,c.point2,c.point3]),this):this}),c.prepareUpdate().update(),c},t.registerElement("sector",t.createSector),t.createCircumcircleSector=function(t,e,i){var r,s,o,a;if(!1===(a=n.providePoints(t,e,i,"point")))throw new Error("JSXGraph: Can't create circumcircle sector with parent types '"+typeof e[0]+"' and '"+typeof e[1]+"' and '"+typeof e[2]+"'.");return s=t.create("circumcenter",a.slice(0,3),o),s.dump=!1,o=n.copyAttributes(i,t.options,"circumcirclesector"),r=t.create("sector",[s,a[0],a[2],a[1]],o),r.elType="circumcirclesector",r.setParents(a),r.center=s,r.subs={center:s},r},t.registerElement("circumcirclesector",t.createCircumcircleSector),t.createMinorSector=function(e,i,r){return r.selection="minor",t.createSector(e,i,r)},t.registerElement("minorsector",t.createMinorSector),t.createMajorSector=function(e,i,r){return r.selection="major",t.createSector(e,i,r)},t.registerElement("majorsector",t.createMajorSector),t.createAngle=function(t,r,a){var h,l,c,d,u,p,f="invalid";if(r[0].elementClass===o.OBJECT_CLASS_LINE&&r[1].elementClass===o.OBJECT_CLASS_LINE&&(n.isArray(r[2])||n.isNumber(r[2]))&&(n.isArray(r[3])||n.isNumber(r[3])))f="2lines";else{if(!1===(p=n.providePoints(t,r,a,"point")))throw new Error("JSXGraph: Can't create angle with parent types '"+typeof r[0]+"' and '"+typeof r[1]+"' and '"+typeof r[2]+"'.");f="3points"}if(c=n.copyAttributes(a,t.options,"angle"),n.exists(c.name)&&""!==c.name||(c.name=t.generateName({type:o.OBJECT_TYPE_ANGLE})),l=n.exists(c.radius)?c.radius:0,"2lines"===f?(r.push(l),h=t.create("sector",r,c),h.updateDataArraySector=h.updateDataArray,h.setAngle=function(t){},h.free=function(t){}):(h=t.create("sector",[p[1],p[0],p[2]],c),h.arc.visProp.priv=!0,h.point=h.point2=h.radiuspoint=p[0],h.pointsquare=h.point3=h.anglepoint=p[2],h.Radius=function(){return n.evaluate(l)},h.updateDataArraySector=function(){var t,i,r=this.point2,s=this.point1,o=this.point3,a=this.Radius(),h=s.Dist(r),l=1,c=n.evaluate(this.visProp.selection);i=e.rad(r,s,o),("minor"===c&&i>Math.PI||"major"===c&&i<Math.PI)&&(l=-1),r=r.coords.usrCoords,s=s.coords.usrCoords,o=o.coords.usrCoords,r=[1,s[1]+(r[1]-s[1])*a/h,s[2]+(r[2]-s[2])*a/h],o=[1,s[1]+(o[1]-s[1])*a/h,s[2]+(o[2]-s[2])*a/h],t=e.bezierArc(r,s,o,!0,l),this.dataX=t[0],this.dataY=t[1],this.bezierDegree=3},h.setAngle=function(t){var e,i=this.anglepoint,r=this.radiuspoint;return i.draggable()&&(e=this.board.create("transform",[t,this.center],{type:"rotate"}),i.addTransform(r,e),i.isDraggable=!1,i.setParents(r)),this},h.free=function(){var t=this.anglepoint;return t.transformations.length>0&&(t.transformations.pop(),t.isDraggable=!0,t.parents=[]),this},h.setParents(p)),n.exists(h.visProp.text)&&h.label.setText(n.evaluate(h.visProp.text)),h.elType="angle",h.type=o.OBJECT_TYPE_ANGLE,h.subs={},h.updateDataArraySquare=function(){var t,r,s,o,n,a,h,l,c=this.Radius();"2lines"===f&&this.updateDataArraySector(),t=this.point2,r=this.point1,s=this.point3,t=t.coords.usrCoords,r=r.coords.usrCoords,s=s.coords.usrCoords,o=e.distance(t,r,3),n=e.distance(s,r,3),t=[1,r[1]+(t[1]-r[1])*c/o,r[2]+(t[2]-r[2])*c/o],s=[1,r[1]+(s[1]-r[1])*c/n,r[2]+(s[2]-r[2])*c/n],a=i.crossProduct(s,r),h=[-t[1]*a[1]-t[2]*a[2],t[0]*a[1],t[0]*a[2]],a=i.crossProduct(t,r),l=[-s[1]*a[1]-s[2]*a[2],s[0]*a[1],s[0]*a[2]],a=i.crossProduct(h,l),a[1]/=a[0],a[2]/=a[0],this.dataX=[r[1],t[1],a[1],s[1],r[1]],this.dataY=[r[2],t[2],a[2],s[2],r[2]],this.bezierDegree=1},h.updateDataArrayNone=function(){this.dataX=[NaN],this.dataY=[NaN],this.bezierDegree=1},h.updateDataArray=function(){var t=n.evaluate(this.visProp.type),r=e.trueAngle(this.point2,this.point1,this.point3),s=n.evaluate(this.visProp.selection);("minor"===s&&r>180||"major"===s&&r<180)&&(r=360-r),Math.abs(r-90)<n.evaluate(this.visProp.orthosensitivity)+i.eps&&(t=n.evaluate(this.visProp.orthotype)),"none"===t?this.updateDataArrayNone():"square"===t?this.updateDataArraySquare():"sector"===t?this.updateDataArraySector():"sectordot"===t&&(this.updateDataArraySector(),this.dot.visProp.visible||this.dot.setAttribute({visible:!0})),(!this.visProp.visible||"sectordot"!==t&&this.dot.visProp.visible)&&this.dot.setAttribute({visible:!1})},d=n.copyAttributes(a,t.options,"angle","dot"),h.dot=t.create("point",[function(){var t,r,s,o,a,l,c,d,u;return n.exists(h.dot)&&!h.dot.visProp.visible?[0,0]:(t=h.point2.coords.usrCoords,r=h.point1.coords.usrCoords,s=h.Radius(),o=e.distance(t,r,3),a=e.rad(h.point2,h.point1,h.point3),u=n.evaluate(h.visProp.selection),("minor"===u&&a>Math.PI||"major"===u&&a<Math.PI)&&(a=-(2*Math.PI-a)),a*=.5,l=Math.cos(a),c=Math.sin(a),t=[1,r[1]+(t[1]-r[1])*s/o,r[2]+(t[2]-r[2])*s/o],d=[[1,0,0],[r[1]-.5*r[1]*l+.5*r[2]*c,.5*l,.5*-c],[r[2]-.5*r[1]*c-.5*r[2]*l,.5*c,.5*l]],i.matVecMult(d,t))}],d),h.dot.dump=!1,h.subs.dot=h.dot,"2lines"===f)for(u=0;u<2;u++)t.select(r[u]).addChild(h.dot);else for(u=0;u<3;u++)t.select(p[u]).addChild(h.dot);return h.getLabelAnchor=function(){var t,r,a,l,c,d,u,p,f,m=12,g=n.evaluate(h.visProp.selection),b=this.label?this.label.visProp:this.visProp.label;return n.exists(this.label.visProp.fontSize)&&(m=n.evaluate(this.label.visProp.fontSize)),m/=this.board.unitX,r=h.point2.coords.usrCoords,a=h.point1.coords.usrCoords,l=h.Radius(),c=e.distance(r,a,3),d=e.rad(h.point2,h.point1,h.point3),("minor"===g&&d>Math.PI||"major"===g&&d<Math.PI)&&(d=-(2*Math.PI-d)),d*=.5,u=Math.cos(d),p=Math.sin(d),r=[1,a[1]+(r[1]-a[1])*l/c,a[2]+(r[2]-a[2])*l/c],f=[[1,0,0],[a[1]-.5*a[1]*u+.5*a[2]*p,.5*u,.5*-p],[a[2]-.5*a[1]*p-.5*a[2]*u,.5*p,.5*u]],t=i.matVecMult(f,r),t[1]/=t[0],t[2]/=t[0],t[0]/=t[0],c=e.distance(t,a,3),t=[t[0],a[1]+(t[1]-a[1])*(l+m)/c,a[2]+(t[2]-a[2])*(l+m)/c],b.position=e.calcLabelQuadrant(e.rad([1,0],[0,0],t)),new s(o.COORDS_BY_USER,t,this.board)},h.Value=function(){return e.rad(this.point2,this.point1,this.point3)},h.methodMap=n.deepCopy(h.methodMap,{Value:"Value",setAngle:"setAngle",free:"free"}),h},t.registerElement("angle",t.createAngle),t.createNonreflexAngle=function(i,r,s){var o;return s.selection="minor",o=t.createAngle(i,r,s),o.Value=function(){var t=e.rad(this.point2,this.point1,this.point3);return t<Math.PI?t:2*Math.PI-t},o},t.registerElement("nonreflexangle",t.createNonreflexAngle),t.createReflexAngle=function(i,r,s){var o;return s.selection="major",o=t.createAngle(i,r,s),o.Value=function(){var t=e.rad(this.point2,this.point1,this.point3);return t>=Math.PI?t:2*Math.PI-t},o},t.registerElement("reflexangle",t.createReflexAngle),{createSector:t.createSector,createCircumcircleSector:t.createCircumcircleSector,createMinorSector:t.createMinorSector,createMajorSector:t.createMajorSector,createAngle:t.createAngle,createReflexAngle:t.createReflexAngle,createNonreflexAngle:t.createNonreflexAngle}}),define("element/locus",["jxg","math/symbolic","utils/type"],function(t,e,i){"use strict";return t.createLocus=function(t,r,s){var o,n;if(!i.isArray(r)||1!==r.length||!i.isPoint(r[0]))throw new Error("JSXGraph: Can't create locus with parent of type other than point.\nPossible parent types: [point]");return n=r[0],o=t.create("curve",[[null],[null]],s),o.dontCallServer=!1,o.elType="locus",o.setParents([n.id]),o.updateDataArray=function(){var i,r,s;o.board.mode>0||(i=e.generatePolynomials(t,n,!0).join("|"))!==o.spe&&(o.spe=i,r=function(t,e,i,r){o.dataX=t,o.dataY=e,o.eq=i,o.ctime=r,o.generatePolynomial=function(t){return function(e){var i,r="("+e.symbolic.x+")",s="("+e.symbolic.y+")",o=[];for(i=0;i<t.length;i++)o[i]=t[i].replace(/\*\*/g,"^").replace(/x/g,r).replace(/y/g,s);return o}}(i)},s=e.geometricLocusByGroebnerBase(t,n,r),r(s.datax,s.datay,s.polynomial,s.exectime))},o},t.registerElement("locus",t.createLocus),{createLocus:t.createLocus}}),define("base/image",["jxg","base/constants","base/coords","base/element","math/math","utils/type","base/coordselement"],function(t,e,i,r,s,o,n){"use strict";return t.Image=function(i,r,s,n,a){this.constructor(i,s,e.OBJECT_TYPE_IMAGE,e.OBJECT_CLASS_OTHER),this.element=this.board.select(s.anchor),this.coordsConstructor(r),this.W=o.createFunction(a[0],this.board,""),this.H=o.createFunction(a[1],this.board,""),this.usrSize=[this.W(),this.H()],this.size=[Math.abs(this.usrSize[0]*i.unitX),Math.abs(this.usrSize[1]*i.unitY)],this.url=n,this.elType="image",this.span=[this.coords.usrCoords.slice(0),[this.coords.usrCoords[0],this.W(),0],[this.coords.usrCoords[0],0,this.H()]],this.id=this.board.setId(this,"Im"),this.board.renderer.drawImage(this),this.board.finalizeAdding(this),this.methodMap=t.deepCopy(this.methodMap,{addTransformation:"addTransform",trans:"addTransform"})},t.Image.prototype=new r,o.copyPrototypeMethods(t.Image,n,"coordsConstructor"),t.extend(t.Image.prototype,{hasPoint:function(t,r){var n,a,h,l,c,d,u,p,f,m=this.transformations.length;return o.isObject(o.evaluate(this.visProp.precision))?(l=this.board._inputDevice,c=o.evaluate(this.visProp.precision[l])):c=this.board.options.precision.hasPoint,0===m?(n=t-this.coords.scrCoords[1],a=this.coords.scrCoords[2]-r,h=c,n>=-h&&n-this.size[0]<=h&&a>=-h&&a-this.size[1]<=h):(d=new i(e.COORDS_BY_SCREEN,[t,r],this.board),d=d.usrCoords,u=[d[0]-this.span[0][0],d[1]-this.span[0][1],d[2]-this.span[0][2]],f=s.innerProduct,0<=(p=f(u,this.span[1]))&&p<=f(this.span[1],this.span[1])&&0<=(p=f(u,this.span[2]))&&p<=f(this.span[2],this.span[2]))},update:function(t){return this.needsUpdate?(this.updateCoords(t),this.updateSize(),this.updateSpan(),this):this},updateRenderer:function(){return this.updateRendererGeneric("updateImage")},updateSize:function(){return this.usrSize=[this.W(),this.H()],this.size=[Math.abs(this.usrSize[0]*this.board.unitX),Math.abs(this.usrSize[1]*this.board.unitY)],this},updateSpan:function(){var t,e,i=this.transformations.length,r=[];if(0===i)this.span=[[this.Z(),this.X(),this.Y()],[this.Z(),this.W(),0],[this.Z(),0,this.H()]];else{for(r[0]=[this.Z(),this.X(),this.Y()],r[1]=[this.Z(),this.X()+this.W(),this.Y()],r[2]=[this.Z(),this.X(),this.Y()+this.H()],t=0;t<i;t++)for(e=0;e<3;e++)r[e]=s.matVecMult(this.transformations[t].matrix,r[e]);for(e=0;e<3;e++)r[e][1]/=r[e][0],r[e][2]/=r[e][0],r[e][0]/=r[e][0];for(e=1;e<3;e++)r[e][0]-=r[0][0],r[e][1]-=r[0][1],r[e][2]-=r[0][2];this.span=r}return this},addTransform:function(t){var e;if(o.isArray(t))for(e=0;e<t.length;e++)this.transformations.push(t[e]);else this.transformations.push(t);return this},getParents:function(){var t=[this.url,[this.Z(),this.X(),this.Y()],this.usrSize];return 0!==this.parents.length&&(t=this.parents),t},setSize:function(t,e){return this.W=o.createFunction(t,this.board,""),this.H=o.createFunction(e,this.board,""),this},W:function(){},H:function(){}}),t.createImage=function(e,i,r){var s,a,h=i[0],l=i[1],c=i[2];if(s=o.copyAttributes(r,e.options,"image"),!(a=n.create(t.Image,e,l,s,h,c)))throw new Error("JSXGraph: Can't create image with parent types '"+typeof i[0]+"' and '"+typeof i[1]+"'.\nPossible parent types: [x,y], [z,x,y], [element,transformation]");return 0!==s.rotate&&a.addRotation(s.rotate),a},t.registerElement("image",t.createImage),{Image:t.Image,createImage:t.createImage}}), -define("base/ticks",["jxg","math/math","math/geometry","math/numerics","base/constants","base/element","base/coords","utils/type","base/text"],function(t,e,i,r,s,o,n,a,h){"use strict";return t.Ticks=function(t,i,r){if(this.constructor(t.board,r,s.OBJECT_TYPE_TICKS,s.OBJECT_CLASS_OTHER),this.line=t,this.board=this.line.board,this.ticksFunction=null,this.fixedTicks=null,this.equidistant=!1,this.labelsData=[],a.isFunction(i))throw this.ticksFunction=i,new Error("Function arguments are no longer supported.");a.isArray(i)?this.fixedTicks=i:((Math.abs(i)<e.eps||i<0)&&(i=r.defaultdistance),this.ticksFunction=this.makeTicksFunction(i),this.equidistant=!0),this.minTicksDistance=r.minticksdistance,this.ticks=[],this.ticksDelta=1,this.labels=[],this.labelData=[],this.labelCounter=0,this.id=this.line.addTicks(this),this.elType="ticks",this.inherits.push(this.labels),this.board.setId(this,"Ti")},t.Ticks.prototype=new o,t.extend(t.Ticks.prototype,{makeTicksFunction:function(t){return function(){var e,i,r;return a.evaluate(this.visProp.insertticks)?(i=this.getLowerAndUpperBounds(this.getZeroCoordinates(),"ticksdistance"),r=i.upper-i.lower,e=Math.pow(10,Math.floor(Math.log(.6*r)/Math.LN10)),r<=6*e&&(e*=.5),e):t}},hasPoint:function(t,i){var r,o,n,h,l=this.ticks&&this.ticks.length||0;if(a.isObject(a.evaluate(this.visProp.precision))?(h=this.board._inputDevice,n=a.evaluate(this.visProp.precision[h])):n=this.board.options.precision.hasPoint,n+=.5*a.evaluate(this.visProp.strokewidth),!a.evaluate(this.line.visProp.scalable)||this.line.elementClass===s.OBJECT_CLASS_CURVE)return!1;if(0!==this.line.stdform[1]&&0!==this.line.stdform[2]&&this.line.type!==s.OBJECT_TYPE_AXIS)return!1;for(r=0;r<l;r++)if(o=this.ticks[r],o[2]&&!(0===this.line.stdform[1]&&Math.abs(o[0][0]-this.line.point1.coords.scrCoords[1])<e.eps||0===this.line.stdform[2]&&Math.abs(o[1][0]-this.line.point1.coords.scrCoords[2])<e.eps)&&(Math.abs(o[0][0]-o[0][1])>=1||Math.abs(o[1][0]-o[1][1])>=1))if(0===this.line.stdform[1]){if(Math.abs(i-.5*(o[1][0]+o[1][1]))<2*n&&o[0][0]-n<t&&t<o[0][1]+n)return!0}else if(0===this.line.stdform[2]&&Math.abs(t-.5*(o[0][0]+o[0][1]))<2*n&&o[1][0]-n<i&&i<o[1][1]+n)return!0;return!1},setPositionDirectly:function(t,i,r){var o,h,l=new n(t,i,this.board),c=new n(t,r,this.board),d=this.board.getBoundingBox();return this.line.type===s.OBJECT_TYPE_AXIS&&a.evaluate(this.line.visProp.scalable)?(Math.abs(this.line.stdform[1])<e.eps&&Math.abs(l.usrCoords[1]*c.usrCoords[1])>e.eps?(o=c.usrCoords[1]/l.usrCoords[1],d[0]*=o,d[2]*=o,this.board.setBoundingBox(d,!1)):Math.abs(this.line.stdform[2])<e.eps&&Math.abs(l.usrCoords[2]*c.usrCoords[2])>e.eps&&(h=c.usrCoords[2]/l.usrCoords[2],d[3]*=h,d[1]*=h,this.board.setBoundingBox(d,!1)),this):this},calculateTicksCoordinates:function(){var t,i,r,o;if(!(this.line.elementClass===s.OBJECT_CLASS_LINE&&(this.setTicksSizeVariables(),Math.abs(this.dx)<e.eps&&Math.abs(this.dy)<e.eps)))return t=this.getZeroCoordinates(),i=this.line.elementClass===s.OBJECT_CLASS_LINE?this.getLowerAndUpperBounds(t):{lower:this.line.minX(),upper:this.line.maxX()},"polar"===a.evaluate(this.visProp.type)&&(o=this.board.getBoundingBox(),r=Math.max(Math.sqrt(o[0]*o[0]+o[1]*o[1]),Math.sqrt(o[2]*o[2]+o[3]*o[3])),i.upper=r),this.ticks=[],this.labelsData=[],this.equidistant?this.generateEquidistantTicks(t,i):this.generateFixedTicks(t,i),this},setTicksSizeVariables:function(t){var i,s,o,n,h=.5*a.evaluate(this.visProp.majorheight),l=.5*a.evaluate(this.visProp.minorheight);a.exists(t)?(s=this.line.minX(),o=this.line.maxX(),n=this.line.points.length,n<2?(this.dxMaj=0,this.dyMaj=0):e.relDif(t,s)<e.eps?(this.dxMaj=this.line.points[0].usrCoords[2]-this.line.points[1].usrCoords[2],this.dyMaj=this.line.points[1].usrCoords[1]-this.line.points[0].usrCoords[1]):e.relDif(t,o)<e.eps?(this.dxMaj=this.line.points[n-2].usrCoords[2]-this.line.points[n-1].usrCoords[2],this.dyMaj=this.line.points[n-1].usrCoords[1]-this.line.points[n-2].usrCoords[1]):(this.dxMaj=-r.D(this.line.Y)(t),this.dyMaj=r.D(this.line.X)(t))):(this.dxMaj=this.line.stdform[1],this.dyMaj=this.line.stdform[2]),this.dxMin=this.dxMaj,this.dyMin=this.dyMaj,this.dx=this.dxMaj,this.dy=this.dyMaj,i=Math.sqrt(this.dxMaj*this.dxMaj*this.board.unitX*this.board.unitX+this.dyMaj*this.dyMaj*this.board.unitY*this.board.unitY),this.dxMaj*=h/i*this.board.unitX,this.dyMaj*=h/i*this.board.unitY,this.dxMin*=l/i*this.board.unitX,this.dyMin*=l/i*this.board.unitY,this.minStyle=a.evaluate(this.visProp.minorheight)<0?"infinite":"finite",this.majStyle=a.evaluate(this.visProp.majorheight)<0?"infinite":"finite"},getZeroCoordinates:function(){var t,e,r,o,h,l,c,d,u=a.evaluate(this.visProp.anchor);return this.line.elementClass===s.OBJECT_CLASS_LINE?this.line.type===s.OBJECT_TYPE_AXIS?i.projectPointToLine({coords:{usrCoords:[1,0,0]}},this.line,this.board):(r=this.line.point1.coords.usrCoords[0],t=this.line.point1.coords.usrCoords[1],e=this.line.point1.coords.usrCoords[2],l=this.line.point2.coords.usrCoords[0],o=this.line.point2.coords.usrCoords[1],h=this.line.point2.coords.usrCoords[2],"right"===u?this.line.point2.coords:"middle"===u?new n(s.COORDS_BY_USER,[.5*(r+l),.5*(t+o),.5*(e+h)],this.board):a.isNumber(u)?new n(s.COORDS_BY_USER,[r+(l-r)*u,t+(o-t)*u,e+(h-e)*u],this.board):this.line.point1.coords):(c=this.line.minX(),d=this.line.maxX(),"right"===u?d:"middle"===u?.5*(c+d):a.isNumber(u)?c*(1-u)+d*u:c)},getLowerAndUpperBounds:function(t,r){var o,h,l,c,d,u,p,f,m,g,b=a.evaluate(this.line.visProp.straightfirst),v=a.evaluate(this.line.visProp.straightlast),y=a.evaluate(this.visProp.includeboundaries);return this.line.elementClass===s.OBJECT_CLASS_CURVE?{lower:this.line.minX(),upper:this.line.maxX()}:(d=new n(s.COORDS_BY_USER,this.line.point1.coords.usrCoords,this.board),u=new n(s.COORDS_BY_USER,this.line.point2.coords.usrCoords,this.board),p=Math.abs(d.usrCoords[0])>=e.eps&&d.scrCoords[1]>=0&&d.scrCoords[1]<=this.board.canvasWidth&&d.scrCoords[2]>=0&&d.scrCoords[2]<=this.board.canvasHeight,f=Math.abs(u.usrCoords[0])>=e.eps&&u.scrCoords[1]>=0&&u.scrCoords[1]<=this.board.canvasWidth&&u.scrCoords[2]>=0&&u.scrCoords[2]<=this.board.canvasHeight,a.exists(r)||"tickdistance"===r?i.calcStraight(this.line,d,u,a.evaluate(this.line.visProp.margin)):i.calcLineDelimitingPoints(this.line,d,u),l=a.evaluate(this.line.visProp.firstarrow),c=a.evaluate(this.line.visProp.lastarrow),(l||c)&&(this.board.renderer.getPositionArrowHead(this.line,d,u,a.evaluate(this.line.visProp.strokewidth)),l&&d.setCoordinates(s.COORDS_BY_SCREEN,[d.scrCoords[1],d.scrCoords[2]]),c&&u.setCoordinates(s.COORDS_BY_SCREEN,[u.scrCoords[1],u.scrCoords[2]])),m=this.getDistanceFromZero(t,d),g=this.getDistanceFromZero(t,u),m<g?(o=m,b||!p||y||(o+=e.eps),h=g,v||!f||y||(h-=e.eps)):g<m?(o=g,v||!f||y||(o+=e.eps),h=m,b||!p||y||(h-=e.eps)):(o=0,h=0),{lower:o,upper:h})},getDistanceFromZero:function(t,i){var r,o,n,a,h;return r=this.line.point1.coords,o=this.line.point2.coords,h=t.distance(s.COORDS_BY_USER,i),n=[o.usrCoords[0]-r.usrCoords[0],o.usrCoords[1]-r.usrCoords[1],o.usrCoords[2]-r.usrCoords[2]],a=[i.usrCoords[0]-t.usrCoords[0],i.usrCoords[1]-t.usrCoords[1],i.usrCoords[2]-t.usrCoords[2]],e.innerProduct(n,a,3)<0&&(h*=-1),h},generateEquidistantTicks:function(t,i){var r,o,n=e.eps,h=this.equidistant?this.ticksFunction(1):this.ticksDelta,l=a.evaluate(this.visProp.insertticks),c=a.evaluate(this.visProp.minorticks);if(this.line.elementClass===s.OBJECT_CLASS_LINE&&(o=this.getXandYdeltas()),h*=a.evaluate(this.visProp.scale),l&&this.minTicksDistance>e.eps?(h=this.adjustTickDistance(h,t,o),h/=c+1):l||(h/=c+1),this.ticksDelta=h,!(h<e.eps)){for(r=0,a.evaluate(this.visProp.drawzero)||(r=h);r<=i.upper+n;)r>=i.lower-n&&this.processTickPosition(t,r,h,o),r+=h;for(r=-h;r>=i.lower-n;)r<=i.upper+n&&this.processTickPosition(t,r,h,o),r-=h}},adjustTickDistance:function(t,e,i){var r,o,h,l=1,c=a.evaluate(this.visProp.minorticks);if(this.line.elementClass===s.OBJECT_CLASS_CURVE)return t;if(this.getLowerAndUpperBounds(e,"ticksdistance"),r=e.usrCoords[1]+i.x*t,o=e.usrCoords[2]+i.y*t,h=e.distance(s.COORDS_BY_SCREEN,new n(s.COORDS_BY_USER,[r,o],this.board)),0===t)return 0;for(;h/(c+1)<this.minTicksDistance;)t*=1===l?2:5,l*=-1,r=e.usrCoords[1]+i.x*t,o=e.usrCoords[2]+i.y*t,h=e.distance(s.COORDS_BY_SCREEN,new n(s.COORDS_BY_USER,[r,o],this.board));return t},processTickPosition:function(t,e,i,r){var o,h,l,c,d=null;this.line.elementClass===s.OBJECT_CLASS_LINE?(o=t.usrCoords[1]+e*r.x,h=t.usrCoords[2]+e*r.y):(o=this.line.X(t+e),h=this.line.Y(t+e)),l=new n(s.COORDS_BY_USER,[o,h],this.board),this.line.elementClass===s.OBJECT_CLASS_CURVE&&(d=t+e,this.setTicksSizeVariables(d)),l.major=Math.round(e/i)%(a.evaluate(this.visProp.minorticks)+1)==0,c=this.createTickPath(l,l.major),3===c.length&&(this.ticks.push(c),l.major&&a.evaluate(this.visProp.drawlabels)?this.labelsData.push(this.generateLabelData(this.generateLabelText(l,t,d),l,this.ticks.length)):this.labelsData.push(null))},generateFixedTicks:function(t,i){var r,o,h,l,c,d,u,p,f=e.eps,m=a.isArray(this.visProp.labels),g=a.evaluate(this.visProp.drawlabels);for(this.line.elementClass===s.OBJECT_CLASS_LINE&&(p=this.getXandYdeltas()),h=0;h<this.fixedTicks.length;h++)this.line.elementClass===s.OBJECT_CLASS_LINE?(u=this.fixedTicks[h],c=t.usrCoords[1]+u*p.x,d=t.usrCoords[2]+u*p.y):(u=t+this.fixedTicks[h],c=this.line.X(u),d=this.line.Y(u)),r=new n(s.COORDS_BY_USER,[c,d],this.board),this.line.elementClass===s.OBJECT_CLASS_CURVE&&this.setTicksSizeVariables(u),l=this.createTickPath(r,!0),3===l.length&&u>=i.lower-f&&u<=i.upper+f&&(this.ticks.push(l),g&&(m||a.exists(this.visProp.labels[h]))?(o=m?a.evaluate(this.visProp.labels[h]):u,this.labelsData.push(this.generateLabelData(this.generateLabelText(r,t,o),r,h))):this.labelsData.push(null))},getXandYdeltas:function(){var t,i,r=this.line.point1.Dist(this.line.point2);return this.line.type===s.OBJECT_TYPE_AXIS?(t=this.line.point1.coords.usrCoords,i=this.line.point2.coords.usrCoords,(t[1]>i[1]||Math.abs(t[1]-i[1])<e.eps&&t[2]>i[2])&&(t=this.line.point2.coords.usrCoords,i=this.line.point1.coords.usrCoords)):(t=this.line.point1.coords.usrCoords,i=this.line.point2.coords.usrCoords),{x:(i[1]-t[1])/r,y:(i[2]-t[2])/r}},_isInsideCanvas:function(t,e,i){var r=this.board.canvasWidth,s=this.board.canvasHeight;return void 0===i&&(i=0),t[0]>=i&&t[0]<=r-i&&e[0]>=i&&e[0]<=s-i||t[1]>=i&&t[1]<=r-i&&e[1]>=i&&e[1]<=s-i},createTickPath:function(t,e){var r,s,o,n,h,l,c,d,u,p,f,m,g,b,v,y=[-2e6,-2e6],C=[-2e6,-2e6];if(r=t.scrCoords,e?(n=this.dxMaj,h=this.dyMaj,u=this.majStyle):(n=this.dxMin,h=this.dyMin,u=this.minStyle),s=[-h*r[1]-n*r[2],h,n],e&&"polar"===a.evaluate(this.visProp.type)){if(g=this.board.getBoundingBox(),b=2*Math.PI,v=b/180,r=t.usrCoords,f=Math.sqrt(r[1]*r[1]+r[2]*r[2]),m=Math.max(Math.sqrt(g[0]*g[0]+g[1]*g[1]),Math.sqrt(g[2]*g[2]+g[3]*g[3])),f<m){for(y=[],C=[],p=0;p<=b;p+=v)y.push(this.board.origin.scrCoords[1]+f*Math.cos(p)*this.board.unitX),C.push(this.board.origin.scrCoords[2]+f*Math.sin(p)*this.board.unitY);return[y,C,e]}}else if("infinite"===u?(o=i.meetLineBoard(s,this.board),y[0]=o[0].scrCoords[1],y[1]=o[1].scrCoords[1],C[0]=o[0].scrCoords[2],C[1]=o[1].scrCoords[2]):(d=">"===a.evaluate(this.visProp.face)?Math.PI/4:"<"===a.evaluate(this.visProp.face)?-Math.PI/4:0,l=Math.cos(d)*n-Math.sin(d)*h,c=Math.sin(d)*n+Math.cos(d)*h,y[0]=r[1]+l*a.evaluate(this.visProp.tickendings[0]),C[0]=r[2]-c*a.evaluate(this.visProp.tickendings[0]),y[1]=r[1],C[1]=r[2],d=-d,l=Math.cos(d)*n-Math.sin(d)*h,c=Math.sin(d)*n+Math.cos(d)*h,y[2]=r[1]-l*a.evaluate(this.visProp.tickendings[1]),C[2]=r[2]+c*a.evaluate(this.visProp.tickendings[1])),this._isInsideCanvas(y,C))return[y,C,e];return[]},formatLabelText:function(t){var e=t.toString(),i=a.evaluate(this.visProp.scalesymbol);return a.isNumber(t)&&((e.length>a.evaluate(this.visProp.maxlabellength)||-1!==e.indexOf("e"))&&(e=t.toPrecision(a.evaluate(this.visProp.precision)).toString()),a.evaluate(this.visProp.beautifulscientificticklabels)&&(e=this.beautifyScientificNotationLabel(e)),e.indexOf(".")>-1&&-1===e.indexOf("e")&&(e=e.replace(/0+$/,""),e=e.replace(/\.$/,""))),i.length>0&&("1"===e?e=i:"-1"===e?e="-"+i:"0"!==e&&(e+=i)),a.evaluate(this.visProp.useunicodeminus)&&(e=e.replace(/-/g,"−")),e},beautifyScientificNotationLabel:function(t){var e;return-1===t.indexOf("e")?t:(e=parseFloat(t.substring(0,t.indexOf("e")))+t.substring(t.indexOf("e")),e=e.replace(/e(.*)$/g,function(t,e){var i="•10";return i+=e.replace(/-/g,"⁻").replace(/\+/g,"").replace(/0/g,"⁰").replace(/1/g,"¹").replace(/2/g,"²").replace(/3/g,"³").replace(/4/g,"⁴").replace(/5/g,"⁵").replace(/6/g,"⁶").replace(/7/g,"⁷").replace(/8/g,"⁸").replace(/9/g,"⁹")}))},generateLabelText:function(t,i,r){var s;if(!a.exists(r)){if(s=this.getDistanceFromZero(i,t),Math.abs(s)<e.eps)return"0";r=s/a.evaluate(this.visProp.scale)}return this.formatLabelText(r)},generateLabelData:function(t,e,i){var r,s,o,n;return n=a.evaluate(this.visProp.label.fontsize),r=[e.scrCoords[1],e.scrCoords[1]],s=[e.scrCoords[2],e.scrCoords[2]],o=void 0===n?12:n,o*=.5,this._isInsideCanvas(r,s,o)?(r=a.evaluate(this.visProp.label.offset[0]),s=a.evaluate(this.visProp.label.offset[1]),{x:e.usrCoords[1]+r/this.board.unitX,y:e.usrCoords[2]+s/this.board.unitY,t:t,i:i}):null},update:function(){return this.needsUpdate&&0!==this.board.canvasWidth&&0!==this.board.canvasHeight&&this.calculateTicksCoordinates(),this},updateRenderer:function(){return this.needsUpdate?(this.visPropCalc.visible&&this.board.renderer.updateTicks(this),this.updateRendererLabels(),this.setDisplayRendNode(),this.needsUpdate=!1,this):this},updateRendererLabels:function(){var t,e,i,r,s,o,n,l;for(i=this.labelsData.length,r=this.labels.length,t=0,e=0;t<i;t++)null!==this.labelsData[t]&&(n=this.labelsData[t],e<r?(o=this.labels[e],o.setText(n.t),o.setCoords(n.x,n.y),e++):(this.labelCounter+=1,s={isLabel:!0,layer:this.board.options.layer.line,highlightStrokeColor:this.board.options.text.strokeColor,highlightStrokeWidth:this.board.options.text.strokeWidth,highlightStrokeOpacity:this.board.options.text.strokeOpacity,priv:this.visProp.priv},s=a.deepCopy(s,this.visProp.label),s.id=this.id+n.i+"Label"+this.labelCounter,o=h.createText(this.board,[n.x,n.y,n.t],s),o.isDraggable=!1,o.dump=!1,this.labels.push(o)),l=a.evaluate(this.visProp.label.visible),"inherit"===l&&(l=this.visPropCalc.visible),o.prepareUpdate().updateVisibility(l).updateRenderer(),o.distanceX=a.evaluate(this.visProp.label.offset[0]),o.distanceY=a.evaluate(this.visProp.label.offset[1]));for(i=e,e=i;e<r;e++)this.board.renderer.display(this.labels[e],!1),this.labels[e].visProp.visible=this.labels[e].visPropCalc.visible=!1;return this},hideElement:function(){var e;for(t.deprecated("Element.hideElement()","Element.setDisplayRendNode()"),this.visPropCalc.visible=!1,this.board.renderer.display(this,!1),e=0;e<this.labels.length;e++)a.exists(this.labels[e])&&this.labels[e].hideElement();return this},showElement:function(){var e;for(t.deprecated("Element.showElement()","Element.setDisplayRendNode()"),this.visPropCalc.visible=!0,this.board.renderer.display(this,!1),e=0;e<this.labels.length;e++)a.exists(this.labels[e])&&this.labels[e].showElement();return this}}),t.createTicks=function(e,i,r){var o,n,h=a.copyAttributes(r,e.options,"ticks");if(n=i.length<2?h.ticksdistance:i[1],i[0].elementClass!==s.OBJECT_CLASS_LINE&&i[0].elementClass!==s.OBJECT_CLASS_CURVE)throw new Error("JSXGraph: Can't create Ticks with parent types '"+typeof i[0]+"'.");return o=new t.Ticks(i[0],n,h),a.isFunction(h.generatelabelvalue)&&(o.generateLabelText=h.generatelabelvalue),a.isFunction(h.generatelabeltext)&&(o.generateLabelText=h.generatelabeltext),o.setParents(i[0]),o.isDraggable=!0,o.fullUpdate(i[0].visPropCalc.visible),o},t.createHatchmark=function(t,e,i){var r,o,n,h,l,c,d=[],u=a.copyAttributes(i,t.options,"hatch");if(e[0].elementClass!==s.OBJECT_CLASS_LINE&&e[0].elementClass!==s.OBJECT_CLASS_CURVE||"number"!=typeof e[1])throw new Error("JSXGraph: Can't create Hatch mark with parent types '"+typeof e[0]+"' and '"+typeof e[1]+" and ''"+typeof e[2]+"'.");for(r=e[1],h=u.ticksdistance,l=(r-1)*h,n=.5*-l,o=0;o<r;o++)d[o]=n+o*h;return c=t.create("ticks",[e[0],d],u),c.elType="hatch",c},t.registerElement("ticks",t.createTicks),t.registerElement("hash",t.createHatchmark),t.registerElement("hatch",t.createHatchmark),{Ticks:t.Ticks,createTicks:t.createTicks,createHashmark:t.createHatchmark,createHatchmark:t.createHatchmark}}),define("element/slider",["jxg","math/math","base/constants","base/coords","utils/type","base/point","base/group","base/element","base/line","base/ticks","base/text"],function(t,e,i,r,s,o,n,a,h,l,c){"use strict";return t.createSlider=function(t,n,a){var h,l,c,d,u,p,f,m,g,b,v,y,C,_,P,E,x,S,w,O,T,N,M;return N=s.copyAttributes(a,t.options,"slider"),S=N.withticks,x=N.withlabel,w=N.snapwidth,M=N.precision,N=s.copyAttributes(a,t.options,"slider","point1"),f=t.create("point",n[0],N),N=s.copyAttributes(a,t.options,"slider","point2"),m=t.create("point",n[1],N),N=s.copyAttributes(a,t.options,"slider","baseline"),g=t.create("segment",[f,m],N),g.updateStdform(),h=f.coords.usrCoords.slice(1),l=m.coords.usrCoords.slice(1),c=n[2][0],d=n[2][1],u=n[2][2],p=u-c,O=s.evaluate(w),T=-1==O?d:Math.round(d/O)*O,y=h[0]+(l[0]-h[0])*(T-c)/(u-c),C=h[1]+(l[1]-h[1])*(T-c)/(u-c),N=s.copyAttributes(a,t.options,"slider"),N.withLabel=!1,_=t.create("glider",[y,C,g],N),_.setAttribute({snapwidth:w}),N=s.copyAttributes(a,t.options,"slider","highline"),P=t.create("segment",[f,_],N),_.Value=function(){var t=this._smax-this._smin,e=s.evaluate(this.visProp.snapwidth);return-1===e?this.position*t+this._smin:Math.round((this.position*t+this._smin)/e)*e},_.methodMap=s.deepCopy(_.methodMap,{Value:"Value",setValue:"setValue",smax:"_smax",smin:"_smin",setMax:"setMax",setMin:"setMin"}),_._smax=u,_._smin=c,_.setMax=function(t){return this._smax=t,this},_.setValue=function(t){var i=this._smax-this._smin;return Math.abs(i)>e.eps?this.position=(t-this._smin)/i:this.position=0,this.position=Math.max(0,Math.min(1,this.position)),this},_.setMin=function(t){return this._smin=t,this},x&&(N=s.copyAttributes(a,t.options,"slider","label"),E=t.create("text",[function(){return.05*(m.X()-f.X())+m.X()},function(){return.05*(m.Y()-f.Y())+m.Y()},function(){var t,e=s.evaluate(_.visProp.suffixlabel),i=s.evaluate(_.visProp.unitlabel),r=s.evaluate(_.visProp.postlabel);return t=null!==e?e:_.name&&""!==_.name?_.name+" = ":"",t+=s.toFixed(_.Value(),M),null!==i&&(t+=i),null!==r&&(t+=r),t}],N),_.label=E,_.visProp.withlabel=!0,_.hasLabel=!0),_.point1=f,_.point2=m,_.baseline=g,_.highline=P,S&&(N=s.copyAttributes(a,t.options,"slider","ticks"),s.exists(N.generatelabeltext)||(N.generateLabelText=function(t,i,r){var s=_.point1.Dist(_.point2),o=_._smin,n=_._smax,a=this.getDistanceFromZero(i,t)*(n-o)/s+o;return s<e.eps||Math.abs(a)<e.eps?"0":this.formatLabelText(a)}),b=2,v=t.create("ticks",[_.baseline,_.point1.Dist(f)/b,function(t){var r=_.point1.Dist(_.point2),s=_.point1.coords.distance(i.COORDS_BY_USER,t);return r<e.eps?0:s/r*p+c}],N),_.ticks=v),_.remove=function(){x&&t.removeObject(E),t.removeObject(P),t.removeObject(g),t.removeObject(m),t.removeObject(f),o.Point.prototype.remove.call(_)},f.dump=!1,m.dump=!1,g.dump=!1,P.dump=!1,_.elType="slider",_.parents=n,_.subs={point1:f,point2:m,baseLine:g,highLine:P},_.inherits.push(f,m,g,P),S&&(v.dump=!1,_.subs.ticks=v,_.inherits.push(v)),_.baseline.on("up",function(t){var e,o;s.evaluate(_.visProp.moveonup)&&!s.evaluate(_.visProp.fixed)&&(e=g.board.getMousePosition(t,0),o=new r(i.COORDS_BY_SCREEN,e,this.board),_.moveTo([o.usrCoords[1],o.usrCoords[2]]))}),_.prepareUpdate().update(),t.isSuspendedUpdate||(_.updateVisibility().updateRenderer(),_.baseline.updateVisibility().updateRenderer(),_.highline.updateVisibility().updateRenderer(),S&&_.ticks.updateVisibility().updateRenderer()),_},t.registerElement("slider",t.createSlider),{createSlider:t.createSlider}}),define("element/measure",["jxg","utils/type","base/element","base/point","base/line","base/ticks"],function(t,e,i,r,s,o){"use strict";return t.createTapemeasure=function(r,s,o){var n,a,h,l,c,d,u,p,f,m,g;return n=s[0],a=s[1],h=e.copyAttributes(o,r.options,"tapemeasure","point1"),p=r.create("point",n,h),h=e.copyAttributes(o,r.options,"tapemeasure","point2"),f=r.create("point",a,h),p.setAttribute({ignoredSnapToPoints:[f]}),f.setAttribute({ignoredSnapToPoints:[p]}),h=e.copyAttributes(o,r.options,"tapemeasure"),l=h.withticks,c=h.withlabel,d=h.precision,c&&(h.withlabel=!0),u=r.create("segment",[p,f],h),c&&(m=o.name&&""!==o.name?o.name+" = ":"",u.label.setText(function(){return m+e.toFixed(p.Dist(f),d)})),l&&(h=e.copyAttributes(o,r.options,"tapemeasure","ticks"),g=r.create("ticks",[u,.1],h),u.inherits.push(g)),u.remove=function(){l&&u.removeTicks(g),r.removeObject(f),r.removeObject(p),i.prototype.remove.call(this)},u.Value=function(){return p.Dist(f)},p.dump=!1,f.dump=!1,u.elType="tapemeasure",u.getParents=function(){return[[p.X(),p.Y()],[f.X(),f.Y()]]},u.subs={point1:p,point2:f},l&&(g.dump=!1),u.methodMap=t.deepCopy(u.methodMap,{Value:"Value"}),u.prepareUpdate().update(),r.isSuspendedUpdate||(u.updateVisibility().updateRenderer(),u.point1.updateVisibility().updateRenderer(),u.point2.updateVisibility().updateRenderer()),u},t.registerElement("tapemeasure",t.createTapemeasure),{createTapemeasure:t.createTapemeasure}}),define("parser/datasource",["jxg","utils/type"],function(t,e){"use strict";return t.DataSource=function(){return this.data=[],this.columnHeaders=[],this.rowHeaders=[],this},t.extend(t.DataSource.prototype,{loadFromArray:function(t,i,r){var s,o,n;if(e.isArray(i)&&(this.columnHeaders=i,i=!1),e.isArray(r)&&(this.rowHeaders=r,r=!1),this.data=[],i&&(this.columnHeaders=[]),r&&(this.rowHeaders=[]),e.exists(t)){for(this.data=[],s=0;s<t.length;s++)for(this.data[s]=[],o=0;o<t[s].length;o++)n=t[s][o],parseFloat(n).toString()===n?this.data[s][o]=parseFloat(n):this.data[s][o]="-"!==n?n:NaN;if(i&&(this.columnHeaders=this.data[0].slice(1),this.data=this.data.slice(1)),r)for(this.rowHeaders=[],s=0;s<this.data.length;s++)this.rowHeaders.push(this.data[s][0]),this.data[s]=this.data[s].slice(1)}return this},loadFromTable:function(t,i,r){var s,o,n,a,h;if(e.isArray(i)&&(this.columnHeaders=i,i=!1),e.isArray(r)&&(this.rowHeaders=r,r=!1),this.data=[],i&&(this.columnHeaders=[]),r&&(this.rowHeaders=[]),t=document.getElementById(t),e.exists(t)){for(s=t.getElementsByTagName("tr"),this.data=[],o=0;o<s.length;o++)for(a=s[o].getElementsByTagName("td"),this.data[o]=[],n=0;n<a.length;n++)h=a[n].innerHTML,parseFloat(h).toString()===h?this.data[o][n]=parseFloat(h):this.data[o][n]="-"!==h?h:NaN;if(i&&(this.columnHeaders=this.data[0].slice(1),this.data=this.data.slice(1)),r)for(this.rowHeaders=[],o=0;o<this.data.length;o++)this.rowHeaders.push(this.data[o][0]),this.data[o]=this.data[o].slice(1)}return this},addColumn:function(t,e,i){throw new Error("not implemented")},addRow:function(t,e,i){throw new Error("not implemented")},getColumn:function(t){var i,r=[];if(e.isString(t))for(i=0;i<this.columnHeaders.length;i++)if(t===this.columnHeaders[i]){t=i;break}for(i=0;i<this.data.length;i++)this.data[i].length>t&&(r[i]=parseFloat(this.data[i][t]));return r},getRow:function(t){var i,r;if(e.isString(t))for(r=0;r<this.rowHeaders.length;r++)if(t===this.rowHeaders[r]){t=r;break}for(i=[],r=0;r<this.data[t].length;r++)i[r]=this.data[t][r];return i}}),t.DataSource}),define("base/chart",["jxg","math/numerics","math/statistics","base/constants","base/coords","base/element","parser/datasource","utils/color","utils/type","utils/env","base/curve","base/point","base/text","base/polygon","element/sector","base/transformation","base/line","base/circle"],function(t,e,i,r,s,o,n,a,h,l,c,d,u,p,f,m,g,b){"use strict";return t.Chart=function(t,e,i){this.constructor(t,i);var r,s,o,n,a,l;if(!h.isArray(e)||0===e.length)throw new Error("JSXGraph: Can't create a chart without data");if(this.elements=[],h.isNumber(e[0]))for(s=e,r=[],o=0;o<s.length;o++)r[o]=o+1;else if(1===e.length&&h.isArray(e[0]))for(s=e[0],r=[],l=h.evaluate(s).length,o=0;o<l;o++)r[o]=o+1;else 2===e.length&&(l=Math.min(e[0].length,e[1].length),r=e[0].slice(0,l),s=e[1].slice(0,l));if(h.isArray(s)&&0===s.length)throw new Error("JSXGraph: Can't create charts without data.");for(a=i.chartstyle.replace(/ /g,"").split(","),o=0;o<a.length;o++){switch(a[o]){case"bar":n=this.drawBar(t,r,s,i);break;case"line":n=this.drawLine(t,r,s,i);break;case"fit":n=this.drawFit(t,r,s,i);break;case"spline":n=this.drawSpline(t,r,s,i);break;case"pie":n=this.drawPie(t,s,i);break;case"point":n=this.drawPoints(t,r,s,i);break;case"radar":n=this.drawRadar(t,e,i)}this.elements.push(n)}return this.id=this.board.setId(this,"Chart"),this.elements},t.Chart.prototype=new o,t.extend(t.Chart.prototype,{drawLine:function(t,e,i,r){return r.fillcolor="none",r.highlightfillcolor="none",t.create("curve",[e,i],r)},drawSpline:function(t,e,i,r){return r.fillColor="none",r.highlightfillcolor="none",t.create("spline",[e,i],r)},drawFit:function(t,i,r,s){var o=s.degree;return o=Math.max(parseInt(o,10),1)||1,s.fillcolor="none",s.highlightfillcolor="none",t.create("functiongraph",[e.regressionPolynomial(o,i,r)],s)},drawBar:function(t,e,i,r){var s,o,n,a,l,c,d,u,p,f,m=[],g=[],b=function(t,i){return function(){return e[t]()-i*n}},v={fixed:!0,withLabel:!1,visible:!1,name:""};if((p=h.copyAttributes(r,t.options,"chart"))&&p.width)n=p.width;else{if(e.length<=1)n=1;else for(n=e[1]-e[0],s=1;s<e.length-1;s++)n=e[s+1]-e[s]<n?e[s+1]-e[s]:n;n*=.8}for(f=h.copyAttributes(r,t.options,"chart","label"),s=0;s<e.length;s++)h.isFunction(e[s])?(a=b(s,-.5),l=b(s,0),c=b(s,.5)):(a=e[s]-.5*n,l=e[s],c=e[s]+.5*n),d=h.isFunction(i[s])?i[s]():i[s],d=i[s],"horizontal"===p.dir?(g[0]=t.create("point",[0,a],v),g[1]=t.create("point",[d,a],v),g[2]=t.create("point",[d,c],v),g[3]=t.create("point",[0,c],v),h.exists(p.labels)&&h.exists(p.labels[s])&&(f.anchorY="middle",o=t.create("text",[d,l,p.labels[s]],f),o.visProp.anchorx=function(t){return function(){return t.X()>=0?"left":"right"}}(o))):(g[0]=t.create("point",[a,0],v),g[1]=t.create("point",[a,d],v),g[2]=t.create("point",[c,d],v),g[3]=t.create("point",[c,0],v),h.exists(p.labels)&&h.exists(p.labels[s])&&(f.anchorX="middle",o=t.create("text",[l,d,p.labels[s]],f),o.visProp.anchory=function(t){return function(){return t.Y()>=0?"bottom":"top"}}(o))),h.isArray(p.colors)&&(u=p.colors,p.fillcolor=u[s%u.length]),m[s]=t.create("polygon",g,p),h.exists(p.labels)&&h.exists(p.labels[s])&&(m[s].text=o);return m},drawPoints:function(t,e,i,r){var s,o=[],n=r.infoboxarray;for(r.fixed=!0,r.name="",s=0;s<e.length;s++)r.infoboxtext=!!n&&n[s%n.length],o[s]=t.create("point",[e[s],i[s]],r);return o},drawPie:function(t,e,o){var n,a,l=[],c=[],d=(i.sum(e),o.colors),u=o.highlightcolors,p=o.labels,f=o.radius||4,m=f,g=o.center||[0,0],b=g[0],v=g[1],y=function(t,i,r){return function(){var s,o,n,a=0;for(o=0;o<=t;o++)a+=parseFloat(h.evaluate(e[o]));for(s=a,o=t+1;o<e.length;o++)s+=parseFloat(h.evaluate(e[o]));return n=0!==s?2*Math.PI*a/s:0,m()*Math[i](n)+r}},C=function(t,e){var i=-this.point1.coords.usrCoords[1]+this.point2.coords.usrCoords[1],o=-this.point1.coords.usrCoords[2]+this.point2.coords.usrCoords[2];h.exists(this.label)&&(this.label.rendNode.style.fontSize=e*h.evaluate(this.label.visProp.fontsize)+"px",this.label.fullUpdate()),this.point2.coords=new s(r.COORDS_BY_USER,[this.point1.coords.usrCoords[1]+i*t,this.point1.coords.usrCoords[2]+o*t],this.board),this.fullUpdate()},_=function(){this.highlighted||(this.highlighted=!0,this.board.highlightedObjects[this.id]=this,this.board.renderer.highlight(this),C.call(this,1.1,2))},P=function(){this.highlighted&&(this.highlighted=!1,this.board.renderer.noHighlight(this),C.call(this,.9090909,1))},E={fixed:!0,withLabel:!1,visible:!1,name:""};if(!h.isArray(p))for(p=[],n=0;n<e.length;n++)p[n]="";for(h.isFunction(f)||(m=function(){return f}),o.highlightonsector=o.highlightonsector||!1,o.straightfirst=!1,o.straightlast=!1,a=t.create("point",[b,v],E),l[0]=t.create("point",[function(){return m()+b},function(){return v}],E),n=0;n<e.length;n++)l[n+1]=t.create("point",[y(n,"cos",b),y(n,"sin",v)],E),o.name=p[n],o.withlabel=""!==o.name,o.fillcolor=d&&d[n%d.length],o.labelcolor=d&&d[n%d.length],o.highlightfillcolor=u&&u[n%u.length],c[n]=t.create("sector",[a,l[n],l[n+1]],o),o.highlightonsector&&(c[n].hasPoint=c[n].hasPointSector),o.highlightbysize&&(c[n].highlight=_,c[n].noHighlight=P);return{sectors:c,points:l,midpoint:a}},drawRadar:function(e,i,o){var n,a,l,c,d,u,p,f,m,g,b,v,y,C,_,P,E,x,S,w,O,T,N,M,A,R,L,k,B,I,Y,D,j,X,G,F,U,J,z,H,V,$,q,W=i.length,Z=function(){var t,e,i,o,n=h.evaluate(this.visProp.label.offset).slice(0);return t=this.point1.X(),e=this.point2.X(),i=this.point1.Y(),o=this.point2.Y(),e<t&&(n[0]=-n[0]),o<i&&(n[1]=-n[1]),this.setLabelRelativeCoords(n),new s(r.COORDS_BY_USER,[this.point2.X(),this.point2.Y()],this.board)},Q=function(t,i){var r,s,o;return r=e.create("transform",[-(_[i]-y[i]),0],{type:"translate"}),s=e.create("transform",[S/(P[i]+C[i]-(_[i]-y[i])),1],{type:"scale"}),r.melt(s),o=e.create("transform",[t],{type:"rotate"}),r.melt(o),r};if(W<=0)throw new Error("JSXGraph radar chart: no data");if(l=o.paramarray,!h.exists(l))throw new Error("JSXGraph radar chart: need paramArray attribute");if((c=l.length)<=1)throw new Error("JSXGraph radar chart: need more than one param in paramArray");for(n=0;n<W;n++)if(c!==i[n].length)throw new Error("JSXGraph radar chart: use data length equal to number of params ("+i[n].length+" != "+c+")");for(d=[],u=[],a=0;a<c;a++)d[a]=i[0][a],u[a]=d[a];for(n=1;n<W;n++)for(a=0;a<c;a++)i[n][a]>d[a]&&(d[a]=i[n][a]),i[n][a]<u[a]&&(u[a]=i[n][a]);for(p=[],f=[],n=0;n<W;n++)p[n]="",f[n]=[];for(m=[],g=[],b=o.startshiftratio||0,v=o.endshiftratio||0,n=0;n<c;n++)m[n]=(d[n]-u[n])*b,g[n]=(d[n]-u[n])*v;if(y=o.startshiftarray||m,C=o.endshiftarray||g,_=o.startarray||u,h.exists(o.start))for(n=0;n<c;n++)_[n]=o.start;if(P=o.endarray||d,h.exists(o.end))for(n=0;n<c;n++)P[n]=o.end;if(y.length!==c)throw new Error("JSXGraph radar chart: start shifts length is not equal to number of parameters");if(C.length!==c)throw new Error("JSXGraph radar chart: end shifts length is not equal to number of parameters");if(_.length!==c)throw new Error("JSXGraph radar chart: starts length is not equal to number of parameters");if(P.length!==c)throw new Error("JSXGraph radar chart: snds length is not equal to number of parameters");for(E=o.labelarray||p,x=o.colors,o.highlightcolors,S=o.radius||10,$=o.strokewidth||1,h.exists(o.highlightonsector)||(o.highlightonsector=!1),w={name:o.name,id:o.id,strokewidth:$,polystrokewidth:o.polystrokewidth||$,strokecolor:o.strokecolor||"black",straightfirst:!1,straightlast:!1,fillcolor:o.fillColor||"#FFFF88",fillopacity:o.fillOpacity||.4,highlightfillcolor:o.highlightFillColor||"#FF7400",highlightstrokecolor:o.highlightStrokeColor||"black",gradient:o.gradient||"none"},O=o.center||[0,0],T=O[0],N=O[1],M=e.create("point",[T,N],{name:"",fixed:!0,withlabel:!1,visible:!1}),A=Math.PI/2-Math.PI/c,A=o.startangle||0,R=A,L=[],k=[],n=0;n<c;n++)for(R+=2*Math.PI/c,I=S*Math.cos(R)+T,Y=S*Math.sin(R)+N,L[n]=e.create("point",[I,Y],{name:"",fixed:!0,withlabel:!1,visible:!1}),k[n]=e.create("line",[M,L[n]],{name:l[n],strokeColor:w.strokecolor,strokeWidth:w.strokewidth,strokeOpacity:1,straightFirst:!1,straightLast:!1,withLabel:!0,highlightStrokeColor:w.highlightstrokecolor}),k[n].getLabelAnchor=Z,B=Q(R,n),a=0;a<i.length;a++)q=i[a][n],f[a][n]=e.create("point",[q,0],{name:"",fixed:!0,withlabel:!1,visible:!1}),f[a][n].addTransform(f[a][n],B);for(D=[],n=0;n<W;n++)for(w.labelcolor=x&&x[n%x.length],w.strokecolor=x&&x[n%x.length],w.fillcolor=x&&x[n%x.length],D[n]=e.create("polygon",f[n],{withLines:!0,withLabel:!1,fillColor:w.fillcolor,fillOpacity:w.fillopacity,highlightFillColor:w.highlightfillcolor}),a=0;a<c;a++)D[n].borders[a].setAttribute("strokecolor:"+x[n%x.length]),D[n].borders[a].setAttribute("strokewidth:"+w.polystrokewidth);switch(o.legendposition||"none"){case"right":X=o.legendleftoffset||2,G=o.legendtopoffset||1, -this.legend=e.create("legend",[T+S+X,N+S-G],{labels:E,colors:x});break;case"none":break;default:t.debug("Unknown legend position")}if(j=[],o.showcircles){for(F=[],n=0;n<6;n++)F[n]=20*n;if(F[0]="0",U=o.circlelabelarray||F,(J=U.length)<2)throw new Error("JSXGraph radar chart: too less circles in circleLabelArray");for(z=[],H=A+Math.PI/c,B=Q(H,0),w.fillcolor="none",w.highlightfillcolor="none",w.strokecolor=o.strokecolor||"black",w.strokewidth=o.circlestrokewidth||.5,w.layer=0,V=(P[0]-_[0])/(J-1),n=0;n<J;n++)z[n]=e.create("point",[_[0]+n*V,0],{name:U[n],size:0,fixed:!0,withLabel:!0,visible:!0}),z[n].addTransform(z[n],B),j[n]=e.create("circle",[M,z[n]],w)}return this.rendNode=D[0].rendNode,{circles:j,lines:k,points:f,midpoint:M,polygons:D}},updateRenderer:function(){return this},update:function(){return this.needsUpdate&&this.updateDataArray(),this},updateDataArray:function(){return this}}),t.createChart=function(e,i,r){var s,o,c,d,u,p,f,m,g,b,v,y,C,_,P,E,x=[],S=l.isBrowser?e.document.getElementById(i[0]):null;if(1===i.length&&h.isString(i[0])){if(h.exists(S)){if(g=h.copyAttributes(r,e.options,"chart"),S=(new n).loadFromTable(i[0],g.withheaders,g.withheaders),s=S.data,u=S.columnHeaders,o=S.rowHeaders,b=g.width,v=g.name,y=g.strokecolor,C=g.fillcolor,_=g.highlightstrokecolor,P=g.highlightfillcolor,e.suspendUpdate(),E=s.length,m=[],g.rows&&h.isArray(g.rows)){for(c=0;c<E;c++)for(d=0;d<g.rows.length;d++)if(g.rows[d]===c||g.withheaders&&g.rows[d]===o[c]){m.push(s[c]);break}}else m=s;for(E=m.length,c=0;c<E;c++){if(f=[],g.chartstyle&&-1!==g.chartstyle.indexOf("bar")){for(p=b||.8,f.push(1-p/2+(c+.5)*p/E),d=1;d<m[c].length;d++)f.push(f[d-1]+1);g.width=p/E}v&&v.length===E?g.name=v[c]:g.withheaders&&(g.name=u[c]),y&&y.length===E?g.strokecolor=y[c]:g.strokecolor=a.hsv2rgb((c+1)/E*360,.9,.6),C&&C.length===E?g.fillcolor=C[c]:g.fillcolor=a.hsv2rgb((c+1)/E*360,.9,1),_&&_.length===E?g.highlightstrokecolor=_[c]:g.highlightstrokecolor=a.hsv2rgb((c+1)/E*360,.9,1),P&&P.length===E?g.highlightfillcolor=P[c]:g.highlightfillcolor=a.hsv2rgb((c+1)/E*360,.9,.6),g.chartstyle&&-1!==g.chartstyle.indexOf("bar")?x.push(new t.Chart(e,[f,m[c]],g)):x.push(new t.Chart(e,[m[c]],g))}e.unsuspendUpdate()}return x}return g=h.copyAttributes(r,e.options,"chart"),new t.Chart(e,i,g)},t.registerElement("chart",t.createChart),t.Legend=function(t,e,i){var o;if(this.constructor(),o=h.copyAttributes(i,t.options,"legend"),this.board=t,this.coords=new s(r.COORDS_BY_USER,e,this.board),this.myAtts={},this.label_array=o.labelarray||o.labels,this.color_array=o.colorarray||o.colors,this.lines=[],this.myAtts.strokewidth=o.strokewidth||5,this.myAtts.straightfirst=!1,this.myAtts.straightlast=!1,this.myAtts.withlabel=!0,this.myAtts.fixed=!0,this.style=o.legendstyle||o.style,"vertical"!==this.style)throw new Error("JSXGraph: Unknown legend style: "+this.style);this.drawVerticalLegend(t,o)},t.Legend.prototype=new o,t.Legend.prototype.drawVerticalLegend=function(t,e){var i,o=e.linelength||1,n=(e.rowheight||20)/this.board.unitY,a=function(){return this.setLabelRelativeCoords(this.visProp.label.offset),new s(r.COORDS_BY_USER,[this.point2.X(),this.point2.Y()],this.board)};for(i=0;i<this.label_array.length;i++)this.myAtts.name=this.label_array[i],this.myAtts.strokecolor=this.color_array[i%this.color_array.length],this.myAtts.highlightstrokecolor=this.color_array[i%this.color_array.length],this.myAtts.label={offset:[10,0],strokeColor:this.color_array[i%this.color_array.length],strokeWidth:this.myAtts.strokewidth},this.lines[i]=t.create("line",[[this.coords.usrCoords[1],this.coords.usrCoords[2]-i*n],[this.coords.usrCoords[1]+o,this.coords.usrCoords[2]-i*n]],this.myAtts),this.lines[i].getLabelAnchor=a,this.lines[i].prepareUpdate().update().updateVisibility(h.evaluate(this.lines[i].visProp.visible)).updateRenderer()},t.createLegend=function(e,i,r){var s=[0,0];if(!h.exists(i)||2!==i.length)throw new Error("JSXGraph: Legend element needs two numbers as parameters");return s=i,new t.Legend(e,s,r)},t.registerElement("legend",t.createLegend),{Chart:t.Chart,Legend:t.Legend,createChart:t.createChart,createLegend:t.createLegend}}),define("base/turtle",["jxg","base/constants","base/element","utils/type","base/curve","base/point","base/line","base/transformation"],function(t,e,i,r,s,o,n,a){"use strict";return t.Turtle=function(t,i,s){var o,n,a;return this.constructor(t,s,e.OBJECT_TYPE_TURTLE,e.OBJECT_CLASS_OTHER),this.turtleIsHidden=!1,this.board=t,this.visProp.curveType="plot",this._attributes=r.copyAttributes(this.visProp,t.options,"turtle"),delete this._attributes.id,o=0,n=0,a=90,0!==i.length&&(3===i.length?(o=i[0],n=i[1],a=i[2]):2===i.length?r.isArray(i[0])?(o=i[0][0],n=i[0][1],a=i[1]):(o=i[0],n=i[1]):(o=i[0][0],n=i[0][1])),this.init(o,n,a),this.methodMap=r.deepCopy(this.methodMap,{forward:"forward",fd:"forward",back:"back",bk:"back",right:"right",rt:"right",left:"left",lt:"left",penUp:"penUp",pu:"penUp",penDown:"penDown",pd:"penDown",clearScreen:"clearScreen",cs:"clearScreen",clean:"clean",setPos:"setPos",home:"home",hideTurtle:"hideTurtle",ht:"hideTurtle",showTurtle:"showTurtle",st:"showTurtle",penSize:"setPenSize",penColor:"setPenColor",pushTurtle:"pushTurtle",push:"pushTurtle",popTurtle:"popTurtle",pop:"popTurtle",lookTo:"lookTo",pos:"pos",moveTo:"moveTo",X:"X",Y:"Y"}),this},t.Turtle.prototype=new i,t.extend(t.Turtle.prototype,{init:function(t,e,i){var r={fixed:!0,name:"",visible:!1,withLabel:!1};this.arrowLen=20/Math.sqrt(this.board.unitX*this.board.unitX+this.board.unitY*this.board.unitY),this.pos=[t,e],this.isPenDown=!0,this.dir=90,this.stack=[],this.objects=[],this.curve=this.board.create("curve",[[this.pos[0]],[this.pos[1]]],this._attributes),this.objects.push(this.curve),this.turtle=this.board.create("point",this.pos,r),this.objects.push(this.turtle),this.turtle2=this.board.create("point",[this.pos[0],this.pos[1]+this.arrowLen],r),this.objects.push(this.turtle2),this.visProp.arrow.lastArrow=!0,this.visProp.arrow.straightFirst=!1,this.visProp.arrow.straightLast=!1,this.arrow=this.board.create("line",[this.turtle,this.turtle2],this.visProp.arrow),this.objects.push(this.arrow),this.subs={arrow:this.arrow},this.inherits.push(this.arrow),this.right(90-i),this.board.update()},forward:function(t){if(0===t)return this;var e,i=t*Math.cos(this.dir*Math.PI/180),r=t*Math.sin(this.dir*Math.PI/180);return this.turtleIsHidden||(e=this.board.create("transform",[i,r],{type:"translate"}),e.applyOnce(this.turtle),e.applyOnce(this.turtle2)),this.isPenDown&&this.curve.dataX.length>=8192&&(this.curve=this.board.create("curve",[[this.pos[0]],[this.pos[1]]],this._attributes),this.objects.push(this.curve)),this.pos[0]+=i,this.pos[1]+=r,this.isPenDown&&(this.curve.dataX.push(this.pos[0]),this.curve.dataY.push(this.pos[1])),this.board.update(),this},back:function(t){return this.forward(-t)},right:function(t){if(this.dir-=t,this.dir%=360,!this.turtleIsHidden){this.board.create("transform",[-t*Math.PI/180,this.turtle],{type:"rotate"}).applyOnce(this.turtle2)}return this.board.update(),this},left:function(t){return this.right(-t)},penUp:function(){return this.isPenDown=!1,this},penDown:function(){return this.isPenDown=!0,this.curve=this.board.create("curve",[[this.pos[0]],[this.pos[1]]],this._attributes),this.objects.push(this.curve),this},clean:function(){var t,i;for(t=0;t<this.objects.length;t++)i=this.objects[t],i.type===e.OBJECT_TYPE_CURVE&&(this.board.removeObject(i),this.objects.splice(t,1));return this.curve=this.board.create("curve",[[this.pos[0]],[this.pos[1]]],this._attributes),this.objects.push(this.curve),this.board.update(),this},clearScreen:function(){var t,e,i=this.objects.length;for(t=0;t<i;t++)e=this.objects[t],this.board.removeObject(e);return this.init(0,0,90),this},setPos:function(t,i){var s;return r.isArray(t)?this.pos=t:this.pos=[t,i],this.turtleIsHidden||(this.turtle.setPositionDirectly(e.COORDS_BY_USER,[t,i]),this.turtle2.setPositionDirectly(e.COORDS_BY_USER,[t,i+this.arrowLen]),s=this.board.create("transform",[-(this.dir-90)*Math.PI/180,this.turtle],{type:"rotate"}),s.applyOnce(this.turtle2)),this.curve=this.board.create("curve",[[this.pos[0]],[this.pos[1]]],this._attributes),this.objects.push(this.curve),this.board.update(),this},setPenSize:function(t){return this.curve=this.board.create("curve",[[this.pos[0]],[this.pos[1]]],this.copyAttr("strokeWidth",t)),this.objects.push(this.curve),this},setPenColor:function(t){return this.curve=this.board.create("curve",[[this.pos[0]],[this.pos[1]]],this.copyAttr("strokeColor",t)),this.objects.push(this.curve),this},setHighlightPenColor:function(t){return this.curve=this.board.create("curve",[[this.pos[0]],[this.pos[1]]],this.copyAttr("highlightStrokeColor",t)),this.objects.push(this.curve),this},setAttribute:function(t){var i,s,o,n=this.objects.length;for(i=0;i<n;i++)s=this.objects[i],s.type===e.OBJECT_TYPE_CURVE&&s.setAttribute(t);return o=this.visProp.id,this.visProp=r.deepCopy(this.curve.visProp),this.visProp.id=o,this._attributes=r.deepCopy(this.visProp),delete this._attributes.id,this},copyAttr:function(t,e){return this._attributes[t.toLowerCase()]=e,this._attributes},showTurtle:function(){return this.turtleIsHidden=!1,this.arrow.setAttribute({visible:!0}),this.visProp.arrow.visible=!1,this.setPos(this.pos[0],this.pos[1]),this.board.update(),this},hideTurtle:function(){return this.turtleIsHidden=!0,this.arrow.setAttribute({visible:!1}),this.visProp.arrow.visible=!1,this.board.update(),this},home:function(){return this.pos=[0,0],this.setPos(this.pos[0],this.pos[1]),this},pushTurtle:function(){return this.stack.push([this.pos[0],this.pos[1],this.dir]),this},popTurtle:function(){var t=this.stack.pop();return this.pos[0]=t[0],this.pos[1]=t[1],this.dir=t[2],this.setPos(this.pos[0],this.pos[1]),this},lookTo:function(t){var e,i,s,o,n;return r.isArray(t)?(e=this.pos[0],i=this.pos[1],s=t[0],o=t[1],n=Math.atan2(o-i,s-e),this.right(this.dir-180*n/Math.PI)):r.isNumber(t)&&this.right(this.dir-t),this},moveTo:function(t){var e,i,s;return r.isArray(t)&&(e=t[0]-this.pos[0],i=t[1]-this.pos[1],this.turtleIsHidden||(s=this.board.create("transform",[e,i],{type:"translate"}),s.applyOnce(this.turtle),s.applyOnce(this.turtle2)),this.isPenDown&&this.curve.dataX.length>=8192&&(this.curve=this.board.create("curve",[[this.pos[0]],[this.pos[1]]],this._attributes),this.objects.push(this.curve)),this.pos[0]=t[0],this.pos[1]=t[1],this.isPenDown&&(this.curve.dataX.push(this.pos[0]),this.curve.dataY.push(this.pos[1])),this.board.update()),this},fd:function(t){return this.forward(t)},bk:function(t){return this.back(t)},lt:function(t){return this.left(t)},rt:function(t){return this.right(t)},pu:function(){return this.penUp()},pd:function(){return this.penDown()},ht:function(){return this.hideTurtle()},st:function(){return this.showTurtle()},cs:function(){return this.clearScreen()},push:function(){return this.pushTurtle()},pop:function(){return this.popTurtle()},evalAt:function(t,i){var r,s,o,n,a=this.objects.length;for(r=0,s=0;r<a;r++)if(o=this.objects[r],o.elementClass===e.OBJECT_CLASS_CURVE){if(s<=t&&t<s+o.numberPoints)return n=t-s,o[i](n);s+=o.numberPoints}return this[i]()},X:function(t){return r.exists(t)?this.evalAt(t,"X"):this.pos[0]},Y:function(t){return r.exists(t)?this.evalAt(t,"Y"):this.pos[1]},Z:function(t){return 1},minX:function(){return 0},maxX:function(){var t,i,r=this.objects.length,s=0;for(t=0;t<r;t++)i=this.objects[t],i.elementClass===e.OBJECT_CLASS_CURVE&&(s+=this.objects[t].numberPoints);return s},hasPoint:function(t,i){var r,s;for(r=0;r<this.objects.length;r++)if(s=this.objects[r],s.type===e.OBJECT_TYPE_CURVE&&s.hasPoint(t,i))return!0;return!1}}),t.createTurtle=function(e,i,s){var o;return i=i||[],o=r.copyAttributes(s,e.options,"turtle"),new t.Turtle(e,i,o)},t.registerElement("turtle",t.createTurtle),{Turtle:t.Turtle,createTurtle:t.createTurtle}}),define("parser/ca",["jxg","base/constants","base/text","math/math","math/geometry","math/statistics","utils/type","utils/env"],function(t,e,i,r,s,o,n,a){"use strict";return t.CA=function(t,e,i){this.node=t,this.createNode=e,this.parser=i},t.extend(t.CA.prototype,{findMapNode:function(t,e){var i,r,s;if("op_assign"===e.value&&e.children[0].value===t)return e.children[1];if(e.children)for(r=e.children.length,i=0;i<r;++i)if(null!==(s=this.findMapNode(t,e.children[i])))return s;return null},setMath:function(t){var e,i;if(("node_op"!=t.type||"op_add"!=t.value&&"op_sub"!=t.value&&"op_mul"!=t.value&&"op_div"!=t.value&&"op_neg"!=t.value&&"op_execfun"!=t.value&&"op_exp"!=t.value)&&"node_var"!=t.type&&"node_const"!=t.type||(t.isMath=!0),t.children)for(i=t.children.length,e=0;e<i;++e)this.setMath(t.children[e])},deriveElementary:function(t,e){var i,r=t.children[0].value,s=t.children[1];switch(r){case"abs":i=this.createNode("node_op","op_div",s[0],this.createNode("node_op","op_execfun",this.createNode("node_var","sqrt"),[this.createNode("node_op","op_mul",n.deepCopy(s[0]),n.deepCopy(s[0]))]));break;case"sqrt":i=this.createNode("node_op","op_div",this.createNode("node_const",1),this.createNode("node_op","op_mul",this.createNode("node_const",2),this.createNode(t.type,t.value,n.deepCopy(t.children[0]),n.deepCopy(t.children[1]))));break;case"sin":i=this.createNode("node_op","op_execfun",this.createNode("node_var","cos"),n.deepCopy(s));break;case"cos":i=this.createNode("node_op","op_neg",this.createNode("node_op","op_execfun",this.createNode("node_var","sin"),n.deepCopy(s)));break;case"tan":i=this.createNode("node_op","op_div",this.createNode("node_const",1),this.createNode("node_op","op_exp",this.createNode("node_op","op_execfun",this.createNode("node_var","cos"),n.deepCopy(s)),this.createNode("node_const",2)));break;case"cot":i=this.createNode("node_op","op_neg",this.createNode("node_op","op_div",this.createNode("node_const",1),this.createNode("node_op","op_exp",this.createNode("node_op","op_execfun",this.createNode("node_var","sin"),n.deepCopy(s)),this.createNode("node_const",2))));break;case"exp":i=this.createNode(t.type,t.value,n.deepCopy(t.children[0]),n.deepCopy(t.children[1]));break;case"pow":i=this.createNode("node_op","op_mul",this.createNode("node_op","op_execfun",n.deepCopy(t.children[0]),n.deepCopy(t.children[1])),this.createNode("node_op","op_add",this.createNode("node_op","op_mul",this.derivative(t.children[1][0],e),this.createNode("node_op","op_div",n.deepCopy(t.children[1][1]),n.deepCopy(t.children[1][0]))),this.createNode("node_op","op_mul",this.derivative(t.children[1][1],e),this.createNode("node_op","op_execfun",this.createNode("node_var","log"),[n.deepCopy(t.children[1][0])]))));break;case"log":case"ln":i=this.createNode("node_op","op_div",this.createNode("node_const",1),n.deepCopy(s[0]));break;case"log2":case"lb":case"ld":i=this.createNode("node_op","op_mul",this.createNode("node_op","op_div",this.createNode("node_const",1),n.deepCopy(s[0])),this.createNode("node_const",1.4426950408889634));break;case"log10":case"lg":i=this.createNode("node_op","op_mul",this.createNode("node_op","op_div",this.createNode("node_const",1),n.deepCopy(s[0])),this.createNode("node_const",.43429448190325176));break;case"asin":i=this.createNode("node_op","op_div",this.createNode("node_const",1),this.createNode("node_op","op_execfun",this.createNode("node_var","sqrt"),[this.createNode("node_op","op_sub",this.createNode("node_const",1),this.createNode("node_op","op_mul",n.deepCopy(s[0]),n.deepCopy(s[0])))]));break;case"acos":i=this.createNode("node_op","op_neg",this.createNode("node_op","op_div",this.createNode("node_const",1),this.createNode("node_op","op_execfun",this.createNode("node_var","sqrt"),[this.createNode("node_op","op_sub",this.createNode("node_const",1),this.createNode("node_op","op_mul",n.deepCopy(s[0]),n.deepCopy(s[0])))])));break;case"atan":i=this.createNode("node_op","op_div",this.createNode("node_const",1),this.createNode("node_op","op_add",this.createNode("node_const",1),this.createNode("node_op","op_mul",n.deepCopy(s[0]),n.deepCopy(s[0]))));break;case"acot":i=this.createNode("node_op","op_neg",this.createNode("node_op","op_div",this.createNode("node_const",1),this.createNode("node_op","op_add",this.createNode("node_const",1),this.createNode("node_op","op_mul",n.deepCopy(s[0]),n.deepCopy(s[0])))));break;case"sinh":i=this.createNode("node_op","op_execfun",this.createNode("node_var","cosh"),[n.deepCopy(s[0])]);break;case"cosh":i=this.createNode("node_op","op_execfun",this.createNode("node_var","sinh"),[n.deepCopy(s[0])]);break;case"tanh":i=this.createNode("node_op","op_sub",this.createNode("node_const",1),this.createNode("node_op","op_exp",this.createNode("node_op","op_execfun",this.createNode("node_var","tanh"),[n.deepCopy(s[0])]),this.createNode("node_const",2)));break;case"asinh":i=this.createNode("node_op","op_div",this.createNode("node_const",1),this.createNode("node_op","op_execfun",this.createNode("node_var","sqrt"),[this.createNode("node_op","op_add",this.createNode("node_op","op_mul",n.deepCopy(s[0]),n.deepCopy(s[0])),this.createNode("node_const",1))]));break;case"acosh":i=this.createNode("node_op","op_div",this.createNode("node_const",1),this.createNode("node_op","op_execfun",this.createNode("node_var","sqrt"),[this.createNode("node_op","op_sub",this.createNode("node_op","op_mul",n.deepCopy(s[0]),n.deepCopy(s[0])),this.createNode("node_const",1))]));break;case"atanh":i=this.createNode("node_op","op_div",this.createNode("node_const",1),this.createNode("node_op","op_sub",this.createNode("node_const",1),this.createNode("node_op","op_mul",n.deepCopy(s[0]),n.deepCopy(s[0]))));break;default:i=this.createNode("node_const",0),this._error('Derivative of "'+r+'" not yet implemented')}return i},derivative:function(t,e){var i;switch(t.type){case"node_op":switch(t.value){case"op_execfun":i="pow"==t.children[0].value?this.deriveElementary(t,e):this.createNode("node_op","op_mul",this.deriveElementary(t,e),this.derivative(t.children[1][0],e));break;case"op_div":i=this.createNode("node_op","op_div",this.createNode("node_op","op_sub",this.createNode("node_op","op_mul",this.derivative(t.children[0],e),n.deepCopy(t.children[1])),this.createNode("node_op","op_mul",n.deepCopy(t.children[0]),this.derivative(t.children[1],e))),this.createNode("node_op","op_mul",n.deepCopy(t.children[1]),n.deepCopy(t.children[1])));break;case"op_mul":i=this.createNode("node_op","op_add",this.createNode("node_op","op_mul",n.deepCopy(t.children[0]),this.derivative(t.children[1],e)),this.createNode("node_op","op_mul",this.derivative(t.children[0],e),n.deepCopy(t.children[1])));break;case"op_neg":i=this.createNode("node_op","op_neg",this.derivative(t.children[0],e));break;case"op_add":case"op_sub":i=this.createNode("node_op",t.value,this.derivative(t.children[0],e),this.derivative(t.children[1],e));break;case"op_exp":i=this.createNode("node_op","op_mul",n.deepCopy(t),this.createNode("node_op","op_add",this.createNode("node_op","op_mul",this.derivative(t.children[0],e),this.createNode("node_op","op_div",n.deepCopy(t.children[1]),n.deepCopy(t.children[0]))),this.createNode("node_op","op_mul",this.derivative(t.children[1],e),this.createNode("node_op","op_execfun",this.createNode("node_var","log"),[n.deepCopy(t.children[0])]))))}break;case"node_var":i=t.value===e?this.createNode("node_const",1):this.createNode("node_const",0);break;case"node_const":i=this.createNode("node_const",0)}return i},expandDerivatives:function(t,e,i){var r,s,o,a,h,l,c,d,u,p,f,m;if(l=0,!t)return l;for(this.line=t.line,this.col=t.col,r=t.children.length,s=0;s<r;++s)if(t.children[s]&&t.children[s].type)t.children[s]=this.expandDerivatives(t.children[s],t,i);else if(n.isArray(t.children[s]))for(o=0;o<t.children[s].length;++o)t.children[s][o]&&t.children[s][o].type&&(t.children[s][o]=this.expandDerivatives(t.children[s][o],t,i));switch(t.type){case"node_op":switch(t.value){case"op_execfun":if(t.children[0]&&"D"===t.children[0].value){if("node_var"==t.children[1][0].type?(u=t.children[1][0].value,a=this.findMapNode(u,i),f=a.children[0],p=t.children[1].length>=2?t.children[1][1].value:a.children[0][0],h=a.children[1]):(h=t.children[1][0],f=["x"],p=t.children[1].length>=2?t.children[1][1].value:"x"),m=t.children[1].length>=3?t.children[1][2].value:1,d=h,m>=1)for(;m>=1;)d=this.derivative(d,p),d=this.removeTrivialNodes(d),m--;c="node_op"==e.type&&"op_assign"==e.value?this.createNode("node_op","op_map",f,d):d,this.setMath(c),t.type=c.type,t.value=c.value,t.children[0]=c.children[0],t.children[1]=c.children[1]}}}return t},removeTrivialNodes:function(t){var e,i,r,s,o;if(n.isArray(t))for(i=t.length,e=0;e<i;++e)t[e]=this.removeTrivialNodes(t[e]);if("node_op"!=t.type||!t.children)return t;for(i=t.children.length,e=0;e<i;++e){this.mayNotBeSimplified=!1;do{t.children[e]=this.removeTrivialNodes(t.children[e])}while(this.mayNotBeSimplified)}switch(t.value){case"op_map":if(r=t.children[0],s=t.children[1],"node_var"==s.type)for(e=0;e<r.length;++e)if(r[e]==s.value){s.isMath=!0;break}break;case"op_add":if(r=t.children[0],s=t.children[1],"node_const"==r.type&&0===r.value)return s;if("node_const"==s.type&&0===s.value)return r;if("node_const"==r.type&&"node_const"==s.type)return r.value+=s.value,r;break;case"op_mul":if(r=t.children[0],s=t.children[1],"node_const"==r.type&&1==r.value)return s;if("node_const"==s.type&&1==s.value)return r;if("node_const"==r.type&&0===r.value)return r;if("node_const"==s.type&&0===s.value)return s;if("node_const"==s.type&&0===s.value)return s;if("node_op"==r.type&&"op_neg"==r.value&&"node_op"==s.type&&"op_neg"==s.value)return t.children=[r.children[0],s.children[0]],this.mayNotBeSimplified=!0,t;if("op_neg"==r.value&&"op_neg"!=s.value)return t.type="node_op",t.value="op_neg",t.children=[this.createNode("node_op","op_mul",r.children[0],s)],this.mayNotBeSimplified=!0,t;if("op_neg"!=r.value&&"op_neg"==s.value)return t.type="node_op",t.value="op_neg",t.children=[this.createNode("node_op","op_mul",r,s.children[0])],this.mayNotBeSimplified=!0,t;if("op_div"==r.value&&"node_const"==r.children[0].type&&1==r.children[0].value)return t.type="node_op",t.value="op_div",t.children=[s,r.children[1]],this.mayNotBeSimplified=!0,t;if("op_div"==s.value&&"node_const"==s.children[0].type&&1==s.children[0].value)return t.type="node_op",t.value="op_div",t.children=[r,s.children[1]],this.mayNotBeSimplified=!0,t;if("node_const"!=r.type&&"node_const"==s.type)return t.children=[s,r],this.mayNotBeSimplified=!0,t;if("node_const"!=r.type&&"node_op"==s.type&&"op_neg"==s.value&&"node_const"==s.children[0].type)return t.children=[s,r],this.mayNotBeSimplified=!0,t;if("node_op"==r.type&&"op_execfun"!=r.value&&("node_var"==s.type||"node_op"==s.type&&"op_execfun"==s.value))return t.children=[s,r],this.mayNotBeSimplified=!0,t;if("node_op"!=r.type&&"node_op"==s.type&&"op_neg"==s.value&&"node_var"==s.children[0].type)return t.children=[s,r],this.mayNotBeSimplified=!0,t;if("node_const"!=r.type&&"node_op"==s.type&&("op_mul"==s.value||"op_div"==s.value)&&"node_const"==s.children[0].type)return o=s.children[0],s.children[0]=r,t.children=[o,s],this.mayNotBeSimplified=!0,t;if("node_const"!=s.type&&"node_op"==r.type&&"op_mul"==r.value&&"node_const"==r.children[0].type)return t.children=[r.children[0],this.createNode("node_op","op_mul",r.children[1],s)],this.mayNotBeSimplified=!0,t;if("node_const"==r.type&&"node_const"==s.type)return r.value*=s.value,r;if("node_const"==r.type&&"node_op"==s.type&&("op_mul"==s.value||"op_div"==s.value)&&"node_const"==s.children[0].type)return s.children[0].value*=r.value,s;if(r.hash=this.parser.compile(r),s.hash=this.parser.compile(s),r.hash===s.hash)return t.value="op_exp",t.children[1]=this.createNode("node_const",2),t;if("node_const"==r.type&&"node_op"==s.type&&("op_mul"==s.value||"op_div"==s.value)&&"node_const"==s.children[0].type)return s.children[0].value*=r.value,s;if("node_op"==s.type&&"op_exp"==s.value&&(r.hash||(r.hash=this.parser.compile(r)),s.children[0].hash||(s.children[0].hash=this.parser.compile(s.children[0])),r.hash===s.children[0].hash))return s.children[1]=this.createNode("node_op","op_add",s.children[1],this.createNode("node_const",1)),this.mayNotBeSimplified=!0,s;if("node_op"==r.type&&"op_exp"==r.value&&"node_op"==s.type&&"op_exp"==s.value&&(r.children[0].hash=this.parser.compile(r.children[0]),s.children[0].hash=this.parser.compile(s.children[0]),r.children[0].hash===s.children[0].hash))return r.children[1]=this.createNode("node_op","op_add",r.children[1],s.children[1]),this.mayNotBeSimplified=!0,r;break;case"op_sub":if(r=t.children[0],s=t.children[1],"node_const"==r.type&&0===r.value)return t.value="op_neg",t.children[0]=s,t;if("node_const"==s.type&&0===s.value)return r;if("node_const"==r.type&&"node_const"==s.type&&r.value==s.value)return this.createNode("node_const",0);if("node_var"==r.type&&"node_var"==s.type&&r.value==s.value)return this.createNode("node_const",0);if("node_const"==r.type&&"node_const"==s.type)return r.value-=s.value,r;if("node_op"==r.type&&"op_mul"==r.value&&"node_op"==s.type&&"op_mul"==s.value&&(r.children[1].hash=this.parser.compile(r.children[1]),s.children[1].hash=this.parser.compile(s.children[1]),r.children[1].hash===s.children[1].hash))return t.value="op_mul",t.children=[this.createNode("node_op","op_sub",r.children[0],s.children[0]),r.children[1]],this.mayNotBeSimplified=!0,t;if("node_op"==r.type&&"op_mul"==r.value&&(r.children[1].hash=this.parser.compile(r.children[1]),s.hash=this.parser.compile(s),r.children[1].hash===s.hash))return t.value="op_mul",t.children=[this.createNode("node_op","op_sub",r.children[0],this.createNode("node_const",1)),s],this.mayNotBeSimplified=!0,t;if("node_op"==s.type&&"op_mul"==s.value&&(s.children[1].hash=this.parser.compile(s.children[1]),r.hash=this.parser.compile(r),s.children[1].hash===r.hash))return t.value="op_mul",t.children=[this.createNode("node_op","op_sub",this.createNode("node_const",1),s.children[0]),r],this.mayNotBeSimplified=!0,t;break;case"op_neg":if(r=t.children[0],"node_const"==r.type&&0===r.value)return r;if("node_op"==r.type&&"op_neg"==r.value)return r.children[0];break;case"op_div":if(r=t.children[0],s=t.children[1],"node_const"==r.type&&"node_const"==s.type&&r.value==s.value&&0!==r.value)return r.value=1,r;if("node_const"==r.type&&0===r.value&&"node_const"==s.type&&0!==s.value)return r.value=0,r;if("node_const"==r.type&&0===r.value&&("node_op"==s.type||"node_var"==s.type))return t.type="node_const",t.value=0,t;if("node_var"==r.type&&"node_var"==s.type&&r.value==s.value)return this.createNode("node_const",1);if("node_const"==r.type&&0!==r.value&&"node_const"==s.type&&0===s.value)return r.value>0?r.value=1/0:r.value=-1/0,r;if("node_op"==r.type&&"op_neg"==r.value&&"node_op"==s.type&&"op_neg"==s.value)return t.children=[r.children[0],s.children[0]],this.mayNotBeSimplified=!0,t;if("op_neg"==r.value&&"op_neg"!=s.value)return t.type="node_op",t.value="op_neg",t.children=[this.createNode("node_op","op_div",r.children[0],s)],this.mayNotBeSimplified=!0,t;if("op_neg"!=r.value&&"op_neg"==s.value)return t.type="node_op",t.value="op_neg",t.children=[this.createNode("node_op","op_div",r,s.children[0])],this.mayNotBeSimplified=!0,t;if("node_op"==r.type&&"op_exp"==r.value&&(s.hash||(s.hash=this.parser.compile(s)),r.children[0].hash||(r.children[0].hash=this.parser.compile(r.children[0])),s.hash===r.children[0].hash))return r.children[1]=this.createNode("node_op","op_sub",r.children[1],this.createNode("node_const",1)),this.mayNotBeSimplified=!0,r;if("node_const"!=s.type&&"node_op"==r.type&&"op_mul"==r.value&&"node_const"==r.children[0].type)return t.value="op_mul",t.children=[r.children[0],this.createNode("node_op","op_div",r.children[1],s)],this.mayNotBeSimplified=!0,t;if("node_op"==r.type&&"op_exp"==r.value&&"node_op"==s.type&&"op_exp"==s.value&&(r.children[0].hash=this.parser.compile(r.children[0]),s.children[0].hash=this.parser.compile(s.children[0]),r.children[0].hash===s.children[0].hash))return r.children[1]=this.createNode("node_op","op_sub",r.children[1],s.children[1]),this.mayNotBeSimplified=!0,r;break;case"op_exp":if(r=t.children[0],s=t.children[1],"node_const"==s.type&&0===s.value)return s.value=1,s;if("node_const"==s.type&&1==s.value)return r;if("node_const"==r.type&&1==r.value)return r;if("node_const"==r.type&&0===r.value&&"node_const"==s.type&&0!==s.value)return r;if("node_op"==r.type&&"op_exp"==r.value)return t.children=[r.children[0],this.createNode("node_op","op_mul",r.children[1],s)],t}switch(t.value){case"op_add":if(r=t.children[0],s=t.children[1],"node_const"==r.type&&"node_const"==s.type&&r.value==s.value)return r.value+=s.value,r;if("node_var"==r.type&&"node_var"==s.type&&r.value==s.value)return t.children[0]=this.createNode("node_const",2),t.value="op_mul",t;if("node_op"==r.type&&"op_neg"==r.value)return t.value="op_sub",t.children[0]=s,t.children[1]=r.children[0],this.mayNotBeSimplified=!0,t;if("node_op"==s.type&&"op_neg"==s.value)return t.value="op_sub",t.children[1]=s.children[0],this.mayNotBeSimplified=!0,t;if("node_op"==r.type&&"op_mul"==r.value&&"node_op"==s.type&&"op_mul"==s.value&&(r.children[1].hash=this.parser.compile(r.children[1]),s.children[1].hash=this.parser.compile(s.children[1]),r.children[1].hash===s.children[1].hash))return t.value="op_mul",t.children=[this.createNode("node_op","op_add",r.children[0],s.children[0]),r.children[1]],this.mayNotBeSimplified=!0,t;if("node_op"==r.type&&"op_mul"==r.value&&(r.children[1].hash=this.parser.compile(r.children[1]),s.hash=this.parser.compile(s),r.children[1].hash===s.hash))return t.value="op_mul",t.children=[this.createNode("node_op","op_add",r.children[0],this.createNode("node_const",1)),s],this.mayNotBeSimplified=!0,t;if("node_op"==s.type&&"op_mul"==s.value&&(s.children[1].hash=this.parser.compile(s.children[1]),r.hash=this.parser.compile(r),s.children[1].hash===r.hash))return t.value="op_mul",t.children=[this.createNode("node_op","op_add",this.createNode("node_const",1),s.children[0]),r],this.mayNotBeSimplified=!0,t;break;case"op_sub":if(r=t.children[0],s=t.children[1],"node_op"==s.type&&"op_neg"==s.value)return t.value="op_add",t.children[1]=s.children[0],this.mayNotBeSimplified=!0,t;break;case"op_execfun":return this.simplifyElementary(t)}return t},simplifyElementary:function(t){var e=t.children[0].value,i=t.children[1];if(0==i.length)return t;switch(e){case"sin":case"tan":if("node_const"==i[0].type&&0===i[0].value)return t.type="node_const",t.value=0,t;if("node_var"==i[0].type&&"PI"==i[0].value)return t.type="node_const",t.value=0,t;if("node_op"==i[0].type&&"op_mul"==i[0].value&&"node_const"==i[0].children[0].type&&i[0].children[0].value%1==0&&"node_var"==i[0].children[1].type&&"PI"==i[0].children[1].value)return t.type="node_const",t.value=0,t;break;case"cos":if("node_const"==i[0].type&&0===i[0].value)return t.type="node_const",t.value=1,t;if("node_var"==i[0].type&&"PI"==i[0].value)return t.type="node_op",t.value="op_neg",t.children=[this.createNode("node_const",1)],t;break;case"exp":if("node_const"==i[0].type&&0===i[0].value)return t.type="node_const",t.value=1,t;break;case"pow":if("node_const"==i[1].type&&0===i[1].value)return t.type="node_const",t.value=1,t}return t}}),t.CA}),define("utils/dump",["jxg","utils/type"],function(t,e){"use strict";return t.Dump={addMarkers:function(t,i,r){var s,o,n;e.isArray(i)||(i=[i]),e.isArray(r)||(r=[r]),o=Math.min(i.length,r.length),i.length=o,r.length=o;for(s in t.objects)if(t.objects.hasOwnProperty(s))for(n=0;n<o;n++)t.objects[s][i[n]]=r[n]},deleteMarkers:function(t,i){var r,s,o;e.isArray(i)||(i=[i]),s=i.length,i.length=s;for(r in t.objects)if(t.objects.hasOwnProperty(r))for(o=0;o<s;o++)delete t.objects[r][i[o]]},str:function(t){return"string"==typeof t&&"function"!==t.substr(0,7)&&(t='"'+t+'"'),t},minimizeObject:function(i,r){var s,o,n,a={},h=e.deepCopy(i),l=[];for(n=1;n<arguments.length;n++)l.push(arguments[n]);for(a=e.deepCopy(a,t.Options.elements,!0),n=l.length;n>0;n--)a=e.deepCopy(a,l[n-1],!0);for(s in a)a.hasOwnProperty(s)&&(o=s.toLowerCase(),"object"!=typeof a[s]&&a[s]===h[o]&&delete h[o]);return h},prepareAttributes:function(e,i){var r,s -;r=this.minimizeObject(i.getAttributes(),t.Options[i.elType]);for(s in i.subs)i.subs.hasOwnProperty(s)&&(r[s]=this.minimizeObject(i.subs[s].getAttributes(),t.Options[i.elType][s],t.Options[i.subs[s].elType]),r[s].id=i.subs[s].id,r[s].name=i.subs[s].name);return r.id=i.id,r.name=i.name,r},setBoundingBox:function(t,e,i){return t.push({obj:i,method:"setBoundingBox",params:[e.getBoundingBox(),!0]}),t},dump:function(t){var i,r,s,o,n=[],a=[],h=[],l=t.objectsList.length;for(this.addMarkers(t,"dumped",!1),i=0;i<l;i++)if(r=t.objectsList[i],s={},!r.dumped&&r.dump){for(s.type=r.getType(),s.parents=r.getParents().slice(),"point"===s.type&&1===s.parents[0]&&(s.parents=s.parents.slice(1)),o=0;o<s.parents.length;o++)e.isString(s.parents[o])&&"'"!==s.parents[o][0]&&'"'!==s.parents[o][0]?s.parents[o]='"'+s.parents[o]+'"':e.isArray(s.parents[o])&&(s.parents[o]="["+s.parents[o].toString()+"]");s.attributes=this.prepareAttributes(t,r),"glider"===s.type&&r.onPolygon&&n.push({obj:r.id,prop:"onPolygon",val:!0}),h.push(s)}return this.deleteMarkers(t,"dumped"),{elements:h,props:n,methods:a}},arrayToParamStr:function(t,e){var i,r=[];for(i=0;i<t.length;i++)r.push(e.call(this,t[i]));return r.join(", ")},toJCAN:function(t){var i,r,s;switch(typeof t){case"object":if(t){if(r=[],e.isArray(t)){for(i=0;i<t.length;i++)r.push(this.toJCAN(t[i]));return"["+r.join(",")+"]"}for(s in t)t.hasOwnProperty(s)&&r.push(s+": "+this.toJCAN(t[s]));return"<<"+r.join(", ")+">> "}return"null";case"string":return"'"+t.replace(/(["'])/g,"\\$1")+"'";case"number":case"boolean":return t.toString();case"null":return"null"}},toJessie:function(t){var e,i,r=this.dump(t),s=[];for(r.methods=this.setBoundingBox(r.methods,t,"$board"),i=r.elements,e=0;e<i.length;e++)i[e].attributes.name.length>0&&s.push("// "+i[e].attributes.name),s.push("s"+e+" = "+i[e].type+"("+i[e].parents.join(", ")+") "+this.toJCAN(i[e].attributes).replace(/\n/,"\\n")+";"),s.push("");for(e=0;e<r.methods.length;e++)s.push(r.methods[e].obj+"."+r.methods[e].method+"("+this.arrayToParamStr(r.methods[e].params,this.toJCAN)+");"),s.push("");for(e=0;e<r.props.length;e++)s.push(r.props[e].obj+"."+r.props[e].prop+" = "+this.toJCAN(r.props[e].val)+";"),s.push("");return s.join("\n")},toJavaScript:function(t){var i,r,s=this.dump(t),o=[];for(s.methods=this.setBoundingBox(s.methods,t,"board"),r=s.elements,i=0;i<r.length;i++)o.push('board.create("'+r[i].type+'", ['+r[i].parents.join(", ")+"], "+e.toJSON(r[i].attributes)+");");for(i=0;i<s.methods.length;i++)o.push(s.methods[i].obj+"."+s.methods[i].method+"("+this.arrayToParamStr(s.methods[i].params,e.toJSON)+");"),o.push("");for(i=0;i<s.props.length;i++)o.push(s.props[i].obj+"."+s.props[i].prop+" = "+e.toJSON(s.props[i].val)+";"),o.push("");return o.join("\n")}},t.Dump}),define("element/comb",["jxg","options","utils/type","base/constants","base/line","base/polygon","base/point"],function(t,e,i,r,s,o,n){"use strict";return t.createComb=function(t,e,r){var s,o,a,h,l;if(2!==e.length)throw l=e.map(function(t){return"'"+typeof t+"'"}),new Error("JSXGraph: Can't create comb with parent types "+l.join(", ")+".\nPossible parent types: [point,point], [[x1,y1],[x2,y2]]");if(i.isArray(e[0])&&e[0].length>1)h=i.copyAttributes(r,t.options,"comb","point1"),s=t.create("point",e[0],h);else if(i.isString(e[0])||i.isPoint(e[0]))s=t.select(e[0]);else if(i.isFunction(e[0])&&i.isPoint(e[0]()))s=e[0]();else{if(!(i.isFunction(e[0])&&e[0]().length&&e[0]().length>=2))throw new Error("JSXGraph: Can't create comb with parent types '"+typeof e[0]+"' and '"+typeof e[1]+"'.\nPossible parent types: [point,point], [[x1,y1],[x2,y2]]");h=i.copyAttributes(r,t.options,"comb","point1"),s=n.createPoint(t,e[0](),h)}if(i.isArray(e[1])&&e[1].length>1)h=i.copyAttributes(r,t.options,"comb","point2"),o=t.create("point",e[1],h);else if(i.isString(e[1])||i.isPoint(e[1]))o=t.select(e[1]);else if(i.isFunction(e[1])&&i.isPoint(e[1]()))o=e[1]();else{if(!(i.isFunction(e[1])&&e[1]().length&&e[1]().length>=2))throw new Error("JSXGraph: Can't create comb with parent types '"+typeof e[0]+"' and '"+typeof e[1]+"'.\nPossible parent types: [point,point], [[x1,y1],[x2,y2]]");h=i.copyAttributes(r,t.options,"comb","point2"),o=n.createPoint(t,e[1](),h)}return h=i.copyAttributes(r,t.options,"comb"),i.merge(h,i.copyAttributes(r,t.options,"comb","curve")),a=t.create("curve",[[0],[0]],h),a.updateDataArray=function(){var t,e,r,n,h,l,c,d,u,p,f=0,m=s.Dist(o),g=s,b=o;for(d=i.evaluate(a.visProp.frequency),u=-i.evaluate(a.visProp.angle),p=i.evaluate(a.visProp.width),i.evaluate(a.visProp.reverse)&&(g=o,b=s,u=-u),t=Math.cos(u),e=Math.sin(u),r=(b.X()-g.X())/m,n=(b.Y()-g.Y())/m,t*=p/Math.abs(e),e*=p/Math.abs(e),this.dataX=[],this.dataY=[];f<m;)h=g.X()+r*f,l=g.Y()+n*f,c=Math.min(t,m-f)/Math.abs(t),e*=c,t*=c,this.dataX.push(h),this.dataY.push(l),this.dataX.push(h+r*t+n*e),this.dataY.push(l-r*e+n*t),this.dataX.push(NaN),this.dataY.push(NaN),f+=d},a},t.registerElement("comb",t.createComb),{createComb:t.createComb}}),define("element/slopetriangle",["jxg","options","utils/type","base/constants","base/line","base/polygon","base/point","base/element"],function(t,e,i,r,s,o,n,a){"use strict";var h={removeSlopeTriangle:function(){o.Polygon.prototype.remove.call(this),this.board.removeObject(this.toppoint),this.board.removeObject(this.glider),this.board.removeObject(this.baseline),this.board.removeObject(this.basepoint),this.board.removeObject(this.label),this._isPrivateTangent&&this.board.removeObject(this.tangent)},Value:function(){return this.tangent.getSlope()}};return t.createSlopeTriangle=function(e,s,o){var n,a,l,c,d,u,p,f,m,g=!1;if(1===s.length&&s[0].type===r.OBJECT_TYPE_TANGENT)a=s[0],l=a.glider;else if(1===s.length&&s[0].type===r.OBJECT_TYPE_GLIDER)l=s[0],m=i.copyAttributes(o,e.options,"slopetriangle","tangent"),a=e.create("tangent",[l],m),g=!0;else{if(2!==s.length||s[0].elementClass!==r.OBJECT_CLASS_LINE||!i.isPoint(s[1]))throw new Error("JSXGraph: Can't create slope triangle with parent types '"+typeof s[0]+"'.");a=s[0],l=s[1]}return m=i.copyAttributes(o,e.options,"slopetriangle","basepoint"),p=e.create("point",[function(){return[l.X()+1,l.Y()]}],m),m=i.copyAttributes(o,e.options,"slopetriangle","baseline"),u=e.create("line",[l,p],m),m=i.copyAttributes(o,e.options,"slopetriangle","glider"),c=e.create("glider",[l.X()+1,l.Y(),u],m),m=i.copyAttributes(o,e.options,"slopetriangle","toppoint"),d=e.create("point",[function(){return[c.X(),c.Y()+(c.X()-l.X())*a.getSlope()]}],m),m=i.copyAttributes(o,e.options,"slopetriangle"),m.borders=i.copyAttributes(m.borders,e.options,"slopetriangle","borders"),n=e.create("polygon",[l,c,d],m),n.Value=h.Value,n.tangent=a,n._isPrivateTangent=g,n.borders[2].setArrow(!1,!1),m=i.copyAttributes(o,e.options,"slopetriangle","label"),f=e.create("text",[function(){return c.X()+.1},function(){return.5*(c.Y()+d.Y())},function(){return""}],m),f._setText(function(){return i.toFixed(n.Value(),i.evaluate(f.visProp.digits))}),f.fullUpdate(),n.glider=c,n.basepoint=p,n.baseline=u,n.toppoint=d,n.label=f,n.subs={glider:c,basePoint:p,baseLine:u,topPoint:d,label:f},n.inherits.push(c,p,u,d,f),n.methodMap=t.deepCopy(n.methodMap,{tangent:"tangent",glider:"glider",basepoint:"basepoint",baseline:"baseline",toppoint:"toppoint",label:"label",Value:"Value",V:"Value"}),n.remove=h.removeSlopeTriangle,n},t.registerElement("slopetriangle",t.createSlopeTriangle),{createSlopeTriangle:t.createSlopeTriangle}}),define("element/checkbox",["jxg","utils/env","utils/type"],function(t,e,i){"use strict";var r={CheckboxChangeEventHandler:function(){this._value=this.rendNodeCheckbox.checked,this.board.update()}};return t.createCheckbox=function(s,o,n){var a,h,l=i.copyAttributes(n,s.options,"checkbox");return h=[o[0],o[1],'<span style="display:inline"><input type="checkbox" /><label for=""></label></span>'],a=s.create("text",h,l),a.type=i.OBJECT_TYPE_CHECKBOX,a.rendNodeCheckbox=a.rendNode.childNodes[0].childNodes[0],a.rendNodeLabel=a.rendNode.childNodes[0].childNodes[1],a.rendNodeTag=a.rendNodeCheckbox,a.rendNodeTag.disabled=!!l.disabled,a.rendNodeLabel.innerHTML=o[2],a.rendNodeCheckbox.id=a.rendNode.id+"_checkbox",a.rendNodeLabel.id=a.rendNode.id+"_label",a.rendNodeLabel.setAttribute("for",a.rendNodeCheckbox.id),a.visPropOld.fontsize="0px",s.renderer.updateTextStyle(a,!1),a.rendNodeCheckbox.checked=l.checked,a._value=l.checked,a.Value=function(){return this._value},a.update=function(){return this.needsUpdate&&(t.Text.prototype.update.call(this),this._value=this.rendNodeCheckbox.checked),this},e.addEvent(a.rendNodeCheckbox,"change",r.CheckboxChangeEventHandler,a),a},t.registerElement("checkbox",t.createCheckbox),{createCheckbox:t.createCheckbox}}),define("element/input",["jxg","utils/env","utils/type"],function(t,e,i){"use strict";var r={InputInputEventHandler:function(t){this._value=this.rendNodeInput.value,this.board.update()}};return t.createInput=function(s,o,n){var a,h,l=i.copyAttributes(n,s.options,"input");return h=[o[0],o[1],'<span style="display:inline; white-space:nowrap; padding:0px;"><span></span><input type="text" maxlength="'+l.maxlength+'" style="width:100%"/></span>'],a=s.create("text",h,l),a.type=i.OBJECT_TYPE_INPUT,a.rendNodeLabel=a.rendNode.childNodes[0].childNodes[0],a.rendNodeInput=a.rendNode.childNodes[0].childNodes[1],a.rendNodeLabel.innerHTML=o[3],a.rendNodeInput.value=o[2],a.rendNodeTag=a.rendNodeInput,a.rendNodeTag.disabled=!!l.disabled,a.rendNodeLabel.id=a.rendNode.id+"_label",a.rendNodeInput.id=a.rendNode.id+"_input",a._value=o[2],a.update=function(){return this.needsUpdate&&(t.Text.prototype.update.call(this),this._value=this.rendNodeInput.value),this},a.Value=function(){return this._value},a.set=function(t){return this._value=t,this.rendNodeInput.value=t,this},e.addEvent(a.rendNodeInput,"input",r.InputInputEventHandler,a),e.addEvent(a.rendNodeInput,"mousedown",function(t){i.exists(t.stopPropagation)&&t.stopPropagation()},a),e.addEvent(a.rendNodeInput,"touchstart",function(t){i.exists(t.stopPropagation)&&t.stopPropagation()},a),e.addEvent(a.rendNodeInput,"pointerdown",function(t){i.exists(t.stopPropagation)&&t.stopPropagation()},a),a.visPropOld.fontsize="0px",s.renderer.updateTextStyle(a,!1),a},t.registerElement("input",t.createInput),{createInput:t.createInput}}),define("element/button",["jxg","utils/env","utils/type"],function(t,e,i){"use strict";var r={ButtonClickEventHandler:function(){this._handler&&this._handler(),this.board.update()}};return t.createButton=function(s,o,n){var a,h,l=i.copyAttributes(n,s.options,"button");return h=[o[0],o[1],'<button type="button" style="width:100%;"></button>'],a=s.create("text",h,l),a.type=i.OBJECT_TYPE_BUTTON,a.rendNodeButton=a.rendNode.childNodes[0],a.rendNodeButton.id=a.rendNode.id+"_button",a.rendNodeButton.innerHTML=o[2],a.rendNodeTag=a.rendNodeButton,a.rendNodeTag.disabled=!!l.disabled,a.visPropOld.fontsize="0px",s.renderer.updateTextStyle(a,!1),o[3]&&(i.isString(o[3])?(a._jc=new t.JessieCode,a._jc.use(s),a._handler=function(){a._jc.parse(o[3])}):a._handler=o[3]),e.addEvent(a.rendNodeButton,"click",r.ButtonClickEventHandler,a),e.addEvent(a.rendNodeButton,"mousedown",function(t){i.exists(t.stopPropagation)&&t.stopPropagation()},a),e.addEvent(a.rendNodeButton,"touchstart",function(t){i.exists(t.stopPropagation)&&t.stopPropagation()},a),e.addEvent(a.rendNodeButton,"pointerdown",function(t){i.exists(t.stopPropagation)&&t.stopPropagation()},a),a},t.registerElement("button",t.createButton),{createButton:t.createButton}}),define("../build/core.deps.js",["jxg","utils/env","base/constants","utils/type","utils/xml","utils/event","utils/expect","math/math","math/ia","math/extrapolate","math/qdt","math/numerics","math/plot","math/metapost","math/statistics","math/symbolic","math/geometry","math/clip","math/poly","math/complex","renderer/abstract","reader/file","parser/geonext","base/board","options","jsxgraph","base/element","base/coords","base/coordselement","base/point","base/line","base/group","base/circle","element/conic","base/polygon","base/curve","element/arc","element/sector","base/composition","element/composition","element/locus","base/text","base/image","element/slider","element/measure","base/chart","base/transformation","base/turtle","utils/color","base/ticks","utils/zip","utils/base64","utils/uuid","utils/encoding","server/server","parser/datasource","parser/jessiecode","parser/ca","utils/dump","renderer/svg","renderer/vml","renderer/canvas","renderer/no","element/comb","element/slopetriangle","element/checkbox","element/input","element/button"],function(t,e){"use strict";return e.isBrowser?window.JXG=t:e.isNode()&&"object"==typeof module?module.exports=t:e.isWebWorker()&&(self.JXG=t),t}),require("../build/core.deps.js")}); +//# sourceMappingURL=jsxgraphcore-lazy.min.js.map \ No newline at end of file diff --git a/amd/build/jsxgraphcore-lazy.min.js.map b/amd/build/jsxgraphcore-lazy.min.js.map new file mode 100644 index 000000000..b2c3be3e3 --- /dev/null +++ b/amd/build/jsxgraphcore-lazy.min.js.map @@ -0,0 +1 @@ +{"version":3,"file":"jsxgraphcore-lazy.min.js","sources":["../src/jsxgraphcore-lazy.js"],"sourcesContent":["/*\n JSXGraph 1.4.4\n\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Andreas Walter,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <https://www.gnu.org/licenses/>\n and <https://opensource.org/licenses/MIT/>.\n*/\n\ndefine(function () {\n\n/**\n * @license almond 0.3.3 Copyright jQuery Foundation and other contributors.\n * Released under MIT license, http://github.com/requirejs/almond/LICENSE\n */\n//Going sloppy to avoid 'use strict' string cost, but strict practices should\n//be followed.\n/*global setTimeout: false */\n\nvar requirejs, require, define;\n(function (undef) {\n var main, req, makeMap, handlers,\n defined = {},\n waiting = {},\n config = {},\n defining = {},\n hasOwn = Object.prototype.hasOwnProperty,\n aps = [].slice,\n jsSuffixRegExp = /\\.js$/;\n\n function hasProp(obj, prop) {\n return hasOwn.call(obj, prop);\n }\n\n /**\n * Given a relative module name, like ./something, normalize it to\n * a real name that can be mapped to a path.\n * @param {String} name the relative name\n * @param {String} baseName a real name that the name arg is relative\n * to.\n * @returns {String} normalized name\n */\n function normalize(name, baseName) {\n var nameParts, nameSegment, mapValue, foundMap, lastIndex,\n foundI, foundStarMap, starI, i, j, part, normalizedBaseParts,\n baseParts = baseName && baseName.split(\"/\"),\n map = config.map,\n starMap = (map && map['*']) || {};\n\n //Adjust any relative paths.\n if (name) {\n name = name.split('/');\n lastIndex = name.length - 1;\n\n // If wanting node ID compatibility, strip .js from end\n // of IDs. Have to do this here, and not in nameToUrl\n // because node allows either .js or non .js to map\n // to same file.\n if (config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex])) {\n name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, '');\n }\n\n // Starts with a '.' so need the baseName\n if (name[0].charAt(0) === '.' && baseParts) {\n //Convert baseName to array, and lop off the last part,\n //so that . matches that 'directory' and not name of the baseName's\n //module. For instance, baseName of 'one/two/three', maps to\n //'one/two/three.js', but we want the directory, 'one/two' for\n //this normalization.\n normalizedBaseParts = baseParts.slice(0, baseParts.length - 1);\n name = normalizedBaseParts.concat(name);\n }\n\n //start trimDots\n for (i = 0; i < name.length; i++) {\n part = name[i];\n if (part === '.') {\n name.splice(i, 1);\n i -= 1;\n } else if (part === '..') {\n // If at the start, or previous value is still ..,\n // keep them so that when converted to a path it may\n // still work when converted to a path, even though\n // as an ID it is less than ideal. In larger point\n // releases, may be better to just kick out an error.\n if (i === 0 || (i === 1 && name[2] === '..') || name[i - 1] === '..') {\n continue;\n } else if (i > 0) {\n name.splice(i - 1, 2);\n i -= 2;\n }\n }\n }\n //end trimDots\n\n name = name.join('/');\n }\n\n //Apply map config if available.\n if ((baseParts || starMap) && map) {\n nameParts = name.split('/');\n\n for (i = nameParts.length; i > 0; i -= 1) {\n nameSegment = nameParts.slice(0, i).join(\"/\");\n\n if (baseParts) {\n //Find the longest baseName segment match in the config.\n //So, do joins on the biggest to smallest lengths of baseParts.\n for (j = baseParts.length; j > 0; j -= 1) {\n mapValue = map[baseParts.slice(0, j).join('/')];\n\n //baseName segment has config, find if it has one for\n //this name.\n if (mapValue) {\n mapValue = mapValue[nameSegment];\n if (mapValue) {\n //Match, update name to the new value.\n foundMap = mapValue;\n foundI = i;\n break;\n }\n }\n }\n }\n\n if (foundMap) {\n break;\n }\n\n //Check for a star map match, but just hold on to it,\n //if there is a shorter segment match later in a matching\n //config, then favor over this star map.\n if (!foundStarMap && starMap && starMap[nameSegment]) {\n foundStarMap = starMap[nameSegment];\n starI = i;\n }\n }\n\n if (!foundMap && foundStarMap) {\n foundMap = foundStarMap;\n foundI = starI;\n }\n\n if (foundMap) {\n nameParts.splice(0, foundI, foundMap);\n name = nameParts.join('/');\n }\n }\n\n return name;\n }\n\n function makeRequire(relName, forceSync) {\n return function () {\n //A version of a require function that passes a moduleName\n //value for items that may need to\n //look up paths relative to the moduleName\n var args = aps.call(arguments, 0);\n\n //If first arg is not require('string'), and there is only\n //one arg, it is the array form without a callback. Insert\n //a null so that the following concat is correct.\n if (typeof args[0] !== 'string' && args.length === 1) {\n args.push(null);\n }\n return req.apply(undef, args.concat([relName, forceSync]));\n };\n }\n\n function makeNormalize(relName) {\n return function (name) {\n return normalize(name, relName);\n };\n }\n\n function makeLoad(depName) {\n return function (value) {\n defined[depName] = value;\n };\n }\n\n function callDep(name) {\n if (hasProp(waiting, name)) {\n var args = waiting[name];\n delete waiting[name];\n defining[name] = true;\n main.apply(undef, args);\n }\n\n if (!hasProp(defined, name) && !hasProp(defining, name)) {\n throw new Error('No ' + name);\n }\n return defined[name];\n }\n\n //Turns a plugin!resource to [plugin, resource]\n //with the plugin being undefined if the name\n //did not have a plugin prefix.\n function splitPrefix(name) {\n var prefix,\n index = name ? name.indexOf('!') : -1;\n if (index > -1) {\n prefix = name.substring(0, index);\n name = name.substring(index + 1, name.length);\n }\n return [prefix, name];\n }\n\n //Creates a parts array for a relName where first part is plugin ID,\n //second part is resource ID. Assumes relName has already been normalized.\n function makeRelParts(relName) {\n return relName ? splitPrefix(relName) : [];\n }\n\n /**\n * Makes a name map, normalizing the name, and using a plugin\n * for normalization if necessary. Grabs a ref to plugin\n * too, as an optimization.\n */\n makeMap = function (name, relParts) {\n var plugin,\n parts = splitPrefix(name),\n prefix = parts[0],\n relResourceName = relParts[1];\n\n name = parts[1];\n\n if (prefix) {\n prefix = normalize(prefix, relResourceName);\n plugin = callDep(prefix);\n }\n\n //Normalize according\n if (prefix) {\n if (plugin && plugin.normalize) {\n name = plugin.normalize(name, makeNormalize(relResourceName));\n } else {\n name = normalize(name, relResourceName);\n }\n } else {\n name = normalize(name, relResourceName);\n parts = splitPrefix(name);\n prefix = parts[0];\n name = parts[1];\n if (prefix) {\n plugin = callDep(prefix);\n }\n }\n\n //Using ridiculous property names for space reasons\n return {\n f: prefix ? prefix + '!' + name : name, //fullName\n n: name,\n pr: prefix,\n p: plugin\n };\n };\n\n function makeConfig(name) {\n return function () {\n return (config && config.config && config.config[name]) || {};\n };\n }\n\n handlers = {\n require: function (name) {\n return makeRequire(name);\n },\n exports: function (name) {\n var e = defined[name];\n if (typeof e !== 'undefined') {\n return e;\n } else {\n return (defined[name] = {});\n }\n },\n module: function (name) {\n return {\n id: name,\n uri: '',\n exports: defined[name],\n config: makeConfig(name)\n };\n }\n };\n\n main = function (name, deps, callback, relName) {\n var cjsModule, depName, ret, map, i, relParts,\n args = [],\n callbackType = typeof callback,\n usingExports;\n\n //Use name if no relName\n relName = relName || name;\n relParts = makeRelParts(relName);\n\n //Call the callback to define the module, if necessary.\n if (callbackType === 'undefined' || callbackType === 'function') {\n //Pull out the defined dependencies and pass the ordered\n //values to the callback.\n //Default to [require, exports, module] if no deps\n deps = !deps.length && callback.length ? ['require', 'exports', 'module'] : deps;\n for (i = 0; i < deps.length; i += 1) {\n map = makeMap(deps[i], relParts);\n depName = map.f;\n\n //Fast path CommonJS standard dependencies.\n if (depName === \"require\") {\n args[i] = handlers.require(name);\n } else if (depName === \"exports\") {\n //CommonJS module spec 1.1\n args[i] = handlers.exports(name);\n usingExports = true;\n } else if (depName === \"module\") {\n //CommonJS module spec 1.1\n cjsModule = args[i] = handlers.module(name);\n } else if (hasProp(defined, depName) ||\n hasProp(waiting, depName) ||\n hasProp(defining, depName)) {\n args[i] = callDep(depName);\n } else if (map.p) {\n map.p.load(map.n, makeRequire(relName, true), makeLoad(depName), {});\n args[i] = defined[depName];\n } else {\n throw new Error(name + ' missing ' + depName);\n }\n }\n\n ret = callback ? callback.apply(defined[name], args) : undefined;\n\n if (name) {\n //If setting exports via \"module\" is in play,\n //favor that over return value and exports. After that,\n //favor a non-undefined return value over exports use.\n if (cjsModule && cjsModule.exports !== undef &&\n cjsModule.exports !== defined[name]) {\n defined[name] = cjsModule.exports;\n } else if (ret !== undef || !usingExports) {\n //Use the return value from the function.\n defined[name] = ret;\n }\n }\n } else if (name) {\n //May just be an object definition for the module. Only\n //worry about defining if have a module name.\n defined[name] = callback;\n }\n };\n\n requirejs = require = req = function (deps, callback, relName, forceSync, alt) {\n if (typeof deps === \"string\") {\n if (handlers[deps]) {\n //callback in this case is really relName\n return handlers[deps](callback);\n }\n //Just return the module wanted. In this scenario, the\n //deps arg is the module name, and second arg (if passed)\n //is just the relName.\n //Normalize module name, if it contains . or ..\n return callDep(makeMap(deps, makeRelParts(callback)).f);\n } else if (!deps.splice) {\n //deps is a config object, not an array.\n config = deps;\n if (config.deps) {\n req(config.deps, config.callback);\n }\n if (!callback) {\n return;\n }\n\n if (callback.splice) {\n //callback is an array, which means it is a dependency list.\n //Adjust args if there are dependencies\n deps = callback;\n callback = relName;\n relName = null;\n } else {\n deps = undef;\n }\n }\n\n //Support require(['a'])\n callback = callback || function () {};\n\n //If relName is a function, it is an errback handler,\n //so remove it.\n if (typeof relName === 'function') {\n relName = forceSync;\n forceSync = alt;\n }\n\n //Simulate async callback;\n if (forceSync) {\n main(undef, deps, callback, relName);\n } else {\n //Using a non-zero value because of concern for what old browsers\n //do, and latest browsers \"upgrade\" to 4 if lower value is used:\n //http://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html#dom-windowtimers-settimeout:\n //If want a value immediately, use require('id') instead -- something\n //that works in almond on the global level, but not guaranteed and\n //unlikely to work in other AMD implementations.\n setTimeout(function () {\n main(undef, deps, callback, relName);\n }, 4);\n }\n\n return req;\n };\n\n /**\n * Just drops the config on the floor, but returns req in case\n * the config return value is used.\n */\n req.config = function (cfg) {\n return req(cfg);\n };\n\n /**\n * Expose module registry for debugging and tooling\n */\n requirejs._defined = defined;\n\n define = function (name, deps, callback) {\n if (typeof name !== 'string') {\n throw new Error('See almond README: incorrect module build, no module name');\n }\n\n //This module may not have dependencies\n if (!deps.splice) {\n //deps is not an array, so probably means\n //an object literal or factory function for\n //the value. Adjust args.\n callback = deps;\n deps = [];\n }\n\n if (!hasProp(defined, name) && !hasProp(waiting, name)) {\n waiting[name] = [name, deps, callback];\n }\n };\n\n define.amd = {\n jQuery: true\n };\n}());\n\ndefine(\"../node_modules/almond/almond\", function(){});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Andreas Walter,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph and JSXCompressor.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n JSXCompressor is free software dual licensed under the GNU LGPL or Apache License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n OR\n * Apache License Version 2.0\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License, Apache\n License, and the MIT License along with JSXGraph. If not, see\n <http://www.gnu.org/licenses/>, <https://www.apache.org/licenses/LICENSE-2.0.html>,\n and <http://opensource.org/licenses/MIT/>.\n\n */\n\n/*global JXG: true, define: true, jQuery: true, window: true, document: true, navigator: true, require: true, module: true, console: true */\n/*jslint nomen:true, plusplus:true, forin:true*/\n\n/* depends:\n */\n\n/**\n * @fileoverview The JSXGraph object is defined in this file. JXG.JSXGraph controls all boards.\n * It has methods to create, save, load and free boards. Additionally some helper functions are\n * defined in this file directly in the JXG namespace.\n */\n\ndefine('jxg',[], function () {\n\n 'use strict';\n\n /**\n * JXG is the top object of JSXGraph and defines the namespace\n * @exports jxg as JXG\n */\n var jxg = {};\n\n // Make sure JXG.extend is not defined\n // If jsxgraph is loaded via loadjsxgraph.js, this is required, but JXG.extend will be undefined\n // If jsxgraph is compiled as an amd module, it is possible that another jsxgraph version is already loaded and we\n // therefore must not re-use the global JXG variable. But in this case JXG.extend will already be defined.\n // This is the reason for this check.\n if (typeof JXG === 'object' && !JXG.extend) {\n jxg = JXG;\n }\n\n // We need the following two methods \"extend\" and \"shortcut\" to create the JXG object via JXG.extend.\n\n /**\n * Copy all properties of the <tt>extension</tt> object to <tt>object</tt>.\n * @param {Object} object\n * @param {Object} extension\n * @param {Boolean} [onlyOwn=false] Only consider properties that belong to extension itself, not any inherited properties.\n * @param {Boolean} [toLower=false] If true the keys are convert to lower case. This is needed for visProp, see JXG#copyAttributes\n */\n jxg.extend = function (object, extension, onlyOwn, toLower) {\n var e, e2;\n\n onlyOwn = onlyOwn || false;\n toLower = toLower || false;\n\n // the purpose of this for...in loop is indeed to use hasOwnProperty only if the caller\n // explicitly wishes so.\n for (e in extension) {\n if (!onlyOwn || (onlyOwn && extension.hasOwnProperty(e))) {\n if (toLower) {\n e2 = e.toLowerCase();\n } else {\n e2 = e;\n }\n\n object[e2] = extension[e];\n }\n }\n };\n\n /**\n * Set a constant <tt>name</tt> in <tt>object</tt> to <tt>value</tt>. The value can't be changed after declaration.\n * @param {Object} object\n * @param {String} name\n * @param {Number|String|Boolean} value\n * @param {Boolean} ignoreRedefine This should be left at its default: false.\n */\n jxg.defineConstant = function (object, name, value, ignoreRedefine) {\n ignoreRedefine = ignoreRedefine || false;\n\n if (ignoreRedefine && jxg.exists(object[name])) {\n return;\n }\n\n Object.defineProperty(object, name, {\n value: value,\n writable: false,\n enumerable: true,\n configurable: false,\n });\n };\n\n /**\n * Copy all properties of the <tt>constants</tt> object in <tt>object</tt> as a constant.\n * @param {Object} object\n * @param {Object} constants\n * @param {Boolean} [onlyOwn=false] Only consider properties that belong to extension itself, not any inherited properties.\n * @param {Boolean} [toUpper=false] If true the keys are convert to lower case. This is needed for visProp, see JXG#copyAttributes\n */\n jxg.extendConstants = function (object, constants, onlyOwn, toUpper) {\n var e, e2;\n\n onlyOwn = onlyOwn || false;\n toUpper = toUpper || false;\n\n // The purpose of this for...in loop is indeed to use hasOwnProperty only if the caller explicitly wishes so.\n for (e in constants) {\n if (!onlyOwn || (onlyOwn && constants.hasOwnProperty(e))) {\n if (toUpper) {\n e2 = e.toUpperCase();\n } else {\n e2 = e;\n }\n\n this.defineConstant(object, e2, constants[e]);\n }\n }\n };\n\n jxg.extend(jxg, /** @lends JXG */ {\n /**\n * Store a reference to every board in this central list. This will at some point\n * replace JXG.JSXGraph.boards.\n * @type Object\n */\n boards: {},\n\n /**\n * Store the available file readers in this structure.\n * @type Object\n */\n readers: {},\n\n /**\n * Associative array that keeps track of all constructable elements registered\n * via {@link JXG.registerElement}.\n * @type Object\n */\n elements: {},\n\n /**\n * This registers a new construction element to JSXGraph for the construction via the {@link JXG.Board.create}\n * interface.\n * @param {String} element The elements name. This is case-insensitive, existing elements with the same name\n * will be overwritten.\n * @param {Function} creator A reference to a function taking three parameters: First the board, the element is\n * to be created on, a parent element array, and an attributes object. See {@link JXG.createPoint} or any other\n * <tt>JXG.create...</tt> function for an example.\n */\n registerElement: function (element, creator) {\n element = element.toLowerCase();\n this.elements[element] = creator;\n },\n\n /**\n * Register a file reader.\n * @param {function} reader A file reader. This object has to provide two methods: <tt>prepareString()</tt>\n * and <tt>read()</tt>.\n * @param {Array} ext\n */\n registerReader: function (reader, ext) {\n var i, e;\n\n for (i = 0; i < ext.length; i++) {\n e = ext[i].toLowerCase();\n\n if (typeof this.readers[e] !== 'function') {\n this.readers[e] = reader;\n }\n }\n },\n\n /**\n * Creates a shortcut to a method, e.g. {@link JXG.Board#createElement} is a shortcut to {@link JXG.Board#create}.\n * Sometimes the target is undefined by the time you want to define the shortcut so we need this little helper.\n * @param {Object} object The object the method we want to create a shortcut for belongs to.\n * @param {String} fun The method we want to create a shortcut for.\n * @returns {Function} A function that calls the given method.\n */\n shortcut: function (object, fun) {\n return function () {\n return object[fun].apply(this, arguments);\n };\n },\n\n /**\n * s may be a string containing the name or id of an element or even a reference\n * to the element itself. This function returns a reference to the element. Search order: id, name.\n * @param {JXG.Board} board Reference to the board the element belongs to.\n * @param {String} s String or reference to a JSXGraph element.\n * @returns {Object} Reference to the object given in parameter object\n * @deprecated Use {@link JXG.Board#select}\n */\n getRef: function (board, s) {\n jxg.deprecated('JXG.getRef()', 'Board.select()');\n return board.select(s);\n },\n\n /**\n * This is just a shortcut to {@link JXG.getRef}.\n * @deprecated Use {@link JXG.Board#select}.\n */\n getReference: function (board, s) {\n jxg.deprecated('JXG.getReference()', 'Board.select()');\n return board.select(s);\n },\n\n /**\n * s may be the string containing the id of an HTML tag that hosts a JSXGraph board.\n * This function returns the reference to the board.\n * @param {String} s String of an HTML tag that hosts a JSXGraph board\n * @returns {Object} Reference to the board or null.\n */\n getBoardByContainerId: function (s) {\n var b;\n for (b in JXG.boards) {\n if (JXG.boards.hasOwnProperty(b) &&\n JXG.boards[b].container === s) {\n return JXG.boards[b];\n }\n }\n\n return null;\n },\n\n /**\n * This method issues a warning to the developer that the given function is deprecated\n * and, if available, offers an alternative to the deprecated function.\n * @param {String} what Describes the function that is deprecated\n * @param {String} [replacement] The replacement that should be used instead.\n */\n deprecated: function (what, replacement) {\n var warning = what + ' is deprecated.';\n\n if (replacement) {\n warning += ' Please use ' + replacement + ' instead.';\n }\n\n jxg.warn(warning);\n },\n\n /**\n * Outputs a warning via console.warn(), if available. If console.warn() is\n * unavailable this function will look for an HTML element with the id 'warning'\n * and append the warning to this element's innerHTML.\n * @param {String} warning The warning text\n */\n warn: function (warning) {\n if (typeof window === 'object' && window.console && console.warn) {\n console.warn('WARNING:', warning);\n } else if (typeof document === 'object' && document.getElementById('warning')) {\n document.getElementById('debug').innerHTML += 'WARNING: ' + warning + '<br />';\n }\n },\n\n /**\n * Add something to the debug log. If available a JavaScript debug console is used. Otherwise\n * we're looking for a HTML div with id \"debug\". If this doesn't exist, too, the output is omitted.\n * @param s An arbitrary number of parameters.\n * @see JXG#debugWST\n */\n debugInt: function (s) {\n var i, p;\n\n for (i = 0; i < arguments.length; i++) {\n p = arguments[i];\n if (typeof window === 'object' && window.console && console.log) {\n console.log(p);\n } else if (typeof document === 'object' && document.getElementById('debug')) {\n document.getElementById('debug').innerHTML += p + '<br/>';\n }\n }\n },\n\n /**\n * Add something to the debug log. If available a JavaScript debug console is used. Otherwise\n * we're looking for a HTML div with id \"debug\". If this doesn't exist, too, the output is omitted.\n * This method adds a stack trace (if available).\n * @param s An arbitrary number of parameters.\n * @see JXG#debug\n */\n debugWST: function (s) {\n var e = new Error();\n\n jxg.debugInt.apply(this, arguments);\n\n if (e && e.stack) {\n jxg.debugInt('stacktrace');\n jxg.debugInt(e.stack.split('\\n').slice(1).join('\\n'));\n }\n },\n\n /**\n * Add something to the debug log. If available a JavaScript debug console is used. Otherwise\n * we're looking for a HTML div with id \"debug\". If this doesn't exist, too, the output is omitted.\n * This method adds a line of the stack trace (if available).\n *\n * @param s An arbitrary number of parameters.\n * @see JXG#debug\n */\n debugLine: function (s) {\n var e = new Error();\n\n jxg.debugInt.apply(this, arguments);\n\n if (e && e.stack) {\n jxg.debugInt('Called from', e.stack.split('\\n').slice(2, 3).join('\\n'));\n }\n },\n\n /**\n * Add something to the debug log. If available a JavaScript debug console is used. Otherwise\n * we're looking for a HTML div with id \"debug\". If this doesn't exist, too, the output is omitted.\n * @param s An arbitrary number of parameters.\n * @see JXG#debugWST\n * @see JXG#debugLine\n * @see JXG#debugInt\n */\n debug: function (s) {\n jxg.debugInt.apply(this, arguments);\n }\n });\n\n return jxg;\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Andreas Walter,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n/*global JXG: true, define: true*/\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n jxg\n */\n\ndefine('base/constants',['jxg'], function (JXG) {\n 'use strict';\n\n var major = 1,\n minor = 4,\n patch = 4,\n add = '', //'dev'\n version = major + '.' + minor + '.' + patch + (add ? '-' + add : ''),\n constants;\n\n constants = /** @lends JXG */ {\n /**\n * Constant: the currently used JSXGraph version.\n *\n * @name JXG.version\n * @type String\n */\n version: version,\n\n /**\n * Constant: the small gray version indicator in the top left corner of every JSXGraph board (if\n * showCopyright is not set to false on board creation).\n *\n * @name JXG.licenseText\n * @type String\n */\n licenseText: 'JSXGraph v' + version + ' Copyright (C) see https://jsxgraph.org',\n\n /**\n * Constant: user coordinates relative to the coordinates system defined by the bounding box.\n * @name JXG.COORDS_BY_USER\n * @type Number\n */\n COORDS_BY_USER: 0x0001,\n\n /**\n * Constant: screen coordinates in pixel relative to the upper left corner of the div element.\n * @name JXG.COORDS_BY_SCREEN\n * @type Number\n */\n COORDS_BY_SCREEN: 0x0002,\n\n // object types\n OBJECT_TYPE_ARC: 1,\n OBJECT_TYPE_ARROW: 2,\n OBJECT_TYPE_AXIS: 3,\n OBJECT_TYPE_AXISPOINT: 4,\n OBJECT_TYPE_TICKS: 5,\n OBJECT_TYPE_CIRCLE: 6,\n OBJECT_TYPE_CONIC: 7,\n OBJECT_TYPE_CURVE: 8,\n OBJECT_TYPE_GLIDER: 9,\n OBJECT_TYPE_IMAGE: 10,\n OBJECT_TYPE_LINE: 11,\n OBJECT_TYPE_POINT: 12,\n OBJECT_TYPE_SLIDER: 13,\n OBJECT_TYPE_CAS: 14,\n OBJECT_TYPE_GXTCAS: 15,\n OBJECT_TYPE_POLYGON: 16,\n OBJECT_TYPE_SECTOR: 17,\n OBJECT_TYPE_TEXT: 18,\n OBJECT_TYPE_ANGLE: 19,\n OBJECT_TYPE_INTERSECTION: 20,\n OBJECT_TYPE_TURTLE: 21,\n OBJECT_TYPE_VECTOR: 22,\n OBJECT_TYPE_OPROJECT: 23,\n OBJECT_TYPE_GRID: 24,\n OBJECT_TYPE_TANGENT: 25,\n OBJECT_TYPE_HTMLSLIDER: 26,\n OBJECT_TYPE_CHECKBOX: 27,\n OBJECT_TYPE_INPUT: 28,\n OBJECT_TYPE_BUTTON: 29,\n OBJECT_TYPE_TRANSFORMATION: 30,\n OBJECT_TYPE_FOREIGNOBJECT: 31,\n OBJECT_TYPE_VIEW3D: 32,\n\n // IMPORTANT:\n // ----------\n // For being able to differentiate between the (sketchometry specific) SPECIAL_OBJECT_TYPEs and\n // (core specific) OBJECT_TYPEs, the non-sketchometry types MUST NOT be changed\n // to values > 100.\n\n // object classes\n OBJECT_CLASS_POINT: 1,\n OBJECT_CLASS_LINE: 2,\n OBJECT_CLASS_CIRCLE: 3,\n OBJECT_CLASS_CURVE: 4,\n OBJECT_CLASS_AREA: 5,\n OBJECT_CLASS_OTHER: 6,\n OBJECT_CLASS_TEXT: 7,\n\n // SketchReader constants\n GENTYPE_ABC: 1, // unused\n GENTYPE_AXIS: 2,\n GENTYPE_MID: 3,\n\n /**\n * @ignore\n * @deprecated, now use {@link JXG.GENTYPE_REFLECTION_ON_LINE}\n *\n */\n GENTYPE_REFLECTION: 4,\n /**\n * @ignore\n * @deprecated, now use {@link JXG.GENTYPE_REFLECTION_ON_POINT}\n */\n GENTYPE_MIRRORELEMENT: 5,\n\n GENTYPE_REFLECTION_ON_LINE: 4,\n GENTYPE_REFLECTION_ON_POINT: 5,\n GENTYPE_TANGENT: 6,\n GENTYPE_PARALLEL: 7,\n GENTYPE_BISECTORLINES: 8,\n GENTYPE_BOARDIMG: 9,\n GENTYPE_BISECTOR: 10,\n GENTYPE_NORMAL: 11,\n GENTYPE_POINT: 12,\n GENTYPE_GLIDER: 13,\n GENTYPE_INTERSECTION: 14,\n GENTYPE_CIRCLE: 15,\n /**\n * @ignore @deprecated NOT USED ANY MORE SINCE SKETCHOMETRY 2.0 (only for old constructions needed)\n */\n GENTYPE_CIRCLE2POINTS: 16,\n\n GENTYPE_LINE: 17,\n GENTYPE_TRIANGLE: 18,\n GENTYPE_QUADRILATERAL: 19,\n GENTYPE_TEXT: 20,\n GENTYPE_POLYGON: 21,\n GENTYPE_REGULARPOLYGON: 22,\n GENTYPE_SECTOR: 23,\n GENTYPE_ANGLE: 24,\n GENTYPE_PLOT: 25,\n GENTYPE_SLIDER: 26,\n GENTYPE_TRUNCATE: 27,\n GENTYPE_JCODE: 28,\n GENTYPE_MOVEMENT: 29,\n GENTYPE_COMBINED: 30,\n GENTYPE_RULER: 31,\n GENTYPE_SLOPETRIANGLE: 32,\n GENTYPE_PERPSEGMENT: 33,\n GENTYPE_LABELMOVEMENT: 34,\n GENTYPE_VECTOR: 35,\n GENTYPE_NONREFLEXANGLE: 36,\n GENTYPE_REFLEXANGLE: 37,\n GENTYPE_PATH: 38,\n GENTYPE_DERIVATIVE: 39,\n // 40 // unused ...\n GENTYPE_DELETE: 41,\n GENTYPE_COPY: 42,\n GENTYPE_MIRROR: 43,\n GENTYPE_ROTATE: 44,\n GENTYPE_ABLATION: 45,\n GENTYPE_MIGRATE: 46,\n GENTYPE_VECTORCOPY: 47,\n GENTYPE_POLYGONCOPY: 48, /**\n * Constants\n * @name Constants\n * @namespace\n */\n\n // GENTYPE_TRANSFORM: 48, // unused\n // 49 ... 50 // unused ...\n\n // IMPORTANT:\n // ----------\n // For being able to differentiate between the (GUI-specific) CTX and\n // (CORE-specific) non-CTX steps, the non-CTX steps MUST NOT be changed\n // to values > 50.\n\n GENTYPE_CTX_TYPE_G: 51,\n GENTYPE_CTX_TYPE_P: 52,\n GENTYPE_CTX_TRACE: 53,\n GENTYPE_CTX_VISIBILITY: 54,\n GENTYPE_CTX_CCVISIBILITY: 55, // unused\n GENTYPE_CTX_MPVISIBILITY: 56,\n GENTYPE_CTX_WITHLABEL: 57,\n GENTYPE_CTX_LABEL: 58,\n GENTYPE_CTX_FIXED: 59,\n GENTYPE_CTX_STROKEWIDTH: 60,\n GENTYPE_CTX_LABELSIZE: 61,\n GENTYPE_CTX_SIZE: 62,\n GENTYPE_CTX_FACE: 63,\n GENTYPE_CTX_STRAIGHT: 64,\n GENTYPE_CTX_ARROW: 65,\n GENTYPE_CTX_COLOR: 66,\n GENTYPE_CTX_RADIUS: 67,\n GENTYPE_CTX_COORDS: 68,\n GENTYPE_CTX_TEXT: 69,\n GENTYPE_CTX_ANGLERADIUS: 70,\n GENTYPE_CTX_DOTVISIBILITY: 71,\n GENTYPE_CTX_FILLOPACITY: 72,\n GENTYPE_CTX_PLOT: 73,\n GENTYPE_CTX_SCALE: 74,\n GENTYPE_CTX_INTVAL: 75,\n GENTYPE_CTX_POINT1: 76,\n GENTYPE_CTX_POINT2: 77,\n GENTYPE_CTX_LABELSTICKY: 78,\n GENTYPE_CTX_TYPE_I: 79,\n GENTYPE_CTX_HASINNERPOINTS: 80,\n GENTYPE_CTX_SNAPWIDTH: 81,\n GENTYPE_CTX_SNAPTOGRID: 82\n };\n\n JXG.extendConstants(JXG, constants);\n\n return constants;\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Andreas Walter,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n/*global JXG: true, define: true, html_sanitize: true*/\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n jxg\n base/constants\n */\n\n/**\n * @fileoverview type.js contains several functions to help deal with javascript's weak types.\n * This file mainly consists of detector functions which verify if a variable is or is not of\n * a specific type and converter functions that convert variables to another type or normalize\n * the type of a variable.\n */\n\ndefine('utils/type',[\n 'jxg', 'base/constants'\n], function (JXG, Const) {\n\n 'use strict';\n\n JXG.extend(JXG, /** @lends JXG */ {\n /**\n * Checks if the given string is an id within the given board.\n * @param {JXG.Board} board\n * @param {String} s\n * @returns {Boolean}\n */\n isId: function (board, s) {\n return (typeof s === 'string') && !!board.objects[s];\n },\n\n /**\n * Checks if the given string is a name within the given board.\n * @param {JXG.Board} board\n * @param {String} s\n * @returns {Boolean}\n */\n isName: function (board, s) {\n return typeof s === 'string' && !!board.elementsByName[s];\n },\n\n /**\n * Checks if the given string is a group id within the given board.\n * @param {JXG.Board} board\n * @param {String} s\n * @returns {Boolean}\n */\n isGroup: function (board, s) {\n return typeof s === 'string' && !!board.groups[s];\n },\n\n /**\n * Checks if the value of a given variable is of type string.\n * @param v A variable of any type.\n * @returns {Boolean} True, if v is of type string.\n */\n isString: function (v) {\n return typeof v === 'string';\n },\n\n /**\n * Checks if the value of a given variable is of type number.\n * @param v A variable of any type.\n * @returns {Boolean} True, if v is of type number.\n */\n isNumber: function (v) {\n return typeof v === 'number' || Object.prototype.toString.call(v) === '[Object Number]';\n },\n\n /**\n * Checks if a given variable references a function.\n * @param v A variable of any type.\n * @returns {Boolean} True, if v is a function.\n */\n isFunction: function (v) {\n return typeof v === 'function';\n },\n\n /**\n * Checks if a given variable references an array.\n * @param v A variable of any type.\n * @returns {Boolean} True, if v is of type array.\n */\n isArray: function (v) {\n var r;\n\n // use the ES5 isArray() method and if that doesn't exist use a fallback.\n if (Array.isArray) {\n r = Array.isArray(v);\n } else {\n r = (v !== null && typeof v === 'object' && typeof v.splice === 'function' && typeof v.join === 'function');\n }\n\n return r;\n },\n\n /**\n * Tests if the input variable is an Object\n * @param v\n */\n isObject: function (v) {\n return typeof v === 'object' && !this.isArray(v);\n },\n\n /**\n * Checks if a given variable is a reference of a JSXGraph Point element.\n * @param v A variable of any type.\n * @returns {Boolean} True, if v is of type JXG.Point.\n */\n isPoint: function (v) {\n if (v !== null && typeof v === 'object') {\n return (v.elementClass === Const.OBJECT_CLASS_POINT);\n }\n\n return false;\n },\n\n /**\n * Checks if a given variable is a reference of a JSXGraph Point element or an array of length at least two or\n * a function returning an array of length two or three.\n * @param {JXG.Board} board\n * @param v A variable of any type.\n * @returns {Boolean} True, if v is of type JXG.Point.\n */\n isPointType: function (board, v) {\n var val, p;\n\n if (this.isArray(v)) {\n return true;\n }\n if (this.isFunction(v)) {\n val = v();\n if (this.isArray(val) && val.length > 1) {\n return true;\n }\n }\n p = board.select(v);\n return this.isPoint(p);\n },\n\n /**\n * Checks if a given variable is a reference of a JSXGraph transformation element or an array\n * of JSXGraph transformation elements.\n * @param v A variable of any type.\n * @returns {Boolean} True, if v is of type JXG.Transformation.\n */\n isTransformationOrArray: function (v) {\n if (v !== null) {\n if (this.isArray(v) && v.length > 0) {\n return this.isTransformationOrArray(v[0]);\n }\n if (typeof v === 'object') {\n return (v.type === Const.OBJECT_TYPE_TRANSFORMATION);\n }\n }\n return false;\n },\n\n /**\n * Checks if a given variable is neither undefined nor null. You should not use this together with global\n * variables!\n * @param v A variable of any type.\n * @param {Boolean} [checkEmptyString=false] If set to true, it is also checked whether v is not equal to ''.\n * @returns {Boolean} True, if v is neither undefined nor null.\n */\n exists: function (v, checkEmptyString) {\n /* eslint-disable eqeqeq */\n var result = !(v == undefined || v === null);\n /* eslint-enable eqeqeq */\n checkEmptyString = checkEmptyString || false;\n\n if (checkEmptyString) {\n return result && v !== '';\n }\n return result;\n },\n // exists: (function (undef) {\n // return function (v, checkEmptyString) {\n // var result = !(v === undef || v === null);\n\n // checkEmptyString = checkEmptyString || false;\n\n // if (checkEmptyString) {\n // return result && v !== '';\n // }\n // return result;\n // };\n // }()),\n\n /**\n * Checks if v is an empty object or empty.\n * @param v {Object|Array}\n * @returns {boolean} True, if v is an empty object or array.\n */\n isEmpty: function(v) {\n return Object.keys(v).length === 0;\n },\n\n /**\n * Handle default parameters.\n * @param v Given value\n * @param d Default value\n * @returns <tt>d</tt>, if <tt>v</tt> is undefined or null.\n */\n def: function (v, d) {\n if (this.exists(v)) {\n return v;\n }\n\n return d;\n },\n\n /**\n * Converts a string containing either <strong>true</strong> or <strong>false</strong> into a boolean value.\n * @param {String} s String containing either <strong>true</strong> or <strong>false</strong>.\n * @returns {Boolean} String typed boolean value converted to boolean.\n */\n str2Bool: function (s) {\n if (!this.exists(s)) {\n return true;\n }\n\n if (typeof s === 'boolean') {\n return s;\n }\n\n if (this.isString(s)) {\n return (s.toLowerCase() === 'true');\n }\n\n return false;\n },\n\n /**\n * Convert a String, a number or a function into a function. This method is used in Transformation.js\n * @param {JXG.Board} board Reference to a JSXGraph board. It is required to resolve dependencies given\n * by a GEONE<sub>X</sub>T string, thus it must be a valid reference only in case one of the param\n * values is of type string.\n * @param {Array} param An array containing strings, numbers, or functions.\n * @param {Number} n Length of <tt>param</tt>.\n * @returns {Function} A function taking one parameter k which specifies the index of the param element\n * to evaluate.\n */\n createEvalFunction: function (board, param, n) {\n var f = [], i;\n\n for (i = 0; i < n; i++) {\n f[i] = JXG.createFunction(param[i], board, '', true);\n }\n\n return function (k) {\n return f[k]();\n };\n },\n\n /**\n * Convert a String, number or function into a function.\n * @param {String|Number|Function} term A variable of type string, function or number.\n * @param {JXG.Board} board Reference to a JSXGraph board. It is required to resolve dependencies given\n * by a GEONE<sub>X</sub>T string, thus it must be a valid reference only in case one of the param\n * values is of type string.\n * @param {String} variableName Only required if evalGeonext is set to true. Describes the variable name\n * of the variable in a GEONE<sub>X</sub>T string given as term.\n * @param {Boolean} [evalGeonext=true] Set this true, if term should be treated as a GEONE<sub>X</sub>T string.\n * @returns {Function} A function evaluation the value given by term or null if term is not of type string,\n * function or number.\n */\n createFunction: function (term, board, variableName, evalGeonext) {\n var f = null;\n\n if ((!this.exists(evalGeonext) || evalGeonext) && this.isString(term)) {\n // Convert GEONExT syntax into JavaScript syntax\n //newTerm = JXG.GeonextParser.geonext2JS(term, board);\n //return new Function(variableName,'return ' + newTerm + ';');\n\n //term = JXG.GeonextParser.replaceNameById(term, board);\n //term = JXG.GeonextParser.geonext2JS(term, board);\n f = board.jc.snippet(term, true, variableName, true);\n } else if (this.isFunction(term)) {\n f = term;\n } else if (this.isNumber(term)) {\n /** @ignore */\n f = function () {\n return term;\n };\n } else if (this.isString(term)) {\n // In case of string function like fontsize\n /** @ignore */\n f = function () {\n return term;\n };\n }\n\n if (f !== null) {\n f.origin = term;\n }\n\n return f;\n },\n\n /**\n * Test if the parents array contains existing points. If instead parents contains coordinate arrays or\n * function returning coordinate arrays\n * free points with these coordinates are created.\n *\n * @param {JXG.Board} board Board object\n * @param {Array} parents Array containing parent elements for a new object. This array may contain\n * <ul>\n * <li> {@link JXG.Point} objects\n * <li> {@link JXG.GeometryElement#name} of {@link JXG.Point} objects\n * <li> {@link JXG.GeometryElement#id} of {@link JXG.Point} objects\n * <li> Coordinates of points given as array of numbers of length two or three, e.g. [2, 3].\n * <li> Coordinates of points given as array of functions of length two or three. Each function returns one coordinate, e.g.\n * [function(){ return 2; }, function(){ return 3; }]\n * <li> Function returning coordinates, e.g. function() { return [2, 3]; }\n * </ul>\n * In the last three cases a new point will be created.\n * @param {String} attrClass Main attribute class of newly created points, see {@link JXG#copyAttributes}\n * @param {Array} attrArray List of subtype attributes for the newly created points. The list of subtypes is mapped to the list of new points.\n * @returns {Array} List of newly created {@link JXG.Point} elements or false if not all returned elements are points.\n */\n providePoints: function (board, parents, attributes, attrClass, attrArray) {\n var i, j,\n len,\n lenAttr = 0,\n points = [], attr, val;\n\n if (!this.isArray(parents)) {\n parents = [parents];\n }\n len = parents.length;\n if (this.exists(attrArray)) {\n lenAttr = attrArray.length;\n }\n if (lenAttr === 0) {\n attr = this.copyAttributes(attributes, board.options, attrClass);\n }\n\n for (i = 0; i < len; ++i) {\n if (lenAttr > 0) {\n j = Math.min(i, lenAttr - 1);\n attr = this.copyAttributes(attributes, board.options, attrClass, attrArray[j]);\n }\n if (this.isArray(parents[i]) && parents[i].length > 1) {\n points.push(board.create('point', parents[i], attr));\n points[points.length - 1]._is_new = true;\n } else if (this.isFunction(parents[i])) {\n val = parents[i]();\n if (this.isArray(val) && (val.length > 1)) {\n points.push(board.create('point', [parents[i]], attr));\n points[points.length - 1]._is_new = true;\n }\n } else {\n points.push(board.select(parents[i]));\n }\n\n if (!this.isPoint(points[i])) {\n return false;\n }\n }\n\n return points;\n },\n\n /**\n * Generates a function which calls the function fn in the scope of owner.\n * @param {Function} fn Function to call.\n * @param {Object} owner Scope in which fn is executed.\n * @returns {Function} A function with the same signature as fn.\n */\n bind: function (fn, owner) {\n return function () {\n return fn.apply(owner, arguments);\n };\n },\n\n /**\n * If <tt>val</tt> is a function, it will be evaluated without giving any parameters, else the input value\n * is just returned.\n * @param val Could be anything. Preferably a number or a function.\n * @returns If <tt>val</tt> is a function, it is evaluated and the result is returned. Otherwise <tt>val</tt> is returned.\n */\n evaluate: function (val) {\n if (this.isFunction(val)) {\n return val();\n }\n\n return val;\n },\n\n /**\n * Search an array for a given value.\n * @param {Array} array\n * @param value\n * @param {String} [sub] Use this property if the elements of the array are objects.\n * @returns {Number} The index of the first appearance of the given value, or\n * <tt>-1</tt> if the value was not found.\n */\n indexOf: function (array, value, sub) {\n var i, s = this.exists(sub);\n\n if (Array.indexOf && !s) {\n return array.indexOf(value);\n }\n\n for (i = 0; i < array.length; i++) {\n if ((s && array[i][sub] === value) || (!s && array[i] === value)) {\n return i;\n }\n }\n\n return -1;\n },\n\n /**\n * Eliminates duplicate entries in an array consisting of numbers and strings.\n * @param {Array} a An array of numbers and/or strings.\n * @returns {Array} The array with duplicate entries eliminated.\n */\n eliminateDuplicates: function (a) {\n var i,\n len = a.length,\n result = [],\n obj = {};\n\n for (i = 0; i < len; i++) {\n obj[a[i]] = 0;\n }\n\n for (i in obj) {\n if (obj.hasOwnProperty(i)) {\n result.push(i);\n }\n }\n\n return result;\n },\n\n /**\n * Swaps to array elements.\n * @param {Array} arr\n * @param {Number} i\n * @param {Number} j\n * @returns {Array} Reference to the given array.\n */\n swap: function (arr, i, j) {\n var tmp;\n\n tmp = arr[i];\n arr[i] = arr[j];\n arr[j] = tmp;\n\n return arr;\n },\n\n /**\n * Generates a copy of an array and removes the duplicate entries. The original\n * Array will be altered.\n * @param {Array} arr\n * @returns {Array}\n */\n uniqueArray: function (arr) {\n var i, j, isArray, ret = [];\n\n if (arr.length === 0) {\n return [];\n }\n\n for (i = 0; i < arr.length; i++) {\n isArray = this.isArray(arr[i]);\n\n if (!this.exists(arr[i])) {\n arr[i] = '';\n continue;\n }\n for (j = i + 1; j < arr.length; j++) {\n if (isArray && JXG.cmpArrays(arr[i], arr[j])) {\n arr[i] = [];\n } else if (!isArray && arr[i] === arr[j]) {\n arr[i] = '';\n }\n }\n }\n\n j = 0;\n\n for (i = 0; i < arr.length; i++) {\n isArray = this.isArray(arr[i]);\n\n if (!isArray && arr[i] !== '') {\n ret[j] = arr[i];\n j++;\n } else if (isArray && arr[i].length !== 0) {\n ret[j] = (arr[i].slice(0));\n j++;\n }\n }\n\n arr = ret;\n return ret;\n },\n\n /**\n * Checks if an array contains an element equal to <tt>val</tt> but does not check the type!\n * @param {Array} arr\n * @param val\n * @returns {Boolean}\n */\n isInArray: function (arr, val) {\n return JXG.indexOf(arr, val) > -1;\n },\n\n /**\n * Converts an array of {@link JXG.Coords} objects into a coordinate matrix.\n * @param {Array} coords\n * @param {Boolean} split\n * @returns {Array}\n */\n coordsArrayToMatrix: function (coords, split) {\n var i,\n x = [],\n m = [];\n\n for (i = 0; i < coords.length; i++) {\n if (split) {\n x.push(coords[i].usrCoords[1]);\n m.push(coords[i].usrCoords[2]);\n } else {\n m.push([coords[i].usrCoords[1], coords[i].usrCoords[2]]);\n }\n }\n\n if (split) {\n m = [x, m];\n }\n\n return m;\n },\n\n /**\n * Compare two arrays.\n * @param {Array} a1\n * @param {Array} a2\n * @returns {Boolean} <tt>true</tt>, if the arrays coefficients are of same type and value.\n */\n cmpArrays: function (a1, a2) {\n var i;\n\n // trivial cases\n if (a1 === a2) {\n return true;\n }\n\n if (a1.length !== a2.length) {\n return false;\n }\n\n for (i = 0; i < a1.length; i++) {\n if (this.isArray(a1[i]) && this.isArray(a2[i])) {\n if (!this.cmpArrays(a1[i], a2[i])) {\n return false;\n }\n } else if (a1[i] !== a2[i]) {\n return false;\n }\n }\n\n return true;\n },\n\n /**\n * Removes an element from the given array\n * @param {Array} ar\n * @param el\n * @returns {Array}\n */\n removeElementFromArray: function (ar, el) {\n var i;\n\n for (i = 0; i < ar.length; i++) {\n if (ar[i] === el) {\n ar.splice(i, 1);\n return ar;\n }\n }\n\n return ar;\n },\n\n /**\n * Truncate a number <tt>n</tt> after <tt>p</tt> decimals.\n * @param {Number} n\n * @param {Number} p\n * @returns {Number}\n */\n trunc: function (n, p) {\n p = JXG.def(p, 0);\n\n return this.toFixed(n, p);\n },\n\n /**\n * Decimal adjustment of a number.\n * From https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Math/round\n *\n * @param {String} type The type of adjustment.\n * @param {Number} value The number.\n * @param {Number} exp The exponent (the 10 logarithm of the adjustment base).\n * @returns {Number} The adjusted value.\n *\n * @private\n */\n _decimalAdjust: function (type, value, exp) {\n // If the exp is undefined or zero...\n if (exp === undefined || +exp === 0) {\n return Math[type](value);\n }\n\n value = +value;\n exp = +exp;\n // If the value is not a number or the exp is not an integer...\n if (isNaN(value) || !(typeof exp === 'number' && exp % 1 === 0)) {\n return NaN;\n }\n\n // Shift\n value = value.toString().split('e');\n value = Math[type](+(value[0] + 'e' + (value[1] ? (+value[1] - exp) : -exp)));\n\n // Shift back\n value = value.toString().split('e');\n return +(value[0] + 'e' + (value[1] ? (+value[1] + exp) : exp));\n },\n\n /**\n * Round a number to given number of decimal digits.\n *\n * Example: JXG._toFixed(3.14159, -2) gives 3.14\n * @param {Number} value Number to be rounded\n * @param {Number} exp Number of decimal digits given as negative exponent\n * @return {Number} Rounded number.\n *\n * @private\n */\n _round10: function (value, exp) {\n return this._decimalAdjust('round', value, exp);\n },\n\n /**\n * \"Floor\" a number to given number of decimal digits.\n *\n * Example: JXG._toFixed(3.14159, -2) gives 3.14\n * @param {Number} value Number to be floored\n * @param {Number} exp Number of decimal digits given as negative exponent\n * @return {Number} \"Floored\" number.\n *\n * @private\n */\n _floor10: function (value, exp) {\n return this._decimalAdjust('floor', value, exp);\n },\n\n /**\n * \"Ceil\" a number to given number of decimal digits.\n *\n * Example: JXG._toFixed(3.14159, -2) gives 3.15\n * @param {Number} value Number to be ceiled\n * @param {Number} exp Number of decimal digits given as negative exponent\n * @return {Number} \"Ceiled\" number.\n *\n * @private\n */\n _ceil10: function (value, exp) {\n return this._decimalAdjust('ceil', value, exp);\n },\n\n /**\n * Replacement of the default toFixed() method.\n * It does a correct rounding (independent of the browser) and\n * returns \"0.00\" for toFixed(-0.000001, 2) instead of \"-0.00\" which\n * is returned by JavaScript's toFixed()\n *\n * @memberOf JXG\n * @param {Number} num Number tp be rounded\n * @param {Number} digits Decimal digits\n * @return {String} Rounded number is returned as string\n */\n toFixed: function (num, digits) {\n return this._round10(num, -digits).toFixed(digits);\n },\n\n /**\n * Truncate a number <tt>val</tt> automatically.\n * @memberOf JXG\n * @param val\n * @returns {Number}\n */\n autoDigits: function (val) {\n var x = Math.abs(val),\n str;\n\n if (x > 0.1) {\n str = this.toFixed(val, 2);\n } else if (x >= 0.01) {\n str = this.toFixed(val, 4);\n } else if (x >= 0.0001) {\n str = this.toFixed(val, 6);\n } else {\n str = val;\n }\n return str;\n },\n\n /**\n * Extracts the keys of a given object.\n * @param object The object the keys are to be extracted\n * @param onlyOwn If true, hasOwnProperty() is used to verify that only keys are collected\n * the object owns itself and not some other object in the prototype chain.\n * @returns {Array} All keys of the given object.\n */\n keys: function (object, onlyOwn) {\n var keys = [], property;\n\n // the caller decides if we use hasOwnProperty\n /*jslint forin:true*/\n for (property in object) {\n if (onlyOwn) {\n if (object.hasOwnProperty(property)) {\n keys.push(property);\n }\n } else {\n keys.push(property);\n }\n }\n /*jslint forin:false*/\n\n return keys;\n },\n\n /**\n * This outputs an object with a base class reference to the given object. This is useful if\n * you need a copy of an e.g. attributes object and want to overwrite some of the attributes\n * without changing the original object.\n * @param {Object} obj Object to be embedded.\n * @returns {Object} An object with a base class reference to <tt>obj</tt>.\n */\n clone: function (obj) {\n var cObj = {};\n\n cObj.prototype = obj;\n\n return cObj;\n },\n\n /**\n * Embeds an existing object into another one just like {@link #clone} and copies the contents of the second object\n * to the new one. Warning: The copied properties of obj2 are just flat copies.\n * @param {Object} obj Object to be copied.\n * @param {Object} obj2 Object with data that is to be copied to the new one as well.\n * @returns {Object} Copy of given object including some new/overwritten data from obj2.\n */\n cloneAndCopy: function (obj, obj2) {\n var r,\n cObj = function () { return undefined; };\n\n cObj.prototype = obj;\n\n // no hasOwnProperty on purpose\n /*jslint forin:true*/\n /*jshint forin:true*/\n\n for (r in obj2) {\n cObj[r] = obj2[r];\n }\n\n /*jslint forin:false*/\n /*jshint forin:false*/\n\n return cObj;\n },\n\n /**\n * Recursively merges obj2 into obj1. Contrary to {@link JXG#deepCopy} this won't create a new object\n * but instead will overwrite obj1.\n * @param {Object} obj1\n * @param {Object} obj2\n * @returns {Object}\n */\n merge: function (obj1, obj2) {\n var i, j;\n\n for (i in obj2) {\n if (obj2.hasOwnProperty(i)) {\n if (this.isArray(obj2[i])) {\n if (!obj1[i]) {\n obj1[i] = [];\n }\n\n for (j = 0; j < obj2[i].length; j++) {\n if (typeof obj2[i][j] === 'object') {\n obj1[i][j] = this.merge(obj1[i][j], obj2[i][j]);\n } else {\n obj1[i][j] = obj2[i][j];\n }\n }\n } else if (typeof obj2[i] === 'object') {\n if (!obj1[i]) {\n obj1[i] = {};\n }\n\n obj1[i] = this.merge(obj1[i], obj2[i]);\n } else {\n obj1[i] = obj2[i];\n }\n }\n }\n\n return obj1;\n },\n\n /**\n * Creates a deep copy of an existing object, i.e. arrays or sub-objects are copied component resp.\n * element-wise instead of just copying the reference. If a second object is supplied, the two objects\n * are merged into one object. The properties of the second object have priority.\n * @param {Object} obj This object will be copied.\n * @param {Object} obj2 This object will merged into the newly created object\n * @param {Boolean} [toLower=false] If true the keys are convert to lower case. This is needed for visProp, see JXG#copyAttributes\n * @returns {Object} copy of obj or merge of obj and obj2.\n */\n deepCopy: function (obj, obj2, toLower) {\n var c, i, prop, i2;\n\n toLower = toLower || false;\n\n if (typeof obj !== 'object' || obj === null) {\n return obj;\n }\n\n // missing hasOwnProperty is on purpose in this function\n if (this.isArray(obj)) {\n c = [];\n for (i = 0; i < obj.length; i++) {\n prop = obj[i];\n if (typeof prop === 'object') {\n // We certainly do not want to recurse into a JSXGraph object.\n // This would for sure result in an infinite recursion.\n // As alternative we copy the id of the object.\n if (this.exists(prop.board)) {\n c[i] = prop.id;\n } else {\n c[i] = this.deepCopy(prop);\n }\n } else {\n c[i] = prop;\n }\n }\n } else {\n c = {};\n for (i in obj) {\n if (obj.hasOwnProperty(i)) {\n i2 = toLower ? i.toLowerCase() : i;\n prop = obj[i];\n if (prop !== null && typeof prop === 'object') {\n if (this.exists(prop.board)) {\n c[i2] = prop.id;\n } else {\n c[i2] = this.deepCopy(prop);\n }\n } else {\n c[i2] = prop;\n }\n }\n }\n\n for (i in obj2) {\n if (obj2.hasOwnProperty(i)) {\n i2 = toLower ? i.toLowerCase() : i;\n\n prop = obj2[i];\n if (typeof prop === 'object') {\n if (this.isArray(prop) || !this.exists(c[i2])) {\n c[i2] = this.deepCopy(prop);\n } else {\n c[i2] = this.deepCopy(c[i2], prop, toLower);\n }\n } else {\n c[i2] = prop;\n }\n }\n }\n }\n\n return c;\n },\n\n /**\n * Generates an attributes object that is filled with default values from the Options object\n * and overwritten by the user specified attributes.\n * @param {Object} attributes user specified attributes\n * @param {Object} options defaults options\n * @param {String} s variable number of strings, e.g. 'slider', subtype 'point1'.\n * @returns {Object} The resulting attributes object\n */\n copyAttributes: function (attributes, options, s) {\n var a, i, len, o, isAvail,\n primitives = {\n 'circle': 1,\n 'curve': 1,\n 'image': 1,\n 'line': 1,\n 'point': 1,\n 'polygon': 1,\n 'text': 1,\n 'ticks': 1,\n 'integral': 1\n };\n\n len = arguments.length;\n if (len < 3 || primitives[s]) {\n // default options from Options.elements\n a = JXG.deepCopy(options.elements, null, true);\n } else {\n a = {};\n }\n\n // Only the layer of the main element is set.\n if (len < 4 && this.exists(s) && this.exists(options.layer[s])) {\n a.layer = options.layer[s];\n }\n\n // default options from specific elements\n o = options;\n isAvail = true;\n for (i = 2; i < len; i++) {\n if (this.exists(o[arguments[i]])) {\n o = o[arguments[i]];\n } else {\n isAvail = false;\n break;\n }\n }\n if (isAvail) {\n a = JXG.deepCopy(a, o, true);\n }\n\n // options from attributes\n o = (typeof attributes === 'object') ? attributes : {};\n isAvail = true;\n for (i = 3; i < len; i++) {\n if (this.exists(o[arguments[i]])) {\n o = o[arguments[i]];\n } else {\n isAvail = false;\n break;\n }\n }\n if (isAvail) {\n this.extend(a, o, null, true);\n }\n\n if (arguments[2] === 'board') {\n // For board attributes we are done now.\n return a;\n }\n\n // Special treatment of labels\n o = options;\n isAvail = true;\n for (i = 2; i < len; i++) {\n if (this.exists(o[arguments[i]])) {\n o = o[arguments[i]];\n } else {\n isAvail = false;\n break;\n }\n }\n if (isAvail && this.exists(o.label)) {\n a.label = JXG.deepCopy(o.label, a.label);\n }\n a.label = JXG.deepCopy(options.label, a.label);\n\n return a;\n },\n\n /**\n * Copy all prototype methods from object \"superObject\" to object\n * \"subObject\". The constructor of superObject will be available\n * in subObject as subObject.constructor[constructorName].\n * @param {Object} subObj A JavaScript object which receives new methods.\n * @param {Object} superObj A JavaScript object which lends its prototype methods to subObject\n * @returns {String} constructorName Under this name the constructor of superObj will be available\n * in subObject.\n * @private\n */\n copyPrototypeMethods: function (subObject, superObject, constructorName) {\n var key;\n\n subObject.prototype[constructorName] = superObject.prototype.constructor;\n for (key in superObject.prototype) {\n if (superObject.prototype.hasOwnProperty(key)) {\n subObject.prototype[key] = superObject.prototype[key];\n }\n }\n },\n\n /**\n * Converts a JavaScript object into a JSON string.\n * @param {Object} obj A JavaScript object, functions will be ignored.\n * @param {Boolean} [noquote=false] No quotes around the name of a property.\n * @returns {String} The given object stored in a JSON string.\n */\n toJSON: function (obj, noquote) {\n var list, prop, i, s, val;\n\n noquote = JXG.def(noquote, false);\n\n // check for native JSON support:\n if (typeof JSON && JSON.stringify && !noquote) {\n try {\n s = JSON.stringify(obj);\n return s;\n } catch (e) {\n // if something goes wrong, e.g. if obj contains functions we won't return\n // and use our own implementation as a fallback\n }\n }\n\n switch (typeof obj) {\n case 'object':\n if (obj) {\n list = [];\n\n if (this.isArray(obj)) {\n for (i = 0; i < obj.length; i++) {\n list.push(JXG.toJSON(obj[i], noquote));\n }\n\n return '[' + list.join(',') + ']';\n }\n\n for (prop in obj) {\n if (obj.hasOwnProperty(prop)) {\n try {\n val = JXG.toJSON(obj[prop], noquote);\n } catch (e2) {\n val = '';\n }\n\n if (noquote) {\n list.push(prop + ':' + val);\n } else {\n list.push('\"' + prop + '\":' + val);\n }\n }\n }\n\n return '{' + list.join(',') + '} ';\n }\n return 'null';\n case 'string':\n return '\\'' + obj.replace(/([\"'])/g, '\\\\$1') + '\\'';\n case 'number':\n case 'boolean':\n return obj.toString();\n }\n\n return '0';\n },\n\n /**\n * Resets visPropOld.\n * @param {JXG.GeometryElement} el\n * @returns {GeometryElement}\n */\n clearVisPropOld: function (el) {\n el.visPropOld = {\n cssclass: '',\n cssdefaultstyle: '',\n cssstyle: '',\n fillcolor: '',\n fillopacity: '',\n firstarrow: false,\n fontsize: -1,\n lastarrow: false,\n left: -100000,\n linecap: '',\n shadow: false,\n strokecolor: '',\n strokeopacity: '',\n strokewidth: '',\n tabindex: -100000,\n transitionduration: 0,\n top: -100000,\n visible: null\n };\n\n return el;\n },\n\n /**\n * Checks if an object contains a key, whose value equals to val.\n * @param {Object} obj\n * @param val\n * @returns {Boolean}\n */\n isInObject: function (obj, val) {\n var el;\n\n for (el in obj) {\n if (obj.hasOwnProperty(el)) {\n if (obj[el] === val) {\n return true;\n }\n }\n }\n\n return false;\n },\n\n /**\n * Replaces all occurences of & by &amp;, > by &gt;, and < by &lt;.\n * @param {String} str\n * @returns {String}\n */\n escapeHTML: function (str) {\n return str.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');\n },\n\n /**\n * Eliminates all substrings enclosed by < and > and replaces all occurences of\n * &amp; by &, &gt; by >, and &lt; by <.\n * @param {String} str\n * @returns {String}\n */\n unescapeHTML: function (str) {\n // This regex is NOT insecure. We are replacing everything found with ''\n /*jslint regexp:true*/\n return str.replace(/<\\/?[^>]+>/gi, '').replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');\n },\n\n /**\n * Makes a string lower case except for the first character which will be upper case.\n * @param {String} str Arbitrary string\n * @returns {String} The capitalized string.\n */\n capitalize: function (str) {\n return str.charAt(0).toUpperCase() + str.substring(1).toLowerCase();\n },\n\n /**\n * Make numbers given as strings nicer by removing all unnecessary leading and trailing zeroes.\n * @param {String} str\n * @returns {String}\n */\n trimNumber: function (str) {\n str = str.replace(/^0+/, '');\n str = str.replace(/0+$/, '');\n\n if (str[str.length - 1] === '.' || str[str.length - 1] === ',') {\n str = str.slice(0, -1);\n }\n\n if (str[0] === '.' || str[0] === ',') {\n str = '0' + str;\n }\n\n return str;\n },\n\n /**\n * Filter an array of elements.\n * @param {Array} list\n * @param {Object|function} filter\n * @returns {Array}\n */\n filterElements: function (list, filter) {\n var i, f, item, flower, value, visPropValue, pass,\n l = list.length,\n result = [];\n\n if (typeof filter !== 'function' && typeof filter !== 'object') {\n return result;\n }\n\n for (i = 0; i < l; i++) {\n pass = true;\n item = list[i];\n\n if (typeof filter === 'object') {\n for (f in filter) {\n if (filter.hasOwnProperty(f)) {\n flower = f.toLowerCase();\n\n if (typeof item[f] === 'function') {\n value = item[f]();\n } else {\n value = item[f];\n }\n\n if (item.visProp && typeof item.visProp[flower] === 'function') {\n visPropValue = item.visProp[flower]();\n } else {\n visPropValue = item.visProp && item.visProp[flower];\n }\n\n if (typeof filter[f] === 'function') {\n pass = filter[f](value) || filter[f](visPropValue);\n } else {\n pass = (value === filter[f] || visPropValue === filter[f]);\n }\n\n if (!pass) {\n break;\n }\n }\n }\n } else if (typeof filter === 'function') {\n pass = filter(item);\n }\n\n if (pass) {\n result.push(item);\n }\n }\n\n return result;\n },\n\n /**\n * Remove all leading and trailing whitespaces from a given string.\n * @param {String} str\n * @returns {String}\n */\n trim: function (str) {\n // str = str.replace(/^\\s+/, '');\n // str = str.replace(/\\s+$/, '');\n //\n // return str;\n return str.replace(/^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g, '');\n },\n\n /**\n * Convert HTML tags to entities or use html_sanitize if the google caja html sanitizer is available.\n * @param {String} str\n * @param {Boolean} caja\n * @returns {String} Sanitized string\n */\n sanitizeHTML: function (str, caja) {\n if (typeof html_sanitize === 'function' && caja) {\n return html_sanitize(str, function () { return undefined; }, function (id) { return id; });\n }\n\n if (str && typeof str === 'string') {\n str = str.replace(/</g, '<').replace(/>/g, '>');\n }\n\n return str;\n },\n\n /**\n * If <tt>s</tt> is a slider, it returns the sliders value, otherwise it just returns the given value.\n * @param {*} s\n * @returns {*} s.Value() if s is an element of type slider, s otherwise\n */\n evalSlider: function (s) {\n if (s && s.type === Const.OBJECT_TYPE_GLIDER && typeof s.Value === 'function') {\n return s.Value();\n }\n\n return s;\n }\n });\n\n return JXG;\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Andreas Walter,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n/*global JXG: true, define: true, window: true, document: true, navigator: true, module: true, global: true, self: true, require: true*/\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n jxg\n utils/type\n */\n\n/**\n * @fileoverview The functions in this file help with the detection of the environment JSXGraph runs in. We can distinguish\n * between node.js, windows 8 app and browser, what rendering techniques are supported and (most of the time) if the device\n * the browser runs on is a tablet/cell or a desktop computer.\n */\n\ndefine('utils/env',['jxg', 'utils/type'], function (JXG, Type) {\n\n 'use strict';\n\n JXG.extendConstants(JXG, /** @lends JXG */{\n /**\n * Determines the property that stores the relevant information in the event object.\n * @type String\n * @default 'touches'\n * @private\n */\n touchProperty: 'touches',\n });\n\n JXG.extend(JXG, /** @lends JXG */ {\n /**\n * Determines whether evt is a touch event.\n * @param evt {Event}\n * @returns {Boolean}\n */\n isTouchEvent: function (evt) {\n return JXG.exists(evt[JXG.touchProperty]);\n },\n\n /**\n * Determines whether evt is a pointer event.\n * @param evt {Event}\n * @returns {Boolean}\n */\n isPointerEvent: function (evt) {\n return JXG.exists(evt.pointerId);\n },\n\n /**\n * Determines whether evt is neither a touch event nor a pointer event.\n * @param evt {Event}\n * @returns {Boolean}\n */\n isMouseEvent: function (evt) {\n return !JXG.isTouchEvent(evt)&&!JXG.isPointerEvent(evt);\n },\n\n /**\n * Determines the number of touch points in a touch event.\n * For other events, -1 is returned.\n * @param evt {Event}\n * @returns {Number}\n */\n getNumberOfTouchPoints: function (evt) {\n var n = -1;\n\n if (JXG.isTouchEvent(evt)) {\n n = evt[JXG.touchProperty].length;\n }\n\n return n;\n },\n\n /**\n * Checks whether an mouse, pointer or touch event evt is the first event of a multitouch event.\n * Attention: When two or more pointer device types are being used concurrently,\n * it is only checked whether the passed event is the first one of its type!\n * @param evt {Event}\n * @returns {boolean}\n */\n isFirstTouch: function (evt) {\n var touchPoints = JXG.getNumberOfTouchPoints(evt);\n\n if (JXG.isPointerEvent(evt)) {\n return evt.isPrimary;\n }\n\n return (touchPoints === 1);\n },\n\n /**\n * A document/window environment is available.\n * @type Boolean\n * @default false\n */\n isBrowser: typeof window === 'object' && typeof document === 'object',\n\n /**\n * Features of ECMAScript 6+ are available.\n * @type Boolean\n * @default false\n */\n supportsES6: function () {\n var testMap;\n /* jshint ignore:start */\n try {\n // This would kill the old uglifyjs: testMap = (a = 0) => a;\n new Function('(a = 0) => a');\n return true;\n } catch (err) {\n return false;\n }\n /* jshint ignore:end */\n },\n\n /**\n * Detect browser support for VML.\n * @returns {Boolean} True, if the browser supports VML.\n */\n supportsVML: function () {\n // From stackoverflow.com\n return this.isBrowser && !!document.namespaces;\n },\n\n /**\n * Detect browser support for SVG.\n * @returns {Boolean} True, if the browser supports SVG.\n */\n supportsSVG: function () {\n return this.isBrowser && document.implementation.hasFeature('http://www.w3.org/TR/SVG11/feature#BasicStructure', '1.1');\n },\n\n /**\n * Detect browser support for Canvas.\n * @returns {Boolean} True, if the browser supports HTML canvas.\n */\n supportsCanvas: function () {\n var c, hasCanvas = false;\n\n if (this.isNode()) {\n try {\n c = (typeof module === 'object' ? module.require('canvas') : require('canvas'));\n hasCanvas = !!c;\n } catch (err) {\n }\n }\n\n return hasCanvas || (this.isBrowser && !!document.createElement('canvas').getContext);\n },\n\n /**\n * True, if run inside a node.js environment.\n * @returns {Boolean}\n */\n isNode: function () {\n // this is not a 100% sure but should be valid in most cases\n\n // we are not inside a browser\n return !this.isBrowser && (\n // there is a module object (plain node, no requirejs)\n (typeof module === 'object' && !!module.exports) ||\n // there is a global object and requirejs is loaded\n (typeof global === 'object' && global.requirejsVars && !global.requirejsVars.isBrowser)\n );\n },\n\n /**\n * True if run inside a webworker environment.\n * @returns {Boolean}\n */\n isWebWorker: function () {\n return !this.isBrowser && (typeof self === 'object' && typeof self.postMessage === 'function');\n },\n\n /**\n * Checks if the environments supports the W3C Pointer Events API {@link http://www.w3.org/Submission/pointer-events/}\n * @returns {Boolean}\n */\n supportsPointerEvents: function () {\n return !!(this.isBrowser && window.navigator &&\n (window.PointerEvent || // Chrome/Edge/IE11+\n window.navigator.pointerEnabled || // IE11+\n window.navigator.msPointerEnabled // IE10-\n )\n );\n },\n\n /**\n * Determine if the current browser supports touch events\n * @returns {Boolean} True, if the browser supports touch events.\n */\n isTouchDevice: function () {\n return this.isBrowser && window.ontouchstart !== undefined;\n },\n\n /**\n * Detects if the user is using an Android powered device.\n * @returns {Boolean}\n */\n isAndroid: function () {\n return Type.exists(navigator) && navigator.userAgent.toLowerCase().indexOf('android') > -1;\n },\n\n /**\n * Detects if the user is using the default Webkit browser on an Android powered device.\n * @returns {Boolean}\n */\n isWebkitAndroid: function () {\n return this.isAndroid() && navigator.userAgent.indexOf(' AppleWebKit/') > -1;\n },\n\n /**\n * Detects if the user is using a Apple iPad / iPhone.\n * @returns {Boolean}\n */\n isApple: function () {\n return Type.exists(navigator) && (navigator.userAgent.indexOf('iPad') > -1 || navigator.userAgent.indexOf('iPhone') > -1);\n },\n\n /**\n * Detects if the user is using Safari on an Apple device.\n * @returns {Boolean}\n */\n isWebkitApple: function () {\n return this.isApple() && (navigator.userAgent.search(/Mobile\\/[0-9A-Za-z.]*Safari/) > -1);\n },\n\n /**\n * Returns true if the run inside a Windows 8 \"Metro\" App.\n * @returns {Boolean}\n */\n isMetroApp: function () {\n return typeof window === 'object' && window.clientInformation && window.clientInformation.appVersion && window.clientInformation.appVersion.indexOf('MSAppHost') > -1;\n },\n\n /**\n * Detects if the user is using a Mozilla browser\n * @returns {Boolean}\n */\n isMozilla: function () {\n return Type.exists(navigator) &&\n navigator.userAgent.toLowerCase().indexOf('mozilla') > -1 &&\n navigator.userAgent.toLowerCase().indexOf('apple') === -1;\n },\n\n /**\n * Detects if the user is using a firefoxOS powered device.\n * @returns {Boolean}\n */\n isFirefoxOS: function () {\n return Type.exists(navigator) &&\n navigator.userAgent.toLowerCase().indexOf('android') === -1 &&\n navigator.userAgent.toLowerCase().indexOf('apple') === -1 &&\n navigator.userAgent.toLowerCase().indexOf('mobile') > -1 &&\n navigator.userAgent.toLowerCase().indexOf('mozilla') > -1;\n },\n\n /**\n * Internet Explorer version. Works only for IE > 4.\n * @type Number\n */\n ieVersion: (function () {\n var div, all,\n v = 3;\n\n if (typeof document !== 'object') {\n return 0;\n }\n\n div = document.createElement('div');\n all = div.getElementsByTagName('i');\n\n do {\n div.innerHTML = '<!--[if gt IE ' + (++v) + ']><' + 'i><' + '/i><![endif]-->';\n } while (all[0]);\n\n return v > 4 ? v : undefined;\n\n }()),\n\n /**\n * Reads the width and height of an HTML element.\n * @param {String} elementId The HTML id of an HTML DOM node.\n * @returns {Object} An object with the two properties width and height.\n */\n getDimensions: function (elementId, doc) {\n var element, display, els, originalVisibility, originalPosition,\n originalDisplay, originalWidth, originalHeight, style,\n pixelDimRegExp = /\\d+(\\.\\d*)?px/;\n\n if (!this.isBrowser || elementId === null) {\n return {\n width: 500,\n height: 500\n };\n }\n\n doc = doc || document;\n // Borrowed from prototype.js\n element = doc.getElementById(elementId);\n if (!Type.exists(element)) {\n throw new Error('\\nJSXGraph: HTML container element \\'' + elementId + '\\' not found.');\n }\n\n display = element.style.display;\n\n // Work around a bug in Safari\n if (display !== 'none' && display !== null) {\n if (element.clientWidth > 0 && element.clientHeight > 0) {\n return {width: element.clientWidth, height: element.clientHeight};\n }\n\n // a parent might be set to display:none; try reading them from styles\n style = window.getComputedStyle ? window.getComputedStyle(element) : element.style;\n return {\n width: pixelDimRegExp.test(style.width) ? parseFloat(style.width) : 0,\n height: pixelDimRegExp.test(style.height) ? parseFloat(style.height) : 0\n };\n }\n\n // All *Width and *Height properties give 0 on elements with display set to none,\n // hence we show the element temporarily\n els = element.style;\n\n // save style\n originalVisibility = els.visibility;\n originalPosition = els.position;\n originalDisplay = els.display;\n\n // show element\n els.visibility = 'hidden';\n els.position = 'absolute';\n els.display = 'block';\n\n // read the dimension\n originalWidth = element.clientWidth;\n originalHeight = element.clientHeight;\n\n // restore original css values\n els.display = originalDisplay;\n els.position = originalPosition;\n els.visibility = originalVisibility;\n\n return {\n width: originalWidth,\n height: originalHeight\n };\n },\n\n /**\n * Adds an event listener to a DOM element.\n * @param {Object} obj Reference to a DOM node.\n * @param {String} type The event to catch, without leading 'on', e.g. 'mousemove' instead of 'onmousemove'.\n * @param {Function} fn The function to call when the event is triggered.\n * @param {Object} owner The scope in which the event trigger is called.\n */\n addEvent: function (obj, type, fn, owner) {\n var el = function () {\n return fn.apply(owner, arguments);\n };\n\n el.origin = fn;\n owner['x_internal' + type] = owner['x_internal' + type] || [];\n owner['x_internal' + type].push(el);\n\n // Non-IE browser\n if (Type.exists(obj) && Type.exists(obj.addEventListener)) {\n obj.addEventListener(type, el, false);\n }\n\n // IE\n if (Type.exists(obj) && Type.exists(obj.attachEvent)) {\n obj.attachEvent('on' + type, el);\n }\n },\n\n /**\n * Removes an event listener from a DOM element.\n * @param {Object} obj Reference to a DOM node.\n * @param {String} type The event to catch, without leading 'on', e.g. 'mousemove' instead of 'onmousemove'.\n * @param {Function} fn The function to call when the event is triggered.\n * @param {Object} owner The scope in which the event trigger is called.\n */\n removeEvent: function (obj, type, fn, owner) {\n var i;\n\n if (!Type.exists(owner)) {\n JXG.debug('no such owner');\n return;\n }\n\n if (!Type.exists(owner['x_internal' + type])) {\n JXG.debug('no such type: ' + type);\n return;\n }\n\n if (!Type.isArray(owner['x_internal' + type])) {\n JXG.debug('owner[x_internal + ' + type + '] is not an array');\n return;\n }\n\n i = Type.indexOf(owner['x_internal' + type], fn, 'origin');\n\n if (i === -1) {\n JXG.debug('removeEvent: no such event function in internal list: ' + fn);\n return;\n }\n\n try {\n // Non-IE browser\n if (Type.exists(obj) && Type.exists(obj.removeEventListener)) {\n obj.removeEventListener(type, owner['x_internal' + type][i], false);\n }\n\n // IE\n if (Type.exists(obj) && Type.exists(obj.detachEvent)) {\n obj.detachEvent('on' + type, owner['x_internal' + type][i]);\n }\n } catch (e) {\n JXG.debug('event not registered in browser: (' + type + ' -- ' + fn + ')');\n }\n\n owner['x_internal' + type].splice(i, 1);\n },\n\n /**\n * Removes all events of the given type from a given DOM node; Use with caution and do not use it on a container div\n * of a {@link JXG.Board} because this might corrupt the event handling system.\n * @param {Object} obj Reference to a DOM node.\n * @param {String} type The event to catch, without leading 'on', e.g. 'mousemove' instead of 'onmousemove'.\n * @param {Object} owner The scope in which the event trigger is called.\n */\n removeAllEvents: function (obj, type, owner) {\n var i, len;\n if (owner['x_internal' + type]) {\n len = owner['x_internal' + type].length;\n\n for (i = len - 1; i >= 0; i--) {\n JXG.removeEvent(obj, type, owner['x_internal' + type][i].origin, owner);\n }\n\n if (owner['x_internal' + type].length > 0) {\n JXG.debug('removeAllEvents: Not all events could be removed.');\n }\n }\n },\n\n /**\n * Cross browser mouse / touch coordinates retrieval relative to the board's top left corner.\n * @param {Object} [e] The browsers event object. If omitted, <tt>window.event</tt> will be used.\n * @param {Number} [index] If <tt>e</tt> is a touch event, this provides the index of the touch coordinates, i.e. it determines which finger.\n * @param {Object} [doc] The document object.\n * @returns {Array} Contains the position as x,y-coordinates in the first resp. second component.\n */\n getPosition: function (e, index, doc) {\n var i, len, evtTouches,\n posx = 0,\n posy = 0;\n\n if (!e) {\n e = window.event;\n }\n\n doc = doc || document;\n evtTouches = e[JXG.touchProperty];\n\n // touchend events have their position in \"changedTouches\"\n if (Type.exists(evtTouches) && evtTouches.length === 0) {\n evtTouches = e.changedTouches;\n }\n\n if (Type.exists(index) && Type.exists(evtTouches)) {\n if (index === -1) {\n len = evtTouches.length;\n\n for (i = 0; i < len; i++) {\n if (evtTouches[i]) {\n e = evtTouches[i];\n break;\n }\n }\n\n } else {\n e = evtTouches[index];\n }\n }\n\n // Scrolling is ignored.\n // e.clientX is supported since IE6\n if (e.clientX) {\n posx = e.clientX;\n posy = e.clientY;\n }\n\n return [posx, posy];\n },\n\n /**\n * Calculates recursively the offset of the DOM element in which the board is stored.\n * @param {Object} obj A DOM element\n * @returns {Array} An array with the elements left and top offset.\n */\n getOffset: function (obj) {\n var cPos,\n o = obj,\n o2 = obj,\n l = o.offsetLeft - o.scrollLeft,\n t = o.offsetTop - o.scrollTop;\n\n cPos = this.getCSSTransform([l, t], o);\n l = cPos[0];\n t = cPos[1];\n\n /*\n * In Mozilla and Webkit: offsetParent seems to jump at least to the next iframe,\n * if not to the body. In IE and if we are in an position:absolute environment\n * offsetParent walks up the DOM hierarchy.\n * In order to walk up the DOM hierarchy also in Mozilla and Webkit\n * we need the parentNode steps.\n */\n o = o.offsetParent;\n while (o) {\n l += o.offsetLeft;\n t += o.offsetTop;\n\n if (o.offsetParent) {\n l += o.clientLeft - o.scrollLeft;\n t += o.clientTop - o.scrollTop;\n }\n\n cPos = this.getCSSTransform([l, t], o);\n l = cPos[0];\n t = cPos[1];\n\n o2 = o2.parentNode;\n\n while (o2 !== o) {\n l += o2.clientLeft - o2.scrollLeft;\n t += o2.clientTop - o2.scrollTop;\n\n cPos = this.getCSSTransform([l, t], o2);\n l = cPos[0];\n t = cPos[1];\n\n o2 = o2.parentNode;\n }\n o = o.offsetParent;\n }\n\n return [l, t];\n },\n\n /**\n * Access CSS style sheets.\n * @param {Object} obj A DOM element\n * @param {String} stylename The CSS property to read.\n * @returns The value of the CSS property and <tt>undefined</tt> if it is not set.\n */\n getStyle: function (obj, stylename) {\n var r,\n doc = obj.ownerDocument;\n\n // Non-IE\n if (doc.defaultView && doc.defaultView.getComputedStyle) {\n r = doc.defaultView.getComputedStyle(obj, null).getPropertyValue(stylename);\n // IE\n } else if (obj.currentStyle && JXG.ieVersion >= 9) {\n r = obj.currentStyle[stylename];\n } else {\n if (obj.style) {\n // make stylename lower camelcase\n stylename = stylename.replace(/-([a-z]|[0-9])/ig, function (all, letter) {\n return letter.toUpperCase();\n });\n r = obj.style[stylename];\n }\n }\n\n return r;\n },\n\n /**\n * Reads css style sheets of a given element. This method is a getStyle wrapper and\n * defaults the read value to <tt>0</tt> if it can't be parsed as an integer value.\n * @param {DOMElement} el\n * @param {string} css\n * @returns {number}\n */\n getProp: function (el, css) {\n var n = parseInt(this.getStyle(el, css), 10);\n return isNaN(n) ? 0 : n;\n },\n\n /**\n * Correct position of upper left corner in case of\n * a CSS transformation. Here, only translations are\n * extracted. All scaling transformations are corrected\n * in {@link JXG.Board#getMousePosition}.\n * @param {Array} cPos Previously determined position\n * @param {Object} obj A DOM element\n * @returns {Array} The corrected position.\n */\n getCSSTransform: function (cPos, obj) {\n var i, j, str, arrStr, start, len, len2, arr,\n t = ['transform', 'webkitTransform', 'MozTransform', 'msTransform', 'oTransform'];\n\n // Take the first transformation matrix\n len = t.length;\n\n for (i = 0, str = ''; i < len; i++) {\n if (Type.exists(obj.style[t[i]])) {\n str = obj.style[t[i]];\n break;\n }\n }\n\n /**\n * Extract the coordinates and apply the transformation\n * to cPos\n */\n if (str !== '') {\n start = str.indexOf('(');\n\n if (start > 0) {\n len = str.length;\n arrStr = str.substring(start + 1, len - 1);\n arr = arrStr.split(',');\n\n for (j = 0, len2 = arr.length; j < len2; j++) {\n arr[j] = parseFloat(arr[j]);\n }\n\n if (str.indexOf('matrix') === 0) {\n cPos[0] += arr[4];\n cPos[1] += arr[5];\n } else if (str.indexOf('translateX') === 0) {\n cPos[0] += arr[0];\n } else if (str.indexOf('translateY') === 0) {\n cPos[1] += arr[0];\n } else if (str.indexOf('translate') === 0) {\n cPos[0] += arr[0];\n cPos[1] += arr[1];\n }\n }\n }\n\n // Zoom is used by reveal.js\n if (Type.exists(obj.style.zoom)) {\n str = obj.style.zoom;\n if (str !== '') {\n cPos[0] *= parseFloat(str);\n cPos[1] *= parseFloat(str);\n }\n }\n\n return cPos;\n },\n\n /**\n * Scaling CSS transformations applied to the div element containing the JSXGraph constructions\n * are determined. In IE prior to 9, 'rotate', 'skew', 'skewX', 'skewY' are not supported.\n * @returns {Array} 3x3 transformation matrix without translation part. See {@link JXG.Board#updateCSSTransforms}.\n */\n getCSSTransformMatrix: function (obj) {\n var i, j, str, arrstr, start, len, len2, arr,\n st,\n doc = obj.ownerDocument,\n t = ['transform', 'webkitTransform', 'MozTransform', 'msTransform', 'oTransform'],\n mat = [[1, 0, 0],\n [0, 1, 0],\n [0, 0, 1]];\n\n // This should work on all browsers except IE 6-8\n if (doc.defaultView && doc.defaultView.getComputedStyle) {\n st = doc.defaultView.getComputedStyle(obj, null);\n str = st.getPropertyValue('-webkit-transform') ||\n st.getPropertyValue('-moz-transform') ||\n st.getPropertyValue('-ms-transform') ||\n st.getPropertyValue('-o-transform') ||\n st.getPropertyValue('transform');\n } else {\n // Take the first transformation matrix\n len = t.length;\n for (i = 0, str = ''; i < len; i++) {\n if (Type.exists(obj.style[t[i]])) {\n str = obj.style[t[i]];\n break;\n }\n }\n }\n\n if (str !== '') {\n start = str.indexOf('(');\n\n if (start > 0) {\n len = str.length;\n arrstr = str.substring(start + 1, len - 1);\n arr = arrstr.split(',');\n\n for (j = 0, len2 = arr.length; j < len2; j++) {\n arr[j] = parseFloat(arr[j]);\n }\n\n if (str.indexOf('matrix') === 0) {\n mat = [[1, 0, 0],\n [0, arr[0], arr[1]],\n [0, arr[2], arr[3]]];\n } else if (str.indexOf('scaleX') === 0) {\n mat[1][1] = arr[0];\n } else if (str.indexOf('scaleY') === 0) {\n mat[2][2] = arr[0];\n } else if (str.indexOf('scale') === 0) {\n mat[1][1] = arr[0];\n mat[2][2] = arr[1];\n }\n }\n }\n\n // CSS style zoom is used by reveal.js\n // Recursively search for zoom style entries.\n // This is necessary for reveal.js on webkit.\n // It fails if the user does zooming\n if (Type.exists(obj.style.zoom)) {\n str = obj.style.zoom;\n if (str !== '') {\n mat[1][1] *= parseFloat(str);\n mat[2][2] *= parseFloat(str);\n }\n }\n\n return mat;\n },\n\n /**\n * Process data in timed chunks. Data which takes long to process, either because it is such\n * a huge amount of data or the processing takes some time, causes warnings in browsers about\n * irresponsive scripts. To prevent these warnings, the processing is split into smaller pieces\n * called chunks which will be processed in serial order.\n * Copyright 2009 Nicholas C. Zakas. All rights reserved. MIT Licensed\n * @param {Array} items to do\n * @param {Function} process Function that is applied for every array item\n * @param {Object} context The scope of function process\n * @param {Function} callback This function is called after the last array element has been processed.\n */\n timedChunk: function (items, process, context, callback) {\n //create a clone of the original\n var todo = items.concat(),\n timerFun = function () {\n var start = +new Date();\n\n do {\n process.call(context, todo.shift());\n } while (todo.length > 0 && (+new Date() - start < 300));\n\n if (todo.length > 0) {\n window.setTimeout(timerFun, 1);\n } else {\n callback(items);\n }\n };\n\n window.setTimeout(timerFun, 1);\n },\n\n /**\n * Calculate the scale factor and vertical shift for the JSXGraph div\n * in full screen mode.\n *\n * @param {Object} obj Reference to a DOM node.\n * @returns Object {scale: number, vshift: number}\n * @see JXG.Board#fullscreenListener\n * @private\n */\n _getScaleFactors: function (node) {\n var width = node.getBoundingClientRect().width,\n height = node.getBoundingClientRect().height,\n\n // Determine the maximum scale factor.\n r_w = window.screen.width / width,\n r_h = window.screen.height / height,\n\n // Determine the vertical shift to place the div in the center of the screen\n vshift = (window.screen.height - height) * 0.5,\n\n // Scaling factor: if not supplied, it's taken as large as possible\n scale = Math.min(r_w, r_h);\n\n // Adapt vshift and scale for landscape on tablets\n if (window.matchMedia && window.matchMedia('(orientation:landscape)').matches &&\n window.screen.width < window.screen.height) {\n // Landscape on iOS: it returns 'landscape', but still width < height.\n r_w = window.screen.height / width;\n r_h = window.screen.width / height;\n scale = Math.min(r_w, r_h);\n vshift = (window.screen.width - height) * 0.5;\n }\n scale *= 0.85;\n\n return { scale: scale, vshift: vshift, width: width };\n },\n\n /**\n * Scale and vertically shift a DOM element (usually a JSXGraph div)\n * inside of a parent DOM\n * element which is set to fullscreen.\n * This is realized with a CSS transformation.\n * *\n * @param {String} wrap_id id of the parent DOM element which is in fullscreen mode\n * @param {String} inner_id id of the DOM element which is scaled and shifted\n * @param {Number} scale Scaling factor\n * @param {Number} vshift Vertical shift (in pixel)\n *\n * @private\n * @see JXG.Board#toFullscreen\n * @see JXG.Board#fullscreenListener\n *\n */\n scaleJSXGraphDiv: function (wrap_id, inner_id, scale, vshift) {\n var len = document.styleSheets.length, style,\n\n pseudo_keys = [':fullscreen', ':-webkit-full-screen', ':-moz-full-screen', ':-ms-fullscreen'],\n len_pseudo = pseudo_keys.length, i,\n\n // CSS rules to center the inner div horizontally and vertically.\n rule_inner = '{margin:0 auto;transform:matrix(' + scale + ',0,0,' + scale + ',0,' + vshift + ');}',\n\n // A previously installed CSS rule to center the JSXGraph div has to\n // be searched and removed again.\n regex = new RegExp('.*#' + wrap_id + ':.*full.*screen.*#' + inner_id + '.*auto;.*transform:.*matrix');\n\n if (len === 0) {\n // In case there is not a single CSS rule defined at all.\n style = document.createElement('style');\n // WebKit hack :(\n style.appendChild(document.createTextNode(''));\n // Add the <style> element to the page\n document.body.appendChild(style);\n len = document.styleSheets.length;\n }\n\n // Remove a previously installed CSS rule.\n if (document.styleSheets[len - 1].cssRules.length > 0 &&\n regex.test(document.styleSheets[len - 1].cssRules[0].cssText) &&\n document.styleSheets[len - 1].deleteRule) {\n\n document.styleSheets[len - 1].deleteRule(0);\n }\n\n // Install a CSS rule to center the JSXGraph div at the first position of the list.\n for (i = 0; i < len_pseudo; i++) {\n try {\n document.styleSheets[len - 1].insertRule('#' + wrap_id + pseudo_keys[i] + ' #' + inner_id + rule_inner, 0);\n break;\n } catch (err) {\n // console.log('JXG.scaleJSXGraphDiv: Could not add CSS rule \"' + pseudo_keys[i] + '\".');\n // console.log('One possible reason could be that the id of the JSXGraph container does not start with a letter.');\n }\n }\n if (i === len_pseudo) {\n console.log('JXG.scaleJSXGraphDiv: Could not add any CSS rule.');\n console.log('One possible reason could be that the id of the JSXGraph container does not start with a letter.');\n }\n }\n });\n\n return JXG;\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true, DOMParser: true, ActiveXObject: true*/\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n jxg\n utils/type\n */\n\ndefine('utils/xml',['jxg', 'utils/type'], function (JXG, Type) {\n\n \"use strict\";\n\n /**\n * Holds browser independent xml parsing routines. Won't work in environments other than browsers.\n * @namespace\n */\n JXG.XML = {\n /**\n * Cleans out unneccessary whitespaces in a chunk of xml.\n * @param {Object} el\n */\n cleanWhitespace: function (el) {\n var cur = el.firstChild;\n\n while (Type.exists(cur)) {\n if (cur.nodeType === 3 && !/\\S/.test(cur.nodeValue)) {\n el.removeChild(cur);\n } else if (cur.nodeType === 1) {\n this.cleanWhitespace(cur);\n }\n cur = cur.nextSibling;\n }\n },\n\n /**\n * Converts a given string into a XML tree.\n * @param {String} str\n * @returns {Object} The xml tree represented by the root node.\n */\n parse: function (str) {\n var parser, tree, DP;\n\n // DOMParser is a function in all browsers, except older IE and Safari.\n // In IE it does not exists (workaround in else branch), in Safari it's an object.\n if (typeof DOMParser === 'function' || typeof DOMParser === 'object') {\n DP = DOMParser;\n } else {\n // IE workaround, since there is no DOMParser\n DP = function () {\n this.parseFromString = function (str) {\n var d;\n\n if (typeof ActiveXObject === 'function') {\n d = new ActiveXObject('MSXML.DomDocument');\n d.loadXML(str);\n }\n\n return d;\n };\n };\n }\n\n parser = new DP();\n tree = parser.parseFromString(str, 'text/xml');\n this.cleanWhitespace(tree);\n\n return tree;\n }\n };\n\n return JXG.XML;\n});\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true*/\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n jxg\n utils/type\n */\n\n/**\n * @fileoverview In this file the EventEmitter interface is defined.\n */\n\ndefine('utils/event',['jxg', 'utils/type'], function (JXG, Type) {\n\n \"use strict\";\n\n /**\n * Event namespace\n * @namespace\n */\n JXG.EventEmitter = {\n /**\n * Holds the registered event handlers.\n * @type Object\n */\n eventHandlers: {},\n\n /**\n * Events can be suspended to prevent endless loops.\n * @type Object\n */\n suspended: {},\n\n /**\n * Triggers all event handlers of this element for a given event.\n * @param {Array} event\n * @param {Array} args The arguments passed onto the event handler\n * @returns Reference to the object.\n */\n trigger: function (event, args) {\n var i, j, h, evt, len1, len2;\n\n len1 = event.length;\n for (j = 0; j < len1; j++) {\n evt = this.eventHandlers[event[j]];\n\n if (!this.suspended[event[j]]) {\n this.suspended[event[j]] = true;\n\n if (evt) {\n len2 = evt.length;\n\n for (i = 0; i < len2; i++) {\n h = evt[i];\n h.handler.apply(h.context, args);\n }\n }\n\n this.suspended[event[j]] = false;\n }\n }\n\n return this;\n },\n\n /**\n * Register a new event handler. For a list of possible events see documentation\n * of the elements and objects implementing\n * the {@link EventEmitter} interface.\n * @param {String} event\n * @param {Function} handler\n * @param {Object} [context] The context the handler will be called in, default is the element itself.\n * @returns Reference to the object.\n */\n on: function (event, handler, context) {\n if (!Type.isArray(this.eventHandlers[event])) {\n this.eventHandlers[event] = [];\n }\n\n context = Type.def(context, this);\n\n this.eventHandlers[event].push({\n handler: handler,\n context: context\n });\n\n return this;\n },\n\n /**\n * Unregister an event handler.\n * @param {String} event\n * @param {Function} [handler]\n * @returns Reference to the object.\n */\n off: function (event, handler) {\n var i;\n\n if (!event || !Type.isArray(this.eventHandlers[event])) {\n return this;\n }\n\n if (handler) {\n i = Type.indexOf(this.eventHandlers[event], handler, 'handler');\n if (i > -1) {\n this.eventHandlers[event].splice(i, 1);\n }\n\n if (this.eventHandlers[event].length === 0) {\n delete this.eventHandlers[event];\n }\n } else {\n delete this.eventHandlers[event];\n }\n\n return this;\n },\n\n /**\n * @description Implements the functionality from this interface in the given object.\n * All objects getting their event handling\n * capabilities from this method should document it by adding\n * the <tt>on, off, triggerEventHandlers</tt> via the\n * borrows tag as methods to their documentation:\n * <pre>@borrows JXG.EventEmitter#on as this.on</pre>\n * @param {Object} o\n */\n eventify: function (o) {\n o.eventHandlers = {};\n o.on = this.on;\n o.off = this.off;\n o.triggerEventHandlers = this.trigger;\n o.trigger = this.trigger;\n o.suspended = {};\n }\n };\n\n return JXG.EventEmitter;\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true, Float32Array: true */\n/*jslint nomen: true, plusplus: true, bitwise: true*/\n\n/* depends:\n jxg\n */\n\n/**\n * @fileoverview In this file the namespace JXG.Math is defined, which is the base namespace\n * for namespaces like Math.Numerics, Math.Algebra, Math.Statistics etc.\n */\n\ndefine('math/math',['jxg', 'utils/type'], function (JXG, Type) {\n\n \"use strict\";\n\n var undef,\n\n /*\n * Dynamic programming approach for recursive functions.\n * From \"Speed up your JavaScript, Part 3\" by Nicholas C. Zakas.\n * @see JXG.Math.factorial\n * @see JXG.Math.binomial\n * http://blog.thejit.org/2008/09/05/memoization-in-javascript/\n *\n * This method is hidden, because it is only used in JXG.Math. If someone wants\n * to use it in JSXGraph outside of JXG.Math, it should be moved to jsxgraph.js\n */\n memoizer = function (f) {\n var cache, join;\n\n if (f.memo) {\n return f.memo;\n }\n\n cache = {};\n join = Array.prototype.join;\n\n f.memo = function () {\n var key = join.call(arguments);\n\n // Seems to be a bit faster than \"if (a in b)\"\n return (cache[key] !== undef) ?\n cache[key] :\n cache[key] = f.apply(this, arguments);\n };\n\n return f.memo;\n };\n\n /**\n * Math namespace.\n * @namespace\n */\n JXG.Math = {\n /**\n * eps defines the closeness to zero. If the absolute value of a given number is smaller\n * than eps, it is considered to be equal to zero.\n * @type Number\n */\n eps: 0.000001,\n\n /**\n * Determine the relative difference between two numbers.\n * @param {Number} a First number\n * @param {Number} b Second number\n * @returns {Number} Relative difference between a and b: |a-b| / max(|a|, |b|)\n */\n relDif: function(a, b) {\n var c = Math.abs(a),\n d = Math.abs(b);\n\n d = Math.max(c, d);\n\n return (d === 0.0) ? 0.0 : Math.abs(a - b) / d;\n },\n\n /**\n * The JavaScript implementation of the % operator returns the symmetric modulo.\n * mod and \"%\" are both identical if a >= 0 and m >= 0 but the results differ if a or m < 0.\n * @param {Number} a\n * @param {Number} m\n * @returns {Number} Mathematical modulo <tt>a mod m</tt>\n */\n mod: function (a, m) {\n return a - Math.floor(a / m) * m;\n },\n\n /**\n * Initializes a vector as an array with the coefficients set to the given value resp. zero.\n * @param {Number} n Length of the vector\n * @param {Number} [init=0] Initial value for each coefficient\n * @returns {Array} A <tt>n</tt> times <tt>m</tt>-matrix represented by a\n * two-dimensional array. The inner arrays hold the columns, the outer array holds the rows.\n */\n vector: function (n, init) {\n var r, i;\n\n init = init || 0;\n r = [];\n\n for (i = 0; i < n; i++) {\n r[i] = init;\n }\n\n return r;\n },\n\n /**\n * Initializes a matrix as an array of rows with the given value.\n * @param {Number} n Number of rows\n * @param {Number} [m=n] Number of columns\n * @param {Number} [init=0] Initial value for each coefficient\n * @returns {Array} A <tt>n</tt> times <tt>m</tt>-matrix represented by a\n * two-dimensional array. The inner arrays hold the columns, the outer array holds the rows.\n */\n matrix: function (n, m, init) {\n var r, i, j;\n\n init = init || 0;\n m = m || n;\n r = [];\n\n for (i = 0; i < n; i++) {\n r[i] = [];\n\n for (j = 0; j < m; j++) {\n r[i][j] = init;\n }\n }\n\n return r;\n },\n\n /**\n * Generates an identity matrix. If n is a number and m is undefined or not a number, a square matrix is generated,\n * if n and m are both numbers, an nxm matrix is generated.\n * @param {Number} n Number of rows\n * @param {Number} [m=n] Number of columns\n * @returns {Array} A square matrix of length <tt>n</tt> with all coefficients equal to 0 except a_(i,i), i out of (1, ..., n), if <tt>m</tt> is undefined or not a number\n * or a <tt>n</tt> times <tt>m</tt>-matrix with a_(i,j) = 0 and a_(i,i) = 1 if m is a number.\n */\n identity: function (n, m) {\n var r, i;\n\n if ((m === undef) && (typeof m !== 'number')) {\n m = n;\n }\n\n r = this.matrix(n, m);\n\n for (i = 0; i < Math.min(n, m); i++) {\n r[i][i] = 1;\n }\n\n return r;\n },\n\n /**\n * Generates a 4x4 matrix for 3D to 2D projections.\n * @param {Number} l Left\n * @param {Number} r Right\n * @param {Number} t Top\n * @param {Number} b Bottom\n * @param {Number} n Near\n * @param {Number} f Far\n * @returns {Array} 4x4 Matrix\n */\n frustum: function (l, r, b, t, n, f) {\n var ret = this.matrix(4, 4);\n\n ret[0][0] = (n * 2) / (r - l);\n ret[0][1] = 0;\n ret[0][2] = (r + l) / (r - l);\n ret[0][3] = 0;\n\n ret[1][0] = 0;\n ret[1][1] = (n * 2) / (t - b);\n ret[1][2] = (t + b) / (t - b);\n ret[1][3] = 0;\n\n ret[2][0] = 0;\n ret[2][1] = 0;\n ret[2][2] = -(f + n) / (f - n);\n ret[2][3] = -(f * n * 2) / (f - n);\n\n ret[3][0] = 0;\n ret[3][1] = 0;\n ret[3][2] = -1;\n ret[3][3] = 0;\n\n return ret;\n },\n\n /**\n * Generates a 4x4 matrix for 3D to 2D projections.\n * @param {Number} fov Field of view in vertical direction, given in rad.\n * @param {Number} ratio Aspect ratio of the projection plane.\n * @param {Number} n Near\n * @param {Number} f Far\n * @returns {Array} 4x4 Projection Matrix\n */\n projection: function (fov, ratio, n, f) {\n var t = n * Math.tan(fov / 2),\n r = t * ratio;\n\n return this.frustum(-r, r, -t, t, n, f);\n },\n\n /**\n * Multiplies a vector vec to a matrix mat: mat * vec. The matrix is interpreted by this function as an array of rows. Please note: This\n * function does not check if the dimensions match.\n * @param {Array} mat Two dimensional array of numbers. The inner arrays describe the columns, the outer ones the matrix' rows.\n * @param {Array} vec Array of numbers\n * @returns {Array} Array of numbers containing the result\n * @example\n * var A = [[2, 1],\n * [1, 3]],\n * b = [4, 5],\n * c;\n * c = JXG.Math.matVecMult(A, b)\n * // c === [13, 19];\n */\n matVecMult: function (mat, vec) {\n var i, s, k,\n m = mat.length,\n n = vec.length,\n res = [];\n\n if (n === 3) {\n for (i = 0; i < m; i++) {\n res[i] = mat[i][0] * vec[0] + mat[i][1] * vec[1] + mat[i][2] * vec[2];\n }\n } else {\n for (i = 0; i < m; i++) {\n s = 0;\n for (k = 0; k < n; k++) {\n s += mat[i][k] * vec[k];\n }\n res[i] = s;\n }\n }\n return res;\n },\n\n /**\n * Computes the product of the two matrices mat1*mat2.\n * @param {Array} mat1 Two dimensional array of numbers\n * @param {Array} mat2 Two dimensional array of numbers\n * @returns {Array} Two dimensional Array of numbers containing result\n */\n matMatMult: function (mat1, mat2) {\n var i, j, s, k,\n m = mat1.length,\n n = m > 0 ? mat2[0].length : 0,\n m2 = mat2.length,\n res = this.matrix(m, n);\n\n for (i = 0; i < m; i++) {\n for (j = 0; j < n; j++) {\n s = 0;\n for (k = 0; k < m2; k++) {\n s += mat1[i][k] * mat2[k][j];\n }\n res[i][j] = s;\n }\n }\n return res;\n },\n\n /**\n * Transposes a matrix given as a two dimensional array.\n * @param {Array} M The matrix to be transposed\n * @returns {Array} The transpose of M\n */\n transpose: function (M) {\n var MT, i, j,\n m, n;\n\n // number of rows of M\n m = M.length;\n // number of columns of M\n n = M.length > 0 ? M[0].length : 0;\n MT = this.matrix(n, m);\n\n for (i = 0; i < n; i++) {\n for (j = 0; j < m; j++) {\n MT[i][j] = M[j][i];\n }\n }\n\n return MT;\n },\n\n /**\n * Compute the inverse of an nxn matrix with Gauss elimination.\n * @param {Array} Ain\n * @returns {Array} Inverse matrix of Ain\n */\n inverse: function (Ain) {\n var i, j, k, s, ma, r, swp,\n n = Ain.length,\n A = [],\n p = [],\n hv = [];\n\n for (i = 0; i < n; i++) {\n A[i] = [];\n for (j = 0; j < n; j++) {\n A[i][j] = Ain[i][j];\n }\n p[i] = i;\n }\n\n for (j = 0; j < n; j++) {\n // pivot search:\n ma = Math.abs(A[j][j]);\n r = j;\n\n for (i = j + 1; i < n; i++) {\n if (Math.abs(A[i][j]) > ma) {\n ma = Math.abs(A[i][j]);\n r = i;\n }\n }\n\n // Singular matrix\n if (ma <= this.eps) {\n return [];\n }\n\n // swap rows:\n if (r > j) {\n for (k = 0; k < n; k++) {\n swp = A[j][k];\n A[j][k] = A[r][k];\n A[r][k] = swp;\n }\n\n swp = p[j];\n p[j] = p[r];\n p[r] = swp;\n }\n\n // transformation:\n s = 1.0 / A[j][j];\n for (i = 0; i < n; i++) {\n A[i][j] *= s;\n }\n A[j][j] = s;\n\n for (k = 0; k < n; k++) {\n if (k !== j) {\n for (i = 0; i < n; i++) {\n if (i !== j) {\n A[i][k] -= A[i][j] * A[j][k];\n }\n }\n A[j][k] = -s * A[j][k];\n }\n }\n }\n\n // swap columns:\n for (i = 0; i < n; i++) {\n for (k = 0; k < n; k++) {\n hv[p[k]] = A[i][k];\n }\n for (k = 0; k < n; k++) {\n A[i][k] = hv[k];\n }\n }\n\n return A;\n },\n\n /**\n * Inner product of two vectors a and b. n is the length of the vectors.\n * @param {Array} a Vector\n * @param {Array} b Vector\n * @param {Number} [n] Length of the Vectors. If not given the length of the first vector is taken.\n * @returns {Number} The inner product of a and b.\n */\n innerProduct: function (a, b, n) {\n var i,\n s = 0;\n\n if (n === undef || !Type.isNumber(n)) {\n n = a.length;\n }\n\n for (i = 0; i < n; i++) {\n s += a[i] * b[i];\n }\n\n return s;\n },\n\n /**\n * Calculates the cross product of two vectors both of length three.\n * In case of homogeneous coordinates this is either\n * <ul>\n * <li>the intersection of two lines</li>\n * <li>the line through two points</li>\n * </ul>\n * @param {Array} c1 Homogeneous coordinates of line or point 1\n * @param {Array} c2 Homogeneous coordinates of line or point 2\n * @returns {Array} vector of length 3: homogeneous coordinates of the resulting point / line.\n */\n crossProduct: function (c1, c2) {\n return [c1[1] * c2[2] - c1[2] * c2[1],\n c1[2] * c2[0] - c1[0] * c2[2],\n c1[0] * c2[1] - c1[1] * c2[0]];\n },\n\n /**\n * Euclidean norm of a vector.\n *\n * @param {Array} a Array containing a vector.\n * @param {Number} n (Optional) length of the array.\n * @returns {Number} Euclidean norm of the vector.\n */\n norm: function(a, n) {\n var i, sum = 0.0;\n\n if (n === undef || !Type.isNumber(n)) {\n n = a.length;\n }\n\n for (i = 0; i < n; i++) {\n sum += a[i] * a[i];\n }\n\n return Math.sqrt(sum);\n },\n\n axpy: function (a, x, y) {\n var i, le = x.length,\n p = [];\n for (i = 0; i < le; i++) {\n p[i] = a * x[i] + y[i];\n }\n return p;\n },\n\n /**\n * Compute the factorial of a positive integer. If a non-integer value\n * is given, the fraction will be ignored.\n * @function\n * @param {Number} n\n * @returns {Number} n! = n*(n-1)*...*2*1\n */\n factorial: memoizer(function (n) {\n if (n < 0) {\n return NaN;\n }\n\n n = Math.floor(n);\n\n if (n === 0 || n === 1) {\n return 1;\n }\n\n return n * this.factorial(n - 1);\n }),\n\n /**\n * Computes the binomial coefficient n over k.\n * @function\n * @param {Number} n Fraction will be ignored\n * @param {Number} k Fraction will be ignored\n * @returns {Number} The binomial coefficient n over k\n */\n binomial: memoizer(function (n, k) {\n var b, i;\n\n if (k > n || k < 0) {\n return NaN;\n }\n\n k = Math.round(k);\n n = Math.round(n);\n\n if (k === 0 || k === n) {\n return 1;\n }\n\n b = 1;\n\n for (i = 0; i < k; i++) {\n b *= (n - i);\n b /= (i + 1);\n }\n\n return b;\n }),\n\n /**\n * Calculates the cosine hyperbolicus of x.\n * @function\n * @param {Number} x The number the cosine hyperbolicus will be calculated of.\n * @returns {Number} Cosine hyperbolicus of the given value.\n */\n cosh: Math.cosh || function (x) {\n return (Math.exp(x) + Math.exp(-x)) * 0.5;\n },\n\n /**\n * Sine hyperbolicus of x.\n * @function\n * @param {Number} x The number the sine hyperbolicus will be calculated of.\n * @returns {Number} Sine hyperbolicus of the given value.\n */\n sinh: Math.sinh || function (x) {\n return (Math.exp(x) - Math.exp(-x)) * 0.5;\n },\n\n /**\n * Hyperbolic arc-cosine of a number.\n *\n * @param {Number} x\n * @returns {Number}\n */\n acosh: Math.acosh || function(x) {\n return Math.log(x + Math.sqrt(x * x - 1));\n },\n\n /**\n * Hyperbolic arcsine of a number\n * @param {Number} x\n * @returns {Number}\n */\n asinh: Math.asinh || function(x) {\n if (x === -Infinity) {\n return x;\n }\n return Math.log(x + Math.sqrt(x * x + 1));\n },\n\n /**\n * Computes the cotangent of x.\n * @function\n * @param {Number} x The number the cotangent will be calculated of.\n * @returns {Number} Cotangent of the given value.\n */\n cot: function (x) {\n return 1 / Math.tan(x);\n },\n\n /**\n * Computes the inverse cotangent of x.\n * @param {Number} x The number the inverse cotangent will be calculated of.\n * @returns {Number} Inverse cotangent of the given value.\n */\n acot: function (x) {\n return ((x >= 0) ? (0.5) : (-0.5)) * Math.PI - Math.atan(x);\n },\n\n /**\n * Compute n-th real root of a real number. n must be strictly positive integer.\n * If n is odd, the real n-th root exists and is negative.\n * For n even, for negative valuees of x NaN is returned\n * @param {Number} x radicand. Must be non-negative, if n even.\n * @param {Number} n index of the root. must be strictly positive integer.\n * @returns {Number} returns real root or NaN\n *\n * @example\n * nthroot(16, 4): 2\n * nthroot(-27, 3): -3\n * nthroot(-4, 2): NaN\n */\n nthroot: function(x, n) {\n var inv = 1 / n;\n\n if (n <= 0 || Math.floor(n) !== n) {\n return NaN;\n }\n\n if (x === 0.0) {\n return 0.0;\n }\n\n if (x > 0) {\n return Math.exp(inv * Math.log(x));\n }\n\n // From here on, x is negative\n if (n % 2 === 1) {\n return -Math.exp(inv * Math.log(-x));\n }\n\n // x negative, even root\n return NaN;\n },\n\n /**\n * Computes cube root of real number\n * Polyfill for Math.cbrt().\n *\n * @function\n * @param {Number} x Radicand\n * @returns {Number} Cube root of x.\n */\n cbrt: Math.cbrt || function(x) {\n return this.nthroot(x, 3);\n },\n\n /**\n * Compute base to the power of exponent.\n * @param {Number} base\n * @param {Number} exponent\n * @returns {Number} base to the power of exponent.\n */\n pow: function (base, exponent) {\n if (base === 0) {\n if (exponent === 0) {\n return 1;\n }\n return 0;\n }\n\n // exponent is an integer\n if (Math.floor(exponent) === exponent) {\n return Math.pow(base, exponent);\n }\n\n // exponent is not an integer\n if (base > 0) {\n return Math.exp(exponent * Math.log(base));\n }\n\n return NaN;\n },\n\n /**\n * Compute base to the power of the rational exponent m / n.\n * This function first reduces the fraction m/n and then computes\n * JXG.Math.pow(base, m/n).\n *\n * This function is necessary to have the same results for e.g.\n * (-8)^(1/3) = (-8)^(2/6) = -2\n * @param {Number} base\n * @param {Number} m numerator of exponent\n * @param {Number} n denominator of exponent\n * @returns {Number} base to the power of exponent.\n */\n ratpow: function(base, m, n) {\n var g;\n if (m === 0) {\n return 1;\n }\n if (n === 0) {\n return NaN;\n }\n\n g = this.gcd(m, n);\n return this.nthroot(this.pow(base, m / g), n / g);\n },\n\n /**\n * Logarithm to base 10.\n * @param {Number} x\n * @returns {Number} log10(x) Logarithm of x to base 10.\n */\n log10: function (x) {\n return Math.log(x) / Math.log(10.0);\n },\n\n /**\n * Logarithm to base 2.\n * @param {Number} x\n * @returns {Number} log2(x) Logarithm of x to base 2.\n */\n log2: function (x) {\n return Math.log(x) / Math.log(2.0);\n },\n\n /**\n * Logarithm to arbitrary base b. If b is not given, natural log is taken, i.e. b = e.\n * @param {Number} x\n * @param {Number} b base\n * @returns {Number} log(x, b) Logarithm of x to base b, that is log(x)/log(b).\n */\n log: function (x, b) {\n if (b !== undefined && Type.isNumber(b)) {\n return Math.log(x) / Math.log(b);\n }\n\n return Math.log(x);\n },\n\n /**\n * The sign() function returns the sign of a number, indicating whether the number is positive, negative or zero.\n *\n * @function\n * @param {Number} x A Number\n * @returns {[type]} This function has 5 kinds of return values,\n * 1, -1, 0, -0, NaN, which represent \"positive number\", \"negative number\", \"positive zero\", \"negative zero\"\n * and NaN respectively.\n */\n sign: Math.sign || function(x) {\n x = +x; // convert to a number\n if (x === 0 || isNaN(x)) {\n return x;\n }\n return x > 0 ? 1 : -1;\n },\n\n /**\n * A square & multiply algorithm to compute base to the power of exponent.\n * Implementated by Wolfgang Riedl.\n *\n * @param {Number} base\n * @param {Number} exponent\n * @returns {Number} Base to the power of exponent\n */\n squampow: function (base, exponent) {\n var result;\n\n if (Math.floor(exponent) === exponent) {\n // exponent is integer (could be zero)\n result = 1;\n\n if (exponent < 0) {\n // invert: base\n base = 1.0 / base;\n exponent *= -1;\n }\n\n while (exponent !== 0) {\n if (exponent & 1) {\n result *= base;\n }\n\n exponent >>= 1;\n base *= base;\n }\n return result;\n }\n\n return this.pow(base, exponent);\n },\n\n /**\n * Greatest common divisor (gcd) of two numbers.\n * @see <a href=\"http://rosettacode.org/wiki/Greatest_common_divisor#JavaScript\">rosettacode.org</a>\n *\n * @param {Number} a First number\n * @param {Number} b Second number\n * @returns {Number} gcd(a, b) if a and b are numbers, NaN else.\n */\n gcd: function (a, b) {\n a = Math.abs(a);\n b = Math.abs(b);\n\n if (!(Type.isNumber(a) && Type.isNumber(b))) {\n return NaN;\n }\n if (b > a) {\n var temp = a;\n a = b;\n b = temp;\n }\n\n while (true) {\n a %= b;\n if (a === 0) { return b; }\n b %= a;\n if (b === 0) { return a; }\n }\n },\n\n /**\n * Least common multiple (lcm) of two numbers.\n *\n * @param {Number} a First number\n * @param {Number} b Second number\n * @returns {Number} lcm(a, b) if a and b are numbers, NaN else.\n */\n lcm: function (a, b) {\n var ret;\n\n if (!(Type.isNumber(a) && Type.isNumber(b))) {\n return NaN;\n }\n\n ret = a * b;\n if (ret !== 0) {\n return ret / this.gcd(a, b);\n }\n\n return 0;\n },\n\n /**\n * Error function, see {@link https://en.wikipedia.org/wiki/Error_function}.\n *\n * @see JXG.Math.PropFunc.erf\n * @param {Number} x\n * @returns {Number}\n */\n erf: function(x) {\n return this.ProbFuncs.erf(x);\n },\n\n /**\n * Complementary error function, i.e. 1 - erf(x).\n *\n * @see JXG.Math.erf\n * @see JXG.Math.PropFunc.erfc\n * @param {Number} x\n * @returns {Number}\n */\n erfc: function(x) {\n return this.ProbFuncs.erfc(x);\n },\n\n /**\n * Inverse of error function\n *\n * @see JXG.Math.erf\n * @see JXG.Math.PropFunc.erfi\n * @param {Number} x\n * @returns {Number}\n */\n erfi: function(x) {\n return this.ProbFuncs.erfi(x);\n },\n\n /**\n * Normal distribution function\n *\n * @see JXG.Math.PropFunc.ndtr\n * @param {Number} x\n * @returns {Number}\n */\n ndtr: function(x) {\n return this.ProbFuncs.ndtr(x);\n },\n\n /**\n * Inverse of normal distribution function\n *\n * @see JXG.Math.ndtr\n * @see JXG.Math.PropFunc.ndtri\n * @param {Number} x\n * @returns {Number}\n */\n ndtri: function(x) {\n return this.ProbFuncs.ndtri(x);\n },\n\n /* ******************** Comparisons and logical operators ************** */\n\n /**\n * Logical test: a < b?\n *\n * @param {Number} a\n * @param {Number} b\n * @returns {Boolean}\n */\n lt: function(a, b) {\n return a < b;\n },\n\n /**\n * Logical test: a <= b?\n *\n * @param {Number} a\n * @param {Number} b\n * @returns {Boolean}\n */\n leq: function(a, b) {\n return a <= b;\n },\n\n /**\n * Logical test: a > b?\n *\n * @param {Number} a\n * @param {Number} b\n * @returns {Boolean}\n */\n gt: function(a, b) {\n return a > b;\n },\n\n /**\n * Logical test: a >= b?\n *\n * @param {Number} a\n * @param {Number} b\n * @returns {Boolean}\n */\n geq: function(a, b) {\n return a >= b;\n },\n\n /**\n * Logical test: a === b?\n *\n * @param {Number} a\n * @param {Number} b\n * @returns {Boolean}\n */\n eq: function(a, b) {\n return a === b;\n },\n\n /**\n * Logical test: a !== b?\n *\n * @param {Number} a\n * @param {Number} b\n * @returns {Boolean}\n */\n neq: function(a, b) {\n return a !== b;\n },\n\n /**\n * Logical operator: a && b?\n *\n * @param {Boolean} a\n * @param {Boolean} b\n * @returns {Boolean}\n */\n and: function(a, b) {\n return a && b;\n },\n\n /**\n * Logical operator: !a?\n *\n * @param {Boolean} a\n * @returns {Boolean}\n */\n not: function(a) {\n return !a;\n },\n\n /**\n * Logical operator: a || b?\n *\n * @param {Boolean} a\n * @param {Boolean} b\n * @returns {Boolean}\n */\n or: function(a, b) {\n return a || b;\n },\n\n /**\n * Logical operator: either a or b?\n *\n * @param {Boolean} a\n * @param {Boolean} b\n * @returns {Boolean}\n */\n xor: function(a, b) {\n return (a || b) && !(a && b);\n },\n\n /* *************************** Normalize *************************** */\n\n /**\n * Normalize the standard form [c, b0, b1, a, k, r, q0, q1].\n * @private\n * @param {Array} stdform The standard form to be normalized.\n * @returns {Array} The normalized standard form.\n */\n normalize: function (stdform) {\n var n, signr,\n a2 = 2 * stdform[3],\n r = stdform[4] / a2;\n\n stdform[5] = r;\n stdform[6] = -stdform[1] / a2;\n stdform[7] = -stdform[2] / a2;\n\n if (!isFinite(r)) {\n n = Math.sqrt(stdform[1] * stdform[1] + stdform[2] * stdform[2]);\n\n stdform[0] /= n;\n stdform[1] /= n;\n stdform[2] /= n;\n stdform[3] = 0;\n stdform[4] = 1;\n } else if (Math.abs(r) >= 1) {\n stdform[0] = (stdform[6] * stdform[6] + stdform[7] * stdform[7] - r * r) / (2 * r);\n stdform[1] = -stdform[6] / r;\n stdform[2] = -stdform[7] / r;\n stdform[3] = 1 / (2 * r);\n stdform[4] = 1;\n } else {\n signr = (r <= 0 ? -1 : 1);\n stdform[0] = signr * (stdform[6] * stdform[6] + stdform[7] * stdform[7] - r * r) * 0.5;\n stdform[1] = -signr * stdform[6];\n stdform[2] = -signr * stdform[7];\n stdform[3] = signr / 2;\n stdform[4] = signr * r;\n }\n\n return stdform;\n },\n\n /**\n * Converts a two dimensional array to a one dimensional Float32Array that can be processed by WebGL.\n * @param {Array} m A matrix in a two dimensional array.\n * @returns {Float32Array} A one dimensional array containing the matrix in column wise notation. Provides a fall\n * back to the default JavaScript Array if Float32Array is not available.\n */\n toGL: function (m) {\n var v, i, j;\n\n if (typeof Float32Array === 'function') {\n v = new Float32Array(16);\n } else {\n v = new Array(16);\n }\n\n if (m.length !== 4 && m[0].length !== 4) {\n return v;\n }\n\n for (i = 0; i < 4; i++) {\n for (j = 0; j < 4; j++) {\n v[i + 4 * j] = m[i][j];\n }\n }\n\n return v;\n },\n\n /**\n * Theorem of Vieta: Given a set of simple zeroes x_0, ..., x_n\n * of a polynomial f, compute the coefficients s_k, (k=0,...,n-1)\n * of the polynomial of the form. See {@link https://de.wikipedia.org/wiki/Elementarsymmetrisches_Polynom}.\n * <p>\n * f(x) = (x-x_0)*...*(x-x_n) =\n * x^n + sum_{k=1}^{n} (-1)^(k) s_{k-1} x^(n-k)\n * </p>\n * @param {Array} x Simple zeroes of the polynomial.\n * @returns {Array} Coefficients of the polynomial.\n *\n */\n Vieta: function(x) {\n var n = x.length,\n s = [],\n m, k, y;\n\n s = x.slice();\n for (m = 1; m < n; ++m) {\n y = s[m];\n s[m] *= s[m - 1];\n for (k = m - 1; k >= 1; --k) {\n s[k] += s[k - 1] * y;\n }\n s[0] += y;\n }\n return s;\n }\n };\n\n return JXG.Math;\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true, AMprocessNode: true, MathJax: true, document: true */\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n jxg\n base/constants\n utils/event\n math/math\n */\n\ndefine('base/coords',[\n 'jxg', 'base/constants', 'utils/event', 'utils/type', 'math/math'\n], function (JXG, Const, EventEmitter, Type, Mat) {\n\n \"use strict\";\n\n /**\n * @fileoverview In this file the Coords object is defined, a class to manage all\n * properties and methods coordinates usually have.\n */\n\n /**\n * Constructs a new Coordinates object.\n * @class This is the Coordinates class.\n * All members a coordinate has to provide\n * are defined here.\n * @param {Number} method The type of coordinates given by the user. Accepted values are <b>COORDS_BY_SCREEN</b> and <b>COORDS_BY_USER</b>.\n * @param {Array} coordinates An array of affine coordinates.\n * @param {JXG.Board} board A reference to a board.\n * @oaram {Boolean} [emitter=true]\n * @borrows JXG.EventEmitter#on as this.on\n * @borrows JXG.EventEmitter#off as this.off\n * @borrows JXG.EventEmitter#triggerEventHandlers as this.triggerEventHandlers\n * @borrows JXG.EventEmitter#eventHandlers as this.eventHandlers\n * @constructor\n */\n JXG.Coords = function (method, coordinates, board, emitter) {\n /**\n * Stores the board the object is used on.\n * @type JXG.Board\n */\n this.board = board;\n\n /**\n * Stores coordinates for user view as homogeneous coordinates.\n * @type Array\n */\n this.usrCoords = [];\n //this.usrCoords = new Float64Array(3);\n\n /**\n * Stores coordinates for screen view as homogeneous coordinates.\n * @type Array\n */\n this.scrCoords = [];\n //this.scrCoords = new Float64Array(3);\n\n /**\n * If true, this coordinates object will emit update events every time\n * the coordinates are set.\n * @type boolean\n * @default true\n */\n this.emitter = !Type.exists(emitter) || emitter;\n\n if (this.emitter) {\n EventEmitter.eventify(this);\n }\n this.setCoordinates(method, coordinates, false, true);\n };\n\n JXG.extend(JXG.Coords.prototype, /** @lends JXG.Coords.prototype */ {\n /**\n * Normalize homogeneous coordinates\n * @private\n */\n normalizeUsrCoords: function () {\n if (Math.abs(this.usrCoords[0]) > Mat.eps) {\n this.usrCoords[1] /= this.usrCoords[0];\n this.usrCoords[2] /= this.usrCoords[0];\n this.usrCoords[0] = 1.0;\n }\n },\n\n /**\n * Compute screen coordinates out of given user coordinates.\n * @private\n */\n usr2screen: function (doRound) {\n var mround = Math.round, // Is faster on IE, maybe slower with JIT compilers\n b = this.board,\n uc = this.usrCoords,\n oc = b.origin.scrCoords;\n\n if (doRound === true) {\n this.scrCoords[0] = mround(uc[0]);\n this.scrCoords[1] = mround(uc[0] * oc[1] + uc[1] * b.unitX);\n this.scrCoords[2] = mround(uc[0] * oc[2] - uc[2] * b.unitY);\n } else {\n this.scrCoords[0] = uc[0];\n this.scrCoords[1] = uc[0] * oc[1] + uc[1] * b.unitX;\n this.scrCoords[2] = uc[0] * oc[2] - uc[2] * b.unitY;\n }\n },\n\n /**\n * Compute user coordinates out of given screen coordinates.\n * @private\n */\n screen2usr: function () {\n var o = this.board.origin.scrCoords,\n sc = this.scrCoords,\n b = this.board;\n\n this.usrCoords[0] = 1.0;\n this.usrCoords[1] = (sc[1] - o[1]) / b.unitX;\n this.usrCoords[2] = (o[2] - sc[2]) / b.unitY;\n },\n\n /**\n * Calculate distance of one point to another.\n * @param {Number} coord_type The type of coordinates used here. Possible values are <b>JXG.COORDS_BY_USER</b> and <b>JXG.COORDS_BY_SCREEN</b>.\n * @param {JXG.Coords} coordinates The Coords object to which the distance is calculated.\n * @returns {Number} The distance\n */\n distance: function (coord_type, coordinates) {\n var sum = 0,\n c,\n ucr = this.usrCoords,\n scr = this.scrCoords,\n f;\n\n if (coord_type === Const.COORDS_BY_USER) {\n c = coordinates.usrCoords;\n f = ucr[0] - c[0];\n sum = f * f;\n\n if (sum > Mat.eps * Mat.eps) {\n return Number.POSITIVE_INFINITY;\n }\n f = ucr[1] - c[1];\n sum += f * f;\n f = ucr[2] - c[2];\n sum += f * f;\n } else {\n c = coordinates.scrCoords;\n //f = scr[0]-c[0];\n //sum = f*f;\n f = scr[1] - c[1];\n sum += f * f;\n f = scr[2] - c[2];\n sum += f * f;\n }\n\n return Math.sqrt(sum);\n },\n\n /**\n * Set coordinates by either user coordinates or screen coordinates and recalculate the other one.\n * @param {Number} coord_type The type of coordinates used here. Possible values are <b>COORDS_BY_USER</b> and <b>COORDS_BY_SCREEN</b>.\n * @param {Array} coordinates An array of affine coordinates the Coords object is set to.\n * @param {Boolean} [doRound=true] flag If true or null round the coordinates in usr2screen. This is used in smooth curve plotting.\n * The IE needs rounded coordinates. Id doRound==false we have to round in updatePathString.\n * @param {Boolean} [noevent=false]\n * @returns {JXG.Coords} Reference to the coords object.\n */\n setCoordinates: function (coord_type, coordinates, doRound, noevent) {\n var uc = this.usrCoords,\n sc = this.scrCoords,\n // Original values\n ou = [uc[0], uc[1], uc[2]],\n os = [sc[0], sc[1], sc[2]];\n\n if (coord_type === Const.COORDS_BY_USER) {\n if (coordinates.length === 2) { // Euclidean coordinates\n uc[0] = 1.0;\n uc[1] = coordinates[0];\n uc[2] = coordinates[1];\n } else { // Homogeneous coordinates (normalized)\n uc[0] = coordinates[0];\n uc[1] = coordinates[1];\n uc[2] = coordinates[2];\n this.normalizeUsrCoords();\n }\n this.usr2screen(doRound);\n } else {\n if (coordinates.length === 2) { // Euclidean coordinates\n sc[1] = coordinates[0];\n sc[2] = coordinates[1];\n } else { // Homogeneous coordinates (normalized)\n sc[1] = coordinates[1];\n sc[2] = coordinates[2];\n }\n this.screen2usr();\n }\n\n if (this.emitter && !noevent && (os[1] !== sc[1] || os[2] !== sc[2])) {\n this.triggerEventHandlers(['update'], [ou, os]);\n }\n\n return this;\n },\n\n /**\n * Copy array, either scrCoords or usrCoords\n * Uses slice() in case of standard arrays and set() in case of\n * typed arrays.\n * @private\n * @param {String} obj Either 'scrCoords' or 'usrCoords'\n * @param {Number} offset Offset, defaults to 0 if not given\n * @returns {Array} Returns copy of the coords array either as standard array or as\n * typed array.\n */\n copy: function (obj, offset) {\n if (offset === undefined) {\n offset = 0;\n }\n\n return this[obj].slice(offset);\n },\n\n /**\n * Test if one of the usrCoords is NaN or the coordinates are infinite.\n * @returns {Boolean} true if the coordinates are finite, false otherwise.\n */\n isReal: function() {\n return (!isNaN(this.usrCoords[1] + this.usrCoords[2])) && (Math.abs(this.usrCoords[0]) > Mat.eps);\n },\n\n /**\n * Triggered whenever the coordinates change.\n * @name JXG.Coords#update\n * @param {Array} ou Old user coordinates\n * @param {Array} os Old screen coordinates\n * @event\n */\n __evt__update: function (ou, os) { },\n\n /**\n * @ignore\n */\n __evt: function () {}\n });\n\n return JXG.Coords;\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true, html_sanitize: true*/\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n jxg\n base/constants\n */\n\n/**\n * @fileoverview expect.js provides utilities for parameter magic by normalizing multi-type parameters.\n */\n\ndefine('utils/expect',[\n 'jxg', 'utils/type', 'base/constants', 'base/coords'\n], function (JXG, Type, Const, Coords) {\n\n \"use strict\";\n\n var Expect = {\n /**\n * Apply an expect method on every element of an array.\n *\n * @param {Array} a\n * @param {function} format\n * @param {Boolean} [copy=false]\n *\n * @returns {Array}\n */\n each: function (a, format, copy) {\n var i, len,\n r = [];\n\n if (Type.exists(a.length)) {\n len = a.length;\n for (i = 0; i < len; i++) {\n r.push(format.call(this, a[i], copy));\n }\n }\n\n return r;\n },\n\n /**\n * Normalize points and coord objects into a coord object.\n *\n * @param {JXG.Point|JXG.Coords} c\n * @param {Boolean} [copy=false] Return a copy, not a reference\n *\n * @returns {JXG.Coords}\n */\n coords: function (c, copy) {\n var coord = c;\n\n if (c && c.elementClass === Const.OBJECT_CLASS_POINT) {\n coord = c.coords;\n } else if (c.usrCoords && c.scrCoords && c.usr2screen) {\n coord = c;\n }\n\n if (copy) {\n coord = new Coords(Const.COORDS_BY_USER, coord.usrCoords, coord.board);\n }\n\n return coord;\n },\n\n /**\n * Normalize points, coordinate arrays and coord objects into a coordinate array.\n *\n * @param {JXG.Point|JXG.Coords|Array} c\n * @param {Boolean} [copy=false] Return a copy, not a reference\n *\n * @returns {Array} Homogeneous coordinates\n */\n coordsArray: function (c, copy) {\n var coord;\n\n if (!Type.isArray(c)) {\n coord = this.coords(c).usrCoords;\n } else {\n coord = c;\n }\n\n if (coord.length < 3) {\n coord.unshift(1);\n }\n\n if (copy) {\n coord = [coord[0], coord[1], coord[2]];\n }\n\n return coord;\n }\n };\n\n JXG.Expect = Expect;\n\n return Expect;\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Carsten Miller,\n Andreas Walter,\n Alfred Wassermann\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true*/\n/*jslint nomen: true, plusplus: true*/\n/*eslint no-loss-of-precision: off */\n\n/* depends:\n jxg\n math/math\n utils/type\n */\n\ndefine('math/probfuncs',['math/math', 'utils/type'], function (Mat, Type) {\n\n \"use strict\";\n\n /**\n * Probability functions, e.g. error function,\n * see: https://en.wikipedia.org/wiki/Error_function\n * Ported from\n * by https://github.com/jeremybarnes/cephes/blob/master/cprob/ndtr.c,\n *\n * Cephes Math Library Release 2.9: November, 2000\n * Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier\n *\n * @name JXG.Math.ProbFuncs\n * @exports Mat.ProbFuncs as JXG.Math.ProbFuncs\n * @namespace\n */\n Mat.ProbFuncs = {\n MAXNUM: 1.701411834604692317316873e38, // 2**127\n SQRTH: 7.07106781186547524401E-1, // sqrt(2)/2\n SQRT2: 1.41421356237309504880, // sqrt(2)\n MAXLOG: 7.08396418532264106224E2, // log 2**1022\n\n P: [\n 2.46196981473530512524E-10,\n 5.64189564831068821977E-1,\n 7.46321056442269912687E0,\n 4.86371970985681366614E1,\n 1.96520832956077098242E2,\n 5.26445194995477358631E2,\n 9.34528527171957607540E2,\n 1.02755188689515710272E3,\n 5.57535335369399327526E2\n ],\n\n Q: [\n 1.32281951154744992508E1,\n 8.67072140885989742329E1,\n 3.54937778887819891062E2,\n 9.75708501743205489753E2,\n 1.82390916687909736289E3,\n 2.24633760818710981792E3,\n 1.65666309194161350182E3,\n 5.57535340817727675546E2\n ],\n\n R: [\n 5.64189583547755073984E-1,\n 1.27536670759978104416E0,\n 5.01905042251180477414E0,\n 6.16021097993053585195E0,\n 7.40974269950448939160E0,\n 2.97886665372100240670E0\n ],\n\n S: [\n 2.26052863220117276590E0,\n 9.39603524938001434673E0,\n 1.20489539808096656605E1,\n 1.70814450747565897222E1,\n 9.60896809063285878198E0,\n 3.36907645100081516050E0\n ],\n\n T: [\n 9.60497373987051638749E0,\n 9.00260197203842689217E1,\n 2.23200534594684319226E3,\n 7.00332514112805075473E3,\n 5.55923013010394962768E4\n ],\n\n U: [\n 3.35617141647503099647E1,\n 5.21357949780152679795E2,\n 4.59432382970980127987E3,\n 2.26290000613890934246E4,\n 4.92673942608635921086E4\n ],\n\n // UTHRESH: 37.519379347,\n M: 128.0,\n MINV: 0.0078125,\n\n /**\n *\n *\tExponential of squared argument\n *\n * SYNOPSIS:\n *\n * double x, y, expx2();\n * int sign;\n *\n * y = expx2( x, sign );\n *\n *\n *\n * DESCRIPTION:\n *\n * Computes y = exp(x*x) while suppressing error amplification\n * that would ordinarily arise from the inexactness of the\n * exponential argument x*x.\n *\n * If sign < 0, the result is inverted; i.e., y = exp(-x*x) .\n *\n *\n * ACCURACY:\n *\n * Relative error:\n * arithmetic domain # trials peak rms\n * IEEE -26.6, 26.6 10^7 3.9e-16 8.9e-17\n *\n * @private\n * @param {Number} x\n * @param {Number} sign (int)\n * @returns {Number}\n */\n expx2: function(x, sign) {\n // double x;\n // int sign;\n var u, u1, m, f;\n\n x = Math.abs(x);\n if (sign < 0) {\n x = -x;\n }\n\n // Represent x as an exact multiple of M plus a residual.\n // M is a power of 2 chosen so that exp(m * m) does not overflow\n // or underflow and so that |x - m| is small.\n m = this.MINV * Math.floor(this.M * x + 0.5);\n f = x - m;\n\n // x^2 = m^2 + 2mf + f^2\n u = m * m;\n u1 = 2 * m * f + f * f;\n\n if (sign < 0) {\n u = -u;\n u1 = -u1;\n }\n\n if ( u + u1 > this.MAXLOG) {\n return Infinity;\n }\n\n // u is exact, u1 is small.\n u = Math.exp(u) * Math.exp(u1);\n return u;\n },\n\n /**\n *\n *\tEvaluate polynomial\n *\n * SYNOPSIS:\n *\n * int N;\n * double x, y, coef[N+1], polevl[];\n *\n * y = polevl( x, coef, N );\n *\n * DESCRIPTION:\n *\n * Evaluates polynomial of degree N:\n *\n * 2 N\n * y = C + C x + C x +...+ C x\n * 0 1 2 N\n *\n * Coefficients are stored in reverse order:\n *\n * coef[0] = C , ..., coef[N] = C .\n * N 0\n *\n * The function p1evl() assumes that coef[N] = 1.0 and is\n * omitted from the array. Its calling arguments are\n * otherwise the same as polevl().\n *\n *\n * SPEED:\n *\n * In the interest of speed, there are no checks for out\n * of bounds arithmetic. This routine is used by most of\n * the functions in the library. Depending on available\n * equipment features, the user may wish to rewrite the\n * program in microcode or assembly language.\n *\n * @private\n * @param {Number} x\n * @param {Number} coef\n * @param {Number} N\n * @returns {Number}\n */\n polevl: function(x, coef, N) {\n var ans, i;\n\n if (Type.exists(coef.reduce)) {\n return coef.reduce(function(acc, c) {\n return acc * x + c;\n }, 0);\n }\n // Polyfill\n for (i = 0, ans = 0; i <= N; i++) {\n ans = ans * x + coef[i];\n }\n return ans;\n\n },\n\n /**\n * Evaluate polynomial when coefficient of x is 1.0.\n * Otherwise same as polevl.\n *\n * @private\n * @param {Number} x\n * @param {Number} coef\n * @param {Number} N\n * @returns {Number}\n */\n p1evl: function(x, coef, N) {\n var ans, i;\n\n if (Type.exists(coef.reduce)) {\n return coef.reduce(function(acc, c) {\n return acc * x + c;\n }, 1);\n }\n // Polyfill\n for (i = 0, ans = 1; i < N; i++) {\n ans = ans * x + coef[i];\n }\n return ans;\n },\n\n /**\n *\n *\tNormal distribution function\n *\n * SYNOPSIS:\n *\n * y = ndtr( x );\n *\n * DESCRIPTION:\n *\n * Returns the area under the Gaussian probability density\n * function, integrated from minus infinity to x:\n *\n * x\n * -\n * 1 | | 2\n * ndtr(x) = --------- | exp( - t /2 ) dt\n * sqrt(2pi) | |\n * -\n * -inf.\n *\n * = ( 1 + erf(z) ) / 2\n * = erfc(z) / 2\n *\n * where z = x/sqrt(2). Computation is via the functions\n * erf and erfc with care to avoid error amplification in computing exp(-x^2).\n *\n *\n * ACCURACY:\n *\n * Relative error:\n * arithmetic domain # trials peak rms\n * IEEE -13,0 30000 1.3e-15 2.2e-16\n *\n *\n * ERROR MESSAGES:\n *\n * message condition value returned\n * erfc underflow x > 37.519379347 0.0\n *\n * @param {Number} a\n * @returns {Number}\n */\n ndtr: function(a) {\n // a: double, return double\n var x, y, z;\n\n x = a * this.SQRTH;\n z = Math.abs(x);\n\n if (z < 1.0) {\n y = 0.5 + 0.5 * this.erf(x);\n } else {\n y = 0.5 * this.erfce(z);\n /* Multiply by exp(-x^2 / 2) */\n z = this.expx2(a, -1);\n y = y * Math.sqrt(z);\n if (x > 0) {\n y = 1.0 - y;\n }\n }\n return y;\n },\n\n /**\n * @private\n * @param {Number} a\n * @returns {Number}\n */\n _underflow: function(a) {\n console.log('erfc', 'UNDERFLOW');\n if (a < 0) {\n return 2.0;\n }\n return 0.0;\n },\n\n /**\n *\n *\tComplementary error function\n *\n * SYNOPSIS:\n *\n * double x, y, erfc();\n *\n * y = erfc( x );\n *\n *\n *\n * DESCRIPTION:\n *\n *\n * 1 - erf(x) =\n *\n * inf.\n * -\n * 2 | | 2\n * erfc(x) = -------- | exp( - t ) dt\n * sqrt(pi) | |\n * -\n * x\n *\n *\n * For small x, erfc(x) = 1 - erf(x); otherwise rational\n * approximations are computed.\n *\n * A special function expx2.c is used to suppress error amplification\n * in computing exp(-x^2).\n *\n *\n * ACCURACY:\n *\n * Relative error:\n * arithmetic domain # trials peak rms\n * IEEE 0,26.6417 30000 1.3e-15 2.2e-16\n *\n *\n * ERROR MESSAGES:\n *\n * message condition value returned\n * erfc underflow x > 9.231948545 (DEC) 0.0\n *\n * @param {Number} a\n * @returns {Number}\n */\n erfc: function(a) {\n var p, q, x, y, z;\n\n if (a < 0.0) {\n x = -a;\n } else {\n x = a;\n }\n if (x < 1.0) {\n return 1.0 - this.erf(a);\n }\n\n z = -a * a;\n if (z < -this.MAXLOG) {\n return this._underflow(a);\n }\n\n z = this.expx2(a, -1); // Compute z = exp(z).\n\n if (x < 8.0) {\n p = this.polevl(x, this.P, 8);\n q = this.p1evl(x, this.Q, 8);\n } else {\n p = this.polevl(x, this.R, 5);\n q = this.p1evl(x, this.S, 6);\n }\n\n y = (z * p) / q;\n\n if (a < 0) {\n y = 2.0 - y;\n }\n\n if (y === 0.0) {\n return this._underflow(a);\n }\n\n return y;\n },\n\n /**\n * Exponentially scaled erfc function\n * exp(x^2) erfc(x)\n * valid for x > 1.\n * Use with ndtr and expx2.\n *\n * @private\n * @param {Number} x\n * @returns {Number}\n */\n erfce: function(x) {\n var p, q;\n\n if (x < 8.0) {\n p = this.polevl(x, this.P, 8);\n q = this.p1evl(x, this.Q, 8);\n } else {\n p = this.polevl( x, this.R, 5 );\n q = this.p1evl( x, this.S, 6 );\n }\n return p / q;\n },\n\n /**\n *\tError function\n *\n * SYNOPSIS:\n *\n * double x, y, erf();\n *\n * y = erf( x );\n *\n *\n *\n * DESCRIPTION:\n *\n * The integral is\n *\n * x\n * -\n * 2 | | 2\n * erf(x) = -------- | exp( - t ) dt.\n * sqrt(pi) | |\n * -\n * 0\n *\n * For 0 <= |x| < 1, erf(x) = x * P4(x**2)/Q5(x**2); otherwise\n * erf(x) = 1 - erfc(x).\n *\n *\n * ACCURACY:\n *\n * Relative error:\n * arithmetic domain # trials peak rms\n * DEC 0,1 14000 4.7e-17 1.5e-17\n * IEEE 0,1 30000 3.7e-16 1.0e-16\n *\n * @param {Number} x\n * @returns {Number}\n */\n erf: function(x) {\n var y, z;\n\n if (Math.abs(x) > 1.0) {\n return 1.0 - this.erfc(x);\n }\n z = x * x;\n y = x * this.polevl(z, this.T, 4) / this.p1evl(z, this.U, 5);\n return y;\n },\n\n s2pi: 2.50662827463100050242E0, // sqrt(2pi)\n\n // approximation for 0 <= |y - 0.5| <= 3/8 */\n P0: [\n -5.99633501014107895267E1,\n 9.80010754185999661536E1,\n -5.66762857469070293439E1,\n 1.39312609387279679503E1,\n -1.23916583867381258016E0\n ],\n\n Q0: [\n 1.95448858338141759834E0,\n 4.67627912898881538453E0,\n 8.63602421390890590575E1,\n -2.25462687854119370527E2,\n 2.00260212380060660359E2,\n -8.20372256168333339912E1,\n 1.59056225126211695515E1,\n -1.18331621121330003142E0,\n ],\n\n // Approximation for interval z = sqrt(-2 log y ) between 2 and 8\n // i.e., y between exp(-2) = .135 and exp(-32) = 1.27e-14.\n P1: [\n 4.05544892305962419923E0,\n 3.15251094599893866154E1,\n 5.71628192246421288162E1,\n 4.40805073893200834700E1,\n 1.46849561928858024014E1,\n 2.18663306850790267539E0,\n -1.40256079171354495875E-1,\n -3.50424626827848203418E-2,\n -8.57456785154685413611E-4\n ],\n\n Q1: [\n 1.57799883256466749731E1,\n 4.53907635128879210584E1,\n 4.13172038254672030440E1,\n 1.50425385692907503408E1,\n 2.50464946208309415979E0,\n -1.42182922854787788574E-1,\n -3.80806407691578277194E-2,\n -9.33259480895457427372E-4\n ],\n\n // Approximation for interval z = sqrt(-2 log y ) between 8 and 64\n // i.e., y between exp(-32) = 1.27e-14 and exp(-2048) = 3.67e-890.\n P2: [\n 3.23774891776946035970E0,\n 6.91522889068984211695E0,\n 3.93881025292474443415E0,\n 1.33303460815807542389E0,\n 2.01485389549179081538E-1,\n 1.23716634817820021358E-2,\n 3.01581553508235416007E-4,\n 2.65806974686737550832E-6,\n 6.23974539184983293730E-9\n ],\n\n Q2: [\n 6.02427039364742014255E0,\n 3.67983563856160859403E0,\n 1.37702099489081330271E0,\n 2.16236993594496635890E-1,\n 1.34204006088543189037E-2,\n 3.28014464682127739104E-4,\n 2.89247864745380683936E-6,\n 6.79019408009981274425E-9\n ],\n\n /**\n *\n *\tInverse of Normal distribution function\n *\n * SYNOPSIS:\n *\n * double x, y, ndtri();\n *\n * x = ndtri( y );\n *\n * DESCRIPTION:\n *\n * Returns the argument, x, for which the area under the\n * Gaussian probability density function (integrated from\n * minus infinity to x) is equal to y.\n *\n *\n * For small arguments 0 < y < exp(-2), the program computes\n * z = sqrt( -2.0 * log(y) ); then the approximation is\n * x = z - log(z)/z - (1/z) P(1/z) / Q(1/z).\n * There are two rational functions P/Q, one for 0 < y < exp(-32)\n * and the other for y up to exp(-2). For larger arguments,\n * w = y - 0.5, and x/sqrt(2pi) = w + w**3 R(w**2)/S(w**2)).\n *\n *\n * ACCURACY:\n *\n * Relative error:\n * arithmetic domain # trials peak rms\n * DEC 0.125, 1 5500 9.5e-17 2.1e-17\n * DEC 6e-39, 0.135 3500 5.7e-17 1.3e-17\n * IEEE 0.125, 1 20000 7.2e-16 1.3e-16\n * IEEE 3e-308, 0.135 50000 4.6e-16 9.8e-17\n *\n *\n * ERROR MESSAGES:\n *\n * message condition value returned\n * ndtri domain x <= 0 -MAXNUM\n * ndtri domain x >= 1 MAXNUM\n *\n * @param {Number} y0\n * @returns {Number}\n */\n ndtri: function(y0) {\n var x, y, z, y2, x0, x1, code;\n\n if (y0 <= 0.0) {\n //console.log(\"ndtri\", \"DOMAIN \");\n return -Infinity; // -this.MAXNUM;\n }\n if (y0 >= 1.0) {\n // console.log(\"ndtri\", \"DOMAIN\");\n return Infinity; // this.MAXNUM;\n }\n\n code = 1;\n y = y0;\n if (y > (1.0 - 0.13533528323661269189)) { // 0.135... = exp(-2)\n y = 1.0 - y;\n code = 0;\n }\n\n if (y > 0.13533528323661269189) {\n y = y - 0.5;\n y2 = y * y;\n x = y + y * (y2 * this.polevl(y2, this.P0, 4) / this.p1evl(y2, this.Q0, 8));\n x = x * this.s2pi;\n return x;\n }\n\n x = Math.sqrt( -2.0 * Math.log(y) );\n x0 = x - Math.log(x) / x;\n\n z = 1.0 / x;\n if (x < 8.0) { // y > exp(-32) = 1.2664165549e-14\n x1 = z * this.polevl(z, this.P1, 8 ) / this.p1evl(z, this.Q1, 8);\n } else {\n x1 = z * this.polevl(z, this.P2, 8) / this.p1evl(z, this.Q2, 8);\n }\n x = x0 - x1;\n if (code !== 0) {\n x = -x;\n }\n return x;\n },\n\n /**\n * Inverse of error function erf.\n * \n * @param {Number} x\n * @returns {Number}\n */\n erfi: function(x) {\n return this.ndtri((x + 1) * 0.5) * this.SQRTH;\n }\n };\n\n return Mat.ProbFuncs;\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Alfred Wassermann\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true*/\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n jxg\n math/math\n utils/type\n */\n\ndefine('math/ia',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, Type) {\n\n \"use strict\";\n\n JXG.Math.DoubleBits = function() {\n var hasTypedArrays = false,\n DOUBLE_VIEW = new Float64Array(1),\n UINT_VIEW = new Uint32Array(DOUBLE_VIEW.buffer),\n doubleBitsLE, toDoubleLE, lowUintLE, highUintLE,\n doubleBitsBE, toDoubleBE, lowUintBE, highUintBE,\n doubleBits, toDouble, lowUint, highUint;\n\n if (Float64Array !== undefined) {\n\n DOUBLE_VIEW[0] = 1.0;\n hasTypedArrays = true;\n if (UINT_VIEW[1] === 0x3ff00000) {\n // Use little endian\n doubleBitsLE = function(n) {\n DOUBLE_VIEW[0] = n;\n return [UINT_VIEW[0], UINT_VIEW[1]];\n };\n toDoubleLE = function(lo, hi) {\n UINT_VIEW[0] = lo;\n UINT_VIEW[1] = hi;\n return DOUBLE_VIEW[0];\n };\n\n lowUintLE = function(n) {\n DOUBLE_VIEW[0] = n;\n return UINT_VIEW[0];\n };\n\n highUintLE = function(n) {\n DOUBLE_VIEW[0] = n;\n return UINT_VIEW[1];\n };\n\n this.doubleBits = doubleBitsLE;\n this.pack = toDoubleLE;\n this.lo = lowUintLE;\n this.hi = highUintLE;\n } else if (UINT_VIEW[0] === 0x3ff00000) {\n //Use big endian\n doubleBitsBE = function(n) {\n DOUBLE_VIEW[0] = n;\n return [UINT_VIEW[1], UINT_VIEW[0]];\n };\n\n toDoubleBE = function(lo, hi) {\n UINT_VIEW[1] = lo;\n UINT_VIEW[0] = hi;\n return DOUBLE_VIEW[0];\n };\n\n lowUintBE = function(n) {\n DOUBLE_VIEW[0] = n;\n return UINT_VIEW[1];\n };\n\n highUintBE = function(n) {\n DOUBLE_VIEW[0] = n;\n return UINT_VIEW[0];\n };\n\n this.doubleBits = doubleBitsBE;\n this.pack = toDoubleBE;\n this.lo = lowUintBE;\n this.hi = highUintBE;\n } else {\n hasTypedArrays = false;\n }\n }\n\n // if (!hasTypedArrays) {\n // var buffer = new Buffer(8)\n // doubleBits = function(n) {\n // buffer.writeDoubleLE(n, 0, true);\n // return [buffer.readUInt32LE(0, true), buffer.readUInt32LE(4, true)];\n // };\n\n // toDouble = function(lo, hi) {\n // buffer.writeUInt32LE(lo, 0, true);\n // buffer.writeUInt32LE(hi, 4, true);\n // return buffer.readDoubleLE(0, true);\n // };\n // lowUint = function(n) {\n // buffer.writeDoubleLE(n, 0, true);\n // return buffer.readUInt32LE(0, true);\n // };\n\n // highUint = function(n) {\n // buffer.writeDoubleLE(n, 0, true);\n // return buffer.readUInt32LE(4, true);\n // };\n\n // this.doubleBits = doubleBits;\n // this.pack = toDouble;\n // this.lo = lowUint;\n // this.hi = highUint;\n // }\n };\n\n JXG.extend(JXG.Math.DoubleBits.prototype, /** @lends JXG.Math.DoubleBits.prototype */ {\n\n sign: function(n) {\n return this.hi(n) >>> 31;\n },\n\n exponent: function(n) {\n var b = this.hi(n);\n return ((b<<1) >>> 21) - 1023;\n },\n\n fraction: function(n) {\n var lo = this.lo(n),\n hi = this.hi(n),\n b = hi & ((1<<20) - 1);\n\n if (hi & 0x7ff00000) {\n b += (1<<20);\n }\n return [lo, b];\n },\n\n denormalized: function(n) {\n var hi = this.hi(n);\n return !(hi & 0x7ff00000);\n }\n });\n\n var doubleBits = new JXG.Math.DoubleBits(),\n\n /**\n * Interval for interval arithmetics. Consists of the properties\n * <ul>\n * <li>lo\n * <li>hi\n * </ul>\n * @name JXG.Math.Interval\n * @type Object\n */\n MatInterval = function (lo, hi) {\n if (lo !== undefined && hi !== undefined) {\n // possible cases:\n // - Interval(1, 2)\n // - Interval(Interval(1, 1), Interval(2, 2)) // singletons are required\n if (Mat.IntervalArithmetic.isInterval(lo)) {\n if (!Mat.IntervalArithmetic.isSingleton(lo)) {\n throw new TypeError('JXG.Math.IntervalArithmetic: interval `lo` must be a singleton');\n }\n this.lo = lo.lo;\n } else {\n this.lo = lo;\n }\n if (Mat.IntervalArithmetic.isInterval(hi)) {\n if (!Mat.IntervalArithmetic.isSingleton(hi)) {\n throw new TypeError('JXG.Math.IntervalArithmetic: interval `hi` must be a singleton');\n }\n this.hi = hi.hi;\n } else {\n this.hi = hi;\n }\n } else if (lo !== undefined) {\n // possible cases:\n // - Interval([1, 2])\n // - Interval([Interval(1, 1), Interval(2, 2)])\n if (Array.isArray(lo)) {\n return new MatInterval(lo[0], lo[1]);\n }\n // - Interval(1)\n return new MatInterval(lo, lo);\n } else { // This else is necessary even if jslint declares it as redundant\n // possible cases:\n // - Interval()\n this.lo = this.hi = 0;\n }\n };\n\n JXG.extend(MatInterval.prototype, {\n print: function() {\n console.log('[',this.lo, this.hi,']');\n },\n\n set: function(lo, hi) {\n this.lo = lo;\n this.hi = hi;\n return this;\n },\n\n bounded: function(lo, hi) {\n return this.set(Mat.IntervalArithmetic.prev(lo), Mat.IntervalArithmetic.next(hi));\n },\n\n boundedSingleton: function(v) {\n return this.bounded(v, v);\n },\n\n assign: function(lo, hi) {\n if (typeof lo !== 'number' || typeof hi !== 'number') {\n throw new TypeError('JXG.Math.Interval#assign: arguments must be numbers');\n }\n if (isNaN(lo) || isNaN(hi) || lo > hi) {\n return this.setEmpty();\n }\n return this.set(lo, hi);\n },\n\n setEmpty: function() {\n return this.set(Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY);\n },\n\n setWhole: function() {\n return this.set(Number.NEGATIVE_INFINITY, Number.POSITIVE_INFINITY);\n },\n\n open: function(lo, hi){\n return this.assign(Mat.IntervalArithmetic.next(lo), Mat.IntervalArithmetic.prev(hi));\n },\n\n halfOpenLeft: function(lo, hi) {\n return this.assign(Mat.IntervalArithmetic.next(lo), hi);\n },\n\n halfOpenRight: function(lo, hi) {\n return this.assign(lo, Mat.IntervalArithmetic.prev(hi));\n },\n\n toArray: function() {\n return [this.lo, this.hi];\n },\n\n clone: function() {\n return new MatInterval().set(this.lo, this.hi);\n }\n });\n\n /**\n * Object for interval arithmetics.\n * @name JXG.Math.IntervalArithmetic\n * @namespace\n */\n JXG.Math.IntervalArithmetic = {\n\n Interval: function(lo, hi) {\n return new MatInterval(lo, hi);\n },\n\n isInterval: function(i) {\n return i !== null && typeof i === 'object' && typeof i.lo === 'number' && typeof i.hi === 'number';\n },\n\n isSingleton: function(i) {\n return i.lo === i.hi;\n },\n\n /*\n * Arithmetics\n */\n\n /**\n * Addition\n *\n * @param {JXG.Math.Interval|Number} x\n * @param {JXG.Math.Interval|Number} y\n * @returns JXG.Math.Interval\n */\n add: function(x, y) {\n if (Type.isNumber(x)) {\n x = this.Interval(x);\n }\n if (Type.isNumber(y)) {\n y = this.Interval(y);\n }\n return new MatInterval(this.addLo(x.lo, y.lo), this.addHi(x.hi, y.hi));\n },\n\n /**\n * Subtraction\n *\n * @param {JXG.Math.Interval|Number} x\n * @param {JXG.Math.Interval|Number} y\n * @returns JXG.Math.Interval\n */\n sub: function(x, y) {\n if (Type.isNumber(x)) {\n x = this.Interval(x);\n }\n if (Type.isNumber(y)) {\n y = this.Interval(y);\n }\n return new MatInterval(this.subLo(x.lo, y.hi), this.subHi(x.hi, y.lo));\n },\n\n /**\n * Multiplication\n *\n * @param {JXG.Math.Interval|Number} x\n * @param {JXG.Math.Interval|Number} y\n * @returns JXG.Math.Interval\n */\n mul: function(x, y) {\n var xl, xh, yl, yh, out;\n\n if (Type.isNumber(x)) {\n x = this.Interval(x);\n }\n if (Type.isNumber(y)) {\n y = this.Interval(y);\n }\n\n if (this.isEmpty(x) || this.isEmpty(y)) {\n return this.EMPTY.clone();\n }\n xl = x.lo;\n xh = x.hi;\n yl = y.lo;\n yh = y.hi;\n out = new MatInterval();\n\n if (xl < 0) {\n if (xh > 0) {\n if (yl < 0) {\n if (yh > 0) {\n // mixed * mixed\n out.lo = Math.min(this.mulLo(xl, yh), this.mulLo(xh, yl));\n out.hi = Math.max(this.mulHi(xl, yl), this.mulHi(xh, yh));\n } else {\n // mixed * negative\n out.lo = this.mulLo(xh, yl);\n out.hi = this.mulHi(xl, yl);\n }\n } else {\n if (yh > 0) {\n // mixed * positive\n out.lo = this.mulLo(xl, yh);\n out.hi = this.mulHi(xh, yh);\n } else {\n // mixed * zero\n out.lo = 0;\n out.hi = 0;\n }\n }\n } else {\n if (yl < 0) {\n if (yh > 0) {\n // negative * mixed\n out.lo = this.mulLo(xl, yh);\n out.hi = this.mulHi(xl, yl);\n } else {\n // negative * negative\n out.lo = this.mulLo(xh, yh);\n out.hi = this.mulHi(xl, yl);\n }\n } else {\n if (yh > 0) {\n // negative * positive\n out.lo = this.mulLo(xl, yh);\n out.hi = this.mulHi(xh, yl);\n } else {\n // negative * zero\n out.lo = 0;\n out.hi = 0;\n }\n }\n }\n } else {\n if (xh > 0) {\n if (yl < 0) {\n if (yh > 0) {\n // positive * mixed\n out.lo = this.mulLo(xh, yl);\n out.hi = this.mulHi(xh, yh);\n } else {\n // positive * negative\n out.lo = this.mulLo(xh, yl);\n out.hi = this.mulHi(xl, yh);\n }\n } else {\n if (yh > 0) {\n // positive * positive\n out.lo = this.mulLo(xl, yl);\n out.hi = this.mulHi(xh, yh);\n } else {\n // positive * zero\n out.lo = 0;\n out.hi = 0;\n }\n }\n } else {\n // zero * any other value\n out.lo = 0;\n out.hi = 0;\n }\n }\n return out;\n },\n\n /**\n * Division\n *\n * @param {JXG.Math.Interval|Number} x\n * @param {JXG.Math.Interval|Number} y\n * @returns JXG.Math.Interval\n */\n div: function(x, y) {\n if (Type.isNumber(x)) {\n x = this.Interval(x);\n }\n if (Type.isNumber(y)) {\n y = this.Interval(y);\n }\n\n if (this.isEmpty(x) || this.isEmpty(y)) {\n return this.EMPTY.clone();\n }\n if (this.zeroIn(y)) {\n if (y.lo !== 0) {\n if (y.hi !== 0) {\n return this.divZero(x);\n }\n return this.divNegative(x, y.lo);\n }\n if (y.hi !== 0) {\n return this.divPositive(x, y.hi);\n }\n return this.EMPTY.clone();\n }\n return this.divNonZero(x, y);\n },\n\n /**\n * Return +x (i.e. identity)\n *\n * @param {JXG.Math.Interval} x\n * @returns JXG.Math.Interval\n */\n positive: function(x) {\n return new MatInterval(x.lo, x.hi);\n },\n\n /**\n * Return -x\n *\n * @param {JXG.Math.Interval} x\n * @returns JXG.Math.Interval\n */\n negative: function(x) {\n if (Type.isNumber(x)) {\n return new MatInterval(-x);\n }\n return new MatInterval(-x.hi, -x.lo);\n },\n\n /*\n * Utils\n */\n\n /**\n * Test if interval is empty set.\n * @param {JXG.Math.Interval} i\n * @returns Boolean\n */\n isEmpty: function(i) {\n return i.lo > i.hi;\n },\n\n /**\n * Test if interval is (-Infinity, Infinity).\n * @param {JXG.Math.Interval} i\n * @returns Boolean\n */\n isWhole: function(i){\n return i.lo === -Infinity && i.hi === Infinity;\n },\n\n /**\n * Test if interval contains 0.\n * @param {JXG.Math.Interval} i\n * @returns Boolean\n */\n zeroIn: function(i) {\n return this.hasValue(i, 0);\n },\n\n /**\n * Test if interval contains a specific value.\n * @param {JXG.Math.Interval} i\n * @param {Number} value\n * @returns Boolean\n */\n hasValue: function(i, value) {\n if (this.isEmpty(i)) {\n return false;\n }\n return i.lo <= value && value <= i.hi;\n },\n\n /**\n * Test if interval x contains interval y.\n * @param {JXG.Math.Interval} x\n * @param {JXG.Math.Interval} y\n * @returns Boolean\n */\n hasInterval: function(x, y) {\n if (this.isEmpty(x)) {\n return true;\n }\n return !this.isEmpty(y) && y.lo <= x.lo && x.hi <= y.hi;\n },\n\n /**\n * Test if intervals x and y have non-zero intersection.\n * @param {JXG.Math.Interval} x\n * @param {JXG.Math.Interval} y\n * @returns Boolean\n */\n intervalsOverlap: function(x, y) {\n if (this.isEmpty(x) || this.isEmpty(y)) {\n return false;\n }\n return (x.lo <= y.lo && y.lo <= x.hi) || (y.lo <= x.lo && x.lo <= y.hi);\n },\n\n /*\n * Division\n */\n /**\n * @private\n * @param {JXG.Math.Interval} x\n * @param {JXG.Math.Interval} y\n * @returns JXG.Math.Interval\n */\n divNonZero: function(x, y) {\n var xl = x.lo,\n xh = x.hi,\n yl = y.lo,\n yh = y.hi,\n out = new MatInterval();\n\n if (xh < 0) {\n if (yh < 0) {\n out.lo = this.divLo(xh, yl);\n out.hi = this.divHi(xl, yh);\n } else {\n out.lo = this.divLo(xl, yl);\n out.hi = this.divHi(xh, yh);\n }\n } else if (xl < 0) {\n if (yh < 0) {\n out.lo = this.divLo(xh, yh);\n out.hi = this.divHi(xl, yh);\n } else {\n out.lo = this.divLo(xl, yl);\n out.hi = this.divHi(xh, yl);\n }\n } else {\n if (yh < 0) {\n out.lo = this.divLo(xh, yh);\n out.hi = this.divHi(xl, yl);\n } else {\n out.lo = this.divLo(xl, yh);\n out.hi = this.divHi(xh, yl);\n }\n }\n return out;\n },\n\n /**\n * @private\n * @param {JXG.Math.Interval} x\n * @param {JXG.Math.Interval} y\n * @returns JXG.Math.Interval\n */\n divPositive: function(x, v) {\n if (x.lo === 0 && x.hi === 0) {\n return x;\n }\n\n if (this.zeroIn(x)) {\n // mixed considering zero in both ends\n return this.WHOLE;\n }\n\n if (x.hi < 0) {\n // negative / v\n return new MatInterval(Number.NEGATIVE_INFINITY, this.divHi(x.hi, v));\n }\n // positive / v\n return new MatInterval(this.divLo(x.lo, v), Number.POSITIVE_INFINITY);\n },\n\n /**\n * @private\n * @param {JXG.Math.Interval} x\n * @param {JXG.Math.Interval} y\n * @returns JXG.Math.Interval\n */\n divNegative: function(x, v) {\n if (x.lo === 0 && x.hi === 0) {\n return x;\n }\n\n if (this.zeroIn(x)) {\n // mixed considering zero in both ends\n return this.WHOLE;\n }\n\n if (x.hi < 0) {\n // negative / v\n return new MatInterval(this.divLo(x.hi, v), Number.POSITIVE_INFINITY);\n }\n // positive / v\n return new MatInterval(Number.NEGATIVE_INFINITY, this.divHi(x.lo, v));\n },\n\n /**\n * @private\n * @param {JXG.Math.Interval} x\n * @returns JXG.Math.Interval\n */\n divZero: function(x) {\n if (x.lo === 0 && x.hi === 0) {\n return x;\n }\n return this.WHOLE;\n },\n\n /*\n * Algebra\n */\n /**\n * x mod y: x - n * y\n * @param {JXG.Math.Interval|Number} x\n * @param {JXG.Math.Interval|Number} y\n * @returns JXG.Math.Interval\n */\n fmod: function(x, y) {\n var yb, n;\n if (Type.isNumber(x)) {\n x = this.Interval(x);\n }\n if (Type.isNumber(y)) {\n y = this.Interval(y);\n }\n if (this.isEmpty(x) || this.isEmpty(y)) {\n return this.EMPTY.clone();\n }\n yb = x.lo < 0 ? y.lo : y.hi;\n n = x.lo / yb;\n if (n < 0) {\n n = Math.ceil(n);\n } else {\n n = Math.floor(n);\n }\n // x mod y = x - n * y\n return this.sub(x, this.mul(y, new MatInterval(n)));\n },\n\n /**\n * 1 / x\n * @param {JXG.Math.Interval|Number} x\n * @returns JXG.Math.Interval\n */\n multiplicativeInverse: function(x) {\n if (Type.isNumber(x)) {\n x = this.Interval(x);\n }\n if (this.isEmpty(x)) {\n return this.EMPTY.clone();\n }\n if (this.zeroIn(x)) {\n if (x.lo !== 0) {\n if (x.hi !== 0) {\n // [negative, positive]\n return this.WHOLE;\n }\n // [negative, zero]\n return new MatInterval(Number.NEGATIVE_INFINITY, this.divHi(1, x.lo));\n }\n if (x.hi !== 0) {\n // [zero, positive]\n return new MatInterval(this.divLo(1, x.hi), Number.POSITIVE_INFINITY);\n }\n // [zero, zero]\n return this.EMPTY.clone();\n }\n // [positive, positive]\n return new MatInterval(this.divLo(1, x.hi), this.divHi(1, x.lo));\n },\n\n /**\n * x<sup>power</sup>\n * @param {JXG.Math.Interval|Number} x\n * @param {JXG.Math.Interval|Number} power\n * @returns JXG.Math.Interval\n */\n pow: function(x, power) {\n var yl, yh;\n\n if (Type.isNumber(x)) {\n x = this.Interval(x);\n }\n if (this.isEmpty(x)) {\n return this.EMPTY.clone();\n }\n if (this.isInterval(power)) {\n if (!this.isSingleton(power)) {\n return this.EMPTY.clone();\n }\n power = power.lo;\n }\n\n if (power === 0) {\n if (x.lo === 0 && x.hi === 0) {\n // 0^0\n return this.EMPTY.clone();\n }\n // x^0\n return this.ONE.clone();\n }\n if (power < 0) {\n // compute [1 / x]^-power if power is negative\n return this.pow(this.multiplicativeInverse(x), -power);\n }\n\n // power > 0\n if (power % 1 === 0) { // isSafeInteger(power) as boolean) {\n // power is integer\n if (x.hi < 0) {\n // [negative, negative]\n // assume that power is even so the operation will yield a positive interval\n // if not then just switch the sign and order of the interval bounds\n yl = this.powLo(-x.hi, power);\n yh = this.powHi(-x.lo, power);\n if ((power & 1) === 1) {\n // odd power\n return new MatInterval(-yh, -yl);\n }\n // even power\n return new MatInterval(yl, yh);\n }\n if (x.lo < 0) {\n // [negative, positive]\n if ((power & 1) === 1) {\n return new MatInterval(-this.powLo(-x.lo, power), this.powHi(x.hi, power));\n }\n // even power means that any negative number will be zero (min value = 0)\n // and the max value will be the max of x.lo^power, x.hi^power\n return new MatInterval(0, this.powHi(Math.max(-x.lo, x.hi), power));\n }\n // [positive, positive]\n return new MatInterval(this.powLo(x.lo, power), this.powHi(x.hi, power));\n }\n console.warn('power is not an integer, you should use nth-root instead, returning an empty interval');\n return this.EMPTY.clone();\n },\n\n /**\n * sqrt(x)\n * @param {JXG.Math.Interval|Number} x\n * @returns JXG.Math.Interval\n */\n sqrt: function(x) {\n if (Type.isNumber(x)) {\n x = this.Interval(x);\n }\n return this.nthRoot(x, 2);\n },\n\n /**\n * x<sup>1/n</sup>\n * @param {JXG.Math.Interval|Number} x\n * @param {Number} n\n * @returns JXG.Math.Interval\n */\n nthRoot: function(x, n) {\n var power,yl, yh, yp, yn;\n\n if (Type.isNumber(x)) {\n x = this.Interval(x);\n }\n if (this.isEmpty(x) || n < 0) {\n // compute 1 / x^-power if power is negative\n return this.EMPTY.clone();\n }\n\n // singleton interval check\n if (this.isInterval(n)) {\n if (!this.isSingleton(n)) {\n return this.EMPTY.clone();\n }\n n = n.lo;\n }\n\n power = 1 / n;\n if (x.hi < 0) {\n // [negative, negative]\n //if ((isSafeInteger(n) as boolean) && (n & 1) === 1) {\n if (n % 1 === 0 && (n & 1) === 1) {\n // when n is odd we can always take the nth root\n yl = this.powHi(-x.lo, power);\n yh = this.powLo(-x.hi, power);\n return new MatInterval(-yl, -yh);\n }\n\n // n is not odd therefore there's no nth root\n return this.EMPTY.clone();\n }\n if (x.lo < 0) {\n // [negative, positive]\n yp = this.powHi(x.hi, power);\n // if ((isSafeInteger(n) as boolean) && (n & 1) === 1) {\n if (n % 1 === 0 && (n & 1) === 1) {\n // nth root of x.lo is possible (n is odd)\n yn = -this.powHi(-x.lo, power);\n return new MatInterval(yn, yp);\n }\n return new MatInterval(0, yp);\n }\n // [positive, positive]\n return new MatInterval(this.powLo(x.lo, power), this.powHi(x.hi, power));\n },\n\n /*\n * Misc\n */\n /**\n *\n * @param {JXG.Math.Interval|Number} x\n * @returns JXG.Math.Interval\n */\n exp: function(x) {\n if (Type.isNumber(x)) {\n x = this.Interval(x);\n }\n if (this.isEmpty(x)) {\n return this.EMPTY.clone();\n }\n return new MatInterval(this.expLo(x.lo), this.expHi(x.hi));\n },\n\n /**\n * Natural log\n * @param {JXG.Math.Interval|Number} x\n * @returns JXG.Math.Interval\n */\n log: function(x) {\n var l;\n if (Type.isNumber(x)) {\n x = this.Interval(x);\n }\n if (this.isEmpty(x)) {\n return this.EMPTY.clone();\n }\n l = x.lo <= 0 ? Number.NEGATIVE_INFINITY : this.logLo(x.lo);\n return new MatInterval(l, this.logHi(x.hi));\n },\n\n /**\n * Natural log, alias for {@link JXG.Math.IntervalArithmetic#log}.\n * @param {JXG.Math.Interval|Number} x\n * @returns JXG.Math.Interval\n */\n ln: function(x) {\n return this.log(x);\n },\n\n // export const LOG_EXP_10 = this.log(new MatInterval(10, 10))\n // export const LOG_EXP_2 = log(new MatInterval(2, 2))\n /**\n * Logarithm to base 10.\n * @param {JXG.Math.Interval|Number} x\n * @returns JXG.Math.Interval\n */\n log10: function(x) {\n if (this.isEmpty(x)) {\n return this.EMPTY.clone();\n }\n return this.div(this.log(x), this.log(new MatInterval(10, 10)));\n },\n\n /**\n * Logarithm to base 2.\n * @param {JXG.Math.Interval|Number} x\n * @returns JXG.Math.Interval\n */\n log2: function(x) {\n if (this.isEmpty(x)) {\n return this.EMPTY.clone();\n }\n return this.div(this.log(x), this.log(new MatInterval(2, 2)));\n },\n\n /**\n * Hull of intervals x and y\n * @param {JXG.Math.Interval} x\n * @param {JXG.Math.Interval} y\n * @returns JXG.Math.Interval\n */\n hull: function(x, y) {\n var badX = this.isEmpty(x),\n badY = this.isEmpty(y);\n if (badX && badY) {\n return this.EMPTY.clone();\n }\n if (badX) {\n return y.clone();\n }\n if (badY) {\n return x.clone();\n }\n return new MatInterval(Math.min(x.lo, y.lo), Math.max(x.hi, y.hi));\n },\n\n /**\n * Intersection of intervals x and y\n * @param {JXG.Math.Interval} x\n * @param {JXG.Math.Interval} y\n * @returns JXG.Math.Interval\n */\n intersection: function(x, y) {\n var lo, hi;\n if (this.isEmpty(x) || this.isEmpty(y)) {\n return this.EMPTY.clone();\n }\n lo = Math.max(x.lo, y.lo);\n hi = Math.min(x.hi, y.hi);\n if (lo <= hi) {\n return new MatInterval(lo, hi);\n }\n return this.EMPTY.clone();\n },\n\n /**\n * Union of overlapping intervals x and y\n * @param {JXG.Math.Interval} x\n * @param {JXG.Math.Interval} y\n * @returns JXG.Math.Interval\n */\n union: function(x, y) {\n if (!this.intervalsOverlap(x, y)) {\n throw new Error('Interval#unions do not overlap');\n }\n return new MatInterval(Math.min(x.lo, y.lo), Math.max(x.hi, y.hi));\n },\n\n /**\n * Difference of overlapping intervals x and y\n * @param {JXG.Math.Interval} x\n * @param {JXG.Math.Interval} y\n * @returns JXG.Math.Interval\n */\n difference: function(x, y) {\n if (this.isEmpty(x) || this.isWhole(y)) {\n return this.EMPTY.clone();\n }\n if (this.intervalsOverlap(x, y)) {\n if (x.lo < y.lo && y.hi < x.hi) {\n // difference creates multiple subsets\n throw new Error('Interval.difference: difference creates multiple intervals');\n }\n\n // handle corner cases first\n if ((y.lo <= x.lo && y.hi === Infinity) || (y.hi >= x.hi && y.lo === -Infinity)) {\n return this.EMPTY.clone();\n }\n\n // NOTE: empty interval is handled automatically\n // e.g.\n //\n // n = difference([0,1], [0,1]) // n = Interval(next(1), 1) = EMPTY\n // isEmpty(n) === true\n //\n if (y.lo <= x.lo) {\n return new MatInterval().halfOpenLeft(y.hi, x.hi);\n }\n\n // y.hi >= x.hi\n return new MatInterval().halfOpenRight(x.lo, y.lo);\n }\n return x.clone();\n },\n\n /**\n * @param {JXG.Math.Interval} x\n * @returns JXG.Math.Interval\n */\n width: function(x) {\n if (this.isEmpty(x)) {\n return 0;\n }\n return this.subHi(x.hi, x.lo);\n },\n\n /**\n * @param {JXG.Math.Interval} x\n * @returns JXG.Math.Interval\n */\n abs: function(x) {\n if (Type.isNumber(x)) {\n x = this.Interval(x);\n }\n if (this.isEmpty(x)) {\n return this.EMPTY.clone();\n }\n if (x.lo >= 0) {\n return x.clone();\n }\n if (x.hi <= 0) {\n return this.negative(x);\n }\n return new MatInterval(0, Math.max(-x.lo, x.hi));\n },\n\n /**\n * @param {JXG.Math.Interval} x\n * @param {JXG.Math.Interval} y\n * @returns JXG.Math.Interval\n */\n max: function(x, y) {\n var badX = this.isEmpty(x),\n badY = this.isEmpty(y);\n if (badX && badY) {\n return this.EMPTY.clone();\n }\n if (badX) {\n return y.clone();\n }\n if (badY) {\n return x.clone();\n }\n return new MatInterval(Math.max(x.lo, y.lo), Math.max(x.hi, y.hi));\n },\n\n /**\n * @param {JXG.Math.Interval} x\n * @param {JXG.Math.Interval} y\n * @returns JXG.Math.Interval\n */\n min: function(x, y) {\n var badX = this.isEmpty(x),\n badY = this.isEmpty(y);\n if (badX && badY) {\n return this.EMPTY.clone();\n }\n if (badX) {\n return y.clone();\n }\n if (badY) {\n return x.clone();\n }\n return new MatInterval(Math.min(x.lo, y.lo), Math.min(x.hi, y.hi));\n },\n\n /*\n * Trigonometric\n */\n onlyInfinity: function(x) {\n return !isFinite(x.lo) && x.lo === x.hi;\n },\n\n _handleNegative: function(interval) {\n var n;\n if (interval.lo < 0) {\n if (interval.lo === -Infinity) {\n interval.lo = 0;\n interval.hi = Infinity;\n } else {\n n = Math.ceil(-interval.lo / this.piTwiceLow);\n interval.lo += this.piTwiceLow * n;\n interval.hi += this.piTwiceLow * n;\n }\n }\n return interval;\n },\n\n /**\n * @param {JXG.Math.Interval} x\n * @returns JXG.Math.Interval\n */\n cos: function(x) {\n var cache, pi2, t, cosv,\n lo, hi, rlo, rhi;\n\n if (this.isEmpty(x) || this.onlyInfinity(x)) {\n return this.EMPTY.clone();\n }\n\n // create a clone of `x` because the clone is going to be modified\n cache = new MatInterval().set(x.lo, x.hi);\n this._handleNegative(cache);\n\n pi2 = this.PI_TWICE;\n t = this.fmod(cache, pi2);\n if (this.width(t) >= pi2.lo) {\n return new MatInterval(-1, 1);\n }\n\n // when t.lo > pi it's the same as\n // -cos(t - pi)\n if (t.lo >= this.piHigh) {\n cosv = this.cos(this.sub(t, this.PI));\n return this.negative(cosv);\n }\n\n lo = t.lo;\n hi = t.hi;\n rlo = this.cosLo(hi);\n rhi = this.cosHi(lo);\n // it's ensured that t.lo < pi and that t.lo >= 0\n if (hi <= this.piLow) {\n // when t.hi < pi\n // [cos(t.lo), cos(t.hi)]\n return new MatInterval(rlo, rhi);\n }\n if (hi <= pi2.lo) {\n // when t.hi < 2pi\n // [-1, max(cos(t.lo), cos(t.hi))]\n return new MatInterval(-1, Math.max(rlo, rhi));\n }\n // t.lo < pi and t.hi > 2pi\n return new MatInterval(-1, 1);\n },\n\n /**\n * @param {JXG.Math.Interval} x\n * @returns JXG.Math.Interval\n */\n sin: function(x) {\n if (this.isEmpty(x) || this.onlyInfinity(x)) {\n return this.EMPTY.clone();\n }\n return this.cos(this.sub(x, this.PI_HALF));\n },\n\n /**\n * @param {JXG.Math.Interval} x\n * @returns JXG.Math.Interval\n */\n tan: function(x) {\n var cache, t, pi;\n if (this.isEmpty(x) || this.onlyInfinity(x)) {\n return this.EMPTY.clone();\n }\n\n // create a clone of `x` because the clone is going to be modified\n cache = new MatInterval().set(x.lo, x.hi);\n this._handleNegative(cache);\n\n pi = this.PI;\n t = this.fmod(cache, pi);\n if (t.lo >= this.piHalfLow) {\n t = this.sub(t, pi);\n }\n if (t.lo <= -this.piHalfLow || t.hi >= this.piHalfLow) {\n return this.WHOLE.clone();\n }\n return new MatInterval(this.tanLo(t.lo), this.tanHi(t.hi));\n },\n\n /**\n * @param {JXG.Math.Interval} x\n * @returns JXG.Math.Interval\n */\n asin: function(x) {\n var lo, hi;\n if (this.isEmpty(x) || x.hi < -1 || x.lo > 1) {\n return this.EMPTY.clone();\n }\n lo = x.lo <= -1 ? -this.piHalfHigh : this.asinLo(x.lo);\n hi = x.hi >= 1 ? this.piHalfHigh : this.asinHi(x.hi);\n return new MatInterval(lo, hi);\n },\n\n /**\n * @param {JXG.Math.Interval} x\n * @returns JXG.Math.Interval\n */\n acos: function(x) {\n var lo, hi;\n if (this.isEmpty(x) || x.hi < -1 || x.lo > 1) {\n return this.EMPTY.clone();\n }\n lo = x.hi >= 1 ? 0 : this.acosLo(x.hi);\n hi = x.lo <= -1 ? this.piHigh : this.acosHi(x.lo);\n return new MatInterval(lo, hi);\n },\n\n /**\n * @param {JXG.Math.Interval} x\n * @returns JXG.Math.Interval\n */\n atan: function(x) {\n if (this.isEmpty(x)) {\n return this.EMPTY.clone();\n }\n return new MatInterval(this.atanLo(x.lo), this.atanHi(x.hi));\n },\n\n /**\n * @param {JXG.Math.Interval} x\n * @returns JXG.Math.Interval\n */\n sinh: function(x) {\n if (this.isEmpty(x)) {\n return this.EMPTY.clone();\n }\n return new MatInterval(this.sinhLo(x.lo), this.sinhHi(x.hi));\n },\n\n /**\n * @param {JXG.Math.Interval} x\n * @returns JXG.Math.Interval\n */\n cosh: function(x) {\n if (this.isEmpty(x)) {\n return this.EMPTY.clone();\n }\n if (x.hi < 0) {\n return new MatInterval(this.coshLo(x.hi), this.coshHi(x.lo));\n }\n if (x.lo >= 0) {\n return new MatInterval(this.coshLo(x.lo), this.coshHi(x.hi));\n }\n return new MatInterval(1, this.coshHi(-x.lo > x.hi ? x.lo : x.hi));\n },\n\n /**\n * @param {JXG.Math.Interval} x\n * @returns JXG.Math.Interval\n */\n tanh: function(x) {\n if (this.isEmpty(x)) {\n return this.EMPTY.clone();\n }\n return new MatInterval(this.tanhLo(x.lo), this.tanhHi(x.hi));\n },\n\n /*\n * Relational\n */\n\n /**\n * @param {JXG.Math.Interval} x\n * @param {JXG.Math.Interval} y\n * @returns Boolean\n */\n equal: function(x, y) {\n if (this.isEmpty(x)) {\n return this.isEmpty(y);\n }\n return !this.isEmpty(y) && x.lo === y.lo && x.hi === y.hi;\n },\n\n // almostEqual: function(x, y): void {\n // x = Array.isArray(x) ? x : x.toArray();\n // y = Array.isArray(y) ? y : y.toArray();\n // assertEps(x[0], y[0])\n // assertEps(x[1], y[1])\n // },\n\n /**\n * @param {JXG.Math.Interval} x\n * @param {JXG.Math.Interval} y\n * @returns Boolean\n */\n notEqual: function(x, y) {\n if (this.isEmpty(x)) {\n return !this.isEmpty(y);\n }\n return this.isEmpty(y) || x.hi < y.lo || x.lo > y.hi;\n },\n\n /**\n * @param {JXG.Math.Interval} x\n * @param {JXG.Math.Interval} y\n * @returns Boolean\n */\n lt: function(x, y) {\n if (Type.isNumber(x)) {\n x = this.Interval(x);\n }\n if (Type.isNumber(y)) {\n y = this.Interval(y);\n }\n if (this.isEmpty(x) || this.isEmpty(y)) {\n return false;\n }\n return x.hi < y.lo;\n },\n\n /**\n * @param {JXG.Math.Interval} x\n * @param {JXG.Math.Interval} y\n * @returns Boolean\n */\n gt: function(x, y) {\n if (Type.isNumber(x)) {\n x = this.Interval(x);\n }\n if (Type.isNumber(y)) {\n y = this.Interval(y);\n }\n if (this.isEmpty(x) || this.isEmpty(y)) {\n return false;\n }\n return x.lo > y.hi;\n },\n\n /**\n * @param {JXG.Math.Interval} x\n * @param {JXG.Math.Interval} y\n * @returns Boolean\n */\n leq: function(x, y) {\n if (Type.isNumber(x)) {\n x = this.Interval(x);\n }\n if (Type.isNumber(y)) {\n y = this.Interval(y);\n }\n if (this.isEmpty(x) || this.isEmpty(y)) {\n return false;\n }\n return x.hi <= y.lo;\n },\n\n /**\n * @param {JXG.Math.Interval} x\n * @param {JXG.Math.Interval} y\n * @returns Boolean\n */\n geq: function(x, y) {\n if (Type.isNumber(x)) {\n x = this.Interval(x);\n }\n if (Type.isNumber(y)) {\n y = this.Interval(y);\n }\n if (this.isEmpty(x) || this.isEmpty(y)) {\n return false;\n }\n return x.lo >= y.hi;\n },\n\n /*\n * Constants\n */\n piLow: (3373259426.0 + 273688.0 / (1 << 21)) / (1 << 30),\n piHigh: (3373259426.0 + 273689.0 / (1 << 21)) / (1 << 30),\n piHalfLow: (3373259426.0 + 273688.0 / (1 << 21)) / (1 << 30) * 0.5,\n piHalfHigh: (3373259426.0 + 273689.0 / (1 << 21)) / (1 << 30) * 0.5,\n piTwiceLow: (3373259426.0 + 273688.0 / (1 << 21)) / (1 << 30) * 2,\n piTwiceHigh: (3373259426.0 + 273689.0 / (1 << 21)) / (1 << 30) * 2,\n\n /*\n * Round\n * Rounding functions for numbers\n */\n identity: function(v) {\n return v;\n },\n\n _prev: function(v) {\n if (v === Infinity) {\n return v;\n }\n return this.nextafter(v, -Infinity);\n },\n\n _next: function(v) {\n if (v === -Infinity) {\n return v;\n }\n return this.nextafter(v, Infinity);\n },\n\n prev: function(v) {\n return this._prev(v);\n },\n\n next: function(v) {\n return this._next(v);\n },\n\n toInteger: function(x) {\n return x < 0 ? Math.ceil(x) : Math.floor(x);\n },\n\n addLo: function(x, y) { return this.prev(x + y); },\n addHi: function(x, y) { return this.next(x + y); },\n subLo: function(x, y) { return this.prev(x - y); },\n subHi: function(x, y) { return this.next(x - y); },\n mulLo: function(x, y) { return this.prev(x * y); },\n mulHi: function(x, y) { return this.next(x * y); },\n divLo: function(x, y) { return this.prev(x / y); },\n divHi: function(x, y) { return this.next(x / y); },\n intLo: function(x) { return this.toInteger(this.prev(x)); },\n intHi: function(x) { return this.toInteger(this.next(x)); },\n logLo: function(x) { return this.prev(Math.log(x)); },\n logHi: function(x) { return this.next(Math.log(x)); },\n expLo: function(x) { return this.prev(Math.exp(x)); },\n expHi: function(x) { return this.next(Math.exp(x)); },\n sinLo: function(x) { return this.prev(Math.sin(x)); },\n sinHi: function(x) { return this.next(Math.sin(x)); },\n cosLo: function(x) { return this.prev(Math.cos(x)); },\n cosHi: function(x) { return this.next(Math.cos(x)); },\n tanLo: function(x) { return this.prev(Math.tan(x)); },\n tanHi: function(x) { return this.next(Math.tan(x)); },\n asinLo: function(x) { return this.prev(Math.asin(x)); },\n asinHi: function(x) { return this.next(Math.asin(x)); },\n acosLo: function(x) { return this.prev(Math.acos(x)); },\n acosHi: function(x) { return this.next(Math.acos(x)); },\n atanLo: function(x) { return this.prev(Math.atan(x)); },\n atanHi: function(x) { return this.next(Math.atan(x)); },\n sinhLo: function(x) { return this.prev(Mat.sinh(x)); },\n sinhHi: function(x) { return this.next(Mat.sinh(x)); },\n coshLo: function(x) { return this.prev(Mat.cosh(x)); },\n coshHi: function(x) { return this.next(Mat.cosh(x)); },\n tanhLo: function(x) { return this.prev(Mat.tanh(x)); },\n tanhHi: function(x) { return this.next(Mat.tanh(x)); },\n sqrtLo: function(x) { return this.prev(Math.sqrt(x)); },\n sqrtHi: function(x) { return this.next(Math.sqrt(x)); },\n\n powLo: function(x, power) {\n var y;\n if (power % 1 !== 0) {\n // power has decimals\n return this.prev(Math.pow(x, power));\n }\n\n y = (power & 1) === 1 ? x : 1;\n power >>= 1;\n while (power > 0) {\n x = this.mulLo(x, x);\n if ((power & 1) === 1) {\n y = this.mulLo(x, y);\n }\n power >>= 1;\n }\n return y;\n },\n\n powHi: function(x, power) {\n var y;\n if (power % 1 !== 0) {\n // power has decimals\n return this.next(Math.pow(x, power));\n }\n\n y = (power & 1) === 1 ? x : 1;\n power >>= 1;\n while (power > 0) {\n x = this.mulHi(x, x);\n if ((power & 1) === 1) {\n y = this.mulHi(x, y);\n }\n power >>= 1;\n }\n return y;\n },\n\n /**\n * @ignore\n * @private\n */\n disable: function() {\n this.next = this.prev = this.identity;\n },\n\n /**\n * @ignore\n * @private\n */\n enable: function() {\n this.prev = function(v) {\n return this._prev(v);\n };\n\n this.next = function(v) {\n return this._next(v);\n };\n },\n\n\n /*\n * nextafter\n */\n SMALLEST_DENORM: Math.pow(2, -1074),\n UINT_MAX: (-1)>>>0,\n\n nextafter: function(x, y) {\n var lo, hi;\n\n if (isNaN(x) || isNaN(y)) {\n return NaN;\n }\n if (x === y) {\n return x;\n }\n if (x === 0) {\n if (y < 0) {\n return -this.SMALLEST_DENORM;\n }\n return this.SMALLEST_DENORM;\n }\n hi = doubleBits.hi(x);\n lo = doubleBits.lo(x);\n if ((y > x) === (x > 0)) {\n if (lo === this.UINT_MAX) {\n hi += 1;\n lo = 0;\n } else {\n lo += 1;\n }\n } else {\n if (lo === 0) {\n lo = this.UINT_MAX;\n hi -= 1;\n } else {\n lo -= 1;\n }\n }\n return doubleBits.pack(lo, hi);\n }\n\n };\n\n JXG.Math.IntervalArithmetic.PI = new MatInterval(Mat.IntervalArithmetic.piLow, Mat.IntervalArithmetic.piHigh);\n JXG.Math.IntervalArithmetic.PI_HALF = new MatInterval(Mat.IntervalArithmetic.piHalfLow, Mat.IntervalArithmetic.piHalfHigh);\n JXG.Math.IntervalArithmetic.PI_TWICE = new MatInterval(Mat.IntervalArithmetic.piTwiceLow, Mat.IntervalArithmetic.piTwiceHigh);\n JXG.Math.IntervalArithmetic.ZERO = new MatInterval(0);\n JXG.Math.IntervalArithmetic.ONE = new MatInterval(1);\n JXG.Math.IntervalArithmetic.WHOLE = new MatInterval().setWhole();\n JXG.Math.IntervalArithmetic.EMPTY = new MatInterval().setEmpty();\n\n return JXG.Math.IntervalArithmetic;\n});\n\n\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Alfred Wassermann\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true*/\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n jxg\n math/math\n utils/type\n */\n\ndefine('math/extrapolate',['math/math'], function (Mat) {\n\n \"use strict\";\n\n /**\n * Functions for extrapolation of sequences. Used for finding limits of sequences which is used for curve plotting.\n * @name JXG.Math.Extrapolate\n * @exports Mat.Extrapolate as JXG.Math.Extrapolate\n * @namespace\n */\n Mat.Extrapolate = {\n upper: 15,\n infty: 1.e+4,\n\n /**\n * Wynn's epsilon algorithm. Ported from the FORTRAN version in\n * Ernst Joachim Weniger, \"Nonlinear sequence transformations for the acceleration of convergence\n * and the summation of divergent series\", Computer Physics Reports Vol. 10, 189-371 (1989).\n *\n * @param {Number} s_n next value of sequence, i.e. n-th element of sequence\n * @param {Number} n index of s_n in the sequence\n * @param {Array} e One-dimensional array containing the extrapolation data. Has to be supplied by the calling routine.\n * @returns {Number} New estimate of the limit of the sequence.\n *\n * @memberof JXG.Math.Extrapolate\n */\n wynnEps: function(s_n, n, e) {\n var HUGE = 1.e+20,\n TINY = 1.e-15,\n f0 = 1, // f0 may be changed to other values, see vanden Broeck, Schwartz (1979)\n f, j, aux1, aux2, diff, estlim;\n\n e[n] = s_n;\n if (n === 0) {\n estlim = s_n;\n } else {\n aux2 = 0.0;\n for (j = n; j > 0; j--) {\n aux1 = aux2;\n aux2 = e[j - 1];\n diff = e[j] - aux2;\n if (Math.abs(diff) <= TINY) {\n e[j - 1] = HUGE;\n } else {\n f = ((n - j + 1) % 2 === 1) ? f0 : 1;\n e[j - 1] = aux1 * f + 1 / diff;\n }\n }\n estlim = e[n % 2];\n }\n\n return estlim;\n },\n\n // wynnRho: function(s_n, n, e) {\n // var HUGE = 1.e+20,\n // TINY = 1.e-15,\n // j, f,\n // aux1, aux2, diff, estlim;\n\n // e[n] = s_n;\n // if (n === 0) {\n // estlim = s_n;\n // } else {\n // aux2 = 0.0;\n // for (j = n; j >= 1; j--) {\n // aux1 = aux2;\n // aux2 = e[j - 1];\n // diff = e[j] - aux2;\n // if (Math.abs(diff) <= TINY) {\n // e[j - 1] = HUGE;\n // } else {\n // f = ((n - j + 1) % 2 === 1) ? n - j + 1 : 1;\n // e[j - 1] = aux1 + f / diff;\n // }\n // }\n // estlim = e[n % 2];\n // }\n\n // return estlim;\n // },\n\n /**\n * Aitken transformation. Ported from the FORTRAN version in\n * Ernst Joachim Weniger, \"Nonlinear sequence transformations for the acceleration of convergence\n * and the summation of divergent series\", Computer Physics Reports Vol. 10, 189-371 (1989).\n *\n * @param {Number} s_n next value of sequence, i.e. n-th element of sequence\n * @param {Number} n index of s_n in the sequence\n * @param {Array} a One-dimensional array containing the extrapolation data. Has to be supplied by the calling routine.\n * @returns {Number} New estimate of the limit of the sequence.\n *\n * @memberof JXG.Math.Extrapolate\n */\n aitken: function(s_n, n, a) {\n var estlim,\n HUGE = 1.e+20,\n TINY = 1.e-15,\n denom, v,\n lowmax, j, m;\n\n a[n] = s_n;\n if (n < 2) {\n estlim = s_n;\n } else {\n lowmax = n / 2;\n for (j = 1; j <= lowmax; j++) {\n m = n - 2 * j;\n denom = a[m + 2] - 2 * a[m + 1] + a[m];\n if (Math.abs(denom) < TINY) {\n a[m] = HUGE;\n } else {\n v = a[m] - a[m + 1];\n a[m] -= v * v / denom;\n }\n }\n estlim = a[n % 2];\n }\n return estlim;\n },\n\n /**\n * Iterated Brezinski transformation. Ported from the FORTRAN version in\n * Ernst Joachim Weniger, \"Nonlinear sequence transformations for the acceleration of convergence\n * and the summation of divergent series\", Computer Physics Reports Vol. 10, 189-371 (1989).\n *\n * @param {Number} s_n next value of sequence, i.e. n-th element of sequence\n * @param {Number} n index of s_n in the sequence\n * @param {Array} a One-dimensional array containing the extrapolation data. Has to be supplied by the calling routine.\n * @returns {Number} New estimate of the limit of the sequence.\n *\n * @memberof JXG.Math.Extrapolate\n */\n brezinski: function(s_n, n, a) {\n var estlim,\n HUGE = 1.e+20,\n TINY = 1.e-15,\n denom,\n d0, d1, d2,\n lowmax, j, m;\n\n a[n] = s_n;\n if (n < 3) {\n estlim = s_n;\n } else {\n lowmax = n / 3;\n m = n;\n for (j = 1; j <= lowmax; j++) {\n m -= 3;\n d0 = a[m + 1] - a[m];\n d1 = a[m + 2] - a[m + 1];\n d2 = a[m + 3] - a[m + 2];\n denom = d2 * (d1 - d0) - d0 * (d2 - d1);\n if (Math.abs(denom) < TINY) {\n a[m] = HUGE;\n } else {\n a[m] = a[m + 1] - d0 * d1 * (d2 - d1) / denom;\n }\n }\n estlim = a[n % 3];\n }\n return estlim;\n },\n\n /**\n * Extrapolated iteration to approximate the value f(x_0).\n *\n * @param {Number} x0 Value for which the limit of f is to be determined. f(x0) may or may not exist.\n * @param {Number} h0 Initial (signed) distance from x0.\n * @param {Function} f Function for which the limit at x0 is to be determined\n * @param {String} method String to choose the method. Available values: \"wynnEps\", \"aitken\", \"brezinski\"\n * @param {Number} step_type Approximation method. step_type = 0 uses the sequence x0 + h0/n; step_type = 1 uses the sequence x0 + h0 * 2^(-n)\n *\n * @returns {Array} Array of length 3. Position 0: estimated value for f(x0), position 1: 'finite', 'infinite', or 'NaN'.\n * Position 2: value between 0 and 1 judging the reliability of the result (1: high, 0: not successful).\n *\n * @memberof JXG.Math.Extrapolate\n * @see JXG.Math.Extrapolate.limit\n * @see JXG.Math.Extrapolate.wynnEps\n * @see JXG.Math.Extrapolate.aitken\n * @see JXG.Math.Extrapolate.brezinski\n */\n iteration: function(x0, h0, f, method, step_type) {\n var n, v, w,\n estlim = NaN,\n diff,\n r = 0.5,\n E = [],\n result = 'finite',\n h = h0;\n\n step_type = step_type || 0;\n\n for (n = 1; n <= this.upper; n++) {\n h = (step_type === 0) ? h0 / (n + 1) : h * r;\n v = f(x0 + h, true);\n\n w = this[method](v, n - 1, E);\n//console.log(n, x0 + h, v, w);\n if (isNaN(w)) {\n result = 'NaN';\n break;\n }\n if (v !== 0 && w / v > this.infty) {\n estlim = w;\n result = 'infinite';\n break;\n }\n diff = w - estlim;\n if (Math.abs(diff) < 1.e-7) {\n break;\n }\n estlim = w;\n }\n return [estlim, result, 1 - (n - 1) / this.upper];\n },\n\n /**\n * Levin transformation. See Numerical Recipes, ed. 3.\n * Not yet ready for use.\n *\n * @param {Number} s_n next value of sequence, i.e. n-th element of sequence\n * @param {Number} n index of s_n in the sequence\n * @param {Array} numer One-dimensional array containing the extrapolation data for the numerator. Has to be supplied by the calling routine.\n * @param {Array} denom One-dimensional array containing the extrapolation data for the denominator. Has to be supplied by the calling routine.\n *\n * @memberof JXG.Math.Extrapolate\n */\n levin: function(s_n, n, omega, beta, numer, denom) {\n var HUGE = 1.e+20,\n TINY = 1.e-15,\n j,\n fact, ratio, term, estlim;\n\n term = 1.0 / (beta + n);\n numer[n] = s_n / omega;\n denom[n] = 1 / omega;\n if (n > 0) {\n numer[n - 1] = numer[n] - numer[n - 1];\n denom[n - 1] = denom[n] - denom[n - 1];\n if (n > 1) {\n ratio = (beta + n - 1) * term;\n for (j = 2; j <= n; j++) {\n fact = (beta + n - j) * Math.pow(ratio, j - 2) * term;\n numer[n - j] = numer[n - j + 1] - fact * numer[n - j];\n denom[n - j] = denom[n - j + 1] - fact * denom[n - j];\n term *= ratio;\n }\n }\n }\n if (Math.abs(denom[0]) < TINY) {\n estlim = HUGE;\n } else {\n estlim = numer[0] / denom[0];\n }\n return estlim;\n },\n\n iteration_levin: function(x0, h0, f, step_type) {\n var n, v, w,\n estlim = NaN,\n v_prev,\n delta, diff, omega,\n beta = 1,\n r = 0.5,\n numer = [],\n denom = [],\n result = 'finite',\n h = h0, transform = 'u';\n\n step_type = step_type || 0;\n\n v_prev = f(x0 + h0, true);\n for (n = 1; n <= this.upper; n++) {\n h = (step_type === 0) ? h0 / (n + 1) : h * r;\n v = f(x0 + h, true);\n delta = v - v_prev;\n if (Math.abs(delta) < 1) {\n transform = 'u';\n } else {\n transform = 't';\n }\n if (transform === 'u') {\n omega = (beta + n) * delta; // u transformation\n } else {\n omega = delta; // t transformation\n }\n\n v_prev = v;\n w = this.levin(v, n - 1, omega, beta, numer, denom);\n diff = w - estlim;\n// console.log(n, delta, transform, x0 + h, v, w, diff);\n\n if (isNaN(w)) {\n result = 'NaN';\n break;\n }\n if (v !== 0 && w / v > this.infty) {\n estlim = w;\n result = 'infinite';\n break;\n }\n if (Math.abs(diff) < 1.e-7) {\n break;\n }\n estlim = w;\n }\n return [estlim, result, 1 - (n - 1) / this.upper];\n },\n\n /**\n *\n * @param {Number} x0 Value for which the limit of f is to be determined. f(x0) may or may not exist.\n * @param {Number} h0 Initial (signed) distance from x0.\n * @param {Function} f Function for which the limit at x0 is to be determined\n *\n * @returns {Array} Array of length 3. Position 0: estimated value for f(x0), position 1: 'finite', 'infinite', or 'NaN'.\n * Position 2: value between 0 and 1 judging the reliability of the result (1: high, 0: not successful).\n * In case that the extrapolation fails, position 1 and 2 contain 'direct' and 0.\n *\n * @example\n * var f1 = (x) => Math.log(x),\n * f2 = (x) => Math.tan(x - Math.PI * 0.5),\n * f3 = (x) => 4 / x;\n *\n * var x0 = 0.0000001;\n * var h = 0.1;\n * for (let f of [f1, f2, f3]) {\n * console.log(\"x0=\", x0, f.toString());\n * console.log(JXG.Math.Extrapolate.limit(x0, h, f));\n * }\n *\n * </pre><div id=\"JXG5e8c6a7e-eeae-43fb-a669-26b5c9e40cab\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG5e8c6a7e-eeae-43fb-a669-26b5c9e40cab',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var f1 = (x) => Math.log(x),\n * f2 = (x) => Math.tan(x - Math.PI * 0.5),\n * f3 = (x) => 4 / x;\n *\n * var x0 = 0.0000001;\n * var h = 0.1;\n * for (let f of [f1, f2, f3]) {\n * console.log(\"x0=\", x0, f.toString());\n * console.log(JXG.Math.Extrapolate.limit(x0, h, f));\n * }\n * \n * })();\n * \n * </script><pre>\n *\n *\n * @see JXG.Math.Extrapolate.iteration\n * @memberof JXG.Math.Extrapolate\n */\n limit: function(x0, h0, f) {\n return this.iteration_levin(x0, h0, f, 0);\n //return this.iteration(x0, h0, f, 'wynnEps', 1);\n\n // var algs = ['wynnEps', 'levin'], //, 'wynnEps', 'levin', 'aitken', 'brezinski'],\n // le = algs.length,\n // i, t, res;\n // for (i = 0; i < le; i++) {\n // for (t = 0; t < 1; t++) {\n // if (algs[i] === 'levin') {\n // res = this.iteration_levin(x0, h0, f, t);\n // } else {\n // res = this.iteration(x0, h0, f, algs[i], t);\n // }\n // if (res[2] > 0.6) {\n // return res;\n // }\n // console.log(algs[i], t, res)\n // }\n // }\n // return [f(x0 + Math.sign(h0) * Math.sqrt(Mat.eps)), 'direct', 0];\n }\n };\n\n return Mat.Extrapolate;\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG:true, define: true*/\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n math/math\n utils/type\n */\n\ndefine('math/qdt',['math/math', 'utils/type'], function (Mat, Type) {\n\n \"use strict\";\n\n /**\n * Instantiate a new quad tree.\n *\n * @name JXG.Math.Quadtree\n * @exports Mat.Quadtree as JXG.Math.Quadtree\n * @param {Array} bbox Bounding box of the new quad (sub)tree.\n * @constructor\n */\n Mat.Quadtree = function (bbox) {\n /**\n * The maximum number of points stored in a quad tree node\n * before it is subdivided.\n * @type Number\n * @default 10\n */\n this.capacity = 10;\n\n /**\n * Point storage.\n * @name JXG.Math.Quadtree#points\n * @type Array\n */\n this.points = [];\n this.xlb = bbox[0];\n this.xub = bbox[2];\n this.ylb = bbox[3];\n this.yub = bbox[1];\n\n /**\n * In a subdivided quad tree this represents the top left subtree.\n * @name JXG.Math.Quadtree#northWest\n * @type JXG.Math.Quadtree\n */\n this.northWest = null;\n\n /**\n * In a subdivided quad tree this represents the top right subtree.\n * @name JXG.Math.Quadtree#northEast\n * @type JXG.Math.Quadtree\n */\n this.northEast = null;\n\n /**\n * In a subdivided quad tree this represents the bottom right subtree.\n * @name JXG.Math.Quadtree#southEast\n * @type JXG.Math.Quadtree\n */\n this.southEast = null;\n\n /**\n * In a subdivided quad tree this represents the bottom left subtree.\n * @name JXG.Math.Quadtree#southWest\n * @type JXG.Math.Quadtree\n */\n this.southWest = null;\n };\n\n Type.extend(Mat.Quadtree.prototype, /** @lends JXG.Math.Quadtree.prototype */ {\n /**\n * Checks if the given coordinates are inside the quad tree.\n * @param {Number} x\n * @param {Number} y\n * @returns {Boolean}\n */\n contains: function (x, y) {\n return this.xlb < x && x <= this.xub && this.ylb < y && y <= this.yub;\n },\n\n /**\n * Insert a new point into this quad tree.\n * @param {JXG.Coords} p\n * @returns {Boolean}\n */\n insert: function (p) {\n if (!this.contains(p.usrCoords[1], p.usrCoords[2])) {\n return false;\n }\n\n if (this.points.length < this.capacity) {\n this.points.push(p);\n return true;\n }\n\n if (this.northWest === null) {\n this.subdivide();\n }\n\n if (this.northWest.insert(p)) {\n return true;\n }\n\n if (this.northEast.insert(p)) {\n return true;\n }\n\n if (this.southEast.insert(p)) {\n return true;\n }\n\n return !!this.southWest.insert(p);\n\n\n },\n\n /**\n * Subdivide the quad tree.\n */\n subdivide: function () {\n var i,\n l = this.points.length,\n mx = this.xlb + (this.xub - this.xlb) / 2,\n my = this.ylb + (this.yub - this.ylb) / 2;\n\n this.northWest = new Mat.Quadtree([this.xlb, this.yub, mx, my]);\n this.northEast = new Mat.Quadtree([mx, this.yub, this.xub, my]);\n this.southEast = new Mat.Quadtree([this.xlb, my, mx, this.ylb]);\n this.southWest = new Mat.Quadtree([mx, my, this.xub, this.ylb]);\n\n for (i = 0; i < l; i += 1) {\n this.northWest.insert(this.points[i]);\n this.northEast.insert(this.points[i]);\n this.southEast.insert(this.points[i]);\n this.southWest.insert(this.points[i]);\n }\n },\n\n /**\n * Internal _query method that lacks adjustment of the parameter.\n * @name JXG.Math.Quadtree#_query\n * @param {Number} x\n * @param {Number} y\n * @returns {Boolean|JXG.Quadtree} The quad tree if the point is found, false\n * if none of the quad trees contains the point (i.e. the point is not inside\n * the root tree's AABB).\n * @private\n */\n _query: function (x, y) {\n var r;\n\n if (this.contains(x, y)) {\n if (this.northWest === null) {\n return this;\n }\n\n r = this.northWest._query(x, y);\n if (r) {\n return r;\n }\n\n r = this.northEast._query(x, y);\n if (r) {\n return r;\n }\n\n r = this.southEast._query(x, y);\n if (r) {\n return r;\n }\n\n r = this.southWest._query(x, y);\n if (r) {\n return r;\n }\n }\n\n return false;\n },\n\n /**\n * Retrieve the smallest quad tree that contains the given point.\n * @name JXG.Math.Quadtree#_query\n * @param {JXG.Coords|Number} xp\n * @param {Number} y\n * @returns {Boolean|JXG.Quadtree} The quad tree if the point is found, false\n * if none of the quad trees contains the point (i.e. the point is not inside\n * the root tree's AABB).\n * @private\n */\n query: function (xp, y) {\n var _x, _y;\n\n if (Type.exists(y)) {\n _x = xp;\n _y = y;\n } else {\n _x = xp.usrCoords[1];\n _y = xp.usrCoords[2];\n }\n\n return this._query(_x, _y);\n }\n });\n\n return Mat.Quadtree;\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n/*global JXG: true, define: true*/\n/*jslint nomen: true, plusplus: true*/\n/*eslint no-loss-of-precision: off */\n\n/* depends:\n utils/type\n math/math\n */\n\n/**\n * @fileoverview In this file the namespace Math.Numerics is defined, which holds numerical\n * algorithms for solving linear equations etc.\n */\n\ndefine('math/numerics',['jxg', 'utils/type', 'utils/env', 'math/math'], function (JXG, Type, Env, Mat) {\n\n \"use strict\";\n\n // Predefined butcher tableaus for the common Runge-Kutta method (fourth order), Heun method (second order), and Euler method (first order).\n var predefinedButcher = {\n rk4: {\n s: 4,\n A: [\n [ 0, 0, 0, 0],\n [0.5, 0, 0, 0],\n [ 0, 0.5, 0, 0],\n [ 0, 0, 1, 0]\n ],\n b: [1.0 / 6.0, 1.0 / 3.0, 1.0 / 3.0, 1.0 / 6.0],\n c: [0, 0.5, 0.5, 1]\n },\n heun: {\n s: 2,\n A: [\n [0, 0],\n [1, 0]\n ],\n b: [0.5, 0.5],\n c: [0, 1]\n },\n euler: {\n s: 1,\n A: [\n [0]\n ],\n b: [1],\n c: [0]\n }\n };\n\n /**\n * The JXG.Math.Numerics namespace holds numerical algorithms, constants, and variables.\n * @name JXG.Math.Numerics\n * @exports Mat.Numerics as JXG.Math.Numerics\n * @namespace\n */\n Mat.Numerics = {\n\n //JXG.extend(Mat.Numerics, /** @lends JXG.Math.Numerics */ {\n /**\n * Solves a system of linear equations given by A and b using the Gauss-Jordan-elimination.\n * The algorithm runs in-place. I.e. the entries of A and b are changed.\n * @param {Array} A Square matrix represented by an array of rows, containing the coefficients of the lineare equation system.\n * @param {Array} b A vector containing the linear equation system's right hand side.\n * @throws {Error} If a non-square-matrix is given or if b has not the right length or A's rank is not full.\n * @returns {Array} A vector that solves the linear equation system.\n * @memberof JXG.Math.Numerics\n */\n Gauss: function (A, b) {\n var i, j, k,\n // copy the matrix to prevent changes in the original\n Acopy,\n // solution vector, to prevent changing b\n x,\n eps = Mat.eps,\n // number of columns of A\n n = A.length > 0 ? A[0].length : 0;\n\n if ((n !== b.length) || (n !== A.length)) {\n throw new Error(\"JXG.Math.Numerics.Gauss: Dimensions don't match. A must be a square matrix and b must be of the same length as A.\");\n }\n\n // initialize solution vector\n Acopy = [];\n x = b.slice(0, n);\n\n for (i = 0; i < n; i++) {\n Acopy[i] = A[i].slice(0, n);\n }\n\n // Gauss-Jordan-elimination\n for (j = 0; j < n; j++) {\n for (i = n - 1; i > j; i--) {\n // Is the element which is to eliminate greater than zero?\n if (Math.abs(Acopy[i][j]) > eps) {\n // Equals pivot element zero?\n if (Math.abs(Acopy[j][j]) < eps) {\n // At least numerically, so we have to exchange the rows\n Type.swap(Acopy, i, j);\n Type.swap(x, i, j);\n } else {\n // Saves the L matrix of the LR-decomposition. unnecessary.\n Acopy[i][j] /= Acopy[j][j];\n // Transform right-hand-side b\n x[i] -= Acopy[i][j] * x[j];\n\n // subtract the multiple of A[i][j] / A[j][j] of the j-th row from the i-th.\n for (k = j + 1; k < n; k++) {\n Acopy[i][k] -= Acopy[i][j] * Acopy[j][k];\n }\n }\n }\n }\n\n // The absolute values of all coefficients below the j-th row in the j-th column are smaller than JXG.Math.eps.\n if (Math.abs(Acopy[j][j]) < eps) {\n throw new Error(\"JXG.Math.Numerics.Gauss(): The given matrix seems to be singular.\");\n }\n }\n\n this.backwardSolve(Acopy, x, true);\n\n return x;\n },\n\n /**\n * Solves a system of linear equations given by the right triangular matrix R and vector b.\n * @param {Array} R Right triangular matrix represented by an array of rows. All entries a_(i,j) with i < j are ignored.\n * @param {Array} b Right hand side of the linear equation system.\n * @param {Boolean} [canModify=false] If true, the right hand side vector is allowed to be changed by this method.\n * @returns {Array} An array representing a vector that solves the system of linear equations.\n * @memberof JXG.Math.Numerics\n */\n backwardSolve: function (R, b, canModify) {\n var x, m, n, i, j;\n\n if (canModify) {\n x = b;\n } else {\n x = b.slice(0, b.length);\n }\n\n // m: number of rows of R\n // n: number of columns of R\n m = R.length;\n n = R.length > 0 ? R[0].length : 0;\n\n for (i = m - 1; i >= 0; i--) {\n for (j = n - 1; j > i; j--) {\n x[i] -= R[i][j] * x[j];\n }\n x[i] /= R[i][i];\n }\n\n return x;\n },\n\n /**\n * @private\n * Gauss-Bareiss algorithm to compute the\n * determinant of matrix without fractions.\n * See Henri Cohen, \"A Course in Computational\n * Algebraic Number Theory (Graduate texts\n * in mathematics; 138)\", Springer-Verlag,\n * ISBN 3-540-55640-0 / 0-387-55640-0\n * Third, Corrected Printing 1996\n * \"Algorithm 2.2.6\", pg. 52-53\n * @memberof JXG.Math.Numerics\n */\n gaussBareiss: function (mat) {\n var k, c, s, i, j, p, n, M, t,\n eps = Mat.eps;\n\n n = mat.length;\n\n if (n <= 0) {\n return 0;\n }\n\n if (mat[0].length < n) {\n n = mat[0].length;\n }\n\n // Copy the input matrix to M\n M = [];\n\n for (i = 0; i < n; i++) {\n M[i] = mat[i].slice(0, n);\n }\n\n c = 1;\n s = 1;\n\n for (k = 0; k < n - 1; k++) {\n p = M[k][k];\n\n // Pivot step\n if (Math.abs(p) < eps) {\n for (i = k + 1; i < n; i++) {\n if (Math.abs(M[i][k]) >= eps) {\n break;\n }\n }\n\n // No nonzero entry found in column k -> det(M) = 0\n if (i === n) {\n return 0.0;\n }\n\n // swap row i and k partially\n for (j = k; j < n; j++) {\n t = M[i][j];\n M[i][j] = M[k][j];\n M[k][j] = t;\n }\n s = -s;\n p = M[k][k];\n }\n\n // Main step\n for (i = k + 1; i < n; i++) {\n for (j = k + 1; j < n; j++) {\n t = p * M[i][j] - M[i][k] * M[k][j];\n M[i][j] = t / c;\n }\n }\n\n c = p;\n }\n\n return s * M[n - 1][n - 1];\n },\n\n /**\n * Computes the determinant of a square nxn matrix with the\n * Gauss-Bareiss algorithm.\n * @param {Array} mat Matrix.\n * @returns {Number} The determinant pf the matrix mat.\n * The empty matrix returns 0.\n * @memberof JXG.Math.Numerics\n */\n det: function (mat) {\n var n = mat.length;\n\n if (n === 2 && mat[0].length === 2) {\n return mat[0][0] * mat[1][1] - mat[1][0] * mat[0][1];\n }\n\n return this.gaussBareiss(mat);\n },\n\n /**\n * Compute the Eigenvalues and Eigenvectors of a symmetric 3x3 matrix with the Jacobi method\n * Adaption of a FORTRAN program by Ed Wilson, Dec. 25, 1990\n * @param {Array} Ain A symmetric 3x3 matrix.\n * @returns {Array} [A,V] the matrices A and V. The diagonal of A contains the Eigenvalues, V contains the Eigenvectors.\n * @memberof JXG.Math.Numerics\n */\n Jacobi: function (Ain) {\n var i, j, k, aa, si, co, tt, ssum, amax,\n eps = Mat.eps * Mat.eps,\n sum = 0.0,\n n = Ain.length,\n V = [\n [0, 0, 0],\n [0, 0, 0],\n [0, 0, 0]\n ],\n A = [\n [0, 0, 0],\n [0, 0, 0],\n [0, 0, 0]\n ],\n nloops = 0;\n\n // Initialization. Set initial Eigenvectors.\n for (i = 0; i < n; i++) {\n for (j = 0; j < n; j++) {\n V[i][j] = 0.0;\n A[i][j] = Ain[i][j];\n sum += Math.abs(A[i][j]);\n }\n V[i][i] = 1.0;\n }\n\n // Trivial problems\n if (n === 1) {\n return [A, V];\n }\n\n if (sum <= 0.0) {\n return [A, V];\n }\n\n sum /= (n * n);\n\n // Reduce matrix to diagonal\n do {\n ssum = 0.0;\n amax = 0.0;\n for (j = 1; j < n; j++) {\n for (i = 0; i < j; i++) {\n // Check if A[i][j] is to be reduced\n aa = Math.abs(A[i][j]);\n\n if (aa > amax) {\n amax = aa;\n }\n\n ssum += aa;\n\n if (aa >= eps) {\n // calculate rotation angle\n aa = Math.atan2(2.0 * A[i][j], A[i][i] - A[j][j]) * 0.5;\n si = Math.sin(aa);\n co = Math.cos(aa);\n\n // Modify 'i' and 'j' columns\n for (k = 0; k < n; k++) {\n tt = A[k][i];\n A[k][i] = co * tt + si * A[k][j];\n A[k][j] = -si * tt + co * A[k][j];\n tt = V[k][i];\n V[k][i] = co * tt + si * V[k][j];\n V[k][j] = -si * tt + co * V[k][j];\n }\n\n // Modify diagonal terms\n A[i][i] = co * A[i][i] + si * A[j][i];\n A[j][j] = -si * A[i][j] + co * A[j][j];\n A[i][j] = 0.0;\n\n // Make 'A' matrix symmetrical\n for (k = 0; k < n; k++) {\n A[i][k] = A[k][i];\n A[j][k] = A[k][j];\n }\n // A[i][j] made zero by rotation\n }\n }\n }\n nloops += 1;\n } while (Math.abs(ssum) / sum > eps && nloops < 2000);\n\n return [A, V];\n },\n\n /**\n * Calculates the integral of function f over interval using Newton-Cotes-algorithm.\n * @param {Array} interval The integration interval, e.g. [0, 3].\n * @param {function} f A function which takes one argument of type number and returns a number.\n * @param {Object} [config] The algorithm setup. Accepted properties are number_of_nodes of type number and integration_type\n * with value being either 'trapez', 'simpson', or 'milne'.\n * @param {Number} [config.number_of_nodes=28]\n * @param {String} [config.integration_type='milne'] Possible values are 'milne', 'simpson', 'trapez'\n * @returns {Number} Integral value of f over interval\n * @throws {Error} If config.number_of_nodes doesn't match config.integration_type an exception is thrown. If you want to use\n * simpson rule respectively milne rule config.number_of_nodes must be dividable by 2 respectively 4.\n * @example\n * function f(x) {\n * return x*x;\n * }\n *\n * // calculates integral of <tt>f</tt> from 0 to 2.\n * var area1 = JXG.Math.Numerics.NewtonCotes([0, 2], f);\n *\n * // the same with an anonymous function\n * var area2 = JXG.Math.Numerics.NewtonCotes([0, 2], function (x) { return x*x; });\n *\n * // use trapez rule with 16 nodes\n * var area3 = JXG.Math.Numerics.NewtonCotes([0, 2], f,\n * {number_of_nodes: 16, integration_type: 'trapez'});\n * @memberof JXG.Math.Numerics\n */\n NewtonCotes: function (interval, f, config) {\n var evaluation_point, i, number_of_intervals,\n integral_value = 0.0,\n number_of_nodes = config && Type.isNumber(config.number_of_nodes) ? config.number_of_nodes : 28,\n available_types = {trapez: true, simpson: true, milne: true},\n integration_type = config && config.integration_type && available_types.hasOwnProperty(config.integration_type) && available_types[config.integration_type] ? config.integration_type : 'milne',\n step_size = (interval[1] - interval[0]) / number_of_nodes;\n\n switch (integration_type) {\n case 'trapez':\n integral_value = (f(interval[0]) + f(interval[1])) * 0.5;\n evaluation_point = interval[0];\n\n for (i = 0; i < number_of_nodes - 1; i++) {\n evaluation_point += step_size;\n integral_value += f(evaluation_point);\n }\n\n integral_value *= step_size;\n break;\n case 'simpson':\n if (number_of_nodes % 2 > 0) {\n throw new Error(\"JSXGraph: INT_SIMPSON requires config.number_of_nodes dividable by 2.\");\n }\n\n number_of_intervals = number_of_nodes / 2.0;\n integral_value = f(interval[0]) + f(interval[1]);\n evaluation_point = interval[0];\n\n for (i = 0; i < number_of_intervals - 1; i++) {\n evaluation_point += 2.0 * step_size;\n integral_value += 2.0 * f(evaluation_point);\n }\n\n evaluation_point = interval[0] - step_size;\n\n for (i = 0; i < number_of_intervals; i++) {\n evaluation_point += 2.0 * step_size;\n integral_value += 4.0 * f(evaluation_point);\n }\n\n integral_value *= step_size / 3.0;\n break;\n default:\n if (number_of_nodes % 4 > 0) {\n throw new Error(\"JSXGraph: Error in INT_MILNE: config.number_of_nodes must be a multiple of 4\");\n }\n\n number_of_intervals = number_of_nodes * 0.25;\n integral_value = 7.0 * (f(interval[0]) + f(interval[1]));\n evaluation_point = interval[0];\n\n for (i = 0; i < number_of_intervals - 1; i++) {\n evaluation_point += 4.0 * step_size;\n integral_value += 14.0 * f(evaluation_point);\n }\n\n evaluation_point = interval[0] - 3.0 * step_size;\n\n for (i = 0; i < number_of_intervals; i++) {\n evaluation_point += 4.0 * step_size;\n integral_value += 32.0 * (f(evaluation_point) + f(evaluation_point + 2 * step_size));\n }\n\n evaluation_point = interval[0] - 2.0 * step_size;\n\n for (i = 0; i < number_of_intervals; i++) {\n evaluation_point += 4.0 * step_size;\n integral_value += 12.0 * f(evaluation_point);\n }\n\n integral_value *= 2.0 * step_size / 45.0;\n }\n return integral_value;\n },\n\n /**\n * Calculates the integral of function f over interval using Romberg iteration.\n * @param {Array} interval The integration interval, e.g. [0, 3].\n * @param {function} f A function which takes one argument of type number and returns a number.\n * @param {Object} [config] The algorithm setup. Accepted properties are max_iterations of type number and precision eps.\n * @param {Number} [config.max_iterations=20]\n * @param {Number} [config.eps=0.0000001]\n * @returns {Number} Integral value of f over interval\n * @example\n * function f(x) {\n * return x*x;\n * }\n *\n * // calculates integral of <tt>f</tt> from 0 to 2.\n * var area1 = JXG.Math.Numerics.Romberg([0, 2], f);\n *\n * // the same with an anonymous function\n * var area2 = JXG.Math.Numerics.Romberg([0, 2], function (x) { return x*x; });\n *\n * // use trapez rule with maximum of 16 iterations or stop if the precision 0.0001 has been reached.\n * var area3 = JXG.Math.Numerics.Romberg([0, 2], f,\n * {max_iterations: 16, eps: 0.0001});\n * @memberof JXG.Math.Numerics\n */\n Romberg: function (interval, f, config) {\n var a, b, h, s, n,\n k, i, q,\n p = [],\n integral = 0.0,\n last = Infinity,\n m = config && Type.isNumber(config.max_iterations) ? config.max_iterations : 20,\n eps = config && Type.isNumber(config.eps) ? config.eps : config.eps || 0.0000001;\n\n a = interval[0];\n b = interval[1];\n h = b - a;\n n = 1;\n\n p[0] = 0.5 * h * (f(a) + f(b));\n\n for (k = 0; k < m; ++k) {\n s = 0;\n h *= 0.5;\n n *= 2;\n q = 1;\n\n for (i = 1; i < n; i += 2) {\n s += f(a + i * h);\n }\n\n p[k + 1] = 0.5 * p[k] + s * h;\n\n integral = p[k + 1];\n for (i = k - 1; i >= 0; --i) {\n q *= 4;\n p[i] = p[i + 1] + (p[i + 1] - p[i]) / (q - 1.0);\n integral = p[i];\n }\n\n if (Math.abs(integral - last) < eps * Math.abs(integral)) {\n break;\n }\n last = integral;\n }\n\n return integral;\n },\n\n /**\n * Calculates the integral of function f over interval using Gauss-Legendre quadrature.\n * @param {Array} interval The integration interval, e.g. [0, 3].\n * @param {function} f A function which takes one argument of type number and returns a number.\n * @param {Object} [config] The algorithm setup. Accepted property is the order n of type number. n is allowed to take\n * values between 2 and 18, default value is 12.\n * @param {Number} [config.n=16]\n * @returns {Number} Integral value of f over interval\n * @example\n * function f(x) {\n * return x*x;\n * }\n *\n * // calculates integral of <tt>f</tt> from 0 to 2.\n * var area1 = JXG.Math.Numerics.GaussLegendre([0, 2], f);\n *\n * // the same with an anonymous function\n * var area2 = JXG.Math.Numerics.GaussLegendre([0, 2], function (x) { return x*x; });\n *\n * // use 16 point Gauss-Legendre rule.\n * var area3 = JXG.Math.Numerics.GaussLegendre([0, 2], f,\n * {n: 16});\n * @memberof JXG.Math.Numerics\n */\n GaussLegendre: function (interval, f, config) {\n var a, b,\n i, m,\n xp, xm,\n result = 0.0,\n table_xi = [],\n table_w = [],\n xi, w,\n n = config && Type.isNumber(config.n) ? config.n : 12;\n\n if (n > 18) {\n n = 18;\n }\n\n /* n = 2 */\n table_xi[2] = [0.5773502691896257645091488];\n table_w[2] = [1.0000000000000000000000000];\n\n /* n = 4 */\n table_xi[4] = [0.3399810435848562648026658, 0.8611363115940525752239465];\n table_w[4] = [0.6521451548625461426269361, 0.3478548451374538573730639];\n\n /* n = 6 */\n table_xi[6] = [0.2386191860831969086305017, 0.6612093864662645136613996, 0.9324695142031520278123016];\n table_w[6] = [0.4679139345726910473898703, 0.3607615730481386075698335, 0.1713244923791703450402961];\n\n /* n = 8 */\n table_xi[8] = [0.1834346424956498049394761, 0.5255324099163289858177390, 0.7966664774136267395915539, 0.9602898564975362316835609];\n table_w[8] = [0.3626837833783619829651504, 0.3137066458778872873379622, 0.2223810344533744705443560, 0.1012285362903762591525314];\n\n /* n = 10 */\n table_xi[10] = [0.1488743389816312108848260, 0.4333953941292471907992659, 0.6794095682990244062343274, 0.8650633666889845107320967, 0.9739065285171717200779640];\n table_w[10] = [0.2955242247147528701738930, 0.2692667193099963550912269, 0.2190863625159820439955349, 0.1494513491505805931457763, 0.0666713443086881375935688];\n\n /* n = 12 */\n table_xi[12] = [0.1252334085114689154724414, 0.3678314989981801937526915, 0.5873179542866174472967024, 0.7699026741943046870368938, 0.9041172563704748566784659, 0.9815606342467192506905491];\n table_w[12] = [0.2491470458134027850005624, 0.2334925365383548087608499, 0.2031674267230659217490645, 0.1600783285433462263346525, 0.1069393259953184309602547, 0.0471753363865118271946160];\n\n /* n = 14 */\n table_xi[14] = [0.1080549487073436620662447, 0.3191123689278897604356718, 0.5152486363581540919652907, 0.6872929048116854701480198, 0.8272013150697649931897947, 0.9284348836635735173363911, 0.9862838086968123388415973];\n table_w[14] = [0.2152638534631577901958764, 0.2051984637212956039659241, 0.1855383974779378137417166, 0.1572031671581935345696019, 0.1215185706879031846894148, 0.0801580871597602098056333, 0.0351194603317518630318329];\n\n /* n = 16 */\n table_xi[16] = [0.0950125098376374401853193, 0.2816035507792589132304605, 0.4580167776572273863424194, 0.6178762444026437484466718, 0.7554044083550030338951012, 0.8656312023878317438804679, 0.9445750230732325760779884, 0.9894009349916499325961542];\n table_w[16] = [0.1894506104550684962853967, 0.1826034150449235888667637, 0.1691565193950025381893121, 0.1495959888165767320815017, 0.1246289712555338720524763, 0.0951585116824927848099251, 0.0622535239386478928628438, 0.0271524594117540948517806];\n\n /* n = 18 */\n table_xi[18] = [0.0847750130417353012422619, 0.2518862256915055095889729, 0.4117511614628426460359318, 0.5597708310739475346078715, 0.6916870430603532078748911, 0.8037049589725231156824175, 0.8926024664975557392060606, 0.9558239495713977551811959, 0.9915651684209309467300160];\n table_w[18] = [0.1691423829631435918406565, 0.1642764837458327229860538, 0.1546846751262652449254180, 0.1406429146706506512047313, 0.1225552067114784601845191, 0.1009420441062871655628140, 0.0764257302548890565291297, 0.0497145488949697964533349, 0.0216160135264833103133427];\n\n /* n = 3 */\n table_xi[3] = [0.0000000000000000000000000, 0.7745966692414833770358531];\n table_w[3] = [0.8888888888888888888888889, 0.5555555555555555555555556];\n\n /* n = 5 */\n table_xi[5] = [0.0000000000000000000000000, 0.5384693101056830910363144, 0.9061798459386639927976269];\n table_w[5] = [0.5688888888888888888888889, 0.4786286704993664680412915, 0.2369268850561890875142640];\n\n /* n = 7 */\n table_xi[7] = [0.0000000000000000000000000, 0.4058451513773971669066064, 0.7415311855993944398638648, 0.9491079123427585245261897];\n table_w[7] = [0.4179591836734693877551020, 0.3818300505051189449503698, 0.2797053914892766679014678, 0.1294849661688696932706114];\n\n /* n = 9 */\n table_xi[9] = [0.0000000000000000000000000, 0.3242534234038089290385380, 0.6133714327005903973087020, 0.8360311073266357942994298, 0.9681602395076260898355762];\n table_w[9] = [0.3302393550012597631645251, 0.3123470770400028400686304, 0.2606106964029354623187429, 0.1806481606948574040584720, 0.0812743883615744119718922];\n\n /* n = 11 */\n table_xi[11] = [0.0000000000000000000000000, 0.2695431559523449723315320, 0.5190961292068118159257257, 0.7301520055740493240934163, 0.8870625997680952990751578, 0.9782286581460569928039380];\n table_w[11] = [0.2729250867779006307144835, 0.2628045445102466621806889, 0.2331937645919904799185237, 0.1862902109277342514260976, 0.1255803694649046246346943, 0.0556685671161736664827537];\n\n /* n = 13 */\n table_xi[13] = [0.0000000000000000000000000, 0.2304583159551347940655281, 0.4484927510364468528779129, 0.6423493394403402206439846, 0.8015780907333099127942065, 0.9175983992229779652065478, 0.9841830547185881494728294];\n table_w[13] = [0.2325515532308739101945895, 0.2262831802628972384120902, 0.2078160475368885023125232, 0.1781459807619457382800467, 0.1388735102197872384636018, 0.0921214998377284479144218, 0.0404840047653158795200216];\n\n /* n = 15 */\n table_xi[15] = [0.0000000000000000000000000, 0.2011940939974345223006283, 0.3941513470775633698972074, 0.5709721726085388475372267, 0.7244177313601700474161861, 0.8482065834104272162006483, 0.9372733924007059043077589, 0.9879925180204854284895657];\n table_w[15] = [0.2025782419255612728806202, 0.1984314853271115764561183, 0.1861610000155622110268006, 0.1662692058169939335532009, 0.1395706779261543144478048, 0.1071592204671719350118695, 0.0703660474881081247092674, 0.0307532419961172683546284];\n\n /* n = 17 */\n table_xi[17] = [0.0000000000000000000000000, 0.1784841814958478558506775, 0.3512317634538763152971855, 0.5126905370864769678862466, 0.6576711592166907658503022, 0.7815140038968014069252301, 0.8802391537269859021229557, 0.9506755217687677612227170, 0.9905754753144173356754340];\n table_w[17] = [0.1794464703562065254582656, 0.1765627053669926463252710, 0.1680041021564500445099707, 0.1540457610768102880814316, 0.1351363684685254732863200, 0.1118838471934039710947884, 0.0850361483171791808835354, 0.0554595293739872011294402, 0.0241483028685479319601100];\n\n a = interval[0];\n b = interval[1];\n\n //m = Math.ceil(n * 0.5);\n m = (n + 1) >> 1;\n\n xi = table_xi[n];\n w = table_w[n];\n\n xm = 0.5 * (b - a);\n xp = 0.5 * (b + a);\n\n if (n & 1 === 1) { // n odd\n result = w[0] * f(xp);\n for (i = 1; i < m; ++i) {\n result += w[i] * (f(xp + xm * xi[i]) + f(xp - xm * xi[i]));\n }\n } else { // n even\n result = 0.0;\n for (i = 0; i < m; ++i) {\n result += w[i] * (f(xp + xm * xi[i]) + f(xp - xm * xi[i]));\n }\n }\n\n return xm * result;\n },\n\n /**\n * Scale error in Gauss Kronrod quadrature.\n * Internal method used in {@link JXG.Math.Numerics._gaussKronrod}.\n * @private\n */\n _rescale_error: function (err, result_abs, result_asc) {\n var scale, min_err,\n DBL_MIN = 2.2250738585072014e-308,\n DBL_EPS = 2.2204460492503131e-16;\n\n err = Math.abs(err);\n if (result_asc !== 0 && err !== 0) {\n scale = Math.pow((200 * err / result_asc), 1.5);\n\n if (scale < 1.0) {\n err = result_asc * scale;\n } else {\n err = result_asc;\n }\n }\n if (result_abs > DBL_MIN / (50 * DBL_EPS)) {\n min_err = 50 * DBL_EPS * result_abs;\n\n if (min_err > err) {\n err = min_err;\n }\n }\n\n return err;\n },\n\n /**\n * Generic Gauss-Kronrod quadrature algorithm.\n * Internal method used in {@link JXG.Math.Numerics.GaussKronrod15},\n * {@link JXG.Math.Numerics.GaussKronrod21},\n * {@link JXG.Math.Numerics.GaussKronrod31}.\n * Taken from QUADPACK.\n *\n * @param {Array} interval The integration interval, e.g. [0, 3].\n * @param {function} f A function which takes one argument of type number and returns a number.\n * @param {Number} n order\n * @param {Array} xgk Kronrod quadrature abscissae\n * @param {Array} wg Weights of the Gauss rule\n * @param {Array} wgk Weights of the Kronrod rule\n * @param {Object} resultObj Object returning resultObj.abserr, resultObj.resabs, resultObj.resasc.\n * See the library QUADPACK for an explanation.\n *\n * @returns {Number} Integral value of f over interval\n *\n * @private\n */\n _gaussKronrod: function (interval, f, n, xgk, wg, wgk, resultObj) {\n var a = interval[0],\n b = interval[1],\n up,\n result,\n\n center = 0.5 * (a + b),\n half_length = 0.5 * (b - a),\n abs_half_length = Math.abs(half_length),\n f_center = f(center),\n\n result_gauss = 0.0,\n result_kronrod = f_center * wgk[n - 1],\n\n result_abs = Math.abs(result_kronrod),\n result_asc = 0.0,\n mean = 0.0,\n err = 0.0,\n\n j, jtw, abscissa, fval1, fval2, fsum,\n jtwm1,\n fv1 = [], fv2 = [];\n\n if (n % 2 === 0) {\n result_gauss = f_center * wg[n / 2 - 1];\n }\n\n up = Math.floor((n - 1) / 2);\n for (j = 0; j < up; j++) {\n jtw = j * 2 + 1; // in original fortran j=1,2,3 jtw=2,4,6\n abscissa = half_length * xgk[jtw];\n fval1 = f(center - abscissa);\n fval2 = f(center + abscissa);\n fsum = fval1 + fval2;\n fv1[jtw] = fval1;\n fv2[jtw] = fval2;\n result_gauss += wg[j] * fsum;\n result_kronrod += wgk[jtw] * fsum;\n result_abs += wgk[jtw] * (Math.abs(fval1) + Math.abs(fval2));\n }\n\n up = Math.floor(n / 2);\n for (j = 0; j < up; j++) {\n jtwm1 = j * 2;\n abscissa = half_length * xgk[jtwm1];\n fval1 = f(center - abscissa);\n fval2 = f(center + abscissa);\n fv1[jtwm1] = fval1;\n fv2[jtwm1] = fval2;\n result_kronrod += wgk[jtwm1] * (fval1 + fval2);\n result_abs += wgk[jtwm1] * (Math.abs(fval1) + Math.abs(fval2));\n }\n\n mean = result_kronrod * 0.5;\n result_asc = wgk[n - 1] * Math.abs(f_center - mean);\n\n for (j = 0; j < n - 1; j++) {\n result_asc += wgk[j] * (Math.abs(fv1[j] - mean) + Math.abs(fv2[j] - mean));\n }\n\n // scale by the width of the integration region\n err = (result_kronrod - result_gauss) * half_length;\n\n result_kronrod *= half_length;\n result_abs *= abs_half_length;\n result_asc *= abs_half_length;\n result = result_kronrod;\n\n resultObj.abserr = this._rescale_error(err, result_abs, result_asc);\n resultObj.resabs = result_abs;\n resultObj.resasc = result_asc;\n\n return result;\n },\n\n /**\n * 15 point Gauss-Kronrod quadrature algorithm, see the library QUADPACK\n * @param {Array} interval The integration interval, e.g. [0, 3].\n * @param {function} f A function which takes one argument of type number and returns a number.\n * @param {Object} resultObj Object returning resultObj.abserr, resultObj.resabs, resultObj.resasc. See the library\n * QUADPACK for an explanation.\n *\n * @returns {Number} Integral value of f over interval\n *\n * @memberof JXG.Math.Numerics\n */\n GaussKronrod15: function (interval, f, resultObj) {\n /* Gauss quadrature weights and kronrod quadrature abscissae and\n weights as evaluated with 80 decimal digit arithmetic by\n L. W. Fullerton, Bell Labs, Nov. 1981. */\n\n var xgk = /* abscissae of the 15-point kronrod rule */\n [\n 0.991455371120812639206854697526329,\n 0.949107912342758524526189684047851,\n 0.864864423359769072789712788640926,\n 0.741531185599394439863864773280788,\n 0.586087235467691130294144838258730,\n 0.405845151377397166906606412076961,\n 0.207784955007898467600689403773245,\n 0.000000000000000000000000000000000\n ],\n\n /* xgk[1], xgk[3], ... abscissae of the 7-point gauss rule.\n xgk[0], xgk[2], ... abscissae to optimally extend the 7-point gauss rule */\n\n wg = /* weights of the 7-point gauss rule */\n [\n 0.129484966168869693270611432679082,\n 0.279705391489276667901467771423780,\n 0.381830050505118944950369775488975,\n 0.417959183673469387755102040816327\n ],\n\n wgk = /* weights of the 15-point kronrod rule */\n [\n 0.022935322010529224963732008058970,\n 0.063092092629978553290700663189204,\n 0.104790010322250183839876322541518,\n 0.140653259715525918745189590510238,\n 0.169004726639267902826583426598550,\n 0.190350578064785409913256402421014,\n 0.204432940075298892414161999234649,\n 0.209482141084727828012999174891714\n ];\n\n return this._gaussKronrod(interval, f, 8, xgk, wg, wgk, resultObj);\n },\n\n /**\n * 21 point Gauss-Kronrod quadrature algorithm, see the library QUADPACK\n * @param {Array} interval The integration interval, e.g. [0, 3].\n * @param {function} f A function which takes one argument of type number and returns a number.\n * @param {Object} resultObj Object returning resultObj.abserr, resultObj.resabs, resultObj.resasc. See the library\n * QUADPACK for an explanation.\n *\n * @returns {Number} Integral value of f over interval\n *\n * @memberof JXG.Math.Numerics\n */\n GaussKronrod21: function (interval, f, resultObj) {\n /* Gauss quadrature weights and kronrod quadrature abscissae and\n weights as evaluated with 80 decimal digit arithmetic by\n L. W. Fullerton, Bell Labs, Nov. 1981. */\n\n var xgk = /* abscissae of the 21-point kronrod rule */\n [\n 0.995657163025808080735527280689003,\n 0.973906528517171720077964012084452,\n 0.930157491355708226001207180059508,\n 0.865063366688984510732096688423493,\n 0.780817726586416897063717578345042,\n 0.679409568299024406234327365114874,\n 0.562757134668604683339000099272694,\n 0.433395394129247190799265943165784,\n 0.294392862701460198131126603103866,\n 0.148874338981631210884826001129720,\n 0.000000000000000000000000000000000\n ],\n\n /* xgk[1], xgk[3], ... abscissae of the 10-point gauss rule.\n xgk[0], xgk[2], ... abscissae to optimally extend the 10-point gauss rule */\n wg = /* weights of the 10-point gauss rule */\n [\n 0.066671344308688137593568809893332,\n 0.149451349150580593145776339657697,\n 0.219086362515982043995534934228163,\n 0.269266719309996355091226921569469,\n 0.295524224714752870173892994651338\n ],\n\n wgk = /* weights of the 21-point kronrod rule */\n [\n 0.011694638867371874278064396062192,\n 0.032558162307964727478818972459390,\n 0.054755896574351996031381300244580,\n 0.075039674810919952767043140916190,\n 0.093125454583697605535065465083366,\n 0.109387158802297641899210590325805,\n 0.123491976262065851077958109831074,\n 0.134709217311473325928054001771707,\n 0.142775938577060080797094273138717,\n 0.147739104901338491374841515972068,\n 0.149445554002916905664936468389821\n ];\n\n return this._gaussKronrod(interval, f, 11, xgk, wg, wgk, resultObj);\n },\n\n /**\n * 31 point Gauss-Kronrod quadrature algorithm, see the library QUADPACK\n * @param {Array} interval The integration interval, e.g. [0, 3].\n * @param {function} f A function which takes one argument of type number and returns a number.\n * @param {Object} resultObj Object returning resultObj.abserr, resultObj.resabs, resultObj.resasc. See the library\n * QUADPACK for an explanation.\n *\n * @returns {Number} Integral value of f over interval\n *\n * @memberof JXG.Math.Numerics\n */\n GaussKronrod31: function (interval, f, resultObj) {\n /* Gauss quadrature weights and kronrod quadrature abscissae and\n weights as evaluated with 80 decimal digit arithmetic by\n L. W. Fullerton, Bell Labs, Nov. 1981. */\n\n var xgk = /* abscissae of the 21-point kronrod rule */\n [\n 0.998002298693397060285172840152271,\n 0.987992518020485428489565718586613,\n 0.967739075679139134257347978784337,\n 0.937273392400705904307758947710209,\n 0.897264532344081900882509656454496,\n 0.848206583410427216200648320774217,\n 0.790418501442465932967649294817947,\n 0.724417731360170047416186054613938,\n 0.650996741297416970533735895313275,\n 0.570972172608538847537226737253911,\n 0.485081863640239680693655740232351,\n 0.394151347077563369897207370981045,\n 0.299180007153168812166780024266389,\n 0.201194093997434522300628303394596,\n 0.101142066918717499027074231447392,\n 0.000000000000000000000000000000000\n ],\n\n /* xgk[1], xgk[3], ... abscissae of the 10-point gauss rule.\n xgk[0], xgk[2], ... abscissae to optimally extend the 10-point gauss rule */\n wg = /* weights of the 10-point gauss rule */\n [\n 0.030753241996117268354628393577204,\n 0.070366047488108124709267416450667,\n 0.107159220467171935011869546685869,\n 0.139570677926154314447804794511028,\n 0.166269205816993933553200860481209,\n 0.186161000015562211026800561866423,\n 0.198431485327111576456118326443839,\n 0.202578241925561272880620199967519\n ],\n\n wgk = /* weights of the 21-point kronrod rule */\n [\n 0.005377479872923348987792051430128,\n 0.015007947329316122538374763075807,\n 0.025460847326715320186874001019653,\n 0.035346360791375846222037948478360,\n 0.044589751324764876608227299373280,\n 0.053481524690928087265343147239430,\n 0.062009567800670640285139230960803,\n 0.069854121318728258709520077099147,\n 0.076849680757720378894432777482659,\n 0.083080502823133021038289247286104,\n 0.088564443056211770647275443693774,\n 0.093126598170825321225486872747346,\n 0.096642726983623678505179907627589,\n 0.099173598721791959332393173484603,\n 0.100769845523875595044946662617570,\n 0.101330007014791549017374792767493\n ];\n\n return this._gaussKronrod(interval, f, 16, xgk, wg, wgk, resultObj);\n },\n\n /**\n * Generate workspace object for {@link JXG.Math.Numerics.Qag}.\n * @param {Array} interval The integration interval, e.g. [0, 3].\n * @param {Number} n Max. limit\n * @returns {Object} Workspace object\n *\n * @private\n * @memberof JXG.Math.Numerics\n */\n _workspace: function (interval, n) {\n return {\n limit: n,\n size: 0,\n nrmax: 0,\n i: 0,\n alist: [interval[0]],\n blist: [interval[1]],\n rlist: [0.0],\n elist: [0.0],\n order: [0],\n level: [0],\n\n qpsrt: function () {\n var last = this.size - 1,\n limit = this.limit,\n errmax, errmin, i, k, top,\n i_nrmax = this.nrmax,\n i_maxerr = this.order[i_nrmax];\n\n /* Check whether the list contains more than two error estimates */\n if (last < 2) {\n this.order[0] = 0;\n this.order[1] = 1;\n this.i = i_maxerr;\n return;\n }\n\n errmax = this.elist[i_maxerr];\n\n /* This part of the routine is only executed if, due to a difficult\n integrand, subdivision increased the error estimate. In the normal\n case the insert procedure should start after the nrmax-th largest\n error estimate. */\n while (i_nrmax > 0 && errmax > this.elist[this.order[i_nrmax - 1]]) {\n this.order[i_nrmax] = this.order[i_nrmax - 1];\n i_nrmax--;\n }\n\n /* Compute the number of elements in the list to be maintained in\n descending order. This number depends on the number of\n subdivisions still allowed. */\n if (last < (limit / 2 + 2)) {\n top = last;\n } else {\n top = limit - last + 1;\n }\n\n /* Insert errmax by traversing the list top-down, starting\n comparison from the element elist(order(i_nrmax+1)). */\n i = i_nrmax + 1;\n\n /* The order of the tests in the following line is important to\n prevent a segmentation fault */\n while (i < top && errmax < this.elist[this.order[i]]) {\n this.order[i - 1] = this.order[i];\n i++;\n }\n\n this.order[i - 1] = i_maxerr;\n\n /* Insert errmin by traversing the list bottom-up */\n errmin = this.elist[last];\n k = top - 1;\n\n while (k > i - 2 && errmin >= this.elist[this.order[k]]) {\n this.order[k + 1] = this.order[k];\n k--;\n }\n\n this.order[k + 1] = last;\n\n /* Set i_max and e_max */\n i_maxerr = this.order[i_nrmax];\n this.i = i_maxerr;\n this.nrmax = i_nrmax;\n },\n\n set_initial_result: function (result, error) {\n this.size = 1;\n this.rlist[0] = result;\n this.elist[0] = error;\n },\n\n update: function (a1, b1, area1, error1, a2, b2, area2, error2) {\n var i_max = this.i,\n i_new = this.size,\n new_level = this.level[this.i] + 1;\n\n /* append the newly-created intervals to the list */\n\n if (error2 > error1) {\n this.alist[i_max] = a2; /* blist[maxerr] is already == b2 */\n this.rlist[i_max] = area2;\n this.elist[i_max] = error2;\n this.level[i_max] = new_level;\n\n this.alist[i_new] = a1;\n this.blist[i_new] = b1;\n this.rlist[i_new] = area1;\n this.elist[i_new] = error1;\n this.level[i_new] = new_level;\n } else {\n this.blist[i_max] = b1; /* alist[maxerr] is already == a1 */\n this.rlist[i_max] = area1;\n this.elist[i_max] = error1;\n this.level[i_max] = new_level;\n\n this.alist[i_new] = a2;\n this.blist[i_new] = b2;\n this.rlist[i_new] = area2;\n this.elist[i_new] = error2;\n this.level[i_new] = new_level;\n }\n\n this.size++;\n\n if (new_level > this.maximum_level) {\n this.maximum_level = new_level;\n }\n\n this.qpsrt();\n },\n\n retrieve: function() {\n var i = this.i;\n return {\n a: this.alist[i],\n b: this.blist[i],\n r: this.rlist[i],\n e: this.elist[i]\n };\n },\n\n sum_results: function () {\n var nn = this.size,\n k,\n result_sum = 0.0;\n\n for (k = 0; k < nn; k++) {\n result_sum += this.rlist[k];\n }\n\n return result_sum;\n },\n\n subinterval_too_small: function (a1, a2, b2) {\n var e = 2.2204460492503131e-16,\n u = 2.2250738585072014e-308,\n tmp = (1 + 100 * e) * (Math.abs(a2) + 1000 * u);\n\n return Math.abs(a1) <= tmp && Math.abs(b2) <= tmp;\n }\n\n };\n },\n\n /**\n * Quadrature algorithm qag from QUADPACK.\n * Internal method used in {@link JXG.Math.Numerics.GaussKronrod15},\n * {@link JXG.Math.Numerics.GaussKronrod21},\n * {@link JXG.Math.Numerics.GaussKronrod31}.\n *\n * @param {Array} interval The integration interval, e.g. [0, 3].\n * @param {function} f A function which takes one argument of type number and returns a number.\n * @param {Object} [config] The algorithm setup. Accepted propert are max. recursion limit of type number,\n * and epsrel and epsabs, the relative and absolute required precision of type number. Further,\n * q the internal quadrature sub-algorithm of type function.\n * @param {Number} [config.limit=15]\n * @param {Number} [config.epsrel=0.0000001]\n * @param {Number} [config.epsabs=0.0000001]\n * @param {Number} [config.q=JXG.Math.Numerics.GaussKronrod15]\n * @returns {Number} Integral value of f over interval\n *\n * @example\n * function f(x) {\n * return x*x;\n * }\n *\n * // calculates integral of <tt>f</tt> from 0 to 2.\n * var area1 = JXG.Math.Numerics.Qag([0, 2], f);\n *\n * // the same with an anonymous function\n * var area2 = JXG.Math.Numerics.Qag([0, 2], function (x) { return x*x; });\n *\n * // use JXG.Math.Numerics.GaussKronrod31 rule as sub-algorithm.\n * var area3 = JXG.Math.Numerics.Quag([0, 2], f,\n * {q: JXG.Math.Numerics.GaussKronrod31});\n * @memberof JXG.Math.Numerics\n */\n Qag: function (interval, f, config) {\n var DBL_EPS = 2.2204460492503131e-16,\n ws = this._workspace(interval, 1000),\n\n limit = config && Type.isNumber(config.limit) ? config.limit : 15,\n epsrel = config && Type.isNumber(config.epsrel) ? config.epsrel : 0.0000001,\n epsabs = config && Type.isNumber(config.epsabs) ? config.epsabs : 0.0000001,\n q = config && Type.isFunction(config.q) ? config.q : this.GaussKronrod15,\n\n resultObj = {},\n area, errsum,\n result0, abserr0, resabs0, resasc0,\n result,\n tolerance,\n iteration = 0,\n roundoff_type1 = 0, roundoff_type2 = 0, error_type = 0,\n round_off,\n\n a1, b1, a2, b2,\n a_i, b_i, r_i, e_i,\n area1 = 0, area2 = 0, area12 = 0,\n error1 = 0, error2 = 0, error12 = 0,\n resasc1, resasc2,\n // resabs1, resabs2,\n wsObj,\n delta;\n\n\n if (limit > ws.limit) {\n JXG.warn('iteration limit exceeds available workspace');\n }\n if (epsabs <= 0 && (epsrel < 50 * Mat.eps || epsrel < 0.5e-28)) {\n JXG.warn('tolerance cannot be acheived with given epsabs and epsrel');\n }\n\n result0 = q.apply(this, [interval, f, resultObj]);\n abserr0 = resultObj.abserr;\n resabs0 = resultObj.resabs;\n resasc0 = resultObj.resasc;\n\n ws.set_initial_result(result0, abserr0);\n tolerance = Math.max(epsabs, epsrel * Math.abs(result0));\n round_off = 50 * DBL_EPS * resabs0;\n\n if (abserr0 <= round_off && abserr0 > tolerance) {\n result = result0;\n // abserr = abserr0;\n\n JXG.warn('cannot reach tolerance because of roundoff error on first attempt');\n return -Infinity;\n }\n\n if ((abserr0 <= tolerance && abserr0 !== resasc0) || abserr0 === 0.0) {\n result = result0;\n // abserr = abserr0;\n\n return result;\n }\n\n if (limit === 1) {\n result = result0;\n // abserr = abserr0;\n\n JXG.warn('a maximum of one iteration was insufficient');\n return -Infinity;\n }\n\n area = result0;\n errsum = abserr0;\n iteration = 1;\n\n do {\n area1 = 0;\n area2 = 0;\n area12 = 0;\n error1 = 0;\n error2 = 0;\n error12 = 0;\n\n /* Bisect the subinterval with the largest error estimate */\n wsObj = ws.retrieve();\n a_i = wsObj.a;\n b_i = wsObj.b;\n r_i = wsObj.r;\n e_i = wsObj.e;\n\n a1 = a_i;\n b1 = 0.5 * (a_i + b_i);\n a2 = b1;\n b2 = b_i;\n\n area1 = q.apply(this, [[a1, b1], f, resultObj]);\n error1 = resultObj.abserr;\n // resabs1 = resultObj.resabs;\n resasc1 = resultObj.resasc;\n\n area2 = q.apply(this, [[a2, b2], f, resultObj]);\n error2 = resultObj.abserr;\n // resabs2 = resultObj.resabs;\n resasc2 = resultObj.resasc;\n\n area12 = area1 + area2;\n error12 = error1 + error2;\n\n errsum += (error12 - e_i);\n area += area12 - r_i;\n\n if (resasc1 !== error1 && resasc2 !== error2) {\n delta = r_i - area12;\n if (Math.abs(delta) <= 1.0e-5 * Math.abs(area12) && error12 >= 0.99 * e_i) {\n roundoff_type1++;\n }\n if (iteration >= 10 && error12 > e_i) {\n roundoff_type2++;\n }\n }\n\n tolerance = Math.max(epsabs, epsrel * Math.abs(area));\n\n if (errsum > tolerance) {\n if (roundoff_type1 >= 6 || roundoff_type2 >= 20) {\n error_type = 2; /* round off error */\n }\n\n /* set error flag in the case of bad integrand behaviour at\n a point of the integration range */\n\n if (ws.subinterval_too_small(a1, a2, b2)) {\n error_type = 3;\n }\n }\n\n ws.update(a1, b1, area1, error1, a2, b2, area2, error2);\n wsObj = ws.retrieve();\n a_i = wsObj.a_i;\n b_i = wsObj.b_i;\n r_i = wsObj.r_i;\n e_i = wsObj.e_i;\n\n iteration++;\n\n } while (iteration < limit && !error_type && errsum > tolerance);\n\n result = ws.sum_results();\n // abserr = errsum;\n/*\n if (errsum <= tolerance)\n {\n return GSL_SUCCESS;\n }\n else if (error_type == 2)\n {\n GSL_ERROR (\"roundoff error prevents tolerance from being achieved\",\n GSL_EROUND);\n }\n else if (error_type == 3)\n {\n GSL_ERROR (\"bad integrand behavior found in the integration interval\",\n GSL_ESING);\n }\n else if (iteration == limit)\n {\n GSL_ERROR (\"maximum number of subdivisions reached\", GSL_EMAXITER);\n }\n else\n {\n GSL_ERROR (\"could not integrate function\", GSL_EFAILED);\n }\n*/\n\n return result;\n },\n\n /**\n * Integral of function f over interval.\n * @param {Array} interval The integration interval, e.g. [0, 3].\n * @param {function} f A function which takes one argument of type number and returns a number.\n * @returns {Number} The value of the integral of f over interval\n * @see JXG.Math.Numerics.NewtonCotes\n * @see JXG.Math.Numerics.Romberg\n * @see JXG.Math.Numerics.Qag\n * @memberof JXG.Math.Numerics\n */\n I: function (interval, f) {\n // return this.NewtonCotes(interval, f, {number_of_nodes: 16, integration_type: 'milne'});\n // return this.Romberg(interval, f, {max_iterations: 20, eps: 0.0000001});\n return this.Qag(interval, f, {q: this.GaussKronrod15, limit: 15, epsrel: 0.0000001, epsabs: 0.0000001});\n },\n\n /**\n * Newton's method to find roots of a funtion in one variable.\n * @param {function} f We search for a solution of f(x)=0.\n * @param {Number} x initial guess for the root, i.e. start value.\n * @param {Object} context optional object that is treated as \"this\" in the function body. This is useful if\n * the function is a method of an object and contains a reference to its parent object via \"this\".\n * @returns {Number} A root of the function f.\n * @memberof JXG.Math.Numerics\n */\n Newton: function (f, x, context) {\n var df,\n i = 0,\n h = Mat.eps,\n newf = f.apply(context, [x]);\n // nfev = 1;\n\n // For compatibility\n if (Type.isArray(x)) {\n x = x[0];\n }\n\n while (i < 50 && Math.abs(newf) > h) {\n df = this.D(f, context)(x);\n // nfev += 2;\n\n if (Math.abs(df) > h) {\n x -= newf / df;\n } else {\n x += (Math.random() * 0.2 - 1.0);\n }\n\n newf = f.apply(context, [x]);\n // nfev += 1;\n i += 1;\n }\n\n return x;\n },\n\n /**\n * Abstract method to find roots of univariate functions, which - for the time being -\n * is an alias for {@link JXG.Math.Numerics.chandrupatla}.\n * @param {function} f We search for a solution of f(x)=0.\n * @param {Number|Array} x initial guess for the root, i.e. starting value, or start interval enclosing the root.\n * @param {Object} context optional object that is treated as \"this\" in the function body. This is useful if\n * the function is a method of an object and contains a reference to its parent object via \"this\".\n * @returns {Number} A root of the function f.\n *\n * @see JXG.Math.Numerics.chandrupatla\n * @see JXG.Math.Numerics.fzero\n * @memberof JXG.Math.Numerics\n */\n root: function (f, x, context) {\n //return this.fzero(f, x, context);\n return this.chandrupatla(f, x, context);\n },\n\n /**\n * Compute an intersection of the curves c1 and c2\n * with a generalized Newton method.\n * We want to find values t1, t2 such that\n * c1(t1) = c2(t2), i.e.\n * (c1_x(t1)-c2_x(t2),c1_y(t1)-c2_y(t2)) = (0,0).\n * We set\n * (e,f) := (c1_x(t1)-c2_x(t2),c1_y(t1)-c2_y(t2))\n *\n * The Jacobian J is defined by\n * J = (a, b)\n * (c, d)\n * where\n * a = c1_x'(t1)\n * b = -c2_x'(t2)\n * c = c1_y'(t1)\n * d = -c2_y'(t2)\n *\n * The inverse J^(-1) of J is equal to\n * (d, -b)/\n * (-c, a) / (ad-bc)\n *\n * Then, (t1new, t2new) := (t1,t2) - J^(-1)*(e,f).\n * If the function meetCurveCurve possesses the properties\n * t1memo and t2memo then these are taken as start values\n * for the Newton algorithm.\n * After stopping of the Newton algorithm the values of t1 and t2 are stored in\n * t1memo and t2memo.\n *\n * @param {JXG.Curve} c1 Curve, Line or Circle\n * @param {JXG.Curve} c2 Curve, Line or Circle\n * @param {Number} t1ini start value for t1\n * @param {Number} t2ini start value for t2\n * @returns {JXG.Coords} intersection point\n * @memberof JXG.Math.Numerics\n */\n generalizedNewton: function (c1, c2, t1ini, t2ini) {\n var t1, t2,\n a, b, c, d, disc,\n e, f, F,\n D00, D01,\n D10, D11,\n count = 0;\n\n if (this.generalizedNewton.t1memo) {\n t1 = this.generalizedNewton.t1memo;\n t2 = this.generalizedNewton.t2memo;\n } else {\n t1 = t1ini;\n t2 = t2ini;\n }\n\n e = c1.X(t1) - c2.X(t2);\n f = c1.Y(t1) - c2.Y(t2);\n F = e * e + f * f;\n\n D00 = this.D(c1.X, c1);\n D01 = this.D(c2.X, c2);\n D10 = this.D(c1.Y, c1);\n D11 = this.D(c2.Y, c2);\n\n while (F > Mat.eps && count < 10) {\n a = D00(t1);\n b = -D01(t2);\n c = D10(t1);\n d = -D11(t2);\n disc = a * d - b * c;\n t1 -= (d * e - b * f) / disc;\n t2 -= (a * f - c * e) / disc;\n e = c1.X(t1) - c2.X(t2);\n f = c1.Y(t1) - c2.Y(t2);\n F = e * e + f * f;\n count += 1;\n }\n\n this.generalizedNewton.t1memo = t1;\n this.generalizedNewton.t2memo = t2;\n\n if (Math.abs(t1) < Math.abs(t2)) {\n return [c1.X(t1), c1.Y(t1)];\n }\n\n return [c2.X(t2), c2.Y(t2)];\n },\n\n /**\n * Returns the Lagrange polynomials for curves with equidistant nodes, see\n * Jean-Paul Berrut, Lloyd N. Trefethen: Barycentric Lagrange Interpolation,\n * SIAM Review, Vol 46, No 3, (2004) 501-517.\n * The graph of the parametric curve [x(t),y(t)] runs through the given points.\n * @param {Array} p Array of JXG.Points\n * @returns {Array} An array consisting of two functions x(t), y(t) which define a parametric curve\n * f(t) = (x(t), y(t)), a number x1 (which equals 0) and a function x2 defining the curve's domain.\n * That means the curve is defined between x1 and x2(). x2 returns the (length of array p minus one).\n * @memberof JXG.Math.Numerics\n *\n * @example\n * var p = [];\n *\n * p[0] = board.create('point', [0, -2], {size:2, name: 'C(a)'});\n * p[1] = board.create('point', [-1.5, 5], {size:2, name: ''});\n * p[2] = board.create('point', [1, 4], {size:2, name: ''});\n * p[3] = board.create('point', [3, 3], {size:2, name: 'C(b)'});\n *\n * // Curve\n * var fg = JXG.Math.Numerics.Neville(p);\n * var graph = board.create('curve', fg, {strokeWidth:3, strokeOpacity:0.5});\n *\n * </pre><div id=\"JXG88a8b3a8-6561-44f5-a678-76bca13fd484\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG88a8b3a8-6561-44f5-a678-76bca13fd484',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var p = [];\n *\n * p[0] = board.create('point', [0, -2], {size:2, name: 'C(a)'});\n * p[1] = board.create('point', [-1.5, 5], {size:2, name: ''});\n * p[2] = board.create('point', [1, 4], {size:2, name: ''});\n * p[3] = board.create('point', [3, 3], {size:2, name: 'C(b)'});\n *\n * // Curve\n * var fg = JXG.Math.Numerics.Neville(p);\n * var graph = board.create('curve', fg, {strokeWidth:3, strokeOpacity:0.5});\n *\n * })();\n *\n * </script><pre>\n *\n */\n Neville: function (p) {\n var w = [],\n /** @ignore */\n makeFct = function (fun) {\n return function (t, suspendedUpdate) {\n var i, d, s,\n bin = Mat.binomial,\n len = p.length,\n len1 = len - 1,\n num = 0.0,\n denom = 0.0;\n\n if (!suspendedUpdate) {\n s = 1;\n for (i = 0; i < len; i++) {\n w[i] = bin(len1, i) * s;\n s *= (-1);\n }\n }\n\n d = t;\n\n for (i = 0; i < len; i++) {\n if (d === 0) {\n return p[i][fun]();\n }\n s = w[i] / d;\n d -= 1;\n num += p[i][fun]() * s;\n denom += s;\n }\n return num / denom;\n };\n },\n\n xfct = makeFct('X'),\n yfct = makeFct('Y');\n\n return [xfct, yfct, 0, function () {\n return p.length - 1;\n }];\n },\n\n /**\n * Calculates second derivatives at the given knots.\n * @param {Array} x x values of knots\n * @param {Array} y y values of knots\n * @returns {Array} Second derivatives of the interpolated function at the knots.\n * @see #splineEval\n * @memberof JXG.Math.Numerics\n */\n splineDef: function (x, y) {\n var pair, i, l,\n n = Math.min(x.length, y.length),\n diag = [],\n z = [],\n data = [],\n dx = [],\n delta = [],\n F = [];\n\n if (n === 2) {\n return [0, 0];\n }\n\n for (i = 0; i < n; i++) {\n pair = {X: x[i], Y: y[i]};\n data.push(pair);\n }\n data.sort(function (a, b) {\n return a.X - b.X;\n });\n for (i = 0; i < n; i++) {\n x[i] = data[i].X;\n y[i] = data[i].Y;\n }\n\n for (i = 0; i < n - 1; i++) {\n dx.push(x[i + 1] - x[i]);\n }\n for (i = 0; i < n - 2; i++) {\n delta.push(6 * (y[i + 2] - y[i + 1]) / (dx[i + 1]) - 6 * (y[i + 1] - y[i]) / (dx[i]));\n }\n\n // ForwardSolve\n diag.push(2 * (dx[0] + dx[1]));\n z.push(delta[0]);\n\n for (i = 0; i < n - 3; i++) {\n l = dx[i + 1] / diag[i];\n diag.push(2 * (dx[i + 1] + dx[i + 2]) - l * dx[i + 1]);\n z.push(delta[i + 1] - l * z[i]);\n }\n\n // BackwardSolve\n F[n - 3] = z[n - 3] / diag[n - 3];\n for (i = n - 4; i >= 0; i--) {\n F[i] = (z[i] - (dx[i + 1] * F[i + 1])) / diag[i];\n }\n\n // Generate f''-Vector\n for (i = n - 3; i >= 0; i--) {\n F[i + 1] = F[i];\n }\n\n // natural cubic spline\n F[0] = 0;\n F[n - 1] = 0;\n\n return F;\n },\n\n /**\n * Evaluate points on spline.\n * @param {Number,Array} x0 A single float value or an array of values to evaluate\n * @param {Array} x x values of knots\n * @param {Array} y y values of knots\n * @param {Array} F Second derivatives at knots, calculated by {@link JXG.Math.Numerics.splineDef}\n * @see #splineDef\n * @returns {Number,Array} A single value or an array, depending on what is given as x0.\n * @memberof JXG.Math.Numerics\n */\n splineEval: function (x0, x, y, F) {\n var i, j, a, b, c, d, x_,\n n = Math.min(x.length, y.length),\n l = 1,\n asArray = false,\n y0 = [];\n\n // number of points to be evaluated\n if (Type.isArray(x0)) {\n l = x0.length;\n asArray = true;\n } else {\n x0 = [x0];\n }\n\n for (i = 0; i < l; i++) {\n // is x0 in defining interval?\n if ((x0[i] < x[0]) || (x[i] > x[n - 1])) {\n return NaN;\n }\n\n // determine part of spline in which x0 lies\n for (j = 1; j < n; j++) {\n if (x0[i] <= x[j]) {\n break;\n }\n }\n\n j -= 1;\n\n // we're now in the j-th partial interval, i.e. x[j] < x0[i] <= x[j+1];\n // determine the coefficients of the polynomial in this interval\n a = y[j];\n b = (y[j + 1] - y[j]) / (x[j + 1] - x[j]) - (x[j + 1] - x[j]) / 6 * (F[j + 1] + 2 * F[j]);\n c = F[j] / 2;\n d = (F[j + 1] - F[j]) / (6 * (x[j + 1] - x[j]));\n // evaluate x0[i]\n x_ = x0[i] - x[j];\n //y0.push(a + b*x_ + c*x_*x_ + d*x_*x_*x_);\n y0.push(a + (b + (c + d * x_) * x_) * x_);\n }\n\n if (asArray) {\n return y0;\n }\n\n return y0[0];\n },\n\n /**\n * Generate a string containing the function term of a polynomial.\n * @param {Array} coeffs Coefficients of the polynomial. The position i belongs to x^i.\n * @param {Number} deg Degree of the polynomial\n * @param {String} varname Name of the variable (usually 'x')\n * @param {Number} prec Precision\n * @returns {String} A string containg the function term of the polynomial.\n * @memberof JXG.Math.Numerics\n */\n generatePolynomialTerm: function (coeffs, deg, varname, prec) {\n var i, t = [];\n\n for (i = deg; i >= 0; i--) {\n t = t.concat(['(', coeffs[i].toPrecision(prec), ')']);\n\n if (i > 1) {\n t = t.concat(['*', varname, '<sup>', i, '<', '/sup> + ']);\n } else if (i === 1) {\n t = t.concat(['*', varname, ' + ']);\n }\n }\n\n return t.join('');\n },\n\n /**\n * Computes the polynomial through a given set of coordinates in Lagrange form.\n * Returns the Lagrange polynomials, see\n * Jean-Paul Berrut, Lloyd N. Trefethen: Barycentric Lagrange Interpolation,\n * SIAM Review, Vol 46, No 3, (2004) 501-517.\n * <p>\n * It possesses the method getTerm() which returns the string containing the function term of the polynomial.\n * @param {Array} p Array of JXG.Points\n * @returns {function} A function of one parameter which returns the value of the polynomial, whose graph runs through the given points.\n * @memberof JXG.Math.Numerics\n *\n * @example\n * var p = [];\n * p[0] = board.create('point', [-1,2], {size:4});\n * p[1] = board.create('point', [0,3], {size:4});\n * p[2] = board.create('point', [1,1], {size:4});\n * p[3] = board.create('point', [3,-1], {size:4});\n * var f = JXG.Math.Numerics.lagrangePolynomial(p);\n * var graph = board.create('functiongraph', [f,-10, 10], {strokeWidth:3});\n *\n * </pre><div id=\"JXGc058aa6b-74d4-41e1-af94-df06169a2d89\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXGc058aa6b-74d4-41e1-af94-df06169a2d89',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var p = [];\n * p[0] = board.create('point', [-1,2], {size:4});\n * p[1] = board.create('point', [0,3], {size:4});\n * p[2] = board.create('point', [1,1], {size:4});\n * p[3] = board.create('point', [3,-1], {size:4});\n * var f = JXG.Math.Numerics.lagrangePolynomial(p);\n * var graph = board.create('functiongraph', [f,-10, 10], {strokeWidth:3});\n *\n * })();\n *\n * </script><pre>\n *\n * @example\n * var points = [];\n * points[0] = board.create('point', [-1,2], {size:4});\n * points[1] = board.create('point', [0, 0], {size:4});\n * points[2] = board.create('point', [2, 1], {size:4});\n *\n * var f = JXG.Math.Numerics.lagrangePolynomial(points);\n * var graph = board.create('functiongraph', [f,-10, 10], {strokeWidth:3});\n * var txt = board.create('text', [-3, -4, () => f.getTerm(2, 't', ' * ')], {fontSize: 16});\n *\n * </pre><div id=\"JXG73fdaf12-e257-4374-b488-ae063e4eecbb\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG73fdaf12-e257-4374-b488-ae063e4eecbb',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var points = [];\n * points[0] = board.create('point', [-1,2], {size:4});\n * points[1] = board.create('point', [0, 0], {size:4});\n * points[2] = board.create('point', [2, 1], {size:4});\n *\n * var f = JXG.Math.Numerics.lagrangePolynomial(points);\n * var graph = board.create('functiongraph', [f,-10, 10], {strokeWidth:3});\n * var txt = board.create('text', [-3, -4, () => f.getTerm(2, 't', ' * ')], {fontSize: 16});\n *\n * })();\n *\n * </script><pre>\n *\n */\n lagrangePolynomial: function (p) {\n var w = [],\n that = this,\n /** @ignore */\n fct = function (x, suspendedUpdate) {\n var i, // j,\n k, xi, s, //M,\n len = p.length,\n num = 0,\n denom = 0;\n\n if (!suspendedUpdate) {\n for (i = 0; i < len; i++) {\n w[i] = 1.0;\n xi = p[i].X();\n\n for (k = 0; k < len; k++) {\n if (k !== i) {\n w[i] *= (xi - p[k].X());\n }\n }\n\n w[i] = 1 / w[i];\n }\n\n // M = [];\n // for (k = 0; k < len; k++) {\n // M.push([1]);\n // }\n }\n\n for (i = 0; i < len; i++) {\n xi = p[i].X();\n\n if (x === xi) {\n return p[i].Y();\n }\n\n s = w[i] / (x - xi);\n denom += s;\n num += s * p[i].Y();\n }\n\n return num / denom;\n };\n\n /**\n * Get the term of the Lagrange polynomial as string.\n * Calls {@link JXG.Math.Numerics#lagrangePolynomialTerm}.\n *\n * @name JXG.Math.Numerics#lagrangePolynomial.getTerm\n * @param {Number} digits Number of digits of the coefficients\n * @param {String} param Variable name\n * @param {String} dot Dot symbol\n * @returns {String} containing the term of Lagrange polynomial as string.\n * @see JXG.Math.Numerics#lagrangePolynomialTerm\n * @example\n * var points = [];\n * points[0] = board.create('point', [-1,2], {size:4});\n * points[1] = board.create('point', [0, 0], {size:4});\n * points[2] = board.create('point', [2, 1], {size:4});\n *\n * var f = JXG.Math.Numerics.lagrangePolynomial(points);\n * var graph = board.create('functiongraph', [f,-10, 10], {strokeWidth:3});\n * var txt = board.create('text', [-3, -4, () => f.getTerm(2, 't', ' * ')], {fontSize: 16});\n *\n * </pre><div id=\"JXG73fdaf12-e257-4374-b488-ae063e4eeccf\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG73fdaf12-e257-4374-b488-ae063e4eeccf',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var points = [];\n * points[0] = board.create('point', [-1,2], {size:4});\n * points[1] = board.create('point', [0, 0], {size:4});\n * points[2] = board.create('point', [2, 1], {size:4});\n *\n * var f = JXG.Math.Numerics.lagrangePolynomial(points);\n * var graph = board.create('functiongraph', [f,-10, 10], {strokeWidth:3});\n * var txt = board.create('text', [-3, -4, () => f.getTerm(2, 't', ' * ')], {fontSize: 16});\n *\n * })();\n *\n * </script><pre>\n *\n */\n fct.getTerm = function(digits, param, dot) {\n return that.lagrangePolynomialTerm(p, digits, param, dot)();\n };\n\n return fct;\n },\n // fct.getTerm = that.lagrangePolynomialTerm(p, 2, 'x');\n\n /**\n * Determine the Lagrange polynomial through an array of points and\n * return the term of the polynomial as string.\n *\n * @param {Array} points Array of JXG.Points\n * @param {Number} digits Number of decimal digits of the coefficients\n * @param {String} param Name of the parameter. Default: 'x'.\n * @param {String} dot Multiplication symbol. Default: ' * '.\n * @returns {String} containing the Lagrange polynomial through\n * the supplied points.\n * @memberof JXG.Math.Numerics\n *\n * @example\n * var points = [];\n * points[0] = board.create('point', [-1,2], {size:4});\n * points[1] = board.create('point', [0, 0], {size:4});\n * points[2] = board.create('point', [2, 1], {size:4});\n *\n * var f = JXG.Math.Numerics.lagrangePolynomial(points);\n * var graph = board.create('functiongraph', [f,-10, 10], {strokeWidth:3});\n *\n * var f_txt = JXG.Math.Numerics.lagrangePolynomialTerm(points, 2, 't', ' * ');\n * var txt = board.create('text', [-3, -4, f_txt], {fontSize: 16});\n *\n * </pre><div id=\"JXGd45e9e96-7526-486d-aa43-e1178d5f2baa\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXGd45e9e96-7526-486d-aa43-e1178d5f2baa',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var points = [];\n * points[0] = board.create('point', [-1,2], {size:4});\n * points[1] = board.create('point', [0, 0], {size:4});\n * points[2] = board.create('point', [2, 1], {size:4});\n *\n * var f = JXG.Math.Numerics.lagrangePolynomial(points);\n * var graph = board.create('functiongraph', [f,-10, 10], {strokeWidth:3});\n *\n * var f_txt = JXG.Math.Numerics.lagrangePolynomialTerm(points, 2, 't', ' * ');\n * var txt = board.create('text', [-3, -4, f_txt], {fontSize: 16});\n *\n * })();\n *\n * </script><pre>\n *\n */\n lagrangePolynomialTerm: function(points, digits, param, dot) {\n return function() {\n var len = points.length,\n zeroes = [],\n coeffs = [],\n coeffs_sum = [],\n isLeading = true,\n n, t,\n i, j, c, p;\n\n param = param || 'x';\n if (dot === undefined) {\n dot = ' * ';\n }\n\n n = len - 1; // (Max) degree of the polynomial\n for (j = 0; j < len; j++) {\n coeffs_sum[j] = 0;\n }\n\n for (i = 0; i < len; i++) {\n c = points[i].Y();\n p = points[i].X();\n zeroes = [];\n for (j = 0; j < len; j++) {\n if (j !== i) {\n c /= p - points[j].X();\n zeroes.push(points[j].X());\n }\n }\n coeffs = [1].concat(Mat.Vieta(zeroes));\n for (j = 0; j < coeffs.length; j++) {\n coeffs_sum[j] += (j%2===1?(-1):1) * coeffs[j] * c;\n }\n }\n\n t = '';\n for (j = 0; j < coeffs_sum.length; j++) {\n c = coeffs_sum[j];\n if (Math.abs(c) < Mat.eps) {\n continue;\n }\n if (JXG.exists(digits)) {\n c = Env._round10(c, -digits);\n }\n if (isLeading) {\n t += (c > 0) ? (c) : ('-' + (-c));\n isLeading = false;\n } else {\n t += (c > 0) ? (' + ' + c) : (' - ' + (-c));\n }\n\n if (n - j > 1) {\n t += dot + param + '^' + (n - j);\n } else if (n - j === 1) {\n t += dot + param;\n }\n }\n return t; // board.jc.manipulate('f = map(x) -> ' + t + ';');\n };\n },\n\n /**\n * Determine the coefficients of a cardinal spline polynom, See\n * http://stackoverflow.com/questions/9489736/catmull-rom-curve-with-no-cusps-and-no-self-intersections\n * @param {Number} x1 point 1\n * @param {Number} x2 point 2\n * @param {Number} t1 tangent slope 1\n * @param {Number} t2 tangent slope 2\n * @return {Array} coefficents array c for the polynomial t maps to\n * c[0] + c[1]*t + c[2]*t*t + c[3]*t*t*t\n */\n _initCubicPoly: function(x1, x2, t1, t2) {\n return [\n x1,\n t1,\n -3 * x1 + 3 * x2 - 2 * t1 - t2,\n 2 * x1 - 2 * x2 + t1 + t2\n ];\n },\n\n /**\n * Computes the cubic cardinal spline curve through a given set of points. The curve\n * is uniformly parametrized.\n * Two artificial control points at the beginning and the end are added.\n *\n * The implementation (especially the centripetal parametrization) is from\n * http://stackoverflow.com/questions/9489736/catmull-rom-curve-with-no-cusps-and-no-self-intersections .\n * @param {Array} points Array consisting of JXG.Points.\n * @param {Number|Function} tau The tension parameter, either a constant number or a function returning a number. This number is between 0 and 1.\n * tau=1/2 give Catmull-Rom splines.\n * @param {String} type (Optional) parameter which allows to choose between \"uniform\" (default) and\n * \"centripetal\" parameterization. Thus the two possible values are \"uniform\" or \"centripetal\".\n * @returns {Array} An Array consisting of four components: Two functions each of one parameter t\n * which return the x resp. y coordinates of the Catmull-Rom-spline curve in t, a zero value,\n * and a function simply returning the length of the points array\n * minus three.\n * @memberof JXG.Math.Numerics\n */\n CardinalSpline: function (points, tau_param, type) {\n var p,\n coeffs = [],\n makeFct,\n tau, _tau,\n that = this;\n\n if (Type.isFunction(tau_param)) {\n _tau = tau_param;\n } else {\n _tau = function () { return tau_param; };\n }\n\n if (type === undefined) {\n type = 'uniform';\n }\n\n /** @ignore */\n makeFct = function (which) {\n return function (t, suspendedUpdate) {\n var s, c,\n // control point at the beginning and at the end\n first, last,\n t1, t2, dt0, dt1, dt2,\n // dx, dy,\n len;\n\n if (points.length < 2) {\n return NaN;\n }\n\n if (!suspendedUpdate) {\n tau = _tau();\n\n // New point list p: [first, points ..., last]\n first = {\n X: function () { return 2 * points[0].X() - points[1].X(); },\n Y: function () { return 2 * points[0].Y() - points[1].Y(); },\n Dist: function(p) {\n var dx = this.X() - p.X(),\n dy = this.Y() - p.Y();\n return Math.sqrt(dx * dx + dy * dy);\n }\n };\n\n last = {\n X: function () { return 2 * points[points.length - 1].X() - points[points.length - 2].X(); },\n Y: function () { return 2 * points[points.length - 1].Y() - points[points.length - 2].Y(); },\n Dist: function(p) {\n var dx = this.X() - p.X(),\n dy = this.Y() - p.Y();\n return Math.sqrt(dx * dx + dy * dy);\n }\n };\n\n p = [first].concat(points, [last]);\n len = p.length;\n\n coeffs[which] = [];\n\n for (s = 0; s < len - 3; s++) {\n if (type === 'centripetal') {\n // The order is important, since p[0].coords === undefined\n dt0 = p[s].Dist(p[s + 1]);\n dt1 = p[s + 2].Dist(p[s + 1]);\n dt2 = p[s + 3].Dist(p[s + 2]);\n\n dt0 = Math.sqrt(dt0);\n dt1 = Math.sqrt(dt1);\n dt2 = Math.sqrt(dt2);\n\n if (dt1 < Mat.eps) { dt1 = 1.0; }\n if (dt0 < Mat.eps) { dt0 = dt1; }\n if (dt2 < Mat.eps) { dt2 = dt1; }\n\n t1 = (p[s + 1][which]() - p[s][which]()) / dt0 -\n (p[s + 2][which]() - p[s][which]()) / (dt1 + dt0) +\n (p[s + 2][which]() - p[s + 1][which]()) / dt1;\n\n t2 = (p[s + 2][which]() - p[s + 1][which]()) / dt1 -\n (p[s + 3][which]() - p[s + 1][which]()) / (dt2 + dt1) +\n (p[s + 3][which]() - p[s + 2][which]()) / dt2;\n\n t1 *= dt1;\n t2 *= dt1;\n\n coeffs[which][s] = that._initCubicPoly(\n p[s + 1][which](),\n p[s + 2][which](),\n tau * t1,\n tau * t2\n );\n } else {\n coeffs[which][s] = that._initCubicPoly(\n p[s + 1][which](),\n p[s + 2][which](),\n tau * (p[s + 2][which]() - p[s][which]()),\n tau * (p[s + 3][which]() - p[s + 1][which]())\n );\n }\n }\n }\n\n if (isNaN(t)) {\n return NaN;\n }\n\n len = points.length;\n // This is necessary for our advanced plotting algorithm:\n if (t <= 0.0) {\n return points[0][which]();\n }\n if (t >= len) {\n return points[len - 1][which]();\n }\n\n s = Math.floor(t);\n if (s === t) {\n return points[s][which]();\n }\n\n t -= s;\n c = coeffs[which][s];\n if (c === undefined) {\n return NaN;\n }\n\n return (((c[3] * t + c[2]) * t + c[1]) * t + c[0]);\n };\n };\n\n return [makeFct('X'), makeFct('Y'), 0,\n function () {\n return points.length - 1;\n }];\n },\n\n /**\n * Computes the cubic Catmull-Rom spline curve through a given set of points. The curve\n * is uniformly parametrized. The curve is the cardinal spline curve for tau=0.5.\n * Two artificial control points at the beginning and the end are added.\n * @param {Array} points Array consisting of JXG.Points.\n * @param {String} type (Optional) parameter which allows to choose between \"uniform\" (default) and\n * \"centripetal\" parameterization. Thus the two possible values are \"uniform\" or \"centripetal\".\n * @returns {Array} An Array consisting of four components: Two functions each of one parameter t\n * which return the x resp. y coordinates of the Catmull-Rom-spline curve in t, a zero value, and a function simply\n * returning the length of the points array minus three.\n * @memberof JXG.Math.Numerics\n */\n CatmullRomSpline: function (points, type) {\n return this.CardinalSpline(points, 0.5, type);\n },\n\n /**\n * Computes the regression polynomial of a given degree through a given set of coordinates.\n * Returns the regression polynomial function.\n * @param {Number,function,Slider} degree number, function or slider.\n * Either\n * @param {Array} dataX Array containing either the x-coordinates of the data set or both coordinates in\n * an array of {@link JXG.Point}s or {@link JXG.Coords}.\n * In the latter case, the <tt>dataY</tt> parameter will be ignored.\n * @param {Array} dataY Array containing the y-coordinates of the data set,\n * @returns {function} A function of one parameter which returns the value of the regression polynomial of the given degree.\n * It possesses the method getTerm() which returns the string containing the function term of the polynomial.\n * @memberof JXG.Math.Numerics\n */\n regressionPolynomial: function (degree, dataX, dataY) {\n var coeffs, deg, dX, dY, inputType, fct,\n term = '';\n\n // Slider\n if (Type.isPoint(degree) && Type.isFunction(degree.Value)) {\n /** @ignore */\n deg = function () {\n return degree.Value();\n };\n // function\n } else if (Type.isFunction(degree)) {\n deg = degree;\n // number\n } else if (Type.isNumber(degree)) {\n /** @ignore */\n deg = function () {\n return degree;\n };\n } else {\n throw new Error(\"JSXGraph: Can't create regressionPolynomial from degree of type'\" + (typeof degree) + \"'.\");\n }\n\n // Parameters degree, dataX, dataY\n if (arguments.length === 3 && Type.isArray(dataX) && Type.isArray(dataY)) {\n inputType = 0;\n // Parameters degree, point array\n } else if (arguments.length === 2 && Type.isArray(dataX) && dataX.length > 0 && Type.isPoint(dataX[0])) {\n inputType = 1;\n } else if (arguments.length === 2 && Type.isArray(dataX) && dataX.length > 0 && dataX[0].usrCoords && dataX[0].scrCoords) {\n inputType = 2;\n } else {\n throw new Error(\"JSXGraph: Can't create regressionPolynomial. Wrong parameters.\");\n }\n\n /** @ignore */\n fct = function (x, suspendedUpdate) {\n var i, j, M, MT, y, B, c, s, d,\n // input data\n len = dataX.length;\n\n d = Math.floor(deg());\n\n if (!suspendedUpdate) {\n // point list as input\n if (inputType === 1) {\n dX = [];\n dY = [];\n\n for (i = 0; i < len; i++) {\n dX[i] = dataX[i].X();\n dY[i] = dataX[i].Y();\n }\n }\n\n if (inputType === 2) {\n dX = [];\n dY = [];\n\n for (i = 0; i < len; i++) {\n dX[i] = dataX[i].usrCoords[1];\n dY[i] = dataX[i].usrCoords[2];\n }\n }\n\n // check for functions\n if (inputType === 0) {\n dX = [];\n dY = [];\n\n for (i = 0; i < len; i++) {\n if (Type.isFunction(dataX[i])) {\n dX.push(dataX[i]());\n } else {\n dX.push(dataX[i]);\n }\n\n if (Type.isFunction(dataY[i])) {\n dY.push(dataY[i]());\n } else {\n dY.push(dataY[i]);\n }\n }\n }\n\n M = [];\n\n for (j = 0; j < len; j++) {\n M.push([1]);\n }\n\n for (i = 1; i <= d; i++) {\n for (j = 0; j < len; j++) {\n M[j][i] = M[j][i - 1] * dX[j];\n }\n }\n\n y = dY;\n MT = Mat.transpose(M);\n B = Mat.matMatMult(MT, M);\n c = Mat.matVecMult(MT, y);\n coeffs = Mat.Numerics.Gauss(B, c);\n term = Mat.Numerics.generatePolynomialTerm(coeffs, d, 'x', 3);\n }\n\n // Horner's scheme to evaluate polynomial\n s = coeffs[d];\n\n for (i = d - 1; i >= 0; i--) {\n s = (s * x + coeffs[i]);\n }\n\n return s;\n };\n\n fct.getTerm = function () {\n return term;\n };\n\n return fct;\n },\n\n /**\n * Computes the cubic Bezier curve through a given set of points.\n * @param {Array} points Array consisting of 3*k+1 {@link JXG.Points}.\n * The points at position k with k mod 3 = 0 are the data points,\n * points at position k with k mod 3 = 1 or 2 are the control points.\n * @returns {Array} An array consisting of two functions of one parameter t which return the\n * x resp. y coordinates of the Bezier curve in t, one zero value, and a third function accepting\n * no parameters and returning one third of the length of the points.\n * @memberof JXG.Math.Numerics\n */\n bezier: function (points) {\n var len, flen,\n /** @ignore */\n makeFct = function (which) {\n return function (t, suspendedUpdate) {\n var z = Math.floor(t) * 3,\n t0 = t % 1,\n t1 = 1 - t0;\n\n if (!suspendedUpdate) {\n flen = 3 * Math.floor((points.length - 1) / 3);\n len = Math.floor(flen / 3);\n }\n\n if (t < 0) {\n return points[0][which]();\n }\n\n if (t >= len) {\n return points[flen][which]();\n }\n\n if (isNaN(t)) {\n return NaN;\n }\n\n return t1 * t1 * (t1 * points[z][which]() + 3 * t0 * points[z + 1][which]()) + (3 * t1 * points[z + 2][which]() + t0 * points[z + 3][which]()) * t0 * t0;\n };\n };\n\n return [makeFct('X'), makeFct('Y'), 0,\n function () {\n return Math.floor(points.length / 3);\n }];\n },\n\n /**\n * Computes the B-spline curve of order k (order = degree+1) through a given set of points.\n * @param {Array} points Array consisting of JXG.Points.\n * @param {Number} order Order of the B-spline curve.\n * @returns {Array} An Array consisting of four components: Two functions each of one parameter t\n * which return the x resp. y coordinates of the B-spline curve in t, a zero value, and a function simply\n * returning the length of the points array minus one.\n * @memberof JXG.Math.Numerics\n */\n bspline: function (points, order) {\n var knots,\n _knotVector = function (n, k) {\n var j,\n kn = [];\n\n for (j = 0; j < n + k + 1; j++) {\n if (j < k) {\n kn[j] = 0.0;\n } else if (j <= n) {\n kn[j] = j - k + 1;\n } else {\n kn[j] = n - k + 2;\n }\n }\n\n return kn;\n },\n\n _evalBasisFuncs = function (t, kn, k, s) {\n var i, j, a, b, den,\n N = [];\n\n if (kn[s] <= t && t < kn[s + 1]) {\n N[s] = 1;\n } else {\n N[s] = 0;\n }\n\n for (i = 2; i <= k; i++) {\n for (j = s - i + 1; j <= s; j++) {\n if (j <= s - i + 1 || j < 0) {\n a = 0.0;\n } else {\n a = N[j];\n }\n\n if (j >= s) {\n b = 0.0;\n } else {\n b = N[j + 1];\n }\n\n den = kn[j + i - 1] - kn[j];\n\n if (den === 0) {\n N[j] = 0;\n } else {\n N[j] = (t - kn[j]) / den * a;\n }\n\n den = kn[j + i] - kn[j + 1];\n\n if (den !== 0) {\n N[j] += (kn[j + i] - t) / den * b;\n }\n }\n }\n return N;\n },\n /** @ignore */\n makeFct = function (which) {\n return function (t, suspendedUpdate) {\n var y, j, s, N = [],\n len = points.length,\n n = len - 1,\n k = order;\n\n if (n <= 0) {\n return NaN;\n }\n\n if (n + 2 <= k) {\n k = n + 1;\n }\n\n if (t <= 0) {\n return points[0][which]();\n }\n\n if (t >= n - k + 2) {\n return points[n][which]();\n }\n\n s = Math.floor(t) + k - 1;\n knots = _knotVector(n, k);\n N = _evalBasisFuncs(t, knots, k, s);\n\n y = 0.0;\n for (j = s - k + 1; j <= s; j++) {\n if (j < len && j >= 0) {\n y += points[j][which]() * N[j];\n }\n }\n\n return y;\n };\n };\n\n return [makeFct('X'), makeFct('Y'), 0,\n function () {\n return points.length - 1;\n }];\n },\n\n /**\n * Numerical (symmetric) approximation of derivative. suspendUpdate is piped through,\n * see {@link JXG.Curve#updateCurve}\n * and {@link JXG.Curve#hasPoint}.\n * @param {function} f Function in one variable to be differentiated.\n * @param {object} [obj] Optional object that is treated as \"this\" in the function body. This is useful, if the function is a\n * method of an object and contains a reference to its parent object via \"this\".\n * @returns {function} Derivative function of a given function f.\n * @memberof JXG.Math.Numerics\n */\n D: function (f, obj) {\n if (!Type.exists(obj)) {\n return function (x, suspendedUpdate) {\n var h = 0.00001,\n h2 = (h * 2.0);\n\n // Experiments with Richardsons rule\n /*\n var phi = (f(x + h, suspendedUpdate) - f(x - h, suspendedUpdate)) / h2;\n var phi2;\n h *= 0.5;\n h2 *= 0.5;\n phi2 = (f(x + h, suspendedUpdate) - f(x - h, suspendedUpdate)) / h2;\n\n return phi2 + (phi2 - phi) / 3.0;\n */\n return (f(x + h, suspendedUpdate) - f(x - h, suspendedUpdate)) / h2;\n };\n }\n\n return function (x, suspendedUpdate) {\n var h = 0.00001,\n h2 = (h * 2.0);\n\n return (f.apply(obj, [x + h, suspendedUpdate]) - f.apply(obj, [x - h, suspendedUpdate])) / h2;\n };\n },\n\n /**\n * Evaluate the function term for {@see #riemann}.\n * @private\n * @param {Number} x function argument\n * @param {function} f JavaScript function returning a number\n * @param {String} type Name of the Riemann sum type, e.g. 'lower', see {@see #riemann}.\n * @param {Number} delta Width of the bars in user coordinates\n * @returns {Number} Upper (delta > 0) or lower (delta < 0) value of the bar containing x of the Riemann sum.\n *\n * @memberof JXG.Math.Numerics\n */\n _riemannValue: function (x, f, type, delta) {\n var y, y1, x1, delta1;\n\n if (delta < 0) { // delta is negative if the lower function term is evaluated\n if (type !== 'trapezoidal') {\n x = x + delta;\n }\n delta *= -1;\n if (type === 'lower') {\n type = 'upper';\n } else if (type === 'upper') {\n type = 'lower';\n }\n }\n\n delta1 = delta * 0.01; // for 'lower' and 'upper'\n\n if (type === 'right') {\n y = f(x + delta);\n } else if (type === 'middle') {\n y = f(x + delta * 0.5);\n } else if (type === 'left' || type === 'trapezoidal') {\n y = f(x);\n } else if (type === 'lower') {\n y = f(x);\n\n for (x1 = x + delta1; x1 <= x + delta; x1 += delta1) {\n y1 = f(x1);\n\n if (y1 < y) {\n y = y1;\n }\n }\n\n y1 = f(x + delta);\n if (y1 < y) {\n y = y1;\n }\n } else if (type === 'upper') {\n y = f(x);\n\n for (x1 = x + delta1; x1 <= x + delta; x1 += delta1) {\n y1 = f(x1);\n if (y1 > y) {\n y = y1;\n }\n }\n\n y1 = f(x + delta);\n if (y1 > y) {\n y = y1;\n }\n } else if (type === 'random') {\n y = f(x + delta * Math.random());\n } else if (type === 'simpson') {\n y = (f(x) + 4 * f(x + delta * 0.5) + f(x + delta)) / 6.0;\n } else {\n y = f(x); // default is lower\n }\n\n return y;\n },\n\n /**\n * Helper function to create curve which displays Riemann sums.\n * Compute coordinates for the rectangles showing the Riemann sum.\n * @param {Function,Array} f Function or array of two functions.\n * If f is a function the integral of this function is approximated by the Riemann sum.\n * If f is an array consisting of two functions the area between the two functions is filled\n * by the Riemann sum bars.\n * @param {Number} n number of rectangles.\n * @param {String} type Type of approximation. Possible values are: 'left', 'right', 'middle', 'lower', 'upper', 'random', 'simpson', or 'trapezoidal'.\n * @param {Number} start Left border of the approximation interval\n * @param {Number} end Right border of the approximation interval\n * @returns {Array} An array of two arrays containing the x and y coordinates for the rectangles showing the Riemann sum. This\n * array may be used as parent array of a {@link JXG.Curve}. The third parameteris the riemann sum, i.e. the sum of the volumes of all\n * rectangles.\n * @memberof JXG.Math.Numerics\n */\n riemann: function (gf, n, type, start, end) {\n var i, delta,\n xarr = [],\n yarr = [],\n j = 0,\n x = start, y,\n sum = 0,\n f, g,\n ylow, yup;\n\n if (Type.isArray(gf)) {\n g = gf[0];\n f = gf[1];\n } else {\n f = gf;\n }\n\n n = Math.floor(n);\n\n if (n <= 0) {\n return [xarr, yarr, sum];\n }\n\n delta = (end - start) / n;\n\n // Upper bar ends\n for (i = 0; i < n; i++) {\n y = this._riemannValue(x, f, type, delta);\n xarr[j] = x;\n yarr[j] = y;\n\n j += 1;\n x += delta;\n if (type === 'trapezoidal') {\n y = f(x);\n }\n xarr[j] = x;\n yarr[j] = y;\n\n j += 1;\n }\n\n // Lower bar ends\n for (i = 0; i < n; i++) {\n if (g) {\n y = this._riemannValue(x, g, type, -delta);\n } else {\n y = 0.0;\n }\n xarr[j] = x;\n yarr[j] = y;\n\n j += 1;\n x -= delta;\n if (type === 'trapezoidal' && g) {\n y = g(x);\n }\n xarr[j] = x;\n yarr[j] = y;\n\n // Add the area of the bar to 'sum'\n if (type !== 'trapezoidal') {\n ylow = y;\n yup = yarr[2 * (n - 1) - 2 * i];\n } else {\n yup = 0.5 * (f(x + delta) + f(x));\n if (g) {\n ylow = 0.5 * (g(x + delta) + g(x));\n } else {\n ylow = 0.0;\n }\n }\n sum += (yup - ylow) * delta;\n\n // Draw the vertical lines\n j += 1;\n xarr[j] = x;\n yarr[j] = yarr[2 * (n - 1) - 2 * i];\n\n j += 1;\n }\n\n return [xarr, yarr, sum];\n },\n\n /**\n * Approximate the integral by Riemann sums.\n * Compute the area described by the riemann sum rectangles.\n *\n * If there is an element of type {@link Riemannsum}, then it is more efficient\n * to use the method JXG.Curve.Value() of this element instead.\n *\n * @param {Function_Array} f Function or array of two functions.\n * If f is a function the integral of this function is approximated by the Riemann sum.\n * If f is an array consisting of two functions the area between the two functions is approximated\n * by the Riemann sum.\n * @param {Number} n number of rectangles.\n * @param {String} type Type of approximation. Possible values are: 'left', 'right', 'middle', 'lower', 'upper', 'random', 'simpson' or 'trapezoidal'.\n *\n * @param {Number} start Left border of the approximation interval\n * @param {Number} end Right border of the approximation interval\n * @returns {Number} The sum of the areas of the rectangles.\n * @memberof JXG.Math.Numerics\n */\n riemannsum: function (f, n, type, start, end) {\n JXG.deprecated('Numerics.riemannsum()', 'Numerics.riemann()');\n return this.riemann(f, n, type, start, end)[2];\n },\n\n /**\n * Solve initial value problems numerically using Runge-Kutta-methods.\n * See {@link http://en.wikipedia.org/wiki/Runge-Kutta_methods} for more information on the algorithm.\n * @param {object,String} butcher Butcher tableau describing the Runge-Kutta method to use. This can be either a string describing\n * a Runge-Kutta method with a Butcher tableau predefined in JSXGraph like 'euler', 'heun', 'rk4' or an object providing the structure\n * <pre>\n * {\n * s: <Number>,\n * A: <matrix>,\n * b: <Array>,\n * c: <Array>\n * }\n * </pre>\n * which corresponds to the Butcher tableau structure shown here: http://en.wikipedia.org/w/index.php?title=List_of_Runge%E2%80%93Kutta_methods&oldid=357796696\n * @param {Array} x0 Initial value vector. If the problem is of one-dimensional, the initial value also has to be given in an array.\n * @param {Array} I Interval on which to integrate.\n * @param {Number} N Number of evaluation points.\n * @param {function} f Function describing the right hand side of the first order ordinary differential equation, i.e. if the ode\n * is given by the equation <pre>dx/dt = f(t, x(t)).</pre> So f has to take two parameters, a number <tt>t</tt> and a\n * vector <tt>x</tt>, and has to return a vector of the same dimension as <tt>x</tt> has.\n * @returns {Array} An array of vectors describing the solution of the ode on the given interval I.\n * @example\n * // A very simple autonomous system dx(t)/dt = x(t);\n * function f(t, x) {\n * return x;\n * }\n *\n * // Solve it with initial value x(0) = 1 on the interval [0, 2]\n * // with 20 evaluation points.\n * var data = JXG.Math.Numerics.rungeKutta('heun', [1], [0, 2], 20, f);\n *\n * // Prepare data for plotting the solution of the ode using a curve.\n * var dataX = [];\n * var dataY = [];\n * var h = 0.1; // (I[1] - I[0])/N = (2-0)/20\n * for(var i=0; i<data.length; i++) {\n * dataX[i] = i*h;\n * dataY[i] = data[i][0];\n * }\n * var g = board.create('curve', [dataX, dataY], {strokeWidth:'2px'});\n * </pre><div class=\"jxgbox\" id=\"JXGd2432d04-4ef7-4159-a90b-a2eb8d38c4f6\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * var board = JXG.JSXGraph.initBoard('JXGd2432d04-4ef7-4159-a90b-a2eb8d38c4f6', {boundingbox: [-1, 5, 5, -1], axis: true, showcopyright: false, shownavigation: false});\n * function f(t, x) {\n * // we have to copy the value.\n * // return x; would just return the reference.\n * return [x[0]];\n * }\n * var data = JXG.Math.Numerics.rungeKutta('heun', [1], [0, 2], 20, f);\n * var dataX = [];\n * var dataY = [];\n * var h = 0.1;\n * for(var i=0; i<data.length; i++) {\n * dataX[i] = i*h;\n * dataY[i] = data[i][0];\n * }\n * var g = board.create('curve', [dataX, dataY], {strokeColor:'red', strokeWidth:'2px'});\n * </script><pre>\n * @memberof JXG.Math.Numerics\n */\n rungeKutta: function (butcher, x0, I, N, f) {\n var e, i, j, k, l, s,\n x = [],\n y = [],\n h = (I[1] - I[0]) / N,\n t = I[0],\n dim = x0.length,\n result = [],\n r = 0;\n\n if (Type.isString(butcher)) {\n butcher = predefinedButcher[butcher] || predefinedButcher.euler;\n }\n s = butcher.s;\n\n // don't change x0, so copy it\n for (e = 0; e < dim; e++) {\n x[e] = x0[e];\n }\n\n for (i = 0; i < N; i++) {\n // Optimization doesn't work for ODEs plotted using time\n // if((i % quotient == 0) || (i == N-1)) {\n result[r] = [];\n for (e = 0; e < dim; e++) {\n result[r][e] = x[e];\n }\n\n r += 1;\n k = [];\n\n for (j = 0; j < s; j++) {\n // init y = 0\n for (e = 0; e < dim; e++) {\n y[e] = 0.0;\n }\n\n\n // Calculate linear combination of former k's and save it in y\n for (l = 0; l < j; l++) {\n for (e = 0; e < dim; e++) {\n y[e] += (butcher.A[j][l]) * h * k[l][e];\n }\n }\n\n // add x(t) to y\n for (e = 0; e < dim; e++) {\n y[e] += x[e];\n }\n\n // calculate new k and add it to the k matrix\n k.push(f(t + butcher.c[j] * h, y));\n }\n\n // init y = 0\n for (e = 0; e < dim; e++) {\n y[e] = 0.0;\n }\n\n for (l = 0; l < s; l++) {\n for (e = 0; e < dim; e++) {\n y[e] += butcher.b[l] * k[l][e];\n }\n }\n\n for (e = 0; e < dim; e++) {\n x[e] = x[e] + h * y[e];\n }\n\n t += h;\n }\n\n return result;\n },\n\n /**\n * Maximum number of iterations in {@link JXG.Math.Numerics.fzero} and\n * {@link JXG.Math.Numerics.chandrupatla}\n * @type Number\n * @default 80\n * @memberof JXG.Math.Numerics\n */\n maxIterationsRoot: 80,\n\n /**\n * Maximum number of iterations in {@link JXG.Math.Numerics.fminbr}\n * @type Number\n * @default 500\n * @memberof JXG.Math.Numerics\n */\n maxIterationsMinimize: 500,\n\n /**\n * Given a value x_0, this function tries to find a second value x_1 such that\n * the function f has opposite signs at x_0 and x_1.\n * The return values have to be tested if the method succeeded.\n *\n * @param {Function} f Function, whose root is to be found\n * @param {Number} x0 Start value\n * @param {Object} object Parent object in case f is method of it\n * @returns {Array} [x_0, f(x_0), x_1, f(x_1)]\n *\n * @see JXG.Math.Numerics.fzero\n * @see JXG.Math.Numerics.chandrupatla\n *\n * @memberof JXG.Math.Numerics\n */\n findBracket: function(f, x0, object) {\n var a, aa, fa,\n blist, b, fb,\n u, fu,\n i, len;\n\n if (Type.isArray(x0)) {\n return x0;\n }\n\n a = x0;\n fa = f.call(object, a);\n // nfev += 1;\n\n // Try to get b, by trying several values related to a\n aa = (a === 0) ? 1 : a;\n blist = [\n a - 0.1 * aa, a + 0.1 * aa,\n a - 1, a + 1,\n a - 0.5 * aa, a + 0.5 * aa,\n a - 0.6 * aa, a + 0.6 * aa,\n a - 1 * aa, a + 1 * aa,\n a - 2 * aa, a + 2 * aa,\n a - 5 * aa, a + 5 * aa,\n a - 10 * aa, a + 10 * aa,\n a - 50 * aa, a + 50 * aa,\n a - 100 * aa, a + 100 * aa\n ];\n len = blist.length;\n\n for (i = 0; i < len; i++) {\n b = blist[i];\n fb = f.call(object, b);\n // nfev += 1;\n\n if (fa * fb <= 0) {\n break;\n }\n }\n if (b < a) {\n u = a;\n a = b;\n b = u;\n\n fu = fa;\n fa = fb;\n fb = fu;\n }\n return [a, fa, b, fb];\n },\n\n /**\n *\n * Find zero of an univariate function f.\n * @param {function} f Function, whose root is to be found\n * @param {Array,Number} x0 Start value or start interval enclosing the root\n * @param {Object} object Parent object in case f is method of it\n * @returns {Number} the approximation of the root\n * Algorithm:\n * Brent's root finder from\n * G.Forsythe, M.Malcolm, C.Moler, Computer methods for mathematical\n * computations. M., Mir, 1980, p.180 of the Russian edition\n * http://www.netlib.org/c/brent.shar\n *\n * If x0 is an array containing lower and upper bound for the zero\n * algorithm 748 is applied. Otherwise, if x0 is a number,\n * the algorithm tries to bracket a zero of f starting from x0.\n * If this fails, we fall back to Newton's method.\n *\n * @see JXG.Math.Numerics.chandrupatla\n * @see JXG.Math.Numerics.root\n * @memberof JXG.Math.Numerics\n */\n fzero: function (f, x0, object) {\n var a, b, c,\n d, e,\n fa, fb, fc,\n res,\n prev_step, t1, cb, t2,\n // Actual tolerance\n tol_act,\n // Interpolation step is calculated in the form p/q; division\n // operations is delayed until the last moment\n p, q,\n // Step at this iteration\n new_step,\n eps = Mat.eps,\n maxiter = this.maxIterationsRoot,\n niter = 0;\n // nfev = 0;\n\n if (Type.isArray(x0)) {\n if (x0.length < 2) {\n throw new Error(\"JXG.Math.Numerics.fzero: length of array x0 has to be at least two.\");\n }\n\n a = x0[0];\n fa = f.call(object, a);\n // nfev += 1;\n b = x0[1];\n fb = f.call(object, b);\n // nfev += 1;\n } else {\n res = this.findBracket(f, x0, object);\n a = res[0];\n fa = res[1];\n b = res[2];\n fb = res[3];\n }\n\n if (Math.abs(fa) <= eps) {\n return a;\n }\n if (Math.abs(fb) <= eps) {\n return b;\n }\n\n if (fa * fb > 0) {\n // Bracketing not successful, fall back to Newton's method or to fminbr\n if (Type.isArray(x0)) {\n return this.fminbr(f, [a, b], object);\n }\n\n return this.Newton(f, a, object);\n }\n\n // OK, we have enclosed a zero of f.\n // Now we can start Brent's method\n c = a;\n fc = fa;\n\n // Main iteration loop\n while (niter < maxiter) {\n // Distance from the last but one to the last approximation\n prev_step = b - a;\n\n // Swap data for b to be the best approximation\n if (Math.abs(fc) < Math.abs(fb)) {\n a = b;\n b = c;\n c = a;\n\n fa = fb;\n fb = fc;\n fc = fa;\n }\n tol_act = 2 * eps * Math.abs(b) + eps * 0.5;\n new_step = (c - b) * 0.5;\n\n if (Math.abs(new_step) <= tol_act || Math.abs(fb) <= eps) {\n // Acceptable approx. is found\n return b;\n }\n\n // Decide if the interpolation can be tried\n // If prev_step was large enough and was in true direction Interpolatiom may be tried\n if (Math.abs(prev_step) >= tol_act && Math.abs(fa) > Math.abs(fb)) {\n cb = c - b;\n\n // If we have only two distinct points linear interpolation can only be applied\n if (a === c) {\n t1 = fb / fa;\n p = cb * t1;\n q = 1.0 - t1;\n // Quadric inverse interpolation\n } else {\n q = fa / fc;\n t1 = fb / fc;\n t2 = fb / fa;\n\n p = t2 * (cb * q * (q - t1) - (b - a) * (t1 - 1.0));\n q = (q - 1.0) * (t1 - 1.0) * (t2 - 1.0);\n }\n\n // p was calculated with the opposite sign; make p positive\n if (p > 0) {\n q = -q;\n // and assign possible minus to q\n } else {\n p = -p;\n }\n\n // If b+p/q falls in [b,c] and isn't too large it is accepted\n // If p/q is too large then the bissection procedure can reduce [b,c] range to more extent\n if (p < (0.75 * cb * q - Math.abs(tol_act * q) * 0.5) &&\n p < Math.abs(prev_step * q * 0.5)) {\n new_step = p / q;\n }\n }\n\n // Adjust the step to be not less than tolerance\n if (Math.abs(new_step) < tol_act) {\n new_step = (new_step > 0) ? tol_act : -tol_act;\n }\n\n // Save the previous approx.\n a = b;\n fa = fb;\n b += new_step;\n fb = f.call(object, b);\n // Do step to a new approxim.\n // nfev += 1;\n\n // Adjust c for it to have a sign opposite to that of b\n if ((fb > 0 && fc > 0) || (fb < 0 && fc < 0)) {\n c = a;\n fc = fa;\n }\n niter++;\n } // End while\n\n return b;\n },\n\n /**\n * Find zero of an univariate function f.\n * @param {function} f Function, whose root is to be found\n * @param {Array,Number} x0 Start value or start interval enclosing the root\n * @param {Object} object Parent object in case f is method of it\n * @returns {Number} the approximation of the root\n * Algorithm:\n * Chandrupatla's method, see\n * Tirupathi R. Chandrupatla,\n * \"A new hybrid quadratic/bisection algorithm for finding the zero of a nonlinear function without using derivatives\",\n * Advances in Engineering Software, Volume 28, Issue 3, April 1997, Pages 145-149.\n *\n * If x0 is an array containing lower and upper bound for the zero\n * algorithm 748 is applied. Otherwise, if x0 is a number,\n * the algorithm tries to bracket a zero of f starting from x0.\n * If this fails, we fall back to Newton's method.\n *\n * @see JXG.Math.Numerics.root\n * @see JXG.Math.Numerics.fzero\n * @memberof JXG.Math.Numerics\n */\n chandrupatla: function (f, x0, object) {\n var a, fa, b, fb, res,\n niter = 0,\n maxiter = this.maxIterationsRoot,\n rand = (1 + Math.random() * 0.001),\n t = 0.5 * rand,\n eps = Mat.eps, // 1.e-10,\n dlt = 0.00001,\n x1, x2, x3, x,\n f1, f2, f3, y,\n xm, fm, tol, tl,\n xi, ph, fl, fh,\n AL, A, B, C, D;\n\n if (Type.isArray(x0)) {\n if (x0.length < 2) {\n throw new Error(\"JXG.Math.Numerics.fzero: length of array x0 has to be at least two.\");\n }\n\n a = x0[0];\n fa = f.call(object, a);\n // nfev += 1;\n b = x0[1];\n fb = f.call(object, b);\n // nfev += 1;\n } else {\n res = this.findBracket(f, x0, object);\n a = res[0];\n fa = res[1];\n b = res[2];\n fb = res[3];\n }\n\n if (fa * fb > 0) {\n // Bracketing not successful, fall back to Newton's method or to fminbr\n if (Type.isArray(x0)) {\n return this.fminbr(f, [a, b], object);\n }\n\n return this.Newton(f, a, object);\n }\n\n x1 = a; x2 = b;\n f1 = fa; f2 = fb;\n do {\n x = x1 + t * (x2 - x1);\n y = f.call(object, x);\n\n // Arrange 2-1-3: 2-1 interval, 1 middle, 3 discarded point\n if (Math.sign(y) === Math.sign(f1)) {\n x3 = x1; x1 = x;\n f3 = f1; f1 = y;\n } else {\n x3 = x2; x2 = x1;\n f3 = f2; f2 = f1;\n }\n x1 = x; f1 = y;\n\n xm = x1; fm = f1;\n if (Math.abs(f2) < Math.abs(f1)) {\n xm = x2; fm = f2;\n }\n tol = 2 * eps * Math.abs(xm) + 0.5 * dlt;\n tl = tol / Math.abs(x2 - x1);\n if (tl > 0.5 || fm === 0) {\n break;\n }\n // If inverse quadratic interpolation holds, use it\n xi = (x1 - x2) / (x3 - x2);\n ph = (f1 - f2) / (f3 - f2);\n fl = 1 - Math.sqrt(1 - xi);\n fh = Math.sqrt(xi);\n if (fl < ph && ph < fh) {\n AL = (x3 - x1) / (x2 - x1);\n A = f1 / (f2 - f1);\n B = f3 / (f2 - f3);\n C = f1 / (f3 - f1);\n D = f2 / (f3 - f2);\n t = A * B + C * D * AL;\n } else {\n t = 0.5 * rand;\n }\n // Adjust t away from the interval boundary\n if (t < tl) {\n t = tl;\n }\n if (t > 1 - tl) {\n t = 1 - tl;\n }\n niter++;\n } while (niter <= maxiter);\n // console.log(niter);\n\n return xm;\n },\n\n /**\n *\n * Find minimum of an univariate function f.\n * <p>\n * Algorithm:\n * G.Forsythe, M.Malcolm, C.Moler, Computer methods for mathematical\n * computations. M., Mir, 1980, p.180 of the Russian edition\n *\n * @param {function} f Function, whose minimum is to be found\n * @param {Array} x0 Start interval enclosing the minimum\n * @param {Object} context Parent object in case f is method of it\n * @returns {Number} the approximation of the minimum value position\n * @memberof JXG.Math.Numerics\n **/\n fminbr: function (f, x0, context) {\n var a, b, x, v, w,\n fx, fv, fw,\n range, middle_range, tol_act, new_step,\n p, q, t, ft,\n // Golden section ratio\n r = (3.0 - Math.sqrt(5.0)) * 0.5,\n tol = Mat.eps,\n sqrteps = Mat.eps, //Math.sqrt(Mat.eps),\n maxiter = this.maxIterationsMinimize,\n niter = 0;\n // nfev = 0;\n\n if (!Type.isArray(x0) || x0.length < 2) {\n throw new Error(\"JXG.Math.Numerics.fminbr: length of array x0 has to be at least two.\");\n }\n\n a = x0[0];\n b = x0[1];\n v = a + r * (b - a);\n fv = f.call(context, v);\n\n // First step - always gold section\n // nfev += 1;\n x = v;\n w = v;\n fx = fv;\n fw = fv;\n\n while (niter < maxiter) {\n // Range over the interval in which we are looking for the minimum\n range = b - a;\n middle_range = (a + b) * 0.5;\n\n // Actual tolerance\n tol_act = sqrteps * Math.abs(x) + tol / 3.0;\n\n if (Math.abs(x - middle_range) + range * 0.5 <= 2.0 * tol_act) {\n // Acceptable approx. is found\n return x;\n }\n\n // Obtain the golden section step\n new_step = r * (x < middle_range ? b - x : a - x);\n\n // Decide if the interpolation can be tried. If x and w are distinct interpolatiom may be tried\n if (Math.abs(x - w) >= tol_act) {\n // Interpolation step is calculated as p/q;\n // division operation is delayed until last moment\n t = (x - w) * (fx - fv);\n q = (x - v) * (fx - fw);\n p = (x - v) * q - (x - w) * t;\n q = 2 * (q - t);\n\n if (q > 0) { // q was calculated with the op-\n p = -p; // posite sign; make q positive\n } else { // and assign possible minus to\n q = -q; // p\n }\n if (Math.abs(p) < Math.abs(new_step * q) && // If x+p/q falls in [a,b]\n p > q * (a - x + 2 * tol_act) && // not too close to a and\n p < q * (b - x - 2 * tol_act)) { // b, and isn't too large\n new_step = p / q; // it is accepted\n }\n // If p/q is too large then the\n // golden section procedure can\n // reduce [a,b] range to more\n // extent\n }\n\n // Adjust the step to be not less than tolerance\n if (Math.abs(new_step) < tol_act) {\n if (new_step > 0) {\n new_step = tol_act;\n } else {\n new_step = -tol_act;\n }\n }\n\n // Obtain the next approximation to min\n // and reduce the enveloping range\n\n // Tentative point for the min\n t = x + new_step;\n ft = f.call(context, t);\n // nfev += 1;\n\n // t is a better approximation\n if (ft <= fx) {\n // Reduce the range so that t would fall within it\n if (t < x) {\n b = x;\n } else {\n a = x;\n }\n\n // Assign the best approx to x\n v = w;\n w = x;\n x = t;\n\n fv = fw;\n fw = fx;\n fx = ft;\n // x remains the better approx\n } else {\n // Reduce the range enclosing x\n if (t < x) {\n a = t;\n } else {\n b = t;\n }\n\n if (ft <= fw || w === x) {\n v = w;\n w = t;\n fv = fw;\n fw = ft;\n } else if (ft <= fv || v === x || v === w) {\n v = t;\n fv = ft;\n }\n }\n niter += 1;\n }\n\n return x;\n },\n\n /**\n * Implements the Ramer-Douglas-Peucker algorithm.\n * It discards points which are not necessary from the polygonal line defined by the point array\n * pts. The computation is done in screen coordinates.\n * Average runtime is O(nlog(n)), worst case runtime is O(n^2), where n is the number of points.\n * @param {Array} pts Array of {@link JXG.Coords}\n * @param {Number} eps If the absolute value of a given number <tt>x</tt> is smaller than <tt>eps</tt> it is considered to be equal <tt>0</tt>.\n * @returns {Array} An array containing points which represent an apparently identical curve as the points of pts do, but contains fewer points.\n * @memberof JXG.Math.Numerics\n */\n RamerDouglasPeucker: function (pts, eps) {\n var allPts = [], newPts = [], i, k, len,\n\n /**\n * findSplit() is a subroutine of {@link JXG.Math.Numerics.RamerDouglasPeucker}.\n * It searches for the point between index i and j which\n * has the largest distance from the line between the points i and j.\n * @param {Array} pts Array of {@link JXG.Coords}\n * @param {Number} i Index of a point in pts\n * @param {Number} j Index of a point in pts\n * @ignore\n * @private\n */\n findSplit = function (pts, i, j) {\n var d, k, ci, cj, ck,\n x0, y0, x1, y1,\n den, lbda,\n huge = 10000,\n dist = 0,\n f = i;\n\n if (j - i < 2) {\n return [-1.0, 0];\n }\n\n ci = pts[i].scrCoords;\n cj = pts[j].scrCoords;\n\n if (isNaN(ci[1]) || isNaN(ci[2])) {\n return [NaN, i];\n }\n if (isNaN(cj[1]) || isNaN(cj[2])) {\n return [NaN, j];\n }\n\n for (k = i + 1; k < j; k++) {\n ck = pts[k].scrCoords;\n if (isNaN(ck[1]) || isNaN(ck[2])) {\n return [NaN, k];\n }\n\n x0 = ck[1] - ci[1];\n y0 = ck[2] - ci[2];\n x1 = cj[1] - ci[1];\n y1 = cj[2] - ci[2];\n x0 = x0 === Infinity ? huge : x0;\n y0 = y0 === Infinity ? huge : y0;\n x1 = x1 === Infinity ? huge : x1;\n y1 = y1 === Infinity ? huge : y1;\n x0 = x0 === -Infinity ? -huge : x0;\n y0 = y0 === -Infinity ? -huge : y0;\n x1 = x1 === -Infinity ? -huge : x1;\n y1 = y1 === -Infinity ? -huge : y1;\n den = x1 * x1 + y1 * y1;\n\n if (den >= Mat.eps) {\n lbda = (x0 * x1 + y0 * y1) / den;\n\n if (lbda < 0.0) {\n lbda = 0.0;\n } else if (lbda > 1.0) {\n lbda = 1.0;\n }\n\n x0 = x0 - lbda * x1;\n y0 = y0 - lbda * y1;\n d = x0 * x0 + y0 * y0;\n } else {\n lbda = 0.0;\n d = x0 * x0 + y0 * y0;\n }\n\n if (d > dist) {\n dist = d;\n f = k;\n }\n }\n return [Math.sqrt(dist), f];\n },\n\n /**\n * RDP() is a private subroutine of {@link JXG.Math.Numerics.RamerDouglasPeucker}.\n * It runs recursively through the point set and searches the\n * point which has the largest distance from the line between the first point and\n * the last point. If the distance from the line is greater than eps, this point is\n * included in our new point set otherwise it is discarded.\n * If it is taken, we recursively apply the subroutine to the point set before\n * and after the chosen point.\n * @param {Array} pts Array of {@link JXG.Coords}\n * @param {Number} i Index of an element of pts\n * @param {Number} j Index of an element of pts\n * @param {Number} eps If the absolute value of a given number <tt>x</tt> is smaller than <tt>eps</tt> it is considered to be equal <tt>0</tt>.\n * @param {Array} newPts Array of {@link JXG.Coords}\n * @ignore\n * @private\n */\n RDP = function (pts, i, j, eps, newPts) {\n var result = findSplit(pts, i, j),\n k = result[1];\n\n if (isNaN(result[0])) {\n RDP(pts, i, k - 1, eps, newPts);\n newPts.push(pts[k]);\n do {\n ++k;\n } while (k <= j && isNaN(pts[k].scrCoords[1] + pts[k].scrCoords[2]));\n if (k <= j) {\n newPts.push(pts[k]);\n }\n RDP(pts, k + 1, j, eps, newPts);\n } else if (result[0] > eps) {\n RDP(pts, i, k, eps, newPts);\n RDP(pts, k, j, eps, newPts);\n } else {\n newPts.push(pts[j]);\n }\n };\n\n len = pts.length;\n\n i = 0;\n while (true) {\n // Search for the next point without NaN coordinates\n while (i < len && isNaN(pts[i].scrCoords[1] + pts[i].scrCoords[2])) {\n i += 1;\n }\n // Search for the next position of a NaN point\n k = i + 1;\n while (k < len && !isNaN(pts[k].scrCoords[1] + pts[k].scrCoords[2])) {\n k += 1;\n }\n k--;\n\n // Only proceed if something is left\n if (i < len && k > i) {\n newPts = [];\n newPts[0] = pts[i];\n RDP(pts, i, k, eps, newPts);\n allPts = allPts.concat(newPts);\n }\n if (i >= len) {\n break;\n }\n // Push the NaN point\n if (k < len - 1) {\n allPts.push(pts[k + 1]);\n }\n i = k + 1;\n }\n\n return allPts;\n },\n\n /**\n * Old name for the implementation of the Ramer-Douglas-Peucker algorithm.\n * @deprecated Use {@link JXG.Math.Numerics.RamerDouglasPeucker}\n * @memberof JXG.Math.Numerics\n */\n RamerDouglasPeuker: function (pts, eps) {\n JXG.deprecated('Numerics.RamerDouglasPeuker()', 'Numerics.RamerDouglasPeucker()');\n return this.RamerDouglasPeucker(pts, eps);\n },\n\n /**\n * Implements the Visvalingam-Whyatt algorithm.\n * See M. Visvalingam, J. D. Whyatt:\n * \"Line generalisation by repeated elimination of the smallest area\", C.I.S.R.G Discussion paper 10, July 1992\n *\n * The algorithm discards points which are not necessary from the polygonal line defined by the point array\n * pts (consisting of type JXG.Coords).\n * @param {Array} pts Array of {@link JXG.Coords}\n * @param {Number} numPoints Number of remaining intermediate points. The first and the last point of the original points will\n * be taken in any case.\n * @returns {Array} An array containing points which approximates the curve defined by pts.\n * @memberof JXG.Math.Numerics\n *\n * @example\n * var i, p = [];\n * for (i = 0; i < 5; ++i) {\n * p.push(board.create('point', [Math.random() * 12 - 6, Math.random() * 12 - 6]));\n * }\n *\n * // Plot a cardinal spline curve\n * var splineArr = JXG.Math.Numerics.CardinalSpline(p, 0.5);\n * var cu1 = board.create('curve', splineArr, {strokeColor: 'green'});\n *\n * var c = board.create('curve', [[0],[0]], {strokeWidth: 2, strokeColor: 'black'});\n * c.updateDataArray = function() {\n * var i, len, points;\n *\n * // Reduce number of intermediate points with Visvakingam-Whyatt to 6\n * points = JXG.Math.Numerics.Visvalingam(cu1.points, 6);\n * // Plot the remaining points\n * len = points.length;\n * this.dataX = [];\n * this.dataY = [];\n * for (i = 0; i < len; i++) {\n * this.dataX.push(points[i].usrCoords[1]);\n * this.dataY.push(points[i].usrCoords[2]);\n * }\n * };\n * board.update();\n *\n * </pre><div id=\"JXGce0cc55c-b592-11e6-8270-104a7d3be7eb\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXGce0cc55c-b592-11e6-8270-104a7d3be7eb',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n *\n * var i, p = [];\n * for (i = 0; i < 5; ++i) {\n * p.push(board.create('point', [Math.random() * 12 - 6, Math.random() * 12 - 6]));\n * }\n *\n * // Plot a cardinal spline curve\n * var splineArr = JXG.Math.Numerics.CardinalSpline(p, 0.5);\n * var cu1 = board.create('curve', splineArr, {strokeColor: 'green'});\n *\n * var c = board.create('curve', [[0],[0]], {strokeWidth: 2, strokeColor: 'black'});\n * c.updateDataArray = function() {\n * var i, len, points;\n *\n * // Reduce number of intermediate points with Visvakingam-Whyatt to 6\n * points = JXG.Math.Numerics.Visvalingam(cu1.points, 6);\n * // Plot the remaining points\n * len = points.length;\n * this.dataX = [];\n * this.dataY = [];\n * for (i = 0; i < len; i++) {\n * this.dataX.push(points[i].usrCoords[1]);\n * this.dataY.push(points[i].usrCoords[2]);\n * }\n * };\n * board.update();\n *\n * })();\n *\n * </script><pre>\n *\n */\n Visvalingam: function(pts, numPoints) {\n var i, len, vol, lastVol,\n linkedList = [],\n heap = [],\n points = [],\n lft, rt, lft2, rt2,\n obj;\n\n len = pts.length;\n\n // At least one intermediate point is needed\n if (len <= 2) {\n return pts;\n }\n\n // Fill the linked list\n // Add first point to the linked list\n linkedList[0] = {\n used: true,\n lft: null,\n node: null\n };\n\n // Add all intermediate points to the linked list,\n // whose triangle area is nonzero.\n lft = 0;\n for (i = 1; i < len - 1; i++) {\n vol = Math.abs(JXG.Math.Numerics.det([pts[i - 1].usrCoords,\n pts[i].usrCoords,\n pts[i + 1].usrCoords]));\n if (!isNaN(vol)) {\n obj = {\n v: vol,\n idx: i\n };\n heap.push(obj);\n linkedList[i] = {\n used: true,\n lft: lft,\n node: obj\n };\n linkedList[lft].rt = i;\n lft = i;\n }\n }\n\n // Add last point to the linked list\n linkedList[len - 1] = {\n used: true,\n rt: null,\n lft: lft,\n node: null\n };\n linkedList[lft].rt = len - 1;\n\n // Remove points until only numPoints intermediate points remain\n lastVol = -Infinity;\n while (heap.length > numPoints) {\n // Sort the heap with the updated volume values\n heap.sort(function(a, b) {\n // descending sort\n return b.v - a.v;\n });\n\n // Remove the point with the smallest triangle\n i = heap.pop().idx;\n linkedList[i].used = false;\n lastVol = linkedList[i].node.v;\n\n // Update the pointers of the linked list\n lft = linkedList[i].lft;\n rt = linkedList[i].rt;\n linkedList[lft].rt = rt;\n linkedList[rt].lft = lft;\n\n // Update the values for the volumes in the linked list\n lft2 = linkedList[lft].lft;\n if (lft2 !== null) {\n vol = Math.abs(JXG.Math.Numerics.det(\n [pts[lft2].usrCoords,\n pts[lft].usrCoords,\n pts[rt].usrCoords]));\n\n linkedList[lft].node.v = (vol >= lastVol) ? vol : lastVol;\n }\n rt2 = linkedList[rt].rt;\n if (rt2 !== null) {\n vol = Math.abs(JXG.Math.Numerics.det(\n [pts[lft].usrCoords,\n pts[rt].usrCoords,\n pts[rt2].usrCoords]));\n\n linkedList[rt].node.v = (vol >= lastVol) ? vol : lastVol;\n }\n }\n\n // Return an array with the remaining points\n i = 0;\n points = [pts[i]];\n do {\n i = linkedList[i].rt;\n points.push(pts[i]);\n } while (linkedList[i].rt !== null);\n\n return points;\n }\n };\n\n return Mat.Numerics;\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Carsten Miller,\n Reinhard Oldenburg,\n Alfred Wassermann\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n\n This is a port of jcobyla\n\n - to JavaScript by Reihard Oldenburg and\n - to JSXGraph By Alfred Wassermann\n*/\n/*\n * jcobyla\n * \n * The MIT License\n *\n * Copyright (c) 2012 Anders Gustafsson, Cureos AB.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files\n * (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, \n * publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, \n * subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF \n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE \n * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION \n * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n * \n * Remarks:\n * \n * The original Fortran 77 version of this code was by Michael Powell (M.J.D.Powell @ damtp.cam.ac.uk)\n * The Fortran 90 version was by Alan Miller (Alan.Miller @ vic.cmis.csiro.au). Latest revision - 30 October 1998\n */\n\n/**\n * Constrained Optimization BY Linear Approximation in Java.\n * \n * COBYLA2 is an implementation of Powell's nonlinear derivative free constrained optimization that uses\n * a linear approximation approach. The algorithm is a sequential trust region algorithm that employs linear\n * approximations to the objective and constraint functions, where the approximations are formed by linear\n * interpolation at n + 1 points in the space of the variables and tries to maintain a regular shaped simplex\n * over iterations.\n * \n * It solves nonsmooth NLP with a moderate number of variables (about 100). Inequality constraints only.\n * \n * The initial point X is taken as one vertex of the initial simplex with zero being another, so, X should\n * not be entered as the zero vector.\n * \n * @author Anders Gustafsson, Cureos AB. Translation to Javascript by Reinhard Oldenburg, Goethe-University\n */\n\n/*global JXG: true, define: true*/\n/*jslint nomen: true, plusplus: true, continue: true*/\n\n/* depends:\n jxg\n math/math\n utils/type\n */\n\ndefine('math/nlp',['jxg'], function (JXG) {\n\n \"use strict\";\n\n /**\n * The JXG.Math.Nlp namespace holds numerical algorithms for non-linear optimization.\n * @name JXG.Math.Nlp\n * @namespace\n * \n */\n JXG.Math.Nlp = {\n\n arr: function(n) {\n var a = new Array(n),\n i;\n for (i = 0; i <n ; i++) {\n a[i] = 0.0;\n }\n return a;\n },\n\n arr2: function(n, m) {\n var i = 0,\n a = new Array(n);\n\n while (i < n) {\n a[i] = this.arr(m);\n i++;\n }\n return a;\n },\n\n arraycopy: function(x, a, iox, b, n) {\n var i = 0;\n while (i < n) {\n iox[i + b] = x[i + a];\n i++;\n }\n },\n\n // status Variables\n Normal: 0,\n MaxIterationsReached: 1,\n DivergingRoundingErrors: 2,\n\n /**\n * Minimizes the objective function F with respect to a set of inequality constraints CON,\n * and returns the optimal variable array. F and CON may be non-linear, and should preferably be smooth.\n * Calls {@link JXG.Math.Nlp#cobylb}.\n *\n * @param calcfc Interface implementation for calculating objective function and constraints.\n * @param n Number of variables.\n * @param m Number of constraints.\n * @param x On input initial values of the variables (zero-based array). On output\n * optimal values of the variables obtained in the COBYLA minimization.\n * @param rhobeg Initial size of the simplex.\n * @param rhoend Final value of the simplex.\n * @param iprint Print level, 0 <= iprint <= 3, where 0 provides no output and\n * 3 provides full output to the console.\n * @param maxfun Maximum number of function evaluations before terminating.\n * @returns {Number} Exit status of the COBYLA2 optimization.\n */\n FindMinimum: function(calcfc, n, m, x, rhobeg, rhoend, iprint, maxfun) {\n // CobylaExitStatus FindMinimum(final Calcfc calcfc, int n, int m, double[] x, double rhobeg, double rhoend, int iprint, int maxfun)\n // This subroutine minimizes an objective function F(X) subject to M\n // inequality constraints on X, where X is a vector of variables that has\n // N components. The algorithm employs linear approximations to the\n // objective and constraint functions, the approximations being formed by\n // linear interpolation at N+1 points in the space of the variables.\n // We regard these interpolation points as vertices of a simplex. The\n // parameter RHO controls the size of the simplex and it is reduced\n // automatically from RHOBEG to RHOEND. For each RHO the subroutine tries\n // to achieve a good vector of variables for the current size, and then\n // RHO is reduced until the value RHOEND is reached. Therefore RHOBEG and\n // RHOEND should be set to reasonable initial changes to and the required\n // accuracy in the variables respectively, but this accuracy should be\n // viewed as a subject for experimentation because it is not guaranteed.\n // The subroutine has an advantage over many of its competitors, however,\n // which is that it treats each constraint individually when calculating\n // a change to the variables, instead of lumping the constraints together\n // into a single penalty function. The name of the subroutine is derived\n // from the phrase Constrained Optimization BY Linear Approximations.\n\n // The user must set the values of N, M, RHOBEG and RHOEND, and must\n // provide an initial vector of variables in X. Further, the value of\n // IPRINT should be set to 0, 1, 2 or 3, which controls the amount of\n // printing during the calculation. Specifically, there is no output if\n // IPRINT=0 and there is output only at the end of the calculation if\n // IPRINT=1. Otherwise each new value of RHO and SIGMA is printed.\n // Further, the vector of variables and some function information are\n // given either when RHO is reduced or when each new value of F(X) is\n // computed in the cases IPRINT=2 or IPRINT=3 respectively. Here SIGMA\n // is a penalty parameter, it being assumed that a change to X is an\n // improvement if it reduces the merit function\n // F(X)+SIGMA*MAX(0.0, - C1(X), - C2(X),..., - CM(X)),\n // where C1,C2,...,CM denote the constraint functions that should become\n // nonnegative eventually, at least to the precision of RHOEND. In the\n // printed output the displayed term that is multiplied by SIGMA is\n // called MAXCV, which stands for 'MAXimum Constraint Violation'. The\n // argument ITERS is an integer variable that must be set by the user to a\n // limit on the number of calls of CALCFC, the purpose of this routine being\n // given below. The value of ITERS will be altered to the number of calls\n // of CALCFC that are made.\n // In order to define the objective and constraint functions, we require\n // a subroutine that has the name and arguments\n // SUBROUTINE CALCFC (N,M,X,F,CON)\n // DIMENSION X(:),CON(:) .\n // The values of N and M are fixed and have been defined already, while\n // X is now the current vector of variables. The subroutine should return\n // the objective and constraint functions at X in F and CON(1),CON(2),\n // ...,CON(M). Note that we are trying to adjust X so that F(X) is as\n // small as possible subject to the constraint functions being nonnegative.\n\n // Local variables\n var mpp = m + 2,\n status,\n // Internal base-1 X array\n iox = this.arr(n + 1),\n that = this,\n fcalcfc;\n\n iox[0] = 0.0;\n this.arraycopy(x, 0, iox, 1, n);\n\n // Internal representation of the objective and constraints calculation method,\n // accounting for that X and CON arrays in the cobylb method are base-1 arrays.\n fcalcfc = function(n, m, thisx, con) { // int n, int m, double[] x, double[] con\n var ix = that.arr(n),\n ocon, f;\n\n that.arraycopy(thisx, 1, ix, 0, n);\n ocon = that.arr(m);\n f = calcfc(n, m, ix, ocon);\n that.arraycopy(ocon, 0, con, 1, m);\n return f;\n };\n\n status = this.cobylb(fcalcfc, n, m, mpp, iox, rhobeg, rhoend, iprint, maxfun);\n this.arraycopy(iox, 1, x, 0, n);\n\n return status;\n },\n\n // private static CobylaExitStatus cobylb(Calcfc calcfc, int n, int m, int mpp, double[] x,\n // double rhobeg, double rhoend, int iprint, int maxfun)\n /**\n * JavaScript implementation of the non-linear optimization method COBYLA.\n * @param {Function} calcfc \n * @param {Number} n \n * @param {Number} m \n * @param {Number} mpp \n * @param {Number} x \n * @param {Number} rhobeg \n * @param {Number} rhoend \n * @param {Number} iprint \n * @param {Number} maxfun \n * @returns {Number} Exit status of the COBYLA2 optimization\n */\n cobylb: function (calcfc, n, m, mpp, x, rhobeg, rhoend, iprint, maxfun) {\n // calcf ist funktion die aufgerufen wird wie calcfc(n, m, ix, ocon)\n // N.B. Arguments CON, SIM, SIMI, DATMAT, A, VSIG, VETA, SIGBAR, DX, W & IACT\n // have been removed.\n\n // Set the initial values of some parameters. The last column of SIM holds\n // the optimal vertex of the current simplex, and the preceding N columns\n // hold the displacements from the optimal vertex to the other vertices.\n // Further, SIMI holds the inverse of the matrix that is contained in the\n // first N columns of SIM.\n\n // Local variables\n var status = -1,\n\n alpha = 0.25,\n beta = 2.1,\n gamma = 0.5,\n delta = 1.1,\n\n f = 0.0,\n resmax = 0.0,\n total,\n\n np = n + 1,\n mp = m + 1,\n rho = rhobeg,\n parmu = 0.0,\n\n iflag = false,\n ifull = false,\n parsig = 0.0,\n prerec = 0.0,\n prerem = 0.0,\n\n con = this.arr(1 + mpp),\n sim = this.arr2(1 + n, 1 + np),\n simi = this.arr2(1 + n, 1 + n),\n datmat = this.arr2(1 + mpp, 1 + np),\n a = this.arr2(1 + n, 1 + mp),\n vsig = this.arr(1 + n),\n veta = this.arr(1 + n),\n sigbar = this.arr(1 + n),\n dx = this.arr(1 + n),\n w = this.arr(1 + n),\n i, j, k, l,\n temp, tempa, nfvals,\n jdrop, ibrnch,\n skipVertexIdent,\n phimin, nbest,\n error,\n pareta, wsig, weta,\n cvmaxp, cvmaxm, dxsign,\n resnew, barmu, phi,\n vmold, vmnew, trured, ratio, edgmax, cmin, cmax, denom;\n\n if (iprint >= 2) {\n console.log(\"The initial value of RHO is \" + rho + \" and PARMU is set to zero.\");\n }\n\n nfvals = 0;\n temp = 1.0 / rho;\n\n for (i = 1; i <= n; ++i) {\n sim[i][np] = x[i];\n sim[i][i] = rho;\n simi[i][i] = temp;\n }\n\n jdrop = np;\n ibrnch = false;\n\n // Make the next call of the user-supplied subroutine CALCFC. These\n // instructions are also used for calling CALCFC during the iterations of\n // the algorithm.\n //alert(\"Iteration \"+nfvals+\" x=\"+x);\n L_40:\n do {\n if (nfvals >= maxfun && nfvals > 0) {\n status = this.MaxIterationsReached;\n break L_40;\n }\n\n ++nfvals;\n f = calcfc(n, m, x, con);\n resmax = 0.0;\n for (k = 1; k <= m; ++k) {\n resmax = Math.max(resmax, -con[k]);\n }\n //alert( \" f=\"+f+\" resmax=\"+resmax);\n\n if (nfvals === iprint - 1 || iprint === 3) {\n this.PrintIterationResult(nfvals, f, resmax, x, n, iprint);\n }\n\n con[mp] = f;\n con[mpp] = resmax;\n\n // Set the recently calculated function values in a column of DATMAT. This\n // array has a column for each vertex of the current simplex, the entries of\n // each column being the values of the constraint functions (if any)\n // followed by the objective function and the greatest constraint violation\n // at the vertex.\n skipVertexIdent = true;\n if (!ibrnch) {\n skipVertexIdent = false;\n\n for (i = 1; i <= mpp; ++i) {\n datmat[i][jdrop] = con[i];\n }\n\n if (nfvals <= np) {\n // Exchange the new vertex of the initial simplex with the optimal vertex if\n // necessary. Then, if the initial simplex is not complete, pick its next\n // vertex and calculate the function values there.\n\n if (jdrop <= n) {\n if (datmat[mp][np] <= f) {\n x[jdrop] = sim[jdrop][np];\n } else {\n sim[jdrop][np] = x[jdrop];\n for (k = 1; k <= mpp; ++k) {\n datmat[k][jdrop] = datmat[k][np];\n datmat[k][np] = con[k];\n }\n for (k = 1; k <= jdrop; ++k) {\n sim[jdrop][k] = -rho;\n temp = 0.0;\n for (i = k; i <= jdrop; ++i) {\n temp -= simi[i][k];\n }\n simi[jdrop][k] = temp;\n }\n }\n }\n if (nfvals <= n) {\n jdrop = nfvals;\n x[jdrop] += rho;\n continue L_40;\n }\n }\n ibrnch = true;\n }\n\n L_140:\n do {\n L_550:\n do {\n if (!skipVertexIdent) {\n // Identify the optimal vertex of the current simplex.\n phimin = datmat[mp][np] + parmu * datmat[mpp][np];\n nbest = np;\n\n for (j = 1; j <= n; ++j) {\n temp = datmat[mp][j] + parmu * datmat[mpp][j];\n if (temp < phimin) {\n nbest = j;\n phimin = temp;\n } else if (temp === phimin && parmu === 0.0 && datmat[mpp][j] < datmat[mpp][nbest]) {\n nbest = j;\n }\n }\n\n // Switch the best vertex into pole position if it is not there already,\n // and also update SIM, SIMI and DATMAT.\n if (nbest <= n) {\n for (i = 1; i <= mpp; ++i) {\n temp = datmat[i][np];\n datmat[i][np] = datmat[i][nbest];\n datmat[i][nbest] = temp;\n }\n for (i = 1; i <= n; ++i) {\n temp = sim[i][nbest];\n sim[i][nbest] = 0.0;\n sim[i][np] += temp;\n\n tempa = 0.0;\n for (k = 1; k <= n; ++k)\n {\n sim[i][k] -= temp;\n tempa -= simi[k][i];\n }\n simi[nbest][i] = tempa;\n }\n }\n\n // Make an error return if SIGI is a poor approximation to the inverse of\n // the leading N by N submatrix of SIG.\n error = 0.0;\n for (i = 1; i <= n; ++i) {\n for (j = 1; j <= n; ++j) {\n temp = this.DOT_PRODUCT(\n this.PART(this.ROW(simi, i), 1, n),\n this.PART(this.COL(sim, j), 1, n)\n ) - (i === j ? 1.0 : 0.0);\n error = Math.max(error, Math.abs(temp));\n }\n }\n if (error > 0.1) {\n status = this.DivergingRoundingErrors;\n break L_40;\n }\n\n // Calculate the coefficients of the linear approximations to the objective\n // and constraint functions, placing minus the objective function gradient\n // after the constraint gradients in the array A. The vector W is used for\n // working space.\n for (k = 1; k <= mp; ++k) {\n con[k] = -datmat[k][np];\n for (j = 1; j <= n; ++j) {\n w[j] = datmat[k][j] + con[k];\n }\n\n for (i = 1; i <= n; ++i) {\n a[i][k] = (k === mp ? -1.0 : 1.0) * this.DOT_PRODUCT(\n this.PART(w, 1, n), this.PART(this.COL(simi, i), 1, n));\n }\n }\n\n // Calculate the values of sigma and eta, and set IFLAG = 0 if the current\n // simplex is not acceptable.\n iflag = true;\n parsig = alpha * rho;\n pareta = beta * rho;\n\n for (j = 1; j <= n; ++j) {\n wsig = 0.0;\n for (k = 1; k <= n; ++k) {\n wsig += simi[j][k] * simi[j][k];\n }\n weta = 0.0;\n for (k = 1; k <= n; ++k) {\n weta += sim[k][j] * sim[k][j];\n }\n vsig[j] = 1.0 / Math.sqrt(wsig);\n veta[j] = Math.sqrt(weta);\n if (vsig[j] < parsig || veta[j] > pareta) { iflag = false; }\n }\n\n // If a new vertex is needed to improve acceptability, then decide which\n // vertex to drop from the simplex.\n if (!ibrnch && !iflag) {\n jdrop = 0;\n temp = pareta;\n for (j = 1; j <= n; ++j) {\n if (veta[j] > temp) {\n jdrop = j;\n temp = veta[j];\n }\n }\n if (jdrop === 0) {\n for (j = 1; j <= n; ++j) {\n if (vsig[j] < temp) {\n jdrop = j;\n temp = vsig[j];\n }\n }\n }\n\n // Calculate the step to the new vertex and its sign.\n temp = gamma * rho * vsig[jdrop];\n for (k = 1; k <= n; ++k) {\n dx[k] = temp * simi[jdrop][k];\n }\n cvmaxp = 0.0;\n cvmaxm = 0.0;\n total = 0.0;\n for (k = 1; k <= mp; ++k) {\n total = this.DOT_PRODUCT(\n this.PART(this.COL(a, k), 1, n),\n this.PART(dx, 1, n)\n );\n if (k < mp) {\n temp = datmat[k][np];\n cvmaxp = Math.max(cvmaxp, -total - temp);\n cvmaxm = Math.max(cvmaxm, total - temp);\n }\n }\n dxsign = parmu * (cvmaxp - cvmaxm) > 2.0 * total ? -1.0 : 1.0;\n\n // Update the elements of SIM and SIMI, and set the next X.\n temp = 0.0;\n for (i = 1; i <= n; ++i) {\n dx[i] = dxsign * dx[i];\n sim[i][jdrop] = dx[i];\n temp += simi[jdrop][i] * dx[i];\n }\n for (k = 1; k <= n; ++k) {\n simi[jdrop][k] /= temp;\n }\n\n for (j = 1; j <= n; ++j) {\n if (j !== jdrop) {\n temp = this.DOT_PRODUCT(\n this.PART(this.ROW(simi, j), 1, n),\n this.PART(dx, 1, n)\n );\n for (k = 1; k <= n; ++k) {\n simi[j][k] -= temp * simi[jdrop][k];\n }\n }\n x[j] = sim[j][np] + dx[j];\n }\n continue L_40;\n }\n\n // Calculate DX = x(*)-x(0).\n // Branch if the length of DX is less than 0.5*RHO.\n ifull = this.trstlp(n, m, a, con, rho, dx);\n if (!ifull) {\n temp = 0.0;\n for (k = 1; k <= n; ++k) {\n temp += dx[k] * dx[k];\n }\n if (temp < 0.25 * rho * rho) {\n ibrnch = true;\n break L_550;\n }\n }\n\n // Predict the change to F and the new maximum constraint violation if the\n // variables are altered from x(0) to x(0) + DX.\n total = 0.0;\n resnew = 0.0;\n con[mp] = 0.0;\n for (k = 1; k <= mp; ++k) {\n total = con[k] - this.DOT_PRODUCT(this.PART(this.COL(a, k), 1, n), this.PART(dx, 1, n));\n if (k < mp) { resnew = Math.max(resnew, total); }\n }\n\n // Increase PARMU if necessary and branch back if this change alters the\n // optimal vertex. Otherwise PREREM and PREREC will be set to the predicted\n // reductions in the merit function and the maximum constraint violation\n // respectively.\n prerec = datmat[mpp][np] - resnew;\n barmu = prerec > 0.0 ? total / prerec : 0.0;\n if (parmu < 1.5 * barmu) {\n parmu = 2.0 * barmu;\n if (iprint >= 2) { console.log(\"Increase in PARMU to \" + parmu); }\n phi = datmat[mp][np] + parmu * datmat[mpp][np];\n for (j = 1; j <= n; ++j) {\n temp = datmat[mp][j] + parmu * datmat[mpp][j];\n if (temp < phi || (temp === phi && parmu === 0.0 && datmat[mpp][j] < datmat[mpp][np])) {\n continue L_140;\n }\n }\n }\n prerem = parmu * prerec - total;\n\n // Calculate the constraint and objective functions at x(*).\n // Then find the actual reduction in the merit function.\n for (k = 1; k <= n; ++k) {\n x[k] = sim[k][np] + dx[k];\n }\n ibrnch = true;\n continue L_40;\n }\n\n skipVertexIdent = false;\n vmold = datmat[mp][np] + parmu * datmat[mpp][np];\n vmnew = f + parmu * resmax;\n trured = vmold - vmnew;\n if (parmu === 0.0 && f === datmat[mp][np]) {\n prerem = prerec;\n trured = datmat[mpp][np] - resmax;\n }\n\n // Begin the operations that decide whether x(*) should replace one of the\n // vertices of the current simplex, the change being mandatory if TRURED is\n // positive. Firstly, JDROP is set to the index of the vertex that is to be\n // replaced.\n ratio = trured <= 0.0 ? 1.0 : 0.0;\n jdrop = 0;\n for (j = 1; j <= n; ++j) {\n temp = Math.abs(this.DOT_PRODUCT(this.PART(this.ROW(simi, j), 1, n), this.PART(dx, 1, n)));\n if (temp > ratio) {\n jdrop = j;\n ratio = temp;\n }\n sigbar[j] = temp * vsig[j];\n }\n\n // Calculate the value of ell.\n\n edgmax = delta * rho;\n l = 0;\n for (j = 1; j <= n; ++j) {\n if (sigbar[j] >= parsig || sigbar[j] >= vsig[j]) {\n temp = veta[j];\n if (trured > 0.0) {\n temp = 0.0;\n for (k = 1; k <= n; ++k) {\n temp += Math.pow(dx[k] - sim[k][j], 2.0);\n }\n temp = Math.sqrt(temp);\n }\n if (temp > edgmax) {\n l = j;\n edgmax = temp;\n }\n }\n }\n if (l > 0) { jdrop = l; }\n\n if (jdrop !== 0) {\n // Revise the simplex by updating the elements of SIM, SIMI and DATMAT.\n temp = 0.0;\n for (i = 1; i <= n; ++i) {\n sim[i][jdrop] = dx[i];\n temp += simi[jdrop][i] * dx[i];\n }\n for (k = 1; k <= n; ++k) { simi[jdrop][k] /= temp; }\n for (j = 1; j <= n; ++j) {\n if (j !== jdrop) {\n temp = this.DOT_PRODUCT(this.PART(this.ROW(simi, j), 1, n), this.PART(dx, 1, n));\n for (k = 1; k <= n; ++k) {\n simi[j][k] -= temp * simi[jdrop][k];\n }\n }\n }\n for (k = 1; k <= mpp; ++k) {\n datmat[k][jdrop] = con[k];\n }\n\n // Branch back for further iterations with the current RHO.\n if (trured > 0.0 && trured >= 0.1 * prerem) {\n continue L_140;\n }\n }\n } while (false);\n\n if (!iflag) {\n ibrnch = false;\n continue L_140;\n }\n\n if (rho <= rhoend) {\n status = this.Normal;\n break L_40;\n }\n\n // Otherwise reduce RHO if it is not at its least value and reset PARMU.\n cmin = 0.0;\n cmax = 0.0;\n rho *= 0.5;\n if (rho <= 1.5 * rhoend) { rho = rhoend; }\n if (parmu > 0.0) {\n denom = 0.0;\n for (k = 1; k <= mp; ++k) {\n cmin = datmat[k][np];\n cmax = cmin;\n for (i = 1; i <= n; ++i) {\n cmin = Math.min(cmin, datmat[k][i]);\n cmax = Math.max(cmax, datmat[k][i]);\n }\n if (k <= m && cmin < 0.5 * cmax) {\n temp = Math.max(cmax, 0.0) - cmin;\n denom = denom <= 0.0 ? temp : Math.min(denom, temp);\n }\n }\n if (denom === 0.0) {\n parmu = 0.0;\n } else if (cmax - cmin < parmu * denom) {\n parmu = (cmax - cmin) / denom;\n }\n }\n if (iprint >= 2) {\n console.log(\"Reduction in RHO to \"+rho+\" and PARMU = \"+parmu);\n }\n if (iprint === 2) {\n this.PrintIterationResult(nfvals, datmat[mp][np], datmat[mpp][np], this.COL(sim, np), n, iprint);\n }\n } while (true);\n } while (true);\n\n switch (status) {\n case this.Normal:\n if (iprint >= 1) { console.log(\"%nNormal return from subroutine COBYLA%n\"); }\n if (ifull) {\n if (iprint >= 1) { this.PrintIterationResult(nfvals, f, resmax, x, n, iprint); }\n return status;\n }\n break;\n case this.MaxIterationsReached:\n if (iprint >= 1) {\n console.log(\"%nReturn from subroutine COBYLA because the MAXFUN limit has been reached.%n\");\n }\n break;\n case this.DivergingRoundingErrors:\n if (iprint >= 1) {\n console.log(\"%nReturn from subroutine COBYLA because rounding errors are becoming damaging.%n\");\n }\n break;\n }\n\n for (k = 1; k <= n; ++k) { x[k] = sim[k][np]; }\n f = datmat[mp][np];\n resmax = datmat[mpp][np];\n if (iprint >= 1) { this.PrintIterationResult(nfvals, f, resmax, x, n, iprint); }\n\n return status;\n },\n\n trstlp: function(n, m, a, b, rho, dx) { //(int n, int m, double[][] a, double[] b, double rho, double[] dx)\n // N.B. Arguments Z, ZDOTA, VMULTC, SDIRN, DXNEW, VMULTD & IACT have been removed.\n\n // This subroutine calculates an N-component vector DX by applying the\n // following two stages. In the first stage, DX is set to the shortest\n // vector that minimizes the greatest violation of the constraints\n // A(1,K)*DX(1)+A(2,K)*DX(2)+...+A(N,K)*DX(N) .GE. B(K), K = 2,3,...,M,\n // subject to the Euclidean length of DX being at most RHO. If its length is\n // strictly less than RHO, then we use the resultant freedom in DX to\n // minimize the objective function\n // -A(1,M+1)*DX(1) - A(2,M+1)*DX(2) - ... - A(N,M+1)*DX(N)\n // subject to no increase in any greatest constraint violation. This\n // notation allows the gradient of the objective function to be regarded as\n // the gradient of a constraint. Therefore the two stages are distinguished\n // by MCON .EQ. M and MCON .GT. M respectively. It is possible that a\n // degeneracy may prevent DX from attaining the target length RHO. Then the\n // value IFULL = 0 would be set, but usually IFULL = 1 on return.\n //\n // In general NACT is the number of constraints in the active set and\n // IACT(1),...,IACT(NACT) are their indices, while the remainder of IACT\n // contains a permutation of the remaining constraint indices. Further, Z\n // is an orthogonal matrix whose first NACT columns can be regarded as the\n // result of Gram-Schmidt applied to the active constraint gradients. For\n // J = 1,2,...,NACT, the number ZDOTA(J) is the scalar product of the J-th\n // column of Z with the gradient of the J-th active constraint. DX is the\n // current vector of variables and here the residuals of the active\n // constraints should be zero. Further, the active constraints have\n // nonnegative Lagrange multipliers that are held at the beginning of\n // VMULTC. The remainder of this vector holds the residuals of the inactive\n // constraints at DX, the ordering of the components of VMULTC being in\n // agreement with the permutation of the indices of the constraints that is\n // in IACT. All these residuals are nonnegative, which is achieved by the\n // shift RESMAX that makes the least residual zero.\n\n // Initialize Z and some other variables. The value of RESMAX will be\n // appropriate to DX = 0, while ICON will be the index of a most violated\n // constraint if RESMAX is positive. Usually during the first stage the\n // vector SDIRN gives a search direction that reduces all the active\n // constraint violations by one simultaneously.\n\n // Local variables\n\n var temp = 0,\n nactx = 0,\n resold = 0.0,\n\n z = this.arr2(1 + n, 1 + n),\n zdota = this.arr(2 + m),\n vmultc = this.arr(2 + m),\n sdirn = this.arr(1 + n),\n dxnew = this.arr(1 + n),\n vmultd = this.arr(2 + m),\n iact = this.arr(2 + m),\n\n mcon = m,\n nact = 0,\n icon, resmax,\n i, k,\n first,\n optold, icount, step, stpful, optnew,\n ratio, isave, vsave,\n total,\n kp, kk, sp, alpha, beta,\n tot, spabs, acca, accb,\n zdotv, zdvabs, kw,\n dd, ss, sd,\n zdotw, zdwabs,\n kl, sumabs, tempa;\n\n for (i = 1; i <= n; ++i) {\n z[i][i] = 1.0;\n dx[i] = 0.0;\n }\n\n icon = 0;\n resmax = 0.0;\n if (m >= 1) {\n for (k = 1; k <= m; ++k) {\n if (b[k] > resmax) {\n resmax = b[k];\n icon = k;\n }\n }\n for (k = 1; k <= m; ++k) {\n iact[k] = k;\n vmultc[k] = resmax - b[k];\n }\n }\n\n // End the current stage of the calculation if 3 consecutive iterations\n // have either failed to reduce the best calculated value of the objective\n // function or to increase the number of active constraints since the best\n // value was calculated. This strategy prevents cycling, but there is a\n // remote possibility that it will cause premature termination.\n\n first = true;\n do {\n L_60:\n do {\n if (!first || (first && resmax === 0.0)) {\n mcon = m + 1;\n icon = mcon;\n iact[mcon] = mcon;\n vmultc[mcon] = 0.0;\n }\n first = false;\n\n optold = 0.0;\n icount = 0;\n step = 0;\n stpful = 0;\n\n L_70:\n do {\n optnew = (mcon === m) ? resmax : -this.DOT_PRODUCT(\n this.PART(dx, 1, n), this.PART(this.COL(a, mcon), 1, n)\n );\n\n if (icount === 0 || optnew < optold) {\n optold = optnew;\n nactx = nact;\n icount = 3;\n } else if (nact > nactx) {\n nactx = nact;\n icount = 3;\n } else {\n --icount;\n }\n if (icount === 0) { break L_60; }\n\n // If ICON exceeds NACT, then we add the constraint with index IACT(ICON) to\n // the active set. Apply Givens rotations so that the last N-NACT-1 columns\n // of Z are orthogonal to the gradient of the new constraint, a scalar\n // product being set to zero if its nonzero value could be due to computer\n // rounding errors. The array DXNEW is used for working space.\n ratio = 0;\n if (icon <= nact) {\n if (icon < nact) {\n // Delete the constraint that has the index IACT(ICON) from the active set.\n\n isave = iact[icon];\n vsave = vmultc[icon];\n k = icon;\n do {\n kp = k + 1;\n kk = iact[kp];\n sp = this.DOT_PRODUCT(\n this.PART(this.COL(z, k), 1, n),\n this.PART(this.COL(a, kk), 1, n)\n );\n temp = Math.sqrt(sp * sp + zdota[kp] * zdota[kp]);\n alpha = zdota[kp] / temp;\n beta = sp / temp;\n zdota[kp] = alpha * zdota[k];\n zdota[k] = temp;\n for (i = 1; i <= n; ++i) {\n temp = alpha * z[i][kp] + beta * z[i][k];\n z[i][kp] = alpha * z[i][k] - beta * z[i][kp];\n z[i][k] = temp;\n }\n iact[k] = kk;\n vmultc[k] = vmultc[kp];\n k = kp;\n } while (k < nact);\n\n iact[k] = isave;\n vmultc[k] = vsave;\n }\n --nact;\n\n // If stage one is in progress, then set SDIRN to the direction of the next\n // change to the current vector of variables.\n if (mcon > m) {\n // Pick the next search direction of stage two.\n temp = 1.0 / zdota[nact];\n for (k = 1; k <= n; ++k) { sdirn[k] = temp * z[k][nact]; }\n } else {\n temp = this.DOT_PRODUCT(\n this.PART(sdirn, 1, n), this.PART(this.COL(z, nact + 1), 1, n)\n );\n for (k = 1; k <= n; ++k) { sdirn[k] -= temp * z[k][nact + 1]; }\n }\n } else {\n kk = iact[icon];\n for (k = 1; k <= n; ++k) { dxnew[k] = a[k][kk]; }\n tot = 0.0;\n\n // {\n k = n;\n while (k > nact) {\n sp = 0.0;\n spabs = 0.0;\n for (i = 1; i <= n; ++i) {\n temp = z[i][k] * dxnew[i];\n sp += temp;\n spabs += Math.abs(temp);\n }\n acca = spabs + 0.1 * Math.abs(sp);\n accb = spabs + 0.2 * Math.abs(sp);\n if (spabs >= acca || acca >= accb) { sp = 0.0; }\n if (tot === 0.0) {\n tot = sp;\n } else {\n kp = k + 1;\n temp = Math.sqrt(sp * sp + tot * tot);\n alpha = sp / temp;\n beta = tot / temp;\n tot = temp;\n for (i = 1; i <= n; ++i) {\n temp = alpha * z[i][k] + beta * z[i][kp];\n z[i][kp] = alpha * z[i][kp] - beta * z[i][k];\n z[i][k] = temp;\n }\n }\n --k;\n }\n // }\n\n if (tot === 0.0) {\n // The next instruction is reached if a deletion has to be made from the\n // active set in order to make room for the new active constraint, because\n // the new constraint gradient is a linear combination of the gradients of\n // the old active constraints. Set the elements of VMULTD to the multipliers\n // of the linear combination. Further, set IOUT to the index of the\n // constraint to be deleted, but branch if no suitable index can be found.\n\n ratio = -1.0;\n //{\n k = nact;\n do {\n zdotv = 0.0;\n zdvabs = 0.0;\n\n for (i = 1; i <= n; ++i) {\n temp = z[i][k] * dxnew[i];\n zdotv += temp;\n zdvabs += Math.abs(temp);\n }\n acca = zdvabs + 0.1 * Math.abs(zdotv);\n accb = zdvabs + 0.2 * Math.abs(zdotv);\n if (zdvabs < acca && acca < accb) {\n temp = zdotv / zdota[k];\n if (temp > 0.0 && iact[k] <= m) {\n tempa = vmultc[k] / temp;\n if (ratio < 0.0 || tempa < ratio) { ratio = tempa; }\n }\n\n if (k >= 2) {\n kw = iact[k];\n for (i = 1; i <= n; ++i) { dxnew[i] -= temp * a[i][kw]; }\n }\n vmultd[k] = temp;\n } else {\n vmultd[k] = 0.0;\n }\n } while (--k > 0);\n //}\n if (ratio < 0.0) { break L_60; }\n\n // Revise the Lagrange multipliers and reorder the active constraints so\n // that the one to be replaced is at the end of the list. Also calculate the\n // new value of ZDOTA(NACT) and branch if it is not acceptable.\n\n for (k = 1; k <= nact; ++k) {\n vmultc[k] = Math.max(0.0, vmultc[k] - ratio * vmultd[k]);\n }\n if (icon < nact) {\n isave = iact[icon];\n vsave = vmultc[icon];\n k = icon;\n do {\n kp = k + 1;\n kw = iact[kp];\n sp = this.DOT_PRODUCT(\n this.PART(this.COL(z, k), 1, n),\n this.PART(this.COL(a, kw), 1, n)\n );\n temp = Math.sqrt(sp * sp + zdota[kp] * zdota[kp]);\n alpha = zdota[kp] / temp;\n beta = sp / temp;\n zdota[kp] = alpha * zdota[k];\n zdota[k] = temp;\n for (i = 1; i <= n; ++i) {\n temp = alpha * z[i][kp] + beta * z[i][k];\n z[i][kp] = alpha * z[i][k] - beta * z[i][kp];\n z[i][k] = temp;\n }\n iact[k] = kw;\n vmultc[k] = vmultc[kp];\n k = kp;\n } while (k < nact);\n iact[k] = isave;\n vmultc[k] = vsave;\n }\n temp = this.DOT_PRODUCT(\n this.PART(this.COL(z, nact), 1, n),\n this.PART(this.COL(a, kk), 1, n)\n );\n if (temp === 0.0) { break L_60; }\n zdota[nact] = temp;\n vmultc[icon] = 0.0;\n vmultc[nact] = ratio;\n } else {\n // Add the new constraint if this can be done without a deletion from the\n // active set.\n\n ++nact;\n zdota[nact] = tot;\n vmultc[icon] = vmultc[nact];\n vmultc[nact] = 0.0;\n }\n\n // Update IACT and ensure that the objective function continues to be\n // treated as the last active constraint when MCON>M.\n\n iact[icon] = iact[nact];\n iact[nact] = kk;\n if (mcon > m && kk !== mcon) {\n k = nact - 1;\n sp = this.DOT_PRODUCT(\n this.PART(this.COL(z, k), 1, n),\n this.PART(this.COL(a, kk), 1, n)\n );\n temp = Math.sqrt(sp * sp + zdota[nact] * zdota[nact]);\n alpha = zdota[nact] / temp;\n beta = sp / temp;\n zdota[nact] = alpha * zdota[k];\n zdota[k] = temp;\n for (i = 1; i <= n; ++i) {\n temp = alpha * z[i][nact] + beta * z[i][k];\n z[i][nact] = alpha * z[i][k] - beta * z[i][nact];\n z[i][k] = temp;\n }\n iact[nact] = iact[k];\n iact[k] = kk;\n temp = vmultc[k];\n vmultc[k] = vmultc[nact];\n vmultc[nact] = temp;\n }\n\n // If stage one is in progress, then set SDIRN to the direction of the next\n // change to the current vector of variables.\n if (mcon > m) {\n // Pick the next search direction of stage two.\n temp = 1.0 / zdota[nact];\n for (k = 1; k <= n; ++k) { sdirn[k] = temp * z[k][nact]; }\n } else {\n kk = iact[nact];\n temp = (this.DOT_PRODUCT(\n this.PART(sdirn, 1, n),\n this.PART(this.COL(a, kk), 1, n)\n ) - 1.0) / zdota[nact];\n for (k = 1; k <= n; ++k) { sdirn[k] -= temp * z[k][nact]; }\n }\n }\n\n // Calculate the step to the boundary of the trust region or take the step\n // that reduces RESMAX to zero. The two statements below that include the\n // factor 1.0E-6 prevent some harmless underflows that occurred in a test\n // calculation. Further, we skip the step if it could be zero within a\n // reasonable tolerance for computer rounding errors.\n dd = rho * rho;\n sd = 0.0;\n ss = 0.0;\n for (i = 1; i <= n; ++i) {\n if (Math.abs(dx[i]) >= 1.0E-6 * rho) { dd -= dx[i] * dx[i]; }\n sd += dx[i] * sdirn[i];\n ss += sdirn[i] * sdirn[i];\n }\n if (dd <= 0.0) { break L_60; }\n temp = Math.sqrt(ss * dd);\n if (Math.abs(sd) >= 1.0E-6 * temp) { temp = Math.sqrt(ss * dd + sd * sd); }\n stpful = dd / (temp + sd);\n step = stpful;\n if (mcon === m) {\n acca = step + 0.1 * resmax;\n accb = step + 0.2 * resmax;\n if (step >= acca || acca >= accb) { break L_70; }\n step = Math.min(step, resmax);\n }\n\n // Set DXNEW to the new variables if STEP is the steplength, and reduce\n // RESMAX to the corresponding maximum residual if stage one is being done.\n // Because DXNEW will be changed during the calculation of some Lagrange\n // multipliers, it will be restored to the following value later.\n for (k = 1; k <= n; ++k) { dxnew[k] = dx[k] + step * sdirn[k]; }\n if (mcon === m) {\n resold = resmax;\n resmax = 0.0;\n for (k = 1; k <= nact; ++k) {\n kk = iact[k];\n temp = b[kk] - this.DOT_PRODUCT(\n this.PART(this.COL(a, kk), 1, n), this.PART(dxnew, 1, n)\n );\n resmax = Math.max(resmax, temp);\n }\n }\n\n // Set VMULTD to the VMULTC vector that would occur if DX became DXNEW. A\n // device is included to force VMULTD(K) = 0.0 if deviations from this value\n // can be attributed to computer rounding errors. First calculate the new\n // Lagrange multipliers.\n //{\n k = nact;\n do {\n zdotw = 0.0;\n zdwabs = 0.0;\n for (i = 1; i <= n; ++i) {\n temp = z[i][k] * dxnew[i];\n zdotw += temp;\n zdwabs += Math.abs(temp);\n }\n acca = zdwabs + 0.1 * Math.abs(zdotw);\n accb = zdwabs + 0.2 * Math.abs(zdotw);\n if (zdwabs >= acca || acca >= accb) { zdotw = 0.0; }\n vmultd[k] = zdotw / zdota[k];\n if (k >= 2) {\n kk = iact[k];\n for (i = 1; i <= n; ++i) { dxnew[i] -= vmultd[k] * a[i][kk]; }\n }\n } while (k-- >= 2);\n if (mcon > m) { vmultd[nact] = Math.max(0.0, vmultd[nact]); }\n //}\n\n // Complete VMULTC by finding the new constraint residuals.\n\n for (k = 1; k <= n; ++k) { dxnew[k] = dx[k] + step * sdirn[k]; }\n if (mcon > nact) {\n kl = nact + 1;\n for (k = kl; k <= mcon; ++k) {\n kk = iact[k];\n total = resmax - b[kk];\n sumabs = resmax + Math.abs(b[kk]);\n for (i = 1; i <= n; ++i) {\n temp = a[i][kk] * dxnew[i];\n total += temp;\n sumabs += Math.abs(temp);\n }\n acca = sumabs + 0.1 * Math.abs(total);\n accb = sumabs + 0.2 * Math.abs(total);\n if (sumabs >= acca || acca >= accb) { total = 0.0; }\n vmultd[k] = total;\n }\n }\n\n // Calculate the fraction of the step from DX to DXNEW that will be taken.\n\n ratio = 1.0;\n icon = 0;\n for (k = 1; k <= mcon; ++k) {\n if (vmultd[k] < 0.0) {\n temp = vmultc[k] / (vmultc[k] - vmultd[k]);\n if (temp < ratio) {\n ratio = temp;\n icon = k;\n }\n }\n }\n\n // Update DX, VMULTC and RESMAX.\n\n temp = 1.0 - ratio;\n for (k = 1; k <= n; ++k) { dx[k] = temp * dx[k] + ratio * dxnew[k]; }\n for (k = 1; k <= mcon; ++k) {\n vmultc[k] = Math.max(0.0, temp * vmultc[k] + ratio * vmultd[k]);\n }\n if (mcon === m) { resmax = resold + ratio * (resmax - resold); }\n\n // If the full step is not acceptable then begin another iteration.\n // Otherwise switch to stage two or end the calculation.\n } while (icon > 0);\n\n if (step === stpful) {\n return true;\n }\n\n } while (true);\n\n // We employ any freedom that may be available to reduce the objective\n // function before returning a DX whose length is less than RHO.\n\n } while (mcon === m);\n\n return false;\n },\n\n PrintIterationResult: function(nfvals, f, resmax, x, n, iprint) {\n if (iprint > 1) { console.log(\"NFVALS = \"+nfvals+\" F = \"+f+\" MAXCV = \"+resmax); }\n if (iprint > 1) { console.log(\"X = \" + this.PART(x, 1, n)); }\n },\n\n ROW: function(src, rowidx) {\n return src[rowidx].slice();\n // var col,\n // cols = src[0].length,\n // dest = this.arr(cols);\n\n // for (col = 0; col < cols; ++col) {\n // dest[col] = src[rowidx][col];\n // }\n // return dest;\n },\n\n COL: function(src, colidx) {\n var row,\n rows = src.length,\n dest = this.arr(rows);\n for (row = 0; row < rows; ++row) {\n dest[row] = src[row][colidx];\n }\n return dest;\n },\n\n PART: function(src, from, to) {\n return src.slice(from, to + 1);\n // var srcidx,\n // dest = this.arr(to - from + 1),\n // destidx = 0;\n // for (srcidx = from; srcidx <= to; ++srcidx, ++destidx) {\n // dest[destidx] = src[srcidx];\n // }\n // return dest;\n },\n\n FORMAT: function(x) {\n return x.join(',');\n // var i, fmt = \"\";\n // for (i = 0; i < x.length; ++i) {\n // fmt += \", \" + x[i];\n // }\n // return fmt;\n },\n\n DOT_PRODUCT: function(lhs, rhs) {\n var i, sum = 0.0,\n len = lhs.length;\n for (i = 0; i < len; ++i) {\n sum += lhs[i] * rhs[i];\n }\n return sum;\n }\n\n };\n\n return JXG.Math.Nlp;\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true*/\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n jxg\n math/math\n utils/type\n */\n\ndefine('math/statistics',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, Type) {\n\n \"use strict\";\n\n /**\n * Functions for mathematical statistics. Most functions are like in the statistics package R.\n * @name JXG.Math.Statistics\n * @exports Mat.Statistics as JXG.Math.Statistics\n * @namespace\n */\n Mat.Statistics = {\n /**\n * Sums up all elements of the given array.\n * @param {Array} arr An array of numbers.\n * @returns {Number}\n * @memberof JXG.Math.Statistics\n */\n sum: function (arr) {\n var i,\n len = arr.length,\n res = 0;\n\n for (i = 0; i < len; i++) {\n res += arr[i];\n }\n return res;\n },\n\n /**\n * Multiplies all elements of the given array.\n * @param {Array} arr An array of numbers.\n * @returns {Number}\n * @memberof JXG.Math.Statistics\n */\n prod: function (arr) {\n var i,\n len = arr.length,\n res = 1;\n\n for (i = 0; i < len; i++) {\n res *= arr[i];\n }\n return res;\n },\n\n /**\n * Determines the mean value of the values given in an array.\n * @param {Array} arr\n * @returns {Number}\n * @memberof JXG.Math.Statistics\n */\n mean: function (arr) {\n if (arr.length > 0) {\n return this.sum(arr) / arr.length;\n }\n\n return 0.0;\n },\n\n /**\n * The median of a finite set of values is the value that divides the set\n * into two equal sized subsets.\n * @param {Array} arr The set of values.\n * @returns {Number}\n * @memberof JXG.Math.Statistics\n */\n median: function (arr) {\n var tmp, len;\n\n if (arr.length > 0) {\n if (ArrayBuffer.isView(arr)) {\n tmp = new Float64Array(arr);\n tmp.sort();\n } else {\n tmp = arr.slice(0);\n tmp.sort(function (a, b) {\n return a - b;\n });\n }\n len = tmp.length;\n\n if (len & 1) { // odd\n return tmp[parseInt(len * 0.5, 10)];\n }\n\n return (tmp[len * 0.5 - 1] + tmp[len * 0.5]) * 0.5;\n }\n\n return 0.0;\n },\n\n /**\n * The P-th percentile ( 0 < P ≤ 100 ) of a list of N ordered values (sorted from least to greatest)\n * is the smallest value in the list such that no more than P percent of the data is strictly less\n * than the value and at least P percent of the data is less than or equal to that value. See {@link https://en.wikipedia.org/wiki/Percentile}.\n *\n * Here, the <i>linear interpolation between closest ranks</i> method is used.\n * @param {Array} arr The set of values, need not be ordered.\n * @param {Number|Array} percentile One or several percentiles\n * @returns {Number|Array} Depending if a number or an array is the input for percentile, a number or an array containing the percentils\n * is returned.\n */\n percentile: function(arr, percentile) {\n var tmp, len, i, p, res = [], per;\n\n if (arr.length > 0) {\n if (ArrayBuffer.isView(arr)) {\n tmp = new Float64Array(arr);\n tmp.sort();\n } else {\n tmp = arr.slice(0);\n tmp.sort(function (a, b) {\n return a - b;\n });\n }\n len = tmp.length;\n\n if (Type.isArray(percentile)) {\n p = percentile;\n } else {\n p = [percentile];\n }\n\n for (i = 0; i < p.length; i++) {\n per = len * p[i] * 0.01;\n if (parseInt(per, 10) === per) {\n res.push( (tmp[per - 1] + tmp[per]) * 0.5 );\n } else {\n res.push( tmp[parseInt(per, 10)] );\n }\n }\n\n if (Type.isArray(percentile)) {\n return res;\n } else {\n return res[0];\n }\n }\n\n return 0.0;\n },\n\n /**\n * Bias-corrected sample variance. A variance is a measure of how far a\n * set of numbers are spread out from each other.\n * @param {Array} arr\n * @returns {Number}\n * @memberof JXG.Math.Statistics\n */\n variance: function (arr) {\n var m, res, i, len = arr.length;\n\n if (len > 1) {\n m = this.mean(arr);\n res = 0;\n for (i = 0; i < len; i++) {\n res += (arr[i] - m) * (arr[i] - m);\n }\n return res / (arr.length - 1);\n }\n\n return 0.0;\n },\n\n /**\n * Determines the <strong>s</strong>tandard <strong>d</strong>eviation which shows how much\n * variation there is from the average value of a set of numbers.\n * @param {Array} arr\n * @returns {Number}\n * @memberof JXG.Math.Statistics\n */\n sd: function (arr) {\n return Math.sqrt(this.variance(arr));\n },\n\n /**\n * Weighted mean value is basically the same as {@link JXG.Math.Statistics.mean} but here the values\n * are weighted, i.e. multiplied with another value called <em>weight</em>. The weight values are given\n * as a second array with the same length as the value array..\n * @throws {Error} If the dimensions of the arrays don't match.\n * @param {Array} arr Set of alues.\n * @param {Array} w Weight values.\n * @returns {Number}\n * @memberof JXG.Math.Statistics\n */\n weightedMean: function (arr, w) {\n if (arr.length !== w.length) {\n throw new Error('JSXGraph error (Math.Statistics.weightedMean): Array dimension mismatch.');\n }\n\n if (arr.length > 0) {\n return this.mean(this.multiply(arr, w));\n }\n\n return 0.0;\n },\n\n /**\n * Extracts the maximum value from the array.\n * @param {Array} arr\n * @returns {Number} The highest number from the array. It returns <tt>NaN</tt> if not every element could be\n * interpreted as a number and <tt>-Infinity</tt> if an empty array is given or no element could be interpreted\n * as a number.\n * @memberof JXG.Math.Statistics\n */\n max: function (arr) {\n return Math.max.apply(this, arr);\n },\n\n /**\n * Extracts the minimum value from the array.\n * @param {Array} arr\n * @returns {Number} The lowest number from the array. It returns <tt>NaN</tt> if not every element could be\n * interpreted as a number and <tt>Infinity</tt> if an empty array is given or no element could be interpreted\n * as a number.\n * @memberof JXG.Math.Statistics\n */\n min: function (arr) {\n return Math.min.apply(this, arr);\n },\n\n /**\n * Determines the lowest and the highest value from the given array.\n * @param {Array} arr\n * @returns {Array} The minimum value as the first and the maximum value as the second value.\n * @memberof JXG.Math.Statistics\n */\n range: function (arr) {\n return [this.min(arr), this.max(arr)];\n },\n\n /**\n * Determines the absolute value of every given value.\n * @param {Array|Number} arr\n * @returns {Array|Number}\n * @memberof JXG.Math.Statistics\n */\n abs: function (arr) {\n var i, len, res;\n\n if (Type.isArray(arr)) {\n if (arr.map) {\n res = arr.map(Math.abs);\n } else {\n len = arr.length;\n res = [];\n\n for (i = 0; i < len; i++) {\n res[i] = Math.abs(arr[i]);\n }\n }\n } else if (ArrayBuffer.isView(arr)) {\n res = arr.map(Math.abs);\n } else {\n res = Math.abs(arr);\n }\n return res;\n },\n\n /**\n * Adds up two (sequences of) values. If one value is an array and the other one is a number the number\n * is added to every element of the array. If two arrays are given and the lengths don't match the shortest\n * length is taken.\n * @param {Array|Number} arr1\n * @param {Array|Number} arr2\n * @returns {Array|Number}\n * @memberof JXG.Math.Statistics\n */\n add: function (arr1, arr2) {\n var i, len, res = [];\n\n arr1 = Type.evalSlider(arr1);\n arr2 = Type.evalSlider(arr2);\n\n if (Type.isArray(arr1) && Type.isNumber(arr2)) {\n len = arr1.length;\n\n for (i = 0; i < len; i++) {\n res[i] = arr1[i] + arr2;\n }\n } else if (Type.isNumber(arr1) && Type.isArray(arr2)) {\n len = arr2.length;\n\n for (i = 0; i < len; i++) {\n res[i] = arr1 + arr2[i];\n }\n } else if (Type.isArray(arr1) && Type.isArray(arr2)) {\n len = Math.min(arr1.length, arr2.length);\n\n for (i = 0; i < len; i++) {\n res[i] = arr1[i] + arr2[i];\n }\n } else {\n res = arr1 + arr2;\n }\n\n return res;\n },\n\n /**\n * Divides two (sequences of) values. If two arrays are given and the lengths don't match the shortest length\n * is taken.\n * @param {Array|Number} arr1 Dividend\n * @param {Array|Number} arr2 Divisor\n * @returns {Array|Number}\n * @memberof JXG.Math.Statistics\n */\n div: function (arr1, arr2) {\n var i, len, res = [];\n\n arr1 = Type.evalSlider(arr1);\n arr2 = Type.evalSlider(arr2);\n\n if (Type.isArray(arr1) && Type.isNumber(arr2)) {\n len = arr1.length;\n\n for (i = 0; i < len; i++) {\n res[i] = arr1[i] / arr2;\n }\n } else if (Type.isNumber(arr1) && Type.isArray(arr2)) {\n len = arr2.length;\n\n for (i = 0; i < len; i++) {\n res[i] = arr1 / arr2[i];\n }\n } else if (Type.isArray(arr1) && Type.isArray(arr2)) {\n len = Math.min(arr1.length, arr2.length);\n\n for (i = 0; i < len; i++) {\n res[i] = arr1[i] / arr2[i];\n }\n } else {\n res = arr1 / arr2;\n }\n\n return res;\n },\n\n /**\n * @function\n * @deprecated Use {@link JXG.Math.Statistics.div} instead.\n * @memberof JXG.Math.Statistics\n */\n divide: function () {\n JXG.deprecated('Statistics.divide()', 'Statistics.div()');\n Mat.Statistics.div.apply(Mat.Statistics, arguments);\n },\n\n /**\n * Divides two (sequences of) values and returns the remainder. If two arrays are given and the lengths don't\n * match the shortest length is taken.\n * @param {Array|Number} arr1 Dividend\n * @param {Array|Number} arr2 Divisor\n * @param {Boolean} [math=false] Mathematical mod or symmetric mod? Default is symmetric, the JavaScript <tt>%</tt> operator.\n * @returns {Array|Number}\n * @memberof JXG.Math.Statistics\n */\n mod: function (arr1, arr2, math) {\n var i, len, res = [], mod = function (a, m) {\n return a % m;\n };\n\n math = Type.def(math, false);\n\n if (math) {\n mod = Mat.mod;\n }\n\n arr1 = Type.evalSlider(arr1);\n arr2 = Type.evalSlider(arr2);\n\n if (Type.isArray(arr1) && Type.isNumber(arr2)) {\n len = arr1.length;\n\n for (i = 0; i < len; i++) {\n res[i] = mod(arr1[i], arr2);\n }\n } else if (Type.isNumber(arr1) && Type.isArray(arr2)) {\n len = arr2.length;\n\n for (i = 0; i < len; i++) {\n res[i] = mod(arr1, arr2[i]);\n }\n } else if (Type.isArray(arr1) && Type.isArray(arr2)) {\n len = Math.min(arr1.length, arr2.length);\n\n for (i = 0; i < len; i++) {\n res[i] = mod(arr1[i], arr2[i]);\n }\n } else {\n res = mod(arr1, arr2);\n }\n\n return res;\n },\n\n /**\n * Multiplies two (sequences of) values. If one value is an array and the other one is a number the number\n * is multiplied to every element of the array. If two arrays are given and the lengths don't match the shortest\n * length is taken.\n * @param {Array|Number} arr1\n * @param {Array|Number} arr2\n * @returns {Array|Number}\n * @memberof JXG.Math.Statistics\n */\n multiply: function (arr1, arr2) {\n var i, len, res = [];\n\n arr1 = Type.evalSlider(arr1);\n arr2 = Type.evalSlider(arr2);\n\n if (Type.isArray(arr1) && Type.isNumber(arr2)) {\n len = arr1.length;\n\n for (i = 0; i < len; i++) {\n res[i] = arr1[i] * arr2;\n }\n } else if (Type.isNumber(arr1) && Type.isArray(arr2)) {\n len = arr2.length;\n\n for (i = 0; i < len; i++) {\n res[i] = arr1 * arr2[i];\n }\n } else if (Type.isArray(arr1) && Type.isArray(arr2)) {\n len = Math.min(arr1.length, arr2.length);\n\n for (i = 0; i < len; i++) {\n res[i] = arr1[i] * arr2[i];\n }\n } else {\n res = arr1 * arr2;\n }\n\n return res;\n },\n\n /**\n * Subtracts two (sequences of) values. If two arrays are given and the lengths don't match the shortest\n * length is taken.\n * @param {Array|Number} arr1 Minuend\n * @param {Array|Number} arr2 Subtrahend\n * @returns {Array|Number}\n * @memberof JXG.Math.Statistics\n */\n subtract: function (arr1, arr2) {\n var i, len, res = [];\n\n arr1 = Type.evalSlider(arr1);\n arr2 = Type.evalSlider(arr2);\n\n if (Type.isArray(arr1) && Type.isNumber(arr2)) {\n len = arr1.length;\n\n for (i = 0; i < len; i++) {\n res[i] = arr1[i] - arr2;\n }\n } else if (Type.isNumber(arr1) && Type.isArray(arr2)) {\n len = arr2.length;\n\n for (i = 0; i < len; i++) {\n res[i] = arr1 - arr2[i];\n }\n } else if (Type.isArray(arr1) && Type.isArray(arr2)) {\n len = Math.min(arr1.length, arr2.length);\n\n for (i = 0; i < len; i++) {\n res[i] = arr1[i] - arr2[i];\n }\n } else {\n res = arr1 - arr2;\n }\n\n return res;\n },\n\n /**\n * The Theil-Sen estimator can be used to determine a more robust linear regression of a set of sample\n * points than least squares regression in {@link JXG.Math.Numerics.regressionPolynomial}.\n *\n * If the function should be applied to an array a of points, a the coords array can be generated with\n * JavaScript array.map:\n *\n * <pre>\n * JXG.Math.Statistics.TheilSenRegression(a.map(el => el.coords));\n * </pre>\n *\n * @param {Array} coords Array of {@link JXG.Coords}.\n * @returns {Array} A stdform array of the regression line.\n * @memberof JXG.Math.Statistics\n *\n * @example\n * var board = JXG.JSXGraph.initBoard('jxgbox', { boundingbox: [-6,6,6,-6], axis : true });\n * var a=[];\n * a[0]=board.create('point', [0,0]);\n * a[1]=board.create('point', [3,0]);\n * a[2]=board.create('point', [0,3]);\n *\n * board.create('line', [\n * () => JXG.Math.Statistics.TheilSenRegression(a.map(el => el.coords))\n * ],\n * {strokeWidth:1, strokeColor:'black'});\n *\n * </pre><div id=\"JXG0a28be85-91c5-44d3-aae6-114e81217cf0\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG0a28be85-91c5-44d3-aae6-114e81217cf0',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var board = JXG.JSXGraph.initBoard('jxgbox', { boundingbox: [-6,6,6,-6], axis : true });\n * var a=[];\n * a[0]=board.create('point', [0,0]);\n * a[1]=board.create('point', [3,0]);\n * a[2]=board.create('point', [0,3]);\n *\n * board.create('line', [\n * () => JXG.Math.Statistics.TheilSenRegression(a.map(el => el.coords))\n * ],\n * {strokeWidth:1, strokeColor:'black'});\n *\n * })();\n *\n * </script><pre>\n *\n */\n TheilSenRegression: function (coords) {\n var i, j,\n slopes = [],\n tmpslopes = [],\n yintercepts = [];\n\n for (i = 0; i < coords.length; i++) {\n tmpslopes.length = 0;\n\n for (j = 0; j < coords.length; j++) {\n if (Math.abs(coords[j].usrCoords[1] - coords[i].usrCoords[1]) > Mat.eps) {\n tmpslopes[j] = (coords[j].usrCoords[2] - coords[i].usrCoords[2]) /\n (coords[j].usrCoords[1] - coords[i].usrCoords[1]);\n }\n }\n\n slopes[i] = this.median(tmpslopes);\n yintercepts.push(coords[i].usrCoords[2] - slopes[i] * coords[i].usrCoords[1]);\n }\n\n return [this.median(yintercepts), this.median(slopes), -1];\n },\n\n /**\n * Generate values of a standard normal random variable with the Marsaglia polar method, see\n * https://en.wikipedia.org/wiki/Marsaglia_polar_method .\n *\n * @param {Number} mean mean value of the normal distribution\n * @param {Number} stdDev standard deviation of the normal distribution\n * @returns {Number} value of a standard normal random variable\n */\n generateGaussian: function (mean, stdDev) {\n var u, v, s;\n\n if (this.hasSpare) {\n this.hasSpare = false;\n return this.spare * stdDev + mean;\n }\n\n do {\n u = Math.random() * 2 - 1;\n v = Math.random() * 2 - 1;\n s = u * u + v * v;\n } while (s >= 1 || s === 0);\n\n s = Math.sqrt(-2.0 * Math.log(s) / s);\n\n this.spare = v * s;\n this.hasSpare = true;\n return mean + stdDev * u * s;\n }\n };\n\n return Mat.Statistics;\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Andreas Walter,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true*/\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n jxg\n base/constants\n base/coords\n math/math\n math/numerics\n utils/type\n */\n\n/**\n * @fileoverview This file contains the Math.Geometry namespace for calculating algebraic/geometric\n * stuff like intersection points, angles, midpoint, and so on.\n */\n\ndefine('math/geometry',[\n 'jxg', 'base/constants', 'base/coords', 'math/math', 'math/numerics', 'utils/type', 'utils/expect'\n], function (JXG, Const, Coords, Mat, Numerics, Type, Expect) {\n\n \"use strict\";\n\n /**\n * Math.Geometry namespace definition. This namespace holds geometrical algorithms,\n * especially intersection algorithms.\n * @name JXG.Math.Geometry\n * @namespace\n */\n Mat.Geometry = {};\n\n// the splitting is necessary due to the shortcut for the circumcircleMidpoint method to circumcenter.\n\n JXG.extend(Mat.Geometry, /** @lends JXG.Math.Geometry */ {\n /* ***************************************/\n /* *** GENERAL GEOMETRIC CALCULATIONS ****/\n /* ***************************************/\n\n /**\n * Calculates the angle defined by the points A, B, C.\n * @param {JXG.Point,Array} A A point or [x,y] array.\n * @param {JXG.Point,Array} B Another point or [x,y] array.\n * @param {JXG.Point,Array} C A circle - no, of course the third point or [x,y] array.\n * @deprecated Use {@link JXG.Math.Geometry.rad} instead.\n * @see #rad\n * @see #trueAngle\n * @returns {Number} The angle in radian measure.\n */\n angle: function (A, B, C) {\n var u, v, s, t,\n a = [],\n b = [],\n c = [];\n\n JXG.deprecated('Geometry.angle()', 'Geometry.rad()');\n if (A.coords) {\n a[0] = A.coords.usrCoords[1];\n a[1] = A.coords.usrCoords[2];\n } else {\n a[0] = A[0];\n a[1] = A[1];\n }\n\n if (B.coords) {\n b[0] = B.coords.usrCoords[1];\n b[1] = B.coords.usrCoords[2];\n } else {\n b[0] = B[0];\n b[1] = B[1];\n }\n\n if (C.coords) {\n c[0] = C.coords.usrCoords[1];\n c[1] = C.coords.usrCoords[2];\n } else {\n c[0] = C[0];\n c[1] = C[1];\n }\n\n u = a[0] - b[0];\n v = a[1] - b[1];\n s = c[0] - b[0];\n t = c[1] - b[1];\n\n return Math.atan2(u * t - v * s, u * s + v * t);\n },\n\n /**\n * Calculates the angle defined by the three points A, B, C if you're going from A to C around B counterclockwise.\n * @param {JXG.Point,Array} A Point or [x,y] array\n * @param {JXG.Point,Array} B Point or [x,y] array\n * @param {JXG.Point,Array} C Point or [x,y] array\n * @see #rad\n * @returns {Number} The angle in degrees.\n */\n trueAngle: function (A, B, C) {\n return this.rad(A, B, C) * 57.295779513082323; // *180.0/Math.PI;\n },\n\n /**\n * Calculates the internal angle defined by the three points A, B, C if you're going from A to C around B counterclockwise.\n * @param {JXG.Point,Array} A Point or [x,y] array\n * @param {JXG.Point,Array} B Point or [x,y] array\n * @param {JXG.Point,Array} C Point or [x,y] array\n * @see #trueAngle\n * @returns {Number} Angle in radians.\n */\n rad: function (A, B, C) {\n var ax, ay, bx, by, cx, cy, phi;\n\n if (A.coords) {\n ax = A.coords.usrCoords[1];\n ay = A.coords.usrCoords[2];\n } else {\n ax = A[0];\n ay = A[1];\n }\n\n if (B.coords) {\n bx = B.coords.usrCoords[1];\n by = B.coords.usrCoords[2];\n } else {\n bx = B[0];\n by = B[1];\n }\n\n if (C.coords) {\n cx = C.coords.usrCoords[1];\n cy = C.coords.usrCoords[2];\n } else {\n cx = C[0];\n cy = C[1];\n }\n\n phi = Math.atan2(cy - by, cx - bx) - Math.atan2(ay - by, ax - bx);\n\n if (phi < 0) {\n phi += 6.2831853071795862;\n }\n\n return phi;\n },\n\n /**\n * Calculates a point on the bisection line between the three points A, B, C.\n * As a result, the bisection line is defined by two points:\n * Parameter B and the point with the coordinates calculated in this function.\n * Does not work for ideal points.\n * @param {JXG.Point} A Point\n * @param {JXG.Point} B Point\n * @param {JXG.Point} C Point\n * @param [board=A.board] Reference to the board\n * @returns {JXG.Coords} Coordinates of the second point defining the bisection.\n */\n angleBisector: function (A, B, C, board) {\n var phiA, phiC, phi,\n Ac = A.coords.usrCoords,\n Bc = B.coords.usrCoords,\n Cc = C.coords.usrCoords,\n x, y;\n\n if (!Type.exists(board)) {\n board = A.board;\n }\n\n // Parallel lines\n if (Bc[0] === 0) {\n return new Coords(Const.COORDS_BY_USER,\n [1, (Ac[1] + Cc[1]) * 0.5, (Ac[2] + Cc[2]) * 0.5], board);\n }\n\n // Non-parallel lines\n x = Ac[1] - Bc[1];\n y = Ac[2] - Bc[2];\n phiA = Math.atan2(y, x);\n\n x = Cc[1] - Bc[1];\n y = Cc[2] - Bc[2];\n phiC = Math.atan2(y, x);\n\n phi = (phiA + phiC) * 0.5;\n\n if (phiA > phiC) {\n phi += Math.PI;\n }\n\n x = Math.cos(phi) + Bc[1];\n y = Math.sin(phi) + Bc[2];\n\n return new Coords(Const.COORDS_BY_USER, [1, x, y], board);\n },\n\n // /**\n // * Calculates a point on the m-section line between the three points A, B, C.\n // * As a result, the m-section line is defined by two points:\n // * Parameter B and the point with the coordinates calculated in this function.\n // * The m-section generalizes the bisector to any real number.\n // * For example, the trisectors of an angle are simply the 1/3-sector and the 2/3-sector.\n // * Does not work for ideal points.\n // * @param {JXG.Point} A Point\n // * @param {JXG.Point} B Point\n // * @param {JXG.Point} C Point\n // * @param {Number} m Number\n // * @param [board=A.board] Reference to the board\n // * @returns {JXG.Coords} Coordinates of the second point defining the bisection.\n // */\n // angleMsector: function (A, B, C, m, board) {\n // var phiA, phiC, phi,\n // Ac = A.coords.usrCoords,\n // Bc = B.coords.usrCoords,\n // Cc = C.coords.usrCoords,\n // x, y;\n\n // if (!Type.exists(board)) {\n // board = A.board;\n // }\n\n // // Parallel lines\n // if (Bc[0] === 0) {\n // return new Coords(Const.COORDS_BY_USER,\n // [1, (Ac[1] + Cc[1]) * m, (Ac[2] + Cc[2]) * m], board);\n // }\n\n // // Non-parallel lines\n // x = Ac[1] - Bc[1];\n // y = Ac[2] - Bc[2];\n // phiA = Math.atan2(y, x);\n\n // x = Cc[1] - Bc[1];\n // y = Cc[2] - Bc[2];\n // phiC = Math.atan2(y, x);\n\n // phi = phiA + ((phiC - phiA) * m);\n\n // if (phiA - phiC > Math.PI) {\n // phi += 2*m*Math.PI;\n // }\n\n // x = Math.cos(phi) + Bc[1];\n // y = Math.sin(phi) + Bc[2];\n\n // return new Coords(Const.COORDS_BY_USER, [1, x, y], board);\n // },\n\n /**\n * Reflects the point along the line.\n * @param {JXG.Line} line Axis of reflection.\n * @param {JXG.Point} point Point to reflect.\n * @param [board=point.board] Reference to the board\n * @returns {JXG.Coords} Coordinates of the reflected point.\n */\n reflection: function (line, point, board) {\n // (v,w) defines the slope of the line\n var x0, y0, x1, y1, v, w, mu,\n pc = point.coords.usrCoords,\n p1c = line.point1.coords.usrCoords,\n p2c = line.point2.coords.usrCoords;\n\n if (!Type.exists(board)) {\n board = point.board;\n }\n\n v = p2c[1] - p1c[1];\n w = p2c[2] - p1c[2];\n\n x0 = pc[1] - p1c[1];\n y0 = pc[2] - p1c[2];\n\n mu = (v * y0 - w * x0) / (v * v + w * w);\n\n // point + mu*(-y,x) is the perpendicular foot\n x1 = pc[1] + 2 * mu * w;\n y1 = pc[2] - 2 * mu * v;\n\n return new Coords(Const.COORDS_BY_USER, [x1, y1], board);\n },\n\n /**\n * Computes the new position of a point which is rotated\n * around a second point (called rotpoint) by the angle phi.\n * @param {JXG.Point} rotpoint Center of the rotation\n * @param {JXG.Point} point point to be rotated\n * @param {Number} phi rotation angle in arc length\n * @param {JXG.Board} [board=point.board] Reference to the board\n * @returns {JXG.Coords} Coordinates of the new position.\n */\n rotation: function (rotpoint, point, phi, board) {\n var x0, y0, c, s, x1, y1,\n pc = point.coords.usrCoords,\n rotpc = rotpoint.coords.usrCoords;\n\n if (!Type.exists(board)) {\n board = point.board;\n }\n\n x0 = pc[1] - rotpc[1];\n y0 = pc[2] - rotpc[2];\n\n c = Math.cos(phi);\n s = Math.sin(phi);\n\n x1 = x0 * c - y0 * s + rotpc[1];\n y1 = x0 * s + y0 * c + rotpc[2];\n\n return new Coords(Const.COORDS_BY_USER, [x1, y1], board);\n },\n\n /**\n * Calculates the coordinates of a point on the perpendicular to the given line through\n * the given point.\n * @param {JXG.Line} line A line.\n * @param {JXG.Point} point Point which is projected to the line.\n * @param {JXG.Board} [board=point.board] Reference to the board\n * @returns {Array} Array of length two containing coordinates of a point on the perpendicular to the given line\n * through the given point and boolean flag \"change\".\n */\n perpendicular: function (line, point, board) {\n var x, y, change,\n c, z,\n A = line.point1.coords.usrCoords,\n B = line.point2.coords.usrCoords,\n C = point.coords.usrCoords;\n\n if (!Type.exists(board)) {\n board = point.board;\n }\n\n // special case: point is the first point of the line\n if (point === line.point1) {\n x = A[1] + B[2] - A[2];\n y = A[2] - B[1] + A[1];\n z = A[0] * B[0];\n\n if (Math.abs(z) < Mat.eps) {\n x = B[2];\n y = -B[1];\n }\n c = [z, x, y];\n change = true;\n\n // special case: point is the second point of the line\n } else if (point === line.point2) {\n x = B[1] + A[2] - B[2];\n y = B[2] - A[1] + B[1];\n z = A[0] * B[0];\n\n if (Math.abs(z) < Mat.eps) {\n x = A[2];\n y = -A[1];\n }\n c = [z, x, y];\n change = false;\n\n // special case: point lies somewhere else on the line\n } else if (Math.abs(Mat.innerProduct(C, line.stdform, 3)) < Mat.eps) {\n x = C[1] + B[2] - C[2];\n y = C[2] - B[1] + C[1];\n z = B[0];\n\n if (Math.abs(z) < Mat.eps) {\n x = B[2];\n y = -B[1];\n }\n\n change = true;\n if (Math.abs(z) > Mat.eps && Math.abs(x - C[1]) < Mat.eps && Math.abs(y - C[2]) < Mat.eps) {\n x = C[1] + A[2] - C[2];\n y = C[2] - A[1] + C[1];\n change = false;\n }\n c = [z, x, y];\n\n // general case: point does not lie on the line\n // -> calculate the foot of the dropped perpendicular\n } else {\n c = [0, line.stdform[1], line.stdform[2]];\n c = Mat.crossProduct(c, C); // perpendicuar to line\n c = Mat.crossProduct(c, line.stdform); // intersection of line and perpendicular\n change = true;\n }\n\n return [new Coords(Const.COORDS_BY_USER, c, board), change];\n },\n\n /**\n * @deprecated Please use {@link JXG.Math.Geometry.circumcenter} instead.\n */\n circumcenterMidpoint: function () {\n JXG.deprecated('Geometry.circumcenterMidpoint()', 'Geometry.circumcenter()');\n this.circumcenter.apply(this, arguments);\n },\n\n /**\n * Calculates the center of the circumcircle of the three given points.\n * @param {JXG.Point} point1 Point\n * @param {JXG.Point} point2 Point\n * @param {JXG.Point} point3 Point\n * @param {JXG.Board} [board=point1.board] Reference to the board\n * @returns {JXG.Coords} Coordinates of the center of the circumcircle of the given points.\n */\n circumcenter: function (point1, point2, point3, board) {\n var u, v, m1, m2,\n A = point1.coords.usrCoords,\n B = point2.coords.usrCoords,\n C = point3.coords.usrCoords;\n\n if (!Type.exists(board)) {\n board = point1.board;\n }\n\n u = [B[0] - A[0], -B[2] + A[2], B[1] - A[1]];\n v = [(A[0] + B[0]) * 0.5, (A[1] + B[1]) * 0.5, (A[2] + B[2]) * 0.5];\n m1 = Mat.crossProduct(u, v);\n\n u = [C[0] - B[0], -C[2] + B[2], C[1] - B[1]];\n v = [(B[0] + C[0]) * 0.5, (B[1] + C[1]) * 0.5, (B[2] + C[2]) * 0.5];\n m2 = Mat.crossProduct(u, v);\n\n return new Coords(Const.COORDS_BY_USER, Mat.crossProduct(m1, m2), board);\n },\n\n /**\n * Calculates the Euclidean distance for two given arrays of the same length.\n * @param {Array} array1 Array of Number\n * @param {Array} array2 Array of Number\n * @param {Number} [n] Length of the arrays. Default is the minimum length of the given arrays.\n * @returns {Number} Euclidean distance of the given vectors.\n */\n distance: function (array1, array2, n) {\n var i,\n sum = 0;\n\n if (!n) {\n n = Math.min(array1.length, array2.length);\n }\n\n for (i = 0; i < n; i++) {\n sum += (array1[i] - array2[i]) * (array1[i] - array2[i]);\n }\n\n return Math.sqrt(sum);\n },\n\n /**\n * Calculates Euclidean distance for two given arrays of the same length.\n * If one of the arrays contains a zero in the first coordinate, and the Euclidean distance\n * is different from zero it is a point at infinity and we return Infinity.\n * @param {Array} array1 Array containing elements of type number.\n * @param {Array} array2 Array containing elements of type number.\n * @param {Number} [n] Length of the arrays. Default is the minimum length of the given arrays.\n * @returns {Number} Euclidean (affine) distance of the given vectors.\n */\n affineDistance: function (array1, array2, n) {\n var d;\n\n d = this.distance(array1, array2, n);\n\n if (d > Mat.eps && (Math.abs(array1[0]) < Mat.eps || Math.abs(array2[0]) < Mat.eps)) {\n return Infinity;\n }\n\n return d;\n },\n\n /**\n * Affine ratio of three collinear points a, b, c: (c - a) / (b - a).\n * If r > 1 or r < 0 then c is outside of the segment ab.\n *\n * @param {Array|JXG.Coords} a\n * @param {Array|JXG.Coords} b\n * @param {Array|JXG.Coords} c\n * @returns {Number} affine ratio (c - a) / (b - a)\n */\n affineRatio: function(a, b, c) {\n var r = 0.0, dx;\n\n if (Type.exists(a.usrCoords)) {\n a = a.usrCoords;\n }\n if (Type.exists(b.usrCoords)) {\n b = b.usrCoords;\n }\n if (Type.exists(c.usrCoords)) {\n c = c.usrCoords;\n }\n\n dx = b[1] - a[1];\n\n if (Math.abs(dx) > Mat.eps) {\n r = (c[1] - a[1]) / dx;\n } else {\n r = (c[2] - a[2]) / (b[2] - a[2]);\n }\n return r;\n },\n\n /**\n * Sort vertices counter clockwise starting with the first point.\n *\n * @param {Array} p An array containing {@link JXG.Point}, {@link JXG.Coords}, and/or arrays.\n *\n * @returns {Array}\n */\n sortVertices: function (p) {\n var ll,\n ps = Expect.each(p, Expect.coordsArray),\n N = ps.length,\n lastPoint = null;\n\n // If the last point equals the first point, we take the last point out of the array.\n // It may be that the several points at the end of the array are equal to the first point.\n // The polygonal chain is been closed by JSXGraph, but this may also have been done by the user.\n // Therefore, we use a while lopp to pop the last points.\n while (ps[0][0] === ps[N - 1][0] && ps[0][1] === ps[N - 1][1] && ps[0][2] === ps[N - 1][2]) {\n lastPoint = ps.pop();\n N--;\n }\n // Find the point with the lowest y value\n // for (i = 1; i < N; i++) {\n // if ((ps[i][2] < ps[0][2]) ||\n // // if the current and the lowest point have the same y value, pick the one with\n // // the lowest x value.\n // (Math.abs(ps[i][2] - ps[0][2]) < Mat.eps && ps[i][1] < ps[0][1])) {\n // console.log(i, 0);\n // ps = Type.swap(ps, i, 0);\n // }\n // }\n\n ll = ps[0];\n // Sort ps in increasing order of the angle between a point and the first point ll.\n // If a point is equal to the first point ll, the angle is defined to be -Infinity.\n // Otherwise, atan2 would return zero, which is a value which also attained by points\n // on the same horizontal line.\n ps.sort(function (a, b) {\n var rad1 = (a[2] === ll[2] && a[1] === ll[1]) ? -Infinity : Math.atan2(a[2] - ll[2], a[1] - ll[1]),\n rad2 = (b[2] === ll[2] && b[1] === ll[1]) ? -Infinity : Math.atan2(b[2] - ll[2], b[1] - ll[1]);\n\n return rad1 - rad2;\n });\n\n // If the last point has been taken out of the array, we put it in again.\n if (lastPoint !== null) {\n ps.push(lastPoint);\n }\n\n return ps;\n },\n\n /**\n * Signed triangle area of the three points given.\n *\n * @param {JXG.Point|JXG.Coords|Array} p1\n * @param {JXG.Point|JXG.Coords|Array} p2\n * @param {JXG.Point|JXG.Coords|Array} p3\n *\n * @returns {Number}\n */\n signedTriangle: function (p1, p2, p3) {\n var A = Expect.coordsArray(p1),\n B = Expect.coordsArray(p2),\n C = Expect.coordsArray(p3);\n\n return 0.5 * ((B[1] - A[1]) * (C[2] - A[2]) - (B[2] - A[2]) * (C[1] - A[1]));\n },\n\n /**\n * Determine the signed area of a non-selfintersecting polygon.\n * Surveyor's Formula\n *\n * @param {Array} p An array containing {@link JXG.Point}, {@link JXG.Coords}, and/or arrays.\n * @param {Boolean} [sort=true]\n *\n * @returns {Number}\n */\n signedPolygon: function (p, sort) {\n var i, N,\n A = 0,\n ps = Expect.each(p, Expect.coordsArray);\n\n if (sort === undefined) {\n sort = true;\n }\n\n if (!sort) {\n ps = this.sortVertices(ps);\n } else {\n // Make sure the polygon is closed. If it is already closed this won't change the sum because the last\n // summand will be 0.\n ps.unshift(ps[ps.length - 1]);\n }\n\n N = ps.length;\n\n for (i = 1; i < N; i++) {\n A += ps[i - 1][1] * ps[i][2] - ps[i][1] * ps[i - 1][2];\n }\n\n return 0.5 * A;\n },\n\n /**\n * Calculate the complex hull of a point cloud.\n *\n * @param {Array} points An array containing {@link JXG.Point}, {@link JXG.Coords}, and/or arrays.\n *\n * @returns {Array}\n */\n GrahamScan: function (points) {\n var i,\n M = 1,\n ps = Expect.each(points, Expect.coordsArray),\n N = ps.length;\n\n ps = this.sortVertices(ps);\n N = ps.length;\n\n for (i = 2; i < N; i++) {\n while (this.signedTriangle(ps[M - 1], ps[M], ps[i]) <= 0) {\n if (M > 1) {\n M -= 1;\n } else if (i === N - 1) {\n break;\n }\n i += 1;\n }\n\n M += 1;\n ps = Type.swap(ps, M, i);\n }\n\n return ps.slice(0, M);\n },\n\n /**\n * A line can be a segment, a straight, or a ray. So it is not always delimited by point1 and point2\n * calcStraight determines the visual start point and end point of the line. A segment is only drawn\n * from start to end point, a straight line is drawn until it meets the boards boundaries.\n * @param {JXG.Line} el Reference to a line object, that needs calculation of start and end point.\n * @param {JXG.Coords} point1 Coordinates of the point where line drawing begins. This value is calculated and\n * set by this method.\n * @param {JXG.Coords} point2 Coordinates of the point where line drawing ends. This value is calculated and set\n * by this method.\n * @param {Number} margin Optional margin, to avoid the display of the small sides of lines.\n * @returns null\n * @see Line\n * @see JXG.Line\n */\n calcStraight: function (el, point1, point2, margin) {\n var takePoint1, takePoint2, intersection, intersect1, intersect2, straightFirst, straightLast,\n c, p1, p2;\n\n if (!Type.exists(margin)) {\n // Enlarge the drawable region slightly. This hides the small sides\n // of thick lines in most cases.\n margin = 10;\n }\n\n straightFirst = Type.evaluate(el.visProp.straightfirst);\n straightLast = Type.evaluate(el.visProp.straightlast);\n\n // If one of the point is an ideal point in homogeneous coordinates\n // drawing of line segments or rays are not possible.\n if (Math.abs(point1.scrCoords[0]) < Mat.eps) {\n straightFirst = true;\n }\n if (Math.abs(point2.scrCoords[0]) < Mat.eps) {\n straightLast = true;\n }\n\n // Do nothing in case of line segments (inside or outside of the board)\n if (!straightFirst && !straightLast) {\n return;\n }\n\n // Compute the stdform of the line in screen coordinates.\n c = [];\n c[0] = el.stdform[0] -\n el.stdform[1] * el.board.origin.scrCoords[1] / el.board.unitX +\n el.stdform[2] * el.board.origin.scrCoords[2] / el.board.unitY;\n c[1] = el.stdform[1] / el.board.unitX;\n c[2] = -el.stdform[2] / el.board.unitY;\n\n // p1=p2\n if (isNaN(c[0] + c[1] + c[2])) {\n return;\n }\n\n takePoint1 = false;\n takePoint2 = false;\n\n // Line starts at point1 and point1 is inside the board\n takePoint1 = !straightFirst &&\n Math.abs(point1.usrCoords[0]) >= Mat.eps &&\n point1.scrCoords[1] >= 0.0 && point1.scrCoords[1] <= el.board.canvasWidth &&\n point1.scrCoords[2] >= 0.0 && point1.scrCoords[2] <= el.board.canvasHeight;\n\n // Line ends at point2 and point2 is inside the board\n takePoint2 = !straightLast &&\n Math.abs(point2.usrCoords[0]) >= Mat.eps &&\n point2.scrCoords[1] >= 0.0 && point2.scrCoords[1] <= el.board.canvasWidth &&\n point2.scrCoords[2] >= 0.0 && point2.scrCoords[2] <= el.board.canvasHeight;\n\n // Intersect the line with the four borders of the board.\n intersection = this.meetLineBoard(c, el.board, margin);\n intersect1 = intersection[0];\n intersect2 = intersection[1];\n\n /**\n * At this point we have four points:\n * point1 and point2 are the first and the second defining point on the line,\n * intersect1, intersect2 are the intersections of the line with border around the board.\n */\n\n /*\n * Here we handle rays where both defining points are outside of the board.\n */\n // If both points are outside and the complete ray is outside we do nothing\n if (!takePoint1 && !takePoint2) {\n // Ray starting at point 1\n if (!straightFirst && straightLast &&\n !this.isSameDirection(point1, point2, intersect1) && !this.isSameDirection(point1, point2, intersect2)) {\n return;\n }\n\n // Ray starting at point 2\n if (straightFirst && !straightLast &&\n !this.isSameDirection(point2, point1, intersect1) && !this.isSameDirection(point2, point1, intersect2)) {\n return;\n }\n }\n\n /*\n * If at least one of the defining points is outside of the board\n * we take intersect1 or intersect2 as one of the end points\n * The order is also important for arrows of axes\n */\n if (!takePoint1) {\n if (!takePoint2) {\n // Two border intersection points are used\n if (this.isSameDir(point1, point2, intersect1, intersect2)) {\n p1 = intersect1;\n p2 = intersect2;\n } else {\n p2 = intersect1;\n p1 = intersect2;\n }\n } else {\n // One border intersection points is used\n if (this.isSameDir(point1, point2, intersect1, intersect2)) {\n p1 = intersect1;\n } else {\n p1 = intersect2;\n }\n }\n } else {\n if (!takePoint2) {\n // One border intersection points is used\n if (this.isSameDir(point1, point2, intersect1, intersect2)) {\n p2 = intersect2;\n } else {\n p2 = intersect1;\n }\n }\n }\n\n if (p1) {\n //point1.setCoordinates(Const.COORDS_BY_USER, p1.usrCoords.slice(1));\n point1.setCoordinates(Const.COORDS_BY_USER, p1.usrCoords);\n }\n\n if (p2) {\n //point2.setCoordinates(Const.COORDS_BY_USER, p2.usrCoords.slice(1));\n point2.setCoordinates(Const.COORDS_BY_USER, p2.usrCoords);\n }\n },\n\n /**\n * A line can be a segment, a straight, or a ray. so it is not always delimited by point1 and point2.\n *\n * This method adjusts the line's delimiting points taking into account its nature, the viewport defined\n * by the board.\n *\n * A segment is delimited by start and end point, a straight line or ray is delimited until it meets the\n * boards boundaries. However, if the line has infinite ticks, it will be delimited by the projection of\n * the boards vertices onto itself.\n *\n * @param {JXG.Line} el Reference to a line object, that needs calculation of start and end point.\n * @param {JXG.Coords} point1 Coordinates of the point where line drawing begins. This value is calculated and\n * set by this method.\n * @param {JXG.Coords} point2 Coordinates of the point where line drawing ends. This value is calculated and set\n * by this method.\n * @see Line\n * @see JXG.Line\n */\n calcLineDelimitingPoints: function (el, point1, point2) {\n var distP1P2, boundingBox, lineSlope,\n intersect1, intersect2, straightFirst, straightLast,\n c, p1, p2,\n takePoint1 = false,\n takePoint2 = false;\n\n straightFirst = Type.evaluate(el.visProp.straightfirst);\n straightLast = Type.evaluate(el.visProp.straightlast);\n\n // If one of the point is an ideal point in homogeneous coordinates\n // drawing of line segments or rays are not possible.\n if (Math.abs(point1.scrCoords[0]) < Mat.eps) {\n straightFirst = true;\n }\n if (Math.abs(point2.scrCoords[0]) < Mat.eps) {\n straightLast = true;\n }\n\n // Compute the stdform of the line in screen coordinates.\n c = [];\n c[0] = el.stdform[0] -\n el.stdform[1] * el.board.origin.scrCoords[1] / el.board.unitX +\n el.stdform[2] * el.board.origin.scrCoords[2] / el.board.unitY;\n c[1] = el.stdform[1] / el.board.unitX;\n c[2] = -el.stdform[2] / el.board.unitY;\n\n // p1=p2\n if (isNaN(c[0] + c[1] + c[2])) {\n return;\n }\n\n takePoint1 = !straightFirst;\n takePoint2 = !straightLast;\n // Intersect the board vertices on the line to establish the available visual space for the infinite ticks\n // Based on the slope of the line we can optimise and only project the two outer vertices\n\n // boundingBox = [x1, y1, x2, y2] upper left, lower right vertices\n boundingBox = el.board.getBoundingBox();\n lineSlope = el.getSlope();\n if (lineSlope >= 0) {\n // project vertices (x2,y1) (x1, y2)\n intersect1 = this.projectPointToLine({ coords: { usrCoords: [1, boundingBox[2], boundingBox[1]] } }, el, el.board);\n intersect2 = this.projectPointToLine({ coords: { usrCoords: [1, boundingBox[0], boundingBox[3]] } }, el, el.board);\n } else {\n // project vertices (x1, y1) (x2, y2)\n intersect1 = this.projectPointToLine({ coords: { usrCoords: [1, boundingBox[0], boundingBox[1]] } }, el, el.board);\n intersect2 = this.projectPointToLine({ coords: { usrCoords: [1, boundingBox[2], boundingBox[3]] } }, el, el.board);\n }\n\n /**\n * we have four points:\n * point1 and point2 are the first and the second defining point on the line,\n * intersect1, intersect2 are the intersections of the line with border around the board.\n */\n\n /*\n * Here we handle rays/segments where both defining points are outside of the board.\n */\n if (!takePoint1 && !takePoint2) {\n // Segment, if segment does not cross the board, do nothing\n if (!straightFirst && !straightLast) {\n distP1P2 = point1.distance(Const.COORDS_BY_USER, point2);\n // if intersect1 not between point1 and point2\n if (Math.abs(point1.distance(Const.COORDS_BY_USER, intersect1) +\n intersect1.distance(Const.COORDS_BY_USER, point2) - distP1P2) > Mat.eps) {\n return;\n }\n // if insersect2 not between point1 and point2\n if (Math.abs(point1.distance(Const.COORDS_BY_USER, intersect2) +\n intersect2.distance(Const.COORDS_BY_USER, point2) - distP1P2) > Mat.eps) {\n return;\n }\n }\n\n // If both points are outside and the complete ray is outside we do nothing\n // Ray starting at point 1\n if (!straightFirst && straightLast &&\n !this.isSameDirection(point1, point2, intersect1) && !this.isSameDirection(point1, point2, intersect2)) {\n return;\n }\n\n // Ray starting at point 2\n if (straightFirst && !straightLast &&\n !this.isSameDirection(point2, point1, intersect1) && !this.isSameDirection(point2, point1, intersect2)) {\n return;\n }\n }\n\n /*\n * If at least one of the defining points is outside of the board\n * we take intersect1 or intersect2 as one of the end points\n * The order is also important for arrows of axes\n */\n if (!takePoint1) {\n if (!takePoint2) {\n // Two border intersection points are used\n if (this.isSameDir(point1, point2, intersect1, intersect2)) {\n p1 = intersect1;\n p2 = intersect2;\n } else {\n p2 = intersect1;\n p1 = intersect2;\n }\n } else {\n // One border intersection points is used\n if (this.isSameDir(point1, point2, intersect1, intersect2)) {\n p1 = intersect1;\n } else {\n p1 = intersect2;\n }\n }\n } else {\n if (!takePoint2) {\n // One border intersection points is used\n if (this.isSameDir(point1, point2, intersect1, intersect2)) {\n p2 = intersect2;\n } else {\n p2 = intersect1;\n }\n }\n }\n\n if (p1) {\n //point1.setCoordinates(Const.COORDS_BY_USER, p1.usrCoords.slice(1));\n point1.setCoordinates(Const.COORDS_BY_USER, p1.usrCoords);\n }\n\n if (p2) {\n //point2.setCoordinates(Const.COORDS_BY_USER, p2.usrCoords.slice(1));\n point2.setCoordinates(Const.COORDS_BY_USER, p2.usrCoords);\n }\n },\n\n /**\n * Calculates the visProp.position corresponding to a given angle.\n * @param {number} angle angle in radians. Must be in range (-2pi,2pi).\n */\n calcLabelQuadrant: function(angle) {\n var q;\n if (angle < 0) {\n angle += 2*Math.PI;\n }\n q = Math.floor((angle+Math.PI/8)/(Math.PI/4))%8;\n return ['rt','urt','top','ulft','lft','llft','lrt'][q];\n },\n\n /**\n * The vectors <tt>p2-p1</tt> and <tt>i2-i1</tt> are supposed to be collinear. If their cosine is positive\n * they point into the same direction otherwise they point in opposite direction.\n * @param {JXG.Coords} p1\n * @param {JXG.Coords} p2\n * @param {JXG.Coords} i1\n * @param {JXG.Coords} i2\n * @returns {Boolean} True, if <tt>p2-p1</tt> and <tt>i2-i1</tt> point into the same direction\n */\n isSameDir: function (p1, p2, i1, i2) {\n var dpx = p2.usrCoords[1] - p1.usrCoords[1],\n dpy = p2.usrCoords[2] - p1.usrCoords[2],\n dix = i2.usrCoords[1] - i1.usrCoords[1],\n diy = i2.usrCoords[2] - i1.usrCoords[2];\n\n if (Math.abs(p2.usrCoords[0]) < Mat.eps) {\n dpx = p2.usrCoords[1];\n dpy = p2.usrCoords[2];\n }\n\n if (Math.abs(p1.usrCoords[0]) < Mat.eps) {\n dpx = -p1.usrCoords[1];\n dpy = -p1.usrCoords[2];\n }\n\n return dpx * dix + dpy * diy >= 0;\n },\n\n /**\n * If you're looking from point \"start\" towards point \"s\" and you can see the point \"p\", return true.\n * Otherwise return false.\n * @param {JXG.Coords} start The point you're standing on.\n * @param {JXG.Coords} p The point in which direction you're looking.\n * @param {JXG.Coords} s The point that should be visible.\n * @returns {Boolean} True, if from start the point p is in the same direction as s is, that means s-start = k*(p-start) with k>=0.\n */\n isSameDirection: function (start, p, s) {\n var dx, dy, sx, sy, r = false;\n\n dx = p.usrCoords[1] - start.usrCoords[1];\n dy = p.usrCoords[2] - start.usrCoords[2];\n\n sx = s.usrCoords[1] - start.usrCoords[1];\n sy = s.usrCoords[2] - start.usrCoords[2];\n\n if (Math.abs(dx) < Mat.eps) {\n dx = 0;\n }\n\n if (Math.abs(dy) < Mat.eps) {\n dy = 0;\n }\n\n if (Math.abs(sx) < Mat.eps) {\n sx = 0;\n }\n\n if (Math.abs(sy) < Mat.eps) {\n sy = 0;\n }\n\n if (dx >= 0 && sx >= 0) {\n r = (dy >= 0 && sy >= 0) || (dy <= 0 && sy <= 0);\n } else if (dx <= 0 && sx <= 0) {\n r = (dy >= 0 && sy >= 0) || (dy <= 0 && sy <= 0);\n }\n\n return r;\n },\n\n /****************************************/\n /**** INTERSECTIONS ****/\n /****************************************/\n\n /**\n * Generate the function which computes the coordinates of the intersection point.\n * Primarily used in {@link JXG.Point#createIntersectionPoint}.\n * @param {JXG.Board} board object\n * @param {JXG.Line,JXG.Circle_JXG.Line,JXG.Circle_Number} el1,el2,i The result will be a intersection point on el1 and el2.\n * i determines the intersection point if two points are available: <ul>\n * <li>i==0: use the positive square root,</li>\n * <li>i==1: use the negative square root.</li></ul>\n * See further {@link JXG.Point#createIntersectionPoint}.\n * @param {Boolean} alwaysintersect. Flag that determines if segments and arc can have an outer intersection point\n * on their defining line or circle.\n * @returns {Function} Function returning a {@link JXG.Coords} object that determines\n * the intersection point.\n */\n intersectionFunction: function (board, el1, el2, i, j, alwaysintersect) {\n var func, that = this,\n el1_isArcType = false,\n el2_isArcType = false;\n\n el1_isArcType = (el1.elementClass === Const.OBJECT_CLASS_CURVE &&\n (el1.type === Const.OBJECT_TYPE_ARC || el1.type === Const.OBJECT_TYPE_SECTOR)\n ) ? true : false;\n el2_isArcType = (el2.elementClass === Const.OBJECT_CLASS_CURVE &&\n (el2.type === Const.OBJECT_TYPE_ARC || el2.type === Const.OBJECT_TYPE_SECTOR)\n ) ? true : false;\n\n if ((el1.elementClass === Const.OBJECT_CLASS_CURVE || el2.elementClass === Const.OBJECT_CLASS_CURVE) &&\n (el1.elementClass === Const.OBJECT_CLASS_CURVE || el1.elementClass === Const.OBJECT_CLASS_CIRCLE) &&\n (el2.elementClass === Const.OBJECT_CLASS_CURVE || el2.elementClass === Const.OBJECT_CLASS_CIRCLE) /*&&\n !(el1_isArcType && el2_isArcType)*/ ) {\n // curve - curve\n // with the exception that both elements are arc types\n /** @ignore */\n func = function () {\n return that.meetCurveCurve(el1, el2, i, j, el1.board);\n };\n\n } else if ((\n el1.elementClass === Const.OBJECT_CLASS_CURVE &&\n !el1_isArcType &&\n el2.elementClass === Const.OBJECT_CLASS_LINE\n ) ||\n (\n el2.elementClass === Const.OBJECT_CLASS_CURVE &&\n !el2_isArcType &&\n el1.elementClass === Const.OBJECT_CLASS_LINE\n )\n ) {\n // curve - line (this includes intersections between conic sections and lines)\n // with the exception that the curve is of arc type\n /** @ignore */\n func = function () {\n return that.meetCurveLine(el1, el2, i, el1.board, alwaysintersect);\n };\n\n } else if (el1.type === Const.OBJECT_TYPE_POLYGON || el2.type === Const.OBJECT_TYPE_POLYGON) {\n // polygon - other\n // Uses the Greiner-Hormann clipping algorithm\n // Not implemented: polygon - point\n\n if (el1.elementClass === Const.OBJECT_CLASS_LINE) {\n // line - path\n /** @ignore */\n func = function () {\n return that.meetPolygonLine(el2, el1, i, el1.board, alwaysintersect);\n };\n } else if (el2.elementClass === Const.OBJECT_CLASS_LINE) {\n // path - line\n func = function () {\n return that.meetPolygonLine(el1, el2, i, el1.board, alwaysintersect);\n };\n } else {\n // path - path\n /** @ignore */\n func = function () {\n return that.meetPathPath(el1, el2, i, el1.board);\n };\n }\n\n } else if (el1.elementClass === Const.OBJECT_CLASS_LINE && el2.elementClass === Const.OBJECT_CLASS_LINE) {\n // line - line, lines may also be segments.\n /** @ignore */\n func = function () {\n var res, c,\n first1 = Type.evaluate(el1.visProp.straightfirst),\n last1 = Type.evaluate(el1.visProp.straightlast),\n first2 = Type.evaluate(el2.visProp.straightfirst),\n last2 = Type.evaluate(el2.visProp.straightlast);\n\n /**\n * If one of the lines is a segment or ray and\n * the intersection point should disappear if outside\n * of the segment or ray we call\n * meetSegmentSegment\n */\n if (!Type.evaluate(alwaysintersect) && (!first1 || !last1 || !first2 || !last2)) {\n res = that.meetSegmentSegment(\n el1.point1.coords.usrCoords,\n el1.point2.coords.usrCoords,\n el2.point1.coords.usrCoords,\n el2.point2.coords.usrCoords\n );\n\n if ((!first1 && res[1] < 0) || (!last1 && res[1] > 1) ||\n (!first2 && res[2] < 0) || (!last2 && res[2] > 1)) {\n // Non-existent\n c = [0, NaN, NaN];\n } else {\n c = res[0];\n }\n\n return (new Coords(Const.COORDS_BY_USER, c, el1.board));\n }\n\n return that.meet(el1.stdform, el2.stdform, i, el1.board);\n };\n } else {\n // All other combinations of circles and lines,\n // Arc types are treated as circles.\n /** @ignore */\n func = function () {\n var res = that.meet(el1.stdform, el2.stdform, i, el1.board),\n has = true,\n first, last, r, dx;\n\n if (alwaysintersect) {\n return res;\n }\n if (el1.elementClass === Const.OBJECT_CLASS_LINE) {\n first = Type.evaluate(el1.visProp.straightfirst);\n last = Type.evaluate(el1.visProp.straightlast);\n if (!first || !last) {\n r = that.affineRatio(el1.point1.coords, el1.point2.coords, res);\n if ( (!last && r > 1 + Mat.eps) || (!first && r < 0 - Mat.eps) ) {\n return (new Coords(JXG.COORDS_BY_USER, [0, NaN, NaN], el1.board));\n }\n }\n }\n if (el2.elementClass === Const.OBJECT_CLASS_LINE) {\n first = Type.evaluate(el2.visProp.straightfirst);\n last = Type.evaluate(el2.visProp.straightlast);\n if (!first || !last) {\n r = that.affineRatio(el2.point1.coords, el2.point2.coords, res);\n if ( (!last && r > 1 + Mat.eps) || (!first && r < 0 - Mat.eps) ) {\n return (new Coords(JXG.COORDS_BY_USER, [0, NaN, NaN], el1.board));\n }\n }\n }\n if (el1_isArcType) {\n has = that.coordsOnArc(el1, res);\n if (has && el2_isArcType) {\n has = that.coordsOnArc(el2, res);\n }\n if (!has) {\n return (new Coords(JXG.COORDS_BY_USER, [0, NaN, NaN], el1.board));\n }\n }\n return res;\n };\n }\n\n return func;\n },\n\n /**\n * Returns true if the coordinates are on the arc element,\n * false otherwise. Usually, coords is an intersection\n * on the circle line. Now it is decided if coords are on the\n * circle restricted to the arc line.\n * @param {Arc} arc arc or sector element\n * @param {JXG.Coords} coords Coords object of an intersection\n * @returns {Boolean}\n * @private\n */\n coordsOnArc: function(arc, coords) {\n var angle = this.rad(arc.radiuspoint, arc.center, coords.usrCoords.slice(1)),\n alpha = 0.0,\n beta = this.rad(arc.radiuspoint, arc.center, arc.anglepoint),\n ev_s = Type.evaluate(arc.visProp.selection);\n\n if ((ev_s === 'minor' && beta > Math.PI) ||\n (ev_s === 'major' && beta < Math.PI)) {\n alpha = beta;\n beta = 2 * Math.PI;\n }\n if (angle < alpha || angle > beta) {\n return false;\n }\n return true;\n },\n\n /**\n * Computes the intersection of a pair of lines, circles or both.\n * It uses the internal data array stdform of these elements.\n * @param {Array} el1 stdform of the first element (line or circle)\n * @param {Array} el2 stdform of the second element (line or circle)\n * @param {Number} i Index of the intersection point that should be returned.\n * @param board Reference to the board.\n * @returns {JXG.Coords} Coordinates of one of the possible two or more intersection points.\n * Which point will be returned is determined by i.\n */\n meet: function (el1, el2, i, board) {\n var result,\n eps = Mat.eps;\n\n // line line\n if (Math.abs(el1[3]) < eps && Math.abs(el2[3]) < eps) {\n result = this.meetLineLine(el1, el2, i, board);\n // circle line\n } else if (Math.abs(el1[3]) >= eps && Math.abs(el2[3]) < eps) {\n result = this.meetLineCircle(el2, el1, i, board);\n // line circle\n } else if (Math.abs(el1[3]) < eps && Math.abs(el2[3]) >= eps) {\n result = this.meetLineCircle(el1, el2, i, board);\n // circle circle\n } else {\n result = this.meetCircleCircle(el1, el2, i, board);\n }\n\n return result;\n },\n\n /**\n * Intersection of the line with the board\n * @param {Array} line stdform of the line in screen coordinates\n * @param {JXG.Board} board reference to a board.\n * @param {Number} margin optional margin, to avoid the display of the small sides of lines.\n * @returns {Array} [intersection coords 1, intersection coords 2]\n */\n meetLineBoard: function (line, board, margin) {\n // Intersect the line with the four borders of the board.\n var s = [], intersect1, intersect2, i, j;\n\n if (!Type.exists(margin)) {\n margin = 0;\n }\n\n // top\n s[0] = Mat.crossProduct(line, [margin, 0, 1]);\n // left\n s[1] = Mat.crossProduct(line, [margin, 1, 0]);\n // bottom\n s[2] = Mat.crossProduct(line, [-margin - board.canvasHeight, 0, 1]);\n // right\n s[3] = Mat.crossProduct(line, [-margin - board.canvasWidth, 1, 0]);\n\n // Normalize the intersections\n for (i = 0; i < 4; i++) {\n if (Math.abs(s[i][0]) > Mat.eps) {\n for (j = 2; j > 0; j--) {\n s[i][j] /= s[i][0];\n }\n s[i][0] = 1.0;\n }\n }\n\n // line is parallel to \"left\", take \"top\" and \"bottom\"\n if (Math.abs(s[1][0]) < Mat.eps) {\n intersect1 = s[0]; // top\n intersect2 = s[2]; // bottom\n // line is parallel to \"top\", take \"left\" and \"right\"\n } else if (Math.abs(s[0][0]) < Mat.eps) {\n intersect1 = s[1]; // left\n intersect2 = s[3]; // right\n // left intersection out of board (above)\n } else if (s[1][2] < 0) {\n intersect1 = s[0]; // top\n\n // right intersection out of board (below)\n if (s[3][2] > board.canvasHeight) {\n intersect2 = s[2]; // bottom\n } else {\n intersect2 = s[3]; // right\n }\n // left intersection out of board (below)\n } else if (s[1][2] > board.canvasHeight) {\n intersect1 = s[2]; // bottom\n\n // right intersection out of board (above)\n if (s[3][2] < 0) {\n intersect2 = s[0]; // top\n } else {\n intersect2 = s[3]; // right\n }\n } else {\n intersect1 = s[1]; // left\n\n // right intersection out of board (above)\n if (s[3][2] < 0) {\n intersect2 = s[0]; // top\n // right intersection out of board (below)\n } else if (s[3][2] > board.canvasHeight) {\n intersect2 = s[2]; // bottom\n } else {\n intersect2 = s[3]; // right\n }\n }\n\n intersect1 = new Coords(Const.COORDS_BY_SCREEN, intersect1.slice(1), board);\n intersect2 = new Coords(Const.COORDS_BY_SCREEN, intersect2.slice(1), board);\n return [intersect1, intersect2];\n },\n\n /**\n * Intersection of two lines.\n * @param {Array} l1 stdform of the first line\n * @param {Array} l2 stdform of the second line\n * @param {number} i unused\n * @param {JXG.Board} board Reference to the board.\n * @returns {JXG.Coords} Coordinates of the intersection point.\n */\n meetLineLine: function (l1, l2, i, board) {\n /*\n var s = Mat.crossProduct(l1, l2);\n\n if (Math.abs(s[0]) > Mat.eps) {\n s[1] /= s[0];\n s[2] /= s[0];\n s[0] = 1.0;\n }\n */\n var s = isNaN(l1[5] + l2[5]) ? [0, 0, 0] : Mat.crossProduct(l1, l2);\n return new Coords(Const.COORDS_BY_USER, s, board);\n },\n\n /**\n * Intersection of line and circle.\n * @param {Array} lin stdform of the line\n * @param {Array} circ stdform of the circle\n * @param {number} i number of the returned intersection point.\n * i==0: use the positive square root,\n * i==1: use the negative square root.\n * @param {JXG.Board} board Reference to a board.\n * @returns {JXG.Coords} Coordinates of the intersection point\n */\n meetLineCircle: function (lin, circ, i, board) {\n var a, b, c, d, n,\n A, B, C, k, t;\n\n // Radius is zero, return center of circle\n if (circ[4] < Mat.eps) {\n if (Math.abs(Mat.innerProduct([1, circ[6], circ[7]], lin, 3)) < Mat.eps) {\n return new Coords(Const.COORDS_BY_USER, circ.slice(6, 8), board);\n }\n\n return new Coords(Const.COORDS_BY_USER, [NaN, NaN], board);\n }\n c = circ[0];\n b = circ.slice(1, 3);\n a = circ[3];\n d = lin[0];\n n = lin.slice(1, 3);\n\n // Line is assumed to be normalized. Therefore, nn==1 and we can skip some operations:\n /*\n var nn = n[0]*n[0]+n[1]*n[1];\n A = a*nn;\n B = (b[0]*n[1]-b[1]*n[0])*nn;\n C = a*d*d - (b[0]*n[0]+b[1]*n[1])*d + c*nn;\n */\n A = a;\n B = (b[0] * n[1] - b[1] * n[0]);\n C = a * d * d - (b[0] * n[0] + b[1] * n[1]) * d + c;\n\n k = B * B - 4 * A * C;\n if (k > -Mat.eps * Mat.eps) {\n k = Math.sqrt(Math.abs(k));\n t = [(-B + k) / (2 * A), (-B - k) / (2 * A)];\n\n return ((i === 0) ?\n new Coords(Const.COORDS_BY_USER, [-t[0] * (-n[1]) - d * n[0], -t[0] * n[0] - d * n[1]], board) :\n new Coords(Const.COORDS_BY_USER, [-t[1] * (-n[1]) - d * n[0], -t[1] * n[0] - d * n[1]], board)\n );\n }\n\n return new Coords(Const.COORDS_BY_USER, [0, 0, 0], board);\n },\n\n /**\n * Intersection of two circles.\n * @param {Array} circ1 stdform of the first circle\n * @param {Array} circ2 stdform of the second circle\n * @param {number} i number of the returned intersection point.\n * i==0: use the positive square root,\n * i==1: use the negative square root.\n * @param {JXG.Board} board Reference to the board.\n * @returns {JXG.Coords} Coordinates of the intersection point\n */\n meetCircleCircle: function (circ1, circ2, i, board) {\n var radicalAxis;\n\n // Radius is zero, return center of circle, if on other circle\n if (circ1[4] < Mat.eps) {\n if (Math.abs(this.distance(circ1.slice(6, 2), circ2.slice(6, 8)) - circ2[4]) < Mat.eps) {\n return new Coords(Const.COORDS_BY_USER, circ1.slice(6, 8), board);\n }\n\n return new Coords(Const.COORDS_BY_USER, [0, 0, 0], board);\n }\n\n // Radius is zero, return center of circle, if on other circle\n if (circ2[4] < Mat.eps) {\n if (Math.abs(this.distance(circ2.slice(6, 2), circ1.slice(6, 8)) - circ1[4]) < Mat.eps) {\n return new Coords(Const.COORDS_BY_USER, circ2.slice(6, 8), board);\n }\n\n return new Coords(Const.COORDS_BY_USER, [0, 0, 0], board);\n }\n\n radicalAxis = [circ2[3] * circ1[0] - circ1[3] * circ2[0],\n circ2[3] * circ1[1] - circ1[3] * circ2[1],\n circ2[3] * circ1[2] - circ1[3] * circ2[2],\n 0, 1, Infinity, Infinity, Infinity];\n radicalAxis = Mat.normalize(radicalAxis);\n\n return this.meetLineCircle(radicalAxis, circ1, i, board);\n },\n\n /**\n * Compute an intersection of the curves c1 and c2.\n * We want to find values t1, t2 such that\n * c1(t1) = c2(t2), i.e. (c1_x(t1)-c2_x(t2),c1_y(t1)-c2_y(t2)) = (0,0).\n *\n * Methods: segment-wise intersections (default) or generalized Newton method.\n * @param {JXG.Curve} c1 Curve, Line or Circle\n * @param {JXG.Curve} c2 Curve, Line or Circle\n * @param {Number} nr the nr-th intersection point will be returned.\n * @param {Number} t2ini not longer used.\n * @param {JXG.Board} [board=c1.board] Reference to a board object.\n * @param {String} [method='segment'] Intersection method, possible values are 'newton' and 'segment'.\n * @returns {JXG.Coords} intersection point\n */\n meetCurveCurve: function (c1, c2, nr, t2ini, board, method) {\n var co;\n\n if (Type.exists(method) && method === 'newton') {\n co = Numerics.generalizedNewton(c1, c2, nr, t2ini);\n } else {\n if (c1.bezierDegree === 3 || c2.bezierDegree === 3) {\n co = this.meetBezierCurveRedBlueSegments(c1, c2, nr);\n } else {\n co = this.meetCurveRedBlueSegments(c1, c2, nr);\n }\n }\n\n return (new Coords(Const.COORDS_BY_USER, co, board));\n },\n\n /**\n * Intersection of curve with line,\n * Order of input does not matter for el1 and el2.\n * From version 0.99.7 on this method calls\n * {@link JXG.Math.Geometry.meetCurveLineDiscrete}.\n * If higher precision is needed, {@link JXG.Math.Geometry.meetCurveLineContinuous}\n * has to be used.\n *\n * @param {JXG.Curve,JXG.Line} el1 Curve or Line\n * @param {JXG.Curve,JXG.Line} el2 Curve or Line\n * @param {Number} nr the nr-th intersection point will be returned.\n * @param {JXG.Board} [board=el1.board] Reference to a board object.\n * @param {Boolean} alwaysIntersect If false just the segment between the two defining points are tested for intersection\n * @returns {JXG.Coords} Intersection point. In case no intersection point is detected,\n * the ideal point [0,1,0] is returned.\n */\n meetCurveLine: function (el1, el2, nr, board, alwaysIntersect) {\n var v = [0, NaN, NaN], cu, li;\n\n if (!Type.exists(board)) {\n board = el1.board;\n }\n\n if (el1.elementClass === Const.OBJECT_CLASS_CURVE) {\n cu = el1;\n li = el2;\n } else {\n cu = el2;\n li = el1;\n }\n\n v = this.meetCurveLineDiscrete(cu, li, nr, board, !alwaysIntersect);\n\n return v;\n },\n\n /**\n * Intersection of line and curve, continuous case.\n * Finds the nr-the intersection point\n * Uses {@link JXG.Math.Geometry.meetCurveLineDiscrete} as a first approximation.\n * A more exact solution is then found with {@link JXG.Math.Numerics.root}.\n *\n * @param {JXG.Curve} cu Curve\n * @param {JXG.Line} li Line\n * @param {Number} nr Will return the nr-th intersection point.\n * @param {JXG.Board} board\n * @param {Boolean} testSegment Test if intersection has to be inside of the segment or somewhere on the\n * line defined by the segment\n * @returns {JXG.Coords} Coords object containing the intersection.\n */\n meetCurveLineContinuous: function (cu, li, nr, board, testSegment) {\n var t, func0, func1, v, x, y, z,\n eps = Mat.eps,\n epsLow = Mat.eps,\n steps, delta, tnew, i,\n tmin, fmin, ft;\n\n v = this.meetCurveLineDiscrete(cu, li, nr, board, testSegment);\n x = v.usrCoords[1];\n y = v.usrCoords[2];\n\n func0 = function (t) {\n var c1, c2;\n\n if (t > cu.maxX() || t < cu.minX()) {\n return Infinity;\n }\n c1 = x - cu.X(t);\n c2 = y - cu.Y(t);\n return c1 * c1 + c2 * c2;\n };\n\n func1 = function (t) {\n var v = li.stdform[0] + li.stdform[1] * cu.X(t) + li.stdform[2] * cu.Y(t);\n return v * v;\n };\n\n // Find t\n steps = 50;\n delta = (cu.maxX() - cu.minX()) / steps;\n tnew = cu.minX();\n\n fmin = 0.0001; //eps;\n tmin = NaN;\n for (i = 0; i < steps; i++) {\n t = Numerics.root(func0, [Math.max(tnew, cu.minX()), Math.min(tnew + delta, cu.maxX())]);\n ft = Math.abs(func0(t));\n if (ft <= fmin) {\n fmin = ft;\n tmin = t;\n if (fmin < eps) {\n break;\n }\n }\n\n tnew += delta;\n }\n t = tmin;\n // Compute \"exact\" t\n t = Numerics.root(func1, [Math.max(t - delta, cu.minX()), Math.min(t + delta, cu.maxX())]);\n\n ft = func1(t);\n // Is the point on the line?\n if (isNaN(ft) || Math.abs(ft) > epsLow) {\n z = 0.0; //NaN;\n } else {\n z = 1.0;\n }\n\n return (new Coords(Const.COORDS_BY_USER, [z, cu.X(t), cu.Y(t)], board));\n },\n\n /**\n * Intersection of line and curve, discrete case.\n * Segments are treated as lines.\n * Finding the nr-th intersection point should work for all nr.\n * @param {JXG.Curve} cu\n * @param {JXG.Line} li\n * @param {Number} nr\n * @param {JXG.Board} board\n * @param {Boolean} testSegment Test if intersection has to be inside of the segment or somewhere on the\n * line defined by the segment\n *\n * @returns {JXG.Coords} Intersection point. In case no intersection point is detected,\n * the ideal point [0,1,0] is returned.\n */\n meetCurveLineDiscrete: function (cu, li, nr, board, testSegment) {\n var i, j,\n p1, p2, p, q,\n lip1 = li.point1.coords.usrCoords,\n lip2 = li.point2.coords.usrCoords,\n d, res,\n cnt = 0,\n len = cu.numberPoints,\n ev_sf = Type.evaluate(li.visProp.straightfirst),\n ev_sl = Type.evaluate(li.visProp.straightlast);\n\n // In case, no intersection will be found we will take this\n q = new Coords(Const.COORDS_BY_USER, [0, NaN, NaN], board);\n\n if (lip1[0] === 0.0) {\n lip1 = [1, lip2[1] + li.stdform[2], lip2[2] - li.stdform[1]];\n } else if (lip2[0] === 0.0) {\n lip2 = [1, lip1[1] + li.stdform[2], lip1[2] - li.stdform[1]];\n }\n\n p2 = cu.points[0].usrCoords;\n for (i = 1; i < len; i += cu.bezierDegree) {\n p1 = p2.slice(0);\n p2 = cu.points[i].usrCoords;\n d = this.distance(p1, p2);\n\n // The defining points are not identical\n if (d > Mat.eps) {\n if (cu.bezierDegree === 3) {\n res = this.meetBeziersegmentBeziersegment([\n cu.points[i - 1].usrCoords.slice(1),\n cu.points[i].usrCoords.slice(1),\n cu.points[i + 1].usrCoords.slice(1),\n cu.points[i + 2].usrCoords.slice(1)\n ], [\n lip1.slice(1),\n lip2.slice(1)\n ], testSegment);\n } else {\n res = [this.meetSegmentSegment(p1, p2, lip1, lip2)];\n }\n\n for (j = 0; j < res.length; j++) {\n p = res[j];\n if (0 <= p[1] && p[1] <= 1) {\n if (cnt === nr) {\n /**\n * If the intersection point is not part of the segment,\n * this intersection point is set to non-existent.\n * This prevents jumping behavior of the intersection points.\n * But it may be discussed if it is the desired behavior.\n */\n if (testSegment &&\n ((!ev_sf && p[2] < 0) || (!ev_sl && p[2] > 1))) {\n return q; // break;\n }\n\n q = new Coords(Const.COORDS_BY_USER, p[0], board);\n return q; // break;\n }\n cnt += 1;\n }\n }\n }\n }\n\n return q;\n },\n\n /**\n * Find the n-th intersection point of two curves named red (first parameter) and blue (second parameter).\n * We go through each segment of the red curve and search if there is an intersection with a segemnt of the blue curve.\n * This double loop, i.e. the outer loop runs along the red curve and the inner loop runs along the blue curve, defines\n * the n-th intersection point. The segments are either line segments or Bezier curves of degree 3. This depends on\n * the property bezierDegree of the curves.\n * <p>\n * This method works also for transformed curves, since only the already\n * transformed points are used.\n *\n * @param {JXG.Curve} red\n * @param {JXG.Curve} blue\n * @param {Number} nr\n */\n meetCurveRedBlueSegments: function (red, blue, nr) {\n var i, j,\n red1, red2, blue1, blue2, m,\n minX, maxX,\n iFound = 0,\n lenBlue = blue.numberPoints, //points.length,\n lenRed = red.numberPoints; //points.length;\n\n if (lenBlue <= 1 || lenRed <= 1) {\n return [0, NaN, NaN];\n }\n\n for (i = 1; i < lenRed; i++) {\n red1 = red.points[i - 1].usrCoords;\n red2 = red.points[i].usrCoords;\n minX = Math.min(red1[1], red2[1]);\n maxX = Math.max(red1[1], red2[1]);\n\n blue2 = blue.points[0].usrCoords;\n for (j = 1; j < lenBlue; j++) {\n blue1 = blue2;\n blue2 = blue.points[j].usrCoords;\n\n if (Math.min(blue1[1], blue2[1]) < maxX && Math.max(blue1[1], blue2[1]) > minX) {\n m = this.meetSegmentSegment(red1, red2, blue1, blue2);\n if (m[1] >= 0.0 && m[2] >= 0.0 &&\n // The two segments meet in the interior or at the start points\n ((m[1] < 1.0 && m[2] < 1.0) ||\n // One of the curve is intersected in the very last point\n (i === lenRed - 1 && m[1] === 1.0) ||\n (j === lenBlue - 1 && m[2] === 1.0))) {\n if (iFound === nr) {\n return m[0];\n }\n\n iFound++;\n }\n }\n }\n }\n\n return [0, NaN, NaN];\n },\n\n /**\n * (Virtual) Intersection of two segments.\n * @param {Array} p1 First point of segment 1 using normalized homogeneous coordinates [1,x,y]\n * @param {Array} p2 Second point or direction of segment 1 using normalized homogeneous coordinates [1,x,y] or point at infinity [0,x,y], respectively\n * @param {Array} q1 First point of segment 2 using normalized homogeneous coordinates [1,x,y]\n * @param {Array} q2 Second point or direction of segment 2 using normalized homogeneous coordinates [1,x,y] or point at infinity [0,x,y], respectively\n * @returns {Array} [Intersection point, t, u] The first entry contains the homogeneous coordinates\n * of the intersection point. The second and third entry give the position of the intersection with respect\n * to the definiting parameters. For example, the second entry t is defined by: intersection point = p1 + t * deltaP, where\n * deltaP = (p2 - p1) when both parameters are coordinates, and deltaP = p2 if p2 is a point at infinity.\n * If the two segments are collinear, [[0,0,0], Infinity, Infinity] is returned.\n **/\n meetSegmentSegment: function (p1, p2, q1, q2) {\n var t, u, i, d,\n li1 = Mat.crossProduct(p1, p2),\n li2 = Mat.crossProduct(q1, q2),\n c = Mat.crossProduct(li1, li2);\n\n if (Math.abs(c[0]) < Mat.eps) {\n return [c, Infinity, Infinity];\n }\n\n // Normalize the intersection coordinates\n c[1] /= c[0];\n c[2] /= c[0];\n c[0] /= c[0];\n\n // Now compute in principle:\n // t = dist(c - p1) / dist(p2 - p1) and\n // u = dist(c - q1) / dist(q2 - q1)\n // However: the points q1, q2, p1, p2 might be ideal points - or in general - the\n // coordinates might be not normalized.\n // Note that the z-coordinates of p2 and q2 are used to determine whether it should be interpreted\n // as a segment coordinate or a direction.\n i = (Math.abs(p2[1] - p2[0] * p1[1]) < Mat.eps) ? 2 : 1;\n d = p1[i] / p1[0];\n t = (c[i] - d) / ( (p2[0] !== 0) ? (p2[i] / p2[0] - d) : p2[i] );\n\n i = (Math.abs(q2[1] - q2[0] * q1[1]) < Mat.eps) ? 2 : 1;\n d = q1[i] / q1[0];\n u = (c[i] - d) / ( (q2[0] !== 0) ? (q2[i] / q2[0] - d) : q2[i] );\n\n return [c, t, u];\n },\n\n /**\n * Find the n-th intersection point of two pathes, usually given by polygons. Uses parts of the\n * Greiner-Hormann algorithm in JXG.Math.Clip.\n *\n * @param {JXG.Circle|JXG.Curve|JXG.Polygon} path1\n * @param {JXG.Circle|JXG.Curve|JXG.Polygon} path2\n * @param {Number} n\n * @param {JXG.Board} board\n *\n * @returns {JXG.Coords} Intersection point. In case no intersection point is detected,\n * the ideal point [0,0,0] is returned.\n *\n */\n meetPathPath: function(path1, path2, nr, board) {\n var S, C, len, intersections;\n\n S = JXG.Math.Clip._getPath(path1, board);\n len = S.length;\n if (len > 0 && this.distance(S[0].coords.usrCoords, S[len - 1].coords.usrCoords, 3) < Mat.eps) {\n S.pop();\n }\n\n C = JXG.Math.Clip._getPath(path2, board);\n len = C.length;\n if (len > 0 && this.distance(C[0].coords.usrCoords, C[len - 1].coords.usrCoords, 3) < Mat.eps * Mat.eps) {\n C.pop();\n }\n\n // Handle cases where at least one of the paths is empty\n if (nr < 0 || JXG.Math.Clip.isEmptyCase(S, C, 'intersection')) {\n return (new Coords(Const.COORDS_BY_USER, [0, 0, 0], board));\n }\n\n JXG.Math.Clip.makeDoublyLinkedList(S);\n JXG.Math.Clip.makeDoublyLinkedList(C);\n\n intersections = JXG.Math.Clip.findIntersections(S, C, board)[0];\n if (nr < intersections.length) {\n return intersections[nr].coords;\n }\n return (new Coords(Const.COORDS_BY_USER, [0, 0, 0], board));\n },\n\n /**\n * Find the n-th intersection point between a polygon and a line.\n * @param {JXG.Polygon} path\n * @param {JXG.Line} line\n * @param {Number} nr\n * @param {JXG.Board} board\n * @param {Boolean} alwaysIntersect If false just the segment between the two defining points of the line are tested for intersection.\n *\n * @returns {JXG.Coords} Intersection point. In case no intersection point is detected,\n * the ideal point [0,0,0] is returned.\n */\n meetPolygonLine: function(path, line, nr, board, alwaysIntersect) {\n var i, res, border,\n crds = [0,0,0],\n len = path.borders.length,\n intersections = [];\n\n for (i = 0; i < len; i++) {\n border = path.borders[i];\n res = this.meetSegmentSegment(\n border.point1.coords.usrCoords,\n border.point2.coords.usrCoords,\n line.point1.coords.usrCoords,\n line.point2.coords.usrCoords);\n\n if (\n (!alwaysIntersect || (res[2] >= 0 && res[2] < 1)) &&\n res[1] >= 0 && res[1] < 1) {\n intersections.push(res[0]);\n }\n }\n\n if (nr >= 0 && nr < intersections.length) {\n crds = intersections[nr];\n }\n return (new Coords(Const.COORDS_BY_USER, crds, board));\n },\n\n /****************************************/\n /**** BEZIER CURVE ALGORITHMS ****/\n /****************************************/\n\n /**\n * Splits a Bezier curve segment defined by four points into\n * two Bezier curve segments. Dissection point is t=1/2.\n * @param {Array} curve Array of four coordinate arrays of length 2 defining a\n * Bezier curve segment, i.e. [[x0,y0], [x1,y1], [x2,y2], [x3,y3]].\n * @returns {Array} Array consisting of two coordinate arrays for Bezier curves.\n */\n _bezierSplit: function (curve) {\n var p0, p1, p2, p00, p22, p000;\n\n p0 = [(curve[0][0] + curve[1][0]) * 0.5, (curve[0][1] + curve[1][1]) * 0.5];\n p1 = [(curve[1][0] + curve[2][0]) * 0.5, (curve[1][1] + curve[2][1]) * 0.5];\n p2 = [(curve[2][0] + curve[3][0]) * 0.5, (curve[2][1] + curve[3][1]) * 0.5];\n\n p00 = [(p0[0] + p1[0]) * 0.5, (p0[1] + p1[1]) * 0.5];\n p22 = [(p1[0] + p2[0]) * 0.5, (p1[1] + p2[1]) * 0.5];\n\n p000 = [(p00[0] + p22[0]) * 0.5, (p00[1] + p22[1]) * 0.5];\n\n return [[curve[0], p0, p00, p000], [p000, p22, p2, curve[3]]];\n },\n\n /**\n * Computes the bounding box [minX, maxY, maxX, minY] of a Bezier curve segment\n * from its control points.\n * @param {Array} curve Array of four coordinate arrays of length 2 defining a\n * Bezier curve segment, i.e. [[x0,y0], [x1,y1], [x2,y2], [x3,y3]].\n * @returns {Array} Bounding box [minX, maxY, maxX, minY]\n */\n _bezierBbox: function (curve) {\n var bb = [];\n\n if (curve.length === 4) { // bezierDegree == 3\n bb[0] = Math.min(curve[0][0], curve[1][0], curve[2][0], curve[3][0]); // minX\n bb[1] = Math.max(curve[0][1], curve[1][1], curve[2][1], curve[3][1]); // maxY\n bb[2] = Math.max(curve[0][0], curve[1][0], curve[2][0], curve[3][0]); // maxX\n bb[3] = Math.min(curve[0][1], curve[1][1], curve[2][1], curve[3][1]); // minY\n } else { // bezierDegree == 1\n bb[0] = Math.min(curve[0][0], curve[1][0]); // minX\n bb[1] = Math.max(curve[0][1], curve[1][1]); // maxY\n bb[2] = Math.max(curve[0][0], curve[1][0]); // maxX\n bb[3] = Math.min(curve[0][1], curve[1][1]); // minY\n }\n\n return bb;\n },\n\n /**\n * Decide if two Bezier curve segments overlap by comparing their bounding boxes.\n * @param {Array} bb1 Bounding box of the first Bezier curve segment\n * @param {Array} bb2 Bounding box of the second Bezier curve segment\n * @returns {Boolean} true if the bounding boxes overlap, false otherwise.\n */\n _bezierOverlap: function (bb1, bb2) {\n return bb1[2] >= bb2[0] && bb1[0] <= bb2[2] && bb1[1] >= bb2[3] && bb1[3] <= bb2[1];\n },\n\n /**\n * Append list of intersection points to a list.\n * @private\n */\n _bezierListConcat: function (L, Lnew, t1, t2) {\n var i,\n t2exists = Type.exists(t2),\n start = 0,\n len = Lnew.length,\n le = L.length;\n\n if (le > 0 && len > 0 &&\n ((L[le - 1][1] === 1 && Lnew[0][1] === 0) ||\n (t2exists && L[le - 1][2] === 1 && Lnew[0][2] === 0))) {\n start = 1;\n }\n\n for (i = start; i < len; i++) {\n if (t2exists) {\n Lnew[i][2] *= 0.5;\n Lnew[i][2] += t2;\n }\n\n Lnew[i][1] *= 0.5;\n Lnew[i][1] += t1;\n\n L.push(Lnew[i]);\n }\n },\n\n /**\n * Find intersections of two Bezier curve segments by recursive subdivision.\n * Below maxlevel determine intersections by intersection line segments.\n * @param {Array} red Array of four coordinate arrays of length 2 defining the first\n * Bezier curve segment, i.e. [[x0,y0], [x1,y1], [x2,y2], [x3,y3]].\n * @param {Array} blue Array of four coordinate arrays of length 2 defining the second\n * Bezier curve segment, i.e. [[x0,y0], [x1,y1], [x2,y2], [x3,y3]].\n * @param {Number} level Recursion level\n * @returns {Array} List of intersection points (up to nine). Each intersection point is an\n * array of length three (homogeneous coordinates) plus preimages.\n */\n _bezierMeetSubdivision: function (red, blue, level) {\n var bbb, bbr,\n ar, b0, b1, r0, r1, m,\n p0, p1, q0, q1,\n L = [],\n maxLev = 5; // Maximum recursion level\n\n bbr = this._bezierBbox(blue);\n bbb = this._bezierBbox(red);\n\n if (!this._bezierOverlap(bbr, bbb)) {\n return [];\n }\n\n if (level < maxLev) {\n ar = this._bezierSplit(red);\n r0 = ar[0];\n r1 = ar[1];\n\n ar = this._bezierSplit(blue);\n b0 = ar[0];\n b1 = ar[1];\n\n this._bezierListConcat(L, this._bezierMeetSubdivision(r0, b0, level + 1), 0.0, 0.0);\n this._bezierListConcat(L, this._bezierMeetSubdivision(r0, b1, level + 1), 0, 0.5);\n this._bezierListConcat(L, this._bezierMeetSubdivision(r1, b0, level + 1), 0.5, 0.0);\n this._bezierListConcat(L, this._bezierMeetSubdivision(r1, b1, level + 1), 0.5, 0.5);\n\n return L;\n }\n\n // Make homogeneous coordinates\n q0 = [1].concat(red[0]);\n q1 = [1].concat(red[3]);\n p0 = [1].concat(blue[0]);\n p1 = [1].concat(blue[3]);\n\n m = this.meetSegmentSegment(q0, q1, p0, p1);\n\n if (m[1] >= 0.0 && m[2] >= 0.0 && m[1] <= 1.0 && m[2] <= 1.0) {\n return [m];\n }\n\n return [];\n },\n\n /**\n * @param {Boolean} testSegment Test if intersection has to be inside of the segment or somewhere on the line defined by the segment\n */\n _bezierLineMeetSubdivision: function (red, blue, level, testSegment) {\n var bbb, bbr,\n ar, r0, r1, m,\n p0, p1, q0, q1,\n L = [],\n maxLev = 5; // Maximum recursion level\n\n bbb = this._bezierBbox(blue);\n bbr = this._bezierBbox(red);\n\n if (testSegment && !this._bezierOverlap(bbr, bbb)) {\n return [];\n }\n\n if (level < maxLev) {\n ar = this._bezierSplit(red);\n r0 = ar[0];\n r1 = ar[1];\n\n this._bezierListConcat(L, this._bezierLineMeetSubdivision(r0, blue, level + 1), 0.0);\n this._bezierListConcat(L, this._bezierLineMeetSubdivision(r1, blue, level + 1), 0.5);\n\n return L;\n }\n\n // Make homogeneous coordinates\n q0 = [1].concat(red[0]);\n q1 = [1].concat(red[3]);\n p0 = [1].concat(blue[0]);\n p1 = [1].concat(blue[1]);\n\n m = this.meetSegmentSegment(q0, q1, p0, p1);\n\n if (m[1] >= 0.0 && m[1] <= 1.0) {\n if (!testSegment || (m[2] >= 0.0 && m[2] <= 1.0)) {\n return [m];\n }\n }\n\n return [];\n },\n\n /**\n * Find the nr-th intersection point of two Bezier curve segments.\n * @param {Array} red Array of four coordinate arrays of length 2 defining the first\n * Bezier curve segment, i.e. [[x0,y0], [x1,y1], [x2,y2], [x3,y3]].\n * @param {Array} blue Array of four coordinate arrays of length 2 defining the second\n * Bezier curve segment, i.e. [[x0,y0], [x1,y1], [x2,y2], [x3,y3]].\n * @param {Boolean} testSegment Test if intersection has to be inside of the segment or somewhere on the line defined by the segment\n * @returns {Array} Array containing the list of all intersection points as homogeneous coordinate arrays plus\n * preimages [x,y], t_1, t_2] of the two Bezier curve segments.\n *\n */\n meetBeziersegmentBeziersegment: function (red, blue, testSegment) {\n var L, L2, i;\n\n if (red.length === 4 && blue.length === 4) {\n L = this._bezierMeetSubdivision(red, blue, 0);\n } else {\n L = this._bezierLineMeetSubdivision(red, blue, 0, testSegment);\n }\n\n L.sort(function (a, b) {\n return (a[1] - b[1]) * 10000000.0 + (a[2] - b[2]);\n });\n\n L2 = [];\n for (i = 0; i < L.length; i++) {\n // Only push entries different from their predecessor\n if (i === 0 || (L[i][1] !== L[i - 1][1] || L[i][2] !== L[i - 1][2])) {\n L2.push(L[i]);\n }\n }\n return L2;\n },\n\n /**\n * Find the nr-th intersection point of two Bezier curves, i.e. curves with bezierDegree == 3.\n * @param {JXG.Curve} red Curve with bezierDegree == 3\n * @param {JXG.Curve} blue Curve with bezierDegree == 3\n * @param {Number} nr The number of the intersection point which should be returned.\n * @returns {Array} The homogeneous coordinates of the nr-th intersection point.\n */\n meetBezierCurveRedBlueSegments: function (red, blue, nr) {\n var p, i, j, k, po,\n redArr, blueArr,\n bbr, bbb, intersections,\n startRed = 0,\n startBlue = 0,\n lenBlue = blue.numberPoints,\n lenRed = red.numberPoints,\n L = [];\n\n if (lenBlue < blue.bezierDegree + 1 || lenRed < red.bezierDegree + 1) {\n return [0, NaN, NaN];\n }\n lenBlue -= blue.bezierDegree;\n lenRed -= red.bezierDegree;\n\n // For sectors, we ignore the \"legs\"\n if (red.type === Const.OBJECT_TYPE_SECTOR) {\n startRed = 3;\n lenRed -= 3;\n }\n if (blue.type === Const.OBJECT_TYPE_SECTOR) {\n startBlue = 3;\n lenBlue -= 3;\n }\n\n for (i = startRed; i < lenRed; i += red.bezierDegree) {\n p = red.points;\n redArr = [\n p[i].usrCoords.slice(1),\n p[i + 1].usrCoords.slice(1)\n ];\n if (red.bezierDegree === 3) {\n redArr[2] = p[i + 2].usrCoords.slice(1);\n redArr[3] = p[i + 3].usrCoords.slice(1);\n }\n\n bbr = this._bezierBbox(redArr);\n\n for (j = startBlue; j < lenBlue; j += blue.bezierDegree) {\n p = blue.points;\n blueArr = [\n p[j].usrCoords.slice(1),\n p[j + 1].usrCoords.slice(1)\n ];\n if (blue.bezierDegree === 3) {\n blueArr[2] = p[j + 2].usrCoords.slice(1);\n blueArr[3] = p[j + 3].usrCoords.slice(1);\n }\n\n bbb = this._bezierBbox(blueArr);\n if (this._bezierOverlap(bbr, bbb)) {\n intersections = this.meetBeziersegmentBeziersegment(redArr, blueArr);\n if (intersections.length === 0) {\n continue;\n }\n for (k = 0; k < intersections.length; k++) {\n po = intersections[k];\n if (po[1] < -Mat.eps ||\n po[1] > 1 + Mat.eps ||\n po[2] < -Mat.eps ||\n po[2] > 1 + Mat.eps) {\n continue;\n }\n L.push(po);\n }\n if (L.length > nr) {\n return L[nr][0];\n }\n }\n }\n }\n if (L.length > nr) {\n return L[nr][0];\n }\n\n return [0, NaN, NaN];\n },\n\n bezierSegmentEval: function (t, curve) {\n var f, x, y,\n t1 = 1.0 - t;\n\n x = 0;\n y = 0;\n\n f = t1 * t1 * t1;\n x += f * curve[0][0];\n y += f * curve[0][1];\n\n f = 3.0 * t * t1 * t1;\n x += f * curve[1][0];\n y += f * curve[1][1];\n\n f = 3.0 * t * t * t1;\n x += f * curve[2][0];\n y += f * curve[2][1];\n\n f = t * t * t;\n x += f * curve[3][0];\n y += f * curve[3][1];\n\n return [1.0, x, y];\n },\n\n /**\n * Generate the defining points of a 3rd degree bezier curve that approximates\n * a circle sector defined by three coordinate points A, B, C, each defined by an array of length three.\n * The coordinate arrays are given in homogeneous coordinates.\n * @param {Array} A First point\n * @param {Array} B Second point (intersection point)\n * @param {Array} C Third point\n * @param {Boolean} withLegs Flag. If true the legs to the intersection point are part of the curve.\n * @param {Number} sgn Wither 1 or -1. Needed for minor and major arcs. In case of doubt, use 1.\n */\n bezierArc: function (A, B, C, withLegs, sgn) {\n var p1, p2, p3, p4,\n r, phi, beta,\n PI2 = Math.PI * 0.5,\n x = B[1],\n y = B[2],\n z = B[0],\n dataX = [], dataY = [],\n co, si, ax, ay, bx, by, k, v, d, matrix;\n\n r = this.distance(B, A);\n\n // x,y, z is intersection point. Normalize it.\n x /= z;\n y /= z;\n\n phi = this.rad(A.slice(1), B.slice(1), C.slice(1));\n if (sgn === -1) {\n phi = 2 * Math.PI - phi;\n }\n\n p1 = A;\n p1[1] /= p1[0];\n p1[2] /= p1[0];\n p1[0] /= p1[0];\n\n p4 = p1.slice(0);\n\n if (withLegs) {\n dataX = [x, x + 0.333 * (p1[1] - x), x + 0.666 * (p1[1] - x), p1[1]];\n dataY = [y, y + 0.333 * (p1[2] - y), y + 0.666 * (p1[2] - y), p1[2]];\n } else {\n dataX = [p1[1]];\n dataY = [p1[2]];\n }\n\n while (phi > Mat.eps) {\n if (phi > PI2) {\n beta = PI2;\n phi -= PI2;\n } else {\n beta = phi;\n phi = 0;\n }\n\n co = Math.cos(sgn * beta);\n si = Math.sin(sgn * beta);\n\n matrix = [\n [1, 0, 0],\n [x * (1 - co) + y * si, co, -si],\n [y * (1 - co) - x * si, si, co]\n ];\n v = Mat.matVecMult(matrix, p1);\n p4 = [v[0] / v[0], v[1] / v[0], v[2] / v[0]];\n\n ax = p1[1] - x;\n ay = p1[2] - y;\n bx = p4[1] - x;\n by = p4[2] - y;\n\n d = Math.sqrt((ax + bx) * (ax + bx) + (ay + by) * (ay + by));\n\n if (Math.abs(by - ay) > Mat.eps) {\n k = (ax + bx) * (r / d - 0.5) / (by - ay) * 8 / 3;\n } else {\n k = (ay + by) * (r / d - 0.5) / (ax - bx) * 8 / 3;\n }\n\n p2 = [1, p1[1] - k * ay, p1[2] + k * ax];\n p3 = [1, p4[1] + k * by, p4[2] - k * bx];\n\n dataX = dataX.concat([p2[1], p3[1], p4[1]]);\n dataY = dataY.concat([p2[2], p3[2], p4[2]]);\n p1 = p4.slice(0);\n }\n\n if (withLegs) {\n dataX = dataX.concat([ p4[1] + 0.333 * (x - p4[1]), p4[1] + 0.666 * (x - p4[1]), x]);\n dataY = dataY.concat([ p4[2] + 0.333 * (y - p4[2]), p4[2] + 0.666 * (y - p4[2]), y]);\n }\n\n return [dataX, dataY];\n },\n\n /****************************************/\n /**** PROJECTIONS ****/\n /****************************************/\n\n /**\n * Calculates the coordinates of the projection of a given point on a given circle. I.o.w. the\n * nearest one of the two intersection points of the line through the given point and the circles\n * center.\n * @param {JXG.Point,JXG.Coords} point Point to project or coords object to project.\n * @param {JXG.Circle} circle Circle on that the point is projected.\n * @param {JXG.Board} [board=point.board] Reference to the board\n * @returns {JXG.Coords} The coordinates of the projection of the given point on the given circle.\n */\n projectPointToCircle: function (point, circle, board) {\n var dist, P, x, y, factor,\n M = circle.center.coords.usrCoords;\n\n if (!Type.exists(board)) {\n board = point.board;\n }\n\n // gave us a point\n if (Type.isPoint(point)) {\n dist = point.coords.distance(Const.COORDS_BY_USER, circle.center.coords);\n P = point.coords.usrCoords;\n // gave us coords\n } else {\n dist = point.distance(Const.COORDS_BY_USER, circle.center.coords);\n P = point.usrCoords;\n }\n\n if (Math.abs(dist) < Mat.eps) {\n dist = Mat.eps;\n }\n\n factor = circle.Radius() / dist;\n x = M[1] + factor * (P[1] - M[1]);\n y = M[2] + factor * (P[2] - M[2]);\n\n return new Coords(Const.COORDS_BY_USER, [x, y], board);\n },\n\n /**\n * Calculates the coordinates of the orthogonal projection of a given point on a given line. I.o.w. the\n * intersection point of the given line and its perpendicular through the given point.\n * @param {JXG.Point|JXG.Coords} point Point to project.\n * @param {JXG.Line} line Line on that the point is projected.\n * @param {JXG.Board} [board=point.board|board=line.board] Reference to a board.\n * @returns {JXG.Coords} The coordinates of the projection of the given point on the given line.\n */\n projectPointToLine: function (point, line, board) {\n var v = [0, line.stdform[1], line.stdform[2]],\n coords;\n\n if (!Type.exists(board)) {\n if (Type.exists(point.coords)) {\n board = point.board;\n } else {\n board = line.board;\n }\n }\n\n if (Type.exists(point.coords)) {\n coords = point.coords.usrCoords;\n } else {\n coords = point.usrCoords;\n }\n\n v = Mat.crossProduct(v, coords);\n return new Coords(Const.COORDS_BY_USER, Mat.crossProduct(v, line.stdform), board);\n },\n\n /**\n * Calculates the coordinates of the orthogonal projection of a given coordinate array on a given line\n * segment defined by two coordinate arrays.\n * @param {Array} p Point to project.\n * @param {Array} q1 Start point of the line segment on that the point is projected.\n * @param {Array} q2 End point of the line segment on that the point is projected.\n * @returns {Array} The coordinates of the projection of the given point on the given segment\n * and the factor that determines the projected point as a convex combination of the\n * two endpoints q1 and q2 of the segment.\n */\n projectCoordsToSegment: function (p, q1, q2) {\n var t, denom,\n s = [q2[1] - q1[1], q2[2] - q1[2]],\n v = [p[1] - q1[1], p[2] - q1[2]];\n\n /**\n * If the segment has length 0, i.e. is a point,\n * the projection is equal to that point.\n */\n if (Math.abs(s[0]) < Mat.eps && Math.abs(s[1]) < Mat.eps) {\n return [q1, 0];\n }\n\n t = Mat.innerProduct(v, s);\n denom = Mat.innerProduct(s, s);\n t /= denom;\n\n return [ [1, t * s[0] + q1[1], t * s[1] + q1[2]], t];\n },\n\n /**\n * Finds the coordinates of the closest point on a Bezier segment of a\n * {@link JXG.Curve} to a given coordinate array.\n * @param {Array} pos Point to project in homogeneous coordinates.\n * @param {JXG.Curve} curve Curve of type \"plot\" having Bezier degree 3.\n * @param {Number} start Number of the Bezier segment of the curve.\n * @returns {Array} The coordinates of the projection of the given point\n * on the given Bezier segment and the preimage of the curve which\n * determines the closest point.\n */\n projectCoordsToBeziersegment: function (pos, curve, start) {\n var t0,\n /** @ignore */\n minfunc = function (t) {\n var z = [1, curve.X(start + t), curve.Y(start + t)];\n\n z[1] -= pos[1];\n z[2] -= pos[2];\n\n return z[1] * z[1] + z[2] * z[2];\n };\n\n t0 = JXG.Math.Numerics.fminbr(minfunc, [0.0, 1.0]);\n\n return [[1, curve.X(t0 + start), curve.Y(t0 + start)], t0];\n },\n\n /**\n * Calculates the coordinates of the projection of a given point on a given curve.\n * Uses {@link JXG.Math.Geometry.projectCoordsToCurve}.\n *\n * @param {JXG.Point} point Point to project.\n * @param {JXG.Curve} curve Curve on that the point is projected.\n * @param {JXG.Board} [board=point.board] Reference to a board.\n * @see #projectCoordsToCurve\n * @returns {Array} [JXG.Coords, position] The coordinates of the projection of the given\n * point on the given graph and the relative position on the curve (real number).\n */\n projectPointToCurve: function (point, curve, board) {\n if (!Type.exists(board)) {\n board = point.board;\n }\n\n var x = point.X(),\n y = point.Y(),\n t = point.position || 0.0,\n result = this.projectCoordsToCurve(x, y, t, curve, board);\n\n // point.position = result[1];\n\n return result;\n },\n\n /**\n * Calculates the coordinates of the projection of a coordinates pair on a given curve. In case of\n * function graphs this is the\n * intersection point of the curve and the parallel to y-axis through the given point.\n * @param {Number} x coordinate to project.\n * @param {Number} y coordinate to project.\n * @param {Number} t start value for newtons method\n * @param {JXG.Curve} curve Curve on that the point is projected.\n * @param {JXG.Board} [board=curve.board] Reference to a board.\n * @see #projectPointToCurve\n * @returns {JXG.Coords} Array containing the coordinates of the projection of the given point on the given curve and\n * the position on the curve.\n */\n projectCoordsToCurve: function (x, y, t, curve, board) {\n var newCoords, newCoordsObj, i, j,\n mindist, dist, lbda, v, coords, d,\n p1, p2, res,\n minfunc, t_new, f_new, f_old, delta, steps,\n minX, maxX,\n infty = Number.POSITIVE_INFINITY;\n\n if (!Type.exists(board)) {\n board = curve.board;\n }\n\n\n if (Type.evaluate(curve.visProp.curvetype) === 'plot') {\n t = 0;\n mindist = infty;\n if (curve.numberPoints === 0) {\n newCoords = [0, 1, 1];\n } else {\n newCoords = [curve.Z(0), curve.X(0), curve.Y(0)];\n }\n\n if (curve.numberPoints > 1) {\n v = [1, x, y];\n if (curve.bezierDegree === 3) {\n j = 0;\n } else {\n p1 = [curve.Z(0), curve.X(0), curve.Y(0)];\n }\n for (i = 0; i < curve.numberPoints - 1; i++) {\n if (curve.bezierDegree === 3) {\n res = this.projectCoordsToBeziersegment(v, curve, j);\n } else {\n p2 = [curve.Z(i + 1), curve.X(i + 1), curve.Y(i + 1)];\n res = this.projectCoordsToSegment(v, p1, p2);\n }\n lbda = res[1];\n coords = res[0];\n\n if (0.0 <= lbda && lbda <= 1.0) {\n dist = this.distance(coords, v);\n d = i + lbda;\n } else if (lbda < 0.0) {\n coords = p1;\n dist = this.distance(p1, v);\n d = i;\n } else if (lbda > 1.0 && i === curve.numberPoints - 2) {\n coords = p2;\n dist = this.distance(coords, v);\n d = curve.numberPoints - 1;\n }\n\n if (dist < mindist) {\n mindist = dist;\n t = d;\n newCoords = coords;\n }\n\n if (curve.bezierDegree === 3) {\n j++;\n i += 2;\n } else {\n p1 = p2;\n }\n }\n }\n\n newCoordsObj = new Coords(Const.COORDS_BY_USER, newCoords, board);\n } else { // 'parameter', 'polar', 'functiongraph'\n /** @ignore */\n minfunc = function (t) {\n var dx, dy;\n if (t < curve.minX() || t > curve.maxX()) {\n return Infinity;\n }\n dx = x - curve.X(t);\n dy = y - curve.Y(t);\n return dx * dx + dy * dy;\n };\n\n f_old = minfunc(t);\n steps = 50;\n minX = curve.minX();\n maxX = curve.maxX();\n\n delta = (maxX - minX) / steps;\n t_new = minX;\n\n for (i = 0; i < steps; i++) {\n f_new = minfunc(t_new);\n\n if (f_new < f_old || f_old === Infinity) {\n t = t_new;\n f_old = f_new;\n }\n\n t_new += delta;\n }\n\n //t = Numerics.root(Numerics.D(minfunc), t);\n t = Numerics.fminbr(minfunc, [Math.max(t - delta, minX), Math.min(t + delta, maxX)]);\n\n // Distinction between closed and open curves is not necessary.\n // If closed, the cyclic projection shift will work anyhow\n // if (Math.abs(curve.X(minX) - curve.X(maxX)) < Mat.eps &&\n // Math.abs(curve.Y(minX) - curve.Y(maxX)) < Mat.eps) {\n // // Cyclically\n // if (t < minX) {\n // t = maxX + t - minX;\n // }\n // if (t > maxX) {\n // t = minX + t - maxX;\n // }\n // } else {\n t = (t < minX) ? minX : t;\n t = (t > maxX) ? maxX : t;\n // }\n\n newCoordsObj = new Coords(Const.COORDS_BY_USER, [curve.X(t), curve.Y(t)], board);\n }\n\n return [curve.updateTransform(newCoordsObj), t];\n },\n\n /**\n * Calculates the coordinates of the closest orthogonal projection of a given coordinate array onto the\n * border of a polygon.\n * @param {Array} p Point to project.\n * @param {JXG.Polygon} pol Polygon element\n * @returns {Array} The coordinates of the closest projection of the given point to the border of the polygon.\n */\n projectCoordsToPolygon: function (p, pol) {\n var i,\n len = pol.vertices.length,\n d_best = Infinity,\n d,\n projection, proj,\n bestprojection;\n\n for (i = 0; i < len - 1; i++) {\n projection = JXG.Math.Geometry.projectCoordsToSegment(\n p,\n pol.vertices[i].coords.usrCoords,\n pol.vertices[i + 1].coords.usrCoords\n );\n\n if (0 <= projection[1] && projection[1] <= 1) {\n d = JXG.Math.Geometry.distance(projection[0], p, 3);\n proj = projection[0];\n } else if (projection[1] < 0) {\n d = JXG.Math.Geometry.distance(pol.vertices[i].coords.usrCoords, p, 3);\n proj = pol.vertices[i].coords.usrCoords;\n } else {\n d = JXG.Math.Geometry.distance(pol.vertices[i + 1].coords.usrCoords, p, 3);\n proj = pol.vertices[i + 1].coords.usrCoords;\n }\n if (d < d_best) {\n bestprojection = proj.slice(0);\n d_best = d;\n }\n }\n return bestprojection;\n },\n\n /**\n * Calculates the coordinates of the projection of a given point on a given turtle. A turtle consists of\n * one or more curves of curveType 'plot'. Uses {@link JXG.Math.Geometry.projectPointToCurve}.\n * @param {JXG.Point} point Point to project.\n * @param {JXG.Turtle} turtle on that the point is projected.\n * @param {JXG.Board} [board=point.board] Reference to a board.\n * @returns {Array} [JXG.Coords, position] Array containing the coordinates of the projection of the given point on the turtle and\n * the position on the turtle.\n */\n projectPointToTurtle: function (point, turtle, board) {\n var newCoords, t, x, y, i, dist, el, minEl,\n res, newPos,\n np = 0,\n npmin = 0,\n mindist = Number.POSITIVE_INFINITY,\n len = turtle.objects.length;\n\n if (!Type.exists(board)) {\n board = point.board;\n }\n\n // run through all curves of this turtle\n for (i = 0; i < len; i++) {\n el = turtle.objects[i];\n\n if (el.elementClass === Const.OBJECT_CLASS_CURVE) {\n res = this.projectPointToCurve(point, el);\n newCoords = res[0];\n newPos = res[1];\n dist = this.distance(newCoords.usrCoords, point.coords.usrCoords);\n\n if (dist < mindist) {\n x = newCoords.usrCoords[1];\n y = newCoords.usrCoords[2];\n t = newPos;\n mindist = dist;\n minEl = el;\n npmin = np;\n }\n np += el.numberPoints;\n }\n }\n\n newCoords = new Coords(Const.COORDS_BY_USER, [x, y], board);\n // point.position = t + npmin;\n // return minEl.updateTransform(newCoords);\n return [minEl.updateTransform(newCoords), t + npmin];\n },\n\n /**\n * Trivial projection of a point to another point.\n * @param {JXG.Point} point Point to project (not used).\n * @param {JXG.Point} dest Point on that the point is projected.\n * @returns {JXG.Coords} The coordinates of the projection of the given point on the given circle.\n */\n projectPointToPoint: function (point, dest) {\n return dest.coords;\n },\n\n /**\n *\n * @param {JXG.Point|JXG.Coords} point\n * @param {JXG.Board} [board]\n */\n projectPointToBoard: function (point, board) {\n var i, l, c,\n brd = board || point.board,\n // comparison factor, point coord idx, bbox idx, 1st bbox corner x & y idx, 2nd bbox corner x & y idx\n config = [\n // left\n [1, 1, 0, 0, 3, 0, 1],\n // top\n [-1, 2, 1, 0, 1, 2, 1],\n // right\n [-1, 1, 2, 2, 1, 2, 3],\n // bottom\n [1, 2, 3, 0, 3, 2, 3]\n ],\n coords = point.coords || point,\n bbox = brd.getBoundingBox();\n\n for (i = 0; i < 4; i++) {\n c = config[i];\n if (c[0] * coords.usrCoords[c[1]] < c[0] * bbox[c[2]]) {\n // define border\n l = Mat.crossProduct([1, bbox[c[3]], bbox[c[4]]], [1, bbox[c[5]], bbox[c[6]]]);\n l[3] = 0;\n l = Mat.normalize(l);\n\n // project point\n coords = this.projectPointToLine({coords: coords}, {stdform: l}, brd);\n }\n }\n\n return coords;\n },\n\n /**\n * Calculates the distance of a point to a line. The point and the line are given by homogeneous\n * coordinates. For lines this can be line.stdform.\n * @param {Array} point Homogeneous coordinates of a point.\n * @param {Array} line Homogeneous coordinates of a line ([C,A,B] where A*x+B*y+C*z=0).\n * @returns {Number} Distance of the point to the line.\n */\n distPointLine: function (point, line) {\n var a = line[1],\n b = line[2],\n c = line[0],\n nom;\n\n if (Math.abs(a) + Math.abs(b) < Mat.eps) {\n return Number.POSITIVE_INFINITY;\n }\n\n nom = a * point[1] + b * point[2] + c;\n a *= a;\n b *= b;\n\n return Math.abs(nom) / Math.sqrt(a + b);\n },\n\n /**\n * Helper function to create curve which displays a Reuleaux polygons.\n * @param {Array} points Array of points which should be the vertices of the Reuleaux polygon. Typically,\n * these point list is the array vertices of a regular polygon.\n * @param {Number} nr Number of vertices\n * @returns {Array} An array containing the two functions defining the Reuleaux polygon and the two values\n * for the start and the end of the paramtric curve. array may be used as parent array of a\n * {@link JXG.Curve}.\n *\n * @example\n * var A = brd.create('point',[-2,-2]);\n * var B = brd.create('point',[0,1]);\n * var pol = brd.create('regularpolygon',[A,B,3], {withLines:false, fillColor:'none', highlightFillColor:'none', fillOpacity:0.0});\n * var reuleauxTriangle = brd.create('curve', JXG.Math.Geometry.reuleauxPolygon(pol.vertices, 3),\n * {strokeWidth:6, strokeColor:'#d66d55', fillColor:'#ad5544', highlightFillColor:'#ad5544'});\n *\n * </pre><div class=\"jxgbox\" id=\"JXG2543a843-46a9-4372-abc1-94d9ad2db7ac\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * var brd = JXG.JSXGraph.initBoard('JXG2543a843-46a9-4372-abc1-94d9ad2db7ac', {boundingbox: [-5, 5, 5, -5], axis: true, showcopyright:false, shownavigation: false});\n * var A = brd.create('point',[-2,-2]);\n * var B = brd.create('point',[0,1]);\n * var pol = brd.create('regularpolygon',[A,B,3], {withLines:false, fillColor:'none', highlightFillColor:'none', fillOpacity:0.0});\n * var reuleauxTriangle = brd.create('curve', JXG.Math.Geometry.reuleauxPolygon(pol.vertices, 3),\n * {strokeWidth:6, strokeColor:'#d66d55', fillColor:'#ad5544', highlightFillColor:'#ad5544'});\n * </script><pre>\n */\n reuleauxPolygon: function (points, nr) {\n var beta,\n pi2 = Math.PI * 2,\n pi2_n = pi2 / nr,\n diag = (nr - 1) / 2,\n d = 0,\n makeFct = function (which, trig) {\n return function (t, suspendUpdate) {\n var t1 = (t % pi2 + pi2) % pi2,\n j = Math.floor(t1 / pi2_n) % nr;\n\n if (!suspendUpdate) {\n d = points[0].Dist(points[diag]);\n beta = Mat.Geometry.rad([points[0].X() + 1, points[0].Y()], points[0], points[diag % nr]);\n }\n\n if (isNaN(j)) {\n return j;\n }\n\n t1 = t1 * 0.5 + j * pi2_n * 0.5 + beta;\n\n return points[j][which]() + d * Math[trig](t1);\n };\n };\n\n return [makeFct('X', 'cos'), makeFct('Y', 'sin'), 0, pi2];\n },\n\n\n meet3Planes: function (n1, d1, n2, d2, n3, d3) {\n var p = [0, 0, 0],\n n31, n12, n23, denom,\n i;\n\n n31 = Mat.crossProduct(n3, n1);\n n12 = Mat.crossProduct(n1, n2);\n n23 = Mat.crossProduct(n2, n3);\n denom = Mat.innerProduct(n1, n23, 3);\n for (i = 0; i < 3; i++) {\n p[i] = (d1 * n23[i] + d2 * n31[i] + d3 * n12[i]) / denom;\n }\n return p;\n },\n\n\n meetPlanePlane: function (v11, v12, v21, v22) {\n var i, no1, no2,\n v = [0, 0, 0],\n w = [0, 0, 0];\n\n for (i = 0; i < 3; i++) {\n v[i] = Type.evaluate(v11[i]);\n w[i] = Type.evaluate(v12[i]);\n }\n no1 = Mat.crossProduct(v, w);\n\n for (i = 0; i < 3; i++) {\n v[i] = Type.evaluate(v21[i]);\n w[i] = Type.evaluate(v22[i]);\n }\n no2 = Mat.crossProduct(v, w);\n\n return Mat.crossProduct(no1, no2);\n },\n\n project3DTo3DPlane: function (point, normal, foot) {\n // TODO: homogeneous 3D coordinates\n var sol = [0, 0, 0],\n le, d1, d2, lbda;\n\n foot = foot || [0, 0, 0];\n\n le = Mat.norm(normal);\n d1 = Mat.innerProduct(point, normal, 3);\n d2 = Mat.innerProduct(foot, normal, 3);\n // (point - lbda * normal / le) * normal / le == foot * normal / le\n // => (point * normal - foot * normal) == lbda * le\n lbda = (d1 - d2) / le;\n sol = Mat.axpy(-lbda, normal, point);\n\n return sol;\n },\n\n getPlaneBounds: function (v1, v2, q, s, e) {\n var s1, s2, e1, e2, mat, rhs, sol;\n\n if (v1[2] + v2[0] !== 0) {\n mat = [\n [v1[0], v2[0]],\n [v1[1], v2[1]]\n ];\n rhs = [s - q[0], s - q[1]];\n\n sol = Numerics.Gauss(mat, rhs);\n s1 = sol[0];\n s2 = sol[1];\n\n rhs = [e - q[0], e - q[1]];\n sol = Numerics.Gauss(mat, rhs);\n e1 = sol[0];\n e2 = sol[1];\n return [s1, e1, s2, e2];\n }\n return null;\n },\n\n });\n\n return Mat.Geometry;\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Alfred Wassermann\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true*/\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n jxg\n math/math\n utils/type\n */\n\ndefine('math/plot',['jxg', 'base/constants', 'base/coords', 'math/math', 'math/extrapolate', 'math/numerics',\n 'math/statistics', 'math/geometry', 'math/ia', 'utils/type'],\n function (JXG, Const, Coords, Mat, Extrapolate, Numerics, Statistics, Geometry, IntervalArithmetic, Type) {\n\n \"use strict\";\n\n /**\n * Functions for plotting of curves.\n * @name JXG.Math.Plot\n * @exports Mat.Plot as JXG.Math.Plot\n * @namespace\n */\n Mat.Plot = {\n\n /**\n * Check if at least one point on the curve is finite and real.\n **/\n checkReal: function (points) {\n var b = false,\n i, p,\n len = points.length;\n\n for (i = 0; i < len; i++) {\n p = points[i].usrCoords;\n if (!isNaN(p[1]) && !isNaN(p[2]) && Math.abs(p[0]) > Mat.eps) {\n b = true;\n break;\n }\n }\n return b;\n },\n\n //----------------------------------------------------------------------\n // Plot algorithm v0\n //----------------------------------------------------------------------\n /**\n * Updates the data points of a parametric curve. This version is used if {@link JXG.Curve#doadvancedplot} is <tt>false</tt>.\n * @param {JXG.Curve} curve JSXGraph curve element\n * @param {Number} mi Left bound of curve\n * @param {Number} ma Right bound of curve\n * @param {Number} len Number of data points\n * @returns {JXG.Curve} Reference to the curve object.\n */\n updateParametricCurveNaive: function (curve, mi, ma, len) {\n var i, t,\n suspendUpdate = false,\n stepSize = (ma - mi) / len;\n\n for (i = 0; i < len; i++) {\n t = mi + i * stepSize;\n // The last parameter prevents rounding in usr2screen().\n curve.points[i].setCoordinates(Const.COORDS_BY_USER, [curve.X(t, suspendUpdate), curve.Y(t, suspendUpdate)], false);\n curve.points[i]._t = t;\n suspendUpdate = true;\n }\n return curve;\n },\n\n //----------------------------------------------------------------------\n // Plot algorithm v1\n //----------------------------------------------------------------------\n /**\n * Crude and cheap test if the segment defined by the two points <tt>(x0, y0)</tt> and <tt>(x1, y1)</tt> is\n * outside the viewport of the board. All parameters have to be given in screen coordinates.\n *\n * @private\n * @deprecated\n * @param {Number} x0\n * @param {Number} y0\n * @param {Number} x1\n * @param {Number} y1\n * @param {JXG.Board} board\n * @returns {Boolean} <tt>true</tt> if the given segment is outside the visible area.\n */\n isSegmentOutside: function (x0, y0, x1, y1, board) {\n return (y0 < 0 && y1 < 0) || (y0 > board.canvasHeight && y1 > board.canvasHeight) ||\n (x0 < 0 && x1 < 0) || (x0 > board.canvasWidth && x1 > board.canvasWidth);\n },\n\n /**\n * Compares the absolute value of <tt>dx</tt> with <tt>MAXX</tt> and the absolute value of <tt>dy</tt>\n * with <tt>MAXY</tt>.\n *\n * @private\n * @deprecated\n * @param {Number} dx\n * @param {Number} dy\n * @param {Number} MAXX\n * @param {Number} MAXY\n * @returns {Boolean} <tt>true</tt>, if <tt>|dx| < MAXX</tt> and <tt>|dy| < MAXY</tt>.\n */\n isDistOK: function (dx, dy, MAXX, MAXY) {\n return (Math.abs(dx) < MAXX && Math.abs(dy) < MAXY) && !isNaN(dx + dy);\n },\n\n /**\n * @private\n * @deprecated\n */\n isSegmentDefined: function (x0, y0, x1, y1) {\n return !(isNaN(x0 + y0) && isNaN(x1 + y1));\n },\n\n /**\n * Updates the data points of a parametric curve. This version is used if {@link JXG.Curve#doadvancedplot} is <tt>true</tt>.\n * Since 0.99 this algorithm is deprecated. It still can be used if {@link JXG.Curve#doadvancedplotold} is <tt>true</tt>.\n *\n * @deprecated\n * @param {JXG.Curve} curve JSXGraph curve element\n * @param {Number} mi Left bound of curve\n * @param {Number} ma Right bound of curve\n * @returns {JXG.Curve} Reference to the curve object.\n */\n updateParametricCurveOld: function (curve, mi, ma) {\n var i, t, d,\n x, y, t0, x0, y0, top, depth,\n MAX_DEPTH, MAX_XDIST, MAX_YDIST,\n suspendUpdate = false,\n po = new Coords(Const.COORDS_BY_USER, [0, 0], curve.board, false),\n dyadicStack = [],\n depthStack = [],\n pointStack = [],\n divisors = [],\n distOK = false,\n j = 0,\n distFromLine = function (p1, p2, p0) {\n var lbda, d,\n x0 = p0[1] - p1[1],\n y0 = p0[2] - p1[2],\n x1 = p2[0] - p1[1],\n y1 = p2[1] - p1[2],\n den = x1 * x1 + y1 * y1;\n\n if (den >= Mat.eps) {\n lbda = (x0 * x1 + y0 * y1) / den;\n if (lbda > 0) {\n if (lbda <= 1) {\n x0 -= lbda * x1;\n y0 -= lbda * y1;\n // lbda = 1.0;\n } else {\n x0 -= x1;\n y0 -= y1;\n }\n }\n }\n d = x0 * x0 + y0 * y0;\n return Math.sqrt(d);\n };\n\n JXG.deprecated('Curve.updateParametricCurveOld()');\n\n if (curve.board.updateQuality === curve.board.BOARD_QUALITY_LOW) {\n MAX_DEPTH = 15;\n MAX_XDIST = 10; // 10\n MAX_YDIST = 10; // 10\n } else {\n MAX_DEPTH = 21;\n MAX_XDIST = 0.7; // 0.7\n MAX_YDIST = 0.7; // 0.7\n }\n\n divisors[0] = ma - mi;\n for (i = 1; i < MAX_DEPTH; i++) {\n divisors[i] = divisors[i - 1] * 0.5;\n }\n\n i = 1;\n dyadicStack[0] = 1;\n depthStack[0] = 0;\n\n t = mi;\n po.setCoordinates(Const.COORDS_BY_USER, [curve.X(t, suspendUpdate), curve.Y(t, suspendUpdate)], false);\n\n // Now, there was a first call to the functions defining the curve.\n // Defining elements like sliders have been evaluated.\n // Therefore, we can set suspendUpdate to false, so that these defining elements\n // need not be evaluated anymore for the rest of the plotting.\n suspendUpdate = true;\n x0 = po.scrCoords[1];\n y0 = po.scrCoords[2];\n t0 = t;\n\n t = ma;\n po.setCoordinates(Const.COORDS_BY_USER, [curve.X(t, suspendUpdate), curve.Y(t, suspendUpdate)], false);\n x = po.scrCoords[1];\n y = po.scrCoords[2];\n\n pointStack[0] = [x, y];\n\n top = 1;\n depth = 0;\n\n curve.points = [];\n curve.points[j++] = new Coords(Const.COORDS_BY_SCREEN, [x0, y0], curve.board, false);\n\n do {\n distOK = this.isDistOK(x - x0, y - y0, MAX_XDIST, MAX_YDIST) || this.isSegmentOutside(x0, y0, x, y, curve.board);\n while (depth < MAX_DEPTH && (!distOK || depth < 6) && (depth <= 7 || this.isSegmentDefined(x0, y0, x, y))) {\n // We jump out of the loop if\n // * depth>=MAX_DEPTH or\n // * (depth>=6 and distOK) or\n // * (depth>7 and segment is not defined)\n\n dyadicStack[top] = i;\n depthStack[top] = depth;\n pointStack[top] = [x, y];\n top += 1;\n\n i = 2 * i - 1;\n // Here, depth is increased and may reach MAX_DEPTH\n depth++;\n // In that case, t is undefined and we will see a jump in the curve.\n t = mi + i * divisors[depth];\n\n po.setCoordinates(Const.COORDS_BY_USER, [curve.X(t, suspendUpdate), curve.Y(t, suspendUpdate)], false, true);\n x = po.scrCoords[1];\n y = po.scrCoords[2];\n distOK = this.isDistOK(x - x0, y - y0, MAX_XDIST, MAX_YDIST) || this.isSegmentOutside(x0, y0, x, y, curve.board);\n }\n\n if (j > 1) {\n d = distFromLine(curve.points[j - 2].scrCoords, [x, y], curve.points[j - 1].scrCoords);\n if (d < 0.015) {\n j -= 1;\n }\n }\n\n curve.points[j] = new Coords(Const.COORDS_BY_SCREEN, [x, y], curve.board, false);\n curve.points[j]._t = t;\n j += 1;\n\n x0 = x;\n y0 = y;\n t0 = t;\n\n top -= 1;\n x = pointStack[top][0];\n y = pointStack[top][1];\n depth = depthStack[top] + 1;\n i = dyadicStack[top] * 2;\n\n } while (top > 0 && j < 500000);\n\n curve.numberPoints = curve.points.length;\n\n return curve;\n },\n\n //----------------------------------------------------------------------\n // Plot algorithm v2\n //----------------------------------------------------------------------\n\n /**\n * Add a point to the curve plot. If the new point is too close to the previously inserted point,\n * it is skipped.\n * Used in {@link JXG.Curve._plotRecursive}.\n *\n * @private\n * @param {JXG.Coords} pnt Coords to add to the list of points\n */\n _insertPoint_v2: function (curve, pnt, t) {\n var lastReal = !isNaN(this._lastCrds[1] + this._lastCrds[2]), // The last point was real\n newReal = !isNaN(pnt.scrCoords[1] + pnt.scrCoords[2]), // New point is real point\n cw = curve.board.canvasWidth,\n ch = curve.board.canvasHeight,\n off = 500;\n\n newReal = newReal &&\n (pnt.scrCoords[1] > -off && pnt.scrCoords[2] > -off &&\n pnt.scrCoords[1] < cw + off && pnt.scrCoords[2] < ch + off);\n\n /*\n * Prevents two consecutive NaNs or points wich are too close\n */\n if ((!newReal && lastReal) ||\n (newReal && (!lastReal ||\n Math.abs(pnt.scrCoords[1] - this._lastCrds[1]) > 0.7 ||\n Math.abs(pnt.scrCoords[2] - this._lastCrds[2]) > 0.7))) {\n pnt._t = t;\n curve.points.push(pnt);\n this._lastCrds = pnt.copy('scrCoords');\n }\n },\n\n /**\n * Check if there is a single NaN function value at t0.\n * @param {*} curve\n * @param {*} t0\n * @returns {Boolean} true if there is a second NaN point close by, false otherwise\n */\n neighborhood_isNaN_v2: function(curve, t0) {\n var is_undef,\n pnt = new Coords(Const.COORDS_BY_USER, [0, 0], curve.board, false),\n t, p;\n\n t = t0 + Mat.eps;\n pnt.setCoordinates(Const.COORDS_BY_USER, [curve.X(t, true), curve.Y(t, true)], false);\n p = pnt.usrCoords;\n is_undef = isNaN(p[1] + p[2]);\n if (!is_undef) {\n t = t0 - Mat.eps;\n pnt.setCoordinates(Const.COORDS_BY_USER, [curve.X(t, true), curve.Y(t, true)], false);\n p = pnt.usrCoords;\n is_undef = isNaN(p[1] + p[2]);\n if (!is_undef) {\n return false;\n }\n }\n return true;\n },\n\n /**\n * Investigate a function term at the bounds of intervals where\n * the function is not defined, e.g. log(x) at x = 0.\n *\n * c is inbetween a and b\n * @private\n * @param {JXG.Curve} curve JSXGraph curve element\n * @param {Array} a Screen coordinates of the left interval bound\n * @param {Array} b Screen coordinates of the right interval bound\n * @param {Array} c Screen coordinates of the bisection point at (ta + tb) / 2\n * @param {Number} ta Parameter which evaluates to a, i.e. [1, X(ta), Y(ta)] = a in screen coordinates\n * @param {Number} tb Parameter which evaluates to b, i.e. [1, X(tb), Y(tb)] = b in screen coordinates\n * @param {Number} tc (ta + tb) / 2 = tc. Parameter which evaluates to b, i.e. [1, X(tc), Y(tc)] = c in screen coordinates\n * @param {Number} depth Actual recursion depth. The recursion stops if depth is equal to 0.\n * @returns {JXG.Boolean} true if the point is inserted and the recursion should stop, false otherwise.\n */\n _borderCase: function (curve, a, b, c, ta, tb, tc, depth) {\n var t, pnt, p,\n p_good = null,\n j,\n max_it = 30,\n is_undef = false,\n t_nan, t_real, t_real2,\n vx, vy, vx2, vy2, dx, dy;\n // asymptote;\n\n if (depth <= 1) {\n pnt = new Coords(Const.COORDS_BY_USER, [0, 0], curve.board, false);\n // Test if there is a single undefined point.\n // If yes, we ignore it.\n if (isNaN(a[1] + a[2]) && !isNaN(c[1] + c[2]) && !this.neighborhood_isNaN_v2(curve, ta)) {\n return false;\n }\n if (isNaN(b[1] + b[2]) && !isNaN(c[1] + c[2]) && !this.neighborhood_isNaN_v2(curve, tb)) {\n return false;\n }\n if (isNaN(c[1] + c[2]) && (!isNaN(a[1] + a[2]) || !isNaN(b[1] + b[2])) &&\n !this.neighborhood_isNaN_v2(curve, tc)) {\n return false;\n }\n\n j = 0;\n // Bisect a, b and c until the point t_real is inside of the definition interval\n // and as close as possible at the boundary.\n // t_real2 is the second closest point.\n do {\n // There are four cases:\n // a | c | b\n // ---------------\n // inf | R | R\n // R | R | inf\n // inf | inf | R\n // R | inf | inf\n //\n if (isNaN(a[1] + a[2]) && !isNaN(c[1] + c[2])) {\n t_nan = ta;\n t_real = tc;\n t_real2 = tb;\n } else if (isNaN(b[1] + b[2]) && !isNaN(c[1] + c[2])) {\n t_nan = tb;\n t_real = tc;\n t_real2 = ta;\n } else if (isNaN(c[1] + c[2]) && !isNaN(b[1] + b[2])) {\n t_nan = tc;\n t_real = tb;\n t_real2 = tb + (tb - tc);\n } else if (isNaN(c[1] + c[2]) && !isNaN(a[1] + a[2])) {\n t_nan = tc;\n t_real = ta;\n t_real2 = ta - (tc - ta);\n } else {\n return false;\n }\n t = 0.5 * (t_nan + t_real);\n pnt.setCoordinates(Const.COORDS_BY_USER, [curve.X(t, true), curve.Y(t, true)], false);\n p = pnt.usrCoords;\n\n is_undef = isNaN(p[1] + p[2]);\n if (is_undef) {\n t_nan = t;\n } else {\n t_real2 = t_real;\n t_real = t;\n }\n ++j;\n } while (is_undef && j < max_it);\n\n // If bisection was successful, take this point.\n // Useful only for general curves, for function graph\n // the code below overwrite p_good from here.\n if (j < max_it) {\n p_good = p.slice();\n c = p.slice();\n t_real = t;\n }\n\n // OK, bisection has been done now.\n // t_real contains the closest inner point to the border of the interval we could find.\n // t_real2 is the second nearest point to this boundary.\n // Now we approximate the derivative by computing the slope of the line through these two points\n // and test if it is \"infinite\", i.e larger than 400 in absolute values.\n //\n vx = curve.X(t_real, true) ;\n vx2 = curve.X(t_real2, true) ;\n dx = (vx - vx2) / (t_real - t_real2);\n vy = curve.Y(t_real, true) ;\n vy2 = curve.Y(t_real2, true) ;\n dy = (vy - vy2) / (t_real - t_real2);\n\n if (p_good !== null) {\n this._insertPoint_v2(curve, new Coords(Const.COORDS_BY_USER, p_good, curve.board, false));\n return true;\n }\n }\n return false;\n },\n\n /**\n * Recursive interval bisection algorithm for curve plotting.\n * Used in {@link JXG.Curve.updateParametricCurve}.\n * @private\n * @deprecated\n * @param {JXG.Curve} curve JSXGraph curve element\n * @param {Array} a Screen coordinates of the left interval bound\n * @param {Number} ta Parameter which evaluates to a, i.e. [1, X(ta), Y(ta)] = a in screen coordinates\n * @param {Array} b Screen coordinates of the right interval bound\n * @param {Number} tb Parameter which evaluates to b, i.e. [1, X(tb), Y(tb)] = b in screen coordinates\n * @param {Number} depth Actual recursion depth. The recursion stops if depth is equal to 0.\n * @param {Number} delta If the distance of the bisection point at (ta + tb) / 2 from the point (a + b) / 2 is less then delta,\n * the segment [a,b] is regarded as straight line.\n * @returns {JXG.Curve} Reference to the curve object.\n */\n _plotRecursive_v2: function (curve, a, ta, b, tb, depth, delta) {\n var tc, c,\n ds, mindepth = 0,\n isSmooth, isJump, isCusp,\n cusp_threshold = 0.5,\n jump_threshold = 0.99,\n pnt = new Coords(Const.COORDS_BY_USER, [0, 0], curve.board, false);\n\n if (curve.numberPoints > 65536) {\n return;\n }\n\n // Test if the function is undefined in an interval\n if (depth < this.nanLevel && this._isUndefined(curve, a, ta, b, tb)) {\n return this;\n }\n\n if (depth < this.nanLevel && this._isOutside(a, ta, b, tb, curve.board)) {\n return this;\n }\n\n tc = (ta + tb) * 0.5;\n pnt.setCoordinates(Const.COORDS_BY_USER, [curve.X(tc, true), curve.Y(tc, true)], false);\n c = pnt.scrCoords;\n\n if (this._borderCase(curve, a, b, c, ta, tb, tc, depth)) {\n return this;\n }\n\n ds = this._triangleDists(a, b, c); // returns [d_ab, d_ac, d_cb, d_cd]\n\n isSmooth = (depth < this.smoothLevel) && (ds[3] < delta);\n\n isJump = (depth < this.jumpLevel) &&\n ((ds[2] > jump_threshold * ds[0]) ||\n (ds[1] > jump_threshold * ds[0]) ||\n ds[0] === Infinity || ds[1] === Infinity || ds[2] === Infinity);\n\n isCusp = (depth < this.smoothLevel + 2) && (ds[0] < cusp_threshold * (ds[1] + ds[2]));\n\n if (isCusp) {\n mindepth = 0;\n isSmooth = false;\n }\n\n --depth;\n\n if (isJump) {\n this._insertPoint_v2(curve, new Coords(Const.COORDS_BY_SCREEN, [NaN, NaN], curve.board, false), tc);\n } else if (depth <= mindepth || isSmooth) {\n this._insertPoint_v2(curve, pnt, tc);\n //if (this._borderCase(a, b, c, ta, tb, tc, depth)) {}\n } else {\n this._plotRecursive_v2(curve, a, ta, c, tc, depth, delta);\n\n if (!isNaN(pnt.scrCoords[1] + pnt.scrCoords[2])) {\n this._insertPoint_v2(curve, pnt, tc);\n }\n\n this._plotRecursive_v2(curve, c, tc, b, tb, depth, delta);\n }\n\n return this;\n },\n\n /**\n * Updates the data points of a parametric curve. This version is used if {@link JXG.Curve#plotVersion} is <tt>3</tt>.\n *\n * @param {JXG.Curve} curve JSXGraph curve element\n * @param {Number} mi Left bound of curve\n * @param {Number} ma Right bound of curve\n * @returns {JXG.Curve} Reference to the curve object.\n */\n updateParametricCurve_v2: function (curve, mi, ma) {\n var ta, tb, a, b,\n suspendUpdate = false,\n pa = new Coords(Const.COORDS_BY_USER, [0, 0], curve.board, false),\n pb = new Coords(Const.COORDS_BY_USER, [0, 0], curve.board, false),\n depth, delta,\n w2, h2, bbox,\n ret_arr;\n\n //console.time(\"plot\");\n if (curve.board.updateQuality === curve.board.BOARD_QUALITY_LOW) {\n depth = Type.evaluate(curve.visProp.recursiondepthlow) || 13;\n delta = 2;\n // this.smoothLevel = 5; //depth - 7;\n this.smoothLevel = depth - 6;\n this.jumpLevel = 3;\n } else {\n depth = Type.evaluate(curve.visProp.recursiondepthhigh) || 17;\n delta = 2;\n // smoothLevel has to be small for graphs in a huge interval.\n // this.smoothLevel = 3; //depth - 7; // 9\n this.smoothLevel = depth - 9; // 9\n this.jumpLevel = 2;\n }\n this.nanLevel = depth - 4;\n\n curve.points = [];\n\n if (this.xterm === 'x') {\n // For function graphs we can restrict the plot interval\n // to the visible area +plus margin\n bbox = curve.board.getBoundingBox();\n w2 = (bbox[2] - bbox[0]) * 0.3;\n h2 = (bbox[1] - bbox[3]) * 0.3;\n ta = Math.max(mi, bbox[0] - w2);\n tb = Math.min(ma, bbox[2] + w2);\n } else {\n ta = mi;\n tb = ma;\n }\n pa.setCoordinates(Const.COORDS_BY_USER, [curve.X(ta, suspendUpdate), curve.Y(ta, suspendUpdate)], false);\n\n // The first function calls of X() and Y() are done. We can now\n // switch `suspendUpdate` on. If supported by the functions, this\n // avoids for the rest of the plotting algorithm, evaluation of any\n // parent elements.\n suspendUpdate = true;\n\n pb.setCoordinates(Const.COORDS_BY_USER, [curve.X(tb, suspendUpdate), curve.Y(tb, suspendUpdate)], false);\n\n // Find start and end points of the visible area (plus a certain margin)\n ret_arr = this._findStartPoint(curve, pa.scrCoords, ta, pb.scrCoords, tb);\n pa.setCoordinates(Const.COORDS_BY_SCREEN, ret_arr[0], false);\n ta = ret_arr[1];\n ret_arr = this._findStartPoint(curve, pb.scrCoords, tb, pa.scrCoords, ta);\n pb.setCoordinates(Const.COORDS_BY_SCREEN, ret_arr[0], false);\n tb = ret_arr[1];\n\n // Save the visible area.\n // This can be used in Curve.hasPoint().\n this._visibleArea = [ta, tb];\n\n // Start recursive plotting algorithm\n a = pa.copy('scrCoords');\n b = pb.copy('scrCoords');\n pa._t = ta;\n curve.points.push(pa);\n this._lastCrds = pa.copy('scrCoords'); // Used in _insertPoint\n this._plotRecursive_v2(curve, a, ta, b, tb, depth, delta);\n pb._t = tb;\n curve.points.push(pb);\n\n curve.numberPoints = curve.points.length;\n //console.timeEnd(\"plot\");\n\n return curve;\n },\n\n //----------------------------------------------------------------------\n // Plot algorithm v3\n //----------------------------------------------------------------------\n /**\n *\n * @param {JXG.Curve} curve JSXGraph curve element\n * @param {*} pnt\n * @param {*} t\n * @param {*} depth\n * @param {*} limes\n * @private\n */\n _insertLimesPoint: function(curve, pnt, t, depth, limes) {\n var p0, p1, p2;\n\n // Ignore jump point if it follows limes\n if ((Math.abs(this._lastUsrCrds[1]) === Infinity && Math.abs(limes.left_x) === Infinity) ||\n (Math.abs(this._lastUsrCrds[2]) === Infinity && Math.abs(limes.left_y) === Infinity)) {\n // console.log(\"SKIP:\", pnt.usrCoords, this._lastUsrCrds, limes);\n return;\n }\n\n // // Ignore jump left from limes\n // if (Math.abs(limes.left_x) > 100 * Math.abs(this._lastUsrCrds[1])) {\n // x = Math.sign(limes.left_x) * Infinity;\n // } else {\n // x = limes.left_x;\n // }\n // if (Math.abs(limes.left_y) > 100 * Math.abs(this._lastUsrCrds[2])) {\n // y = Math.sign(limes.left_y) * Infinity;\n // } else {\n // y = limes.left_y;\n // }\n // //pnt.setCoordinates(Const.COORDS_BY_USER, [x, y], false);\n\n // Add points at a jump. pnt contains [NaN, NaN]\n //console.log(\"Add\", t, pnt.usrCoords, limes, depth)\n p0 = new Coords(Const.COORDS_BY_USER, [limes.left_x, limes.left_y], curve.board);\n p0._t = t;\n curve.points.push(p0);\n\n if (!isNaN(limes.left_x) && !isNaN(limes.left_y) && !isNaN(limes.right_x) && !isNaN(limes.right_y) &&\n (Math.abs(limes.left_x - limes.right_x) > Mat.eps || Math.abs(limes.left_y - limes.right_y) > Mat.eps)) {\n p1 = new Coords(Const.COORDS_BY_SCREEN, pnt, curve.board);\n p1._t = t;\n curve.points.push(p1);\n }\n\n p2 = new Coords(Const.COORDS_BY_USER, [limes.right_x, limes.right_y], curve.board);\n p2._t = t;\n curve.points.push(p2);\n this._lastScrCrds = p2.copy('scrCoords');\n this._lastUsrCrds = p2.copy('usrCoords');\n\n },\n\n /**\n * Add a point to the curve plot. If the new point is too close to the previously inserted point,\n * it is skipped.\n * Used in {@link JXG.Curve._plotRecursive}.\n *\n * @private\n * @param {JXG.Curve} curve JSXGraph curve element\n * @param {JXG.Coords} pnt Coords to add to the list of points\n */\n _insertPoint: function (curve, pnt, t, depth, limes) {\n var last_is_real = !isNaN(this._lastScrCrds[1] + this._lastScrCrds[2]), // The last point was real\n point_is_real = !isNaN(pnt[1] + pnt[2]), // New point is real point\n cw = curve.board.canvasWidth,\n ch = curve.board.canvasHeight,\n p,\n near = 0.8,\n off = 500;\n\n if (Type.exists(limes)) {\n this._insertLimesPoint(curve, pnt, t, depth, limes);\n return;\n }\n\n // Check if point has real coordinates and\n // coordinates are not too far away from canvas.\n point_is_real = point_is_real &&\n (pnt[1] > -off && pnt[2] > -off &&\n pnt[1] < cw + off && pnt[2] < ch + off);\n\n // Prevent two consecutive NaNs\n if (!last_is_real && !point_is_real) {\n return;\n }\n\n // Prevent two consecutive points which are too close\n if (point_is_real && last_is_real &&\n Math.abs(pnt[1] - this._lastScrCrds[1]) < near &&\n Math.abs(pnt[2] - this._lastScrCrds[2]) < near) {\n return;\n }\n\n // Prevent two consecutive points at infinity (either direction)\n if ((Math.abs(pnt[1]) === Infinity &&\n Math.abs(this._lastUsrCrds[1]) === Infinity) ||\n (Math.abs(pnt[2]) === Infinity &&\n Math.abs(this._lastUsrCrds[2]) === Infinity)) {\n return;\n }\n\n //console.log(\"add\", t, pnt.usrCoords, depth)\n // Add regular point\n p = new Coords(Const.COORDS_BY_SCREEN, pnt, curve.board);\n p._t = t;\n curve.points.push(p);\n this._lastScrCrds = p.copy('scrCoords');\n this._lastUsrCrds = p.copy('usrCoords');\n },\n\n /**\n * Compute distances in screen coordinates between the points ab,\n * ac, cb, and cd, where d = (a + b)/2.\n * cd is used for the smoothness test, ab, ac, cb are used to detect jumps, cusps and poles.\n *\n * @private\n * @param {Array} a Screen coordinates of the left interval bound\n * @param {Array} b Screen coordinates of the right interval bound\n * @param {Array} c Screen coordinates of the bisection point at (ta + tb) / 2\n * @returns {Array} array of distances in screen coordinates between: ab, ac, cb, and cd.\n */\n _triangleDists: function (a, b, c) {\n var d, d_ab, d_ac, d_cb, d_cd;\n\n d = [a[0] * b[0], (a[1] + b[1]) * 0.5, (a[2] + b[2]) * 0.5];\n\n d_ab = Geometry.distance(a, b, 3);\n d_ac = Geometry.distance(a, c, 3);\n d_cb = Geometry.distance(c, b, 3);\n d_cd = Geometry.distance(c, d, 3);\n\n return [d_ab, d_ac, d_cb, d_cd];\n },\n\n /**\n * Test if the function is undefined on an interval:\n * If the interval borders a and b are undefined, 20 random values\n * are tested if they are undefined, too.\n * Only if all values are undefined, we declare the function to be undefined in this interval.\n *\n * @private\n * @param {JXG.Curve} curve JSXGraph curve element\n * @param {Array} a Screen coordinates of the left interval bound\n * @param {Number} ta Parameter which evaluates to a, i.e. [1, X(ta), Y(ta)] = a in screen coordinates\n * @param {Array} b Screen coordinates of the right interval bound\n * @param {Number} tb Parameter which evaluates to b, i.e. [1, X(tb), Y(tb)] = b in screen coordinates\n */\n _isUndefined: function (curve, a, ta, b, tb) {\n var t, i, pnt;\n\n if (!isNaN(a[1] + a[2]) || !isNaN(b[1] + b[2])) {\n return false;\n }\n\n pnt = new Coords(Const.COORDS_BY_USER, [0, 0], curve.board, false);\n\n for (i = 0; i < 20; ++i) {\n t = ta + Math.random() * (tb - ta);\n pnt.setCoordinates(Const.COORDS_BY_USER, [curve.X(t, true), curve.Y(t, true)], false);\n if (!isNaN(pnt.scrCoords[0] + pnt.scrCoords[1] + pnt.scrCoords[2])) {\n return false;\n }\n }\n\n return true;\n },\n\n /**\n * Decide if a path segment is too far from the canvas that we do not need to draw it.\n * @private\n * @param {Array} a Screen coordinates of the start point of the segment\n * @param {Array} ta Curve parameter of a (unused).\n * @param {Array} b Screen coordinates of the end point of the segment\n * @param {Array} tb Curve parameter of b (unused).\n * @param {JXG.Board} board\n * @returns {Boolean} True if the segment is too far away from the canvas, false otherwise.\n */\n _isOutside: function (a, ta, b, tb, board) {\n var off = 500,\n cw = board.canvasWidth,\n ch = board.canvasHeight;\n\n return !!((a[1] < -off && b[1] < -off) ||\n (a[2] < -off && b[2] < -off) ||\n (a[1] > cw + off && b[1] > cw + off) ||\n (a[2] > ch + off && b[2] > ch + off));\n },\n\n /**\n * Decide if a point of a curve is too far from the canvas that we do not need to draw it.\n * @private\n * @param {Array} a Screen coordinates of the point\n * @param {JXG.Board} board\n * @returns {Boolean} True if the point is too far away from the canvas, false otherwise.\n */\n _isOutsidePoint: function (a, board) {\n var off = 500,\n cw = board.canvasWidth,\n ch = board.canvasHeight;\n\n return !!(a[1] < -off ||\n a[2] < -off ||\n a[1] > cw + off ||\n a[2] > ch + off);\n },\n\n /**\n * For a curve c(t) defined on the interval [ta, tb] find the first point\n * which is in the visible area of the board (plus some outside margin).\n * <p>\n * This method is necessary to restrict the recursive plotting algorithm\n * {@link JXG.Curve._plotRecursive} to the visible area and not waste\n * recursion to areas far outside of the visible area.\n * <p>\n * This method can also be used to find the last visible point\n * by reversing the input parameters.\n *\n * @param {JXG.Curve} curve JSXGraph curve element\n * @param {Array} ta Curve parameter of a.\n * @param {Array} b Screen coordinates of the end point of the segment (unused)\n * @param {Array} tb Curve parameter of b\n * @return {Array} Array of length two containing the screen ccordinates of\n * the starting point and the curve parameter at this point.\n * @private\n */\n _findStartPoint: function (curve, a, ta, b, tb) {\n var i, delta, tc,\n td, z, isFound,\n w2, h2,\n pnt = new Coords(Const.COORDS_BY_USER, [0, 0], curve.board, false),\n steps = 40,\n eps = 0.01,\n fnX1, fnX2, fnY1, fnY2,\n bbox = curve.board.getBoundingBox();\n\n // The code below is too unstable.\n // E.g. [function(t) { return Math.pow(t, 2) * (t + 5) * Math.pow(t - 5, 2); }, -8, 8]\n // Therefore, we return here.\n if (true || !this._isOutsidePoint(a, curve.board)) {\n return [a, ta];\n }\n\n w2 = (bbox[2] - bbox[0]) * 0.3;\n h2 = (bbox[1] - bbox[3]) * 0.3;\n bbox[0] -= w2;\n bbox[1] += h2;\n bbox[2] += w2;\n bbox[3] -= h2;\n\n delta = (tb - ta) / steps;\n tc = ta + delta;\n isFound = false;\n\n fnX1 = function(t) { return curve.X(t, true) - bbox[0]; };\n fnY1 = function(t) { return curve.Y(t, true) - bbox[1]; };\n fnX2 = function(t) { return curve.X(t, true) - bbox[2]; };\n fnY2 = function(t) { return curve.Y(t, true) - bbox[3]; };\n for (i = 0; i < steps; ++i) {\n // Left border\n z = bbox[0];\n td = Numerics.root(fnX1, [tc - delta, tc], curve);\n // td = Numerics.fzero(fnX1, [tc - delta, tc], this);\n // console.log(\"A\", tc - delta, tc, td, Math.abs(this.X(td, true) - z));\n if (Math.abs(curve.X(td, true) - z) < eps) { //} * Math.abs(z)) {\n isFound = true;\n break;\n }\n // Top border\n z = bbox[1];\n td = Numerics.root(fnY1, [tc - delta, tc], curve);\n // td = Numerics.fzero(fnY1, [tc - delta, tc], this);\n // console.log(\"B\", tc - delta, tc, td, Math.abs(this.Y(td, true) - z));\n if (Math.abs(curve.Y(td, true) - z) < eps) { // * Math.abs(z)) {\n isFound = true;\n break;\n }\n // Right border\n z = bbox[2];\n td = Numerics.root(fnX2, [tc - delta, tc], curve);\n // td = Numerics.fzero(fnX2, [tc - delta, tc], this);\n // console.log(\"C\", tc - delta, tc, td, Math.abs(this.X(td, true) - z));\n if (Math.abs(curve.X(td, true) - z) < eps) { // * Math.abs(z)) {\n isFound = true;\n break;\n }\n // Bottom border\n z = bbox[3];\n td = Numerics.root(fnY2, [tc - delta, tc], curve);\n // td = Numerics.fzero(fnY2, [tc - delta, tc], this);\n // console.log(\"D\", tc - delta, tc, td, Math.abs(this.Y(td, true) - z));\n if (Math.abs(curve.Y(td, true) - z) < eps) { // * Math.abs(z)) {\n isFound = true;\n break;\n }\n tc += delta;\n }\n if (isFound) {\n pnt.setCoordinates(Const.COORDS_BY_USER, [curve.X(td, true), curve.Y(td, true)], false);\n return [pnt.scrCoords, td];\n }\n console.log(\"TODO _findStartPoint\", curve.Y.toString(), tc);\n pnt.setCoordinates(Const.COORDS_BY_USER, [curve.X(ta, true), curve.Y(ta, true)], false);\n return [pnt.scrCoords, ta];\n },\n\n /**\n * Investigate a function term at the bounds of intervals where\n * the function is not defined, e.g. log(x) at x = 0.\n *\n * c is inbetween a and b\n *\n * @param {JXG.Curve} curve JSXGraph curve element\n * @param {Array} a Screen coordinates of the left interval bound\n * @param {Array} b Screen coordinates of the right interval bound\n * @param {Array} c Screen coordinates of the bisection point at (ta + tb) / 2\n * @param {Number} ta Parameter which evaluates to a, i.e. [1, X(ta), Y(ta)] = a in screen coordinates\n * @param {Number} tb Parameter which evaluates to b, i.e. [1, X(tb), Y(tb)] = b in screen coordinates\n * @param {Number} tc (ta + tb) / 2 = tc. Parameter which evaluates to b, i.e. [1, X(tc), Y(tc)] = c in screen coordinates\n * @param {Number} depth Actual recursion depth. The recursion stops if depth is equal to 0.\n * @returns {JXG.Boolean} true if the point is inserted and the recursion should stop, false otherwise.\n *\n * @private\n */\n _getBorderPos: function(curve, ta, a, tc, c, tb, b) {\n var t, pnt, p,\n j,\n max_it = 30,\n is_undef = false,\n t_real2,\n t_good, t_bad;\n\n pnt = new Coords(Const.COORDS_BY_USER, [0, 0], curve.board, false);\n j = 0;\n // Bisect a, b and c until the point t_real is inside of the definition interval\n // and as close as possible at the boundary.\n // t_real2 is the second closest point.\n // There are four cases:\n // a | c | b\n // ---------------\n // inf | R | R\n // R | R | inf\n // inf | inf | R\n // R | inf | inf\n //\n if (isNaN(a[1] + a[2]) && !isNaN(c[1] + c[2])) {\n t_bad = ta;\n t_good = tc;\n t_real2 = tb;\n } else if (isNaN(b[1] + b[2]) && !isNaN(c[1] + c[2])) {\n t_bad = tb;\n t_good = tc;\n t_real2 = ta;\n } else if (isNaN(c[1] + c[2]) && !isNaN(b[1] + b[2])) {\n t_bad = tc;\n t_good = tb;\n t_real2 = tb + (tb - tc);\n } else if (isNaN(c[1] + c[2]) && !isNaN(a[1] + a[2])) {\n t_bad = tc;\n t_good = ta;\n t_real2 = ta - (tc - ta);\n } else {\n return false;\n }\n do {\n t = 0.5 * (t_good + t_bad);\n pnt.setCoordinates(Const.COORDS_BY_USER, [curve.X(t, true), curve.Y(t, true)], false);\n p = pnt.usrCoords;\n is_undef = isNaN(p[1] + p[2]);\n if (is_undef) {\n t_bad = t;\n } else {\n t_real2 = t_good;\n t_good = t;\n }\n ++j;\n } while (j < max_it && Math.abs(t_good - t_bad) > Mat.eps);\n return t;\n },\n\n /**\n *\n * @param {JXG.Curve} curve JSXGraph curve element\n * @param {Number} ta\n * @param {Number} tb\n */\n _getCuspPos: function(curve, ta, tb) {\n var a = [curve.X(ta, true), curve.Y(ta, true)],\n b = [curve.X(tb, true), curve.Y(tb, true)],\n max_func = function(t) {\n var c = [curve.X(t, true), curve.Y(t, true)];\n return -(Math.sqrt((a[0] - c[0]) * (a[0] - c[0]) + (a[1] - c[1]) * (a[1] - c[1])) +\n Math.sqrt((b[0] - c[0]) * (b[0] - c[0]) + (b[1] - c[1]) * (b[1] - c[1])));\n };\n\n return Numerics.fminbr(max_func, [ta, tb], curve);\n },\n\n /**\n *\n * @param {JXG.Curve} curve JSXGraph curve element\n * @param {Number} ta\n * @param {Number} tb\n */\n _getJumpPos: function(curve, ta, tb) {\n var max_func = function(t) {\n var e = Mat.eps * Mat.eps,\n c1 = [curve.X(t, true), curve.Y(t, true)],\n c2 = [curve.X(t + e, true), curve.Y(t + e, true)];\n return -Math.abs( (c2[1] - c1[1]) / (c2[0] - c1[0]) );\n };\n\n return Numerics.fminbr(max_func, [ta, tb], curve);\n },\n\n /**\n *\n * @param {JXG.Curve} curve JSXGraph curve element\n * @param {Number} t\n * @private\n */\n _getLimits: function(curve, t) {\n var res,\n step = 2 / (curve.maxX() - curve.minX()),\n x_l, x_r, y_l, y_r;\n\n // From left\n res = Extrapolate.limit(t, -step, curve.X);\n x_l = res[0];\n if (res[1] === 'infinite') {\n x_l = Math.sign(x_l) * Infinity;\n }\n\n res = Extrapolate.limit(t, -step, curve.Y);\n y_l = res[0];\n if (res[1] === 'infinite') {\n y_l = Math.sign(y_l) * Infinity;\n }\n\n // From right\n res = Extrapolate.limit(t, step, curve.X);\n x_r = res[0];\n if (res[1] === 'infinite') {\n x_r = Math.sign(x_r) * Infinity;\n }\n\n res = Extrapolate.limit(t, step, curve.Y);\n y_r = res[0];\n if (res[1] === 'infinite') {\n y_r = Math.sign(y_r) * Infinity;\n }\n\n return {\n left_x: x_l,\n left_y: y_l,\n right_x: x_r,\n right_y: y_r,\n t: t\n };\n },\n\n /**\n *\n * @param {JXG.Curve} curve JSXGraph curve element\n * @param {Array} a\n * @param {Number} tc\n * @param {Array} c\n * @param {Number} tb\n * @param {Array} b\n * @param {String} may_be_special\n * @param {Number} depth\n * @private\n */\n _getLimes: function(curve, ta, a, tc, c, tb, b, may_be_special, depth) {\n var t;\n\n if (may_be_special === 'border') {\n t = this._getBorderPos(curve, ta, a, tc, c, tb, b);\n } else if (may_be_special === 'cusp') {\n t = this._getCuspPos(curve, ta, tb);\n } else if (may_be_special === 'jump') {\n t = this._getJumpPos(curve, ta, tb);\n }\n return this._getLimits(curve, t);\n },\n\n /**\n * Recursive interval bisection algorithm for curve plotting.\n * Used in {@link JXG.Curve.updateParametricCurve}.\n * @private\n * @param {JXG.Curve} curve JSXGraph curve element\n * @param {Array} a Screen coordinates of the left interval bound\n * @param {Number} ta Parameter which evaluates to a, i.e. [1, X(ta), Y(ta)] = a in screen coordinates\n * @param {Array} b Screen coordinates of the right interval bound\n * @param {Number} tb Parameter which evaluates to b, i.e. [1, X(tb), Y(tb)] = b in screen coordinates\n * @param {Number} depth Actual recursion depth. The recursion stops if depth is equal to 0.\n * @param {Number} delta If the distance of the bisection point at (ta + tb) / 2 from the point (a + b) / 2 is less then delta,\n * the segment [a,b] is regarded as straight line.\n * @returns {JXG.Curve} Reference to the curve object.\n */\n _plotNonRecursive: function (curve, a, ta, b, tb, d) {\n var tc, c, ds,\n mindepth = 0,\n limes = null,\n a_nan, b_nan,\n isSmooth = false,\n may_be_special = '',\n x, y, oc, depth, ds0,\n stack = [],\n stack_length = 0,\n item;\n\n oc = curve.board.origin.scrCoords;\n stack[stack_length++] = [a, ta, b, tb, d, Infinity];\n while (stack_length > 0) {\n // item = stack.pop();\n item = stack[--stack_length];\n a = item[0];\n ta = item[1];\n b = item[2];\n tb = item[3];\n depth = item[4];\n ds0 = item[5];\n\n isSmooth = false;\n may_be_special = '';\n limes = null;\n //console.log(stack.length, item)\n\n if (curve.points.length > 65536) {\n return;\n }\n\n if (depth < this.nanLevel) {\n // Test if the function is undefined in the whole interval [ta, tb]\n if (this._isUndefined(curve, a, ta, b, tb)) {\n continue;\n }\n // Test if the graph is far outside the visible are for the interval [ta, tb]\n if (this._isOutside(a, ta, b, tb, curve.board)) {\n continue;\n }\n }\n\n tc = (ta + tb) * 0.5;\n\n // Screen coordinates of point at tc\n x = curve.X(tc, true);\n y = curve.Y(tc, true);\n c = [1, oc[1] + x * curve.board.unitX, oc[2] - y * curve.board.unitY];\n ds = this._triangleDists(a, b, c); // returns [d_ab, d_ac, d_cb, d_cd]\n\n a_nan = isNaN(a[1] + a[2]);\n b_nan = isNaN(b[1] + b[2]);\n if ((a_nan && !b_nan) || (!a_nan && b_nan)) {\n may_be_special = 'border';\n } else if (ds[0] > 0.66 * ds0 ||\n ds[0] < this.cusp_threshold * (ds[1] + ds[2]) ||\n ds[1] > 5 * ds[2] ||\n ds[2] > 5 * ds[1]) {\n may_be_special = 'cusp';\n } else if ((ds[2] > this.jump_threshold * ds[0]) ||\n (ds[1] > this.jump_threshold * ds[0]) ||\n ds[0] === Infinity || ds[1] === Infinity || ds[2] === Infinity) {\n may_be_special = 'jump';\n }\n isSmooth = (may_be_special === '' && depth < this.smoothLevel && ds[3] < this.smooth_threshold);\n\n if (depth < this.testLevel && !isSmooth) {\n if (may_be_special === '') {\n isSmooth = true;\n } else {\n limes = this._getLimes(curve, ta, a, tc, c, tb, b, may_be_special, depth);\n }\n }\n\n if (limes !== null) {\n c = [1, NaN, NaN];\n this._insertPoint(curve, c, tc, depth, limes);\n } else if (depth <= mindepth || isSmooth) {\n this._insertPoint(curve, c, tc, depth, null);\n } else {\n stack[stack_length++] = [c, tc, b, tb, depth - 1, ds[0]];\n stack[stack_length++] = [a, ta, c, tc, depth - 1, ds[0]];\n }\n }\n\n return this;\n },\n\n /**\n * Updates the data points of a parametric curve. This version is used if {@link JXG.Curve#plotVersion} is <tt>3</tt>.\n * This is an experimental plot version, <b>not recommended</b> to be used.\n * @param {JXG.Curve} curve JSXGraph curve element\n * @param {Number} mi Left bound of curve\n * @param {Number} ma Right bound of curve\n * @returns {JXG.Curve} Reference to the curve object.\n */\n updateParametricCurve_v3: function (curve, mi, ma) {\n var ta, tb, a, b,\n suspendUpdate = false,\n pa = new Coords(Const.COORDS_BY_USER, [0, 0], curve.board, false),\n pb = new Coords(Const.COORDS_BY_USER, [0, 0], curve.board, false),\n depth,\n w2, // h2,\n bbox,\n ret_arr;\n\n // console.log(\"-----------------------------------------------------------\");\n // console.time(\"plot\");\n if (curve.board.updateQuality === curve.board.BOARD_QUALITY_LOW) {\n depth = Type.evaluate(curve.visProp.recursiondepthlow) || 14;\n } else {\n depth = Type.evaluate(curve.visProp.recursiondepthhigh) || 17;\n }\n\n // smoothLevel has to be small for graphs in a huge interval.\n this.smoothLevel = 7; //depth - 10;\n this.nanLevel = depth - 4;\n this.testLevel = 4;\n this.cusp_threshold = 0.5;\n this.jump_threshold = 0.99;\n this.smooth_threshold = 2;\n\n curve.points = [];\n\n if (curve.xterm === 'x') {\n // For function graphs we can restrict the plot interval\n // to the visible area +plus margin\n bbox = curve.board.getBoundingBox();\n w2 = (bbox[2] - bbox[0]) * 0.3;\n //h2 = (bbox[1] - bbox[3]) * 0.3;\n ta = Math.max(mi, bbox[0] - w2);\n tb = Math.min(ma, bbox[2] + w2);\n } else {\n ta = mi;\n tb = ma;\n }\n pa.setCoordinates(Const.COORDS_BY_USER, [curve.X(ta, suspendUpdate), curve.Y(ta, suspendUpdate)], false);\n\n // The first function calls of X() and Y() are done. We can now\n // switch `suspendUpdate` on. If supported by the functions, this\n // avoids for the rest of the plotting algorithm, evaluation of any\n // parent elements.\n suspendUpdate = true;\n\n pb.setCoordinates(Const.COORDS_BY_USER, [curve.X(tb, suspendUpdate), curve.Y(tb, suspendUpdate)], false);\n\n // Find start and end points of the visible area (plus a certain margin)\n ret_arr = this._findStartPoint(curve, pa.scrCoords, ta, pb.scrCoords, tb);\n pa.setCoordinates(Const.COORDS_BY_SCREEN, ret_arr[0], false);\n ta = ret_arr[1];\n ret_arr = this._findStartPoint(curve, pb.scrCoords, tb, pa.scrCoords, ta);\n pb.setCoordinates(Const.COORDS_BY_SCREEN, ret_arr[0], false);\n tb = ret_arr[1];\n\n // Save the visible area.\n // This can be used in Curve.hasPoint().\n this._visibleArea = [ta, tb];\n\n // Start recursive plotting algorithm\n a = pa.copy('scrCoords');\n b = pb.copy('scrCoords');\n pa._t = ta;\n curve.points.push(pa);\n this._lastScrCrds = pa.copy('scrCoords'); // Used in _insertPoint\n this._lastUsrCrds = pa.copy('usrCoords'); // Used in _insertPoint\n\n this._plotNonRecursive(curve, a, ta, b, tb, depth);\n\n pb._t = tb;\n curve.points.push(pb);\n\n curve.numberPoints = curve.points.length;\n // console.timeEnd(\"plot\");\n // console.log(\"number of points:\", this.numberPoints);\n\n return curve;\n },\n\n //----------------------------------------------------------------------\n // Plot algorithm v4\n //----------------------------------------------------------------------\n\n _criticalInterval: function(vec, le, level) {\n var i, j, le1, med,\n sgn, sgnChange,\n isGroup = false,\n abs_vec,\n last = -Infinity,\n very_small = false,\n smooth = false,\n group = 0,\n groups = [],\n types = [],\n positions = [];\n\n abs_vec = Statistics.abs(vec);\n med = Statistics.median(abs_vec);\n\n if (med < 1.0e-7) {\n med = 1.0e-7;\n very_small = true;\n } else {\n med *= this.criticalThreshold;\n }\n\n //console.log(\"Median\", med);\n for (i = 0; i < le; i++) {\n // Start a group if not yet done and\n // add position to group\n if (abs_vec[i] > med /*&& abs_vec[i] > 0.01*/) {\n positions.push({i: i, v: vec[i], group: group});\n last = i;\n if (!isGroup) {\n isGroup = true;\n }\n } else {\n if (isGroup && i > last + 4) {\n // End the group\n if (positions.length > 0) {\n groups.push(positions.slice(0));\n }\n positions = [];\n isGroup = false;\n group++;\n }\n }\n }\n if (isGroup) {\n if (positions.length > 1) {\n groups.push(positions.slice(0));\n }\n }\n\n if (very_small && groups.length === 0) {\n smooth = true;\n }\n\n // Decide if there is a singular critical point\n // or if a whole interval is problematic.\n // The latter is the case if the differences have many sign changes.\n for (j = 0; j < groups.length; j++) {\n types[j] = 'point';\n le1 = groups[j].length;\n if (le1 < 64) {\n continue;\n }\n sgnChange = 0;\n sgn = Math.sign(groups[j][0].v);\n for (i = 1; i < le1; i++) {\n if (Math.sign(groups[j][i].v) !== sgn) {\n sgnChange++;\n sgn = Math.sign(groups[j][i].v);\n }\n }\n if (sgnChange * 6 > le1) {\n types[j] = 'interval';\n }\n }\n\n return {smooth: smooth, groups: groups, types: types};\n },\n\n Component: function() {\n this.left_isNaN = false;\n this.right_isNaN = false;\n this.left_t = null;\n this.right_t = null;\n this.t_values = [];\n this.x_values = [];\n this.y_values = [];\n this.len = 0;\n },\n\n findComponents: function(curve, mi, ma, steps) {\n var i, t, le, h, x, y,\n components = [],\n comp,\n comp_nr = 0,\n cnt = 0,\n cntNaNs = 0,\n comp_started = false,\n suspended = false;\n\n h = (ma - mi) / steps;\n components[comp_nr] = new this.Component();\n comp = components[comp_nr];\n\n for (i = 0, t = mi; i <= steps; i++, t += h) {\n x = curve.X(t, suspended);\n y = curve.Y(t, suspended);\n\n if (isNaN(x) || isNaN(y)) {\n cntNaNs++;\n // Wait for - at least - two consecutive NaNs\n // This avoids starting a new component if\n // the function value has infinity as intermediate value.\n if (cntNaNs > 1 && comp_started) {\n // Finalize a component\n comp.right_isNaN = true;\n comp.right_t = t - h;\n comp.len = cnt;\n\n // Prepare a new component\n comp_started = false;\n comp_nr++;\n components[comp_nr] = new this.Component();\n comp = components[comp_nr];\n cntNaNs = 0;\n }\n } else {\n // Now there is a non-NaN entry.\n if (!comp_started) {\n // Start the component\n comp_started = true;\n cnt = 0;\n if (cntNaNs > 0) {\n comp.left_t = t - h;\n comp.left_isNaN = true;\n }\n }\n cntNaNs = 0;\n // Add the value to the component\n comp.t_values[cnt] = t;\n comp.x_values[cnt] = x;\n comp.y_values[cnt] = y;\n cnt++;\n }\n if (i === 0) {\n suspended = true;\n }\n }\n if (comp_started) {\n comp.len = cnt;\n } else {\n components.pop();\n }\n\n return components;\n },\n\n getPointType: function(curve, pos, t_approx, t_values, x_table, y_table, len) {\n var x_values = x_table[0],\n y_values = y_table[0],\n full_len = t_values.length,\n result = {\n idx: pos,\n t: t_approx, //t_values[pos],\n x: x_values[pos],\n y: y_values[pos],\n type: 'other'\n };\n\n if (pos < 5) {\n result.type = 'borderleft';\n result.idx = 0;\n result.t = t_values[0];\n result.x = x_values[0];\n result.y = y_values[0];\n\n // console.log('Border left', result.t);\n return result;\n }\n if (pos > len - 6) {\n result.type = 'borderright';\n result.idx = full_len - 1;\n result.t = t_values[full_len - 1];\n result.x = x_values[full_len - 1];\n result.y = y_values[full_len - 1];\n\n // console.log('Border right', result.t, full_len - 1);\n return result;\n }\n\n return result;\n },\n\n newtonApprox: function(idx, t, h, level, table) {\n var i, s = 0.0;\n for (i = level; i > 0; i--) {\n s = (s + table[i][idx]) * (t - (i - 1) * h) / i;\n }\n return s + table[0][idx];\n },\n\n thiele: function(t, recip, t_values, idx, degree) {\n var i, v = 0.0;\n for (i = degree; i > 1; i--) {\n v = (t - t_values[idx + i]) / (recip[i][idx + 1] - recip[i - 2][idx + 1] + v);\n }\n return recip[0][idx + 1] + (t - t_values[idx + 1]) / (recip[1][idx + 1] + v);\n },\n\n differenceMethodExperiments: function(component, curve) {\n var i, level, le, up,\n t_values = component.t_values,\n x_values = component.x_values,\n y_values = component.y_values,\n x_diffs = [],\n y_diffs = [],\n x_slopes = [],\n y_slopes = [],\n x_table = [],\n y_table = [],\n x_recip = [],\n y_recip = [],\n h, numerator,\n // x_med, y_med,\n foundCriticalPoint = 0,\n pos, ma, j, v,\n groups,\n criticalPoints = [];\n\n h = t_values[1] - t_values[0];\n x_table.push([]);\n y_table.push([]);\n x_recip.push([]);\n y_recip.push([]);\n le = y_values.length;\n for (i = 0; i < le; i++) {\n x_table[0][i] = x_values[i];\n y_table[0][i] = y_values[i];\n x_recip[0][i] = x_values[i];\n y_recip[0][i] = y_values[i];\n }\n\n x_table.push([]);\n y_table.push([]);\n x_recip.push([]);\n y_recip.push([]);\n numerator = h;\n le = y_values.length - 1;\n for (i = 0; i < le; i++) {\n x_diffs[i] = x_values[i + 1] - x_values[i];\n y_diffs[i] = y_values[i + 1] - y_values[i];\n x_slopes[i] = x_diffs[i];\n y_slopes[i] = y_diffs[i];\n x_table[1][i] = x_diffs[i];\n y_table[1][i] = y_diffs[i];\n x_recip[1][i] = numerator / x_diffs[i];\n y_recip[1][i] = numerator / y_diffs[i];\n }\n le--;\n\n up = Math.min(8, y_values.length - 1);\n for (level = 1; level < up; level++) {\n x_table.push([]);\n y_table.push([]);\n x_recip.push([]);\n y_recip.push([]);\n numerator *= h;\n for (i = 0; i < le; i++) {\n x_diffs[i] = x_diffs[i + 1] - x_diffs[i];\n y_diffs[i] = y_diffs[i + 1] - y_diffs[i];\n x_table[level + 1][i] = x_diffs[i];\n y_table[level + 1][i] = y_diffs[i];\n x_recip[level + 1][i] = numerator / (x_recip[level][i + 1] - x_recip[level][i]) + x_recip[level - 1][i + 1];\n y_recip[level + 1][i] = numerator / (y_recip[level][i + 1] - y_recip[level][i]) + y_recip[level - 1][i + 1];\n }\n\n // if (level == 1) {\n // console.log(\"bends level=\", level, y_diffs.toString());\n // }\n\n // Store point location which may be centered around\n // critical points.\n // If the lebvel is suitable, step out of the loop.\n groups = this._criticalPoints(y_diffs, le, level);\n if (groups === false) {\n // Its seems, the degree of the polynomial is equal to level\nconsole.log(\"Polynomial of degree\", level);\n groups = [];\n break;\n }\n if (groups.length > 0) {\n foundCriticalPoint++;\n if (foundCriticalPoint > 1 && level % 2 === 0) {\n break;\n }\n }\n le--;\n }\n\n // console.log(\"Last diffs\", y_diffs, \"level\", level);\n\n // Analyze the groups which have been found.\n for (i = 0; i < groups.length; i++) {\n // console.log(\"Group\", i, groups[i])\n // Identify the maximum difference, i.e. the center of the \"problem\"\n ma = -Infinity;\n for (j = 0; j < groups[i].length; j++) {\n v = Math.abs(groups[i][j].v);\n if (v > ma) {\n ma = v;\n pos = j;\n }\n }\n pos = Math.floor(groups[i][pos].i + level / 2);\n // Analyze the critical point\n criticalPoints.push(this.getPointType(curve, pos, t_values, x_values, y_values, x_slopes, y_slopes, le + 1));\n }\n\n return [criticalPoints, x_table, y_table, x_recip, y_recip];\n\n },\n\n getCenterOfCriticalInterval: function(group, degree, t_values) {\n var ma, j, pos, v,\n num = 0.0,\n den = 0.0,\n h = t_values[1] - t_values[0],\n pos_mean,\n range = [];\n\n // Identify the maximum difference, i.e. the center of the \"problem\"\n // If there are several equal maxima, store the positions\n // in the array range and determine the center of the array.\n\n ma = -Infinity;\n range = [];\n for (j = 0; j < group.length; j++) {\n v = Math.abs(group[j].v);\n if (v > ma) {\n range = [j];\n ma = v;\n pos = j;\n } else if (ma === v) {\n range.push(j);\n }\n }\n if (range.length > 0) {\n pos_mean = range.reduce(function(total, val) { return total + val; }, 0) / range.length;\n pos = Math.floor(pos_mean);\n pos_mean += group[0].i;\n }\n\n if (ma < Infinity) {\n for (j = 0; j < group.length; j++) {\n num += Math.abs(group[j].v) * group[j].i;\n den += Math.abs(group[j].v);\n }\n pos_mean = num / den;\n }\n pos_mean += degree / 2;\n return [group[pos].i + degree / 2, pos_mean, t_values[Math.floor(pos_mean)] + h * (pos_mean - Math.floor(pos_mean))];\n },\n\n differenceMethod: function(component, curve) {\n var i, level, le, up,\n t_values = component.t_values,\n x_values = component.x_values,\n y_values = component.y_values,\n x_table = [],\n y_table = [],\n foundCriticalPoint = 0,\n degree_x = -1,\n degree_y = -1,\n pos, res, res_x, res_y, t_approx,\n groups = [],\n types,\n criticalPoints = [];\n\n le = y_values.length;\n // x_table.push([]);\n // y_table.push([]);\n // for (i = 0; i < le; i++) {\n // x_table[0][i] = x_values[i];\n // y_table[0][i] = y_values[i];\n // }\n x_table.push(new Float64Array(x_values));\n y_table.push(new Float64Array(y_values));\n\n le--;\n up = Math.min(12, le);\n for (level = 0; level < up; level++) {\n // Old style method:\n // x_table.push([]);\n // y_table.push([]);\n // for (i = 0; i < le; i++) {\n // x_table[level + 1][i] = x_table[level][i + 1] - x_table[level][i];\n // y_table[level + 1][i] = y_table[level][i + 1] - y_table[level][i];\n // }\n // New method:\n x_table.push(new Float64Array(le));\n y_table.push(new Float64Array(le));\n x_table[level + 1] = x_table[level].map(function(v, idx, arr) { return arr[idx + 1] - v;});\n y_table[level + 1] = y_table[level].map(function(v, idx, arr) { return arr[idx + 1] - v;});\n\n // Store point location which may be centered around critical points.\n // If the level is suitable, step out of the loop.\n res_y = this._criticalInterval(y_table[level + 1], le, level);\n if (res_y.smooth === true) {\n // Its seems, the degree of the polynomial is equal to level\n // If the values in level + 1 are zero, it might be a polynomial of degree level.\n // Seems to work numerically stable until degree 6.\n degree_y = level;\n groups = [];\n }\n res_x = this._criticalInterval(x_table[level + 1], le, level);\n if (degree_x === -1 && res_x.smooth === true) {\n // Its seems, the degree of the polynomial is equal to level\n // If the values in level + 1 are zero, it might be a polynomial of degree level.\n // Seems to work numerically stable until degree 6.\n degree_x = level;\n }\n if (degree_y >= 0) {\n break;\n }\n\n if (res_y.groups.length > 0) {\n foundCriticalPoint++;\n if (foundCriticalPoint > 2 && (level + 1) % 2 === 0) {\n groups = res_y.groups;\n types = res_y.types;\n break;\n }\n }\n le--;\n }\n\n // console.log(\"Last diffs\", y_table[Math.min(level + 1, up)], \"level\", level + 1);\n // Analyze the groups which have been found.\n for (i = 0; i < groups.length; i++) {\n if (types[i] === 'interval') {\n continue;\n }\n // console.log(\"Group\", i, groups[i], types[i], level + 1)\n res = this.getCenterOfCriticalInterval(groups[i], level + 1, t_values);\n pos = res_y[0];\n pos = Math.floor(res[1]);\n t_approx = res[2];\n // console.log(\"Critical points:\", groups, res, pos)\n\n // Analyze the type of the critical point\n // Result is of type 'borderleft', borderright', 'other'\n criticalPoints.push(this.getPointType(curve, pos, t_approx, t_values, x_table, y_table, le + 1));\n }\n\n // if (level === up) {\n // console.log(\"No convergence!\");\n // } else {\n // console.log(\"Convergence level\", level);\n // }\n return [criticalPoints, x_table, y_table, degree_x, degree_y];\n\n },\n\n _insertPoint_v4: function (curve, crds, t, doLog) {\n var p,\n prev = null,\n x, y,\n near = 0.8;\n\n if (curve.points.length > 0) {\n prev = curve.points[curve.points.length - 1].scrCoords;\n }\n\n // Add regular point\n p = new Coords(Const.COORDS_BY_USER, crds, curve.board);\n\n if (prev !== null) {\n x = p.scrCoords[1] - prev[1];\n y = p.scrCoords[2] - prev[2];\n if (x * x + y * y < near * near) {\n // Math.abs(p.scrCoords[1] - prev[1]) < near &&\n // Math.abs(p.scrCoords[2] - prev[2]) < near) {\n return;\n }\n }\n\n p._t = t;\n curve.points.push(p);\n },\n\n getInterval: function(curve, ta, tb) {\n var t_int, x_int, y_int;\n\n //console.log('critical point', ta, tb);\n IntervalArithmetic.disable();\n\n t_int = IntervalArithmetic.Interval(ta, tb);\n curve.board.mathLib = IntervalArithmetic;\n curve.board.mathLibJXG = IntervalArithmetic;\n x_int = curve.X(t_int, true);\n y_int = curve.Y(t_int, true);\n curve.board.mathLib = Math;\n curve.board.mathLibJXG = JXG.Math;\n\n //console.log(x_int, y_int);\n return y_int;\n },\n\n sign: function (v) {\n if (v < 0) { return -1; }\n if (v > 0) { return 1; }\n return 0;\n },\n\n handleBorder: function(curve, comp, group, x_table, y_table) {\n var idx = group.idx,\n t, t1, t2,\n size = 32,\n y_int,\n x, y,\n lo, hi, i,\n components2, le, h;\n\n // console.log(\"HandleBorder at t =\", t_approx);\n // console.log(\"component:\", comp)\n // console.log(\"Group:\", group);\n\n h = comp.t_values[1] - comp.t_values[0];\n if (group.type === 'borderleft') {\n t = comp.left_isNaN ? comp.left_t : group.t - h;\n t1 = t;\n t2 = t1 + h;\n } else if (group.type === 'borderright') {\n t = comp.right_isNaN ? comp.right_t : group.t + h;\n t2 = t;\n t1 = t2 - h;\n } else {\n console.log(\"No bordercase!!!\");\n }\n\n components2 = this.findComponents(curve, t1, t2, size);\n if (components2.length === 0) {\n return;\n }\n if (group.type === 'borderleft') {\n t1 = components2[0].left_t;\n t2 = components2[0].t_values[0];\n h = components2[0].t_values[1] - components2[0].t_values[0];\n t1 = (t1 === null) ? t2- h : t1;\n t = t1;\n y_int = this.getInterval(curve, t1, t2);\n if (Type.isObject(y_int)) {\n lo = y_int.lo;\n hi = y_int.hi;\n\n x = curve.X(t, true);\n y = (y_table[1][idx] < 0) ? hi : lo;\n this._insertPoint_v4(curve, [1, x, y], t);\n }\n }\n\n le = components2[0].t_values.length;\n for (i = 0; i < le; i++) {\n t = components2[0].t_values[i];\n x = components2[0].x_values[i];\n y = components2[0].y_values[i];\n this._insertPoint_v4(curve, [1, x, y], t);\n }\n\n if (group.type === 'borderright') {\n t1 = components2[0].t_values[le - 1];\n t2 = components2[0].right_t;\n h = components2[0].t_values[1] - components2[0].t_values[0];\n t2 = (t2 === null) ? t1 + h : t2;\n\n t = t2;\n y_int = this.getInterval(curve, t1, t2);\n if (Type.isObject(y_int)) {\n lo = y_int.lo;\n hi = y_int.hi;\n x = curve.X(t, true);\n y = (y_table[1][idx] > 0) ? hi : lo;\n this._insertPoint_v4(curve, [1, x, y], t);\n }\n }\n\n },\n\n _seconditeration_v4: function(curve, comp, group, x_table, y_table) {\n var i, t1, t2, ret,\n components2, comp2, idx, groups2, g,\n x_table2, y_table2, start, le;\n\n // Look at two points, hopefully left and right from the critical point\n t1 = comp.t_values[group.idx - 2];\n t2 = comp.t_values[group.idx + 2];\n components2 = this.findComponents(curve, t1, t2, 64);\n for (idx = 0; idx < components2.length; idx++) {\n comp2 = components2[idx];\n ret = this.differenceMethod(comp2, curve);\n groups2 = ret[0];\n x_table2 = ret[1];\n y_table2 = ret[2];\n start = 0;\n for (g = 0; g <= groups2.length; g++) {\n if (g === groups2.length) {\n le = comp2.len;\n } else {\n le = groups2[g].idx;\n }\n\n // Insert all uncritical points until next critical point\n for (i = start; i < le; i++) {\n if (!isNaN(comp2.x_values[i]) && !isNaN(comp2.y_values[i])) {\n this._insertPoint_v4(curve, [1, comp2.x_values[i], comp2.y_values[i]], comp2.t_values[i]);\n }\n }\n // Handle next critical point\n if (g < groups2.length) {\n this.handleSingularity(curve, comp2, groups2[g], x_table2, y_table2);\n start = groups2[g].idx + 1;\n }\n }\n le = comp2.len;\n if (idx < components2.length - 1) {\n this._insertPoint_v4(curve, [1, NaN, NaN], comp2.right_t);\n }\n }\n return this;\n },\n\n _recurse_v4: function(curve, t1, t2, x1, y1, x2, y2, level) {\n var tol = 2,\n t = (t1 + t2) * 0.5,\n x = curve.X(t, true),\n y = curve.Y(t, true),\n dx, dy;\n\n //console.log(\"Level\", level)\n if (level === 0) {\n this._insertPoint_v4(curve, [1, NaN, NaN], t);\n return;\n }\n // console.log(\"R\", t1, t2)\n dx = (x - x1) * curve.board.unitX;\n dy = (y - y1) * curve.board.unitY;\n // console.log(\"D1\", Math.sqrt(dx * dx + dy * dy))\n if (Math.sqrt(dx * dx + dy * dy) > tol) {\n this._recurse_v4(curve, t1, t, x1, y1, x, y, level - 1);\n } else {\n this._insertPoint_v4(curve, [1, x, y], t);\n }\n dx = (x - x2) * curve.board.unitX;\n dy = (y - y2) * curve.board.unitY;\n // console.log(\"D2\", Math.sqrt(dx * dx + dy * dy), x-x2, y-y2)\n if (Math.sqrt(dx * dx + dy * dy) > tol) {\n this._recurse_v4(curve, t, t2, x, y, x2, y2, level - 1);\n } else {\n this._insertPoint_v4(curve, [1, x, y], t);\n }\n },\n\n handleSingularity: function(curve, comp, group, x_table, y_table) {\n var idx = group.idx,\n t, t1, t2, y_int,\n i1, i2,\n x, y, lo, hi,\n d_lft, d_rgt,\n d_thresh = 100,\n di1 = 5,\n di2 = 3,\n d1, d2;\n\n t = group.t;\n console.log(\"HandleSingularity at t =\", t);\n // console.log(comp.t_values[idx - 1], comp.y_values[idx - 1], comp.t_values[idx + 1], comp.y_values[idx + 1]);\n // console.log(group);\n\n // Look at two points, hopefully left and right from the critical point\n t1 = comp.t_values[idx - di1];\n t2 = comp.t_values[idx + di1];\n\n y_int = this.getInterval(curve, t1, t2);\n if (Type.isObject(y_int)) {\n lo = y_int.lo;\n hi = y_int.hi;\n } else {\n if (y_table[0][idx - 1] < y_table[0][idx + 1]) {\n lo = y_table[0][idx - 1];\n hi = y_table[0][idx + 1];\n } else {\n lo = y_table[0][idx + 1];\n hi = y_table[0][idx - 1];\n }\n }\n\n x = curve.X(t, true);\n\n d_lft = (y_table[0][idx - di2] - y_table[0][idx - di1]) / (comp.t_values[idx - di2] - comp.t_values[idx - di1]);\n d_rgt = (y_table[0][idx + di2] - y_table[0][idx + di1]) / (comp.t_values[idx + di2] - comp.t_values[idx + di1]);\n\n console.log(\":::\", d_lft, d_rgt);\n\n //this._insertPoint_v4(curve, [1, NaN, NaN], 0);\n\n if (d_lft < -d_thresh) {\n // Left branch very steep downwards -> add the minimum\n this._insertPoint_v4(curve, [1, x, lo], t, true);\n if (d_rgt <= d_thresh) {\n // Right branch not very steep upwards -> interrupt the curve\n // I.e. it looks like -infty / (finite or infty) and not like -infty / -infty\n this._insertPoint_v4(curve, [1, NaN, NaN], t);\n }\n } else if (d_lft > d_thresh) {\n // Left branch very steep upwards -> add the maximum\n this._insertPoint_v4(curve, [1, x, hi], t);\n if (d_rgt >= -d_thresh) {\n // Right branch not very steep downwards -> interrupt the curve\n // I.e. it looks like infty / (finite or -infty) and not like infty / infty\n this._insertPoint_v4(curve, [1, NaN, NaN], t);\n }\n } else {\n if (lo === -Infinity) {\n this._insertPoint_v4(curve, [1, x, lo], t, true);\n this._insertPoint_v4(curve, [1, NaN, NaN], t);\n }\n if (hi === Infinity) {\n this._insertPoint_v4(curve, [1, NaN, NaN], t);\n this._insertPoint_v4(curve, [1, x, hi], t, true);\n }\n\n if (group.t < comp.t_values[idx]) {\n i1 = idx - 1;\n i2 = idx;\n } else {\n i1 = idx;\n i2 = idx + 1;\n }\n t1 = comp.t_values[i1];\n t2 = comp.t_values[i2];\n this._recurse_v4(curve, t1, t2,\n x_table[0][i1],\n y_table[0][i1],\n x_table[0][i2],\n y_table[0][i2],\n 10\n );\n\n // x = (x_table[0][idx] - x_table[0][idx - 1]) * curve.board.unitX;\n // y = (y_table[0][idx] - y_table[0][idx - 1]) * curve.board.unitY;\n // d1 = Math.sqrt(x * x + y * y);\n // x = (x_table[0][idx + 1] - x_table[0][idx]) * curve.board.unitX;\n // y = (y_table[0][idx + 1] - y_table[0][idx]) * curve.board.unitY;\n // d2 = Math.sqrt(x * x + y * y);\n\n // console.log(\"end\", t1, t2, t);\n // if (true || (d1 > 2 || d2 > 2)) {\n\n// console.log(d1, d2, y_table[0][idx])\n// // Finite jump\n// this._insertPoint_v4(curve, [1, NaN, NaN], t);\n// } else {\n// if (lo !== -Infinity && hi !== Infinity) {\n// // Critical point which can be ignored\n// this._insertPoint_v4(curve, [1, x_table[0][idx], y_table[0][idx]], comp.t_values[idx]);\n// } else {\n// if (lo === -Infinity) {\n// this._insertPoint_v4(curve, [1, x, lo], t, true);\n// this._insertPoint_v4(curve, [1, NaN, NaN], t);\n// }\n// if (hi === Infinity) {\n// this._insertPoint_v4(curve, [1, NaN, NaN], t);\n// this._insertPoint_v4(curve, [1, x, hi], t, true);\n// }\n// }\n // }\n }\n if (d_rgt < -d_thresh) {\n // Right branch very steep downwards -> add the maximum\n this._insertPoint_v4(curve, [1, x, hi], t);\n } else if (d_rgt > d_thresh) {\n // Right branch very steep upwards -> add the minimum\n this._insertPoint_v4(curve, [1, x, lo], t);\n }\n\n },\n\n /**\n * Number of equidistant points where the function is evaluated\n */\n steps: 1021, //2053, // 1021,\n\n /**\n * If the absolute maximum of the set of differences is larger than\n * criticalThreshold * median of these values, it is regarded as critical point.\n * @see JXG.Math.Plot#_criticalInterval\n */\n criticalThreshold: 1000,\n\n plot_v4: function(curve, ta, tb, steps) {\n var i, j, le, components, idx, comp,\n groups, g, start,\n ret, x_table, y_table,\n t, t1, t2,\n good, bad,\n x_int, y_int,\n degree_x, degree_y,\n h = (tb - ta) / steps,\n Ypl = function(x) { return curve.Y(x, true); },\n Ymi = function(x) { return -curve.Y(x, true); },\n h2 = h * 0.5;\n\n components = this.findComponents(curve, ta, tb, steps);\n for (idx = 0; idx < components.length; idx++) {\n comp = components[idx];\n ret = this.differenceMethod(comp, curve);\n groups = ret[0];\n x_table = ret[1];\n y_table = ret[2];\n degree_x = ret[3];\n degree_y = ret[4];\n\n // if (degree_x >= 0) {\n // console.log(\"x polynomial of degree\", degree_x);\n // }\n // if (degree_y >= 0) {\n // console.log(\"y polynomial of degree\", degree_y);\n // }\n if (groups.length === 0 || groups[0].type !== 'borderleft') {\n groups.unshift({\n idx: 0,\n t: comp.t_values[0],\n x: comp.x_values[0],\n y: comp.y_values[0],\n type: 'borderleft'\n });\n }\n if (groups[groups.length - 1].type !== 'borderright') {\n le = comp.t_values.length;\n groups.push({\n idx: le - 1,\n t: comp.t_values[le - 1],\n x: comp.x_values[le - 1],\n y: comp.y_values[le - 1],\n type: 'borderright'\n });\n }\n\n\n start = 0;\n for (g = 0; g <= groups.length; g++) {\n if (g === groups.length) {\n le = comp.len;\n } else {\n le = groups[g].idx - 1;\n }\n\n good = 0;\n bad = 0;\n // Insert all uncritical points until next critical point\n for (i = start; i < le - 2; i++) {\n this._insertPoint_v4(curve, [1, comp.x_values[i], comp.y_values[i]], comp.t_values[i]);\n j = Math.max(0, i - 2);\n // Add more points in critical intervals\n if (true &&\n //degree_y === -1 && // No polynomial\n i >= start + 3 &&\n i < le - 3 && // Do not do this if too close to a critical point\n y_table.length > 3 &&\n Math.abs(y_table[2][i]) > 0.2 * Math.abs(y_table[0][i])) {\n t = comp.t_values[i];\n h2 = h * 0.25;\n y_int = this.getInterval(curve, t, t + h);\n if (Type.isObject(y_int)) {\n if (y_table[2][i] > 0) {\n this._insertPoint_v4(curve, [1, t + h2, y_int.lo], t + h2);\n } else {\n this._insertPoint_v4(curve, [1, t + h - h2, y_int.hi], t + h - h2);\n }\n } else {\n t1 = Numerics.fminbr(Ypl, [t, t + h]);\n t2 = Numerics.fminbr(Ymi, [t, t + h]);\n if (t1 < t2) {\n this._insertPoint_v4(curve, [1, curve.X(t1, true), curve.Y(t1, true)], t1);\n this._insertPoint_v4(curve, [1, curve.X(t2, true), curve.Y(t2, true)], t2);\n } else {\n this._insertPoint_v4(curve, [1, curve.X(t2, true), curve.Y(t2, true)], t2);\n this._insertPoint_v4(curve, [1, curve.X(t1, true), curve.Y(t1, true)], t1);\n }\n }\n bad++;\n } else {\n good++;\n }\n }\n // console.log(\"GOOD\", good, \"BAD\", bad);\n\n // Handle next critical point\n if (g < groups.length) {\n //console.log(\"critical point / interval\", groups[g]);\n\n i = groups[g].idx;\n if (groups[g].type === 'borderleft' || groups[g].type === 'borderright') {\n this.handleBorder(curve, comp, groups[g], x_table, y_table);\n } else {\n this._seconditeration_v4(curve, comp, groups[g], x_table, y_table);\n }\n\n start = groups[g].idx + 1 + 1;\n }\n }\n\n le = comp.len;\n if (idx < components.length - 1) {\n this._insertPoint_v4(curve, [1, NaN, NaN], comp.right_t);\n }\n }\n\n\n },\n\n /**\n * Updates the data points of a parametric curve, plotVersion 4. This version is used if {@link JXG.Curve#plotVersion} is <tt>4</tt>.\n * @param {JXG.Curve} curve JSXGraph curve element\n * @param {Number} mi Left bound of curve\n * @param {Number} ma Right bound of curve\n * @returns {JXG.Curve} Reference to the curve object.\n */\n updateParametricCurve_v4: function (curve, mi, ma) {\n var ta, tb, w2, bbox;\n\n if (curve.xterm === 'x') {\n // For function graphs we can restrict the plot interval\n // to the visible area +plus margin\n bbox = curve.board.getBoundingBox();\n w2 = (bbox[2] - bbox[0]) * 0.3;\n // h2 = (bbox[1] - bbox[3]) * 0.3;\n ta = Math.max(mi, bbox[0] - w2);\n tb = Math.min(ma, bbox[2] + w2);\n } else {\n ta = mi;\n tb = ma;\n }\n\n curve.points = [];\n\n //console.log(\"--------------------\");\n this.plot_v4(curve, ta, tb, this.steps);\n\n curve.numberPoints = curve.points.length;\n //console.log(curve.numberPoints);\n },\n\n //----------------------------------------------------------------------\n // Plot algorithm alias\n //----------------------------------------------------------------------\n\n /**\n * Updates the data points of a parametric curve, alias for {@link JXG.Curve#updateParametricCurve_v2}.\n * This is needed for backwards compatibility, if this method has been\n * used directly in an application.\n * @param {JXG.Curve} curve JSXGraph curve element\n * @param {Number} mi Left bound of curve\n * @param {Number} ma Right bound of curve\n * @returns {JXG.Curve} Reference to the curve object.\n *\n * @see JXG.Curve#updateParametricCurve_v2\n */\n updateParametricCurve: function (curve, mi, ma) {\n return this.updateParametricCurve_v2(curve, mi, ma);\n }\n };\n\n\n return Mat.Plot;\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n\n\n Metapost/Hobby curves, see e.g. https://bosker.wordpress.com/2013/11/13/beyond-bezier-curves/\n\n * Ported to Python for the project PyX. Copyright (C) 2011 Michael Schindler <m-schindler@users.sourceforge.net>\n * Ported to javascript from the PyX implementation (http://pyx.sourceforge.net/) by Vlad-X.\n * Adapted to JSXGraph and some code changes by Alfred Wassermann 2020.\n\n This program is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU General Public License for more details.\n\n You should have received a copy of the GNU General Public License\n along with this program; if not, write to the Free Software\n Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n\n Internal functions of MetaPost\n This file re-implements some of the functionality of MetaPost\n (http://tug.org/metapost). MetaPost was developed by John D. Hobby and\n others. The code of Metapost is in the public domain, which we understand as\n an implicit permission to reuse the code here (see the comment at\n http://www.gnu.org/licenses/license-list.html)\n\n This file is based on the MetaPost version distributed by TeXLive:\n svn://tug.org/texlive/trunk/Build/source/texk/web2c/mplibdir revision 22737 #\n (2011-05-31)\n*/\n\n/*global JXG: true, define: true*/\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n utils/type\n math/math\n */\n\n/**\n * @fileoverview In this file the namespace Math.Metapost is defined which holds algorithms translated from Metapost\n * by D.E. Knuth and J.D. Hobby.\n */\n\ndefine('math/metapost',['utils/type', 'math/math'], function (Type, Mat) {\n\n \"use strict\";\n\n /**\n * The JXG.Math.Metapost namespace holds algorithms translated from Metapost\n * by D.E. Knuth and J.D. Hobby.\n *\n * @name JXG.Math.Metapost\n * @exports Mat.Metapost as JXG.Math.Metapost\n * @namespace\n */\n Mat.Metapost = {\n MP_ENDPOINT: 0,\n MP_EXPLICIT: 1,\n MP_GIVEN: 2,\n MP_CURL: 3,\n MP_OPEN: 4,\n MP_END_CYCLE: 5,\n\n UNITY: 1.0,\n // two: 2,\n // fraction_half: 0.5,\n FRACTION_ONE: 1.0,\n FRACTION_THREE: 3.0,\n ONE_EIGHTY_DEG: Math.PI,\n THREE_SIXTY_DEG: 2 * Math.PI,\n // EPSILON: 1e-5,\n EPS_SQ: 1e-5 * 1e-5,\n\n /**\n * @private\n */\n make_choices: function (knots) {\n var dely, h, k, delx, n,\n q, p, s, cosine, t, sine,\n delta_x, delta_y, delta, psi;\n\n p = knots[0];\n do {\n if (!p) {\n break;\n }\n q = p.next;\n\n // Join two identical knots by setting the control points to the same\n // coordinates.\n // MP 291\n if (p.rtype > this.MP_EXPLICIT &&\n ((p.x - q.x) * (p.x - q.x) + (p.y - q.y) * (p.y - q.y) < this.EPS_SQ)) {\n\n p.rtype = this.MP_EXPLICIT;\n if (p.ltype === this.MP_OPEN) {\n p.ltype = this.MP_CURL;\n p.set_left_curl(this.UNITY);\n }\n\n q.ltype = this.MP_EXPLICIT;\n if (q.rtype === this.MP_OPEN) {\n q.rtype = this.MP_CURL;\n q.set_right_curl(this.UNITY);\n }\n\n p.rx = p.x;\n q.lx = p.x;\n p.ry = p.y;\n q.ly = p.y;\n }\n p = q;\n } while (p !== knots[0]);\n\n // Find the first breakpoint, h, on the path\n // MP 292\n h = knots[0];\n while (true) {\n if (h.ltype !== this.MP_OPEN || h.rtype !== this.MP_OPEN) {\n break;\n }\n h = h.next;\n if (h === knots[0]) {\n h.ltype = this.MP_END_CYCLE;\n break;\n }\n }\n\n p = h;\n while (true) {\n if (!p) {\n break;\n }\n\n // Fill in the control points between p and the next breakpoint,\n // then advance p to that breakpoint\n // MP 299\n q = p.next;\n if (p.rtype >= this.MP_GIVEN) {\n while (q.ltype === this.MP_OPEN && q.rtype === this.MP_OPEN) {\n q = q.next;\n }\n\n // Calculate the turning angles psi_ k and the distances d_{k,k+1};\n // set n to the length of the path\n // MP 302\n k = 0;\n s = p;\n n = knots.length;\n\n delta_x = [];\n delta_y = [];\n delta = [];\n psi = [null];\n\n // tuple([]) = tuple([[], [], [], [null]]);\n while (true) {\n t = s.next;\n // None;\n delta_x.push(t.x - s.x);\n delta_y.push(t.y - s.y);\n delta.push( this.mp_pyth_add(delta_x[k], delta_y[k]) );\n if (k > 0) {\n sine = delta_y[k - 1] / delta[k - 1];\n cosine = delta_x[k - 1] / delta[k - 1];\n psi.push(\n Math.atan2(\n delta_y[k] * cosine - delta_x[k] * sine,\n delta_x[k] * cosine + delta_y[k] * sine\n )\n );\n }\n k++;\n s = t;\n if (s === q) {\n n = k;\n }\n if (k >= n && s.ltype !== this.MP_END_CYCLE) {\n break;\n }\n }\n if (k === n) {\n psi.push(0);\n } else {\n psi.push(psi[1]);\n }\n\n // Remove open types at the breakpoints\n // MP 303\n if (q.ltype === this.MP_OPEN) {\n delx = (q.rx - q.x);\n dely = (q.ry - q.y);\n if (delx * delx + dely * dely < this.EPS_SQ) {\n q.ltype = this.MP_CURL;\n q.set_left_curl(this.UNITY);\n } else {\n q.ltype = this.MP_GIVEN;\n q.set_left_given(Math.atan2(dely, delx));\n }\n }\n if (p.rtype === this.MP_OPEN && p.ltype === this.MP_EXPLICIT) {\n delx = (p.x - p.lx);\n dely = (p.y - p.ly);\n if ( delx * delx + dely * dely < this.EPS_SQ) {\n p.rtype = this.MP_CURL;\n p.set_right_curl(this.UNITY);\n } else {\n p.rtype = this.MP_GIVEN;\n p.set_right_given(Math.atan2(dely, delx));\n }\n }\n this.mp_solve_choices(p, q, n, delta_x, delta_y, delta, psi);\n } else if (p.rtype === this.MP_ENDPOINT) {\n // MP 294\n p.rx = p.x;\n p.ry = p.y;\n q.lx = q.x;\n q.ly = q.y;\n }\n p = q;\n\n if (p === h) {\n break;\n }\n }\n },\n\n /**\n * Implements solve_choices form metapost\n * MP 305\n * @private\n */\n mp_solve_choices: function (p, q, n, delta_x, delta_y, delta, psi) {\n var aa, acc, vv, bb, ldelta, ee, k, s,\n ww, uu, lt, r, t, ff, theta, rt, dd, cc,\n ct_st, ct, st, cf_sf, cf, sf, i,\n k_idx;\n\n ldelta = delta.length + 1;\n uu = new Array(ldelta);\n ww = new Array(ldelta);\n vv = new Array(ldelta);\n theta = new Array(ldelta);\n for (i = 0; i < ldelta; i++) {\n theta[i] = vv[i] = ww[i] = uu[i] = 0;\n }\n k = 0;\n s = p;\n r = 0;\n while (true) {\n t = s.next;\n if (k === 0) {\n // MP 306\n if (s.rtype === this.MP_GIVEN) {\n // MP 314\n if (t.ltype === this.MP_GIVEN) {\n aa = Math.atan2(delta_y[0], delta_x[0]);\n ct_st = this.mp_n_sin_cos(p.right_given() - aa);\n ct = ct_st[0];\n st = ct_st[1];\n cf_sf = this.mp_n_sin_cos(q.left_given() - aa);\n cf = cf_sf[0];\n sf = cf_sf[1];\n this.mp_set_controls(p, q, delta_x[0], delta_y[0], st, ct, -sf, cf);\n return;\n }\n vv[0] = s.right_given() - Math.atan2(delta_y[0], delta_x[0]);\n vv[0] = this.reduce_angle(vv[0]);\n uu[0] = 0;\n ww[0] = 0;\n\n } else if (s.rtype === this.MP_CURL) {\n // MP 315\n if (t.ltype === this.MP_CURL) {\n p.rtype = this.MP_EXPLICIT;\n q.ltype = this.MP_EXPLICIT;\n lt = Math.abs(q.left_tension());\n rt = Math.abs(p.right_tension());\n ff = this.UNITY / (3.0 * rt);\n p.rx = p.x + delta_x[0] * ff;\n p.ry = p.y + delta_y[0] * ff;\n ff = this.UNITY / (3.0 * lt);\n q.lx = q.x - delta_x[0] * ff;\n q.ly = q.y - delta_y[0] * ff;\n return;\n }\n cc = s.right_curl();\n lt = Math.abs(t.left_tension());\n rt = Math.abs(s.right_tension());\n uu[0] = this.mp_curl_ratio(cc, rt, lt);\n vv[0] = -psi[1] * uu[0];\n ww[0] = 0;\n } else {\n if (s.rtype === this.MP_OPEN) {\n uu[0] = 0;\n vv[0] = 0;\n ww[0] = this.FRACTION_ONE;\n }\n }\n } else {\n if (s.ltype === this.MP_END_CYCLE || s.ltype === this.MP_OPEN) {\n // MP 308\n aa = this.UNITY / (3.0 * Math.abs(r.right_tension()) - this.UNITY);\n dd = delta[k] * (this.FRACTION_THREE - this.UNITY / Math.abs(r.right_tension()));\n bb = this.UNITY / (3 * Math.abs(t.left_tension()) - this.UNITY);\n ee = delta[k - 1] * (this.FRACTION_THREE - this.UNITY / Math.abs(t.left_tension()));\n cc = this.FRACTION_ONE - uu[k - 1] * aa;\n dd = dd * cc;\n lt = Math.abs(s.left_tension());\n rt = Math.abs(s.right_tension());\n if (lt < rt) {\n dd *= Math.pow(lt / rt, 2);\n } else {\n if (lt > rt) {\n ee *= Math.pow(rt / lt, 2);\n }\n }\n ff = ee / (ee + dd);\n uu[k] = ff * bb;\n acc = -psi[k + 1] * uu[k];\n if (r.rtype === this.MP_CURL) {\n ww[k] = 0;\n vv[k] = acc - psi[1] * (this.FRACTION_ONE - ff);\n } else {\n ff = (this.FRACTION_ONE - ff) / cc;\n acc = acc - psi[k] * ff;\n ff = ff * aa;\n vv[k] = acc - vv[k - 1] * ff;\n ww[k] = -ww[k - 1] * ff;\n }\n if (s.ltype === this.MP_END_CYCLE) {\n aa = 0;\n bb = this.FRACTION_ONE;\n while (true) {\n k -= 1;\n if (k === 0) {\n k = n;\n }\n aa = vv[k] - aa * uu[k];\n bb = ww[k] - bb * uu[k];\n if (k === n) {\n break;\n }\n }\n aa = aa / (this.FRACTION_ONE - bb);\n theta[n] = aa;\n vv[0] = aa;\n // k_val = range(1, n);\n // for (k_idx in k_val) {\n // k = k_val[k_idx];\n for (k_idx = 1; k_idx < n; k_idx++) {\n vv[k_idx] = vv[k_idx] + aa * ww[k_idx];\n }\n break;\n }\n } else {\n if (s.ltype === this.MP_CURL) {\n cc = s.left_curl();\n lt = Math.abs(s.left_tension());\n rt = Math.abs(r.right_tension());\n ff = this.mp_curl_ratio(cc, lt, rt);\n theta[n] = -(vv[n - 1] * ff) / (this.FRACTION_ONE - ff * uu[n - 1]);\n break;\n }\n if (s.ltype === this.MP_GIVEN) {\n theta[n] = s.left_given() - Math.atan2(delta_y[n - 1], delta_x[n - 1]);\n theta[n] = this.reduce_angle(theta[n]);\n break;\n }\n }\n }\n r = s;\n s = t;\n k += 1;\n }\n\n // MP 318\n for (k = n-1; k > -1; k--) {\n theta[k] = vv[k] - theta[k + 1] * uu[k];\n }\n\n s = p;\n k = 0;\n while (true) {\n t = s.next;\n ct_st = this.mp_n_sin_cos(theta[k]);\n ct = ct_st[0];\n st = ct_st[1];\n cf_sf = this.mp_n_sin_cos((-(psi[k + 1]) - theta[k + 1]));\n cf = cf_sf[0];\n sf = cf_sf[1];\n this.mp_set_controls(s, t, delta_x[k], delta_y[k], st, ct, sf, cf);\n k++;\n s = t;\n if (k === n) {\n break;\n }\n }\n },\n\n /**\n * @private\n */\n mp_n_sin_cos: function (z) {\n return [Math.cos(z), Math.sin(z)];\n },\n\n /**\n * @private\n */\n mp_set_controls: function (p, q, delta_x, delta_y, st, ct, sf, cf) {\n var rt, ss, lt, sine, rr;\n lt = Math.abs(q.left_tension());\n rt = Math.abs(p.right_tension());\n rr = this.mp_velocity(st, ct, sf, cf, rt);\n ss = this.mp_velocity(sf, cf, st, ct, lt);\n\n // console.log('lt rt rr ss', lt, rt, rr, ss);\n if (p.right_tension() < 0 || q.left_tension() < 0) {\n if ((st >= 0 && sf >= 0) || (st <= 0 && sf <= 0)) {\n sine = Math.abs(st) * cf + Math.abs(sf) * ct;\n if (sine > 0) {\n sine *= 1.00024414062;\n if (p.right_tension() < 0) {\n if (this.mp_ab_vs_cd(Math.abs(sf), this.FRACTION_ONE, rr, sine) < 0) {\n rr = Math.abs(sf) / sine;\n }\n }\n if (q.left_tension() < 0) {\n if (this.mp_ab_vs_cd(Math.abs(st), this.FRACTION_ONE, ss, sine) < 0) {\n ss = Math.abs(st) / sine;\n }\n }\n }\n }\n }\n p.rx = p.x + (delta_x * ct - delta_y * st) * rr;\n p.ry = p.y + (delta_y * ct + delta_x * st) * rr;\n q.lx = q.x - (delta_x * cf + delta_y * sf) * ss;\n q.ly = q.y - (delta_y * cf - delta_x * sf) * ss;\n p.rtype = this.MP_EXPLICIT;\n q.ltype = this.MP_EXPLICIT;\n },\n\n /**\n * @private\n */\n mp_pyth_add: function (a, b) {\n return Math.sqrt((a * a + b * b));\n },\n\n /**\n *\n * @private\n */\n mp_curl_ratio: function (gamma, a_tension, b_tension) {\n var alpha = 1.0 / a_tension,\n beta = 1.0 / b_tension;\n\n return Math.min (4.0,\n ((3.0 - alpha) * alpha * alpha * gamma + beta * beta * beta) /\n (alpha * alpha * alpha * gamma + (3.0 - beta) * beta * beta)\n );\n },\n\n /**\n * @private\n */\n mp_ab_vs_cd: function (a, b, c, d) {\n if (a * b === c * d) {\n return 0;\n }\n if (a * b > c * d) {\n return 1;\n }\n return -1;\n },\n\n /**\n * @private\n */\n mp_velocity: function (st, ct, sf, cf, t) {\n return Math.min (4.0,\n (2.0 + Math.sqrt(2) * (st - sf / 16.0) * (sf - st / 16.0) * (ct - cf)) /\n (1.5 * t * ((2 + (Math.sqrt(5) - 1) * ct) + (3 - Math.sqrt(5)) * cf))\n );\n },\n\n /**\n * @private\n * @param {Number} A\n */\n reduce_angle: function (A) {\n if (Math.abs(A) > this.ONE_EIGHTY_DEG) {\n if (A > 0) {\n A -= this.THREE_SIXTY_DEG;\n } else {\n A += this.THREE_SIXTY_DEG;\n }\n }\n return A;\n },\n\n /**\n *\n * @private\n * @param {Array} p\n * @param {Number} tension\n * @param {Boolean} cycle\n */\n makeknots: function (p, tension, cycle) {\n var i, len,\n knots = [];\n\n tension = tension || 1;\n\n len = p.length;\n for (i = 0; i < len; i++) {\n knots.push({\n x: p[i][0],\n y: p[i][1],\n ltype: this.MP_OPEN,\n rtype: this.MP_OPEN,\n ly: tension,\n ry: tension,\n lx: tension,\n rx: tension,\n left_curl: function() { return this.lx || 0; },\n right_curl: function() { return this.rx || 0; },\n left_tension: function() {\n if (!this.ly) { this.ly = 1; }\n return this.ly;\n },\n right_tension: function() {\n if (!this.ry) { this.ry = 1; }\n return this.ry;\n },\n set_right_curl: function(x) { this.rx = x || 0; },\n set_left_curl: function(x) { this.lx = x || 0; }\n });\n }\n len = knots.length;\n for (i = 0; i < len; i++) {\n knots[i].next = knots[i+1] || knots[i];\n knots[i].set_right_given = knots[i].set_right_curl;\n knots[i].set_left_given = knots[i].set_left_curl;\n knots[i].right_given = knots[i].right_curl;\n knots[i].left_given = knots[i].left_curl;\n }\n knots[len - 1].next = knots[0];\n\n if (!cycle) {\n knots[len - 1].rtype = this.MP_ENDPOINT;\n\n knots[len - 1].ltype = this.MP_CURL;\n knots[0].rtype = this.MP_CURL;\n }\n\n return knots;\n },\n\n /**\n *\n * @param {Array} point_list\n * @param {Object} controls\n *\n * @returns {Array}\n */\n curve: function(point_list, controls) {\n var knots, len, i, val,\n x = [],\n y = [];\n\n controls = controls || {\n tension: 1,\n direction: {},\n curl: {},\n isClosed: false\n };\n\n knots = this.makeknots(point_list, Type.evaluate(controls.tension), controls.isClosed);\n\n len = knots.length;\n for (i in controls.direction) {\n if (controls.direction.hasOwnProperty(i)) {\n val = Type.evaluate(controls.direction[i]);\n if (Type.isArray(val)) {\n if (val[0] !== false) {\n knots[i].lx = val[0] * Math.PI / 180;\n knots[i].ltype = this.MP_GIVEN;\n }\n if (val[1] !== false) {\n knots[i].rx = val[1] * Math.PI / 180;\n knots[i].rtype = this.MP_GIVEN;\n }\n } else {\n knots[i].lx = val * Math.PI / 180;\n knots[i].rx = val * Math.PI / 180;\n knots[i].ltype = knots[i].rtype = this.MP_GIVEN;\n }\n }\n }\n for (i in controls.curl) {\n if (controls.curl.hasOwnProperty(i)) {\n val = Type.evaluate(controls.curl[i]);\n if (parseInt(i, 10) === 0) {\n knots[i].rtype = this.MP_CURL;\n knots[i].set_right_curl(val);\n } else if (parseInt(i, 10) === len - 1) {\n knots[i].ltype = this.MP_CURL;\n knots[i].set_left_curl(val);\n }\n }\n }\n\n this.make_choices(knots);\n\n for (i = 0; i < len - 1; i++) {\n x.push(knots[i].x);\n x.push(knots[i].rx);\n x.push(knots[i + 1].lx);\n y.push(knots[i].y);\n y.push(knots[i].ry);\n y.push(knots[i + 1].ly);\n }\n x.push(knots[len - 1].x);\n y.push(knots[len - 1].y);\n\n if (controls.isClosed) {\n x.push(knots[len - 1].rx);\n y.push(knots[len - 1].ry);\n x.push(knots[0].lx);\n y.push(knots[0].ly);\n x.push(knots[0].x);\n y.push(knots[0].y);\n }\n\n return [x, y];\n }\n\n };\n\n return Mat.Metapost;\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph and JSXCompressor.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n JSXCompressor is free software dual licensed under the GNU LGPL or Apache License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n OR\n * Apache License Version 2.0\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License, Apache\n License, and the MIT License along with JSXGraph. If not, see\n <http://www.gnu.org/licenses/>, <https://www.apache.org/licenses/LICENSE-2.0.html>,\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true*/\n/*jslint nomen: true, plusplus: true, bitwise: true*/\n\n/* depends:\n jxg\n */\n\n/**\n * @fileoverview Utilities for uncompressing and base64 decoding\n */\n\ndefine('utils/zip',['jxg'], function (JXG) {\n\n \"use strict\";\n\n // Zip routine constants\n\n var bitReverse = [\n 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,\n 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,\n 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,\n 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,\n 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,\n 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,\n 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,\n 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,\n 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,\n 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,\n 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,\n 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,\n 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,\n 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,\n 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,\n 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,\n 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,\n 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,\n 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,\n 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,\n 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,\n 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,\n 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,\n 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,\n 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,\n 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,\n 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,\n 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,\n 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,\n 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,\n 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,\n 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff\n ],\n cplens = [\n 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,\n 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0\n ],\n\n cplext = [\n 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,\n 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99\n ], /* 99==invalid */\n\n cpdist = [\n 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0007, 0x0009, 0x000d,\n 0x0011, 0x0019, 0x0021, 0x0031, 0x0041, 0x0061, 0x0081, 0x00c1,\n 0x0101, 0x0181, 0x0201, 0x0301, 0x0401, 0x0601, 0x0801, 0x0c01,\n 0x1001, 0x1801, 0x2001, 0x3001, 0x4001, 0x6001\n ],\n\n cpdext = [\n 0, 0, 0, 0, 1, 1, 2, 2,\n 3, 3, 4, 4, 5, 5, 6, 6,\n 7, 7, 8, 8, 9, 9, 10, 10,\n 11, 11, 12, 12, 13, 13\n ],\n\n border = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15],\n\n NAMEMAX = 256;\n\n\n // Util namespace\n JXG.Util = JXG.Util || {};\n\n /**\n * @class Unzip class\n * Class for gunzipping, unzipping and base64 decoding of files.\n * It is used for reading GEONExT, Geogebra and Intergeo files.\n *\n * Only Huffman codes are decoded in gunzip.\n * The code is based on the source code for gunzip.c by Pasi Ojala\n * @see http://www.cs.tut.fi/~albert/Dev/gunzip/gunzip.c\n * @see http://www.cs.tut.fi/~albert\n */\n JXG.Util.Unzip = function (barray) {\n var gpflags, crc, SIZE, fileout, flens, fmax,\n outputArr = [],\n output = '',\n debug = false,\n files = 0,\n unzipped = [],\n buf32k = new Array(32768),\n bIdx = 0,\n modeZIP = false,\n barraylen = barray.length,\n bytepos = 0,\n bitpos = 0,\n bb = 1,\n bits = 0,\n literalTree = new Array(288),\n distanceTree = new Array(32),\n treepos = 0,\n Places = null,\n Places2 = null,\n impDistanceTree = new Array(64),\n impLengthTree = new Array(64),\n len = 0,\n fpos = new Array(17),\n nameBuf = [];\n\n fpos[0] = 0;\n\n function readByte() {\n bits += 8;\n\n if (bytepos < barraylen) {\n return barray[bytepos++];\n }\n\n return -1;\n }\n\n function byteAlign() {\n bb = 1;\n }\n\n function readBit() {\n var carry;\n\n try { // Prevent problems on iOS7 with >>\n bits++;\n carry = (bb & 1);\n bb >>= 1;\n\n if (bb === 0) {\n bb = readByte();\n carry = (bb & 1);\n bb = (bb >> 1) | 0x80;\n }\n\n return carry;\n } catch (e) {\n throw e;\n }\n }\n\n function readBits(a) {\n var res = 0,\n i = a;\n\n // Prevent problems on iOS7 with >>\n try {\n while (i--) {\n res = (res << 1) | readBit();\n }\n\n if (a) {\n res = bitReverse[res] >> (8 - a);\n }\n } catch (e) {\n throw e;\n }\n\n return res;\n }\n\n function flushBuffer() {\n bIdx = 0;\n }\n\n function addBuffer(a) {\n SIZE++;\n buf32k[bIdx++] = a;\n outputArr.push(String.fromCharCode(a));\n\n if (bIdx === 0x8000) {\n bIdx = 0;\n }\n }\n\n function HufNode() {\n this.b0 = 0;\n this.b1 = 0;\n this.jump = null;\n this.jumppos = -1;\n }\n\n function isPat() {\n while (true) {\n if (fpos[len] >= fmax) {\n return -1;\n }\n\n if (flens[fpos[len]] === len) {\n return fpos[len]++;\n }\n\n fpos[len]++;\n }\n }\n\n function rec() {\n var curplace = Places[treepos],\n tmp;\n\n if (len === 17) {\n return -1;\n }\n treepos++;\n len++;\n\n tmp = isPat();\n\n if (tmp >= 0) {\n /* leaf cell for 0-bit */\n curplace.b0 = tmp;\n } else {\n /* Not a Leaf cell */\n curplace.b0 = 0x8000;\n\n if (rec()) {\n return -1;\n }\n }\n\n tmp = isPat();\n\n if (tmp >= 0) {\n /* leaf cell for 1-bit */\n curplace.b1 = tmp;\n /* Just for the display routine */\n curplace.jump = null;\n } else {\n /* Not a Leaf cell */\n curplace.b1 = 0x8000;\n curplace.jump = Places[treepos];\n curplace.jumppos = treepos;\n if (rec()) {\n return -1;\n }\n }\n len--;\n\n return 0;\n }\n\n function createTree(currentTree, numval, lengths, show) {\n var i;\n\n Places = currentTree;\n treepos = 0;\n flens = lengths;\n fmax = numval;\n\n for (i = 0; i < 17; i++) {\n fpos[i] = 0;\n }\n len = 0;\n\n if (rec()) {\n return -1;\n }\n\n return 0;\n }\n\n function decodeValue(currentTree) {\n var len, i, b,\n xtreepos = 0,\n X = currentTree[xtreepos];\n\n /* decode one symbol of the data */\n while (true) {\n b = readBit();\n\n if (b) {\n if (!(X.b1 & 0x8000)) {\n /* If leaf node, return data */\n return X.b1;\n }\n\n X = X.jump;\n len = currentTree.length;\n\n for (i = 0; i < len; i++) {\n if (currentTree[i] === X) {\n xtreepos = i;\n break;\n }\n }\n } else {\n if (!(X.b0 & 0x8000)) {\n /* If leaf node, return data */\n return X.b0;\n }\n xtreepos++;\n X = currentTree[xtreepos];\n }\n }\n }\n\n function deflateLoop() {\n var last, c, type, i, j, l, ll, ll2, len, blockLen, dist, cSum,\n n, literalCodes, distCodes, lenCodes, z;\n\n do {\n last = readBit();\n type = readBits(2);\n\n if (type === 0) {\n // Stored\n byteAlign();\n blockLen = readByte();\n blockLen |= (readByte() << 8);\n\n cSum = readByte();\n cSum |= (readByte() << 8);\n\n if (((blockLen ^ ~cSum) & 0xffff)) {\n JXG.debug('BlockLen checksum mismatch\\n');\n }\n\n while (blockLen--) {\n c = readByte();\n addBuffer(c);\n }\n } else if (type === 1) {\n /* Fixed Huffman tables -- fixed decode routine */\n while (true) {\n /*\n 256 0000000 0\n : : :\n 279 0010111 23\n 0 00110000 48\n : : :\n 143 10111111 191\n 280 11000000 192\n : : :\n 287 11000111 199\n 144 110010000 400\n : : :\n 255 111111111 511\n\n Note the bit order!\n */\n\n j = (bitReverse[readBits(7)] >> 1);\n\n if (j > 23) {\n j = (j << 1) | readBit(); /* 48..255 */\n\n if (j > 199) { /* 200..255 */\n j -= 128; /* 72..127 */\n j = (j << 1) | readBit(); /* 144..255 << */\n } else { /* 48..199 */\n j -= 48; /* 0..151 */\n if (j > 143) {\n j = j + 136; /* 280..287 << */\n /* 0..143 << */\n }\n }\n } else { /* 0..23 */\n j += 256; /* 256..279 << */\n }\n\n if (j < 256) {\n addBuffer(j);\n } else if (j === 256) {\n /* EOF */\n break;\n } else {\n j -= 256 + 1; /* bytes + EOF */\n len = readBits(cplext[j]) + cplens[j];\n j = bitReverse[readBits(5)] >> 3;\n\n if (cpdext[j] > 8) {\n dist = readBits(8);\n dist |= (readBits(cpdext[j] - 8) << 8);\n } else {\n dist = readBits(cpdext[j]);\n }\n\n dist += cpdist[j];\n\n for (j = 0; j < len; j++) {\n c = buf32k[(bIdx - dist) & 0x7fff];\n addBuffer(c);\n }\n }\n } // while\n } else if (type === 2) {\n // \"static\" just to preserve stack\n ll = new Array(288 + 32);\n\n // Dynamic Huffman tables\n literalCodes = 257 + readBits(5);\n distCodes = 1 + readBits(5);\n lenCodes = 4 + readBits(4);\n\n for (j = 0; j < 19; j++) {\n ll[j] = 0;\n }\n\n // Get the decode tree code lengths\n\n for (j = 0; j < lenCodes; j++) {\n ll[border[j]] = readBits(3);\n }\n len = distanceTree.length;\n\n for (i = 0; i < len; i++) {\n distanceTree[i] = new HufNode();\n }\n\n if (createTree(distanceTree, 19, ll, 0)) {\n flushBuffer();\n return 1;\n }\n\n //read in literal and distance code lengths\n n = literalCodes + distCodes;\n i = 0;\n z = -1;\n\n while (i < n) {\n z++;\n j = decodeValue(distanceTree);\n\n // length of code in bits (0..15)\n if (j < 16) {\n ll[i++] = j;\n // repeat last length 3 to 6 times\n } else if (j === 16) {\n j = 3 + readBits(2);\n\n if (i + j > n) {\n flushBuffer();\n return 1;\n }\n l = i ? ll[i - 1] : 0;\n\n while (j--) {\n ll[i++] = l;\n }\n } else {\n // 3 to 10 zero length codes\n if (j === 17) {\n j = 3 + readBits(3);\n // j == 18: 11 to 138 zero length codes\n } else {\n j = 11 + readBits(7);\n }\n\n if (i + j > n) {\n flushBuffer();\n return 1;\n }\n\n while (j--) {\n ll[i++] = 0;\n }\n }\n }\n\n // Can overwrite tree decode tree as it is not used anymore\n len = literalTree.length;\n for (i = 0; i < len; i++) {\n literalTree[i] = new HufNode();\n }\n\n if (createTree(literalTree, literalCodes, ll, 0)) {\n flushBuffer();\n return 1;\n }\n\n len = literalTree.length;\n\n for (i = 0; i < len; i++) {\n distanceTree[i] = new HufNode();\n }\n\n ll2 = [];\n\n for (i = literalCodes; i < ll.length; i++) {\n ll2[i - literalCodes] = ll[i];\n }\n\n if (createTree(distanceTree, distCodes, ll2, 0)) {\n flushBuffer();\n return 1;\n }\n\n while (true) {\n j = decodeValue(literalTree);\n\n // In C64: if carry set\n if (j >= 256) {\n j -= 256;\n if (j === 0) {\n // EOF\n break;\n }\n\n j -= 1;\n len = readBits(cplext[j]) + cplens[j];\n j = decodeValue(distanceTree);\n\n if (cpdext[j] > 8) {\n dist = readBits(8);\n dist |= (readBits(cpdext[j] - 8) << 8);\n } else {\n dist = readBits(cpdext[j]);\n }\n\n dist += cpdist[j];\n\n while (len--) {\n c = buf32k[(bIdx - dist) & 0x7fff];\n addBuffer(c);\n }\n } else {\n addBuffer(j);\n }\n }\n }\n } while (!last);\n\n flushBuffer();\n byteAlign();\n\n return 0;\n }\n\n\n /**\n * nextFile:\n * Extract the next file from the compressed archive.\n * Calls skipdir() to proceed recursively.\n *\n * @return {Boolean} false if the end of files' data section has baseElement\n * reached. Then, then all recursive functions are stopped immediately.\n *\n */\n function nextFile() {\n var i, c, extralen, filelen, size, compSize, crc, method,\n tmp = [];\n\n // Prevent problems on iOS7 with >>\n try {\n outputArr = [];\n modeZIP = false;\n tmp[0] = readByte();\n tmp[1] = readByte();\n\n //GZIP\n if (tmp[0] === 0x78 && tmp[1] === 0xda) {\n deflateLoop();\n unzipped[files] = [outputArr.join(''), 'geonext.gxt'];\n files++;\n }\n\n //GZIP\n if (tmp[0] === 0x1f && tmp[1] === 0x8b) {\n skipdir();\n unzipped[files] = [outputArr.join(''), 'file'];\n files++;\n }\n\n //ZIP\n if (tmp[0] === 0x50 && tmp[1] === 0x4b) {\n modeZIP = true;\n tmp[2] = readByte();\n tmp[3] = readByte();\n\n if (tmp[2] === 0x03 && tmp[3] === 0x04) {\n //MODE_ZIP\n tmp[0] = readByte();\n tmp[1] = readByte();\n\n gpflags = readByte();\n gpflags |= (readByte() << 8);\n\n method = readByte();\n method |= (readByte() << 8);\n\n readByte();\n readByte();\n readByte();\n readByte();\n\n crc = readByte();\n crc |= (readByte() << 8);\n crc |= (readByte() << 16);\n crc |= (readByte() << 24);\n\n compSize = readByte();\n compSize |= (readByte() << 8);\n compSize |= (readByte() << 16);\n compSize |= (readByte() << 24);\n\n size = readByte();\n size |= (readByte() << 8);\n size |= (readByte() << 16);\n size |= (readByte() << 24);\n\n filelen = readByte();\n filelen |= (readByte() << 8);\n\n extralen = readByte();\n extralen |= (readByte() << 8);\n\n i = 0;\n nameBuf = [];\n\n while (filelen--) {\n c = readByte();\n if (c === '/' | c === ':') {\n i = 0;\n } else if (i < NAMEMAX - 1) {\n nameBuf[i++] = String.fromCharCode(c);\n }\n }\n\n if (!fileout) {\n fileout = nameBuf;\n }\n\n i = 0;\n while (i < extralen) {\n c = readByte();\n i++;\n }\n\n SIZE = 0;\n if (method === 8) {\n deflateLoop();\n unzipped[files] = new Array(2);\n unzipped[files][0] = outputArr.join('');\n unzipped[files][1] = nameBuf.join('');\n files++;\n }\n\n if (skipdir()) {\n // We are beyond the files' data in the zip archive.\n // Let's get out immediately...\n return false;\n }\n }\n return true;\n }\n } catch (e) {\n throw e;\n }\n return false;\n }\n\n\n /**\n * Test if the end of the files' data part of the archive has baseElement\n * reached. If not, uncompressing is resumed.\n *\n * @return {Boolean} true if the end of the files' data sections have\n * been reached.\n *\n * @private\n */\n function skipdir() {\n var crc, compSize, size, os, i, c,\n tmp = [];\n\n if ((gpflags & 8)) {\n tmp[0] = readByte();\n tmp[1] = readByte();\n tmp[2] = readByte();\n tmp[3] = readByte();\n\n // signature for data descriptor record: 0x08074b50\n // 12 bytes:\n // crc 4 bytes\n // compressed size 4 bytes\n // uncompressed size 4 bytes\n if (tmp[0] === 0x50 &&\n tmp[1] === 0x4b &&\n tmp[2] === 0x07 &&\n tmp[3] === 0x08) {\n crc = readByte();\n crc |= (readByte() << 8);\n crc |= (readByte() << 16);\n crc |= (readByte() << 24);\n } else {\n crc = tmp[0] | (tmp[1] << 8) | (tmp[2] << 16) | (tmp[3] << 24);\n }\n\n compSize = readByte();\n compSize |= (readByte() << 8);\n compSize |= (readByte() << 16);\n compSize |= (readByte() << 24);\n\n size = readByte();\n size |= (readByte() << 8);\n size |= (readByte() << 16);\n size |= (readByte() << 24);\n }\n\n if (modeZIP) {\n if (nextFile()) {\n // A file has been decompressed, we have to proceed\n return false;\n }\n }\n\n tmp[0] = readByte();\n if (tmp[0] !== 8) {\n // It seems, we are beyond the files' data in the zip archive.\n // We'll skip the rest..\n return true;\n }\n\n // There is another file in the zip file. We proceed...\n gpflags = readByte();\n\n readByte();\n readByte();\n readByte();\n readByte();\n\n readByte();\n os = readByte();\n\n if ((gpflags & 4)) {\n tmp[0] = readByte();\n tmp[2] = readByte();\n len = tmp[0] + 256 * tmp[1];\n for (i = 0; i < len; i++) {\n readByte();\n }\n }\n\n if ((gpflags & 8)) {\n i = 0;\n nameBuf = [];\n\n c = readByte();\n while (c) {\n if (c === '7' || c === ':') {\n i = 0;\n }\n\n if (i < NAMEMAX - 1) {\n nameBuf[i++] = c;\n }\n\n c = readByte();\n }\n }\n\n if ((gpflags & 16)) {\n c = readByte();\n while (c) {\n c = readByte();\n }\n }\n\n if ((gpflags & 2)) {\n readByte();\n readByte();\n }\n\n deflateLoop();\n\n crc = readByte();\n crc |= (readByte() << 8);\n crc |= (readByte() << 16);\n crc |= (readByte() << 24);\n\n size = readByte();\n size |= (readByte() << 8);\n size |= (readByte() << 16);\n size |= (readByte() << 24);\n\n if (modeZIP) {\n if (nextFile()) {\n // A file has been decompressed, we have to proceed\n return false;\n }\n }\n\n // We are here in non-ZIP-files only,\n // In that case the eturn value doesn't matter\n return false;\n }\n\n JXG.Util.Unzip.prototype.unzipFile = function (name) {\n var i;\n\n this.unzip();\n\n for (i = 0; i < unzipped.length; i++) {\n if (unzipped[i][1] === name) {\n return unzipped[i][0];\n }\n }\n\n return '';\n };\n\n JXG.Util.Unzip.prototype.unzip = function () {\n nextFile();\n return unzipped;\n };\n };\n\n return JXG.Util;\n});\n\n/*global JXG: true, define: true, escape: true, unescape: true*/\n/*jslint nomen: true, plusplus: true, bitwise: true*/\n\n/* depends:\n jxg\n */\n\ndefine('utils/encoding',['jxg'], function (JXG) {\n\n \"use strict\";\n\n // constants\n var UTF8_ACCEPT = 0,\n UTF8_REJECT = 12,\n UTF8D = [\n // The first part of the table maps bytes to character classes that\n // to reduce the size of the transition table and create bitmasks.\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,\n 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,\n 8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,\n 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 11, 6, 6, 6, 5, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,\n\n // The second part is a transition table that maps a combination\n // of a state of the automaton and a character class to a state.\n 0, 12, 24, 36, 60, 96, 84, 12, 12, 12, 48, 72, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,\n 12, 0, 12, 12, 12, 12, 12, 0, 12, 0, 12, 12, 12, 24, 12, 12, 12, 12, 12, 24, 12, 24, 12, 12,\n 12, 12, 12, 12, 12, 12, 12, 24, 12, 12, 12, 12, 12, 24, 12, 12, 12, 12, 12, 12, 12, 24, 12, 12,\n 12, 12, 12, 12, 12, 12, 12, 36, 12, 36, 12, 12, 12, 36, 12, 12, 12, 12, 12, 36, 12, 36, 12, 12,\n 12, 36, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12\n ];\n\n // Util namespace\n JXG.Util = JXG.Util || {};\n\n /**\n * UTF8 encoding routines\n * @namespace\n */\n JXG.Util.UTF8 = {\n /**\n * Encode a string to utf-8.\n * @param {String} string\n * @returns {String} utf8 encoded string\n */\n encode : function (string) {\n var n, c,\n utftext = '',\n len = string.length;\n\n string = string.replace(/\\r\\n/g, '\\n');\n\n // See\n // http://ecmanaut.blogspot.ca/2006/07/encoding-decoding-utf8-in-javascript.html\n // http://monsur.hossa.in/2012/07/20/utf-8-in-javascript.html\n if (typeof unescape === 'function' && typeof encodeURIComponent === 'function') {\n return unescape(encodeURIComponent(string));\n }\n\n for (n = 0; n < len; n++) {\n c = string.charCodeAt(n);\n\n if (c < 128) {\n utftext += String.fromCharCode(c);\n } else if ((c > 127) && (c < 2048)) {\n utftext += String.fromCharCode((c >> 6) | 192);\n utftext += String.fromCharCode((c & 63) | 128);\n } else {\n utftext += String.fromCharCode((c >> 12) | 224);\n utftext += String.fromCharCode(((c >> 6) & 63) | 128);\n utftext += String.fromCharCode((c & 63) | 128);\n }\n\n }\n\n return utftext;\n },\n\n /**\n * Decode a string from utf-8.\n * @param {String} utftext to decode\n * @returns {String} utf8 decoded string\n */\n decode : function (utftext) {\n /*\n The following code is a translation from C99 to JavaScript.\n\n The original C99 code can be found at\n http://bjoern.hoehrmann.de/utf-8/decoder/dfa/\n\n Original copyright note:\n\n Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>\n\n License: MIT License (see LICENSE.MIT)\n */\n\n var i, charCode, type,\n j = 0,\n codepoint = 0,\n state = UTF8_ACCEPT,\n chars = [],\n len = utftext.length,\n results = [];\n\n for (i = 0; i < len; i++) {\n charCode = utftext.charCodeAt(i);\n type = UTF8D[charCode];\n\n if (state !== UTF8_ACCEPT) {\n codepoint = (charCode & 0x3f) | (codepoint << 6);\n } else {\n codepoint = (0xff >> type) & charCode;\n }\n\n state = UTF8D[256 + state + type];\n\n if (state === UTF8_ACCEPT) {\n if (codepoint > 0xffff) {\n chars.push(0xD7C0 + (codepoint >> 10), 0xDC00 + (codepoint & 0x3FF));\n } else {\n chars.push(codepoint);\n }\n\n j++;\n\n if (j % 10000 === 0) {\n results.push(String.fromCharCode.apply(null, chars));\n chars = [];\n }\n }\n }\n results.push(String.fromCharCode.apply(null, chars));\n return results.join(\"\");\n },\n\n /**\n * Extends the standard charCodeAt() method of the String class to find the ASCII char code of\n * a character at a given position in a UTF8 encoded string.\n * @param {String} str\n * @param {Number} i position of the character\n * @returns {Number}\n */\n asciiCharCodeAt: function (str, i) {\n var c = str.charCodeAt(i);\n\n if (c > 255) {\n switch (c) {\n case 8364:\n c = 128;\n break;\n case 8218:\n c = 130;\n break;\n case 402:\n c = 131;\n break;\n case 8222:\n c = 132;\n break;\n case 8230:\n c = 133;\n break;\n case 8224:\n c = 134;\n break;\n case 8225:\n c = 135;\n break;\n case 710:\n c = 136;\n break;\n case 8240:\n c = 137;\n break;\n case 352:\n c = 138;\n break;\n case 8249:\n c = 139;\n break;\n case 338:\n c = 140;\n break;\n case 381:\n c = 142;\n break;\n case 8216:\n c = 145;\n break;\n case 8217:\n c = 146;\n break;\n case 8220:\n c = 147;\n break;\n case 8221:\n c = 148;\n break;\n case 8226:\n c = 149;\n break;\n case 8211:\n c = 150;\n break;\n case 8212:\n c = 151;\n break;\n case 732:\n c = 152;\n break;\n case 8482:\n c = 153;\n break;\n case 353:\n c = 154;\n break;\n case 8250:\n c = 155;\n break;\n case 339:\n c = 156;\n break;\n case 382:\n c = 158;\n break;\n case 376:\n c = 159;\n break;\n default:\n break;\n }\n }\n return c;\n }\n };\n\n return JXG.Util.UTF8;\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true*/\n/*jslint nomen: true, plusplus: true, bitwise: true*/\n\n/* depends:\n jxg\n utils/encoding\n */\n\ndefine('utils/base64',['jxg', 'utils/encoding'], function (JXG, Encoding) {\n\n \"use strict\";\n\n var alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',\n pad = '=';\n\n // Util namespace\n JXG.Util = JXG.Util || {};\n\n // Local helper functions\n /**\n * Extracts one byte from a string and ensures the result is less than or equal to 255.\n * @param {String} s\n * @param {Number} i\n * @returns {Number} <= 255\n * @private\n */\n function _getByte(s, i) {\n return s.charCodeAt(i) & 0xff;\n }\n\n /**\n * Determines the index of a base64 character in the base64 alphabet.\n * @param {String} s\n * @param {Number} i\n * @returns {Number}\n * @throws {Error} If the character can not be found in the alphabet.\n * @private\n */\n function _getIndex(s, i) {\n return alphabet.indexOf(s.charAt(i));\n }\n\n /**\n * Base64 routines\n * @namespace\n */\n JXG.Util.Base64 = {\n /**\n * Encode the given string.\n * @param {String} input\n * @returns {string} base64 encoded version of the input string.\n */\n encode : function (input) {\n var i, bin, len, padLen, encInput,\n buffer = [];\n\n encInput = Encoding.encode(input);\n len = encInput.length;\n padLen = len % 3;\n\n for (i = 0; i < len - padLen; i += 3) {\n bin = (_getByte(encInput, i) << 16) | (_getByte(encInput, i + 1) << 8) | (_getByte(encInput, i + 2));\n buffer.push(\n alphabet.charAt(bin >> 18),\n alphabet.charAt((bin >> 12) & 63),\n alphabet.charAt((bin >> 6) & 63),\n alphabet.charAt(bin & 63)\n );\n }\n\n switch (padLen) {\n case 1:\n bin = _getByte(encInput, len - 1);\n buffer.push(alphabet.charAt(bin >> 2), alphabet.charAt((bin << 4) & 63), pad, pad);\n break;\n case 2:\n bin = (_getByte(encInput, len - 2) << 8) | _getByte(encInput, len - 1);\n buffer.push(\n alphabet.charAt(bin >> 10),\n alphabet.charAt((bin >> 4) & 63),\n alphabet.charAt((bin << 2) & 63),\n pad\n );\n break;\n }\n\n return buffer.join('');\n },\n\n /**\n * Decode from Base64\n * @param {String} input Base64 encoded data\n * @param {Boolean} utf8 In case this parameter is true {@link JXG.Util.UTF8.decode} will be applied to\n * the result of the base64 decoder.\n * @throws {Error} If the string has the wrong length.\n * @returns {String}\n */\n decode : function (input, utf8) {\n var encInput, i, len, padLen, bin, output,\n result = [],\n buffer = [];\n\n // deactivate regexp linting. Our regex is secure, because we replace everything with ''\n /*jslint regexp:true*/\n encInput = input.replace(/[^A-Za-z0-9+/=]/g, '');\n /*jslint regexp:false*/\n\n len = encInput.length;\n\n if (len % 4 !== 0) {\n throw new Error('JSXGraph/utils/base64: Can\\'t decode string (invalid input length).');\n }\n\n if (encInput.charAt(len - 1) === pad) {\n padLen = 1;\n\n if (encInput.charAt(len - 2) === pad) {\n padLen = 2;\n }\n\n // omit the last four bytes (taken care of after the for loop)\n len -= 4;\n }\n\n for (i = 0; i < len; i += 4) {\n bin = (_getIndex(encInput, i) << 18) | (_getIndex(encInput, i + 1) << 12) | (_getIndex(encInput, i + 2) << 6) | _getIndex(encInput, i + 3);\n buffer.push(bin >> 16, (bin >> 8) & 255, bin & 255);\n\n // flush the buffer, if it gets too big fromCharCode will crash\n if (i % 10000 === 0) {\n result.push(String.fromCharCode.apply(null, buffer));\n buffer = [];\n }\n }\n\n switch (padLen) {\n case 1:\n bin = (_getIndex(encInput, len) << 12) | (_getIndex(encInput, len + 1) << 6) | (_getIndex(encInput, len + 2));\n buffer.push(bin >> 10, (bin >> 2) & 255);\n break;\n\n case 2:\n bin = (_getIndex(encInput, i) << 6) | (_getIndex(encInput, i + 1));\n buffer.push(bin >> 4);\n break;\n }\n\n result.push(String.fromCharCode.apply(null, buffer));\n output = result.join('');\n\n if (utf8) {\n output = Encoding.decode(output);\n }\n\n return output;\n },\n\n /**\n * Decode the base64 input data as an array\n * @param {string} input\n * @returns {Array}\n */\n decodeAsArray: function (input) {\n var i,\n dec = this.decode(input),\n ar = [],\n len = dec.length;\n\n for (i = 0; i < len; i++) {\n ar[i] = dec.charCodeAt(i);\n }\n\n return ar;\n }\n };\n\n return JXG.Util.Base64;\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n \n You can redistribute it and/or modify it under the terms of the\n \n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n \n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n \n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true, escape:true, window:true, ActiveXObject:true, XMLHttpRequest:true*/\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n jxg\n utils/zip\n utils/base64\n utils/type\n */\n\n/**\n * @fileoverview The JXG.Server is a wrapper for a smoother integration of server side calculations. on the\n * server side a python plugin system is used.\n */\n\ndefine('server/server',[\n 'jxg', 'utils/zip', 'utils/base64', 'utils/type'\n], function (JXG, Zip, Base64, Type) {\n\n \"use strict\";\n\n /**\n * @namespace\n * JXG.Server namespace holding functions to load JXG server modules.\n */\n JXG.Server = {\n /**\n * This is where all of a module's handlers are accessed from. If you're loading a module named JXGModule which\n * provides a handler called ImaHandler, then this handler can be called by invoking JXG.Server.modules.JXGModule.ImaHandler().\n * @namespace\n */\n modules: {},\n\n /**\n * Stores all asynchronous calls to server which aren't finished yet.\n * @private\n */\n runningCalls: {},\n\n /**\n * Handles errors, just a default implementation, can be overwritten by you, if you want to handle errors by yourself.\n * @param {object} data An object holding a field of type string named message handling the error described in the message string.\n */\n handleError: function (data) {\n JXG.debug('error occured, server says: ' + data.message);\n },\n\n /**\n * The main method of JXG.Server. Actually makes the calls to the server and parses the feedback.\n * @param {String} action Can be 'load' or 'exec'.\n * @param {function} callback Function pointer or anonymous function which takes as it's only argument an\n * object containing the data from the server. The fields of this object depend on the reply of the server\n * module. See the correspondings server module readme.\n * @param {Object} data What is to be sent to the server.\n * @param {Boolean} sync If the call should be synchronous or not.\n */\n callServer: function (action, callback, data, sync) {\n var fileurl, passdata, AJAX,\n params, id, dataJSONStr,\n k;\n\n sync = sync || false;\n\n params = '';\n for (k in data) {\n if (data.hasOwnProperty(k)) {\n params += '&' + escape(k) + '=' + escape(data[k]);\n }\n }\n\n dataJSONStr = Type.toJSON(data);\n\n // generate id\n do {\n id = action + Math.floor(Math.random() * 4096);\n } while (Type.exists(this.runningCalls[id]));\n\n // store information about the calls\n this.runningCalls[id] = {action: action};\n if (Type.exists(data.module)) {\n this.runningCalls[id].module = data.module;\n }\n\n fileurl = JXG.serverBase + 'JXGServer.py';\n passdata = 'action=' + escape(action) + '&id=' + id + '&dataJSON=' + escape(Base64.encode(dataJSONStr));\n\n this.cbp = function (d) {\n /*jslint evil:true*/\n var str, data,\n tmp, inject, paramlist, id,\n i, j;\n\n str = (new Zip.Unzip(Base64.decodeAsArray(d))).unzip();\n if (Type.isArray(str) && str.length > 0) {\n str = str[0][0];\n }\n\n if (!Type.exists(str)) {\n return;\n }\n\n data = window.JSON && window.JSON.parse ? window.JSON.parse(str) : (new Function('return ' + str))();\n\n if (data.type === 'error') {\n this.handleError(data);\n } else if (data.type === 'response') {\n id = data.id;\n\n // inject fields\n for (i = 0; i < data.fields.length; i++) {\n tmp = data.fields[i];\n inject = tmp.namespace + (typeof ((new Function('return ' + tmp.namespace))()) === 'object' ? '.' : '.prototype.') + tmp.name + ' = ' + tmp.value;\n (new Function(inject))();\n }\n\n // inject handlers\n for (i = 0; i < data.handler.length; i++) {\n tmp = data.handler[i];\n paramlist = [];\n\n for (j = 0; j < tmp.parameters.length; j++) {\n paramlist[j] = '\"' + tmp.parameters[j] + '\": ' + tmp.parameters[j];\n }\n // insert subnamespace named after module.\n inject = 'if(typeof JXG.Server.modules.' + this.runningCalls[id].module + ' == \"undefined\")' + 'JXG.Server.modules.' + this.runningCalls[id].module + ' = {};';\n\n // insert callback method which fetches and uses the server's data for calculation in JavaScript\n inject += 'JXG.Server.modules.' + this.runningCalls[id].module + '.' + tmp.name + '_cb = ' + tmp.callback + ';';\n\n // insert handler as JXG.Server.modules.<module name>.<handler name>\n inject += 'JXG.Server.modules.' + this.runningCalls[id].module + '.' + tmp.name + ' = function (' + tmp.parameters.join(',') + ', __JXGSERVER_CB__, __JXGSERVER_SYNC) {' +\n 'if(typeof __JXGSERVER_CB__ == \"undefined\") __JXGSERVER_CB__ = JXG.Server.modules.' + this.runningCalls[id].module + '.' + tmp.name + '_cb;' +\n 'var __JXGSERVER_PAR__ = {' + paramlist.join(',') + ', \"module\": \"' + this.runningCalls[id].module + '\", \"handler\": \"' + tmp.name + '\" };' +\n 'JXG.Server.callServer(\"exec\", __JXGSERVER_CB__, __JXGSERVER_PAR__, __JXGSERVER_SYNC);' +\n '};';\n (new Function(inject))();\n }\n\n delete this.runningCalls[id];\n\n // handle data\n callback(data.data);\n }\n };\n\n // bind cbp callback method to JXG.Server to get access to JXG.Server fields from within cpb\n this.cb = JXG.bind(this.cbp, this);\n\n // We are using our own XMLHttpRequest object in here because of a/sync and POST\n if (window.XMLHttpRequest) {\n AJAX = new XMLHttpRequest();\n AJAX.overrideMimeType('text/plain; charset=iso-8859-1');\n } else {\n AJAX = new ActiveXObject(\"Microsoft.XMLHTTP\");\n }\n if (AJAX) {\n // POST is required if data sent to server is too long for a url.\n // some browsers/http servers don't accept long urls.\n AJAX.open(\"POST\", fileurl, !sync);\n AJAX.setRequestHeader(\"Content-type\", \"application/x-www-form-urlencoded\");\n\n if (!sync) {\n // Define function to fetch data received from server\n // that function returning a function is required to make this.cb known to the function.\n AJAX.onreadystatechange = (function (cb) {\n return function () {\n if (AJAX.readyState === 4 && AJAX.status === 200) {\n cb(AJAX.responseText);\n return true;\n }\n return false;\n };\n }(this.cb));\n }\n\n // send the data\n AJAX.send(passdata);\n if (sync) {\n this.cb(AJAX.responseText);\n return true;\n }\n }\n\n return false;\n },\n\n /**\n * Callback for the default action 'load'.\n */\n loadModule_cb: function (data) {\n var i;\n for (i = 0; i < data.length; i++) {\n JXG.debug(data[i].name + ': ' + data[i].value);\n }\n },\n\n /**\n * Loads a module from the server.\n * @param {string} module A string containing the module. Has to match the filename of the Python module on the server exactly including\n * lower and upper case letters without the file ending .py.\n */\n loadModule: function (module) {\n return JXG.Server.callServer('load', JXG.Server.loadModule_cb, {'module': module}, true);\n }\n };\n\n JXG.Server.load = JXG.Server.loadModule;\n\n return JXG.Server;\n});\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true*/\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n jxg\n base/constants\n base/coords\n math/math\n math/geometry\n server/server\n utils/type\n */\n\n/**\n * @fileoverview In this file the namespace Math.Symbolic is defined, which holds methods\n * and algorithms for symbolic computations.\n * @author graphjs\n */\n\ndefine('math/symbolic',[\n 'base/constants', 'base/coords', 'math/math', 'math/geometry', 'server/server', 'utils/type'\n], function (Const, Coords, Mat, Geometry, Server, Type) {\n\n \"use strict\";\n\n var undef;\n\n /**\n * The JXG.Math.Symbolic namespace holds algorithms for symbolic computations.\n * @name JXG.Math.Symbolic\n * @exports Mat.Symbolic as JXG.Math.Symbolic\n * @namespace\n */\n Mat.Symbolic = {\n /**\n * Generates symbolic coordinates for the part of a construction including all the elements from that\n * a specific element depends of. These coordinates will be stored in GeometryElement.symbolic.\n * @param {JXG.Board} board The board that's element get some symbolic coordinates.\n * @param {JXG.GeometryElement} element All ancestor of this element get symbolic coordinates.\n * @param {String} variable Name for the coordinates, e.g. x or u.\n * @param {String} append Method for how to append the number of the coordinates. Possible values are\n * 'underscore' (e.g. x_2), 'none' (e.g. x2), 'brace' (e.g. x[2]).\n * @returns {Number} Number of coordinates given.\n * @memberof JXG.Math.Symbolic\n */\n generateSymbolicCoordinatesPartial: function (board, element, variable, append) {\n var t_num, t, k,\n list = element.ancestors,\n count = 0,\n makeCoords = function (num) {\n var r;\n\n if (append === 'underscore') {\n r = variable + '_{' + num + '}';\n } else if (append === 'brace') {\n r = variable + '[' + num + ']';\n } else {\n r = variable + num;\n }\n\n return r;\n };\n\n board.listOfFreePoints = [];\n board.listOfDependantPoints = [];\n\n for (t in list) {\n if (list.hasOwnProperty(t)) {\n t_num = 0;\n\n if (Type.isPoint(list[t])) {\n for (k in list[t].ancestors) {\n if (list[t].ancestors.hasOwnProperty(k)) {\n t_num++;\n }\n }\n\n if (t_num === 0) {\n list[t].symbolic.x = list[t].coords.usrCoords[1];\n list[t].symbolic.y = list[t].coords.usrCoords[2];\n board.listOfFreePoints.push(list[t]);\n } else {\n count += 1;\n list[t].symbolic.x = makeCoords(count);\n count += 1;\n list[t].symbolic.y = makeCoords(count);\n board.listOfDependantPoints.push(list[t]);\n }\n\n }\n }\n }\n\n if (Type.isPoint(element)) {\n element.symbolic.x = 'x';\n element.symbolic.y = 'y';\n }\n\n return count;\n },\n\n /**\n * Clears all .symbolic.x and .symbolic.y members on every point of a given board.\n * @param {JXG.Board} board The board that's points get cleared their symbolic coordinates.\n * @memberof JXG.Math.Symbolic\n */\n clearSymbolicCoordinates: function (board) {\n var clear = function (list) {\n var t, l = (list && list.length) || 0;\n\n for (t = 0; t < l; t++) {\n if (Type.isPoint(list[t])) {\n list[t].symbolic.x = '';\n list[t].symbolic.y = '';\n }\n }\n };\n\n clear(board.listOfFreePoints);\n clear(board.listOfDependantPoints);\n\n delete (board.listOfFreePoints);\n delete (board.listOfDependantPoints);\n },\n\n /**\n * Generates polynomials for a part of the construction including all the points from that\n * a specific element depends of.\n * @param {JXG.Board} board The board that's points polynomials will be generated.\n * @param {JXG.GeometryElement} element All points in the set of ancestors of this element are used to generate the set of polynomials.\n * @param {Boolean} generateCoords\n * @returns {Array} An array of polynomials as strings.\n * @memberof JXG.Math.Symbolic\n */\n generatePolynomials: function (board, element, generateCoords) {\n var t, k, i,\n list = element.ancestors,\n number_of_ancestors,\n pgs = [],\n result = [];\n\n if (generateCoords) {\n this.generateSymbolicCoordinatesPartial(board, element, 'u', 'brace');\n }\n\n list[element.id] = element;\n\n for (t in list) {\n if (list.hasOwnProperty(t)) {\n number_of_ancestors = 0;\n pgs = [];\n\n if (Type.isPoint(list[t])) {\n for (k in list[t].ancestors) {\n if (list[t].ancestors.hasOwnProperty(k)) {\n number_of_ancestors++;\n }\n }\n if (number_of_ancestors > 0) {\n pgs = list[t].generatePolynomial();\n\n for (i = 0; i < pgs.length; i++) {\n result.push(pgs[i]);\n }\n }\n }\n }\n }\n\n if (generateCoords) {\n this.clearSymbolicCoordinates(board);\n }\n\n return result;\n },\n\n /**\n * Calculate geometric locus of a point given on a board. Invokes python script on server.\n * @param {JXG.Board} board The board on which the point lies.\n * @param {JXG.Point} point The point that will be traced.\n * @returns {Array} An array of points.\n * @memberof JXG.Math.Symbolic\n */\n geometricLocusByGroebnerBase: function (board, point) {\n var poly, polyStr, result,\n P1, P2, i,\n xs, xe, ys, ye,\n c, s, tx,\n bol = board.options.locus,\n oldRadius = {},\n numDependent = this.generateSymbolicCoordinatesPartial(board, point, 'u', 'brace'),\n xsye = new Coords(Const.COORDS_BY_USR, [0, 0], board),\n xeys = new Coords(Const.COORDS_BY_USR, [board.canvasWidth, board.canvasHeight], board),\n sf = 1, transx = 0, transy = 0, rot = 0;\n\n if (Server.modules.geoloci === undef) {\n Server.loadModule('geoloci');\n }\n\n if (Server.modules.geoloci === undef) {\n throw new Error(\"JSXGraph: Unable to load JXG.Server module 'geoloci.py'.\");\n }\n\n xs = xsye.usrCoords[1];\n xe = xeys.usrCoords[1];\n ys = xeys.usrCoords[2];\n ye = xsye.usrCoords[2];\n\n // Optimizations - but only if the user wants to\n // Step 1: Translate all related points, such that one point P1 (board.options.locus.toOrigin if set\n // or a random point otherwise) is moved to (0, 0)\n // Step 2: Rotate the construction around the new P1, such that another point P2 (board.options.locus.to10 if set\n // or a random point \\neq P1 otherwise) is moved onto the positive x-axis\n // Step 3: Dilate the construction, such that P2 is moved to (1, 0)\n // Step 4: Give the scale factor (sf), the rotation (rot) and the translation vector (transx, transy) to\n // the server, which retransforms the plot (if any).\n\n // Step 1\n if (bol.translateToOrigin && (board.listOfFreePoints.length > 0)) {\n if ((bol.toOrigin !== undef) && (bol.toOrigin !== null) && Type.isInArray(board.listOfFreePoints, bol.toOrigin.id)) {\n P1 = bol.toOrigin;\n } else {\n P1 = board.listOfFreePoints[0];\n }\n\n transx = P1.symbolic.x;\n transy = P1.symbolic.y;\n // translate the whole construction\n for (i = 0; i < board.listOfFreePoints.length; i++) {\n board.listOfFreePoints[i].symbolic.x -= transx;\n board.listOfFreePoints[i].symbolic.y -= transy;\n }\n\n xs -= transx;\n xe -= transx;\n ys -= transy;\n ye -= transy;\n\n // Step 2\n if (bol.translateTo10 && (board.listOfFreePoints.length > 1)) {\n if ((bol.to10 !== undef) && (bol.to10 !== null) && (bol.to10.id !== bol.toOrigin.id) && Type.isInArray(board.listOfFreePoints, bol.to10.id)) {\n P2 = bol.to10;\n } else {\n if (board.listOfFreePoints[0].id === P1.id) {\n P2 = board.listOfFreePoints[1];\n } else {\n P2 = board.listOfFreePoints[0];\n }\n }\n\n rot = Geometry.rad([1, 0], [0, 0], [P2.symbolic.x, P2.symbolic.y]);\n c = Math.cos(-rot);\n s = Math.sin(-rot);\n\n\n for (i = 0; i < board.listOfFreePoints.length; i++) {\n tx = board.listOfFreePoints[i].symbolic.x;\n board.listOfFreePoints[i].symbolic.x = c * board.listOfFreePoints[i].symbolic.x - s * board.listOfFreePoints[i].symbolic.y;\n board.listOfFreePoints[i].symbolic.y = s * tx + c * board.listOfFreePoints[i].symbolic.y;\n }\n\n // thanks to the rotation this is zero\n P2.symbolic.y = 0;\n\n tx = xs;\n xs = c * xs - s * ys;\n ys = s * tx + c * ys;\n tx = xe;\n xe = c * xe - s * ye;\n ye = s * tx + c * ye;\n\n // Step 3\n if (bol.stretch && (Math.abs(P2.symbolic.x) > Mat.eps)) {\n sf = P2.symbolic.x;\n\n for (i = 0; i < board.listOfFreePoints.length; i++) {\n board.listOfFreePoints[i].symbolic.x /= sf;\n board.listOfFreePoints[i].symbolic.y /= sf;\n }\n\n for (i = 0; i < board.objectsList.length; i++) {\n if ((board.objectsList[i].elementClass === Const.OBJECT_CLASS_CIRCLE) && (board.objectsList[i].method === 'pointRadius')) {\n oldRadius[i] = board.objectsList[i].radius;\n board.objectsList[i].radius /= sf;\n }\n }\n\n xs /= sf;\n xe /= sf;\n ys /= sf;\n ye /= sf;\n\n // this is now 1\n P2.symbolic.x = 1;\n }\n }\n\n // make the coordinates \"as rational as possible\"\n for (i = 0; i < board.listOfFreePoints.length; i++) {\n tx = board.listOfFreePoints[i].symbolic.x;\n\n if (Math.abs(tx) < Mat.eps) {\n board.listOfFreePoints[i].symbolic.x = 0;\n }\n\n if (Math.abs(tx - Math.round(tx)) < Mat.eps) {\n board.listOfFreePoints[i].symbolic.x = Math.round(tx);\n }\n\n tx = board.listOfFreePoints[i].symbolic.y;\n\n if (Math.abs(tx) < Mat.eps) {\n board.listOfFreePoints[i].symbolic.y = 0;\n }\n\n if (Math.abs(tx - Math.round(tx)) < Mat.eps) {\n board.listOfFreePoints[i].symbolic.y = Math.round(tx);\n }\n }\n }\n\n // end of optimizations\n\n poly = this.generatePolynomials(board, point);\n polyStr = poly.join(',');\n\n this.cbp = function (data) {\n result = data;\n };\n\n this.cb = Type.bind(this.cbp, this);\n\n Server.modules.geoloci.lociCoCoA(xs, xe, ys, ye, numDependent, polyStr, sf, rot, transx, transy, this.cb, true);\n\n this.clearSymbolicCoordinates(board);\n\n for (i in oldRadius) {\n if (oldRadius.hasOwnProperty(i)) {\n board.objects[i].radius = oldRadius[i];\n }\n }\n\n\n return result;\n }\n };\n\n return Mat.Symbolic;\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Alfred Wassermann\nconsole.log(\"P:\", P.coords.usrCoords, P.data.type)\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true*/\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n jxg\n base/constants\n base/coords\n math/math\n math/numerics\n math/geometry\n utils/type\n */\n\n/**\n * @fileoverview This file contains the Math.Clip namespace for clipping and computing boolean operations\n * on polygons and curves\n *\n * // TODO:\n * * Check if input polygons are closed. If not, handle this case.\n */\n\ndefine('math/clip',[\n 'jxg', 'base/constants', 'base/coords', 'math/math', 'math/geometry', 'utils/type'\n], function (JXG, Const, Coords, Mat, Geometry, Type) {\n\n \"use strict\";\n\n /**\n * Math.Clip namespace definition. This namespace contains algorithms for Boolean operations on paths, i.e.\n * intersection, union and difference of paths. Base is the Greiner-Hormann algorithm.\n * @name JXG.Math.Clip\n * @exports Mat.Clip as JXG.Math.Clip\n * @namespace\n */\n // Mat.Clip = function () {\n // };\n\n // JXG.extend(Mat.Clip.prototype, /** @lends JXG.Curve.prototype */ {\n\n Mat.Clip = {\n\n _isSeparator: function(node) {\n return isNaN(node.coords.usrCoords[1]) && isNaN(node.coords.usrCoords[2]);\n },\n\n /**\n * Add pointers to an array S such that it is a circular doubly-linked list.\n *\n * @private\n * @param {Array} S Array\n * @return {Array} return containing the starter indices of each component.\n */\n makeDoublyLinkedList: function(S) {\n var i,\n first = null,\n components = [],\n le = S.length;\n\n if (le > 0) {\n for (i = 0; i < le; i++) {\n // S[i]._next = S[(i + 1) % le];\n // S[i]._prev = S[(le + i - 1) % le];\n\n // If S[i] is component separator we proceed with the next node.\n if (this._isSeparator(S[i])) {\n S[i]._next = S[(i + 1) % le];\n S[i]._prev = S[(le + i - 1) % le];\n continue;\n }\n\n // Now we know that S[i] is a path component\n if (first === null) {\n // Start the component if it is not yet started.\n first = i;\n components.push(first);\n }\n if (this._isSeparator(S[(i + 1) % le]) || i === le - 1) {\n // If the next node is a component separator or if the node is the last node,\n // then we close the loop\n\n S[i]._next = S[first];\n S[first]._prev = S[i];\n S[i]._end = true;\n first = null;\n } else {\n // Here, we are not at the end of component\n S[i]._next = S[(i + 1) % le];\n S[first]._prev = S[i];\n }\n if (!this._isSeparator(S[(le + i - 1) % le])) {\n S[i]._prev = S[(le + i - 1) % le];\n }\n }\n }\n return components;\n },\n\n /**\n * Determinant of three points in the Euclidean plane.\n * Zero, if the points are collinear. Used to determine of a point q is left or\n * right to a segment defined by points p1 and p2.\n * @private\n * @param {Array} p1 Coordinates of the first point of the segment. Array of length 3. First coordinate is equal to 1.\n * @param {Array} p2 Coordinates of the second point of the segment. Array of length 3. First coordinate is equal to 1.\n * @param {Array} q Coordinates of the point. Array of length 3. First coordinate is equal to 1.\n * @return {Number} Signed area of the triangle formed by these three points.\n */\n det: function(p1, p2, q) {\n return (p1[1] - q[1]) * (p2[2] - q[2]) - (p2[1] - q[1]) * (p1[2] - q[2]);\n },\n\n /**\n * Winding number of a point in respect to a polygon path.\n *\n * The point is regarded outside if the winding number is zero,\n * inside otherwise. The algorithm tries to find degenerate cases, i.e.\n * if the point is on the path. This is regarded as \"outside\".\n * If the point is a vertex of the path, it is regarded as \"inside\".\n *\n * Implementation of algorithm 7 from \"The point in polygon problem for\n * arbitrary polygons\" by Kai Hormann and Alexander Agathos, Computational Geometry,\n * Volume 20, Issue 3, November 2001, Pages 131-144.\n *\n * @param {Array} usrCoords Homogenous coordinates of the point\n * @param {Array} path Array of points determining a path, i.e. the vertices of the polygon. The array elements\n * do not have to be full points, but have to have a subobject \"coords\".\n * @return {Number} Winding number of the point. The point is\n * regarded outside if the winding number is zero,\n * inside otherwise.\n */\n windingNumber: function(usrCoords, path) {\n var wn = 0,\n le = path.length,\n x = usrCoords[1],\n y = usrCoords[2],\n p1, p2, d, sign, i;\n\n if (le === 0) {\n return 0;\n }\n\n // Infinite points are declared outside\n if (isNaN(x) || isNaN(y)) {\n return 1;\n }\n\n // Handle the case if the point is a vertex of the path\n if (path[0].coords.usrCoords[1] === x &&\n path[0].coords.usrCoords[2] === y) {\n\n // console.log('<<<<<<< Vertex 1');\n return 1;\n }\n\n for (i = 0; i < le; i++) {\n // Consider the edge from p1 = path[i] to p2 = path[i+1]\n p1 = path[i].coords.usrCoords;\n p2 = path[(i + 1) % le].coords.usrCoords;\n if (p1[0] === 0 || p2[0] === 0 ||\n isNaN(p1[1]) || isNaN(p2[1]) ||\n isNaN(p1[2]) || isNaN(p2[2])) {\n\n continue;\n }\n\n if (p2[2] === y) {\n if (p2[1] === x) {\n // console.log('<<<<<<< Vertex 2');\n return 1;\n }\n if (p1[2] === y && ((p2[1] > x) === (p1[1] < x))) {\n // console.log('<<<<<<< Edge 1', p1, p2, [x, y]);\n return 0;\n }\n }\n\n if ((p1[2] < y) !== (p2[2] < y)) {\n sign = 2 * ((p2[2] > p1[2]) ? 1 : 0) - 1;\n if (p1[1] >= x) {\n if (p2[1] > x) {\n wn += sign;\n } else {\n d = this.det(p1, p2, usrCoords);\n if (d === 0) {\n // console.log('<<<<<<< Edge 2');\n return 0;\n }\n if ((d > 0) === (p2[2] > p1[2])) {\n wn += sign;\n }\n }\n } else {\n if (p2[1] > x) {\n d = this.det(p1, p2, usrCoords);\n if ((d > 0 + Mat.eps) === (p2[2] > p1[2])) {\n wn += sign;\n }\n }\n }\n }\n }\n\n return wn;\n },\n\n /**\n * JavaScript object containing the intersection of two paths. Every intersection point is on one path, but\n * comes with a neighbour point having the same coordinates and being on the other path.\n *\n * The intersection point is inserted into the doubly linked list of the path.\n *\n * @private\n * @param {JXG.Coords} coords JSXGraph Coords object conatining the coordinates of the intersection\n * @param {Number} i Number of the segment of the subject path (first path) containing the intersection.\n * @param {Number} alpha The intersection is a p_1 + alpha*(p_2 - p_1), where p_1 and p_2 are the end points\n * of the i-th segment.\n * @param {Array} path Pointer to the path containing the intersection point\n * @param {String} pathname Name of the path: 'S' or 'C'.\n */\n Vertex: function(coords, i, alpha, path, pathname, type) {\n this.pos = i;\n this.intersection = true;\n this.coords = coords;\n this.elementClass = Const.OBJECT_CLASS_POINT;\n\n this.data = {\n alpha: alpha,\n path: path,\n pathname: pathname,\n done: false,\n type: type,\n idx: 0\n };\n\n // Set after initialisation\n this.neighbour = null;\n this.entry_exit = false;\n },\n\n _addToList: function(list, coords, pos) {\n var len = list.length,\n eps = Mat.eps * Mat.eps;\n\n if (len > 0 &&\n Math.abs(list[len - 1].coords.usrCoords[0] - coords.usrCoords[0]) < eps &&\n Math.abs(list[len - 1].coords.usrCoords[1] - coords.usrCoords[1]) < eps &&\n Math.abs(list[len - 1].coords.usrCoords[2] - coords.usrCoords[2]) < eps) {\n // Skip point\n return;\n }\n list.push({\n pos: pos,\n intersection: false,\n coords: coords,\n elementClass: Const.OBJECT_CLASS_POINT\n });\n },\n\n /**\n * Sort the intersection points into their path.\n * @private\n * @param {Array} P_crossings Array of arrays. Each array contains the intersections of the path\n * with one segment of the other path.\n * @return {Array} Array of intersection points ordered by first occurrence in the path.\n */\n sortIntersections: function(P_crossings) {\n var i, j, P, Q,\n last,\n next_node,\n P_intersect = [],\n P_le = P_crossings.length;\n\n for (i = 0; i < P_le; i++) {\n P_crossings[i].sort(function(a, b) { return (a.data.alpha > b.data.alpha) ? 1 : -1; });\n\n if (P_crossings[i].length > 0) {\n // console.log(\"Crossings\", P_crossings[i])\n last = P_crossings[i].length - 1;\n P = P_crossings[i][0];\n\n //console.log(\"SORT\", P.coords.usrCoords)\n Q = P.data.path[P.pos];\n next_node = Q._next; // Store the next \"normal\" node\n\n if (i === P_le - 1) {\n Q._end = false;\n }\n\n if (P.data.alpha === 0.0 && P.data.type === 'T') {\n // console.log(\"SKIP\", P.coords.usrCoords, P.data.type, P.neighbour.data.type);\n Q.intersection = true;\n Q.data = P.data;\n Q.neighbour = P.neighbour;\n Q.neighbour.neighbour = Q;\n Q.entry_exit = false;\n P_crossings[i][0] = Q;\n } else {\n // Insert the first intersection point\n P._prev = Q;\n P._prev._next = P;\n }\n\n // Insert the other intersection points, but the last\n for (j = 1; j <= last; j++) {\n P = P_crossings[i][j];\n P._prev = P_crossings[i][j - 1];\n P._prev._next = P;\n }\n\n // Link last intersection point to the next node\n P = P_crossings[i][last];\n P._next = next_node;\n P._next._prev = P;\n\n if (i === P_le - 1) {\n P._end = true;\n //console.log(\"END\", P._end, P.coords.usrCoords, P._prev.coords.usrCoords, P._next.coords.usrCoords);\n }\n\n P_intersect = P_intersect.concat(P_crossings[i]);\n }\n }\n return P_intersect;\n },\n\n _inbetween: function(q, p1, p2) {\n var alpha,\n eps = Mat.eps * Mat.eps,\n px = p2[1] - p1[1],\n py = p2[2] - p1[2],\n qx = q[1] - p1[1],\n qy = q[2] - p1[2];\n\n if (px === 0 && py === 0 && qx === 0 && qy === 0) {\n // All three points are equal\n return true;\n }\n if (Math.abs(qx) < eps && Math.abs(px) < eps) {\n alpha = qy / py;\n } else {\n alpha = qx / px;\n }\n if (Math.abs(alpha) < eps) {\n alpha = 0.0;\n }\n return alpha;\n },\n\n _print_array: function(arr) {\n var i, end;\n for (i = 0; i < arr.length; i++) {\n //console.log(i, arr[i].coords.usrCoords, arr[i].data.type);\n try {\n end = \"\";\n if (arr[i]._end) {\n end = \" end\";\n }\n console.log(i, arr[i].coords.usrCoords, arr[i].data.type, \"\\t\",\n \"prev\", arr[i]._prev.coords.usrCoords,\n \"next\", arr[i]._next.coords.usrCoords + end);\n } catch (e) {\n console.log(i, arr[i].coords.usrCoords);\n }\n }\n },\n\n _print_list: function(P) {\n var cnt = 0, alpha;\n while (cnt < 100) {\n if (P.data) {\n alpha = P.data.alpha;\n } else {\n alpha = '-';\n }\n console.log(\"\\t\", P.coords.usrCoords, \"\\n\\t\\tis:\", P.intersection, \"end:\", P._end,\n alpha,\n \"\\n\\t\\t-:\", P._prev.coords.usrCoords,\n \"\\n\\t\\t+:\", P._next.coords.usrCoords,\n \"\\n\\t\\tn:\", (P.intersection) ? P.neighbour.coords.usrCoords : '-'\n );\n if (P._end) {\n break;\n }\n P = P._next;\n cnt++;\n }\n },\n\n _noOverlap: function(p1, p2, q1, q2) {\n var k,\n eps = Math.sqrt(Mat.eps),\n minp, maxp, minq, maxq,\n no_overlap = false;\n\n for (k = 0; k < 3; k++) {\n minp = Math.min(p1[k], p2[k]);\n maxp = Math.max(p1[k], p2[k]);\n minq = Math.min(q1[k], q2[k]);\n maxq = Math.max(q1[k], q2[k]);\n if (maxp < minq - eps || minp > maxq + eps) {\n no_overlap = true;\n break;\n }\n }\n return no_overlap;\n },\n\n /**\n * Find all intersections between two paths.\n * @private\n * @param {Array} S Subject path\n * @param {Array} C Clip path\n * @param {JXG.Board} board JSXGraph board object. It is needed to convert between\n * user coordinates and screen coordinates.\n * @return {Array} Array containing two arrays. The first array contains the intersection vertices\n * of the subject path and the second array contains the intersection vertices of the clip path.\n * @see JXG.Clip#Vertex\n */\n findIntersections: function(S, C, board) {\n var res = [],\n eps = Mat.eps,\n i, j,\n crds,\n S_le = S.length,\n C_le = C.length,\n Si, Si1, Cj, Cj1,\n d1, d2,\n alpha,\n type,\n IS, IC,\n S_intersect = [],\n C_intersect = [],\n S_crossings = [],\n C_crossings = [],\n hasMultCompsS = false,\n hasMultCompsC = false,\n DEBUG = false;\n\n for (j = 0; j < C_le; j++) {\n C_crossings.push([]);\n }\n\n // Run through the subject path.\n for (i = 0; i < S_le; i++) {\n S_crossings.push([]);\n\n // Test if S[i] or its successor is a path separator.\n // If yes, we know that the path consists of multiple components.\n // We immediately jump to the next segment.\n if (this._isSeparator(S[i]) || this._isSeparator(S[(i + 1) % S_le])) {\n hasMultCompsS = true;\n continue;\n }\n\n // If the path consists of multiple components then there is\n // no path-closing segment between the last node and the first\n // node. In this case we can leave the loop now.\n if (hasMultCompsS && i === S_le - 1) {\n break;\n }\n\n Si = S[i].coords.usrCoords;\n Si1 = S[(i + 1) % S_le].coords.usrCoords;\n // Run through the clip path.\n for (j = 0; j < C_le; j++) {\n // Test if C[j] or its successor is a path separator.\n // If yes, we know that the path consists of multiple components.\n // We immediately jump to the next segment.\n if (this._isSeparator(C[j]) || this._isSeparator(C[(j + 1) % C_le])) {\n hasMultCompsC = true;\n continue;\n }\n\n // If the path consists of multiple components then there is\n // no path-closing segment between the last node and the first\n // node. In this case we can leave the loop now.\n if (hasMultCompsC && j === C_le - 1) {\n break;\n }\n\n // Test if bounding boxes of the two curve segments overlap\n // If not, the expensive intersection test can be skipped.\n Cj = C[j].coords.usrCoords;\n Cj1 = C[(j + 1) % C_le].coords.usrCoords;\n\n if (this._noOverlap(Si, Si1, Cj, Cj1)) {\n continue;\n }\n\n // Intersection test\n res = Geometry.meetSegmentSegment(Si, Si1, Cj, Cj1);\n\n d1 = Geometry.distance(Si, Si1, 3);\n d2 = Geometry.distance(Cj, Cj1, 3);\n\n // Found an intersection point\n if ( // \"Regular\" intersection\n (res[1] * d1 > -eps && res[1] < 1 - eps / d1 && res[2] * d2 > -eps && res[2] < 1 - eps / d2) ||\n // Collinear segments\n (res[1] === Infinity && res[2] === Infinity && Mat.norm(res[0], 3) < eps)\n ) {\n\n crds = new Coords(Const.COORDS_BY_USER, res[0], board);\n type = 'X';\n\n // Handle degenerated cases\n if (Math.abs(res[1]) * d1 < eps || Math.abs(res[2]) * d2 < eps) {\n // Crossing / bouncing at vertex or\n // end of delayed crossing / bouncing\n type = 'T';\n if (Math.abs(res[1]) * d1 < eps) {\n res[1] = 0;\n }\n if (Math.abs(res[2]) * d2 < eps) {\n res[2] = 0;\n }\n if (res[1] === 0) {\n crds = new Coords(Const.COORDS_BY_USER, Si, board);\n } else {\n crds = new Coords(Const.COORDS_BY_USER, Cj, board);\n }\n\n if (DEBUG) {\n console.log(\"Degenerate case I\", res[1], res[2], crds.usrCoords, \"type\", type);\n }\n } else if (res[1] === Infinity &&\n res[2] === Infinity &&\n Mat.norm(res[0], 3) < eps) { // console.log(C_intersect);\n\n\n // Collinear segments\n // Here, there might be two intersection points to be added\n\n alpha = this._inbetween(Si, Cj, Cj1);\n if (DEBUG) {\n // console.log(\"alpha Si\", alpha, Si);\n // console.log(j, Cj)\n // console.log((j + 1) % C_le, Cj1)\n }\n if (alpha >= 0 && alpha < 1) {\n type = 'T';\n crds = new Coords(Const.COORDS_BY_USER, Si, board);\n res[1] = 0;\n res[2] = alpha;\n IS = new this.Vertex(crds, i, res[1], S, 'S', type);\n IC = new this.Vertex(crds, j, res[2], C, 'C', type);\n IS.neighbour = IC;\n IC.neighbour = IS;\n S_crossings[i].push(IS);\n C_crossings[j].push(IC);\n if (DEBUG) {\n console.log(\"Degenerate case II\", res[1], res[2], crds.usrCoords, \"type T\");\n }\n }\n alpha = this._inbetween(Cj, Si, Si1);\n if (DEBUG) {\n // console.log(\"alpha Cj\", alpha, Si, Geometry.distance(Si, Cj, 3));\n }\n if (Geometry.distance(Si, Cj, 3) > eps &&\n alpha >= 0 && alpha < 1) {\n\n type = 'T';\n crds = new Coords(Const.COORDS_BY_USER, Cj, board);\n res[1] = alpha;\n res[2] = 0;\n IS = new this.Vertex(crds, i, res[1], S, 'S', type);\n IC = new this.Vertex(crds, j, res[2], C, 'C', type);\n IS.neighbour = IC;\n IC.neighbour = IS;\n S_crossings[i].push(IS);\n C_crossings[j].push(IC);\n if (DEBUG) {\n console.log(\"Degenerate case III\", res[1], res[2], crds.usrCoords, \"type T\");\n }\n }\n continue;\n }\n if (DEBUG) {\n console.log(\"IS\", i, j, crds.usrCoords, type);\n }\n\n IS = new this.Vertex(crds, i, res[1], S, 'S', type);\n IC = new this.Vertex(crds, j, res[2], C, 'C', type);\n IS.neighbour = IC;\n IC.neighbour = IS;\n\n S_crossings[i].push(IS);\n C_crossings[j].push(IC);\n }\n }\n }\n\n // For both paths, sort their intersection points\n S_intersect = this.sortIntersections(S_crossings);\n\n if (DEBUG) {\n console.log('>>>>>> Intersections ');\n console.log(\"S_intersect\");\n this._print_array(S_intersect);\n console.log('----------');\n }\n for (i = 0; i < S_intersect.length; i++) {\n S_intersect[i].data.idx = i;\n S_intersect[i].neighbour.data.idx = i;\n }\n C_intersect = this.sortIntersections(C_crossings);\n\n if (DEBUG) {\n console.log(\"C_intersect\");\n this._print_array(C_intersect);\n console.log('<<<<<< Phase 1 done');\n }\n return [S_intersect, C_intersect];\n },\n\n /**\n * It is testedd if the point q lies to the left or right\n * of the poylgonal chain [p1, p2, p3].\n * @param {Array} q User coords array\n * @param {Array} p1 User coords array\n * @param {Array} p2 User coords array\n * @param {Array} p3 User coords array\n * @returns string 'left' or 'right'\n * @private\n */\n _getPosition: function(q, p1, p2, p3) {\n var s1 = this.det(q, p1, p2),\n s2 = this.det(q, p2, p3),\n s3 = this.det(p1, p2, p3);\n\n // Left turn\n if (s3 >= 0) {\n if (s1 >= 0 && s2 >= 0) {\n return 'left';\n }\n return 'right';\n }\n // Right turn\n if (s1 >= 0 || s2 >= 0) {\n return 'left';\n }\n return 'right';\n },\n\n /**\n * Determine the delayed status of degenerated intersection points.\n * It is of the form\n * ['on|left|right', 'on|left|right']\n * <p>\n * If all four determinants are zero, we add random noise to the point.\n *\n * @param {JXG.Math.Clip.Vertex} P Start of path\n * @private\n * @see JXG.Math.Clip#markEntryExit\n * @see JXG.Math.Clip#_handleIntersectionChains\n */\n _classifyDegenerateIntersections: function(P) {\n var Pp, Pm, Qp, Qm, Q, side,\n cnt, tmp,\n oppositeDir,\n s1, s2, s3, s4,\n DEBUG = false;\n\n if (DEBUG) {\n console.log(\"\\n-------------- _classifyDegenerateIntersections()\", (Type.exists(P.data))?P.data.pathname:' ');\n }\n cnt = 0;\n P._tours = 0;\n while (true) {\n if (DEBUG) {\n console.log(\"Inspect P:\", P.coords.usrCoords, (P.data) ? P.data.type : \" \");\n }\n if (P.intersection && (P.data.type === 'T')) {\n\n // Handle the degenerate cases\n // Decide if they are (delayed) bouncing or crossing intersections\n Pp = P._next.coords.usrCoords; // P+\n Pm = P._prev.coords.usrCoords; // P-\n\n // If the intersection point is degenerated and\n // equal to the start and end of one component,\n // then there will be two adjacent points with\n // the same coordinate.\n // In that case, we proceed to the next node.\n if (Geometry.distance(P.coords.usrCoords, Pp, 3) < Mat.eps) {\n Pp = P._next._next.coords.usrCoords;\n }\n if (Geometry.distance(P.coords.usrCoords, Pm, 3) < Mat.eps) {\n Pm = P._prev._prev.coords.usrCoords;\n }\n\n Q = P.neighbour;\n Qm = Q._prev.coords.usrCoords; // Q-\n Qp = Q._next.coords.usrCoords; // Q+\n if (Geometry.distance(Q.coords.usrCoords, Qp, 3) < Mat.eps) {\n Qp = Q._next._next.coords.usrCoords;\n }\n if (Geometry.distance(Q.coords.usrCoords, Qm, 3) < Mat.eps) {\n Qm = Q._prev._prev.coords.usrCoords;\n }\n\n if (DEBUG) {\n console.log(\"P chain:\", Pm, P.coords.usrCoords, Pp);\n console.log(\"Q chain:\", Qm, P.neighbour.coords.usrCoords, Qp);\n console.log(\"Pm\", this._getPosition(Pm, Qm, Q.coords.usrCoords, Qp));\n console.log(\"Pp\", this._getPosition(Pp, Qm, Q.coords.usrCoords, Qp));\n }\n\n s1 = this.det(P.coords.usrCoords, Pm, Qm);\n s2 = this.det(P.coords.usrCoords, Pp, Qp);\n s3 = this.det(P.coords.usrCoords, Pm, Qp);\n s4 = this.det(P.coords.usrCoords, Pp, Qm);\n\n if (s1 === 0 && s2 === 0 && s3 === 0 && s4 === 0) {\n P.coords.usrCoords[1] *= 1 + Math.random() * Mat.eps;\n P.coords.usrCoords[2] *= 1 + Math.random() * Mat.eps;\n Q.coords.usrCoords[1] = P.coords.usrCoords[1];\n Q.coords.usrCoords[2] = P.coords.usrCoords[2];\n s1 = this.det(P.coords.usrCoords, Pm, Qm);\n s2 = this.det(P.coords.usrCoords, Pp, Qp);\n s3 = this.det(P.coords.usrCoords, Pm, Qp);\n s4 = this.det(P.coords.usrCoords, Pp, Qm);\n if (DEBUG) {\n console.log(\"Random shift\", P.coords.usrCoords);\n console.log(s1, s2, s3, s4, s2 === 0);\n console.log(this._getPosition(Pm, Qm, Q.coords.usrCoords, Qp),\n this._getPosition(Pp, Qm, Q.coords.usrCoords, Qp));\n }\n }\n oppositeDir = false;\n if (s1 === 0) {\n // Q-, Q=P, P- on straight line\n if (Geometry.affineRatio(P.coords.usrCoords, Pm, Qm) < 0) {\n oppositeDir = true;\n }\n } else if (s2 === 0) {\n if (Geometry.affineRatio(P.coords.usrCoords, Pp, Qp) < 0) {\n oppositeDir = true;\n }\n } else if (s3 === 0) {\n if (Geometry.affineRatio(P.coords.usrCoords, Pm, Qp) > 0) {\n oppositeDir = true;\n }\n } else if (s4 === 0) {\n if (Geometry.affineRatio(P.coords.usrCoords, Pp, Qm) > 0) {\n oppositeDir = true;\n }\n }\n if (oppositeDir) {\n // Swap Qm and Qp\n // Then Qm Q Qp has the same direction as Pm P Pp\n tmp = Qm; Qm = Qp; Qp = tmp;\n tmp = s1; s1 = s3; s3 = tmp;\n tmp = s2; s2 = s4; s4 = tmp;\n }\n\n if (DEBUG) {\n console.log(s1, s2, s3, s4, oppositeDir);\n }\n\n if (!Type.exists(P.delayedStatus)) {\n P.delayedStatus = [];\n }\n\n if (s1 === 0 && s2 === 0) {\n // Line [P-,P] equals [Q-,Q] and line [P,P+] equals [Q,Q+]\n // Interior of delayed crossing / bouncing\n P.delayedStatus = ['on', 'on'];\n\n } else if (s1 === 0) {\n // P- on line [Q-,Q], P+ not on line [Q,Q+]\n // Begin / end of delayed crossing / bouncing\n side = this._getPosition(Pp, Qm, Q.coords.usrCoords, Qp);\n P.delayedStatus = ['on', side];\n\n } else if (s2 === 0) {\n // P+ on line [Q,Q+], P- not on line [Q-,Q]\n // Begin / end of delayed crossing / bouncing\n side = this._getPosition(Pm, Qm, Q.coords.usrCoords, Qp);\n P.delayedStatus = [side, 'on'];\n\n } else {\n // Neither P+ on line [Q,Q+], nor P- on line [Q-,Q]\n // No delayed crossing / bouncing\n if (P.delayedStatus.length === 0) {\n if (this._getPosition(Pm, Qm, Q.coords.usrCoords, Qp) !== this._getPosition(Pp, Qm, Q.coords.usrCoords, Qp)) {\n P.data.type = 'X';\n } else {\n P.data.type = 'B';\n }\n }\n }\n\n if (DEBUG) {\n console.log(\">>>> P:\", P.coords.usrCoords, \"delayedStatus:\", P.delayedStatus.toString(), (P.data) ? P.data.type : \" \", \"\\n---\");\n }\n\n }\n\n if (Type.exists(P._tours)) {\n P._tours++;\n }\n\n if (P._tours > 3 || P._end || cnt > 1000) {\n // Jump out if either\n // - we reached the end\n // - there are more than 1000 intersection points\n // - P._tours > 3: We went already 4 times through this path.\n if (cnt > 1000) {\n console.log(\"Clipping: _classifyDegenerateIntersections exit\");\n }\n if (Type.exists(P._tours)) {\n delete P._tours;\n }\n break;\n }\n if (P.intersection) {\n cnt++;\n }\n P = P._next;\n }\n if (DEBUG) {\n console.log(\"------------------------\");\n }\n },\n\n /**\n * At this point the degenerated intersections have been classified.\n * Now we decide if the intersection chains of the given path\n * ultimatively cross the other path or bounce.\n *\n * @param {JXG.Math.Clip.Vertex} P Start of path\n *\n * @see JXG.Math.Clip#markEntryExit\n * @see JXG.Math.Clip#_classifyDegenerateIntersections\n * @private\n */\n _handleIntersectionChains: function(P) {\n var cnt = 0,\n start_status = 'Null',\n P_start,\n intersection_chain = false,\n wait_for_exit = false,\n DEBUG = false;\n\n if (DEBUG) {\n console.log(\"\\n-------------- _handleIntersectionChains()\",\n (Type.exists(P.data))?P.data.pathname:' ');\n }\n while (true) {\n if (P.intersection === true) {\n if (DEBUG) {\n if (P.data.type === 'T') {\n console.log(\"Degenerate point\", P.coords.usrCoords, P.data.type, (P.data.type === 'T')?P.delayedStatus:' ');\n } else {\n console.log(\"Intersection point\", P.coords.usrCoords, P.data.type);\n }\n }\n if (P.data.type === 'T') {\n if (P.delayedStatus[0] !== 'on' && P.delayedStatus[1] === 'on') {\n // First point of intersection chain\n intersection_chain = true;\n P_start = P;\n start_status = P.delayedStatus[0];\n\n } else if (intersection_chain &&\n P.delayedStatus[0] === 'on' && P.delayedStatus[1] === 'on') {\n // Interior of intersection chain\n P.data.type = 'B';\n if (DEBUG) {\n console.log(\"Interior\", P.coords.usrCoords);\n }\n } else if (intersection_chain &&\n P.delayedStatus[0] === 'on' && P.delayedStatus[1] !== 'on') {\n // Last point of intersection chain\n intersection_chain = false;\n if (start_status === P.delayedStatus[1]) {\n // Intersection chain is delayed bouncing\n P_start.data.type = 'DB';\n P.data.type = 'DB';\n if (DEBUG) {\n console.log(\"Chain: delayed bouncing\", P_start.coords.usrCoords, '...', P.coords.usrCoords);\n }\n } else {\n // Intersection chain is delayed crossing\n P_start.data.type = 'DX';\n P.data.type = 'DX';\n if (DEBUG) {\n console.log(\"Chain: delayed crossing\", P_start.coords.usrCoords, '...', P.coords.usrCoords);\n }\n }\n }\n }\n cnt++;\n }\n if (P._end) {\n wait_for_exit = true;\n }\n if (wait_for_exit && !intersection_chain) {\n break;\n }\n if (cnt > 1000) {\n console.log(\"Warning: _handleIntersectionChains: intersection chain reached maximum numbers of iterations\");\n break;\n }\n P = P._next;\n }\n },\n\n /**\n * Handle the case that all vertices of one path are contained\n * in the other path. In this case we search for a midpoint of an edge\n * which is not contained in the other path and add it to the path.\n * It will be used as starting point for the entry/exit algorithm.\n *\n * @private\n * @param {Array} S Subject path\n * @param {Array} C Clip path\n * @param {JXG.board} board JSXGraph board object. It is needed to convert between\n * user coordinates and screen coordinates.\n */\n _handleFullyDegenerateCase: function(S, C, board) {\n var P, Q, l, M, crds, q1, q2, node,\n i, j, le, le2, is_on_Q,\n is_fully_degenerated,\n arr = [S, C];\n\n for (l = 0; l < 2; l++) {\n P = arr[l];\n le = P.length;\n for (i = 0, is_fully_degenerated = true; i < le; i++) {\n if (!P[i].intersection) {\n is_fully_degenerated = false;\n break;\n }\n }\n\n if (is_fully_degenerated) {\n // All nodes of P are also on the other path.\n Q = arr[(l + 1) % 2];\n le2 = Q.length;\n\n // We search for a midpoint of one edge of P which is not the other path and\n // we add that midpoint to P.\n for (i = 0; i < le; i++) {\n q1 = P[i].coords.usrCoords;\n q2 = P[(i + 1) % le].coords.usrCoords;\n // M id the midpoint\n M = [(q1[0] + q2[0]) * 0.5,\n (q1[1] + q2[1]) * 0.5,\n (q1[2] + q2[2]) * 0.5];\n\n // Test if M is on path Q. If this is not the case,\n // we take M as additional point of P.\n for (j = 0, is_on_Q = false; j < le2; j++) {\n if (Math.abs(this.det(Q[j].coords.usrCoords, Q[(j + 1) % le2].coords.usrCoords, M)) < Mat.eps) {\n is_on_Q = true;\n break;\n }\n }\n if (!is_on_Q) {\n // The midpoint is added to the doubly-linked list.\n crds = new Coords(Const.COORDS_BY_USER, M, board);\n node = {\n pos: i,\n intersection: false,\n coords: crds,\n elementClass: Const.OBJECT_CLASS_POINT\n };\n P[i]._next = node;\n node._prev = P[i];\n P[(i + 1) % le]._prev = node;\n node._next = P[(i + 1) % le];\n if (P[i]._end) {\n P[i]._end = false;\n node._end = true;\n }\n\n break;\n }\n }\n }\n }\n },\n\n _getStatus: function(P, path) {\n var status;\n while (P.intersection) {\n if (P._end) {\n break;\n }\n P = P._next;\n }\n if (this.windingNumber(P.coords.usrCoords, path) % 2 === 0) {\n // Outside\n status = 'entry';\n } else {\n // Inside\n status = 'exit';\n }\n\n return [P, status];\n },\n\n /**\n * Mark the intersection vertices of path1 as entry points or as exit points\n * in respect to path2.\n * <p>\n * This is the simple algorithm as in\n * Greiner, Günther; Kai Hormann (1998). \"Efficient clipping of arbitrary polygons\".\n * ACM Transactions on Graphics. 17 (2): 71–83\n * <p>\n * The algorithm handles also \"delayed crossings\" from\n * Erich, L. Foster, and Kai Hormann, Kai, and Romeo Traaian Popa (2019),\n * \"Clipping simple polygons with degenerate intersections\", Computers & Graphics:X, 2.\n * and - as an additional improvement -\n * handles self intersections of delayed crossings (A.W. 2021).\n *\n * @private\n * @param {Array} path1 First path\n * @param {Array} path2 Second path\n */\n markEntryExit: function(path1, path2, starters) {\n var status, P, cnt, res,\n i, len, start,\n chain_start = null,\n intersection_chain = 0,\n DEBUG = false;\n\n len = starters.length;\n for (i = 0; i < len; i++) {\n start = starters[i];\n if (DEBUG) {\n console.log(\"\\n;;;;;;;;;; Labelling phase\",\n (Type.exists(path1[start].data))?path1[start].data.pathname:' ',\n path1[start].coords.usrCoords);\n }\n this._classifyDegenerateIntersections(path1[start]);\n this._handleIntersectionChains(path1[start]);\n if (DEBUG) {\n console.log(\"\\n---- back to markEntryExit\");\n }\n\n // Decide if the first point of the component is inside or outside\n // of the other path.\n res = this._getStatus(path1[start], path2);\n P = res[0];\n status = res[1];\n if (DEBUG) {\n console.log(\"Start node:\", P.coords.usrCoords, status);\n }\n\n P._starter = true;\n\n // Greiner-Hormann entry/exit algorithm\n // with additional handling of delayed crossing / bouncing\n cnt = 0;\n chain_start = null;\n intersection_chain = 0;\n\n while (true) {\n if (P.intersection === true) {\n if (P.data.type === 'X' && intersection_chain === 1) {\n // While we are in an intersection chain, i.e. a delayed crossing,\n // we stumble on a crossing intersection.\n // Probably, the other path is self intersecting.\n // We end the intersection chain here and\n // mark this event by setting intersection_chain = 2.\n chain_start.entry_exit = status;\n if (status === 'exit') {\n chain_start.data.type = 'X';\n }\n intersection_chain = 2;\n }\n\n if (P.data.type === 'X' || P.data.type === 'DB') {\n P.entry_exit = status;\n status = (status === 'entry') ? 'exit' : 'entry';\n if (DEBUG) {\n console.log(\"mark:\", P.coords.usrCoords, P.data.type, P.entry_exit);\n }\n }\n\n if (P.data.type === 'DX') {\n if (intersection_chain === 0) {\n // Start of intersection chain.\n // No active intersection chain yet,\n // i.e. we did not pass a the first node of a delayed crossing.\n chain_start = P;\n intersection_chain = 1;\n if (DEBUG) {\n console.log(\"Start intersection chain:\", P.coords.usrCoords, P.data.type, status);\n }\n\n } else if (intersection_chain === 1) {\n // Active intersection chain (intersection_chain===1)!\n // End of delayed crossing chain reached\n P.entry_exit = status;\n chain_start.entry_exit = status;\n if (status === 'exit') {\n chain_start.data.type = 'X';\n } else {\n P.data.type = 'X';\n }\n status = (status === 'entry') ? 'exit' : 'entry';\n\n if (DEBUG) {\n console.log(\"mark':\", chain_start.coords.usrCoords, chain_start.data.type, chain_start.entry_exit);\n console.log(\"mark:\", P.coords.usrCoords, P.data.type, P.entry_exit);\n }\n chain_start = null;\n intersection_chain = 0;\n\n } else if (intersection_chain === 2) {\n // The delayed crossing had been interrupted by a crossing intersection.\n // Now we treat the end of the delayed crossing as regular crossing.\n P.entry_exit = status;\n P.data.type = 'X';\n status = (status === 'entry') ? 'exit' : 'entry';\n chain_start = null;\n intersection_chain = 0;\n }\n }\n }\n\n P = P._next;\n if (Type.exists(P._starter) || cnt > 10000) {\n break;\n }\n\n cnt++;\n }\n }\n },\n\n /**\n *\n * @private\n * @param {Array} P\n * @param {Boolean} isBackward\n * @returns {Boolean} True, if the node is an intersection and is of type 'X'\n */\n _stayOnPath: function(P, status) {\n var stay = true;\n\n if (P.intersection && P.data.type !== 'B') {\n stay = (status === P.entry_exit);\n }\n return stay;\n },\n\n /**\n * Add a point to the clipping path and returns if the algorithms\n * arrived at an intersection point which has already been visited.\n * In this case, true is returned.\n *\n * @param {Array} path Resulting path\n * @param {JXG.Math.Clip.Vertex} vertex Point to be added\n * @param {Boolean} DEBUG debug output to console.log\n * @returns {Boolean} true: point has been visited before, false otherwise\n * @private\n */\n _addVertex: function(path, vertex, DEBUG) {\n if (!isNaN(vertex.coords.usrCoords[1]) && !isNaN(vertex.coords.usrCoords[2])) {\n path.push(vertex);\n }\n if (vertex.intersection && vertex.data.done) {\n if (DEBUG) {\n console.log(\"Add last intersection point\", vertex.coords.usrCoords,\n \"on\", vertex.data.pathname, vertex.entry_exit,\n vertex.data.type);\n }\n return true;\n }\n if (vertex.intersection) {\n vertex.data.done = true;\n\n if (DEBUG) {\n console.log(\"Add intersection point\", vertex.coords.usrCoords,\n \"on\", vertex.data.pathname, vertex.entry_exit,\n vertex.data.type);\n }\n }\n return false;\n },\n\n /**\n * Tracing phase of the Greiner-Hormann algorithm, see\n * Greiner, Günther; Kai Hormann (1998).\n * \"Efficient clipping of arbitrary polygons\". ACM Transactions on Graphics. 17 (2): 71–83\n *\n * Boolean operations on polygons are distinguished: 'intersection', 'union', 'difference'.\n *\n * @private\n * @param {Array} S Subject path\n * @param {Array} S_intersect Array containing the intersection vertices of the subject path\n * @param {String} clip_type contains the Boolean operation: 'intersection', 'union', or 'difference'\n * @return {Array} Array consisting of two arrays containing the x-coordinates and the y-coordintaes of\n * the resulting path.\n */\n tracing: function(S, S_intersect, clip_type) {\n var P, current, start,\n cnt = 0,\n status,\n maxCnt = 10000,\n S_idx = 0,\n path = [],\n done = false,\n DEBUG = false;\n\n if (DEBUG) {\n console.log(\"\\n------ Start Phase 3\");\n }\n\n // reverse = (clip_type === 'difference' || clip_type === 'union') ? true : false;\n while (S_idx < S_intersect.length && cnt < maxCnt) {\n // Take the first intersection node of the subject path\n // which is not yet included as start point.\n current = S_intersect[S_idx];\n if (current.data.done || current.data.type !== 'X' /*|| !this._isCrossing(current, reverse)*/) {\n S_idx++;\n continue;\n }\n\n if (DEBUG) {\n console.log(\"\\nStart\", current.data.pathname, current.coords.usrCoords, current.data.type, current.entry_exit, S_idx);\n }\n if (path.length > 0) { // Add a new path\n path.push([NaN, NaN]);\n }\n\n // Start now the tracing with that node of the subject path\n start = current.data.idx;\n P = S;\n\n done = this._addVertex(path, current, DEBUG);\n status = current.entry_exit;\n do {\n if (done) {\n break;\n }\n //\n // Decide if we follow the current path forward or backward.\n // for example, in case the clipping is of type \"intersection\"\n // and the current intersection node is of type entry, we go forward.\n //\n if ((clip_type === 'intersection' && current.entry_exit === 'entry') ||\n (clip_type === 'union' && current.entry_exit === 'exit') ||\n (clip_type === 'difference' && (P === S) === (current.entry_exit === 'exit')) ) {\n\n if (DEBUG) {\n console.log(\"Go forward on\", current.data.pathname, current.entry_exit);\n }\n\n //\n // Take the next nodes and add them to the path\n // as long as they are not intersection nodes of type 'X'.\n //\n do {\n current = current._next;\n done = this._addVertex(path, current, DEBUG);\n if (done) {\n break;\n }\n } while (this._stayOnPath(current, status));\n cnt++;\n } else {\n if (DEBUG) {\n console.log(\"Go backward on\", current.data.pathname);\n }\n //\n // Here, we go backward:\n // Take the previous nodes and add them to the path\n // as long as they are not intersection nodes of type 'X'.\n //\n do {\n current = current._prev;\n done = this._addVertex(path, current, DEBUG);\n if (done) {\n break;\n }\n } while (this._stayOnPath(current, status));\n cnt++;\n }\n\n if (done) {\n break;\n }\n\n if (!current.neighbour) {\n console.log(\"Tracing: emergency break - no neighbour!!!!!!!!!!!!!!!!!\", cnt);\n return [[0], [0]];\n }\n //\n // We stopped the forward or backward loop, because we've\n // arrived at a crossing intersection node, i.e. we have to\n // switch to the other path now.\n if (DEBUG) {\n console.log(\"Switch from\", current.coords.usrCoords, current.data.pathname, \"to\",\n current.neighbour.coords.usrCoords, \"on\", current.neighbour.data.pathname);\n }\n current = current.neighbour;\n if (current.data.done) {\n break;\n }\n current.data.done = true;\n status = current.entry_exit;\n\n // if (current.data.done) {\n // // We arrived at an intersection node which is already\n // // added to the clipping path.\n // // We add it again to close the clipping path and jump out of the\n // // loop.\n // path.push(current);\n // if (DEBUG) {\n // console.log(\"Push last\", current.coords.usrCoords);\n // }\n // break;\n // }\n P = current.data.path;\n\n // Polygon closed:\n // if (DEBUG) {\n // console.log(\"End of loop:\", \"start=\", start, \"idx=\", current.data.idx);\n // }\n // } while (!(current.data.pathname === 'S' && current.data.idx === start) && cnt < maxCnt);\n } while (current.data.idx !== start && cnt < maxCnt);\n\n if (cnt >= maxCnt) {\n console.log(\"Tracing: stopping an infinite loop!\", cnt);\n }\n\n S_idx++;\n }\n return this._getCoordsArrays(path, false);\n },\n\n /**\n * Handle path clipping if one of the two paths is empty.\n * @private\n * @param {Array} S First path, array of JXG.Coords\n * @param {Array} C Second path, array of JXG.Coords\n * @param {String} clip_type Type of Boolean operation: 'intersection', 'union', 'differrence'.\n * @return {Boolean} true, if one of the input paths is empty, false otherwise.\n */\n isEmptyCase: function(S, C, clip_type) {\n if (clip_type === 'intersection' && (S.length === 0 || C.length === 0)) {\n return true;\n }\n if (clip_type === 'union' && (S.length === 0 && C.length === 0)) {\n return true;\n }\n if (clip_type === 'difference' && S.length === 0) {\n return true;\n }\n\n return false;\n },\n\n _getCoordsArrays: function(path, doClose) {\n var pathX = [],\n pathY = [],\n i, le = path.length;\n\n for (i = 0; i < le; i++) {\n if (path[i].coords) {\n pathX.push(path[i].coords.usrCoords[1]);\n pathY.push(path[i].coords.usrCoords[2]);\n } else {\n pathX.push(path[i][0]);\n pathY.push(path[i][1]);\n }\n }\n if (doClose && le > 0) {\n if (path[0].coords) {\n pathX.push(path[0].coords.usrCoords[1]);\n pathY.push(path[0].coords.usrCoords[2]);\n } else {\n pathX.push(path[0][0]);\n pathY.push(path[0][1]);\n }\n }\n\n return [pathX, pathY];\n },\n\n /**\n * Handle cases when there are no intersection points of the two paths. This is the case if the\n * paths are disjoint or one is contained in the other.\n * @private\n * @param {Array} S First path, array of JXG.Coords\n * @param {Array} C Second path, array of JXG.Coords\n * @param {String} clip_type Type of Boolean operation: 'intersection', 'union', 'differrence'.\n * @return {Array} Array consisting of two arrays containing the x-coordinates and the y-coordinates of\n * the resulting path.\n */\n handleEmptyIntersection: function(S, C, clip_type) {\n var P, Q,\n doClose = false,\n path = [];\n\n // Handle trivial cases\n if (S.length === 0) {\n if (clip_type === 'union') {\n // S cup C = C\n path = C;\n } else {\n // S cap C = S \\ C = {}\n path = [];\n }\n return this._getCoordsArrays(path, true);\n }\n if (C.length === 0) {\n if (clip_type === 'intersection') {\n // S cap C = {}\n path = [];\n } else {\n // S cup C = S \\ C = S\n path = S;\n }\n return this._getCoordsArrays(path, true);\n }\n\n // From now on, both paths have non-zero length.\n // The two paths have no crossing intersections,\n // but there might be bouncing intersections.\n\n // First, we find -- if possible -- on each path a point which is not an intersection point.\n if (S.length > 0) {\n P = S[0];\n while (P.intersection) {\n P = P._next;\n if (P._end) {\n break;\n }\n }\n }\n if (C.length > 0) {\n Q = C[0];\n while (Q.intersection) {\n Q = Q._next;\n if (Q._end) {\n break;\n }\n }\n }\n\n // Test if one curve is contained by the other\n if (this.windingNumber(P.coords.usrCoords, C) === 0) {\n // P is outside of C:\n // Either S is disjoint from C or C is inside of S\n if (this.windingNumber(Q.coords.usrCoords, S) !== 0) {\n // C is inside of S, i.e. C subset of S\n\n if (clip_type === 'union') {\n path = path.concat(S);\n path.push(S[0]);\n } else if (clip_type === 'difference') {\n path = path.concat(S);\n path.push(S[0]);\n if (Geometry.signedPolygon(S) * Geometry.signedPolygon(C) > 0) {\n // Pathes have same orientation, we have to revert one.\n path.reverse();\n }\n path.push([NaN, NaN]);\n }\n if (clip_type === 'difference' || clip_type === 'intersection') {\n path = path.concat(C);\n path.push(C[0]);\n doClose = false;\n }\n } else { // The curves are disjoint\n if (clip_type === 'difference') {\n path = path.concat(S);\n doClose = true;\n } else if (clip_type === 'union') {\n path = path.concat(S);\n path.push(S[0]);\n path.push([NaN, NaN]);\n path = path.concat(C);\n path.push(C[0]);\n }\n }\n } else {\n // S inside of C, i.e. S subset of C\n if (clip_type === 'intersection') {\n path = path.concat(S);\n doClose = true;\n } else if (clip_type === 'union') {\n path = path.concat(C);\n path.push(C[0]);\n }\n\n // 'difference': path is empty\n }\n\n return this._getCoordsArrays(path, doClose);\n },\n\n /**\n * Count intersection points of type 'X'.\n * @param {JXG.Mat.Clip.Vertex} intersections\n * @returns Number\n * @private\n */\n _countCrossingIntersections: function(intersections) {\n var i,\n le = intersections.length,\n sum = 0;\n\n for (i = 0; i < le; i++) {\n if (intersections[i].data.type === 'X') {\n sum++;\n }\n }\n return sum;\n },\n\n /**\n * Create path from all sorts of input elements and convert it\n * to a suitable input path for greinerHormann().\n *\n * @private\n * @param {Object} obj Maybe curve, arc, sector, circle, polygon, array of points, array of JXG.Coords,\n * array of coordinate pairs.\n * @param {JXG.Board} board JSXGraph board object. It is needed to convert between\n * user coordinates and screen coordinates.\n * @returns {Array} Array of JXG.Coords elements containing a path.\n * @see JXG.Math.Clip#greinerHormann\n */\n _getPath: function(obj, board) {\n var i, len, r, rad, angle, alpha,\n steps,\n S = [];\n\n // Collect all points into path array S\n if (obj.elementClass === Const.OBJECT_CLASS_CURVE &&\n (obj.type === Const.OBJECT_TYPE_ARC || obj.type === Const.OBJECT_TYPE_SECTOR)) {\n angle = Geometry.rad(obj.radiuspoint, obj.center, obj.anglepoint);\n steps = Math.floor(angle * 180 / Math.PI);\n r = obj.Radius();\n rad = angle / steps;\n alpha = Math.atan2(obj.radiuspoint.coords.usrCoords[2] - obj.center.coords.usrCoords[2],\n obj.radiuspoint.coords.usrCoords[1] - obj.center.coords.usrCoords[1]);\n\n if (obj.type === Const.OBJECT_TYPE_SECTOR) {\n this._addToList(S, obj.center.coords, 0);\n }\n for (i = 0; i <= steps; i++) {\n this._addToList(S, new Coords(Const.COORDS_BY_USER, [\n obj.center.coords.usrCoords[0],\n obj.center.coords.usrCoords[1] + Math.cos(i * rad + alpha) * r,\n obj.center.coords.usrCoords[2] + Math.sin(i * rad + alpha) * r\n ], board), i + 1);\n }\n if (obj.type === Const.OBJECT_TYPE_SECTOR) {\n this._addToList(S, obj.center.coords, steps + 2);\n }\n\n } else if (obj.elementClass === Const.OBJECT_CLASS_CURVE && Type.exists(obj.points)) {\n len = obj.numberPoints;\n for (i = 0; i < len; i++) {\n this._addToList(S, obj.points[i], i);\n }\n } else if (obj.type === Const.OBJECT_TYPE_POLYGON) {\n for (i = 0; i < obj.vertices.length; i++) {\n this._addToList(S, obj.vertices[i].coords, i);\n }\n } else if (obj.elementClass === Const.OBJECT_CLASS_CIRCLE) {\n steps = 359;\n r = obj.Radius();\n rad = 2 * Math.PI / steps;\n for (i = 0; i <= steps; i++) {\n this._addToList(S, new Coords(Const.COORDS_BY_USER, [\n obj.center.coords.usrCoords[0],\n obj.center.coords.usrCoords[1] + Math.cos(i * rad) * r,\n obj.center.coords.usrCoords[2] + Math.sin(i * rad) * r\n ], board), i);\n }\n } else if (Type.isArray(obj)) {\n len = obj.length;\n for (i = 0; i < len; i++) {\n if (Type.exists(obj[i].coords)) {\n // Point type\n this._addToList(S, obj[i].coords, i);\n } else if (Type.isArray(obj[i])) {\n // Coordinate pair\n this._addToList(S, new Coords(Const.COORDS_BY_USER, obj[i], board), i);\n } else if (Type.exists(obj[i].usrCoords)) {\n // JXG.Coordinates\n this._addToList(S, obj[i], i);\n }\n }\n }\n\n return S;\n },\n\n /**\n * Determine the intersection, union or difference of two closed paths.\n * <p>\n * This is an implementation of the Greiner-Hormann algorithm, see\n * Günther Greiner and Kai Hormann (1998).\n * \"Efficient clipping of arbitrary polygons\". ACM Transactions on Graphics. 17 (2): 71–83.\n * and\n * Erich, L. Foster, and Kai Hormann, Kai, and Romeo Traaian Popa (2019),\n * \"Clipping simple polygons with degenerate intersections\", Computers & Graphics:X, 2.\n * <p>\n * It is assumed that the pathes are closed, whereby it does not matter if the last point indeed\n * equals the first point. In contrast to the original Greiner-Hormann algorithm,\n * this algorithm can cope with many degenerate cases. A degenerate case is a vertext of one path\n * which is contained in the other path.\n * <p>\n *\n * <p>Problematic are:\n * <ul>\n * <li>degenerate cases where one path additionally has self-intersections\n * <li>differences with one path having self-intersections.\n * </ul>\n *\n * @param {JXG.Circle|JXG.Curve|JXG.Polygon} subject First closed path, usually called 'subject'.\n * Maybe curve, arc, sector, circle, polygon, array of points, array of JXG.Coords,\n * array of coordinate pairs.\n * @param {JXG.Circle|JXG.Curve|JXG.Polygon} clip Second closed path, usually called 'clip'.\n * Maybe curve, arc, sector, circle, polygon, array of points, array of JXG.Coords,\n * array of coordinate pairs.\n * @param {String} clip_type Determines the type of boolean operation on the two paths.\n * Possible values are 'intersection', 'union', or 'difference'.\n * @param {JXG.Board} board JSXGraph board object. It is needed to convert between\n * user coordinates and screen coordinates.\n * @return {Array} Array consisting of two arrays containing the x-coordinates and the y-coordinates of\n * the resulting path.\n *\n * @see JXG.Math.Clip#intersection\n * @see JXG.Math.Clip#union\n * @see JXG.Math.Clip#difference\n *\n * @example\n * var curve1 = board.create('curve', [\n * [-3, 3, 0, -3],\n * [3, 3, 0, 3]\n * ],\n * {strokeColor: 'black'});\n *\n * var curve2 = board.create('curve', [\n * [-4, 4, 0, -4],\n * [2, 2, 4, 2]\n * ],\n * {strokeColor: 'blue'});\n *\n * var clip_path = board.create('curve', [[], []], {strokeWidth: 3, fillColor: 'yellow', fillOpacity: 0.6});\n * clip_path.updateDataArray = function() {\n * var a = JXG.Math.Clip.greinerHormann(curve2, curve1, 'intersection', this.board);\n *\n * this.dataX = a[0];\n * this.dataY = a[1];\n * };\n *\n * board.update();\n *\n * </pre><div id=\"JXG9d2a6acf-a43b-4035-8f8a-9b1bee580210\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG9d2a6acf-a43b-4035-8f8a-9b1bee580210',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n *\n * var curve1 = board.create('curve', [\n * [-3, 3, 0, -3],\n * [3, 3, 0, 3]\n * ],\n * {strokeColor: 'black'});\n *\n * var curve2 = board.create('curve', [\n * [-4, 4, 0, -4],\n * [2, 2, 4, 2]\n * ],\n * {strokeColor: 'blue'});\n *\n * var clip_path = board.create('curve', [[], []], {strokeWidth: 3, fillColor: 'yellow', fillOpacity: 0.6});\n * clip_path.updateDataArray = function() {\n * var a = JXG.Math.Clip.greinerHormann(curve2, curve1, 'intersection', this.board);\n *\n * this.dataX = a[0];\n * this.dataY = a[1];\n * };\n *\n * board.update();\n *\n * })();\n *\n * </script><pre>\n *\n * @example\n * var curve1 = board.create('curve', [\n * [-3, 3, 0, -3],\n * [3, 3, 0, 3]\n * ],\n * {strokeColor: 'black', fillColor: 'none', fillOpacity: 0.8});\n *\n * var curve2 = board.create('polygon', [[3, 4], [-4, 0], [-4, 4]],\n * {strokeColor: 'blue', fillColor: 'none'});\n *\n * var clip_path = board.create('curve', [[], []], {strokeWidth: 3, fillColor: 'yellow', fillOpacity: 0.6});\n * clip_path.updateDataArray = function() {\n * var a = JXG.Math.Clip.greinerHormann(curve1, curve2, 'union', this.board);\n * this.dataX = a[0];\n * this.dataY = a[1];\n * };\n *\n * board.update();\n *\n * </pre><div id=\"JXG6075c918-4d57-4b72-b600-6597a6a4f44e\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG6075c918-4d57-4b72-b600-6597a6a4f44e',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var curve1 = board.create('curve', [\n * [-3, 3, 0, -3],\n * [3, 3, 0, 3]\n * ],\n * {strokeColor: 'black', fillColor: 'none', fillOpacity: 0.8});\n *\n * var curve2 = board.create('polygon', [[3, 4], [-4, 0], [-4, 4]],\n * {strokeColor: 'blue', fillColor: 'none'});\n *\n *\n * var clip_path = board.create('curve', [[], []], {strokeWidth: 3, fillColor: 'yellow', fillOpacity: 0.6});\n * clip_path.updateDataArray = function() {\n * var a = JXG.Math.Clip.greinerHormann(curve1, curve2, 'union', this.board);\n * this.dataX = a[0];\n * this.dataY = a[1];\n * };\n *\n * board.update();\n *\n * })();\n *\n * </script><pre>\n *\n * @example\n * var curve1 = board.create('curve', [\n * [-4, 4, 0, -4],\n * [4, 4, -2, 4]\n * ],\n * {strokeColor: 'black', fillColor: 'none', fillOpacity: 0.8});\n *\n * var curve2 = board.create('circle', [[0, 0], [0, -2]],\n * {strokeColor: 'blue', strokeWidth: 1, fillColor: 'red', fixed: true, fillOpacity: 0.3,\n * center: {visible: true, size: 5}, point2: {size: 5}});\n *\n * var clip_path = board.create('curve', [[], []], {strokeWidth: 3, fillColor: 'yellow', fillOpacity: 0.6});\n * clip_path.updateDataArray = function() {\n * var a = JXG.Math.Clip.greinerHormann(curve1, curve2, 'difference', this.board);\n *\n * this.dataX = a[0];\n * this.dataY = a[1];\n * };\n *\n * board.update();\n *\n * </pre><div id=\"JXG46b3316b-5ab9-4928-9473-ccb476ca4185\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG46b3316b-5ab9-4928-9473-ccb476ca4185',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var curve1 = board.create('curve', [\n * [-4, 4, 0, -4],\n * [4, 4, -2, 4]\n * ],\n * {strokeColor: 'black', fillColor: 'none', fillOpacity: 0.8});\n *\n * var curve2 = board.create('circle', [[0, 0], [0, -2]],\n * {strokeColor: 'blue', strokeWidth: 1, fillColor: 'red', fixed: true, fillOpacity: 0.3,\n * center: {visible: true, size: 5}, point2: {size: 5}});\n *\n *\n * var clip_path = board.create('curve', [[], []], {strokeWidth: 3, fillColor: 'yellow', fillOpacity: 0.6});\n * clip_path.updateDataArray = function() {\n * var a = JXG.Math.Clip.greinerHormann(curve1, curve2, 'difference', this.board);\n *\n * this.dataX = a[0];\n * this.dataY = a[1];\n * };\n *\n * board.update();\n *\n * })();\n *\n * </script><pre>\n *\n * @example\n * var clip_path = board.create('curve', [[], []], {strokeWidth: 1, fillColor: 'yellow', fillOpacity: 0.6});\n * clip_path.updateDataArray = function() {\n * var bbox = this.board.getBoundingBox(),\n * canvas, triangle;\n *\n * canvas = [[bbox[0], bbox[1]], // ul\n * [bbox[0], bbox[3]], // ll\n * [bbox[2], bbox[3]], // lr\n * [bbox[2], bbox[1]], // ur\n * [bbox[0], bbox[1]]] // ul\n * triangle = [[-1,1], [1,1], [0,-1], [-1,1]];\n *\n * var a = JXG.Math.Clip.greinerHormann(canvas, triangle, 'difference', this.board);\n * this.dataX = a[0];\n * this.dataY = a[1];\n * };\n *\n * </pre><div id=\"JXGe94da07a-2a01-4498-ad62-f71a327f8e25\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXGe94da07a-2a01-4498-ad62-f71a327f8e25',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var clip_path = board.create('curve', [[], []], {strokeWidth: 1, fillColor: 'yellow', fillOpacity: 0.6});\n * clip_path.updateDataArray = function() {\n * var bbox = this.board.getBoundingBox(),\n * canvas, triangle;\n *\n * canvas = [[bbox[0], bbox[1]], // ul\n * [bbox[0], bbox[3]], // ll\n * [bbox[2], bbox[3]], // lr\n * [bbox[2], bbox[1]], // ur\n * [bbox[0], bbox[1]]] // ul\n * triangle = [[-1,1], [1,1], [0,-1], [-1,1]];\n *\n * var a = JXG.Math.Clip.greinerHormann(canvas, triangle, 'difference', this.board);\n * this.dataX = a[0];\n * this.dataY = a[1];\n * };\n *\n * })();\n *\n * </script><pre>\n *\n */\n greinerHormann: function(subject, clip, clip_type, board) { //},\n // subject_first_point_type, clip_first_point_type) {\n\n var len, S = [],\n C = [],\n S_intersect = [],\n // C_intersect = [],\n S_starters,\n C_starters,\n res = [],\n DEBUG = false;\n\n if (DEBUG) {\n console.log(\"\\n------------ GREINER-HORMANN --------------\");\n }\n // Collect all subject points into subject array S\n S = this._getPath(subject, board);\n len = S.length;\n if (len > 0 && Geometry.distance(S[0].coords.usrCoords, S[len - 1].coords.usrCoords, 3) < Mat.eps) {\n S.pop();\n }\n\n // Collect all points into clip array C\n C = this._getPath(clip, board);\n len = C.length;\n if (len > 0 && Geometry.distance(C[0].coords.usrCoords, C[len - 1].coords.usrCoords, 3) < Mat.eps * Mat.eps) {\n C.pop();\n }\n\n // Handle cases where at least one of the paths is empty\n if (this.isEmptyCase(S, C, clip_type)) {\n return [[], []];\n }\n\n // Add pointers for doubly linked lists\n S_starters = this.makeDoublyLinkedList(S);\n C_starters = this.makeDoublyLinkedList(C);\n\n if (DEBUG) {\n this._print_array(S);\n console.log(\"Components:\", S_starters);\n this._print_array(C);\n console.log(\"Components:\", C_starters);\n }\n\n res = this.findIntersections(S, C, board);\n S_intersect = res[0];\n\n this._handleFullyDegenerateCase(S, C, board);\n\n // Phase 2: mark intersection points as entry or exit points\n this.markEntryExit(S, C, S_starters);\n\n // if (S[0].coords.distance(Const.COORDS_BY_USER, C[0].coords) === 0) {\n // // Randomly disturb the first point of the second path\n // // if both paths start at the same point.\n // C[0].usrCoords[1] *= 1 + Math.random() * 0.0001 - 0.00005;\n // C[0].usrCoords[2] *= 1 + Math.random() * 0.0001 - 0.00005;\n // }\n this.markEntryExit(C, S, C_starters);\n\n // Handle cases without intersections\n if (this._countCrossingIntersections(S_intersect) === 0) {\n return this.handleEmptyIntersection(S, C, clip_type);\n }\n\n // Phase 3: tracing\n return this.tracing(S, S_intersect, clip_type);\n },\n\n /**\n * Union of two closed paths. The paths could be JSXGraph elements circle, curve, or polygon.\n * Computed by the Greiner-Hormann algorithm.\n *\n * @param {JXG.Circle|JXG.Curve|JXG.Polygon} subject First closed path.\n * @param {JXG.Circle|JXG.Curve|JXG.Polygon} clip Second closed path.\n * @param {JXG.Board} board JSXGraph board object. It is needed to convert between\n * user coordinates and screen coordinates.\n * @return {Array} Array consisting of two arrays containing the x-coordinates and the y-coordinates of\n * the resulting path.\n *\n * @see JXG.Math.Clip#greinerHormann\n * @see JXG.Math.Clip#intersection\n * @see JXG.Math.Clip#difference\n *\n * @example\n * var curve1 = board.create('curve', [\n * [-3, 3, 0, -3],\n * [3, 3, 0, 3]\n * ],\n * {strokeColor: 'black'});\n *\n * var curve2 = board.create('polygon', [[3, 4], [-4, 0], [-4, 4]],\n * {strokeColor: 'blue', fillColor: 'none'});\n *\n * var clip_path = board.create('curve', [[], []], {strokeWidth: 3, fillColor: 'yellow', fillOpacity: 0.3});\n * clip_path.updateDataArray = function() {\n * var a = JXG.Math.Clip.union(curve1, curve2, this.board);\n * this.dataX = a[0];\n * this.dataY = a[1];\n * };\n *\n * board.update();\n *\n * </pre><div id=\"JXG7c5204aa-3824-4464-819c-80df7bf1d917\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG7c5204aa-3824-4464-819c-80df7bf1d917',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var curve1 = board.create('curve', [\n * [-3, 3, 0, -3],\n * [3, 3, 0, 3]\n * ],\n * {strokeColor: 'black'});\n *\n * var curve2 = board.create('polygon', [[3, 4], [-4, 0], [-4, 4]],\n * {strokeColor: 'blue', fillColor: 'none'});\n *\n *\n * var clip_path = board.create('curve', [[], []], {strokeWidth: 3, fillColor: 'yellow', fillOpacity: 0.3});\n * clip_path.updateDataArray = function() {\n * var a = JXG.Math.Clip.union(curve1, curve2, this.board);\n * this.dataX = a[0];\n * this.dataY = a[1];\n * };\n *\n * board.update();\n *\n * })();\n *\n * </script><pre>\n *\n */\n union: function(path1, path2, board) {\n return this.greinerHormann(path1, path2, 'union', board);\n },\n\n /**\n * Intersection of two closed paths. The paths could be JSXGraph elements circle, curve, or polygon.\n * Computed by the Greiner-Hormann algorithm.\n *\n * @param {JXG.Circle|JXG.Curve|JXG.Polygon} subject First closed path.\n * @param {JXG.Circle|JXG.Curve|JXG.Polygon} clip Second closed path.\n * @param {JXG.Board} board JSXGraph board object. It is needed to convert between\n * user coordinates and screen coordinates.\n * @return {Array} Array consisting of two arrays containing the x-coordinates and the y-coordinates of\n * the resulting path.\n *\n * @see JXG.Math.Clip#greinerHormann\n * @see JXG.Math.Clip#union\n * @see JXG.Math.Clip#difference\n *\n * @example\n * var p = [];\n * p.push(board.create('point', [0, -5]));\n * p.push(board.create('point', [-5, 0]));\n * p.push(board.create('point', [-3, 3]));\n *\n * var curve1 = board.create('ellipse', p,\n * {strokeColor: 'black'});\n *\n * var curve2 = board.create('curve', [function(phi){return 4 * Math.cos(2*phi); },\n * [0, 0],\n * 0, 2 * Math.PI],\n * {curveType:'polar', strokeColor: 'blue', strokewidth:1});\n *\n * var clip_path = board.create('curve', [[], []], {strokeWidth: 3, fillColor: 'yellow', fillOpacity: 0.3});\n * clip_path.updateDataArray = function() {\n * var a = JXG.Math.Clip.intersection(curve2, curve1, this.board);\n *\n * this.dataX = a[0];\n * this.dataY = a[1];\n * };\n *\n * board.update();\n *\n * </pre><div id=\"JXG7ad547eb-7b6c-4a1a-a4d4-4ed298fc7998\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG7ad547eb-7b6c-4a1a-a4d4-4ed298fc7998',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var p = [];\n * p.push(board.create('point', [0, -5]));\n * p.push(board.create('point', [-5, 0]));\n * p.push(board.create('point', [-3, 3]));\n *\n * var curve1 = board.create('ellipse', p,\n * {strokeColor: 'black'});\n *\n * var curve2 = board.create('curve', [function(phi){return 4 * Math.cos(2*phi); },\n * [0, 0],\n * 0, 2 * Math.PI],\n * {curveType:'polar', strokeColor: 'blue', strokewidth:1});\n *\n *\n * var clip_path = board.create('curve', [[], []], {strokeWidth: 3, fillColor: 'yellow', fillOpacity: 0.3});\n * clip_path.updateDataArray = function() {\n * var a = JXG.Math.Clip.intersection(curve2, curve1, this.board);\n *\n * this.dataX = a[0];\n * this.dataY = a[1];\n * };\n *\n * board.update();\n *\n * })();\n *\n * </script><pre>\n *\n *\n */\n intersection: function(path1, path2, board) {\n return this.greinerHormann(path1, path2, 'intersection', board);\n },\n\n /**\n * Difference of two closed paths, i.e. path1 minus path2.\n * The paths could be JSXGraph elements circle, curve, or polygon.\n * Computed by the Greiner-Hormann algorithm.\n *\n * @param {JXG.Circle|JXG.Curve|JXG.Polygon} subject First closed path.\n * @param {JXG.Circle|JXG.Curve|JXG.Polygon} clip Second closed path.\n * @param {JXG.Board} board JSXGraph board object. It is needed to convert between\n * user coordinates and screen coordinates.\n * @return {Array} Array consisting of two arrays containing the x-coordinates and the y-coordinates of\n * the resulting path.\n *\n * @see JXG.Math.Clip#greinerHormann\n * @see JXG.Math.Clip#intersection\n * @see JXG.Math.Clip#union\n *\n * @example\n * var curve1 = board.create('polygon', [[-4, 4], [4, 4], [0, -1]],\n * {strokeColor: 'blue', fillColor: 'none'});\n *\n * var curve2 = board.create('curve', [\n * [-1, 1, 0, -1],\n * [1, 1, 3, 1]\n * ],\n * {strokeColor: 'black', fillColor: 'none', fillOpacity: 0.8});\n *\n * var clip_path = board.create('curve', [[], []], {strokeWidth: 3, fillColor: 'yellow', fillOpacity: 0.3});\n * clip_path.updateDataArray = function() {\n * var a = JXG.Math.Clip.difference(curve1, curve2, this.board);\n * this.dataX = a[0];\n * this.dataY = a[1];\n * };\n *\n * board.update();\n *\n * </pre><div id=\"JXGc5ce6bb3-146c-457f-a48b-6b9081fb68a3\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXGc5ce6bb3-146c-457f-a48b-6b9081fb68a3',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var curve1 = board.create('polygon', [[-4, 4], [4, 4], [0, -1]],\n * {strokeColor: 'blue', fillColor: 'none'});\n *\n * var curve2 = board.create('curve', [\n * [-1, 1, 0, -1],\n * [1, 1, 3, 1]\n * ],\n * {strokeColor: 'black', fillColor: 'none', fillOpacity: 0.8});\n *\n *\n * var clip_path = board.create('curve', [[], []], {strokeWidth: 3, fillColor: 'yellow', fillOpacity: 0.3});\n * clip_path.updateDataArray = function() {\n * var a = JXG.Math.Clip.difference(curve1, curve2, this.board);\n * this.dataX = a[0];\n * this.dataY = a[1];\n * };\n *\n * board.update();\n *\n * })();\n *\n * </script><pre>\n *\n */\n difference: function(path1, path2, board) {\n return this.greinerHormann(path1, path2, 'difference', board);\n }\n }; //);\n\n JXG.extend(Mat.Clip, /** @lends JXG.Math.Clip */ {\n });\n\n return Mat.Clip;\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true*/\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n jxg\n math/math\n utils/type\n */\n\n/**\n * @fileoverview In this file the namespace Math.Poly is defined, which holds algorithms to create and\n * manipulate polynomials.\n */\n\ndefine('math/poly',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, Type) {\n\n \"use strict\";\n\n /**\n * The JXG.Math.Poly namespace holds algorithms to create and manipulate polynomials.\n * @name JXG.Math.Poly\n * @exports Mat.Poly as JXG.Math.Poly\n * @namespace\n */\n Mat.Poly = {};\n\n /**\n * Define a polynomial ring over R.\n * @class\n * @name JXG.Math.Poly.Ring\n * @param {Array} variables List of indeterminates.\n */\n Mat.Poly.Ring = function (variables) {\n /**\n * A list of variables in this polynomial ring.\n * @type Array\n */\n this.vars = variables;\n };\n\n JXG.extend(Mat.Poly.Ring.prototype, /** @lends JXG.Math.Poly.Ring.prototype */ {\n // nothing yet.\n });\n\n\n /**\n * Define a monomial over the polynomial ring <tt>ring</tt>.\n * @class\n * @name JXG.Math.Poly.Monomial\n * @param {JXG.Math.Poly.Ring} ring\n * @param {Number} coefficient\n * @param {Array} exponents An array of exponents, corresponding to ring\n */\n Mat.Poly.Monomial = function (ring, coefficient, exponents) {\n var i;\n\n if (!Type.exists(ring)) {\n throw new Error('JSXGraph error: In JXG.Math.Poly.monomial missing parameter \\'ring\\'.');\n }\n\n if (!Type.isArray(exponents)) {\n exponents = [];\n }\n\n exponents = exponents.slice(0, ring.vars.length);\n\n for (i = exponents.length; i < ring.vars.length; i++) {\n exponents.push(0);\n }\n\n /**\n * A polynomial ring.\n * @type JXG.Math.Poly.Ring\n */\n this.ring = ring;\n\n /**\n * The monomial's coefficient\n * @type Number\n */\n this.coefficient = coefficient || 0;\n\n /**\n * Exponent vector, the order depends on the order of the variables\n * in the ring definition.\n * @type Array\n */\n this.exponents = Type.deepCopy(exponents);\n };\n\n JXG.extend(Mat.Poly.Monomial.prototype, /** @lends JXG.Math.Poly.Monomial.prototype */ {\n\n /**\n * Creates a deep copy of the monomial.\n *\n * @returns {JXG.Math.Poly.Monomial}\n *\n * @memberof JXG.Math.Poly.Monomial\n */\n copy: function () {\n return new Mat.Poly.Monomial(this.ring, this.coefficient, this.exponents);\n },\n\n /**\n * Print the monomial.\n * @returns {String} String representation of the monomial\n\n * @memberof JXG.Math.Poly.Monomial\n */\n print: function () {\n var s = [],\n i;\n\n for (i = 0; i < this.ring.vars.length; i++) {\n s.push(this.ring.vars[i] + '^' + this.exponents[i]);\n }\n\n return this.coefficient + '*' + s.join('*');\n }\n });\n\n\n /**\n * A polynomial is a sum of monomials.\n * @class\n * @name JXG.Math.Poly.Polynomial\n * @param {JXG.Math.Poly.Ring} ring A polynomial ring.\n * @param {String} str TODO String representation of the polynomial, will be parsed.\n */\n Mat.Poly.Polynomial = function (ring, str) {\n var parse = function () {\n\n },\n mons;\n\n if (!Type.exists(ring)) {\n throw new Error('JSXGraph error: In JXG.Math.Poly.polynomial missing parameter \\'ring\\'.');\n }\n\n if (Type.exists(str) && Type.isString(str)) {\n mons = parse(str);\n } else {\n mons = [];\n }\n\n /**\n * A polynomial ring.\n * @type JXG.Math.Poly.Ring\n */\n this.ring = ring;\n\n /**\n * List of monomials.\n * @type Array\n */\n this.monomials = mons;\n };\n\n JXG.extend(Mat.Poly.Polynomial.prototype, /** @lends JXG.Math.Poly.Polynomial.prototype */ {\n /**\n * Find a monomial with the given signature, i.e. exponent vector.\n * @param {Array} sig An array of numbers\n * @returns {Number} The index of the first monomial with the given signature, or -1\n * if no monomial could be found.\n * @memberof JXG.Math.Poly.Polynomial\n */\n findSignature: function (sig) {\n var i;\n\n for (i = 0; i < this.monomials.length; i++) {\n if (Type.cmpArrays(this.monomials[i].exponents, sig)) {\n return i;\n }\n }\n\n return -1;\n },\n\n /**\n * Adds a monomial to the polynomial. Checks the existing monomials for the added\n * monomial's signature and just adds the coefficient if one is found.\n * @param {JXG.Math.Poly.Monomial} m\n * @param {Number} factor Either <tt>1</tt> or <tt>-1</tt>.\n * @memberof JXG.Math.Poly.Polynomial\n */\n addSubMonomial: function (m, factor) {\n var i;\n\n i = this.findSignature(m.exponents);\n if (i > -1) {\n this.monomials[i].coefficient += factor * m.coefficient;\n } else {\n m.coefficient *= factor;\n this.monomials.push(m);\n }\n },\n\n /**\n * Adds another polynomial or monomial to this one and merges them by checking for the\n * signature of each new monomial in the existing monomials.\n * @param {JXG.Math.Poly.Polynomial|JXG.Math.Poly.Monomial} mp\n * @memberof JXG.Math.Poly.Polynomial\n */\n add: function (mp) {\n var i;\n\n if (Type.exists(mp) && mp.ring === this.ring) {\n if (Type.isArray(mp.exponents)) {\n // mp is a monomial\n this.addSubMonomial(mp, 1);\n } else {\n // mp is a polynomial\n for (i = 0; i < mp.monomials.length; i++) {\n this.addSubMonomial(mp.monomials[i], 1);\n }\n }\n } else {\n throw new Error('JSXGraph error: In JXG.Math.Poly.polynomial.add either summand is undefined or rings don\\'t match.');\n }\n },\n\n /**\n * Subtracts another polynomial or monomial from this one and merges them by checking for the\n * signature of each new monomial in the existing monomials.\n * @param {JXG.Math.Poly.Polynomial|JXG.Math.Poly.Monomial} mp\n * @memberof JXG.Math.Poly.Polynomial\n */\n sub: function (mp) {\n var i;\n\n if (Type.exists(mp) && mp.ring === this.ring) {\n if (Type.isArray(mp.exponents)) {\n // mp is a monomial\n this.addSubMonomial(mp, -1);\n } else {\n // mp is a polynomial\n for (i = 0; i < mp.monomials.length; i++) {\n this.addSubMonomial(mp.monomials[i], -1);\n }\n }\n } else {\n throw new Error('JSXGraph error: In JXG.Math.Poly.polynomial.sub either summand is undefined or rings don\\'t match.');\n }\n },\n\n /**\n * Creates a deep copy of the polynomial.\n * @returns {JXG.Math.Poly.Polynomial}\n * @memberof JXG.Math.Poly.Polynomial\n */\n copy: function () {\n var i, p;\n\n p = new Mat.Poly.Polynomial(this.ring);\n\n for (i = 0; i < this.monomials.length; i++) {\n p.monomials.push(this.monomials[i].copy());\n }\n return p;\n },\n\n /**\n * Prints the polynomial.\n * @returns {String} A string representation of the polynomial.\n * @memberof JXG.Math.Poly.Polynomial\n */\n print: function () {\n var s = [],\n i;\n\n for (i = 0; i < this.monomials.length; i++) {\n s.push('(' + this.monomials[i].print() + ')');\n }\n\n return s.join('+');\n }\n });\n\n return Mat.Poly;\n});\n\n/*\r\n Copyright 2008-2022\r\n Matthias Ehmann,\r\n Michael Gerhaeuser,\r\n Carsten Miller,\r\n Bianca Valentin,\r\n Alfred Wassermann,\r\n Peter Wilfahrt\r\n\r\n This file is part of JSXGraph.\r\n\r\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\r\n\r\n You can redistribute it and/or modify it under the terms of the\r\n\r\n * GNU Lesser General Public License as published by\r\n the Free Software Foundation, either version 3 of the License, or\r\n (at your option) any later version\r\n OR\r\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\r\n\r\n JSXGraph is distributed in the hope that it will be useful,\r\n but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r\n GNU Lesser General Public License for more details.\r\n\r\n You should have received a copy of the GNU Lesser General Public License and\r\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\r\n and <http://opensource.org/licenses/MIT/>.\r\n */\r\n\r\n\r\n/*global JXG: true, define: true*/\r\n/*jslint nomen: true, plusplus: true*/\r\n\r\n/* depends:\r\n jxg\r\n */\r\n\r\n/**\r\n * @fileoverview A class for complex arithmetics JXG.Complex is defined in this\r\n * file. Also a namespace JXG.C is included to provide instance-independent\r\n * arithmetic functions.\r\n */\r\n\r\ndefine('math/complex',['jxg', 'utils/type'], function (JXG, Type) {\r\n\r\n \"use strict\";\r\n\r\n /**\r\n * Creates a new complex number.\r\n * @class This class is for calculating with complex numbers.\r\n * @constructor\r\n * @param {Number} [x=0] Real part.\r\n * @param {Number} [y=0] Imaginary part.\r\n */\r\n JXG.Complex = function (x, y) {\r\n /**\r\n * This property is only to signalize that this object is of type JXG.Complex. Only\r\n * used internally to distinguish between normal JavaScript numbers and JXG.Complex numbers.\r\n * @type Boolean\r\n * @default true\r\n * @private\r\n */\r\n this.isComplex = true;\r\n\r\n /* is the first argument a complex number? if it is,\r\n * extract real and imaginary part. */\r\n if (x && x.isComplex) {\r\n y = x.imaginary;\r\n x = x.real;\r\n }\r\n\r\n /**\r\n * Real part of the complex number.\r\n * @type Number\r\n * @default 0\r\n */\r\n this.real = x || 0;\r\n\r\n /**\r\n * Imaginary part of the complex number.\r\n * @type Number\r\n * @default 0\r\n */\r\n this.imaginary = y || 0;\r\n\r\n /**\r\n * Absolute value in the polar form of the complex number. Currently unused.\r\n * @type Number\r\n */\r\n this.absval = 0;\r\n\r\n /**\r\n * Angle value in the polar form of the complex number. Currently unused.\r\n * @type Number\r\n */\r\n this.angle = 0;\r\n };\r\n\r\n JXG.extend(JXG.Complex.prototype, /** @lends JXG.Complex.prototype */ {\r\n /**\r\n * Converts a complex number into a string.\r\n * @returns {String} Formatted string containing the complex number in human readable form (algebraic form).\r\n */\r\n toString: function () {\r\n return this.real + ' + ' + this.imaginary + 'i';\r\n },\r\n\r\n /**\r\n * Add another complex number to this complex number.\r\n * @param {JXG.Complex,Number} c A JavaScript number or a JXG.Complex object to be added to the current object.\r\n * @returns {JXG.Complex} Reference to this complex number\r\n */\r\n add: function (c) {\r\n if (Type.isNumber(c)) {\r\n this.real += c;\r\n } else {\r\n this.real += c.real;\r\n this.imaginary += c.imaginary;\r\n }\r\n\r\n return this;\r\n },\r\n\r\n /**\r\n * Subtract another complex number from this complex number.\r\n * @param {JXG.Complex,Number} c A JavaScript number or a JXG.Complex object to subtract from the current object.\r\n * @returns {JXG.Complex} Reference to this complex number\r\n */\r\n sub: function (c) {\r\n if (Type.isNumber(c)) {\r\n this.real -= c;\r\n } else {\r\n this.real -= c.real;\r\n this.imaginary -= c.imaginary;\r\n }\r\n\r\n return this;\r\n },\r\n\r\n /**\r\n * Multiply another complex number to this complex number.\r\n * @param {JXG.Complex,Number} c A JavaScript number or a JXG.Complex object to\r\n * multiply with the current object.\r\n * @returns {JXG.Complex} Reference to this complex number\r\n */\r\n mult: function (c) {\r\n var re, im;\r\n\r\n if (Type.isNumber(c)) {\r\n this.real *= c;\r\n this.imaginary *= c;\r\n } else {\r\n re = this.real;\r\n im = this.imaginary;\r\n\r\n // (a+ib)(x+iy) = ax-by + i(xb+ay)\r\n this.real = re * c.real - im * c.imaginary;\r\n this.imaginary = re * c.imaginary + im * c.real;\r\n }\r\n\r\n return this;\r\n },\r\n\r\n /**\r\n * Divide this complex number by the given complex number.\r\n * @param {JXG.Complex,Number} c A JavaScript number or a JXG.Complex object to\r\n * divide the current object by.\r\n * @returns {JXG.Complex} Reference to this complex number\r\n */\r\n div: function (c) {\r\n var denom, im, re;\r\n\r\n if (Type.isNumber(c)) {\r\n if (Math.abs(c) < Math.eps) {\r\n this.real = Infinity;\r\n this.imaginary = Infinity;\r\n\r\n return this;\r\n }\r\n\r\n this.real /= c;\r\n this.imaginary /= c;\r\n } else {\r\n // (a+ib)(x+iy) = ax-by + i(xb+ay)\r\n if ((Math.abs(c.real) < Math.eps) && (Math.abs(c.imaginary) < Math.eps)) {\r\n this.real = Infinity;\r\n this.imaginary = Infinity;\r\n\r\n return this;\r\n }\r\n\r\n denom = c.real * c.real + c.imaginary * c.imaginary;\r\n\r\n re = this.real;\r\n im = this.imaginary;\r\n this.real = (re * c.real + im * c.imaginary) / denom;\r\n this.imaginary = (im * c.real - re * c.imaginary) / denom;\r\n }\r\n\r\n return this;\r\n },\r\n\r\n /**\r\n * Conjugate a complex number in place.\r\n * @returns {JXG.Complex} Reference to this complex number\r\n */\r\n conj: function () {\r\n this.imaginary *= -1;\r\n\r\n return this;\r\n }\r\n });\r\n\r\n /**\r\n * @description\r\n * JXG.C is the complex number (name)space. It provides functions to calculate with\r\n * complex numbers (defined in {@link JXG.Complex}). With this namespace you don't have to modify\r\n * your existing complex numbers, e.g. to add two complex numbers:\r\n * <pre class=\"code\"> var z1 = new JXG.Complex(1, 0);\r\n * var z2 = new JXG.Complex(0, 1);\r\n * z = JXG.C.add(z1, z1);</pre>\r\n * z1 and z2 here remain unmodified. With the object oriented approach above this\r\n * section the code would look like:\r\n * <pre class=\"code\"> var z1 = new JXG.Complex(1, 0);\r\n * var z2 = new JXG.Complex(0, 1);\r\n * var z = new JXG.Complex(z1);\r\n * z.add(z2);</pre>\r\n * @namespace Namespace for the complex number arithmetic functions.\r\n */\r\n JXG.C = {};\r\n\r\n /**\r\n * Add two (complex) numbers z1 and z2 and return the result as a (complex) number.\r\n * @param {JXG.Complex,Number} z1 Summand\r\n * @param {JXG.Complex,Number} z2 Summand\r\n * @returns {JXG.Complex} A complex number equal to the sum of the given parameters.\r\n */\r\n JXG.C.add = function (z1, z2) {\r\n var z = new JXG.Complex(z1);\r\n z.add(z2);\r\n return z;\r\n };\r\n\r\n /**\r\n * Subtract two (complex) numbers z1 and z2 and return the result as a (complex) number.\r\n * @param {JXG.Complex,Number} z1 Minuend\r\n * @param {JXG.Complex,Number} z2 Subtrahend\r\n * @returns {JXG.Complex} A complex number equal to the difference of the given parameters.\r\n */\r\n JXG.C.sub = function (z1, z2) {\r\n var z = new JXG.Complex(z1);\r\n z.sub(z2);\r\n return z;\r\n };\r\n\r\n /**\r\n * Multiply two (complex) numbers z1 and z2 and return the result as a (complex) number.\r\n * @param {JXG.Complex,Number} z1 Factor\r\n * @param {JXG.Complex,Number} z2 Factor\r\n * @returns {JXG.Complex} A complex number equal to the product of the given parameters.\r\n */\r\n JXG.C.mult = function (z1, z2) {\r\n var z = new JXG.Complex(z1);\r\n z.mult(z2);\r\n return z;\r\n };\r\n\r\n /**\r\n * Divide two (complex) numbers z1 and z2 and return the result as a (complex) number.\r\n * @param {JXG.Complex,Number} z1 Dividend\r\n * @param {JXG.Complex,Number} z2 Divisor\r\n * @returns {JXG.Complex} A complex number equal to the quotient of the given parameters.\r\n */\r\n JXG.C.div = function (z1, z2) {\r\n var z = new JXG.Complex(z1);\r\n z.div(z2);\r\n return z;\r\n };\r\n\r\n /**\r\n * Conjugate a complex number and return the result.\r\n * @param {JXG.Complex,Number} z1 Complex number\r\n * @returns {JXG.Complex} A complex number equal to the conjugate of the given parameter.\r\n */\r\n JXG.C.conj = function (z1) {\r\n var z = new JXG.Complex(z1);\r\n z.conj();\r\n return z;\r\n };\r\n\r\n /**\r\n * Absolute value of a complex number.\r\n * @param {JXG.Complex,Number} z1 Complex number\r\n * @returns {Number} real number equal to the absolute value of the given parameter.\r\n */\r\n JXG.C.abs = function (z1) {\r\n var z = new JXG.Complex(z1);\r\n\r\n z.conj();\r\n z.mult(z1);\r\n\r\n return Math.sqrt(z.real);\r\n };\r\n\r\n JXG.Complex.C = JXG.C;\r\n\r\n return JXG.Complex;\r\n});\r\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Andreas Walter,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n/*global JXG: true, define: true*/\n\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n jxg\n utils/type\n math/math\n */\n\n/**\n * Functions for color conversions. This was originally based on a class to parse color values by\n * Stoyan Stefanov <sstoo@gmail.com> (see http://www.phpied.com/rgb-color-parser-in-javascript/)\n */\n\ndefine('utils/color',['jxg', 'utils/type', 'math/math'],\n function (JXG, Type, Mat) {\n\n \"use strict\";\n\n // private constants and helper functions\n\n // simple colors contains string color constants that can be used in various browser\n // in javascript\n var simpleColors = {\n aliceblue: 'f0f8ff',\n antiquewhite: 'faebd7',\n aqua: '00ffff',\n aquamarine: '7fffd4',\n azure: 'f0ffff',\n beige: 'f5f5dc',\n bisque: 'ffe4c4',\n black: '000000',\n blanchedalmond: 'ffebcd',\n blue: '0000ff',\n blueviolet: '8a2be2',\n brown: 'a52a2a',\n burlywood: 'deb887',\n cadetblue: '5f9ea0',\n chartreuse: '7fff00',\n chocolate: 'd2691e',\n coral: 'ff7f50',\n cornflowerblue: '6495ed',\n cornsilk: 'fff8dc',\n crimson: 'dc143c',\n cyan: '00ffff',\n darkblue: '00008b',\n darkcyan: '008b8b',\n darkgoldenrod: 'b8860b',\n darkgray: 'a9a9a9',\n darkgreen: '006400',\n darkkhaki: 'bdb76b',\n darkmagenta: '8b008b',\n darkolivegreen: '556b2f',\n darkorange: 'ff8c00',\n darkorchid: '9932cc',\n darkred: '8b0000',\n darksalmon: 'e9967a',\n darkseagreen: '8fbc8f',\n darkslateblue: '483d8b',\n darkslategray: '2f4f4f',\n darkturquoise: '00ced1',\n darkviolet: '9400d3',\n deeppink: 'ff1493',\n deepskyblue: '00bfff',\n dimgray: '696969',\n dodgerblue: '1e90ff',\n feldspar: 'd19275',\n firebrick: 'b22222',\n floralwhite: 'fffaf0',\n forestgreen: '228b22',\n fuchsia: 'ff00ff',\n gainsboro: 'dcdcdc',\n ghostwhite: 'f8f8ff',\n gold: 'ffd700',\n goldenrod: 'daa520',\n gray: '808080',\n green: '008000',\n greenyellow: 'adff2f',\n honeydew: 'f0fff0',\n hotpink: 'ff69b4',\n indianred: 'cd5c5c',\n indigo: '4b0082',\n ivory: 'fffff0',\n khaki: 'f0e68c',\n lavender: 'e6e6fa',\n lavenderblush: 'fff0f5',\n lawngreen: '7cfc00',\n lemonchiffon: 'fffacd',\n lightblue: 'add8e6',\n lightcoral: 'f08080',\n lightcyan: 'e0ffff',\n lightgoldenrodyellow: 'fafad2',\n lightgrey: 'd3d3d3',\n lightgreen: '90ee90',\n lightpink: 'ffb6c1',\n lightsalmon: 'ffa07a',\n lightseagreen: '20b2aa',\n lightskyblue: '87cefa',\n lightslateblue: '8470ff',\n lightslategray: '778899',\n lightsteelblue: 'b0c4de',\n lightyellow: 'ffffe0',\n lime: '00ff00',\n limegreen: '32cd32',\n linen: 'faf0e6',\n magenta: 'ff00ff',\n maroon: '800000',\n mediumaquamarine: '66cdaa',\n mediumblue: '0000cd',\n mediumorchid: 'ba55d3',\n mediumpurple: '9370d8',\n mediumseagreen: '3cb371',\n mediumslateblue: '7b68ee',\n mediumspringgreen: '00fa9a',\n mediumturquoise: '48d1cc',\n mediumvioletred: 'c71585',\n midnightblue: '191970',\n mintcream: 'f5fffa',\n mistyrose: 'ffe4e1',\n moccasin: 'ffe4b5',\n navajowhite: 'ffdead',\n navy: '000080',\n oldlace: 'fdf5e6',\n olive: '808000',\n olivedrab: '6b8e23',\n orange: 'ffa500',\n orangered: 'ff4500',\n orchid: 'da70d6',\n palegoldenrod: 'eee8aa',\n palegreen: '98fb98',\n paleturquoise: 'afeeee',\n palevioletred: 'd87093',\n papayawhip: 'ffefd5',\n peachpuff: 'ffdab9',\n peru: 'cd853f',\n pink: 'ffc0cb',\n plum: 'dda0dd',\n powderblue: 'b0e0e6',\n purple: '800080',\n red: 'ff0000',\n rosybrown: 'bc8f8f',\n royalblue: '4169e1',\n saddlebrown: '8b4513',\n salmon: 'fa8072',\n sandybrown: 'f4a460',\n seagreen: '2e8b57',\n seashell: 'fff5ee',\n sienna: 'a0522d',\n silver: 'c0c0c0',\n skyblue: '87ceeb',\n slateblue: '6a5acd',\n slategray: '708090',\n snow: 'fffafa',\n springgreen: '00ff7f',\n steelblue: '4682b4',\n tan: 'd2b48c',\n teal: '008080',\n thistle: 'd8bfd8',\n tomato: 'ff6347',\n turquoise: '40e0d0',\n violet: 'ee82ee',\n violetred: 'd02090',\n wheat: 'f5deb3',\n white: 'ffffff',\n whitesmoke: 'f5f5f5',\n yellow: 'ffff00',\n yellowgreen: '9acd32'\n },\n\n // array of color definition objects\n colorDefs = [{\n re: /^\\s*rgba\\(\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*,\\s*([\\d.]{1,3})\\s*\\)\\s*$/,\n example: ['rgba(123, 234, 45, 0.5)', 'rgba(255,234,245,1.0)'],\n process: function (bits) {\n return [\n parseInt(bits[1], 10),\n parseInt(bits[2], 10),\n parseInt(bits[3], 10)\n ];\n }\n }, {\n re: /^\\s*rgb\\(\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*\\)\\s*$/,\n example: ['rgb(123, 234, 45)', 'rgb(255,234,245)'],\n process: function (bits) {\n return [\n parseInt(bits[1], 10),\n parseInt(bits[2], 10),\n parseInt(bits[3], 10)\n ];\n }\n }, {\n re: /^(\\w{2})(\\w{2})(\\w{2})$/,\n example: ['#00ff00', '336699'],\n process: function (bits) {\n return [\n parseInt(bits[1], 16),\n parseInt(bits[2], 16),\n parseInt(bits[3], 16)\n ];\n }\n }, {\n re: /^(\\w{1})(\\w{1})(\\w{1})$/,\n example: ['#fb0', 'f0f'],\n process: function (bits) {\n return [\n parseInt(bits[1] + bits[1], 16),\n parseInt(bits[2] + bits[2], 16),\n parseInt(bits[3] + bits[3], 16)\n ];\n }\n }];\n\n /**\n * Converts a valid HTML/CSS color string into a rgb value array. This is the base\n * function for the following wrapper functions which only adjust the output to\n * different flavors like an object, string or hex values.\n * @param {String,Array,Number} color A valid HTML or CSS styled color value, e.g. '#12ab21', '#abc', 'black',\n * or 'rgb(12, 132, 233)'. This can also be an array containing three color values either from 0.0 to 1.0 or\n * from 0 to 255. They will be interpreted as red, green, and blue values. In case this is a number this method\n * expects the parameters ag and ab.\n * @param {Number} ag\n * @param {Number} ab\n * @returns {Array} RGB color values as an array [r, g, b] with values ranging from 0 to 255.\n */\n JXG.rgbParser = function (color, ag, ab) {\n var color_string, channels, re, processor, bits, i,\n r, g, b,\n values = color,\n testFloat;\n\n if (!Type.exists(color)) {\n return [];\n }\n\n if (Type.exists(ag) && Type.exists(ab)) {\n values = [color, ag, ab];\n }\n\n color_string = values;\n\n testFloat = false;\n if (Type.isArray(color_string)) {\n for (i = 0; i < 3; i++) {\n testFloat = testFloat || /\\./.test(values[i].toString());\n }\n\n for (i = 0; i < 3; i++) {\n testFloat = testFloat && (values[i] >= 0.0) && (values[i] <= 1.0);\n }\n\n if (testFloat) {\n return [Math.ceil(values[0] * 255), Math.ceil(values[1] * 255), Math.ceil(values[2] * 255)];\n }\n\n return values;\n }\n\n if (typeof values === 'string') {\n color_string = values;\n }\n\n // strip any leading #\n if (color_string.charAt(0) === '#') { // remove # if any\n color_string = color_string.substr(1, 6);\n }\n\n color_string = color_string.replace(/ /g, '').toLowerCase();\n\n // before getting into regexps, try simple matches\n // and overwrite the input\n color_string = simpleColors[color_string] || color_string;\n\n // search through the colorDefs definitions to find a match\n for (i = 0; i < colorDefs.length; i++) {\n re = colorDefs[i].re;\n processor = colorDefs[i].process;\n bits = re.exec(color_string);\n\n if (bits) {\n channels = processor(bits);\n r = channels[0];\n g = channels[1];\n b = channels[2];\n }\n\n }\n\n if (isNaN(r) || isNaN(g) || isNaN(b)) {\n return [];\n }\n\n // validate/cleanup values\n r = (r < 0 || isNaN(r)) ? 0 : ((r > 255) ? 255 : r);\n g = (g < 0 || isNaN(g)) ? 0 : ((g > 255) ? 255 : g);\n b = (b < 0 || isNaN(b)) ? 0 : ((b > 255) ? 255 : b);\n\n return [r, g, b];\n };\n\n /**\n * Converts a valid HTML/CSS color string into a string of the 'rgb(r, g, b)' format.\n * @param {String,Array,Number} color A valid HTML or CSS styled color value, e.g. '#12ab21', '#abc', 'black',\n * or 'rgb(12, 132, 233)'. This can also be an array containing three color values either from 0.0 to 1.0 or\n * from 0 to 255. They will be interpreted as red, green, and blue values. In case this is a number this method\n * expects the parameters ag and ab.\n * @param {Number} ag\n * @param {Number} ab\n * @returns {String} A 'rgb(r, g, b)' formatted string\n */\n JXG.rgb2css = function (color, ag, ab) {\n var r;\n\n r = JXG.rgbParser(color, ag, ab);\n\n return 'rgb(' + r[0] + ', ' + r[1] + ', ' + r[2] + ')';\n };\n\n /**\n * Converts a valid HTML/CSS color string into a HTML rgb string.\n * @param {String,Array,Number} color A valid HTML or CSS styled color value, e.g. '#12ab21', '#abc', 'black',\n * or 'rgb(12, 132, 233)'. This can also be an array containing three color values either from 0.0 to 1.0 or\n * from 0 to 255. They will be interpreted as red, green, and blue values. In case this is a number this method\n * expects the parameters ag and ab.\n * @param {Number} ag\n * @param {Number} ab\n * @returns {String} A '#rrggbb' formatted string\n */\n JXG.rgb2hex = function (color, ag, ab) {\n var r, g, b;\n\n r = JXG.rgbParser(color, ag, ab);\n g = r[1];\n b = r[2];\n r = r[0];\n r = r.toString(16);\n g = g.toString(16);\n b = b.toString(16);\n\n if (r.length === 1) {\n r = '0' + r;\n }\n\n if (g.length === 1) {\n g = '0' + g;\n }\n\n if (b.length === 1) {\n b = '0' + b;\n }\n\n return '#' + r + g + b;\n };\n\n /**\n * Converts a valid HTML/CSS color string from the '#rrggbb' format into the 'rgb(r, g, b)' format.\n * @param {String} hex A valid HTML or CSS styled color value, e.g. '#12ab21', '#abc', or 'black'\n * @deprecated Use {@link JXG#rgb2css} instead.\n * @returns {String} A 'rgb(r, g, b)' formatted string\n */\n JXG.hex2rgb = function (hex) {\n JXG.deprecated('JXG.hex2rgb()', 'JXG.rgb2css()');\n return JXG.rgb2css(hex);\n };\n\n /**\n * Converts HSV color to RGB color.\n * Based on C Code in \"Computer Graphics -- Principles and Practice,\"\n * Foley et al, 1996, p. 593.\n * See also http://www.efg2.com/Lab/Graphics/Colors/HSV.htm\n * @param {Number} H value between 0 and 360\n * @param {Number} S value between 0.0 (shade of gray) to 1.0 (pure color)\n * @param {Number} V value between 0.0 (black) to 1.0 (white)\n * @returns {String} RGB color string\n */\n JXG.hsv2rgb = function (H, S, V) {\n var R, G, B, f, i, hTemp, p, q, t;\n\n H = ((H % 360.0) + 360.0) % 360;\n\n if (S === 0) {\n if (isNaN(H) || H < Mat.eps) {\n R = V;\n G = V;\n B = V;\n } else {\n return '#ffffff';\n }\n } else {\n if (H >= 360) {\n hTemp = 0.0;\n } else {\n hTemp = H;\n }\n\n // h is now IN [0,6)\n hTemp = hTemp / 60;\n // largest integer <= h\n i = Math.floor(hTemp);\n // fractional part of h\n f = hTemp - i;\n p = V * (1.0 - S);\n q = V * (1.0 - (S * f));\n t = V * (1.0 - (S * (1.0 - f)));\n\n switch (i) {\n case 0:\n R = V;\n G = t;\n B = p;\n break;\n case 1:\n R = q;\n G = V;\n B = p;\n break;\n case 2:\n R = p;\n G = V;\n B = t;\n break;\n case 3:\n R = p;\n G = q;\n B = V;\n break;\n case 4:\n R = t;\n G = p;\n B = V;\n break;\n case 5:\n R = V;\n G = p;\n B = q;\n break;\n }\n }\n\n R = Math.round(R * 255).toString(16);\n R = (R.length === 2) ? R : ((R.length === 1) ? '0' + R : '00');\n G = Math.round(G * 255).toString(16);\n G = (G.length === 2) ? G : ((G.length === 1) ? '0' + G : '00');\n B = Math.round(B * 255).toString(16);\n B = (B.length === 2) ? B : ((B.length === 1) ? '0' + B : '00');\n\n return ['#', R, G, B].join('');\n };\n\n /**\n * Converts a color from the RGB color space into the HSV space. Input can be any valid HTML/CSS color definition.\n * @param {String,Array,Number} color A valid HTML or CSS styled color value, e.g. '#12ab21', '#abc', 'black',\n * or 'rgb(12, 132, 233)'. This can also be an array containing three color values either from 0.0 to 1.0 or\n * from 0 to 255. They will be interpreted as red, green, and blue values. In case this is a number this method\n * expects the parameters ag and ab.\n * @param {Number} ag\n * @param {Number} ab\n * @returns {Array} Contains the h, s, and v value in this order.\n * @see http://zach.in.tu-clausthal.de/teaching/cg1_0708/folien/13_color_3_4up.pdf\n */\n JXG.rgb2hsv = function (color, ag, ab) {\n var r, g, b, fr, fg, fb, fmax, fmin, h, s, v, max, min;\n\n r = JXG.rgbParser(color, ag, ab);\n\n g = r[1];\n b = r[2];\n r = r[0];\n fr = r / 255.0;\n fg = g / 255.0;\n fb = b / 255.0;\n max = Math.max(r, g, b);\n min = Math.min(r, g, b);\n fmax = max / 255.0;\n fmin = min / 255.0;\n\n v = fmax;\n s = 0.0;\n\n if (v > 0) {\n s = (v - fmin) / v;\n }\n\n h = 1.0 / (fmax - fmin);\n\n if (s > 0) {\n if (max === r) {\n h = (fg - fb) * h;\n } else if (max === g) {\n h = 2 + (fb - fr) * h;\n } else {\n h = 4 + (fr - fg) * h;\n }\n }\n\n h *= 60;\n\n if (h < 0) {\n h += 360;\n }\n\n if (max === min) {\n h = 0.0;\n }\n\n return [h, s, v];\n };\n\n /**\n * Converts a color from the RGB color space into the LMS space. Input can be any valid HTML/CSS color definition.\n * @param {String,Array,Number} color A valid HTML or CSS styled color value, e.g. '#12ab21', '#abc', 'black',\n * or 'rgb(12, 132, 233)'. This can also be an array containing three color values either from 0.0 to 1.0 or\n * from 0 to 255. They will be interpreted as red, green, and blue values. In case this is a number this method\n * expects the parameters ag and ab.\n * @param {Number} ag\n * @param {Number} ab\n * @returns {Array} Contains the l, m, and s value in this order.\n */\n JXG.rgb2LMS = function (color, ag, ab) {\n var r, g, b, l, m, s, ret,\n // constants\n matrix = [[0.05059983, 0.08585369, 0.00952420],\n [0.01893033, 0.08925308, 0.01370054],\n [0.00292202, 0.00975732, 0.07145979]];\n\n r = JXG.rgbParser(color, ag, ab);\n g = r[1];\n b = r[2];\n r = r[0];\n\n // de-gamma\n // Maybe this can be made faster by using a cache\n r = Math.pow(r, 0.476190476);\n g = Math.pow(g, 0.476190476);\n b = Math.pow(b, 0.476190476);\n\n l = r * matrix[0][0] + g * matrix[0][1] + b * matrix[0][2];\n m = r * matrix[1][0] + g * matrix[1][1] + b * matrix[1][2];\n s = r * matrix[2][0] + g * matrix[2][1] + b * matrix[2][2];\n\n ret = [l, m, s];\n ret.l = l;\n ret.m = m;\n ret.s = s;\n\n return ret;\n };\n\n /**\n * Convert color information from LMS to RGB color space.\n * @param {Number} l\n * @param {Number} m\n * @param {Number} s\n * @returns {Array} Contains the r, g, and b value in this order.\n */\n JXG.LMS2rgb = function (l, m, s) {\n var r, g, b, ret,\n // constants\n matrix = [[30.830854, -29.832659, 1.610474],\n [-6.481468, 17.715578, -2.532642],\n [-0.375690, -1.199062, 14.273846]],\n\n // re-gamma, inspired by GIMP modules/display-filter-color-blind.c:\n // Copyright (C) 2002-2003 Michael Natterer <mitch@gimp.org>,\n // Sven Neumann <sven@gimp.org>,\n // Robert Dougherty <bob@vischeck.com> and\n // Alex Wade <alex@vischeck.com>\n // This code is an implementation of an algorithm described by Hans Brettel,\n // Francoise Vienot and John Mollon in the Journal of the Optical Society of\n // America V14(10), pg 2647. (See http://vischeck.com/ for more info.)\n lut_lookup = function (value) {\n var offset = 127, step = 64;\n\n while (step > 0) {\n if (Math.pow(offset, 0.476190476) > value) {\n offset -= step;\n } else {\n if (Math.pow(offset + 1, 0.476190476) > value) {\n return offset;\n }\n\n offset += step;\n }\n\n step /= 2;\n }\n\n /* the algorithm above can't reach 255 */\n if (offset === 254 && 13.994955247 < value) {\n return 255;\n }\n\n return offset;\n };\n\n // transform back to rgb\n r = l * matrix[0][0] + m * matrix[0][1] + s * matrix[0][2];\n g = l * matrix[1][0] + m * matrix[1][1] + s * matrix[1][2];\n b = l * matrix[2][0] + m * matrix[2][1] + s * matrix[2][2];\n\n r = lut_lookup(r);\n g = lut_lookup(g);\n b = lut_lookup(b);\n\n ret = [r, g, b];\n ret.r = r;\n ret.g = g;\n ret.b = b;\n\n return ret;\n };\n\n /**\n * Splits a RGBA color value like #112233AA into it's RGB and opacity parts.\n * @param {String} rgba A RGBA color value\n * @returns {Array} An array containing the rgb color value in the first and the opacity in the second field.\n */\n JXG.rgba2rgbo = function (rgba) {\n var opacity;\n\n if (rgba.length === 9 && rgba.charAt(0) === '#') {\n opacity = parseInt(rgba.substr(7, 2).toUpperCase(), 16) / 255;\n rgba = rgba.substr(0, 7);\n } else {\n opacity = 1;\n }\n\n return [rgba, opacity];\n };\n\n /**\n * Generates a RGBA color value like #112233AA from it's RGB and opacity parts.\n * @param {String} rgb A RGB color value.\n * @param {Number} o The desired opacity >=0, <=1.\n * @returns {String} The RGBA color value.\n */\n JXG.rgbo2rgba = function (rgb, o) {\n var rgba;\n\n if (rgb === 'none') {\n return rgb;\n }\n\n rgba = Math.round(o * 255).toString(16);\n if (rgba.length === 1) {\n rgba = \"0\" + rgba;\n }\n\n return rgb + rgba;\n };\n\n /**\n * Decolorizes the given color.\n * @param {String} color HTML string containing the HTML color code.\n * @returns {String} Returns a HTML color string\n */\n JXG.rgb2bw = function (color) {\n var x, tmp, arr,\n HexChars = \"0123456789ABCDEF\";\n\n if (color === 'none') {\n return color;\n }\n\n arr = JXG.rgbParser(color);\n x = Math.floor(0.3 * arr[0] + 0.59 * arr[1] + 0.11 * arr[2]);\n\n // rgbParser and Math.floor ensure that x is 0 <= x <= 255.\n // Bitwise operators can be used.\n /*jslint bitwise: true*/\n tmp = HexChars.charAt((x >> 4) & 0xf) + HexChars.charAt(x & 0xf);\n\n color = \"#\" + tmp + tmp + tmp;\n\n return color;\n };\n\n /**\n * Converts a color into how a colorblind human approximately would see it.\n * @param {String} color HTML string containing the HTML color code.\n * @param {String} deficiency The type of color blindness. Possible\n * options are <i>protanopia</i>, <i>deuteranopia</i>, and <i>tritanopia</i>.\n * @returns {String} Returns a HTML color string\n */\n JXG.rgb2cb = function (color, deficiency) {\n var rgb, l, m, s, lms, tmp,\n a1, b1, c1, a2, b2, c2,\n inflection,\n HexChars = \"0123456789ABCDEF\";\n\n if (color === 'none') {\n return color;\n }\n\n lms = JXG.rgb2LMS(color);\n l = lms[0];\n m = lms[1];\n s = lms[2];\n\n deficiency = deficiency.toLowerCase();\n\n switch (deficiency) {\n case \"protanopia\":\n a1 = -0.06150039994295001;\n b1 = 0.08277001656812001;\n c1 = -0.013200141220000003;\n a2 = 0.05858939668799999;\n b2 = -0.07934519995360001;\n c2 = 0.013289415272000003;\n inflection = 0.6903216543277437;\n\n tmp = s / m;\n\n if (tmp < inflection) {\n l = -(b1 * m + c1 * s) / a1;\n } else {\n l = -(b2 * m + c2 * s) / a2;\n }\n break;\n case \"tritanopia\":\n a1 = -0.00058973116217;\n b1 = 0.007690316482;\n c1 = -0.01011703519052;\n a2 = 0.025495080838999994;\n b2 = -0.0422740347;\n c2 = 0.017005316784;\n inflection = 0.8349489908460004;\n\n tmp = m / l;\n\n if (tmp < inflection) {\n s = -(a1 * l + b1 * m) / c1;\n } else {\n s = -(a2 * l + b2 * m) / c2;\n }\n break;\n default:\n a1 = -0.06150039994295001;\n b1 = 0.08277001656812001;\n c1 = -0.013200141220000003;\n a2 = 0.05858939668799999;\n b2 = -0.07934519995360001;\n c2 = 0.013289415272000003;\n inflection = 0.5763833686400911;\n\n tmp = s / l;\n\n if (tmp < inflection) {\n m = -(a1 * l + c1 * s) / b1;\n } else {\n m = -(a2 * l + c2 * s) / b2;\n }\n break;\n }\n\n rgb = JXG.LMS2rgb(l, m, s);\n\n // LMS2rgb returns an array of values ranging from 0 to 255 (both included)\n // bitwise operators are safe to use.\n /*jslint bitwise: true*/\n tmp = HexChars.charAt((rgb[0] >> 4) & 0xf) + HexChars.charAt(rgb[0] & 0xf);\n color = \"#\" + tmp;\n tmp = HexChars.charAt((rgb[1] >> 4) & 0xf) + HexChars.charAt(rgb[1] & 0xf);\n color += tmp;\n tmp = HexChars.charAt((rgb[2] >> 4) & 0xf) + HexChars.charAt(rgb[2] & 0xf);\n color += tmp;\n\n return color;\n };\n\n /**\n * Determines highlight color to a given color. Done by reducing (or increasing) the opacity.\n * @param {String} color HTML RGBA string containing the HTML color code.\n * @returns {String} Returns a HTML RGBA color string\n */\n JXG.autoHighlight = function (colstr) {\n var col = JXG.rgba2rgbo(colstr),\n c = col[0],\n opa = col[1];\n\n if (colstr.charAt(0) === '#') {\n if (opa < 0.3) {\n opa *= 1.8;\n } else {\n opa *= 0.4;\n }\n\n return JXG.rgbo2rgba(c, opa);\n }\n\n return colstr;\n };\n\n /**\n * Calculate whether a light or a dark color is needed as a contrast.\n * Especially useful to determine whether white or black font goes\n * better with a given background color.\n * @param {String} hexColor HEX value of color.\n * @param {String} [darkColor=\"#000000\"] HEX string for a dark color.\n * @param {String} [lightColor=\"#ffffff\"] HEX string for a light color.\n * @param {Number} [threshold=8]\n * @returns {String} Returns darkColor or lightColor.\n */\n JXG.contrast = function (hexColor, darkColor, lightColor, threshold) {\n var rgb,\n black = '#000000',\n rgbBlack,\n l1, l2,\n contrastRatio;\n\n darkColor = darkColor || '#000000';\n lightColor = lightColor || '#ffffff';\n threshold = threshold || 7;\n\n // hexColor RGB\n rgb = JXG.rgbParser(hexColor);\n\n // Black RGB\n rgbBlack = JXG.rgbParser(black);\n\n // Calc contrast ratio\n l1 = 0.2126 * Math.pow(rgb[0] / 255, 2.2) +\n 0.7152 * Math.pow(rgb[1] / 255, 2.2) +\n 0.0722 * Math.pow(rgb[2] / 255, 2.2);\n\n l2 = 0.2126 * Math.pow(rgbBlack[0] / 255, 2.2) +\n 0.7152 * Math.pow(rgbBlack[1] / 255, 2.2) +\n 0.0722 * Math.pow(rgbBlack[2] / 255, 2.2);\n\n if (l1 > l2) {\n contrastRatio = Math.floor((l1 + 0.05) / (l2 + 0.05));\n } else {\n contrastRatio = Math.floor((l2 + 0.05) / (l1 + 0.05));\n }\n contrastRatio = contrastRatio - 1;\n\n // If contrast is more than threshold, return darkColor\n if (contrastRatio > threshold) {\n return darkColor;\n }\n // if not, return lightColor.\n return lightColor;\n };\n\n /**\n * Use the color scheme of JSXGraph up to version 1.3.2.\n * This method has to be called before JXG.JSXGraph.initBoard();\n *\n * @see JXG.palette\n * @see JXG.paletteWong\n *\n * @example\n *\n * JXG.setClassicColors();\n * var board = JXG.JSXGraph.initBoard('jxgbox', {boundingbox: [-5, 5, 5,-5]});\n *\n */\n JXG.setClassicColors = function() {\n JXG.Options.elements.strokeColor = 'blue';\n JXG.Options.elements.fillColor = 'red';\n JXG.Options.hatch.strokeColor = 'blue';\n JXG.Options.angle.fillColor = '#ff7f00';\n JXG.Options.angle.highlightFillColor = '#ff7f00';\n JXG.Options.angle.strokeColor = '#ff7f00';\n JXG.Options.angle.label.strokeColor = 'blue';\n JXG.Options.arc.strokeColor = 'blue';\n JXG.Options.circle.center.fillColor = 'red';\n JXG.Options.circle.center.strokeColor = 'blue';\n JXG.Options.circumcircle.strokeColor = 'blue';\n JXG.Options.circumcircle.center.fillColor = 'red';\n JXG.Options.circumcircle.center.strokeColor = 'blue';\n JXG.Options.circumcirclearc.strokeColor = 'blue';\n JXG.Options.circumcirclesector.strokeColor = 'blue';\n JXG.Options.circumcirclesector.fillColor = 'green';\n JXG.Options.circumcirclesector.highlightFillColor = 'green';\n JXG.Options.conic.strokeColor = 'blue';\n JXG.Options.curve.strokeColor = 'blue';\n JXG.Options.incircle.strokeColor = 'blue';\n JXG.Options.incircle.center.fillColor = 'red';\n JXG.Options.incircle.center.strokeColor = 'blue';\n JXG.Options.inequality.fillColor = 'red';\n JXG.Options.integral.fillColor = 'red';\n JXG.Options.integral.curveLeft.color = 'red';\n JXG.Options.integral.curveRight.color = 'red';\n JXG.Options.line.strokeColor = 'blue';\n JXG.Options.point.fillColor = 'red';\n JXG.Options.point.strokeColor = 'red';\n JXG.Options.polygon.fillColor = 'green';\n JXG.Options.polygon.highlightFillColor = 'green';\n JXG.Options.polygon.vertices.strokeColor = 'red';\n JXG.Options.polygon.vertices.fillColor = 'red';\n JXG.Options.regularpolygon.fillColor = 'green';\n JXG.Options.regularpolygon.highlightFillColor = 'green';\n JXG.Options.regularpolygon.vertices.strokeColor = 'red';\n JXG.Options.regularpolygon.vertices.fillColor = 'red';\n JXG.Options.riemannsum.fillColor = 'yellow';\n JXG.Options.sector.fillColor = 'green';\n JXG.Options.sector.highlightFillColor = 'green';\n JXG.Options.semicircle.center.fillColor = 'red';\n JXG.Options.semicircle.center.strokeColor = 'blue';\n JXG.Options.slopetriangle.fillColor = 'red';\n JXG.Options.slopetriangle.highlightFillColor = 'red';\n JXG.Options.turtle.arrow.strokeColor = 'blue';\n };\n\n JXG.extend(JXG, /** @lends JXG */ {\n /**\n * Bang Wong color palette,\n * optimized for various type\n * of color blindness.\n * It contains values for\n * <ul>\n * <li> 'black'\n * <li> 'orange'\n * <li> 'skyblue'\n * <li> 'bluishgreen'\n * <li> 'yellow'\n * <li> 'darkblue'\n * <li> 'vermillion'\n * <li> 'reddishpurple'\n * </ul>\n *\n * As substitutes for standard colors, it contains the following aliases:\n *\n * <ul>\n * <li> black (= #000000)\n * <li> blue (= darkblue)\n * <li> green (= bluishgreen)\n * <li> purple (= reddishpurple)\n * <li> red (= vermillion)\n * <li> white (= #ffffff)\n * </ul>\n *\n * See <a href=\"https://www.nature.com/articles/nmeth.1618\">Bang Wong: \"Points of view: Color blindness\"</a>\n * and\n * <a href=\"https://davidmathlogic.com/colorblind/\">https://davidmathlogic.com/colorblind/</a>.\n *\n * @name JXG.paletteWong\n * @type Object\n * @see JXG.palette\n * @example\n * var p = board.create('line', [[-1, 1], [2, -3]], {strokeColor: JXG.paletteWong.yellow});\n */\n paletteWong: {\n black: '#000000',\n orange: '#E69F00',\n skyblue: '#56B4E9',\n bluishgreen: '#009E73',\n yellow: '#F0E442',\n darkblue: '#0072B2',\n vermillion: '#D55E00',\n reddishpurple: '#CC79A7',\n\n blue: '#0072B2',\n red: '#D55E00', // vermillion\n green: '#009E73', // bluishgreen\n purple: '#CC79A7', // reddishpurple\n white: '#ffffff'\n }\n });\n\n /**\n * Default color palette.\n * Contains at least color values for\n * <ul>\n * <li> black\n * <li> blue\n * <li> green\n * <li> purple\n * <li> red\n * <li> white\n * <li> yellow\n * </ul>\n *\n * @name JXG.palette\n * @type Object\n * @default JXG.paletteWong\n * @see JXG.paletteWong\n *\n * @example\n *\n * var p = board.create('line', [[-1, 1], [2, -3]], {strokeColor: JXG.palette.yellow});\n *\n */\n JXG.palette = JXG.paletteWong;\n\n return JXG;\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG:true, define: true*/\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n jxg\n base/constants\n math/math\n utils/color\n utils/type\n */\n\ndefine('options',[\n 'jxg', 'base/constants', 'math/math', 'utils/color', 'utils/type'\n], function (JXG, Const, Mat, Color, Type) {\n\n \"use strict\";\n\n /**\n * Options Namespace\n * @description These are the default options of the board and of all geometry elements.\n * @namespace\n * @name JXG.Options\n */\n JXG.Options = {\n jc: {\n enabled: true,\n compile: true\n },\n\n /*\n * Options that are used directly within the board class\n */\n board: {\n /**#@+\n * @visprop\n */\n\n //updateType: 'hierarchical', // 'all'\n\n /**\n * Bounding box of the visible area in user coordinates.\n * It is an array consisting of four values:\n * [x<sub>1</sub>, y<sub>1</sub>, x<sub>2</sub>, y<sub>2</sub>]\n *\n * The canvas will be spanned from the upper left corner (<sub>1</sub>, y<sub>1</sub>)\n * to the lower right corner (x<sub>2</sub>, y<sub>2</sub>).\n *\n * @name JXG.Board#boundingbox\n * @type Array\n * @default [-5, 5, 5, -5]\n * @example\n * var board = JXG.JSXGraph.initBoard('jxgbox', {\n * boundingbox: [-5, 5, 5, -5],\n * axis: true\n * });\n */\n boundingBox: [-5, 5, 5, -5],\n\n /**\n * Maximal bounding box of the visible area in user coordinates.\n * It is an array consisting of four values:\n * [x<sub>1</sub>, y<sub>1</sub>, x<sub>2</sub>, y<sub>2</sub>]\n *\n * The bounding box of the canvas must be inside of this maximal\n * boundings box.\n * @name JXG.Board#maxboundingbox\n * @type Array\n * @see JXG.Board#boundingbox\n * @default [-Infinity, Infinity, Infinity, -Infinity]\n *\n * @example\n * var board = JXG.JSXGraph.initBoard('jxgbox', {\n * boundingbox: [-5, 5, 5, -5],\n * maxboundingbox: [-8, 8, 8, -8],\n * pan: {enabled: true},\n * axis: true\n * });\n *\n * </pre><div id=\"JXG065e2750-217c-48ed-a52b-7d7df6de7055\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG065e2750-217c-48ed-a52b-7d7df6de7055', {\n * showcopyright: false, shownavigation: false,\n * boundingbox: [-5,5,5,-5],\n * maxboundingbox: [-8,8,8,-8],\n * pan: {enabled: true},\n * axis:true\n * });\n *\n * })();\n *\n * </script><pre>\n *\n */\n maxBoundingBox: [-Infinity, Infinity, Infinity, -Infinity],\n\n /**\n * Additional zoom factor multiplied to {@link JXG.Board#zoomX} and {@link JXG.Board#zoomY}.\n *\n * @name JXG.Board#zoomFactor\n * @type Number\n * @default 1.0\n */\n zoomFactor: 1,\n\n /**\n * Zoom factor in horizontal direction.\n *\n * @name JXG.Board#zoomX\n * @see JXG.Board#zoomY\n * @type Number\n * @default 1.0\n */\n zoomX: 1,\n\n /**\n * Zoom factor in vertical direction.\n *\n * @name JXG.Board#zoomY\n * @see JXG.Board#zoomX\n * @type Number\n * @default 1.0\n */\n zoomY: 1,\n\n /**\n * Title string for the board.\n * Primarily used in an invisible text element which is adressed by\n * the attribute 'aria-labelledby' from the JSXGraph container.\n * JSXGraph creates a new div-element with id \"{containerid}_ARIAlabel\"\n * containing this string.\n *\n * @name JXG.Board#title\n * @see JXG.Board#description\n * @type String\n * @default ''\n *\n */\n title: '',\n\n /**\n * Description string for the board.\n * Primarily used in an invisible text element which is adressed by\n * the attribute 'aria-describedby' from the JSXGraph container.\n * JSXGraph creates a new div-element with id \"{containerid}_ARIAdescription\"\n * containing this string.\n *\n * @name JXG.Board#description\n * @see JXG.Board#title\n * @type String\n * @default ''\n *\n */\n description: '',\n\n /**\n * Show copyright string in canvas.\n *\n * @name JXG.Board#showCopyright\n * @type Boolean\n * @default true\n */\n showCopyright: true,\n\n /**\n * Show default axis.\n * If shown, the horizontal axis can be accessed via JXG.Board.defaultAxes.x, the\n * vertical axis can be accessed via JXG.Board.defaultAxes.y.\n * Both axes have a sub-element \"defaultTicks\".\n *\n * Value can be Boolean or an object containing axis attributes.\n *\n * @name JXG.Board#axis\n * @type Boolean\n * @default false\n */\n axis: false,\n\n /**\n * Attributes for the default axes in case of the attribute\n * axis:true in {@link JXG.JSXGraph#initBoard}.\n *\n * @name JXG.Board#defaultAxes\n * @type Object\n * @default {x: {name:'x'}, y: {name: 'y'}}\n *\n */\n defaultAxes: {\n x: {\n name: 'x',\n ticks: {\n label: {\n visible: 'inherit',\n anchorX: 'middle',\n anchorY: 'top',\n fontSize: 12,\n offset: [0, -3]\n },\n drawZero: false,\n visible: 'inherit'\n }\n },\n y: {\n name: 'y',\n ticks: {\n label: {\n visible: 'inherit',\n anchorX: 'right',\n anchorY: 'middle',\n fontSize: 12,\n offset: [-6, 0]\n },\n tickEndings: [1, 0],\n drawZero: false,\n visible: 'inherit'\n }\n }\n },\n\n /**\n * Display of navigation arrows and zoom buttons in the navigation bar.\n *\n * @name JXG.Board#showNavigation\n * @type Boolean\n * @default true\n */\n showNavigation: true,\n\n /**\n * Display of zoom buttons in the navigation bar. To show zoom buttons, additionally\n * showNavigation has to be set to true.\n *\n * @name JXG.Board#showZoom\n * @type Boolean\n * @default true\n */\n showZoom: true,\n\n /**\n * Show a button in the navigation bar to force reload of a construction.\n * Works only with the JessieCode tag.\n *\n * @name JXG.Board#showReload\n * @type Boolean\n * @default false\n */\n showReload: false,\n\n /**\n * Show a button in the navigation bar to enable screenshots.\n *\n * @name JXG.Board#showScreenshot\n * @type Boolean\n * @default false\n */\n showScreenshot: false,\n\n /**\n * Attributes to control the screenshot function.\n * The following attributes can be set:\n * <ul>\n * <li>scale: scaling factor (default=1.0)\n * <li>type: format of the screenshot image. Default: png\n * <li>symbol: Unicode symbol which is shown in the navigation bar. Default: '\\u2318'\n * <li>css: CSS rules to format the div element containing the screen shot image\n * <li>cssButton: CSS rules to format the close button of the div element containing the screen shot image\n * </ul>\n *\n * @name JXG.Board#screenshot\n * @type Object\n */\n screenshot: {\n scale: 1.0,\n type: 'png',\n symbol: '\\u2318', //'\\u22b9', //'\\u26f6',\n css: 'background-color:#eeeeee; opacity:1.0; border:2px solid black; border-radius:10px; text-align:center',\n cssButton: 'padding: 4px 10px; border: solid #356AA0 1px; border-radius: 5px; position: absolute; right: 2ex; top: 2ex; background-color: rgba(255, 255, 255, 0.3);'\n },\n\n /**\n * Show a button in the navigation bar to start fullscreen mode.\n *\n * @name JXG.Board#showFullscreen\n * @type Boolean\n * @see JXG.Board#fullscreen\n * @default false\n */\n showFullscreen: false,\n\n /**\n * Attribute(s) to control the fullscreen icon. The attribute \"showFullscreen\"\n * controls if the icon is shown.\n * The following attribute(s) can be set:\n * <ul>\n * <li>symbol (String): Unicode symbol which is shown in the navigation bar. Default: '\\u25a1'\n * <li>id (String): Id of the HTML element which is brought to full screen or null if the JSXgraph div is taken.\n * It may be an outer div element, e.g. if the old aspect ratio trick is used. Default: null, i.e. use the JSXGraph div.\n * </ul>\n *\n * @example\n * var board = JXG.JSXGraph.initBoard('35bec5a2-fd4d-11e8-ab14-901b0e1b8723',\n * {boundingbox: [-8, 8, 8,-8], axis: true,\n * showcopyright: false,\n * showFullscreen: true,\n * fullscreen: {\n * symbol: '\\u22c7'\n * }\n * });\n * var pol = board.create('polygon', [[0, 1], [3,4], [1,-4]], {fillColor: 'yellow'});\n *\n * </pre><div id=\"JXGa35bec5a2-fd4d-11e8-ab14-901b0e1b8723\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXGa35bec5a2-fd4d-11e8-ab14-901b0e1b8723',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false,\n * showFullscreen: true,\n * fullscreen: {\n * symbol: '\\u22c7'\n * }\n * });\n * var pol = board.create('polygon', [[0, 1], [3,4], [1,-4]], {fillColor: 'yellow'});\n * })();\n *\n * </script><pre>\n *\n * @name JXG.Board#fullscreen\n * @see JXG.Board#showFullscreen\n * @type Object\n */\n fullscreen: {\n symbol: '\\u25a1', // '\\u26f6' (not supported by MacOS), // '\\u25a1'\n id: null\n },\n\n /**\n * Show a button which allows to clear all traces of a board.\n *\n * @name JXG.Board#showClearTraces\n * @type Boolean\n * @default false\n */\n showClearTraces: false,\n\n /**\n * If set to true the bounding box might be changed such that\n * the ratio of width and height of the hosting HTML div is equal\n * to the ratio of width and height of the bounding box.\n *\n * This is necessary if circles should look like circles and not\n * like ellipses. It is recommended to set keepAspectRatio = true\n * for geometric applets. For function plotting keepAspectRatio = false\n * might be the better choice.\n *\n * @name JXG.Board#keepAspectRatio\n * @see JXG.Board#boundingbox\n * @see JXG.Board#setBoundingBox\n * @type Boolean\n * @default false\n */\n keepAspectRatio: false,\n\n /**\n * If set true and\n * hasPoint() is true for both an element and it's label,\n * the element (and not the label) is taken as drag element.\n *\n * If set false and hasPoint() is true for both an element and it's label,\n * the label is taken (if it is on a higher layer than the element)\n *\n * @name JXG.Board#ignoreLabels\n * @type Booelan\n * @default true\n */\n ignoreLabels: true,\n\n /**\n * Maximum number of digits in automatic label generation.\n * For example, if set to 1 automatic point labels end at \"Z\".\n * If set to 2, point labels end at \"ZZ\".\n *\n * @name JXG.Board#maxNameLength\n * @see JXG.Board#generateName\n * @type Number\n * @default 1\n */\n maxNameLength: 1,\n\n /**\n * Supply the document object. Defaults to window.document\n *\n * @name JXG.Board#document\n * @type DOM object\n * @default false (meaning window.document)\n */\n document: false,\n\n /**\n * If true the first element of the set JXG.board.objects having hasPoint==true is taken as drag element.\n *\n * @name JXG.Board#takeFirst\n * @type Boolean\n * @default false\n */\n takeFirst: false,\n\n /**\n * If true, when read from a file or string - the size of the div can be changed by the construction text.\n *\n * @name JXG.Board#takeSizeFromFile\n * @type Boolean\n * @default false\n */\n takeSizeFromFile: false,\n\n /**\n * Default rendering engine. Possible values are 'svg', 'canvas', 'vml', 'no', or 'auto'.\n * If the rendering engine is not available JSXGraph tries to detect a different engine.\n *\n * <p>\n * In case of 'canvas' it is advisable to call 'board.update()' after all elements have been\n * constructed. This ensures that all elements are drawn with their intended visual appearance.\n *\n * @name JXG.Board#renderer\n * @type String\n * @default 'auto'\n */\n renderer: 'auto',\n\n /**\n * Time (in msec) between two animation steps. Used in\n * {@link JXG.CoordsElement#moveAlong}, {@link JXG.CoordsElement#moveTo} and\n * {@link JXG.CoordsElement#visit}.\n *\n * @name JXG.Board#animationDelay\n * @type Number\n * @default 35\n * @see JXG.CoordsElement#moveAlong\n * @see JXG.CoordsElement#moveTo\n * @see JXG.CoordsElement#visit\n */\n animationDelay: 35,\n\n /**\n * Maximum frame rate of the board, i.e. maximum number of updates per second\n * triggered by move events.\n *\n * @name JXG.Board#maxFrameRate\n * @type Number\n * @default 40\n */\n maxFrameRate: 40,\n\n /**\n * Allow user interaction by registering mouse, pointer and touch events.\n *\n * @name JXG.Board#registerEvents\n * @type Boolean\n * @default true\n */\n registerEvents: true,\n\n /**\n * Change redraw strategy in SVG rendering engine.\n * <p>\n * This optimization seems to be <b>obsolete</b> in newer browsers (from 2021 on, at least)\n * and even slow down the constructions. Therefore, the default is set to 'none' since v1.2.4.\n * <p>\n * If set to 'svg', before every redrawing of the JSXGraph construction\n * the SVG sub-tree of the DOM tree is taken out of the DOM.\n *\n * If set to 'all', before every redrawing of the JSXGraph construction the\n * complete DOM tree is taken out of the DOM.\n * If set to 'none' the redrawing is done in-place.\n *\n * Using 'svg' or 'all' speeds up the update process considerably. The risk\n * is that if there is an exception, only a white div or window is left.\n *\n *\n * @name JXG.Board#minimizeReflow\n * @type String\n * @default 'none'\n */\n minimizeReflow: 'none',\n\n /**\n * A number that will be added to the absolute position of the board used in mouse coordinate\n * calculations in {@link JXG.Board#getCoordsTopLeftCorner}.\n *\n * @name JXG.Board#offsetX\n * @see JXG.Board#offsetY\n * @type Number\n * @default 0\n */\n offsetX: 0,\n\n /**\n * A number that will be added to the absolute position of the board used in mouse coordinate\n * calculations in {@link JXG.Board#getCoordsTopLeftCorner}.\n *\n * @name JXG.Board#offsetY\n * @see JXG.Board#offsetX\n * @type Number\n * @default 0\n */\n offsetY: 0,\n\n /**\n * Control the possibilities for zoom interaction.\n *\n * Possible sub-attributes with default values are:\n * <pre>\n * zoom: {\n * factorX: 1.25, // horizontal zoom factor (multiplied to {@link JXG.Board#zoomX})\n * factorY: 1.25, // vertical zoom factor (multiplied to {@link JXG.Board#zoomY})\n * wheel: true, // allow zooming by mouse wheel or\n * \t\t\t\t // by pinch-to-toom gesture on touch devices\n * needShift: true, // mouse wheel zooming needs pressing of the shift key\n * min: 0.001, // minimal values of {@link JXG.Board#zoomX} and {@link JXG.Board#zoomY}, limits zoomOut\n * max: 1000.0, // maximal values of {@link JXG.Board#zoomX} and {@link JXG.Board#zoomY}, limits zoomIn\n *\n * pinchHorizontal: true, // Allow pinch-to-zoom to zoom only horizontal axis\n * pinchVertical: true, // Allow pinch-to-zoom to zoom only vertical axis\n * pinchSensitivity: 7 // Sensitivity (in degrees) for recognizing horizontal or vertical pinch-to-zoom gestures.\n * }\n * </pre>\n *\n * Deprecated: zoom.eps which is superseded by zoom.min\n *\n * @name JXG.Board#zoom\n * @type Object\n * @default\n */\n zoom: {\n enabled: true,\n factorX: 1.25,\n factorY: 1.25,\n wheel: true,\n needShift: true,\n min: 0.0001,\n max: 10000.0,\n pinchHorizontal: true,\n pinchVertical: true,\n pinchSensitivity: 7\n },\n\n /**\n * Control the possibilities for panning interaction (i.e. moving the origin).\n *\n * Possible sub-attributes with default values are:\n * <pre>\n * pan: {\n * enabled: true // Allow panning\n * needTwoFingers: false, // panning is done with two fingers on touch devices\n * needShift: true, // mouse panning needs pressing of the shift key\n * }\n * </pre>\n *\n * @name JXG.Board#pan\n * @type Object\n */\n pan: {\n needShift: true,\n needTwoFingers: false,\n enabled: true\n },\n\n /**\n * Control the possibilities for dragging objects.\n *\n * Possible sub-attributes with default values are:\n * <pre>\n * drag: {\n * enabled: true // Allow dragging\n * }\n * </pre>\n *\n * @name JXG.Board#drag\n * @type Object\n * @default {enabled: true}\n */\n drag: {\n enabled: true\n },\n\n /**\n * Control using the keyboard to change the construction.\n * <ul>\n * <li> enabled: true / false\n * <li> dx: horizontal shift amount per key press\n * <li> dy: vertical shift amount per key press\n * <li> panShift: zoom if shift key is pressed\n * <li> panCtrl: zoom if ctrl key is pressed\n * </ul>\n *\n * @example\n * var board = JXG.JSXGraph.initBoard(\"jxgbox\", {boundingbox: [-5,5,5,-5],\n * axis: true,\n * showCopyright:true,\n * showNavigation:true,\n * keyboard: {\n * enabled: true,\n * dy: 30,\n * panShift: true,\n * panCtrl: false\n * }\n * });\n *\n * </pre><div id=\"JXGb1d3aab6-ced2-4fe9-8fa5-b0accc8c7266\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXGb1d3aab6-ced2-4fe9-8fa5-b0accc8c7266',\n * {boundingbox: [-5,5,5,-5],\n * axis: true,\n * showCopyright:true,\n * showNavigation:true,\n * keyboard: {\n * enabled: true,\n * dy: 30,\n * panShift: true,\n * panCtrl: false\n * }\n * });\n *\n * })();\n *\n * </script><pre>\n *\n *\n * @see JXG.Board#keyDownListener\n * @see JXG.Board#keyFocusInListener\n * @see JXG.Board#keyFocusOutListener\n *\n * @name JXG.Board#keyboard\n * @type Object\n * @default {enabled: true, dx: 10, dy:10, panShift: true, panCtrl: false}\n */\n keyboard: {\n enabled: true,\n dx: 10,\n dy: 10,\n panShift: true,\n panCtrl: false\n },\n\n /**\n * Control if JSXGraph reacts to resizing of the JSXGraph container element\n * by the user / browser.\n * The attribute \"throttle\" determines the minimal time in msec between to\n * resize calls.\n *\n * @see JXG.Board#startResizeObserver\n * @see JXG.Board#resizeListener\n *\n * @name JXG.Board#resize\n * @type Object\n * @default {enabled: true, throttle: 10}\n *\n * @example\n * var board = JXG.JSXGraph.initBoard('jxgbox', {\n * boundingbox: [-5,5,5,-5],\n * keepAspectRatio: true,\n * axis: true,\n * resize: {enabled: true, throttle: 200}\n * });\n *\n * </pre><div id=\"JXGb55d4608-5d71-4bc3-b332-18c15fbda8c3\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXGb55d4608-5d71-4bc3-b332-18c15fbda8c3', {\n * boundingbox: [-5,5,5,-5],\n * keepAspectRatio: true,\n * axis: true,\n * resize: {enabled: true, throttle: 200}\n * });\n *\n * })();\n *\n * </script><pre>\n *\n *\n */\n resize: {\n enabled: true,\n throttle: 10\n },\n\n /**\n * Element which listens to move events of the pointing device.\n * This allows to drag elements of a JSXGraph construction outside of the board.\n * Especially, on mobile devices this enhances the user experience.\n * However, it is recommended to allow dragging outside of the JSXGraph board only\n * in certain constructions where users may not \"loose\" points outside of the board.\n * Then points may become unreachable.\n * <p>\n * A situation where dragging outside of the board is uncritical is for example if\n * only sliders are used to interact with the construction.\n * <p>\n * Possible values for this attributes are:\n * <ul>\n * <li> an element specified by document.getElementById('some id');\n * <li> null: to use the JSXgraph container div element\n * <li> document\n * </ul>\n *\n * @name JXG.Board#moveTarget\n * @type HTML node or document\n * @default null\n *\n * @example\n * var board = JXG.JSXGraph.initBoard('jxgbox', {\n * boundingbox: [-5,5,5,-5],\n * axis: true,\n * moveTarget: document\n * });\n *\n * </pre><div id=\"JXG973457e5-c63f-4516-8570-743f2cc560e1\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG973457e5-c63f-4516-8570-743f2cc560e1',\n * {boundingbox: [-5,5,5,-5],\n * axis: true,\n * moveTarget: document\n * });\n *\n * })();\n *\n * </script><pre>\n *\n *\n */\n moveTarget: null,\n\n /**\n * Control the possibilities for a selection rectangle.\n * Starting a selection event triggers the \"startselecting\" event.\n * When the mouse pointer is released, the \"stopselecting\" event is fired.\n * The \"stopselecting\" event must be supplied by the user.\n * <p>\n * Possible sub-attributes with default values are:\n * <pre>\n * selection: {\n * enabled: false,\n * name: 'selectionPolygon',\n * needShift: false, // mouse selection needs pressing of the shift key\n * needCtrl: true, // mouse selection needs pressing of the shift key\n * withLines: false, // Selection polygon has border lines\n * vertices: {\n * visible: false\n * },\n * fillColor: '#ffff00',\n * visible: false // Initial visibility. Should be set to false always\n * }\n * </pre>\n * <p>\n * Board events triggered by selection manipulation:\n * 'startselecting', 'stopselecting', 'mousestartselecting', 'mousestopselecting',\n * 'pointerstartselecting', 'pointerstopselecting', 'touchstartselecting', 'touchstopselecting'.\n *\n * @example\n * board.on('stopselecting', function(){\n * var box = board.stopSelectionMode(),\n * // bbox has the coordinates of the selectionr rectangle.\n * // Attention: box[i].usrCoords have the form [1, x, y], i.e.\n * // are homogeneous coordinates.\n * bbox = box[0].usrCoords.slice(1).concat(box[1].usrCoords.slice(1));\n * // Set a new bounding box\n * board.setBoundingBox(bbox, false);\n * });\n *\n * @name JXG.Board#selection\n *\n * @see JXG.Board#startSelectionMode\n * @see JXG.Board#stopSelectionMode\n *\n * @type Object\n * @default\n */\n selection: {\n enabled: false,\n name: 'selectionPolygon',\n needShift: false,\n needCtrl: true,\n withLines: false,\n vertices: {\n visible: false\n },\n fillColor: '#ffff00',\n visible: false\n },\n\n /**\n * If true, the infobox is shown on mouse/pen over for all points\n * which have set their attribute showInfobox to 'inherit'.\n * If a point has set its attribute showInfobox to false or true,\n * that value will have priority over this value.\n *\n * @name JXG.Board#showInfobox\n * @see Point#showInfobox\n * @type Boolean\n * @default true\n */\n showInfobox: true\n\n /**#@-*/\n },\n\n /**\n * Options that are used by the navigation bar.\n *\n * Default values are\n * <pre>\n * JXG.Option.navbar: {\n * strokeColor: '#333333',\n * fillColor: 'transparent',\n * highlightFillColor: '#aaaaaa',\n * padding: '2px',\n * position: 'absolute',\n * fontSize: '14px',\n * cursor: 'pointer',\n * zIndex: '100',\n * right: '5px',\n * bottom: '5px'\n * },\n * </pre>\n * These settings are overruled by the CSS class 'JXG_navigation'.\n * @deprecated\n * @type Object\n * @name JXG.Options#navbar\n *\n */\n navbar: {\n strokeColor: '#333333', //'#aaaaaa',\n fillColor: 'transparent', //#f5f5f5',\n highlightFillColor: '#aaaaaa',\n padding: '2px',\n position: 'absolute',\n fontSize: '14px',\n cursor: 'pointer',\n zIndex: '100',\n right: '5px',\n bottom: '5px'\n //border: 'none 1px black',\n //borderRadius: '4px'\n },\n\n /*\n * Generic options used by {@link JXG.GeometryElement}\n */\n elements: {\n // the following tag is a meta tag: http://code.google.com/p/jsdoc-toolkit/wiki/MetaTags\n\n /**#@+\n * @visprop\n */\n\n /**\n * The stroke color of the given geometry element.\n * @type String\n * @name JXG.GeometryElement#strokeColor\n * @see JXG.GeometryElement#highlightStrokeColor\n * @see JXG.GeometryElement#strokeWidth\n * @see JXG.GeometryElement#strokeOpacity\n * @see JXG.GeometryElement#highlightStrokeOpacity\n * @default {@link JXG.Options.elements.color#strokeColor}\n */\n strokeColor: Color.palette.blue,\n\n /**\n * The stroke color of the given geometry element when the user moves the mouse over it.\n * @type String\n * @name JXG.GeometryElement#highlightStrokeColor\n * @see JXG.GeometryElement#strokeColor\n * @see JXG.GeometryElement#strokeWidth\n * @see JXG.GeometryElement#strokeOpacity\n * @see JXG.GeometryElement#highlightStrokeOpacity\n * @default {@link JXG.Options.elements.color#highlightStrokeColor}\n */\n highlightStrokeColor: '#c3d9ff',\n\n /**\n * The fill color of this geometry element.\n * @type String\n * @name JXG.GeometryElement#fillColor\n * @see JXG.GeometryElement#highlightFillColor\n * @see JXG.GeometryElement#fillOpacity\n * @see JXG.GeometryElement#highlightFillOpacity\n * @default {@link JXG.Options.elements.color#fillColor}\n */\n fillColor: Color.palette.red,\n\n /**\n * The fill color of the given geometry element when the mouse is pointed over it.\n * @type String\n * @name JXG.GeometryElement#highlightFillColor\n * @see JXG.GeometryElement#fillColor\n * @see JXG.GeometryElement#fillOpacity\n * @see JXG.GeometryElement#highlightFillOpacity\n * @default {@link JXG.Options.elements.color#highlightFillColor}\n */\n highlightFillColor: 'none',\n\n /**\n * Opacity for element's stroke color.\n * @type Number\n * @name JXG.GeometryElement#strokeOpacity\n * @see JXG.GeometryElement#strokeColor\n * @see JXG.GeometryElement#highlightStrokeColor\n * @see JXG.GeometryElement#strokeWidth\n * @see JXG.GeometryElement#highlightStrokeOpacity\n * @default {@link JXG.Options.elements#strokeOpacity}\n */\n strokeOpacity: 1,\n\n /**\n * Opacity for stroke color when the object is highlighted.\n * @type Number\n * @name JXG.GeometryElement#highlightStrokeOpacity\n * @see JXG.GeometryElement#strokeColor\n * @see JXG.GeometryElement#highlightStrokeColor\n * @see JXG.GeometryElement#strokeWidth\n * @see JXG.GeometryElement#strokeOpacity\n * @default {@link JXG.Options.elements#highlightStrokeOpacity}\n */\n highlightStrokeOpacity: 1,\n\n /**\n * Opacity for fill color.\n * @type Number\n * @name JXG.GeometryElement#fillOpacity\n * @see JXG.GeometryElement#fillColor\n * @see JXG.GeometryElement#highlightFillColor\n * @see JXG.GeometryElement#highlightFillOpacity\n * @default {@link JXG.Options.elements.color#fillOpacity}\n */\n fillOpacity: 1,\n\n /**\n * Opacity for fill color when the object is highlighted.\n * @type Number\n * @name JXG.GeometryElement#highlightFillOpacity\n * @see JXG.GeometryElement#fillColor\n * @see JXG.GeometryElement#highlightFillColor\n * @see JXG.GeometryElement#fillOpacity\n * @default {@link JXG.Options.elements.color#highlightFillOpacity}\n */\n highlightFillOpacity: 1,\n\n /**\n * Gradient type. Possible values are 'linear'. 'radial' or null.\n *\n * @example\n * var a = board.create('slider', [[0, -0.2], [3.5, -0.2], [0, 0, 2 * Math.PI]], {name: 'angle'});\n * var b = board.create('slider', [[0, -0.4], [3.5, -0.4], [0, 0, 1]], {name: 'offset1'});\n * var c = board.create('slider', [[0, -0.6], [3.5, -0.6], [0, 1, 1]], {name: 'offset2'});\n *\n * var pol = board.create('polygon', [[0, 0], [4, 0], [4,4], [0,4]], {\n * fillOpacity: 1,\n * fillColor: 'yellow',\n * gradient: 'linear',\n * gradientSecondColor: 'blue',\n * gradientAngle: function() { return a.Value(); },\n * gradientStartOffset: function() { return b.Value(); },\n * gradientEndOffset: function() { return c.Value(); },\n * hasInnerPoints: true\n * });\n *\n * </pre><div id=\"JXG3d04b5fd-0cd4-4f49-8c05-4e9686cd7ff0\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG3d04b5fd-0cd4-4f49-8c05-4e9686cd7ff0',\n * {boundingbox: [-1.5, 4.5, 5, -1.5], axis: true, showcopyright: false, shownavigation: false});\n * var a = board.create('slider', [[0, -0.2], [3.5, -0.2], [0, 0, 2 * Math.PI]], {name: 'angle'});\n * var b = board.create('slider', [[0, -0.4], [3.5, -0.4], [0, 0, 1]], {name: 'offset1'});\n * var c = board.create('slider', [[0, -0.6], [3.5, -0.6], [0, 1, 1]], {name: 'offset2'});\n *\n * var pol = board.create('polygon', [[0, 0], [4, 0], [4,4], [0,4]], {\n * fillOpacity: 1,\n * fillColor: 'yellow',\n * gradient: 'linear',\n * gradientSecondColor: 'blue',\n * gradientAngle: function() { return a.Value(); },\n * gradientStartOffset: function() { return b.Value(); },\n * gradientEndOffset: function() { return c.Value(); },\n * hasInnerPoints: true\n * });\n *\n * })();\n *\n * </script><pre>\n *\n * @example\n * var cx = board.create('slider', [[0, -.2], [3.5, -.2], [0, 0.5, 1]], {name: 'cx, cy'});\n * var fx = board.create('slider', [[0, -.4], [3.5, -.4], [0, 0.5, 1]], {name: 'fx, fy'});\n * var o1 = board.create('slider', [[0, -.6], [3.5, -.6], [0, 0.0, 1]], {name: 'offset1'});\n * var o2 = board.create('slider', [[0, -.8], [3.5, -.8], [0, 1, 1]], {name: 'offset2'});\n * var r = board.create('slider', [[0, -1], [3.5, -1], [0, 0.5, 1]], {name: 'r'});\n * var fr = board.create('slider', [[0, -1.2], [3.5, -1.2], [0, 0, 1]], {name: 'fr'});\n *\n * var pol = board.create('polygon', [[0, 0], [4, 0], [4,4], [0,4]], {\n * fillOpacity: 1,\n * fillColor: 'yellow',\n * gradient: 'radial',\n * gradientSecondColor: 'blue',\n * gradientCX: function() { return cx.Value(); },\n * gradientCY: function() { return cx.Value(); },\n * gradientR: function() { return r.Value(); },\n * gradientFX: function() { return fx.Value(); },\n * gradientFY: function() { return fx.Value(); },\n * gradientFR: function() { return fr.Value(); },\n * gradientStartOffset: function() { return o1.Value(); },\n * gradientEndOffset: function() { return o2.Value(); },\n * hasInnerPoints: true\n * });\n *\n * </pre><div id=\"JXG6081ca7f-0d09-4525-87ac-325a02fe2225\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG6081ca7f-0d09-4525-87ac-325a02fe2225',\n * {boundingbox: [-1.5, 4.5, 5, -1.5], axis: true, showcopyright: false, shownavigation: false});\n * var cx = board.create('slider', [[0, -.2], [3.5, -.2], [0, 0.5, 1]], {name: 'cx, cy'});\n * var fx = board.create('slider', [[0, -.4], [3.5, -.4], [0, 0.5, 1]], {name: 'fx, fy'});\n * var o1 = board.create('slider', [[0, -.6], [3.5, -.6], [0, 0.0, 1]], {name: 'offset1'});\n * var o2 = board.create('slider', [[0, -.8], [3.5, -.8], [0, 1, 1]], {name: 'offset2'});\n * var r = board.create('slider', [[0, -1], [3.5, -1], [0, 0.5, 1]], {name: 'r'});\n * var fr = board.create('slider', [[0, -1.2], [3.5, -1.2], [0, 0, 1]], {name: 'fr'});\n *\n * var pol = board.create('polygon', [[0, 0], [4, 0], [4,4], [0,4]], {\n * fillOpacity: 1,\n * fillColor: 'yellow',\n * gradient: 'radial',\n * gradientSecondColor: 'blue',\n * gradientCX: function() { return cx.Value(); },\n * gradientCY: function() { return cx.Value(); },\n * gradientR: function() { return r.Value(); },\n * gradientFX: function() { return fx.Value(); },\n * gradientFY: function() { return fx.Value(); },\n * gradientFR: function() { return fr.Value(); },\n * gradientStartOffset: function() { return o1.Value(); },\n * gradientEndOffset: function() { return o2.Value(); },\n * hasInnerPoints: true\n * });\n *\n * })();\n *\n * </script><pre>\n *\n *\n * @type String\n * @name JXG.GeometryElement#gradient\n * @see JXG.GeometryElement#gradientSecondColor\n * @see JXG.GeometryElement#gradientSecondOpacity\n * @default null\n */\n gradient: null,\n\n /**\n * Second color for gradient.\n * @type String\n * @name JXG.GeometryElement#gradientSecondColor\n * @see JXG.GeometryElement#gradient\n * @see JXG.GeometryElement#gradientSecondOpacity\n * @default '#ffffff'\n */\n gradientSecondColor: '#ffffff',\n\n /**\n * Opacity of second gradient color. Takes a value between 0 and 1.\n * @type Number\n * @name JXG.GeometryElement#gradientSecondOpacity\n * @see JXG.GeometryElement#gradient\n * @see JXG.GeometryElement#gradientSecondColor\n * @default 1\n */\n gradientSecondOpacity: 1,\n\n /**\n * The gradientStartOffset attribute is a number (ranging from 0 to 1) which indicates where the first gradient stop is placed,\n * see the SVG specification for more information.\n * For linear gradients, this attribute represents a location along the gradient vector.\n * For radial gradients, it represents a percentage distance from (fx,fy) to the edge of the outermost/largest circle.\n * @type Number\n * @name JXG.GeometryElement#gradientStartOffset\n * @see JXG.GeometryElement#gradient\n * @see JXG.GeometryElement#gradientEndOffset\n * @default 0.0\n */\n gradientStartOffset: 0.0,\n\n /**\n * The gradientEndOffset attribute is a number (ranging from 0 to 1) which indicates where the second gradient stop is placed,\n * see the SVG specification for more information.\n * For linear gradients, this attribute represents a location along the gradient vector.\n * For radial gradients, it represents a percentage distance from (fx,fy) to the edge of the outermost/largest circle.\n * @type Number\n * @name JXG.GeometryElement#gradientEndOffset\n * @see JXG.GeometryElement#gradient\n * @see JXG.GeometryElement#gradientStartOffset\n * @default 1.0\n */\n gradientEndOffset: 1.0,\n\n\n /**\n * Angle (in radians) of the gradiant in case the gradient is of type 'linear'.\n * If the angle is 0, the first color is on the left and the second color is on the right.\n * If the angle is pi/4 the first color is on top and the second color at the\n * bottom.\n * @type Number\n * @name JXG.GeometryElement#gradientAngle\n * @see JXG.GeometryElement#gradient\n * @default 0\n */\n gradientAngle: 0,\n\n /**\n * From the SVG specification: ‘cx’, ‘cy’ and ‘r’ define the largest (i.e., outermost) circle for the radial gradient.\n * The gradient will be drawn such that the 100% gradient stop is mapped to the perimeter of this largest (i.e., outermost) circle.\n * For radial gradients in canvas this is the value 'x1'.\n * Takes a value between 0 and 1.\n * @type Number\n * @name JXG.GeometryElement#gradientCX\n * @see JXG.GeometryElement#gradient\n * @see JXG.GeometryElement#gradientCY\n * @see JXG.GeometryElement#gradientR\n * @default 0.5\n */\n gradientCX: 0.5,\n\n /**\n * From the SVG specification: ‘cx’, ‘cy’ and ‘r’ define the largest (i.e., outermost) circle for the radial gradient.\n * The gradient will be drawn such that the 100% gradient stop is mapped to the perimeter of this largest (i.e., outermost) circle.\n * For radial gradients in canvas this is the value 'y1'.\n * Takes a value between 0 and 1.\n * @type Number\n * @name JXG.GeometryElement#gradientCY\n * @see JXG.GeometryElement#gradient\n * @see JXG.GeometryElement#gradientCX\n * @see JXG.GeometryElement#gradientR\n * @default 0.5\n */\n gradientCY: 0.5,\n\n /**\n * From the SVG specification: ‘cx’, ‘cy’ and ‘r’ define the largest (i.e., outermost) circle for the radial gradient.\n * The gradient will be drawn such that the 100% gradient stop is mapped to the perimeter of this largest (i.e., outermost) circle.\n * For radial gradients in canvas this is the value 'r1'.\n * Takes a value between 0 and 1.\n * @type Number\n * @name JXG.GeometryElement#gradientR\n * @see JXG.GeometryElement#gradient\n * @see JXG.GeometryElement#gradientCX\n * @see JXG.GeometryElement#gradientCY\n * @default 0.5\n */\n gradientR: 0.5,\n\n /**\n * ‘fx’ and ‘fy’ define the focal point for the radial gradient.\n * The gradient will be drawn such that the 0% gradient stop is mapped to (fx, fy).\n * For radial gradients in canvas this is the value 'x0'.\n * Takes a value between 0 and 1.\n * @type Number\n * @name JXG.GeometryElement#gradientFX\n * @see JXG.GeometryElement#gradient\n * @see JXG.GeometryElement#gradientFY\n * @see JXG.GeometryElement#gradientFR\n * @default 0.5\n */\n gradientFX: 0.5,\n\n /**\n * y-coordinate of the circle center for the second color in case of gradient 'radial'. (The attribute fy in SVG)\n * For radial gradients in canvas this is the value 'y0'.\n * Takes a value between 0 and 1.\n * @type Number\n * @name JXG.GeometryElement#gradientFY\n * @see JXG.GeometryElement#gradient\n * @see JXG.GeometryElement#gradientFX\n * @see JXG.GeometryElement#gradientFR\n * @default 0.5\n */\n gradientFY: 0.5,\n\n /**\n * This attribute defines the radius of the start circle of the radial gradient.\n * The gradient will be drawn such that the 0% <stop> is mapped to the perimeter of the start circle.\n * For radial gradients in canvas this is the value 'r0'.\n * Takes a value between 0 and 1.\n * @type Number\n * @name JXG.GeometryElement#gradientFR\n * @see JXG.GeometryElement#gradient\n * @see JXG.GeometryElement#gradientFX\n * @see JXG.GeometryElement#gradientFY\n * @default 0.0\n */\n gradientFR: 0.0,\n\n /**\n * Transition duration (in milliseconds) for color and opacity\n * changes. Works in SVG renderer, only.\n * @type Number\n * @name JXG.GeometryElement#transitionDuration\n * @see JXG.GeometryElement#strokeColor\n * @see JXG.GeometryElement#highlightStrokeColor\n * @see JXG.GeometryElement#strokeOpacity\n * @see JXG.GeometryElement#highlightStrokeOpacity\n * @see JXG.GeometryElement#fillColor\n * @see JXG.GeometryElement#highlightFillColor\n * @see JXG.GeometryElement#fillOpacity\n * @see JXG.GeometryElement#highlightFillOpacity\n * @default {@link JXG.Options.elements#transitionDuration}\n */\n transitionDuration: 100,\n\n /**\n * Width of the element's stroke.\n * @type Number\n * @name JXG.GeometryElement#strokeWidth\n * @see JXG.GeometryElement#strokeColor\n * @see JXG.GeometryElement#highlightStrokeColor\n * @see JXG.GeometryElement#strokeOpacity\n * @see JXG.GeometryElement#highlightStrokeOpacity\n * @default {@link JXG.Options.elements#strokeWidth}\n */\n strokeWidth: 2,\n\n /**\n * Width of the element's stroke when the mouse is pointed over it.\n * @type Number\n * @name JXG.GeometryElement#highlightStrokeWidth\n * @see JXG.GeometryElement#strokeColor\n * @see JXG.GeometryElement#highlightStrokeColor\n * @see JXG.GeometryElement#strokeOpacity\n * @see JXG.GeometryElement#highlightStrokeOpacity\n * @see JXG.GeometryElement#highlightFillColor\n * @default {@link JXG.Options.elements#strokeWidth}\n */\n highlightStrokeWidth: 2,\n\n /**\n * If true the element is fixed and can not be dragged around. The element\n * will be repositioned on zoom and moveOrigin events.\n * @type Boolean\n * @default false\n * @name JXG.GeometryElement#fixed\n */\n fixed: false,\n\n /**\n * If true the element is fixed and can not be dragged around. The element\n * will even stay at its position on zoom and moveOrigin events.\n * Only free elements like points, texts, curves can be frozen.\n * @type Boolean\n * @default false\n * @name JXG.GeometryElement#frozen\n */\n frozen: false,\n\n /**\n * If true a label will display the element's name.\n * @type Boolean\n * @default false\n * @name JXG.GeometryElement#withLabel\n */\n withLabel: false,\n\n /**\n * If false the element won't be visible on the board, otherwise it is shown.\n * @type Boolean\n * @name JXG.GeometryElement#visible\n * @see JXG.GeometryElement#hideElement\n * @see JXG.GeometryElement#showElement\n * @default true\n */\n visible: true,\n\n /**\n * A private element will be inaccessible in certain environments, e.g. a graphical user interface.\n * @default false\n */\n priv: false,\n\n /**\n * Display layer which will contain the element.\n * @see JXG.Options#layer\n * @default See {@link JXG.Options#layer}\n */\n layer: 0,\n\n /**\n * Determines the elements border-style.\n * Possible values are:\n * <ul><li>0 for a solid line</li>\n * <li>1 for a dotted line</li>\n * <li>2 for a line with small dashes</li>\n\n\n * <li>3 for a line with medium dashes</li>\n * <li>4 for a line with big dashes</li>\n * <li>5 for a line with alternating medium and big dashes and large gaps</li>\n * <li>6 for a line with alternating medium and big dashes and small gaps</li></ul>\n * @type Number\n * @name JXG.GeometryElement#dash\n * @default 0\n */\n dash: 0,\n\n /**\n * If true the element will get a shadow.\n * @type Boolean\n * @name JXG.GeometryElement#shadow\n * @default false\n */\n shadow: false,\n\n /**\n * If true the element will be traced, i.e. on every movement the element will be copied\n * to the background. Use {@link JXG.GeometryElement#clearTrace} to delete the trace elements.\n *\n * The calling of element.setAttribute({trace:false}) additionally\n * deletes all traces of this element. By calling\n * element.setAttribute({trace:'pause'})\n * the removal of already existing traces can be prevented.\n * @see JXG.GeometryElement#clearTrace\n * @see JXG.GeometryElement#traces\n * @see JXG.GeometryElement#numTraces\n * @type Boolean|String\n * @default false\n * @name JXG.GeometryElement#trace\n */\n trace: false,\n\n /**\n * Extra visual properties for traces of an element\n * @type Object\n * @see JXG.GeometryElement#trace\n * @name JXG.GeometryElement#traceAttributes\n */\n traceAttributes: {},\n\n /**\n *\n * @type Boolean\n * @default true\n * @name JXG.GeometryElement#highlight\n */\n highlight: true,\n\n /**\n * If this is set to true, the element is updated in every update\n * call of the board. If set to false, the element is updated only after\n * zoom events or more generally, when the bounding box has been changed.\n * Examples for the latter behaviour should be axes.\n * @type Boolean\n * @default true\n * @see JXG.GeometryElement#needsRegularUpdate\n * @name JXG.GeometryElement#needsRegularUpdate\n */\n needsRegularUpdate: true,\n\n /**\n * Snaps the element or its parents to the grid. Currently only relevant for points, circles,\n * and lines. Points are snapped to grid directly, on circles and lines it's only the parent\n * points that are snapped\n * @type Boolean\n * @default false\n * @name JXG.GeometryElement#snapToGrid\n */\n snapToGrid: false,\n\n /**\n * Determines whether two-finger manipulation of this object may change its size.\n * If set to false, the object is only rotated and translated.\n * <p>\n * In case the element is a horizontal or vertical line having ticks, \"scalable:true\"\n * enables zooming of the board by dragging ticks lines. This feature is enabled,\n * for the ticks element of the line element the attribute \"fixed\" has to be false\n * and the line element's scalable attribute has to be true.\n * <p>\n * In case the element is a polygon or line and it has the attribute \"scalable:false\",\n * moving the element with two fingers results in a rotation or translation.\n *\n * @type Boolean\n * @default true\n * @name JXG.GeometryElement#scalable\n * @see JXG.Ticks#fixed\n */\n scalable: true,\n\n /**\n * If the element is dragged it will be moved on mousedown or touchstart to the\n * top of its layer. Works only for SVG renderer and for simple elements\n * consisting of one SVG node.\n * @example\n * var li1 = board.create('line', [1, 1, 1], {strokeWidth: 20, dragToTopOfLayer: true});\n * var li2 = board.create('line', [1, -1, 1], {strokeWidth: 20, strokeColor: 'red'});\n *\n * </pre><div id=\"JXG38449fee-1ab4-44de-b7d1-43caa1f50f86\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG38449fee-1ab4-44de-b7d1-43caa1f50f86',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var li1 = board.create('line', [1, 1, 1], {strokeWidth: 20, dragToTopOfLayer: true});\n * var li2 = board.create('line', [1, -1, 1], {strokeWidth: 20, strokeColor: 'red'});\n *\n * })();\n *\n * </script><pre>\n *\n * @type Boolean\n * @default false\n * @name JXG.GeometryElement#dragToTopOfLayer\n */\n dragToTopOfLayer: false,\n\n /**\n * Precision options for JSXGraph elements.\n * This attributes takes either the value 'inherit' or an object of the form:\n * <pre>\n * precision: {\n * touch: 30,\n * mouse: 4,\n * pen: 4\n * }\n * </pre>\n *\n * In the first case, the global, JSXGraph-wide values of JXGraph.Options.precision\n * are taken.\n *\n * @type {String|Object}\n * @name JXG.GeometryElement#precision\n * @see JXG.Options#precision\n * @default 'inherit'\n */\n precision: 'inherit',\n\n /*draft options */\n draft: {\n /**\n * If true the element will be drawn in grey scale colors to visualize that it's only a draft.\n * @type Boolean\n * @name JXG.GeometryElement#draft\n * @default {@link JXG.Options.elements.draft#draft}\n */\n draft: false,\n strokeColor: '#565656',\n fillColor: '#565656',\n strokeOpacity: 0.8,\n fillOpacity: 0.8,\n strokeWidth: 1\n },\n\n /**\n * @private\n * By default, an element is not a label. Do not change this.\n */\n isLabel: false,\n\n /**\n * Controls if an element can get the focus with the tab key.\n * See <a href=\"https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex\">descriptiona at MDN</a>.\n * The additional value null completely disables focus of an element.\n * The value will be ignored if keyboard control of the board is not enabled or\n * the element is fixed or not visible.\n *\n * @name JXG.GeometryElement#tabindex\n * @type Number\n * @default 0\n * @see JXG.Board#keyboard\n * @see JXG.GeometryElement#fixed\n * @see JXG.GeometryElement#visible\n */\n tabindex: 0\n\n // close the meta tag\n /**#@-*/\n },\n\n /*\n * Generic options used by {@link JXG.Ticks}\n */\n ticks: {\n /**#@+\n * @visprop\n */\n\n /**\n * A function that expects two {@link JXG.Coords}, the first one representing the coordinates of the\n * tick that is to be labeled, the second one the coordinates of the center (the tick with position 0).\n *\n * @type function\n * @name Ticks#generateLabelText\n */\n generateLabelText: null,\n\n /**\n * A function that expects two {@link JXG.Coords}, the first one representing the coordinates of the\n * tick that is to be labeled, the second one the coordinates of the center (the tick with position 0).\n *\n * @deprecated Use {@link JGX.Options@generateLabelValue}\n * @type function\n * @name Ticks#generateLabelValue\n */\n generateLabelValue: null,\n\n /**\n * Draw labels yes/no\n *\n * @type Boolean\n * @name Ticks#drawLabels\n * @default false\n */\n drawLabels: false,\n\n /**\n * Attributes for the ticks labels\n *\n * @name Ticks#label\n * @type Object\n * @default {}\n *\n */\n label: {\n },\n\n /**\n * Format tick labels that were going to have scientific notation\n * like 5.00e+6 to look like 5•10⁶.\n *\n * @example\n * var board = JXG.JSXGraph.initBoard(\"jxgbox\", {\n * boundingbox: [-500000, 500000, 500000, -500000],\n * axis: true,\n * defaultAxes: {\n * x: {\n * scalable: true,\n * ticks: {\n * beautifulScientificTickLabels: true\n * },\n * },\n * y: {\n * scalable: true,\n * ticks: {\n * beautifulScientificTickLabels: true\n * },\n * }\n * },\n * });\n *\n * </pre><div id=\"JXGc1e46cd1-e025-4002-80aa-b450869fdaa2\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXGc1e46cd1-e025-4002-80aa-b450869fdaa2', {\n * boundingbox: [-500000, 500000, 500000, -500000],\n * showcopyright: false, shownavigation: false,\n * axis: true,\n * defaultAxes: {\n * x: {\n * scalable: true,\n * ticks: {\n * beautifulScientificTickLabels: true\n * },\n * },\n * y: {\n * scalable: true,\n * ticks: {\n * beautifulScientificTickLabels: true\n * },\n * }\n * },\n * });\n *\n * })();\n *\n * </script><pre>\n *\n * @name Ticks#beautifulScientificTickLabels\n * @type Boolean\n * @default false\n */\n beautifulScientificTickLabels: false,\n\n /**\n * Use the unicode character 0x2212, i.e. the HTML entity &minus; as minus sign.\n * That is −1 instead of -1.\n *\n * @type Boolean\n * @name Ticks#useUnicodeMinus\n * @default true\n */\n useUnicodeMinus: true,\n\n /**\n * Determine the position of the tick with value 0. 'left' means point1 of the line, 'right' means point2,\n * and 'middle' is equivalent to the midpoint of the defining points. This attribute is ignored if the parent\n * line is of type axis.\n *\n * @type String\n * @name Ticks#anchor\n * @default 'left'\n */\n anchor: 'left',\n\n /**\n * Draw the zero tick, that lies at line.point1?\n *\n * @type Boolean\n * @name Ticks#drawZero\n * @default false\n */\n drawZero: false,\n\n /**\n * If the distance between two ticks is too big we could insert new ticks. If insertTicks\n * is <tt>true</tt>, we'll do so, otherwise we leave the distance as is.\n * This option is ignored if equidistant is false. In the example below the distance between\n * two ticks is given as <tt>1</tt> but because insertTicks is set to true many ticks will\n * be omitted in the rendering process to keep the display clear.\n *\n * @type Boolean\n * @name Ticks#insertTicks\n * @see Ticks#minTicksDistance\n * @default false\n * @example\n * // Create an axis providing two coord pairs.\n * var p1 = board.create('point', [0, 0]);\n * var p2 = board.create('point', [50, 25]);\n * var l1 = board.create('line', [p1, p2]);\n * var t = board.create('ticks', [l1, 1], {\n * insertTicks: true,\n * majorHeight: -1,\n * label: {\n * offset: [4, -9]\n * },\n * drawLabels: true\n * });\n * </pre><div class=\"jxgbox\" id=\"JXG2f6fb842-40bd-4223-aa28-3e9369d2097f\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function () {\n * var board = JXG.JSXGraph.initBoard('JXG2f6fb842-40bd-4223-aa28-3e9369d2097f', {boundingbox: [-100, 70, 70, -100], showcopyright: false, shownavigation: false});\n * var p1 = board.create('point', [0, 0]);\n * var p2 = board.create('point', [50, 25]);\n * var l1 = board.create('line', [p1, p2]);\n * var t = board.create('ticks', [l1, 1], {insertTicks: true, majorHeight: -1, label: {offset: [4, -9]}, drawLabels: true});\n * })();\n * </script><pre>\n */\n insertTicks: false,\n\n /**\n * Minimum distance in pixel of equidistant ticks in case insertTicks==true.\n * @name Ticks#minTicksDistance\n * @type: Number\n * @default: 10\n * @see Ticks#insertTicks\n */\n minTicksDistance: 10,\n\n /**\n * Total height of a minor tick. If negative the full height of the board is taken.\n *\n * @type Number\n * @name Ticks#minorHeight\n * @default 4\n */\n minorHeight: 4,\n\n /**\n * Total height of a major tick. If negative the full height of the board is taken.\n *\n * @type Number\n * @name Ticks#majorHeight\n * @default 10\n */\n majorHeight: 10,\n\n /**\n * Decides in which direction finite ticks are visible. Possible values are either the constants\n * 0=false or 1=true or a function returning 0 or 1.\n *\n * In case of [0,1] the tick is only visible to the right of the line. In case of\n * [1,0] the tick is only visible to the left of the line.\n *\n * @type Array\n * @name Ticks#tickEndings\n * @default [1, 1]\n */\n tickEndings: [1, 1],\n\n /**\n * The number of minor ticks between two major ticks.\n * @type Number\n * @name Ticks#minorTicks\n * @default 4\n */\n minorTicks: 4,\n\n /**\n * Scale the ticks but not the tick labels.\n * @type Number\n * @default 1\n * @name Ticks#scale\n * @see Ticks#scaleSymbol\n */\n scale: 1,\n\n /**\n * A string that is appended to every tick, used to represent the scale\n * factor given in {@link Ticks#scaleSymbol}.\n *\n * @type String\n * @default ''\n * @name Ticks#scaleSymbol\n * @see Ticks#scale\n */\n scaleSymbol: '',\n\n /**\n * User defined labels for special ticks. Instead of the i-th tick's position, the i-th string stored in this array\n * is shown. If the number of strings in this array is less than the number of special ticks, the tick's position is\n * shown as a fallback.\n *\n * @type Array\n * @name Ticks#labels\n * @default []\n */\n labels: [],\n\n /**\n * The maximum number of characters a tick label can use.\n *\n * @type Number\n * @name Ticks#maxLabelLength\n * @see Ticks#precision\n * @default 5\n */\n maxLabelLength: 5,\n\n /**\n * If a label exceeds {@link Ticks#maxLabelLength} this determines the precision used to shorten the tick label.\n * Replaced by the digits attribute.\n *\n * @type Number\n * @name Ticks#precision\n * @see Ticks#maxLabelLength\n * @see Ticks#digits\n * @deprecated\n * @default 3\n */\n precision: 3,\n\n /**\n * If a label exceeds {@link Ticks#maxLabelLength} this determines the number of digits used to shorten the tick label.\n *\n * @type Number\n * @name Ticks#digits\n * @see Ticks#maxLabelLength\n * @deprecated\n * @default 3\n */\n digits: 3,\n\n /**\n * The default distance between two ticks. Please be aware that this value does not have\n * to be used if {@link Ticks#insertTicks} is set to true.\n *\n * @type Number\n * @name Ticks#ticksDistance\n * @see Ticks#insertTicks\n * @default 1\n */\n ticksDistance: 1,\n\n /**\n * Tick face for ticks of finite length. By default (face: '|') this is a straight line.\n * Possible other values are '<' and '>'. These faces are used in\n * {@link JXG.Hatch} for hatch marking parallel lines.\n * @type String\n * @name{Ticks#face}\n * @see hatch\n * @default '|'\n * @example\n * var p1 = board.create('point', [0, 3]);\n * var p2 = board.create('point', [1, 3]);\n * var l1 = board.create('line', [p1, p2]);\n * var t = board.create('ticks', [l1], {ticksDistance: 2, face: '>'});\n *\n * </pre><div id=\"JXG950a568a-1264-4e3a-b61d-b6881feecf4b\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG950a568a-1264-4e3a-b61d-b6881feecf4b',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var p1 = board.create('point', [0, 3]);\n * var p2 = board.create('point', [1, 3]);\n * var l1 = board.create('line', [p1, p2]);\n * var t = board.create('ticks', [l1], {ticksDistance: 2, face: '>'});\n *\n * })();\n *\n * </script><pre>\n *\n */\n face: '|',\n\n strokeOpacity: 1,\n strokeWidth: 1,\n strokeColor: '#000000',\n highlightStrokeColor: '#888888',\n fillColor: 'none',\n highlightFillColor: 'none',\n visible: 'inherit',\n\n /**\n * Whether line boundaries should be counted or not in the lower and upper bounds when\n * creating ticks.\n *\n * @type Boolean\n * @name Ticks#includeBoundaries\n * @default false\n */\n includeBoundaries: false,\n\n /**\n * Set the ticks type.\n * Possible values are 'linear' or 'polar'.\n *\n * @type String\n * @name Ticks#type\n * @default 'linear'\n */\n type: 'linear'\n\n // close the meta tag\n /**#@-*/\n },\n\n /*\n * Generic options used by {@link JXG.Hatch}\n */\n hatch: {\n drawLabels: false,\n drawZero: true,\n majorHeight: 20,\n anchor: 'middle',\n face: '|',\n strokeWidth: 2,\n strokeColor: Color.palette.blue,\n ticksDistance: 0.2\n },\n\n /**\n * Precision options, defining how close a pointer device (mouse, finger, pen) has to be\n * to an object such that the object is highlighted or can be dragged.\n * These values are board-wide and can be overwritten for individual elements by\n * changing their precision attribute.\n *\n * The default values are\n * <pre>\n * JXG.Options.precision: {\n * touch: 30,\n * touchMax: 100,\n * mouse: 4,\n * pen: 4,\n * epsilon: 0.0001,\n * hasPoint: 4\n * }\n * </pre>\n *\n * @type Object\n * @name JXG.Options#precision\n * @see JXG.GeometryElement#precision\n */\n precision: {\n touch: 30,\n touchMax: 100,\n mouse: 4,\n pen: 4,\n epsilon: 0.0001, // Unused\n hasPoint: 4\n },\n\n /**\n * Default ordering of the layers.\n * The numbering starts from 0 and the highest layer number is numlayers-1.\n *\n * The default values are\n * <pre>\n * JXG.Options.layer: {\n * numlayers: 20, // only important in SVG\n * text: 9,\n * point: 9,\n * glider: 9,\n * arc: 8,\n * line: 7,\n * circle: 6,\n * curve: 5,\n * turtle: 5,\n * polygon: 3,\n * sector: 3,\n * angle: 3,\n * integral: 3,\n * axis: 2,\n * ticks: 2,\n * grid: 1,\n * image: 0,\n * trace: 0\n * }\n * </pre>\n * @type Object\n * @name JXG.Options#layer\n */\n layer: {\n numlayers: 20, // only important in SVG\n unused9: 19,\n unused8: 18,\n unused7: 17,\n unused6: 16,\n unused5: 15,\n unused4: 14,\n unused3: 13,\n unused2: 12,\n unused1: 11,\n unused0: 10,\n text: 9,\n point: 9,\n glider: 9,\n arc: 8,\n line: 7,\n circle: 6,\n curve: 5,\n turtle: 5,\n polygon: 3,\n sector: 3,\n angle: 3,\n integral: 3,\n axis: 2,\n ticks: 2,\n grid: 1,\n image: 0,\n trace: 0\n },\n\n /* special angle options */\n angle: {\n /**#@+\n * @visprop\n */\n\n withLabel: true,\n\n /**\n * Radius of the sector, displaying the angle.\n * The radius can be given as number (in user coordinates)\n * or as string 'auto'. In the latter case, the angle\n * is set to an value between 20 and 50 px.\n *\n * @type {Number|String}\n * @name Angle#radius\n * @default 'auto'\n * @visprop\n */\n radius: 'auto',\n\n /**\n * Display type of the angle field. Possible values are\n * 'sector' or 'sectordot' or 'square' or 'none'.\n *\n * @type String\n * @default 'sector'\n * @name Angle#type\n * @visprop\n */\n type: 'sector',\n\n /**\n * Display type of the angle field in case of a right angle. Possible values are\n * 'sector' or 'sectordot' or 'square' or 'none'.\n *\n * @type String\n * @default square\n * @name Angle#orthoType\n * @see Angle#orthoSensitivity\n * @visprop\n */\n orthoType: 'square',\n\n /**\n * Sensitivity (in degrees) to declare an angle as right angle.\n * If the angle measure is inside this distance from a rigth angle, the orthoType\n * of the angle is used for display.\n *\n * @type Number\n * @default 1.0\n * @name Angle#orthoSensitivity\n * @see Angle#orthoType\n * @visprop\n */\n orthoSensitivity: 1.0,\n\n fillColor: Color.palette.orange,\n highlightFillColor: Color.palette.orange,\n strokeColor: Color.palette.orange,\n // fillColor: '#ff7f00',\n // highlightFillColor: '#ff7f00',\n // strokeColor: '#ff7f00',\n\n fillOpacity: 0.3,\n highlightFillOpacity: 0.3,\n\n /**\n * @deprecated\n */\n radiuspoint: {\n withLabel: false,\n visible: false,\n name: ''\n },\n\n /**\n * @deprecated\n */\n pointsquare: {\n withLabel: false,\n visible: false,\n name: ''\n },\n\n dot: {\n visible: false,\n strokeColor: 'none',\n fillColor: '#000000',\n size: 2,\n face: 'o',\n withLabel: false,\n name: ''\n },\n\n label: {\n position: 'top',\n offset: [0, 0],\n strokeColor: Color.palette.blue\n },\n\n /**\n * Attributes for sub-element arc. In general, the arc will run through the first point and\n * thus will not have the same radius as the angle sector.\n *\n * @type Arc\n * @name Angle#arc\n * @default '{visible:false}'\n */\n arc: {\n visible: false,\n fillColor: 'none'\n },\n\n /**#@-*/\n },\n\n /* special arc options */\n arc: {\n /**#@+\n * @visprop\n */\n\n /**\n * Type of arc. Possible values are 'minor', 'major', and 'auto'.\n *\n * @type String\n * @name Arc#selection\n * @default 'auto'\n */\n selection: 'auto',\n\n /**\n * If <tt>true</tt>, moving the mouse over inner points triggers hasPoint.\n *\n * @see JXG.GeometryElement#hasPoint\n * @name Arc#hasInnerPoints\n * @type Boolean\n * @default false\n */\n hasInnerPoints: false,\n\n label: {\n anchorX: 'auto',\n anchorY: 'auto'\n },\n firstArrow: false,\n lastArrow: false,\n fillColor: 'none',\n highlightFillColor: 'none',\n strokeColor: Color.palette.blue,\n highlightStrokeColor: '#c3d9ff',\n useDirection: false,\n\n /**\n * Attributes for center point.\n *\n * @type Point\n * @name Arc#center\n */\n center: {\n },\n\n /**\n * Attributes for radius point.\n *\n * @type Point\n * @name Arc#radiusPoint\n */\n radiusPoint: {\n },\n\n /**\n * Attributes for angle point.\n *\n * @type Point\n * @name Arc#anglePoint\n */\n anglePoint: {\n }\n\n /**#@-*/\n },\n\n /* special arrow options */\n arrow: {\n /**#@+\n * @visprop\n */\n\n firstArrow: false,\n\n lastArrow: {\n type: 1,\n highlightSize: 6,\n size: 6\n }\n\n /**#@-*/\n },\n\n /* special axis options */\n axis: {\n /**#@+\n * @visprop\n */\n\n name: '', // By default, do not generate names for axes.\n needsRegularUpdate: false, // Axes only updated after zooming and moving of the origin.\n strokeWidth: 1,\n lastArrow: {\n type: 1,\n highlightSize: 8,\n size: 8\n },\n strokeColor: '#666666',\n highlightStrokeWidth: 1,\n highlightStrokeColor: '#888888',\n\n\n /**\n * Show / hide ticks.\n *\n * Deprecated. Suggested alternative is \"ticks: {visible: false}\"\n *\n * @type Boolean\n * @name Axis#withTicks\n * @default true\n * @deprecated\n */\n withTicks: true,\n straightFirst: true,\n straightLast: true,\n margin: -4,\n withLabel: false,\n scalable: false,\n\n /**\n * Attributes for ticks of the axis.\n *\n * @type Ticks\n * @name Axis#ticks\n */\n ticks: {\n label: {\n offset: [4, -12 + 3], // This seems to be a good offset for 12 point fonts\n parse: false,\n needsRegularUpdate: false,\n display: 'internal',\n visible: 'inherit',\n layer: 9\n },\n visible: 'inherit',\n needsRegularUpdate: false,\n strokeWidth: 1,\n strokeColor: '#666666',\n highlightStrokeColor: '#888888',\n drawLabels: true,\n drawZero: false,\n insertTicks: true,\n minTicksDistance: 5,\n minorHeight: 10, // if <0: full width and height\n majorHeight: -1, // if <0: full width and height\n tickEndings: [0, 1],\n minorTicks: 4,\n ticksDistance: 1, // TODO doc\n strokeOpacity: 0.25\n },\n\n /**\n * Attributes for first point the axis.\n *\n * @type Point\n * @name Axis#point1\n */\n point1: { // Default values for point1 if created by line\n needsRegularUpdate: false,\n visible: false\n },\n\n /**\n * Attributes for second point the axis.\n *\n * @type Point\n * @name Axis#point2\n */\n point2: { // Default values for point2 if created by line\n needsRegularUpdate: false,\n visible: false\n },\n\n tabindex: -1,\n\n /**\n * Attributes for the axis label.\n *\n * @type Label\n * @name Axis#label\n */\n label: {\n position: 'lft',\n offset: [10, 10]\n }\n /**#@-*/\n },\n\n /* special options for angle bisector of 3 points */\n bisector: {\n /**#@+\n * @visprop\n */\n\n strokeColor: '#000000', // Bisector line\n\n /**\n * Attributes for the helper point of the bisector.\n *\n * @type Point\n * @name Bisector#point\n */\n point: { // Bisector point\n visible: false,\n fixed: false,\n withLabel: false,\n name: ''\n }\n\n /**#@-*/\n },\n\n /* special options for the 2 bisectors of 2 lines */\n bisectorlines: {\n /**#@+\n * @visprop\n */\n\n /**\n * Attributes for first line.\n *\n * @type Line\n * @name Bisectorlines#line1\n */\n line1: { //\n strokeColor: '#000000'\n },\n\n /**\n * Attributes for second line.\n *\n * @type Line\n * @name Bisectorlines#line2\n */\n line2: { //\n strokeColor: '#000000'\n }\n\n /**#@-*/\n },\n\n /* special options for boxplot curves */\n boxplot: {\n /**#@+\n * @visprop\n */\n\n /**\n * Direction of the box plot: 'vertical' or 'horizontal'\n *\n * @type String\n * @name Boxplot#dir\n * @default: 'vertical'\n */\n dir: 'vertical',\n\n /**\n * Relative width of the maximum and minimum quantile\n *\n * @type Number\n * @name Boxplot#smallWidth\n * @default: 0.5\n */\n smallWidth: 0.5,\n\n strokeWidth: 2,\n strokeColor: Color.palette.blue,\n fillColor: Color.palette.blue,\n fillOpacity: 0.2,\n highlightStrokeWidth: 2,\n highlightStrokeColor: Color.palette.blue,\n highlightFillColor: Color.palette.blue,\n highlightFillOpacity: 0.1\n\n /**#@-*/\n },\n\n /* special button options */\n button: {\n /**#@+\n * @visprop\n */\n\n /**\n * Control the attribute \"disabled\" of the HTML button.\n *\n * @name disabled\n * @memberOf Button.prototype\n *\n * @type Boolean\n * @default false\n */\n disabled: false,\n\n display: 'html'\n\n /**#@-*/\n },\n\n /* special cardinal spline options */\n cardinalspline: {\n /**#@+\n * @visprop\n */\n\n /**\n * Controls if the data points of the cardinal spline when given as\n * arrays should be converted into {@link JXG.Points}.\n *\n * @name createPoints\n * @memberOf Cardinalspline.prototype\n *\n * @see Cardinalspline#points\n *\n * @type Boolean\n * @default true\n */\n createPoints: true,\n\n /**\n * If set to true, the supplied coordinates are interpreted as\n * [[x_0, y_0], [x_1, y_1], p, ...].\n * Otherwise, if the data consists of two arrays of equal length,\n * it is interpreted as\n * [[x_o x_1, ..., x_n], [y_0, y_1, ..., y_n]]\n *\n * @name isArrayOfCoordinates\n * @memberOf Cardinalspline.prototype\n * @type Boolean\n * @default false\n */\n isArrayOfCoordinates: false,\n\n /**\n * Attributes for the points generated by Cardinalspline in cases\n * {@link createPoints} is set to true\n *\n * @name points\n * @memberOf Cardinalspline.prototype\n *\n * @see Cardinalspline#createPoints\n * @type Object\n */\n points: {\n strokeOpacity: 0.05,\n fillOpacity: 0.05,\n highlightStrokeOpacity: 1.0,\n highlightFillOpacity: 1.0,\n withLabel: false,\n name: '',\n fixed: false\n }\n\n /**#@-*/\n },\n\n /* special chart options */\n chart: {\n /**#@+\n * @visprop\n */\n\n chartStyle: 'line',\n colors: ['#B02B2C', '#3F4C6B', '#C79810', '#D15600', '#FFFF88', '#c3d9ff', '#4096EE', '#008C00'],\n highlightcolors: null,\n fillcolor: null,\n highlightonsector: false,\n highlightbysize: false,\n\n fillOpacity: 0.6,\n withLines: false,\n\n label: {\n }\n /**#@-*/\n },\n\n /* special html slider options */\n checkbox: {\n /**#@+\n * @visprop\n */\n\n /**\n * Control the attribute \"disabled\" of the HTML checkbox.\n *\n * @name disabled\n * @memberOf Checkbox.prototype\n *\n * @type Boolean\n * @default false\n */\n disabled: false,\n\n /**\n * Control the attribute \"checked\" of the HTML checkbox.\n *\n * @name checked\n * @memberOf Checkbox.prototype\n *\n * @type Boolean\n * @default false\n */\n checked: false,\n\n display: 'html'\n\n /**#@-*/\n },\n\n /*special circle options */\n circle: {\n /**#@+\n * @visprop\n */\n\n /**\n * If <tt>true</tt>, moving the mouse over inner points triggers hasPoint.\n *\n * @see JXG.GeometryElement#hasPoint\n * @name Circle#hasInnerPoints\n * @type Boolean\n * @default false\n */\n hasInnerPoints: false,\n\n fillColor: 'none',\n highlightFillColor: 'none',\n strokeColor: Color.palette.blue,\n highlightStrokeColor: '#c3d9ff',\n\n /**\n * Attributes for center point.\n *\n * @type Point\n * @name Circle#center\n */\n center: {\n visible: false,\n withLabel: false,\n fixed: false,\n\n fillColor: Color.palette.red,\n strokeColor: Color.palette.red,\n highlightFillColor: '#c3d9ff',\n highlightStrokeColor: '#c3d9ff',\n\n name: ''\n },\n\n /**\n * Attributes for center point.\n *\n * @type Point\n * @name Circle#center\n */\n point2: {\n visible: false,\n withLabel: false,\n fixed: false,\n name: ''\n },\n\n /**\n * Attributes for circle label.\n *\n * @type Label\n * @name Circle#label\n */\n label: {\n position: 'urt'\n }\n /**#@-*/\n },\n\n /* special options for circumcircle of 3 points */\n circumcircle: {\n /**#@+\n * @visprop\n */\n\n fillColor: 'none',\n highlightFillColor: 'none',\n strokeColor: Color.palette.blue,\n highlightStrokeColor: '#c3d9ff',\n\n /**\n * Attributes for center point.\n *\n * @type Point\n * @name Circumcircle#center\n */\n center: { // center point\n visible: false,\n fixed: false,\n withLabel: false,\n fillColor: Color.palette.red,\n strokeColor: Color.palette.red,\n highlightFillColor: '#c3d9ff',\n highlightStrokeColor: '#c3d9ff',\n name: ''\n }\n /**#@-*/\n },\n\n circumcirclearc: {\n /**#@+\n * @visprop\n */\n\n fillColor: 'none',\n highlightFillColor: 'none',\n strokeColor: Color.palette.blue,\n highlightStrokeColor: '#c3d9ff',\n\n /**\n * Attributes for center point.\n *\n * @type Point\n * @name CircumcircleArc#center\n */\n center: {\n visible: false,\n withLabel: false,\n fixed: false,\n name: ''\n }\n /**#@-*/\n },\n\n /* special options for circumcircle sector of 3 points */\n circumcirclesector: {\n /**#@+\n * @visprop\n */\n\n useDirection: true,\n fillColor: Color.palette.yellow,\n highlightFillColor: Color.palette.yellow,\n fillOpacity: 0.3,\n highlightFillOpacity: 0.3,\n strokeColor: Color.palette.blue,\n highlightStrokeColor: '#c3d9ff',\n\n /**\n * Attributes for center point.\n *\n * @type Point\n * @name Circle#point\n */\n point: {\n visible: false,\n fixed: false,\n withLabel: false,\n name: ''\n }\n /**#@-*/\n },\n\n /* special conic options */\n conic: {\n /**#@+\n * @visprop\n */\n\n fillColor: 'none',\n highlightFillColor: 'none',\n strokeColor: Color.palette.blue,\n highlightStrokeColor: '#c3d9ff',\n\n /**\n * Attributes for foci points.\n *\n * @type Point\n * @name Conic#foci\n */\n foci: {\n // points\n fixed: false,\n visible: false,\n withLabel: false,\n name: ''\n },\n\n /**\n * Attributes for center point.\n *\n * @type Point\n * @name Conic#center\n */\n center: {\n visible: false,\n withLabel: false,\n name: ''\n },\n\n /**\n * Attributes for five points defining the conic, if some of them are given as coordinates.\n *\n * @type Point\n * @name Conic#point\n */\n point: {\n withLabel: false,\n name: ''\n },\n\n /**\n * Attributes for parabola line in case the line is given by two\n * points or coordinate pairs.\n *\n * @type Line\n * @name Conic#line\n */\n line: {\n visible: false\n }\n\n /**#@-*/\n },\n\n /* special curve options */\n curve: {\n strokeWidth: 1,\n strokeColor: Color.palette.blue,\n fillColor: 'none',\n fixed: true,\n\n useQDT: false,\n\n /**#@+\n * @visprop\n */\n\n /**\n * The data points of the curve are not connected with straight lines but with bezier curves.\n * @name Curve#handDrawing\n * @type Boolean\n * @default false\n */\n handDrawing: false,\n\n /**\n * The curveType is set in {@link JXG.Curve#generateTerm} and used in {@link JXG.Curve#updateCurve}.\n * Possible values are <ul>\n * <li>'none'</li>\n * <li>'plot': Data plot</li>\n * <li>'parameter': we can not distinguish function graphs and parameter curves</li>\n * <li>'functiongraph': function graph</li>\n * <li>'polar'</li>\n * <li>'implicit' (not yet)</li></ul>\n * Only parameter and plot are set directly. Polar is set with {@link JXG.GeometryElement#setAttribute} only.\n * @name Curve#curveType\n * @type String\n * @default null\n */\n curveType: null,\n\n /**\n * Apply Ramer-Douglas-Peuker smoothing.\n *\n * @type Boolean\n * @name Curve#RDPsmoothing\n * @default false\n */\n RDPsmoothing: false, // Apply the Ramer-Douglas-Peuker algorithm\n\n /**\n * Number of points used for plotting triggered by up events\n * (i.e. high quality plotting) in case\n * {@link Curve#doAdvancedPlot} is false.\n *\n * @name Curve#numberPointsHigh\n * @see Curve#doAdvancedPlot\n * @type Number\n * @default 1600\n */\n numberPointsHigh: 1600, // Number of points on curves after mouseUp\n\n /**\n * Number of points used for plotting triggered by move events\n * (i.e. lower quality plotting but fast) in case\n * {@link Curve#doAdvancedPlot} is false.\n *\n * @name Curve#numberPointsLow\n * @see Curve#doAdvancedPlot\n * @type Number\n * @default 400\n */\n numberPointsLow: 400, // Number of points on curves after mousemove\n\n /**\n * If true use a recursive bisection algorithm.\n * It is slower, but usually the result is better. It tries to detect jumps\n * and singularities.\n *\n * @name Curve#doAdvancedPlot\n * @type Boolean\n * @default true\n */\n doAdvancedPlot: true,\n\n /**\n *\n * Recursion depth used for plotting triggered by up events\n * (i.e. high quality plotting) in case\n * {@link Curve#doAdvancedPlot} is true.\n *\n * @name Curve#recursionDepthHigh\n * @see Curve#doAdvancedPlot\n * @type Number\n * @default 17\n */\n recursionDepthHigh: 17,\n\n /**\n * Number of points used for plotting triggered by move events in case\n * (i.e. lower quality plotting but fast)\n * {@link Curve#doAdvancedPlot} is true.\n *\n * @name Curve#recursionDepthLow\n * @see Curve#doAdvancedPlot\n * @type Number\n * @default 13\n */\n recursionDepthLow: 15,\n\n /**\n * If true use the algorithm by Gillam and Hohenwarter, which was default until version 0.98.\n *\n * @name Curve#doAdvancedPlotOld\n * @see Curve#doAdvancedPlot\n * @type Boolean\n * @default false\n * @deprecated\n */\n doAdvancedPlotOld: false, // v1\n\n /**\n * Select the version of the plot algorithm.\n * <ul>\n * <li> Version 1 is very outdated\n * <li> Version 2 is the default version in JSXGraph v0.99.*, v1.0, and v1.1, v1.2.0\n * <li> Version 3 is an internal version that was never published in a stable version.\n * <li> Version 4 is available since JSXGraph v1.2.0\n * </ul>\n * Version 4 plots correctly logarithms if the function term is supplied as string (i.e. as JessieCode)\n *\n * @example\n * var c = board.create('functiongraph', [\"log(x)\"]);\n *\n * @name Curve#plotVersion\n * @type Number\n * @default 2\n */\n plotVersion: 2,\n\n /**\n * Attributes for circle label.\n *\n * @type Label\n * @name Circle#label\n */\n label: {\n position: 'lft'\n },\n\n /**\n * Configure arrow head at the start position for curve.\n * Recommended arrow head type is 7.\n *\n * @name Curve#firstArrow\n * @type Boolean / Object\n * @default false\n * @see Line#firstArrow for options\n */\n firstArrow: false,\n\n /**\n * Configure arrow head at the end position for curve.\n * Recommended arrow head type is 7.\n *\n * @name Curve#lastArrow\n * @see Line#lastArrow for options\n * @type Boolean / Object\n * @default false\n */\n lastArrow: false\n\n /**#@-*/\n },\n\n /* special foreignObject options */\n foreignobject: {\n\n /**#@+\n * @visprop\n */\n attractors: [],\n fixed: true,\n visible: true\n\n /**#@-*/\n },\n\n glider: {\n /**#@+\n * @visprop\n */\n\n label: {}\n /**#@-*/\n },\n\n /* special grid options */\n grid: {\n /**#@+\n * @visprop\n */\n\n /* grid styles */\n needsRegularUpdate: false,\n hasGrid: false,\n gridX: 1,\n gridY: 1,\n //strokeColor: '#c0c0c0',\n strokeColor: '#c0c0c0',\n strokeOpacity: 0.5,\n strokeWidth: 1,\n dash: 0, // dashed grids slow down the iPad considerably\n /* snap to grid options */\n\n /**\n * @deprecated\n */\n snapToGrid: false,\n /**\n * @deprecated\n */\n snapSizeX: 10,\n /**\n * @deprecated\n */\n snapSizeY: 10\n\n /**#@-*/\n },\n\n group: {\n needsRegularUpdate: true\n },\n\n /* special html slider options */\n htmlslider: {\n /**#@+\n * @visprop\n */\n\n /**\n *\n * These affect the DOM element input type=\"range\".\n * The other attributes affect the DOM element div containing the range element.\n */\n widthRange: 100,\n widthOut: 34,\n step: 0.01,\n\n frozen: true,\n isLabel: false,\n strokeColor: '#000000',\n display: 'html',\n anchorX: 'left',\n anchorY: 'middle',\n withLabel: false\n\n /**#@-*/\n },\n\n /* special image options */\n image: {\n /**#@+\n * @visprop\n */\n\n imageString: null,\n fillOpacity: 1.0,\n highlightFillOpacity: 0.6,\n\n\n /**\n * Defines the CSS class used by the image. CSS attributes defined in\n * this class will overwrite the corresponding JSXGraph attributes, e.g.\n * opacity.\n * The default CSS class is defined in jsxgraph.css.\n *\n * @name Image#cssClass\n *\n * @see Image#highlightCssClass\n * @type String\n * @default 'JXGimage'\n */\n cssClass: 'JXGimage',\n\n /**\n * Defines the CSS class used by the image when highlighted.\n * CSS attributes defined in this class will overwrite the\n * corresponding JSXGraph attributes, e.g. highlightFillOpacity.\n * The default CSS class is defined in jsxgraph.css.\n *\n * @name Image#highlightCssClass\n *\n * @see Image#cssClass\n * @type String\n * @default 'JXGimageHighlight'\n */\n highlightCssClass: 'JXGimageHighlight',\n\n /**\n * Image rotation in degrees.\n *\n * @name Image#rotate\n * @type Number\n * @default 0\n */\n rotate: 0,\n\n /**\n * Defines together with {@link Image#snapSizeY} the grid the image snaps on to.\n * The image will only snap on user coordinates which are\n * integer multiples to snapSizeX in x and snapSizeY in y direction.\n * If this value is equal to or less than <tt>0</tt>, it will use the grid displayed by the major ticks\n * of the default ticks of the default x axes of the board.\n *\n * @name Image#snapSizeX\n *\n * @see Point#snapToGrid\n * @see Image#snapSizeY\n * @see JXG.Board#defaultAxes\n * @type Number\n * @default 1\n */\n snapSizeX: 1,\n\n /**\n * Defines together with {@link Image#snapSizeX} the grid the image snaps on to.\n * The image will only snap on integer multiples to snapSizeX in x and snapSizeY in y direction.\n * If this value is equal to or less than <tt>0</tt>, it will use the grid displayed by the major ticks\n * of the default ticks of the default y axes of the board.\n *\n * @name Image#snapSizeY\n *\n * @see Point#snapToGrid\n * @see Image#snapSizeX\n * @see JXG.Board#defaultAxes\n * @type Number\n * @default 1\n */\n snapSizeY: 1,\n\n /**\n * List of attractor elements. If the distance of the image is less than\n * attractorDistance the image is made to glider of this element.\n *\n * @name Image#attractors\n *\n * @type Array\n * @default empty\n */\n attractors: []\n\n /**#@-*/\n },\n\n /* special options for incircle of 3 points */\n incircle: {\n /**#@+\n * @visprop\n */\n\n fillColor: 'none',\n highlightFillColor: 'none',\n strokeColor: Color.palette.blue,\n highlightStrokeColor: '#c3d9ff',\n\n /**\n * Attributes of circle center.\n *\n * @type Point\n * @name Incircle#center\n */\n center: { // center point\n visible: false,\n fixed: false,\n withLabel: false,\n fillColor: Color.palette.red,\n strokeColor: Color.palette.red,\n highlightFillColor: '#c3d9ff',\n highlightStrokeColor: '#c3d9ff',\n name: ''\n }\n /**#@-*/\n },\n\n inequality: {\n /**#@+\n * @visprop\n */\n\n fillColor: Color.palette.red,\n fillOpacity: 0.2,\n strokeColor: 'none',\n\n /**\n * By default an inequality is less (or equal) than. Set inverse to <tt>true</tt> will consider the inequality\n * greater (or equal) than.\n *\n * @type Boolean\n * @default false\n * @name Inequality#inverse\n * @visprop\n */\n inverse: false\n /**#@-*/\n },\n\n infobox: {\n /**#@+\n * @visprop\n */\n\n fontSize: 12,\n isLabel: false,\n strokeColor: '#bbbbbb',\n display: 'html', // 'html' or 'internal'\n anchorX: 'left', // 'left', 'middle', or 'right': horizontal alignment\n // of the text.\n anchorY: 'middle', // 'top', 'middle', or 'bottom': vertical alignment\n // of the text.\n cssClass: 'JXGinfobox',\n rotate: 0, // works for non-zero values only in combination\n // with display=='internal'\n visible: true,\n parse: false,\n transitionDuration: 0,\n needsRegularUpdate: false\n\n /**#@-*/\n },\n\n /* special options for integral */\n integral: {\n /**#@+\n * @visprop\n */\n\n axis: 'x', // 'x' or 'y'\n withLabel: true, // Show integral value as text\n fixed: true,\n strokeWidth: 0,\n strokeOpacity: 0,\n fillColor: Color.palette.red,\n fillOpacity: 0.3,\n highlightFillColor: Color.palette.red,\n highlightFillOpacity: 0.2,\n\n /**\n * Attributes of the (left) starting point of the integral.\n *\n * @type Point\n * @name Integral#curveLeft\n * @see Integral#baseLeft\n */\n curveLeft: { // Start point\n visible: true,\n withLabel: false,\n color: Color.palette.red,\n fillOpacity: 0.8,\n layer: 9\n },\n\n /**\n * Attributes of the (left) base point of the integral.\n *\n * @type Point\n * @name Integral#baseLeft\n * @see Integral#curveLeft\n */\n baseLeft: { // Start point\n visible: false,\n fixed: false,\n withLabel: false,\n name: ''\n },\n\n /**\n * Attributes of the (right) end point of the integral.\n *\n * @type Point\n * @name Integral#curveRight\n * @see Integral#baseRight\n */\n curveRight: { // End point\n visible: true,\n withLabel: false,\n color: Color.palette.red,\n fillOpacity: 0.8,\n layer: 9\n },\n\n /**\n * Attributes of the (right) base point of the integral.\n *\n * @type Point\n * @name Integral#baseRight\n * @see Integral#curveRight\n */\n baseRight: { // End point\n visible: false,\n fixed: false,\n withLabel: false,\n name: ''\n },\n\n /**\n * Attributes for integral label.\n *\n * @type Label\n * @name Integral#label\n */\n label: {\n fontSize: 20\n }\n /**#@-*/\n },\n\n /* special input options */\n input: {\n /**#@+\n * @visprop\n */\n\n /**\n * Control the attribute \"disabled\" of the HTML input field.\n *\n * @name disabled\n * @memberOf Input.prototype\n *\n * @type Boolean\n * @default false\n */\n disabled: false,\n\n /**\n * Control the attribute \"maxlength\" of the HTML input field.\n *\n * @name maxlength\n * @memberOf Input.prototype\n *\n * @type Number\n * @default 524288 (as in HTML)\n */\n maxlength: 524288,\n\n display: 'html'\n\n /**#@-*/\n },\n\n /* special intersection point options */\n intersection: {\n /**#@+\n * @visprop\n */\n\n /**\n * Used in {@link JXG.Intersection}.\n * This flag sets the behaviour of intersection points of e.g.\n * two segments. If true, the intersection is treated as intersection of lines. If false\n * the intersection point exists if the segments intersect setwise.\n *\n * @name Intersection.alwaysIntersect\n * @type Boolean\n * @default true\n */\n alwaysIntersect: true\n\n /**#@-*/\n },\n\n /* special label options */\n label: {\n /**#@+\n * @visprop\n */\n\n visible: 'inherit',\n strokeColor: '#000000',\n strokeOpacity: 1,\n highlightStrokeOpacity: 0.666666,\n highlightStrokeColor: '#000000',\n\n fixed: true,\n\n /**\n * Possible string values for the position of a label for\n * label anchor points are:\n * <ul>\n * <li> 'lft'\n * <li> 'rt'\n * <li> 'top'\n * <li> 'bot'\n * <li> 'ulft'\n * <li> 'urt'\n * <li> 'llft'\n * <li> 'lrt'\n * </ul>\n * This is relevant for non-points: line, circle, curve.\n *\n * The names have been borrowed from <a href=\"https://www.tug.org/metapost.html\">MetaPost</a>.\n *\n * @name Label#position\n * @see Label#offset\n * @type String\n * @default 'urt'\n */\n position: 'urt',\n\n /**\n * Label offset from label anchor.\n * The label anchor is determined by {@link Label#position}\n *\n * @name Label#offset\n * @see Label#position\n * @type Array\n * @default [10,10]\n */\n offset: [10, 10],\n\n /**\n * Automatic position of label text. When called first, the positioning algorithm\n * starts at the position defined by offset.\n * The algorithm tries to find a position with the least number of\n * overlappings with other elements, while retaining the distance\n * to the anchor element.\n *\n * @name Label#autoPosition\n * @see Label#offset\n * @type Boolean\n * @default false\n *\n * @example\n * \tvar p1 = board.create('point', [-2, 1], {id: 'A'});\n * \tvar p2 = board.create('point', [-0.85, 1], {\n * name: 'B', id: 'B', label:{autoPosition: true, offset:[10, 10]}\n * });\n * \tvar p3 = board.create('point', [-1, 1.2], {\n * name: 'C', id: 'C', label:{autoPosition: true, offset:[10, 10]}\n * });\n * var c = board.create('circle', [p1, p2]);\n * \tvar l = board.create('line', [p1, p2]);\n *\n * </pre><div id=\"JXG7d4dafe7-1a07-4d3f-95cb-bfed9d96dea2\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG7d4dafe7-1a07-4d3f-95cb-bfed9d96dea2',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * \tvar p1 = board.create('point', [-2, 1], {id: 'A'});\n * \tvar p2 = board.create('point', [-0.85, 1], {name: 'B', id: 'B', label:{autoPosition: true, offset:[10, 10]}});\n * \tvar p3 = board.create('point', [-1, 1.2], {name: 'C', id: 'C', label:{autoPosition: true, offset:[10, 10]}});\n * var c = board.create('circle', [p1, p2]);\n * \tvar l = board.create('line', [p1, p2]);\n *\n * })();\n *\n * </script><pre>\n *\n *\n */\n autoPosition: false\n\n /**#@-*/\n },\n\n /* special legend options */\n legend: {\n /**\n * @visprop\n */\n\n /**\n * Default style of a legend element. The only possible value is 'vertical'.\n * @name: Legend#style\n * @type String\n * @default 'vertical'\n */\n style: 'vertical',\n\n /**\n * Label names of a legend element.\n * @name: Legend#labels\n * @type Array\n * @default \"['1', '2', '3', '4', '5', '6', '7', '8']\"\n */\n labels: ['1', '2', '3', '4', '5', '6', '7', '8'],\n\n /**\n * (Circular) array of label colors.\n * @name: Legend#colors\n * @type Array\n * @default \"['#B02B2C', '#3F4C6B', '#C79810', '#D15600', '#FFFF88', '#c3d9ff', '#4096EE', '#008C00']\"\n */\n colors: ['#B02B2C', '#3F4C6B', '#C79810', '#D15600', '#FFFF88', '#c3d9ff', '#4096EE', '#008C00'],\n\n /**\n * Height (in px) of one legend entry\n * @name: Legend#rowHeight\n * @type Number\n * @default 20\n *\n */\n rowHeight: 20,\n\n strokeWidth: 5\n\n /**#@-*/\n },\n\n /* special line options */\n line: {\n /**#@+\n * @visprop\n */\n\n /**\n * Configure the arrow head at the position of its first point or the corresponding\n * intersection with the canvas border\n *\n * In case firstArrow is an object it has the sub-attributes:\n * <pre>\n * {\n * type: 1, // possible values are 1, 2, ..., 7. Default value is 1.\n * size: 6, // size of the arrow head. Default value is 6.\n * // This value is multiplied with the strokeWidth of the line\n * // Exception: for type=7 size is ignored\n * highlightSize: 6, // size of the arrow head in case the element is highlighted. Default value\n * }\n * </pre>\n * type=7 is the default for curves if firstArrow: true\n *\n * @name Line#firstArrow\n * @see Line#lastArrow\n * @see Line#touchFirstPoint\n * @type Boolean / Object\n * @default false\n */\n firstArrow: false,\n\n /**\n * Configute the arrow head at the position of its second point or the corresponding\n * intersection with the canvas border.\n *\n * In case lastArrow is an object it has the sub-attributes:\n * <pre>\n * {\n * type: 1, // possible values are 1, 2, ..., 7. Default value is 1.\n * size: 6, // size of the arrow head. Default value is 6.\n * // This value is multiplied with the strokeWidth of the line.\n * // Exception: for type=7 size is ignored\n * highlightSize: 6, // size of the arrow head in case the element is highlighted. Default value is 6.\n * }\n * </pre>\n * type=7 is the default for curves if lastArrow: true\n *\n * @example\n * var p1 = board.create('point', [-5, 2], {size:1});\n * var p2 = board.create('point', [5, 2], {size:10});\n * var li = board.create('segment', ['A','B'],\n * {name:'seg',\n * strokeColor:'#000000',\n * strokeWidth:1,\n * highlightStrokeWidth: 5,\n * lastArrow: {type: 2, size: 8, highlightSize: 6},\n * touchLastPoint: true,\n * firstArrow: {type: 3, size: 8}\n * });\n *\n * </pre><div id=\"JXG184e915c-c2ef-11e8-bece-04d3b0c2aad3\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG184e915c-c2ef-11e8-bece-04d3b0c2aad3',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var p1 = board.create('point', [-5, 2], {size:1});\n * var p2 = board.create('point', [5, 2], {size:10});\n * var li = board.create('segment', ['A','B'],\n * {name:'seg',\n * strokeColor:'#000000',\n * strokeWidth:1,\n * highlightStrokeWidth: 5,\n * lastArrow: {type: 2, size: 8, highlightSize: 6},\n * touchLastPoint: true,\n * firstArrow: {type: 3, size: 8}\n * });\n *\n * })();\n *\n * </script>\n *\n * @name Line#lastArrow\n * @see Line#firstArrow\n * @see Line#touchLastPoint\n * @type Boolean / Object\n * @default false\n */\n lastArrow: false,\n\n\n /**\n * This number (pixel value) controls where infinite lines end at the canvas border. If zero, the line\n * ends exactly at the border, if negative there is a margin to the inside, if positive the line\n * ends outside of the canvas (which is invisible).\n *\n * @name: Line#margin\n * @type Number\n * @default 0\n */\n margin: 0,\n\n /**\n * If true, line stretches infinitely in direction of its first point.\n * Otherwise it ends at point1.\n *\n * @name Line#straightFirst\n * @see Line#straightLast\n * @type Boolean\n * @default true\n */\n straightFirst: true,\n\n /**\n * If true, line stretches infinitely in direction of its second point.\n * Otherwise it ends at point2.\n *\n * @name Line#straightLast\n * @see Line#straightFirst\n * @type Boolean\n * @default true\n */\n straightLast: true,\n\n fillColor: 'none', // Important for VML on IE\n highlightFillColor: 'none', // Important for VML on IE\n strokeColor: Color.palette.blue,\n highlightStrokeColor: '#c3d9ff',\n withTicks: false,\n\n /**\n * Attributes for first defining point of the line.\n *\n * @type Point\n * @name Line#point1\n */\n point1: { // Default values for point1 if created by line\n visible: false,\n withLabel: false,\n fixed: false,\n name: ''\n },\n\n /**\n * Attributes for second defining point of the line.\n *\n * @type Point\n * @name Line#point2\n */\n point2: { // Default values for point2 if created by line\n visible: false,\n withLabel: false,\n fixed: false,\n name: ''\n },\n\n /**\n * Attributes for ticks of the line.\n *\n * @type Ticks\n * @name Line#ticks\n */\n ticks: {\n drawLabels: true,\n label: {\n offset: [4, -12 + 3] // This seems to be a good offset for 12 point fonts\n },\n drawZero: false,\n insertTicks: false,\n minTicksDistance: 50,\n minorHeight: 4, // if <0: full width and height\n majorHeight: -1, // if <0: full width and height\n minorTicks: 4,\n defaultDistance: 1,\n strokeOpacity: 0.3,\n visible: 'inherit'\n },\n\n /**\n * Attributes for the line label.\n *\n * @type Label\n * @name Line#label\n */\n label: {\n position: 'llft'\n },\n\n /**\n * If set to true, the point will snap to a grid defined by\n * {@link Point#snapSizeX} and {@link Point#snapSizeY}.\n *\n * @see Point#snapSizeX\n * @see Point#snapSizeY\n * @type Boolean\n * @name Line#snapToGrid\n * @default false\n */\n snapToGrid: false,\n\n /**\n * Defines together with {@link Point#snapSizeY} the grid the point snaps on to.\n * The point will only snap on integer multiples to snapSizeX in x and snapSizeY in y direction.\n * If this value is equal to or less than <tt>0</tt>, it will use the grid displayed by the major ticks\n * of the default ticks of the default x axes of the board.\n *\n * @see Point#snapToGrid\n * @see Point#snapSizeY\n * @see JXG.Board#defaultAxes\n * @type Number\n * @name Line#snapSizeX\n * @default 1\n */\n snapSizeX: 1,\n\n /**\n * Defines together with {@link Point#snapSizeX} the grid the point snaps on to.\n * The point will only snap on integer multiples to snapSizeX in x and snapSizeY in y direction.\n * If this value is equal to or less than <tt>0</tt>, it will use the grid displayed by the major ticks\n * of the default ticks of the default y axes of the board.\n *\n * @see Point#snapToGrid\n * @see Point#snapSizeX\n * @see JXG.Board#defaultAxes\n * @type Number\n * @name Line#snapSizeY\n * @default 1\n */\n snapSizeY: 1,\n\n /**\n * If set to true and {@link Line#firstArrow} is set to true, the arrow head will just touch\n * the circle line of the start point of the line.\n *\n * @see Line#firstArrow\n * @type Boolean\n * @name Line#touchFirstPoint\n * @default false\n */\n touchFirstPoint: false,\n\n /**\n * If set to true and {@link Line#lastArrow} is set to true, the arrow head will just touch\n * the circle line of the start point of the line.\n * @see Line#firstArrow\n * @type Boolean\n * @name Line#touchLastPoint\n * @default false\n */\n touchLastPoint: false,\n\n /**\n * Line endings (linecap) of a straight line.\n * Possible values are:\n * <ul>\n * <li> 'butt',\n * <li> 'round',\n * <li> 'square'.\n * </ul>\n * Not available for VML renderer.\n * [lineCap description]\n * @name Line#lineCap\n * @type String\n * @default 'butt'\n */\n lineCap: 'butt'\n\n\n /**#@-*/\n },\n\n /* special options for locus curves */\n locus: {\n /**#@+\n * @visprop\n */\n\n translateToOrigin: false,\n translateTo10: false,\n stretch: false,\n toOrigin: null,\n to10: null\n /**#@-*/\n },\n\n /* special cardinal spline options */\n metapostspline: {\n /**#@+\n * @visprop\n */\n\n /**\n * Controls if the data points of the cardinal spline when given as\n * arrays should be converted into {@link JXG.Points}.\n *\n * @name createPoints\n * @memberOf Metapostspline.prototype\n *\n * @see Metapostspline#points\n *\n * @type Boolean\n * @default true\n */\n createPoints: true,\n\n /**\n * If set to true, the supplied coordinates are interpreted as\n * [[x_0, y_0], [x_1, y_1], p, ...].\n * Otherwise, if the data consists of two arrays of equal length,\n * it is interpreted as\n * [[x_o x_1, ..., x_n], [y_0, y_1, ..., y_n]]\n *\n * @name isArrayOfCoordinates\n * @memberOf Metapostspline.prototype\n * @type Boolean\n * @default false\n */\n isArrayOfCoordinates: false,\n\n /**\n * Attributes for the points generated by Metapostspline in cases\n * {@link createPoints} is set to true\n *\n * @name points\n * @memberOf Metapostspline.prototype\n *\n * @see Metapostspline#createPoints\n * @type Object\n */\n points: {\n strokeOpacity: 0.05,\n fillOpacity: 0.05,\n highlightStrokeOpacity: 1.0,\n highlightFillOpacity: 1.0,\n withLabel: false,\n name: '',\n fixed: false\n }\n\n /**#@-*/\n },\n\n /* special mirrorelement options */\n mirrorelement: {\n /**#@+\n * @visprop\n */\n\n fixed: true,\n\n /**\n * Attributes of mirror point, i.e. the point along which the element is mirrored.\n *\n * @type Point\n * @name mirrorelement#point\n */\n point: {},\n\n /**\n * Attributes of circle center, i.e. the center of the circle,\n * if a circle is the mirror element and the transformation type is 'Euclidean'\n *\n * @type Point\n * @name mirrorelement#center\n */\n center: {},\n\n /**\n * Type of transformation. Possible values are 'Euclidean', 'projective'.\n *\n * If the value is 'Euclidean', the mirror element of a circle is again a circle,\n * otherwise it is a conic section.\n *\n * @type String\n * @name mirrorelement#type\n * @default 'Euclidean'\n */\n type: 'Euclidean'\n\n /**#@-*/\n },\n\n // /* special options for Msector of 3 points */\n // msector: {\n // strokeColor: '#000000', // Msector line\n // point: { // Msector point\n // visible: false,\n // fixed: false,\n // withLabel: false,\n // name: ''\n // }\n // },\n\n /* special options for normal lines */\n normal: {\n /**#@+\n * @visprop\n */\n\n strokeColor: '#000000', // normal line\n\n /**\n * Attributes of helper point of normal.\n *\n * @type Point\n * @name Normal#point\n */\n point: {\n visible: false,\n fixed: false,\n withLabel: false,\n name: ''\n }\n /**#@-*/\n },\n\n /* special options for orthogonal projection points */\n orthogonalprojection: {\n /**#@+\n * @visprop\n */\n\n\n /**#@-*/\n },\n\n /* special options for parallel lines */\n parallel: {\n /**#@+\n * @visprop\n */\n\n strokeColor: '#000000', // Parallel line\n\n /**\n * Attributes of helper point of normal.\n *\n * @type Point\n * @name Parallel#point\n */\n point: {\n visible: false,\n fixed: false,\n withLabel: false,\n name: ''\n },\n\n label: {\n position: 'llft'\n }\n /**#@-*/\n },\n\n /* special perpendicular options */\n perpendicular: {\n /**#@+\n * @visprop\n */\n\n strokeColor: '#000000', // Perpendicular line\n straightFirst: true,\n straightLast: true\n /**#@-*/\n },\n\n /* special perpendicular options */\n perpendicularsegment: {\n /**#@+\n * @visprop\n */\n\n strokeColor: '#000000', // Perpendicular segment\n straightFirst: false,\n straightLast: false,\n point: { // Perpendicular point\n visible: false,\n fixed: true,\n withLabel: false,\n name: ''\n }\n /**#@-*/\n },\n\n /* special point options */\n point: {\n /**#@+\n * @visprop\n */\n\n withLabel: true,\n label: {},\n\n /**\n * This attribute was used to determined the point layout. It was derived from GEONExT and was\n * replaced by {@link Point#face} and {@link Point#size}.\n *\n * @name Point#style\n *\n * @see Point#face\n * @see Point#size\n * @type Number\n * @default 5\n * @deprecated\n */\n style: 5,\n\n /**\n * There are different point styles which differ in appearance.\n * Posssible values are\n * <table><tr><th>Value</th></tr>\n * <tr><td>cross</td></tr>\n * <tr><td>circle</td></tr>\n * <tr><td>square</td></tr>\n * <tr><td>plus</td></tr>\n * <tr><td>diamond</td></tr>\n * <tr><td>triangleUp</td></tr>\n * <tr><td>triangleDown</td></tr>\n * <tr><td>triangleLeft</td></tr>\n * <tr><td>triangleRight</td></tr>\n * </table>\n *\n * @name Point#face\n *\n * @type String\n * @see JXG.Point#setStyle\n * @default circle\n */\n face: 'o',\n\n /**\n * Size of a point, either in pixel or user coordinates.\n * Means radius resp. half the width of a point (depending on the face).\n *\n * @name Point#size\n *\n * @see Point#face\n * @see JXG.Point#setStyle\n * @see Point#sizeUnit\n * @type Number\n * @default 3\n */\n size: 3,\n\n /**\n * Unit for size.\n * Possible values are 'screen' and 'user.\n *\n * @name Point#sizeUnit\n *\n * @see Point#size\n * @type String\n * @default 'screen'\n */\n sizeUnit: 'screen',\n\n strokeWidth: 2,\n\n fillColor: Color.palette.red,\n strokeColor: Color.palette.red,\n highlightFillColor:'#c3d9ff',\n highlightStrokeColor: '#c3d9ff',\n // strokeOpacity: 1.0,\n // fillOpacity: 1.0,\n // highlightFillOpacity: 0.5,\n // highlightStrokeOpacity: 0.5,\n\n // fillColor: '#ff0000',\n // highlightFillColor: '#eeeeee',\n // strokeWidth: 2,\n // strokeColor: '#ff0000',\n // highlightStrokeColor: '#c3d9ff',\n\n /**\n * If true, the point size changes on zoom events.\n *\n * @type Boolean\n * @name Point#zoom\n * @default false\n *\n */\n zoom: false, // Change the point size on zoom\n\n /**\n * If true, the infobox is shown on mouse/pen over, if false not.\n * If the value is 'inherit', the value of\n * {@link JXG.Board#showInfobox} is taken.\n *\n * @name Point#showInfobox\n * @see JXG.Board#showInfobox\n * @type {Boolean|String} true | false | 'inherit'\n * @default true\n */\n showInfobox: 'inherit',\n\n /**\n * Truncating rule for the digits in the infobox.\n * <ul>\n * <li>'auto': done automatically by JXG.autoDigits()\n * <li>'none': no truncation\n * <li>number: truncate after \"number digits\" with JXG.toFixed()\n * </ul>\n *\n * @name Point#infoboxDigits\n *\n * @type String, Number\n * @default 'auto'\n * @see JXG#autoDigits\n * @see JXG#toFixed\n */\n infoboxDigits: 'auto',\n\n draft: false,\n\n /**\n * List of attractor elements. If the distance of the point is less than\n * attractorDistance the point is made to glider of this element.\n *\n * @name Point#attractors\n *\n * @type Array\n * @default empty\n */\n attractors: [],\n\n /**\n * Unit for attractorDistance and snatchDistance, used for magnetized points and for snapToPoints.\n * Possible values are 'screen' and 'user'.\n *\n * @name Point#attractorUnit\n *\n * @see Point#attractorDistance\n * @see Point#snatchDistance\n * @see Point#snapToPoints\n * @see Point#attractors\n * @type String\n * @default 'user'\n */\n attractorUnit: 'user', // 'screen', 'user'\n\n /**\n * If the distance of the point to one of its attractors is less\n * than this number the point will be a glider on this\n * attracting element.\n * If set to zero nothing happens.\n *\n * @name Point#attractorDistance\n *\n * @type Number\n * @default 0.0\n */\n attractorDistance: 0.0,\n\n /**\n * If the distance of the point to one of its attractors is at least\n * this number the point will be released from being a glider on the\n * attracting element.\n * If set to zero nothing happens.\n *\n * @name Point#snatchDistance\n *\n * @type Number\n * @default 0.0\n */\n snatchDistance: 0.0,\n\n /**\n * If set to true, the point will snap to a grid of integer multiples of\n * {@link Point#snapSizeX} and {@link Point#snapSizeY} (in user coordinates).\n * <p>\n * The coordinates of the grid points are either integer multiples of snapSizeX and snapSizeY\n * (given in user coordinates, not pixels) or are the intersection points\n * of the major ticks of the boards default axes in case that snapSizeX, snapSizeY are negative.\n *\n * @name Point#snapToGrid\n *\n * @see Point#snapSizeX\n * @see Point#snapSizeY\n * @type Boolean\n * @default false\n */\n snapToGrid: false,\n\n /**\n * If set to true, the point will only snap to (possibly invisibly) grid points\n * when within {@link Point#attractorDistance} of such a grid point.\n * <p>\n * The coordinates of the grid points are either integer multiples of snapSizeX and snapSizeY\n * (given in user coordinates, not pixels) or are the intersection points\n * of the major ticks of the boards default axes in case that snapSizeX, snapSizeY are negative.\n *\n * @name Point#attractToGrid\n *\n * @see Point#attractorDistance\n * @see Point#attractorUnit\n * @see Point#snapToGrid\n * @see Point#snapSizeX\n * @see Point#snapSizeY\n * @type Boolean\n * @default false\n *\n * @example\n * board.create('point', [3, 3], { attractToGrid: true, attractorDistance: 10, attractorunit: 'screen' });\n *\n * </pre><div id=\"JXG397ab787-cd40-449c-a7e7-a3f7bab1d4f6\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG397ab787-cd40-449c-a7e7-a3f7bab1d4f6',\n * {boundingbox: [-1, 4, 7,-4], axis: true, showcopyright: false, shownavigation: false});\n * board.create('point', [3, 3], { attractToGrid: true, attractorDistance: 10, attractorunit: 'screen' });\n *\n * })();\n *\n * </script><pre>\n *\n */\n attractToGrid: false,\n\n /**\n * Defines together with {@link Point#snapSizeY} the grid the point snaps on to.\n * It is given in user coordinates, not in pixels.\n * The point will only snap on integer multiples to snapSizeX in x and snapSizeY in y direction.\n * If this value is equal to or less than <tt>0</tt>, it will use the grid displayed by the major ticks\n * of the default ticks of the default x axes of the board.\n *\n * @name Point#snapSizeX\n *\n * @see Point#snapToGrid\n * @see Point#snapSizeY\n * @see JXG.Board#defaultAxes\n * @type Number\n * @default 1\n */\n snapSizeX: 1,\n\n /**\n * Defines together with {@link Point#snapSizeX} the grid the point snaps on to.\n * It is given in user coordinates, not in pixels.\n * The point will only snap on integer multiples to snapSizeX in x and snapSizeY in y direction.\n * If this value is equal to or less than <tt>0</tt>, it will use the grid displayed by the major ticks\n * of the default ticks of the default y axes of the board.\n *\n * @name Point#snapSizeY\n *\n * @see Point#snapToGrid\n * @see Point#snapSizeX\n * @see JXG.Board#defaultAxes\n * @type Number\n * @default 1\n */\n snapSizeY: 1,\n\n /**\n * If set to true, the point will snap to the nearest point in distance of\n * {@link Point#attractorDistance}.\n *\n * @name Point#snapToPoints\n *\n * @see Point#attractorDistance\n * @type Boolean\n * @default false\n */\n snapToPoints: false,\n\n /**\n * List of elements which are ignored by snapToPoints.\n * @name Point#ignoredSnapToPoints\n *\n * @type Array\n * @default empty\n */\n ignoredSnapToPoints: []\n\n /**#@-*/\n },\n\n /* special polygon options */\n polygon: {\n /**#@+\n * @visprop\n */\n\n /**\n * If <tt>true</tt>, moving the mouse over inner points triggers hasPoint.\n *\n * @see JXG.GeometryElement#hasPoint\n * @name Polygon#hasInnerPoints\n * @type Boolean\n * @default false\n */\n hasInnerPoints: false,\n\n fillColor: Color.palette.yellow,\n highlightFillColor: Color.palette.yellow,\n // fillColor: '#00ff00',\n // highlightFillColor: '#00ff00',\n fillOpacity: 0.3,\n highlightFillOpacity: 0.2,\n\n /**\n * Is the polygon bordered by lines?\n *\n * @type Boolean\n * @name Polygon#withLines\n * @default true\n */\n withLines: true,\n\n /**\n * Attributes for the polygon border lines.\n *\n * @type Line\n * @name Polygon#borders\n */\n borders: {\n withLabel: false,\n strokeWidth: 1,\n highlightStrokeWidth: 1,\n // Polygon layer + 1\n layer: 5,\n label: {\n position: 'top'\n },\n visible: 'inherit'\n },\n\n /**\n * Attributes for the polygon vertices.\n *\n * @type Point\n * @name Polygon#vertices\n */\n vertices: {\n layer: 9,\n withLabel: false,\n name: '',\n strokeColor: Color.palette.red,\n fillColor: Color.palette.red,\n fixed: false,\n visible: 'inherit'\n },\n\n /**\n * Attributes for the polygon label.\n *\n * @type Label\n * @name Polygon#label\n */\n label: {\n offset: [0, 0]\n }\n\n /**#@-*/\n },\n\n /* special polygonal chain options\n */\n polygonalchain: {\n /**#@+\n * @visprop\n */\n\n fillColor: 'none',\n highlightFillColor: 'none'\n\n /**#@-*/\n },\n\n /* special prescribed angle options\n * Not yet implemented. But angle.setAngle(val) is implemented.\n */\n prescribedangle: {\n /**#@+\n * @visprop\n */\n\n /**\n * Attributes for the helper point of the prescribed angle.\n *\n * @type Point\n * @name PrescribedAngle#anglePoint\n */\n anglePoint: {\n size: 2,\n visible: false,\n withLabel: false\n }\n\n /**#@-*/\n },\n\n /* special reflection options */\n reflection: {\n /**#@+\n * @visprop\n */\n\n fixed: true,\n\n /**\n * Attributes of circle center, i.e. the center of the circle,\n * if a circle is the mirror element and the transformation type is 'Euclidean'\n *\n * @type Point\n * @name mirrorelement#center\n */\n center: {},\n\n /**\n * Type of transformation. Possible values are 'Euclidean', 'projective'.\n *\n * If the value is 'Euclidean', the reflected element of a circle is again a circle,\n * otherwise it is a conic section.\n *\n * @type String\n * @name reflection#type\n * @default 'Euclidean'\n */\n type: 'Euclidean'\n\n /**#@-*/\n },\n\n /* special regular polygon options */\n regularpolygon: {\n /**#@+\n * @visprop\n */\n\n /**\n * If <tt>true</tt>, moving the mouse over inner points triggers hasPoint.\n * @see JXG.GeometryElement#hasPoint\n *\n * @name RegularPolygon#hasInnerPoints\n * @type Boolean\n * @default false\n */\n hasInnerPoints: false,\n fillColor: Color.palette.yellow,\n highlightFillColor: Color.palette.yellow,\n fillOpacity: 0.3,\n highlightFillOpacity: 0.2,\n\n /**\n * Is the polygon bordered by lines?\n *\n * @type Boolean\n * @name RegularPolygon#withLines\n * @default true\n */\n withLines: true,\n\n /**\n * Attributes for the polygon border lines.\n *\n * @type Line\n * @name RegularPolygon#borders\n */\n borders: {\n withLabel: false,\n strokeWidth: 1,\n highlightStrokeWidth: 1,\n // Polygon layer + 1\n layer: 5,\n label: {\n position: 'top'\n }\n },\n\n /**\n * Attributes for the polygon vertices.\n *\n * @type Point\n * @name RegularPolygon#vertices\n */\n vertices: {\n layer: 9,\n withLabel: true,\n strokeColor: Color.palette.red,\n fillColor: Color.palette.red,\n fixed: false\n },\n\n /**\n * Attributes for the polygon label.\n *\n * @type Label\n * @name Polygon#label\n */\n label: {\n offset: [0, 0]\n }\n\n /**#@-*/\n },\n\n /* special options for riemann sums */\n riemannsum: {\n /**#@+\n * @visprop\n */\n\n withLabel: false,\n fillOpacity: 0.3,\n fillColor: Color.palette.yellow\n\n /**#@-*/\n },\n\n /* special sector options */\n sector: {\n /**#@+\n * @visprop\n */\n\n fillColor: Color.palette.yellow,\n highlightFillColor: Color.palette.yellow,\n // fillColor: '#00ff00',\n // highlightFillColor: '#00ff00',\n\n fillOpacity: 0.3,\n highlightFillOpacity: 0.3,\n highlightOnSector: false,\n highlightStrokeWidth: 0,\n\n /**\n * Type of sector. Possible values are 'minor', 'major', and 'auto'.\n *\n * @type String\n * @name Sector#selection\n * @default 'auto'\n */\n selection: 'auto',\n\n /**\n * Attributes for sub-element arc. It is only available, if the sector is defined by three points.\n *\n * @type Arc\n * @name Sector#arc\n * @default '{visible:false}'\n */\n arc: {\n visible: false,\n fillColor: 'none'\n },\n\n /**\n * Attributes for helper point radiuspoint in case it is provided by coordinates.\n *\n * @type Point\n * @name Sector#radiusPoint\n */\n radiusPoint: {\n visible: false,\n withLabel: false\n },\n\n /**\n * Attributes for helper point center in case it is provided by coordinates.\n *\n * @type Point\n * @name Sector#center\n */\n center: {\n visible: false,\n withLabel: false\n },\n\n /**\n * Attributes for helper point anglepoint in case it is provided by coordinates.\n *\n * @type Point\n * @name Sector#anglePoint\n */\n anglePoint: {\n visible: false,\n withLabel: false\n },\n\n /**\n * Attributes for the sector label.\n *\n * @type Label\n * @name Sector#label\n */\n label: {\n offset: [0, 0],\n anchorX: 'auto',\n anchorY: 'auto'\n }\n\n /**#@-*/\n },\n\n /* special segment options */\n segment: {\n /**#@+\n * @visprop\n */\n\n label: {\n position: 'top'\n }\n /**#@-*/\n },\n\n semicircle: {\n /**#@+\n * @visprop\n */\n\n /**\n * Attributes for center point of the semicircle.\n *\n * @type Point\n * @name Semicircle#center\n */\n center: {\n visible: false,\n withLabel: false,\n fixed: false,\n fillColor: Color.palette.red,\n strokeColor: Color.palette.red,\n highlightFillColor:'#eeeeee',\n highlightStrokeColor: Color.palette.red,\n name: ''\n }\n\n /**#@-*/\n },\n\n /* special slider options */\n slider: {\n /**#@+\n * @visprop\n */\n\n /**\n * The slider only returns integer multiples of this value, e.g. for discrete values set this property to <tt>1</tt>. For\n * continuous results set this to <tt>-1</tt>.\n *\n * @memberOf Slider.prototype\n * @name snapWidth\n * @type Number\n */\n snapWidth: -1, // -1 = deactivated\n\n /**\n * The precision of the slider value displayed in the optional text.\n * Replaced by the attribute \"digits\".\n *\n * @memberOf Slider.prototype\n * @name precision\n * @type Number\n * @deprecated\n * @see Slider#digits\n * @default 2\n */\n precision: 2,\n\n /**\n * The number of digits of the slider value displayed in the optional text.\n *\n * @memberOf Slider.prototype\n * @name digits\n * @type Number\n * @default 2\n */\n digits: 2,\n\n firstArrow: false,\n lastArrow: false,\n\n /**\n * Show slider ticks.\n *\n * @type Boolean\n * @name Slider#withTicks\n * @default true\n */\n withTicks: true,\n\n /**\n * Show slider label.\n *\n * @type Boolean\n * @name Slider#withLabel\n * @default true\n */\n withLabel: true,\n\n /**\n * If not null, this replaces the part \"name = \" in the slider label.\n * Possible types: string, number or function.\n * @type String\n * @name suffixLabel\n * @memberOf Slider.prototype\n * @default null\n * @see JXG.Slider#unitLabel\n * @see JXG.Slider#postLabel\n */\n suffixLabel: null,\n\n /**\n * If not null, this is appended to the value in the slider label.\n * Possible types: string, number or function.\n * @type String\n * @name unitLabel\n * @memberOf Slider.prototype\n * @default null\n * @see JXG.Slider#suffixLabel\n * @see JXG.Slider#postLabel\n */\n unitLabel: null,\n\n /**\n * If not null, this is appended to the value and to unitLabel in the slider label.\n * Possible types: string, number or function.\n * @type String\n * @name postLabel\n * @memberOf Slider.prototype\n * @default null\n * @see JXG.Slider#suffixLabel\n * @see JXG.Slider#unitLabel\n */\n postLabel: null,\n\n layer: 9,\n showInfobox: false,\n name: '',\n visible: true,\n strokeColor: '#000000',\n highlightStrokeColor: '#888888',\n fillColor: '#ffffff',\n highlightFillColor: 'none',\n\n /**\n * Size of slider point.\n *\n * @type Number\n * @name Slider#size\n * @default 6\n * @see Point#size\n */\n size: 6,\n\n /**\n * Attributes for first (left) helper point defining the slider position.\n *\n * @type Point\n * @name Slider#point1\n */\n point1: {\n needsRegularUpdate: false,\n showInfobox: false,\n withLabel: false,\n visible: false,\n fixed: true,\n name: ''\n },\n\n /**\n * Attributes for second (right) helper point defining the slider position.\n *\n * @type Point\n * @name Slider#point2\n */\n point2: {\n needsRegularUpdate: false,\n showInfobox: false,\n withLabel: false,\n visible: false,\n fixed: true,\n name: ''\n },\n\n /**\n * Attributes for the base line of the slider.\n *\n * @type Line\n * @name Slider#baseline\n */\n baseline: {\n needsRegularUpdate: false,\n visible: 'inherit',\n fixed: true,\n scalable: false,\n tabindex: null,\n name: '',\n strokeWidth: 1,\n strokeColor: '#000000',\n highlightStrokeColor: '#888888'\n },\n\n /**\n * Attributes for the ticks of the base line of the slider.\n *\n * @type Ticks\n * @name Slider#ticks\n */\n ticks: {\n needsRegularUpdate: false,\n fixed: true,\n\n // Label drawing\n drawLabels: false,\n digits: 2,\n includeBoundaries: 1,\n drawZero: true,\n label: {\n offset: [-4, -14],\n display: 'internal'\n },\n\n minTicksDistance: 30,\n insertTicks: true,\n minorHeight: 4, // if <0: full width and height\n majorHeight: 5, // if <0: full width and height\n minorTicks: 0,\n defaultDistance: 1,\n strokeOpacity: 1,\n strokeWidth: 1,\n tickEndings: [0, 1],\n strokeColor: '#000000',\n visible: 'inherit'\n },\n\n /**\n * Attributes for the highlighting line of the slider.\n *\n * @type Line\n * @name Slider#highline\n */\n highline: {\n strokeWidth: 3,\n visible: 'inherit',\n fixed: true,\n tabindex: null,\n name: '',\n strokeColor: '#000000',\n highlightStrokeColor: '#888888'\n },\n\n /**\n * Attributes for the slider label.\n *\n * @type Label\n * @name Slider#label\n */\n label: {\n visible: 'inherit',\n strokeColor: '#000000'\n },\n\n /**\n * If true, 'up' events on the baseline will trigger slider moves.\n *\n * @type: Boolean\n * @name Slider#moveOnUp\n * @default: true\n */\n moveOnUp: true\n\n /**#@-*/\n },\n\n /* special options for comb */\n comb: {\n /**#@+\n * @visprop\n */\n\n /**\n * Frequency of comb elements.\n *\n * @type Number\n * @name Comb#frequency\n * @default 0.2\n */\n frequency: 0.2,\n\n /**\n * Width of the comb.\n *\n * @type Number\n * @name Comb#width\n * @default 0.4\n */\n width: 0.4,\n\n /**\n * Angle under which comb elements are positioned.\n *\n * @type Number\n * @name Comb#angle\n * @default 60 degrees\n */\n angle: Math.PI / 3,\n\n /**\n * Should the comb go right to left instead of left to right.\n *\n * @type Boolean\n * @name Comb#reverse\n * @default false\n */\n reverse: false,\n\n /**\n * Attributes for first defining point of the comb.\n *\n * @type Point\n * @name Comb#point1\n */\n point1: {\n visible: false,\n withLabel: false,\n fixed: false,\n name: ''\n },\n\n /**\n * Attributes for second defining point of the comb.\n *\n * @type Point\n * @name Comb#point2\n */\n point2: {\n visible: false,\n withLabel: false,\n fixed: false,\n name: ''\n },\n\n /**\n * Attributes for the curve displaying the comb.\n *\n * @type Curve\n * @name Comb#curve\n */\n curve: {\n strokeWidth: 1,\n strokeColor: '#000000',\n fillColor: 'none'\n }\n },\n\n /* special options for slope triangle */\n slopetriangle: {\n /**#@+\n * @visprop\n */\n\n fillColor: Color.palette.red,\n fillOpacity: 0.4,\n highlightFillColor: Color.palette.red,\n highlightFillOpacity: 0.3,\n\n borders: {\n lastArrow: {\n type: 1,\n size: 6\n }\n },\n\n /**\n * Attributes for the gliding helper point.\n *\n * @type Point\n * @name Slopetriangle#glider\n */\n glider: {\n fixed: true,\n visible: false,\n withLabel: false\n },\n\n /**\n * Attributes for the base line.\n *\n * @type Line\n * @name Slopetriangle#baseline\n */\n baseline: {\n visible: false,\n withLabel: false,\n name: ''\n },\n\n /**\n * Attributes for the base point.\n *\n * @type Point\n * @name Slopetriangle#basepoint\n */\n basepoint: {\n visible: false,\n withLabel: false,\n name: ''\n },\n\n /**\n * Attributes for the tangent.\n * The tangent is constructed by slop triangle if the construction\n * is based on a glider, solely.\n *\n * @type Line\n * @name Slopetriangle#tangent\n */\n tangent: {\n visible: false,\n withLabel: false,\n name: ''\n },\n\n /**\n * Attributes for the top point.\n *\n * @type Point\n * @name Slopetriangle#toppoint\n */\n toppoint: {\n visible: false,\n withLabel: false,\n name: ''\n },\n\n /**\n * Attributes for the slope triangle label.\n *\n * @type Label\n * @name Slopetriangle#label\n */\n label: {\n visible: true\n }\n /**#@-*/\n },\n\n /* special options for step functions */\n stepfunction: {\n /**#@+\n * @visprop\n */\n\n /**#@-*/\n },\n\n /* special tape measure options */\n tapemeasure: {\n /**#@+\n * @visprop\n */\n\n strokeColor: '#000000',\n strokeWidth: 2,\n highlightStrokeColor: '#000000',\n\n /**\n * Show tape measure ticks.\n *\n * @type Boolean\n * @name Tapemeasure#withTicks\n * @default true\n */\n withTicks: true,\n\n /**\n * Show tape measure label.\n *\n * @type Boolean\n * @name Tapemeasure#withLabel\n * @default true\n */\n withLabel: true,\n\n /**\n * The precision of the tape measure value displayed in the optional text.\n * Replaced by the attribute digits\n *\n * @memberOf Tapemeasure.prototype\n * @name precision\n * @type Number\n * @deprecated\n * @see Tapemeasure#digits\n * @default 2\n */\n precision: 2,\n\n /**\n * The precision of the tape measure value displayed in the optional text.\n * @memberOf Tapemeasure.prototype\n * @name precision\n * @type Number\n * @default 2\n */\n digits: 2,\n\n /**\n * Attributes for first helper point defining the tape measure position.\n *\n * @type Point\n * @name Tapemeasure#point1\n */\n point1: {\n visible: 'inherit',\n strokeColor: '#000000',\n fillColor: '#ffffff',\n fillOpacity: 0.0,\n highlightFillOpacity: 0.1,\n size: 6,\n snapToPoints: true,\n attractorUnit: 'screen',\n attractorDistance: 20,\n showInfobox: false,\n withLabel: false,\n name: ''\n },\n\n /**\n * Attributes for second helper point defining the tape measure position.\n *\n * @type Point\n * @name Tapemeasure#point2\n */\n point2: {\n visible: 'inherit',\n strokeColor: '#000000',\n fillColor: '#ffffff',\n fillOpacity: 0.0,\n highlightFillOpacity: 0.1,\n size: 6,\n snapToPoints: true,\n attractorUnit: 'screen',\n attractorDistance: 20,\n showInfobox: false,\n withLabel: false,\n name: ''\n },\n\n /**\n * Attributes for the ticks of the tape measure.\n *\n * @type Ticks\n * @name Tapemeasure#ticks\n */\n ticks: {\n drawLabels: false,\n drawZero: true,\n insertTicks: true,\n minorHeight: 8,\n majorHeight: 16,\n minorTicks: 4,\n tickEndings: [0, 1],\n defaultDistance: 0.1,\n strokeOpacity: 1,\n strokeWidth: 1,\n strokeColor: '#000000',\n visible: 'inherit'\n },\n\n /**\n * Attributes for the tape measure label.\n *\n * @type Label\n * @name Tapemeasure#label\n */\n label: {\n position: 'top'\n }\n /**#@-*/\n },\n\n /* special text options */\n text: {\n /**#@+\n * @visprop\n */\n\n /**\n * The font size in pixels.\n *\n * @name fontSize\n * @memberOf Text.prototype\n * @default 12\n * @type Number\n * @see Text#fontUnit\n */\n fontSize: 12,\n\n /**\n * CSS unit for the font size of a text element. Usually, this will be the default value 'px' but\n * for responsive application, also 'vw', 'vh', vmax', 'vmin' or 'rem' might be useful.\n *\n * @name fontUnit\n * @memberOf Text.prototype\n * @default 'px'\n * @type String\n * @see Text#fontSize\n *\n * @example\n * var txt = board.create('text', [2, 2, \"hello\"], {fontSize: 8, fontUnit: 'vmin'});\n *\n * </pre><div id=\"JXG2da7e972-ac62-416b-a94b-32559c9ec9f9\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG2da7e972-ac62-416b-a94b-32559c9ec9f9',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var txt = board.create('text', [2, 2, \"hello\"], {fontSize: 8, fontUnit: 'vmin'});\n *\n * })();\n *\n * </script><pre>\n *\n */\n fontUnit: 'px',\n\n /**\n * Used to round texts given by a number.\n *\n * @name digits\n * @memberOf Text.prototype\n * @default 2\n * @type Number\n */\n digits: 2,\n\n /**\n * If set to true, the text is parsed and evaluated.\n * For labels parse==true results in converting names of the form k_a to subscripts.\n * If the text is given by string and parse==true, the string is parsed as\n * JessieCode expression.\n *\n * @name parse\n * @memberOf Text.prototype\n * @default true\n * @type Boolean\n */\n parse: true,\n\n /**\n * If set to true and caja's sanitizeHTML function can be found it\n * will be used to sanitize text output.\n *\n * @name useCaja\n * @memberOf Text.prototype\n * @default false\n * @type Boolean\n */\n useCaja: false,\n\n /**\n * If enabled, the text will be handled as label. Intended for internal use.\n *\n * @name isLabel\n * @memberOf Text.prototype\n * @default false\n * @type Boolean\n */\n isLabel: false,\n\n strokeColor: '#000000',\n highlightStrokeColor: '#000000',\n highlightStrokeOpacity: 0.666666,\n\n /**\n * Default CSS properties of the HTML text element.\n * <p>\n * The CSS properties which are set here, are handed over to the style property\n * of the HTML text element. That means, they have higher property than any\n * CSS class.\n * <p>\n * If a property which is set here should be overruled by a CSS class\n * then this property should be removed here.\n * <p>\n * The reason, why this attribute should be kept to its default value at all,\n * is that screen dumps of SVG boards with <tt>board.renderer.dumpToCanvas()</tt>\n * will ignore the font-family if it is set in a CSS class.\n * It has to be set explicitly as style attribute.\n * <p>\n * In summary, the order of priorities from high to low is\n * <ol>\n * <li> JXG.Options.text.cssStyle\n * <li> JXG.Options.text.cssDefaultStyle\n * <li> JXG.Options.text.cssClass\n * </ol>\n * @example\n * If all texts should get its font-family from the default CSS class\n * before initializing the board\n * <pre>\n * JXG.Options.text.cssDefaultStyle = '';\n * JXG.Options.text.highlightCssDefaultStyle = '';\n * </pre>\n * should be called.\n *\n * @name cssDefaultStyle\n * @memberOf Text.prototype\n * @default 'font-family: Arial, Helvetica, Geneva, sans-serif;'\n * @type String\n * @see Text#highlightCssDefaultStyle\n * @see Text#cssStyle\n * @see Text#highlightCssStyle\n */\n cssDefaultStyle: 'font-family: Arial, Helvetica, Geneva, sans-serif;',\n\n /**\n * Default CSS properties of the HTML text element in case of highlighting.\n * <p>\n * The CSS properties which are set here, are handed over to the style property\n * of the HTML text element. That means, they have higher property than any\n * CSS class.\n * @example\n * If all texts should get its font-family from the default CSS class\n * before initializing the board\n * <pre>\n * JXG.Options.text.cssDefaultStyle = '';\n * JXG.Options.text.highlightCssDefaultStyle = '';\n * </pre>\n * should be called.\n *\n * @name highlightCssDefaultStyle\n * @memberOf Text.prototype\n * @default 'font-family: Arial, Helvetica, Geneva, sans-serif;'\n * @type String\n * @see Text#cssDefaultStyle\n * @see Text#cssStyle\n * @see Text#highlightCssStyle\n */\n highlightCssDefaultStyle: 'font-family: Arial, Helvetica, Geneva, sans-serif;',\n\n /**\n * CSS properties of the HTML text element.\n * <p>\n * The CSS properties which are set here, are handed over to the style property\n * of the HTML text element. That means, they have higher property than any\n * CSS class.\n *\n * @name cssStyle\n * @memberOf Text.prototype\n * @default ''\n * @type String\n * @see Text#cssDefaultStyle\n * @see Text#highlightCssDefaultStyle\n * @see Text#highlightCssStyle\n */\n cssStyle: '',\n\n /**\n * CSS properties of the HTML text element in case of highlighting.\n * <p>\n * The CSS properties which are set here, are handed over to the style property\n * of the HTML text element. That means, they have higher property than any\n * CSS class.\n *\n * @name highlightCssStyle\n * @memberOf Text.prototype\n * @default ''\n * @type String\n * @see Text#cssDefaultStyle\n * @see Text#highlightCssDefaultStyle\n * @see Text#cssStyle\n */\n highlightCssStyle: '',\n\n /**\n * If true, the input will be given to ASCIIMathML before rendering.\n *\n * @name useASCIIMathML\n * @memberOf Text.prototype\n * @default false\n * @type Boolean\n */\n useASCIIMathML: false,\n\n /**\n * If true, MathJax will be used to render the input string.\n * Supports MathJax 2 as well as Mathjax 3.\n * It is recommended to use this option together with the option\n * \"parse: false\". Otherwise, 4 backslashes (e.g. \\\\\\\\alpha) are needed\n * instead of two (e.g. \\\\alpha).\n *\n * @name useMathJax\n * @memberOf Text.prototype\n * @default false\n * @type Boolean\n * @see Text#parse\n *\n * @example\n * // Before loading MathJax, it has to be configured something like this:\n * window.MathJax = {\n * tex: {\n * inlineMath: [ ['$','$'], [\"\\\\(\",\"\\\\)\"] ],\n * displayMath: [ ['$$','$$'], [\"\\\\[\",\"\\\\]\"] ],\n * packages: ['base', 'ams']\n * },\n * options: {\n * ignoreHtmlClass: 'tex2jax_ignore',\n * processHtmlClass: 'tex2jax_process'\n * }\n * };\n *\n * // Display style\n * board.create('text',[ 2,2, function(){return '$$X=\\\\frac{2}{x}$$'}], {\n * fontSize: 15, color:'green', useMathJax: true});\n *\n * // Inline style\n * board.create('text',[-2,2, function(){return '$X_A=\\\\frac{2}{x}$'}], {\n * fontSize: 15, color:'green', useMathJax: true});\n *\n * var A = board.create('point', [-2, 0]);\n * var B = board.create('point', [1, 0]);\n * var C = board.create('point', [0, 1]);\n *\n * var graph = board.create('ellipse', [A, B, C], {\n * fixed: true,\n * withLabel: true,\n * strokeColor: 'black',\n * strokeWidth: 2,\n * fillColor: '#cccccc',\n * fillOpacity: 0.3,\n * highlightStrokeColor: 'red',\n * highlightStrokeWidth: 3,\n * name: '$1=\\\\frac{(x-h)^2}{a^2}+\\\\frac{(y-k)^2}{b^2}$',\n * label: {useMathJax: true}\n * });\n *\n * var nvect1 = board.create('text', [-4, -3, '\\\\[\\\\overrightarrow{V}\\\\]'],\n * {\n * fontSize: 24, parse: false\n * });\n * var nvect1 = board.create('text', [-2, -4, function() {return '$\\\\overrightarrow{G}$';}],\n * {\n * fontSize: 24, useMathJax: true\n * });\n *\n * </pre>\n * <script>\n * window.MathJax = {\n * tex: {\n * inlineMath: [ ['$','$'], [\"\\\\(\",\"\\\\)\"] ],\n * displayMath: [ ['$$','$$'], [\"\\\\[\",\"\\\\]\"] ],\n * packages: ['base', 'ams']\n * },\n * options: {\n * ignoreHtmlClass: 'tex2jax_ignore',\n * processHtmlClass: 'tex2jax_process'\n * }\n * };\n * </script>\n * <script src=\"https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js\" id=\"MathJax-script\"></script>\n * <div id=\"JXGe2a04876-5813-4db0-b7e8-e48bf4e220b9\" class=\"jxgbox\" style=\"width: 400px; height: 400px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXGe2a04876-5813-4db0-b7e8-e48bf4e220b9',\n * {boundingbox: [-5, 5, 5, -5], axis: true, showcopyright: false, shownavigation: false});\n * // Display style\n * board.create('text',[ 2,2, function(){return '$$X=\\\\frac{2}{x}$$'}], {\n * fontSize: 15, color:'green', useMathJax: true});\n *\n * // Inline style\n * board.create('text',[-2,2, function(){return '$X_A=\\\\frac{2}{x}$'}], {\n * fontSize: 15, color:'green', useMathJax: true});\n *\n * var A = board.create('point', [-2, 0]);\n * var B = board.create('point', [1, 0]);\n * var C = board.create('point', [0, 1]);\n *\n * var graph = board.create('ellipse', [A, B, C], {\n * fixed: true,\n * withLabel: true,\n * strokeColor: 'black',\n * strokeWidth: 2,\n * fillColor: '#cccccc',\n * fillOpacity: 0.3,\n * highlightStrokeColor: 'red',\n * highlightStrokeWidth: 3,\n * name: '$1=\\\\frac{(x-h)^2}{a^2}+\\\\frac{(y-k)^2}{b^2}$',\n * label: {useMathJax: true}\n * });\n *\n * var nvect1 = board.create('text', [-4, -3, '\\\\[\\\\overrightarrow{V}\\\\]'],\n * {\n * fontSize: 24, parse: false\n * });\n * var nvect1 = board.create('text', [-2, -4, function() {return '$\\\\overrightarrow{G}$';}],\n * {\n * fontSize: 24, useMathJax: true\n * });\n * })();\n *\n * </script><pre>\n *\n *\n * @example\n * // Load MathJax:\n * // <script src=\"https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js\"<</script>\n *\n * // function and its derivative\n * var f1 = function(x) { return x * x * x; },\n * graph1 = board.create('functiongraph', [f1, -0.1, 1.1]),\n *\n * A = board.create('glider', [0.5, f1(0.5), graph1], {\n * name: 'f(x)',\n * color: 'black',\n * face:'x',\n * fixed: true,\n * size: 3,\n * label: {offset: [-30, 10], fontSize: 15}\n * }),\n * B = board.create('glider', [0.7, f1(0.7), graph1], {\n * name: 'f(x+Δx)',\n * size: 3,\n * label: {offset: [-60, 10], fontSize: 15}\n * }),\n *\n * secant_line = board.create('line', [A,B],{dash: 1, color: 'green'}),\n * a_h_segment = board.create('segment', [A, [\n * function(){ return B.X() > A.X() ? B.X() : A.X()},\n * function(){ return B.X() > A.X() ? A.Y() : B.Y()}\n * ]],{ name: 'Δx', dash: 1, color: 'black'});\n *\n * b_v_segment = board.create('segment', [B, [\n * function(){ return B.X() > A.X() ? B.X() : A.X()},\n * function(){ return B.X() > A.X() ? A.Y() : B.Y()}\n * ]],{ name: 'Δy', dash: 1, color: 'black'}),\n *\n * ma = board.create('midpoint', [a_h_segment.point1, a_h_segment.point2\n * ], {visible: false});\n *\n * board.create('text', [0, 0, function() {return '\\\\[\\\\Delta_x='+(B.X()-A.X()).toFixed(4)+'\\\\]'}], {\n * anchor: ma, useMathJax: true, fixed: true, color: 'green', anchorY: 'top'\n * });\n *\n * mb = board.create('midpoint', [b_v_segment.point1, b_v_segment.point2], {visible: false});\n * board.create('text', [0, 0, function() {return '\\\\[\\\\Delta_y='+(B.Y()-A.Y()).toFixed(4)+'\\\\]'}], {\n * anchor: mb, useMathJax: true, fixed: true, color: 'green'\n * });\n *\n * dval = board.create('text',[0.1, 0.8,\n * function(){\n * return '\\\\[\\\\frac{\\\\Delta_y}{\\\\Delta_x}=\\\\frac{' + ((B.Y()-A.Y()).toFixed(4)) + '}{' + ((B.X()-A.X()).toFixed(4)) +\n * '}=' + (((B.Y()-A.Y()).toFixed(4))/((B.X()-A.X()).toFixed(4))).toFixed(4) + '\\\\]';\n * }],{fontSize: 15, useMathJax: true});\n *\n * </pre>\n * <script src=\"https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js\" id=\"MathJax-script\"></script>\n * <div id=\"JXG8c2b65e7-4fc4-43f7-b23c-5076a7fa9621\" class=\"jxgbox\" style=\"width: 400px; height: 400px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG8c2b65e7-4fc4-43f7-b23c-5076a7fa9621',\n * {boundingbox: [-0.1, 1.1, 1.1, -0.1], axis: true, showcopyright: false, shownavigation: false});\n * // function and its derivative\n * var f1 = function(x) { return x * x * x; },\n * graph1 = board.create('functiongraph', [f1, -0.1, 1.1]),\n *\n * A = board.create('glider', [0.5, f1(0.5), graph1], {\n * name: 'f(x)',\n * color: 'black',\n * face:'x',\n * fixed: true,\n * size: 3,\n * label: {offset: [-30, 10], fontSize: 15}\n * }),\n * B = board.create('glider', [0.7, f1(0.7), graph1], {\n * name: 'f(x+Δx)',\n * size: 3,\n * label: {offset: [-60, 10], fontSize: 15}\n * }),\n *\n * secant_line = board.create('line', [A,B],{dash: 1, color: 'green'}),\n * a_h_segment = board.create('segment', [A, [\n * function(){ return B.X() > A.X() ? B.X() : A.X()},\n * function(){ return B.X() > A.X() ? A.Y() : B.Y()}\n * ]],{ name: 'Δx', dash: 1, color: 'black'});\n *\n * b_v_segment = board.create('segment', [B, [\n * function(){ return B.X() > A.X() ? B.X() : A.X()},\n * function(){ return B.X() > A.X() ? A.Y() : B.Y()}\n * ]],{ name: 'Δy', dash: 1, color: 'black'}),\n *\n * ma = board.create('midpoint', [a_h_segment.point1, a_h_segment.point2\n * ], {visible: false});\n *\n * board.create('text', [0, 0, function() {return '\\\\[\\\\Delta_x='+(B.X()-A.X()).toFixed(4)+'\\\\]'}], {\n * anchor: ma, useMathJax: true, fixed: true, color: 'green', anchorY: 'top'\n * });\n *\n * mb = board.create('midpoint', [b_v_segment.point1, b_v_segment.point2], {visible: false});\n * board.create('text', [0, 0, function() {return '\\\\[\\\\Delta_y='+(B.Y()-A.Y()).toFixed(4)+'\\\\]'}], {\n * anchor: mb, useMathJax: true, fixed: true, color: 'green'\n * });\n *\n * dval = board.create('text',[0.1, 0.8,\n * function(){\n * return '\\\\[\\\\frac{\\\\Delta_y}{\\\\Delta_x}=\\\\frac{' + ((B.Y()-A.Y()).toFixed(4)) + '}{' + ((B.X()-A.X()).toFixed(4)) +\n * '}=' + (((B.Y()-A.Y()).toFixed(4))/((B.X()-A.X()).toFixed(4))).toFixed(4) + '\\\\]';\n * }],{fontSize: 15, useMathJax: true});\n *\n * })();\n *\n * </script><pre>\n *\n * @example\n * var board = JXG.JSXGraph.initBoard('jxgbox', {boundingbox: [-1, 10, 11, -2], axis: true});\n * board.options.text.useMathjax = true;\n *\n * a = board.create('slider',[[-0.7,1.5],[5,1.5],[0,0.5,1]], {\n * suffixlabel:'\\\\(t_1=\\\\)',\n * unitLabel: ' \\\\(\\\\text{ ms}\\\\)',\n * snapWidth:0.01}),\n *\n * func = board.create('functiongraph',[function(x){return (a.Value()*x*x)}], {strokeColor: \"red\"});\n * text1 = board.create('text', [5, 1, function(){\n * return '\\\\(a(t)= { 1 \\\\over ' + a.Value().toFixed(3) + '}\\\\)';\n * }], {fontSize: 15, fixed:true, strokeColor:'red', anchorY: 'top', parse: false});\n *\n * </pre><div id=\"JXGf8bd01db-fb6a-4a5c-9e7f-8823f7aa5ac6\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXGf8bd01db-fb6a-4a5c-9e7f-8823f7aa5ac6',\n * {boundingbox: [-1, 10, 11, -2], axis: true, showcopyright: false, shownavigation: false});\n * board.options.text.useMathjax = true;\n *\n * a = board.create('slider',[[-0.7,1.5],[5,1.5],[0,0.5,1]], {\n * suffixlabel:'\\\\(t_1=\\\\)',\n * unitLabel: ' \\\\(\\\\text{ ms}\\\\)',\n * snapWidth:0.01}),\n *\n * func = board.create('functiongraph',[function(x){return (a.Value()*x*x)}], {strokeColor: \"red\"});\n * text1 = board.create('text', [5, 1, function(){\n * return '\\\\(a(t)= { 1 \\\\over ' + a.Value().toFixed(3) + '}\\\\)';\n * }], {fontSize: 15, fixed:true, strokeColor:'red', anchorY: 'top', parse: false});\n *\n * })();\n *\n * </script><pre>\n *\n */\n useMathJax: false,\n\n /**\n *\n * If true, KaTeX will be used to render the input string.\n * For this feature, katex.min.js and katex.min.css have to be included.\n * <p>\n * The example below does not work, because there is a conflict with\n * the MathJax library which is used below.\n * </p>\n *\n * @name useKatex\n * @memberOf Text.prototype\n * @default false\n * @type Boolean\n *\n *\n * @example\n * JXG.Options.text.useKatex = true;\n *\n * const board = JXG.JSXGraph.initBoard('jxgbox', {\n * boundingbox: [-2, 5, 8, -5], axis:true\n * });\n *\n * var a = board.create('slider',[[-0.7,1.5],[5,1.5],[0,0.5,1]], {\n * suffixlabel:'t_1=',\n * unitLabel: ' \\\\text{ ms}',\n * snapWidth:0.01});\n *\n * func = board.create('functiongraph',[function(x){return (a.Value()*x*x)}], {strokeColor: \"red\"});\n * text1 = board.create('text', [5, 1, function(){\n * return 'a(t)= { 1 \\\\over ' + a.Value().toFixed(3) + '}';\n * }], {fontSize: 15, fixed:true, strokeColor:'red', anchorY: 'top'});\n *\n * </pre>\n * <link rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/npm/katex@0.13.10/dist/katex.min.css\" integrity=\"sha384-0cCFrwW/0bAk1Z/6IMgIyNU3kfTcNirlObr4WjrUU7+hZeD6ravdYJ3kPWSeC31M\" crossorigin=\"anonymous\">\n * <script src=\"https://cdn.jsdelivr.net/npm/katex@0.13.10/dist/katex.min.js\" integrity=\"sha384-dtFDxK2tSkECx/6302Z4VN2ZRqt6Gis+b1IwCjJPrn0kMYFQT9rbtyQWg5NFWAF7\" crossorigin=\"anonymous\"></script>\n * <div id=\"JXG497f065c-cfc1-44c3-ba21-5fa581668869\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG497f065c-cfc1-44c3-ba21-5fa581668869',\n * {boundingbox: [-2, 5, 8, -5], axis: true, showcopyright: false, shownavigation: false});\n * board.options.useKatex = true;\n * var a = board.create('slider',[[-0.7,1.5],[5,1.5],[0,0.5,1]], {\n * suffixlabel:'t_1=',\n * unitLabel: ' \\\\text{ ms}',\n * snapWidth:0.01});\n *\n * func = board.create('functiongraph',[function(x){return (a.Value()*x*x)}], {strokeColor: \"red\"});\n * text1 = board.create('text', [5, 1, function(){\n * return 'a(t)= { 1 \\\\over ' + a.Value().toFixed(3) + '}';\n * }], {fontSize: 15, fixed:true, strokeColor:'red', anchorY: 'top'});\n *\n * })();\n *\n * </script><pre>\n */\n useKatex: false,\n\n /**\n * Determines the rendering method of the text. Possible values\n * include <tt>'html'</tt> and <tt>'internal</tt>.\n *\n * @name display\n * @memberOf Text.prototype\n * @default 'html'\n * @type String\n */\n display: 'html',\n\n /**\n * Anchor element {@link Point}, {@link Text} or {@link Image} of the text. If it exists, the coordinates of the text are relative\n * to this anchor element.\n *\n * @name anchor\n * @memberOf Text.prototype\n * @default null\n * @type Object\n */\n anchor: null,\n\n /**\n * The horizontal alignment of the text. Possible values include <tt>'auto</tt>, <tt>'left'</tt>, <tt>'middle'</tt>, and\n * <tt>'right'</tt>.\n *\n * @name anchorX\n * @memberOf Text.prototype\n * @default 'left'\n * @type String\n */\n anchorX: 'left',\n\n /**\n * The vertical alignment of the text. Possible values include <tt>'auto</tt>, <tt>'top'</tt>, <tt>'middle'</tt>, and\n * <tt>'bottom'</tt>.\n *\n * @name anchorY\n * @memberOf Text.prototype\n * @default 'auto'\n * @type String\n */\n anchorY: 'middle',\n\n /**\n * CSS class of the text in non-highlighted view.\n *\n * @name cssClass\n * @memberOf Text.prototype\n * @type String\n */\n cssClass: 'JXGtext',\n\n /**\n * CSS class of the text in highlighted view.\n *\n * @name highlightCssClass\n * @memberOf Text.prototype\n * @type String\n */\n highlightCssClass: 'JXGtext',\n\n /**\n * Sensitive area for dragging the text.\n * Possible values are 'all', or something else.\n * If set to 'small', a sensitivity margin at the right and left border is taken.\n * This may be extended to left, right, ... in the future.\n *\n * @name Text#dragArea\n * @type String\n * @default 'all'\n */\n dragArea: 'all',\n\n withLabel: false,\n\n /**\n * Text rotation in degrees.\n * Works for non-zero values only in combination with display=='internal'.\n *\n * @name Text#rotate\n * @type Number\n * @default 0\n */\n rotate: 0,\n\n visible: true,\n\n /**\n * Defines together with {@link Text#snapSizeY} the grid the text snaps on to.\n * The text will only snap on integer multiples to snapSizeX in x and snapSizeY in y direction.\n * If this value is equal to or less than <tt>0</tt>, it will use the grid displayed by the major ticks\n * of the default ticks of the default x axes of the board.\n *\n * @name snapSizeX\n * @memberOf Text.prototype\n *\n * @see Point#snapToGrid\n * @see Text#snapSizeY\n * @see JXG.Board#defaultAxes\n * @type Number\n * @default 1\n */\n snapSizeX: 1,\n\n /**\n * Defines together with {@link Text#snapSizeX} the grid the text snaps on to.\n * The text will only snap on integer multiples to snapSizeX in x and snapSizeY in y direction.\n * If this value is equal to or less than <tt>0</tt>, it will use the grid displayed by the major ticks\n * of the default ticks of the default y axes of the board.\n *\n * @name snapSizeY\n * @memberOf Text.prototype\n *\n * @see Point#snapToGrid\n * @see Text#snapSizeX\n * @see JXG.Board#defaultAxes\n * @type Number\n * @default 1\n */\n snapSizeY: 1,\n\n /**\n * List of attractor elements. If the distance of the text is less than\n * attractorDistance the text is made to glider of this element.\n *\n * @name attractors\n * @memberOf Text.prototype\n * @type Array\n * @default empty\n */\n attractors: []\n\n /**#@-*/\n },\n\n /* special options for trace curves */\n tracecurve: {\n /**#@+\n * @visprop\n */\n strokeColor: '#000000',\n fillColor: 'none',\n\n /**\n * The number of evaluated data points.\n * @memberOf Tracecurve.prototype\n * @default 100\n * @name numberPoints\n * @type Number\n */\n numberPoints: 100\n\n /**#@-*/\n },\n\n /*special turtle options */\n turtle: {\n /**#@+\n * @visprop\n */\n\n strokeWidth: 1,\n fillColor: 'none',\n strokeColor: '#000000',\n\n /**\n * Attributes for the turtle arrow.\n *\n * @type Curve\n * @name Turtle#arrow\n */\n arrow: {\n strokeWidth: 2,\n withLabel: false,\n strokeColor: Color.palette.red,\n lastArrow: true\n }\n /**#@-*/\n },\n\n /**\n * Abbreviations of attributes. Setting the shortcut means setting abbreviated properties\n * to the same value.\n * It is used in {@link JXG.GeometryElement#setAttribute} and in\n * the constructor {@link JXG.GeometryElement}.\n * Attention: In Options.js abbreviations are not allowed.\n * @type Object\n * @name JXG.Options#shortcuts\n *\n */\n shortcuts: {\n color: ['strokeColor', 'fillColor'],\n opacity: ['strokeOpacity', 'fillOpacity'],\n highlightColor: ['highlightStrokeColor', 'highlightFillColor'],\n highlightOpacity: ['highlightStrokeOpacity', 'highlightFillOpacity'],\n strokeWidth: ['strokeWidth', 'highlightStrokeWidth']\n }\n };\n\n /**\n * Holds all possible properties and the according validators for geometry elements.\n * A validator is either a function\n * which takes one parameter and returns true, if the value is valid for the property,\n * or it is false if no validator is required.\n */\n JXG.Validator = (function () {\n var i,\n validatePixel = function (v) {\n return (/^[0-9]+px$/).test(v);\n },\n validateDisplay = function (v) {\n return (v === 'html' || v === 'internal');\n },\n validateColor = function (v) {\n // for now this should do it...\n return Type.isString(v);\n },\n validatePointFace = function (v) {\n return Type.exists(JXG.normalizePointFace(v));\n },\n validateInteger = function (v) {\n return (Math.abs(v - Math.round(v)) < Mat.eps);\n },\n validateNotNegativeInteger = function (v) {\n return validateInteger(v) && v >= 0;\n },\n validatePositiveInteger = function (v) {\n return validateInteger(v) && v > 0;\n },\n validateScreenCoords = function (v) {\n return v.length >= 2 && validateInteger(v[0]) && validateInteger(v[1]);\n },\n validateRenderer = function (v) {\n return (v === 'vml' || v === 'svg' || v === 'canvas' || v === 'no');\n },\n validatePositive = function (v) {\n return v > 0;\n },\n validateNotNegative = function (v) {\n return v >= 0;\n },\n v = {},\n validators = {\n attractorDistance: validateNotNegative,\n color: validateColor,\n defaultDistance: Type.isNumber,\n display: validateDisplay,\n doAdvancedPlot: false,\n draft: false,\n drawLabels: false,\n drawZero: false,\n face: validatePointFace,\n factor: Type.isNumber,\n fillColor: validateColor,\n fillOpacity: Type.isNumber,\n firstArrow: false,\n fontSize: validateInteger,\n dash: validateInteger,\n gridX: Type.isNumber,\n gridY: Type.isNumber,\n hasGrid: false,\n highlightFillColor: validateColor,\n highlightFillOpacity: Type.isNumber,\n highlightStrokeColor: validateColor,\n highlightStrokeOpacity: Type.isNumber,\n insertTicks: false,\n //: validateScreenCoords,\n lastArrow: false,\n layer: validateNotNegativeInteger,\n majorHeight: validateInteger,\n minorHeight: validateInteger,\n minorTicks: validateNotNegative,\n minTicksDistance: validatePositiveInteger,\n numberPointsHigh: validatePositiveInteger,\n numberPointsLow: validatePositiveInteger,\n opacity: Type.isNumber,\n radius: Type.isNumber,\n RDPsmoothing: false,\n renderer: validateRenderer,\n right: validatePixel,\n showCopyright: false,\n showInfobox: false,\n showNavigation: false,\n size: validateNotNegative, //validateInteger,\n snapSizeX: validatePositive,\n snapSizeY: validatePositive,\n snapWidth: Type.isNumber,\n snapToGrid: false,\n snatchDistance: validateNotNegative,\n straightFirst: false,\n straightLast: false,\n stretch: false,\n strokeColor: validateColor,\n strokeOpacity: Type.isNumber,\n strokeWidth: validateNotNegative, //validateInteger,\n takeFirst: false,\n takeSizeFromFile: false,\n to10: false,\n toOrigin: false,\n translateTo10: false,\n translateToOrigin: false,\n useASCIIMathML: false,\n useDirection: false,\n useMathJax: false,\n withLabel: false,\n withTicks: false,\n zoom: false\n };\n\n // this seems like a redundant step but it makes sure that\n // all properties in the validator object have lower case names\n // and the validator object is easier to read.\n for (i in validators) {\n if (validators.hasOwnProperty(i)) {\n v[i.toLowerCase()] = validators[i];\n }\n }\n\n return v;\n }());\n\n /**\n * All point faces can be defined with more than one name, e.g. a cross faced point can be given\n * by face equal to 'cross' or equal to 'x'. This method maps all possible values to fixed ones to\n * simplify if- and switch-clauses regarding point faces. The translation table is as follows:\n * <table>\n * <tr><th>Input</th><th>Output</th></tr>\n * <tr><td>cross, x</td><td>x</td></tr>\n * <tr><td>circle, o</td><td>o</td></tr>\n * <tr><td>square, []</td><td>[]</td></tr>\n * <tr><td>plus, +</td><td>+</td></tr>\n * <tr><td>diamond, <></td><td><></td></tr>\n * <tr><td>triangleup, a, ^</td><td>A</td></tr>\n * <tr><td>triangledown, v</td><td>v</td></tr>\n * <tr><td>triangleleft, <</td><td><</td></tr>\n * <tr><td>triangleright, ></td><td>></td></tr>\n * </table>\n * @param {String} s A string which should determine a valid point face.\n * @returns {String} Returns a normalized string or undefined if the given string is not a valid\n * point face.\n */\n JXG.normalizePointFace = function (s) {\n var map = {\n cross: 'x',\n x: 'x',\n circle: 'o',\n o: 'o',\n square: '[]',\n '[]': '[]',\n plus: '+',\n '+': '+',\n diamond: '<>',\n '<>': '<>',\n triangleup: '^',\n a: '^',\n '^': '^',\n triangledown: 'v',\n v: 'v',\n triangleleft: '<',\n '<': '<',\n triangleright: '>',\n '>': '>'\n };\n\n return map[s];\n };\n\n\n /**\n * Apply the options stored in this object to all objects on the given board.\n * @param {JXG.Board} board The board to which objects the options will be applied.\n */\n JXG.useStandardOptions = function (board) {\n var el, t, p, copyProps,\n o = JXG.Options,\n boardHadGrid = board.hasGrid;\n\n board.options.grid.hasGrid = o.grid.hasGrid;\n board.options.grid.gridX = o.grid.gridX;\n board.options.grid.gridY = o.grid.gridY;\n board.options.grid.gridColor = o.grid.gridColor;\n board.options.grid.gridOpacity = o.grid.gridOpacity;\n board.options.grid.gridDash = o.grid.gridDash;\n board.options.grid.snapToGrid = o.grid.snapToGrid;\n board.options.grid.snapSizeX = o.grid.SnapSizeX;\n board.options.grid.snapSizeY = o.grid.SnapSizeY;\n board.takeSizeFromFile = o.takeSizeFromFile;\n\n copyProps = function (p, o) {\n p.visProp.fillcolor = o.fillColor;\n p.visProp.highlightfillcolor = o.highlightFillColor;\n p.visProp.strokecolor = o.strokeColor;\n p.visProp.highlightstrokecolor = o.highlightStrokeColor;\n };\n\n for (el in board.objects) {\n if (board.objects.hasOwnProperty(el)) {\n p = board.objects[el];\n if (p.elementClass === Const.OBJECT_CLASS_POINT) {\n copyProps(p, o.point);\n } else if (p.elementClass === Const.OBJECT_CLASS_LINE) {\n copyProps(p, o.line);\n\n for (t = 0; t < p.ticks.length; t++) {\n p.ticks[t].majorTicks = o.line.ticks.majorTicks;\n p.ticks[t].minTicksDistance = o.line.ticks.minTicksDistance;\n p.ticks[t].visProp.minorheight = o.line.ticks.minorHeight;\n p.ticks[t].visProp.majorheight = o.line.ticks.majorHeight;\n }\n } else if (p.elementClass === Const.OBJECT_CLASS_CIRCLE) {\n copyProps(p, o.circle);\n } else if (p.type === Const.OBJECT_TYPE_ANGLE) {\n copyProps(p, o.angle);\n } else if (p.type === Const.OBJECT_TYPE_ARC) {\n copyProps(p, o.arc);\n } else if (p.type === Const.OBJECT_TYPE_POLYGON) {\n copyProps(p, o.polygon);\n } else if (p.type === Const.OBJECT_TYPE_CONIC) {\n copyProps(p, o.conic);\n } else if (p.type === Const.OBJECT_TYPE_CURVE) {\n copyProps(p, o.curve);\n } else if (p.type === Const.OBJECT_TYPE_SECTOR) {\n p.arc.visProp.fillcolor = o.sector.fillColor;\n p.arc.visProp.highlightfillcolor = o.sector.highlightFillColor;\n p.arc.visProp.fillopacity = o.sector.fillOpacity;\n p.arc.visProp.highlightfillopacity = o.sector.highlightFillOpacity;\n }\n }\n }\n\n board.fullUpdate();\n if (boardHadGrid && !board.hasGrid) {\n board.removeGrids(board);\n } else if (!boardHadGrid && board.hasGrid) {\n board.create('grid', []);\n }\n };\n\n /**\n * Converts all color values to greyscale and calls useStandardOption to put them onto the board.\n * @param {JXG.Board} board The board to which objects the options will be applied.\n * @see #useStandardOptions\n */\n JXG.useBlackWhiteOptions = function (board) {\n var o = JXG.Options;\n o.point.fillColor = Color.rgb2bw(o.point.fillColor);\n o.point.highlightFillColor = Color.rgb2bw(o.point.highlightFillColor);\n o.point.strokeColor = Color.rgb2bw(o.point.strokeColor);\n o.point.highlightStrokeColor = Color.rgb2bw(o.point.highlightStrokeColor);\n\n o.line.fillColor = Color.rgb2bw(o.line.fillColor);\n o.line.highlightFillColor = Color.rgb2bw(o.line.highlightFillColor);\n o.line.strokeColor = Color.rgb2bw(o.line.strokeColor);\n o.line.highlightStrokeColor = Color.rgb2bw(o.line.highlightStrokeColor);\n\n o.circle.fillColor = Color.rgb2bw(o.circle.fillColor);\n o.circle.highlightFillColor = Color.rgb2bw(o.circle.highlightFillColor);\n o.circle.strokeColor = Color.rgb2bw(o.circle.strokeColor);\n o.circle.highlightStrokeColor = Color.rgb2bw(o.circle.highlightStrokeColor);\n\n o.arc.fillColor = Color.rgb2bw(o.arc.fillColor);\n o.arc.highlightFillColor = Color.rgb2bw(o.arc.highlightFillColor);\n o.arc.strokeColor = Color.rgb2bw(o.arc.strokeColor);\n o.arc.highlightStrokeColor = Color.rgb2bw(o.arc.highlightStrokeColor);\n\n o.polygon.fillColor = Color.rgb2bw(o.polygon.fillColor);\n o.polygon.highlightFillColor = Color.rgb2bw(o.polygon.highlightFillColor);\n\n o.sector.fillColor = Color.rgb2bw(o.sector.fillColor);\n o.sector.highlightFillColor = Color.rgb2bw(o.sector.highlightFillColor);\n\n o.curve.strokeColor = Color.rgb2bw(o.curve.strokeColor);\n o.grid.gridColor = Color.rgb2bw(o.grid.gridColor);\n\n JXG.useStandardOptions(board);\n };\n\n // needs to be exported\n JXG.Options.normalizePointFace = JXG.normalizePointFace;\n\n return JXG.Options;\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true, AMprocessNode: true, MathJax: true, document: true, window: true */\n\n/*\n nomen: Allow underscores to indicate private class members. Might be replaced by local variables.\n plusplus: Only allowed in for-loops\n newcap: AsciiMathMl exposes non-constructor functions beginning with upper case letters\n*/\n/*jslint nomen: true, plusplus: true, newcap: true, unparam: true*/\n/*eslint no-unused-vars: \"off\"*/\n\n/* depends:\n jxg\n options\n base/coords\n base/constants\n math/math\n math/geometry\n utils/type\n utils/env\n*/\n\n/**\n * @fileoverview JSXGraph can use various technologies to render the contents of a construction, e.g.\n * SVG, VML, and HTML5 Canvas. To accomplish this, The rendering and the logic and control mechanisms\n * are completely separated from each other. Every rendering technology has it's own class, called\n * Renderer, e.g. SVGRenderer for SVG, the same for VML and Canvas. The common base for all available\n * renderers is the class AbstractRenderer defined in this file.\n */\n\ndefine('renderer/abstract',[\n 'jxg', 'options', 'base/coords', 'base/constants', 'math/math', 'math/geometry', 'utils/type', 'utils/env'\n], function (JXG, Options, Coords, Const, Mat, Geometry, Type, Env) {\n\n \"use strict\";\n\n /**\n * <p>This class defines the interface to the graphics part of JSXGraph. This class is an abstract class, it\n * actually does not render anything. This is up to the {@link JXG.SVGRenderer}, {@link JXG.VMLRenderer},\n * and {@link JXG.CanvasRenderer} classes. We strongly discourage you from using the methods in these classes\n * directly. Only the methods which are defined in this class and are not marked as private are guaranteed\n * to exist in any renderer instance you can access via {@link JXG.Board#renderer}. But not all methods may\n * work as expected.</p>\n * <p>The methods of this renderer can be divided into different categories:\n * <dl>\n * <dt>Draw basic elements</dt>\n * <dd>In this category we find methods to draw basic elements like {@link JXG.Point}, {@link JXG.Line},\n * and {@link JXG.Curve} as well as assisting methods tightly bound to these basic painters. You do not\n * need to implement these methods in a descendant renderer but instead implement the primitive drawing\n * methods described below. This approach is encouraged when you're using a XML based rendering engine\n * like VML and SVG. If you want to use a bitmap based rendering technique you are supposed to override\n * these methods instead of the primitive drawing methods.</dd>\n * <dt>Draw primitives</dt>\n * <dd>This category summarizes methods to handle primitive nodes. As creation and management of these nodes\n * is different among different the rendering techniques most of these methods are purely virtual and need\n * proper implementation if you choose to not overwrite the basic element drawing methods.</dd>\n * <dt>Attribute manipulation</dt>\n * <dd>In XML based renders you have to manipulate XML nodes and their attributes to change the graphics.\n * For that purpose attribute manipulation methods are defined to set the color, opacity, and other things.\n * Please note that some of these methods are required in bitmap based renderers, too, because some elements\n * like {@link JXG.Text} can be HTML nodes floating over the construction.</dd>\n * <dt>Renderer control</dt>\n * <dd>Methods to clear the drawing board or to stop and to resume the rendering engine.</dd>\n * </dl></p>\n * @class JXG.AbstractRenderer\n * @constructor\n * @see JXG.SVGRenderer\n * @see JXG.VMLRenderer\n * @see JXG.CanvasRenderer\n */\n JXG.AbstractRenderer = function () {\n\n // WHY THIS IS A CLASS INSTEAD OF A SINGLETON OBJECT:\n //\n // The renderers need to keep track of some stuff which is not always the same on different boards,\n // like enhancedRendering, reference to the container object, and resolution in VML. Sure, those\n // things could be stored in board. But they are rendering related and JXG.Board is already very\n // very big.\n //\n // And we can't save the rendering related data in {SVG,VML,Canvas}Renderer and make only the\n // JXG.AbstractRenderer a singleton because of that:\n //\n // Given an object o with property a set to true\n // var o = {a: true};\n // and a class c doing nothing\n // c = function() {};\n // Set c's prototype to o\n // c.prototype = o;\n // and create an instance of c we get i.a to be true\n // i = new c();\n // i.a;\n // > true\n // But we can overwrite this property via\n // c.prototype.a = false;\n // i.a;\n // > false\n\n /**\n * The vertical offset for {@link Text} elements. Every {@link Text} element will\n * be placed this amount of pixels below the user given coordinates.\n * @type Number\n * @default 0\n */\n this.vOffsetText = 0;\n\n /**\n * If this property is set to <tt>true</tt> the visual properties of the elements are updated\n * on every update. Visual properties means: All the stuff stored in the\n * {@link JXG.GeometryElement#visProp} property won't be set if enhancedRendering is <tt>false</tt>\n * @type Boolean\n * @default true\n */\n this.enhancedRendering = true;\n\n /**\n * The HTML element that stores the JSXGraph board in it.\n * @type Node\n */\n this.container = null;\n\n /**\n * This is used to easily determine which renderer we are using\n * @example if (board.renderer.type === 'vml') {\n * // do something\n * }\n * @type String\n */\n this.type = '';\n\n /**\n * True if the browsers' SVG engine supports foreignObject.\n * Not supported browsers are IE 9 - 11.\n * All other browsers return ture, since it is tested with\n * document.implementation.hasFeature() which is deprecated.\n *\n * @type Boolean\n * @private\n */\n this.supportsForeignObject = false;\n\n };\n\n JXG.extend(JXG.AbstractRenderer.prototype, /** @lends JXG.AbstractRenderer.prototype */ {\n\n /* ******************************** *\n * private methods *\n * should not be called from *\n * outside AbstractRenderer *\n * ******************************** */\n\n /**\n * Update visual properties, but only if {@link JXG.AbstractRenderer#enhancedRendering} or <tt>enhanced</tt> is set to true.\n * @param {JXG.GeometryElement} el The element to update\n * @param {Object} [not={}] Select properties you don't want to be updated: <tt>{fill: true, dash: true}</tt> updates\n * everything except for fill and dash. Possible values are <tt>stroke, fill, dash, shadow, gradient</tt>.\n * @param {Boolean} [enhanced=false] If true, {@link JXG.AbstractRenderer#enhancedRendering} is assumed to be true.\n * @private\n */\n _updateVisual: function (el, not, enhanced) {\n if (enhanced || this.enhancedRendering) {\n not = not || {};\n\n this.setObjectTransition(el);\n if (!Type.evaluate(el.visProp.draft)) {\n if (!not.stroke) {\n if (el.highlighted) {\n this.setObjectStrokeColor(el,\n el.visProp.highlightstrokecolor,\n el.visProp.highlightstrokeopacity);\n this.setObjectStrokeWidth(el, el.visProp.highlightstrokewidth);\n } else {\n this.setObjectStrokeColor(el,\n el.visProp.strokecolor,\n el.visProp.strokeopacity);\n this.setObjectStrokeWidth(el, el.visProp.strokewidth);\n }\n }\n\n if (!not.fill) {\n if (el.highlighted) {\n this.setObjectFillColor(el,\n el.visProp.highlightfillcolor,\n el.visProp.highlightfillopacity);\n } else {\n this.setObjectFillColor(el,\n el.visProp.fillcolor,\n el.visProp.fillopacity);\n }\n }\n\n if (!not.dash) {\n this.setDashStyle(el, el.visProp);\n }\n\n if (!not.shadow) {\n this.setShadow(el);\n }\n\n if (!not.gradient) {\n this.setShadow(el);\n }\n\n if (!not.tabindex) {\n this.setTabindex(el);\n }\n } else {\n this.setDraft(el);\n }\n }\n },\n\n /**\n * Get information if element is highlighted.\n * @param {JXG.GeometryElement} el The element which is tested for being highlighted.\n * @returns {String} 'highlight' if highlighted, otherwise the ampty string '' is returned.\n * @private\n */\n _getHighlighted: function(el) {\n var isTrace = false,\n hl;\n\n if (!Type.exists(el.board) || !Type.exists(el.board.highlightedObjects)) {\n // This case handles trace elements.\n // To make them work, we simply neglect highlighting.\n isTrace = true;\n }\n\n if (!isTrace && Type.exists(el.board.highlightedObjects[el.id])) {\n hl = 'highlight';\n } else {\n hl = '';\n }\n return hl;\n },\n\n /* ******************************** *\n * Point drawing and updating *\n * ******************************** */\n\n /**\n * Draws a point on the {@link JXG.Board}.\n * @param {JXG.Point} el Reference to a {@link JXG.Point} object that has to be drawn.\n * @see Point\n * @see JXG.Point\n * @see JXG.AbstractRenderer#updatePoint\n * @see JXG.AbstractRenderer#changePointStyle\n */\n drawPoint: function (el) {\n var prim,\n // sometimes el is not a real point and lacks the methods of a JXG.Point instance,\n // in these cases to not use el directly.\n face = Options.normalizePointFace(Type.evaluate(el.visProp.face));\n\n // determine how the point looks like\n if (face === 'o') {\n prim = 'ellipse';\n } else if (face === '[]') {\n prim = 'rect';\n } else {\n // cross/x, diamond/<>, triangleup/a/^, triangledown/v, triangleleft/<,\n // triangleright/>, plus/+,\n prim = 'path';\n }\n\n el.rendNode = this.appendChildPrim(this.createPrim(prim, el.id), Type.evaluate(el.visProp.layer));\n this.appendNodesToElement(el, prim);\n\n // adjust visual propertys\n this._updateVisual(el, {dash: true, shadow: true}, true);\n\n // By now we only created the xml nodes and set some styles, in updatePoint\n // the attributes are filled with data.\n this.updatePoint(el);\n },\n\n /**\n * Updates visual appearance of the renderer element assigned to the given {@link JXG.Point}.\n * @param {JXG.Point} el Reference to a {@link JXG.Point} object, that has to be updated.\n * @see Point\n * @see JXG.Point\n * @see JXG.AbstractRenderer#drawPoint\n * @see JXG.AbstractRenderer#changePointStyle\n */\n updatePoint: function (el) {\n var size = Type.evaluate(el.visProp.size),\n // sometimes el is not a real point and lacks the methods of a JXG.Point instance,\n // in these cases to not use el directly.\n face = Options.normalizePointFace(Type.evaluate(el.visProp.face)),\n unit = Type.evaluate(el.visProp.sizeunit),\n zoom = Type.evaluate(el.visProp.zoom),\n s1;\n\n if (!isNaN(el.coords.scrCoords[2] + el.coords.scrCoords[1])) {\n if (unit === 'user') {\n size *= Math.sqrt(el.board.unitX * el.board.unitY);\n }\n size *= ((!el.board || !zoom) ?\n 1.0 : Math.sqrt(el.board.zoomX * el.board.zoomY));\n s1 = (size === 0) ? 0 : size + 1;\n\n if (face === 'o') { // circle\n this.updateEllipsePrim(el.rendNode, el.coords.scrCoords[1],\n el.coords.scrCoords[2], s1, s1);\n } else if (face === '[]') { // rectangle\n this.updateRectPrim(el.rendNode, el.coords.scrCoords[1] - size,\n el.coords.scrCoords[2] - size, size * 2, size * 2);\n } else { // x, +, <>, ^, v, <, >\n this.updatePathPrim(el.rendNode,\n this.updatePathStringPoint(el, size, face), el.board);\n }\n this._updateVisual(el, {dash: false, shadow: false});\n this.setShadow(el);\n }\n },\n\n /**\n * Changes the style of a {@link JXG.Point}. This is required because the point styles differ in what\n * elements have to be drawn, e.g. if the point is marked by a \"x\" or a \"+\" two lines are drawn, if\n * it's marked by spot a circle is drawn. This method removes the old renderer element(s) and creates\n * the new one(s).\n * @param {JXG.Point} el Reference to a {@link JXG.Point} object, that's style is changed.\n * @see Point\n * @see JXG.Point\n * @see JXG.AbstractRenderer#updatePoint\n * @see JXG.AbstractRenderer#drawPoint\n */\n changePointStyle: function (el) {\n var node = this.getElementById(el.id);\n\n // remove the existing point rendering node\n if (Type.exists(node)) {\n this.remove(node);\n }\n\n // and make a new one\n this.drawPoint(el);\n Type.clearVisPropOld(el);\n\n if (!el.visPropCalc.visible) {\n this.display(el, false);\n }\n\n if (Type.evaluate(el.visProp.draft)) {\n this.setDraft(el);\n }\n },\n\n /* ******************************** *\n * Lines *\n * ******************************** */\n\n /**\n * Draws a line on the {@link JXG.Board}.\n * @param {JXG.Line} el Reference to a line object, that has to be drawn.\n * @see Line\n * @see JXG.Line\n * @see JXG.AbstractRenderer#updateLine\n */\n drawLine: function (el) {\n el.rendNode = this.appendChildPrim(this.createPrim('line', el.id),\n Type.evaluate(el.visProp.layer));\n this.appendNodesToElement(el, 'lines');\n this.updateLine(el);\n },\n\n /**\n * Updates visual appearance of the renderer element assigned to the given {@link JXG.Line}.\n * @param {JXG.Line} el Reference to the {@link JXG.Line} object that has to be updated.\n * @see Line\n * @see JXG.Line\n * @see JXG.AbstractRenderer#drawLine\n */\n updateLine: function (el) {\n this._updateVisual(el);\n this.updatePathWithArrowHeads(el); // Calls the renderer primitive\n this.setLineCap(el);\n },\n\n /* **************************\n * Curves\n * **************************/\n\n /**\n * Draws a {@link JXG.Curve} on the {@link JXG.Board}.\n * @param {JXG.Curve} el Reference to a graph object, that has to be plotted.\n * @see Curve\n * @see JXG.Curve\n * @see JXG.AbstractRenderer#updateCurve\n */\n drawCurve: function (el) {\n el.rendNode = this.appendChildPrim(this.createPrim('path', el.id), Type.evaluate(el.visProp.layer));\n this.appendNodesToElement(el, 'path');\n this.updateCurve(el);\n },\n\n /**\n * Updates visual appearance of the renderer element assigned to the given {@link JXG.Curve}.\n * @param {JXG.Curve} el Reference to a {@link JXG.Curve} object, that has to be updated.\n * @see Curve\n * @see JXG.Curve\n * @see JXG.AbstractRenderer#drawCurve\n */\n updateCurve: function (el) {\n this._updateVisual(el);\n this.updatePathWithArrowHeads(el); // Calls the renderer primitive\n this.setLineCap(el);\n },\n\n /* **************************\n * Arrow heads and related stuff\n * **************************/\n\n /**\n * Handles arrow heads of a line or curve element and calls the renderer primitive.\n *\n * @param {JXG.GeometryElement} el Reference to a line or curve object that has to be drawn.\n * @param {Boolean} doHighlight\n *\n * @private\n * @see Line\n * @see JXG.Line\n * @see Curve\n * @see JXG.Curve\n * @see JXG.AbstractRenderer#updateLine\n * @see JXG.AbstractRenderer#updateCurve\n * @see JXG.AbstractRenderer#makeArrows\n * @see JXG.AbstractRenderer#getArrowHeadData\n */\n updatePathWithArrowHeads: function(el, doHighlight) {\n var ev = el.visProp,\n hl = doHighlight ? 'highlight' : '',\n w,\n arrowData;\n\n if (doHighlight && ev.highlightstrokewidth) {\n w = Math.max(Type.evaluate(ev.highlightstrokewidth), Type.evaluate(ev.strokewidth));\n } else {\n w = Type.evaluate(ev.strokewidth);\n }\n\n // Get information if there are arrow heads and how large they are.\n arrowData = this.getArrowHeadData(el, w, hl);\n\n // Create the SVG nodes if neccessary\n this.makeArrows(el, arrowData);\n\n // Draw the paths with arrow heads\n if (el.elementClass === Const.OBJECT_CLASS_LINE) {\n this.updateLineWithEndings(el, arrowData);\n } else if (el.elementClass === Const.OBJECT_CLASS_CURVE) {\n this.updatePath(el);\n }\n\n this.setArrowSize(el, arrowData);\n },\n\n /**\n * This method determines some data about the line endings of this element.\n * If there are arrow heads, the offset is determined so that no parts of the line stroke\n * lap over the arrow head.\n * <p>\n * The returned object also contains the types of the arrow heads.\n *\n * @param {JXG.GeometryElement} el JSXGraph line or curve element\n * @param {Number} strokewidth strokewidth of the element\n * @param {String} hl Ither 'highlight' or empty string\n * @returns {Object} object containing the data\n *\n * @private\n */\n getArrowHeadData: function(el, strokewidth, hl) {\n var minlen = Mat.eps,\n typeFirst, typeLast,\n offFirst = 0,\n offLast = 0,\n sizeFirst = 0,\n sizeLast = 0,\n ev_fa = Type.evaluate(el.visProp.firstarrow),\n ev_la = Type.evaluate(el.visProp.lastarrow),\n off, size;\n\n /*\n Handle arrow heads.\n\n The default arrow head is an isosceles triangle with base length 10 units and height 10 units.\n These 10 units are scaled to strokeWidth * arrowSize pixels pixels.\n */\n if (ev_fa || ev_la) {\n\n if (Type.exists(ev_fa.type)) {\n typeFirst = Type.evaluate(ev_fa.type);\n } else {\n if (el.elementClass === Const.OBJECT_CLASS_LINE) {\n typeFirst = 1;\n } else {\n typeFirst = 7;\n }\n }\n if (Type.exists(ev_la.type)) {\n typeLast = Type.evaluate(ev_la.type);\n } else {\n if (el.elementClass === Const.OBJECT_CLASS_LINE) {\n typeLast = 1;\n } else {\n typeLast = 7;\n }\n }\n\n if (ev_fa) {\n size = 6;\n if (Type.exists(ev_fa.size)) {\n size = Type.evaluate(ev_fa.size);\n }\n if (hl !== '' && Type.exists(ev_fa[hl + 'size'])) {\n size = Type.evaluate(ev_fa[hl + 'size']);\n }\n\n off = strokewidth * size;\n if (typeFirst === 2) {\n off *= 0.5;\n minlen += strokewidth * size;\n } else if (typeFirst === 3) {\n off = strokewidth * size / 3;\n minlen += strokewidth;\n } else if (typeFirst === 4 || typeFirst === 5 || typeFirst === 6) {\n off = strokewidth * size / 1.5;\n minlen += strokewidth * size;\n } else if (typeFirst === 7) {\n off = 0;\n size = 10;\n minlen += strokewidth;\n } else {\n minlen += strokewidth * size;\n }\n offFirst += off;\n sizeFirst = size;\n }\n\n if (ev_la) {\n size = 6;\n if (Type.exists(ev_la.size)) {\n size = Type.evaluate(ev_la.size);\n }\n if (hl !== '' && Type.exists(ev_la[hl + 'size'])) {\n size = Type.evaluate(ev_la[hl + 'size']);\n }\n off = strokewidth * size;\n if (typeLast === 2) {\n off *= 0.5;\n minlen += strokewidth * size;\n } else if (typeLast === 3) {\n off = strokewidth * size / 3;\n minlen += strokewidth;\n } else if (typeLast === 4 || typeLast === 5 || typeLast === 6) {\n off = strokewidth * size / 1.5;\n minlen += strokewidth * size;\n } else if (typeLast === 7) {\n off = 0;\n size = 10;\n minlen += strokewidth;\n } else {\n minlen += strokewidth * size;\n }\n offLast += off;\n sizeLast = size;\n }\n }\n el.visPropCalc.typeFirst = typeFirst;\n el.visPropCalc.typeLast = typeLast;\n\n return {\n evFirst: ev_fa,\n evLast: ev_la,\n typeFirst: typeFirst,\n typeLast: typeLast,\n offFirst: offFirst,\n offLast: offLast,\n sizeFirst: sizeFirst,\n sizeLast: sizeLast,\n showFirst: 1, // Show arrow head. 0 if the distance is too small\n showLast: 1, // Show arrow head. 0 if the distance is too small\n minLen: minlen,\n strokeWidth: strokewidth\n };\n },\n\n /**\n * Corrects the line length if there are arrow heads, such that\n * the arrow ends exactly at the intended position.\n * Calls the renderer method to draw the line.\n *\n * @param {JXG.Line} el Reference to a line object, that has to be drawn\n * @param {Object} arrowData Data concerning possible arrow heads\n *\n * @returns {JXG.AbstractRenderer} Reference to the renderer\n *\n * @private\n * @see Line\n * @see JXG.Line\n * @see JXG.AbstractRenderer#updateLine\n * @see JXG.AbstractRenderer#getPositionArrowHead\n *\n */\n updateLineWithEndings: function(el, arrowData) {\n var c1, c2,\n // useTotalLength = true,\n margin = null;\n\n c1 = new Coords(Const.COORDS_BY_USER, el.point1.coords.usrCoords, el.board);\n c2 = new Coords(Const.COORDS_BY_USER, el.point2.coords.usrCoords, el.board);\n margin = Type.evaluate(el.visProp.margin);\n Geometry.calcStraight(el, c1, c2, margin);\n\n this.handleTouchpoints(el, c1, c2, arrowData);\n this.getPositionArrowHead(el, c1, c2, arrowData);\n\n this.updateLinePrim(el.rendNode,\n c1.scrCoords[1], c1.scrCoords[2],\n c2.scrCoords[1], c2.scrCoords[2], el.board);\n\n return this;\n },\n\n /**\n *\n * Calls the renderer method to draw a curve.\n *\n * @param {JXG.GeometryElement} el Reference to a line object, that has to be drawn.\n * @returns {JXG.AbstractRenderer} Reference to the renderer\n *\n * @private\n * @see Curve\n * @see JXG.Curve\n * @see JXG.AbstractRenderer#updateCurve\n *\n */\n updatePath: function(el) {\n if (Type.evaluate(el.visProp.handdrawing)) {\n this.updatePathPrim(el.rendNode, this.updatePathStringBezierPrim(el), el.board);\n } else {\n this.updatePathPrim(el.rendNode, this.updatePathStringPrim(el), el.board);\n }\n\n return this;\n },\n\n /**\n * Shorten the length of a line element such that the arrow head touches\n * the start or end point and such that the arrow head ends exactly\n * at the start / end position of the line.\n *\n * @param {JXG.Line} el Reference to the line object that gets arrow heads.\n * @param {JXG.Coords} c1 Coords of the first point of the line (after {@link JXG.Math.Geometry#calcStraight}).\n * @param {JXG.Coords} c2 Coords of the second point of the line (after {@link JXG.Math.Geometry#calcStraight}).\n * @param {Object} a\n * @return {object} Object containing how much the line has to be shortened.\n * Data structure: {c1, c2, d1x, d1y, d2x, d2y, sFirst, sLast}. sFirst and sLast is the length by which\n * firstArrow and lastArrow have to shifted such that there is no gap between arrow head and line.\n * Additionally, if one of these values is zero, the arrow is not displayed. This is the case, if the\n * line length is very short.\n */\n getPositionArrowHead: function(el, c1, c2, a) {\n var d, d1x, d1y, d2x, d2y;\n\n /*\n Handle arrow heads.\n\n The default arrow head (type==1) is an isosceles triangle with base length 10 units and height 10 units.\n These 10 units are scaled to strokeWidth * arrowSize pixels pixels.\n */\n if (a.evFirst || a.evLast) {\n // Correct the position of the arrow heads\n d1x = d1y = d2x = d2y = 0.0;\n d = c1.distance(Const.COORDS_BY_SCREEN, c2);\n\n if (a.evFirst &&\n el.board.renderer.type !== 'vml') {\n if (d >= a.minLen) {\n d1x = (c2.scrCoords[1] - c1.scrCoords[1]) * a.offFirst / d;\n d1y = (c2.scrCoords[2] - c1.scrCoords[2]) * a.offFirst / d;\n } else {\n a.showFirst = 0;\n }\n }\n\n if (a.evLast &&\n el.board.renderer.type !== 'vml') {\n if (d >= a.minLen) {\n d2x = (c2.scrCoords[1] - c1.scrCoords[1]) * a.offLast / d;\n d2y = (c2.scrCoords[2] - c1.scrCoords[2]) * a.offLast / d;\n } else {\n a.showLast = 0;\n }\n }\n c1.setCoordinates(Const.COORDS_BY_SCREEN, [c1.scrCoords[1] + d1x, c1.scrCoords[2] + d1y], false, true);\n c2.setCoordinates(Const.COORDS_BY_SCREEN, [c2.scrCoords[1] - d2x, c2.scrCoords[2] - d2y], false, true);\n }\n\n return this;\n },\n\n /**\n * Handle touchlastpoint / touchfirstpoint\n *\n * @param {JXG.GeometryElement} el\n * @param {JXG.Coords} c1 Coordinates of the start of the line. The coordinates are changed in place.\n * @param {JXG.Coords} c2 Coordinates of the end of the line. The coordinates are changed in place.\n * @param {Object} a\n */\n handleTouchpoints: function(el, c1, c2, a) {\n var s1, s2, d,\n d1x, d1y, d2x, d2y;\n\n if (a.evFirst || a.evLast) {\n d = d1x = d1y = d2x = d2y = 0.0;\n\n s1 = Type.evaluate(el.point1.visProp.size) + Type.evaluate(el.point1.visProp.strokewidth);\n s2 = Type.evaluate(el.point2.visProp.size) + Type.evaluate(el.point2.visProp.strokewidth);\n\n // Handle touchlastpoint /touchfirstpoint\n if (a.evFirst && Type.evaluate(el.visProp.touchfirstpoint)) {\n d = c1.distance(Const.COORDS_BY_SCREEN, c2);\n //if (d > s) {\n d1x = (c2.scrCoords[1] - c1.scrCoords[1]) * s1 / d;\n d1y = (c2.scrCoords[2] - c1.scrCoords[2]) * s1 / d;\n //}\n }\n if (a.evLast && Type.evaluate(el.visProp.touchlastpoint)) {\n d = c1.distance(Const.COORDS_BY_SCREEN, c2);\n //if (d > s) {\n d2x = (c2.scrCoords[1] - c1.scrCoords[1]) * s2 / d;\n d2y = (c2.scrCoords[2] - c1.scrCoords[2]) * s2 / d;\n //}\n }\n c1.setCoordinates(Const.COORDS_BY_SCREEN, [c1.scrCoords[1] + d1x, c1.scrCoords[2] + d1y], false, true);\n c2.setCoordinates(Const.COORDS_BY_SCREEN, [c2.scrCoords[1] - d2x, c2.scrCoords[2] - d2y], false, true);\n }\n\n return this;\n },\n\n /**\n * Set the arrow head size.\n *\n * @param {JXG.GeometryElement} el Reference to a line or curve object that has to be drawn.\n * @param {Object} arrowData Data concerning possible arrow heads\n * @returns {JXG.AbstractRenderer} Reference to the renderer\n *\n * @private\n * @see Line\n * @see JXG.Line\n * @see Curve\n * @see JXG.Curve\n * @see JXG.AbstractRenderer#updatePathWithArrowHeads\n * @see JXG.AbstractRenderer#getArrowHeadData\n */\n setArrowSize: function(el, a) {\n if (a.evFirst) {\n this._setArrowWidth(el.rendNodeTriangleStart, a.showFirst * a.strokeWidth, el.rendNode, a.sizeFirst);\n }\n if (a.evLast) {\n this._setArrowWidth(el.rendNodeTriangleEnd, a.showLast * a.strokeWidth, el.rendNode, a.sizeLast);\n }\n return this;\n },\n\n /**\n * Update the line endings (linecap) of a straight line from its attribute\n * 'linecap'.\n * Possible values for the attribute 'linecap' are: 'butt', 'round', 'square'.\n * The default value is 'butt'. Not available for VML renderer.\n *\n * @param {JXG.Line} element A arbitrary line.\n * @see Line\n * @see JXG.Line\n * @see JXG.AbstractRenderer#updateLine\n */\n setLineCap: function(el) { /* stub */ },\n\n /* **************************\n * Ticks related stuff\n * **************************/\n\n /**\n * Creates a rendering node for ticks added to a line.\n * @param {JXG.Line} el A arbitrary line.\n * @see Line\n * @see Ticks\n * @see JXG.Line\n * @see JXG.Ticks\n * @see JXG.AbstractRenderer#updateTicks\n */\n drawTicks: function (el) {\n el.rendNode = this.appendChildPrim(this.createPrim('path', el.id), Type.evaluate(el.visProp.layer));\n this.appendNodesToElement(el, 'path');\n },\n\n /**\n * Update {@link Ticks} on a {@link JXG.Line}. This method is only a stub and has to be implemented\n * in any descendant renderer class.\n * @param {JXG.Ticks} element Reference of a ticks object that has to be updated.\n * @see Line\n * @see Ticks\n * @see JXG.Line\n * @see JXG.Ticks\n * @see JXG.AbstractRenderer#drawTicks\n */\n updateTicks: function (element) { /* stub */ },\n\n /* **************************\n * Circle related stuff\n * **************************/\n\n /**\n * Draws a {@link JXG.Circle}\n * @param {JXG.Circle} el Reference to a {@link JXG.Circle} object that has to be drawn.\n * @see Circle\n * @see JXG.Circle\n * @see JXG.AbstractRenderer#updateEllipse\n */\n drawEllipse: function (el) {\n el.rendNode = this.appendChildPrim(this.createPrim('ellipse', el.id),\n Type.evaluate(el.visProp.layer));\n this.appendNodesToElement(el, 'ellipse');\n this.updateEllipse(el);\n },\n\n /**\n * Updates visual appearance of a given {@link JXG.Circle} on the {@link JXG.Board}.\n * @param {JXG.Circle} el Reference to a {@link JXG.Circle} object, that has to be updated.\n * @see Circle\n * @see JXG.Circle\n * @see JXG.AbstractRenderer#drawEllipse\n */\n updateEllipse: function (el) {\n this._updateVisual(el);\n\n var radius = el.Radius();\n\n if (radius > 0.0 &&\n Math.abs(el.center.coords.usrCoords[0]) > Mat.eps &&\n !isNaN(radius + el.center.coords.scrCoords[1] + el.center.coords.scrCoords[2]) &&\n radius * el.board.unitX < 2000000) {\n this.updateEllipsePrim(el.rendNode, el.center.coords.scrCoords[1],\n el.center.coords.scrCoords[2],\n (radius * el.board.unitX),\n (radius * el.board.unitY));\n }\n },\n\n /* **************************\n * Polygon related stuff\n * **************************/\n\n /**\n * Draws a {@link JXG.Polygon} on the {@link JXG.Board}.\n * @param {JXG.Polygon} el Reference to a Polygon object, that is to be drawn.\n * @see Polygon\n * @see JXG.Polygon\n * @see JXG.AbstractRenderer#updatePolygon\n */\n drawPolygon: function (el) {\n el.rendNode = this.appendChildPrim(this.createPrim('polygon', el.id),\n Type.evaluate(el.visProp.layer));\n this.appendNodesToElement(el, 'polygon');\n this.updatePolygon(el);\n },\n\n /**\n * Updates properties of a {@link JXG.Polygon}'s rendering node.\n * @param {JXG.Polygon} el Reference to a {@link JXG.Polygon} object, that has to be updated.\n * @see Polygon\n * @see JXG.Polygon\n * @see JXG.AbstractRenderer#drawPolygon\n */\n updatePolygon: function (el) {\n // Here originally strokecolor wasn't updated but strokewidth was.\n // But if there's no strokecolor i don't see why we should update strokewidth.\n this._updateVisual(el, {stroke: true, dash: true});\n this.updatePolygonPrim(el.rendNode, el);\n },\n\n /* **************************\n * Text related stuff\n * **************************/\n\n /**\n * Shows a small copyright notice in the top left corner of the board.\n * @param {String} str The copyright notice itself\n * @param {Number} fontsize Size of the font the copyright notice is written in\n */\n displayCopyright: function (str, fontsize) { /* stub */ },\n\n /**\n * An internal text is a {@link JXG.Text} element which is drawn using only\n * the given renderer but no HTML. This method is only a stub, the drawing\n * is done in the special renderers.\n * @param {JXG.Text} element Reference to a {@link JXG.Text} object\n * @see Text\n * @see JXG.Text\n * @see JXG.AbstractRenderer#updateInternalText\n * @see JXG.AbstractRenderer#drawText\n * @see JXG.AbstractRenderer#updateText\n * @see JXG.AbstractRenderer#updateTextStyle\n */\n drawInternalText: function (element) { /* stub */ },\n\n /**\n * Updates visual properties of an already existing {@link JXG.Text} element.\n * @param {JXG.Text} element Reference to an {@link JXG.Text} object, that has to be updated.\n * @see Text\n * @see JXG.Text\n * @see JXG.AbstractRenderer#drawInternalText\n * @see JXG.AbstractRenderer#drawText\n * @see JXG.AbstractRenderer#updateText\n * @see JXG.AbstractRenderer#updateTextStyle\n */\n updateInternalText: function (element) { /* stub */ },\n\n /**\n * Displays a {@link JXG.Text} on the {@link JXG.Board} by putting a HTML div over it.\n * @param {JXG.Text} el Reference to an {@link JXG.Text} object, that has to be displayed\n * @see Text\n * @see JXG.Text\n * @see JXG.AbstractRenderer#drawInternalText\n * @see JXG.AbstractRenderer#updateText\n * @see JXG.AbstractRenderer#updateInternalText\n * @see JXG.AbstractRenderer#updateTextStyle\n */\n drawText: function (el) {\n var node, z, level,\n ev_visible;\n\n if (Type.evaluate(el.visProp.display) === 'html' && Env.isBrowser && this.type !== 'no') {\n node = this.container.ownerDocument.createElement('div');\n //node = this.container.ownerDocument.createElementNS('http://www.w3.org/1999/xhtml', 'div'); //\n node.style.position = 'absolute';\n node.className = Type.evaluate(el.visProp.cssclass);\n\n level = Type.evaluate(el.visProp.layer);\n if (!Type.exists(level)) { // trace nodes have level not set\n level = 0;\n }\n\n if (this.container.style.zIndex === '') {\n z = 0;\n } else {\n z = parseInt(this.container.style.zIndex, 10);\n }\n\n node.style.zIndex = z + level;\n this.container.appendChild(node);\n\n node.setAttribute('id', this.container.id + '_' + el.id);\n } else {\n node = this.drawInternalText(el);\n }\n\n el.rendNode = node;\n el.htmlStr = '';\n\n // Set el.visPropCalc.visible\n if (el.visProp.islabel && Type.exists(el.visProp.anchor)) {\n ev_visible = Type.evaluate(el.visProp.anchor.visProp.visible);\n el.prepareUpdate().updateVisibility(ev_visible);\n } else {\n el.prepareUpdate().updateVisibility();\n }\n this.updateText(el);\n },\n\n /**\n * Updates visual properties of an already existing {@link JXG.Text} element.\n * @param {JXG.Text} el Reference to an {@link JXG.Text} object, that has to be updated.\n * @see Text\n * @see JXG.Text\n * @see JXG.AbstractRenderer#drawText\n * @see JXG.AbstractRenderer#drawInternalText\n * @see JXG.AbstractRenderer#updateInternalText\n * @see JXG.AbstractRenderer#updateTextStyle\n */\n updateText: function (el) {\n var content = el.plaintext,\n v, c,\n parentNode,\n scale, vshift, id, wrap_id,\n ax, ay;\n\n if (el.visPropCalc.visible) {\n this.updateTextStyle(el, false);\n\n if (Type.evaluate(el.visProp.display) === 'html' && this.type !== 'no') {\n // Set the position\n if (!isNaN(el.coords.scrCoords[1] + el.coords.scrCoords[2])) {\n\n // Horizontal\n c = el.coords.scrCoords[1];\n // webkit seems to fail for extremely large values for c.\n c = Math.abs(c) < 1000000 ? c : 1000000;\n ax = el.getAnchorX();\n\n if (ax === 'right') {\n // v = Math.floor(el.board.canvasWidth - c);\n v = el.board.canvasWidth - c;\n } else if (ax === 'middle') {\n // v = Math.floor(c - 0.5 * el.size[0]);\n v = c - 0.5 * el.size[0];\n } else { // 'left'\n // v = Math.floor(c);\n v = c;\n }\n\n // This may be useful for foreignObj.\n //if (window.devicePixelRatio !== undefined) {\n //v *= window.devicePixelRatio;\n //}\n\n if (el.visPropOld.left !== (ax + v)) {\n if (ax === 'right') {\n el.rendNode.style.right = v + 'px';\n el.rendNode.style.left = 'auto';\n } else {\n el.rendNode.style.left = v + 'px';\n el.rendNode.style.right = 'auto';\n }\n el.visPropOld.left = ax + v;\n }\n\n // Vertical\n c = el.coords.scrCoords[2] + this.vOffsetText;\n c = Math.abs(c) < 1000000 ? c : 1000000;\n ay = el.getAnchorY();\n\n if (ay === 'bottom') {\n // v = Math.floor(el.board.canvasHeight - c);\n v = el.board.canvasHeight - c;\n } else if (ay === 'middle') {\n // v = Math.floor(c - 0.5 * el.size[1]);\n v = c - 0.5 * el.size[1];\n } else { // top\n // v = Math.floor(c);\n v = c;\n }\n\n // This may be useful for foreignObj.\n //if (window.devicePixelRatio !== undefined) {\n //v *= window.devicePixelRatio;\n //}\n\n if (el.visPropOld.top !== (ay + v)) {\n if (ay === 'bottom') {\n el.rendNode.style.top = 'auto';\n el.rendNode.style.bottom = v + 'px';\n } else {\n el.rendNode.style.bottom = 'auto';\n el.rendNode.style.top = v + 'px';\n }\n el.visPropOld.top = ay + v;\n }\n }\n\n // Set the content\n if (el.htmlStr !== content) {\n try {\n if (el.type === Type.OBJECT_TYPE_BUTTON) {\n el.rendNodeButton.innerHTML = content;\n } else if (el.type === Type.OBJECT_TYPE_CHECKBOX ||\n el.type === Type.OBJECT_TYPE_INPUT) {\n el.rendNodeLabel.innerHTML = content;\n } else {\n el.rendNode.innerHTML = content;\n }\n } catch (e) {\n // Setting innerHTML sometimes fails in IE8.\n // A workaround is to take the node off the DOM, assign innerHTML,\n // then append back.\n // Works for text elements as they are absolutely positioned.\n parentNode = el.rendNode.parentNode;\n el.rendNode.parentNode.removeChild(el.rendNode);\n el.rendNode.innerHTML = content;\n parentNode.appendChild(el.rendNode);\n }\n el.htmlStr = content;\n\n if (Type.evaluate(el.visProp.usemathjax)) {\n // Typesetting directly might not work because mathjax was not loaded completely\n // see http://www.mathjax.org/docs/1.1/typeset.html\n try {\n if (MathJax.typeset) {\n // Version 3\n MathJax.typeset([el.rendNode]);\n } else {\n // Version 2\n MathJax.Hub.Queue(['Typeset', MathJax.Hub, el.rendNode]);\n }\n\n // Restore the transformation necessary for fullscreen mode\n // MathJax removes it when handling dynamic content\n id = el.board.container;\n wrap_id = 'fullscreenwrap_' + id;\n if (document.getElementById(wrap_id)) {\n scale = el.board.containerObj._cssFullscreenStore.scale;\n vshift = el.board.containerObj._cssFullscreenStore.vshift;\n Env.scaleJSXGraphDiv('#' + wrap_id, '#' + id, scale, vshift);\n }\n\n } catch (e) {\n JXG.debug('MathJax (not yet) loaded');\n }\n } else if (Type.evaluate(el.visProp.usekatex)) {\n try {\n /* eslint-disable no-undef */\n katex.render(content, el.rendNode, {\n throwOnError: false\n });\n /* eslint-enable no-undef */\n } catch (e) {\n JXG.debug('KaTeX (not yet) loaded');\n }\n } else if (Type.evaluate(el.visProp.useasciimathml)) {\n // This is not a constructor.\n // See http://www1.chapman.edu/~jipsen/mathml/asciimath.html for more information\n // about AsciiMathML and the project's source code.\n try {\n AMprocessNode(el.rendNode, false);\n } catch (e) {\n JXG.debug('AsciiMathML (not yet) loaded');\n }\n }\n }\n this.transformImage(el, el.transformations);\n } else {\n this.updateInternalText(el);\n }\n }\n },\n\n /**\n * Converts string containing CSS properties into\n * array with key-value pair objects.\n *\n * @example\n * \"color:blue; background-color:yellow\" is converted to\n * [{'color': 'blue'}, {'backgroundColor': 'yellow'}]\n *\n * @param {String} cssString String containing CSS properties\n * @return {Array} Array of CSS key-value pairs\n */\n _css2js: function(cssString) {\n var pairs = [],\n i, len, key, val, s,\n list = Type.trim(cssString).replace(/;$/, '').split(\";\");\n\n len = list.length;\n for (i = 0; i < len; ++i) {\n if (Type.trim(list[i]) !== '') {\n s = list[i].split(':');\n key = Type.trim(s[0].replace(/-([a-z])/gi, function(match, char) { return char.toUpperCase(); }));\n val = Type.trim(s[1]);\n pairs.push({'key': key, 'val': val});\n }\n }\n return pairs;\n\n },\n\n /**\n * Updates font-size, color and opacity propertiey and CSS style properties of a {@link JXG.Text} node.\n * This function is also called by highlight() and nohighlight().\n * @param {JXG.Text} el Reference to the {@link JXG.Text} object, that has to be updated.\n * @param {Boolean} doHighlight\n * @see Text\n * @see JXG.Text\n * @see JXG.AbstractRenderer#drawText\n * @see JXG.AbstractRenderer#drawInternalText\n * @see JXG.AbstractRenderer#updateText\n * @see JXG.AbstractRenderer#updateInternalText\n * @see JXG.AbstractRenderer#updateInternalTextStyle\n */\n updateTextStyle: function (el, doHighlight) {\n var fs, so, sc, css, node,\n ev = el.visProp,\n display = Env.isBrowser ? ev.display : 'internal',\n nodeList = ['rendNode', 'rendNodeTag', 'rendNodeLabel'],\n lenN = nodeList.length,\n fontUnit = Type.evaluate(ev.fontunit),\n cssList, prop, style, cssString,\n styleList = ['cssdefaultstyle', 'cssstyle'],\n lenS = styleList.length;\n\n if (doHighlight) {\n sc = ev.highlightstrokecolor;\n so = ev.highlightstrokeopacity;\n css = ev.highlightcssclass;\n } else {\n sc = ev.strokecolor;\n so = ev.strokeopacity;\n css = ev.cssclass;\n }\n\n // This part is executed for all text elements except internal texts in canvas.\n // HTML-texts or internal texts in SVG or VML.\n // HTML internal\n // SVG + +\n // VML + +\n // canvas + -\n // no - -\n if ((this.type !== 'no') &&\n (display === 'html' || this.type !== 'canvas')\n ) {\n for (style = 0; style < lenS; style++) {\n // First set cssString to\n // ev.cssdefaultstyle of ev.highlightcssdefaultstyle,\n // then to\n // ev.cssstyle of ev.highlightcssstyle\n cssString = Type.evaluate(ev[(doHighlight ? 'highlight' : '') + styleList[style]]);\n if (cssString !== '' &&\n el.visPropOld[styleList[style]] !== cssString) {\n cssList = this._css2js(cssString);\n for (node = 0; node < lenN; node++) {\n if (Type.exists(el[nodeList[node]])) {\n for (prop in cssList) {\n if (cssList.hasOwnProperty(prop)) {\n el[nodeList[node]].style[cssList[prop].key] = cssList[prop].val;\n }\n }\n }\n }\n el.visPropOld[styleList[style]] = cssString;\n }\n }\n\n fs = Type.evaluate(ev.fontsize);\n if (el.visPropOld.fontsize !== fs) {\n el.needsSizeUpdate = true;\n try {\n for (node = 0; node < lenN; node++) {\n if (Type.exists(el[nodeList[node]])) {\n el[nodeList[node]].style.fontSize = fs + fontUnit;\n }\n }\n } catch (e) {\n // IE needs special treatment.\n for (node = 0; node < lenN; node++) {\n if (Type.exists(el[nodeList[node]])) {\n el[nodeList[node]].style.fontSize = fs;\n }\n }\n }\n el.visPropOld.fontsize = fs;\n }\n }\n\n this.setObjectTransition(el);\n if (display === 'html' && this.type !== 'no') {\n // Set new CSS class\n if (el.visPropOld.cssclass !== css) {\n el.rendNode.className = css;\n el.visPropOld.cssclass = css;\n el.needsSizeUpdate = true;\n }\n this.setObjectStrokeColor(el, sc, so);\n } else {\n this.updateInternalTextStyle(el, sc, so);\n }\n\n return this;\n },\n\n /**\n * Set color and opacity of internal texts.\n * This method is used for Canvas and VML.\n * SVG needs its own version.\n * @private\n * @see JXG.AbstractRenderer#updateTextStyle\n * @see JXG.SVGRenderer#updateInternalTextStyle\n */\n updateInternalTextStyle: function (el, strokeColor, strokeOpacity) {\n this.setObjectStrokeColor(el, strokeColor, strokeOpacity);\n },\n\n /* **************************\n * Image related stuff\n * **************************/\n\n /**\n * Draws an {@link JXG.Image} on a board; This is just a template that has to be implemented by special\n * renderers.\n * @param {JXG.Image} element Reference to the image object that is to be drawn\n * @see Image\n * @see JXG.Image\n * @see JXG.AbstractRenderer#updateImage\n */\n drawImage: function (element) { /* stub */ },\n\n /**\n * Updates the properties of an {@link JXG.Image} element.\n * @param {JXG.Image} el Reference to an {@link JXG.Image} object, that has to be updated.\n * @see Image\n * @see JXG.Image\n * @see JXG.AbstractRenderer#drawImage\n */\n updateImage: function (el) {\n this.updateRectPrim(el.rendNode, el.coords.scrCoords[1],\n el.coords.scrCoords[2] - el.size[1], el.size[0], el.size[1]);\n\n this.updateImageURL(el);\n this.transformImage(el, el.transformations);\n this._updateVisual(el, {stroke: true, dash: true}, true);\n },\n\n /**\n * Multiplication of transformations without updating. That means, at that point it is expected that the\n * matrices contain numbers only. First, the origin in user coords is translated to <tt>(0,0)</tt> in screen\n * coords. Then, the stretch factors are divided out. After the transformations in user coords, the stretch\n * factors are multiplied in again, and the origin in user coords is translated back to its position. This\n * method does not have to be implemented in a new renderer.\n * @param {JXG.GeometryElement} el A JSXGraph element. We only need its board property.\n * @param {Array} transformations An array of JXG.Transformations.\n * @returns {Array} A matrix represented by a two dimensional array of numbers.\n * @see JXG.AbstractRenderer#transformImage\n */\n joinTransforms: function (el, transformations) {\n var i,\n ox = el.board.origin.scrCoords[1],\n oy = el.board.origin.scrCoords[2],\n ux = el.board.unitX,\n uy = el.board.unitY,\n // Translate to 0,0 in screen coords\n /*\n m = [[1, 0, 0], [0, 1, 0], [0, 0, 1]],\n mpre1 = [[1, 0, 0],\n [-ox, 1, 0],\n [-oy, 0, 1]],\n // Scale\n mpre2 = [[1, 0, 0],\n [0, 1 / ux, 0],\n [0, 0, -1 / uy]],\n // Scale back\n mpost2 = [[1, 0, 0],\n [0, ux, 0],\n [0, 0, -uy]],\n // Translate back\n mpost1 = [[1, 0, 0],\n [ox, 1, 0],\n [oy, 0, 1]],\n */\n len = transformations.length,\n // Translate to 0,0 in screen coords and then scale\n m = [[1, 0, 0],\n [-ox / ux, 1 / ux, 0],\n [ oy / uy, 0, -1 / uy]];\n\n for (i = 0; i < len; i++) {\n //m = Mat.matMatMult(mpre1, m);\n //m = Mat.matMatMult(mpre2, m);\n m = Mat.matMatMult(transformations[i].matrix, m);\n //m = Mat.matMatMult(mpost2, m);\n //m = Mat.matMatMult(mpost1, m);\n }\n // Scale back and then translate back\n m = Mat.matMatMult([[1, 0, 0],\n [ox, ux, 0],\n [oy, 0, -uy]], m);\n return m;\n },\n\n /**\n * Applies transformations on images and text elements. This method is just a stub and has to be implemented in\n * all descendant classes where text and image transformations are to be supported.\n * @param {JXG.Image|JXG.Text} element A {@link JXG.Image} or {@link JXG.Text} object.\n * @param {Array} transformations An array of {@link JXG.Transformation} objects. This is usually the\n * transformations property of the given element <tt>el</tt>.\n */\n transformImage: function (element, transformations) { /* stub */ },\n\n /**\n * If the URL of the image is provided by a function the URL has to be updated during updateImage()\n * @param {JXG.Image} element Reference to an image object.\n * @see JXG.AbstractRenderer#updateImage\n */\n updateImageURL: function (element) { /* stub */ },\n\n /**\n * Updates CSS style properties of a {@link JXG.Image} node.\n * In SVGRenderer opacity is the only available style element.\n * This function is called by highlight() and nohighlight().\n * This function works for VML.\n * It does not work for Canvas.\n * SVGRenderer overwrites this method.\n * @param {JXG.Text} el Reference to the {@link JXG.Image} object, that has to be updated.\n * @param {Boolean} doHighlight\n * @see Image\n * @see JXG.Image\n * @see JXG.AbstractRenderer#highlight\n * @see JXG.AbstractRenderer#noHighlight\n */\n updateImageStyle: function (el, doHighlight) {\n el.rendNode.className = Type.evaluate(doHighlight ? el.visProp.highlightcssclass : el.visProp.cssclass);\n },\n\n drawForeignObject: function (el) { /* stub */ },\n\n updateForeignObject: function(el) { /* stub */ },\n\n /* **************************\n * Render primitive objects\n * **************************/\n\n /**\n * Appends a node to a specific layer level. This is just an abstract method and has to be implemented\n * in all renderers that want to use the <tt>createPrim</tt> model to draw.\n * @param {Node} node A DOM tree node.\n * @param {Number} level The layer the node is attached to. This is the index of the layer in\n * {@link JXG.SVGRenderer#layer} or the <tt>z-index</tt> style property of the node in VMLRenderer.\n */\n appendChildPrim: function (node, level) { /* stub */ },\n\n /**\n * Stores the rendering nodes. This is an abstract method which has to be implemented in all renderers that use\n * the <tt>createPrim</tt> method.\n * @param {JXG.GeometryElement} element A JSXGraph element.\n * @param {String} type The XML node name. Only used in VMLRenderer.\n */\n appendNodesToElement: function (element, type) { /* stub */ },\n\n /**\n * Creates a node of a given type with a given id.\n * @param {String} type The type of the node to create.\n * @param {String} id Set the id attribute to this.\n * @returns {Node} Reference to the created node.\n */\n createPrim: function (type, id) {\n /* stub */\n return null;\n },\n\n /**\n * Removes an element node. Just a stub.\n * @param {Node} node The node to remove.\n */\n remove: function (node) { /* stub */ },\n\n /**\n * Can be used to create the nodes to display arrows. This is an abstract method which has to be implemented\n * in any descendant renderer.\n * @param {JXG.GeometryElement} element The element the arrows are to be attached to.\n * @param {Object} arrowData Data concerning possible arrow heads\n *\n */\n makeArrows: function (element, arrowData) { /* stub */ },\n\n /**\n * Updates width of an arrow DOM node. Used in\n * @param {Node} node The arrow node.\n * @param {Number} width\n * @param {Node} parentNode Used in IE only\n */\n _setArrowWidth: function(node, width, parentNode) { /* stub */},\n\n /**\n * Updates an ellipse node primitive. This is an abstract method which has to be implemented in all renderers\n * that use the <tt>createPrim</tt> method.\n * @param {Node} node Reference to the node.\n * @param {Number} x Centre X coordinate\n * @param {Number} y Centre Y coordinate\n * @param {Number} rx The x-axis radius.\n * @param {Number} ry The y-axis radius.\n */\n updateEllipsePrim: function (node, x, y, rx, ry) { /* stub */ },\n\n /**\n * Refreshes a line node. This is an abstract method which has to be implemented in all renderers that use\n * the <tt>createPrim</tt> method.\n * @param {Node} node The node to be refreshed.\n * @param {Number} p1x The first point's x coordinate.\n * @param {Number} p1y The first point's y coordinate.\n * @param {Number} p2x The second point's x coordinate.\n * @param {Number} p2y The second point's y coordinate.\n * @param {JXG.Board} board\n */\n updateLinePrim: function (node, p1x, p1y, p2x, p2y, board) { /* stub */ },\n\n /**\n * Updates a path element. This is an abstract method which has to be implemented in all renderers that use\n * the <tt>createPrim</tt> method.\n * @param {Node} node The path node.\n * @param {String} pathString A string formatted like e.g. <em>'M 1,2 L 3,1 L5,5'</em>. The format of the string\n * depends on the rendering engine.\n * @param {JXG.Board} board Reference to the element's board.\n */\n updatePathPrim: function (node, pathString, board) { /* stub */ },\n\n /**\n * Builds a path data string to draw a point with a face other than <em>rect</em> and <em>circle</em>. Since\n * the format of such a string usually depends on the renderer this method\n * is only an abstract method. Therefore, it has to be implemented in the descendant renderer itself unless\n * the renderer does not use the createPrim interface but the draw* interfaces to paint.\n * @param {JXG.Point} element The point element\n * @param {Number} size A positive number describing the size. Usually the half of the width and height of\n * the drawn point.\n * @param {String} type A string describing the point's face. This method only accepts the shortcut version of\n * each possible face: <tt>x, +, <>, ^, v, >, < </tt>\n */\n updatePathStringPoint: function (element, size, type) { /* stub */ },\n\n /**\n * Builds a path data string from a {@link JXG.Curve} element. Since the path data strings heavily depend on the\n * underlying rendering technique this method is just a stub. Although such a path string is of no use for the\n * CanvasRenderer, this method is used there to draw a path directly.\n * @param element\n */\n updatePathStringPrim: function (element) { /* stub */ },\n\n /**\n * Builds a path data string from a {@link JXG.Curve} element such that the curve looks like hand drawn. Since\n * the path data strings heavily depend on the underlying rendering technique this method is just a stub.\n * Although such a path string is of no use for the CanvasRenderer, this method is used there to draw a path\n * directly.\n * @param element\n */\n updatePathStringBezierPrim: function (element) { /* stub */ },\n\n\n /**\n * Update a polygon primitive.\n * @param {Node} node\n * @param {JXG.Polygon} element A JSXGraph element of type {@link JXG.Polygon}\n */\n updatePolygonPrim: function (node, element) { /* stub */ },\n\n /**\n * Update a rectangle primitive. This is used only for points with face of type 'rect'.\n * @param {Node} node The node yearning to be updated.\n * @param {Number} x x coordinate of the top left vertex.\n * @param {Number} y y coordinate of the top left vertex.\n * @param {Number} w Width of the rectangle.\n * @param {Number} h The rectangle's height.\n */\n updateRectPrim: function (node, x, y, w, h) { /* stub */ },\n\n /* **************************\n * Set Attributes\n * **************************/\n\n /**\n * Sets a node's attribute.\n * @param {Node} node The node that is to be updated.\n * @param {String} key Name of the attribute.\n * @param {String} val New value for the attribute.\n */\n setPropertyPrim: function (node, key, val) { /* stub */ },\n\n setTabindex: function(element) {\n var val;\n if (element.board.attr.keyboard.enabled && Type.exists(element.rendNode)) {\n val = Type.evaluate(element.visProp.tabindex);\n if (!element.visPropCalc.visible || Type.evaluate(element.visProp.fixed)) {\n val = null;\n }\n if (val !== element.visPropOld.tabindex) {\n element.rendNode.setAttribute('tabindex', val);\n element.visPropOld.tabindex = val;\n }\n }\n },\n\n /**\n * Shows or hides an element on the canvas; Only a stub, requires implementation in the derived renderer.\n * @param {JXG.GeometryElement} element Reference to the object that has to appear.\n * @param {Boolean} value true to show the element, false to hide the element.\n */\n display: function (element, value) {\n if (element) {\n element.visPropOld.visible = value;\n }\n },\n\n /**\n * Shows a hidden element on the canvas; Only a stub, requires implementation in the derived renderer.\n *\n * Please use JXG.AbstractRenderer#display instead\n * @param {JXG.GeometryElement} element Reference to the object that has to appear.\n * @see JXG.AbstractRenderer#hide\n * @deprecated\n */\n show: function (element) { /* stub */ },\n\n /**\n * Hides an element on the canvas; Only a stub, requires implementation in the derived renderer.\n *\n * Please use JXG.AbstractRenderer#display instead\n * @param {JXG.GeometryElement} element Reference to the geometry element that has to disappear.\n * @see JXG.AbstractRenderer#show\n * @deprecated\n */\n hide: function (element) { /* stub */ },\n\n /**\n * Sets the buffering as recommended by SVGWG. Until now only Opera supports this and will be ignored by other\n * browsers. Although this feature is only supported by SVG we have this method in {@link JXG.AbstractRenderer}\n * because it is called from outside the renderer.\n * @param {Node} node The SVG DOM Node which buffering type to update.\n * @param {String} type Either 'auto', 'dynamic', or 'static'. For an explanation see\n * {@link http://www.w3.org/TR/SVGTiny12/painting.html#BufferedRenderingProperty}.\n */\n setBuffering: function (node, type) { /* stub */ },\n\n /**\n * Sets an element's dash style.\n * @param {JXG.GeometryElement} element An JSXGraph element.\n */\n setDashStyle: function (element) { /* stub */ },\n\n /**\n * Puts an object into draft mode, i.e. it's visual appearance will be changed. For GEONE<sub>x</sub>T backwards\n * compatibility.\n * @param {JXG.GeometryElement} el Reference of the object that is in draft mode.\n */\n setDraft: function (el) {\n if (!Type.evaluate(el.visProp.draft)) {\n return;\n }\n var draftColor = el.board.options.elements.draft.color,\n draftOpacity = el.board.options.elements.draft.opacity;\n\n this.setObjectTransition(el);\n if (el.type === Const.OBJECT_TYPE_POLYGON) {\n this.setObjectFillColor(el, draftColor, draftOpacity);\n } else {\n if (el.elementClass === Const.OBJECT_CLASS_POINT) {\n this.setObjectFillColor(el, draftColor, draftOpacity);\n } else {\n this.setObjectFillColor(el, 'none', 0);\n }\n this.setObjectStrokeColor(el, draftColor, draftOpacity);\n this.setObjectStrokeWidth(el, el.board.options.elements.draft.strokeWidth);\n }\n },\n\n /**\n * Puts an object from draft mode back into normal mode.\n * @param {JXG.GeometryElement} el Reference of the object that no longer is in draft mode.\n */\n removeDraft: function (el) {\n this.setObjectTransition(el);\n if (el.type === Const.OBJECT_TYPE_POLYGON) {\n this.setObjectFillColor(el,\n el.visProp.fillcolor,\n el.visProp.fillopacity);\n } else {\n if (el.type === Const.OBJECT_CLASS_POINT) {\n this.setObjectFillColor(el,\n el.visProp.fillcolor,\n el.visProp.fillopacity);\n }\n this.setObjectStrokeColor(el, el.visProp.strokecolor, el.visProp.strokeopacity);\n this.setObjectStrokeWidth(el, el.visProp.strokewidth);\n }\n },\n\n /**\n * Sets up nodes for rendering a gradient fill.\n * @param element\n */\n setGradient: function (element) { /* stub */ },\n\n /**\n * Updates the gradient fill.\n * @param {JXG.GeometryElement} element An JSXGraph element with an area that can be filled.\n */\n updateGradient: function (element) { /* stub */ },\n\n /**\n * Sets the transition duration (in milliseconds) for fill color and stroke\n * color and opacity.\n * @param {JXG.GeometryElement} element Reference of the object that wants a\n * new transition duration.\n * @param {Number} duration (Optional) duration in milliseconds. If not given,\n * element.visProp.transitionDuration is taken. This is the default.\n */\n setObjectTransition: function (element, duration) { /* stub */ },\n\n /**\n * Sets an objects fill color.\n * @param {JXG.GeometryElement} element Reference of the object that wants a new fill color.\n * @param {String} color Color in a HTML/CSS compatible format. If you don't want any fill color at all, choose\n * 'none'.\n * @param {Number} opacity Opacity of the fill color. Must be between 0 and 1.\n */\n setObjectFillColor: function (element, color, opacity) { /* stub */ },\n\n /**\n * Changes an objects stroke color to the given color.\n * @param {JXG.GeometryElement} element Reference of the {@link JXG.GeometryElement} that gets a new stroke\n * color.\n * @param {String} color Color value in a HTML compatible format, e.g. <strong>#00ff00</strong> or\n * <strong>green</strong> for green.\n * @param {Number} opacity Opacity of the fill color. Must be between 0 and 1.\n */\n setObjectStrokeColor: function (element, color, opacity) { /* stub */ },\n\n /**\n * Sets an element's stroke width.\n * @param {JXG.GeometryElement} element Reference to the geometry element.\n * @param {Number} width The new stroke width to be assigned to the element.\n */\n setObjectStrokeWidth: function (element, width) { /* stub */ },\n\n /**\n * Sets the shadow properties to a geometry element. This method is only a stub, it is implemented in the actual\n * renderers.\n * @param {JXG.GeometryElement} element Reference to a geometry object, that should get a shadow\n */\n setShadow: function (element) { /* stub */ },\n\n /**\n * Highlights an object, i.e. changes the current colors of the object to its highlighting colors\n * and highlighting stroke width.\n * @param {JXG.GeometryElement} el Reference of the object that will be highlighted.\n * @returns {JXG.AbstractRenderer} Reference to the renderer\n * @see JXG.AbstractRenderer#updateTextStyle\n */\n highlight: function (el) {\n var i, ev = el.visProp, sw;\n\n this.setObjectTransition(el);\n if (!ev.draft) {\n if (el.type === Const.OBJECT_TYPE_POLYGON) {\n this.setObjectFillColor(el,\n ev.highlightfillcolor,\n ev.highlightfillopacity);\n for (i = 0; i < el.borders.length; i++) {\n this.setObjectStrokeColor(el.borders[i],\n el.borders[i].visProp.highlightstrokecolor,\n el.borders[i].visProp.highlightstrokeopacity);\n }\n } else {\n if (el.elementClass === Const.OBJECT_CLASS_TEXT) {\n this.updateTextStyle(el, true);\n } else if (el.type === Const.OBJECT_TYPE_IMAGE) {\n this.updateImageStyle(el, true);\n this.setObjectFillColor(el,\n ev.highlightfillcolor,\n ev.highlightfillopacity);\n } else {\n this.setObjectStrokeColor(el, ev.highlightstrokecolor, ev.highlightstrokeopacity);\n this.setObjectFillColor(el,\n ev.highlightfillcolor,\n ev.highlightfillopacity);\n }\n }\n if (ev.highlightstrokewidth) {\n sw = Math.max(Type.evaluate(ev.highlightstrokewidth), Type.evaluate(ev.strokewidth));\n this.setObjectStrokeWidth(el, sw);\n if (el.elementClass === Const.OBJECT_CLASS_LINE || el.elementClass === Const.OBJECT_CLASS_CURVE) {\n this.updatePathWithArrowHeads(el, true);\n }\n }\n }\n\n return this;\n },\n\n /**\n * Uses the normal colors of an object, i.e. the opposite of {@link JXG.AbstractRenderer#highlight}.\n * @param {JXG.GeometryElement} el Reference of the object that will get its normal colors.\n * @returns {JXG.AbstractRenderer} Reference to the renderer\n * @see JXG.AbstractRenderer#updateTextStyle\n */\n noHighlight: function (el) {\n var i, ev = el.visProp, sw;\n\n this.setObjectTransition(el);\n if (!Type.evaluate(el.visProp.draft)) {\n if (el.type === Const.OBJECT_TYPE_POLYGON) {\n this.setObjectFillColor(el,\n ev.fillcolor,\n ev.fillopacity);\n for (i = 0; i < el.borders.length; i++) {\n this.setObjectStrokeColor(el.borders[i],\n el.borders[i].visProp.strokecolor,\n el.borders[i].visProp.strokeopacity);\n }\n } else {\n if (el.elementClass === Const.OBJECT_CLASS_TEXT) {\n this.updateTextStyle(el, false);\n } else if (el.type === Const.OBJECT_TYPE_IMAGE) {\n this.updateImageStyle(el, false);\n this.setObjectFillColor(el,\n ev.fillcolor,\n ev.fillopacity);\n } else {\n this.setObjectStrokeColor(el,\n ev.strokecolor,\n ev.strokeopacity);\n this.setObjectFillColor(el,\n ev.fillcolor,\n ev.fillopacity);\n }\n }\n\n sw = Type.evaluate(ev.strokewidth);\n this.setObjectStrokeWidth(el, sw);\n if (el.elementClass === Const.OBJECT_CLASS_LINE || el.elementClass === Const.OBJECT_CLASS_CURVE) {\n this.updatePathWithArrowHeads(el, false);\n }\n\n }\n\n return this;\n },\n\n /* **************************\n * renderer control\n * **************************/\n\n /**\n * Stop redraw. This method is called before every update, so a non-vector-graphics based renderer can use this\n * method to delete the contents of the drawing panel. This is an abstract method every descendant renderer\n * should implement, if appropriate.\n * @see JXG.AbstractRenderer#unsuspendRedraw\n */\n suspendRedraw: function () { /* stub */ },\n\n /**\n * Restart redraw. This method is called after updating all the rendering node attributes.\n * @see JXG.AbstractRenderer#suspendRedraw\n */\n unsuspendRedraw: function () { /* stub */ },\n\n /**\n * The tiny zoom bar shown on the bottom of a board (if showNavigation on board creation is true).\n * @param {JXG.Board} board Reference to a JSXGraph board.\n * @param {Object} attr Attributes of the navigation bar\n *\n */\n drawZoomBar: function (board, attr) {\n var doc,\n node,\n cancelbubble = function (e) {\n if (!e) {\n e = window.event;\n }\n\n if (e.stopPropagation) {\n // Non IE<=8\n e.stopPropagation();\n } else {\n e.cancelBubble = true;\n }\n },\n createButton = function (label, handler) {\n var button;\n\n button = doc.createElement('span');\n node.appendChild(button);\n button.appendChild(doc.createTextNode(label));\n\n // Style settings are superseded by adding the CSS class below\n button.style.paddingLeft = '7px';\n button.style.paddingRight = '7px';\n\n if (button.classList !== undefined) { // classList not available in IE 9\n button.classList.add('JXG_navigation_button');\n }\n // button.setAttribute('tabindex', 0);\n\n // Highlighting is now done with CSS\n // Env.addEvent(button, 'mouseover', function () {\n // this.style.backgroundColor = attr.highlightfillcolor;\n // }, button);\n // Env.addEvent(button, 'mouseover', function () {\n // this.style.backgroundColor = attr.highlightfillcolor;\n // }, button);\n // Env.addEvent(button, 'mouseout', function () {\n // this.style.backgroundColor = attr.fillcolor;\n // }, button);\n\n Env.addEvent(button, 'click', function(e) { (Type.bind(handler, board))(); return false; }, board);\n // prevent the click from bubbling down to the board\n Env.addEvent(button, 'mouseup', cancelbubble, board);\n Env.addEvent(button, 'mousedown', cancelbubble, board);\n Env.addEvent(button, 'touchend', cancelbubble, board);\n Env.addEvent(button, 'touchstart', cancelbubble, board);\n };\n\n if (Env.isBrowser && this.type !== 'no') {\n doc = board.containerObj.ownerDocument;\n node = doc.createElement('div');\n\n node.setAttribute('id', board.containerObj.id + '_navigationbar');\n\n // Style settings are superseded by adding the CSS class below\n node.style.color = attr.strokecolor;\n node.style.backgroundColor = attr.fillcolor;\n node.style.padding = attr.padding;\n node.style.position = attr.position;\n node.style.fontSize = attr.fontsize;\n node.style.cursor = attr.cursor;\n node.style.zIndex = attr.zindex;\n board.containerObj.appendChild(node);\n node.style.right = attr.right;\n node.style.bottom = attr.bottom;\n\n if (node.classList !== undefined) { // classList not available in IE 9\n node.classList.add('JXG_navigation');\n }\n // For XHTML we need unicode instead of HTML entities\n\n if (board.attr.showfullscreen) {\n createButton(board.attr.fullscreen.symbol, function () {\n board.toFullscreen(board.attr.fullscreen.id);\n });\n }\n\n if (board.attr.showscreenshot) {\n createButton(board.attr.screenshot.symbol, function () {\n window.setTimeout(function() {\n board.renderer.screenshot(board, '', false);\n }, 330);\n });\n }\n\n if (board.attr.showreload) {\n // full reload circle: \\u27F2\n // the board.reload() method does not exist during the creation\n // of this button. That's why this anonymous function wrapper is required.\n createButton('\\u21BB', function () {\n board.reload();\n });\n }\n\n if (board.attr.showcleartraces) {\n // clear traces symbol (otimes): \\u27F2\n createButton('\\u2297', function () {\n board.clearTraces();\n });\n }\n\n if (board.attr.shownavigation) {\n if (board.attr.showzoom) {\n createButton('\\u2013', board.zoomOut);\n createButton('o', board.zoom100);\n createButton('+', board.zoomIn);\n }\n createButton('\\u2190', board.clickLeftArrow);\n createButton('\\u2193', board.clickUpArrow);\n createButton('\\u2191', board.clickDownArrow);\n createButton('\\u2192', board.clickRightArrow);\n }\n }\n },\n\n /**\n * Wrapper for getElementById for maybe other renderers which elements are not directly accessible by DOM\n * methods like document.getElementById().\n * @param {String} id Unique identifier for element.\n * @returns {Object} Reference to a JavaScript object. In case of SVG/VMLRenderer it's a reference to a SVG/VML\n * node.\n */\n getElementById: function (id) {\n if (Type.exists(this.container)) {\n return this.container.ownerDocument.getElementById(this.container.id + '_' + id);\n }\n return '';\n },\n\n /**\n * Remove an element and provide a function that inserts it into its original position. This method\n * is taken from this article {@link https://developers.google.com/speed/articles/javascript-dom}.\n * @author KeeKim Heng, Google Web Developer\n * @param {Element} el The element to be temporarily removed\n * @returns {Function} A function that inserts the element into its original position\n */\n removeToInsertLater: function (el) {\n var parentNode = el.parentNode,\n nextSibling = el.nextSibling;\n\n if (parentNode === null) {\n return;\n }\n parentNode.removeChild(el);\n\n return function () {\n if (nextSibling) {\n parentNode.insertBefore(el, nextSibling);\n } else {\n parentNode.appendChild(el);\n }\n };\n },\n\n /**\n * Resizes the rendering element\n * @param {Number} w New width\n * @param {Number} h New height\n */\n resize: function (w, h) { /* stub */},\n\n /**\n * Create crosshair elements (Fadenkreuz) for presentations.\n * @param {Number} n Number of crosshairs.\n */\n createTouchpoints: function (n) {},\n\n /**\n * Show a specific crosshair.\n * @param {Number} i Number of the crosshair to show\n */\n showTouchpoint: function (i) {},\n\n /**\n * Hide a specific crosshair.\n * @param {Number} i Number of the crosshair to show\n */\n hideTouchpoint: function (i) {},\n\n /**\n * Move a specific crosshair.\n * @param {Number} i Number of the crosshair to show\n * @param {Array} pos New positon in screen coordinates\n */\n updateTouchpoint: function (i, pos) {},\n\n /**\n * Convert SVG construction to base64 encoded SVG data URL.\n * Only available on SVGRenderer.\n *\n * @see JXG.SVGRenderer#dumpToDataURI\n */\n dumpToDataURI: function (_ignoreTexts) {},\n\n /**\n * Convert SVG construction to canvas.\n * Only available on SVGRenderer.\n *\n * @see JXG.SVGRenderer#dumpToCanvas\n */\n dumpToCanvas: function (canvasId, w, h, _ignoreTexts) {},\n\n /**\n * Display SVG image in html img-tag which enables\n * easy download for the user.\n *\n * See JXG.SVGRenderer#screenshot\n */\n screenshot: function (board) {},\n\n /**\n * Move element into new layer. This is trivial for canvas, but needs more effort in SVG.\n * Does not work dynamically, i.e. if level is a function.\n *\n * @param {JXG.GeometryElement} el Element which is put into different layer\n * @param {Number} value Layer number\n * @private\n */\n setLayer: function(el, level) {}\n\n });\n\n return JXG.AbstractRenderer;\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG:true, define: true, ActiveXObject:true, jxgBinFileReader:true, DOMParser:true, XMLHttpRequest:true, document:true, navigator:true*/\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n jxg\n utils/env\n utils/type\n utils/encoding\n utils/base64\n */\n\ndefine('reader/file',[\n 'jxg', 'utils/env', 'utils/type', 'utils/encoding', 'utils/base64'\n], function (JXG, Env, Type, Encoding, Base64) {\n\n \"use strict\";\n\n /**\n * The FileReader object bundles the file input capabilities of JSXGraph.\n */\n JXG.FileReader = {\n /**\n *\n * @param {String} url\n * @param {JXG.Board} board\n * @param {String} format\n * @param {Boolean} async\n * @param {Function} callback\n *\n * @private\n */\n handleRemoteFile: function(url, board, format, async, encoding, callback) {\n var request = false;\n\n try {\n request = new XMLHttpRequest();\n if (format.toLowerCase() === 'raw') {\n request.overrideMimeType('text/plain; charset=' + encoding);\n } else {\n request.overrideMimeType('text/xml; charset=' + encoding);\n }\n } catch (e) {\n try {\n request = new ActiveXObject(\"Msxml2.XMLHTTP\");\n } catch (ex) {\n try {\n request = new ActiveXObject(\"Microsoft.XMLHTTP\");\n } catch (exc) {\n request = false;\n }\n }\n }\n if (!request) {\n JXG.debug(\"AJAX not activated!\");\n return;\n }\n\n request.open(\"GET\", url, async);\n if (format.toLowerCase() === 'raw') {\n this.cbp = function () {\n var req = request;\n if (req.readyState === 4) {\n board(req.responseText);\n }\n };\n } else {\n this.cbp = function () {\n var req = request,\n text = '';\n\n if (req.readyState === 4) {\n // Hack for ancient IEs:\n // We use the Visual Basic stuff from below.\n if (Type.exists(req.responseStream) &&\n // PK: zip, geogebra\n // 31: gzip, cinderella\n (req.responseText.slice(0, 2) === \"PK\" ||\n Encoding.asciiCharCodeAt(req.responseText.slice(0, 1), 0) === 31)) {\n\n // After this, text contains the binary? zip-compressed string\n text = Base64.decode(jxgBinFileReader(req));\n } else {\n // This is for all browsers except ancient IEs.\n text = req.responseText;\n // console.log(text);\n }\n this.parseString(text, board, format, callback);\n }\n };\n }\n\n this.cb = Type.bind(this.cbp, this);\n // Old style\n request.onreadystatechange = this.cb;\n\n try {\n request.send(null);\n } catch (ex2) {\n throw new Error(\"JSXGraph: A problem occurred while trying to read remote file '\" + url + \"'.\");\n }\n },\n\n /**\n *\n * @param {Blob} url The Blob or File from which to read\n * @param {JXG.Board} board\n * @param {String} format\n * @param {Boolean} async\n * @param {Function} callback\n *\n * @private\n */\n handleLocalFile: function(url, board, format, async, encoding, callback) {\n if (!Type.exists(async)) {\n async = true;\n }\n\n if (format.toLowerCase() === 'raw') {\n this.cbp = function (e) {\n board(e.target.result);\n };\n } else {\n this.cbp = function (e) {\n var text = e.target.result;\n //console.log(text);\n this.parseString(text, board, format, callback);\n };\n }\n\n this.cb = Type.bind(this.cbp, this);\n\n var reader = new FileReader();\n reader.onload = this.cb;\n if (format.toLowerCase() === 'raw') {\n reader.readAsText(url);\n } else {\n reader.readAsText(url, encoding);\n }\n },\n\n /**\n * Opens a file using the given URL and passes the contents to {@link JXG.FileReader#parseString}\n * @param {String} url\n * @param {JXG.Board|function} board Either a board or in case <tt>format</tt> equals 'raw' this has to be a callback function.\n * @param {String} format The expected file format. Possible values are <dl>\n * <dt>raw</dt><dd>Raw text file. In this case <tt>board</tt> has to be a callback function.</dd>\n * <dt>geonext</dt><dd>Geonext File <a href=\"http://www.geonext.de\">http://www.geonext.de</a></dd>\n * <dt>intergeo</dt><dd>Intergeo file format <a href=\"http://www.i2geo.net\">http://www.i2geo.net</a></dd>\n * <dt>tracenpoche</dt><dd>Tracenpoche construction <a href=\"http://www.tracenpoche.net\">http://www.tracenpoche.net</a></dd>\n * <dt>graph</dt><dd>Graph file</dd>\n * <dt>digraph</dt><dd>DiGraph file</dd>\n * <dt>geogebra</dt><dd>Geogebra File <a href=\"http://www.geogebra.org\">http://www.geogebra.org</a></dd>\n * <dl><dt>cdy or cinderella</dt><dd>Cinderella (<a href=\"http://www.cinderella.de/\">http://www.cinderella.de</a></dd>\n * </dl>\n * @param {Boolean} async Call ajax asynchonously.\n * @param {function} callback A function that is run when the board is ready.\n */\n parseFileContent: function (url, board, format, async, encoding, callback) {\n if (Type.isString(url) || FileReader === undefined) {\n this.handleRemoteFile(url, board, format, async, encoding, callback);\n } else {\n this.handleLocalFile(url, board, format, async, encoding, callback);\n }\n },\n\n /**\n * Parses a given string according to the file format given in format.\n * @param {String} str Contents of the file.\n * @param {JXG.Board} board The board the construction in the file should be loaded in.\n * @param {String} format Possible values are <dl>\n * <dt>raw</dt><dd>Raw text file. In this case <tt>board</tt> has to be a callback function.</dd>\n * <dt>geonext</dt><dd>Geonext File <a href=\"http://www.geonext.de\">http://www.geonext.de</a></dd>\n * <dt>intergeo</dt><dd>Intergeo file format <a href=\"http://www.i2geo.net\">http://www.i2geo.net</a></dd>\n * <dt>tracenpoche</dt><dd>Tracenpoche construction <a href=\"http://www.tracenpoche.net\">http://www.tracenpoche.net</a></dd>\n * <dt>graph</dt><dd>Graph file</dd>\n * <dt>digraph</dt><dd>DiGraph file</dd>\n * <dt>geogebra</dt><dd>Geogebra File <a href=\"http://www.geogebra.org\">http://www.geogebra.org</a></dd>\n * <dl><dt>cdy or cinderella</dt><dd>Cinderella (<a href=\"http://www.cinderella.de/\">http://www.cinderella.de</a></dd>\n * </dl>\n * @param {function} callback\n */\n parseString: function (str, board, format, callback) {\n var Reader,\n read;\n\n format = format.toLowerCase();\n Reader = JXG.readers[format];\n\n if (Type.exists(Reader)) {\n read = new Reader(board, str);\n read.read();\n } else if (format === 'jessiecode') {\n\n } else {\n throw new Error('JSXGraph: There is no reader available for \\'' + format + '\\'.');\n }\n\n if (Type.isFunction(callback)) {\n callback(board);\n }\n }\n };\n\n // The following code is vbscript. This is a workaround to enable binary data downloads via AJAX in\n // Microsoft Internet Explorer.\n\n /*jslint evil:true, es5:true, white:true*/\n /*jshint multistr:true*/\n if (!Env.isMetroApp() && Env.isBrowser && typeof navigator === 'object' && /msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent) && document && document.write) {\n document.write('<script type=\"text/vbscript\">\\n\\\nFunction Base64Encode(inData)\\n\\\n Const Base64 = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\"\\n\\\n Dim cOut, sOut, I\\n\\\n For I = 1 To LenB(inData) Step 3\\n\\\n Dim nGroup, pOut, sGroup\\n\\\n nGroup = &H10000 * AscB(MidB(inData, I, 1)) + _\\n\\\n &H100 * MyASC(MidB(inData, I + 1, 1)) + MyASC(MidB(inData, I + 2, 1))\\n\\\n nGroup = Oct(nGroup)\\n\\\n nGroup = String(8 - Len(nGroup), \"0\") & nGroup\\n\\\n pOut = Mid(Base64, CLng(\"&o\" & Mid(nGroup, 1, 2)) + 1, 1) + _\\n\\\n Mid(Base64, CLng(\"&o\" & Mid(nGroup, 3, 2)) + 1, 1) + _\\n\\\n Mid(Base64, CLng(\"&o\" & Mid(nGroup, 5, 2)) + 1, 1) + _\\n\\\n Mid(Base64, CLng(\"&o\" & Mid(nGroup, 7, 2)) + 1, 1)\\n\\\n sOut = sOut + pOut\\n\\\n Next\\n\\\n Select Case LenB(inData) Mod 3\\n\\\n Case 1: \\'8 bit final\\n\\\n sOut = Left(sOut, Len(sOut) - 2) + \"==\"\\n\\\n Case 2: \\'16 bit final\\n\\\n sOut = Left(sOut, Len(sOut) - 1) + \"=\"\\n\\\n End Select\\n\\\n Base64Encode = sOut\\n\\\nEnd Function\\n\\\n\\n\\\nFunction MyASC(OneChar)\\n\\\n If OneChar = \"\" Then MyASC = 0 Else MyASC = AscB(OneChar)\\n\\\nEnd Function\\n\\\n\\n\\\nFunction jxgBinFileReader(xhr)\\n\\\n Dim byteString\\n\\\n Dim b64String\\n\\\n Dim i\\n\\\n byteString = xhr.responseBody\\n\\\n ReDim byteArray(LenB(byteString))\\n\\\n For i = 1 To LenB(byteString)\\n\\\n byteArray(i-1) = AscB(MidB(byteString, i, 1))\\n\\\n Next\\n\\\n b64String = Base64Encode(byteString)\\n\\\n jxgBinFileReader = b64String\\n\\\nEnd Function\\n\\\n</script>\\n');\n }\n\n return JXG.FileReader;\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true*/\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n jxg\n base/constants\n utils/type\n math/math\n math/geometry\n */\n\ndefine('parser/geonext',[\n 'jxg', 'base/constants', 'utils/type'\n], function (JXG, Const, Type) {\n\n \"use strict\";\n\n /**\n * Parser helper routines. The methods in here are for parsing expressions in Geonext Syntax.\n * @namespace\n */\n JXG.GeonextParser = {\n /**\n * Converts expression of the form <i>leftop^rightop</i> into <i>Math.pow(leftop,rightop)</i>.\n * @param {String} te Expression of the form <i>leftop^rightop</i>\n * @returns {String} Converted expression.\n */\n replacePow: function (te) {\n var count, pos, c, previousIndex,\n leftop, rightop, pre, p, left, i, right, expr;\n\n // delete all whitespace immediately before and after all ^ operators\n te = te.replace(/(\\s*)\\^(\\s*)/g, '^');\n\n // Loop over all ^ operators\n i = te.indexOf('^');\n previousIndex = -1;\n\n while (i >= 0 && i < te.length - 1) {\n if (previousIndex === i) {\n throw new Error(\"JSXGraph: Error while parsing expression '\" + te + \"'\");\n }\n previousIndex = i;\n\n // left and right are the substrings before, resp. after the ^ character\n left = te.slice(0, i);\n right = te.slice(i + 1);\n\n // If there is a \")\" immediately before the ^ operator, it can be the end of a\n // (i) term in parenthesis\n // (ii) function call\n // (iii) method call\n // In either case, first the corresponding opening parenthesis is searched.\n // This is the case, when count==0\n if (left.charAt(left.length - 1) === ')') {\n count = 1;\n pos = left.length - 2;\n\n while (pos >= 0 && count > 0) {\n c = left.charAt(pos);\n if (c === ')') {\n count++;\n } else if (c === '(') {\n count -= 1;\n }\n pos -= 1;\n }\n\n if (count === 0) {\n // Now, we have found the opning parenthesis and we have to look\n // if it is (i), or (ii), (iii).\n leftop = '';\n // Search for F or p.M before (...)^\n pre = left.substring(0, pos + 1);\n p = pos;\n while (p >= 0 && pre.substr(p, 1).match(/([\\w.]+)/)) {\n leftop = RegExp.$1 + leftop;\n p -= 1;\n }\n leftop += left.substring(pos + 1, left.length);\n leftop = leftop.replace(/([()+*%^\\-/\\][])/g, '\\\\$1');\n } else {\n throw new Error(\"JSXGraph: Missing '(' in expression\");\n }\n } else {\n // Otherwise, the operand has to be a constant (or variable).\n leftop = '[\\\\w\\\\.]+'; // former: \\\\w\\\\.\n }\n\n // To the right of the ^ operator there also may be a function or method call\n // or a term in parenthesis. Alos, ere we search for the closing\n // parenthesis.\n if (right.match(/^([\\w.]*\\()/)) {\n count = 1;\n pos = RegExp.$1.length;\n\n while (pos < right.length && count > 0) {\n c = right.charAt(pos);\n\n if (c === ')') {\n count -= 1;\n } else if (c === '(') {\n count += 1;\n }\n pos += 1;\n }\n\n if (count === 0) {\n rightop = right.substring(0, pos);\n rightop = rightop.replace(/([()+*%^\\-/[\\]])/g, '\\\\$1');\n } else {\n throw new Error(\"JSXGraph: Missing ')' in expression\");\n }\n } else {\n // Otherwise, the operand has to be a constant (or variable).\n rightop = '[\\\\w\\\\.]+';\n }\n // Now, we have the two operands and replace ^ by JXG.Math.pow\n expr = new RegExp('(' + leftop + ')\\\\^(' + rightop + ')');\n //te = te.replace(expr, 'JXG.Math.pow($1,$2)');\n te = te.replace(expr, 'pow($1,$2)');\n i = te.indexOf('^');\n }\n\n return te;\n },\n\n /**\n * Converts expression of the form <i>If(a,b,c)</i> into <i>(a)?(b):(c)/i>.\n * @param {String} te Expression of the form <i>If(a,b,c)</i>\n * @returns {String} Converted expression.\n */\n replaceIf: function (te) {\n var left, right,\n i, pos, count, k1, k2, c, meat,\n s = '',\n first = null,\n second = null,\n third = null;\n\n i = te.indexOf('If(');\n if (i < 0) {\n return te;\n }\n\n // \"\" means not defined. Here, we replace it by 0\n te = te.replace(/\"\"/g, '0');\n while (i >= 0) {\n left = te.slice(0, i);\n right = te.slice(i + 3);\n\n // Search the end of the If() command and take out the meat\n count = 1;\n pos = 0;\n k1 = -1;\n k2 = -1;\n\n while (pos < right.length && count > 0) {\n c = right.charAt(pos);\n\n if (c === ')') {\n count -= 1;\n } else if (c === '(') {\n count += 1;\n } else if (c === ',' && count === 1) {\n if (k1 < 0) {\n // first komma\n k1 = pos;\n } else {\n // second komma\n k2 = pos;\n }\n }\n pos += 1;\n }\n meat = right.slice(0, pos - 1);\n right = right.slice(pos);\n\n // Test the two kommas\n if (k1 < 0) {\n // , missing\n return '';\n }\n\n if (k2 < 0) {\n // , missing\n return '';\n }\n\n first = meat.slice(0, k1);\n second = meat.slice(k1 + 1, k2);\n third = meat.slice(k2 + 1);\n\n // Recurse\n first = this.replaceIf(first);\n second = this.replaceIf(second);\n third = this.replaceIf(third);\n\n s += left + '((' + first + ')?' + '(' + second + '):(' + third + '))';\n te = right;\n first = null;\n second = null;\n i = te.indexOf('If(');\n }\n s += right;\n return s;\n },\n\n /**\n * Replace an element's name in terms by an element's id.\n * @param {String} term Term containing names of elements.\n * @param {JXG.Board} board Reference to the board the elements are on.\n * @param {Boolean} [jc=false] If true, all id's will be surrounded by <tt>$('</tt> and <tt>')</tt>.\n * @returns {String} The same string with names replaced by ids.\n **/\n replaceNameById: function (term, board, jc) {\n var end, elName, el, i,\n pos = 0,\n funcs = ['X', 'Y', 'L', 'V'],\n\n printId = function (id) {\n if (jc) {\n return '$(\\'' + id + '\\')';\n }\n\n return id;\n };\n\n // Find X(el), Y(el), ...\n // All functions declared in funcs\n for (i = 0; i < funcs.length; i++) {\n pos = term.indexOf(funcs[i] + '(');\n\n while (pos >= 0) {\n if (pos >= 0) {\n end = term.indexOf(')', pos + 2);\n if (end >= 0) {\n elName = term.slice(pos + 2, end);\n elName = elName.replace(/\\\\(['\"])?/g, '$1');\n el = board.elementsByName[elName];\n\n if (el) {\n term = term.slice(0, pos + 2) + (jc ? '$(\\'' : '') + printId(el.id) + term.slice(end);\n }\n }\n }\n end = term.indexOf(')', pos + 2);\n pos = term.indexOf(funcs[i] + '(', end);\n }\n }\n\n pos = term.indexOf('Dist(');\n while (pos >= 0) {\n if (pos >= 0) {\n end = term.indexOf(',', pos + 5);\n if (end >= 0) {\n elName = term.slice(pos + 5, end);\n elName = elName.replace(/\\\\(['\"])?/g, '$1');\n el = board.elementsByName[elName];\n\n if (el) {\n term = term.slice(0, pos + 5) + printId(el.id) + term.slice(end);\n }\n }\n }\n end = term.indexOf(',', pos + 5);\n pos = term.indexOf(',', end);\n end = term.indexOf(')', pos + 1);\n\n if (end >= 0) {\n elName = term.slice(pos + 1, end);\n elName = elName.replace(/\\\\(['\"])?/g, '$1');\n el = board.elementsByName[elName];\n\n if (el) {\n term = term.slice(0, pos + 1) + printId(el.id) + term.slice(end);\n }\n }\n end = term.indexOf(')', pos + 1);\n pos = term.indexOf('Dist(', end);\n }\n\n funcs = ['Deg', 'Rad'];\n for (i = 0; i < funcs.length; i++) {\n pos = term.indexOf(funcs[i] + '(');\n while (pos >= 0) {\n if (pos >= 0) {\n end = term.indexOf(',', pos + 4);\n if (end >= 0) {\n elName = term.slice(pos + 4, end);\n elName = elName.replace(/\\\\(['\"])?/g, '$1');\n el = board.elementsByName[elName];\n\n if (el) {\n term = term.slice(0, pos + 4) + printId(el.id) + term.slice(end);\n }\n }\n }\n\n end = term.indexOf(',', pos + 4);\n pos = term.indexOf(',', end);\n end = term.indexOf(',', pos + 1);\n\n if (end >= 0) {\n elName = term.slice(pos + 1, end);\n elName = elName.replace(/\\\\(['\"])?/g, '$1');\n el = board.elementsByName[elName];\n\n if (el) {\n term = term.slice(0, pos + 1) + printId(el.id) + term.slice(end);\n }\n }\n\n end = term.indexOf(',', pos + 1);\n pos = term.indexOf(',', end);\n end = term.indexOf(')', pos + 1);\n\n if (end >= 0) {\n elName = term.slice(pos + 1, end);\n elName = elName.replace(/\\\\(['\"])?/g, '$1');\n el = board.elementsByName[elName];\n if (el) {\n term = term.slice(0, pos + 1) + printId(el.id) + term.slice(end);\n }\n }\n\n end = term.indexOf(')', pos + 1);\n pos = term.indexOf(funcs[i] + '(', end);\n }\n }\n\n return term;\n },\n\n /**\n * Replaces element ids in terms by element this.board.objects['id'].\n * @param {String} term A GEONE<sub>x</sub>T function string with JSXGraph ids in it.\n * @returns {String} The input string with element ids replaced by this.board.objects[\"id\"].\n **/\n replaceIdByObj: function (term) {\n // Search for expressions like \"X(gi23)\" or \"Y(gi23A)\" and convert them to objects['gi23'].X().\n var expr = /(X|Y|L)\\(([\\w_]+)\\)/g;\n term = term.replace(expr, '$(\\'$2\\').$1()');\n\n expr = /(V)\\(([\\w_]+)\\)/g;\n term = term.replace(expr, '$(\\'$2\\').Value()');\n\n expr = /(Dist)\\(([\\w_]+),([\\w_]+)\\)/g;\n term = term.replace(expr, 'dist($(\\'$2\\'), $(\\'$3\\'))');\n\n expr = /(Deg)\\(([\\w_]+),([ \\w[\\w_]+),([\\w_]+)\\)/g;\n term = term.replace(expr, 'deg($(\\'$2\\'),$(\\'$3\\'),$(\\'$4\\'))');\n\n // Search for Rad('gi23','gi24','gi25')\n expr = /Rad\\(([\\w_]+),([\\w_]+),([\\w_]+)\\)/g;\n term = term.replace(expr, 'rad($(\\'$1\\'),$(\\'$2\\'),$(\\'$3\\'))');\n\n // it's ok, it will run through the jessiecode parser afterwards...\n /*jslint regexp: true*/\n expr = /N\\((.+)\\)/g;\n term = term.replace(expr, '($1)');\n\n return term;\n },\n\n /**\n * Converts the given algebraic expression in GEONE<sub>x</sub>T syntax into an equivalent expression in JavaScript syntax.\n * @param {String} term Expression in GEONExT syntax\n * @param {JXG.Board} board\n * @returns {String} Given expression translated to JavaScript.\n */\n geonext2JS: function (term, board) {\n var expr, newterm, i,\n from = ['Abs', 'ACos', 'ASin', 'ATan', 'Ceil', 'Cos', 'Exp', 'Factorial', 'Floor',\n 'Log', 'Max', 'Min', 'Random', 'Round', 'Sin', 'Sqrt', 'Tan', 'Trunc'],\n to = ['abs', 'acos', 'asin', 'atan', 'ceil', 'cos',\n 'exp', 'factorial', 'floor', 'log', 'max', 'min',\n 'random', 'round', 'sin', 'sqrt', 'tan', 'ceil'];\n\n // Hacks, to enable not well formed XML, @see JXG.GeonextReader#replaceLessThan\n term = term.replace(/</g, '<');\n term = term.replace(/>/g, '>');\n term = term.replace(/&/g, '&');\n\n // Umwandeln der GEONExT-Syntax in JavaScript-Syntax\n newterm = term;\n newterm = this.replaceNameById(newterm, board);\n newterm = this.replaceIf(newterm);\n // Exponentiations-Problem x^y -> Math(exp(x,y).\n newterm = this.replacePow(newterm);\n newterm = this.replaceIdByObj(newterm);\n\n for (i = 0; i < from.length; i++) {\n // sin -> Math.sin and asin -> Math.asin\n expr = new RegExp(['(\\\\W|^)(', from[i], ')'].join(''), 'ig');\n newterm = newterm.replace(expr, ['$1', to[i]].join(''));\n }\n newterm = newterm.replace(/True/g, 'true');\n newterm = newterm.replace(/False/g, 'false');\n newterm = newterm.replace(/fasle/g, 'false');\n newterm = newterm.replace(/Pi/g, 'PI');\n newterm = newterm.replace(/\"/g, '\\'');\n\n return newterm;\n },\n\n /**\n * Finds dependencies in a given term and resolves them by adding the\n * dependent object to the found objects child elements.\n * @param {JXG.GeometryElement} me Object depending on objects in given term.\n * @param {String} term String containing dependencies for the given object.\n * @param {JXG.Board} [board=me.board] Reference to a board\n */\n findDependencies: function (me, term, board) {\n var elements, el, expr, elmask;\n\n if (!Type.exists(board)) {\n board = me.board;\n }\n\n elements = board.elementsByName;\n\n for (el in elements) {\n if (elements.hasOwnProperty(el)) {\n if (el !== me.name) {\n if (elements[el].elementClass === Const.OBJECT_CLASS_TEXT) {\n if (!Type.evaluate(elements[el].visProp.islabel)) {\n elmask = el.replace(/\\[/g, '\\\\[');\n elmask = elmask.replace(/\\]/g, '\\\\]');\n\n // Searches (A), (A,B),(A,B,C)\n expr = new RegExp(\"\\\\(([\\\\w\\\\[\\\\]'_ ]+,)*(\" + elmask + \")(,[\\\\w\\\\[\\\\]'_ ]+)*\\\\)\", 'g');\n\n if (term.search(expr) >= 0) {\n elements[el].addChild(me);\n }\n }\n } else {\n elmask = el.replace(/\\[/g, '\\\\[');\n elmask = elmask.replace(/\\]/g, '\\\\]');\n\n // Searches (A), (A,B),(A,B,C)\n expr = new RegExp(\"\\\\(([\\\\w\\\\[\\\\]'_ ]+,)*(\" + elmask + \")(,[\\\\w\\\\[\\\\]'_ ]+)*\\\\)\", 'g');\n\n if (term.search(expr) >= 0) {\n elements[el].addChild(me);\n }\n }\n }\n }\n }\n },\n\n /**\n * Converts the given algebraic expression in GEONE<sub>x</sub>T syntax into an equivalent expression in JessieCode syntax.\n * @param {String} term Expression in GEONExT syntax\n * @param {JXG.Board} board\n * @returns {String} Given expression translated to JavaScript.\n */\n gxt2jc: function (term, board) {\n var newterm,\n from = ['Sqrt'],\n to = ['sqrt'];\n\n // Hacks, to enable not well formed XML, @see JXG.GeonextReader#replaceLessThan\n term = term.replace(/</g, '<');\n term = term.replace(/>/g, '>');\n term = term.replace(/&/g, '&');\n newterm = term;\n newterm = this.replaceNameById(newterm, board, true);\n newterm = newterm.replace(/True/g, 'true');\n newterm = newterm.replace(/False/g, 'false');\n newterm = newterm.replace(/fasle/g, 'false');\n\n return newterm;\n }\n };\n\n return JXG.GeonextParser;\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true*/\n/*jslint nomen: true, plusplus: true, unparam: true*/\n\n/* depends:\n jxg\n base/constants\n base/coords\n math/math\n options\n parser/geonext\n utils/event\n utils/color\n utils/type\n */\n\ndefine('base/element',[\n 'jxg', 'base/constants', 'base/coords', 'math/math', 'math/statistics', 'options', 'utils/event', 'utils/color', 'utils/type'\n], function (JXG, Const, Coords, Mat, Statistics, Options, EventEmitter, Color, Type) {\n\n \"use strict\";\n\n /**\n * Constructs a new GeometryElement object.\n * @class This is the basic class for geometry elements like points, circles and lines.\n * @constructor\n * @param {JXG.Board} board Reference to the board the element is constructed on.\n * @param {Object} attributes Hash of attributes and their values.\n * @param {Number} type Element type (a <tt>JXG.OBJECT_TYPE_</tt> value).\n * @param {Number} oclass The element's class (a <tt>JXG.OBJECT_CLASS_</tt> value).\n * @borrows JXG.EventEmitter#on as this.on\n * @borrows JXG.EventEmitter#off as this.off\n * @borrows JXG.EventEmitter#triggerEventHandlers as this.triggerEventHandlers\n * @borrows JXG.EventEmitter#eventHandlers as this.eventHandlers\n */\n JXG.GeometryElement = function (board, attributes, type, oclass) {\n var name, key, attr;\n\n /**\n * Controls if updates are necessary\n * @type Boolean\n * @default true\n */\n this.needsUpdate = true;\n\n /**\n * Controls if this element can be dragged. In GEONExT only\n * free points and gliders can be dragged.\n * @type Boolean\n * @default false\n */\n this.isDraggable = false;\n\n /**\n * If element is in two dimensional real space this is true, else false.\n * @type Boolean\n * @default true\n */\n this.isReal = true;\n\n /**\n * Stores all dependent objects to be updated when this point is moved.\n * @type Object\n */\n this.childElements = {};\n\n /**\n * If element has a label subelement then this property will be set to true.\n * @type Boolean\n * @default false\n */\n this.hasLabel = false;\n\n /**\n * True, if the element is currently highlighted.\n * @type Boolean\n * @default false\n */\n this.highlighted = false;\n\n /**\n * Stores all Intersection Objects which in this moment are not real and\n * so hide this element.\n * @type Object\n */\n this.notExistingParents = {};\n\n /**\n * Keeps track of all objects drawn as part of the trace of the element.\n * @see JXG.GeometryElement#clearTrace\n * @see JXG.GeometryElement#numTraces\n * @type Object\n */\n this.traces = {};\n\n /**\n * Counts the number of objects drawn as part of the trace of the element.\n * @see JXG.GeometryElement#clearTrace\n * @see JXG.GeometryElement#traces\n * @type Number\n */\n this.numTraces = 0;\n\n /**\n * Stores the transformations which are applied during update in an array\n * @type Array\n * @see JXG.Transformation\n */\n this.transformations = [];\n\n /**\n * @type JXG.GeometryElement\n * @default null\n * @private\n */\n this.baseElement = null;\n\n /**\n * Elements depending on this element are stored here.\n * @type Object\n */\n this.descendants = {};\n\n /**\n * Elements on which this element depends on are stored here.\n * @type Object\n */\n this.ancestors = {};\n\n /**\n * Ids of elements on which this element depends directly are stored here.\n * @type Object\n */\n this.parents = [];\n\n /**\n * Stores variables for symbolic computations\n * @type Object\n */\n this.symbolic = {};\n\n /**\n * Stores the SVG (or VML) rendering node for the element. This enables low-level\n * access to SVG nodes. The properties of such an SVG node can then be changed\n * by calling setAttribute(). Note that there are a few elements which consist\n * of more than one SVG nodes:\n * <ul>\n * <li> Elements with arrow tail or head: rendNodeTriangleStart, rendNodeTriangleEnd\n * <li> SVG (or VML) texts: rendNodeText\n * <li> Button: rendNodeForm, rendNodeButton, rendNodeTag\n * <li> Checkbox: rendNodeForm, rendNodeCheckbox, rendNodeLabel, rendNodeTag\n * <li> Input: rendNodeForm, rendNodeInput, rendNodeLabel, rendNodeTag\n * </ul>\n *\n * Here is are two examples: The first example shows how to access the SVG node,\n * the second example demonstrates how to change SVG attributes.\n * @example\n * var p1 = board.create('point', [0, 0]);\n * console.log(p1.rendNode);\n * // returns the full SVG node details of the point p1, something like:\n * // <ellipse id='box_jxgBoard1P6' stroke='#ff0000' stroke-opacity='1' stroke-width='2px'\n * // fill='#ff0000' fill-opacity='1' cx='250' cy='250' rx='4' ry='4'\n * // style='position: absolute;'>\n * // </ellipse>\n *\n * @example\n * var s = board.create('segment', [p1, p2], {strokeWidth: 60});\n * s.rendNode.setAttribute('stroke-linecap', 'round');\n *\n * @type Object\n */\n this.rendNode = null;\n\n /**\n * The string used with {@link JXG.Board#create}\n * @type String\n */\n this.elType = '';\n\n /**\n * The element is saved with an explicit entry in the file (<tt>true</tt>) or implicitly\n * via a composition.\n * @type Boolean\n * @default true\n */\n this.dump = true;\n\n /**\n * Subs contains the subelements, created during the create method.\n * @type Object\n */\n this.subs = {};\n\n /**\n * Inherits contains the subelements, which may have an attribute\n * (in particular the attribute \"visible\") having value 'inherit'.\n * @type Object\n */\n this.inherits = [];\n\n /**\n * The position of this element inside the {@link JXG.Board#objectsList}.\n * @type Number\n * @default -1\n * @private\n */\n this._pos = -1;\n\n /**\n * [c, b0, b1, a, k, r, q0, q1]\n *\n * See\n * A.E. Middleditch, T.W. Stacey, and S.B. Tor:\n * \"Intersection Algorithms for Lines and Circles\",\n * ACM Transactions on Graphics, Vol. 8, 1, 1989, pp 25-40.\n *\n * The meaning of the parameters is:\n * Circle: points p=[p0, p1] on the circle fulfill\n * a<p, p> + <b, p> + c = 0\n * For convenience we also store\n * r: radius\n * k: discriminant = sqrt(<b,b>-4ac)\n * q=[q0, q1] center\n *\n * Points have radius = 0.\n * Lines have radius = infinity.\n * b: normalized vector, representing the direction of the line.\n *\n * Should be put into Coords, when all elements possess Coords.\n * @type Array\n * @default [1, 0, 0, 0, 1, 1, 0, 0]\n */\n this.stdform = [1, 0, 0, 0, 1, 1, 0, 0];\n\n /**\n * The methodMap determines which methods can be called from within JessieCode and under which name it\n * can be used. The map is saved in an object, the name of a property is the name of the method used in JessieCode,\n * the value of a property is the name of the method in JavaScript.\n * @type Object\n */\n this.methodMap = {\n setLabel: 'setLabel',\n label: 'label',\n setName: 'setName',\n getName: 'getName',\n addTransform: 'addTransform',\n setProperty: 'setAttribute',\n setAttribute: 'setAttribute',\n addChild: 'addChild',\n animate: 'animate',\n on: 'on',\n off: 'off',\n trigger: 'trigger',\n addTicks: 'addTicks',\n removeTicks: 'removeTicks',\n removeAllTicks: 'removeAllTicks'\n };\n\n /**\n * Quadratic form representation of circles (and conics)\n * @type Array\n * @default [[1,0,0],[0,1,0],[0,0,1]]\n */\n this.quadraticform = [[1, 0, 0], [0, 1, 0], [0, 0, 1]];\n\n /**\n * An associative array containing all visual properties.\n * @type Object\n * @default empty object\n */\n this.visProp = {};\n\n /**\n * An associative array containing visual properties which are calculated from\n * the attribute values (i.e. visProp) and from other constraints.\n * An example: if an intersection point does not have real coordinates,\n * visPropCalc.visible is set to false.\n * Additionally, the user can control visibility with the attribute \"visible\",\n * even by supplying a functions as value.\n *\n * @type Object\n * @default empty object\n */\n this.visPropCalc = {\n visible: false\n };\n\n EventEmitter.eventify(this);\n\n /**\n * Is the mouse over this element?\n * @type Boolean\n * @default false\n */\n this.mouseover = false;\n\n /**\n * Time stamp containing the last time this element has been dragged.\n * @type Date\n * @default creation time\n */\n this.lastDragTime = new Date();\n\n if (arguments.length > 0) {\n /**\n * Reference to the board associated with the element.\n * @type JXG.Board\n */\n this.board = board;\n\n /**\n * Type of the element.\n * @constant\n * @type Number\n */\n this.type = type;\n\n /**\n * Original type of the element at construction time. Used for removing glider property.\n * @constant\n * @type Number\n */\n this._org_type = type;\n\n /**\n * The element's class.\n * @constant\n * @type Number\n */\n this.elementClass = oclass || Const.OBJECT_CLASS_OTHER;\n\n /**\n * Unique identifier for the element. Equivalent to id-attribute of renderer element.\n * @type String\n */\n this.id = attributes.id;\n\n name = attributes.name;\n /* If name is not set or null or even undefined, generate an unique name for this object */\n if (!Type.exists(name)) {\n name = this.board.generateName(this);\n }\n\n if (name !== '') {\n this.board.elementsByName[name] = this;\n }\n\n /**\n * Not necessarily unique name for the element.\n * @type String\n * @default Name generated by {@link JXG.Board#generateName}.\n * @see JXG.Board#generateName\n */\n this.name = name;\n\n this.needsRegularUpdate = attributes.needsregularupdate;\n\n // create this.visPropOld and set default values\n Type.clearVisPropOld(this);\n\n attr = this.resolveShortcuts(attributes);\n for (key in attr) {\n if (attr.hasOwnProperty(key)) {\n this._set(key, attr[key]);\n }\n }\n\n this.visProp.draft = attr.draft && attr.draft.draft;\n //this.visProp.gradientangle = '270';\n // this.visProp.gradientsecondopacity = Type.evaluate(this.visProp.fillopacity);\n //this.visProp.gradientpositionx = 0.5;\n //this.visProp.gradientpositiony = 0.5;\n }\n };\n\n JXG.extend(JXG.GeometryElement.prototype, /** @lends JXG.GeometryElement.prototype */ {\n /**\n * Add an element as a child to the current element. Can be used to model dependencies between geometry elements.\n * @param {JXG.GeometryElement} obj The dependent object.\n */\n addChild: function (obj) {\n var el, el2;\n\n this.childElements[obj.id] = obj;\n this.addDescendants(obj);\n obj.ancestors[this.id] = this;\n\n for (el in this.descendants) {\n if (this.descendants.hasOwnProperty(el)) {\n this.descendants[el].ancestors[this.id] = this;\n\n for (el2 in this.ancestors) {\n if (this.ancestors.hasOwnProperty(el2)) {\n this.descendants[el].ancestors[this.ancestors[el2].id] = this.ancestors[el2];\n }\n }\n }\n }\n\n for (el in this.ancestors) {\n if (this.ancestors.hasOwnProperty(el)) {\n for (el2 in this.descendants) {\n if (this.descendants.hasOwnProperty(el2)) {\n this.ancestors[el].descendants[this.descendants[el2].id] = this.descendants[el2];\n }\n }\n }\n }\n return this;\n },\n\n /**\n * Adds the given object to the descendants list of this object and all its child objects.\n * @param {JXG.GeometryElement} obj The element that is to be added to the descendants list.\n * @private\n * @return\n */\n addDescendants: function (obj) {\n var el;\n\n this.descendants[obj.id] = obj;\n for (el in obj.childElements) {\n if (obj.childElements.hasOwnProperty(el)) {\n this.addDescendants(obj.childElements[el]);\n }\n }\n return this;\n },\n\n /**\n * Adds ids of elements to the array this.parents. This method needs to be called if some dependencies\n * can not be detected automatically by JSXGraph. For example if a function graph is given by a function\n * which referes to coordinates of a point, calling addParents() is necessary.\n *\n * @param {Array} parents Array of elements or ids of elements.\n * Alternatively, one can give a list of objects as parameters.\n * @returns {JXG.Object} reference to the object itself.\n *\n * @example\n * // Movable function graph\n * var A = board.create('point', [1, 0], {name:'A'}),\n * B = board.create('point', [3, 1], {name:'B'}),\n * f = board.create('functiongraph', function(x) {\n * var ax = A.X(),\n * ay = A.Y(),\n * bx = B.X(),\n * by = B.Y(),\n * a = (by - ay) / ( (bx - ax) * (bx - ax) );\n * return a * (x - ax) * (x - ax) + ay;\n * }, {fixed: false});\n * f.addParents([A, B]);\n * </pre><div class=\"jxgbox\" id=\"JXG7c91d4d2-986c-4378-8135-24505027f251\" style=\"width: 400px; height: 400px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG7c91d4d2-986c-4378-8135-24505027f251', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});\n * var A = board.create('point', [1, 0], {name:'A'}),\n * B = board.create('point', [3, 1], {name:'B'}),\n * f = board.create('functiongraph', function(x) {\n * var ax = A.X(),\n * ay = A.Y(),\n * bx = B.X(),\n * by = B.Y(),\n * a = (by - ay) / ( (bx - ax) * (bx - ax) );\n * return a * (x - ax) * (x - ax) + ay;\n * }, {fixed: false});\n * f.addParents([A, B]);\n * })();\n * </script><pre>\n *\n **/\n addParents: function (parents) {\n var i, len, par;\n\n if (Type.isArray(parents)) {\n par = parents;\n } else {\n par = arguments;\n }\n\n len = par.length;\n for (i = 0; i < len; ++i) {\n if (!Type.exists(par[i])) {\n continue;\n }\n if (Type.isId(this.board, par[i])) {\n this.parents.push(par[i]);\n } else if (Type.exists(par[i].id)) {\n this.parents.push(par[i].id);\n }\n }\n this.parents = Type.uniqueArray(this.parents);\n },\n\n /**\n * Sets ids of elements to the array this.parents.\n * First, this.parents is cleared. See {@link JXG.GeometryElement#addParents}.\n * @param {Array} parents Array of elements or ids of elements.\n * Alternatively, one can give a list of objects as parameters.\n * @returns {JXG.Object} reference to the object itself.\n **/\n setParents: function(parents) {\n this.parents = [];\n this.addParents(parents);\n },\n\n /**\n * Remove an element as a child from the current element.\n * @param {JXG.GeometryElement} obj The dependent object.\n */\n removeChild: function (obj) {\n //var el, el2;\n\n delete this.childElements[obj.id];\n this.removeDescendants(obj);\n delete obj.ancestors[this.id];\n\n /*\n // I do not know if these addDescendants stuff has to be adapted to removeChild. A.W.\n for (el in this.descendants) {\n if (this.descendants.hasOwnProperty(el)) {\n delete this.descendants[el].ancestors[this.id];\n\n for (el2 in this.ancestors) {\n if (this.ancestors.hasOwnProperty(el2)) {\n this.descendants[el].ancestors[this.ancestors[el2].id] = this.ancestors[el2];\n }\n }\n }\n }\n\n for (el in this.ancestors) {\n if (this.ancestors.hasOwnProperty(el)) {\n for (el2 in this.descendants) {\n if (this.descendants.hasOwnProperty(el2)) {\n this.ancestors[el].descendants[this.descendants[el2].id] = this.descendants[el2];\n }\n }\n }\n }\n */\n return this;\n },\n\n /**\n * Removes the given object from the descendants list of this object and all its child objects.\n * @param {JXG.GeometryElement} obj The element that is to be removed from the descendants list.\n * @private\n * @return\n */\n removeDescendants: function (obj) {\n var el;\n\n delete this.descendants[obj.id];\n for (el in obj.childElements) {\n if (obj.childElements.hasOwnProperty(el)) {\n this.removeDescendants(obj.childElements[el]);\n }\n }\n return this;\n },\n\n /**\n * Counts the direct children of an object without counting labels.\n * @private\n * @returns {number} Number of children\n */\n countChildren: function () {\n var prop, d,\n s = 0;\n\n d = this.childElements;\n for (prop in d) {\n if (d.hasOwnProperty(prop) && prop.indexOf('Label') < 0) {\n s++;\n }\n }\n return s;\n },\n\n /**\n * Returns the elements name. Used in JessieCode.\n * @returns {String}\n */\n getName: function () {\n return this.name;\n },\n\n /**\n * Add transformations to this element.\n * @param {JXG.Transformation|Array} transform Either one {@link JXG.Transformation}\n * or an array of {@link JXG.Transformation}s.\n * @returns {JXG.GeometryElement} Reference to the element.\n */\n addTransform: function (transform) {\n return this;\n },\n\n /**\n * Decides whether an element can be dragged. This is used in\n * {@link JXG.GeometryElement#setPositionDirectly} methods\n * where all parent elements are checked if they may be dragged, too.\n * @private\n * @returns {boolean}\n */\n draggable: function () {\n return this.isDraggable && !Type.evaluate(this.visProp.fixed) &&\n /*!this.visProp.frozen &&*/ this.type !== Const.OBJECT_TYPE_GLIDER;\n },\n\n /**\n * Translates the object by <tt>(x, y)</tt>. In case the element is defined by points, the defining points are\n * translated, e.g. a circle constructed by a center point and a point on the circle line.\n * @param {Number} method The type of coordinates used here.\n * Possible values are {@link JXG.COORDS_BY_USER} and {@link JXG.COORDS_BY_SCREEN}.\n * @param {Array} coords array of translation vector.\n * @returns {JXG.GeometryElement} Reference to the element object.\n */\n setPosition: function (method, coords) {\n var parents = [],\n el, i, len, t;\n\n if (!Type.exists(this.parents)) {\n return this;\n }\n\n len = this.parents.length;\n for (i = 0; i < len; ++i) {\n el = this.board.select(this.parents[i]);\n if (Type.isPoint(el)) {\n if (!el.draggable()) {\n return this;\n }\n parents.push(el);\n }\n }\n\n if (coords.length === 3) {\n coords = coords.slice(1);\n }\n\n t = this.board.create('transform', coords, {type: 'translate'});\n\n // We distinguish two cases:\n // 1) elements which depend on free elements, i.e. arcs and sectors\n // 2) other elements\n //\n // In the first case we simply transform the parents elements\n // In the second case we add a transform to the element.\n //\n len = parents.length;\n if (len > 0) {\n t.applyOnce(parents);\n } else {\n if (this.transformations.length > 0 &&\n this.transformations[this.transformations.length - 1].isNumericMatrix) {\n this.transformations[this.transformations.length - 1].melt(t);\n } else {\n this.addTransform(t);\n }\n }\n\n /*\n * If - against the default configuration - defining gliders are marked as\n * draggable, then their position has to be updated now.\n */\n for (i = 0; i < len; ++i) {\n if (parents[i].type === Const.OBJECT_TYPE_GLIDER) {\n parents[i].updateGlider();\n }\n }\n\n return this;\n },\n\n /**\n * Moves an element by the difference of two coordinates.\n * @param {Number} method The type of coordinates used here.\n * Possible values are {@link JXG.COORDS_BY_USER} and {@link JXG.COORDS_BY_SCREEN}.\n * @param {Array} coords coordinates in screen/user units\n * @param {Array} oldcoords previous coordinates in screen/user units\n * @returns {JXG.GeometryElement} this element\n */\n setPositionDirectly: function (method, coords, oldcoords) {\n var c = new Coords(method, coords, this.board, false),\n oldc = new Coords(method, oldcoords, this.board, false),\n dc = Statistics.subtract(c.usrCoords, oldc.usrCoords);\n\n this.setPosition(Const.COORDS_BY_USER, dc);\n\n return this;\n },\n\n /**\n * Array of strings containing the polynomials defining the element.\n * Used for determining geometric loci the groebner way.\n * @returns {Array} An array containing polynomials describing the locus of the current object.\n * @public\n */\n generatePolynomial: function () {\n return [];\n },\n\n /**\n * Animates properties for that object like stroke or fill color, opacity and maybe\n * even more later.\n * @param {Object} hash Object containing properties with target values for the animation.\n * @param {number} time Number of milliseconds to complete the animation.\n * @param {Object} [options] Optional settings for the animation:<ul><li>callback: A function that is called as soon as the animation is finished.</li></ul>\n * @returns {JXG.GeometryElement} A reference to the object\n */\n animate: function (hash, time, options) {\n options = options || {};\n var r, p, i,\n delay = this.board.attr.animationdelay,\n steps = Math.ceil(time / delay),\n self = this,\n\n animateColor = function (startRGB, endRGB, property) {\n var hsv1, hsv2, sh, ss, sv;\n hsv1 = Color.rgb2hsv(startRGB);\n hsv2 = Color.rgb2hsv(endRGB);\n\n sh = (hsv2[0] - hsv1[0]) / steps;\n ss = (hsv2[1] - hsv1[1]) / steps;\n sv = (hsv2[2] - hsv1[2]) / steps;\n self.animationData[property] = [];\n\n for (i = 0; i < steps; i++) {\n self.animationData[property][steps - i - 1] = Color.hsv2rgb(hsv1[0] + (i + 1) * sh, hsv1[1] + (i + 1) * ss, hsv1[2] + (i + 1) * sv);\n }\n },\n\n animateFloat = function (start, end, property, round) {\n var tmp, s;\n\n start = parseFloat(start);\n end = parseFloat(end);\n\n // we can't animate without having valid numbers.\n // And parseFloat returns NaN if the given string doesn't contain\n // a valid float number.\n if (isNaN(start) || isNaN(end)) {\n return;\n }\n\n s = (end - start) / steps;\n self.animationData[property] = [];\n\n for (i = 0; i < steps; i++) {\n tmp = start + (i + 1) * s;\n self.animationData[property][steps - i - 1] = round ? Math.floor(tmp) : tmp;\n }\n };\n\n this.animationData = {};\n\n for (r in hash) {\n if (hash.hasOwnProperty(r)) {\n p = r.toLowerCase();\n\n switch (p) {\n case 'strokecolor':\n case 'fillcolor':\n animateColor(this.visProp[p], hash[r], p);\n break;\n case 'size':\n if (!Type.isPoint(this)) {\n break;\n }\n animateFloat(this.visProp[p], hash[r], p, true);\n break;\n case 'strokeopacity':\n case 'strokewidth':\n case 'fillopacity':\n animateFloat(this.visProp[p], hash[r], p, false);\n break;\n }\n }\n }\n\n this.animationCallback = options.callback;\n this.board.addAnimation(this);\n return this;\n },\n\n /**\n * General update method. Should be overwritten by the element itself.\n * Can be used sometimes to commit changes to the object.\n * @return {JXG.GeometryElement} Reference to the element\n */\n update: function () {\n if (Type.evaluate(this.visProp.trace)) {\n this.cloneToBackground();\n }\n return this;\n },\n\n /**\n * Provide updateRenderer method.\n * @return {JXG.GeometryElement} Reference to the element\n * @private\n */\n updateRenderer: function () {\n return this;\n },\n\n /**\n * Run through the full update chain of an element.\n * @param {Boolean} visible Set visibility in case the elements attribute value is 'inherit'. null is allowed.\n * @return {JXG.GeometryElement} Reference to the element\n * @private\n */\n fullUpdate: function(visible) {\n return this.prepareUpdate()\n .update()\n .updateVisibility(visible)\n .updateRenderer();\n },\n\n /**\n * Show the element or hide it. If hidden, it will still exist but not be\n * visible on the board.\n * @param {Boolean} val true: show the element, false: hide the element\n * @return {JXG.GeometryElement} Reference to the element\n * @private\n */\n setDisplayRendNode: function(val) {\n var i, len, s, len_s, obj;\n\n if (val === undefined) {\n val = this.visPropCalc.visible;\n }\n\n if (val === this.visPropOld.visible) {\n return this;\n }\n\n // Set display of the element itself\n this.board.renderer.display(this, val);\n\n // Set the visibility of elements which inherit the attribute 'visible'\n len = this.inherits.length;\n for (s = 0; s < len; s++) {\n obj = this.inherits[s];\n if (Type.isArray(obj)) {\n len_s = obj.length;\n for (i = 0; i < len_s; i++) {\n if (Type.exists(obj[i]) && Type.exists(obj[i].rendNode) &&\n Type.evaluate(obj[i].visProp.visible) === 'inherit') {\n obj[i].setDisplayRendNode(val);\n }\n }\n } else {\n if (Type.exists(obj) && Type.exists(obj.rendNode) &&\n Type.evaluate(obj.visProp.visible) === 'inherit') {\n obj.setDisplayRendNode(val);\n }\n }\n }\n\n // Set the visibility of the label if it inherits the attribute 'visible'\n if (this.hasLabel && Type.exists(this.label) && Type.exists(this.label.rendNode)) {\n if (Type.evaluate(this.label.visProp.visible) === 'inherit') {\n this.label.setDisplayRendNode(val);\n }\n }\n\n return this;\n },\n\n /**\n * Hide the element. It will still exist but not be visible on the board.\n * Alias for \"element.setAttribute({visible: false});\"\n * @return {JXG.GeometryElement} Reference to the element\n */\n hide: function () {\n this.setAttribute({visible: false});\n return this;\n },\n\n /**\n * Hide the element. It will still exist but not be visible on the board.\n * Alias for {@link JXG.GeometryElement#hide}\n * @returns {JXG.GeometryElement} Reference to the element\n */\n hideElement: function() {\n this.hide();\n return this;\n },\n\n /**\n * Make the element visible.\n * Alias for \"element.setAttribute({visible: true});\"\n * @return {JXG.GeometryElement} Reference to the element\n */\n show: function () {\n this.setAttribute({visible: true});\n return this;\n },\n\n /**\n * Make the element visible.\n * Alias for {@link JXG.GeometryElement#show}\n * @returns {JXG.GeometryElement} Reference to the element\n */\n showElement: function() {\n this.show();\n return this;\n },\n\n /**\n * Set the visibility of an element. The visibility is influenced by\n * (listed in ascending priority):\n * <ol>\n * <li> The value of the element's attribute 'visible'\n * <li> The visibility of a parent element. (Example: label)\n * This overrules the value of the element's attribute value only if\n * this attribute value of the element is 'inherit'.\n * <li> being inside of the canvas\n * </ol>\n * <p>\n * This method is called three times for most elements:\n * <ol>\n * <li> between {@link JXG.GeometryElement#update}\n * and {@link JXG.GeometryElement#updateRenderer}. In case the value is 'inherit', nothing is done.\n * <li> Recursively, called by itself for child elements. Here, 'inherit' is overruled by the parent's value.\n * <li> In {@link JXG.GeometryElement#updateRenderer}, if the element is outside of the canvas.\n * </ol>\n *\n * @param {Boolean} parent_val Visibility of the parent element.\n * @return {JXG.GeometryElement} Reference to the element.\n * @private\n */\n updateVisibility: function(parent_val) {\n var i, len, s, len_s, obj, val;\n\n if (this.needsUpdate) {\n // Handle the element\n if (parent_val !== undefined) {\n this.visPropCalc.visible = parent_val;\n } else {\n val = Type.evaluate(this.visProp.visible);\n\n // infobox uses hiddenByParent\n if (Type.exists(this.hiddenByParent) && this.hiddenByParent) {\n val = false;\n }\n if (val !== 'inherit') {\n this.visPropCalc.visible = val;\n }\n }\n\n // Handle elements which inherit the visibility\n len = this.inherits.length;\n for (s = 0; s < len; s++) {\n obj = this.inherits[s];\n if (Type.isArray(obj)) {\n len_s = obj.length;\n for (i = 0; i < len_s; i++) {\n if (Type.exists(obj[i]) /*&& Type.exists(obj[i].rendNode)*/ &&\n Type.evaluate(obj[i].visProp.visible) === 'inherit') {\n obj[i].prepareUpdate().updateVisibility(this.visPropCalc.visible);\n }\n }\n } else {\n if (Type.exists(obj) /*&& Type.exists(obj.rendNode)*/ &&\n Type.evaluate(obj.visProp.visible) === 'inherit') {\n obj.prepareUpdate().updateVisibility(this.visPropCalc.visible);\n }\n }\n }\n\n // Handle the label if it inherits the visibility\n if (Type.exists(this.label) && Type.exists(this.label.visProp) &&\n Type.evaluate(this.label.visProp.visible)) {\n this.label.prepareUpdate().updateVisibility(this.visPropCalc.visible);\n }\n }\n return this;\n },\n\n /**\n * Sets the value of property <tt>property</tt> to <tt>value</tt>.\n * @param {String} property The property's name.\n * @param value The new value\n * @private\n */\n _set: function (property, value) {\n var el;\n\n property = property.toLocaleLowerCase();\n\n // Search for entries in visProp with \"color\" as part of the property name\n // and containing a RGBA string\n if (this.visProp.hasOwnProperty(property) &&\n property.indexOf('color') >= 0 &&\n Type.isString(value) &&\n value.length === 9 &&\n value.charAt(0) === '#') {\n\n value = Color.rgba2rgbo(value);\n this.visProp[property] = value[0];\n // Previously: *=. But then, we can only decrease opacity.\n this.visProp[property.replace('color', 'opacity')] = value[1];\n } else {\n if (value !== null &&Type.isObject(value) &&\n !Type.exists(value.id) &&\n !Type.exists(value.name)) {\n // value is of type {prop: val, prop: val,...}\n // Convert these attributes to lowercase, too\n this.visProp[property] = {};\n for (el in value) {\n if (value.hasOwnProperty(el)) {\n this.visProp[property][el.toLocaleLowerCase()] = value[el];\n }\n }\n } else {\n this.visProp[property] = value;\n }\n }\n },\n\n /**\n * Resolves attribute shortcuts like <tt>color</tt> and expands them, e.g. <tt>strokeColor</tt> and <tt>fillColor</tt>.\n * Writes the expanded attributes back to the given <tt>attributes</tt>.\n * @param {Object} attributes object\n * @returns {Object} The given attributes object with shortcuts expanded.\n * @private\n */\n resolveShortcuts: function (attributes) {\n var key, i,\n j,\n subattr = ['traceattributes', 'traceAttributes'];\n\n for (key in Options.shortcuts) {\n if (Options.shortcuts.hasOwnProperty(key)) {\n\n if (Type.exists(attributes[key])) {\n for (i = 0; i < Options.shortcuts[key].length; i++) {\n if (!Type.exists(attributes[Options.shortcuts[key][i]])) {\n attributes[Options.shortcuts[key][i]] = attributes[key];\n }\n }\n }\n for (j = 0; j < subattr.length; j++) {\n if (Type.isObject(attributes[subattr[j]])) {\n attributes[subattr[j]] = this.resolveShortcuts(attributes[subattr[j]]);\n }\n }\n }\n }\n return attributes;\n },\n\n /**\n * Sets a label and its text\n * If label doesn't exist, it creates one\n * @param {String} str\n */\n setLabel: function (str) {\n if (!this.hasLabel) {\n this.setAttribute({'withlabel': true});\n }\n this.setLabelText(str);\n },\n\n /**\n * Updates the element's label text, strips all html.\n * @param {String} str\n */\n setLabelText: function (str) {\n\n if (Type.exists(this.label)) {\n str = str.replace(/</g, '<').replace(/>/g, '>');\n this.label.setText(str);\n }\n\n return this;\n },\n\n /**\n * Updates the element's label text and the element's attribute \"name\", strips all html.\n * @param {String} str\n */\n setName: function (str) {\n str = str.replace(/</g, '<').replace(/>/g, '>');\n if (this.elType !== 'slider') {\n this.setLabelText(str);\n }\n this.setAttribute({name: str});\n },\n\n /**\n * Deprecated alias for {@link JXG.GeometryElement#setAttribute}.\n * @deprecated Use {@link JXG.GeometryElement#setAttribute}.\n */\n setProperty: function () {\n JXG.deprecated('setProperty()', 'setAttribute()');\n this.setAttribute.apply(this, arguments);\n },\n\n /**\n * Sets an arbitrary number of attributes. This method has one or more\n * parameters of the following types:\n * <ul>\n * <li> object: {key1:value1,key2:value2,...}\n * <li> string: \"key1:value\"\n * <li> array: [key, value]\n * </ul>\n * @param {Object} attributes An object with attributes.\n * @returns {JXG.GeometryElement} A reference to the element.\n *\n * @function\n * @example\n * // Set property directly on creation of an element using the attributes object parameter\n * var board = JXG.JSXGraph.initBoard('jxgbox', {boundingbox: [-1, 5, 5, 1]};\n * var p = board.create('point', [2, 2], {visible: false});\n *\n * // Now make this point visible and fixed:\n * p.setAttribute({\n * fixed: true,\n * visible: true\n * });\n */\n setAttribute: function (attributes) {\n var i, j, le, key, value, arg, opacity, pair, oldvalue,\n properties = {};\n\n // Normalize the user input\n for (i = 0; i < arguments.length; i++) {\n arg = arguments[i];\n if (Type.isString(arg)) {\n // pairRaw is string of the form 'key:value'\n pair = arg.split(':');\n properties[Type.trim(pair[0])] = Type.trim(pair[1]);\n } else if (!Type.isArray(arg)) {\n // pairRaw consists of objects of the form {key1:value1,key2:value2,...}\n JXG.extend(properties, arg);\n } else {\n // pairRaw consists of array [key,value]\n properties[arg[0]] = arg[1];\n }\n }\n\n // Handle shortcuts\n properties = this.resolveShortcuts(properties);\n\n for (i in properties) {\n if (properties.hasOwnProperty(i)) {\n key = i.replace(/\\s+/g, '').toLowerCase();\n value = properties[i];\n\n // This handles the subobjects, if the key:value pairs are contained in an object.\n // Example:\n // ticks.setAttribute({\n // strokeColor: 'blue',\n // label: {\n // visible: false\n // }\n // })\n // Now, only the supplied label attributes are overwritten.\n // Otherwise, the value of label would be {visible:false} only.\n if (Type.isObject(value) &&\n Type.exists(this.visProp[key])) {\n\n this.visProp[key] = Type.merge(this.visProp[key], value);\n\n // First, handle the special case\n // ticks.setAttribute({label: {anchorX: \"right\", ..., visible: true});\n if (this.type === Const.OBJECT_TYPE_TICKS && Type.exists(this.labels)) {\n le = this.labels.length;\n for (j = 0; j < le; j++) {\n this.labels[j].setAttribute(value);\n }\n } else if (Type.exists(this[key])) {\n if (Type.isArray(this[key])) {\n for (j = 0; j < this[key].length; j++) {\n this[key][j].setAttribute(value);\n }\n } else {\n this[key].setAttribute(value);\n }\n }\n continue;\n }\n\n oldvalue = this.visProp[key];\n switch (key) {\n case 'name':\n oldvalue = this.name;\n delete this.board.elementsByName[this.name];\n this.name = value;\n this.board.elementsByName[this.name] = this;\n break;\n case 'needsregularupdate':\n this.needsRegularUpdate = !(value === 'false' || value === false);\n this.board.renderer.setBuffering(this, this.needsRegularUpdate ? 'auto' : 'static');\n break;\n case 'labelcolor':\n value = Color.rgba2rgbo(value);\n opacity = value[1];\n value = value[0];\n if (opacity === 0) {\n if (Type.exists(this.label) && this.hasLabel) {\n this.label.hideElement();\n }\n }\n if (Type.exists(this.label) && this.hasLabel) {\n this.label.visProp.strokecolor = value;\n this.board.renderer.setObjectStrokeColor(this.label,\n value, opacity);\n }\n if (this.elementClass === Const.OBJECT_CLASS_TEXT) {\n this.visProp.strokecolor = value;\n this.visProp.strokeopacity = opacity;\n this.board.renderer.setObjectStrokeColor(this,\n value, opacity);\n }\n break;\n case 'infoboxtext':\n if (Type.isString(value)) {\n this.infoboxText = value;\n } else {\n this.infoboxText = false;\n }\n break;\n case 'visible':\n if (value === 'false') {\n this.visProp.visible = false;\n } else if (value === 'true') {\n this.visProp.visible = true;\n } else {\n this.visProp.visible = value;\n }\n\n this.setDisplayRendNode(Type.evaluate(this.visProp.visible));\n if (Type.evaluate(this.visProp.visible) && Type.exists(this.updateSize)) {\n this.updateSize();\n }\n\n break;\n case 'face':\n if (Type.isPoint(this)) {\n this.visProp.face = value;\n this.board.renderer.changePointStyle(this);\n }\n break;\n case 'trace':\n if (value === 'false' || value === false) {\n this.clearTrace();\n this.visProp.trace = false;\n } else if (value === 'pause') {\n this.visProp.trace = false;\n } else {\n this.visProp.trace = true;\n }\n break;\n case 'gradient':\n this.visProp.gradient = value;\n this.board.renderer.setGradient(this);\n break;\n case 'gradientsecondcolor':\n value = Color.rgba2rgbo(value);\n this.visProp.gradientsecondcolor = value[0];\n this.visProp.gradientsecondopacity = value[1];\n this.board.renderer.updateGradient(this);\n break;\n case 'gradientsecondopacity':\n this.visProp.gradientsecondopacity = value;\n this.board.renderer.updateGradient(this);\n break;\n case 'withlabel':\n this.visProp.withlabel = value;\n if (!Type.evaluate(value)) {\n if (this.label && this.hasLabel) {\n //this.label.hideElement();\n this.label.setAttribute({visible: false});\n }\n } else {\n if (!this.label) {\n this.createLabel();\n }\n //this.label.showElement();\n this.label.setAttribute({visible: 'inherit'});\n //this.label.setDisplayRendNode(Type.evaluate(this.visProp.visible));\n }\n this.hasLabel = value;\n break;\n case 'radius':\n if (this.type === Const.OBJECT_TYPE_ANGLE || this.type === Const.OBJECT_TYPE_SECTOR) {\n this.setRadius(value);\n }\n break;\n case 'rotate':\n if ((this.elementClass === Const.OBJECT_CLASS_TEXT &&\n Type.evaluate(this.visProp.display) === 'internal') ||\n this.type === Const.OBJECT_TYPE_IMAGE) {\n this.addRotation(value);\n }\n break;\n case 'ticksdistance':\n if (this.type === Const.OBJECT_TYPE_TICKS && Type.isNumber(value)) {\n this.ticksFunction = this.makeTicksFunction(value);\n }\n break;\n case 'generatelabelvalue':\n if (this.type === Const.OBJECT_TYPE_TICKS && Type.isFunction(value)) {\n this.generateLabelValue = value;\n }\n break;\n case 'onpolygon':\n if (this.type === Const.OBJECT_TYPE_GLIDER) {\n this.onPolygon = !!value;\n }\n break;\n case 'disabled':\n // button, checkbox, input. Is not available on initial call.\n if (Type.exists(this.rendNodeTag)) {\n this.rendNodeTag.disabled = !!value;\n }\n break;\n case 'checked':\n // checkbox Is not available on initial call.\n if (Type.exists(this.rendNodeTag)) {\n this.rendNodeCheckbox.checked = !!value;\n }\n break;\n case 'maxlength':\n // input. Is not available on initial call.\n if (Type.exists(this.rendNodeTag)) {\n this.rendNodeTag.maxlength = !!value;\n }\n break;\n case 'layer':\n this.board.renderer.setLayer(this, Type.evaluate(value));\n this._set(key, value);\n break;\n case 'tabindex':\n if (Type.exists(this.rendNode)) {\n this.rendNode.setAttribute('tabindex', value);\n this._set(key, value);\n }\n break;\n default:\n if (Type.exists(this.visProp[key]) &&\n (!JXG.Validator[key] ||\n (JXG.Validator[key] && JXG.Validator[key](value)) ||\n (JXG.Validator[key] && Type.isFunction(value) && JXG.Validator[key](value()))\n )\n ) {\n value = (value.toLowerCase && value.toLowerCase() === 'false') ? false : value;\n this._set(key, value);\n }\n break;\n }\n this.triggerEventHandlers(['attribute:' + key], [oldvalue, value, this]);\n }\n }\n\n this.triggerEventHandlers(['attribute'], [properties, this]);\n\n if (!Type.evaluate(this.visProp.needsregularupdate)) {\n this.board.fullUpdate();\n } else {\n this.board.update(this);\n }\n\n return this;\n },\n\n /**\n * Deprecated alias for {@link JXG.GeometryElement#getAttribute}.\n * @deprecated Use {@link JXG.GeometryElement#getAttribute}.\n */\n getProperty: function () {\n JXG.deprecated('getProperty()', 'getAttribute()');\n this.getProperty.apply(this, arguments);\n },\n\n /**\n * Get the value of the property <tt>key</tt>.\n * @param {String} key The name of the property you are looking for\n * @returns The value of the property\n */\n getAttribute: function (key) {\n var result;\n key = key.toLowerCase();\n\n switch (key) {\n case 'needsregularupdate':\n result = this.needsRegularUpdate;\n break;\n case 'labelcolor':\n result = this.label.visProp.strokecolor;\n break;\n case 'infoboxtext':\n result = this.infoboxText;\n break;\n case 'withlabel':\n result = this.hasLabel;\n break;\n default:\n result = this.visProp[key];\n break;\n }\n\n return result;\n },\n\n /**\n * Set the dash style of an object. See {@link JXG.GeometryElement#dash}\n * for a list of available dash styles.\n * You should use {@link JXG.GeometryElement#setAttribute} instead of this method.\n *\n * @param {number} dash Indicates the new dash style\n * @private\n */\n setDash: function (dash) {\n this.setAttribute({dash: dash});\n return this;\n },\n\n /**\n * Notify all child elements for updates.\n * @private\n */\n prepareUpdate: function () {\n this.needsUpdate = true;\n return this;\n },\n\n /**\n * Removes the element from the construction. This only removes the SVG or VML node of the element and its label (if available) from\n * the renderer, to remove the element completely you should use {@link JXG.Board#removeObject}.\n */\n remove: function () {\n this.board.renderer.remove(this.board.renderer.getElementById(this.id));\n\n if (this.hasLabel) {\n this.board.renderer.remove(this.board.renderer.getElementById(this.label.id));\n }\n return this;\n },\n\n /**\n * Returns the coords object where a text that is bound to the element shall be drawn.\n * Differs in some cases from the values that getLabelAnchor returns.\n * @returns {JXG.Coords} JXG.Coords Place where the text shall be drawn.\n * @see JXG.GeometryElement#getLabelAnchor\n */\n getTextAnchor: function () {\n return new Coords(Const.COORDS_BY_USER, [0, 0], this.board);\n },\n\n /**\n * Returns the coords object where the label of the element shall be drawn.\n * Differs in some cases from the values that getTextAnchor returns.\n * @returns {JXG.Coords} JXG.Coords Place where the text shall be drawn.\n * @see JXG.GeometryElement#getTextAnchor\n */\n getLabelAnchor: function () {\n return new Coords(Const.COORDS_BY_USER, [0, 0], this.board);\n },\n\n /**\n * Determines whether the element has arrows at start or end of the arc.\n * If it is set to be a \"typical\" vector, ie lastArrow == true,\n * then the element.type is set to VECTOR.\n * @param {Boolean} firstArrow True if there is an arrow at the start of the arc, false otherwise.\n * @param {Boolean} lastArrow True if there is an arrow at the end of the arc, false otherwise.\n */\n setArrow: function (firstArrow, lastArrow) {\n this.visProp.firstarrow = firstArrow;\n this.visProp.lastarrow = lastArrow;\n if (lastArrow) {\n this.type = Const.OBJECT_TYPE_VECTOR;\n this.elType = 'arrow';\n }\n\n this.prepareUpdate().update().updateVisibility().updateRenderer();\n return this;\n },\n\n /**\n * Creates a gradient nodes in the renderer.\n * @see JXG.SVGRenderer#setGradient\n * @private\n */\n createGradient: function () {\n var ev_g = Type.evaluate(this.visProp.gradient);\n if (ev_g === 'linear' || ev_g === 'radial') {\n this.board.renderer.setGradient(this);\n }\n },\n\n /**\n * Creates a label element for this geometry element.\n * @see #addLabelToElement\n */\n createLabel: function () {\n var attr,\n that = this;\n\n // this is a dirty hack to resolve the text-dependency. If there is no text element available,\n // just don't create a label. This method is usually not called by a user, so we won't throw\n // an exception here and simply output a warning via JXG.debug.\n if (JXG.elements.text) {\n attr = Type.deepCopy(this.visProp.label, null);\n attr.id = this.id + 'Label';\n attr.isLabel = true;\n attr.anchor = this;\n attr.priv = this.visProp.priv;\n\n if (this.visProp.withlabel) {\n this.label = JXG.elements.text(this.board, [0, 0, function () {\n if (Type.isFunction(that.name)) {\n return that.name();\n }\n return that.name;\n }], attr);\n this.label.needsUpdate = true;\n this.label.dump = false;\n this.label.fullUpdate();\n\n this.hasLabel = true;\n }\n } else {\n JXG.debug('JSXGraph: Can\\'t create label: text element is not available. Make sure you include base/text');\n }\n\n return this;\n },\n\n /**\n * Highlights the element.\n * @param {Boolean} [force=false] Force the highlighting\n * @returns {JXG.Board}\n */\n highlight: function (force) {\n force = Type.def(force, false);\n // I know, we have the JXG.Board.highlightedObjects AND JXG.GeometryElement.highlighted and YES we need both.\n // Board.highlightedObjects is for the internal highlighting and GeometryElement.highlighted is for user highlighting\n // initiated by the user, e.g. through custom DOM events. We can't just pick one because this would break user\n // defined highlighting in many ways:\n // * if overriding the highlight() methods the user had to handle the highlightedObjects stuff, otherwise he'd break\n // everything (e.g. the pie chart example https://jsxgraph.org/wiki/index.php/Pie_chart (not exactly\n // user defined but for this type of chart the highlight method was overridden and not adjusted to the changes in here)\n // where it just kept highlighting until the radius of the pie was far beyond infinity...\n // * user defined highlighting would get pointless, everytime the user highlights something using .highlight(), it would get\n // dehighlighted immediately, because highlight puts the element into highlightedObjects and from there it gets dehighlighted\n // through dehighlightAll.\n\n // highlight only if not highlighted\n if (Type.evaluate(this.visProp.highlight) && (!this.highlighted || force)) {\n this.highlighted = true;\n this.board.highlightedObjects[this.id] = this;\n this.board.renderer.highlight(this);\n }\n return this;\n },\n\n /**\n * Uses the \"normal\" properties of the element.\n * @returns {JXG.Board}\n */\n noHighlight: function () {\n // see comment in JXG.GeometryElement.highlight()\n\n // dehighlight only if not highlighted\n if (this.highlighted) {\n this.highlighted = false;\n delete this.board.highlightedObjects[this.id];\n this.board.renderer.noHighlight(this);\n }\n return this;\n },\n\n /**\n * Removes all objects generated by the trace function.\n */\n clearTrace: function () {\n var obj;\n\n for (obj in this.traces) {\n if (this.traces.hasOwnProperty(obj)) {\n this.board.renderer.remove(this.traces[obj]);\n }\n }\n\n this.numTraces = 0;\n return this;\n },\n\n /**\n * Copy the element to background. This is used for tracing elements.\n * @returns {JXG.GeometryElement} A reference to the element\n */\n cloneToBackground: function () {\n return this;\n },\n\n /**\n * Dimensions of the smallest rectangle enclosing the element.\n * @returns {Array} The coordinates of the enclosing rectangle in a format\n * like the bounding box in {@link JXG.Board#setBoundingBox}.\n * \n * @returns {Array} similar to {@link JXG.Board#setBoundingBox}.\n */\n bounds: function () {\n return [0, 0, 0, 0];\n },\n\n /**\n * Normalize the element's standard form.\n * @private\n */\n normalize: function () {\n this.stdform = Mat.normalize(this.stdform);\n return this;\n },\n\n /**\n * EXPERIMENTAL. Generate JSON object code of visProp and other properties.\n * @type String\n * @private\n * @ignore\n * @returns JSON string containing element's properties.\n */\n toJSON: function () {\n var vis, key,\n json = ['{\"name\":', this.name];\n\n json.push(', ' + '\"id\":' + this.id);\n\n vis = [];\n for (key in this.visProp) {\n if (this.visProp.hasOwnProperty(key)) {\n if (Type.exists(this.visProp[key])) {\n vis.push('\"' + key + '\":' + this.visProp[key]);\n }\n }\n }\n json.push(', \"visProp\":{' + vis.toString() + '}');\n json.push('}');\n\n return json.join('');\n },\n\n /**\n * Rotate texts or images by a given degree. Works only for texts where JXG.Text#display equal to \"internal\".\n * @param {number} angle The degree of the rotation (90 means vertical text).\n * @see JXG.GeometryElement#rotate\n */\n addRotation: function (angle) {\n var tOffInv, tOff, tS, tSInv, tRot,\n that = this;\n\n if (((this.elementClass === Const.OBJECT_CLASS_TEXT &&\n Type.evaluate(this.visProp.display) === 'internal') ||\n this.type === Const.OBJECT_TYPE_IMAGE) && angle !== 0) {\n\n tOffInv = this.board.create('transform', [\n function () {\n return -that.X();\n }, function () {\n return -that.Y();\n }\n ], {type: 'translate'});\n\n tOff = this.board.create('transform', [\n function () {\n return that.X();\n }, function () {\n return that.Y();\n }\n ], {type: 'translate'});\n\n tS = this.board.create('transform', [\n function () {\n return that.board.unitX / that.board.unitY;\n }, function () {\n return 1;\n }\n ], {type: 'scale'});\n\n tSInv = this.board.create('transform', [\n function () {\n return that.board.unitY / that.board.unitX;\n }, function () {\n return 1;\n }\n ], {type: 'scale'});\n\n tRot = this.board.create('transform', [\n function() { return Type.evaluate(angle) * Math.PI / 180; }\n ], {type: 'rotate'});\n\n tOffInv.bindTo(this);\n tS.bindTo(this);\n tRot.bindTo(this);\n tSInv.bindTo(this);\n tOff.bindTo(this);\n }\n\n return this;\n },\n\n /**\n * Set the highlightStrokeColor of an element\n * @param {String} sColor String which determines the stroke color of an object when its highlighted.\n * @see JXG.GeometryElement#highlightStrokeColor\n * @deprecated Use {@link JXG.GeometryElement#setAttribute}\n */\n highlightStrokeColor: function (sColor) {\n JXG.deprecated('highlightStrokeColor()', 'setAttribute()');\n this.setAttribute({highlightStrokeColor: sColor});\n return this;\n },\n\n /**\n * Set the strokeColor of an element\n * @param {String} sColor String which determines the stroke color of an object.\n * @see JXG.GeometryElement#strokeColor\n * @deprecated Use {@link JXG.GeometryElement#setAttribute}\n */\n strokeColor: function (sColor) {\n JXG.deprecated('strokeColor()', 'setAttribute()');\n this.setAttribute({strokeColor: sColor});\n return this;\n },\n\n /**\n * Set the strokeWidth of an element\n * @param {Number} width Integer which determines the stroke width of an outline.\n * @see JXG.GeometryElement#strokeWidth\n * @deprecated Use {@link JXG.GeometryElement#setAttribute}\n */\n strokeWidth: function (width) {\n JXG.deprecated('strokeWidth()', 'setAttribute()');\n this.setAttribute({strokeWidth: width});\n return this;\n },\n\n /**\n * Set the fillColor of an element\n * @param {String} fColor String which determines the fill color of an object.\n * @see JXG.GeometryElement#fillColor\n * @deprecated Use {@link JXG.GeometryElement#setAttribute}\n */\n fillColor: function (fColor) {\n JXG.deprecated('fillColor()', 'setAttribute()');\n this.setAttribute({fillColor: fColor});\n return this;\n },\n\n /**\n * Set the highlightFillColor of an element\n * @param {String} fColor String which determines the fill color of an object when its highlighted.\n * @see JXG.GeometryElement#highlightFillColor\n * @deprecated Use {@link JXG.GeometryElement#setAttribute}\n */\n highlightFillColor: function (fColor) {\n JXG.deprecated('highlightFillColor()', 'setAttribute()');\n this.setAttribute({highlightFillColor: fColor});\n return this;\n },\n\n /**\n * Set the labelColor of an element\n * @param {String} lColor String which determines the text color of an object's label.\n * @see JXG.GeometryElement#labelColor\n * @deprecated Use {@link JXG.GeometryElement#setAttribute}\n */\n labelColor: function (lColor) {\n JXG.deprecated('labelColor()', 'setAttribute()');\n this.setAttribute({labelColor: lColor});\n return this;\n },\n\n /**\n * Set the dash type of an element\n * @param {Number} d Integer which determines the way of dashing an element's outline.\n * @see JXG.GeometryElement#dash\n * @deprecated Use {@link JXG.GeometryElement#setAttribute}\n */\n dash: function (d) {\n JXG.deprecated('dash()', 'setAttribute()');\n this.setAttribute({dash: d});\n return this;\n },\n\n /**\n * Set the visibility of an element\n * @param {Boolean} v Boolean which determines whether the element is drawn.\n * @see JXG.GeometryElement#visible\n * @deprecated Use {@link JXG.GeometryElement#setAttribute}\n */\n visible: function (v) {\n JXG.deprecated('visible()', 'setAttribute()');\n this.setAttribute({visible: v});\n return this;\n },\n\n /**\n * Set the shadow of an element\n * @param {Boolean} s Boolean which determines whether the element has a shadow or not.\n * @see JXG.GeometryElement#shadow\n * @deprecated Use {@link JXG.GeometryElement#setAttribute}\n */\n shadow: function (s) {\n JXG.deprecated('shadow()', 'setAttribute()');\n this.setAttribute({shadow: s});\n return this;\n },\n\n /**\n * The type of the element as used in {@link JXG.Board#create}.\n * @returns {String}\n */\n getType: function () {\n return this.elType;\n },\n\n /**\n * List of the element ids resp. values used as parents in {@link JXG.Board#create}.\n * @returns {Array}\n */\n getParents: function () {\n return Type.isArray(this.parents) ? this.parents : [];\n },\n\n /**\n * Snaps the element to the grid. Only works for points, lines and circles. Points will snap to the grid\n * as defined in their properties {@link JXG.Point#snapSizeX} and {@link JXG.Point#snapSizeY}. Lines and circles\n * will snap their parent points to the grid, if they have {@link JXG.Point#snapToGrid} set to true.\n * @returns {JXG.GeometryElement} Reference to the element.\n */\n snapToGrid: function () {\n return this;\n },\n\n /**\n * Snaps the element to points. Only works for points. Points will snap to the next point\n * as defined in their properties {@link JXG.Point#attractorDistance} and {@link JXG.Point#attractorUnit}.\n * Lines and circles\n * will snap their parent points to points.\n * @returns {JXG.GeometryElement} Reference to the element.\n */\n snapToPoints: function () {\n return this;\n },\n\n /**\n * Retrieve a copy of the current visProp.\n * @returns {Object}\n */\n getAttributes: function () {\n var attributes = Type.deepCopy(this.visProp),\n /*\n cleanThis = ['attractors', 'snatchdistance', 'traceattributes', 'frozen',\n 'shadow', 'gradientangle', 'gradientsecondopacity', 'gradientpositionx', 'gradientpositiony',\n 'needsregularupdate', 'zoom', 'layer', 'offset'],\n */\n cleanThis = [],\n i, len = cleanThis.length;\n\n attributes.id = this.id;\n attributes.name = this.name;\n\n for (i = 0; i < len; i++) {\n delete attributes[cleanThis[i]];\n }\n\n return attributes;\n },\n\n /**\n * Checks whether (x,y) is near the element.\n * @param {Number} x Coordinate in x direction, screen coordinates.\n * @param {Number} y Coordinate in y direction, screen coordinates.\n * @returns {Boolean} True if (x,y) is near the element, False otherwise.\n */\n hasPoint: function (x, y) {\n return false;\n },\n\n /**\n * Adds ticks to this line or curve. Ticks can be added to a curve or any kind of line: line, arrow, and axis.\n * @param {JXG.Ticks} ticks Reference to a ticks object which is describing the ticks (color, distance, how many, etc.).\n * @returns {String} Id of the ticks object.\n */\n addTicks: function (ticks) {\n if (ticks.id === '' || !Type.exists(ticks.id)) {\n ticks.id = this.id + '_ticks_' + (this.ticks.length + 1);\n }\n\n this.board.renderer.drawTicks(ticks);\n this.ticks.push(ticks);\n\n return ticks.id;\n },\n\n /**\n * Removes all ticks from a line or curve.\n */\n removeAllTicks: function () {\n var t;\n if (Type.exists(this.ticks)) {\n for (t = this.ticks.length - 1; t >= 0; t--) {\n this.removeTicks(this.ticks[t]);\n }\n this.ticks = [];\n this.board.update();\n }\n },\n\n /**\n * Removes ticks identified by parameter named tick from this line or curve.\n * @param {JXG.Ticks} tick Reference to tick object to remove.\n */\n removeTicks: function (tick) {\n var t, j;\n\n if (Type.exists(this.defaultTicks) && this.defaultTicks === tick) {\n this.defaultTicks = null;\n }\n\n if (Type.exists(this.ticks)) {\n for (t = this.ticks.length - 1; t >= 0; t--) {\n if (this.ticks[t] === tick) {\n this.board.removeObject(this.ticks[t]);\n\n if (this.ticks[t].ticks) {\n for (j = 0; j < this.ticks[t].ticks.length; j++) {\n if (Type.exists(this.ticks[t].labels[j])) {\n this.board.removeObject(this.ticks[t].labels[j]);\n }\n }\n }\n\n delete this.ticks[t];\n break;\n }\n }\n }\n },\n\n /**\n * Determine values of snapSizeX and snapSizeY. If the attributes\n * snapSizex and snapSizeY are greater than zero, these values are taken.\n * Otherwise, determine the distance between major ticks of the\n * default axes.\n * @returns {Array} containing the snap sizes for x and y direction.\n * @private\n */\n getSnapSizes: function() {\n var sX, sY, ticks;\n\n sX = Type.evaluate(this.visProp.snapsizex);\n sY = Type.evaluate(this.visProp.snapsizey);\n\n if (sX <= 0 && this.board.defaultAxes && this.board.defaultAxes.x.defaultTicks) {\n ticks = this.board.defaultAxes.x.defaultTicks;\n sX = ticks.ticksDelta * (Type.evaluate(ticks.visProp.minorticks) + 1);\n }\n\n if (sY <= 0 && this.board.defaultAxes && this.board.defaultAxes.y.defaultTicks) {\n ticks = this.board.defaultAxes.y.defaultTicks;\n sY = ticks.ticksDelta * (Type.evaluate(ticks.visProp.minorticks) + 1);\n }\n\n return [sX, sY];\n },\n\n /**\n * Move an element to its nearest grid point.\n * The function uses the coords object of the element as\n * its actual position. If there is no coords object or if the object is fixed, nothing is done.\n * @param {Boolean} force force snapping independent from what the snaptogrid attribute says\n * @param {Boolean} fromParent True if the drag comes from a child element. This is the case if a line\n * through two points is dragged. In this case we do not try to force the points to stay inside of\n * the visible board, but the distance between the two points stays constant.\n * @returns {JXG.GeometryElement} Reference to this element\n */\n handleSnapToGrid: function (force, fromParent) {\n var x, y, rx, ry, rcoords,\n boardBB, res, sX, sY,\n needsSnapToGrid = false,\n attractToGrid = Type.evaluate(this.visProp.attracttogrid),\n ev_au = Type.evaluate(this.visProp.attractorunit),\n ev_ad = Type.evaluate(this.visProp.attractordistance);\n\n if (!Type.exists(this.coords) || Type.evaluate(this.visProp.fixed)) {\n return this;\n }\n\n needsSnapToGrid = Type.evaluate(this.visProp.snaptogrid) || attractToGrid || force === true;\n\n if (needsSnapToGrid) {\n x = this.coords.usrCoords[1];\n y = this.coords.usrCoords[2];\n res = this.getSnapSizes();\n sX = res[0];\n sY = res[1];\n\n // If no valid snap sizes are available, don't change the coords.\n if (sX > 0 && sY > 0) {\n boardBB = this.board.getBoundingBox();\n rx = Math.round(x / sX) * sX;\n ry = Math.round(y / sY) * sY;\n rcoords = new JXG.Coords(Const.COORDS_BY_USER, [rx, ry], this.board);\n if (!attractToGrid ||\n rcoords.distance(\n ev_au === 'screen' ? Const.COORDS_BY_SCREEN : Const.COORDS_BY_USER, this.coords\n ) < ev_ad) {\n x = rx;\n y = ry;\n // Checking whether x and y are still within boundingBox.\n // If not, adjust them to remain within the board.\n // Otherwise a point may become invisible.\n if (!fromParent) {\n if (x < boardBB[0]) {\n x += sX;\n } else if (x > boardBB[2]) {\n x -= sX;\n }\n\n if (y < boardBB[3]) {\n y += sY;\n } else if (y > boardBB[1]) {\n y -= sY;\n }\n }\n this.coords.setCoordinates(Const.COORDS_BY_USER, [x, y]);\n }\n }\n }\n return this;\n },\n\n getBoundingBox: function() {\n var i, le, v, x, y,\n bb = [Infinity, Infinity, -Infinity, -Infinity];\n\n if (this.type === Const.OBJECT_TYPE_POLYGON) {\n le = this.vertices.length - 1;\n if (le <= 0) {\n return bb;\n }\n for (i = 0; i < le; i++) {\n v = this.vertices[i].X();\n bb[0] = (v < bb[0]) ? v : bb[0];\n bb[2] = (v > bb[2]) ? v : bb[2];\n v = this.vertices[i].Y();\n bb[1] = (v < bb[1]) ? v : bb[1];\n bb[3] = (v > bb[3]) ? v : bb[3];\n }\n } else if (this.elementClass === Const.OBJECT_CLASS_CIRCLE) {\n x = this.center.X();\n y = this.center.Y();\n bb = [x - this.radius, y + this.radius, x + this.radius, y - this.radius];\n } else if (this.elementClass === Const.OBJECT_CLASS_CURVE) {\n le = this.vertices.length;\n if (le === 0) {\n return bb;\n }\n for (i = 0; i < le; i++) {\n v = this.points[i].coords.usrCoords[1];\n bb[0] = (v < bb[0]) ? v : bb[0];\n bb[2] = (v > bb[2]) ? v : bb[2];\n v = this.points[i].coords.usrCoords[1];\n bb[1] = (v < bb[1]) ? v : bb[1];\n bb[3] = (v > bb[3]) ? v : bb[3];\n }\n }\n\n return bb;\n },\n\n /**\n * Alias of {@link JXG.EventEmitter.on}.\n *\n * @name addEvent\n * @memberof JXG.GeometryElement\n * @function\n */\n addEvent: JXG.shortcut(JXG.GeometryElement.prototype, 'on'),\n\n /**\n * Alias of {@link JXG.EventEmitter.off}.\n *\n * @name removeEvent\n * @memberof JXG.GeometryElement\n * @function\n */\n removeEvent: JXG.shortcut(JXG.GeometryElement.prototype, 'off'),\n\n /* **************************\n * EVENT DEFINITION\n * for documentation purposes\n * ************************** */\n\n //region Event handler documentation\n /**\n * @event\n * @description This event is fired whenever the user is hovering over an element.\n * @name JXG.GeometryElement#over\n * @param {Event} e The browser's event object.\n */\n __evt__over: function (e) { },\n\n /**\n * @event\n * @description This event is fired whenever the user puts the mouse over an element.\n * @name JXG.GeometryElement#mouseover\n * @param {Event} e The browser's event object.\n */\n __evt__mouseover: function (e) { },\n\n /**\n * @event\n * @description This event is fired whenever the user is leaving an element.\n * @name JXG.GeometryElement#out\n * @param {Event} e The browser's event object.\n */\n __evt__out: function (e) { },\n\n /**\n * @event\n * @description This event is fired whenever the user puts the mouse away from an element.\n * @name JXG.GeometryElement#mouseout\n * @param {Event} e The browser's event object.\n */\n __evt__mouseout: function (e) { },\n\n /**\n * @event\n * @description This event is fired whenever the user is moving over an element.\n * @name JXG.GeometryElement#move\n * @param {Event} e The browser's event object.\n */\n __evt__move: function (e) { },\n\n /**\n * @event\n * @description This event is fired whenever the user is moving the mouse over an element.\n * @name JXG.GeometryElement#mousemove\n * @param {Event} e The browser's event object.\n */\n __evt__mousemove: function (e) { },\n\n /**\n * @event\n * @description This event is fired whenever the user drags an element.\n * @name JXG.GeometryElement#drag\n * @param {Event} e The browser's event object.\n */\n __evt__drag: function (e) { },\n\n /**\n * @event\n * @description This event is fired whenever the user drags the element with a mouse.\n * @name JXG.GeometryElement#mousedrag\n * @param {Event} e The browser's event object.\n */\n __evt__mousedrag: function (e) { },\n\n /**\n * @event\n * @description This event is fired whenever the user drags the element with a pen.\n * @name JXG.GeometryElement#pendrag\n * @param {Event} e The browser's event object.\n */\n __evt__pendrag: function (e) { },\n\n /**\n * @event\n * @description This event is fired whenever the user drags the element on a touch device.\n * @name JXG.GeometryElement#touchdrag\n * @param {Event} e The browser's event object.\n */\n __evt__touchdrag: function (e) { },\n\n /**\n * @event\n * @description Whenever the user starts to touch or click an element.\n * @name JXG.GeometryElement#down\n * @param {Event} e The browser's event object.\n */\n __evt__down: function (e) { },\n\n /**\n * @event\n * @description Whenever the user starts to click an element.\n * @name JXG.GeometryElement#mousedown\n * @param {Event} e The browser's event object.\n */\n __evt__mousedown: function (e) { },\n\n /**\n * @event\n * @description Whenever the user taps an element with the pen.\n * @name JXG.GeometryElement#pendown\n * @param {Event} e The browser's event object.\n */\n __evt__pendown: function (e) { },\n\n /**\n * @event\n * @description Whenever the user starts to touch an element.\n * @name JXG.GeometryElement#touchdown\n * @param {Event} e The browser's event object.\n */\n __evt__touchdown: function (e) { },\n\n /**\n * @event\n * @description Whenever the user stops to touch or click an element.\n * @name JXG.GeometryElement#up\n * @param {Event} e The browser's event object.\n */\n __evt__up: function (e) { },\n\n /**\n * @event\n * @description Whenever the user releases the mousebutton over an element.\n * @name JXG.GeometryElement#mouseup\n * @param {Event} e The browser's event object.\n */\n __evt__mouseup: function (e) { },\n\n /**\n * @event\n * @description Whenever the user lifts the pen over an element.\n * @name JXG.GeometryElement#penup\n * @param {Event} e The browser's event object.\n */\n __evt__penup: function (e) { },\n\n /**\n * @event\n * @description Whenever the user stops touching an element.\n * @name JXG.GeometryElement#touchup\n * @param {Event} e The browser's event object.\n */\n __evt__touchup: function (e) {},\n\n /**\n * @event\n * @description Notify every time an attribute is changed.\n * @name JXG.GeometryElement#attribute\n * @param {Object} o A list of changed attributes and their new value.\n * @param {Object} el Reference to the element\n */\n __evt__attribute: function (o, el) {},\n\n /**\n * @event\n * @description This is a generic event handler. It exists for every possible attribute that can be set for\n * any element, e.g. if you want to be notified everytime an element's strokecolor is changed, is the event\n * <tt>attribute:strokecolor</tt>.\n * @name JXG.GeometryElement#attribute:key\n * @param val The old value.\n * @param nval The new value\n * @param {Object} el Reference to the element\n */\n __evt__attribute_: function (val, nval, el) {},\n\n /**\n * @ignore\n */\n __evt: function () {}\n //endregion\n\n });\n\n return JXG.GeometryElement;\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Alfred Wassermann\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true, console: true, window: true*/\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n jxg\n options\n math/math\n math/geometry\n math/numerics\n base/coords\n base/constants\n base/element\n parser/geonext\n utils/type\n elements:\n transform\n */\n\n/**\n * @fileoverview The geometry object CoordsElement is defined in this file.\n * This object provides the coordinate handling of points, images and texts.\n */\n\ndefine('base/coordselement',[\n 'jxg', 'math/math', 'math/geometry', 'math/numerics', 'math/statistics', 'base/coords', 'base/constants', 'utils/type',\n], function (JXG, Mat, Geometry, Numerics, Statistics, Coords, Const, Type) {\n\n \"use strict\";\n\n /**\n * An element containing coords is the basic geometric element. Based on points lines and circles can be constructed which can be intersected\n * which in turn are points again which can be used to construct new lines, circles, polygons, etc. This class holds methods for\n * all kind of coordinate elements like points, texts and images.\n * @class Creates a new coords element object. Do not use this constructor to create an element.\n *\n * @private\n * @augments JXG.GeometryElement\n * @param {Array} coordinates An array with the affine user coordinates of the point.\n * {@link JXG.Options#elements}, and - optionally - a name and an id.\n */\n JXG.CoordsElement = function (coordinates, isLabel) {\n var i;\n\n if (!Type.exists(coordinates)) {\n coordinates = [1, 0, 0];\n }\n\n for (i = 0; i < coordinates.length; ++i) {\n coordinates[i] = parseFloat(coordinates[i]);\n }\n\n /**\n * Coordinates of the element.\n * @type JXG.Coords\n * @private\n */\n this.coords = new Coords(Const.COORDS_BY_USER, coordinates, this.board);\n this.initialCoords = new Coords(Const.COORDS_BY_USER, coordinates, this.board);\n\n /**\n * Relative position on a slide element (line, circle, curve) if element is a glider on this element.\n * @type Number\n * @private\n */\n this.position = null;\n\n /**\n * True if there the method this.updateConstraint() has been set. It is\n * probably different from the prototype function() {return this;}.\n * Used in updateCoords fo glider elements.\n *\n * @see JXG.CoordsElement#updateCoords\n * @type Boolean\n * @private\n */\n this.isConstrained = false;\n\n /**\n * Determines whether the element slides on a polygon if point is a glider.\n * @type Boolean\n * @default false\n * @private\n */\n this.onPolygon = false;\n\n /**\n * When used as a glider this member stores the object, where to glide on.\n * To set the object to glide on use the method\n * {@link JXG.Point#makeGlider} and DO NOT set this property directly\n * as it will break the dependency tree.\n * @type JXG.GeometryElement\n */\n this.slideObject = null;\n\n /**\n * List of elements the element is bound to, i.e. the element glides on.\n * Only the last entry is active.\n * Use {@link JXG.Point#popSlideObject} to remove the currently active slideObject.\n */\n this.slideObjects = [];\n\n /**\n * A {@link JXG.CoordsElement#updateGlider} call is usually followed\n * by a general {@link JXG.Board#update} which calls\n * {@link JXG.CoordsElement#updateGliderFromParent}.\n * To prevent double updates, {@link JXG.CoordsElement#needsUpdateFromParent}\n * is set to false in updateGlider() and reset to true in the following call to\n * {@link JXG.CoordsElement#updateGliderFromParent}\n * @type Boolean\n */\n this.needsUpdateFromParent = true;\n\n /**\n * Stores the groups of this element in an array of Group.\n * @type Array\n * @see JXG.Group\n * @private\n */\n this.groups = [];\n\n /*\n * Do we need this?\n */\n this.Xjc = null;\n this.Yjc = null;\n\n // documented in GeometryElement\n this.methodMap = Type.deepCopy(this.methodMap, {\n move: 'moveTo',\n moveTo: 'moveTo',\n moveAlong: 'moveAlong',\n visit: 'visit',\n glide: 'makeGlider',\n makeGlider: 'makeGlider',\n intersect: 'makeIntersection',\n makeIntersection: 'makeIntersection',\n X: 'X',\n Y: 'Y',\n free: 'free',\n setPosition: 'setGliderPosition',\n setGliderPosition: 'setGliderPosition',\n addConstraint: 'addConstraint',\n dist: 'Dist',\n onPolygon: 'onPolygon'\n });\n\n /*\n * this.element may have been set by the object constructor.\n */\n if (Type.exists(this.element)) {\n this.addAnchor(coordinates, isLabel);\n }\n this.isDraggable = true;\n\n };\n\n JXG.extend(JXG.CoordsElement.prototype, /** @lends JXG.CoordsElement.prototype */ {\n /**\n * Dummy function for unconstrained points or gliders.\n * @private\n */\n updateConstraint: function () {\n return this;\n },\n\n /**\n * Updates the coordinates of the element.\n * @private\n */\n updateCoords: function (fromParent) {\n if (!this.needsUpdate) {\n return this;\n }\n\n if (!Type.exists(fromParent)) {\n fromParent = false;\n }\n\n if (!Type.evaluate(this.visProp.frozen)) {\n this.updateConstraint();\n }\n\n /*\n * We need to calculate the new coordinates no matter of the elements visibility because\n * a child could be visible and depend on the coordinates of the element/point (e.g. perpendicular).\n *\n * Check if the element is a glider and calculate new coords in dependency of this.slideObject.\n * This function is called with fromParent==true in case it is a glider element for example if\n * the defining elements of the line or circle have been changed.\n */\n if (this.type === Const.OBJECT_TYPE_GLIDER) {\n if (this.isConstrained) {\n fromParent = false;\n }\n\n if (fromParent) {\n this.updateGliderFromParent();\n } else {\n this.updateGlider();\n }\n }\n\n this.updateTransform(fromParent);\n\n return this;\n },\n\n /**\n * Update of glider in case of dragging the glider or setting the postion of the glider.\n * The relative position of the glider has to be updated.\n *\n * In case of a glider on a line:\n * If the second point is an ideal point, then -1 < this.position < 1,\n * this.position==+/-1 equals point2, this.position==0 equals point1\n *\n * If the first point is an ideal point, then 0 < this.position < 2\n * this.position==0 or 2 equals point1, this.position==1 equals point2\n *\n * @private\n */\n updateGlider: function () {\n var i, p1c, p2c, d, v, poly, cc, pos, sgn,\n alpha, beta,\n delta = 2.0 * Math.PI,\n angle,\n cp, c, invMat, newCoords, newPos,\n doRound = false,\n ev_sw,\n slide = this.slideObject,\n res, cu,\n slides = [],\n isTransformed;\n\n this.needsUpdateFromParent = false;\n if (slide.elementClass === Const.OBJECT_CLASS_CIRCLE) {\n if (Type.evaluate(this.visProp.isgeonext)) {\n delta = 1.0;\n }\n newCoords = Geometry.projectPointToCircle(this, slide, this.board);\n newPos = Geometry.rad([slide.center.X() + 1.0, slide.center.Y()], slide.center, this) / delta;\n } else if (slide.elementClass === Const.OBJECT_CLASS_LINE) {\n /*\n * onPolygon==true: the point is a slider on a segment and this segment is one of the\n * \"borders\" of a polygon.\n * This is a GEONExT feature.\n */\n if (this.onPolygon) {\n p1c = slide.point1.coords.usrCoords;\n p2c = slide.point2.coords.usrCoords;\n i = 1;\n d = p2c[i] - p1c[i];\n\n if (Math.abs(d) < Mat.eps) {\n i = 2;\n d = p2c[i] - p1c[i];\n }\n\n cc = Geometry.projectPointToLine(this, slide, this.board);\n pos = (cc.usrCoords[i] - p1c[i]) / d;\n poly = slide.parentPolygon;\n\n if (pos < 0) {\n for (i = 0; i < poly.borders.length; i++) {\n if (slide === poly.borders[i]) {\n slide = poly.borders[(i - 1 + poly.borders.length) % poly.borders.length];\n break;\n }\n }\n } else if (pos > 1.0) {\n for (i = 0; i < poly.borders.length; i++) {\n if (slide === poly.borders[i]) {\n slide = poly.borders[(i + 1 + poly.borders.length) % poly.borders.length];\n break;\n }\n }\n }\n\n // If the slide object has changed, save the change to the glider.\n if (slide.id !== this.slideObject.id) {\n this.slideObject = slide;\n }\n }\n\n p1c = slide.point1.coords;\n p2c = slide.point2.coords;\n\n // Distance between the two defining points\n d = p1c.distance(Const.COORDS_BY_USER, p2c);\n\n // The defining points are identical\n if (d < Mat.eps) {\n //this.coords.setCoordinates(Const.COORDS_BY_USER, p1c);\n newCoords = p1c;\n doRound = true;\n newPos = 0.0;\n } else {\n newCoords = Geometry.projectPointToLine(this, slide, this.board);\n p1c = p1c.usrCoords.slice(0);\n p2c = p2c.usrCoords.slice(0);\n\n // The second point is an ideal point\n if (Math.abs(p2c[0]) < Mat.eps) {\n i = 1;\n d = p2c[i];\n\n if (Math.abs(d) < Mat.eps) {\n i = 2;\n d = p2c[i];\n }\n\n d = (newCoords.usrCoords[i] - p1c[i]) / d;\n sgn = (d >= 0) ? 1 : -1;\n d = Math.abs(d);\n newPos = sgn * d / (d + 1);\n\n // The first point is an ideal point\n } else if (Math.abs(p1c[0]) < Mat.eps) {\n i = 1;\n d = p1c[i];\n\n if (Math.abs(d) < Mat.eps) {\n i = 2;\n d = p1c[i];\n }\n\n d = (newCoords.usrCoords[i] - p2c[i]) / d;\n\n // 1.0 - d/(1-d);\n if (d < 0.0) {\n newPos = (1 - 2.0 * d) / (1.0 - d);\n } else {\n newPos = 1 / (d + 1);\n }\n } else {\n i = 1;\n d = p2c[i] - p1c[i];\n\n if (Math.abs(d) < Mat.eps) {\n i = 2;\n d = p2c[i] - p1c[i];\n }\n newPos = (newCoords.usrCoords[i] - p1c[i]) / d;\n }\n }\n\n // Snap the glider point of the slider into its appropiate position\n // First, recalculate the new value of this.position\n // Second, call update(fromParent==true) to make the positioning snappier.\n ev_sw = Type.evaluate(this.visProp.snapwidth);\n if (Type.evaluate(ev_sw) > 0.0 &&\n Math.abs(this._smax - this._smin) >= Mat.eps) {\n newPos = Math.max(Math.min(newPos, 1), 0);\n\n v = newPos * (this._smax - this._smin) + this._smin;\n v = Math.round(v / ev_sw) * ev_sw;\n newPos = (v - this._smin) / (this._smax - this._smin);\n this.update(true);\n }\n\n p1c = slide.point1.coords;\n if (!Type.evaluate(slide.visProp.straightfirst) &&\n Math.abs(p1c.usrCoords[0]) > Mat.eps && newPos < 0) {\n newCoords = p1c;\n doRound = true;\n newPos = 0;\n }\n\n p2c = slide.point2.coords;\n if (!Type.evaluate(slide.visProp.straightlast) &&\n Math.abs(p2c.usrCoords[0]) > Mat.eps && newPos > 1) {\n newCoords = p2c;\n doRound = true;\n newPos = 1;\n }\n } else if (slide.type === Const.OBJECT_TYPE_TURTLE) {\n // In case, the point is a constrained glider.\n this.updateConstraint();\n res = Geometry.projectPointToTurtle(this, slide, this.board);\n newCoords = res[0];\n newPos = res[1]; // save position for the overwriting below\n } else if (slide.elementClass === Const.OBJECT_CLASS_CURVE) {\n if ((slide.type === Const.OBJECT_TYPE_ARC ||\n slide.type === Const.OBJECT_TYPE_SECTOR)) {\n newCoords = Geometry.projectPointToCircle(this, slide, this.board);\n\n angle = Geometry.rad(slide.radiuspoint, slide.center, this);\n alpha = 0.0;\n beta = Geometry.rad(slide.radiuspoint, slide.center, slide.anglepoint);\n newPos = angle;\n\n ev_sw = Type.evaluate(slide.visProp.selection);\n if ((ev_sw === 'minor' && beta > Math.PI) ||\n (ev_sw === 'major' && beta < Math.PI)) {\n alpha = beta;\n beta = 2 * Math.PI;\n }\n\n // Correct the position if we are outside of the sector/arc\n if (angle < alpha || angle > beta) {\n newPos = beta;\n\n if ((angle < alpha && angle > alpha * 0.5) || (angle > beta && angle > beta * 0.5 + Math.PI)) {\n newPos = alpha;\n }\n\n this.needsUpdateFromParent = true;\n this.updateGliderFromParent();\n }\n\n delta = beta - alpha;\n if (this.visProp.isgeonext) {\n delta = 1.0;\n }\n if (Math.abs(delta) > Mat.eps) {\n newPos /= delta;\n }\n } else {\n // In case, the point is a constrained glider.\n this.updateConstraint();\n\n // Handle the case if the curve comes from a transformation of a continous curve.\n if (slide.transformations.length > 0) {\n isTransformed = false;\n res = slide.getTransformationSource();\n if (res[0]) {\n isTransformed = res[0];\n slides.push(slide);\n slides.push(res[1]);\n }\n // Recurse\n while (res[0] && Type.exists(res[1]._transformationSource)) {\n res = res[1].getTransformationSource();\n slides.push(res[1]);\n }\n\n cu = this.coords.usrCoords;\n if (isTransformed) {\n for (i = 0; i < slides.length; i++) {\n slides[i].updateTransformMatrix();\n invMat = Mat.inverse(slides[i].transformMat);\n cu = Mat.matVecMult(invMat, cu);\n }\n cp = (new Coords(Const.COORDS_BY_USER, cu, this.board)).usrCoords;\n c = Geometry.projectCoordsToCurve(cp[1], cp[2],\n this.position || 0,\n slides[slides.length - 1],\n this.board);\n // projectPointCurve() already would apply the transformation.\n // Since we are projecting on the original curve, we have to do\n // the transformations \"by hand\".\n cu = c[0].usrCoords;\n for (i = slides.length - 2; i >= 0; i--) {\n cu = Mat.matVecMult(slides[i].transformMat, cu);\n }\n c[0] = new Coords(Const.COORDS_BY_USER, cu, this.board);\n } else {\n slide.updateTransformMatrix();\n invMat = Mat.inverse(slide.transformMat);\n cu = Mat.matVecMult(invMat, cu);\n cp = (new Coords(Const.COORDS_BY_USER, cu, this.board)).usrCoords;\n c = Geometry.projectCoordsToCurve(cp[1], cp[2], this.position || 0, slide, this.board);\n }\n\n newCoords = c[0];\n newPos = c[1];\n } else {\n res = Geometry.projectPointToCurve(this, slide, this.board);\n newCoords = res[0];\n newPos = res[1]; // save position for the overwriting below\n }\n }\n } else if (Type.isPoint(slide)) {\n //this.coords.setCoordinates(Const.COORDS_BY_USER, Geometry.projectPointToPoint(this, slide, this.board).usrCoords, false);\n newCoords = Geometry.projectPointToPoint(this, slide, this.board);\n newPos = this.position; // save position for the overwriting below\n }\n\n this.coords.setCoordinates(Const.COORDS_BY_USER, newCoords.usrCoords, doRound);\n this.position = newPos;\n },\n\n /**\n * Update of a glider in case a parent element has been updated. That means the\n * relative position of the glider stays the same.\n * @private\n */\n updateGliderFromParent: function () {\n var p1c, p2c, r, lbda, c,\n slide = this.slideObject,\n slides = [],\n res, i,\n isTransformed,\n baseangle, alpha, angle, beta,\n delta = 2.0 * Math.PI;\n\n if (!this.needsUpdateFromParent) {\n this.needsUpdateFromParent = true;\n return;\n }\n\n if (slide.elementClass === Const.OBJECT_CLASS_CIRCLE) {\n r = slide.Radius();\n if (Type.evaluate(this.visProp.isgeonext)) {\n delta = 1.0;\n }\n c = [\n slide.center.X() + r * Math.cos(this.position * delta),\n slide.center.Y() + r * Math.sin(this.position * delta)\n ];\n } else if (slide.elementClass === Const.OBJECT_CLASS_LINE) {\n p1c = slide.point1.coords.usrCoords;\n p2c = slide.point2.coords.usrCoords;\n\n // If one of the defining points of the line does not exist,\n // the glider should disappear\n if ((p1c[0] === 0 && p1c[1] === 0 && p1c[2] === 0) ||\n (p2c[0] === 0 && p2c[1] === 0 && p2c[2] === 0)) {\n c = [0, 0, 0];\n // The second point is an ideal point\n } else if (Math.abs(p2c[0]) < Mat.eps) {\n lbda = Math.min(Math.abs(this.position), 1 - Mat.eps);\n lbda /= (1.0 - lbda);\n\n if (this.position < 0) {\n lbda = -lbda;\n }\n\n c = [\n p1c[0] + lbda * p2c[0],\n p1c[1] + lbda * p2c[1],\n p1c[2] + lbda * p2c[2]\n ];\n // The first point is an ideal point\n } else if (Math.abs(p1c[0]) < Mat.eps) {\n lbda = Math.max(this.position, Mat.eps);\n lbda = Math.min(lbda, 2 - Mat.eps);\n\n if (lbda > 1) {\n lbda = (lbda - 1) / (lbda - 2);\n } else {\n lbda = (1 - lbda) / lbda;\n }\n\n c = [\n p2c[0] + lbda * p1c[0],\n p2c[1] + lbda * p1c[1],\n p2c[2] + lbda * p1c[2]\n ];\n } else {\n lbda = this.position;\n c = [\n p1c[0] + lbda * (p2c[0] - p1c[0]),\n p1c[1] + lbda * (p2c[1] - p1c[1]),\n p1c[2] + lbda * (p2c[2] - p1c[2])\n ];\n }\n } else if (slide.type === Const.OBJECT_TYPE_TURTLE) {\n this.coords.setCoordinates(Const.COORDS_BY_USER, [slide.Z(this.position), slide.X(this.position), slide.Y(this.position)]);\n // In case, the point is a constrained glider.\n this.updateConstraint();\n c = Geometry.projectPointToTurtle(this, slide, this.board)[0].usrCoords;\n } else if (slide.elementClass === Const.OBJECT_CLASS_CURVE) {\n // Handle the case if the curve comes from a transformation of a continuous curve.\n isTransformed = false;\n res = slide.getTransformationSource();\n if (res[0]) {\n isTransformed = res[0];\n slides.push(slide);\n slides.push(res[1]);\n }\n // Recurse\n while (res[0] && Type.exists(res[1]._transformationSource)) {\n res = res[1].getTransformationSource();\n slides.push(res[1]);\n }\n if (isTransformed) {\n this.coords.setCoordinates(Const.COORDS_BY_USER, [\n slides[slides.length - 1].Z(this.position),\n slides[slides.length - 1].X(this.position),\n slides[slides.length - 1].Y(this.position)]);\n } else {\n this.coords.setCoordinates(Const.COORDS_BY_USER, [\n slide.Z(this.position),\n slide.X(this.position),\n slide.Y(this.position)]);\n }\n\n if (slide.type === Const.OBJECT_TYPE_ARC || slide.type === Const.OBJECT_TYPE_SECTOR) {\n baseangle = Geometry.rad([slide.center.X() + 1, slide.center.Y()], slide.center, slide.radiuspoint);\n\n alpha = 0.0;\n beta = Geometry.rad(slide.radiuspoint, slide.center, slide.anglepoint);\n\n if ((slide.visProp.selection === 'minor' && beta > Math.PI) ||\n (slide.visProp.selection === 'major' && beta < Math.PI)) {\n alpha = beta;\n beta = 2 * Math.PI;\n }\n\n delta = beta - alpha;\n if (Type.evaluate(this.visProp.isgeonext)) {\n delta = 1.0;\n }\n angle = this.position * delta;\n\n // Correct the position if we are outside of the sector/arc\n if (angle < alpha || angle > beta) {\n angle = beta;\n\n if ((angle < alpha && angle > alpha * 0.5) ||\n (angle > beta && angle > beta * 0.5 + Math.PI)) {\n angle = alpha;\n }\n\n this.position = angle;\n if (Math.abs(delta) > Mat.eps) {\n this.position /= delta;\n }\n }\n\n r = slide.Radius();\n c = [\n slide.center.X() + r * Math.cos(this.position * delta + baseangle),\n slide.center.Y() + r * Math.sin(this.position * delta + baseangle)\n ];\n } else {\n // In case, the point is a constrained glider.\n this.updateConstraint();\n\n if (isTransformed) {\n c = Geometry.projectPointToCurve(this, slides[slides.length - 1], this.board)[0].usrCoords;\n // projectPointCurve() already would do the transformation.\n // But since we are projecting on the original curve, we have to do\n // the transformation \"by hand\".\n for (i = slides.length - 2; i >= 0; i--) {\n c = (new Coords(Const.COORDS_BY_USER,\n Mat.matVecMult(slides[i].transformMat, c), this.board)).usrCoords;\n }\n\n } else {\n c = Geometry.projectPointToCurve(this, slide, this.board)[0].usrCoords;\n }\n }\n\n } else if (Type.isPoint(slide)) {\n c = Geometry.projectPointToPoint(this, slide, this.board).usrCoords;\n }\n\n this.coords.setCoordinates(Const.COORDS_BY_USER, c, false);\n },\n\n updateRendererGeneric: function (rendererMethod) {\n //var wasReal;\n\n if (!this.needsUpdate) {\n return this;\n }\n\n if (this.visPropCalc.visible) {\n //wasReal = this.isReal;\n this.isReal = (!isNaN(this.coords.usrCoords[1] + this.coords.usrCoords[2]));\n //Homogeneous coords: ideal point\n this.isReal = (Math.abs(this.coords.usrCoords[0]) > Mat.eps) ? this.isReal : false;\n\n if (// wasReal &&\n !this.isReal) {\n this.updateVisibility(false);\n }\n }\n\n // Call the renderer only if element is visible.\n // Update the position\n if (this.visPropCalc.visible) {\n this.board.renderer[rendererMethod](this);\n }\n\n // Update the label if visible.\n if (this.hasLabel && this.visPropCalc.visible && this.label &&\n this.label.visPropCalc.visible && this.isReal) {\n this.label.update();\n this.board.renderer.updateText(this.label);\n }\n\n // Update rendNode display\n this.setDisplayRendNode();\n // if (this.visPropCalc.visible !== this.visPropOld.visible) {\n // this.board.renderer.display(this, this.visPropCalc.visible);\n // this.visPropOld.visible = this.visPropCalc.visible;\n //\n // if (this.hasLabel) {\n // this.board.renderer.display(this.label, this.label.visPropCalc.visible);\n // }\n // }\n\n this.needsUpdate = false;\n return this;\n },\n\n /**\n * Getter method for x, this is used by for CAS-points to access point coordinates.\n * @returns {Number} User coordinate of point in x direction.\n */\n X: function () {\n return this.coords.usrCoords[1];\n },\n\n /**\n * Getter method for y, this is used by CAS-points to access point coordinates.\n * @returns {Number} User coordinate of point in y direction.\n */\n Y: function () {\n return this.coords.usrCoords[2];\n },\n\n /**\n * Getter method for z, this is used by CAS-points to access point coordinates.\n * @returns {Number} User coordinate of point in z direction.\n */\n Z: function () {\n return this.coords.usrCoords[0];\n },\n\n /**\n * New evaluation of the function term.\n * This is required for CAS-points: Their XTerm() method is\n * overwritten in {@link JXG.CoordsElement#addConstraint}.\n *\n * @returns {Number} User coordinate of point in x direction.\n * @private\n */\n XEval: function () {\n return this.coords.usrCoords[1];\n },\n\n /**\n * New evaluation of the function term.\n * This is required for CAS-points: Their YTerm() method is overwritten\n * in {@link JXG.CoordsElement#addConstraint}.\n *\n * @returns {Number} User coordinate of point in y direction.\n * @private\n */\n YEval: function () {\n return this.coords.usrCoords[2];\n },\n\n /**\n * New evaluation of the function term.\n * This is required for CAS-points: Their ZTerm() method is overwritten in\n * {@link JXG.CoordsElement#addConstraint}.\n *\n * @returns {Number} User coordinate of point in z direction.\n * @private\n */\n ZEval: function () {\n return this.coords.usrCoords[0];\n },\n\n /**\n * Getter method for the distance to a second point, this is required for CAS-elements.\n * Here, function inlining seems to be worthwile (for plotting).\n * @param {JXG.Point} point2 The point to which the distance shall be calculated.\n * @returns {Number} Distance in user coordinate to the given point\n */\n Dist: function (point2) {\n if (this.isReal && point2.isReal) {\n return this.coords.distance(Const.COORDS_BY_USER, point2.coords);\n }\n return NaN;\n },\n\n /**\n * Alias for {@link JXG.Element#handleSnapToGrid}\n * @param {Boolean} force force snapping independent from what the snaptogrid attribute says\n * @returns {JXG.CoordsElement} Reference to this element\n */\n snapToGrid: function (force) {\n return this.handleSnapToGrid(force);\n },\n\n /**\n * Let a point snap to the nearest point in distance of\n * {@link JXG.Point#attractorDistance}.\n * The function uses the coords object of the point as\n * its actual position.\n * @param {Boolean} force force snapping independent from what the snaptogrid attribute says\n * @returns {JXG.Point} Reference to this element\n */\n handleSnapToPoints: function (force) {\n var i, pEl, pCoords,\n d = 0,\n len,\n dMax = Infinity,\n c = null,\n ev_au, ev_ad,\n ev_is2p = Type.evaluate(this.visProp.ignoredsnaptopoints),\n len2, j, ignore = false;\n\n len = this.board.objectsList.length;\n\n if (ev_is2p) {\n len2 = ev_is2p.length;\n }\n\n if (Type.evaluate(this.visProp.snaptopoints) || force) {\n ev_au = Type.evaluate(this.visProp.attractorunit);\n ev_ad = Type.evaluate(this.visProp.attractordistance);\n\n for (i = 0; i < len; i++) {\n pEl = this.board.objectsList[i];\n\n if (ev_is2p) {\n ignore = false;\n for (j = 0; j < len2; j++) {\n if (pEl === this.board.select(ev_is2p[j])) {\n ignore = true;\n break;\n }\n }\n if (ignore) {\n continue;\n }\n }\n\n if (Type.isPoint(pEl) && pEl !== this && pEl.visPropCalc.visible) {\n pCoords = Geometry.projectPointToPoint(this, pEl, this.board);\n if (ev_au === 'screen') {\n d = pCoords.distance(Const.COORDS_BY_SCREEN, this.coords);\n } else {\n d = pCoords.distance(Const.COORDS_BY_USER, this.coords);\n }\n\n if (d < ev_ad && d < dMax) {\n dMax = d;\n c = pCoords;\n }\n }\n }\n\n if (c !== null) {\n this.coords.setCoordinates(Const.COORDS_BY_USER, c.usrCoords);\n }\n }\n\n return this;\n },\n\n /**\n * Alias for {@link JXG.CoordsElement#handleSnapToPoints}.\n *\n * @param {Boolean} force force snapping independent from what the snaptogrid attribute says\n * @returns {JXG.Point} Reference to this element\n */\n snapToPoints: function (force) {\n return this.handleSnapToPoints(force);\n },\n\n /**\n * A point can change its type from free point to glider\n * and vice versa. If it is given an array of attractor elements\n * (attribute attractors) and the attribute attractorDistance\n * then the point will be made a glider if it less than attractorDistance\n * apart from one of its attractor elements.\n * If attractorDistance is equal to zero, the point stays in its\n * current form.\n * @returns {JXG.Point} Reference to this element\n */\n handleAttractors: function () {\n var i, el, projCoords,\n d = 0.0,\n projection,\n ev_au = Type.evaluate(this.visProp.attractorunit),\n ev_ad = Type.evaluate(this.visProp.attractordistance),\n ev_sd = Type.evaluate(this.visProp.snatchdistance),\n ev_a = Type.evaluate(this.visProp.attractors),\n len = ev_a.length;\n\n if (ev_ad === 0.0) {\n return;\n }\n\n for (i = 0; i < len; i++) {\n el = this.board.select(ev_a[i]);\n\n if (Type.exists(el) && el !== this) {\n if (Type.isPoint(el)) {\n projCoords = Geometry.projectPointToPoint(this, el, this.board);\n } else if (el.elementClass === Const.OBJECT_CLASS_LINE) {\n projection = Geometry.projectCoordsToSegment(\n this.coords.usrCoords,\n el.point1.coords.usrCoords,\n el.point2.coords.usrCoords);\n if (!Type.evaluate(el.visProp.straightfirst) && projection[1] < 0.0) {\n projCoords = el.point1.coords;\n } else if (!Type.evaluate(el.visProp.straightlast) && projection[1] > 1.0) {\n projCoords = el.point2.coords;\n } else {\n projCoords = new Coords(Const.COORDS_BY_USER, projection[0], this.board);\n }\n } else if (el.elementClass === Const.OBJECT_CLASS_CIRCLE) {\n projCoords = Geometry.projectPointToCircle(this, el, this.board);\n } else if (el.elementClass === Const.OBJECT_CLASS_CURVE) {\n projCoords = Geometry.projectPointToCurve(this, el, this.board)[0];\n } else if (el.type === Const.OBJECT_TYPE_TURTLE) {\n projCoords = Geometry.projectPointToTurtle(this, el, this.board)[0];\n } else if (el.type === Const.OBJECT_TYPE_POLYGON) {\n projCoords = new Coords(Const.COORDS_BY_USER,\n Geometry.projectCoordsToPolygon(this.coords.usrCoords, el),\n this.board);\n }\n\n if (ev_au === 'screen') {\n d = projCoords.distance(Const.COORDS_BY_SCREEN, this.coords);\n } else {\n d = projCoords.distance(Const.COORDS_BY_USER, this.coords);\n }\n\n if (d < ev_ad) {\n if (!(this.type === Const.OBJECT_TYPE_GLIDER &&\n (el === this.slideObject || this.slideObject && this.onPolygon && this.slideObject.parentPolygon === el)\n )\n ) {\n this.makeGlider(el);\n }\n break; // bind the point to the first attractor in its list.\n }\n if (d >= ev_sd &&\n (el === this.slideObject || this.slideObject && this.onPolygon && this.slideObject.parentPolygon === el)\n ) {\n this.popSlideObject();\n }\n }\n }\n\n return this;\n },\n\n /**\n * Sets coordinates and calls the point's update() method.\n * @param {Number} method The type of coordinates used here.\n * Possible values are {@link JXG.COORDS_BY_USER} and {@link JXG.COORDS_BY_SCREEN}.\n * @param {Array} coords coordinates <tt>([z], x, y)</tt> in screen/user units\n * @returns {JXG.Point} this element\n */\n setPositionDirectly: function (method, coords) {\n var i, c, dc,\n oldCoords = this.coords,\n newCoords;\n\n if (this.relativeCoords) {\n c = new Coords(method, coords, this.board);\n if (Type.evaluate(this.visProp.islabel)) {\n dc = Statistics.subtract(c.scrCoords, oldCoords.scrCoords);\n this.relativeCoords.scrCoords[1] += dc[1];\n this.relativeCoords.scrCoords[2] += dc[2];\n } else {\n dc = Statistics.subtract(c.usrCoords, oldCoords.usrCoords);\n this.relativeCoords.usrCoords[1] += dc[1];\n this.relativeCoords.usrCoords[2] += dc[2];\n }\n\n return this;\n }\n\n this.coords.setCoordinates(method, coords);\n this.handleSnapToGrid();\n this.handleSnapToPoints();\n this.handleAttractors();\n\n // Update the initial coordinates. This is needed for free points\n // that have a transformation bound to it.\n for (i = this.transformations.length - 1; i >= 0; i--) {\n if (method === Const.COORDS_BY_SCREEN) {\n newCoords = (new Coords(method, coords, this.board)).usrCoords;\n } else {\n if (coords.length === 2) {\n coords = [1].concat(coords);\n }\n newCoords = coords;\n }\n this.initialCoords.setCoordinates(Const.COORDS_BY_USER, Mat.matVecMult(Mat.inverse(this.transformations[i].matrix), newCoords));\n }\n this.prepareUpdate().update();\n\n // If the user suspends the board updates we need to recalculate the relative position of\n // the point on the slide object. This is done in updateGlider() which is NOT called during the\n // update process triggered by unsuspendUpdate.\n if (this.board.isSuspendedUpdate && this.type === Const.OBJECT_TYPE_GLIDER) {\n this.updateGlider();\n }\n\n return this;\n },\n\n /**\n * Translates the point by <tt>tv = (x, y)</tt>.\n * @param {Number} method The type of coordinates used here.\n * Possible values are {@link JXG.COORDS_BY_USER} and {@link JXG.COORDS_BY_SCREEN}.\n * @param {Array} tv (x, y)\n * @returns {JXG.Point}\n */\n setPositionByTransform: function (method, tv) {\n var t;\n\n tv = new Coords(method, tv, this.board);\n t = this.board.create('transform', tv.usrCoords.slice(1), {type: 'translate'});\n\n if (this.transformations.length > 0 &&\n this.transformations[this.transformations.length - 1].isNumericMatrix) {\n this.transformations[this.transformations.length - 1].melt(t);\n } else {\n this.addTransform(this, t);\n }\n\n this.prepareUpdate().update();\n\n return this;\n },\n\n /**\n * Sets coordinates and calls the point's update() method.\n * @param {Number} method The type of coordinates used here.\n * Possible values are {@link JXG.COORDS_BY_USER} and {@link JXG.COORDS_BY_SCREEN}.\n * @param {Array} coords coordinates in screen/user units\n * @returns {JXG.Point}\n */\n setPosition: function (method, coords) {\n return this.setPositionDirectly(method, coords);\n },\n\n /**\n * Sets the position of a glider relative to the defining elements\n * of the {@link JXG.Point#slideObject}.\n * @param {Number} x\n * @returns {JXG.Point} Reference to the point element.\n */\n setGliderPosition: function (x) {\n if (this.type === Const.OBJECT_TYPE_GLIDER) {\n this.position = x;\n this.board.update();\n }\n\n return this;\n },\n\n /**\n * Convert the point to glider and update the construction.\n * To move the point visual onto the glider, a call of board update is necessary.\n * @param {String|Object} slide The object the point will be bound to.\n */\n makeGlider: function (slide) {\n var slideobj = this.board.select(slide),\n onPolygon = false,\n min,\n i,\n dist;\n\n if (slideobj.type === Const.OBJECT_TYPE_POLYGON){\n // Search for the closest edge of the polygon.\n min = Number.MAX_VALUE;\n for (i = 0; i < slideobj.borders.length; i++){\n dist = JXG.Math.Geometry.distPointLine(this.coords.usrCoords, slideobj.borders[i].stdform);\n if (dist < min){\n min = dist;\n slide = slideobj.borders[i];\n }\n }\n slideobj = this.board.select(slide);\n onPolygon = true;\n }\n\n /* Gliders on Ticks are forbidden */\n if (!Type.exists(slideobj)) {\n throw new Error(\"JSXGraph: slide object undefined.\");\n } else if (slideobj.type === Const.OBJECT_TYPE_TICKS) {\n throw new Error(\"JSXGraph: gliders on ticks are not possible.\");\n }\n\n this.slideObject = this.board.select(slide);\n this.slideObjects.push(this.slideObject);\n this.addParents(slide);\n\n this.type = Const.OBJECT_TYPE_GLIDER;\n this.elType = 'glider';\n this.visProp.snapwidth = -1; // By default, deactivate snapWidth\n this.slideObject.addChild(this);\n this.isDraggable = true;\n this.onPolygon = onPolygon;\n\n this.generatePolynomial = function () {\n return this.slideObject.generatePolynomial(this);\n };\n\n // Determine the initial value of this.position\n this.updateGlider();\n this.needsUpdateFromParent = true;\n this.updateGliderFromParent();\n\n return this;\n },\n\n /**\n * Remove the last slideObject. If there are more than one elements the point is bound to,\n * the second last element is the new active slideObject.\n */\n popSlideObject: function () {\n if (this.slideObjects.length > 0) {\n this.slideObjects.pop();\n\n // It may not be sufficient to remove the point from\n // the list of childElement. For complex dependencies\n // one may have to go to the list of ancestor and descendants. A.W.\n // Yes indeed, see #51 on github bugtracker\n // delete this.slideObject.childElements[this.id];\n this.slideObject.removeChild(this);\n\n if (this.slideObjects.length === 0) {\n this.type = this._org_type;\n if (this.type === Const.OBJECT_TYPE_POINT) {\n this.elType = 'point';\n } else if (this.elementClass === Const.OBJECT_CLASS_TEXT) {\n this.elType = 'text';\n } else if (this.type === Const.OBJECT_TYPE_IMAGE) {\n this.elType = 'image';\n } else if (this.type === Const.OBJECT_TYPE_FOREIGNOBJECT) {\n this.elType = 'foreignobject';\n }\n\n this.slideObject = null;\n } else {\n this.slideObject = this.slideObjects[this.slideObjects.length - 1];\n }\n }\n },\n\n /**\n * Converts a calculated element into a free element,\n * i.e. it will delete all ancestors and transformations and,\n * if the element is currently a glider, will remove the slideObject reference.\n */\n free: function () {\n var ancestorId, ancestor;\n // child;\n\n if (this.type !== Const.OBJECT_TYPE_GLIDER) {\n // remove all transformations\n this.transformations.length = 0;\n\n delete this.updateConstraint;\n this.isConstrained = false;\n // this.updateConstraint = function () {\n // return this;\n // };\n\n if (!this.isDraggable) {\n this.isDraggable = true;\n\n if (this.elementClass === Const.OBJECT_CLASS_POINT) {\n this.type = Const.OBJECT_TYPE_POINT;\n this.elType = 'point';\n }\n\n this.XEval = function () {\n return this.coords.usrCoords[1];\n };\n\n this.YEval = function () {\n return this.coords.usrCoords[2];\n };\n\n this.ZEval = function () {\n return this.coords.usrCoords[0];\n };\n\n this.Xjc = null;\n this.Yjc = null;\n } else {\n return;\n }\n }\n\n // a free point does not depend on anything. And instead of running through tons of descendants and ancestor\n // structures, where we eventually are going to visit a lot of objects twice or thrice with hard to read and\n // comprehend code, just run once through all objects and delete all references to this point and its label.\n for (ancestorId in this.board.objects) {\n if (this.board.objects.hasOwnProperty(ancestorId)) {\n ancestor = this.board.objects[ancestorId];\n\n if (ancestor.descendants) {\n delete ancestor.descendants[this.id];\n delete ancestor.childElements[this.id];\n\n if (this.hasLabel) {\n delete ancestor.descendants[this.label.id];\n delete ancestor.childElements[this.label.id];\n }\n }\n }\n }\n\n // A free point does not depend on anything. Remove all ancestors.\n this.ancestors = {}; // only remove the reference\n\n // Completely remove all slideObjects of the element\n this.slideObject = null;\n this.slideObjects = [];\n if (this.elementClass === Const.OBJECT_CLASS_POINT) {\n this.type = Const.OBJECT_TYPE_POINT;\n this.elType = 'point';\n } else if (this.elementClass === Const.OBJECT_CLASS_TEXT) {\n this.type = this._org_type;\n this.elType = 'text';\n } else if (this.elementClass === Const.OBJECT_CLASS_OTHER) {\n this.type = this._org_type;\n this.elType = 'image';\n }\n },\n\n /**\n * Convert the point to CAS point and call update().\n * @param {Array} terms [[zterm], xterm, yterm] defining terms for the z, x and y coordinate.\n * The z-coordinate is optional and it is used for homogeneous coordinates.\n * The coordinates may be either <ul>\n * <li>a JavaScript function,</li>\n * <li>a string containing GEONExT syntax. This string will be converted into a JavaScript\n * function here,</li>\n * <li>a Number</li>\n * <li>a pointer to a slider object. This will be converted into a call of the Value()-method\n * of this slider.</li>\n * </ul>\n * @see JXG.GeonextParser#geonext2JS\n */\n addConstraint: function (terms) {\n var i, v,\n newfuncs = [],\n what = ['X', 'Y'],\n\n makeConstFunction = function (z) {\n return function () {\n return z;\n };\n },\n\n makeSliderFunction = function (a) {\n return function () {\n return a.Value();\n };\n };\n\n if (this.elementClass === Const.OBJECT_CLASS_POINT) {\n this.type = Const.OBJECT_TYPE_CAS;\n }\n\n this.isDraggable = false;\n\n for (i = 0; i < terms.length; i++) {\n v = terms[i];\n\n if (Type.isString(v)) {\n // Convert GEONExT syntax into JavaScript syntax\n //t = JXG.GeonextParser.geonext2JS(v, this.board);\n //newfuncs[i] = new Function('','return ' + t + ';');\n //v = GeonextParser.replaceNameById(v, this.board);\n newfuncs[i] = this.board.jc.snippet(v, true, null, true);\n\n if (terms.length === 2) {\n this[what[i] + 'jc'] = terms[i];\n }\n } else if (Type.isFunction(v)) {\n newfuncs[i] = v;\n } else if (Type.isNumber(v)) {\n newfuncs[i] = makeConstFunction(v);\n // Slider\n } else if (Type.isObject(v) && Type.isFunction(v.Value)) {\n newfuncs[i] = makeSliderFunction(v);\n }\n\n newfuncs[i].origin = v;\n }\n\n // Intersection function\n if (terms.length === 1) {\n this.updateConstraint = function () {\n var c = newfuncs[0]();\n\n // Array\n if (Type.isArray(c)) {\n this.coords.setCoordinates(Const.COORDS_BY_USER, c);\n // Coords object\n } else {\n this.coords = c;\n }\n return this;\n };\n // Euclidean coordinates\n } else if (terms.length === 2) {\n this.XEval = newfuncs[0];\n this.YEval = newfuncs[1];\n\n this.setParents([newfuncs[0].origin, newfuncs[1].origin]);\n\n this.updateConstraint = function () {\n this.coords.setCoordinates(Const.COORDS_BY_USER, [this.XEval(), this.YEval()]);\n return this;\n };\n // Homogeneous coordinates\n } else {\n this.ZEval = newfuncs[0];\n this.XEval = newfuncs[1];\n this.YEval = newfuncs[2];\n\n this.setParents([newfuncs[0].origin, newfuncs[1].origin, newfuncs[2].origin]);\n\n this.updateConstraint = function () {\n this.coords.setCoordinates(Const.COORDS_BY_USER, [this.ZEval(), this.XEval(), this.YEval()]);\n return this;\n };\n }\n this.isConstrained = true;\n\n /**\n * We have to do an update. Otherwise, elements relying on this point will receive NaN.\n */\n this.prepareUpdate().update();\n if (!this.board.isSuspendedUpdate) {\n this.updateVisibility().updateRenderer();\n if (this.hasLabel) {\n this.label.fullUpdate();\n }\n }\n\n return this;\n },\n\n /**\n * In case there is an attribute \"anchor\", the element is bound to\n * this anchor element.\n * This is handled with this.relativeCoords. If the element is a label\n * relativeCoords are given in scrCoords, otherwise in usrCoords.\n * @param{Array} coordinates Offset from th anchor element. These are the values for this.relativeCoords.\n * In case of a label, coordinates are screen coordinates. Otherwise, coordinates are user coordinates.\n * @param{Boolean} isLabel Yes/no\n * @private\n */\n addAnchor: function (coordinates, isLabel) {\n if (isLabel) {\n this.relativeCoords = new Coords(Const.COORDS_BY_SCREEN, coordinates.slice(0, 2), this.board);\n } else {\n this.relativeCoords = new Coords(Const.COORDS_BY_USER, coordinates, this.board);\n }\n this.element.addChild(this);\n if (isLabel) {\n this.addParents(this.element);\n }\n\n this.XEval = function () {\n var sx, coords, anchor, ev_o;\n\n if (Type.evaluate(this.visProp.islabel)) {\n ev_o = Type.evaluate(this.visProp.offset);\n sx = parseFloat(ev_o[0]);\n anchor = this.element.getLabelAnchor();\n coords = new Coords(Const.COORDS_BY_SCREEN,\n [sx + this.relativeCoords.scrCoords[1] + anchor.scrCoords[1], 0], this.board);\n\n return coords.usrCoords[1];\n }\n\n anchor = this.element.getTextAnchor();\n return this.relativeCoords.usrCoords[1] + anchor.usrCoords[1];\n };\n\n this.YEval = function () {\n var sy, coords, anchor, ev_o;\n\n if (Type.evaluate(this.visProp.islabel)) {\n ev_o = Type.evaluate(this.visProp.offset);\n sy = -parseFloat(ev_o[1]);\n anchor = this.element.getLabelAnchor();\n coords = new Coords(Const.COORDS_BY_SCREEN,\n [0, sy + this.relativeCoords.scrCoords[2] + anchor.scrCoords[2]], this.board);\n\n return coords.usrCoords[2];\n }\n\n anchor = this.element.getTextAnchor();\n return this.relativeCoords.usrCoords[2] + anchor.usrCoords[2];\n };\n\n this.ZEval = Type.createFunction(1, this.board, '');\n\n this.updateConstraint = function () {\n this.coords.setCoordinates(Const.COORDS_BY_USER, [this.ZEval(), this.XEval(), this.YEval()]);\n };\n this.isConstrained = true;\n\n this.updateConstraint();\n //this.coords = new Coords(Const.COORDS_BY_SCREEN, [0, 0], this.board);\n },\n\n /**\n * Applies the transformations of the element.\n * This method applies to text and images. Point transformations are handled differently.\n * @param {Boolean} fromParent True if the drag comes from a child element. Unused.\n * @returns {JXG.CoordsElement} Reference to itself.\n */\n updateTransform: function (fromParent) {\n var i;\n\n if (this.transformations.length === 0) {\n return this;\n }\n\n for (i = 0; i < this.transformations.length; i++) {\n this.transformations[i].update();\n }\n\n return this;\n },\n\n /**\n * Add transformations to this element.\n * @param {JXG.GeometryElement} el\n * @param {JXG.Transformation|Array} transform Either one {@link JXG.Transformation}\n * or an array of {@link JXG.Transformation}s.\n * @returns {JXG.CoordsElement} Reference to itself.\n */\n addTransform: function (el, transform) {\n var i,\n list = Type.isArray(transform) ? transform : [transform],\n len = list.length;\n\n // There is only one baseElement possible\n if (this.transformations.length === 0) {\n this.baseElement = el;\n }\n\n for (i = 0; i < len; i++) {\n this.transformations.push(list[i]);\n }\n\n return this;\n },\n\n /**\n * Animate the point.\n * @param {Number} direction The direction the glider is animated. Can be +1 or -1.\n * @param {Number} stepCount The number of steps in which the parent element is divided.\n * Must be at least 1.\n * @param {Number} delay Time in msec between two animation steps. Default is 250.\n * @returns {JXG.CoordsElement} Reference to iself.\n *\n * @name Glider#startAnimation\n * @see Glider#stopAnimation\n * @function\n * @example\n * // Divide the circle line into 6 steps and\n * // visit every step 330 msec counterclockwise.\n * var ci = board.create('circle', [[-1,2], [2,1]]);\n * var gl = board.create('glider', [0,2, ci]);\n * gl.startAnimation(-1, 6, 330);\n *\n * </pre><div id=\"JXG0f35a50e-e99d-11e8-a1ca-04d3b0c2aad3\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG0f35a50e-e99d-11e8-a1ca-04d3b0c2aad3',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * // Divide the circle line into 6 steps and\n * // visit every step 330 msec counterclockwise.\n * var ci = board.create('circle', [[-1,2], [2,1]]);\n * var gl = board.create('glider', [0,2, ci]);\n * gl.startAnimation(-1, 6, 330);\n *\n * })();\n *\n * </script><pre>\n *\n * @example\n * // Divide the slider area into 20 steps and\n * // visit every step 30 msec.\n * var n = board.create('slider',[[-2,4],[2,4],[1,5,100]],{name:'n'});\n * n.startAnimation(1, 20, 30);\n *\n * </pre><div id=\"JXG40ce04b8-e99c-11e8-a1ca-04d3b0c2aad3\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG40ce04b8-e99c-11e8-a1ca-04d3b0c2aad3',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * // Divide the slider area into 20 steps and\n * // visit every step 30 msec.\n * var n = board.create('slider',[[-2,4],[2,4],[1,5,100]],{name:'n'});\n * n.startAnimation(1, 20, 30);\n *\n * })();\n * </script><pre>\n *\n */\n startAnimation: function (direction, stepCount, delay) {\n var that = this;\n\n delay = delay || 250;\n\n if ((this.type === Const.OBJECT_TYPE_GLIDER) && !Type.exists(this.intervalCode)) {\n this.intervalCode = window.setInterval(function () {\n that._anim(direction, stepCount);\n }, delay);\n\n if (!Type.exists(this.intervalCount)) {\n this.intervalCount = 0;\n }\n }\n return this;\n },\n\n /**\n * Stop animation.\n * @name Glider#stopAnimation\n * @see Glider#startAnimation\n * @function\n * @returns {JXG.CoordsElement} Reference to itself.\n */\n stopAnimation: function () {\n if (Type.exists(this.intervalCode)) {\n window.clearInterval(this.intervalCode);\n delete this.intervalCode;\n }\n\n return this;\n },\n\n /**\n * Starts an animation which moves the point along a given path in given time.\n * @param {Array|function} path The path the point is moved on.\n * This can be either an array of arrays or containing x and y values of the points of\n * the path, or an array of points, or a function taking the amount of elapsed time since the animation\n * has started and returns an array containing a x and a y value or NaN.\n * In case of NaN the animation stops.\n * @param {Number} time The time in milliseconds in which to finish the animation\n * @param {Object} [options] Optional settings for the animation.\n * @param {function} [options.callback] A function that is called as soon as the animation is finished.\n * @param {Boolean} [options.interpolate=true] If <tt>path</tt> is an array moveAlong()\n * will interpolate the path\n * using {@link JXG.Math.Numerics.Neville}. Set this flag to false if you don't want to use interpolation.\n * @returns {JXG.CoordsElement} Reference to itself.\n * @see JXG.CoordsElement#moveAlong\n * @see JXG.CoordsElement#moveTo\n * @see JXG.GeometryElement#animate\n */\n moveAlong: function (path, time, options) {\n options = options || {};\n\n var i, neville,\n interpath = [],\n p = [],\n delay = this.board.attr.animationdelay,\n steps = time / delay,\n len, pos, part,\n\n makeFakeFunction = function (i, j) {\n return function () {\n return path[i][j];\n };\n };\n\n if (Type.isArray(path)) {\n len = path.length;\n for (i = 0; i < len; i++) {\n if (Type.isPoint(path[i])) {\n p[i] = path[i];\n } else {\n p[i] = {\n elementClass: Const.OBJECT_CLASS_POINT,\n X: makeFakeFunction(i, 0),\n Y: makeFakeFunction(i, 1)\n };\n }\n }\n\n time = time || 0;\n if (time === 0) {\n this.setPosition(Const.COORDS_BY_USER, [p[p.length - 1].X(), p[p.length - 1].Y()]);\n return this.board.update(this);\n }\n\n if (!Type.exists(options.interpolate) || options.interpolate) {\n neville = Numerics.Neville(p);\n for (i = 0; i < steps; i++) {\n interpath[i] = [];\n interpath[i][0] = neville[0]((steps - i) / steps * neville[3]());\n interpath[i][1] = neville[1]((steps - i) / steps * neville[3]());\n }\n } else {\n len = path.length - 1;\n for (i = 0; i < steps; ++i) {\n pos = Math.floor(i / steps * len);\n part = i / steps * len - pos;\n\n interpath[i] = [];\n interpath[i][0] = (1.0 - part) * p[pos].X() + part * p[pos + 1].X();\n interpath[i][1] = (1.0 - part) * p[pos].Y() + part * p[pos + 1].Y();\n }\n interpath.push([p[len].X(), p[len].Y()]);\n interpath.reverse();\n /*\n for (i = 0; i < steps; i++) {\n interpath[i] = [];\n interpath[i][0] = path[Math.floor((steps - i) / steps * (path.length - 1))][0];\n interpath[i][1] = path[Math.floor((steps - i) / steps * (path.length - 1))][1];\n }\n */\n }\n\n this.animationPath = interpath;\n } else if (Type.isFunction(path)) {\n this.animationPath = path;\n this.animationStart = new Date().getTime();\n }\n\n this.animationCallback = options.callback;\n this.board.addAnimation(this);\n\n return this;\n },\n\n /**\n * Starts an animated point movement towards the given coordinates <tt>where</tt>.\n * The animation is done after <tt>time</tt> milliseconds.\n * If the second parameter is not given or is equal to 0, setPosition() is called, see #setPosition,\n * i.e. the coordinates are changed without animation.\n * @param {Array} where Array containing the x and y coordinate of the target location.\n * @param {Number} [time] Number of milliseconds the animation should last.\n * @param {Object} [options] Optional settings for the animation\n * @param {function} [options.callback] A function that is called as soon as the animation is finished.\n * @param {String} [options.effect='<>'] animation effects like speed fade in and out. possible values are\n * '<>' for speed increase on start and slow down at the end (default) and '--' for constant speed during\n * the whole animation.\n * @returns {JXG.CoordsElement} Reference to itself.\n * @see JXG.CoordsElement#moveAlong\n * @see JXG.CoordsElement#visit\n * @see JXG.GeometryElement#animate\n */\n moveTo: function (where, time, options) {\n options = options || {};\n where = new Coords(Const.COORDS_BY_USER, where, this.board);\n\n var i,\n delay = this.board.attr.animationdelay,\n steps = Math.ceil(time / delay),\n coords = [],\n X = this.coords.usrCoords[1],\n Y = this.coords.usrCoords[2],\n dX = (where.usrCoords[1] - X),\n dY = (where.usrCoords[2] - Y),\n\n /** @ignore */\n stepFun = function (i) {\n if (options.effect && options.effect === '<>') {\n return Math.pow(Math.sin((i / steps) * Math.PI / 2), 2);\n }\n return i / steps;\n };\n\n if (!Type.exists(time) || time === 0 ||\n (Math.abs(where.usrCoords[0] - this.coords.usrCoords[0]) > Mat.eps)) {\n this.setPosition(Const.COORDS_BY_USER, where.usrCoords);\n return this.board.update(this);\n }\n\n // In case there is no callback and we are already at the endpoint we can stop here\n if (!Type.exists(options.callback) && Math.abs(dX) < Mat.eps && Math.abs(dY) < Mat.eps) {\n return this;\n }\n\n for (i = steps; i >= 0; i--) {\n coords[steps - i] = [where.usrCoords[0], X + dX * stepFun(i), Y + dY * stepFun(i)];\n }\n\n this.animationPath = coords;\n this.animationCallback = options.callback;\n this.board.addAnimation(this);\n\n return this;\n },\n\n /**\n * Starts an animated point movement towards the given coordinates <tt>where</tt>. After arriving at\n * <tt>where</tt> the point moves back to where it started. The animation is done after <tt>time</tt>\n * milliseconds.\n * @param {Array} where Array containing the x and y coordinate of the target location.\n * @param {Number} time Number of milliseconds the animation should last.\n * @param {Object} [options] Optional settings for the animation\n * @param {function} [options.callback] A function that is called as soon as the animation is finished.\n * @param {String} [options.effect='<>'] animation effects like speed fade in and out. possible values are\n * '<>' for speed increase on start and slow down at the end (default) and '--' for constant speed during\n * the whole animation.\n * @param {Number} [options.repeat=1] How often this animation should be repeated.\n * @returns {JXG.CoordsElement} Reference to itself.\n * @see JXG.CoordsElement#moveAlong\n * @see JXG.CoordsElement#moveTo\n * @see JXG.GeometryElement#animate\n */\n visit: function (where, time, options) {\n where = new Coords(Const.COORDS_BY_USER, where, this.board);\n\n var i, j, steps,\n delay = this.board.attr.animationdelay,\n coords = [],\n X = this.coords.usrCoords[1],\n Y = this.coords.usrCoords[2],\n dX = (where.usrCoords[1] - X),\n dY = (where.usrCoords[2] - Y),\n\n /** @ignore */\n stepFun = function (i) {\n var x = (i < steps / 2 ? 2 * i / steps : 2 * (steps - i) / steps);\n\n if (options.effect && options.effect === '<>') {\n return Math.pow(Math.sin(x * Math.PI / 2), 2);\n }\n\n return x;\n };\n\n // support legacy interface where the third parameter was the number of repeats\n if (Type.isNumber(options)) {\n options = {repeat: options};\n } else {\n options = options || {};\n if (!Type.exists(options.repeat)) {\n options.repeat = 1;\n }\n }\n\n steps = Math.ceil(time / (delay * options.repeat));\n\n for (j = 0; j < options.repeat; j++) {\n for (i = steps; i >= 0; i--) {\n coords[j * (steps + 1) + steps - i] = [where.usrCoords[0], X + dX * stepFun(i), Y + dY * stepFun(i)];\n }\n }\n this.animationPath = coords;\n this.animationCallback = options.callback;\n this.board.addAnimation(this);\n\n return this;\n },\n\n /**\n * Animates a glider. Is called by the browser after startAnimation is called.\n * @param {Number} direction The direction the glider is animated.\n * @param {Number} stepCount The number of steps in which the parent element is divided.\n * Must be at least 1.\n * @see #startAnimation\n * @see #stopAnimation\n * @private\n * @returns {JXG.CoordsElement} Reference to itself.\n */\n _anim: function (direction, stepCount) {\n var dX, dY, alpha, startPoint, newX, radius,\n sp1c, sp2c,\n res,\n d;\n\n this.intervalCount += 1;\n if (this.intervalCount > stepCount) {\n this.intervalCount = 0;\n }\n\n if (this.slideObject.elementClass === Const.OBJECT_CLASS_LINE) {\n sp1c = this.slideObject.point1.coords.scrCoords;\n sp2c = this.slideObject.point2.coords.scrCoords;\n\n dX = Math.round((sp2c[1] - sp1c[1]) * this.intervalCount / stepCount);\n dY = Math.round((sp2c[2] - sp1c[2]) * this.intervalCount / stepCount);\n if (direction > 0) {\n startPoint = this.slideObject.point1;\n } else {\n startPoint = this.slideObject.point2;\n dX *= -1;\n dY *= -1;\n }\n\n this.coords.setCoordinates(Const.COORDS_BY_SCREEN, [\n startPoint.coords.scrCoords[1] + dX,\n startPoint.coords.scrCoords[2] + dY\n ]);\n } else if (this.slideObject.elementClass === Const.OBJECT_CLASS_CURVE) {\n if (direction > 0) {\n newX = Math.round(this.intervalCount / stepCount * this.board.canvasWidth);\n } else {\n newX = Math.round((stepCount - this.intervalCount) / stepCount * this.board.canvasWidth);\n }\n\n this.coords.setCoordinates(Const.COORDS_BY_SCREEN, [newX, 0]);\n res = Geometry.projectPointToCurve(this, this.slideObject, this.board);\n this.coords = res[0];\n this.position = res[1];\n } else if (this.slideObject.elementClass === Const.OBJECT_CLASS_CIRCLE) {\n alpha = 2 * Math.PI;\n if (direction < 0) {\n alpha *= this.intervalCount / stepCount;\n } else {\n alpha *= (stepCount - this.intervalCount) / stepCount;\n }\n radius = this.slideObject.Radius();\n\n this.coords.setCoordinates(Const.COORDS_BY_USER, [\n this.slideObject.center.coords.usrCoords[1] + radius * Math.cos(alpha),\n this.slideObject.center.coords.usrCoords[2] + radius * Math.sin(alpha)\n ]);\n }\n\n this.board.update(this);\n return this;\n },\n\n // documented in GeometryElement\n getTextAnchor: function () {\n return this.coords;\n },\n\n // documented in GeometryElement\n getLabelAnchor: function () {\n return this.coords;\n },\n\n // documented in element.js\n getParents: function () {\n var p = [this.Z(), this.X(), this.Y()];\n\n if (this.parents.length !== 0) {\n p = this.parents;\n }\n\n if (this.type === Const.OBJECT_TYPE_GLIDER) {\n p = [this.X(), this.Y(), this.slideObject.id];\n }\n\n return p;\n }\n\n });\n\n /**\n * Generic method to create point, text or image.\n * Determines the type of the construction, i.e. free, or constrained by function,\n * transformation or of glider type.\n * @param{Object} Callback Object type, e.g. JXG.Point, JXG.Text or JXG.Image\n * @param{Object} board Link to the board object\n * @param{Array} coords Array with coordinates. This may be: array of numbers, function\n * returning an array of numbers, array of functions returning a number, object and transformation.\n * If the attribute \"slideObject\" exists, a glider element is constructed.\n * @param{Object} attr Attributes object\n * @param{Object} arg1 Optional argument 1: in case of text this is the text content,\n * in case of an image this is the url.\n * @param{Array} arg2 Optional argument 2: in case of image this is an array containing the size of\n * the image.\n * @returns{Object} returns the created object or false.\n */\n JXG.CoordsElement.create = function (Callback, board, coords, attr, arg1, arg2) {\n var el, isConstrained = false, i;\n\n for (i = 0; i < coords.length; i++) {\n if (Type.isFunction(coords[i]) || Type.isString(coords[i])) {\n isConstrained = true;\n }\n }\n\n if (!isConstrained) {\n if (Type.isNumber(coords[0]) && Type.isNumber(coords[1])) {\n el = new Callback(board, coords, attr, arg1, arg2);\n\n if (Type.exists(attr.slideobject)) {\n el.makeGlider(attr.slideobject);\n } else {\n // Free element\n el.baseElement = el;\n }\n el.isDraggable = true;\n } else if (Type.isObject(coords[0]) && Type.isTransformationOrArray(coords[1])) {\n // Transformation\n // TODO less general specification of isObject\n el = new Callback(board, [0, 0], attr, arg1, arg2);\n el.addTransform(coords[0], coords[1]);\n el.isDraggable = false;\n } else {\n return false;\n }\n } else {\n el = new Callback(board, [0, 0], attr, arg1, arg2);\n el.addConstraint(coords);\n }\n\n el.handleSnapToGrid();\n el.handleSnapToPoints();\n el.handleAttractors();\n\n el.addParents(coords);\n return el;\n };\n\n return JXG.CoordsElement;\n\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n/*global JXG: true, define: true, window: true*/\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n jxg\n base/constants\n base/coords\n base/element\n parser/geonext\n math/statistics\n utils/env\n utils/type\n */\n\n/**\n * @fileoverview In this file the Text element is defined.\n */\n\ndefine('base/text',[\n 'jxg', 'base/constants', 'base/element', 'parser/geonext',\n 'utils/env', 'utils/type', 'math/math', 'base/coordselement'\n], function (JXG, Const, GeometryElement, GeonextParser, Env, Type, Mat, CoordsElement) {\n\n \"use strict\";\n\n var priv = {\n HTMLSliderInputEventHandler: function () {\n this._val = parseFloat(this.rendNodeRange.value);\n this.rendNodeOut.value = this.rendNodeRange.value;\n this.board.update();\n }\n };\n\n /**\n * Construct and handle texts.\n *\n * The coordinates can be relative to the coordinates of an element\n * given in {@link JXG.Options#text.anchor}.\n *\n * MathJax, HTML and GEONExT syntax can be handled.\n * @class Creates a new text object. Do not use this constructor to create a text. Use {@link JXG.Board#create} with\n * type {@link Text} instead.\n * @augments JXG.GeometryElement\n * @augments JXG.CoordsElement\n * @param {string|JXG.Board} board The board the new text is drawn on.\n * @param {Array} coordinates An array with the user coordinates of the text.\n * @param {Object} attributes An object containing visual properties and optional a name and a id.\n * @param {string|function} content A string or a function returning a string.\n *\n */\n JXG.Text = function (board, coords, attributes, content) {\n this.constructor(board, attributes, Const.OBJECT_TYPE_TEXT, Const.OBJECT_CLASS_TEXT);\n\n this.element = this.board.select(attributes.anchor);\n this.coordsConstructor(coords, Type.evaluate(this.visProp.islabel));\n\n this.content = '';\n this.plaintext = '';\n this.plaintextOld = null;\n this.orgText = '';\n\n this.needsSizeUpdate = false;\n // Only used by infobox anymore\n this.hiddenByParent = false;\n\n /**\n * Width and height of the the text element in pixel.\n *\n * @private\n * @type Array\n */\n this.size = [1.0, 1.0];\n this.id = this.board.setId(this, 'T');\n\n this.board.renderer.drawText(this);\n this.board.finalizeAdding(this);\n\n // Set text before drawing\n // this._createFctUpdateText(content);\n // this.updateText();\n\n this.setText(content);\n\n if (Type.isString(this.content)) {\n this.notifyParents(this.content);\n }\n this.elType = 'text';\n\n this.methodMap = Type.deepCopy(this.methodMap, {\n setText: 'setTextJessieCode',\n // free: 'free',\n move: 'setCoords'\n });\n };\n\n JXG.Text.prototype = new GeometryElement();\n Type.copyPrototypeMethods(JXG.Text, CoordsElement, 'coordsConstructor');\n\n JXG.extend(JXG.Text.prototype, /** @lends JXG.Text.prototype */ {\n /**\n * @private\n * Test if the the screen coordinates (x,y) are in a small stripe\n * at the left side or at the right side of the text.\n * Sensitivity is set in this.board.options.precision.hasPoint.\n * If dragarea is set to 'all' (default), tests if the the screen\n * coordinates (x,y) are in within the text boundary.\n * @param {Number} x\n * @param {Number} y\n * @returns {Boolean}\n */\n hasPoint: function (x, y) {\n var lft, rt, top, bot, ax, ay, type, r;\n\n if (Type.isObject(Type.evaluate(this.visProp.precision))) {\n type = this.board._inputDevice;\n r = Type.evaluate(this.visProp.precision[type]);\n } else {\n // 'inherit'\n r = this.board.options.precision.hasPoint;\n }\n if (this.transformations.length > 0) {\n //Transform the mouse/touch coordinates\n // back to the original position of the text.\n lft = Mat.matVecMult(Mat.inverse(this.board.renderer.joinTransforms(this, this.transformations)), [1, x, y]);\n x = lft[1];\n y = lft[2];\n }\n\n ax = this.getAnchorX();\n if (ax === 'right') {\n lft = this.coords.scrCoords[1] - this.size[0];\n } else if (ax === 'middle') {\n lft = this.coords.scrCoords[1] - 0.5 * this.size[0];\n } else {\n lft = this.coords.scrCoords[1];\n }\n rt = lft + this.size[0];\n\n ay = this.getAnchorY();\n if (ay === 'top') {\n bot = this.coords.scrCoords[2] + this.size[1];\n } else if (ay === 'middle') {\n bot = this.coords.scrCoords[2] + 0.5 * this.size[1];\n } else {\n bot = this.coords.scrCoords[2];\n }\n top = bot - this.size[1];\n\n if (Type.evaluate(this.visProp.dragarea) === 'all') {\n return x >= lft - r && x < rt + r && y >= top - r && y <= bot + r;\n }\n // e.g. 'small'\n return (y >= top - r && y <= bot + r) &&\n ((x >= lft - r && x <= lft + 2 * r) ||\n (x >= rt - 2 * r && x <= rt + r));\n },\n\n /**\n * This sets the updateText function of this element depending on the type of text content passed.\n * Used by {@link JXG.Text#_setText} and {@link JXG.Text} constructor.\n * @param {String|Function|Number} text\n * @private\n */\n _createFctUpdateText: function (text) {\n var updateText, resolvedText,\n ev_p = Type.evaluate(this.visProp.parse),\n ev_um = Type.evaluate(this.visProp.usemathjax),\n ev_uk = Type.evaluate(this.visProp.usekatex);\n\n this.orgText = text;\n if (Type.isFunction(text)) {\n this.updateText = function () {\n resolvedText = text().toString();\n if (ev_p && !ev_um && !ev_uk) {\n this.plaintext = this.replaceSub(this.replaceSup(this.convertGeonextAndSketchometry2CSS(resolvedText)));\n } else {\n this.plaintext = resolvedText;\n }\n };\n } else if (Type.isString(text) && !ev_p) { // Do not parse\n this.updateText = function () {\n this.plaintext = text;\n };\n } else { // Parse\n if (Type.isNumber(text)) {\n this.content = Type.toFixed(text, Type.evaluate(this.visProp.digits));\n } else {\n if (Type.evaluate(this.visProp.useasciimathml)) {\n // Convert via ASCIIMathML\n this.content = \"'`\" + text + \"`'\";\n } else if (ev_um || ev_uk) {\n this.content = \"'\" + text + \"'\";\n } else {\n // Converts GEONExT syntax into JavaScript string\n // Short math is allowed\n // Avoid geonext2JS calls\n this.content = this.generateTerm(text, true, true);\n }\n }\n updateText = this.board.jc.snippet(this.content, true, '', false);\n this.updateText = function () {\n this.plaintext = updateText();\n };\n }\n },\n\n /**\n * Defines new content. This is used by {@link JXG.Text#setTextJessieCode} and {@link JXG.Text#setText}. This is required because\n * JessieCode needs to filter all Texts inserted into the DOM and thus has to replace setText by setTextJessieCode.\n * @param {String|Function|Number} text\n * @returns {JXG.Text}\n * @private\n */\n _setText: function (text) {\n this._createFctUpdateText(text);\n\n // First evaluation of the string.\n // We need this for display='internal' and Canvas\n this.updateText();\n this.fullUpdate();\n\n // We do not call updateSize for the infobox to speed up rendering\n if (!this.board.infobox || this.id !== this.board.infobox.id) {\n this.updateSize(); // updateSize() is called at least once.\n }\n\n // This may slow down canvas renderer\n // if (this.board.renderer.type === 'canvas') {\n // this.board.fullUpdate();\n // }\n\n return this;\n },\n\n /**\n * Defines new content but converts < and > to HTML entities before updating the DOM.\n * @param {String|function} text\n */\n setTextJessieCode: function (text) {\n var s;\n\n this.visProp.castext = text;\n if (Type.isFunction(text)) {\n s = function () {\n return Type.sanitizeHTML(text());\n };\n } else {\n if (Type.isNumber(text)) {\n s = text;\n } else {\n s = Type.sanitizeHTML(text);\n }\n }\n\n return this._setText(s);\n },\n\n /**\n * Defines new content.\n * @param {String|function} text\n * @returns {JXG.Text} Reference to the text object.\n */\n setText: function (text) {\n return this._setText(text);\n },\n\n /**\n * Recompute the width and the height of the text box.\n * Updates the array {@link JXG.Text#size} with pixel values.\n * The result may differ from browser to browser\n * by some pixels.\n * In canvas an old IEs we use a very crude estimation of the dimensions of\n * the textbox.\n * JSXGraph needs {@link JXG.Text#size} for applying rotations in IE and\n * for aligning text.\n *\n * @return {[type]} [description]\n */\n updateSize: function () {\n var tmp, that, node,\n ev_d = Type.evaluate(this.visProp.display);\n\n if (!Env.isBrowser || this.board.renderer.type === 'no') {\n return this;\n }\n node = this.rendNode;\n\n /**\n * offsetWidth and offsetHeight seem to be supported for internal vml elements by IE10+ in IE8 mode.\n */\n if (ev_d === 'html' || this.board.renderer.type === 'vml') {\n if (Type.exists(node.offsetWidth)) {\n that = this;\n window.setTimeout(function () {\n that.size = [node.offsetWidth, node.offsetHeight];\n that.needsUpdate = true;\n that.updateRenderer();\n }, 0);\n // In case, there is non-zero padding or borders\n // the following approach does not longer work.\n // s = [node.offsetWidth, node.offsetHeight];\n // if (s[0] === 0 && s[1] === 0) { // Some browsers need some time to set offsetWidth and offsetHeight\n // that = this;\n // window.setTimeout(function () {\n // that.size = [node.offsetWidth, node.offsetHeight];\n // that.needsUpdate = true;\n // that.updateRenderer();\n // }, 0);\n // } else {\n // this.size = s;\n // }\n } else {\n this.size = this.crudeSizeEstimate();\n }\n } else if (ev_d === 'internal') {\n if (this.board.renderer.type === 'svg') {\n that = this;\n window.setTimeout(function () {\n try {\n tmp = node.getBBox();\n that.size = [tmp.width, tmp.height];\n that.needsUpdate = true;\n that.updateRenderer();\n } catch (e) {\n }\n }, 0);\n } else if (this.board.renderer.type === 'canvas') {\n this.size = this.crudeSizeEstimate();\n }\n }\n\n return this;\n },\n\n /**\n * A very crude estimation of the dimensions of the textbox in case nothing else is available.\n * @returns {Array}\n */\n crudeSizeEstimate: function () {\n var ev_fs = parseFloat(Type.evaluate(this.visProp.fontsize));\n return [ev_fs * this.plaintext.length * 0.45, ev_fs * 0.9];\n },\n\n /**\n * Decode unicode entities into characters.\n * @param {String} string\n * @returns {String}\n */\n utf8_decode: function (string) {\n return string.replace(/&#x(\\w+);/g, function (m, p1) {\n return String.fromCharCode(parseInt(p1, 16));\n });\n },\n\n /**\n * Replace _{} by <sub>\n * @param {String} te String containing _{}.\n * @returns {String} Given string with _{} replaced by <sub>.\n */\n replaceSub: function (te) {\n if (!te.indexOf) {\n return te;\n }\n\n var j,\n i = te.indexOf('_{');\n\n // the regexp in here are not used for filtering but to provide some kind of sugar for label creation,\n // i.e. replacing _{...} with <sub>...</sub>. What is passed would get out anyway.\n /*jslint regexp: true*/\n\n while (i >= 0) {\n te = te.substr(0, i) + te.substr(i).replace(/_\\{/, '<sub>');\n j = te.substr(i).indexOf('}');\n if (j >= 0) {\n te = te.substr(0, j) + te.substr(j).replace(/\\}/, '</sub>');\n }\n i = te.indexOf('_{');\n }\n\n i = te.indexOf('_');\n while (i >= 0) {\n te = te.substr(0, i) + te.substr(i).replace(/_(.?)/, '<sub>$1</sub>');\n i = te.indexOf('_');\n }\n\n return te;\n },\n\n /**\n * Replace ^{} by <sup>\n * @param {String} te String containing ^{}.\n * @returns {String} Given string with ^{} replaced by <sup>.\n */\n replaceSup: function (te) {\n if (!te.indexOf) {\n return te;\n }\n\n var j,\n i = te.indexOf('^{');\n\n // the regexp in here are not used for filtering but to provide some kind of sugar for label creation,\n // i.e. replacing ^{...} with <sup>...</sup>. What is passed would get out anyway.\n /*jslint regexp: true*/\n\n while (i >= 0) {\n te = te.substr(0, i) + te.substr(i).replace(/\\^\\{/, '<sup>');\n j = te.substr(i).indexOf('}');\n if (j >= 0) {\n te = te.substr(0, j) + te.substr(j).replace(/\\}/, '</sup>');\n }\n i = te.indexOf('^{');\n }\n\n i = te.indexOf('^');\n while (i >= 0) {\n te = te.substr(0, i) + te.substr(i).replace(/\\^(.?)/, '<sup>$1</sup>');\n i = te.indexOf('^');\n }\n\n return te;\n },\n\n /**\n * Return the width of the text element.\n * @returns {Array} [width, height] in pixel\n */\n getSize: function () {\n return this.size;\n },\n\n /**\n * Move the text to new coordinates.\n * @param {number} x\n * @param {number} y\n * @returns {object} reference to the text object.\n */\n setCoords: function (x, y) {\n var coordsAnchor, dx, dy;\n if (Type.isArray(x) && x.length > 1) {\n y = x[1];\n x = x[0];\n }\n\n if (Type.evaluate(this.visProp.islabel) && Type.exists(this.element)) {\n coordsAnchor = this.element.getLabelAnchor();\n dx = (x - coordsAnchor.usrCoords[1]) * this.board.unitX;\n dy = -(y - coordsAnchor.usrCoords[2]) * this.board.unitY;\n\n this.relativeCoords.setCoordinates(Const.COORDS_BY_SCREEN, [dx, dy]);\n } else {\n /*\n this.X = function () {\n return x;\n };\n\n this.Y = function () {\n return y;\n };\n */\n this.coords.setCoordinates(Const.COORDS_BY_USER, [x, y]);\n }\n\n // this should be a local update, otherwise there might be problems\n // with the tick update routine resulting in orphaned tick labels\n this.fullUpdate();\n\n return this;\n },\n\n /**\n * Evaluates the text.\n * Then, the update function of the renderer\n * is called.\n */\n update: function (fromParent) {\n if (!this.needsUpdate) {\n return this;\n }\n\n this.updateCoords(fromParent);\n this.updateText();\n\n if (Type.evaluate(this.visProp.display) === 'internal') {\n if (Type.isString(this.plaintext)) {\n this.plaintext = this.utf8_decode(this.plaintext);\n }\n }\n\n this.checkForSizeUpdate();\n if (this.needsSizeUpdate) {\n this.updateSize();\n }\n\n return this;\n },\n\n /**\n * Used to save updateSize() calls.\n * Called in JXG.Text.update\n * That means this.update() has been called.\n * More tests are in JXG.Renderer.updateTextStyle. The latter tests\n * are one update off. But this should pose not too many problems, since\n * it affects fontSize and cssClass changes.\n *\n * @private\n */\n checkForSizeUpdate: function () {\n if (this.board.infobox && this.id === this.board.infobox.id) {\n this.needsSizeUpdate = false;\n } else {\n // For some magic reason it is more efficient on the iPad to\n // call updateSize() for EVERY text element EVERY time.\n this.needsSizeUpdate = (this.plaintextOld !== this.plaintext);\n\n if (this.needsSizeUpdate) {\n this.plaintextOld = this.plaintext;\n }\n }\n\n },\n\n /**\n * The update function of the renderert\n * is called.\n * @private\n */\n updateRenderer: function () {\n if (//this.board.updateQuality === this.board.BOARD_QUALITY_HIGH &&\n Type.evaluate(this.visProp.autoposition)) {\n\n this.setAutoPosition()\n .updateConstraint();\n }\n return this.updateRendererGeneric('updateText');\n },\n\n /**\n * Converts shortened math syntax into correct syntax: 3x instead of 3*x or\n * (a+b)(3+1) instead of (a+b)*(3+1).\n *\n * @private\n * @param{String} expr Math term\n * @returns {string} expanded String\n */\n expandShortMath: function (expr) {\n var re = /([)0-9.])\\s*([(a-zA-Z_])/g;\n return expr.replace(re, '$1*$2');\n },\n\n /**\n * Converts the GEONExT syntax of the <value> terms into JavaScript.\n * Also, all Objects whose name appears in the term are searched and\n * the text is added as child to these objects.\n *\n * @param{String} contentStr String to be parsed\n * @param{Boolean} [expand] Optional flag if shortened math syntax is allowed (e.g. 3x instead of 3*x).\n * @param{Boolean} [avoidGeonext2JS] Optional flag if geonext2JS should be called. For backwards compatibility\n * this has to be set explicitely to true.\n * @private\n * @see JXG.GeonextParser.geonext2JS\n */\n generateTerm: function (contentStr, expand, avoidGeonext2JS) {\n var res, term, i, j,\n plaintext = '\"\"';\n\n // revert possible jc replacement\n contentStr = contentStr || '';\n contentStr = contentStr.replace(/\\r/g, '');\n contentStr = contentStr.replace(/\\n/g, '');\n contentStr = contentStr.replace(/\"/g, '\\'');\n contentStr = contentStr.replace(/'/g, \"\\\\'\");\n\n contentStr = contentStr.replace(/&arc;/g, '∠');\n contentStr = contentStr.replace(/<arc\\s*\\/>/g, '∠');\n contentStr = contentStr.replace(/<arc\\s*\\/>/g, '∠');\n contentStr = contentStr.replace(/<sqrt\\s*\\/>/g, '√');\n\n contentStr = contentStr.replace(/<value>/g, '<value>');\n contentStr = contentStr.replace(/<\\/value>/g, '</value>');\n\n // Convert GEONExT syntax into JavaScript syntax\n i = contentStr.indexOf('<value>');\n j = contentStr.indexOf('</value>');\n if (i >= 0) {\n while (i >= 0) {\n plaintext += ' + \"' + this.replaceSub(this.replaceSup(contentStr.slice(0, i))) + '\"';\n term = contentStr.slice(i + 7, j);\n term = term.replace(/\\s+/g, ''); // Remove all whitespace\n if (expand === true) {\n term = this.expandShortMath(term);\n }\n if (avoidGeonext2JS) {\n res = term;\n } else {\n res = GeonextParser.geonext2JS(term, this.board);\n }\n res = res.replace(/\\\\\"/g, \"'\");\n res = res.replace(/\\\\'/g, \"'\");\n\n // GEONExT-Hack: apply rounding once only.\n if (res.indexOf('toFixed') < 0) {\n // output of a value tag\n if (Type.isNumber((Type.bind(this.board.jc.snippet(res, true, '', false), this))())) {\n // may also be a string\n plaintext += '+(' + res + ').toFixed(' + (Type.evaluate(this.visProp.digits)) + ')';\n } else {\n plaintext += '+(' + res + ')';\n }\n } else {\n plaintext += '+(' + res + ')';\n }\n\n contentStr = contentStr.slice(j + 8);\n i = contentStr.indexOf('<value>');\n j = contentStr.indexOf('</value>');\n }\n }\n\n plaintext += ' + \"' + this.replaceSub(this.replaceSup(contentStr)) + '\"';\n plaintext = this.convertGeonextAndSketchometry2CSS(plaintext);\n\n // This should replace &pi; by π\n plaintext = plaintext.replace(/&/g, '&');\n plaintext = plaintext.replace(/\"/g, \"'\");\n\n return plaintext;\n },\n\n /**\n * Converts the GEONExT tags <overline> and <arrow> to\n * HTML span tags with proper CSS formatting.\n * @private\n * @see JXG.Text.generateTerm\n * @see JXG.Text._setText\n */\n convertGeonext2CSS: function (s) {\n if (Type.isString(s)) {\n s = s.replace(\n /(<|<)overline(>|>)/g,\n '<span style=text-decoration:overline;>'\n );\n s = s.replace(\n /(<|<)\\/overline(>|>)/g,\n '</span>'\n );\n s = s.replace(\n /(<|<)arrow(>|>)/g,\n '<span style=text-decoration:overline;>'\n );\n s = s.replace(\n /(<|<)\\/arrow(>|>)/g,\n '</span>'\n );\n }\n\n return s;\n },\n\n /**\n * Converts the sketchometry tag <sketchofont> to\n * HTML span tags with proper CSS formatting.\n * @private\n * @see JXG.Text.generateTerm\n * @see JXG.Text._setText\n */\n convertSketchometry2CSS: function (s) {\n if (Type.isString(s)) {\n s = s.replace(\n /(<|<)sketchofont(>|>)/g,\n '<span style=font-family:sketchometry-light;font-weight:500;>'\n );\n s = s.replace(\n /(<|<)\\/sketchofont(>|>)/g,\n '</span>'\n );\n s = s.replace(\n /(<|<)sketchometry-light(>|>)/g,\n '<span style=font-family:sketchometry-light;font-weight:500;>'\n );\n s = s.replace(\n /(<|<)\\/sketchometry-light(>|>)/g,\n '</span>'\n );\n }\n\n return s;\n },\n\n /**\n * Alias for convertGeonext2CSS and convertSketchometry2CSS\n * @private\n * @see JXG.Text.convertGeonext2CSS\n * @see JXG.Text.convertSketchometry2CSS\n */\n convertGeonextAndSketchometry2CSS: function (s){\n s = this.convertGeonext2CSS(s);\n s = this.convertSketchometry2CSS(s);\n return s;\n },\n\n /**\n * Finds dependencies in a given term and notifies the parents by adding the\n * dependent object to the found objects child elements.\n * @param {String} content String containing dependencies for the given object.\n * @private\n */\n notifyParents: function (content) {\n var search,\n res = null;\n\n // revert possible jc replacement\n content = content.replace(/<value>/g, '<value>');\n content = content.replace(/<\\/value>/g, '</value>');\n\n do {\n search = /<value>([\\w\\s*/^\\-+()[\\],<>=!]+)<\\/value>/;\n res = search.exec(content);\n\n if (res !== null) {\n GeonextParser.findDependencies(this, res[1], this.board);\n content = content.substr(res.index);\n content = content.replace(search, '');\n }\n } while (res !== null);\n\n return this;\n },\n\n // documented in element.js\n getParents: function () {\n var p;\n if (this.relativeCoords !== undefined) { // Texts with anchor elements, excluding labels\n p = [this.relativeCoords.usrCoords[1], this.relativeCoords.usrCoords[2], this.orgText];\n } else { // Other texts\n p = [this.Z(), this.X(), this.Y(), this.orgText];\n }\n\n if (this.parents.length !== 0) {\n p = this.parents;\n }\n\n return p;\n },\n\n bounds: function () {\n var c = this.coords.usrCoords;\n\n if (Type.evaluate(this.visProp.islabel) || this.board.unitY === 0 || this.board.unitX === 0) {\n return [0, 0, 0, 0];\n }\n return [c[1], c[2] + this.size[1] / this.board.unitY, c[1] + this.size[0] / this.board.unitX, c[2]];\n },\n\n getAnchorX: function () {\n var a = Type.evaluate(this.visProp.anchorx);\n if (a === 'auto') {\n switch (this.visProp.position) {\n case 'top':\n case 'bot':\n return 'middle';\n case 'rt':\n case 'lrt':\n case 'urt':\n return 'left';\n case 'lft':\n case 'llft':\n case 'ulft':\n default:\n return 'right';\n }\n }\n return a;\n },\n\n getAnchorY: function () {\n var a = Type.evaluate(this.visProp.anchory);\n if (a === 'auto') {\n switch (this.visProp.position) {\n case 'top':\n case 'ulft':\n case 'urt':\n return 'bottom';\n case 'bot':\n case 'lrt':\n case 'llft':\n return 'top';\n case 'rt':\n case 'lft':\n default:\n return 'middle';\n }\n }\n return a;\n },\n\n /**\n * Computes the number of overlaps of a box of w pixels width, h pixels height\n * and center (x, y)\n *\n * @private\n * @param {Number} x x-coordinate of the center (screen coordinates)\n * @param {Number} y y-coordinate of the center (screen coordinates)\n * @param {Number} w width of the box in pixel\n * @param {Number} h width of the box in pixel\n * @return {Number} Number of overlapping elements\n */\n getNumberofConflicts: function (x, y, w, h) {\n var count = 0,\n i, obj, le,\n savePointPrecision;\n\n // Set the precision of hasPoint to half the max if label isn't too long\n savePointPrecision = this.board.options.precision.hasPoint;\n // this.board.options.precision.hasPoint = Math.max(w, h) * 0.5;\n this.board.options.precision.hasPoint = (w + h) * 0.25;\n // TODO:\n // Make it compatible with the objects' visProp.precision attribute\n for (i = 0, le = this.board.objectsList.length; i < le; i++) {\n obj = this.board.objectsList[i];\n if (obj.visPropCalc.visible &&\n obj.elType !== 'axis' &&\n obj.elType !== 'ticks' &&\n obj !== this.board.infobox &&\n obj !== this &&\n obj.hasPoint(x, y)) {\n\n count++;\n }\n }\n this.board.options.precision.hasPoint = savePointPrecision;\n\n return count;\n },\n\n /**\n * Sets the offset of a label element to the position with the least number\n * of overlaps with other elements, while retaining the distance to its\n * anchor element. Twelve different angles are possible.\n *\n * @returns {JXG.Text} Reference to the text object.\n */\n setAutoPosition: function () {\n var x, y, cx, cy,\n anchorCoords,\n // anchorX, anchorY,\n w = this.size[0],\n h = this.size[1],\n start_angle, angle,\n optimum = {\n conflicts: Infinity,\n angle: 0,\n r: 0\n },\n max_r, delta_r,\n conflicts, offset, r,\n num_positions = 12,\n step = 2 * Math.PI / num_positions,\n j, dx, dy, co, si;\n\n if (this === this.board.infobox ||\n !this.visPropCalc.visible ||\n !Type.evaluate(this.visProp.islabel) ||\n !this.element) {\n return this;\n }\n\n // anchorX = Type.evaluate(this.visProp.anchorx);\n // anchorY = Type.evaluate(this.visProp.anchory);\n offset = Type.evaluate(this.visProp.offset);\n anchorCoords = this.element.getLabelAnchor();\n cx = anchorCoords.scrCoords[1];\n cy = anchorCoords.scrCoords[2];\n\n // Set dx, dy as the relative position of the center of the label\n // to its anchor element ignoring anchorx and anchory.\n dx = offset[0];\n dy = offset[1];\n\n conflicts = this.getNumberofConflicts(cx + dx, cy - dy, w, h);\n if (conflicts === 0) {\n return this;\n }\n // console.log(this.id, conflicts, w, h);\n // r = Geometry.distance([0, 0], offset, 2);\n\n r = 12;\n max_r = 28;\n delta_r = 0.2 * r;\n\n start_angle = Math.atan2(dy, dx);\n\n optimum.conflicts = conflicts;\n optimum.angle = start_angle;\n optimum.r = r;\n\n while (optimum.conflicts > 0 && r < max_r) {\n for (j = 1, angle = start_angle + step; j < num_positions && optimum.conflicts > 0; j++) {\n co = Math.cos(angle);\n si = Math.sin(angle);\n\n x = cx + r * co;\n y = cy - r * si;\n\n conflicts = this.getNumberofConflicts(x, y, w, h);\n if (conflicts < optimum.conflicts) {\n optimum.conflicts = conflicts;\n optimum.angle = angle;\n optimum.r = r;\n }\n if (optimum.conflicts === 0) {\n break;\n }\n angle += step;\n }\n r += delta_r;\n }\n // console.log(this.id, \"after\", optimum)\n r = optimum.r;\n co = Math.cos(optimum.angle);\n si = Math.sin(optimum.angle);\n this.visProp.offset = [r * co, r * si];\n\n if (co < -0.2) {\n this.visProp.anchorx = 'right';\n } else if (co > 0.2) {\n this.visProp.anchorx = 'left';\n } else {\n this.visProp.anchorx = 'middle';\n }\n\n return this;\n }\n });\n\n /**\n * @class Construct and handle texts.\n *\n * The coordinates can be relative to the coordinates of an element\n * given in {@link JXG.Options#text.anchor}.\n *\n * MathJaX, HTML and GEONExT syntax can be handled.\n * @pseudo\n * @description\n * @name Text\n * @augments JXG.Text\n * @constructor\n * @type JXG.Text\n *\n * @param {number,function_number,function_number,function_String,function} z_,x,y,str Parent elements for text elements.\n * <p>\n * Parent elements can be two or three elements of type number, a string containing a GEONE<sub>x</sub>T\n * constraint, or a function which takes no parameter and returns a number. Every parent element determines one coordinate. If a coordinate is\n * given by a number, the number determines the initial position of a free text. If given by a string or a function that coordinate will be constrained\n * that means the user won't be able to change the texts's position directly by mouse because it will be calculated automatically depending on the string\n * or the function's return value. If two parent elements are given the coordinates will be interpreted as 2D affine Euclidean coordinates, if three such\n * parent elements are given they will be interpreted as homogeneous coordinates.\n * <p>\n * The text to display may be given as string or as function returning a string.\n *\n * There is the attribute 'display' which takes the values 'html' or 'internal'. In case of 'html' a HTML division tag is created to display\n * the text. In this case it is also possible to use ASCIIMathML. Incase of 'internal', a SVG or VML text element is used to display the text.\n * @see JXG.Text\n * @example\n * // Create a fixed text at position [0,1].\n * var t1 = board.create('text',[0,1,\"Hello World\"]);\n * </pre><div class=\"jxgbox\" id=\"JXG896013aa-f24e-4e83-ad50-7bc7df23f6b7\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * var t1_board = JXG.JSXGraph.initBoard('JXG896013aa-f24e-4e83-ad50-7bc7df23f6b7', {boundingbox: [-3, 6, 5, -3], axis: true, showcopyright: false, shownavigation: false});\n * var t1 = t1_board.create('text',[0,1,\"Hello World\"]);\n * </script><pre>\n * @example\n * // Create a variable text at a variable position.\n * var s = board.create('slider',[[0,4],[3,4],[-2,0,2]]);\n * var graph = board.create('text',\n * [function(x){ return s.Value();}, 1,\n * function(){return \"The value of s is\"+JXG.toFixed(s.Value(), 2);}\n * ]\n * );\n * </pre><div class=\"jxgbox\" id=\"JXG5441da79-a48d-48e8-9e53-75594c384a1c\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * var t2_board = JXG.JSXGraph.initBoard('JXG5441da79-a48d-48e8-9e53-75594c384a1c', {boundingbox: [-3, 6, 5, -3], axis: true, showcopyright: false, shownavigation: false});\n * var s = t2_board.create('slider',[[0,4],[3,4],[-2,0,2]]);\n * var t2 = t2_board.create('text',[function(x){ return s.Value();}, 1, function(){return \"The value of s is \"+JXG.toFixed(s.Value(), 2);}]);\n * </script><pre>\n * @example\n * // Create a text bound to the point A\n * var p = board.create('point',[0, 1]),\n * t = board.create('text',[0, -1,\"Hello World\"], {anchor: p});\n *\n * </pre><div class=\"jxgbox\" id=\"JXGff5a64b2-2b9a-11e5-8dd9-901b0e1b8723\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXGff5a64b2-2b9a-11e5-8dd9-901b0e1b8723',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var p = board.create('point',[0, 1]),\n * t = board.create('text',[0, -1,\"Hello World\"], {anchor: p});\n *\n * })();\n *\n * </script><pre>\n *\n */\n JXG.createText = function (board, parents, attributes) {\n var t,\n attr = Type.copyAttributes(attributes, board.options, 'text'),\n coords = parents.slice(0, -1),\n content = parents[parents.length - 1];\n\n // downwards compatibility\n attr.anchor = attr.parent || attr.anchor;\n t = CoordsElement.create(JXG.Text, board, coords, attr, content);\n\n if (!t) {\n throw new Error(\"JSXGraph: Can't create text with parent types '\" +\n (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"'.\" +\n \"\\nPossible parent types: [x,y], [z,x,y], [element,transformation]\");\n }\n\n if (attr.rotate !== 0 && attr.display === 'internal') { // This is the default value, i.e. no rotation\n t.addRotation(attr.rotate);\n }\n\n return t;\n };\n\n JXG.registerElement('text', JXG.createText);\n\n /**\n * @class Labels are text objects tied to other elements like points, lines and curves.\n * Labels are handled internally by JSXGraph, only. There is NO constructor \"board.create('label', ...)\".\n *\n * @pseudo\n * @description\n * @name Label\n * @augments JXG.Text\n * @constructor\n * @type JXG.Text\n */\n // See element.js#createLabel\n\n /**\n * [[x,y], [w px, h px], [range]\n */\n JXG.createHTMLSlider = function (board, parents, attributes) {\n var t, par,\n attr = Type.copyAttributes(attributes, board.options, 'htmlslider');\n\n if (parents.length !== 2 || parents[0].length !== 2 || parents[1].length !== 3) {\n throw new Error(\"JSXGraph: Can't create htmlslider with parent types '\" +\n (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"'.\" +\n \"\\nPossible parents are: [[x,y], [min, start, max]]\");\n }\n\n // backwards compatibility\n attr.anchor = attr.parent || attr.anchor;\n attr.fixed = attr.fixed || true;\n\n par = [parents[0][0], parents[0][1],\n '<form style=\"display:inline\">' +\n '<input type=\"range\" /><span></span><input type=\"text\" />' +\n '</form>'];\n\n t = JXG.createText(board, par, attr);\n t.type = Type.OBJECT_TYPE_HTMLSLIDER;\n\n t.rendNodeForm = t.rendNode.childNodes[0];\n\n t.rendNodeRange = t.rendNodeForm.childNodes[0];\n t.rendNodeRange.min = parents[1][0];\n t.rendNodeRange.max = parents[1][2];\n t.rendNodeRange.step = attr.step;\n t.rendNodeRange.value = parents[1][1];\n\n t.rendNodeLabel = t.rendNodeForm.childNodes[1];\n t.rendNodeLabel.id = t.rendNode.id + '_label';\n\n if (attr.withlabel) {\n t.rendNodeLabel.innerHTML = t.name + '=';\n }\n\n t.rendNodeOut = t.rendNodeForm.childNodes[2];\n t.rendNodeOut.value = parents[1][1];\n\n try {\n t.rendNodeForm.id = t.rendNode.id + '_form';\n t.rendNodeRange.id = t.rendNode.id + '_range';\n t.rendNodeOut.id = t.rendNode.id + '_out';\n } catch (e) {\n JXG.debug(e);\n }\n\n t.rendNodeRange.style.width = attr.widthrange + 'px';\n t.rendNodeRange.style.verticalAlign = 'middle';\n t.rendNodeOut.style.width = attr.widthout + 'px';\n\n t._val = parents[1][1];\n\n if (JXG.supportsVML()) {\n /*\n * OnChange event is used for IE browsers\n * The range element is supported since IE10\n */\n Env.addEvent(t.rendNodeForm, 'change', priv.HTMLSliderInputEventHandler, t);\n } else {\n /*\n * OnInput event is used for non-IE browsers\n */\n Env.addEvent(t.rendNodeForm, 'input', priv.HTMLSliderInputEventHandler, t);\n }\n\n t.Value = function () {\n return this._val;\n };\n\n return t;\n };\n\n JXG.registerElement('htmlslider', JXG.createHTMLSlider);\n\n return {\n Text: JXG.Text,\n createText: JXG.createText,\n createHTMLSlider: JXG.createHTMLSlider\n };\n});\n\n/**\n * Generate a random uuid.\n * Written by http://www.broofa.com (robert@broofa.com)\n *\n * Copyright (c) 2010 Robert Kieffer\n * Dual licensed under the MIT and GPL licenses.\n * @returns {String}\n * @example\n * var uuid = JXG.Util.genUUID();\n * > uuid = '92329D39-6F5C-4520-ABFC-AAB64544E172'\n */\n\n/*global JXG: true, define: true*/\n/*jslint nomen: true, plusplus: true, bitwise: true*/\n\n/* depends:\n jxg\n */\n\ndefine('utils/uuid',['jxg'], function (JXG) {\n\n 'use strict';\n\n // constants\n var uuidCharsStr = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',\n uuidChars = uuidCharsStr.split('');\n\n /**\n * General utility routines\n * @namespace\n */\n JXG.Util = JXG.Util || {};\n\n JXG.Util.genUUID = function (prefix) {\n var r, i,\n uuid = [],\n rnd = 0;\n\n prefix = prefix || '';\n\n if (prefix !== '' && prefix.substr(prefix.length - 1) !== '-') {\n prefix = prefix + '-';\n }\n\n for (i = 0; i < 36; i++) {\n if (i === 8 || i === 13 || i === 18 || i === 23) {\n uuid[i] = '-';\n } else if (i === 14) {\n uuid[i] = '4';\n } else {\n if (rnd <= 0x02) {\n rnd = 0x2000000 + (Math.random() * 0x1000000) | 0;\n }\n\n r = rnd & 0xf;\n rnd = rnd >> 4;\n uuid[i] = uuidChars[(i === 19) ? (r & 0x3) | 0x8 : r];\n }\n }\n\n return prefix + uuid.join('');\n };\n\n return JXG.Util;\n});\n/*\n JessieCode Interpreter and Compiler\n\n Copyright 2011-2019\n Michael Gerhaeuser,\n Alfred Wassermann\n\n JessieCode is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JessieCode is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JessieCode. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n/*global JXG: true, define: true, window: true, console: true, self: true, document: true, parser: true*/\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n jxg\n parser/geonext\n base/constants\n base/text\n math/math\n math/geometry\n math/statistics\n utils/type\n utils/uuid\n */\n\n/**\n * @fileoverview JessieCode is a scripting language designed to provide a\n * simple scripting language to build constructions\n * with JSXGraph. It is similar to JavaScript, but prevents access to the DOM.\n * Hence, it can be used in community driven math portals which want to use\n * JSXGraph to display interactive math graphics.\n */\n\ndefine('parser/jessiecode',[\n 'jxg', 'base/constants', 'base/text', 'math/math', 'math/ia', 'math/geometry', 'math/statistics', 'utils/type', 'utils/uuid', 'utils/env'\n], function (JXG, Const, Text, Mat, Interval, Geometry, Statistics, Type, UUID, Env) {\n\n ;\n\n // IE 6-8 compatibility\n if (!Object.create) {\n Object.create = function(o, properties) {\n if (typeof o !== 'object' && typeof o !== 'function') throw new TypeError('Object prototype may only be an Object: ' + o);\n else if (o === null) throw new Error(\"This browser's implementation of Object.create is a shim and doesn't support 'null' as the first argument.\");\n\n if (typeof properties != 'undefined') throw new Error(\"This browser's implementation of Object.create is a shim and doesn't support a second argument.\");\n\n function F() {}\n\n F.prototype = o;\n\n return new F();\n };\n }\n\n var priv = {\n modules: {\n 'math': Mat,\n 'math/geometry': Geometry,\n 'math/statistics': Statistics,\n 'math/numerics': Mat.Numerics\n }\n };\n\n /**\n * A JessieCode object provides an interface to the parser and stores all variables and objects used within a JessieCode script.\n * The optional argument <tt>code</tt> is interpreted after initializing. To evaluate more code after initializing a JessieCode instance\n * please use {@link JXG.JessieCode#parse}. For code snippets like single expressions use {@link JXG.JessieCode#snippet}.\n * @constructor\n * @param {String} [code] Code to parse.\n * @param {Boolean} [geonext=false] Geonext compatibility mode.\n */\n JXG.JessieCode = function (code, geonext) {\n // Control structures\n\n /**\n * The global scope.\n * @type Object\n */\n this.scope = {\n id: 0,\n hasChild: true,\n args: [],\n locals: {},\n context: null,\n previous: null\n };\n\n /**\n * Keeps track of all possible scopes every required.\n * @type Array\n */\n this.scopes = [];\n this.scopes.push(this.scope);\n\n /**\n * A stack to store debug information (like line and column where it was defined) of a parameter\n * @type Array\n * @private\n */\n this.dpstack = [[]];\n\n /**\n * Determines the parameter stack scope.\n * @type Number\n * @private\n */\n this.pscope = 0;\n\n /**\n * Used to store the property-value definition while parsing an object literal.\n * @type Array\n * @private\n */\n this.propstack = [{}];\n\n /**\n * The current scope of the object literal stack {@link JXG.JessieCode#propstack}.\n * @type Number\n * @private\n */\n this.propscope = 0;\n\n /**\n * Store the left hand side of an assignment. If an element is constructed and no attributes are given, this is\n * used as the element's name.\n * @type Array\n * @private\n */\n this.lhs = [];\n\n /**\n * lhs flag, used by JXG.JessieCode#replaceNames\n * @type Boolean\n * @default false\n */\n this.isLHS = false;\n\n /**\n * The id of an HTML node in which innerHTML all warnings are stored (if no <tt>console</tt> object is available).\n * @type String\n * @default 'jcwarn'\n */\n this.warnLog = 'jcwarn';\n\n /**\n * Store $log messages in case there's no console.\n * @type Array\n */\n this.$log = [];\n\n /**\n * Built-in functions and constants\n * @type Object\n */\n this.builtIn = this.defineBuiltIn();\n\n /**\n * List of all possible operands in JessieCode (except of JSXGraph objects).\n * @type Object\n */\n this.operands = this.getPossibleOperands();\n\n /**\n * The board which currently is used to create and look up elements.\n * @type JXG.Board\n */\n this.board = null;\n\n /**\n * Keep track of which element is created in which line.\n * @type Object\n */\n this.lineToElement = {};\n\n this.parCurLine = 1;\n this.parCurColumn = 0;\n this.line = 1;\n this.col = 1;\n\n if (JXG.CA) {\n this.CA = new JXG.CA(this.node, this.createNode, this);\n }\n\n this.code = '';\n\n if (typeof code === 'string') {\n this.parse(code, geonext);\n }\n };\n\n JXG.extend(JXG.JessieCode.prototype, /** @lends JXG.JessieCode.prototype */ {\n /**\n * Create a new parse tree node.\n * @param {String} type Type of node, e.g. node_op, node_var, or node_const\n * @param value The nodes value, e.g. a variables value or a functions body.\n * @param {Array} children Arbitrary number of child nodes.\n */\n node: function (type, value, children) {\n return {\n type: type,\n value: value,\n children: children\n };\n },\n\n /**\n * Create a new parse tree node. Basically the same as node(), but this builds\n * the children part out of an arbitrary number of parameters, instead of one\n * array parameter.\n * @param {String} type Type of node, e.g. node_op, node_var, or node_const\n * @param value The nodes value, e.g. a variables value or a functions body.\n * @param children Arbitrary number of parameters; define the child nodes.\n */\n createNode: function (type, value, children) {\n var n = this.node(type, value, []),\n i;\n\n for (i = 2; i < arguments.length; i++) {\n n.children.push(arguments[i]);\n }\n\n if (n.type == 'node_const' && Type.isNumber(n.value)) {\n n.isMath = true;\n }\n\n n.line = this.parCurLine;\n n.col = this.parCurColumn;\n\n return n;\n },\n\n /**\n * Create a new scope.\n * @param {Array} args\n * @returns {Object}\n */\n pushScope: function (args) {\n var scope = {\n args: args,\n locals: {},\n context: null,\n previous: this.scope\n };\n\n this.scope.hasChild = true;\n this.scope = scope;\n scope.id = this.scopes.push(scope) - 1;\n\n return scope;\n },\n\n /**\n * Remove the current scope and reinstate the previous scope\n * @returns {Object}\n */\n popScope: function () {\n var s = this.scope.previous;\n\n // make sure the global scope is not lost\n this.scope = s !== null ? s : this.scope;\n\n return this.scope;\n },\n\n /**\n * Looks up an {@link JXG.GeometryElement} by its id.\n * @param {String} id\n * @returns {JXG.GeometryElement}\n */\n getElementById: function (id) {\n return this.board.objects[id];\n },\n\n log: function () {\n this.$log.push(arguments);\n\n if (typeof console === 'object' && console.log) {\n console.log.apply(console, arguments);\n }\n },\n\n /**\n * Returns a element creator function which takes two parameters: the parents array and the attributes object.\n * @param {String} vname The element type, e.g. 'point', 'line', 'midpoint'\n * @returns {function}\n */\n creator: (function () {\n // stores the already defined creators\n var _ccache = {}, r;\n\n r = function (vname) {\n var f;\n\n // _ccache is global, i.e. it is the same for ALL JessieCode instances.\n // That's why we need the board id here\n if (typeof _ccache[this.board.id + vname] === 'function') {\n f = _ccache[this.board.id + vname];\n } else {\n f = (function (that) {\n return function (parameters, attributes) {\n var attr;\n\n if (Type.exists(attributes)) {\n attr = attributes;\n } else {\n attr = {};\n }\n if (attr.name === undefined && attr.id === undefined) {\n attr.name = (that.lhs[that.scope.id] !== 0 ? that.lhs[that.scope.id] : '');\n }\n return that.board.create(vname, parameters, attr);\n };\n }(this));\n\n f.creator = true;\n _ccache[this.board.id + vname] = f;\n }\n\n return f;\n };\n\n r.clearCache = function () {\n _ccache = {};\n };\n\n return r;\n }()),\n\n /**\n * Assigns a value to a variable in the current scope.\n * @param {String} vname Variable name\n * @param value Anything\n * @see JXG.JessieCode#sstack\n * @see JXG.JessieCode#scope\n */\n letvar: function (vname, value) {\n if (this.builtIn[vname]) {\n this._warn('\"' + vname + '\" is a predefined value.');\n }\n\n this.scope.locals[vname] = value;\n },\n\n /**\n * Checks if the given variable name can be found in the current scope chain.\n * @param {String} vname\n * @returns {Object} A reference to the scope object the variable can be found in or null if it can't be found.\n */\n isLocalVariable: function (vname) {\n var s = this.scope;\n\n while (s !== null) {\n if (Type.exists(s.locals[vname])) {\n return s;\n }\n\n s = s.previous;\n }\n\n return null;\n },\n\n /**\n * Checks if the given variable name is a parameter in any scope from the current to the global scope.\n * @param {String} vname\n * @returns {Object} A reference to the scope object that contains the variable in its arg list.\n */\n isParameter: function (vname) {\n var s = this.scope;\n\n while (s !== null) {\n if (Type.indexOf(s.args, vname) > -1) {\n return s;\n }\n\n s = s.previous;\n }\n\n return null;\n },\n\n /**\n * Checks if the given variable name is a valid creator method.\n * @param {String} vname\n * @returns {Boolean}\n */\n isCreator: function (vname) {\n // check for an element with this name\n return !!JXG.elements[vname];\n },\n\n /**\n * Checks if the given variable identifier is a valid member of the JavaScript Math Object.\n * @param {String} vname\n * @returns {Boolean}\n */\n isMathMethod: function (vname) {\n return vname !== 'E' && !!Math[vname];\n },\n\n /**\n * Returns true if the given identifier is a builtIn variable/function.\n * @param {String} vname\n * @returns {Boolean}\n */\n isBuiltIn: function (vname) {\n return !!this.builtIn[vname];\n },\n\n /**\n * Looks up the value of the given variable. We use a simple type inspection.\n *\n * @param {String} vname Name of the variable\n * @param {Boolean} [local=false] Only look up the internal symbol table and don't look for\n * the <tt>vname</tt> in Math or the element list.\n * @param {Boolean} [isFunctionName=false] Lookup function of tpye builtIn, Math.*, creator.\n *\n * @see JXG.JessieCode#resolveType\n */\n getvar: function (vname, local, isFunctionName) {\n var s;\n\n local = Type.def(local, false);\n\n // Local scope has always precedence\n s = this.isLocalVariable(vname);\n if (s !== null) {\n return s.locals[vname];\n }\n\n // Handle the - so far only - few constants by hard coding them.\n if (vname === '$board' || vname === 'EULER' || vname === 'PI') {\n return this.builtIn[vname];\n }\n\n if (!!isFunctionName) {\n if (this.isBuiltIn(vname)) {\n return this.builtIn[vname];\n }\n\n if (this.isMathMethod(vname)) {\n return Math[vname];\n }\n\n // check for an element with this name\n if (this.isCreator(vname)) {\n return this.creator(vname);\n }\n }\n\n if (!local) {\n s = this.board.select(vname);\n if (s !== vname) {\n return s;\n }\n }\n },\n\n /**\n * Look up the value of a local variable.\n * @param {string} vname\n * @returns {*}\n */\n resolve: function (vname) {\n var s = this.scope;\n\n while (s !== null) {\n if (Type.exists(s.locals[vname])) {\n return s.locals[vname];\n }\n\n s = s.previous;\n }\n },\n\n /**\n * TODO this needs to be called from JS and should not generate JS code\n * Looks up a variable identifier in various tables and generates JavaScript code that could be eval'd to get the value.\n * @param {String} vname Identifier\n * @param {Boolean} [local=false] Don't resolve ids and names of elements\n * @param {Boolean} [withProps=false]\n */\n getvarJS: function (vname, local, withProps) {\n var s, r = '', re;\n\n local = Type.def(local, false);\n withProps = Type.def(withProps, false);\n\n s = this.isParameter(vname);\n if (s !== null) {\n return vname;\n }\n\n s = this.isLocalVariable(vname);\n if (s !== null && !withProps) {\n return '$jc$.resolve(\\'' + vname + '\\')';\n }\n\n // check for an element with this name\n if (this.isCreator(vname)) {\n return '(function () { var a = Array.prototype.slice.call(arguments, 0), props = ' + (withProps ? 'a.pop()' : '{}') + '; return $jc$.board.create.apply($jc$.board, [\\'' + vname + '\\'].concat([a, props])); })';\n }\n\n if (withProps) {\n this._error('Syntax error (attribute values are allowed with element creators only)');\n }\n\n if (this.isBuiltIn(vname)) {\n // If src does not exist, it is a number. In that case, just return the value.\n r = this.builtIn[vname].src || this.builtIn[vname];\n\n // Get the \"real\" name of the function\n if (Type.isNumber(r)) {\n return r;\n }\n // Search a JSXGraph object in board\n if (r.match(/board\\.select/)) {\n return r;\n }\n\n vname = r.split('.').pop();\n if (Type.exists(this.board.mathLib)) {\n // Handle builtin case: ln(x) -> Math.log\n re = new RegExp('^Math\\.' + vname);\n if (re.exec(r) !== null) {\n return r.replace(re, '$jc$.board.mathLib.' + vname);\n }\n }\n if (Type.exists(this.board.mathLibJXG)) {\n // Handle builtin case: factorial(x) -> JXG.Math.factorial\n re = new RegExp('^JXG\\.Math\\.');\n if (re.exec(r) !== null) {\n return r.replace(re, '$jc$.board.mathLibJXG.');\n }\n return r;\n }\n return r;\n\n // return this.builtIn[vname].src || this.builtIn[vname];\n }\n\n if (this.isMathMethod(vname)) {\n return '$jc$.board.mathLib.' + vname;\n// return 'Math.' + vname;\n }\n\n // if (!local) {\n // if (Type.isId(this.board, vname)) {\n // r = '$jc$.board.objects[\\'' + vname + '\\']';\n // } else if (Type.isName(this.board, vname)) {\n // r = '$jc$.board.elementsByName[\\'' + vname + '\\']';\n // } else if (Type.isGroup(this.board, vname)) {\n // r = '$jc$.board.groups[\\'' + vname + '\\']';\n // }\n\n // return r;\n // }\n if (!local) {\n if (Type.isId(this.board, vname)) {\n r = '$jc$.board.objects[\\'' + vname + '\\']';\n if (this.board.objects[vname].elType === 'slider') {\n r += '.Value()';\n }\n } else if (Type.isName(this.board, vname)) {\n r = '$jc$.board.elementsByName[\\'' + vname + '\\']';\n if (this.board.elementsByName[vname].elType === 'slider') {\n r += '.Value()';\n }\n } else if (Type.isGroup(this.board, vname)) {\n r = '$jc$.board.groups[\\'' + vname + '\\']';\n }\n\n return r;\n }\n\n return '';\n },\n\n /**\n * Adds the property <tt>isMap</tt> to a function and sets it to true.\n * @param {function} f\n * @returns {function}\n */\n makeMap: function (f) {\n f.isMap = true;\n\n return f;\n },\n\n functionCodeJS: function (node) {\n var p = node.children[0].join(', '),\n bo = '',\n bc = '';\n\n if (node.value === 'op_map') {\n bo = '{ return ';\n bc = ' }';\n }\n\n return 'function (' + p + ') {\\n' +\n 'var $oldscope$ = $jc$.scope;\\n' +\n '$jc$.scope = $jc$.scopes[' + this.scope.id + '];\\n' +\n 'var r = (function () ' + bo + this.compile(node.children[1], true) + bc + ')();\\n' +\n '$jc$.scope = $oldscope$;\\n' +\n 'return r;\\n' +\n '}';\n },\n\n /**\n * Converts a node type <tt>node_op</tt> and value <tt>op_map</tt> or <tt>op_function</tt> into a executable\n * function. Does a simple type inspection.\n * @param {Object} node\n * @returns {function}\n * @see JXG.JessieCode#resolveType\n */\n defineFunction: function (node) {\n var fun, i, that = this,\n list = node.children[0],\n scope = this.pushScope(list);\n\n if (this.board.options.jc.compile) {\n this.isLHS = false;\n\n // we currently need to put the parameters into the local scope\n // until the compiled JS variable lookup code is fixed\n for (i = 0; i < list.length; i++) {\n scope.locals[list[i]] = list[i];\n }\n\n this.replaceNames(node.children[1]);\n\n /** @ignore */\n fun = (function ($jc$) {\n var fun,\n str = 'var f = ' + $jc$.functionCodeJS(node) + '; f;';\n\n try {\n // yeah, eval is evil, but we don't have much choice here.\n // the str is well defined and there is no user input in it that we didn't check before\n\n /*jslint evil:true*/\n fun = eval(str);\n /*jslint evil:false*/\n\n scope.argtypes = [];\n for (i = 0; i < list.length; i++) {\n scope.argtypes.push(that.resolveType(list[i], node));\n }\n\n return fun;\n } catch (e) {\n $jc$._warn('error compiling function\\n\\n' + str + '\\n\\n' + e.toString());\n return function () {};\n }\n }(this));\n\n // clean up scope\n this.popScope();\n } else {\n /** @ignore */\n fun = (function (_pstack, that, id) {\n return function () {\n var r, oldscope;\n\n oldscope = that.scope;\n that.scope = that.scopes[id];\n\n for (r = 0; r < _pstack.length; r++) {\n that.scope.locals[_pstack[r]] = arguments[r];\n }\n\n r = that.execute(node.children[1]);\n that.scope = oldscope;\n\n return r;\n };\n }(list, this, scope.id));\n }\n\n fun.node = node;\n fun.scope = scope;\n fun.toJS = fun.toString;\n fun.toString = (function (_that) {\n return function () {\n return _that.compile(_that.replaceIDs(Type.deepCopy(node)));\n };\n }(this));\n\n fun.deps = {};\n this.collectDependencies(node.children[1], fun.deps);\n\n return fun;\n },\n\n /**\n * Merge all attribute values given with an element creator into one object.\n * @param {Object} o An arbitrary number of objects\n * @returns {Object} All given objects merged into one. If properties appear in more (case sensitive) than one\n * object the last value is taken.\n */\n mergeAttributes: function (o) {\n var i, attr = {};\n\n for (i = 0; i < arguments.length; i++) {\n attr = Type.deepCopy(attr, arguments[i], true);\n }\n\n return attr;\n },\n\n /**\n * Sets the property <tt>what</tt> of <tt>o</tt> to <tt>value</tt>\n * @param {JXG.Point|JXG.Text} o\n * @param {String} what\n * @param value\n */\n setProp: function (o, what, value) {\n var par = {}, x, y;\n\n if (o.elementClass === Const.OBJECT_CLASS_POINT && (what === 'X' || what === 'Y')) {\n // set coords\n\n what = what.toLowerCase();\n\n // we have to deal with three cases here:\n // o.isDraggable && typeof value === number:\n // stay draggable, just set the new coords (e.g. via moveTo)\n // o.isDraggable && typeof value === function:\n // convert to !o.isDraggable, set the new coords via o.addConstraint()\n // !o.isDraggable:\n // stay !o.isDraggable, update the given coord by overwriting X/YEval\n\n if (o.isDraggable && typeof value === 'number') {\n x = what === 'x' ? value : o.X();\n y = what === 'y' ? value : o.Y();\n\n o.setPosition(Const.COORDS_BY_USER, [x, y]);\n } else if (o.isDraggable && (typeof value === 'function' || typeof value === 'string')) {\n x = what === 'x' ? value : o.coords.usrCoords[1];\n y = what === 'y' ? value : o.coords.usrCoords[2];\n\n o.addConstraint([x, y]);\n } else if (!o.isDraggable) {\n x = what === 'x' ? value : o.XEval.origin;\n y = what === 'y' ? value : o.YEval.origin;\n\n o.addConstraint([x, y]);\n }\n\n this.board.update();\n } else if (o.elementClass === Const.OBJECT_CLASS_TEXT && (what === 'X' || what === 'Y')) {\n if (typeof value === 'number') {\n o[what] = function () { return value; };\n } else if (typeof value === 'function') {\n o.isDraggable = false;\n o[what] = value;\n } else if (typeof value === 'string') {\n o.isDraggable = false;\n o[what] = Type.createFunction(value, this.board, null, true);\n o[what + 'jc'] = value;\n }\n\n o[what].origin = value;\n\n this.board.update();\n } else if (o.type && o.elementClass && o.visProp) {\n if (Type.exists(o[o.methodMap[what]]) && typeof o[o.methodMap[what]] !== 'function') {\n o[o.methodMap[what]] = value;\n } else {\n par[what] = value;\n o.setAttribute(par);\n }\n } else {\n o[what] = value;\n }\n },\n\n /**\n * Generic method to parse JessieCode.\n * This consists of generating an AST with parser.parse,\n * apply simplifying rules from CA and\n * manipulate the AST according to the second parameter \"cmd\".\n * @param {String} code JessieCode code to be parsed\n * @param {String} cmd Type of manipulation to be done with AST\n * @param {Boolean} [geonext=false] Geonext compatibility mode.\n * @param {Boolean} dontstore If false, the code string is stored in this.code.\n * @return {Object} Returns result of computation as directed in cmd.\n */\n _genericParse: function (code, cmd, geonext, dontstore) {\n var i, setTextBackup, ast, result,\n ccode = code.replace(/\\r\\n/g, '\\n').split('\\n'),\n cleaned = [];\n\n if (!dontstore) {\n this.code += code + '\\n';\n }\n\n if (Text) {\n setTextBackup = Text.Text.prototype.setText;\n Text.Text.prototype.setText = Text.Text.prototype.setTextJessieCode;\n }\n\n try {\n if (!Type.exists(geonext)) {\n geonext = false;\n }\n\n for (i = 0; i < ccode.length; i++) {\n if (geonext) {\n ccode[i] = JXG.GeonextParser.geonext2JS(ccode[i], this.board);\n }\n cleaned.push(ccode[i]);\n }\n\n code = cleaned.join('\\n');\n ast = parser.parse(code);\n if (this.CA) {\n ast = this.CA.expandDerivatives(ast, null, ast);\n ast = this.CA.removeTrivialNodes(ast);\n }\n switch (cmd) {\n case 'parse':\n result = this.execute(ast);\n break;\n case 'manipulate':\n result = this.compile(ast);\n break;\n case 'getAst':\n result = ast;\n break;\n default:\n result = false;\n }\n } catch (e) { // catch is mandatory in old IEs\n // console.log(e);\n // We throw the error again,\n // so the user can catch it.\n throw e;\n } finally {\n // make sure the original text method is back in place\n if (Text) {\n Text.Text.prototype.setText = setTextBackup;\n }\n }\n\n return result;\n },\n\n /**\n * Parses JessieCode.\n * This consists of generating an AST with parser.parse, apply simplifying rules\n * from CA and executing the ast by calling this.execute(ast).\n *\n * @param {String} code JessieCode code to be parsed\n * @param {Boolean} [geonext=false] Geonext compatibility mode.\n * @param {Boolean} dontstore If false, the code string is stored in this.code.\n * @return {Object} Parse JessieCode code and execute it.\n */\n parse: function (code, geonext, dontstore) {\n return this._genericParse(code, 'parse', geonext, dontstore);\n },\n\n /**\n * Manipulate JessieCode.\n * This consists of generating an AST with parser.parse,\n * apply simlifying rules from CA\n * and compile the AST back to JessieCode.\n *\n * @param {String} code JessieCode code to be parsed\n * @param {Boolean} [geonext=false] Geonext compatibility mode.\n * @param {Boolean} dontstore If false, the code string is stored in this.code.\n * @return {String} Simplified JessieCode code\n */\n manipulate: function (code, geonext, dontstore) {\n return this._genericParse(code, 'manipulate', geonext, dontstore);\n },\n\n /**\n * Get abstract syntax tree (AST) from JessieCode code.\n * This consists of generating an AST with parser.parse.\n *\n * @param {String} code\n * @param {Boolean} [geonext=false] Geonext compatibility mode.\n * @param {Boolean} dontstore\n * @return {Node} AST\n */\n getAST: function (code, geonext, dontstore) {\n return this._genericParse(code, 'getAst', geonext, dontstore);\n },\n\n /**\n * Parses a JessieCode snippet, e.g. \"3+4\", and wraps it into a function, if desired.\n * @param {String} code A small snippet of JessieCode. Must not be an assignment.\n * @param {Boolean} funwrap If true, the code is wrapped in a function.\n * @param {String} varname Name of the parameter(s)\n * @param {Boolean} [geonext=false] Geonext compatibility mode.\n */\n snippet: function (code, funwrap, varname, geonext) {\n var c;\n\n funwrap = Type.def(funwrap, true);\n varname = Type.def(varname, '');\n geonext = Type.def(geonext, false);\n\n c = (funwrap ? ' function (' + varname + ') { return ' : '') + code + (funwrap ? '; }' : '') + ';';\n\n return this.parse(c, geonext, true);\n },\n\n /**\n * Traverses through the given subtree and changes all values of nodes with the replaced flag set by\n * {@link JXG.JessieCode#replaceNames} to the name of the element (if not empty).\n * @param {Object} node\n */\n replaceIDs: function (node) {\n var i, v;\n\n if (node.replaced) {\n // These children exist, if node.replaced is set.\n v = this.board.objects[node.children[1][0].value];\n\n if (Type.exists(v) && v.name !== \"\") {\n node.type = 'node_var';\n node.value = v.name;\n\n // Maybe it's not necessary, but just to be sure that everything is cleaned up we better delete all\n // children and the replaced flag\n node.children.length = 0;\n delete node.replaced;\n }\n }\n\n if (Type.isArray(node)) {\n for (i = 0; i < node.length; i++) {\n node[i] = this.replaceIDs(node[i]);\n }\n }\n\n if (node.children) {\n // assignments are first evaluated on the right hand side\n for (i = node.children.length; i > 0; i--) {\n if (Type.exists(node.children[i - 1])) {\n node.children[i - 1] = this.replaceIDs(node.children[i - 1]);\n }\n\n }\n }\n\n return node;\n },\n\n /**\n * Traverses through the given subtree and changes all elements referenced by names through referencing them by ID.\n * An identifier is only replaced if it is not found in all scopes above the current scope and if it\n * has not been blacklisted within the codeblock determined by the given subtree.\n * @param {Object} node\n */\n replaceNames: function (node) {\n var i, v;\n\n v = node.value;\n\n // We are interested only in nodes of type node_var and node_op > op_lhs.\n // Currently, we are not checking if the id is a local variable. in this case, we're stuck anyway.\n\n if (node.type === 'node_op' && v === 'op_lhs' && node.children.length === 1) {\n this.isLHS = true;\n } else if (node.type === 'node_var') {\n if (this.isLHS) {\n this.letvar(v, true);\n } else if (!Type.exists(this.getvar(v, true)) && Type.exists(this.board.elementsByName[v])) {\n node = this.createReplacementNode(node);\n }\n }\n\n if (Type.isArray(node)) {\n for (i = 0; i < node.length; i++) {\n node[i] = this.replaceNames(node[i]);\n }\n }\n\n if (node.children) {\n // Assignments are first evaluated on the right hand side\n for (i = node.children.length; i > 0; i--) {\n if (Type.exists(node.children[i - 1])) {\n node.children[i - 1] = this.replaceNames(node.children[i - 1]);\n }\n }\n }\n\n if (node.type === 'node_op' && node.value === 'op_lhs' && node.children.length === 1) {\n this.isLHS = false;\n }\n\n return node;\n },\n\n /**\n * Replaces node_var nodes with node_op>op_execfun nodes, calling the internal $() function with the id of the\n * element accessed by the node_var node.\n * @param {Object} node\n * @returns {Object} op_execfun node\n */\n createReplacementNode: function (node) {\n var v = node.value,\n el = this.board.elementsByName[v];\n\n node = this.createNode('node_op', 'op_execfun',\n this.createNode('node_var', '$'),\n [this.createNode('node_str', el.id)]);\n\n node.replaced = true;\n\n return node;\n },\n\n /**\n * Search the parse tree below <tt>node</tt> for <em>stationary</em> dependencies, i.e. dependencies hard coded into\n * the function.\n * @param {Object} node\n * @param {Object} result An object where the referenced elements will be stored. Access key is their id.\n */\n collectDependencies: function (node, result) {\n var i, v, e, le;\n\n if (Type.isArray(node)) {\n le = node.length;\n for (i = 0; i < le; i++) {\n this.collectDependencies(node[i], result);\n }\n return;\n }\n\n v = node.value;\n\n if (node.type === 'node_var') {\n e = this.getvar(v);\n if (e && e.visProp && e.type && e.elementClass && e.id) {\n result[e.id] = e;\n }\n }\n\n // The $()-function-calls are special because their parameter is given as a string, not as a node_var.\n if (node.type === 'node_op' && node.value === 'op_execfun' &&\n node.children.length > 1 && node.children[0].value === '$' &&\n node.children[1].length > 0) {\n\n e = node.children[1][0].value;\n result[e] = this.board.objects[e];\n }\n\n if (node.children) {\n for (i = node.children.length; i > 0; i--) {\n if (Type.exists(node.children[i - 1])) {\n this.collectDependencies(node.children[i - 1], result);\n }\n\n }\n }\n },\n\n resolveProperty: function (e, v, compile) {\n compile = Type.def(compile, false);\n\n // is it a geometry element or a board?\n if (e /*&& e.type && e.elementClass*/ && e.methodMap) {\n // yeah, it is. but what does the user want?\n if (Type.exists(e.subs) && Type.exists(e.subs[v])) {\n // a subelement it is, good sir.\n e = e.subs;\n } else if (Type.exists(e.methodMap[v])) {\n // the user wants to call a method\n v = e.methodMap[v];\n } else {\n // the user wants to change an attribute\n e = e.visProp;\n v = v.toLowerCase();\n }\n }\n\n if (Type.isFunction(e)) {\n this._error('Accessing function properties is not allowed.');\n }\n\n if (!Type.exists(e)) {\n this._error(e + ' is not an object');\n }\n\n if (!Type.exists(e[v])) {\n this._error('unknown property ' + v);\n }\n\n if (compile && typeof e[v] === 'function') {\n return function () { return e[v].apply(e, arguments); };\n }\n\n return e[v];\n },\n\n /**\n * Type inspection: check if the string vname appears as function name in the\n * AST node. Used in \"op_execfun\". This allows the JessieCode exmples below.\n *\n * @private\n * @param {String} vname\n * @param {Object} node\n * @returns 'any' or 'function'\n * @see JXG.JessieCode#execute\n * @see JXG.JessieCode#getvar\n *\n * @example\n * var p = board.create('point', [2, 0], {name: 'X'});\n * var txt = 'X(X)';\n * console.log(board.jc.parse(txt));\n *\n * @example\n * var p = board.create('point', [2, 0], {name: 'X'});\n * var txt = 'f = function(el, X) { return X(el); }; f(X, X);';\n * console.log(board.jc.parse(txt));\n *\n * @example\n * var p = board.create('point', [2, 0], {name: 'point'});\n * var txt = 'B = point(1,3); X(point);';\n * console.log(board.jc.parse(txt));\n *\n * @example\n * var p = board.create('point', [2, 0], {name: 'A'});\n * var q = board.create('point', [-2, 0], {name: 'X'});\n * var txt = 'getCoord=function(p, f){ return f(p); }; getCoord(A, X);';\n * console.log(board.jc.parse(txt));\n */\n resolveType: function(vname, node) {\n var i, t,\n type = 'any'; // Possible values: 'function', 'any'\n\n if (Type.isArray(node)) {\n // node contains the parameters of a function call or function declaration\n for (i = 0; i < node.length; i++) {\n t = this.resolveType(vname, node[i]);\n if (t !== 'any') {\n type = t;\n return type;\n }\n }\n }\n\n if (node.type === 'node_op' && node.value === 'op_execfun' &&\n node.children[0].type === 'node_var' && node.children[0].value === vname) {\n return 'function';\n }\n\n if (node.type === 'node_op') {\n for (i = 0; i < node.children.length; i++) {\n if (node.children[0].type === 'node_var' && node.children[0].value === vname &&\n (node.value === 'op_add' || node.value === 'op_sub' || node.value === 'op_mul' ||\n node.value === 'op_div' || node.value === 'op_mod' || node.value === 'op_exp' ||\n node.value === 'op_neg')) {\n return 'any';\n }\n }\n\n for (i = 0; i < node.children.length; i++) {\n t = this.resolveType(vname, node.children[i]);\n if (t !== 'any') {\n type = t;\n return type;\n }\n }\n }\n\n return 'any';\n },\n\n /**\n * Resolves the lefthand side of an assignment operation\n * @param node\n * @returns {Object} An object with two properties. <strong>o</strong> which contains the object, and\n * a string <strong>what</strong> which contains the property name.\n */\n getLHS: function (node) {\n var res;\n\n if (node.type === 'node_var') {\n res = {\n o: this.scope.locals,\n what: node.value\n };\n } else if (node.type === 'node_op' && node.value === 'op_property') {\n res = {\n o: this.execute(node.children[0]),\n what: node.children[1]\n };\n } else if (node.type === 'node_op' && node.value === 'op_extvalue') {\n res = {\n o: this.execute(node.children[0]),\n what: this.execute(node.children[1])\n };\n } else {\n throw new Error('Syntax error: Invalid left-hand side of assignment.');\n }\n\n return res;\n },\n\n getLHSCompiler: function (node, js) {\n var res;\n\n if (node.type === 'node_var') {\n res = node.value;\n } else if (node.type === 'node_op' && node.value === 'op_property') {\n res = [\n this.compile(node.children[0], js),\n \"'\" + node.children[1] + \"'\"\n ];\n } else if (node.type === 'node_op' && node.value === 'op_extvalue') {\n res = [\n this.compile(node.children[0], js),\n node.children[1].type === 'node_const' ? node.children[1].value : this.compile(node.children[1], js)\n ];\n } else {\n throw new Error('Syntax error: Invalid left-hand side of assignment.');\n }\n\n return res;\n },\n\n /**\n * Executes a parse subtree.\n * @param {Object} node\n * @returns {Number|String|Object|Boolean} Something\n * @private\n */\n execute: function (node) {\n var ret, v, i, e, l, undef, list, ilist,\n parents = [],\n // exec fun\n fun, attr, sc;\n\n ret = 0;\n\n if (!node) {\n return ret;\n }\n\n this.line = node.line;\n this.col = node.col;\n\n switch (node.type) {\n case 'node_op':\n switch (node.value) {\n case 'op_none':\n if (node.children[0]) {\n this.execute(node.children[0]);\n }\n if (node.children[1]) {\n ret = this.execute(node.children[1]);\n }\n break;\n case 'op_assign':\n v = this.getLHS(node.children[0]);\n this.lhs[this.scope.id] = v.what;\n\n if (v.o.type && v.o.elementClass && v.o.methodMap && v.what === 'label') {\n this._error('Left-hand side of assignment is read-only.');\n }\n\n ret = this.execute(node.children[1]);\n if (v.o !== this.scope.locals || (Type.isArray(v.o) && typeof v.what === 'number')) {\n // it is either an array component being set or a property of an object.\n this.setProp(v.o, v.what, ret);\n } else {\n // this is just a local variable inside JessieCode\n this.letvar(v.what, ret);\n }\n this.lhs[this.scope.id] = 0;\n break;\n case 'op_if':\n if (this.execute(node.children[0])) {\n ret = this.execute(node.children[1]);\n }\n break;\n case 'op_conditional':\n // fall through\n case 'op_if_else':\n if (this.execute(node.children[0])) {\n ret = this.execute(node.children[1]);\n } else {\n ret = this.execute(node.children[2]);\n }\n break;\n case 'op_while':\n while (this.execute(node.children[0])) {\n this.execute(node.children[1]);\n }\n break;\n case 'op_do':\n do {\n this.execute(node.children[0]);\n } while (this.execute(node.children[1]));\n break;\n case 'op_for':\n for (this.execute(node.children[0]); this.execute(node.children[1]); this.execute(node.children[2])) {\n this.execute(node.children[3]);\n }\n break;\n case 'op_proplst':\n if (node.children[0]) {\n this.execute(node.children[0]);\n }\n if (node.children[1]) {\n this.execute(node.children[1]);\n }\n break;\n case 'op_emptyobject':\n ret = {};\n break;\n case 'op_proplst_val':\n this.propstack.push({});\n this.propscope++;\n\n this.execute(node.children[0]);\n ret = this.propstack[this.propscope];\n\n this.propstack.pop();\n this.propscope--;\n break;\n case 'op_prop':\n // child 0: Identifier\n // child 1: Value\n this.propstack[this.propscope][node.children[0]] = this.execute(node.children[1]);\n break;\n case 'op_array':\n ret = [];\n l = node.children[0].length;\n\n for (i = 0; i < l; i++) {\n ret.push(this.execute(node.children[0][i]));\n }\n\n break;\n case 'op_extvalue':\n ret = this.execute(node.children[0]);\n i = this.execute(node.children[1]);\n\n if (typeof i === 'number' && Math.abs(Math.round(i) - i) < Mat.eps) {\n ret = ret[i];\n } else {\n ret = undef;\n }\n break;\n case 'op_return':\n if (this.scope === 0) {\n this._error('Unexpected return.');\n } else {\n return this.execute(node.children[0]);\n }\n break;\n case 'op_map':\n if (!node.children[1].isMath && node.children[1].type !== 'node_var') {\n this._error('execute: In a map only function calls and mathematical expressions are allowed.');\n }\n\n /** @ignore */\n fun = this.defineFunction(node);\n fun.isMap = true;\n\n ret = fun;\n break;\n case 'op_function':\n // parse the parameter list\n // after this, the parameters are in pstack\n\n /** @ignore */\n fun = this.defineFunction(node);\n fun.isMap = false;\n\n ret = fun;\n break;\n case 'op_execfun':\n // node.children:\n // [0]: Name of the function\n // [1]: Parameter list as a parse subtree\n // [2]: Properties, only used in case of a create function\n this.dpstack.push([]);\n this.pscope++;\n\n // parameter parsing is done below\n list = node.children[1];\n\n // parse the properties only if given\n if (Type.exists(node.children[2])) {\n if (node.children[3]) {\n ilist = node.children[2];\n attr = {};\n\n for (i = 0; i < ilist.length; i++) {\n attr = Type.deepCopy(attr, this.execute(ilist[i]), true);\n }\n } else {\n attr = this.execute(node.children[2]);\n }\n }\n\n // look up the variables name in the variable table\n node.children[0]._isFunctionName = true;\n fun = this.execute(node.children[0]);\n delete node.children[0]._isFunctionName;\n\n // determine the scope the function wants to run in\n if (fun && fun.sc) {\n sc = fun.sc;\n } else {\n sc = this;\n }\n\n if (!fun.creator && Type.exists(node.children[2])) {\n this._error('Unexpected value. Only element creators are allowed to have a value after the function call.');\n }\n\n // interpret ALL the parameters\n for (i = 0; i < list.length; i++) {\n if (Type.exists(fun.scope) && Type.exists(fun.scope.argtypes) &&fun.scope.argtypes[i] === 'function') {\n // Type inspection\n list[i]._isFunctionName = true;\n parents[i] = this.execute(list[i]);\n delete list[i]._isFunctionName;\n } else {\n parents[i] = this.execute(list[i]);\n }\n //parents[i] = Type.evalSlider(this.execute(list[i]));\n this.dpstack[this.pscope].push({\n line: node.children[1][i].line,\n // SketchBin currently works only if the last column of the\n // parent position is taken. This is due to how I patched JS/CC\n // to count the lines and columns. So, ecol will do for now\n col: node.children[1][i].ecol\n });\n }\n\n // check for the function in the variable table\n if (typeof fun === 'function' && !fun.creator) {\n ret = fun.apply(sc, parents);\n } else if (typeof fun === 'function' && !!fun.creator) {\n e = this.line;\n\n // creator methods are the only ones that take properties, hence this special case\n try {\n ret = fun(parents, attr);\n ret.jcLineStart = e;\n ret.jcLineEnd = node.eline;\n\n for (i = e; i <= node.line; i++) {\n this.lineToElement[i] = ret;\n }\n\n ret.debugParents = this.dpstack[this.pscope];\n } catch (ex) {\n this._error(ex.toString());\n }\n } else {\n this._error('Function \\'' + fun + '\\' is undefined.');\n }\n\n // clear parameter stack\n this.dpstack.pop();\n this.pscope--;\n break;\n case 'op_property':\n e = this.execute(node.children[0]);\n v = node.children[1];\n\n ret = this.resolveProperty(e, v, false);\n\n // set the scope, in case this is a method the user wants to call\n if (Type.exists(ret)) {\n ret.sc = e;\n }\n\n break;\n case 'op_use':\n this._warn('Use of the \\'use\\' operator is deprecated.');\n this.use(node.children[0].toString());\n break;\n case 'op_delete':\n this._warn('Use of the \\'delete\\' operator is deprecated. Please use the remove() function.');\n v = this.getvar(node.children[0]);\n ret = this.del(v);\n break;\n case 'op_eq':\n // == is intentional\n /*jslint eqeq:true*/\n ret = this.execute(node.children[0]) == this.execute(node.children[1]);\n /*jslint eqeq:false*/\n break;\n case 'op_neq':\n // != is intentional\n /*jslint eqeq:true*/\n ret = this.execute(node.children[0]) != this.execute(node.children[1]);\n /*jslint eqeq:true*/\n break;\n case 'op_approx':\n ret = Math.abs(this.execute(node.children[0]) - this.execute(node.children[1])) < Mat.eps;\n break;\n case 'op_gt':\n ret = this.execute(node.children[0]) > this.execute(node.children[1]);\n break;\n case 'op_lt':\n ret = this.execute(node.children[0]) < this.execute(node.children[1]);\n break;\n case 'op_geq':\n ret = this.execute(node.children[0]) >= this.execute(node.children[1]);\n break;\n case 'op_leq':\n ret = this.execute(node.children[0]) <= this.execute(node.children[1]);\n break;\n case 'op_or':\n ret = this.execute(node.children[0]) || this.execute(node.children[1]);\n break;\n case 'op_and':\n ret = this.execute(node.children[0]) && this.execute(node.children[1]);\n break;\n case 'op_not':\n ret = !this.execute(node.children[0]);\n break;\n case 'op_add':\n ret = this.add(this.execute(node.children[0]), this.execute(node.children[1]));\n break;\n case 'op_sub':\n ret = this.sub(this.execute(node.children[0]), this.execute(node.children[1]));\n break;\n case 'op_div':\n ret = this.div(this.execute(node.children[0]), this.execute(node.children[1]));\n break;\n case 'op_mod':\n // use mathematical modulo, JavaScript implements the symmetric modulo.\n ret = this.mod(this.execute(node.children[0]), this.execute(node.children[1]), true);\n break;\n case 'op_mul':\n ret = this.mul(this.execute(node.children[0]), this.execute(node.children[1]));\n break;\n case 'op_exp':\n ret = this.pow(this.execute(node.children[0]), this.execute(node.children[1]));\n break;\n case 'op_neg':\n ret = this.neg(this.execute(node.children[0]));\n break;\n }\n break;\n\n case 'node_var':\n // node._isFunctionName is set in execute: at op_execfun.\n ret = this.getvar(node.value, false, node._isFunctionName);\n break;\n\n case 'node_const':\n if(node.value === null) {\n ret = null;\n } else {\n ret = Number(node.value);\n }\n break;\n\n case 'node_const_bool':\n ret = node.value;\n break;\n\n case 'node_str':\n //ret = node.value.replace(/\\\\'/, \"'\").replace(/\\\\\"/, '\"').replace(/\\\\\\\\/, '\\\\');\n /*jslint regexp:true*/\n ret = node.value.replace(/\\\\(.)/, '$1');\n /*jslint regexp:false*/\n break;\n }\n\n return ret;\n },\n\n /**\n * Compiles a parse tree back to JessieCode.\n * @param {Object} node\n * @param {Boolean} [js=false] Compile either to JavaScript or back to JessieCode (required for the UI).\n * @returns Something\n * @private\n */\n compile: function (node, js) {\n var e, i, list, scope,\n ret = '';\n\n if (!Type.exists(js)) {\n js = false;\n }\n\n if (!node) {\n return ret;\n }\n\n switch (node.type) {\n case 'node_op':\n switch (node.value) {\n case 'op_none':\n if (node.children[0]) {\n ret = this.compile(node.children[0], js);\n }\n if (node.children[1]) {\n ret += this.compile(node.children[1], js);\n }\n break;\n case 'op_assign':\n //e = this.compile(node.children[0], js);\n if (js) {\n e = this.getLHSCompiler(node.children[0], js);\n if (Type.isArray(e)) {\n ret = '$jc$.setProp(' + e[0] + ', ' + e[1] + ', ' + this.compile(node.children[1], js) + ');\\n';\n } else {\n if (this.isLocalVariable(e) !== this.scope) {\n this.scope.locals[e] = true;\n }\n ret = '$jc$.scopes[' + this.scope.id + '].locals[\\'' + e + '\\'] = ' + this.compile(node.children[1], js) + ';\\n';\n }\n } else {\n e = this.compile(node.children[0]);\n ret = e + ' = ' + this.compile(node.children[1], js) + ';\\n';\n }\n break;\n case 'op_if':\n ret = ' if (' + this.compile(node.children[0], js) + ') ' + this.compile(node.children[1], js);\n break;\n case 'op_if_else':\n ret = ' if (' + this.compile(node.children[0], js) + ')' + this.compile(node.children[1], js);\n ret += ' else ' + this.compile(node.children[2], js);\n break;\n case 'op_conditional':\n ret = '((' + this.compile(node.children[0], js) + ')?(' + this.compile(node.children[1], js);\n ret += '):(' + this.compile(node.children[2], js) + '))';\n break;\n case 'op_while':\n ret = ' while (' + this.compile(node.children[0], js) + ') {\\n' + this.compile(node.children[1], js) + '}\\n';\n break;\n case 'op_do':\n ret = ' do {\\n' + this.compile(node.children[0], js) + '} while (' + this.compile(node.children[1], js) + ');\\n';\n break;\n case 'op_for':\n //ret = ' for (' + this.compile(node.children[0], js) + '; ' + this.compile(node.children[1], js) + '; ' + this.compile(node.children[2], js) + ') {\\n' + this.compile(node.children[3], js) + '\\n}\\n';\n ret = ' for (' + this.compile(node.children[0], js) + // Assignment ends with \";\"\n this.compile(node.children[1], js) + '; ' + // Logical test comes without \";\"\n this.compile(node.children[2], js).slice(0, -2) + // Counting comes with \";\" which has to be removed\n ') {\\n' + this.compile(node.children[3], js) + '\\n}\\n';\n break;\n case 'op_proplst':\n if (node.children[0]) {\n ret = this.compile(node.children[0], js) + ', ';\n }\n\n ret += this.compile(node.children[1], js);\n break;\n case 'op_prop':\n // child 0: Identifier\n // child 1: Value\n ret = node.children[0] + ': ' + this.compile(node.children[1], js);\n break;\n case 'op_emptyobject':\n ret = js ? '{}' : '<< >>';\n break;\n case 'op_proplst_val':\n ret = this.compile(node.children[0], js);\n break;\n case 'op_array':\n list = [];\n for (i = 0; i < node.children[0].length; i++) {\n list.push(this.compile(node.children[0][i], js));\n }\n ret = '[' + list.join(', ') + ']';\n break;\n case 'op_extvalue':\n ret = this.compile(node.children[0], js) + '[' + this.compile(node.children[1], js) + ']';\n break;\n case 'op_return':\n ret = ' return ' + this.compile(node.children[0], js) + ';\\n';\n break;\n case 'op_map':\n if (!node.children[1].isMath && node.children[1].type !== 'node_var') {\n this._error('compile: In a map only function calls and mathematical expressions are allowed.');\n }\n\n list = node.children[0];\n if (js) {\n ret = ' $jc$.makeMap(function (' + list.join(', ') + ') { return ' + this.compile(node.children[1], js) + '; })';\n } else {\n ret = 'map (' + list.join(', ') + ') -> ' + this.compile(node.children[1], js);\n }\n\n break;\n case 'op_function':\n list = node.children[0];\n scope = this.pushScope(list);\n if (js) {\n ret = this.functionCodeJS(node);\n } else {\n ret = ' function (' + list.join(', ') + ') ' + this.compile(node.children[1], js);\n }\n this.popScope();\n break;\n case 'op_execfunmath':\n console.log('op_execfunmath: TODO');\n ret = '-1';\n break;\n case 'op_execfun':\n // parse the properties only if given\n if (node.children[2]) {\n list = [];\n for (i = 0; i < node.children[2].length; i++) {\n list.push(this.compile(node.children[2][i], js));\n }\n\n if (js) {\n e = '$jc$.mergeAttributes(' + list.join(', ') + ')';\n }\n }\n node.children[0].withProps = !!node.children[2];\n list = [];\n for (i = 0; i < node.children[1].length; i++) {\n list.push(this.compile(node.children[1][i], js));\n }\n ret = this.compile(node.children[0], js) + '(' + list.join(', ') + (node.children[2] && js ? ', ' + e : '') + ')' + (node.children[2] && !js ? e : '');\n if (js) {\n // Inserting a newline here allows simulataneously\n // - procedural calls like Q.moveTo(...); and\n // - function calls in expressions like log(x) + 1;\n // Problem: procedural calls will not be ended by a semicolon.\n ret += '\\n';\n }\n\n // save us a function call when compiled to javascript\n if (js && node.children[0].value === '$') {\n ret = '$jc$.board.objects[' + this.compile(node.children[1][0], js) + ']';\n }\n break;\n case 'op_property':\n if (js && node.children[1] !== 'X' && node.children[1] !== 'Y') {\n ret = '$jc$.resolveProperty(' + this.compile(node.children[0], js) + ', \\'' + node.children[1] + '\\', true)';\n } else {\n ret = this.compile(node.children[0], js) + '.' + node.children[1];\n }\n break;\n case 'op_use':\n this._warn('Use of the \\'use\\' operator is deprecated.');\n if (js) {\n ret = '$jc$.use(\\'';\n } else {\n ret = 'use(\\'';\n }\n\n ret += node.children[0].toString() + '\\');';\n break;\n case 'op_delete':\n this._warn('Use of the \\'delete\\' operator is deprecated. Please use the remove() function.');\n if (js) {\n ret = '$jc$.del(';\n } else {\n ret = 'remove(';\n }\n\n ret += this.compile(node.children[0], js) + ')';\n break;\n case 'op_eq':\n ret = '(' + this.compile(node.children[0], js) + ' === ' + this.compile(node.children[1], js) + ')';\n break;\n case 'op_neq':\n ret = '(' + this.compile(node.children[0], js) + ' !== ' + this.compile(node.children[1], js) + ')';\n break;\n case 'op_approx':\n ret = '(' + this.compile(node.children[0], js) + ' ~= ' + this.compile(node.children[1], js) + ')';\n break;\n case 'op_gt':\n if (js) {\n ret = '$jc$.gt(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ')';\n } else {\n ret = '(' + this.compile(node.children[0], js) + ' > ' + this.compile(node.children[1], js) + ')';\n }\n break;\n case 'op_lt':\n if (js) {\n ret = '$jc$.lt(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ')';\n } else {\n ret = '(' + this.compile(node.children[0], js) + ' < ' + this.compile(node.children[1], js) + ')';\n }\n break;\n case 'op_geq':\n if (js) {\n ret = '$jc$.geq(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ')';\n } else {\n ret = '(' + this.compile(node.children[0], js) + ' >= ' + this.compile(node.children[1], js) + ')';\n }\n break;\n case 'op_leq':\n if (js) {\n ret = '$jc$.leq(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ')';\n } else {\n ret = '(' + this.compile(node.children[0], js) + ' <= ' + this.compile(node.children[1], js) + ')';\n }\n break;\n case 'op_or':\n ret = '(' + this.compile(node.children[0], js) + ' || ' + this.compile(node.children[1], js) + ')';\n break;\n case 'op_and':\n ret = '(' + this.compile(node.children[0], js) + ' && ' + this.compile(node.children[1], js) + ')';\n break;\n case 'op_not':\n ret = '!(' + this.compile(node.children[0], js) + ')';\n break;\n case 'op_add':\n if (js) {\n ret = '$jc$.add(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ')';\n } else {\n ret = '(' + this.compile(node.children[0], js) + ' + ' + this.compile(node.children[1], js) + ')';\n }\n break;\n case 'op_sub':\n if (js) {\n ret = '$jc$.sub(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ')';\n } else {\n ret = '(' + this.compile(node.children[0], js) + ' - ' + this.compile(node.children[1], js) + ')';\n }\n break;\n case 'op_div':\n if (js) {\n ret = '$jc$.div(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ')';\n } else {\n ret = '(' + this.compile(node.children[0], js) + ' / ' + this.compile(node.children[1], js) + ')';\n }\n break;\n case 'op_mod':\n if (js) {\n ret = '$jc$.mod(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ', true)';\n } else {\n ret = '(' + this.compile(node.children[0], js) + ' % ' + this.compile(node.children[1], js) + ')';\n }\n break;\n case 'op_mul':\n if (js) {\n ret = '$jc$.mul(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ')';\n } else {\n ret = '(' + this.compile(node.children[0], js) + ' * ' + this.compile(node.children[1], js) + ')';\n }\n break;\n case 'op_exp':\n if (js) {\n ret = '$jc$.pow(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ')';\n } else {\n ret = '(' + this.compile(node.children[0], js) + '^' + this.compile(node.children[1], js) + ')';\n }\n break;\n case 'op_neg':\n if (js) {\n ret = '$jc$.neg(' + this.compile(node.children[0], js) + ')';\n } else {\n ret = '(-' + this.compile(node.children[0], js) + ')';\n }\n break;\n }\n break;\n\n case 'node_var':\n if (js) {\n ret = this.getvarJS(node.value, false, node.withProps);\n } else {\n ret = node.value;\n }\n break;\n\n case 'node_const':\n ret = node.value;\n break;\n\n case 'node_const_bool':\n ret = node.value;\n break;\n\n case 'node_str':\n ret = '\\'' + node.value + '\\'';\n break;\n }\n\n if (node.needsBrackets) {\n ret = '{\\n' + ret + '\\n}\\n';\n }\n\n return ret;\n },\n\n /**\n * This is used as the global getName() function.\n * @param {JXG.GeometryElement} obj\n * @param {Boolean} useId\n * @returns {String}\n */\n getName: function (obj,useId) {\n var name = '';\n\n if (Type.exists(obj) && Type.exists(obj.getName)) {\n name = obj.getName();\n if ((!Type.exists(name) || name === '') && !!useId) {\n name = obj.id;\n }\n } else if (!!useId) {\n name = obj.id;\n }\n\n return name;\n },\n\n /**\n * This is used as the global X() function.\n * @param {JXG.Point|JXG.Text} e\n * @returns {Number}\n */\n X: function (e) {\n return e.X();\n },\n\n /**\n * This is used as the global Y() function.\n * @param {JXG.Point|JXG.Text} e\n * @returns {Number}\n */\n Y: function (e) {\n return e.Y();\n },\n\n /**\n * This is used as the global V() function.\n * @param {Glider|Slider} e\n * @returns {Number}\n */\n V: function (e) {\n return e.Value();\n },\n\n /**\n * This is used as the global L() function.\n * @param {JXG.Line} e\n * @returns {Number}\n */\n L: function (e) {\n return e.L();\n },\n\n /**\n * This is used as the global area() function.\n * @param {JXG.Circle|JXG.Polygon} obj\n * @returns {Number}\n */\n area: function (obj) {\n if (!Type.exists(obj) || !Type.exists(obj.Area)) {\n this._error('Error: Can\\'t calculate area.');\n }\n\n return obj.Area();\n },\n\n /**\n * This is used as the global dist() function.\n * @param {JXG.Point} p1\n * @param {JXG.Point} p2\n * @returns {Number}\n */\n dist: function (p1, p2) {\n if (!Type.exists(p1) || !Type.exists(p1.Dist)) {\n this._error('Error: Can\\'t calculate distance.');\n }\n\n return p1.Dist(p2);\n },\n\n /**\n * This is used as the global radius() function.\n * @param {JXG.Circle|Sector} obj\n * @returns {Number}\n */\n radius: function (obj) {\n if (!Type.exists(obj) || !Type.exists(obj.Radius)) {\n this._error('Error: Can\\'t calculate radius.');\n }\n\n return obj.Radius();\n },\n\n /**\n * + operator implementation\n * @param {Number|Array|JXG.Point} a\n * @param {Number|Array|JXG.Point} b\n * @returns {Number|Array}\n */\n add: function (a, b) {\n var i, len, res;\n\n a = Type.evalSlider(a);\n b = Type.evalSlider(b);\n\n if (Interval.isInterval(a) || Interval.isInterval(b)) {\n res = Interval.add(a, b);\n } else if (Type.isArray(a) && Type.isArray(b)) {\n len = Math.min(a.length, b.length);\n res = [];\n\n for (i = 0; i < len; i++) {\n res[i] = a[i] + b[i];\n }\n } else if (Type.isNumber(a) && Type.isNumber(b)) {\n res = a + b;\n } else if (Type.isString(a) || Type.isString(b)) {\n res = a.toString() + b.toString();\n } else {\n this._error('Operation + not defined on operands ' + typeof a + ' and ' + typeof b);\n }\n\n return res;\n },\n\n /**\n * - operator implementation\n * @param {Number|Array|JXG.Point} a\n * @param {Number|Array|JXG.Point} b\n * @returns {Number|Array}\n */\n sub: function (a, b) {\n var i, len, res;\n\n a = Type.evalSlider(a);\n b = Type.evalSlider(b);\n\n if (Interval.isInterval(a) || Interval.isInterval(b)) {\n res = Interval.sub(a, b);\n } else if (Type.isArray(a) && Type.isArray(b)) {\n len = Math.min(a.length, b.length);\n res = [];\n\n for (i = 0; i < len; i++) {\n res[i] = a[i] - b[i];\n }\n } else if (Type.isNumber(a) && Type.isNumber(b)) {\n res = a - b;\n } else {\n this._error('Operation - not defined on operands ' + typeof a + ' and ' + typeof b);\n }\n\n return res;\n },\n\n /**\n * unary - operator implementation\n * @param {Number|Array|JXG.Point} a\n * @returns {Number|Array}\n */\n neg: function (a) {\n var i, len, res;\n\n a = Type.evalSlider(a);\n\n if (Interval.isInterval(a)) {\n res = Interval.negative(a);\n } else if (Type.isArray(a)) {\n len = a.length;\n res = [];\n\n for (i = 0; i < len; i++) {\n res[i] = -a[i];\n }\n } else if (Type.isNumber(a)) {\n res = -a;\n } else {\n this._error('Unary operation - not defined on operand ' + typeof a);\n }\n\n return res;\n },\n\n /**\n * Multiplication of vectors and numbers\n * @param {Number|Array} a\n * @param {Number|Array} b\n * @returns {Number|Array} (Inner) product of the given input values.\n */\n mul: function (a, b) {\n var i, len, res;\n\n a = Type.evalSlider(a);\n b = Type.evalSlider(b);\n\n if (Type.isArray(a) && Type.isNumber(b)) {\n // swap b and a\n i = a;\n a = b;\n b = a;\n }\n\n if (Interval.isInterval(a) || Interval.isInterval(b)) {\n res = Interval.mul(a, b);\n } else if (Type.isArray(a) && Type.isArray(b)) {\n len = Math.min(a.length, b.length);\n res = Mat.innerProduct(a, b, len);\n } else if (Type.isNumber(a) && Type.isArray(b)) {\n len = b.length;\n res = [];\n\n for (i = 0; i < len; i++) {\n res[i] = a * b[i];\n }\n } else if (Type.isNumber(a) && Type.isNumber(b)) {\n res = a * b;\n } else {\n this._error('Operation * not defined on operands ' + typeof a + ' and ' + typeof b);\n }\n\n return res;\n },\n\n /**\n * Implementation of the / operator.\n * @param {Number|Array} a\n * @param {Number} b\n * @returns {Number|Array}\n */\n div: function (a, b) {\n var i, len, res;\n\n a = Type.evalSlider(a);\n b = Type.evalSlider(b);\n\n if (Interval.isInterval(a) || Interval.isInterval(b)) {\n res = Interval.div(a, b);\n } else if (Type.isArray(a) && Type.isNumber(b)) {\n len = a.length;\n res = [];\n\n for (i = 0; i < len; i++) {\n res[i] = a[i] / b;\n }\n } else if (Type.isNumber(a) && Type.isNumber(b)) {\n res = a / b;\n } else {\n this._error('Operation * not defined on operands ' + typeof a + ' and ' + typeof b);\n }\n\n return res;\n },\n\n /**\n * Implementation of the % operator.\n * @param {Number|Array} a\n * @param {Number} b\n * @returns {Number|Array}\n */\n mod: function (a, b) {\n var i, len, res;\n\n a = Type.evalSlider(a);\n b = Type.evalSlider(b);\n\n if (Interval.isInterval(a) || Interval.isInterval(b)) {\n return Interval.fmod(a, b);\n } else if (Type.isArray(a) && Type.isNumber(b)) {\n len = a.length;\n res = [];\n\n for (i = 0; i < len; i++) {\n res[i] = Mat.mod(a[i], b, true);\n }\n } else if (Type.isNumber(a) && Type.isNumber(b)) {\n res = Mat.mod(a, b, true);\n } else {\n this._error('Operation * not defined on operands ' + typeof a + ' and ' + typeof b);\n }\n\n return res;\n },\n\n /**\n * Pow function wrapper to allow direct usage of sliders.\n * @param {Number|Slider} a\n * @param {Number|Slider} b\n * @returns {Number}\n */\n pow: function (a, b) {\n a = Type.evalSlider(a);\n b = Type.evalSlider(b);\n\n if (Interval.isInterval(a) || Interval.isInterval(b)) {\n return Interval.pow(a, b);\n }\n return Mat.pow(a, b);\n },\n\n lt: function (a, b) {\n if (Interval.isInterval(a) || Interval.isInterval(b)) {\n return Interval.lt(a, b);\n }\n return a < b;\n },\n leq: function (a, b) {\n if (Interval.isInterval(a) || Interval.isInterval(b)) {\n return Interval.leq(a, b);\n }\n return a <= b;\n },\n gt: function (a, b) {\n if (Interval.isInterval(a) || Interval.isInterval(b)) {\n return Interval.gt(a, b);\n }\n return a > b;\n },\n geq: function (a, b) {\n if (Interval.isInterval(a) || Interval.isInterval(b)) {\n return Intervalt.geq(a, b);\n }\n return a >= b;\n },\n\n randint: function (min, max, step) {\n if (!Type.exists(step)) {\n step = 1;\n }\n return Math.round(Math.random() * (max - min) / step) * step + min;\n },\n\n DDD: function (f) {\n console.log('Dummy derivative function. This should never appear!');\n },\n\n /**\n * Implementation of the ?: operator\n * @param {Boolean} cond Condition\n * @param {*} v1\n * @param {*} v2\n * @returns {*} Either v1 or v2.\n */\n ifthen: function (cond, v1, v2) {\n if (cond) {\n return v1;\n }\n\n return v2;\n },\n\n /**\n * Implementation of the delete() builtin function\n * @param {JXG.GeometryElement} element\n */\n del: function (element) {\n if (typeof element === 'object' && JXG.exists(element.type) && JXG.exists(element.elementClass)) {\n this.board.removeObject(element);\n }\n },\n\n /**\n * Implementation of the use() builtin function\n * @param {String} board\n */\n use: function (board) {\n var b, ref,\n found = false;\n\n if (typeof board === 'string') {\n // search all the boards for the one with the appropriate container div\n for (b in JXG.boards) {\n if (JXG.boards.hasOwnProperty(b) && JXG.boards[b].container === board) {\n ref = JXG.boards[b];\n found = true;\n break;\n }\n }\n } else {\n ref = board;\n found = true;\n }\n\n if (found) {\n this.board = ref;\n this.builtIn.$board = ref;\n this.builtIn.$board.src = '$jc$.board';\n } else {\n this._error('Board \\'' + board + '\\' not found!');\n }\n },\n\n /**\n * Find the first symbol to the given value from the given scope upwards.\n * @param v Value\n * @param {Number} [scope=-1] The scope, default is to start with current scope (-1).\n * @returns {Array} An array containing the symbol and the scope if a symbol could be found,\n * an empty array otherwise;\n */\n findSymbol: function (v, scope) {\n var i, s;\n\n scope = Type.def(scope, -1);\n\n if (scope === -1) {\n s = this.scope;\n } else {\n s = this.scopes[scope];\n }\n\n while (s !== null) {\n for (i in s.locals) {\n if (s.locals.hasOwnProperty(i) && s.locals[i] === v) {\n return [i, s];\n }\n }\n\n s = s.previous;\n }\n\n return [];\n },\n\n /**\n * Import modules into a JessieCode script.\n * @param {String} module\n */\n importModule: function (module) {\n return priv.modules[module.toLowerCase()];\n },\n\n /**\n * Defines built in methods and constants.\n * @returns {Object} BuiltIn control object\n */\n defineBuiltIn: function () {\n var that = this,\n builtIn = {\n PI: Math.PI,\n EULER: Math.E,\n D: that.DDD,\n X: that.X,\n Y: that.Y,\n V: that.V,\n L: that.L,\n\n acosh: Mat.acosh,\n acot: Mat.acot,\n asinh: Mat.asinh,\n binomial: Mat.binomial,\n cbrt: Mat.cbrt,\n cosh: Mat.cosh,\n cot: Mat.cot,\n deg: Geometry.trueAngle,\n A: that.area,\n area: that.area,\n dist: that.dist,\n R: that.radius,\n radius: that.radius,\n erf: Mat.erf,\n erfc: Mat.erfc,\n erfi: Mat.erfi,\n factorial: Mat.factorial,\n gcd: Mat.gcd,\n lb: Mat.log2,\n lcm: Mat.lcm,\n ld: Mat.log2,\n lg: Mat.log10,\n ln: Math.log,\n log: Mat.log,\n log10: Mat.log10,\n log2: Mat.log2,\n ndtr: Mat.ndtr,\n ndtri: Mat.ndtri,\n nthroot: Mat.nthroot,\n pow: Mat.pow,\n rad: Geometry.rad,\n ratpow: Mat.ratpow,\n trunc: Type.trunc,\n sinh: Mat.sinh,\n\n randint: that.randint,\n\n IfThen: that.ifthen,\n 'import': that.importModule,\n 'use': that.use,\n 'remove': that.del,\n '$': that.getElementById,\n getName: that.getName,\n name: that.getName,\n '$board': that.board,\n '$log': that.log\n };\n\n // special scopes for factorial, deg, and rad\n builtIn.rad.sc = Geometry;\n builtIn.deg.sc = Geometry;\n builtIn.factorial.sc = Mat;\n\n // set the javascript equivalent for the builtIns\n // some of the anonymous functions should be replaced by global methods later on\n // EULER and PI don't get a source attribute - they will be lost anyways and apparently\n // some browser will throw an exception when a property is assigned to a primitive value.\n builtIn.X.src = '$jc$.X';\n builtIn.Y.src = '$jc$.Y';\n builtIn.V.src = '$jc$.V';\n builtIn.L.src = '$jc$.L';\n\n builtIn.acosh.src = 'JXG.Math.acosh';\n builtIn.acot.src = 'JXG.Math.acot';\n builtIn.asinh.src = 'JXG.Math.asinh';\n builtIn.binomial.src = 'JXG.Math.binomial';\n builtIn.cbrt.src = 'JXG.Math.cbrt';\n builtIn.cot.src = 'JXG.Math.cot';\n builtIn.cosh.src = 'JXG.Math.cosh';\n builtIn.deg.src = 'JXG.Math.Geometry.trueAngle';\n builtIn.erf.src = 'JXG.Math.erf';\n builtIn.erfc.src = 'JXG.Math.erfc';\n builtIn.erfi.src = 'JXG.Math.erfi';\n builtIn.A.src = '$jc$.area';\n builtIn.area.src = '$jc$.area';\n builtIn.dist.src = '$jc$.dist';\n builtIn.R.src = '$jc$.radius';\n builtIn.radius.src = '$jc$.radius';\n builtIn.factorial.src = 'JXG.Math.factorial';\n builtIn.gcd.src = 'JXG.Math.gcd';\n builtIn.lb.src = 'JXG.Math.log2';\n builtIn.lcm.src = 'JXG.Math.lcm';\n builtIn.ld.src = 'JXG.Math.log2';\n builtIn.lg.src = 'JXG.Math.log10';\n builtIn.ln.src = 'Math.log';\n builtIn.log.src = 'JXG.Math.log';\n builtIn.log10.src = 'JXG.Math.log10';\n builtIn.log2.src = 'JXG.Math.log2';\n builtIn.ndtr.src = 'JXG.Math.ndtr';\n builtIn.ndtri.src = 'JXG.Math.ndtri';\n builtIn.nthroot.src = 'JXG.Math.nthroot';\n builtIn.pow.src = 'JXG.Math.pow';\n builtIn.rad.src = 'JXG.Math.Geometry.rad';\n builtIn.ratpow.src = 'JXG.Math.ratpow';\n builtIn.trunc.src = 'JXG.trunc';\n builtIn.sinh.src = 'JXG.Math.sinh';\n\n builtIn.randint.src = '$jc$.randint';\n\n builtIn['import'].src = '$jc$.importModule';\n builtIn.use.src = '$jc$.use';\n builtIn.remove.src = '$jc$.del';\n builtIn.IfThen.src = '$jc$.ifthen';\n // usually unused, see node_op > op_execfun\n builtIn.$.src = '(function (n) { return $jc$.board.select(n); })';\n builtIn.getName.src = '$jc$.getName';\n builtIn.name.src = '$jc$.getName';\n if (builtIn.$board) {\n builtIn.$board.src = '$jc$.board';\n }\n builtIn.$log.src = '$jc$.log';\n\n return builtIn;\n },\n\n /**\n * Returns information about the possible functions and constants.\n * @returns {Object}\n */\n getPossibleOperands: function () {\n var FORBIDDEN = ['E'],\n jessiecode = this.defineBuiltIn(),\n math = Math,\n jc, ma, merge,\n i, j, p, len, e,\n funcs, funcsJC, consts, operands,\n sort, pack;\n\n sort = function (a, b) {\n return a.toLowerCase().localeCompare(b.toLowerCase());\n };\n\n pack = function (name, origin) {\n var that = null;\n\n if (origin === 'jc') that = jessiecode[name];\n else if (origin === 'Math') that = math[name];\n else return;\n\n if (FORBIDDEN.includes(name)) {\n return;\n } else if (JXG.isFunction(that)) {\n return {\n name: name,\n type: 'function',\n numParams: that.length,\n origin: origin,\n };\n } else if (JXG.isNumber(that)) {\n return {\n name: name,\n type: 'constant',\n value: that,\n origin: origin,\n };\n } else if (that !== undefined) {\n console.error('undefined type', that);\n }\n };\n\n jc = Object.getOwnPropertyNames(jessiecode).sort(sort);\n ma = Object.getOwnPropertyNames(math).sort(sort);\n merge = [];\n i = 0;\n j = 0;\n\n while (i < jc.length || j < ma.length) {\n if (jc[i] === ma[j]) {\n p = pack(ma[j], 'Math');\n if (JXG.exists(p)) merge.push(p);\n i++;\n j++;\n } else if (!JXG.exists(ma[j]) || jc[i].toLowerCase().localeCompare(ma[j].toLowerCase()) < 0) {\n p = pack(jc[i], 'jc');\n if (JXG.exists(p)) merge.push(p);\n i++;\n } else {\n p = pack(ma[j], 'Math');\n if (JXG.exists(p)) merge.push(p);\n j++;\n }\n }\n\n funcs = [];\n funcsJC = [];\n consts = [];\n operands = {};\n len = merge.length;\n for (i = 0; i < len; i++) {\n e = merge[i];\n switch (e.type) {\n case 'function':\n funcs.push(e.name);\n if (e.origin === 'jc')\n funcsJC.push(e.name);\n break;\n case 'constant':\n consts.push(e.name);\n break;\n }\n operands[e.name] = e;\n }\n\n return {\n all: operands,\n list: merge,\n functions: funcs,\n functions_jessiecode: funcsJC,\n constants: consts,\n };\n },\n\n /**\n * Output a debugging message. Uses debug console, if available. Otherwise an HTML element with the\n * id \"debug\" and an innerHTML property is used.\n * @param {String} log\n * @private\n */\n _debug: function (log) {\n if (typeof console === 'object') {\n console.log(log);\n } else if (Env.isBrowser && document && document.getElementById('debug') !== null) {\n document.getElementById('debug').innerHTML += log + '<br />';\n }\n },\n\n /**\n * Throws an exception with the given error message.\n * @param {String} msg Error message\n */\n _error: function (msg) {\n var e = new Error('Error(' + this.line + '): ' + msg);\n e.line = this.line;\n throw e;\n },\n\n /**\n * Output a warning message using {@link JXG#debug} and precedes the message with \"Warning: \".\n * @param {String} msg\n */\n _warn: function (msg) {\n if (typeof console === 'object') {\n console.log('Warning(' + this.line + '): ' + msg);\n } else if (Env.isBrowser && document && document.getElementById(this.warnLog) !== null) {\n document.getElementById(this.warnLog).innerHTML += 'Warning(' + this.line + '): ' + msg + '<br />';\n }\n },\n\n _log: function (msg) {\n if (typeof window !== 'object' && typeof self === 'object' && self.postMessage) {\n self.postMessage({type: 'log', msg: 'Log: ' + msg.toString()});\n } else {\n console.log('Log: ', arguments);\n }\n }\n\n });\n\n/* parser generated by jison 0.4.18 */\n/*\n Returns a Parser object of the following structure:\n\n Parser: {\n yy: {}\n }\n\n Parser.prototype: {\n yy: {},\n trace: function(),\n symbols_: {associative list: name ==> number},\n terminals_: {associative list: number ==> name},\n productions_: [...],\n performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate, $$, _$),\n table: [...],\n defaultActions: {...},\n parseError: function(str, hash),\n parse: function(input),\n\n lexer: {\n EOF: 1,\n parseError: function(str, hash),\n setInput: function(input),\n input: function(),\n unput: function(str),\n more: function(),\n less: function(n),\n pastInput: function(),\n upcomingInput: function(),\n showPosition: function(),\n test_match: function(regex_match_array, rule_index),\n next: function(),\n lex: function(),\n begin: function(condition),\n popState: function(),\n _currentRules: function(),\n topState: function(),\n pushState: function(condition),\n\n options: {\n ranges: boolean (optional: true ==> token location info will include a .range[] member)\n flex: boolean (optional: true ==> flex-like lexing behaviour where the rules are tested exhaustively to find the longest match)\n backtrack_lexer: boolean (optional: true ==> lexer regexes are tested in order and for each matching regex the action code is invoked; the lexer terminates the scan when a token is returned by the action code)\n },\n\n performAction: function(yy, yy_, $avoiding_name_collisions, YY_START),\n rules: [...],\n conditions: {associative list: name ==> set},\n }\n }\n\n\n token location info (@$, _$, etc.): {\n first_line: n,\n last_line: n,\n first_column: n,\n last_column: n,\n range: [start_number, end_number] (where the numbers are indexes into the input string, regular zero-based)\n }\n\n\n the parseError function receives a 'hash' object with these members for lexer and parser errors: {\n text: (matched text)\n token: (the produced terminal token, if any)\n line: (yylineno)\n }\n while parser (grammar) errors will also provide these members, i.e. parser errors deliver a superset of attributes: {\n loc: (yylloc)\n expected: (string describing the set of expected tokens)\n recoverable: (boolean: TRUE when the parser has a error recovery rule available for this particular error)\n }\n*/\nvar parser = (function(){\nvar o=function(k,v,o,l){for(o=o||{},l=k.length;l--;o[k[l]]=v);return o},$V0=[2,14],$V1=[1,13],$V2=[1,37],$V3=[1,14],$V4=[1,15],$V5=[1,21],$V6=[1,16],$V7=[1,17],$V8=[1,33],$V9=[1,18],$Va=[1,19],$Vb=[1,12],$Vc=[1,59],$Vd=[1,60],$Ve=[1,58],$Vf=[1,46],$Vg=[1,48],$Vh=[1,49],$Vi=[1,50],$Vj=[1,51],$Vk=[1,52],$Vl=[1,53],$Vm=[1,54],$Vn=[1,45],$Vo=[1,38],$Vp=[1,39],$Vq=[5,7,8,14,15,16,17,19,20,21,23,26,27,50,51,58,65,74,75,76,77,78,79,80,82,91,93],$Vr=[5,7,8,12,14,15,16,17,19,20,21,23,26,27,50,51,58,65,74,75,76,77,78,79,80,82,91,93],$Vs=[8,10,16,32,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,57,64,65,66,83,86],$Vt=[2,48],$Vu=[1,72],$Vv=[10,16,32,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,57,66,83,86],$Vw=[1,78],$Vx=[8,10,16,32,34,35,37,41,42,43,45,46,47,48,50,51,53,54,55,57,64,65,66,83,86],$Vy=[1,82],$Vz=[8,10,16,32,34,35,37,39,45,46,47,48,50,51,53,54,55,57,64,65,66,83,86],$VA=[1,83],$VB=[1,84],$VC=[1,85],$VD=[8,10,16,32,34,35,37,39,41,42,43,50,51,53,54,55,57,64,65,66,83,86],$VE=[1,89],$VF=[1,90],$VG=[1,91],$VH=[1,92],$VI=[1,97],$VJ=[8,10,16,32,34,35,37,39,41,42,43,45,46,47,48,53,54,55,57,64,65,66,83,86],$VK=[1,103],$VL=[1,104],$VM=[8,10,16,32,34,35,37,39,41,42,43,45,46,47,48,50,51,57,64,65,66,83,86],$VN=[1,105],$VO=[1,106],$VP=[1,107],$VQ=[1,126],$VR=[1,139],$VS=[83,86],$VT=[1,150],$VU=[10,66,86],$VV=[8,10,16,20,32,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,57,64,65,66,82,83,86],$VW=[1,167],$VX=[10,86];\nvar parser = {trace: function trace () { },\nyy: {},\nsymbols_: {\"error\":2,\"Program\":3,\"StatementList\":4,\"EOF\":5,\"IfStatement\":6,\"IF\":7,\"(\":8,\"Expression\":9,\")\":10,\"Statement\":11,\"ELSE\":12,\"LoopStatement\":13,\"WHILE\":14,\"FOR\":15,\";\":16,\"DO\":17,\"UnaryStatement\":18,\"USE\":19,\"IDENTIFIER\":20,\"DELETE\":21,\"ReturnStatement\":22,\"RETURN\":23,\"EmptyStatement\":24,\"StatementBlock\":25,\"{\":26,\"}\":27,\"ExpressionStatement\":28,\"AssignmentExpression\":29,\"ConditionalExpression\":30,\"LeftHandSideExpression\":31,\"=\":32,\"LogicalORExpression\":33,\"?\":34,\":\":35,\"LogicalANDExpression\":36,\"||\":37,\"EqualityExpression\":38,\"&&\":39,\"RelationalExpression\":40,\"==\":41,\"!=\":42,\"~=\":43,\"AdditiveExpression\":44,\"<\":45,\">\":46,\"<=\":47,\">=\":48,\"MultiplicativeExpression\":49,\"+\":50,\"-\":51,\"UnaryExpression\":52,\"*\":53,\"/\":54,\"%\":55,\"ExponentExpression\":56,\"^\":57,\"!\":58,\"MemberExpression\":59,\"CallExpression\":60,\"PrimaryExpression\":61,\"FunctionExpression\":62,\"MapExpression\":63,\".\":64,\"[\":65,\"]\":66,\"BasicLiteral\":67,\"ObjectLiteral\":68,\"ArrayLiteral\":69,\"NullLiteral\":70,\"BooleanLiteral\":71,\"StringLiteral\":72,\"NumberLiteral\":73,\"NULL\":74,\"TRUE\":75,\"FALSE\":76,\"STRING\":77,\"NUMBER\":78,\"NAN\":79,\"INFINITY\":80,\"ElementList\":81,\"<<\":82,\">>\":83,\"PropertyList\":84,\"Property\":85,\",\":86,\"PropertyName\":87,\"Arguments\":88,\"AttributeList\":89,\"Attribute\":90,\"FUNCTION\":91,\"ParameterDefinitionList\":92,\"MAP\":93,\"->\":94,\"$accept\":0,\"$end\":1},\nterminals_: {2:\"error\",5:\"EOF\",7:\"IF\",8:\"(\",10:\")\",12:\"ELSE\",14:\"WHILE\",15:\"FOR\",16:\";\",17:\"DO\",19:\"USE\",20:\"IDENTIFIER\",21:\"DELETE\",23:\"RETURN\",26:\"{\",27:\"}\",32:\"=\",34:\"?\",35:\":\",37:\"||\",39:\"&&\",41:\"==\",42:\"!=\",43:\"~=\",45:\"<\",46:\">\",47:\"<=\",48:\">=\",50:\"+\",51:\"-\",53:\"*\",54:\"/\",55:\"%\",57:\"^\",58:\"!\",64:\".\",65:\"[\",66:\"]\",74:\"NULL\",75:\"TRUE\",76:\"FALSE\",77:\"STRING\",78:\"NUMBER\",79:\"NAN\",80:\"INFINITY\",82:\"<<\",83:\">>\",86:\",\",91:\"FUNCTION\",93:\"MAP\",94:\"->\"},\nproductions_: [0,[3,2],[6,5],[6,7],[13,5],[13,9],[13,7],[18,2],[18,2],[22,2],[22,3],[24,1],[25,3],[4,2],[4,0],[11,1],[11,1],[11,1],[11,1],[11,1],[11,1],[11,1],[28,2],[9,1],[29,1],[29,3],[30,1],[30,5],[33,1],[33,3],[36,1],[36,3],[38,1],[38,3],[38,3],[38,3],[40,1],[40,3],[40,3],[40,3],[40,3],[44,1],[44,3],[44,3],[49,1],[49,3],[49,3],[49,3],[56,1],[56,3],[52,1],[52,2],[52,2],[52,2],[31,1],[31,1],[59,1],[59,1],[59,1],[59,3],[59,4],[61,1],[61,1],[61,1],[61,1],[61,3],[67,1],[67,1],[67,1],[67,1],[70,1],[71,1],[71,1],[72,1],[73,1],[73,1],[73,1],[69,2],[69,3],[68,2],[68,3],[84,1],[84,3],[85,3],[87,1],[87,1],[87,1],[60,2],[60,3],[60,2],[60,4],[60,3],[88,2],[88,3],[89,1],[89,3],[90,1],[90,1],[81,1],[81,3],[62,4],[62,5],[63,5],[63,6],[92,1],[92,3]],\nperformAction: function anonymous(yytext, yyleng, yylineno, yy, yystate /* action[1] */, $$ /* vstack */, _$ /* lstack */) {\n/* this == yyval */\n\nvar $0 = $$.length - 1;\nswitch (yystate) {\ncase 1:\n return $$[$0-1]; \nbreak;\ncase 2:\n this.$ = AST.createNode(lc(_$[$0-4]), 'node_op', 'op_if', $$[$0-2], $$[$0]); \nbreak;\ncase 3:\n this.$ = AST.createNode(lc(_$[$0-6]), 'node_op', 'op_if_else', $$[$0-4], $$[$0-2], $$[$0]); \nbreak;\ncase 4:\n this.$ = AST.createNode(lc(_$[$0-4]), 'node_op', 'op_while', $$[$0-2], $$[$0]); \nbreak;\ncase 5:\n this.$ = AST.createNode(lc(_$[$0-8]), 'node_op', 'op_for', $$[$0-6], $$[$0-4], $$[$0-2], $$[$0]); \nbreak;\ncase 6:\n this.$ = AST.createNode(lc(_$[$0-6]), 'node_op', 'op_do', $$[$0-5], $$[$0-2]); \nbreak;\ncase 7:\n this.$ = AST.createNode(lc(_$[$0-1]), 'node_op', 'op_use', $$[$0]); \nbreak;\ncase 8:\n this.$ = AST.createNode(lc(_$[$0-1]), 'node_op', 'op_delete', $$[$0]); \nbreak;\ncase 9:\n this.$ = AST.createNode(lc(_$[$0-1]), 'node_op', 'op_return', undefined); \nbreak;\ncase 10:\n this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_return', $$[$0-1]); \nbreak;\ncase 11: case 14:\n this.$ = AST.createNode(lc(_$[$0]), 'node_op', 'op_none'); \nbreak;\ncase 12:\n this.$ = $$[$0-1]; this.$.needsBrackets = true; \nbreak;\ncase 13:\n this.$ = AST.createNode(lc(_$[$0-1]), 'node_op', 'op_none', $$[$0-1], $$[$0]); \nbreak;\ncase 15: case 16: case 17: case 18: case 19: case 20: case 21: case 23: case 24: case 26: case 28: case 30: case 32: case 36: case 41: case 44: case 48: case 50: case 52: case 54: case 55: case 56: case 58: case 62: case 81: case 84: case 85: case 86:\n this.$ = $$[$0]; \nbreak;\ncase 22: case 65: case 93:\n this.$ = $$[$0-1]; \nbreak;\ncase 25:\n this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_assign', $$[$0-2], $$[$0]); this.$.isMath = false; \nbreak;\ncase 27:\n this.$ = AST.createNode(lc(_$[$0-4]), 'node_op', 'op_conditional', $$[$0-4], $$[$0-2], $$[$0]); this.$.isMath = false; \nbreak;\ncase 29:\n this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_or', $$[$0-2], $$[$0]); this.$.isMath = false; \nbreak;\ncase 31:\n this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_and', $$[$0-2], $$[$0]); this.$.isMath = false; \nbreak;\ncase 33:\n this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_eq', $$[$0-2], $$[$0]); this.$.isMath = false; \nbreak;\ncase 34:\n this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_neq', $$[$0-2], $$[$0]); this.$.isMath = false; \nbreak;\ncase 35:\n this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_approx', $$[$0-2], $$[$0]); this.$.isMath = false; \nbreak;\ncase 37:\n this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_lt', $$[$0-2], $$[$0]); this.$.isMath = false; \nbreak;\ncase 38:\n this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_gt', $$[$0-2], $$[$0]); this.$.isMath = false; \nbreak;\ncase 39:\n this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_leq', $$[$0-2], $$[$0]); this.$.isMath = false; \nbreak;\ncase 40:\n this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_geq', $$[$0-2], $$[$0]); this.$.isMath = false; \nbreak;\ncase 42:\n this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_add', $$[$0-2], $$[$0]); this.$.isMath = true; \nbreak;\ncase 43:\n this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_sub', $$[$0-2], $$[$0]); this.$.isMath = true; \nbreak;\ncase 45:\n this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_mul', $$[$0-2], $$[$0]); this.$.isMath = true; \nbreak;\ncase 46:\n this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_div', $$[$0-2], $$[$0]); this.$.isMath = true; \nbreak;\ncase 47:\n this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_mod', $$[$0-2], $$[$0]); this.$.isMath = true; \nbreak;\ncase 49:\n this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_exp', $$[$0-2], $$[$0]); this.$.isMath = true; \nbreak;\ncase 51:\n this.$ = AST.createNode(lc(_$[$0-1]), 'node_op', 'op_not', $$[$0]); this.$.isMath = false; \nbreak;\ncase 53:\n this.$ = AST.createNode(lc(_$[$0-1]), 'node_op', 'op_neg', $$[$0]); this.$.isMath = true; \nbreak;\ncase 57: case 63: case 64: case 66: case 67: case 68: case 97:\n this.$ = $$[$0]; this.$.isMath = false; \nbreak;\ncase 59: case 91:\n this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_property', $$[$0-2], $$[$0]); this.$.isMath = true; \nbreak;\ncase 60: case 90:\n this.$ = AST.createNode(lc(_$[$0-3]), 'node_op', 'op_extvalue', $$[$0-3], $$[$0-1]); this.$.isMath = true; \nbreak;\ncase 61:\n this.$ = AST.createNode(lc(_$[$0]), 'node_var', $$[$0]); \nbreak;\ncase 69:\n this.$ = $$[$0]; this.$.isMath = true; \nbreak;\ncase 70:\n this.$ = AST.createNode(lc(_$[$0]), 'node_const', null); \nbreak;\ncase 71:\n this.$ = AST.createNode(lc(_$[$0]), 'node_const_bool', true); \nbreak;\ncase 72:\n this.$ = AST.createNode(lc(_$[$0]), 'node_const_bool', false); \nbreak;\ncase 73:\n this.$ = AST.createNode(lc(_$[$0]), 'node_str', $$[$0].substring(1, $$[$0].length - 1)); \nbreak;\ncase 74:\n this.$ = AST.createNode(lc(_$[$0]), 'node_const', parseFloat($$[$0])); \nbreak;\ncase 75:\n this.$ = AST.createNode(lc(_$[$0]), 'node_const', NaN); \nbreak;\ncase 76:\n this.$ = AST.createNode(lc(_$[$0]), 'node_const', Infinity); \nbreak;\ncase 77:\n this.$ = AST.createNode(lc(_$[$0-1]), 'node_op', 'op_array', []); \nbreak;\ncase 78:\n this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_array', $$[$0-1]); \nbreak;\ncase 79:\n this.$ = AST.createNode(lc(_$[$0-1]), 'node_op', 'op_emptyobject', {}); this.$.needsBrackets = true; \nbreak;\ncase 80:\n this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_proplst_val', $$[$0-1]); this.$.needsBrackets = true; \nbreak;\ncase 82:\n this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_proplst', $$[$0-2], $$[$0]); \nbreak;\ncase 83:\n this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_prop', $$[$0-2], $$[$0]); \nbreak;\ncase 87: case 89:\n this.$ = AST.createNode(lc(_$[$0-1]), 'node_op', 'op_execfun', $$[$0-1], $$[$0]); this.$.isMath = true; \nbreak;\ncase 88:\n this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_execfun', $$[$0-2], $$[$0-1], $$[$0], true); this.$.isMath = false; \nbreak;\ncase 92:\n this.$ = []; \nbreak;\ncase 94: case 98: case 104:\n this.$ = [$$[$0]]; \nbreak;\ncase 95: case 99: case 105:\n this.$ = $$[$0-2].concat($$[$0]); \nbreak;\ncase 96:\n this.$ = AST.createNode(lc(_$[$0]), 'node_var', $$[$0]); this.$.isMath = true; \nbreak;\ncase 100:\n this.$ = AST.createNode(lc(_$[$0-3]), 'node_op', 'op_function', [], $$[$0]); this.$.isMath = false; \nbreak;\ncase 101:\n this.$ = AST.createNode(lc(_$[$0-4]), 'node_op', 'op_function', $$[$0-2], $$[$0]); this.$.isMath = false; \nbreak;\ncase 102:\n this.$ = AST.createNode(lc(_$[$0-4]), 'node_op', 'op_map', [], $$[$0]); \nbreak;\ncase 103:\n this.$ = AST.createNode(lc(_$[$0-5]), 'node_op', 'op_map', $$[$0-3], $$[$0]); \nbreak;\n}\n},\ntable: [o([5,7,8,14,15,16,17,19,20,21,23,26,50,51,58,65,74,75,76,77,78,79,80,82,91,93],$V0,{3:1,4:2}),{1:[3]},{5:[1,3],6:6,7:$V1,8:$V2,9:20,11:4,13:7,14:$V3,15:$V4,16:$V5,17:$V6,18:8,19:$V7,20:$V8,21:$V9,22:9,23:$Va,24:11,25:5,26:$Vb,28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{1:[2,1]},o($Vq,[2,13]),o($Vr,[2,15]),o($Vr,[2,16]),o($Vr,[2,17]),o($Vr,[2,18]),o($Vr,[2,19]),o($Vr,[2,20]),o($Vr,[2,21]),o([7,8,14,15,16,17,19,20,21,23,26,27,50,51,58,65,74,75,76,77,78,79,80,82,91,93],$V0,{4:61}),{8:[1,62]},{8:[1,63]},{8:[1,64]},{6:6,7:$V1,8:$V2,9:20,11:65,13:7,14:$V3,15:$V4,16:$V5,17:$V6,18:8,19:$V7,20:$V8,21:$V9,22:9,23:$Va,24:11,25:5,26:$Vb,28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{20:[1,66]},{20:[1,67]},{8:$V2,9:69,16:[1,68],20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{16:[1,70]},o($Vr,[2,11]),o($Vs,[2,23]),o($Vs,[2,24]),o([8,10,16,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,64,65,66,83,86],$Vt,{32:[1,71],57:$Vu}),o([8,10,16,32,35,39,41,42,43,45,46,47,48,50,51,53,54,55,57,64,65,66,83,86],[2,26],{34:[1,73],37:[1,74]}),o($Vv,[2,54],{88:77,8:$Vw,64:[1,75],65:[1,76]}),o($Vv,[2,55],{88:79,8:$Vw,64:[1,81],65:[1,80]}),o($Vx,[2,28],{39:$Vy}),o($Vs,[2,56]),o($Vs,[2,57]),o($Vs,[2,58]),o($Vz,[2,30],{41:$VA,42:$VB,43:$VC}),o($Vs,[2,61]),o($Vs,[2,62]),o($Vs,[2,63]),o($Vs,[2,64]),{8:$V2,9:86,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:[1,87]},{8:[1,88]},o($VD,[2,32],{45:$VE,46:$VF,47:$VG,48:$VH}),o($Vs,[2,66]),o($Vs,[2,67]),o($Vs,[2,68]),o($Vs,[2,69]),{20:$VI,72:98,73:99,77:$Vj,78:$Vk,79:$Vl,80:$Vm,83:[1,93],84:94,85:95,87:96},{8:$V2,20:$V8,29:102,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,66:[1,100],67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,81:101,82:$Vn,91:$Vo,93:$Vp},o($VJ,[2,36],{50:$VK,51:$VL}),o($Vs,[2,70]),o($Vs,[2,71]),o($Vs,[2,72]),o($Vs,[2,73]),o($Vs,[2,74]),o($Vs,[2,75]),o($Vs,[2,76]),o($VM,[2,41],{53:$VN,54:$VO,55:$VP}),o($Vs,[2,44]),o($Vs,[2,50]),{8:$V2,20:$V8,31:109,50:$Vc,51:$Vd,52:108,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,50:$Vc,51:$Vd,52:110,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,50:$Vc,51:$Vd,52:111,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{6:6,7:$V1,8:$V2,9:20,11:4,13:7,14:$V3,15:$V4,16:$V5,17:$V6,18:8,19:$V7,20:$V8,21:$V9,22:9,23:$Va,24:11,25:5,26:$Vb,27:[1,112],28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,9:113,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,9:114,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,9:115,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{14:[1,116]},o($Vr,[2,7]),o($Vr,[2,8]),o($Vr,[2,9]),{16:[1,117]},o($Vr,[2,22]),{8:$V2,20:$V8,29:118,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,50:$Vc,51:$Vd,52:119,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,29:120,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,36:121,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{20:[1,122]},{8:$V2,9:123,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},o($Vs,[2,87],{89:124,90:125,68:127,20:$VQ,82:$Vn}),{8:$V2,10:[1,128],20:$V8,29:102,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,81:129,82:$Vn,91:$Vo,93:$Vp},o($Vs,[2,89]),{8:$V2,9:130,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{20:[1,131]},{8:$V2,20:$V8,31:109,38:132,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,40:133,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,40:134,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,40:135,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{10:[1,136]},{10:[1,137],20:$VR,92:138},{10:[1,140],20:$VR,92:141},{8:$V2,20:$V8,31:109,44:142,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,44:143,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,44:144,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,44:145,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},o($Vs,[2,79]),{83:[1,146],86:[1,147]},o($VS,[2,81]),{35:[1,148]},{35:[2,84]},{35:[2,85]},{35:[2,86]},o($Vs,[2,77]),{66:[1,149],86:$VT},o($VU,[2,98]),{8:$V2,20:$V8,31:109,49:151,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,49:152,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,50:$Vc,51:$Vd,52:153,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,50:$Vc,51:$Vd,52:154,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,50:$Vc,51:$Vd,52:155,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},o($Vs,[2,51]),o([8,10,16,32,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,64,65,66,83,86],$Vt,{57:$Vu}),o($Vs,[2,52]),o($Vs,[2,53]),o([5,7,8,10,12,14,15,16,17,19,20,21,23,26,27,32,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,57,58,64,65,66,74,75,76,77,78,79,80,82,83,86,91,93],[2,12]),{10:[1,156]},{10:[1,157]},{16:[1,158]},{8:[1,159]},o($Vr,[2,10]),o($Vs,[2,25]),o($Vs,[2,49]),{35:[1,160]},o($Vx,[2,29],{39:$Vy}),o($Vs,[2,59]),{66:[1,161]},o([8,10,16,32,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,57,64,65,66,83],[2,88],{86:[1,162]}),o($Vs,[2,94]),o($Vs,[2,96]),o($Vs,[2,97]),o($VV,[2,92]),{10:[1,163],86:$VT},{66:[1,164]},o($Vs,[2,91]),o($Vz,[2,31],{41:$VA,42:$VB,43:$VC}),o($VD,[2,33],{45:$VE,46:$VF,47:$VG,48:$VH}),o($VD,[2,34],{45:$VE,46:$VF,47:$VG,48:$VH}),o($VD,[2,35],{45:$VE,46:$VF,47:$VG,48:$VH}),o($Vs,[2,65]),{25:165,26:$Vb},{10:[1,166],86:$VW},o($VX,[2,104]),{94:[1,168]},{10:[1,169],86:$VW},o($VJ,[2,37],{50:$VK,51:$VL}),o($VJ,[2,38],{50:$VK,51:$VL}),o($VJ,[2,39],{50:$VK,51:$VL}),o($VJ,[2,40],{50:$VK,51:$VL}),o($Vs,[2,80]),{20:$VI,72:98,73:99,77:$Vj,78:$Vk,79:$Vl,80:$Vm,85:170,87:96},{8:$V2,20:$V8,29:171,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},o($Vs,[2,78]),{8:$V2,20:$V8,29:172,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},o($VM,[2,42],{53:$VN,54:$VO,55:$VP}),o($VM,[2,43],{53:$VN,54:$VO,55:$VP}),o($Vs,[2,45]),o($Vs,[2,46]),o($Vs,[2,47]),{6:6,7:$V1,8:$V2,9:20,11:173,13:7,14:$V3,15:$V4,16:$V5,17:$V6,18:8,19:$V7,20:$V8,21:$V9,22:9,23:$Va,24:11,25:5,26:$Vb,28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{6:6,7:$V1,8:$V2,9:20,11:174,13:7,14:$V3,15:$V4,16:$V5,17:$V6,18:8,19:$V7,20:$V8,21:$V9,22:9,23:$Va,24:11,25:5,26:$Vb,28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,9:175,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,9:176,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,29:177,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},o($Vs,[2,60]),{20:$VQ,68:127,82:$Vn,90:178},o($VV,[2,93]),o($Vs,[2,90]),o($Vs,[2,100]),{25:179,26:$Vb},{20:[1,180]},{8:$V2,9:181,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{94:[1,182]},o($VS,[2,82]),o($VS,[2,83]),o($VU,[2,99]),o($Vq,[2,2],{12:[1,183]}),o($Vr,[2,4]),{16:[1,184]},{10:[1,185]},o($Vs,[2,27]),o($Vs,[2,95]),o($Vs,[2,101]),o($VX,[2,105]),o($Vs,[2,102]),{8:$V2,9:186,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{6:6,7:$V1,8:$V2,9:20,11:187,13:7,14:$V3,15:$V4,16:$V5,17:$V6,18:8,19:$V7,20:$V8,21:$V9,22:9,23:$Va,24:11,25:5,26:$Vb,28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,9:188,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{16:[1,189]},o($Vs,[2,103]),o($Vr,[2,3]),{10:[1,190]},o($Vr,[2,6]),{6:6,7:$V1,8:$V2,9:20,11:191,13:7,14:$V3,15:$V4,16:$V5,17:$V6,18:8,19:$V7,20:$V8,21:$V9,22:9,23:$Va,24:11,25:5,26:$Vb,28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},o($Vr,[2,5])],\ndefaultActions: {3:[2,1],97:[2,84],98:[2,85],99:[2,86]},\nparseError: function parseError (str, hash) {\n if (hash.recoverable) {\n this.trace(str);\n } else {\n var error = new Error(str);\n error.hash = hash;\n throw error;\n }\n},\nparse: function parse(input) {\n var self = this, stack = [0], tstack = [], vstack = [null], lstack = [], table = this.table, yytext = '', yylineno = 0, yyleng = 0, recovering = 0, TERROR = 2, EOF = 1;\n var args = lstack.slice.call(arguments, 1);\n var lexer = Object.create(this.lexer);\n var sharedState = { yy: {} };\n for (var k in this.yy) {\n if (Object.prototype.hasOwnProperty.call(this.yy, k)) {\n sharedState.yy[k] = this.yy[k];\n }\n }\n lexer.setInput(input, sharedState.yy);\n sharedState.yy.lexer = lexer;\n sharedState.yy.parser = this;\n if (typeof lexer.yylloc == 'undefined') {\n lexer.yylloc = {};\n }\n var yyloc = lexer.yylloc;\n lstack.push(yyloc);\n var ranges = lexer.options && lexer.options.ranges;\n if (typeof sharedState.yy.parseError === 'function') {\n this.parseError = sharedState.yy.parseError;\n } else {\n this.parseError = Object.getPrototypeOf(this).parseError;\n }\n function popStack(n) {\n stack.length = stack.length - 2 * n;\n vstack.length = vstack.length - n;\n lstack.length = lstack.length - n;\n }\n _token_stack:\n var lex = function () {\n var token;\n token = lexer.lex() || EOF;\n if (typeof token !== 'number') {\n token = self.symbols_[token] || token;\n }\n return token;\n };\n var symbol, preErrorSymbol, state, action, a, r, yyval = {}, p, len, newState, expected;\n while (true) {\n state = stack[stack.length - 1];\n if (this.defaultActions[state]) {\n action = this.defaultActions[state];\n } else {\n if (symbol === null || typeof symbol == 'undefined') {\n symbol = lex();\n }\n action = table[state] && table[state][symbol];\n }\n if (typeof action === 'undefined' || !action.length || !action[0]) {\n var errStr = '';\n expected = [];\n for (p in table[state]) {\n if (this.terminals_[p] && p > TERROR) {\n expected.push('\\'' + this.terminals_[p] + '\\'');\n }\n }\n if (lexer.showPosition) {\n errStr = 'Parse error on line ' + (yylineno + 1) + ':\\n' + lexer.showPosition() + '\\nExpecting ' + expected.join(', ') + ', got \\'' + (this.terminals_[symbol] || symbol) + '\\'';\n } else {\n errStr = 'Parse error on line ' + (yylineno + 1) + ': Unexpected ' + (symbol == EOF ? 'end of input' : '\\'' + (this.terminals_[symbol] || symbol) + '\\'');\n }\n this.parseError(errStr, {\n text: lexer.match,\n token: this.terminals_[symbol] || symbol,\n line: lexer.yylineno,\n loc: yyloc,\n expected: expected\n });\n }\n if (action[0] instanceof Array && action.length > 1) {\n throw new Error('Parse Error: multiple actions possible at state: ' + state + ', token: ' + symbol);\n }\n switch (action[0]) {\n case 1:\n stack.push(symbol);\n vstack.push(lexer.yytext);\n lstack.push(lexer.yylloc);\n stack.push(action[1]);\n symbol = null;\n if (!preErrorSymbol) {\n yyleng = lexer.yyleng;\n yytext = lexer.yytext;\n yylineno = lexer.yylineno;\n yyloc = lexer.yylloc;\n if (recovering > 0) {\n recovering--;\n }\n } else {\n symbol = preErrorSymbol;\n preErrorSymbol = null;\n }\n break;\n case 2:\n len = this.productions_[action[1]][1];\n yyval.$ = vstack[vstack.length - len];\n yyval._$ = {\n first_line: lstack[lstack.length - (len || 1)].first_line,\n last_line: lstack[lstack.length - 1].last_line,\n first_column: lstack[lstack.length - (len || 1)].first_column,\n last_column: lstack[lstack.length - 1].last_column\n };\n if (ranges) {\n yyval._$.range = [\n lstack[lstack.length - (len || 1)].range[0],\n lstack[lstack.length - 1].range[1]\n ];\n }\n r = this.performAction.apply(yyval, [\n yytext,\n yyleng,\n yylineno,\n sharedState.yy,\n action[1],\n vstack,\n lstack\n ].concat(args));\n if (typeof r !== 'undefined') {\n return r;\n }\n if (len) {\n stack = stack.slice(0, -1 * len * 2);\n vstack = vstack.slice(0, -1 * len);\n lstack = lstack.slice(0, -1 * len);\n }\n stack.push(this.productions_[action[1]][0]);\n vstack.push(yyval.$);\n lstack.push(yyval._$);\n newState = table[stack[stack.length - 2]][stack[stack.length - 1]];\n stack.push(newState);\n break;\n case 3:\n return true;\n }\n }\n return true;\n}};\n\n\n var AST = {\n node: function (type, value, children) {\n return {\n type: type,\n value: value,\n children: children\n };\n },\n\n createNode: function (pos, type, value, children) {\n var i,\n n = this.node(type, value, []);\n\n for (i = 3; i < arguments.length; i++) {\n n.children.push(arguments[i]);\n }\n\n n.line = pos[0];\n n.col = pos[1];\n n.eline = pos[2];\n n.ecol = pos[3];\n\n return n;\n }\n };\n\n var lc = function (lc1) {\n return [lc1.first_line, lc1.first_column, lc1.last_line, lc1.last_column];\n };\n\n/* generated by jison-lex 0.3.4 */\nvar lexer = (function(){\nvar lexer = ({\n\nEOF:1,\n\nparseError:function parseError(str, hash) {\n if (this.yy.parser) {\n this.yy.parser.parseError(str, hash);\n } else {\n throw new Error(str);\n }\n },\n\n// resets the lexer, sets new input\nsetInput:function (input, yy) {\n this.yy = yy || this.yy || {};\n this._input = input;\n this._more = this._backtrack = this.done = false;\n this.yylineno = this.yyleng = 0;\n this.yytext = this.matched = this.match = '';\n this.conditionStack = ['INITIAL'];\n this.yylloc = {\n first_line: 1,\n first_column: 0,\n last_line: 1,\n last_column: 0\n };\n if (this.options.ranges) {\n this.yylloc.range = [0,0];\n }\n this.offset = 0;\n return this;\n },\n\n// consumes and returns one char from the input\ninput:function () {\n var ch = this._input[0];\n this.yytext += ch;\n this.yyleng++;\n this.offset++;\n this.match += ch;\n this.matched += ch;\n var lines = ch.match(/(?:\\r\\n?|\\n).*/g);\n if (lines) {\n this.yylineno++;\n this.yylloc.last_line++;\n } else {\n this.yylloc.last_column++;\n }\n if (this.options.ranges) {\n this.yylloc.range[1]++;\n }\n\n this._input = this._input.slice(1);\n return ch;\n },\n\n// unshifts one char (or a string) into the input\nunput:function (ch) {\n var len = ch.length;\n var lines = ch.split(/(?:\\r\\n?|\\n)/g);\n\n this._input = ch + this._input;\n this.yytext = this.yytext.substr(0, this.yytext.length - len);\n //this.yyleng -= len;\n this.offset -= len;\n var oldLines = this.match.split(/(?:\\r\\n?|\\n)/g);\n this.match = this.match.substr(0, this.match.length - 1);\n this.matched = this.matched.substr(0, this.matched.length - 1);\n\n if (lines.length - 1) {\n this.yylineno -= lines.length - 1;\n }\n var r = this.yylloc.range;\n\n this.yylloc = {\n first_line: this.yylloc.first_line,\n last_line: this.yylineno + 1,\n first_column: this.yylloc.first_column,\n last_column: lines ?\n (lines.length === oldLines.length ? this.yylloc.first_column : 0)\n + oldLines[oldLines.length - lines.length].length - lines[0].length :\n this.yylloc.first_column - len\n };\n\n if (this.options.ranges) {\n this.yylloc.range = [r[0], r[0] + this.yyleng - len];\n }\n this.yyleng = this.yytext.length;\n return this;\n },\n\n// When called from action, caches matched text and appends it on next action\nmore:function () {\n this._more = true;\n return this;\n },\n\n// When called from action, signals the lexer that this rule fails to match the input, so the next matching rule (regex) should be tested instead.\nreject:function () {\n if (this.options.backtrack_lexer) {\n this._backtrack = true;\n } else {\n return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\\n' + this.showPosition(), {\n text: \"\",\n token: null,\n line: this.yylineno\n });\n\n }\n return this;\n },\n\n// retain first n characters of the match\nless:function (n) {\n this.unput(this.match.slice(n));\n },\n\n// displays already matched input, i.e. for error messages\npastInput:function () {\n var past = this.matched.substr(0, this.matched.length - this.match.length);\n return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\\n/g, \"\");\n },\n\n// displays upcoming input, i.e. for error messages\nupcomingInput:function () {\n var next = this.match;\n if (next.length < 20) {\n next += this._input.substr(0, 20-next.length);\n }\n return (next.substr(0,20) + (next.length > 20 ? '...' : '')).replace(/\\n/g, \"\");\n },\n\n// displays the character position where the lexing error occurred, i.e. for error messages\nshowPosition:function () {\n var pre = this.pastInput();\n var c = new Array(pre.length + 1).join(\"-\");\n return pre + this.upcomingInput() + \"\\n\" + c + \"^\";\n },\n\n// test the lexed token: return FALSE when not a match, otherwise return token\ntest_match:function(match, indexed_rule) {\n var token,\n lines,\n backup;\n\n if (this.options.backtrack_lexer) {\n // save context\n backup = {\n yylineno: this.yylineno,\n yylloc: {\n first_line: this.yylloc.first_line,\n last_line: this.last_line,\n first_column: this.yylloc.first_column,\n last_column: this.yylloc.last_column\n },\n yytext: this.yytext,\n match: this.match,\n matches: this.matches,\n matched: this.matched,\n yyleng: this.yyleng,\n offset: this.offset,\n _more: this._more,\n _input: this._input,\n yy: this.yy,\n conditionStack: this.conditionStack.slice(0),\n done: this.done\n };\n if (this.options.ranges) {\n backup.yylloc.range = this.yylloc.range.slice(0);\n }\n }\n\n lines = match[0].match(/(?:\\r\\n?|\\n).*/g);\n if (lines) {\n this.yylineno += lines.length;\n }\n this.yylloc = {\n first_line: this.yylloc.last_line,\n last_line: this.yylineno + 1,\n first_column: this.yylloc.last_column,\n last_column: lines ?\n lines[lines.length - 1].length - lines[lines.length - 1].match(/\\r?\\n?/)[0].length :\n this.yylloc.last_column + match[0].length\n };\n this.yytext += match[0];\n this.match += match[0];\n this.matches = match;\n this.yyleng = this.yytext.length;\n if (this.options.ranges) {\n this.yylloc.range = [this.offset, this.offset += this.yyleng];\n }\n this._more = false;\n this._backtrack = false;\n this._input = this._input.slice(match[0].length);\n this.matched += match[0];\n token = this.performAction.call(this, this.yy, this, indexed_rule, this.conditionStack[this.conditionStack.length - 1]);\n if (this.done && this._input) {\n this.done = false;\n }\n if (token) {\n return token;\n } else if (this._backtrack) {\n // recover context\n for (var k in backup) {\n this[k] = backup[k];\n }\n return false; // rule action called reject() implying the next rule should be tested instead.\n }\n return false;\n },\n\n// return next match in input\nnext:function () {\n if (this.done) {\n return this.EOF;\n }\n if (!this._input) {\n this.done = true;\n }\n\n var token,\n match,\n tempMatch,\n index;\n if (!this._more) {\n this.yytext = '';\n this.match = '';\n }\n var rules = this._currentRules();\n for (var i = 0; i < rules.length; i++) {\n tempMatch = this._input.match(this.rules[rules[i]]);\n if (tempMatch && (!match || tempMatch[0].length > match[0].length)) {\n match = tempMatch;\n index = i;\n if (this.options.backtrack_lexer) {\n token = this.test_match(tempMatch, rules[i]);\n if (token !== false) {\n return token;\n } else if (this._backtrack) {\n match = false;\n continue; // rule action called reject() implying a rule MISmatch.\n } else {\n // else: this is a lexer rule which consumes input without producing a token (e.g. whitespace)\n return false;\n }\n } else if (!this.options.flex) {\n break;\n }\n }\n }\n if (match) {\n token = this.test_match(match, rules[index]);\n if (token !== false) {\n return token;\n }\n // else: this is a lexer rule which consumes input without producing a token (e.g. whitespace)\n return false;\n }\n if (this._input === \"\") {\n return this.EOF;\n } else {\n return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. Unrecognized text.\\n' + this.showPosition(), {\n text: \"\",\n token: null,\n line: this.yylineno\n });\n }\n },\n\n// return next match that has a token\nlex:function lex () {\n var r = this.next();\n if (r) {\n return r;\n } else {\n return this.lex();\n }\n },\n\n// activates a new lexer condition state (pushes the new lexer condition state onto the condition stack)\nbegin:function begin (condition) {\n this.conditionStack.push(condition);\n },\n\n// pop the previously active lexer condition state off the condition stack\npopState:function popState () {\n var n = this.conditionStack.length - 1;\n if (n > 0) {\n return this.conditionStack.pop();\n } else {\n return this.conditionStack[0];\n }\n },\n\n// produce the lexer rule set which is active for the currently active lexer condition state\n_currentRules:function _currentRules () {\n if (this.conditionStack.length && this.conditionStack[this.conditionStack.length - 1]) {\n return this.conditions[this.conditionStack[this.conditionStack.length - 1]].rules;\n } else {\n return this.conditions[\"INITIAL\"].rules;\n }\n },\n\n// return the currently active lexer condition state; when an index argument is provided it produces the N-th previous condition state, if available\ntopState:function topState (n) {\n n = this.conditionStack.length - 1 - Math.abs(n || 0);\n if (n >= 0) {\n return this.conditionStack[n];\n } else {\n return \"INITIAL\";\n }\n },\n\n// alias for begin(condition)\npushState:function pushState (condition) {\n this.begin(condition);\n },\n\n// return the number of states currently on the stack\nstateStackSize:function stateStackSize() {\n return this.conditionStack.length;\n },\noptions: {},\nperformAction: function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) {\nvar YYSTATE=YY_START;\nswitch($avoiding_name_collisions) {\ncase 0:/* ignore */\nbreak;\ncase 1:return 78\nbreak;\ncase 2:return 78\nbreak;\ncase 3: return 77; \nbreak;\ncase 4: return 77; \nbreak;\ncase 5:/* ignore comment */\nbreak;\ncase 6:/* ignore multiline comment */\nbreak;\ncase 7:return 7\nbreak;\ncase 8:return 12\nbreak;\ncase 9:return 14\nbreak;\ncase 10:return 17\nbreak;\ncase 11:return 15\nbreak;\ncase 12:return 91\nbreak;\ncase 13:return 93\nbreak;\ncase 14:return 19\nbreak;\ncase 15:return 23\nbreak;\ncase 16:return 21\nbreak;\ncase 17:return 75\nbreak;\ncase 18:return 76\nbreak;\ncase 19:return 74\nbreak;\ncase 20:return 80\nbreak;\ncase 21:return 94\nbreak;\ncase 22:return 94\nbreak;\ncase 23:return 82\nbreak;\ncase 24:return 83\nbreak;\ncase 25:return 26\nbreak;\ncase 26:return 27\nbreak;\ncase 27:return 16\nbreak;\ncase 28:return '#'\nbreak;\ncase 29:return 34\nbreak;\ncase 30:return 35\nbreak;\ncase 31:return 79\nbreak;\ncase 32:return 64\nbreak;\ncase 33:return 65\nbreak;\ncase 34:return 66\nbreak;\ncase 35:return 8\nbreak;\ncase 36:return 10\nbreak;\ncase 37:return 58\nbreak;\ncase 38:return 57\nbreak;\ncase 39:return 53\nbreak;\ncase 40:return 54\nbreak;\ncase 41:return 55\nbreak;\ncase 42:return 50\nbreak;\ncase 43:return 51\nbreak;\ncase 44:return 47\nbreak;\ncase 45:return 45\nbreak;\ncase 46:return 48\nbreak;\ncase 47:return 46\nbreak;\ncase 48:return 41\nbreak;\ncase 49:return 43\nbreak;\ncase 50:return 42\nbreak;\ncase 51:return 39\nbreak;\ncase 52:return 37\nbreak;\ncase 53:return 32\nbreak;\ncase 54:return 86\nbreak;\ncase 55:return 5\nbreak;\ncase 56:return 20\nbreak;\ncase 57:return 'INVALID'\nbreak;\n}\n},\nrules: [/^(?:\\s+)/,/^(?:[0-9]+\\.[0-9]*|[0-9]*\\.[0-9]+\\b)/,/^(?:[0-9]+)/,/^(?:\"(\\\\[\"]|[^\"])*\")/,/^(?:'(\\\\[']|[^'])*')/,/^(?:\\/\\/.*)/,/^(?:\\/\\*(.|\\n|\\r)*?\\*\\/)/,/^(?:if\\b)/,/^(?:else\\b)/,/^(?:while\\b)/,/^(?:do\\b)/,/^(?:for\\b)/,/^(?:function\\b)/,/^(?:map\\b)/,/^(?:use\\b)/,/^(?:return\\b)/,/^(?:delete\\b)/,/^(?:true\\b)/,/^(?:false\\b)/,/^(?:null\\b)/,/^(?:Infinity\\b)/,/^(?:->)/,/^(?:=>)/,/^(?:<<)/,/^(?:>>)/,/^(?:\\{)/,/^(?:\\})/,/^(?:;)/,/^(?:#)/,/^(?:\\?)/,/^(?::)/,/^(?:NaN\\b)/,/^(?:\\.)/,/^(?:\\[)/,/^(?:\\])/,/^(?:\\()/,/^(?:\\))/,/^(?:!)/,/^(?:\\^)/,/^(?:\\*)/,/^(?:\\/)/,/^(?:%)/,/^(?:\\+)/,/^(?:-)/,/^(?:<=)/,/^(?:<)/,/^(?:>=)/,/^(?:>)/,/^(?:==)/,/^(?:~=)/,/^(?:!=)/,/^(?:&&)/,/^(?:\\|\\|)/,/^(?:=)/,/^(?:,)/,/^(?:$)/,/^(?:[A-Za-z_\\$][A-Za-z0-9_]*)/,/^(?:.)/],\nconditions: {\"INITIAL\":{\"rules\":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57],\"inclusive\":true}}\n});\nreturn lexer;\n})();\nparser.lexer = lexer;\nfunction Parser () {\n this.yy = {};\n}\nParser.prototype = parser;parser.Parser = Parser;\nreturn new Parser;\n})();\n\n\nif (typeof require !== 'undefined' && typeof exports !== 'undefined') {\nexports.parser = parser;\nexports.Parser = parser.Parser;\nexports.parse = function () { return parser.parse.apply(parser, arguments); };\nexports.main = function commonjsMain (args) {\n if (!args[1]) {\n console.log('Usage: '+args[0]+' FILE');\n process.exit(1);\n }\n var source = require('fs').readFileSync(require('path').normalize(args[1]), \"utf8\");\n return exports.parser.parse(source);\n};\nif (typeof module !== 'undefined' && require.main === module) {\n exports.main(process.argv.slice(1));\n}\n}\n // Work around an issue with browsers that don't support Object.getPrototypeOf()\n parser.yy.parseError = parser.parseError;\n\n return JXG.JessieCode;\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true*/\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n jxg\n utils/type\n */\n\ndefine('base/composition',['jxg', 'utils/type'], function (JXG, Type) {\n\n \"use strict\";\n\n /**\n * A composition is a simple container that manages none or more {@link JXG.GeometryElement}s.\n * @param {Object} elements A list of elements with a descriptive name for the element as the key and a reference\n * to the element as the value of every list entry. The name is used to access the element later on.\n * @example\n * var p1 = board.create('point', [1, 2]),\n * p2 = board.create('point', [2, 3]),\n * c = new JXG.Composition({\n * start: p1,\n * end: p2\n * });\n *\n * // moves p1 to [3, 3]\n * c.start.moveTo([3, 3]);\n * @class JXG.Composition\n */\n JXG.Composition = function (elements) {\n var e,\n that = this,\n genericMethods = [\n /**\n * Invokes setAttribute for every stored element with a setAttribute method and hands over the given arguments.\n * See {@link JXG.GeometryElement#setAttribute} for further description, valid parameters and return values.\n * @name setAttribute\n * @memberOf JXG.Composition.prototype\n * @function\n */\n 'setAttribute',\n\n /**\n * Invokes setParents for every stored element with a setParents method and hands over the given arguments.\n * See {@link JXG.GeometryElement#setParents} for further description, valid parameters and return values.\n * @name setParents\n * @memberOf JXG.Composition.prototype\n * @function\n */\n 'setParents',\n\n /**\n * Invokes prepareUpdate for every stored element with a prepareUpdate method and hands over the given arguments.\n * See {@link JXG.GeometryElement#prepareUpdate} for further description, valid parameters and return values.\n * @name prepareUpdate\n * @memberOf JXG.Composition.prototype\n * @function\n */\n 'prepareUpdate',\n\n /**\n * Invokes updateRenderer for every stored element with a updateRenderer method and hands over the given arguments.\n * See {@link JXG.GeometryElement#updateRenderer} for further description, valid parameters and return values.\n * @name updateRenderer\n * @memberOf JXG.Composition.prototype\n * @function\n */\n 'updateRenderer',\n\n /**\n * Invokes update for every stored element with a update method and hands over the given arguments.\n * See {@link JXG.GeometryElement#update} for further description, valid parameters and return values.\n * @name update\n * @memberOf JXG.Composition.prototype\n * @function\n */\n 'update',\n\n /**\n * Invokes fullUpdate for every stored element with a fullUpdate method and hands over the given arguments.\n * See {@link JXG.GeometryElement#fullUpdate} for further description, valid parameters and return values.\n * @name fullUpdate\n * @memberOf JXG.Composition.prototype\n * @function\n */\n 'fullUpdate',\n\n /**\n * Invokes highlight for every stored element with a highlight method and hands over the given arguments.\n * See {@link JXG.GeometryElement#highlight} for further description, valid parameters and return values.\n * @name highlight\n * @memberOf JXG.Composition.prototype\n * @function\n */\n 'highlight',\n\n /**\n * Invokes noHighlight for every stored element with a noHighlight method and hands over the given arguments.\n * See {@link JXG.GeometryElement#noHighlight} for further description, valid parameters and return values.\n * @name noHighlight\n * @memberOf JXG.Composition.prototype\n * @function\n */\n 'noHighlight'\n ],\n generateMethod = function (what) {\n return function () {\n var i;\n\n for (i in that.elements) {\n if (that.elements.hasOwnProperty(i)) {\n if (Type.exists(that.elements[i][what])) {\n that.elements[i][what].apply(that.elements[i], arguments);\n }\n }\n }\n return that;\n };\n };\n\n for (e = 0; e < genericMethods.length; e++) {\n this[genericMethods[e]] = generateMethod(genericMethods[e]);\n }\n\n this.elements = {};\n this.objects = this.elements;\n\n this.elementsByName = {};\n this.objectsList = [];\n\n // unused, required for select()\n this.groups = {};\n\n this.methodMap = {\n setAttribute: 'setAttribute',\n setProperty: 'setAttribute',\n setParents: 'setParents',\n add: 'add',\n remove: 'remove',\n select: 'select'\n };\n\n for (e in elements) {\n if (elements.hasOwnProperty(e)) {\n this.add(e, elements[e]);\n }\n }\n\n this.dump = true;\n this.subs = {};\n };\n\n JXG.extend(JXG.Composition.prototype, /** @lends JXG.Composition.prototype */ {\n\n /**\n * Adds an element to the composition container.\n * @param {String} what Descriptive name for the element, e.g. <em>startpoint</em> or <em>area</em>. This is used to\n * access the element later on. There are some reserved names: <em>elements, add, remove, update, prepareUpdate,\n * updateRenderer, highlight, noHighlight</em>, and all names that would form invalid object property names in\n * JavaScript.\n * @param {JXG.GeometryElement|JXG.Composition} element A reference to the element that is to be added. This can be\n * another composition, too.\n * @returns {Boolean} True, if the element was added successfully. Reasons why adding the element failed include\n * using a reserved name and providing an invalid element.\n */\n add: function (what, element) {\n if (!Type.exists(this[what]) && Type.exists(element)) {\n if (Type.exists(element.id)) {\n this.elements[element.id] = element;\n } else {\n this.elements[what] = element;\n }\n\n if (Type.exists(element.name)) {\n this.elementsByName[element.name] = element;\n }\n\n element.on('attribute:name', this.nameListener, this);\n\n this.objectsList.push(element);\n this[what] = element;\n this.methodMap[what] = element;\n\n return true;\n }\n\n return false;\n },\n\n /**\n * Remove an element from the composition container.\n * @param {String} what The name used to access the element.\n * @returns {Boolean} True, if the element has been removed successfully.\n */\n remove: function (what) {\n var found = false,\n e;\n\n for (e in this.elements) {\n if (this.elements.hasOwnProperty(e)) {\n if (this.elements[e].id === this[what].id) {\n found = true;\n break;\n }\n }\n }\n\n if (found) {\n delete this.elements[this[what].id];\n delete this[what];\n }\n\n return found;\n },\n\n nameListener: function (oval, nval, el) {\n delete this.elementsByName[oval];\n this.elementsByName[nval] = el;\n },\n\n select: function (filter) {\n // for now, hijack JXG.Board's select() method\n if (Type.exists(JXG.Board)) {\n return JXG.Board.prototype.select.call(this, filter);\n }\n\n return new JXG.Composition();\n },\n\n getParents: function () {\n return this.parents;\n },\n\n getType: function () {\n return this.elType;\n },\n\n getAttributes: function () {\n var attr = {},\n e;\n\n for (e in this.subs) {\n if (this.subs.hasOwnProperty(e)) {\n attr[e] = this.subs[e].visProp;\n }\n }\n\n return this.attr;\n }\n });\n\n return JXG.Composition;\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true, AMprocessNode: true, MathJax: true, window: true, document: true, init: true, translateASCIIMath: true, google: true*/\n\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n jxg\n base/constants\n base/coords\n options\n math/numerics\n math/math\n math/geometry\n math/complex\n parser/jessiecode\n parser/geonext\n utils/color\n utils/type\n utils/event\n utils/env\n elements:\n transform\n point\n line\n text\n grid\n */\n\n/**\n * @fileoverview The JXG.Board class is defined in this file. JXG.Board controls all properties and methods\n * used to manage a geonext board like managing geometric elements, managing mouse and touch events, etc.\n */\n\ndefine('base/board',[\n 'jxg', 'base/constants', 'base/coords', 'options', 'math/numerics', 'math/math', 'math/geometry', 'math/complex',\n 'math/statistics',\n 'parser/jessiecode', 'utils/color', 'utils/type', 'utils/event', 'utils/env',\n 'base/composition'\n], function (JXG, Const, Coords, Options, Numerics, Mat, Geometry, Complex, Statistics, JessieCode, Color, Type,\n EventEmitter, Env, Composition) {\n\n 'use strict';\n\n /**\n * Constructs a new Board object.\n * @class JXG.Board controls all properties and methods used to manage a geonext board like managing geometric\n * elements, managing mouse and touch events, etc. You probably don't want to use this constructor directly.\n * Please use {@link JXG.JSXGraph.initBoard} to initialize a board.\n * @constructor\n * @param {String} container The id or reference of the HTML DOM element the board is drawn in. This is usually a HTML div.\n * @param {JXG.AbstractRenderer} renderer The reference of a renderer.\n * @param {String} id Unique identifier for the board, may be an empty string or null or even undefined.\n * @param {JXG.Coords} origin The coordinates where the origin is placed, in user coordinates.\n * @param {Number} zoomX Zoom factor in x-axis direction\n * @param {Number} zoomY Zoom factor in y-axis direction\n * @param {Number} unitX Units in x-axis direction\n * @param {Number} unitY Units in y-axis direction\n * @param {Number} canvasWidth The width of canvas\n * @param {Number} canvasHeight The height of canvas\n * @param {Object} attributes The attributes object given to {@link JXG.JSXGraph.initBoard}\n * @borrows JXG.EventEmitter#on as this.on\n * @borrows JXG.EventEmitter#off as this.off\n * @borrows JXG.EventEmitter#triggerEventHandlers as this.triggerEventHandlers\n * @borrows JXG.EventEmitter#eventHandlers as this.eventHandlers\n */\n JXG.Board = function (container, renderer, id, origin, zoomX, zoomY, unitX, unitY, canvasWidth, canvasHeight, attributes) {\n /**\n * Board is in no special mode, objects are highlighted on mouse over and objects may be\n * clicked to start drag&drop.\n * @type Number\n * @constant\n */\n this.BOARD_MODE_NONE = 0x0000;\n\n /**\n * Board is in drag mode, objects aren't highlighted on mouse over and the object referenced in\n * {@link JXG.Board#mouse} is updated on mouse movement.\n * @type Number\n * @constant\n * @see JXG.Board#drag_obj\n */\n this.BOARD_MODE_DRAG = 0x0001;\n\n /**\n * In this mode a mouse move changes the origin's screen coordinates.\n * @type Number\n * @constant\n */\n this.BOARD_MODE_MOVE_ORIGIN = 0x0002;\n\n /**\n * Update is made with high quality, e.g. graphs are evaluated at much more points.\n * @type Number\n * @constant\n * @see JXG.Board#updateQuality\n */\n this.BOARD_MODE_ZOOM = 0x0011;\n\n /**\n * Update is made with low quality, e.g. graphs are evaluated at a lesser amount of points.\n * @type Number\n * @constant\n * @see JXG.Board#updateQuality\n */\n this.BOARD_QUALITY_LOW = 0x1;\n\n /**\n * Update is made with high quality, e.g. graphs are evaluated at much more points.\n * @type Number\n * @constant\n * @see JXG.Board#updateQuality\n */\n this.BOARD_QUALITY_HIGH = 0x2;\n\n /**\n * Pointer to the document element containing the board.\n * @type Object\n */\n // Former version:\n // this.document = attributes.document || document;\n if (Type.exists(attributes.document) && attributes.document !== false) {\n this.document = attributes.document;\n } else if (document !== undefined && Type.isObject(document)) {\n this.document = document;\n }\n\n /**\n * The html-id of the html element containing the board.\n * @type String\n */\n this.container = container;\n\n /**\n * Pointer to the html element containing the board.\n * @type Object\n */\n this.containerObj = (Env.isBrowser ? this.document.getElementById(this.container) : null);\n\n if (Env.isBrowser && renderer.type !== 'no' && this.containerObj === null) {\n throw new Error(\"\\nJSXGraph: HTML container element '\" + container + \"' not found.\");\n }\n\n /**\n * A reference to this boards renderer.\n * @type JXG.AbstractRenderer\n * @name JXG.Board#renderer\n * @private\n * @ignore\n */\n this.renderer = renderer;\n\n /**\n * Grids keeps track of all grids attached to this board.\n * @type Array\n * @private\n */\n this.grids = [];\n\n /**\n * Some standard options\n * @type JXG.Options\n */\n this.options = Type.deepCopy(Options);\n this.attr = attributes;\n\n /**\n * Dimension of the board.\n * @default 2\n * @type Number\n */\n this.dimension = 2;\n\n this.jc = new JessieCode();\n this.jc.use(this);\n\n /**\n * Coordinates of the boards origin. This a object with the two properties\n * usrCoords and scrCoords. usrCoords always equals [1, 0, 0] and scrCoords\n * stores the boards origin in homogeneous screen coordinates.\n * @type Object\n * @private\n */\n this.origin = {};\n this.origin.usrCoords = [1, 0, 0];\n this.origin.scrCoords = [1, origin[0], origin[1]];\n\n /**\n * Zoom factor in X direction. It only stores the zoom factor to be able\n * to get back to 100% in zoom100().\n * @name JXG.Board.zoomX\n * @type Number\n * @private\n * @ignore\n */\n this.zoomX = zoomX;\n\n /**\n * Zoom factor in Y direction. It only stores the zoom factor to be able\n * to get back to 100% in zoom100().\n * @name JXG.Board.zoomY\n * @type Number\n * @private\n * @ignore\n */\n this.zoomY = zoomY;\n\n /**\n * The number of pixels which represent one unit in user-coordinates in x direction.\n * @type Number\n * @private\n */\n this.unitX = unitX * this.zoomX;\n\n /**\n * The number of pixels which represent one unit in user-coordinates in y direction.\n * @type Number\n * @private\n */\n this.unitY = unitY * this.zoomY;\n\n /**\n * Keep aspect ratio if bounding box is set and the width/height ratio differs from the\n * width/height ratio of the canvas.\n * @type Boolean\n * @private\n */\n this.keepaspectratio = false;\n\n /**\n * Canvas width.\n * @type Number\n * @private\n */\n this.canvasWidth = canvasWidth;\n\n /**\n * Canvas Height\n * @type Number\n * @private\n */\n this.canvasHeight = canvasHeight;\n\n // If the given id is not valid, generate an unique id\n if (Type.exists(id) && id !== '' && Env.isBrowser && !Type.exists(this.document.getElementById(id))) {\n this.id = id;\n } else {\n this.id = this.generateId();\n }\n\n EventEmitter.eventify(this);\n\n this.hooks = [];\n\n /**\n * An array containing all other boards that are updated after this board has been updated.\n * @type Array\n * @see JXG.Board#addChild\n * @see JXG.Board#removeChild\n */\n this.dependentBoards = [];\n\n /**\n * During the update process this is set to false to prevent an endless loop.\n * @default false\n * @type Boolean\n */\n this.inUpdate = false;\n\n /**\n * An associative array containing all geometric objects belonging to the board. Key is the id of the object and value is a reference to the object.\n * @type Object\n */\n this.objects = {};\n\n /**\n * An array containing all geometric objects on the board in the order of construction.\n * @type Array\n */\n this.objectsList = [];\n\n /**\n * An associative array containing all groups belonging to the board. Key is the id of the group and value is a reference to the object.\n * @type Object\n */\n this.groups = {};\n\n /**\n * Stores all the objects that are currently running an animation.\n * @type Object\n */\n this.animationObjects = {};\n\n /**\n * An associative array containing all highlighted elements belonging to the board.\n * @type Object\n */\n this.highlightedObjects = {};\n\n /**\n * Number of objects ever created on this board. This includes every object, even invisible and deleted ones.\n * @type Number\n */\n this.numObjects = 0;\n\n /**\n * An associative array to store the objects of the board by name. the name of the object is the key and value is a reference to the object.\n * @type Object\n */\n this.elementsByName = {};\n\n /**\n * The board mode the board is currently in. Possible values are\n * <ul>\n * <li>JXG.Board.BOARD_MODE_NONE</li>\n * <li>JXG.Board.BOARD_MODE_DRAG</li>\n * <li>JXG.Board.BOARD_MODE_MOVE_ORIGIN</li>\n * </ul>\n * @type Number\n */\n this.mode = this.BOARD_MODE_NONE;\n\n /**\n * The update quality of the board. In most cases this is set to {@link JXG.Board#BOARD_QUALITY_HIGH}.\n * If {@link JXG.Board#mode} equals {@link JXG.Board#BOARD_MODE_DRAG} this is set to\n * {@link JXG.Board#BOARD_QUALITY_LOW} to speed up the update process by e.g. reducing the number of\n * evaluation points when plotting functions. Possible values are\n * <ul>\n * <li>BOARD_QUALITY_LOW</li>\n * <li>BOARD_QUALITY_HIGH</li>\n * </ul>\n * @type Number\n * @see JXG.Board#mode\n */\n this.updateQuality = this.BOARD_QUALITY_HIGH;\n\n /**\n * If true updates are skipped.\n * @type Boolean\n */\n this.isSuspendedRedraw = false;\n\n this.calculateSnapSizes();\n\n /**\n * The distance from the mouse to the dragged object in x direction when the user clicked the mouse button.\n * @type Number\n * @see JXG.Board#drag_dy\n * @see JXG.Board#drag_obj\n */\n this.drag_dx = 0;\n\n /**\n * The distance from the mouse to the dragged object in y direction when the user clicked the mouse button.\n * @type Number\n * @see JXG.Board#drag_dx\n * @see JXG.Board#drag_obj\n */\n this.drag_dy = 0;\n\n /**\n * The last position where a drag event has been fired.\n * @type Array\n * @see JXG.Board#moveObject\n */\n this.drag_position = [0, 0];\n\n /**\n * References to the object that is dragged with the mouse on the board.\n * @type JXG.GeometryElement\n * @see JXG.Board#touches\n */\n this.mouse = {};\n\n /**\n * Keeps track on touched elements, like {@link JXG.Board#mouse} does for mouse events.\n * @type Array\n * @see JXG.Board#mouse\n */\n this.touches = [];\n\n /**\n * A string containing the XML text of the construction.\n * This is set in {@link JXG.FileReader.parseString}.\n * Only useful if a construction is read from a GEONExT-, Intergeo-, Geogebra-, or Cinderella-File.\n * @type String\n */\n this.xmlString = '';\n\n /**\n * Cached result of getCoordsTopLeftCorner for touch/mouseMove-Events to save some DOM operations.\n * @type Array\n */\n this.cPos = [];\n\n /**\n * Contains the last time (epoch, msec) since the last touchMove event which was not thrown away or since\n * touchStart because Android's Webkit browser fires too much of them.\n * @type Number\n */\n this.touchMoveLast = 0;\n\n /**\n * Contains the pointerId of the last touchMove event which was not thrown away or since\n * touchStart because Android's Webkit browser fires too much of them.\n * @type Number\n */\n this.touchMoveLastId = Infinity;\n\n /**\n * Contains the last time (epoch, msec) since the last getCoordsTopLeftCorner call which was not thrown away.\n * @type Number\n */\n this.positionAccessLast = 0;\n\n /**\n * Collects all elements that triggered a mouse down event.\n * @type Array\n */\n this.downObjects = [];\n\n if (this.attr.showcopyright) {\n this.renderer.displayCopyright(Const.licenseText, parseInt(this.options.text.fontSize, 10));\n }\n\n /**\n * Full updates are needed after zoom and axis translates. This saves some time during an update.\n * @default false\n * @type Boolean\n */\n this.needsFullUpdate = false;\n\n /**\n * If reducedUpdate is set to true then only the dragged element and few (e.g. 2) following\n * elements are updated during mouse move. On mouse up the whole construction is\n * updated. This enables us to be fast even on very slow devices.\n * @type Boolean\n * @default false\n */\n this.reducedUpdate = false;\n\n /**\n * The current color blindness deficiency is stored in this property. If color blindness is not emulated\n * at the moment, it's value is 'none'.\n */\n this.currentCBDef = 'none';\n\n /**\n * If GEONExT constructions are displayed, then this property should be set to true.\n * At the moment there should be no difference. But this may change.\n * This is set in {@link JXG.GeonextReader.readGeonext}.\n * @type Boolean\n * @default false\n * @see JXG.GeonextReader.readGeonext\n */\n this.geonextCompatibilityMode = false;\n\n if (this.options.text.useASCIIMathML && translateASCIIMath) {\n init();\n } else {\n this.options.text.useASCIIMathML = false;\n }\n\n /**\n * A flag which tells if the board registers mouse events.\n * @type Boolean\n * @default false\n */\n this.hasMouseHandlers = false;\n\n /**\n * A flag which tells if the board registers touch events.\n * @type Boolean\n * @default false\n */\n this.hasTouchHandlers = false;\n\n /**\n * A flag which stores if the board registered pointer events.\n * @type Boolean\n * @default false\n */\n this.hasPointerHandlers = false;\n\n /**\n * A flag which tells if the board the JXG.Board#mouseUpListener is currently registered.\n * @type Boolean\n * @default false\n */\n this.hasMouseUp = false;\n\n /**\n * A flag which tells if the board the JXG.Board#touchEndListener is currently registered.\n * @type Boolean\n * @default false\n */\n this.hasTouchEnd = false;\n\n /**\n * A flag which tells us if the board has a pointerUp event registered at the moment.\n * @type Boolean\n * @default false\n */\n this.hasPointerUp = false;\n\n /**\n * Offset for large coords elements like images\n * @type Array\n * @private\n * @default [0, 0]\n */\n this._drag_offset = [0, 0];\n\n /**\n * Stores the input device used in the last down or move event.\n * @type String\n * @private\n * @default 'mouse'\n */\n this._inputDevice = 'mouse';\n\n /**\n * Keeps a list of pointer devices which are currently touching the screen.\n * @type Array\n * @private\n */\n this._board_touches = [];\n\n /**\n * A flag which tells us if the board is in the selecting mode\n * @type Boolean\n * @default false\n */\n this.selectingMode = false;\n\n /**\n * A flag which tells us if the user is selecting\n * @type Boolean\n * @default false\n */\n this.isSelecting = false;\n\n /**\n * A flag which tells us if the user is scrolling the viewport\n * @type Boolean\n * @private\n * @default false\n * @see JXG.Board#scrollListener\n */\n this._isScrolling = false;\n\n /**\n * A flag which tells us if a resize is in process\n * @type Boolean\n * @private\n * @default false\n * @see JXG.Board#resizeListener\n */\n this._isResizing = false;\n\n /**\n * A bounding box for the selection\n * @type Array\n * @default [ [0,0], [0,0] ]\n */\n this.selectingBox = [[0, 0], [0, 0]];\n\n this.mathLib = Math; // Math or JXG.Math.IntervalArithmetic\n this.mathLibJXG = JXG.Math; // JXG.Math or JXG.Math.IntervalArithmetic\n\n if (this.attr.registerevents) {\n this.addEventHandlers();\n }\n\n this.methodMap = {\n update: 'update',\n fullUpdate: 'fullUpdate',\n on: 'on',\n off: 'off',\n trigger: 'trigger',\n setView: 'setBoundingBox',\n setBoundingBox: 'setBoundingBox',\n migratePoint: 'migratePoint',\n colorblind: 'emulateColorblindness',\n suspendUpdate: 'suspendUpdate',\n unsuspendUpdate: 'unsuspendUpdate',\n clearTraces: 'clearTraces',\n left: 'clickLeftArrow',\n right: 'clickRightArrow',\n up: 'clickUpArrow',\n down: 'clickDownArrow',\n zoomIn: 'zoomIn',\n zoomOut: 'zoomOut',\n zoom100: 'zoom100',\n zoomElements: 'zoomElements',\n remove: 'removeObject',\n removeObject: 'removeObject'\n };\n };\n\n JXG.extend(JXG.Board.prototype, /** @lends JXG.Board.prototype */ {\n\n /**\n * Generates an unique name for the given object. The result depends on the objects type, if the\n * object is a {@link JXG.Point}, capital characters are used, if it is of type {@link JXG.Line}\n * only lower case characters are used. If object is of type {@link JXG.Polygon}, a bunch of lower\n * case characters prefixed with P_ are used. If object is of type {@link JXG.Circle} the name is\n * generated using lower case characters. prefixed with k_ is used. In any other case, lower case\n * chars prefixed with s_ is used.\n * @param {Object} object Reference of an JXG.GeometryElement that is to be named.\n * @returns {String} Unique name for the object.\n */\n generateName: function (object) {\n var possibleNames, i,\n maxNameLength = this.attr.maxnamelength,\n pre = '',\n post = '',\n indices = [],\n name = '';\n\n if (object.type === Const.OBJECT_TYPE_TICKS) {\n return '';\n }\n\n if (Type.isPoint(object)) {\n // points have capital letters\n possibleNames = ['', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',\n 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];\n } else if (object.type === Const.OBJECT_TYPE_ANGLE) {\n possibleNames = ['', 'α', 'β', 'γ', 'δ', 'ε', 'ζ', 'η', 'θ',\n 'ι', 'κ', 'λ', 'μ', 'ν', 'ξ', 'ο', 'π', 'ρ',\n 'σ', 'τ', 'υ', 'φ', 'χ', 'ψ', 'ω'];\n } else {\n // all other elements get lowercase labels\n possibleNames = ['', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',\n 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'];\n }\n\n if (!Type.isPoint(object) &&\n object.elementClass !== Const.OBJECT_CLASS_LINE &&\n object.type !== Const.OBJECT_TYPE_ANGLE) {\n if (object.type === Const.OBJECT_TYPE_POLYGON) {\n pre = 'P_{';\n } else if (object.elementClass === Const.OBJECT_CLASS_CIRCLE) {\n pre = 'k_{';\n } else if (object.elementClass === Const.OBJECT_CLASS_TEXT) {\n pre = 't_{';\n } else {\n pre = 's_{';\n }\n post = '}';\n }\n\n for (i = 0; i < maxNameLength; i++) {\n indices[i] = 0;\n }\n\n while (indices[maxNameLength - 1] < possibleNames.length) {\n for (indices[0] = 1; indices[0] < possibleNames.length; indices[0]++) {\n name = pre;\n\n for (i = maxNameLength; i > 0; i--) {\n name += possibleNames[indices[i - 1]];\n }\n\n if (!Type.exists(this.elementsByName[name + post])) {\n return name + post;\n }\n\n }\n indices[0] = possibleNames.length;\n\n for (i = 1; i < maxNameLength; i++) {\n if (indices[i - 1] === possibleNames.length) {\n indices[i - 1] = 1;\n indices[i] += 1;\n }\n }\n }\n\n return '';\n },\n\n /**\n * Generates unique id for a board. The result is randomly generated and prefixed with 'jxgBoard'.\n * @returns {String} Unique id for a board.\n */\n generateId: function () {\n var r = 1;\n\n // as long as we don't have a unique id generate a new one\n while (Type.exists(JXG.boards['jxgBoard' + r])) {\n r = Math.round(Math.random() * 65535);\n }\n\n return ('jxgBoard' + r);\n },\n\n /**\n * Composes an id for an element. If the ID is empty ('' or null) a new ID is generated, depending on the\n * object type. As a side effect {@link JXG.Board#numObjects}\n * is updated.\n * @param {Object} obj Reference of an geometry object that needs an id.\n * @param {Number} type Type of the object.\n * @returns {String} Unique id for an element.\n */\n setId: function (obj, type) {\n var randomNumber,\n num = this.numObjects,\n elId = obj.id;\n\n this.numObjects += 1;\n\n // If no id is provided or id is empty string, a new one is chosen\n if (elId === '' || !Type.exists(elId)) {\n elId = this.id + type + num;\n while (Type.exists(this.objects[elId])) {\n randomNumber = Math.round(Math.random() * 65535);\n elId = this.id + type + num + '-' + randomNumber;\n }\n }\n\n obj.id = elId;\n this.objects[elId] = obj;\n obj._pos = this.objectsList.length;\n this.objectsList[this.objectsList.length] = obj;\n\n return elId;\n },\n\n /**\n * After construction of the object the visibility is set\n * and the label is constructed if necessary.\n * @param {Object} obj The object to add.\n */\n finalizeAdding: function (obj) {\n if (Type.evaluate(obj.visProp.visible) === false) {\n this.renderer.display(obj, false);\n }\n },\n\n finalizeLabel: function (obj) {\n if (obj.hasLabel &&\n !Type.evaluate(obj.label.visProp.islabel) &&\n Type.evaluate(obj.label.visProp.visible) === false) {\n this.renderer.display(obj.label, false);\n }\n },\n\n /**********************************************************\n *\n * Event Handler helpers\n *\n **********************************************************/\n\n /**\n * Returns false if the event has been triggered faster than the maximum frame rate.\n *\n * @param {Event} evt Event object given by the browser (unused)\n * @returns {Boolean} If the event has been triggered faster than the maximum frame rate, false is returned.\n * @private\n * @see JXG.Board#pointerMoveListener\n * @see JXG.Board#touchMoveListener\n * @see JXG.Board#mouseMoveListener\n */\n checkFrameRate: function(evt) {\n var handleEvt = false,\n time = new Date().getTime();\n\n if (Type.exists(evt.pointerId) && this.touchMoveLastId !== evt.pointerId) {\n handleEvt = true;\n this.touchMoveLastId = evt.pointerId;\n }\n if (!handleEvt && (time - this.touchMoveLast) * this.attr.maxframerate >= 1000) {\n handleEvt = true;\n }\n if (handleEvt) {\n this.touchMoveLast = time;\n }\n return handleEvt;\n },\n\n /**\n * Calculates mouse coordinates relative to the boards container.\n * @returns {Array} Array of coordinates relative the boards container top left corner.\n */\n getCoordsTopLeftCorner: function () {\n var cPos, doc, crect,\n // In ownerDoc we need the \"real\" document object.\n // The first version is used in the case of shadowDom,\n // the second case in the \"normal\" case.\n ownerDoc = this.document.ownerDocument || this.document, \n docElement = ownerDoc.documentElement || this.document.body.parentNode,\n docBody = ownerDoc.body,\n container = this.containerObj,\n // viewport, content,\n zoom, o;\n\n /**\n * During drags and origin moves the container element is usually not changed.\n * Check the position of the upper left corner at most every 1000 msecs\n */\n if (this.cPos.length > 0 &&\n (this.mode === this.BOARD_MODE_DRAG || this.mode === this.BOARD_MODE_MOVE_ORIGIN ||\n (new Date()).getTime() - this.positionAccessLast < 1000)) {\n return this.cPos;\n }\n this.positionAccessLast = (new Date()).getTime();\n\n // Check if getBoundingClientRect exists. If so, use this as this covers *everything*\n // even CSS3D transformations etc.\n // Supported by all browsers but IE 6, 7.\n\n if (container.getBoundingClientRect) {\n crect = container.getBoundingClientRect();\n\n\n zoom = 1.0;\n // Recursively search for zoom style entries.\n // This is necessary for reveal.js on webkit.\n // It fails if the user does zooming\n o = container;\n while (o && Type.exists(o.parentNode)) {\n if (Type.exists(o.style) && Type.exists(o.style.zoom) && o.style.zoom !== '') {\n zoom *= parseFloat(o.style.zoom);\n }\n o = o.parentNode;\n }\n cPos = [crect.left * zoom, crect.top * zoom];\n\n // add border width\n cPos[0] += Env.getProp(container, 'border-left-width');\n cPos[1] += Env.getProp(container, 'border-top-width');\n\n // vml seems to ignore paddings\n if (this.renderer.type !== 'vml') {\n // add padding\n cPos[0] += Env.getProp(container, 'padding-left');\n cPos[1] += Env.getProp(container, 'padding-top');\n }\n\n this.cPos = cPos.slice();\n return this.cPos;\n }\n\n //\n // OLD CODE\n // IE 6-7 only:\n //\n cPos = Env.getOffset(container);\n doc = this.document.documentElement.ownerDocument;\n\n if (!this.containerObj.currentStyle && doc.defaultView) { // Non IE\n // this is for hacks like this one used in wordpress for the admin bar:\n // html { margin-top: 28px }\n // seems like it doesn't work in IE\n\n cPos[0] += Env.getProp(docElement, 'margin-left');\n cPos[1] += Env.getProp(docElement, 'margin-top');\n\n cPos[0] += Env.getProp(docElement, 'border-left-width');\n cPos[1] += Env.getProp(docElement, 'border-top-width');\n\n cPos[0] += Env.getProp(docElement, 'padding-left');\n cPos[1] += Env.getProp(docElement, 'padding-top');\n }\n\n if (docBody) {\n cPos[0] += Env.getProp(docBody, 'left');\n cPos[1] += Env.getProp(docBody, 'top');\n }\n\n // Google Translate offers widgets for web authors. These widgets apparently tamper with the clientX\n // and clientY coordinates of the mouse events. The minified sources seem to be the only publicly\n // available version so we're doing it the hacky way: Add a fixed offset.\n // see https://groups.google.com/d/msg/google-translate-general/H2zj0TNjjpY/jw6irtPlCw8J\n if (typeof google === 'object' && google.translate) {\n cPos[0] += 10;\n cPos[1] += 25;\n }\n\n // add border width\n cPos[0] += Env.getProp(container, 'border-left-width');\n cPos[1] += Env.getProp(container, 'border-top-width');\n\n // vml seems to ignore paddings\n if (this.renderer.type !== 'vml') {\n // add padding\n cPos[0] += Env.getProp(container, 'padding-left');\n cPos[1] += Env.getProp(container, 'padding-top');\n }\n\n cPos[0] += this.attr.offsetx;\n cPos[1] += this.attr.offsety;\n\n this.cPos = cPos.slice();\n return this.cPos;\n },\n\n /**\n * Get the position of the mouse in screen coordinates, relative to the upper left corner\n * of the host tag.\n * @param {Event} e Event object given by the browser.\n * @param {Number} [i] Only use in case of touch events. This determines which finger to use and should not be set\n * for mouseevents.\n * @returns {Array} Contains the mouse coordinates in screen coordinates, ready for {@link JXG.Coords}\n */\n getMousePosition: function (e, i) {\n var cPos = this.getCoordsTopLeftCorner(),\n absPos,\n v;\n\n // Position of cursor using clientX/Y\n absPos = Env.getPosition(e, i, this.document);\n\n /**\n * In case there has been no down event before.\n */\n if (!Type.exists(this.cssTransMat)) {\n this.updateCSSTransforms();\n }\n // Position relative to the top left corner\n v = [1, absPos[0] - cPos[0], absPos[1] - cPos[1]];\n v = Mat.matVecMult(this.cssTransMat, v);\n v[1] /= v[0];\n v[2] /= v[0];\n return [v[1], v[2]];\n\n // Method without CSS transformation\n /*\n return [absPos[0] - cPos[0], absPos[1] - cPos[1]];\n */\n },\n\n /**\n * Initiate moving the origin. This is used in mouseDown and touchStart listeners.\n * @param {Number} x Current mouse/touch coordinates\n * @param {Number} y Current mouse/touch coordinates\n */\n initMoveOrigin: function (x, y) {\n this.drag_dx = x - this.origin.scrCoords[1];\n this.drag_dy = y - this.origin.scrCoords[2];\n\n this.mode = this.BOARD_MODE_MOVE_ORIGIN;\n this.updateQuality = this.BOARD_QUALITY_LOW;\n },\n\n /**\n * Collects all elements below the current mouse pointer and fulfilling the following constraints:\n * <ul><li>isDraggable</li><li>visible</li><li>not fixed</li><li>not frozen</li></ul>\n * @param {Number} x Current mouse/touch coordinates\n * @param {Number} y current mouse/touch coordinates\n * @param {Object} evt An event object\n * @param {String} type What type of event? 'touch', 'mouse' or 'pen'.\n * @returns {Array} A list of geometric elements.\n */\n initMoveObject: function (x, y, evt, type) {\n var pEl,\n el,\n collect = [],\n offset = [],\n haspoint,\n len = this.objectsList.length,\n dragEl = {visProp: {layer: -10000}};\n\n //for (el in this.objects) {\n for (el = 0; el < len; el++) {\n pEl = this.objectsList[el];\n haspoint = pEl.hasPoint && pEl.hasPoint(x, y);\n\n if (pEl.visPropCalc.visible && haspoint) {\n pEl.triggerEventHandlers([type + 'down', 'down'], [evt]);\n this.downObjects.push(pEl);\n }\n\n if (haspoint &&\n pEl.isDraggable &&\n pEl.visPropCalc.visible &&\n ((this.geonextCompatibilityMode &&\n (Type.isPoint(pEl) ||\n pEl.elementClass === Const.OBJECT_CLASS_TEXT)\n ) ||\n !this.geonextCompatibilityMode\n ) &&\n !Type.evaluate(pEl.visProp.fixed)\n /*(!pEl.visProp.frozen) &&*/\n ) {\n\n // Elements in the highest layer get priority.\n if (pEl.visProp.layer > dragEl.visProp.layer ||\n (pEl.visProp.layer === dragEl.visProp.layer &&\n pEl.lastDragTime.getTime() >= dragEl.lastDragTime.getTime()\n )) {\n // If an element and its label have the focus\n // simultaneously, the element is taken.\n // This only works if we assume that every browser runs\n // through this.objects in the right order, i.e. an element A\n // added before element B turns up here before B does.\n if (!this.attr.ignorelabels ||\n (!Type.exists(dragEl.label) || pEl !== dragEl.label)) {\n dragEl = pEl;\n collect.push(dragEl);\n\n // Save offset for large coords elements.\n if (Type.exists(dragEl.coords)) {\n offset.push(Statistics.subtract(dragEl.coords.scrCoords.slice(1), [x, y]));\n } else {\n offset.push([0, 0]);\n }\n\n // we can't drop out of this loop because of the event handling system\n //if (this.attr.takefirst) {\n // return collect;\n //}\n }\n }\n }\n }\n\n if (this.attr.drag.enabled && collect.length > 0) {\n this.mode = this.BOARD_MODE_DRAG;\n }\n\n // A one-element array is returned.\n if (this.attr.takefirst) {\n collect.length = 1;\n this._drag_offset = offset[0];\n } else {\n collect = collect.slice(-1);\n this._drag_offset = offset[offset.length - 1];\n }\n\n if (!this._drag_offset) {\n this._drag_offset = [0, 0];\n }\n\n // Move drag element to the top of the layer\n if (this.renderer.type === 'svg' &&\n Type.exists(collect[0]) &&\n Type.evaluate(collect[0].visProp.dragtotopoflayer) &&\n collect.length === 1 &&\n Type.exists(collect[0].rendNode)) {\n\n collect[0].rendNode.parentNode.appendChild(collect[0].rendNode);\n }\n\n // Init rotation angle and scale factor for two finger movements\n this.previousRotation = 0.0;\n this.previousScale = 1.0;\n\n if (collect.length >= 1) {\n collect[0].highlight(true);\n this.triggerEventHandlers(['mousehit', 'hit'], [evt, collect[0]]);\n }\n\n return collect;\n },\n\n /**\n * Moves an object.\n * @param {Number} x Coordinate\n * @param {Number} y Coordinate\n * @param {Object} o The touch object that is dragged: {JXG.Board#mouse} or {JXG.Board#touches}.\n * @param {Object} evt The event object.\n * @param {String} type Mouse or touch event?\n */\n moveObject: function (x, y, o, evt, type) {\n var newPos = new Coords(Const.COORDS_BY_SCREEN, this.getScrCoordsOfMouse(x, y), this),\n drag,\n dragScrCoords, newDragScrCoords;\n\n if (!(o && o.obj)) {\n return;\n }\n drag = o.obj;\n\n // Save updates for very small movements of coordsElements, see below\n if (drag.coords) {\n dragScrCoords = drag.coords.scrCoords.slice();\n }\n\n /*\n * Save the position.\n */\n this.drag_position = [newPos.scrCoords[1], newPos.scrCoords[2]];\n this.drag_position = Statistics.add(this.drag_position, this._drag_offset);\n //\n // We have to distinguish between CoordsElements and other elements like lines.\n // The latter need the difference between two move events.\n if (Type.exists(drag.coords)) {\n drag.setPositionDirectly(Const.COORDS_BY_SCREEN, this.drag_position);\n } else {\n this.displayInfobox(false);\n // Hide infobox in case the user has touched an intersection point\n // and drags the underlying line now.\n\n if (!isNaN(o.targets[0].Xprev + o.targets[0].Yprev)) {\n drag.setPositionDirectly(Const.COORDS_BY_SCREEN,\n [newPos.scrCoords[1], newPos.scrCoords[2]],\n [o.targets[0].Xprev, o.targets[0].Yprev]\n );\n }\n // Remember the actual position for the next move event. Then we are able to\n // compute the difference vector.\n o.targets[0].Xprev = newPos.scrCoords[1];\n o.targets[0].Yprev = newPos.scrCoords[2];\n }\n // This may be necessary for some gliders and labels\n if (Type.exists(drag.coords)) {\n drag.prepareUpdate().update(false).updateRenderer();\n this.updateInfobox(drag);\n drag.prepareUpdate().update(true).updateRenderer();\n }\n\n if (drag.coords) {\n newDragScrCoords = drag.coords.scrCoords;\n }\n // No updates for very small movements of coordsElements\n if (!drag.coords ||\n dragScrCoords[1] !== newDragScrCoords[1] ||\n dragScrCoords[2] !== newDragScrCoords[2]) {\n\n drag.triggerEventHandlers([type + 'drag', 'drag'], [evt]);\n\n this.update();\n }\n drag.highlight(true);\n this.triggerEventHandlers(['mousehit', 'hit'], [evt, drag]);\n\n drag.lastDragTime = new Date();\n },\n\n /**\n * Moves elements in multitouch mode.\n * @param {Array} p1 x,y coordinates of first touch\n * @param {Array} p2 x,y coordinates of second touch\n * @param {Object} o The touch object that is dragged: {JXG.Board#touches}.\n * @param {Object} evt The event object that lead to this movement.\n */\n twoFingerMove: function (o, id, evt) {\n var drag;\n\n if (Type.exists(o) && Type.exists(o.obj)) {\n drag = o.obj;\n } else {\n return;\n }\n\n if (drag.elementClass === Const.OBJECT_CLASS_LINE ||\n drag.type === Const.OBJECT_TYPE_POLYGON) {\n this.twoFingerTouchObject(o.targets, drag, id);\n } else if (drag.elementClass === Const.OBJECT_CLASS_CIRCLE) {\n this.twoFingerTouchCircle(o.targets, drag, id);\n }\n\n if (evt) {\n drag.triggerEventHandlers(['touchdrag', 'drag'], [evt]);\n }\n },\n\n /**\n * Moves, rotates and scales a line or polygon with two fingers.\n * @param {Array} tar Array conatining touch event objects: {JXG.Board#touches.targets}.\n * @param {object} drag The object that is dragged:\n * @param {Number} id pointerId of the event. In case of old touch event this is emulated.\n */\n twoFingerTouchObject: function (tar, drag, id) {\n var np, op, nd, od,\n d, alpha,\n S, t1, t3, t4, t5,\n ar, i, len,\n fixEl, moveEl, fix;\n\n if (Type.exists(tar[0]) && Type.exists(tar[1]) &&\n !isNaN(tar[0].Xprev + tar[0].Yprev + tar[1].Xprev + tar[1].Yprev)) {\n\n if (id === tar[0].num) {\n fixEl = tar[1];\n moveEl = tar[0];\n } else {\n fixEl = tar[0];\n moveEl = tar[1];\n }\n\n fix = (new Coords(Const.COORDS_BY_SCREEN, [fixEl.Xprev, fixEl.Yprev], this)).usrCoords;\n // Previous finger position\n op = (new Coords(Const.COORDS_BY_SCREEN, [moveEl.Xprev, moveEl.Yprev], this)).usrCoords;\n // New finger position\n np = (new Coords(Const.COORDS_BY_SCREEN, [moveEl.X, moveEl.Y], this)).usrCoords;\n\n // Old and new directions\n od = Mat.crossProduct(fix, op);\n nd = Mat.crossProduct(fix, np);\n\n // Intersection between the two directions\n S = Mat.crossProduct(od, nd);\n\n // If parallel translate, otherwise rotate\n if (Math.abs(S[0]) < Mat.eps) {\n return;\n }\n\n alpha = Geometry.rad(op.slice(1), fix.slice(1), np.slice(1));\n\n t1 = this.create('transform', [alpha, [fix[1], fix[2]]], {type: 'rotate'});\n t1.update();\n\n if (Type.evaluate(drag.visProp.scalable)) {\n // Scale\n d = Geometry.distance(np, fix) / Geometry.distance(op, fix);\n\n t3 = this.create('transform', [-fix[1], -fix[2]], {type: 'translate'});\n t4 = this.create('transform', [d, d], {type: 'scale'});\n t5 = this.create('transform', [fix[1], fix[2]], {type: 'translate'});\n t1.melt(t3).melt(t4).melt(t5);\n }\n\n if (drag.elementClass === Const.OBJECT_CLASS_LINE) {\n ar = [];\n if (drag.point1.draggable()) {\n ar.push(drag.point1);\n }\n if (drag.point2.draggable()) {\n ar.push(drag.point2);\n }\n t1.applyOnce(ar);\n } else if (drag.type === Const.OBJECT_TYPE_POLYGON) {\n ar = [];\n len = drag.vertices.length - 1;\n for (i = 0; i < len; ++i) {\n if (drag.vertices[i].draggable()) {\n ar.push(drag.vertices[i]);\n }\n }\n t1.applyOnce(ar);\n }\n\n this.update();\n drag.highlight(true);\n }\n },\n\n /*\n * Moves, rotates and scales a circle with two fingers.\n * @param {Array} tar Array conatining touch event objects: {JXG.Board#touches.targets}.\n * @param {object} drag The object that is dragged:\n * @param {Number} id pointerId of the event. In case of old touch event this is emulated.\n */\n twoFingerTouchCircle: function (tar, drag, id) {\n var fixEl, moveEl, np, op, fix,\n d, alpha, t1, t2, t3, t4;\n\n if (drag.method === 'pointCircle' || drag.method === 'pointLine') {\n return;\n }\n\n if (Type.exists(tar[0]) && Type.exists(tar[1]) &&\n !isNaN(tar[0].Xprev + tar[0].Yprev + tar[1].Xprev + tar[1].Yprev)) {\n\n if (id === tar[0].num) {\n fixEl = tar[1];\n moveEl = tar[0];\n } else {\n fixEl = tar[0];\n moveEl = tar[1];\n }\n\n fix = (new Coords(Const.COORDS_BY_SCREEN, [fixEl.Xprev, fixEl.Yprev], this)).usrCoords;\n // Previous finger position\n op = (new Coords(Const.COORDS_BY_SCREEN, [moveEl.Xprev, moveEl.Yprev], this)).usrCoords;\n // New finger position\n np = (new Coords(Const.COORDS_BY_SCREEN, [moveEl.X, moveEl.Y], this)).usrCoords;\n\n alpha = Geometry.rad(op.slice(1), fix.slice(1), np.slice(1));\n\n // Rotate and scale by the movement of the second finger\n t1 = this.create('transform', [-fix[1], -fix[2]], {type: 'translate'});\n t2 = this.create('transform', [alpha], {type: 'rotate'});\n t1.melt(t2);\n if (Type.evaluate(drag.visProp.scalable)) {\n d = Geometry.distance(fix, np) / Geometry.distance(fix, op);\n t3 = this.create('transform', [d, d], {type: 'scale'});\n t1.melt(t3);\n }\n t4 = this.create('transform', [fix[1], fix[2]], {type: 'translate'});\n t1.melt(t4);\n\n if (drag.center.draggable()) {\n t1.applyOnce([drag.center]);\n }\n\n if (drag.method === 'twoPoints') {\n if (drag.point2.draggable()) {\n t1.applyOnce([drag.point2]);\n }\n } else if (drag.method === 'pointRadius') {\n if (Type.isNumber(drag.updateRadius.origin)) {\n drag.setRadius(drag.radius * d);\n }\n }\n\n this.update(drag.center);\n drag.highlight(true);\n }\n },\n\n highlightElements: function (x, y, evt, target) {\n var el, pEl, pId,\n overObjects = {},\n len = this.objectsList.length;\n\n // Elements below the mouse pointer which are not highlighted yet will be highlighted.\n for (el = 0; el < len; el++) {\n pEl = this.objectsList[el];\n pId = pEl.id;\n if (Type.exists(pEl.hasPoint) && pEl.visPropCalc.visible && pEl.hasPoint(x, y)) {\n // this is required in any case because otherwise the box won't be shown until the point is dragged\n this.updateInfobox(pEl);\n\n if (!Type.exists(this.highlightedObjects[pId])) { // highlight only if not highlighted\n overObjects[pId] = pEl;\n pEl.highlight();\n // triggers board event.\n this.triggerEventHandlers(['mousehit', 'hit'], [evt, pEl, target]);\n }\n\n if (pEl.mouseover) {\n pEl.triggerEventHandlers(['mousemove', 'move'], [evt]);\n } else {\n pEl.triggerEventHandlers(['mouseover', 'over'], [evt]);\n pEl.mouseover = true;\n }\n }\n }\n\n for (el = 0; el < len; el++) {\n pEl = this.objectsList[el];\n pId = pEl.id;\n if (pEl.mouseover) {\n if (!overObjects[pId]) {\n pEl.triggerEventHandlers(['mouseout', 'out'], [evt]);\n pEl.mouseover = false;\n }\n }\n }\n },\n\n /**\n * Helper function which returns a reasonable starting point for the object being dragged.\n * Formerly known as initXYstart().\n * @private\n * @param {JXG.GeometryElement} obj The object to be dragged\n * @param {Array} targets Array of targets. It is changed by this function.\n */\n saveStartPos: function (obj, targets) {\n var xy = [], i, len;\n\n if (obj.type === Const.OBJECT_TYPE_TICKS) {\n xy.push([1, NaN, NaN]);\n } else if (obj.elementClass === Const.OBJECT_CLASS_LINE) {\n xy.push(obj.point1.coords.usrCoords);\n xy.push(obj.point2.coords.usrCoords);\n } else if (obj.elementClass === Const.OBJECT_CLASS_CIRCLE) {\n xy.push(obj.center.coords.usrCoords);\n if (obj.method === 'twoPoints') {\n xy.push(obj.point2.coords.usrCoords);\n }\n } else if (obj.type === Const.OBJECT_TYPE_POLYGON) {\n len = obj.vertices.length - 1;\n for (i = 0; i < len; i++) {\n xy.push(obj.vertices[i].coords.usrCoords);\n }\n } else if (obj.type === Const.OBJECT_TYPE_SECTOR) {\n xy.push(obj.point1.coords.usrCoords);\n xy.push(obj.point2.coords.usrCoords);\n xy.push(obj.point3.coords.usrCoords);\n } else if (Type.isPoint(obj) || obj.type === Const.OBJECT_TYPE_GLIDER) {\n xy.push(obj.coords.usrCoords);\n } else if (obj.elementClass === Const.OBJECT_CLASS_CURVE) {\n // if (Type.exists(obj.parents)) {\n // len = obj.parents.length;\n // if (len > 0) {\n // for (i = 0; i < len; i++) {\n // xy.push(this.select(obj.parents[i]).coords.usrCoords);\n // }\n // } else\n // }\n if (obj.points.length > 0) {\n xy.push(obj.points[0].usrCoords);\n }\n } else {\n try {\n xy.push(obj.coords.usrCoords);\n } catch (e) {\n JXG.debug('JSXGraph+ saveStartPos: obj.coords.usrCoords not available: ' + e);\n }\n }\n\n len = xy.length;\n for (i = 0; i < len; i++) {\n targets.Zstart.push(xy[i][0]);\n targets.Xstart.push(xy[i][1]);\n targets.Ystart.push(xy[i][2]);\n }\n },\n\n mouseOriginMoveStart: function (evt) {\n var r, pos;\n\n r = this._isRequiredKeyPressed(evt, 'pan');\n if (r) {\n pos = this.getMousePosition(evt);\n this.initMoveOrigin(pos[0], pos[1]);\n }\n\n return r;\n },\n\n mouseOriginMove: function (evt) {\n var r = (this.mode === this.BOARD_MODE_MOVE_ORIGIN),\n pos;\n\n if (r) {\n pos = this.getMousePosition(evt);\n this.moveOrigin(pos[0], pos[1], true);\n }\n\n return r;\n },\n\n /**\n * Start moving the origin with one finger.\n * @private\n * @param {Object} evt Event from touchStartListener\n * @return {Boolean} returns if the origin is moved.\n */\n touchStartMoveOriginOneFinger: function (evt) {\n var touches = evt[JXG.touchProperty],\n conditions, pos;\n\n conditions = this.attr.pan.enabled &&\n !this.attr.pan.needtwofingers &&\n touches.length === 1;\n\n if (conditions) {\n pos = this.getMousePosition(evt, 0);\n this.initMoveOrigin(pos[0], pos[1]);\n }\n\n return conditions;\n },\n\n /**\n * Move the origin with one finger\n * @private\n * @param {Object} evt Event from touchMoveListener\n * @return {Boolean} returns if the origin is moved.\n */\n touchOriginMove: function (evt) {\n var r = (this.mode === this.BOARD_MODE_MOVE_ORIGIN),\n pos;\n\n if (r) {\n pos = this.getMousePosition(evt, 0);\n this.moveOrigin(pos[0], pos[1], true);\n }\n\n return r;\n },\n\n /**\n * Stop moving the origin with one finger\n * @return {null} null\n * @private\n */\n originMoveEnd: function () {\n this.updateQuality = this.BOARD_QUALITY_HIGH;\n this.mode = this.BOARD_MODE_NONE;\n },\n\n /**********************************************************\n *\n * Event Handler\n *\n **********************************************************/\n\n /**\n * Add all possible event handlers to the board object\n */\n addEventHandlers: function () {\n if (Env.supportsPointerEvents()) {\n this.addPointerEventHandlers();\n } else {\n this.addMouseEventHandlers();\n this.addTouchEventHandlers();\n }\n\n // This one produces errors on IE\n //Env.addEvent(this.containerObj, 'contextmenu', function (e) { e.preventDefault(); return false;}, this);\n // This one works on IE, Firefox and Chromium with default configurations. On some Safari\n // or Opera versions the user must explicitly allow the deactivation of the context menu.\n if (this.containerObj !== null) {\n this.containerObj.oncontextmenu = function (e) {\n if (Type.exists(e)) {\n e.preventDefault();\n }\n return false;\n };\n }\n\n this.addFullscreenEventHandlers();\n this.addKeyboardEventHandlers();\n\n if (Env.isBrowser) {\n try {\n // resizeObserver: triggered if size of the JSXGraph div changes.\n this.startResizeObserver();\n } catch (err) {\n // resize event: triggered if size of window changes\n Env.addEvent(window, 'resize', this.resizeListener, this);\n // intersectionObserver: triggered if JSXGraph becomes visible.\n this.startIntersectionObserver();\n }\n // Scroll event: needs to be captured since on mobile devices\n // sometimes a header bar is displayed / hidden, which triggers a\n // resize event.\n Env.addEvent(window, 'scroll', this.scrollListener, this);\n }\n },\n\n /**\n * Remove all event handlers from the board object\n */\n removeEventHandlers: function () {\n this.removeMouseEventHandlers();\n this.removeTouchEventHandlers();\n this.removePointerEventHandlers();\n\n this.removeFullscreenEventHandlers();\n this.removeKeyboardEventHandlers();\n if (Env.isBrowser) {\n if (Type.exists(this.resizeObserver)) {\n this.stopResizeObserver();\n } else {\n Env.removeEvent(window, 'resize', this.resizeListener, this);\n this.stopIntersectionObserver();\n }\n Env.removeEvent(window, 'scroll', this.scrollListener, this);\n }\n },\n\n /**\n * Registers the MSPointer* event handlers.\n */\n addPointerEventHandlers: function () {\n if (!this.hasPointerHandlers && Env.isBrowser) {\n var moveTarget = this.attr.movetarget || this.containerObj;\n\n if (window.navigator.msPointerEnabled) { // IE10-\n Env.addEvent(this.containerObj, 'MSPointerDown', this.pointerDownListener, this);\n Env.addEvent(moveTarget, 'MSPointerMove', this.pointerMoveListener, this);\n } else {\n Env.addEvent(this.containerObj, 'pointerdown', this.pointerDownListener, this);\n Env.addEvent(moveTarget, 'pointermove', this.pointerMoveListener, this);\n }\n Env.addEvent(this.containerObj, 'mousewheel', this.mouseWheelListener, this);\n Env.addEvent(this.containerObj, 'DOMMouseScroll', this.mouseWheelListener, this);\n\n if (this.containerObj !== null) {\n // This is needed for capturing touch events.\n // It is also in jsxgraph.css, but one never knows...\n this.containerObj.style.touchAction = 'none';\n }\n\n this.hasPointerHandlers = true;\n }\n },\n\n /**\n * Registers mouse move, down and wheel event handlers.\n */\n addMouseEventHandlers: function () {\n if (!this.hasMouseHandlers && Env.isBrowser) {\n var moveTarget = this.attr.movetarget || this.containerObj;\n\n Env.addEvent(this.containerObj, 'mousedown', this.mouseDownListener, this);\n Env.addEvent(moveTarget, 'mousemove', this.mouseMoveListener, this);\n\n Env.addEvent(this.containerObj, 'mousewheel', this.mouseWheelListener, this);\n Env.addEvent(this.containerObj, 'DOMMouseScroll', this.mouseWheelListener, this);\n\n this.hasMouseHandlers = true;\n }\n },\n\n /**\n * Register touch start and move and gesture start and change event handlers.\n * @param {Boolean} appleGestures If set to false the gesturestart and gesturechange event handlers\n * will not be registered.\n *\n * Since iOS 13, touch events were abandoned in favour of pointer events\n */\n addTouchEventHandlers: function (appleGestures) {\n if (!this.hasTouchHandlers && Env.isBrowser) {\n var moveTarget = this.attr.movetarget || this.containerObj;\n\n Env.addEvent(this.containerObj, 'touchstart', this.touchStartListener, this);\n Env.addEvent(moveTarget, 'touchmove', this.touchMoveListener, this);\n\n /*\n if (!Type.exists(appleGestures) || appleGestures) {\n // Gesture listener are called in touchStart and touchMove.\n //Env.addEvent(this.containerObj, 'gesturestart', this.gestureStartListener, this);\n //Env.addEvent(this.containerObj, 'gesturechange', this.gestureChangeListener, this);\n }\n */\n\n this.hasTouchHandlers = true;\n }\n },\n\n /**\n * Add fullscreen events which update the CSS transformation matrix to correct\n * the mouse/touch/pointer positions in case of CSS transformations.\n */\n addFullscreenEventHandlers: function() {\n var i,\n // standard/Edge, firefox, chrome/safari, IE11\n events = ['fullscreenchange', 'mozfullscreenchange', 'webkitfullscreenchange', 'msfullscreenchange'],\n le = events.length;\n\n if (!this.hasFullsceenEventHandlers && Env.isBrowser) {\n for (i = 0; i < le; i++) {\n Env.addEvent(this.document, events[i], this.fullscreenListener, this);\n }\n this.hasFullsceenEventHandlers = true;\n }\n },\n\n addKeyboardEventHandlers: function() {\n if (this.attr.keyboard.enabled && !this.hasKeyboardHandlers && Env.isBrowser) {\n Env.addEvent(this.containerObj, 'keydown', this.keyDownListener, this);\n Env.addEvent(this.containerObj, 'focusin', this.keyFocusInListener, this);\n Env.addEvent(this.containerObj, 'focusout', this.keyFocusOutListener, this);\n this.hasKeyboardHandlers = true;\n }\n },\n\n /**\n * Remove all registered touch event handlers.\n */\n removeKeyboardEventHandlers: function () {\n if (this.hasKeyboardHandlers && Env.isBrowser) {\n Env.removeEvent(this.containerObj, 'keydown', this.keyDownListener, this);\n Env.removeEvent(this.containerObj, 'focusin', this.keyFocusInListener, this);\n Env.removeEvent(this.containerObj, 'focusout', this.keyFocusOutListener, this);\n this.hasKeyboardHandlers = false;\n }\n },\n\n /**\n * Remove all registered event handlers regarding fullscreen mode.\n */\n removeFullscreenEventHandlers: function() {\n var i,\n // standard/Edge, firefox, chrome/safari, IE11\n events = ['fullscreenchange', 'mozfullscreenchange', 'webkitfullscreenchange', 'msfullscreenchange'],\n le = events.length;\n\n if (this.hasFullsceenEventHandlers && Env.isBrowser) {\n for (i = 0; i < le; i++) {\n Env.removeEvent(this.document, events[i], this.fullscreenListener, this);\n }\n this.hasFullsceenEventHandlers = false;\n }\n },\n\n /**\n * Remove MSPointer* Event handlers.\n */\n removePointerEventHandlers: function () {\n if (this.hasPointerHandlers && Env.isBrowser) {\n var moveTarget = this.attr.movetarget || this.containerObj;\n\n if (window.navigator.msPointerEnabled) { // IE10-\n Env.removeEvent(this.containerObj, 'MSPointerDown', this.pointerDownListener, this);\n Env.removeEvent(moveTarget, 'MSPointerMove', this.pointerMoveListener, this);\n } else {\n Env.removeEvent(this.containerObj, 'pointerdown', this.pointerDownListener, this);\n Env.removeEvent(moveTarget, 'pointermove', this.pointerMoveListener, this);\n }\n\n Env.removeEvent(this.containerObj, 'mousewheel', this.mouseWheelListener, this);\n Env.removeEvent(this.containerObj, 'DOMMouseScroll', this.mouseWheelListener, this);\n\n if (this.hasPointerUp) {\n if (window.navigator.msPointerEnabled) { // IE10-\n Env.removeEvent(this.document, 'MSPointerUp', this.pointerUpListener, this);\n } else {\n Env.removeEvent(this.document, 'pointerup', this.pointerUpListener, this);\n Env.removeEvent(this.document, 'pointercancel', this.pointerUpListener, this);\n }\n this.hasPointerUp = false;\n }\n\n this.hasPointerHandlers = false;\n }\n },\n\n /**\n * De-register mouse event handlers.\n */\n removeMouseEventHandlers: function () {\n if (this.hasMouseHandlers && Env.isBrowser) {\n var moveTarget = this.attr.movetarget || this.containerObj;\n\n Env.removeEvent(this.containerObj, 'mousedown', this.mouseDownListener, this);\n Env.removeEvent(moveTarget, 'mousemove', this.mouseMoveListener, this);\n\n if (this.hasMouseUp) {\n Env.removeEvent(this.document, 'mouseup', this.mouseUpListener, this);\n this.hasMouseUp = false;\n }\n\n Env.removeEvent(this.containerObj, 'mousewheel', this.mouseWheelListener, this);\n Env.removeEvent(this.containerObj, 'DOMMouseScroll', this.mouseWheelListener, this);\n\n this.hasMouseHandlers = false;\n }\n },\n\n /**\n * Remove all registered touch event handlers.\n */\n removeTouchEventHandlers: function () {\n if (this.hasTouchHandlers && Env.isBrowser) {\n var moveTarget = this.attr.movetarget || this.containerObj;\n\n Env.removeEvent(this.containerObj, 'touchstart', this.touchStartListener, this);\n Env.removeEvent(moveTarget, 'touchmove', this.touchMoveListener, this);\n\n if (this.hasTouchEnd) {\n Env.removeEvent(this.document, 'touchend', this.touchEndListener, this);\n this.hasTouchEnd = false;\n }\n\n this.hasTouchHandlers = false;\n }\n },\n\n /**\n * Handler for click on left arrow in the navigation bar\n * @returns {JXG.Board} Reference to the board\n */\n clickLeftArrow: function () {\n this.moveOrigin(this.origin.scrCoords[1] + this.canvasWidth * 0.1, this.origin.scrCoords[2]);\n return this;\n },\n\n /**\n * Handler for click on right arrow in the navigation bar\n * @returns {JXG.Board} Reference to the board\n */\n clickRightArrow: function () {\n this.moveOrigin(this.origin.scrCoords[1] - this.canvasWidth * 0.1, this.origin.scrCoords[2]);\n return this;\n },\n\n /**\n * Handler for click on up arrow in the navigation bar\n * @returns {JXG.Board} Reference to the board\n */\n clickUpArrow: function () {\n this.moveOrigin(this.origin.scrCoords[1], this.origin.scrCoords[2] - this.canvasHeight * 0.1);\n return this;\n },\n\n /**\n * Handler for click on down arrow in the navigation bar\n * @returns {JXG.Board} Reference to the board\n */\n clickDownArrow: function () {\n this.moveOrigin(this.origin.scrCoords[1], this.origin.scrCoords[2] + this.canvasHeight * 0.1);\n return this;\n },\n\n /**\n * Triggered on iOS/Safari while the user inputs a gesture (e.g. pinch) and is used to zoom into the board.\n * Works on iOS/Safari and Android.\n * @param {Event} evt Browser event object\n * @returns {Boolean}\n */\n gestureChangeListener: function (evt) {\n var c,\n dir1 = [],\n dir2 = [],\n angle,\n mi = 10,\n isPinch = false,\n // Save zoomFactors\n zx = this.attr.zoom.factorx,\n zy = this.attr.zoom.factory,\n factor,\n dist,\n dx, dy, theta, cx, cy, bound;\n\n if (this.mode !== this.BOARD_MODE_ZOOM) {\n return true;\n }\n evt.preventDefault();\n\n dist = Geometry.distance([evt.touches[0].clientX, evt.touches[0].clientY],\n [evt.touches[1].clientX, evt.touches[1].clientY], 2);\n\n // Android pinch to zoom\n // evt.scale was available in iOS touch events (pre iOS 13)\n // evt.scale is undefined in Android\n if (evt.scale === undefined) {\n evt.scale = dist / this.prevDist;\n }\n\n if (!Type.exists(this.prevCoords)) {\n return false;\n }\n // Compute the angle of the two finger directions\n dir1 = [evt.touches[0].clientX - this.prevCoords[0][0],\n evt.touches[0].clientY - this.prevCoords[0][1]];\n dir2 = [evt.touches[1].clientX - this.prevCoords[1][0],\n evt.touches[1].clientY - this.prevCoords[1][1]];\n\n if ((dir1[0] * dir1[0] + dir1[1] * dir1[1] < mi * mi) &&\n (dir2[0] * dir2[0] + dir2[1] * dir2[1] < mi * mi)) {\n return false;\n }\n\n angle = Geometry.rad(dir1, [0,0], dir2);\n if (this.isPreviousGesture !== 'pan' &&\n Math.abs(angle) > Math.PI * 0.2 &&\n Math.abs(angle) < Math.PI * 1.8) {\n isPinch = true;\n }\n\n if (this.isPreviousGesture !== 'pan' && !isPinch) {\n if (Math.abs(evt.scale) < 0.77 || Math.abs(evt.scale) > 1.3) {\n isPinch = true;\n }\n }\n\n factor = evt.scale / this.prevScale;\n this.prevScale = evt.scale;\n this.prevCoords = [[evt.touches[0].clientX, evt.touches[0].clientY],\n [evt.touches[1].clientX, evt.touches[1].clientY]];\n\n c = new Coords(Const.COORDS_BY_SCREEN, this.getMousePosition(evt, 0), this);\n\n if (this.attr.pan.enabled &&\n this.attr.pan.needtwofingers &&\n !isPinch) {\n // Pan detected\n\n this.isPreviousGesture = 'pan';\n\n this.moveOrigin(c.scrCoords[1], c.scrCoords[2], true);\n } else if (this.attr.zoom.enabled &&\n Math.abs(factor - 1.0) < 0.5) {\n // Pinch detected\n\n if (this.attr.zoom.pinchhorizontal || this.attr.zoom.pinchvertical) {\n dx = Math.abs(evt.touches[0].clientX - evt.touches[1].clientX);\n dy = Math.abs(evt.touches[0].clientY - evt.touches[1].clientY);\n theta = Math.abs(Math.atan2(dy, dx));\n bound = Math.PI * this.attr.zoom.pinchsensitivity / 90.0;\n }\n\n if (this.attr.zoom.pinchhorizontal && theta < bound) {\n this.attr.zoom.factorx = factor;\n this.attr.zoom.factory = 1.0;\n cx = 0;\n cy = 0;\n } else if (this.attr.zoom.pinchvertical && Math.abs(theta - Math.PI * 0.5) < bound) {\n this.attr.zoom.factorx = 1.0;\n this.attr.zoom.factory = factor;\n cx = 0;\n cy = 0;\n } else {\n this.attr.zoom.factorx = factor;\n this.attr.zoom.factory = factor;\n cx = c.usrCoords[1];\n cy = c.usrCoords[2];\n }\n\n this.zoomIn(cx, cy);\n\n // Restore zoomFactors\n this.attr.zoom.factorx = zx;\n this.attr.zoom.factory = zy;\n }\n\n return false;\n },\n\n /**\n * Called by iOS/Safari as soon as the user starts a gesture. Works natively on iOS/Safari,\n * on Android we emulate it.\n * @param {Event} evt\n * @returns {Boolean}\n */\n gestureStartListener: function (evt) {\n var pos;\n\n evt.preventDefault();\n this.prevScale = 1.0;\n // Android pinch to zoom\n this.prevDist = Geometry.distance([evt.touches[0].clientX, evt.touches[0].clientY],\n [evt.touches[1].clientX, evt.touches[1].clientY], 2);\n this.prevCoords = [[evt.touches[0].clientX, evt.touches[0].clientY],\n [evt.touches[1].clientX, evt.touches[1].clientY]];\n this.isPreviousGesture = 'none';\n\n // If pinch-to-zoom is interpreted as panning\n // we have to prepare move origin\n pos = this.getMousePosition(evt, 0);\n this.initMoveOrigin(pos[0], pos[1]);\n\n this.mode = this.BOARD_MODE_ZOOM;\n return false;\n },\n\n /**\n * Test if the required key combination is pressed for wheel zoom, move origin and\n * selection\n * @private\n * @param {Object} evt Mouse or pen event\n * @param {String} action String containing the action: 'zoom', 'pan', 'selection'.\n * Corresponds to the attribute subobject.\n * @return {Boolean} true or false.\n */\n _isRequiredKeyPressed: function (evt, action) {\n var obj = this.attr[action];\n if (!obj.enabled) {\n return false;\n }\n\n if (((obj.needshift && evt.shiftKey) || (!obj.needshift && !evt.shiftKey)) &&\n ((obj.needctrl && evt.ctrlKey) || (!obj.needctrl && !evt.ctrlKey))\n ) {\n return true;\n }\n\n return false;\n },\n\n /*\n * Pointer events\n */\n\n /**\n *\n * Check if pointer event is already registered in {@link JXG.Board#_board_touches}.\n *\n * @param {Object} evt Event object\n * @return {Boolean} true if down event has already been sent.\n * @private\n */\n _isPointerRegistered: function(evt) {\n var i, len = this._board_touches.length;\n\n for (i = 0; i < len; i++) {\n if (this._board_touches[i].pointerId === evt.pointerId) {\n return true;\n }\n }\n return false;\n },\n\n /**\n *\n * Store the position of a pointer event.\n * If not yet done, registers a pointer event in {@link JXG.Board#_board_touches}.\n * Allows to follow the path of that finger on the screen.\n * Only two simultaneous touches are supported.\n *\n * @param {Object} evt Event object\n * @returns {JXG.Board} Reference to the board\n * @private\n */\n _pointerStorePosition: function (evt) {\n var i, found;\n\n for (i = 0, found = false; i < this._board_touches.length; i++) {\n if (this._board_touches[i].pointerId === evt.pointerId) {\n this._board_touches[i].clientX = evt.clientX;\n this._board_touches[i].clientY = evt.clientY;\n found = true;\n break;\n }\n }\n\n // Restrict the number of simultaneous touches to 2\n if (!found && this._board_touches.length < 2) {\n this._board_touches.push({\n pointerId: evt.pointerId,\n clientX: evt.clientX,\n clientY: evt.clientY\n });\n }\n\n return this;\n },\n\n /**\n * Deregisters a pointer event in {@link JXG.Board#_board_touches}.\n * It happens if a finger has been lifted from the screen.\n *\n * @param {Object} evt Event object\n * @returns {JXG.Board} Reference to the board\n * @private\n */\n _pointerRemoveTouches: function (evt) {\n var i;\n for (i = 0; i < this._board_touches.length; i++) {\n if (this._board_touches[i].pointerId === evt.pointerId) {\n this._board_touches.splice(i, 1);\n break;\n }\n }\n\n return this;\n },\n\n /**\n * Remove all registered fingers from {@link JXG.Board#_board_touches}.\n * This might be necessary if too many fingers have been registered.\n * @returns {JXG.Board} Reference to the board\n * @private\n */\n _pointerClearTouches: function() {\n if (this._board_touches.length > 0) {\n this.dehighlightAll();\n }\n this.updateQuality = this.BOARD_QUALITY_HIGH;\n this.mode = this.BOARD_MODE_NONE;\n this._board_touches = [];\n this.touches = [];\n },\n\n /**\n * Determine which input device is used for this action.\n * Possible devices are 'touch', 'pen' and 'mouse'.\n * This affects the precision and certain events.\n * In case of no browser, 'mouse' is used.\n *\n * @see JXG.Board#pointerDownListener\n * @see JXG.Board#pointerMoveListener\n * @see JXG.Board#initMoveObject\n * @see JXG.Board#moveObject\n *\n * @param {Event} evt The browsers event object.\n * @returns {String} 'mouse', 'pen', or 'touch'\n * @private\n */\n _getPointerInputDevice: function(evt) {\n if (Env.isBrowser) {\n if (evt.pointerType === 'touch' || // New\n (window.navigator.msMaxTouchPoints && // Old\n window.navigator.msMaxTouchPoints > 1)) {\n return 'touch';\n }\n if (evt.pointerType === 'mouse') {\n return 'mouse';\n }\n if (evt.pointerType === 'pen') {\n return 'pen';\n }\n }\n return 'mouse';\n },\n\n /**\n * This method is called by the browser when a pointing device is pressed on the screen.\n * @param {Event} evt The browsers event object.\n * @param {Object} object If the object to be dragged is already known, it can be submitted via this parameter\n * @returns {Boolean} ...\n */\n pointerDownListener: function (evt, object) {\n var i, j, k, pos, elements, sel,\n target_obj,\n type = 'mouse', // Used in case of no browser\n found, target;\n\n // Fix for Firefox browser: When using a second finger, the\n // touch event for the first finger is sent again.\n if (!object && this._isPointerRegistered(evt)) {\n return false;\n }\n\n if (!object && evt.isPrimary) {\n // First finger down. To be on the safe side this._board_touches is cleared.\n this._pointerClearTouches();\n }\n\n if (!this.hasPointerUp) {\n if (window.navigator.msPointerEnabled) { // IE10-\n Env.addEvent(this.document, 'MSPointerUp', this.pointerUpListener, this);\n } else {\n // 'pointercancel' is fired e.g. if the finger leaves the browser and drags down the system menu on Android\n Env.addEvent(this.document, 'pointerup', this.pointerUpListener, this);\n Env.addEvent(this.document, 'pointercancel', this.pointerUpListener, this);\n }\n this.hasPointerUp = true;\n }\n\n if (this.hasMouseHandlers) {\n this.removeMouseEventHandlers();\n }\n\n if (this.hasTouchHandlers) {\n this.removeTouchEventHandlers();\n }\n\n // Prevent accidental selection of text\n if (this.document.selection && Type.isFunction(this.document.selection.empty)) {\n this.document.selection.empty();\n } else if (window.getSelection) {\n sel = window.getSelection();\n if (sel.removeAllRanges) {\n try {\n sel.removeAllRanges();\n } catch (e) {}\n }\n }\n\n // Mouse, touch or pen device\n this._inputDevice = this._getPointerInputDevice(evt);\n type = this._inputDevice;\n this.options.precision.hasPoint = this.options.precision[type];\n\n // Handling of multi touch with pointer events should be easier than the touch events.\n // Every pointer device has its own pointerId, e.g. the mouse\n // always has id 1 or 0, fingers and pens get unique ids every time a pointerDown event is fired and they will\n // keep this id until a pointerUp event is fired. What we have to do here is:\n // 1. collect all elements under the current pointer\n // 2. run through the touches control structure\n // a. look for the object collected in step 1.\n // b. if an object is found, check the number of pointers. If appropriate, add the pointer.\n pos = this.getMousePosition(evt);\n\n // selection\n this._testForSelection(evt);\n if (this.selectingMode) {\n this._startSelecting(pos);\n this.triggerEventHandlers(['touchstartselecting', 'pointerstartselecting', 'startselecting'], [evt]);\n return; // don't continue as a normal click\n }\n\n if (this.attr.drag.enabled && object) {\n elements = [ object ];\n this.mode = this.BOARD_MODE_DRAG;\n } else {\n elements = this.initMoveObject(pos[0], pos[1], evt, type);\n }\n\n target_obj = {\n num: evt.pointerId,\n X: pos[0],\n Y: pos[1],\n Xprev: NaN,\n Yprev: NaN,\n Xstart: [],\n Ystart: [],\n Zstart: []\n };\n\n // If no draggable object can be found, get out here immediately\n if (elements.length > 0) {\n // check touches structure\n target = elements[elements.length - 1];\n found = false;\n\n // Reminder: this.touches is the list of elements which\n // currently \"possess\" a pointer (mouse, pen, finger)\n for (i = 0; i < this.touches.length; i++) {\n // An element receives a further touch, i.e.\n // the target is already in our touches array, add the pointer to the existing touch\n if (this.touches[i].obj === target) {\n j = i;\n k = this.touches[i].targets.push(target_obj) - 1;\n found = true;\n break;\n }\n }\n if (!found) {\n // An new element hae been touched.\n k = 0;\n j = this.touches.push({\n obj: target,\n targets: [target_obj]\n }) - 1;\n }\n\n this.dehighlightAll();\n target.highlight(true);\n\n this.saveStartPos(target, this.touches[j].targets[k]);\n\n // Prevent accidental text selection\n // this could get us new trouble: input fields, links and drop down boxes placed as text\n // on the board don't work anymore.\n if (evt && evt.preventDefault) {\n evt.preventDefault();\n } else if (window.event) {\n window.event.returnValue = false;\n }\n }\n\n if (this.touches.length > 0) {\n evt.preventDefault();\n evt.stopPropagation();\n }\n\n if (!Env.isBrowser) {\n return false;\n }\n if (this._getPointerInputDevice(evt) !== 'touch') {\n if (this.mode === this.BOARD_MODE_NONE) {\n this.mouseOriginMoveStart(evt);\n }\n } else {\n this._pointerStorePosition(evt);\n evt.touches = this._board_touches;\n\n // Touch events on empty areas of the board are handled here, see also touchStartListener\n // 1. case: one finger. If allowed, this triggers pan with one finger\n if (evt.touches.length === 1 &&\n this.mode === this.BOARD_MODE_NONE &&\n this.touchStartMoveOriginOneFinger(evt)) {\n // Empty by purpose\n } else if (evt.touches.length === 2 &&\n (this.mode === this.BOARD_MODE_NONE || this.mode === this.BOARD_MODE_MOVE_ORIGIN)\n ) {\n // 2. case: two fingers: pinch to zoom or pan with two fingers needed.\n // This happens when the second finger hits the device. First, the\n // \"one finger pan mode\" has to be cancelled.\n if (this.mode === this.BOARD_MODE_MOVE_ORIGIN) {\n this.originMoveEnd();\n }\n\n this.gestureStartListener(evt);\n }\n }\n\n this.triggerEventHandlers(['touchstart', 'down', 'pointerdown', 'MSPointerDown'], [evt]);\n return false;\n },\n\n // /**\n // * Called if pointer leaves an HTML tag. It is called by the inner-most tag.\n // * That means, if a JSXGraph text, i.e. an HTML div, is placed close\n // * to the border of the board, this pointerout event will be ignored.\n // * @param {Event} evt\n // * @return {Boolean}\n // */\n // pointerOutListener: function (evt) {\n // if (evt.target === this.containerObj ||\n // (this.renderer.type === 'svg' && evt.target === this.renderer.foreignObjLayer)) {\n // this.pointerUpListener(evt);\n // }\n // return this.mode === this.BOARD_MODE_NONE;\n // },\n\n /**\n * Called periodically by the browser while the user moves a pointing device across the screen.\n * @param {Event} evt\n * @returns {Boolean}\n */\n pointerMoveListener: function (evt) {\n var i, j, pos, touchTargets,\n type = 'mouse'; // in case of no browser\n\n if (this._getPointerInputDevice(evt) === 'touch' && !this._isPointerRegistered(evt)) {\n // Test, if there was a previous down event of this _getPointerId\n // (in case it is a touch event).\n // Otherwise this move event is ignored. This is necessary e.g. for sketchometry.\n return this.BOARD_MODE_NONE;\n }\n\n if (!this.checkFrameRate(evt)) {\n return false;\n }\n\n if (this.mode !== this.BOARD_MODE_DRAG) {\n this.dehighlightAll();\n this.displayInfobox(false);\n }\n\n if (this.mode !== this.BOARD_MODE_NONE) {\n evt.preventDefault();\n evt.stopPropagation();\n }\n\n this.updateQuality = this.BOARD_QUALITY_LOW;\n // Mouse, touch or pen device\n this._inputDevice = this._getPointerInputDevice(evt);\n type = this._inputDevice;\n this.options.precision.hasPoint = this.options.precision[type];\n\n // selection\n if (this.selectingMode) {\n pos = this.getMousePosition(evt);\n this._moveSelecting(pos);\n this.triggerEventHandlers(['touchmoveselecting', 'moveselecting', 'pointermoveselecting'], [evt, this.mode]);\n } else if (!this.mouseOriginMove(evt)) {\n if (this.mode === this.BOARD_MODE_DRAG) {\n // Run through all jsxgraph elements which are touched by at least one finger.\n for (i = 0; i < this.touches.length; i++) {\n touchTargets = this.touches[i].targets;\n // Run through all touch events which have been started on this jsxgraph element.\n for (j = 0; j < touchTargets.length; j++) {\n if (touchTargets[j].num === evt.pointerId) {\n\n pos = this.getMousePosition(evt);\n touchTargets[j].X = pos[0];\n touchTargets[j].Y = pos[1];\n\n if (touchTargets.length === 1) {\n // Touch by one finger: this is possible for all elements that can be dragged\n this.moveObject(pos[0], pos[1], this.touches[i], evt, type);\n } else if (touchTargets.length === 2) {\n // Touch by two fingers: e.g. moving lines\n this.twoFingerMove(this.touches[i], evt.pointerId, evt);\n\n touchTargets[j].Xprev = pos[0];\n touchTargets[j].Yprev = pos[1];\n }\n\n // There is only one pointer in the evt object, so there's no point in looking further\n break;\n }\n }\n }\n } else {\n if (this._getPointerInputDevice(evt) === 'touch') {\n this._pointerStorePosition(evt);\n\n if (this._board_touches.length === 2) {\n evt.touches = this._board_touches;\n this.gestureChangeListener(evt);\n }\n }\n\n // Move event without dragging an element\n pos = this.getMousePosition(evt);\n this.highlightElements(pos[0], pos[1], evt, -1);\n }\n }\n\n // Hiding the infobox is commented out, since it prevents showing the infobox\n // on IE 11+ on 'over'\n //if (this.mode !== this.BOARD_MODE_DRAG) {\n //this.displayInfobox(false);\n //}\n this.triggerEventHandlers(['touchmove', 'move', 'pointermove', 'MSPointerMove'], [evt, this.mode]);\n this.updateQuality = this.BOARD_QUALITY_HIGH;\n\n return this.mode === this.BOARD_MODE_NONE;\n },\n\n /**\n * Triggered as soon as the user stops touching the device with at least one finger.\n * @param {Event} evt\n * @returns {Boolean}\n */\n pointerUpListener: function (evt) {\n var i, j, found, touchTargets;\n\n this.triggerEventHandlers(['touchend', 'up', 'pointerup', 'MSPointerUp'], [evt]);\n this.displayInfobox(false);\n\n if (evt) {\n for (i = 0; i < this.touches.length; i++) {\n touchTargets = this.touches[i].targets;\n for (j = 0; j < touchTargets.length; j++) {\n if (touchTargets[j].num === evt.pointerId) {\n touchTargets.splice(j, 1);\n if (touchTargets.length === 0) {\n this.touches.splice(i, 1);\n }\n break;\n }\n }\n }\n }\n\n this.originMoveEnd();\n this.update();\n\n // selection\n if (this.selectingMode) {\n this._stopSelecting(evt);\n this.triggerEventHandlers(['touchstopselecting', 'pointerstopselecting', 'stopselecting'], [evt]);\n this.stopSelectionMode();\n } else {\n for (i = this.downObjects.length - 1; i > -1; i--) {\n found = false;\n for (j = 0; j < this.touches.length; j++) {\n if (this.touches[j].obj.id === this.downObjects[i].id) {\n found = true;\n }\n }\n if (!found) {\n this.downObjects[i].triggerEventHandlers(['touchend', 'up', 'pointerup', 'MSPointerUp'], [evt]);\n // this.downObjects[i].snapToGrid();\n // this.downObjects[i].snapToPoints();\n this.downObjects.splice(i, 1);\n }\n }\n }\n\n if (this.hasPointerUp) {\n if (window.navigator.msPointerEnabled) { // IE10-\n Env.removeEvent(this.document, 'MSPointerUp', this.pointerUpListener, this);\n } else {\n Env.removeEvent(this.document, 'pointerup', this.pointerUpListener, this);\n Env.removeEvent(this.document, 'pointercancel', this.pointerUpListener, this);\n }\n this.hasPointerUp = false;\n }\n\n // this.dehighlightAll();\n // this.updateQuality = this.BOARD_QUALITY_HIGH;\n // this.mode = this.BOARD_MODE_NONE;\n\n // this.originMoveEnd();\n // this.update();\n\n // After one finger leaves the screen the gesture is stopped.\n this._pointerClearTouches();\n return true;\n },\n\n /**\n * Touch-Events\n */\n\n /**\n * This method is called by the browser when a finger touches the surface of the touch-device.\n * @param {Event} evt The browsers event object.\n * @returns {Boolean} ...\n */\n touchStartListener: function (evt) {\n var i, pos, elements, j, k,\n eps = this.options.precision.touch,\n obj, found, targets,\n evtTouches = evt[JXG.touchProperty],\n target, touchTargets;\n\n if (!this.hasTouchEnd) {\n Env.addEvent(this.document, 'touchend', this.touchEndListener, this);\n this.hasTouchEnd = true;\n }\n\n // Do not remove mouseHandlers, since Chrome on win tablets sends mouseevents if used with pen.\n //if (this.hasMouseHandlers) { this.removeMouseEventHandlers(); }\n\n // prevent accidental selection of text\n if (this.document.selection && Type.isFunction(this.document.selection.empty)) {\n this.document.selection.empty();\n } else if (window.getSelection) {\n window.getSelection().removeAllRanges();\n }\n\n // multitouch\n this._inputDevice = 'touch';\n this.options.precision.hasPoint = this.options.precision.touch;\n\n // This is the most critical part. first we should run through the existing touches and collect all targettouches that don't belong to our\n // previous touches. once this is done we run through the existing touches again and watch out for free touches that can be attached to our existing\n // touches, e.g. we translate (parallel translation) a line with one finger, now a second finger is over this line. this should change the operation to\n // a rotational translation. or one finger moves a circle, a second finger can be attached to the circle: this now changes the operation from translation to\n // stretching. as a last step we're going through the rest of the targettouches and initiate new move operations:\n // * points have higher priority over other elements.\n // * if we find a targettouch over an element that could be transformed with more than one finger, we search the rest of the targettouches, if they are over\n // this element and add them.\n // ADDENDUM 11/10/11:\n // (1) run through the touches control object,\n // (2) try to find the targetTouches for every touch. on touchstart only new touches are added, hence we can find a targettouch\n // for every target in our touches objects\n // (3) if one of the targettouches was bound to a touches targets array, mark it\n // (4) run through the targettouches. if the targettouch is marked, continue. otherwise check for elements below the targettouch:\n // (a) if no element could be found: mark the target touches and continue\n // --- in the following cases, \"init\" means:\n // (i) check if the element is already used in another touches element, if so, mark the targettouch and continue\n // (ii) if not, init a new touches element, add the targettouch to the touches property and mark it\n // (b) if the element is a point, init\n // (c) if the element is a line, init and try to find a second targettouch on that line. if a second one is found, add and mark it\n // (d) if the element is a circle, init and try to find TWO other targettouches on that circle. if only one is found, mark it and continue. otherwise\n // add both to the touches array and mark them.\n for (i = 0; i < evtTouches.length; i++) {\n evtTouches[i].jxg_isused = false;\n }\n\n for (i = 0; i < this.touches.length; i++) {\n touchTargets = this.touches[i].targets;\n for (j = 0; j < touchTargets.length; j++) {\n touchTargets[j].num = -1;\n eps = this.options.precision.touch;\n\n do {\n for (k = 0; k < evtTouches.length; k++) {\n // find the new targettouches\n if (Math.abs(Math.pow(evtTouches[k].screenX - touchTargets[j].X, 2) +\n Math.pow(evtTouches[k].screenY - touchTargets[j].Y, 2)) < eps * eps) {\n touchTargets[j].num = k;\n touchTargets[j].X = evtTouches[k].screenX;\n touchTargets[j].Y = evtTouches[k].screenY;\n evtTouches[k].jxg_isused = true;\n break;\n }\n }\n\n eps *= 2;\n\n } while (touchTargets[j].num === -1 &&\n eps < this.options.precision.touchMax);\n\n if (touchTargets[j].num === -1) {\n JXG.debug('i couldn\\'t find a targettouches for target no ' + j + ' on ' + this.touches[i].obj.name + ' (' + this.touches[i].obj.id + '). Removed the target.');\n JXG.debug('eps = ' + eps + ', touchMax = ' + Options.precision.touchMax);\n touchTargets.splice(i, 1);\n }\n\n }\n }\n\n // we just re-mapped the targettouches to our existing touches list.\n // now we have to initialize some touches from additional targettouches\n for (i = 0; i < evtTouches.length; i++) {\n if (!evtTouches[i].jxg_isused) {\n\n pos = this.getMousePosition(evt, i);\n // selection\n // this._testForSelection(evt); // we do not have shift or ctrl keys yet.\n if (this.selectingMode) {\n this._startSelecting(pos);\n this.triggerEventHandlers(['touchstartselecting', 'startselecting'], [evt]);\n evt.preventDefault();\n evt.stopPropagation();\n this.options.precision.hasPoint = this.options.precision.mouse;\n return this.touches.length > 0; // don't continue as a normal click\n }\n\n elements = this.initMoveObject(pos[0], pos[1], evt, 'touch');\n if (elements.length !== 0) {\n obj = elements[elements.length - 1];\n target = {num: i,\n X: evtTouches[i].screenX,\n Y: evtTouches[i].screenY,\n Xprev: NaN,\n Yprev: NaN,\n Xstart: [],\n Ystart: [],\n Zstart: []\n };\n\n if (Type.isPoint(obj) ||\n obj.elementClass === Const.OBJECT_CLASS_TEXT ||\n obj.type === Const.OBJECT_TYPE_TICKS ||\n obj.type === Const.OBJECT_TYPE_IMAGE) {\n // It's a point, so it's single touch, so we just push it to our touches\n targets = [target];\n\n // For the UNDO/REDO of object moves\n this.saveStartPos(obj, targets[0]);\n\n this.touches.push({ obj: obj, targets: targets });\n obj.highlight(true);\n\n } else if (obj.elementClass === Const.OBJECT_CLASS_LINE ||\n obj.elementClass === Const.OBJECT_CLASS_CIRCLE ||\n obj.elementClass === Const.OBJECT_CLASS_CURVE ||\n obj.type === Const.OBJECT_TYPE_POLYGON) {\n found = false;\n\n // first check if this geometric object is already captured in this.touches\n for (j = 0; j < this.touches.length; j++) {\n if (obj.id === this.touches[j].obj.id) {\n found = true;\n // only add it, if we don't have two targets in there already\n if (this.touches[j].targets.length === 1) {\n // For the UNDO/REDO of object moves\n this.saveStartPos(obj, target);\n this.touches[j].targets.push(target);\n }\n\n evtTouches[i].jxg_isused = true;\n }\n }\n\n // we couldn't find it in touches, so we just init a new touches\n // IF there is a second touch targetting this line, we will find it later on, and then add it to\n // the touches control object.\n if (!found) {\n targets = [target];\n\n // For the UNDO/REDO of object moves\n this.saveStartPos(obj, targets[0]);\n this.touches.push({ obj: obj, targets: targets });\n obj.highlight(true);\n }\n }\n }\n\n evtTouches[i].jxg_isused = true;\n }\n }\n\n if (this.touches.length > 0) {\n evt.preventDefault();\n evt.stopPropagation();\n }\n\n // Touch events on empty areas of the board are handled here:\n // 1. case: one finger. If allowed, this triggers pan with one finger\n if (evtTouches.length === 1 && this.mode === this.BOARD_MODE_NONE && this.touchStartMoveOriginOneFinger(evt)) {\n } else if (evtTouches.length === 2 &&\n (this.mode === this.BOARD_MODE_NONE || this.mode === this.BOARD_MODE_MOVE_ORIGIN)\n ) {\n // 2. case: two fingers: pinch to zoom or pan with two fingers needed.\n // This happens when the second finger hits the device. First, the\n // \"one finger pan mode\" has to be cancelled.\n if (this.mode === this.BOARD_MODE_MOVE_ORIGIN) {\n this.originMoveEnd();\n }\n this.gestureStartListener(evt);\n }\n\n this.options.precision.hasPoint = this.options.precision.mouse;\n this.triggerEventHandlers(['touchstart', 'down'], [evt]);\n\n return false;\n //return this.touches.length > 0;\n },\n\n /**\n * Called periodically by the browser while the user moves his fingers across the device.\n * @param {Event} evt\n * @returns {Boolean}\n */\n touchMoveListener: function (evt) {\n var i, pos1, pos2,\n touchTargets,\n evtTouches = evt[JXG.touchProperty];\n\n if (!this.checkFrameRate(evt)) {\n return false;\n }\n\n if (this.mode !== this.BOARD_MODE_NONE) {\n evt.preventDefault();\n evt.stopPropagation();\n }\n\n if (this.mode !== this.BOARD_MODE_DRAG) {\n this.dehighlightAll();\n this.displayInfobox(false);\n }\n\n this._inputDevice = 'touch';\n this.options.precision.hasPoint = this.options.precision.touch;\n this.updateQuality = this.BOARD_QUALITY_LOW;\n\n // selection\n if (this.selectingMode) {\n for (i = 0; i < evtTouches.length; i++) {\n if (!evtTouches[i].jxg_isused) {\n pos1 = this.getMousePosition(evt, i);\n this._moveSelecting(pos1);\n this.triggerEventHandlers(['touchmoves', 'moveselecting'], [evt, this.mode]);\n break;\n }\n }\n } else {\n if (!this.touchOriginMove(evt)) {\n if (this.mode === this.BOARD_MODE_DRAG) {\n // Runs over through all elements which are touched\n // by at least one finger.\n for (i = 0; i < this.touches.length; i++) {\n touchTargets = this.touches[i].targets;\n if (touchTargets.length === 1) {\n\n\n // Touch by one finger: this is possible for all elements that can be dragged\n if (evtTouches[touchTargets[0].num]) {\n pos1 = this.getMousePosition(evt, touchTargets[0].num);\n if (pos1[0] < 0 || pos1[0] > this.canvasWidth ||\n pos1[1] < 0 || pos1[1] > this.canvasHeight) {\n return;\n }\n touchTargets[0].X = pos1[0];\n touchTargets[0].Y = pos1[1];\n this.moveObject(pos1[0], pos1[1], this.touches[i], evt, 'touch');\n }\n\n } else if (touchTargets.length === 2 &&\n touchTargets[0].num > -1 &&\n touchTargets[1].num > -1) {\n\n // Touch by two fingers: moving lines, ...\n if (evtTouches[touchTargets[0].num] &&\n evtTouches[touchTargets[1].num]) {\n\n // Get coordinates of the two touches\n pos1 = this.getMousePosition(evt, touchTargets[0].num);\n pos2 = this.getMousePosition(evt, touchTargets[1].num);\n if (pos1[0] < 0 || pos1[0] > this.canvasWidth ||\n pos1[1] < 0 || pos1[1] > this.canvasHeight ||\n pos2[0] < 0 || pos2[0] > this.canvasWidth ||\n pos2[1] < 0 || pos2[1] > this.canvasHeight) {\n return;\n }\n\n touchTargets[0].X = pos1[0];\n touchTargets[0].Y = pos1[1];\n touchTargets[1].X = pos2[0];\n touchTargets[1].Y = pos2[1];\n\n this.twoFingerMove(this.touches[i], touchTargets[0].num, evt);\n this.twoFingerMove(this.touches[i], touchTargets[1].num);\n\n touchTargets[0].Xprev = pos1[0];\n touchTargets[0].Yprev = pos1[1];\n touchTargets[1].Xprev = pos2[0];\n touchTargets[1].Yprev = pos2[1];\n }\n }\n }\n } else {\n if (evtTouches.length === 2) {\n this.gestureChangeListener(evt);\n }\n // Move event without dragging an element\n pos1 = this.getMousePosition(evt, 0);\n this.highlightElements(pos1[0], pos1[1], evt, -1);\n }\n }\n }\n\n if (this.mode !== this.BOARD_MODE_DRAG) {\n this.displayInfobox(false);\n }\n\n this.triggerEventHandlers(['touchmove', 'move'], [evt, this.mode]);\n this.options.precision.hasPoint = this.options.precision.mouse;\n this.updateQuality = this.BOARD_QUALITY_HIGH;\n\n return this.mode === this.BOARD_MODE_NONE;\n },\n\n /**\n * Triggered as soon as the user stops touching the device with at least one finger.\n * @param {Event} evt\n * @returns {Boolean}\n */\n touchEndListener: function (evt) {\n var i, j, k,\n eps = this.options.precision.touch,\n tmpTouches = [], found, foundNumber,\n evtTouches = evt && evt[JXG.touchProperty],\n touchTargets;\n\n this.triggerEventHandlers(['touchend', 'up'], [evt]);\n this.displayInfobox(false);\n\n // selection\n if (this.selectingMode) {\n this._stopSelecting(evt);\n this.triggerEventHandlers(['touchstopselecting', 'stopselecting'], [evt]);\n this.stopSelectionMode();\n } else if (evtTouches && evtTouches.length > 0) {\n for (i = 0; i < this.touches.length; i++) {\n tmpTouches[i] = this.touches[i];\n }\n this.touches.length = 0;\n\n // try to convert the operation, e.g. if a lines is rotated and translated with two fingers and one finger is lifted,\n // convert the operation to a simple one-finger-translation.\n // ADDENDUM 11/10/11:\n // see addendum to touchStartListener from 11/10/11\n // (1) run through the tmptouches\n // (2) check the touches.obj, if it is a\n // (a) point, try to find the targettouch, if found keep it and mark the targettouch, else drop the touch.\n // (b) line with\n // (i) one target: try to find it, if found keep it mark the targettouch, else drop the touch.\n // (ii) two targets: if none can be found, drop the touch. if one can be found, remove the other target. mark all found targettouches\n // (c) circle with [proceed like in line]\n\n // init the targettouches marker\n for (i = 0; i < evtTouches.length; i++) {\n evtTouches[i].jxg_isused = false;\n }\n\n for (i = 0; i < tmpTouches.length; i++) {\n // could all targets of the current this.touches.obj be assigned to targettouches?\n found = false;\n foundNumber = 0;\n touchTargets = tmpTouches[i].targets;\n\n for (j = 0; j < touchTargets.length; j++) {\n touchTargets[j].found = false;\n for (k = 0; k < evtTouches.length; k++) {\n if (Math.abs(Math.pow(evtTouches[k].screenX - touchTargets[j].X, 2) + Math.pow(evtTouches[k].screenY - touchTargets[j].Y, 2)) < eps * eps) {\n touchTargets[j].found = true;\n touchTargets[j].num = k;\n touchTargets[j].X = evtTouches[k].screenX;\n touchTargets[j].Y = evtTouches[k].screenY;\n foundNumber += 1;\n break;\n }\n }\n }\n\n if (Type.isPoint(tmpTouches[i].obj)) {\n found = (touchTargets[0] && touchTargets[0].found);\n } else if (tmpTouches[i].obj.elementClass === Const.OBJECT_CLASS_LINE) {\n found = (touchTargets[0] && touchTargets[0].found) || (touchTargets[1] && touchTargets[1].found);\n } else if (tmpTouches[i].obj.elementClass === Const.OBJECT_CLASS_CIRCLE) {\n found = foundNumber === 1 || foundNumber === 3;\n }\n\n // if we found this object to be still dragged by the user, add it back to this.touches\n if (found) {\n this.touches.push({\n obj: tmpTouches[i].obj,\n targets: []\n });\n\n for (j = 0; j < touchTargets.length; j++) {\n if (touchTargets[j].found) {\n this.touches[this.touches.length - 1].targets.push({\n num: touchTargets[j].num,\n X: touchTargets[j].screenX,\n Y: touchTargets[j].screenY,\n Xprev: NaN,\n Yprev: NaN,\n Xstart: touchTargets[j].Xstart,\n Ystart: touchTargets[j].Ystart,\n Zstart: touchTargets[j].Zstart\n });\n }\n }\n\n } else {\n tmpTouches[i].obj.noHighlight();\n }\n }\n\n } else {\n this.touches.length = 0;\n }\n\n for (i = this.downObjects.length - 1; i > -1; i--) {\n found = false;\n for (j = 0; j < this.touches.length; j++) {\n if (this.touches[j].obj.id === this.downObjects[i].id) {\n found = true;\n }\n }\n if (!found) {\n this.downObjects[i].triggerEventHandlers(['touchup', 'up'], [evt]);\n // this.downObjects[i].snapToGrid();\n // this.downObjects[i].snapToPoints();\n this.downObjects.splice(i, 1);\n }\n }\n\n if (!evtTouches || evtTouches.length === 0) {\n\n if (this.hasTouchEnd) {\n Env.removeEvent(this.document, 'touchend', this.touchEndListener, this);\n this.hasTouchEnd = false;\n }\n\n this.dehighlightAll();\n this.updateQuality = this.BOARD_QUALITY_HIGH;\n\n this.originMoveEnd();\n this.update();\n }\n\n return true;\n },\n\n /**\n * This method is called by the browser when the mouse button is clicked.\n * @param {Event} evt The browsers event object.\n * @returns {Boolean} True if no element is found under the current mouse pointer, false otherwise.\n */\n mouseDownListener: function (evt) {\n var pos, elements, result;\n\n // prevent accidental selection of text\n if (this.document.selection && Type.isFunction(this.document.selection.empty)) {\n this.document.selection.empty();\n } else if (window.getSelection) {\n window.getSelection().removeAllRanges();\n }\n\n if (!this.hasMouseUp) {\n Env.addEvent(this.document, 'mouseup', this.mouseUpListener, this);\n this.hasMouseUp = true;\n } else {\n // In case this.hasMouseUp==true, it may be that there was a\n // mousedown event before which was not followed by an mouseup event.\n // This seems to happen with interactive whiteboard pens sometimes.\n return;\n }\n\n this._inputDevice = 'mouse';\n this.options.precision.hasPoint = this.options.precision.mouse;\n pos = this.getMousePosition(evt);\n\n // selection\n this._testForSelection(evt);\n if (this.selectingMode) {\n this._startSelecting(pos);\n this.triggerEventHandlers(['mousestartselecting', 'startselecting'], [evt]);\n return; // don't continue as a normal click\n }\n\n elements = this.initMoveObject(pos[0], pos[1], evt, 'mouse');\n\n // if no draggable object can be found, get out here immediately\n if (elements.length === 0) {\n this.mode = this.BOARD_MODE_NONE;\n result = true;\n } else {\n /** @ignore */\n this.mouse = {\n obj: null,\n targets: [{\n X: pos[0],\n Y: pos[1],\n Xprev: NaN,\n Yprev: NaN\n }]\n };\n this.mouse.obj = elements[elements.length - 1];\n\n this.dehighlightAll();\n this.mouse.obj.highlight(true);\n\n this.mouse.targets[0].Xstart = [];\n this.mouse.targets[0].Ystart = [];\n this.mouse.targets[0].Zstart = [];\n\n this.saveStartPos(this.mouse.obj, this.mouse.targets[0]);\n\n // prevent accidental text selection\n // this could get us new trouble: input fields, links and drop down boxes placed as text\n // on the board don't work anymore.\n if (evt && evt.preventDefault) {\n evt.preventDefault();\n } else if (window.event) {\n window.event.returnValue = false;\n }\n }\n\n if (this.mode === this.BOARD_MODE_NONE) {\n result = this.mouseOriginMoveStart(evt);\n }\n\n this.triggerEventHandlers(['mousedown', 'down'], [evt]);\n\n return result;\n },\n\n /**\n * This method is called by the browser when the mouse is moved.\n * @param {Event} evt The browsers event object.\n */\n mouseMoveListener: function (evt) {\n var pos;\n\n if (!this.checkFrameRate(evt)) {\n return false;\n }\n\n pos = this.getMousePosition(evt);\n\n this.updateQuality = this.BOARD_QUALITY_LOW;\n\n if (this.mode !== this.BOARD_MODE_DRAG) {\n this.dehighlightAll();\n this.displayInfobox(false);\n }\n\n // we have to check for four cases:\n // * user moves origin\n // * user drags an object\n // * user just moves the mouse, here highlight all elements at\n // the current mouse position\n // * the user is selecting\n\n // selection\n if (this.selectingMode) {\n this._moveSelecting(pos);\n this.triggerEventHandlers(['mousemoveselecting', 'moveselecting'], [evt, this.mode]);\n } else if (!this.mouseOriginMove(evt)) {\n if (this.mode === this.BOARD_MODE_DRAG) {\n this.moveObject(pos[0], pos[1], this.mouse, evt, 'mouse');\n } else { // BOARD_MODE_NONE\n // Move event without dragging an element\n this.highlightElements(pos[0], pos[1], evt, -1);\n }\n this.triggerEventHandlers(['mousemove', 'move'], [evt, this.mode]);\n }\n this.updateQuality = this.BOARD_QUALITY_HIGH;\n },\n\n /**\n * This method is called by the browser when the mouse button is released.\n * @param {Event} evt\n */\n mouseUpListener: function (evt) {\n var i;\n\n if (this.selectingMode === false) {\n this.triggerEventHandlers(['mouseup', 'up'], [evt]);\n }\n\n // redraw with high precision\n this.updateQuality = this.BOARD_QUALITY_HIGH;\n\n // if (this.mouse && this.mouse.obj) {\n // // The parameter is needed for lines with snapToGrid enabled\n // this.mouse.obj.snapToGrid(this.mouse.targets[0]);\n // this.mouse.obj.snapToPoints();\n // }\n\n this.originMoveEnd();\n this.dehighlightAll();\n this.update();\n\n // selection\n if (this.selectingMode) {\n this._stopSelecting(evt);\n this.triggerEventHandlers(['mousestopselecting', 'stopselecting'], [evt]);\n this.stopSelectionMode();\n } else {\n for (i = 0; i < this.downObjects.length; i++) {\n this.downObjects[i].triggerEventHandlers(['mouseup', 'up'], [evt]);\n }\n }\n\n this.downObjects.length = 0;\n\n if (this.hasMouseUp) {\n Env.removeEvent(this.document, 'mouseup', this.mouseUpListener, this);\n this.hasMouseUp = false;\n }\n\n // release dragged mouse object\n /** @ignore */\n this.mouse = null;\n },\n\n /**\n * Handler for mouse wheel events. Used to zoom in and out of the board.\n * @param {Event} evt\n * @returns {Boolean}\n */\n mouseWheelListener: function (evt) {\n if (!this.attr.zoom.wheel || !this._isRequiredKeyPressed(evt, 'zoom')) {\n return true;\n }\n\n evt = evt || window.event;\n var wd = evt.detail ? -evt.detail : evt.wheelDelta / 40,\n pos = new Coords(Const.COORDS_BY_SCREEN, this.getMousePosition(evt), this);\n\n if (wd > 0) {\n this.zoomIn(pos.usrCoords[1], pos.usrCoords[2]);\n } else {\n this.zoomOut(pos.usrCoords[1], pos.usrCoords[2]);\n }\n\n this.triggerEventHandlers(['mousewheel'], [evt]);\n\n evt.preventDefault();\n return false;\n },\n\n /**\n * Allow moving of JSXGraph elements with arrow keys\n * and zooming of the construction with + / -.\n * Panning of the construction is done with arrow keys\n * if the pan key (shift or ctrl) is pressed.\n * The selection of the element is done with the tab key.\n *\n * @param {Event} evt The browser's event object\n *\n * @see JXG.Board#keyboard\n * @see JXG.Board#keyFocusInListener\n * @see JXG.Board#keyFocusOutListener\n *\n */\n keyDownListener: function (evt) {\n var id_node = evt.target.id,\n id, el, res,\n sX = 0,\n sY = 0,\n // dx, dy are provided in screen units and\n // are converted to user coordinates\n dx = Type.evaluate(this.attr.keyboard.dx) / this.unitX,\n dy = Type.evaluate(this.attr.keyboard.dy) / this.unitY,\n doZoom = false,\n done = true,\n dir, actPos;\n\n if (!this.attr.keyboard.enabled || id_node === '') {\n return false;\n }\n\n // Get the JSXGraph id from the id of the SVG node.\n id = id_node.replace(this.containerObj.id + '_', '');\n el = this.select(id);\n\n if (Type.exists(el.coords)) {\n actPos = el.coords.usrCoords.slice(1);\n }\n\n if (Type.evaluate(this.attr.keyboard.panshift) || Type.evaluate(this.attr.keyboard.panctrl)) {\n doZoom = true;\n }\n\n if ((Type.evaluate(this.attr.keyboard.panshift) && evt.shiftKey) ||\n (Type.evaluate(this.attr.keyboard.panctrl) && evt.ctrlKey)) {\n if (evt.keyCode === 38) { // up\n this.clickUpArrow();\n } else if (evt.keyCode === 40) { // down\n this.clickDownArrow();\n } else if (evt.keyCode === 37) { // left\n this.clickLeftArrow();\n } else if (evt.keyCode === 39) { // right\n this.clickRightArrow();\n } else {\n done = false;\n }\n } else {\n // Adapt dx, dy to snapToGrid and attractToGrid\n // snapToGrid has priority.\n if (Type.exists(el.visProp)) {\n if (Type.exists(el.visProp.snaptogrid) &&\n el.visProp.snaptogrid &&\n Type.evaluate(el.visProp.snapsizex) &&\n Type.evaluate(el.visProp.snapsizey)) {\n\n // Adapt dx, dy such that snapToGrid is possible\n res = el.getSnapSizes();\n sX = res[0];\n sY = res[1];\n dx = Math.max(sX, dx);\n dy = Math.max(sY, dy);\n\n } else if (Type.exists(el.visProp.attracttogrid) &&\n el.visProp.attracttogrid &&\n Type.evaluate(el.visProp.attractordistance) &&\n Type.evaluate(el.visProp.attractorunit)) {\n\n // Adapt dx, dy such that attractToGrid is possible\n sX = 1.1 * Type.evaluate(el.visProp.attractordistance);\n sY = sX;\n\n if (Type.evaluate(el.visProp.attractorunit) === 'screen') {\n sX /= this.unitX;\n sY /= this.unitX;\n }\n dx = Math.max(sX, dx);\n dy = Math.max(sY, dy);\n }\n\n }\n\n if (evt.keyCode === 38) { // up\n dir = [0, dy];\n } else if (evt.keyCode === 40) { // down\n dir = [0, -dy];\n } else if (evt.keyCode === 37) { // left\n dir = [-dx, 0];\n } else if (evt.keyCode === 39) { // right\n dir = [dx, 0];\n // } else if (evt.keyCode === 9) { // tab\n\n } else if (doZoom && evt.key === '+') { // +\n this.zoomIn();\n } else if (doZoom && evt.key === '-') { // -\n this.zoomOut();\n } else if (doZoom && evt.key === 'o') { // o\n this.zoom100();\n } else {\n done = false;\n }\n\n if (dir && el.isDraggable &&\n el.visPropCalc.visible &&\n ((this.geonextCompatibilityMode &&\n (Type.isPoint(el) ||\n el.elementClass === Const.OBJECT_CLASS_TEXT)\n ) || !this.geonextCompatibilityMode) &&\n !Type.evaluate(el.visProp.fixed)\n ) {\n\n if (Type.exists(el.coords)) {\n dir[0] += actPos[0];\n dir[1] += actPos[1];\n }\n // For coordsElement setPosition has to call setPositionDirectly.\n // Otherwise the position is set by a translation.\n el.setPosition(JXG.COORDS_BY_USER, dir);\n if (Type.exists(el.coords)) {\n this.updateInfobox(el);\n }\n this.triggerEventHandlers(['hit'], [evt, el]);\n }\n }\n\n this.update();\n\n if (done && Type.exists(evt.preventDefault)) {\n evt.preventDefault();\n }\n return true;\n },\n\n /**\n * Event listener for SVG elements getting focus.\n * This is needed for highlighting when using keyboard control.\n *\n * @see JXG.Board#keyFocusOutListener\n * @see JXG.Board#keyDownListener\n * @see JXG.Board#keyboard\n *\n * @param {Event} evt The browser's event object\n */\n keyFocusInListener: function (evt) {\n var id_node = evt.target.id,\n id, el;\n\n if (!this.attr.keyboard.enabled || id_node === '') {\n return false;\n }\n\n id = id_node.replace(this.containerObj.id + '_', '');\n el = this.select(id);\n if (Type.exists(el.highlight)) {\n el.highlight(true);\n }\n if (Type.exists(el.coords)) {\n this.updateInfobox(el);\n }\n this.triggerEventHandlers(['hit'], [evt, el]);\n },\n\n /**\n * Event listener for SVG elements losing focus.\n * This is needed for dehighlighting when using keyboard control.\n *\n * @see JXG.Board#keyFocusInListener\n * @see JXG.Board#keyDownListener\n * @see JXG.Board#keyboard\n *\n * @param {Event} evt The browser's event object\n */\n keyFocusOutListener: function (evt) {\n if (!this.attr.keyboard.enabled) {\n return false;\n }\n // var id_node = evt.target.id,\n // id, el;\n\n // id = id_node.replace(this.containerObj.id + '_', '');\n // el = this.select(id);\n this.dehighlightAll();\n this.displayInfobox(false);\n },\n\n /**\n * Update the width and height of the JSXGraph container div element.\n * Read actual values with getBoundingClientRect(),\n * and call board.resizeContainer() with this values.\n * <p>\n * If necessary, also call setBoundingBox().\n *\n * @see JXG.Board#startResizeObserver\n * @see JXG.Board#resizeListener\n * @see JXG.Board#resizeContainer\n * @see JXG.Board#setBoundingBox\n *\n */\n updateContainerDims: function() {\n var w, h,\n bb, css;\n\n // Get size of the board's container div\n bb = this.containerObj.getBoundingClientRect();\n w = bb.width;\n h = bb.height;\n\n // Subtract the border size\n if (window && window.getComputedStyle) {\n css = window.getComputedStyle(this.containerObj, null);\n w -= parseFloat(css.getPropertyValue('border-left-width')) + parseFloat(css.getPropertyValue('border-right-width'));\n h -= parseFloat(css.getPropertyValue('border-top-width')) + parseFloat(css.getPropertyValue('border-bottom-width'));\n }\n\n // If div is invisible - do nothing\n if (w <= 0 || h <= 0 || Type.isNaN(w) || Type.isNaN(h)) {\n return;\n }\n\n // If bounding box is not yet initialized, do it now.\n if (isNaN(this.getBoundingBox()[0])) {\n this.setBoundingBox(this.attr.boundingbox, this.keepaspectratio, 'keep');\n }\n\n // Do nothing if the dimension did not change since being visible\n // the last time. Note that if the div had display:none in the mean time,\n // we did not store this._prevDim.\n if (Type.exists(this._prevDim) &&\n this._prevDim.w === w && this._prevDim.h === h) {\n return;\n }\n\n // Set the size of the SVG or canvas element\n this.resizeContainer(w, h, true);\n this._prevDim = {\n w: w,\n h: h\n };\n },\n\n /**\n * Start observer which reacts to size changes of the JSXGraph\n * container div element. Calls updateContainerDims().\n * If not available, an event listener for the window-resize event is started.\n * On mobile devices also scrolling might trigger resizes.\n * However, resize events triggered by scrolling events should be ignored.\n * Therefore, also a scrollListener is started.\n * Resize can be controlled with the board attribute resize.\n *\n * @see JXG.Board#updateContainerDims\n * @see JXG.Board#resizeListener\n * @see JXG.Board#scrollListener\n * @see JXG.Board#resize\n *\n */\n startResizeObserver: function() {\n var that = this;\n\n if (!Env.isBrowser || !this.attr.resize || !this.attr.resize.enabled) {\n return;\n }\n\n this.resizeObserver = new ResizeObserver(function(entries) {\n if (!that._isResizing) {\n that._isResizing = true;\n window.setTimeout(function() {\n try {\n that.updateContainerDims();\n } catch (err) {\n that.stopResizeObserver();\n } finally {\n that._isResizing = false;\n }\n }, that.attr.resize.throttle);\n }\n });\n this.resizeObserver.observe(this.containerObj);\n },\n\n /**\n * Stops the resize observer.\n * @see JXG.Board#startResizeObserver\n *\n */\n stopResizeObserver: function() {\n if (!Env.isBrowser || !this.attr.resize || !this.attr.resize.enabled) {\n return;\n }\n\n if (Type.exists(this.resizeObserver)) {\n this.resizeObserver.unobserve(this.containerObj);\n }\n },\n\n /**\n * Fallback solutions if there is no resizeObserver available in the browser.\n * Reacts to resize events of the window (only). Otherwise similar to\n * startResizeObserver(). To handle changes of the visibility\n * of the JSXGraph container element, additionally an intersection observer is used.\n * which watches changes in the visibility of the JSXGraph container element.\n * This is necessary e.g. for register tabs or dia shows.\n *\n * @see JXG.Board#startResizeObserver\n * @see JXG.Board#startIntersectionObserver\n */\n resizeListener: function() {\n var that = this;\n\n if (!Env.isBrowser || !this.attr.resize || !this.attr.resize.enabled) {\n return;\n }\n if (!this._isScrolling && !this._isResizing) {\n this._isResizing = true;\n window.setTimeout(function() {\n that.updateContainerDims();\n that._isResizing = false;\n }, this.attr.resize.throttle);\n }\n },\n\n /**\n * Listener to watch for scroll events. Sets board._isScrolling = true\n * @param {Event} evt The browser's event object\n *\n * @see JXG.Board#startResizeObserver\n * @see JXG.Board#resizeListener\n *\n */\n scrollListener: function(evt) {\n var that = this;\n\n if (!Env.isBrowser) {\n return;\n }\n if (!this._isScrolling) {\n this._isScrolling = true;\n window.setTimeout(function() {\n that._isScrolling = false;\n }, 66);\n }\n },\n\n /**\n * Watch for changes of the visibility of the JSXGraph container element.\n *\n * @see JXG.Board#startResizeObserver\n * @see JXG.Board#resizeListener\n *\n */\n startIntersectionObserver: function() {\n var that = this,\n options = {\n root: null,\n rootMargin: '0px',\n threshold: 0.8\n };\n\n try {\n this.intersectionObserver = new IntersectionObserver(function(entries) {\n // If bounding box is not yet initialized, do it now.\n if (isNaN(that.getBoundingBox()[0])) {\n that.updateContainerDims();\n }\n }, options);\n this.intersectionObserver.observe(that.containerObj);\n } catch (err) {\n console.log('JSXGraph: IntersectionObserver not available in this browser.');\n }\n },\n\n /**\n * Stop the intersection observer\n *\n * @see JXG.Board#startIntersectionObserver\n *\n */\n stopIntersectionObserver: function() {\n if (Type.exists(this.intersectionObserver)) {\n this.intersectionObserver.unobserve(this.containerObj);\n }\n },\n\n /**********************************************************\n *\n * End of Event Handlers\n *\n **********************************************************/\n\n /**\n * Initialize the info box object which is used to display\n * the coordinates of points near the mouse pointer,\n * @returns {JXG.Board} Reference to the board\n */\n initInfobox: function () {\n var attr = Type.copyAttributes({}, this.options, 'infobox');\n\n attr.id = this.id + '_infobox';\n /**\n * Infobox close to points in which the points' coordinates are displayed.\n * This is simply a JXG.Text element. Access through board.infobox.\n * Uses CSS class .JXGinfobox.\n * @type JXG.Text\n *\n */\n this.infobox = this.create('text', [0, 0, '0,0'], attr);\n\n this.infobox.distanceX = -20;\n this.infobox.distanceY = 25;\n // this.infobox.needsUpdateSize = false; // That is not true, but it speeds drawing up.\n\n this.infobox.dump = false;\n\n this.displayInfobox(false);\n return this;\n },\n\n /**\n * Updates and displays a little info box to show coordinates of current selected points.\n * @param {JXG.GeometryElement} el A GeometryElement\n * @returns {JXG.Board} Reference to the board\n * @see JXG.Board#displayInfobox\n * @see JXG.Board#showInfobox\n * @see Point#showInfobox\n *\n */\n updateInfobox: function (el) {\n var x, y, xc, yc,\n vpinfoboxdigits,\n vpsi = Type.evaluate(el.visProp.showinfobox);\n\n if ((!Type.evaluate(this.attr.showinfobox) && vpsi === 'inherit') ||\n !vpsi) {\n return this;\n }\n\n if (Type.isPoint(el)) {\n xc = el.coords.usrCoords[1];\n yc = el.coords.usrCoords[2];\n\n vpinfoboxdigits = Type.evaluate(el.visProp.infoboxdigits);\n this.infobox.setCoords(xc + this.infobox.distanceX / this.unitX,\n yc + this.infobox.distanceY / this.unitY);\n\n if (typeof el.infoboxText !== 'string') {\n if (vpinfoboxdigits === 'auto') {\n x = Type.autoDigits(xc);\n y = Type.autoDigits(yc);\n } else if (Type.isNumber(vpinfoboxdigits)) {\n x = Type.toFixed(xc, vpinfoboxdigits);\n y = Type.toFixed(yc, vpinfoboxdigits);\n } else {\n x = xc;\n y = yc;\n }\n\n this.highlightInfobox(x, y, el);\n } else {\n this.highlightCustomInfobox(el.infoboxText, el);\n }\n\n this.displayInfobox(true);\n }\n return this;\n },\n\n /**\n * Set infobox visible / invisible.\n *\n * It uses its property hiddenByParent to memorize its status.\n * In this way, many DOM access can be avoided.\n *\n * @param {Boolean} val true for visible, false for invisible\n * @returns {JXG.Board} Reference to the board.\n * @see JXG.Board#updateInfobox\n *\n */\n displayInfobox: function(val) {\n if (this.infobox.hiddenByParent === val) {\n this.infobox.hiddenByParent = !val;\n this.infobox.prepareUpdate().updateVisibility(val).updateRenderer();\n }\n return this;\n },\n\n // Alias for displayInfobox to be backwards compatible.\n // The method showInfobox clashes with the board attribute showInfobox\n showInfobox: function(val) {\n return this.displayInfobox(val);\n },\n\n /**\n * Changes the text of the info box to show the given coordinates.\n * @param {Number} x\n * @param {Number} y\n * @param {JXG.GeometryElement} [el] The element the mouse is pointing at\n * @returns {JXG.Board} Reference to the board.\n */\n highlightInfobox: function (x, y, el) {\n this.highlightCustomInfobox('(' + x + ', ' + y + ')', el);\n return this;\n },\n\n /**\n * Changes the text of the info box to what is provided via text.\n * @param {String} text\n * @param {JXG.GeometryElement} [el]\n * @returns {JXG.Board} Reference to the board.\n */\n highlightCustomInfobox: function (text, el) {\n this.infobox.setText(text);\n return this;\n },\n\n /**\n * Remove highlighting of all elements.\n * @returns {JXG.Board} Reference to the board.\n */\n dehighlightAll: function () {\n var el, pEl, needsDehighlight = false;\n\n for (el in this.highlightedObjects) {\n if (this.highlightedObjects.hasOwnProperty(el)) {\n pEl = this.highlightedObjects[el];\n\n if (this.hasMouseHandlers || this.hasPointerHandlers) {\n pEl.noHighlight();\n }\n\n needsDehighlight = true;\n\n // In highlightedObjects should only be objects which fulfill all these conditions\n // And in case of complex elements, like a turtle based fractal, it should be faster to\n // just de-highlight the element instead of checking hasPoint...\n // if ((!Type.exists(pEl.hasPoint)) || !pEl.hasPoint(x, y) || !pEl.visPropCalc.visible)\n }\n }\n\n this.highlightedObjects = {};\n\n // We do not need to redraw during dehighlighting in CanvasRenderer\n // because we are redrawing anyhow\n // -- We do need to redraw during dehighlighting. Otherwise objects won't be dehighlighted until\n // another object is highlighted.\n if (this.renderer.type === 'canvas' && needsDehighlight) {\n this.prepareUpdate();\n this.renderer.suspendRedraw(this);\n this.updateRenderer();\n this.renderer.unsuspendRedraw();\n }\n\n return this;\n },\n\n /**\n * Returns the input parameters in an array. This method looks pointless and it really is, but it had a purpose\n * once.\n * @private\n * @param {Number} x X coordinate in screen coordinates\n * @param {Number} y Y coordinate in screen coordinates\n * @returns {Array} Coordinates [x, y] of the mouse in screen coordinates.\n * @see JXG.Board#getUsrCoordsOfMouse\n */\n getScrCoordsOfMouse: function (x, y) {\n return [x, y];\n },\n\n /**\n * This method calculates the user coords of the current mouse coordinates.\n * @param {Event} evt Event object containing the mouse coordinates.\n * @returns {Array} Coordinates [x, y] of the mouse in user coordinates.\n * @example\n * board.on('up', function (evt) {\n * var a = board.getUsrCoordsOfMouse(evt),\n * x = a[0],\n * y = a[1],\n * somePoint = board.create('point', [x,y], {name:'SomePoint',size:4});\n * // Shorter version:\n * //somePoint = board.create('point', a, {name:'SomePoint',size:4});\n * });\n *\n * </pre><div id=\"JXG48d5066b-16ba-4920-b8ea-a4f8eff6b746\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG48d5066b-16ba-4920-b8ea-a4f8eff6b746',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * board.on('up', function (evt) {\n * var a = board.getUsrCoordsOfMouse(evt),\n * x = a[0],\n * y = a[1],\n * somePoint = board.create('point', [x,y], {name:'SomePoint',size:4});\n * // Shorter version:\n * //somePoint = board.create('point', a, {name:'SomePoint',size:4});\n * });\n *\n * })();\n *\n * </script><pre>\n *\n * @see JXG.Board#getScrCoordsOfMouse\n * @see JXG.Board#getAllUnderMouse\n */\n getUsrCoordsOfMouse: function (evt) {\n var cPos = this.getCoordsTopLeftCorner(),\n absPos = Env.getPosition(evt, null, this.document),\n x = absPos[0] - cPos[0],\n y = absPos[1] - cPos[1],\n newCoords = new Coords(Const.COORDS_BY_SCREEN, [x, y], this);\n\n return newCoords.usrCoords.slice(1);\n },\n\n /**\n * Collects all elements under current mouse position plus current user coordinates of mouse cursor.\n * @param {Event} evt Event object containing the mouse coordinates.\n * @returns {Array} Array of elements at the current mouse position plus current user coordinates of mouse.\n * @see JXG.Board#getUsrCoordsOfMouse\n * @see JXG.Board#getAllObjectsUnderMouse\n */\n getAllUnderMouse: function (evt) {\n var elList = this.getAllObjectsUnderMouse(evt);\n elList.push(this.getUsrCoordsOfMouse(evt));\n\n return elList;\n },\n\n /**\n * Collects all elements under current mouse position.\n * @param {Event} evt Event object containing the mouse coordinates.\n * @returns {Array} Array of elements at the current mouse position.\n * @see JXG.Board#getAllUnderMouse\n */\n getAllObjectsUnderMouse: function (evt) {\n var cPos = this.getCoordsTopLeftCorner(),\n absPos = Env.getPosition(evt, null, this.document),\n dx = absPos[0] - cPos[0],\n dy = absPos[1] - cPos[1],\n elList = [],\n el,\n pEl,\n len = this.objectsList.length;\n\n for (el = 0; el < len; el++) {\n pEl = this.objectsList[el];\n if (pEl.visPropCalc.visible && pEl.hasPoint && pEl.hasPoint(dx, dy)) {\n elList[elList.length] = pEl;\n }\n }\n\n return elList;\n },\n\n /**\n * Update the coords object of all elements which possess this\n * property. This is necessary after changing the viewport.\n * @returns {JXG.Board} Reference to this board.\n **/\n updateCoords: function () {\n var el, ob, len = this.objectsList.length;\n\n for (ob = 0; ob < len; ob++) {\n el = this.objectsList[ob];\n\n if (Type.exists(el.coords)) {\n if (Type.evaluate(el.visProp.frozen)) {\n el.coords.screen2usr();\n } else {\n el.coords.usr2screen();\n }\n }\n }\n return this;\n },\n\n /**\n * Moves the origin and initializes an update of all elements.\n * @param {Number} x\n * @param {Number} y\n * @param {Boolean} [diff=false]\n * @returns {JXG.Board} Reference to this board.\n */\n moveOrigin: function (x, y, diff) {\n var ox, oy, ul, lr;\n if (Type.exists(x) && Type.exists(y)) {\n ox = this.origin.scrCoords[1];\n oy = this.origin.scrCoords[2];\n\n this.origin.scrCoords[1] = x;\n this.origin.scrCoords[2] = y;\n\n if (diff) {\n this.origin.scrCoords[1] -= this.drag_dx;\n this.origin.scrCoords[2] -= this.drag_dy;\n }\n\n ul = (new Coords(Const.COORDS_BY_SCREEN, [0, 0], this)).usrCoords;\n lr = (new Coords(Const.COORDS_BY_SCREEN, [this.canvasWidth, this.canvasHeight], this)).usrCoords;\n if (ul[1] < this.maxboundingbox[0] ||\n ul[2] > this.maxboundingbox[1] ||\n lr[1] > this.maxboundingbox[2] ||\n lr[2] < this.maxboundingbox[3]) {\n\n this.origin.scrCoords[1] = ox;\n this.origin.scrCoords[2] = oy;\n }\n }\n\n this.updateCoords().clearTraces().fullUpdate();\n this.triggerEventHandlers(['boundingbox']);\n\n return this;\n },\n\n /**\n * Add conditional updates to the elements.\n * @param {String} str String containing coniditional update in geonext syntax\n */\n addConditions: function (str) {\n var term, m, left, right, name, el, property,\n functions = [],\n // plaintext = 'var el, x, y, c, rgbo;\\n',\n i = str.indexOf('<data>'),\n j = str.indexOf('<' + '/data>'),\n\n xyFun = function (board, el, f, what) {\n return function () {\n var e, t;\n\n e = board.select(el.id);\n t = e.coords.usrCoords[what];\n\n if (what === 2) {\n e.setPositionDirectly(Const.COORDS_BY_USER, [f(), t]);\n } else {\n e.setPositionDirectly(Const.COORDS_BY_USER, [t, f()]);\n }\n e.prepareUpdate().update();\n };\n },\n\n visFun = function (board, el, f) {\n return function () {\n var e, v;\n\n e = board.select(el.id);\n v = f();\n\n e.setAttribute({visible: v});\n };\n },\n\n colFun = function (board, el, f, what) {\n return function () {\n var e, v;\n\n e = board.select(el.id);\n v = f();\n\n if (what === 'strokewidth') {\n e.visProp.strokewidth = v;\n } else {\n v = Color.rgba2rgbo(v);\n e.visProp[what + 'color'] = v[0];\n e.visProp[what + 'opacity'] = v[1];\n }\n };\n },\n\n posFun = function (board, el, f) {\n return function () {\n var e = board.select(el.id);\n\n e.position = f();\n };\n },\n\n styleFun = function (board, el, f) {\n return function () {\n var e = board.select(el.id);\n\n e.setStyle(f());\n };\n };\n\n if (i < 0) {\n return;\n }\n\n while (i >= 0) {\n term = str.slice(i + 6, j); // throw away <data>\n m = term.indexOf('=');\n left = term.slice(0, m);\n right = term.slice(m + 1);\n m = left.indexOf('.'); // Dies erzeugt Probleme bei Variablennamen der Form \" Steuern akt.\"\n name = left.slice(0, m); //.replace(/\\s+$/,''); // do NOT cut out name (with whitespace)\n el = this.elementsByName[Type.unescapeHTML(name)];\n\n property = left.slice(m + 1).replace(/\\s+/g, '').toLowerCase(); // remove whitespace in property\n right = Type.createFunction (right, this, '', true);\n\n // Debug\n if (!Type.exists(this.elementsByName[name])) {\n JXG.debug(\"debug conditions: |\" + name + \"| undefined\");\n } else {\n // plaintext += \"el = this.objects[\\\"\" + el.id + \"\\\"];\\n\";\n\n switch (property) {\n case 'x':\n functions.push(xyFun(this, el, right, 2));\n break;\n case 'y':\n functions.push(xyFun(this, el, right, 1));\n break;\n case 'visible':\n functions.push(visFun(this, el, right));\n break;\n case 'position':\n functions.push(posFun(this, el, right));\n break;\n case 'stroke':\n functions.push(colFun(this, el, right, 'stroke'));\n break;\n case 'style':\n functions.push(styleFun(this, el, right));\n break;\n case 'strokewidth':\n functions.push(colFun(this, el, right, 'strokewidth'));\n break;\n case 'fill':\n functions.push(colFun(this, el, right, 'fill'));\n break;\n case 'label':\n break;\n default:\n JXG.debug(\"property '\" + property + \"' in conditions not yet implemented:\" + right);\n break;\n }\n }\n str = str.slice(j + 7); // cut off \"</data>\"\n i = str.indexOf('<data>');\n j = str.indexOf('<' + '/data>');\n }\n\n this.updateConditions = function () {\n var i;\n\n for (i = 0; i < functions.length; i++) {\n functions[i]();\n }\n\n this.prepareUpdate().updateElements();\n return true;\n };\n this.updateConditions();\n },\n\n /**\n * Computes the commands in the conditions-section of the gxt file.\n * It is evaluated after an update, before the unsuspendRedraw.\n * The function is generated in\n * @see JXG.Board#addConditions\n * @private\n */\n updateConditions: function () {\n return false;\n },\n\n /**\n * Calculates adequate snap sizes.\n * @returns {JXG.Board} Reference to the board.\n */\n calculateSnapSizes: function () {\n var p1 = new Coords(Const.COORDS_BY_USER, [0, 0], this),\n p2 = new Coords(Const.COORDS_BY_USER, [this.options.grid.gridX, this.options.grid.gridY], this),\n x = p1.scrCoords[1] - p2.scrCoords[1],\n y = p1.scrCoords[2] - p2.scrCoords[2];\n\n this.options.grid.snapSizeX = this.options.grid.gridX;\n while (Math.abs(x) > 25) {\n this.options.grid.snapSizeX *= 2;\n x /= 2;\n }\n\n this.options.grid.snapSizeY = this.options.grid.gridY;\n while (Math.abs(y) > 25) {\n this.options.grid.snapSizeY *= 2;\n y /= 2;\n }\n\n return this;\n },\n\n /**\n * Apply update on all objects with the new zoom-factors. Clears all traces.\n * @returns {JXG.Board} Reference to the board.\n */\n applyZoom: function () {\n this.updateCoords().calculateSnapSizes().clearTraces().fullUpdate();\n\n return this;\n },\n\n /**\n * Zooms into the board by the factors board.attr.zoom.factorX and board.attr.zoom.factorY and applies the zoom.\n * The zoom operation is centered at x, y.\n * @param {Number} [x]\n * @param {Number} [y]\n * @returns {JXG.Board} Reference to the board\n */\n zoomIn: function (x, y) {\n var bb = this.getBoundingBox(),\n zX = this.attr.zoom.factorx,\n zY = this.attr.zoom.factory,\n dX = (bb[2] - bb[0]) * (1.0 - 1.0 / zX),\n dY = (bb[1] - bb[3]) * (1.0 - 1.0 / zY),\n lr = 0.5,\n tr = 0.5,\n mi = this.attr.zoom.eps || this.attr.zoom.min || 0.001; // this.attr.zoom.eps is deprecated\n\n if ((this.zoomX > this.attr.zoom.max && zX > 1.0) ||\n (this.zoomY > this.attr.zoom.max && zY > 1.0) ||\n (this.zoomX < mi && zX < 1.0) || // zoomIn is used for all zooms on touch devices\n (this.zoomY < mi && zY < 1.0)) {\n return this;\n }\n\n if (Type.isNumber(x) && Type.isNumber(y)) {\n lr = (x - bb[0]) / (bb[2] - bb[0]);\n tr = (bb[1] - y) / (bb[1] - bb[3]);\n }\n\n this.setBoundingBox([bb[0] + dX * lr, bb[1] - dY * tr, bb[2] - dX * (1 - lr), bb[3] + dY * (1 - tr)], this.keepaspectratio, 'update');\n return this.applyZoom();\n },\n\n /**\n * Zooms out of the board by the factors board.attr.zoom.factorX and board.attr.zoom.factorY and applies the zoom.\n * The zoom operation is centered at x, y.\n *\n * @param {Number} [x]\n * @param {Number} [y]\n * @returns {JXG.Board} Reference to the board\n */\n zoomOut: function (x, y) {\n var bb = this.getBoundingBox(),\n zX = this.attr.zoom.factorx,\n zY = this.attr.zoom.factory,\n dX = (bb[2] - bb[0]) * (1.0 - zX),\n dY = (bb[1] - bb[3]) * (1.0 - zY),\n lr = 0.5,\n tr = 0.5,\n mi = this.attr.zoom.eps || this.attr.zoom.min || 0.001; // this.attr.zoom.eps is deprecated\n\n if (this.zoomX < mi || this.zoomY < mi) {\n return this;\n }\n\n if (Type.isNumber(x) && Type.isNumber(y)) {\n lr = (x - bb[0]) / (bb[2] - bb[0]);\n tr = (bb[1] - y) / (bb[1] - bb[3]);\n }\n\n this.setBoundingBox([bb[0] + dX * lr, bb[1] - dY * tr, bb[2] - dX * (1 - lr), bb[3] + dY * (1 - tr)], this.keepaspectratio, 'update');\n\n return this.applyZoom();\n },\n\n /**\n * Reset the zoom level to the original zoom level from initBoard();\n * Additionally, if the board as been initialized with a boundingBox (which is the default),\n * restore the viewport to the original viewport during initialization. Otherwise,\n * (i.e. if the board as been initialized with unitX/Y and originX/Y),\n * just set the zoom level to 100%.\n *\n * @returns {JXG.Board} Reference to the board\n */\n zoom100: function () {\n var bb, dX, dY;\n\n if (Type.exists(this.attr.boundingbox)) {\n this.setBoundingBox(this.attr.boundingbox, this.keepaspectratio, 'reset');\n } else {\n // Board has been set up with unitX/Y and originX/Y\n bb = this.getBoundingBox();\n dX = (bb[2] - bb[0]) * (1.0 - this.zoomX) * 0.5;\n dY = (bb[1] - bb[3]) * (1.0 - this.zoomY) * 0.5;\n this.setBoundingBox([bb[0] + dX, bb[1] - dY, bb[2] - dX, bb[3] + dY], this.keepaspectratio, 'reset');\n }\n return this.applyZoom();\n },\n\n /**\n * Zooms the board so every visible point is shown. Keeps aspect ratio.\n * @returns {JXG.Board} Reference to the board\n */\n zoomAllPoints: function () {\n var el, border, borderX, borderY, pEl,\n minX = 0,\n maxX = 0,\n minY = 0,\n maxY = 0,\n len = this.objectsList.length;\n\n for (el = 0; el < len; el++) {\n pEl = this.objectsList[el];\n\n if (Type.isPoint(pEl) && pEl.visPropCalc.visible) {\n if (pEl.coords.usrCoords[1] < minX) {\n minX = pEl.coords.usrCoords[1];\n } else if (pEl.coords.usrCoords[1] > maxX) {\n maxX = pEl.coords.usrCoords[1];\n }\n if (pEl.coords.usrCoords[2] > maxY) {\n maxY = pEl.coords.usrCoords[2];\n } else if (pEl.coords.usrCoords[2] < minY) {\n minY = pEl.coords.usrCoords[2];\n }\n }\n }\n\n border = 50;\n borderX = border / this.unitX;\n borderY = border / this.unitY;\n\n this.setBoundingBox([minX - borderX, maxY + borderY, maxX + borderX, minY - borderY], this.keepaspectratio, 'update');\n\n return this.applyZoom();\n },\n\n /**\n * Reset the bounding box and the zoom level to 100% such that a given set of elements is\n * within the board's viewport.\n * @param {Array} elements A set of elements given by id, reference, or name.\n * @returns {JXG.Board} Reference to the board.\n */\n zoomElements: function (elements) {\n var i, e, box,\n newBBox = [Infinity, -Infinity, -Infinity, Infinity],\n cx, cy, dx, dy, d;\n\n if (!Type.isArray(elements) || elements.length === 0) {\n return this;\n }\n\n for (i = 0; i < elements.length; i++) {\n e = this.select(elements[i]);\n\n box = e.bounds();\n if (Type.isArray(box)) {\n if (box[0] < newBBox[0]) { newBBox[0] = box[0]; }\n if (box[1] > newBBox[1]) { newBBox[1] = box[1]; }\n if (box[2] > newBBox[2]) { newBBox[2] = box[2]; }\n if (box[3] < newBBox[3]) { newBBox[3] = box[3]; }\n }\n }\n\n if (Type.isArray(newBBox)) {\n cx = 0.5 * (newBBox[0] + newBBox[2]);\n cy = 0.5 * (newBBox[1] + newBBox[3]);\n dx = 1.5 * (newBBox[2] - newBBox[0]) * 0.5;\n dy = 1.5 * (newBBox[1] - newBBox[3]) * 0.5;\n d = Math.max(dx, dy);\n this.setBoundingBox([cx - d, cy + d, cx + d, cy - d], this.keepaspectratio, 'update');\n }\n\n return this;\n },\n\n /**\n * Sets the zoom level to <tt>fX</tt> resp <tt>fY</tt>.\n * @param {Number} fX\n * @param {Number} fY\n * @returns {JXG.Board} Reference to the board.\n */\n setZoom: function (fX, fY) {\n var oX = this.attr.zoom.factorx,\n oY = this.attr.zoom.factory;\n\n this.attr.zoom.factorx = fX / this.zoomX;\n this.attr.zoom.factory = fY / this.zoomY;\n\n this.zoomIn();\n\n this.attr.zoom.factorx = oX;\n this.attr.zoom.factory = oY;\n\n return this;\n },\n\n /**\n * Removes object from board and renderer.\n * <p>\n * <b>Performance hints:</b> It is recommended to use the object's id.\n * If many elements are removed, it is best to call <tt>board.suspendUpdate()</tt>\n * before looping through the elements to be removed and call\n * <tt>board.unsuspendUpdate()</tt> after the loop. Further, it is advisable to loop\n * in reverse order, i.e. remove the object in reverse order of their creation time.\n *\n * @param {JXG.GeometryElement|Array} object The object to remove or array of objects to be removed.\n * The element(s) is/are given by name, id or a reference.\n * @param {Boolean} saveMethod If true, the algorithm runs through all elements\n * and tests if the element to be deleted is a child element. If yes, it will be\n * removed from the list of child elements. If false (default), the element\n * is removed from the lists of child elements of all its ancestors.\n * This should be much faster.\n * @returns {JXG.Board} Reference to the board\n */\n removeObject: function (object, saveMethod) {\n var el, i;\n\n if (Type.isArray(object)) {\n for (i = 0; i < object.length; i++) {\n this.removeObject(object[i]);\n }\n\n return this;\n }\n\n object = this.select(object);\n\n // If the object which is about to be removed unknown or a string, do nothing.\n // it is a string if a string was given and could not be resolved to an element.\n if (!Type.exists(object) || Type.isString(object)) {\n return this;\n }\n\n try {\n // remove all children.\n for (el in object.childElements) {\n if (object.childElements.hasOwnProperty(el)) {\n object.childElements[el].board.removeObject(object.childElements[el]);\n }\n }\n\n // Remove all children in elements like turtle\n for (el in object.objects) {\n if (object.objects.hasOwnProperty(el)) {\n object.objects[el].board.removeObject(object.objects[el]);\n }\n }\n\n // Remove the element from the childElement list and the descendant list of all elements.\n if (saveMethod) {\n // Running through all objects has quadratic complexity if many objects are deleted.\n for (el in this.objects) {\n if (this.objects.hasOwnProperty(el)) {\n if (Type.exists(this.objects[el].childElements) &&\n Type.exists(this.objects[el].childElements.hasOwnProperty(object.id))\n ) {\n delete this.objects[el].childElements[object.id];\n delete this.objects[el].descendants[object.id];\n }\n }\n }\n } else if (Type.exists(object.ancestors)) {\n // Running through the ancestors should be much more efficient.\n for (el in object.ancestors) {\n if (object.ancestors.hasOwnProperty(el)) {\n if (Type.exists(object.ancestors[el].childElements) &&\n Type.exists(object.ancestors[el].childElements.hasOwnProperty(object.id))\n ) {\n delete object.ancestors[el].childElements[object.id];\n delete object.ancestors[el].descendants[object.id];\n }\n }\n }\n }\n\n // remove the object itself from our control structures\n if (object._pos > -1) {\n this.objectsList.splice(object._pos, 1);\n for (el = object._pos; el < this.objectsList.length; el++) {\n this.objectsList[el]._pos--;\n }\n } else if (object.type !== Const.OBJECT_TYPE_TURTLE) {\n JXG.debug('Board.removeObject: object ' + object.id + ' not found in list.');\n }\n\n delete this.objects[object.id];\n delete this.elementsByName[object.name];\n\n if (object.visProp && Type.evaluate(object.visProp.trace)) {\n object.clearTrace();\n }\n\n // the object deletion itself is handled by the object.\n if (Type.exists(object.remove)) {\n object.remove();\n }\n } catch (e) {\n JXG.debug(object.id + ': Could not be removed: ' + e);\n }\n\n this.update();\n\n return this;\n },\n\n /**\n * Removes the ancestors of an object an the object itself from board and renderer.\n * @param {JXG.GeometryElement} object The object to remove.\n * @returns {JXG.Board} Reference to the board\n */\n removeAncestors: function (object) {\n var anc;\n\n for (anc in object.ancestors) {\n if (object.ancestors.hasOwnProperty(anc)) {\n this.removeAncestors(object.ancestors[anc]);\n }\n }\n\n this.removeObject(object);\n\n return this;\n },\n\n /**\n * Initialize some objects which are contained in every GEONExT construction by default,\n * but are not contained in the gxt files.\n * @returns {JXG.Board} Reference to the board\n */\n initGeonextBoard: function () {\n var p1, p2, p3;\n\n p1 = this.create('point', [0, 0], {\n id: this.id + 'g00e0',\n name: 'Ursprung',\n withLabel: false,\n visible: false,\n fixed: true\n });\n\n p2 = this.create('point', [1, 0], {\n id: this.id + 'gX0e0',\n name: 'Punkt_1_0',\n withLabel: false,\n visible: false,\n fixed: true\n });\n\n p3 = this.create('point', [0, 1], {\n id: this.id + 'gY0e0',\n name: 'Punkt_0_1',\n withLabel: false,\n visible: false,\n fixed: true\n });\n\n this.create('line', [p1, p2], {\n id: this.id + 'gXLe0',\n name: 'X-Achse',\n withLabel: false,\n visible: false\n });\n\n this.create('line', [p1, p3], {\n id: this.id + 'gYLe0',\n name: 'Y-Achse',\n withLabel: false,\n visible: false\n });\n\n return this;\n },\n\n /**\n * Change the height and width of the board's container.\n * After doing so, {@link JXG.JSXGraph.setBoundingBox} is called using\n * the actual size of the bounding box and the actual value of keepaspectratio.\n * If setBoundingbox() should not be called automatically,\n * call resizeContainer with dontSetBoundingBox == true.\n * @param {Number} canvasWidth New width of the container.\n * @param {Number} canvasHeight New height of the container.\n * @param {Boolean} [dontset=false] If true do not set the CSS width and height of the DOM element.\n * @param {Boolean} [dontSetBoundingBox=false] If true do not call setBoundingBox().\n * @returns {JXG.Board} Reference to the board\n */\n resizeContainer: function (canvasWidth, canvasHeight, dontset, dontSetBoundingBox) {\n var box;\n // w, h, cx, cy;\n // box_act,\n // shift_x = 0,\n // shift_y = 0;\n\n if (!dontSetBoundingBox) {\n // box_act = this.getBoundingBox(); // This is the actual bounding box.\n box = this.getBoundingBox(); // This is the actual bounding box.\n }\n\n this.canvasWidth = parseFloat(canvasWidth);\n this.canvasHeight = parseFloat(canvasHeight);\n\n // if (!dontSetBoundingBox) {\n // box = this.attr.boundingbox; // This is the intended bounding box.\n\n // // The shift values compensate the follow-up correction\n // // in setBoundingBox in case of \"this.keepaspectratio==true\"\n // // Otherwise, shift_x and shift_y will be zero.\n // // Obsolet since setBoundingBox centers in case of \"this.keepaspectratio==true\".\n // // shift_x = box_act[0] - box[0] / this.zoomX;\n // // shift_y = box_act[1] - box[1] / this.zoomY;\n\n // cx = (box[2] + box[0]) * 0.5; // + shift_x;\n // cy = (box[3] + box[1]) * 0.5; // + shift_y;\n\n // w = (box[2] - box[0]) * 0.5 / this.zoomX;\n // h = (box[1] - box[3]) * 0.5 / this.zoomY;\n\n // box = [cx - w, cy + h, cx + w, cy - h];\n // }\n\n if (!dontset) {\n this.containerObj.style.width = (this.canvasWidth) + 'px';\n this.containerObj.style.height = (this.canvasHeight) + 'px';\n }\n this.renderer.resize(this.canvasWidth, this.canvasHeight);\n\n if (!dontSetBoundingBox) {\n this.setBoundingBox(box, this.keepaspectratio, 'keep');\n }\n\n return this;\n },\n\n /**\n * Lists the dependencies graph in a new HTML-window.\n * @returns {JXG.Board} Reference to the board\n */\n showDependencies: function () {\n var el, t, c, f, i;\n\n t = '<p>\\n';\n for (el in this.objects) {\n if (this.objects.hasOwnProperty(el)) {\n i = 0;\n for (c in this.objects[el].childElements) {\n if (this.objects[el].childElements.hasOwnProperty(c)) {\n i += 1;\n }\n }\n if (i >= 0) {\n t += '<strong>' + this.objects[el].id + ':<' + '/strong> ';\n }\n\n for (c in this.objects[el].childElements) {\n if (this.objects[el].childElements.hasOwnProperty(c)) {\n t += this.objects[el].childElements[c].id + '(' + this.objects[el].childElements[c].name + ')' + ', ';\n }\n }\n t += '<p>\\n';\n }\n }\n t += '<' + '/p>\\n';\n f = window.open();\n f.document.open();\n f.document.write(t);\n f.document.close();\n return this;\n },\n\n /**\n * Lists the XML code of the construction in a new HTML-window.\n * @returns {JXG.Board} Reference to the board\n */\n showXML: function () {\n var f = window.open('');\n f.document.open();\n f.document.write('<pre>' + Type.escapeHTML(this.xmlString) + '<' + '/pre>');\n f.document.close();\n return this;\n },\n\n /**\n * Sets for all objects the needsUpdate flag to \"true\".\n * @returns {JXG.Board} Reference to the board\n */\n prepareUpdate: function () {\n var el, pEl, len = this.objectsList.length;\n\n /*\n if (this.attr.updatetype === 'hierarchical') {\n return this;\n }\n */\n\n for (el = 0; el < len; el++) {\n pEl = this.objectsList[el];\n pEl.needsUpdate = pEl.needsRegularUpdate || this.needsFullUpdate;\n }\n\n for (el in this.groups) {\n if (this.groups.hasOwnProperty(el)) {\n pEl = this.groups[el];\n pEl.needsUpdate = pEl.needsRegularUpdate || this.needsFullUpdate;\n }\n }\n\n return this;\n },\n\n /**\n * Runs through all elements and calls their update() method.\n * @param {JXG.GeometryElement} drag Element that caused the update.\n * @returns {JXG.Board} Reference to the board\n */\n updateElements: function (drag) {\n var el, pEl;\n //var childId, i = 0;\n\n drag = this.select(drag);\n\n /*\n if (Type.exists(drag)) {\n for (el = 0; el < this.objectsList.length; el++) {\n pEl = this.objectsList[el];\n if (pEl.id === drag.id) {\n i = el;\n break;\n }\n }\n }\n */\n\n for (el = 0; el < this.objectsList.length; el++) {\n pEl = this.objectsList[el];\n if (this.needsFullUpdate && pEl.elementClass === Const.OBJECT_CLASS_TEXT) {\n pEl.updateSize();\n }\n\n // For updates of an element we distinguish if the dragged element is updated or\n // other elements are updated.\n // The difference lies in the treatment of gliders and points based on transformations.\n pEl.update(!Type.exists(drag) || pEl.id !== drag.id)\n .updateVisibility();\n }\n\n // update groups last\n for (el in this.groups) {\n if (this.groups.hasOwnProperty(el)) {\n this.groups[el].update(drag);\n }\n }\n\n return this;\n },\n\n /**\n * Runs through all elements and calls their update() method.\n * @returns {JXG.Board} Reference to the board\n */\n updateRenderer: function () {\n var el,\n len = this.objectsList.length;\n\n /*\n objs = this.objectsList.slice(0);\n objs.sort(function (a, b) {\n if (a.visProp.layer < b.visProp.layer) {\n return -1;\n } else if (a.visProp.layer === b.visProp.layer) {\n return b.lastDragTime.getTime() - a.lastDragTime.getTime();\n } else {\n return 1;\n }\n });\n */\n\n if (this.renderer.type === 'canvas') {\n this.updateRendererCanvas();\n } else {\n for (el = 0; el < len; el++) {\n this.objectsList[el].updateRenderer();\n }\n }\n return this;\n },\n\n /**\n * Runs through all elements and calls their update() method.\n * This is a special version for the CanvasRenderer.\n * Here, we have to do our own layer handling.\n * @returns {JXG.Board} Reference to the board\n */\n updateRendererCanvas: function () {\n var el, pEl, i, mini, la,\n olen = this.objectsList.length,\n layers = this.options.layer,\n len = this.options.layer.numlayers,\n last = Number.NEGATIVE_INFINITY;\n\n for (i = 0; i < len; i++) {\n mini = Number.POSITIVE_INFINITY;\n\n for (la in layers) {\n if (layers.hasOwnProperty(la)) {\n if (layers[la] > last && layers[la] < mini) {\n mini = layers[la];\n }\n }\n }\n\n last = mini;\n\n for (el = 0; el < olen; el++) {\n pEl = this.objectsList[el];\n\n if (pEl.visProp.layer === mini) {\n pEl.prepareUpdate().updateRenderer();\n }\n }\n }\n return this;\n },\n\n /**\n * Please use {@link JXG.Board.on} instead.\n * @param {Function} hook A function to be called by the board after an update occurred.\n * @param {String} [m='update'] When the hook is to be called. Possible values are <i>mouseup</i>, <i>mousedown</i> and <i>update</i>.\n * @param {Object} [context=board] Determines the execution context the hook is called. This parameter is optional, default is the\n * board object the hook is attached to.\n * @returns {Number} Id of the hook, required to remove the hook from the board.\n * @deprecated\n */\n addHook: function (hook, m, context) {\n JXG.deprecated('Board.addHook()', 'Board.on()');\n m = Type.def(m, 'update');\n\n context = Type.def(context, this);\n\n this.hooks.push([m, hook]);\n this.on(m, hook, context);\n\n return this.hooks.length - 1;\n },\n\n /**\n * Alias of {@link JXG.Board.on}.\n */\n addEvent: JXG.shortcut(JXG.Board.prototype, 'on'),\n\n /**\n * Please use {@link JXG.Board.off} instead.\n * @param {Number|function} id The number you got when you added the hook or a reference to the event handler.\n * @returns {JXG.Board} Reference to the board\n * @deprecated\n */\n removeHook: function (id) {\n JXG.deprecated('Board.removeHook()', 'Board.off()');\n if (this.hooks[id]) {\n this.off(this.hooks[id][0], this.hooks[id][1]);\n this.hooks[id] = null;\n }\n\n return this;\n },\n\n /**\n * Alias of {@link JXG.Board.off}.\n */\n removeEvent: JXG.shortcut(JXG.Board.prototype, 'off'),\n\n /**\n * Runs through all hooked functions and calls them.\n * @returns {JXG.Board} Reference to the board\n * @deprecated\n */\n updateHooks: function (m) {\n var arg = Array.prototype.slice.call(arguments, 0);\n\n JXG.deprecated('Board.updateHooks()', 'Board.triggerEventHandlers()');\n\n arg[0] = Type.def(arg[0], 'update');\n this.triggerEventHandlers([arg[0]], arguments);\n\n return this;\n },\n\n /**\n * Adds a dependent board to this board.\n * @param {JXG.Board} board A reference to board which will be updated after an update of this board occurred.\n * @returns {JXG.Board} Reference to the board\n */\n addChild: function (board) {\n if (Type.exists(board) && Type.exists(board.containerObj)) {\n this.dependentBoards.push(board);\n this.update();\n }\n return this;\n },\n\n /**\n * Deletes a board from the list of dependent boards.\n * @param {JXG.Board} board Reference to the board which will be removed.\n * @returns {JXG.Board} Reference to the board\n */\n removeChild: function (board) {\n var i;\n\n for (i = this.dependentBoards.length - 1; i >= 0; i--) {\n if (this.dependentBoards[i] === board) {\n this.dependentBoards.splice(i, 1);\n }\n }\n return this;\n },\n\n /**\n * Runs through most elements and calls their update() method and update the conditions.\n * @param {JXG.GeometryElement} [drag] Element that caused the update.\n * @returns {JXG.Board} Reference to the board\n */\n update: function (drag) {\n var i, len, b, insert,\n storeActiveEl;\n\n if (this.inUpdate || this.isSuspendedUpdate) {\n return this;\n }\n this.inUpdate = true;\n\n if (this.attr.minimizereflow === 'all' && this.containerObj && this.renderer.type !== 'vml') {\n storeActiveEl = this.document.activeElement; // Store focus element\n insert = this.renderer.removeToInsertLater(this.containerObj);\n }\n\n if (this.attr.minimizereflow === 'svg' && this.renderer.type === 'svg') {\n storeActiveEl = this.document.activeElement;\n insert = this.renderer.removeToInsertLater(this.renderer.svgRoot);\n }\n\n this.prepareUpdate().updateElements(drag).updateConditions();\n this.renderer.suspendRedraw(this);\n this.updateRenderer();\n this.renderer.unsuspendRedraw();\n this.triggerEventHandlers(['update'], []);\n\n if (insert) {\n insert();\n storeActiveEl.focus(); // Restore focus element\n }\n\n // To resolve dependencies between boards\n // for (var board in JXG.boards) {\n len = this.dependentBoards.length;\n for (i = 0; i < len; i++) {\n b = this.dependentBoards[i];\n if (Type.exists(b) && b !== this) {\n b.updateQuality = this.updateQuality;\n b.prepareUpdate().updateElements().updateConditions();\n b.renderer.suspendRedraw();\n b.updateRenderer();\n b.renderer.unsuspendRedraw();\n b.triggerEventHandlers(['update'], []);\n }\n\n }\n\n this.inUpdate = false;\n return this;\n },\n\n /**\n * Runs through all elements and calls their update() method and update the conditions.\n * This is necessary after zooming and changing the bounding box.\n * @returns {JXG.Board} Reference to the board\n */\n fullUpdate: function () {\n this.needsFullUpdate = true;\n this.update();\n this.needsFullUpdate = false;\n return this;\n },\n\n /**\n * Adds a grid to the board according to the settings given in board.options.\n * @returns {JXG.Board} Reference to the board.\n */\n addGrid: function () {\n this.create('grid', []);\n\n return this;\n },\n\n /**\n * Removes all grids assigned to this board. Warning: This method also removes all objects depending on one or\n * more of the grids.\n * @returns {JXG.Board} Reference to the board object.\n */\n removeGrids: function () {\n var i;\n\n for (i = 0; i < this.grids.length; i++) {\n this.removeObject(this.grids[i]);\n }\n\n this.grids.length = 0;\n this.update(); // required for canvas renderer\n\n return this;\n },\n\n /**\n * Creates a new geometric element of type elementType.\n * @param {String} elementType Type of the element to be constructed given as a string e.g. 'point' or 'circle'.\n * @param {Array} parents Array of parent elements needed to construct the element e.g. coordinates for a point or two\n * points to construct a line. This highly depends on the elementType that is constructed. See the corresponding JXG.create*\n * methods for a list of possible parameters.\n * @param {Object} [attributes] An object containing the attributes to be set. This also depends on the elementType.\n * Common attributes are name, visible, strokeColor.\n * @returns {Object} Reference to the created element. This is usually a GeometryElement, but can be an array containing\n * two or more elements.\n */\n create: function (elementType, parents, attributes) {\n var el, i;\n\n elementType = elementType.toLowerCase();\n\n if (!Type.exists(parents)) {\n parents = [];\n }\n\n if (!Type.exists(attributes)) {\n attributes = {};\n }\n\n for (i = 0; i < parents.length; i++) {\n if (Type.isString(parents[i]) &&\n !(elementType === 'text' && i === 2) &&\n !(elementType === 'solidofrevolution3d' && i === 2) &&\n !((elementType === 'input' || elementType === 'checkbox' || elementType === 'button') &&\n (i === 2 || i === 3)) &&\n !(elementType === 'curve' && i > 0) // Allow curve plots with jessiecode\n ) {\n parents[i] = this.select(parents[i]);\n }\n }\n\n if (Type.isFunction(JXG.elements[elementType])) {\n el = JXG.elements[elementType](this, parents, attributes);\n } else {\n throw new Error(\"JSXGraph: create: Unknown element type given: \" + elementType);\n }\n\n if (!Type.exists(el)) {\n JXG.debug(\"JSXGraph: create: failure creating \" + elementType);\n return el;\n }\n\n if (el.prepareUpdate && el.update && el.updateRenderer) {\n el.fullUpdate();\n }\n return el;\n },\n\n /**\n * Deprecated name for {@link JXG.Board.create}.\n * @deprecated\n */\n createElement: function () {\n JXG.deprecated('Board.createElement()', 'Board.create()');\n return this.create.apply(this, arguments);\n },\n\n /**\n * Delete the elements drawn as part of a trace of an element.\n * @returns {JXG.Board} Reference to the board\n */\n clearTraces: function () {\n var el;\n\n for (el = 0; el < this.objectsList.length; el++) {\n this.objectsList[el].clearTrace();\n }\n\n this.numTraces = 0;\n return this;\n },\n\n /**\n * Stop updates of the board.\n * @returns {JXG.Board} Reference to the board\n */\n suspendUpdate: function () {\n if (!this.inUpdate) {\n this.isSuspendedUpdate = true;\n }\n return this;\n },\n\n /**\n * Enable updates of the board.\n * @returns {JXG.Board} Reference to the board\n */\n unsuspendUpdate: function () {\n if (this.isSuspendedUpdate) {\n this.isSuspendedUpdate = false;\n this.fullUpdate();\n }\n return this;\n },\n\n /**\n * Set the bounding box of the board.\n * @param {Array} bbox New bounding box [x1,y1,x2,y2]\n * @param {Boolean} [keepaspectratio=false] If set to true, the aspect ratio will be 1:1, but\n * the resulting viewport may be larger.\n * @param {String} [setZoom='reset'] Reset, keep or update the zoom level of the board. 'reset'\n * sets {@link JXG.Board#zoomX} and {@link JXG.Board#zoomY} to the start values (or 1.0).\n * 'update' adapts these values accoring to the new bounding box and 'keep' does nothing.\n * @returns {JXG.Board} Reference to the board\n */\n setBoundingBox: function (bbox, keepaspectratio, setZoom) {\n var h, w, ux, uy,\n offX = 0,\n offY = 0,\n dim = Env.getDimensions(this.container, this.document);\n\n if (!Type.isArray(bbox)) {\n return this;\n }\n\n if (bbox[0] < this.maxboundingbox[0] ||\n bbox[1] > this.maxboundingbox[1] ||\n bbox[2] > this.maxboundingbox[2] ||\n bbox[3] < this.maxboundingbox[3]) {\n return this;\n }\n\n if (!Type.exists(setZoom)) {\n setZoom = 'reset';\n }\n\n ux = this.unitX;\n uy = this.unitY;\n\n this.canvasWidth = parseInt(dim.width, 10);\n this.canvasHeight = parseInt(dim.height, 10);\n w = this.canvasWidth;\n h = this.canvasHeight;\n if (keepaspectratio) {\n this.unitX = w / (bbox[2] - bbox[0]);\n this.unitY = h / (bbox[1] - bbox[3]);\n if (Math.abs(this.unitX) < Math.abs(this.unitY)) {\n this.unitY = Math.abs(this.unitX) * this.unitY / Math.abs(this.unitY);\n // Add the additional units in equal portions above and below\n offY = (h / this.unitY - (bbox[1] - bbox[3])) * 0.5;\n } else {\n this.unitX = Math.abs(this.unitY) * this.unitX / Math.abs(this.unitX);\n // Add the additional units in equal portions left and right\n offX = (w / this.unitX - (bbox[2] - bbox[0])) * 0.5;\n }\n this.keepaspectratio = true;\n } else {\n this.unitX = w / (bbox[2] - bbox[0]);\n this.unitY = h / (bbox[1] - bbox[3]);\n this.keepaspectratio = false;\n }\n\n this.moveOrigin(-this.unitX * (bbox[0] - offX), this.unitY * (bbox[1] + offY));\n\n if (setZoom === 'update') {\n this.zoomX *= this.unitX / ux;\n this.zoomY *= this.unitY / uy;\n } else if (setZoom === 'reset') {\n this.zoomX = Type.exists(this.attr.zoomx) ? this.attr.zoomx : 1.0;\n this.zoomY = Type.exists(this.attr.zoomy) ? this.attr.zoomy : 1.0;\n }\n\n return this;\n },\n\n /**\n * Get the bounding box of the board.\n * @returns {Array} bounding box [x1,y1,x2,y2] upper left corner, lower right corner\n */\n getBoundingBox: function () {\n var ul = (new Coords(Const.COORDS_BY_SCREEN, [0, 0], this)).usrCoords,\n lr = (new Coords(Const.COORDS_BY_SCREEN, [this.canvasWidth, this.canvasHeight], this)).usrCoords;\n\n return [ul[1], ul[2], lr[1], lr[2]];\n },\n\n /**\n * Adds an animation. Animations are controlled by the boards, so the boards need to be aware of the\n * animated elements. This function tells the board about new elements to animate.\n * @param {JXG.GeometryElement} element The element which is to be animated.\n * @returns {JXG.Board} Reference to the board\n */\n addAnimation: function (element) {\n var that = this;\n\n this.animationObjects[element.id] = element;\n\n if (!this.animationIntervalCode) {\n this.animationIntervalCode = window.setInterval(function () {\n that.animate();\n }, element.board.attr.animationdelay);\n }\n\n return this;\n },\n\n /**\n * Cancels all running animations.\n * @returns {JXG.Board} Reference to the board\n */\n stopAllAnimation: function () {\n var el;\n\n for (el in this.animationObjects) {\n if (this.animationObjects.hasOwnProperty(el) && Type.exists(this.animationObjects[el])) {\n this.animationObjects[el] = null;\n delete this.animationObjects[el];\n }\n }\n\n window.clearInterval(this.animationIntervalCode);\n delete this.animationIntervalCode;\n\n return this;\n },\n\n /**\n * General purpose animation function. This currently only supports moving points from one place to another. This\n * is faster than managing the animation per point, especially if there is more than one animated point at the same time.\n * @returns {JXG.Board} Reference to the board\n */\n animate: function () {\n var props, el, o, newCoords, r, p, c, cbtmp,\n count = 0,\n obj = null;\n\n for (el in this.animationObjects) {\n if (this.animationObjects.hasOwnProperty(el) && Type.exists(this.animationObjects[el])) {\n count += 1;\n o = this.animationObjects[el];\n\n if (o.animationPath) {\n if (Type.isFunction(o.animationPath)) {\n newCoords = o.animationPath(new Date().getTime() - o.animationStart);\n } else {\n newCoords = o.animationPath.pop();\n }\n\n if ((!Type.exists(newCoords)) || (!Type.isArray(newCoords) && isNaN(newCoords))) {\n delete o.animationPath;\n } else {\n o.setPositionDirectly(Const.COORDS_BY_USER, newCoords);\n o.fullUpdate();\n obj = o;\n }\n }\n if (o.animationData) {\n c = 0;\n\n for (r in o.animationData) {\n if (o.animationData.hasOwnProperty(r)) {\n p = o.animationData[r].pop();\n\n if (!Type.exists(p)) {\n delete o.animationData[p];\n } else {\n c += 1;\n props = {};\n props[r] = p;\n o.setAttribute(props);\n }\n }\n }\n\n if (c === 0) {\n delete o.animationData;\n }\n }\n\n if (!Type.exists(o.animationData) && !Type.exists(o.animationPath)) {\n this.animationObjects[el] = null;\n delete this.animationObjects[el];\n\n if (Type.exists(o.animationCallback)) {\n cbtmp = o.animationCallback;\n o.animationCallback = null;\n cbtmp();\n }\n }\n }\n }\n\n if (count === 0) {\n window.clearInterval(this.animationIntervalCode);\n delete this.animationIntervalCode;\n } else {\n this.update(obj);\n }\n\n return this;\n },\n\n /**\n * Migrate the dependency properties of the point src\n * to the point dest and delete the point src.\n * For example, a circle around the point src\n * receives the new center dest. The old center src\n * will be deleted.\n * @param {JXG.Point} src Original point which will be deleted\n * @param {JXG.Point} dest New point with the dependencies of src.\n * @param {Boolean} copyName Flag which decides if the name of the src element is copied to the\n * dest element.\n * @returns {JXG.Board} Reference to the board\n */\n migratePoint: function (src, dest, copyName) {\n var child, childId, prop, found, i, srcLabelId, srcHasLabel = false;\n\n src = this.select(src);\n dest = this.select(dest);\n\n if (Type.exists(src.label)) {\n srcLabelId = src.label.id;\n srcHasLabel = true;\n this.removeObject(src.label);\n }\n\n for (childId in src.childElements) {\n if (src.childElements.hasOwnProperty(childId)) {\n child = src.childElements[childId];\n found = false;\n\n for (prop in child) {\n if (child.hasOwnProperty(prop)) {\n if (child[prop] === src) {\n child[prop] = dest;\n found = true;\n }\n }\n }\n\n if (found) {\n delete src.childElements[childId];\n }\n\n for (i = 0; i < child.parents.length; i++) {\n if (child.parents[i] === src.id) {\n child.parents[i] = dest.id;\n }\n }\n\n dest.addChild(child);\n }\n }\n\n // The destination object should receive the name\n // and the label of the originating (src) object\n if (copyName) {\n if (srcHasLabel) {\n delete dest.childElements[srcLabelId];\n delete dest.descendants[srcLabelId];\n }\n\n if (dest.label) {\n this.removeObject(dest.label);\n }\n\n delete this.elementsByName[dest.name];\n dest.name = src.name;\n if (srcHasLabel) {\n dest.createLabel();\n }\n }\n\n this.removeObject(src);\n\n if (Type.exists(dest.name) && dest.name !== '') {\n this.elementsByName[dest.name] = dest;\n }\n\n this.fullUpdate();\n\n return this;\n },\n\n /**\n * Initializes color blindness simulation.\n * @param {String} deficiency Describes the color blindness deficiency which is simulated. Accepted values are 'protanopia', 'deuteranopia', and 'tritanopia'.\n * @returns {JXG.Board} Reference to the board\n */\n emulateColorblindness: function (deficiency) {\n var e, o;\n\n if (!Type.exists(deficiency)) {\n deficiency = 'none';\n }\n\n if (this.currentCBDef === deficiency) {\n return this;\n }\n\n for (e in this.objects) {\n if (this.objects.hasOwnProperty(e)) {\n o = this.objects[e];\n\n if (deficiency !== 'none') {\n if (this.currentCBDef === 'none') {\n // this could be accomplished by JXG.extend, too. But do not use\n // JXG.deepCopy as this could result in an infinite loop because in\n // visProp there could be geometry elements which contain the board which\n // contains all objects which contain board etc.\n o.visPropOriginal = {\n strokecolor: o.visProp.strokecolor,\n fillcolor: o.visProp.fillcolor,\n highlightstrokecolor: o.visProp.highlightstrokecolor,\n highlightfillcolor: o.visProp.highlightfillcolor\n };\n }\n o.setAttribute({\n strokecolor: Color.rgb2cb(Type.evaluate(o.visPropOriginal.strokecolor), deficiency),\n fillcolor: Color.rgb2cb(Type.evaluate(o.visPropOriginal.fillcolor), deficiency),\n highlightstrokecolor: Color.rgb2cb(Type.evaluate(o.visPropOriginal.highlightstrokecolor), deficiency),\n highlightfillcolor: Color.rgb2cb(Type.evaluate(o.visPropOriginal.highlightfillcolor), deficiency)\n });\n } else if (Type.exists(o.visPropOriginal)) {\n JXG.extend(o.visProp, o.visPropOriginal);\n }\n }\n }\n this.currentCBDef = deficiency;\n this.update();\n\n return this;\n },\n\n /**\n * Select a single or multiple elements at once.\n * @param {String|Object|function} str The name, id or a reference to a JSXGraph element on this board. An object will\n * be used as a filter to return multiple elements at once filtered by the properties of the object.\n * @param {Boolean} onlyByIdOrName If true (default:false) elements are only filtered by their id, name or groupId.\n * The advanced filters consisting of objects or functions are ignored.\n * @returns {JXG.GeometryElement|JXG.Composition}\n * @example\n * // select the element with name A\n * board.select('A');\n *\n * // select all elements with strokecolor set to 'red' (but not '#ff0000')\n * board.select({\n * strokeColor: 'red'\n * });\n *\n * // select all points on or below the x axis and make them black.\n * board.select({\n * elementClass: JXG.OBJECT_CLASS_POINT,\n * Y: function (v) {\n * return v <= 0;\n * }\n * }).setAttribute({color: 'black'});\n *\n * // select all elements\n * board.select(function (el) {\n * return true;\n * });\n */\n select: function (str, onlyByIdOrName) {\n var flist, olist, i, l,\n s = str;\n\n if (s === null) {\n return s;\n }\n\n // it's a string, most likely an id or a name.\n if (Type.isString(s) && s !== '') {\n // Search by ID\n if (Type.exists(this.objects[s])) {\n s = this.objects[s];\n // Search by name\n } else if (Type.exists(this.elementsByName[s])) {\n s = this.elementsByName[s];\n // Search by group ID\n } else if (Type.exists(this.groups[s])) {\n s = this.groups[s];\n }\n // it's a function or an object, but not an element\n } else if (!onlyByIdOrName &&\n (Type.isFunction(s) ||\n (Type.isObject(s) && !Type.isFunction(s.setAttribute))\n )) {\n flist = Type.filterElements(this.objectsList, s);\n\n olist = {};\n l = flist.length;\n for (i = 0; i < l; i++) {\n olist[flist[i].id] = flist[i];\n }\n s = new Composition(olist);\n // it's an element which has been deleted (and still hangs around, e.g. in an attractor list\n } else if (Type.isObject(s) && Type.exists(s.id) && !Type.exists(this.objects[s.id])) {\n s = null;\n }\n\n return s;\n },\n\n /**\n * Checks if the given point is inside the boundingbox.\n * @param {Number|JXG.Coords} x User coordinate or {@link JXG.Coords} object.\n * @param {Number} [y] User coordinate. May be omitted in case <tt>x</tt> is a {@link JXG.Coords} object.\n * @returns {Boolean}\n */\n hasPoint: function (x, y) {\n var px = x,\n py = y,\n bbox = this.getBoundingBox();\n\n if (Type.exists(x) && Type.isArray(x.usrCoords)) {\n px = x.usrCoords[1];\n py = x.usrCoords[2];\n }\n\n return !!(Type.isNumber(px) && Type.isNumber(py) &&\n bbox[0] < px && px < bbox[2] && bbox[1] > py && py > bbox[3]);\n },\n\n /**\n * Update CSS transformations of type scaling. It is used to correct the mouse position\n * in {@link JXG.Board.getMousePosition}.\n * The inverse transformation matrix is updated on each mouseDown and touchStart event.\n *\n * It is up to the user to call this method after an update of the CSS transformation\n * in the DOM.\n */\n updateCSSTransforms: function () {\n var obj = this.containerObj,\n o = obj,\n o2 = obj;\n\n this.cssTransMat = Env.getCSSTransformMatrix(o);\n\n /*\n * In Mozilla and Webkit: offsetParent seems to jump at least to the next iframe,\n * if not to the body. In IE and if we are in an position:absolute environment\n * offsetParent walks up the DOM hierarchy.\n * In order to walk up the DOM hierarchy also in Mozilla and Webkit\n * we need the parentNode steps.\n */\n o = o.offsetParent;\n while (o) {\n this.cssTransMat = Mat.matMatMult(Env.getCSSTransformMatrix(o), this.cssTransMat);\n\n o2 = o2.parentNode;\n while (o2 !== o) {\n this.cssTransMat = Mat.matMatMult(Env.getCSSTransformMatrix(o), this.cssTransMat);\n o2 = o2.parentNode || o2.host;\n }\n\n o = o.offsetParent;\n }\n this.cssTransMat = Mat.inverse(this.cssTransMat);\n\n return this;\n },\n\n /**\n * Start selection mode. This function can either be triggered from outside or by\n * a down event together with correct key pressing. The default keys are\n * shift+ctrl. But this can be changed in the options.\n *\n * Starting from out side can be realized for example with a button like this:\n * <pre>\n * \t<button onclick=\"board.startSelectionMode()\">Start</button>\n * </pre>\n * @example\n * //\n * // Set a new bounding box from the selection rectangle\n * //\n * var board = JXG.JSXGraph.initBoard('jxgbox', {\n * boundingBox:[-3,2,3,-2],\n * keepAspectRatio: false,\n * axis:true,\n * selection: {\n * enabled: true,\n * needShift: false,\n * needCtrl: true,\n * withLines: false,\n * vertices: {\n * visible: false\n * },\n * fillColor: '#ffff00',\n * }\n * });\n *\n * var f = function f(x) { return Math.cos(x); },\n * curve = board.create('functiongraph', [f]);\n *\n * board.on('stopselecting', function(){\n * var box = board.stopSelectionMode(),\n *\n * // bbox has the coordinates of the selection rectangle.\n * // Attention: box[i].usrCoords have the form [1, x, y], i.e.\n * // are homogeneous coordinates.\n * bbox = box[0].usrCoords.slice(1).concat(box[1].usrCoords.slice(1));\n *\n * // Set a new bounding box\n * board.setBoundingBox(bbox, false);\n * });\n *\n *\n * </pre><div class=\"jxgbox\" id=\"JXG11eff3a6-8c50-11e5-b01d-901b0e1b8723\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * //\n * // Set a new bounding box from the selection rectangle\n * //\n * var board = JXG.JSXGraph.initBoard('JXG11eff3a6-8c50-11e5-b01d-901b0e1b8723', {\n * boundingBox:[-3,2,3,-2],\n * keepAspectRatio: false,\n * axis:true,\n * selection: {\n * enabled: true,\n * needShift: false,\n * needCtrl: true,\n * withLines: false,\n * vertices: {\n * visible: false\n * },\n * fillColor: '#ffff00',\n * }\n * });\n *\n * var f = function f(x) { return Math.cos(x); },\n * curve = board.create('functiongraph', [f]);\n *\n * board.on('stopselecting', function(){\n * var box = board.stopSelectionMode(),\n *\n * // bbox has the coordinates of the selection rectangle.\n * // Attention: box[i].usrCoords have the form [1, x, y], i.e.\n * // are homogeneous coordinates.\n * bbox = box[0].usrCoords.slice(1).concat(box[1].usrCoords.slice(1));\n *\n * // Set a new bounding box\n * board.setBoundingBox(bbox, false);\n * });\n * })();\n *\n * </script><pre>\n *\n */\n startSelectionMode: function () {\n this.selectingMode = true;\n this.selectionPolygon.setAttribute({visible: true});\n this.selectingBox = [[0, 0], [0, 0]];\n this._setSelectionPolygonFromBox();\n this.selectionPolygon.fullUpdate();\n },\n\n /**\n * Finalize the selection: disable selection mode and return the coordinates\n * of the selection rectangle.\n * @returns {Array} Coordinates of the selection rectangle. The array\n * contains two {@link JXG.Coords} objects. One the upper left corner and\n * the second for the lower right corner.\n */\n stopSelectionMode: function () {\n this.selectingMode = false;\n this.selectionPolygon.setAttribute({visible: false});\n return [this.selectionPolygon.vertices[0].coords, this.selectionPolygon.vertices[2].coords];\n },\n\n /**\n * Start the selection of a region.\n * @private\n * @param {Array} pos Screen coordiates of the upper left corner of the\n * selection rectangle.\n */\n _startSelecting: function (pos) {\n this.isSelecting = true;\n this.selectingBox = [ [pos[0], pos[1]], [pos[0], pos[1]] ];\n this._setSelectionPolygonFromBox();\n },\n\n /**\n * Update the selection rectangle during a move event.\n * @private\n * @param {Array} pos Screen coordiates of the move event\n */\n _moveSelecting: function (pos) {\n if (this.isSelecting) {\n this.selectingBox[1] = [pos[0], pos[1]];\n this._setSelectionPolygonFromBox();\n this.selectionPolygon.fullUpdate();\n }\n },\n\n /**\n * Update the selection rectangle during an up event. Stop selection.\n * @private\n * @param {Object} evt Event object\n */\n _stopSelecting: function (evt) {\n var pos = this.getMousePosition(evt);\n\n this.isSelecting = false;\n this.selectingBox[1] = [pos[0], pos[1]];\n this._setSelectionPolygonFromBox();\n },\n\n /**\n * Update the Selection rectangle.\n * @private\n */\n _setSelectionPolygonFromBox: function () {\n var A = this.selectingBox[0],\n B = this.selectingBox[1];\n\n this.selectionPolygon.vertices[0].setPositionDirectly(JXG.COORDS_BY_SCREEN, [A[0], A[1]]);\n this.selectionPolygon.vertices[1].setPositionDirectly(JXG.COORDS_BY_SCREEN, [A[0], B[1]]);\n this.selectionPolygon.vertices[2].setPositionDirectly(JXG.COORDS_BY_SCREEN, [B[0], B[1]]);\n this.selectionPolygon.vertices[3].setPositionDirectly(JXG.COORDS_BY_SCREEN, [B[0], A[1]]);\n },\n\n /**\n * Test if a down event should start a selection. Test if the\n * required keys are pressed. If yes, {@link JXG.Board.startSelectionMode} is called.\n * @param {Object} evt Event object\n */\n _testForSelection: function (evt) {\n if (this._isRequiredKeyPressed(evt, 'selection')) {\n if (!Type.exists(this.selectionPolygon)) {\n this._createSelectionPolygon(this.attr);\n }\n this.startSelectionMode();\n }\n },\n\n /**\n * Create the internal selection polygon, which will be available as board.selectionPolygon.\n * @private\n * @param {Object} attr board attributes, e.g. the subobject board.attr.\n * @returns {Object} pointer to the board to enable chaining.\n */\n _createSelectionPolygon: function(attr) {\n var selectionattr;\n\n if (!Type.exists(this.selectionPolygon)) {\n selectionattr = Type.copyAttributes(attr, Options, 'board', 'selection');\n if (selectionattr.enabled === true) {\n this.selectionPolygon = this.create('polygon', [[0, 0], [0, 0], [0, 0], [0, 0]], selectionattr);\n }\n }\n\n return this;\n },\n\n /* **************************\n * EVENT DEFINITION\n * for documentation purposes\n * ************************** */\n\n //region Event handler documentation\n\n /**\n * @event\n * @description Whenever the user starts to touch or click the board.\n * @name JXG.Board#down\n * @param {Event} e The browser's event object.\n */\n __evt__down: function (e) { },\n\n /**\n * @event\n * @description Whenever the user starts to click on the board.\n * @name JXG.Board#mousedown\n * @param {Event} e The browser's event object.\n */\n __evt__mousedown: function (e) { },\n\n /**\n * @event\n * @description Whenever the user taps the pen on the board.\n * @name JXG.Board#pendown\n * @param {Event} e The browser's event object.\n */\n __evt__pendown: function (e) { },\n\n /**\n * @event\n * @description Whenever the user starts to click on the board with a\n * device sending pointer events.\n * @name JXG.Board#pointerdown\n * @param {Event} e The browser's event object.\n */\n __evt__pointerdown: function (e) { },\n\n /**\n * @event\n * @description Whenever the user starts to touch the board.\n * @name JXG.Board#touchstart\n * @param {Event} e The browser's event object.\n */\n __evt__touchstart: function (e) { },\n\n /**\n * @event\n * @description Whenever the user stops to touch or click the board.\n * @name JXG.Board#up\n * @param {Event} e The browser's event object.\n */\n __evt__up: function (e) { },\n\n /**\n * @event\n * @description Whenever the user releases the mousebutton over the board.\n * @name JXG.Board#mouseup\n * @param {Event} e The browser's event object.\n */\n __evt__mouseup: function (e) { },\n\n /**\n * @event\n * @description Whenever the user releases the mousebutton over the board with a\n * device sending pointer events.\n * @name JXG.Board#pointerup\n * @param {Event} e The browser's event object.\n */\n __evt__pointerup: function (e) { },\n\n /**\n * @event\n * @description Whenever the user stops touching the board.\n * @name JXG.Board#touchend\n * @param {Event} e The browser's event object.\n */\n __evt__touchend: function (e) { },\n\n /**\n * @event\n * @description This event is fired whenever the user is moving the finger or mouse pointer over the board.\n * @name JXG.Board#move\n * @param {Event} e The browser's event object.\n * @param {Number} mode The mode the board currently is in\n * @see JXG.Board#mode\n */\n __evt__move: function (e, mode) { },\n\n /**\n * @event\n * @description This event is fired whenever the user is moving the mouse over the board.\n * @name JXG.Board#mousemove\n * @param {Event} e The browser's event object.\n * @param {Number} mode The mode the board currently is in\n * @see JXG.Board#mode\n */\n __evt__mousemove: function (e, mode) { },\n\n /**\n * @event\n * @description This event is fired whenever the user is moving the pen over the board.\n * @name JXG.Board#penmove\n * @param {Event} e The browser's event object.\n * @param {Number} mode The mode the board currently is in\n * @see JXG.Board#mode\n */\n __evt__penmove: function (e, mode) { },\n\n /**\n * @event\n * @description This event is fired whenever the user is moving the mouse over the board with a\n * device sending pointer events.\n * @name JXG.Board#pointermove\n * @param {Event} e The browser's event object.\n * @param {Number} mode The mode the board currently is in\n * @see JXG.Board#mode\n */\n __evt__pointermove: function (e, mode) { },\n\n /**\n * @event\n * @description This event is fired whenever the user is moving the finger over the board.\n * @name JXG.Board#touchmove\n * @param {Event} e The browser's event object.\n * @param {Number} mode The mode the board currently is in\n * @see JXG.Board#mode\n */\n __evt__touchmove: function (e, mode) { },\n\n /**\n * @event\n * @description Whenever an element is highlighted this event is fired.\n * @name JXG.Board#hit\n * @param {Event} e The browser's event object.\n * @param {JXG.GeometryElement} el The hit element.\n * @param target\n *\n * @example\n * var c = board.create('circle', [[1, 1], 2]);\n * board.on('hit', function(evt, el) {\n * console.log(\"Hit element\", el);\n * });\n *\n * </pre><div id=\"JXG19eb31ac-88e6-11e8-bcb5-901b0e1b8723\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG19eb31ac-88e6-11e8-bcb5-901b0e1b8723',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var c = board.create('circle', [[1, 1], 2]);\n * board.on('hit', function(evt, el) {\n * console.log(\"Hit element\", el);\n * });\n *\n * })();\n *\n * </script><pre>\n */\n __evt__hit: function (e, el, target) { },\n\n /**\n * @event\n * @description Whenever an element is highlighted this event is fired.\n * @name JXG.Board#mousehit\n * @see JXG.Board#hit\n * @param {Event} e The browser's event object.\n * @param {JXG.GeometryElement} el The hit element.\n * @param target\n */\n __evt__mousehit: function (e, el, target) { },\n\n /**\n * @event\n * @description This board is updated.\n * @name JXG.Board#update\n */\n __evt__update: function () { },\n\n /**\n * @event\n * @description The bounding box of the board has changed.\n * @name JXG.Board#boundingbox\n */\n __evt__boundingbox: function () { },\n\n /**\n * @event\n * @description Select a region is started during a down event or by calling\n * {@link JXG.Board.startSelectionMode}\n * @name JXG.Board#startselecting\n */\n __evt__startselecting: function () { },\n\n /**\n * @event\n * @description Select a region is started during a down event\n * from a device sending mouse events or by calling\n * {@link JXG.Board.startSelectionMode}.\n * @name JXG.Board#mousestartselecting\n */\n __evt__mousestartselecting: function () { },\n\n /**\n * @event\n * @description Select a region is started during a down event\n * from a device sending pointer events or by calling\n * {@link JXG.Board.startSelectionMode}.\n * @name JXG.Board#pointerstartselecting\n */\n __evt__pointerstartselecting: function () { },\n\n /**\n * @event\n * @description Select a region is started during a down event\n * from a device sending touch events or by calling\n * {@link JXG.Board.startSelectionMode}.\n * @name JXG.Board#touchstartselecting\n */\n __evt__touchstartselecting: function () { },\n\n /**\n * @event\n * @description Selection of a region is stopped during an up event.\n * @name JXG.Board#stopselecting\n */\n __evt__stopselecting: function () { },\n\n /**\n * @event\n * @description Selection of a region is stopped during an up event\n * from a device sending mouse events.\n * @name JXG.Board#mousestopselecting\n */\n __evt__mousestopselecting: function () { },\n\n /**\n * @event\n * @description Selection of a region is stopped during an up event\n * from a device sending pointer events.\n * @name JXG.Board#pointerstopselecting\n */\n __evt__pointerstopselecting: function () { },\n\n /**\n * @event\n * @description Selection of a region is stopped during an up event\n * from a device sending touch events.\n * @name JXG.Board#touchstopselecting\n */\n __evt__touchstopselecting: function () { },\n\n /**\n * @event\n * @description A move event while selecting of a region is active.\n * @name JXG.Board#moveselecting\n */\n __evt__moveselecting: function () { },\n\n /**\n * @event\n * @description A move event while selecting of a region is active\n * from a device sending mouse events.\n * @name JXG.Board#mousemoveselecting\n */\n __evt__mousemoveselecting: function () { },\n\n /**\n * @event\n * @description Select a region is started during a down event\n * from a device sending mouse events.\n * @name JXG.Board#pointermoveselecting\n */\n __evt__pointermoveselecting: function () { },\n\n /**\n * @event\n * @description Select a region is started during a down event\n * from a device sending touch events.\n * @name JXG.Board#touchmoveselecting\n */\n __evt__touchmoveselecting: function () { },\n\n /**\n * @ignore\n */\n __evt: function () {},\n\n //endregion\n\n /**\n * Expand the JSXGraph construction to fullscreen.\n * In order to preserve the proportions of the JSXGraph element,\n * a wrapper div is created which is set to fullscreen.\n * <p>\n * The wrapping div has the CSS class 'jxgbox_wrap_private' which is\n * defined in the file 'jsxgraph.css'\n * <p>\n * This feature is not available on iPhones (as of December 2021).\n *\n * @param {String} id (Optional) id of the div element which is brought to fullscreen.\n * If not provided, this defaults to the JSXGraph div. However, it may be necessary for the aspect ratio trick\n * which using padding-bottom/top and an out div element. Then, the id of the outer div has to be supplied.\n *\n * @return {JXG.Board} Reference to the board\n *\n * @example\n * <div id='jxgbox' class='jxgbox' style='width:500px; height:200px;'></div>\n * <button onClick=\"board.toFullscreen()\">Fullscreen</button>\n *\n * <script language=\"Javascript\" type='text/javascript'>\n * var board = JXG.JSXGraph.initBoard('jxgbox', {axis:true, boundingbox:[-5,5,5,-5]});\n * var p = board.create('point', [0, 1]);\n * </script>\n *\n * </pre><div id=\"JXGd5bab8b6-fd40-11e8-ab14-901b0e1b8723\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * var board_d5bab8b6;\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXGd5bab8b6-fd40-11e8-ab14-901b0e1b8723',\n * {boundingbox:[-5,5,5,-5], axis: true, showcopyright: false, shownavigation: false});\n * var p = board.create('point', [0, 1]);\n * board_d5bab8b6 = board;\n * })();\n * </script>\n * <button onClick=\"board_d5bab8b6.toFullscreen()\">Fullscreen</button>\n * <pre>\n *\n * @example\n * <div id='outer' style='max-width: 500px; margin: 0 auto;'>\n * <div id='jxgbox' class='jxgbox' style='height: 0; padding-bottom: 100%'></div>\n * </div>\n * <button onClick=\"board.toFullscreen('outer')\">Fullscreen</button>\n *\n * <script language=\"Javascript\" type='text/javascript'>\n * var board = JXG.JSXGraph.initBoard('jxgbox', {\n * axis:true,\n * boundingbox:[-5,5,5,-5],\n * fullscreen: { id: 'outer' },\n * showFullscreen: true\n * });\n * var p = board.create('point', [-2, 3], {});\n * </script>\n *\n * </pre><div id=\"JXG7103f6b_outer\" style='max-width: 500px; margin: 0 auto;'>\n * <div id=\"JXG7103f6be-6993-4ff8-8133-c78e50a8afac\" class=\"jxgbox\" style=\"height: 0; padding-bottom: 100%;\"></div>\n * </div>\n * <button onClick=\"board_JXG7103f6be.toFullscreen('JXG7103f6b_outer')\">Fullscreen</button>\n * <script type=\"text/javascript\">\n * var board_JXG7103f6be;\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG7103f6be-6993-4ff8-8133-c78e50a8afac',\n * {boundingbox: [-8, 8, 8,-8], axis: true, fullscreen: { id: 'JXG7103f6b_outer' }, showFullscreen: true,\n * showcopyright: false, shownavigation: false});\n * var p = board.create('point', [-2, 3], {});\n * board_JXG7103f6be = board;\n * })();\n *\n * </script><pre>\n *\n *\n */\n toFullscreen: function (id) {\n var wrap_id, wrap_node, inner_node;\n\n id = id || this.container;\n this._fullscreen_inner_id = id;\n inner_node = this.document.getElementById(id);\n wrap_id = 'fullscreenwrap_' + id;\n\n // Wrap a div around the JSXGraph div.\n if (this.document.getElementById(wrap_id)) {\n wrap_node = this.document.getElementById(wrap_id);\n } else {\n wrap_node = document.createElement('div');\n wrap_node.classList.add('JXG_wrap_private');\n wrap_node.setAttribute('id', wrap_id);\n inner_node.parentNode.insertBefore(wrap_node, inner_node);\n wrap_node.appendChild(inner_node);\n }\n\n // Get the real width and height of the JSXGraph div\n // and determine the scaling and vertical shift amount\n this._fullscreen_res = Env._getScaleFactors(inner_node);\n\n // Trigger fullscreen mode\n wrap_node.requestFullscreen = wrap_node.requestFullscreen ||\n wrap_node.webkitRequestFullscreen ||\n wrap_node.mozRequestFullScreen ||\n wrap_node.msRequestFullscreen;\n\n if (wrap_node.requestFullscreen) {\n wrap_node.requestFullscreen();\n }\n\n return this;\n },\n\n /**\n * If fullscreen mode is toggled, the possible CSS transformations\n * which are applied to the JSXGraph canvas have to be reread.\n * Otherwise the position of upper left corner is wrongly interpreted.\n *\n * @param {Object} evt fullscreen event object (unused)\n */\n fullscreenListener: function (evt) {\n var res, inner_id, inner_node;\n\n inner_id = this._fullscreen_inner_id;\n if (!Type.exists(inner_id)) {\n return;\n }\n\n this.document.fullscreenElement = this.document.fullscreenElement ||\n this.document.webkitFullscreenElement ||\n this.document.mozFullscreenElement ||\n this.document.msFullscreenElement;\n\n inner_node = this.document.getElementById(inner_id);\n // If full screen mode is started we have to remove CSS margin around the JSXGraph div.\n // Otherwise, the positioning of the fullscreen div will be false.\n // When leaving the fullscreen mode, the margin is put back in.\n if (this.document.fullscreenElement) {\n // Just entered fullscreen mode\n\n // Get the data computed in board.toFullscreen()\n res = this._fullscreen_res;\n\n // Store the scaling data.\n // It is used in AbstractRenderer.updateText to restore the scaling matrix\n // which is removed by MathJax.\n // Further, the CSS margin has to be removed when in fullscreen mode,\n // and must be restored later.\n inner_node._cssFullscreenStore = {\n id: this.document.fullscreenElement.id,\n isFullscreen: true,\n margin: inner_node.style.margin,\n width: inner_node.style.width,\n scale: res.scale,\n vshift: res.vshift\n };\n\n inner_node.style.margin = '';\n inner_node.style.width = res.width + 'px';\n\n // Do the shifting and scaling via CSS pseudo rules\n // We do this after fullscreen mode has been established to get the correct size\n // of the JSXGraph div.\n Env.scaleJSXGraphDiv(document.fullscreenElement.id, inner_id, res.scale, res.vshift);\n\n // Clear this.document.fullscreenElement, because Safari doesn't to it and\n // when leaving full screen mode it is still set.\n this.document.fullscreenElement = null;\n\n } else if (Type.exists(inner_node._cssFullscreenStore)) {\n // Just left the fullscreen mode\n\n // Remove the CSS rules added in Env.scaleJSXGraphDiv\n try {\n this.document.styleSheets[this.document.styleSheets.length - 1].deleteRule(0);\n } catch (err) {\n console.log('JSXGraph: Could not remove CSS rules for full screen mode');\n }\n\n inner_node._cssFullscreenStore.isFullscreen = false;\n inner_node.style.margin = inner_node._cssFullscreenStore.margin;\n inner_node.style.width = inner_node._cssFullscreenStore.width;\n }\n\n this.updateCSSTransforms();\n },\n\n /**\n * Function to animate a curve rolling on another curve.\n * @param {Curve} c1 JSXGraph curve building the floor where c2 rolls\n * @param {Curve} c2 JSXGraph curve which rolls on c1.\n * @param {number} start_c1 The parameter t such that c1(t) touches c2. This is the start position of the\n * rolling process\n * @param {Number} stepsize Increase in t in each step for the curve c1\n * @param {Number} direction\n * @param {Number} time Delay time for setInterval()\n * @param {Array} pointlist Array of points which are rolled in each step. This list should contain\n * all points which define c2 and gliders on c2.\n *\n * @example\n *\n * // Line which will be the floor to roll upon.\n * var line = brd.create('curve', [function (t) { return t;}, function (t){ return 1;}], {strokeWidth:6});\n * // Center of the rolling circle\n * var C = brd.create('point',[0,2],{name:'C'});\n * // Starting point of the rolling circle\n * var P = brd.create('point',[0,1],{name:'P', trace:true});\n * // Circle defined as a curve. The circle \"starts\" at P, i.e. circle(0) = P\n * var circle = brd.create('curve',[\n * function (t){var d = P.Dist(C),\n * beta = JXG.Math.Geometry.rad([C.X()+1,C.Y()],C,P);\n * t += beta;\n * return C.X()+d*Math.cos(t);\n * },\n * function (t){var d = P.Dist(C),\n * beta = JXG.Math.Geometry.rad([C.X()+1,C.Y()],C,P);\n * t += beta;\n * return C.Y()+d*Math.sin(t);\n * },\n * 0,2*Math.PI],\n * {strokeWidth:6, strokeColor:'green'});\n *\n * // Point on circle\n * var B = brd.create('glider',[0,2,circle],{name:'B', color:'blue',trace:false});\n * var roll = brd.createRoulette(line, circle, 0, Math.PI/20, 1, 100, [C,P,B]);\n * roll.start() // Start the rolling, to be stopped by roll.stop()\n *\n * </pre><div class=\"jxgbox\" id=\"JXGe5e1b53c-a036-4a46-9e35-190d196beca5\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * var brd = JXG.JSXGraph.initBoard('JXGe5e1b53c-a036-4a46-9e35-190d196beca5', {boundingbox: [-5, 5, 5, -5], axis: true, showcopyright:false, shownavigation: false});\n * // Line which will be the floor to roll upon.\n * var line = brd.create('curve', [function (t) { return t;}, function (t){ return 1;}], {strokeWidth:6});\n * // Center of the rolling circle\n * var C = brd.create('point',[0,2],{name:'C'});\n * // Starting point of the rolling circle\n * var P = brd.create('point',[0,1],{name:'P', trace:true});\n * // Circle defined as a curve. The circle \"starts\" at P, i.e. circle(0) = P\n * var circle = brd.create('curve',[\n * function (t){var d = P.Dist(C),\n * beta = JXG.Math.Geometry.rad([C.X()+1,C.Y()],C,P);\n * t += beta;\n * return C.X()+d*Math.cos(t);\n * },\n * function (t){var d = P.Dist(C),\n * beta = JXG.Math.Geometry.rad([C.X()+1,C.Y()],C,P);\n * t += beta;\n * return C.Y()+d*Math.sin(t);\n * },\n * 0,2*Math.PI],\n * {strokeWidth:6, strokeColor:'green'});\n *\n * // Point on circle\n * var B = brd.create('glider',[0,2,circle],{name:'B', color:'blue',trace:false});\n * var roll = brd.createRoulette(line, circle, 0, Math.PI/20, 1, 100, [C,P,B]);\n * roll.start() // Start the rolling, to be stopped by roll.stop()\n * </script><pre>\n */\n createRoulette: function (c1, c2, start_c1, stepsize, direction, time, pointlist) {\n var brd = this,\n Roulette = function () {\n var alpha = 0, Tx = 0, Ty = 0,\n t1 = start_c1,\n t2 = Numerics.root(\n function (t) {\n var c1x = c1.X(t1),\n c1y = c1.Y(t1),\n c2x = c2.X(t),\n c2y = c2.Y(t);\n\n return (c1x - c2x) * (c1x - c2x) + (c1y - c2y) * (c1y - c2y);\n },\n [0, Math.PI * 2]\n ),\n t1_new = 0.0, t2_new = 0.0,\n c1dist,\n\n rotation = brd.create('transform', [\n function () {\n return alpha;\n }\n ], {type: 'rotate'}),\n\n rotationLocal = brd.create('transform', [\n function () {\n return alpha;\n },\n function () {\n return c1.X(t1);\n },\n function () {\n return c1.Y(t1);\n }\n ], {type: 'rotate'}),\n\n translate = brd.create('transform', [\n function () {\n return Tx;\n },\n function () {\n return Ty;\n }\n ], {type: 'translate'}),\n\n // arc length via Simpson's rule.\n arclen = function (c, a, b) {\n var cpxa = Numerics.D(c.X)(a),\n cpya = Numerics.D(c.Y)(a),\n cpxb = Numerics.D(c.X)(b),\n cpyb = Numerics.D(c.Y)(b),\n cpxab = Numerics.D(c.X)((a + b) * 0.5),\n cpyab = Numerics.D(c.Y)((a + b) * 0.5),\n\n fa = Math.sqrt(cpxa * cpxa + cpya * cpya),\n fb = Math.sqrt(cpxb * cpxb + cpyb * cpyb),\n fab = Math.sqrt(cpxab * cpxab + cpyab * cpyab);\n\n return (fa + 4 * fab + fb) * (b - a) / 6;\n },\n\n exactDist = function (t) {\n return c1dist - arclen(c2, t2, t);\n },\n\n beta = Math.PI / 18,\n beta9 = beta * 9,\n interval = null;\n\n this.rolling = function () {\n var h, g, hp, gp, z;\n\n t1_new = t1 + direction * stepsize;\n\n // arc length between c1(t1) and c1(t1_new)\n c1dist = arclen(c1, t1, t1_new);\n\n // find t2_new such that arc length between c2(t2) and c1(t2_new) equals c1dist.\n t2_new = Numerics.root(exactDist, t2);\n\n // c1(t) as complex number\n h = new Complex(c1.X(t1_new), c1.Y(t1_new));\n\n // c2(t) as complex number\n g = new Complex(c2.X(t2_new), c2.Y(t2_new));\n\n hp = new Complex(Numerics.D(c1.X)(t1_new), Numerics.D(c1.Y)(t1_new));\n gp = new Complex(Numerics.D(c2.X)(t2_new), Numerics.D(c2.Y)(t2_new));\n\n // z is angle between the tangents of c1 at t1_new, and c2 at t2_new\n z = Complex.C.div(hp, gp);\n\n alpha = Math.atan2(z.imaginary, z.real);\n // Normalizing the quotient\n z.div(Complex.C.abs(z));\n z.mult(g);\n Tx = h.real - z.real;\n\n // T = h(t1_new)-g(t2_new)*h'(t1_new)/g'(t2_new);\n Ty = h.imaginary - z.imaginary;\n\n // -(10-90) degrees: make corners roll smoothly\n if (alpha < -beta && alpha > -beta9) {\n alpha = -beta;\n rotationLocal.applyOnce(pointlist);\n } else if (alpha > beta && alpha < beta9) {\n alpha = beta;\n rotationLocal.applyOnce(pointlist);\n } else {\n rotation.applyOnce(pointlist);\n translate.applyOnce(pointlist);\n t1 = t1_new;\n t2 = t2_new;\n }\n brd.update();\n };\n\n this.start = function () {\n if (time > 0) {\n interval = window.setInterval(this.rolling, time);\n }\n return this;\n };\n\n this.stop = function () {\n window.clearInterval(interval);\n return this;\n };\n return this;\n };\n return new Roulette();\n }\n });\n\n return JXG.Board;\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n/*global JXG: true, define: true, AMprocessNode: true, MathJax: true, document: true */\n/*jslint nomen: true, plusplus: true, newcap:true*/\n\n/* depends:\n jxg\n options\n renderer/abstract\n base/constants\n utils/type\n utils/env\n utils/color\n math/numerics\n*/\n\ndefine('renderer/svg',[\n 'jxg', 'options', 'renderer/abstract', 'base/constants', 'utils/type', 'utils/color', 'utils/base64', 'math/numerics'\n], function (JXG, Options, AbstractRenderer, Const, Type, Color, Base64, Numerics) {\n\n \"use strict\";\n\n /**\n * Uses SVG to implement the rendering methods defined in {@link JXG.AbstractRenderer}.\n * @class JXG.SVGRenderer\n * @augments JXG.AbstractRenderer\n * @param {Node} container Reference to a DOM node containing the board.\n * @param {Object} dim The dimensions of the board\n * @param {Number} dim.width\n * @param {Number} dim.height\n * @see JXG.AbstractRenderer\n */\n JXG.SVGRenderer = function (container, dim) {\n var i;\n\n // docstring in AbstractRenderer\n this.type = 'svg';\n\n this.isIE = navigator.appVersion.indexOf(\"MSIE\") !== -1 || navigator.userAgent.match(/Trident\\//);\n\n /**\n * SVG root node\n * @type Node\n */\n this.svgRoot = null;\n\n /**\n * The SVG Namespace used in JSXGraph.\n * @see http://www.w3.org/TR/SVG/\n * @type String\n * @default http://www.w3.org/2000/svg\n */\n this.svgNamespace = 'http://www.w3.org/2000/svg';\n\n /**\n * The xlink namespace. This is used for images.\n * @see http://www.w3.org/TR/xlink/\n * @type String\n * @default http://www.w3.org/1999/xlink\n */\n this.xlinkNamespace = 'http://www.w3.org/1999/xlink';\n\n // container is documented in AbstractRenderer\n this.container = container;\n\n // prepare the div container and the svg root node for use with JSXGraph\n this.container.style.MozUserSelect = 'none';\n this.container.style.userSelect = 'none';\n\n this.container.style.overflow = 'hidden';\n if (this.container.style.position === '') {\n this.container.style.position = 'relative';\n }\n\n this.svgRoot = this.container.ownerDocument.createElementNS(this.svgNamespace, \"svg\");\n this.svgRoot.style.overflow = 'hidden';\n this.svgRoot.style.display = 'block';\n\n this.resize(dim.width, dim.height);\n\n //this.svgRoot.setAttributeNS(null, 'shape-rendering', 'crispEdge'); //'optimizeQuality'); //geometricPrecision');\n\n this.container.appendChild(this.svgRoot);\n\n /**\n * The <tt>defs</tt> element is a container element to reference reusable SVG elements.\n * @type Node\n * @see http://www.w3.org/TR/SVG/struct.html#DefsElement\n */\n this.defs = this.container.ownerDocument.createElementNS(this.svgNamespace, 'defs');\n this.svgRoot.appendChild(this.defs);\n\n /**\n * Filters are used to apply shadows.\n * @type Node\n * @see http://www.w3.org/TR/SVG/filters.html#FilterElement\n */\n this.filter = this.container.ownerDocument.createElementNS(this.svgNamespace, 'filter');\n this.filter.setAttributeNS(null, 'id', this.container.id + '_' + 'f1');\n /*\n this.filter.setAttributeNS(null, 'x', '-100%');\n this.filter.setAttributeNS(null, 'y', '-100%');\n this.filter.setAttributeNS(null, 'width', '400%');\n this.filter.setAttributeNS(null, 'height', '400%');\n //this.filter.setAttributeNS(null, 'filterUnits', 'userSpaceOnUse');\n */\n this.filter.setAttributeNS(null, 'width', '300%');\n this.filter.setAttributeNS(null, 'height', '300%');\n this.filter.setAttributeNS(null, 'filterUnits', 'userSpaceOnUse');\n\n this.feOffset = this.container.ownerDocument.createElementNS(this.svgNamespace, 'feOffset');\n this.feOffset.setAttributeNS(null, 'result', 'offOut');\n this.feOffset.setAttributeNS(null, 'in', 'SourceAlpha');\n this.feOffset.setAttributeNS(null, 'dx', '5');\n this.feOffset.setAttributeNS(null, 'dy', '5');\n this.filter.appendChild(this.feOffset);\n\n this.feGaussianBlur = this.container.ownerDocument.createElementNS(this.svgNamespace, 'feGaussianBlur');\n this.feGaussianBlur.setAttributeNS(null, 'result', 'blurOut');\n this.feGaussianBlur.setAttributeNS(null, 'in', 'offOut');\n this.feGaussianBlur.setAttributeNS(null, 'stdDeviation', '3');\n this.filter.appendChild(this.feGaussianBlur);\n\n this.feBlend = this.container.ownerDocument.createElementNS(this.svgNamespace, 'feBlend');\n this.feBlend.setAttributeNS(null, 'in', 'SourceGraphic');\n this.feBlend.setAttributeNS(null, 'in2', 'blurOut');\n this.feBlend.setAttributeNS(null, 'mode', 'normal');\n this.filter.appendChild(this.feBlend);\n\n this.defs.appendChild(this.filter);\n\n /**\n * JSXGraph uses a layer system to sort the elements on the board. This puts certain types of elements in front\n * of other types of elements. For the order used see {@link JXG.Options.layer}. The number of layers is documented\n * there, too. The higher the number, the \"more on top\" are the elements on this layer.\n * @type Array\n */\n this.layer = [];\n for (i = 0; i < Options.layer.numlayers; i++) {\n this.layer[i] = this.container.ownerDocument.createElementNS(this.svgNamespace, 'g');\n this.svgRoot.appendChild(this.layer[i]);\n }\n\n // Already documented in JXG.AbstractRenderer\n this.supportsForeignObject = document.implementation.hasFeature(\"http://w3.org/TR/SVG11/feature#Extensibility\", \"1.1\");\n\n if (this.supportsForeignObject) {\n this.foreignObjLayer = this.container.ownerDocument.createElementNS(this.svgNamespace, 'foreignObject');\n this.foreignObjLayer.setAttribute(\"display\", \"none\");\n this.foreignObjLayer.setAttribute(\"x\", 0);\n this.foreignObjLayer.setAttribute(\"y\", 0);\n this.foreignObjLayer.setAttribute(\"width\", \"100%\");\n this.foreignObjLayer.setAttribute(\"height\", \"100%\");\n this.foreignObjLayer.setAttribute('id', this.container.id + '_foreignObj');\n this.svgRoot.appendChild(this.foreignObjLayer);\n }\n\n /**\n * Defines dash patterns. Defined styles are: <ol>\n * <li value=\"-1\"> 2px dash, 2px space</li>\n * <li> 5px dash, 5px space</li>\n * <li> 10px dash, 10px space</li>\n * <li> 20px dash, 20px space</li>\n * <li> 20px dash, 10px space, 10px dash, 10px dash</li>\n * <li> 20px dash, 5px space, 10px dash, 5px space</li></ol>\n * @type Array\n * @default ['2, 2', '5, 5', '10, 10', '20, 20', '20, 10, 10, 10', '20, 5, 10, 5']\n * @see http://www.w3.org/TR/SVG/painting.html#StrokeProperties\n */\n this.dashArray = ['2, 2', '5, 5', '10, 10', '20, 20', '20, 10, 10, 10', '20, 5, 10, 5'];\n };\n\n JXG.SVGRenderer.prototype = new AbstractRenderer();\n\n JXG.extend(JXG.SVGRenderer.prototype, /** @lends JXG.SVGRenderer.prototype */ {\n\n /**\n * Creates an arrow DOM node. Arrows are displayed in SVG with a <em>marker</em> tag.\n * @private\n * @param {JXG.GeometryElement} el A JSXGraph element, preferably one that can have an arrow attached.\n * @param {String} [idAppendix=''] A string that is added to the node's id.\n * @returns {Node} Reference to the node added to the DOM.\n */\n _createArrowHead: function (el, idAppendix, type) {\n var node2, node3,\n id = el.id + 'Triangle',\n //type = null,\n v, h;\n\n if (Type.exists(idAppendix)) {\n id += idAppendix;\n }\n node2 = this.createPrim('marker', id);\n\n node2.setAttributeNS(null, 'stroke', Type.evaluate(el.visProp.strokecolor));\n node2.setAttributeNS(null, 'stroke-opacity', Type.evaluate(el.visProp.strokeopacity));\n node2.setAttributeNS(null, 'fill', Type.evaluate(el.visProp.strokecolor));\n node2.setAttributeNS(null, 'fill-opacity', Type.evaluate(el.visProp.strokeopacity));\n node2.setAttributeNS(null, 'stroke-width', 0); // this is the stroke-width of the arrow head.\n // Should be zero to simplify the calculations\n\n node2.setAttributeNS(null, 'orient', 'auto');\n node2.setAttributeNS(null, 'markerUnits', 'strokeWidth'); // 'strokeWidth' 'userSpaceOnUse');\n\n /*\n Types 1, 2:\n The arrow head is an isosceles triangle with base length 10 and height 10.\n\n Type 3:\n A rectangle\n\n Types 4, 5, 6:\n Defined by Bezier curves from mp_arrowheads.html\n\n In any case but type 3 the arrow head is 10 units long,\n type 3 is 10 unitsb high.\n These 10 units are scaled to strokeWidth * arrowSize pixels, see\n this._setArrowWidth().\n\n See also abstractRenderer.updateLine() where the line path is shortened accordingly.\n\n Changes here are also necessary in setArrowWidth().\n\n So far, lines with arrow heads are shortenend to avoid overlapping of\n arrow head and line. This is not the case for curves, yet.\n Therefore, the offset refX has to be adapted to the path type.\n */\n node3 = this.container.ownerDocument.createElementNS(this.svgNamespace, 'path');\n h = 5;\n if (idAppendix === 'End') {\n // First arrow\n //type = a.typeFirst;\n // if (JXG.exists(ev_fa.type)) {\n // type = Type.evaluate(ev_fa.type);\n // }\n\n v = 0;\n if (type === 2) {\n node3.setAttributeNS(null, 'd', 'M 10,0 L 0,5 L 10,10 L 5,5 z');\n } else if (type === 3) {\n node3.setAttributeNS(null, 'd', 'M 0,0 L 3.33,0 L 3.33,10 L 0,10 z');\n } else if (type === 4) {\n // insetRatio:0.8 tipAngle:45 wingCurve:15 tailCurve:0\n h = 3.31;\n node3.setAttributeNS(null, 'd', 'M 0.00,3.31 C 3.53,3.84 7.13,4.50 10.00,6.63 C 9.33,5.52 8.67,4.42 8.00,3.31 C 8.67,2.21 9.33,1.10 10.00,0.00 C 7.13,2.13 3.53,2.79 0.00,3.31');\n } else if (type === 5) {\n // insetRatio:0.9 tipAngle:40 wingCurve:5 tailCurve:15\n h = 3.28;\n node3.setAttributeNS(null, 'd', 'M 0.00,3.28 C 3.39,4.19 6.81,5.07 10.00,6.55 C 9.38,5.56 9.00,4.44 9.00,3.28 C 9.00,2.11 9.38,0.99 10.00,0.00 C 6.81,1.49 3.39,2.37 0.00,3.28');\n } else if (type === 6) {\n // insetRatio:0.9 tipAngle:35 wingCurve:5 tailCurve:0\n h = 2.84;\n node3.setAttributeNS(null, 'd', 'M 0.00,2.84 C 3.39,3.59 6.79,4.35 10.00,5.68 C 9.67,4.73 9.33,3.78 9.00,2.84 C 9.33,1.89 9.67,0.95 10.00,0.00 C 6.79,1.33 3.39,2.09 0.00,2.84');\n } else if (type === 7) {\n // insetRatio:0.9 tipAngle:60 wingCurve:30 tailCurve:0\n h = 5.20;\n node3.setAttributeNS(null, 'd', 'M 0.00,5.20 C 4.04,5.20 7.99,6.92 10.00,10.39 M 10.00,0.00 C 7.99,3.47 4.04,5.20 0.00,5.20');\n } else {\n // type == 1 or > 6\n node3.setAttributeNS(null, 'd', 'M 10,0 L 0,5 L 10,10 z');\n }\n if (/*!Type.exists(el.rendNode.getTotalLength) && */el.elementClass === Const.OBJECT_CLASS_LINE) {\n if (type === 2) {\n v = 4.9;\n } else if (type === 3) {\n v = 3.3;\n } else if (type === 4 || type === 5 || type === 6) {\n v = 6.66;\n } else if (type === 7) {\n v = 0.0;\n } else {\n v = 10.0;\n }\n }\n } else {\n // Last arrow\n // if (JXG.exists(ev_la.type)) {\n // type = Type.evaluate(ev_la.type);\n // }\n //type = a.typeLast;\n\n v = 10.0;\n if (type === 2) {\n node3.setAttributeNS(null, 'd', 'M 0,0 L 10,5 L 0,10 L 5,5 z');\n } else if (type === 3) {\n v = 3.3;\n node3.setAttributeNS(null, 'd', 'M 0,0 L 3.33,0 L 3.33,10 L 0,10 z');\n } else if (type === 4) {\n // insetRatio:0.8 tipAngle:45 wingCurve:15 tailCurve:0\n h = 3.31;\n node3.setAttributeNS(null, 'd', 'M 10.00,3.31 C 6.47,3.84 2.87,4.50 0.00,6.63 C 0.67,5.52 1.33,4.42 2.00,3.31 C 1.33,2.21 0.67,1.10 0.00,0.00 C 2.87,2.13 6.47,2.79 10.00,3.31');\n } else if (type === 5) {\n // insetRatio:0.9 tipAngle:40 wingCurve:5 tailCurve:15\n h = 3.28;\n node3.setAttributeNS(null, 'd', 'M 10.00,3.28 C 6.61,4.19 3.19,5.07 0.00,6.55 C 0.62,5.56 1.00,4.44 1.00,3.28 C 1.00,2.11 0.62,0.99 0.00,0.00 C 3.19,1.49 6.61,2.37 10.00,3.28');\n } else if (type === 6) {\n // insetRatio:0.9 tipAngle:35 wingCurve:5 tailCurve:0\n h = 2.84;\n node3.setAttributeNS(null, 'd', 'M 10.00,2.84 C 6.61,3.59 3.21,4.35 0.00,5.68 C 0.33,4.73 0.67,3.78 1.00,2.84 C 0.67,1.89 0.33,0.95 0.00,0.00 C 3.21,1.33 6.61,2.09 10.00,2.84');\n } else if (type === 7) {\n // insetRatio:0.9 tipAngle:60 wingCurve:30 tailCurve:0\n h = 5.20;\n node3.setAttributeNS(null, 'd', 'M 10.00,5.20 C 5.96,5.20 2.01,6.92 0.00,10.39 M 0.00,0.00 C 2.01,3.47 5.96,5.20 10.00,5.20');\n } else {\n // type == 1 or > 6\n node3.setAttributeNS(null, 'd', 'M 0,0 L 10,5 L 0,10 z');\n }\n if (/*!Type.exists(el.rendNode.getTotalLength) &&*/ el.elementClass === Const.OBJECT_CLASS_LINE) {\n if (type === 2) {\n v = 5.1;\n } else if (type === 3) {\n v = 0.02;\n } else if (type === 4 || type === 5 || type === 6) {\n v = 3.33;\n } else if (type === 7) {\n v = 10.0;\n } else {\n v = 0.05;\n }\n }\n }\n if (type === 7) {\n node2.setAttributeNS(null, 'fill', 'none');\n node2.setAttributeNS(null, 'stroke-width', 1); // this is the stroke-width of the arrow head.\n }\n node2.setAttributeNS(null, 'refY', h);\n node2.setAttributeNS(null, 'refX', v);\n\n node2.appendChild(node3);\n return node2;\n },\n\n /**\n * Updates color of an arrow DOM node.\n * @param {Node} node The arrow node.\n * @param {String} color Color value in a HTML compatible format, e.g. <tt>#00ff00</tt> or <tt>green</tt> for green.\n * @param {Number} opacity\n * @param {JXG.GeometryElement} el The element the arrows are to be attached to\n */\n _setArrowColor: function (node, color, opacity, el, type) {\n if (node) {\n if (Type.isString(color)) {\n if (type !== 7) {\n this._setAttribute(function () {\n node.setAttributeNS(null, 'stroke', color);\n node.setAttributeNS(null, 'fill', color);\n node.setAttributeNS(null, 'stroke-opacity', opacity);\n node.setAttributeNS(null, 'fill-opacity', opacity);\n }, el.visPropOld.fillcolor);\n } else {\n this._setAttribute(function () {\n node.setAttributeNS(null, 'fill', 'none');\n node.setAttributeNS(null, 'stroke', color);\n node.setAttributeNS(null, 'stroke-opacity', opacity);\n }, el.visPropOld.fillcolor);\n }\n }\n\n if (this.isIE) {\n el.rendNode.parentNode.insertBefore(el.rendNode, el.rendNode);\n }\n }\n\n },\n\n // Already documented in JXG.AbstractRenderer\n _setArrowWidth: function (node, width, parentNode, size) {\n var s, d;\n\n if (node) {\n // if (width === 0) {\n // // display:none does not work well in webkit\n // node.setAttributeNS(null, 'display', 'none');\n // } else {\n s = width;\n d = s * size;\n node.setAttributeNS(null, 'viewBox', (0) + ' ' + (0) + ' ' + (s * 10) + ' ' + (s * 10));\n node.setAttributeNS(null, 'markerHeight', d);\n node.setAttributeNS(null, 'markerWidth', d);\n node.setAttributeNS(null, 'display', 'inherit');\n // }\n\n if (this.isIE) {\n parentNode.parentNode.insertBefore(parentNode, parentNode);\n }\n }\n },\n\n /* ******************************** *\n * This renderer does not need to\n * override draw/update* methods\n * since it provides draw/update*Prim\n * methods except for some cases like\n * internal texts or images.\n * ******************************** */\n\n /* **************************\n * Lines\n * **************************/\n\n // documented in AbstractRenderer\n updateTicks: function (ticks) {\n var i, j, c, node, x, y,\n tickStr = '',\n len = ticks.ticks.length,\n len2, str,\n isReal = true;\n\n for (i = 0; i < len; i++) {\n c = ticks.ticks[i];\n x = c[0];\n y = c[1];\n\n len2 = x.length;\n str = ' M ' + x[0] + ' ' + y[0];\n if (!Type.isNumber(x[0])) {\n isReal = false;\n }\n for (j = 1; isReal && j < len2; ++j) {\n if (Type.isNumber(x[j])) {\n str += ' L ' + x[j] + ' ' + y[j];\n } else {\n isReal = false;\n }\n\n }\n if (isReal) {\n tickStr += str;\n }\n }\n\n node = ticks.rendNode;\n\n if (!Type.exists(node)) {\n node = this.createPrim('path', ticks.id);\n this.appendChildPrim(node, Type.evaluate(ticks.visProp.layer));\n ticks.rendNode = node;\n }\n\n node.setAttributeNS(null, 'stroke', Type.evaluate(ticks.visProp.strokecolor));\n node.setAttributeNS(null, 'fill', 'none');\n // node.setAttributeNS(null, 'fill', Type.evaluate(ticks.visProp.fillcolor));\n // node.setAttributeNS(null, 'fill-opacity', Type.evaluate(ticks.visProp.fillopacity));\n node.setAttributeNS(null, 'stroke-opacity', Type.evaluate(ticks.visProp.strokeopacity));\n node.setAttributeNS(null, 'stroke-width', Type.evaluate(ticks.visProp.strokewidth));\n this.updatePathPrim(node, tickStr, ticks.board);\n },\n\n /* **************************\n * Text related stuff\n * **************************/\n\n // Already documented in JXG.AbstractRenderer\n displayCopyright: function (str, fontsize) {\n var node = this.createPrim('text', 'licenseText'),\n t;\n node.setAttributeNS(null, 'x', '20px');\n node.setAttributeNS(null, 'y', (2 + fontsize) + 'px');\n node.setAttributeNS(null, \"style\", \"font-family:Arial,Helvetica,sans-serif; font-size:\" + fontsize + \"px; fill:#356AA0; opacity:0.3;\");\n t = this.container.ownerDocument.createTextNode(str);\n node.appendChild(t);\n this.appendChildPrim(node, 0);\n },\n\n // Already documented in JXG.AbstractRenderer\n drawInternalText: function (el) {\n var node = this.createPrim('text', el.id);\n\n //node.setAttributeNS(null, \"style\", \"alignment-baseline:middle\"); // Not yet supported by Firefox\n // Preserve spaces\n //node.setAttributeNS(\"http://www.w3.org/XML/1998/namespace\", \"space\", \"preserve\");\n node.style.whiteSpace = 'nowrap';\n\n el.rendNodeText = this.container.ownerDocument.createTextNode('');\n node.appendChild(el.rendNodeText);\n this.appendChildPrim(node, Type.evaluate(el.visProp.layer));\n\n return node;\n },\n\n // Already documented in JXG.AbstractRenderer\n updateInternalText: function (el) {\n var content = el.plaintext, v,\n ev_ax = el.getAnchorX(),\n ev_ay = el.getAnchorY();\n\n if (el.rendNode.getAttributeNS(null, \"class\") !== el.visProp.cssclass) {\n el.rendNode.setAttributeNS(null, \"class\", Type.evaluate(el.visProp.cssclass));\n el.needsSizeUpdate = true;\n }\n\n if (!isNaN(el.coords.scrCoords[1] + el.coords.scrCoords[2])) {\n // Horizontal\n v = el.coords.scrCoords[1];\n if (el.visPropOld.left !== (ev_ax + v)) {\n el.rendNode.setAttributeNS(null, 'x', v + 'px');\n\n if (ev_ax === 'left') {\n el.rendNode.setAttributeNS(null, 'text-anchor', 'start');\n } else if (ev_ax === 'right') {\n el.rendNode.setAttributeNS(null, 'text-anchor', 'end');\n } else if (ev_ax === 'middle') {\n el.rendNode.setAttributeNS(null, 'text-anchor', 'middle');\n }\n el.visPropOld.left = ev_ax + v;\n }\n\n // Vertical\n v = el.coords.scrCoords[2];\n if (el.visPropOld.top !== (ev_ay + v)) {\n el.rendNode.setAttributeNS(null, 'y', (v + this.vOffsetText * 0.5) + 'px');\n\n if (ev_ay === 'bottom') {\n el.rendNode.setAttributeNS(null, 'dominant-baseline', 'text-after-edge');\n } else if (ev_ay === 'top') {\n el.rendNode.setAttributeNS(null, 'dy', '1.6ex');\n //el.rendNode.setAttributeNS(null, 'dominant-baseline', 'text-before-edge'); // Not supported by IE, edge\n } else if (ev_ay === 'middle') {\n //el.rendNode.setAttributeNS(null, 'dominant-baseline', 'middle');\n el.rendNode.setAttributeNS(null, 'dy', '0.6ex');\n }\n el.visPropOld.top = ev_ay + v;\n }\n }\n if (el.htmlStr !== content) {\n el.rendNodeText.data = content;\n el.htmlStr = content;\n }\n this.transformImage(el, el.transformations);\n },\n\n /**\n * Set color and opacity of internal texts.\n * SVG needs its own version.\n * @private\n * @see JXG.AbstractRenderer#updateTextStyle\n * @see JXG.AbstractRenderer#updateInternalTextStyle\n */\n updateInternalTextStyle: function (el, strokeColor, strokeOpacity, duration) {\n this.setObjectFillColor(el, strokeColor, strokeOpacity);\n },\n\n /* **************************\n * Image related stuff\n * **************************/\n\n // Already documented in JXG.AbstractRenderer\n drawImage: function (el) {\n var node = this.createPrim('image', el.id);\n\n node.setAttributeNS(null, 'preserveAspectRatio', 'none');\n this.appendChildPrim(node, Type.evaluate(el.visProp.layer));\n el.rendNode = node;\n\n this.updateImage(el);\n },\n\n // Already documented in JXG.AbstractRenderer\n transformImage: function (el, t) {\n var s, m,\n node = el.rendNode,\n str = \"\",\n len = t.length;\n\n if (len > 0) {\n m = this.joinTransforms(el, t);\n s = [m[1][1], m[2][1], m[1][2], m[2][2], m[1][0], m[2][0]].join(',');\n str += ' matrix(' + s + ') ';\n node.setAttributeNS(null, 'transform', str);\n }\n },\n\n // Already documented in JXG.AbstractRenderer\n updateImageURL: function (el) {\n var url = Type.evaluate(el.url);\n\n if (el._src !== url) {\n el.imgIsLoaded = false;\n el.rendNode.setAttributeNS(this.xlinkNamespace, 'xlink:href', url);\n el._src = url;\n\n return true;\n }\n\n return false;\n },\n\n // Already documented in JXG.AbstractRenderer\n updateImageStyle: function (el, doHighlight) {\n var css = Type.evaluate(doHighlight ? el.visProp.highlightcssclass : el.visProp.cssclass);\n\n el.rendNode.setAttributeNS(null, 'class', css);\n },\n\n // Already documented in JXG.AbstractRenderer\n drawForeignObject: function (el) {\n el.rendNode = this.appendChildPrim(this.createPrim('foreignObject', el.id),\n Type.evaluate(el.visProp.layer));\n\n this.appendNodesToElement(el, 'foreignObject');\n this.updateForeignObject(el);\n },\n\n // Already documented in JXG.AbstractRenderer\n updateForeignObject: function(el) {\n if (el._useUserSize) {\n el.rendNode.style.overflow = 'hidden';\n } else {\n el.rendNode.style.overflow = 'visible';\n }\n\n this.updateRectPrim(el.rendNode, el.coords.scrCoords[1],\n el.coords.scrCoords[2] - el.size[1], el.size[0], el.size[1]);\n\n el.rendNode.innerHTML = el.content;\n this._updateVisual(el, {stroke: true, dash: true}, true);\n },\n\n /* **************************\n * Render primitive objects\n * **************************/\n\n // Already documented in JXG.AbstractRenderer\n appendChildPrim: function (node, level) {\n if (!Type.exists(level)) { // trace nodes have level not set\n level = 0;\n } else if (level >= Options.layer.numlayers) {\n level = Options.layer.numlayers - 1;\n }\n\n this.layer[level].appendChild(node);\n\n return node;\n },\n\n // Already documented in JXG.AbstractRenderer\n createPrim: function (type, id) {\n var node = this.container.ownerDocument.createElementNS(this.svgNamespace, type);\n node.setAttributeNS(null, 'id', this.container.id + '_' + id);\n node.style.position = 'absolute';\n if (type === 'path') {\n node.setAttributeNS(null, 'stroke-linecap', 'round');\n node.setAttributeNS(null, 'stroke-linejoin', 'round');\n node.setAttributeNS(null, 'fill-rule', 'evenodd');\n }\n return node;\n },\n\n // Already documented in JXG.AbstractRenderer\n remove: function (shape) {\n if (Type.exists(shape) && Type.exists(shape.parentNode)) {\n shape.parentNode.removeChild(shape);\n }\n },\n\n // Already documented in JXG.AbstractRenderer\n setLayer: function (el, level) {\n if (!Type.exists(level)) {\n level = 0;\n } else if (level >= Options.layer.numlayers) {\n level = Options.layer.numlayers - 1;\n }\n\n this.layer[level].appendChild(el.rendNode);\n },\n\n // Already documented in JXG.AbstractRenderer\n makeArrows: function (el, a) {\n var node2,\n ev_fa = a.evFirst,\n ev_la = a.evLast;\n\n // Test if the arrow heads already exist\n if (el.visPropOld.firstarrow === ev_fa &&\n el.visPropOld.lastarrow === ev_la) {\n if (this.isIE && el.visPropCalc.visible &&\n (ev_fa || ev_la)) {\n el.rendNode.parentNode.insertBefore(el.rendNode, el.rendNode);\n }\n return;\n }\n\n if (ev_fa) {\n node2 = el.rendNodeTriangleStart;\n if (!Type.exists(node2)) {\n node2 = this._createArrowHead(el, 'End', a.typeFirst);\n this.defs.appendChild(node2);\n el.rendNodeTriangleStart = node2;\n el.rendNode.setAttributeNS(null, 'marker-start', 'url(#' + this.container.id + '_' + el.id + 'TriangleEnd)');\n } else {\n this.defs.appendChild(node2);\n }\n } else {\n node2 = el.rendNodeTriangleStart;\n if (Type.exists(node2)) {\n this.remove(node2);\n }\n }\n if (ev_la) {\n node2 = el.rendNodeTriangleEnd;\n if (!Type.exists(node2)) {\n node2 = this._createArrowHead(el, 'Start', a.typeLast);\n this.defs.appendChild(node2);\n el.rendNodeTriangleEnd = node2;\n el.rendNode.setAttributeNS(null, 'marker-end', 'url(#' + this.container.id + '_' + el.id + 'TriangleStart)');\n } else {\n this.defs.appendChild(node2);\n }\n } else {\n node2 = el.rendNodeTriangleEnd;\n if (Type.exists(node2)) {\n this.remove(node2);\n }\n }\n el.visPropOld.firstarrow = ev_fa;\n el.visPropOld.lastarrow = ev_la;\n },\n\n // Already documented in JXG.AbstractRenderer\n updateEllipsePrim: function (node, x, y, rx, ry) {\n var huge = 1000000;\n\n huge = 200000; // IE\n // webkit does not like huge values if the object is dashed\n // iE doesn't like huge values above 216000\n x = Math.abs(x) < huge ? x : huge * x / Math.abs(x);\n y = Math.abs(y) < huge ? y : huge * y / Math.abs(y);\n rx = Math.abs(rx) < huge ? rx : huge * rx / Math.abs(rx);\n ry = Math.abs(ry) < huge ? ry : huge * ry / Math.abs(ry);\n\n node.setAttributeNS(null, 'cx', x);\n node.setAttributeNS(null, 'cy', y);\n node.setAttributeNS(null, 'rx', Math.abs(rx));\n node.setAttributeNS(null, 'ry', Math.abs(ry));\n },\n\n // Already documented in JXG.AbstractRenderer\n updateLinePrim: function (node, p1x, p1y, p2x, p2y) {\n var huge = 1000000;\n\n huge = 200000; //IE\n if (!isNaN(p1x + p1y + p2x + p2y)) {\n // webkit does not like huge values if the object is dashed\n // IE doesn't like huge values above 216000\n p1x = Math.abs(p1x) < huge ? p1x : huge * p1x / Math.abs(p1x);\n p1y = Math.abs(p1y) < huge ? p1y : huge * p1y / Math.abs(p1y);\n p2x = Math.abs(p2x) < huge ? p2x : huge * p2x / Math.abs(p2x);\n p2y = Math.abs(p2y) < huge ? p2y : huge * p2y / Math.abs(p2y);\n\n node.setAttributeNS(null, 'x1', p1x);\n node.setAttributeNS(null, 'y1', p1y);\n node.setAttributeNS(null, 'x2', p2x);\n node.setAttributeNS(null, 'y2', p2y);\n }\n },\n\n // Already documented in JXG.AbstractRenderer\n updatePathPrim: function (node, pointString) {\n if (pointString === '') {\n pointString = 'M 0 0';\n }\n node.setAttributeNS(null, 'd', pointString);\n },\n\n // Already documented in JXG.AbstractRenderer\n updatePathStringPoint: function (el, size, type) {\n var s = '',\n scr = el.coords.scrCoords,\n sqrt32 = size * Math.sqrt(3) * 0.5,\n s05 = size * 0.5;\n\n if (type === 'x') {\n s = ' M ' + (scr[1] - size) + ' ' + (scr[2] - size) +\n ' L ' + (scr[1] + size) + ' ' + (scr[2] + size) +\n ' M ' + (scr[1] + size) + ' ' + (scr[2] - size) +\n ' L ' + (scr[1] - size) + ' ' + (scr[2] + size);\n } else if (type === '+') {\n s = ' M ' + (scr[1] - size) + ' ' + (scr[2]) +\n ' L ' + (scr[1] + size) + ' ' + (scr[2]) +\n ' M ' + (scr[1]) + ' ' + (scr[2] - size) +\n ' L ' + (scr[1]) + ' ' + (scr[2] + size);\n } else if (type === '<>') {\n s = ' M ' + (scr[1] - size) + ' ' + (scr[2]) +\n ' L ' + (scr[1]) + ' ' + (scr[2] + size) +\n ' L ' + (scr[1] + size) + ' ' + (scr[2]) +\n ' L ' + (scr[1]) + ' ' + (scr[2] - size) + ' Z ';\n } else if (type === '^') {\n s = ' M ' + (scr[1]) + ' ' + (scr[2] - size) +\n ' L ' + (scr[1] - sqrt32) + ' ' + (scr[2] + s05) +\n ' L ' + (scr[1] + sqrt32) + ' ' + (scr[2] + s05) +\n ' Z '; // close path\n } else if (type === 'v') {\n s = ' M ' + (scr[1]) + ' ' + (scr[2] + size) +\n ' L ' + (scr[1] - sqrt32) + ' ' + (scr[2] - s05) +\n ' L ' + (scr[1] + sqrt32) + ' ' + (scr[2] - s05) +\n ' Z ';\n } else if (type === '>') {\n s = ' M ' + (scr[1] + size) + ' ' + (scr[2]) +\n ' L ' + (scr[1] - s05) + ' ' + (scr[2] - sqrt32) +\n ' L ' + (scr[1] - s05) + ' ' + (scr[2] + sqrt32) +\n ' Z ';\n } else if (type === '<') {\n s = ' M ' + (scr[1] - size) + ' ' + (scr[2]) +\n ' L ' + (scr[1] + s05) + ' ' + (scr[2] - sqrt32) +\n ' L ' + (scr[1] + s05) + ' ' + (scr[2] + sqrt32) +\n ' Z ';\n }\n return s;\n },\n\n // Already documented in JXG.AbstractRenderer\n updatePathStringPrim: function (el) {\n var i, scr, len,\n symbm = ' M ',\n symbl = ' L ',\n symbc = ' C ',\n nextSymb = symbm,\n maxSize = 5000.0,\n pStr = '';\n\n if (el.numberPoints <= 0) {\n return '';\n }\n\n len = Math.min(el.points.length, el.numberPoints);\n\n if (el.bezierDegree === 1) {\n for (i = 0; i < len; i++) {\n scr = el.points[i].scrCoords;\n if (isNaN(scr[1]) || isNaN(scr[2])) { // PenUp\n nextSymb = symbm;\n } else {\n // Chrome has problems with values being too far away.\n scr[1] = Math.max(Math.min(scr[1], maxSize), -maxSize);\n scr[2] = Math.max(Math.min(scr[2], maxSize), -maxSize);\n\n // Attention: first coordinate may be inaccurate if far way\n //pStr += [nextSymb, scr[1], ' ', scr[2]].join('');\n pStr += nextSymb + scr[1] + ' ' + scr[2]; // Seems to be faster now (webkit and firefox)\n nextSymb = symbl;\n }\n }\n } else if (el.bezierDegree === 3) {\n i = 0;\n while (i < len) {\n scr = el.points[i].scrCoords;\n if (isNaN(scr[1]) || isNaN(scr[2])) { // PenUp\n nextSymb = symbm;\n } else {\n pStr += nextSymb + scr[1] + ' ' + scr[2];\n if (nextSymb === symbc) {\n i += 1;\n scr = el.points[i].scrCoords;\n pStr += ' ' + scr[1] + ' ' + scr[2];\n i += 1;\n scr = el.points[i].scrCoords;\n pStr += ' ' + scr[1] + ' ' + scr[2];\n }\n nextSymb = symbc;\n }\n i += 1;\n }\n }\n return pStr;\n },\n\n // Already documented in JXG.AbstractRenderer\n updatePathStringBezierPrim: function (el) {\n var i, j, k, scr, lx, ly, len,\n symbm = ' M ',\n symbl = ' C ',\n nextSymb = symbm,\n maxSize = 5000.0,\n pStr = '',\n f = Type.evaluate(el.visProp.strokewidth),\n isNoPlot = (Type.evaluate(el.visProp.curvetype) !== 'plot');\n\n if (el.numberPoints <= 0) {\n return '';\n }\n\n if (isNoPlot && el.board.options.curve.RDPsmoothing) {\n el.points = Numerics.RamerDouglasPeucker(el.points, 0.5);\n }\n\n len = Math.min(el.points.length, el.numberPoints);\n for (j = 1; j < 3; j++) {\n nextSymb = symbm;\n for (i = 0; i < len; i++) {\n scr = el.points[i].scrCoords;\n\n if (isNaN(scr[1]) || isNaN(scr[2])) { // PenUp\n nextSymb = symbm;\n } else {\n // Chrome has problems with values being too far away.\n scr[1] = Math.max(Math.min(scr[1], maxSize), -maxSize);\n scr[2] = Math.max(Math.min(scr[2], maxSize), -maxSize);\n\n // Attention: first coordinate may be inaccurate if far way\n if (nextSymb === symbm) {\n //pStr += [nextSymb, scr[1], ' ', scr[2]].join('');\n pStr += nextSymb + scr[1] + ' ' + scr[2]; // Seems to be faster now (webkit and firefox)\n } else {\n k = 2 * j;\n pStr += [nextSymb,\n (lx + (scr[1] - lx) * 0.333 + f * (k * Math.random() - j)), ' ',\n (ly + (scr[2] - ly) * 0.333 + f * (k * Math.random() - j)), ' ',\n (lx + (scr[1] - lx) * 0.666 + f * (k * Math.random() - j)), ' ',\n (ly + (scr[2] - ly) * 0.666 + f * (k * Math.random() - j)), ' ',\n scr[1], ' ', scr[2]].join('');\n }\n\n nextSymb = symbl;\n lx = scr[1];\n ly = scr[2];\n }\n }\n }\n return pStr;\n },\n\n // Already documented in JXG.AbstractRenderer\n updatePolygonPrim: function (node, el) {\n var i,\n pStr = '',\n scrCoords,\n len = el.vertices.length;\n\n node.setAttributeNS(null, 'stroke', 'none');\n if (el.elType === 'polygonalchain') {\n len++;\n }\n\n for (i = 0; i < len - 1; i++) {\n if (el.vertices[i].isReal) {\n scrCoords = el.vertices[i].coords.scrCoords;\n pStr = pStr + scrCoords[1] + \",\" + scrCoords[2];\n } else {\n node.setAttributeNS(null, 'points', '');\n return;\n }\n\n if (i < len - 2) {\n pStr += \" \";\n }\n }\n if (pStr.indexOf('NaN') === -1) {\n node.setAttributeNS(null, 'points', pStr);\n }\n },\n\n // Already documented in JXG.AbstractRenderer\n updateRectPrim: function (node, x, y, w, h) {\n node.setAttributeNS(null, 'x', x);\n node.setAttributeNS(null, 'y', y);\n node.setAttributeNS(null, 'width', w);\n node.setAttributeNS(null, 'height', h);\n },\n\n /* **************************\n * Set Attributes\n * **************************/\n\n // documented in JXG.AbstractRenderer\n setPropertyPrim: function (node, key, val) {\n if (key === 'stroked') {\n return;\n }\n node.setAttributeNS(null, key, val);\n },\n\n display: function (el, val) {\n var node;\n\n if (el && el.rendNode) {\n el.visPropOld.visible = val;\n node = el.rendNode;\n if (val) {\n node.setAttributeNS(null, 'display', 'inline');\n node.style.visibility = \"inherit\";\n } else {\n node.setAttributeNS(null, 'display', 'none');\n node.style.visibility = \"hidden\";\n }\n }\n },\n\n // documented in JXG.AbstractRenderer\n show: function (el) {\n JXG.deprecated('Board.renderer.show()', 'Board.renderer.display()');\n this.display(el, true);\n // var node;\n //\n // if (el && el.rendNode) {\n // node = el.rendNode;\n // node.setAttributeNS(null, 'display', 'inline');\n // node.style.visibility = \"inherit\";\n // }\n },\n\n // documented in JXG.AbstractRenderer\n hide: function (el) {\n JXG.deprecated('Board.renderer.hide()', 'Board.renderer.display()');\n this.display(el, false);\n // var node;\n //\n // if (el && el.rendNode) {\n // node = el.rendNode;\n // node.setAttributeNS(null, 'display', 'none');\n // node.style.visibility = \"hidden\";\n // }\n },\n\n // documented in JXG.AbstractRenderer\n setBuffering: function (el, type) {\n el.rendNode.setAttribute('buffered-rendering', type);\n },\n\n // documented in JXG.AbstractRenderer\n setDashStyle: function (el) {\n var dashStyle = Type.evaluate(el.visProp.dash),\n node = el.rendNode;\n\n if (dashStyle > 0) {\n node.setAttributeNS(null, 'stroke-dasharray', this.dashArray[dashStyle - 1]);\n } else {\n if (node.hasAttributeNS(null, 'stroke-dasharray')) {\n node.removeAttributeNS(null, 'stroke-dasharray');\n }\n }\n },\n\n // documented in JXG.AbstractRenderer\n setGradient: function (el) {\n var fillNode = el.rendNode,\n node, node2, node3,\n ev_g = Type.evaluate(el.visProp.gradient);\n\n if (ev_g === 'linear' || ev_g === 'radial') {\n node = this.createPrim(ev_g + 'Gradient', el.id + '_gradient');\n node2 = this.createPrim('stop', el.id + '_gradient1');\n node3 = this.createPrim('stop', el.id + '_gradient2');\n node.appendChild(node2);\n node.appendChild(node3);\n this.defs.appendChild(node);\n fillNode.setAttributeNS(null, 'style', 'fill:url(#' + this.container.id + '_' + el.id + '_gradient)');\n el.gradNode1 = node2;\n el.gradNode2 = node3;\n el.gradNode = node;\n } else {\n fillNode.removeAttributeNS(null, 'style');\n }\n },\n\n /**\n * Set the gradient angle for linear color gradients.\n *\n * @private\n * @param {SVGnode} node SVG gradient node of an arbitrary JSXGraph element.\n * @param {Number} radians angle value in radians. 0 is horizontal from left to right, Pi/4 is vertical from top to bottom.\n */\n updateGradientAngle: function(node, radians) {\n // Angles:\n // 0: ->\n // 90: down\n // 180: <-\n // 90: up\n var f = 1.0,\n co = Math.cos(radians),\n si = Math.sin(radians);\n\n if (Math.abs(co) > Math.abs(si)) {\n f /= Math.abs(co);\n } else {\n f /= Math.abs(si);\n }\n\n if (co >= 0) {\n node.setAttributeNS(null, 'x1', 0);\n node.setAttributeNS(null, 'x2', co * f);\n } else {\n node.setAttributeNS(null, 'x1', -co * f);\n node.setAttributeNS(null, 'x2', 0);\n }\n if (si >= 0) {\n node.setAttributeNS(null, 'y1', 0);\n node.setAttributeNS(null, 'y2', si * f);\n } else {\n node.setAttributeNS(null, 'y1', -si * f);\n node.setAttributeNS(null, 'y2', 0);\n }\n },\n\n /**\n * Set circles for radial color gradients.\n *\n * @private\n * @param {SVGnode} node SVG gradient node\n * @param {Number} cx SVG value cx (value between 0 and 1)\n * @param {Number} cy SVG value cy (value between 0 and 1)\n * @param {Number} r SVG value r (value between 0 and 1)\n * @param {Number} fx SVG value fx (value between 0 and 1)\n * @param {Number} fy SVG value fy (value between 0 and 1)\n * @param {Number} fr SVG value fr (value between 0 and 1)\n */\n updateGradientCircle: function(node, cx, cy, r, fx, fy, fr) {\n node.setAttributeNS(null, 'cx', cx * 100 + '%'); // Center first color\n node.setAttributeNS(null, 'cy', cy * 100 + '%');\n node.setAttributeNS(null, 'r', r * 100 + '%');\n node.setAttributeNS(null, 'fx', fx * 100 + '%'); // Center second color / focal point\n node.setAttributeNS(null, 'fy', fy * 100 + '%');\n node.setAttributeNS(null, 'fr', fr * 100 + '%');\n },\n\n // documented in JXG.AbstractRenderer\n updateGradient: function (el) {\n var col, op,\n node2 = el.gradNode1,\n node3 = el.gradNode2,\n ev_g = Type.evaluate(el.visProp.gradient);\n\n if (!Type.exists(node2) || !Type.exists(node3)) {\n return;\n }\n\n op = Type.evaluate(el.visProp.fillopacity);\n op = (op > 0) ? op : 0;\n col = Type.evaluate(el.visProp.fillcolor);\n\n node2.setAttributeNS(null, 'style', 'stop-color:' + col + ';stop-opacity:' + op);\n node3.setAttributeNS(null, 'style',\n 'stop-color:' + Type.evaluate(el.visProp.gradientsecondcolor) +\n ';stop-opacity:' + Type.evaluate(el.visProp.gradientsecondopacity)\n );\n node2.setAttributeNS(null, 'offset', Type.evaluate(el.visProp.gradientstartoffset) * 100 + '%');\n node3.setAttributeNS(null, 'offset', Type.evaluate(el.visProp.gradientendoffset) * 100 + '%');\n if (ev_g === 'linear') {\n this.updateGradientAngle(el.gradNode, Type.evaluate(el.visProp.gradientangle));\n } else if (ev_g === 'radial') {\n this.updateGradientCircle(el.gradNode,\n Type.evaluate(el.visProp.gradientcx),\n Type.evaluate(el.visProp.gradientcy),\n Type.evaluate(el.visProp.gradientr),\n Type.evaluate(el.visProp.gradientfx),\n Type.evaluate(el.visProp.gradientfy),\n Type.evaluate(el.visProp.gradientfr)\n );\n }\n },\n\n // documented in JXG.AbstractRenderer\n setObjectTransition: function (el, duration) {\n var node, transitionStr,\n i, len,\n nodes = ['rendNode',\n 'rendNodeTriangleStart',\n 'rendNodeTriangleEnd'];\n\n if (duration === undefined) {\n duration = Type.evaluate(el.visProp.transitionduration);\n }\n\n if (duration === el.visPropOld.transitionduration) {\n return;\n }\n\n if (el.elementClass === Const.OBJECT_CLASS_TEXT &&\n Type.evaluate(el.visProp.display) === 'html') {\n transitionStr = ' color ' + duration + 'ms,' +\n ' opacity ' + duration + 'ms';\n } else {\n transitionStr = ' fill ' + duration + 'ms,' +\n ' fill-opacity ' + duration + 'ms,' +\n ' stroke ' + duration + 'ms,' +\n ' stroke-opacity ' + duration + 'ms';\n }\n\n len = nodes.length;\n for (i = 0; i < len; ++i) {\n if (el[nodes[i]]) {\n node = el[nodes[i]];\n node.style.transition = transitionStr;\n }\n }\n\n el.visPropOld.transitionduration = duration;\n },\n\n /**\n * Call user-defined function to set visual attributes.\n * If \"testAttribute\" is the empty string, the function\n * is called immediately, otherwise it is called in a timeOut.\n *\n * This is necessary to realize smooth transitions but avoid transitions\n * when first creating the objects.\n *\n * Usually, the string in testAttribute is the visPropOld attribute\n * of the values which are set.\n *\n * @param {Function} setFunc Some function which usually sets some attributes\n * @param {String} testAttribute If this string is the empty string the function is called immediately,\n * otherwise it is called in a setImeout.\n * @see JXG.SVGRenderer#setObjectFillColor\n * @see JXG.SVGRenderer#setObjectStrokeColor\n * @see JXG.SVGRenderer#_setArrowColor\n * @private\n */\n _setAttribute: function (setFunc, testAttribute) {\n if (testAttribute === '') {\n setFunc();\n } else {\n window.setTimeout(setFunc, 1);\n }\n },\n\n // documented in JXG.AbstractRenderer\n setObjectFillColor: function (el, color, opacity, rendNode) {\n var node, c, rgbo, oo,\n rgba = Type.evaluate(color),\n o = Type.evaluate(opacity),\n grad = Type.evaluate(el.visProp.gradient);\n\n o = (o > 0) ? o : 0;\n\n // TODO save gradient and gradientangle\n if (el.visPropOld.fillcolor === rgba && el.visPropOld.fillopacity === o && grad === null) {\n return;\n }\n\n if (Type.exists(rgba) && rgba !== false) {\n if (rgba.length !== 9) { // RGB, not RGBA\n c = rgba;\n oo = o;\n } else { // True RGBA, not RGB\n rgbo = Color.rgba2rgbo(rgba);\n c = rgbo[0];\n oo = o * rgbo[1];\n }\n\n if (rendNode === undefined) {\n node = el.rendNode;\n } else {\n node = rendNode;\n }\n\n if (c !== 'none') {\n this._setAttribute(function () {\n node.setAttributeNS(null, 'fill', c);\n }, el.visPropOld.fillcolor);\n }\n\n if (el.type === JXG.OBJECT_TYPE_IMAGE) {\n this._setAttribute(function () {\n node.setAttributeNS(null, 'opacity', oo);\n }, el.visPropOld.fillopacity);\n //node.style['opacity'] = oo; // This would overwrite values set by CSS class.\n } else {\n if (c === 'none') { // This is done only for non-images\n // because images have no fill color.\n oo = 0;\n // This is necessary if there is a foreignObject below.\n node.setAttributeNS(null, 'pointer-events', 'visibleStroke');\n } else {\n // This is the default\n node.setAttributeNS(null, 'pointer-events', 'visiblePainted');\n }\n this._setAttribute(function () {\n node.setAttributeNS(null, 'fill-opacity', oo);\n }, el.visPropOld.fillopacity);\n }\n\n if (grad === 'linear' || grad === 'radial') {\n this.updateGradient(el);\n }\n }\n el.visPropOld.fillcolor = rgba;\n el.visPropOld.fillopacity = o;\n },\n\n // documented in JXG.AbstractRenderer\n setObjectStrokeColor: function (el, color, opacity) {\n var rgba = Type.evaluate(color), c, rgbo,\n o = Type.evaluate(opacity), oo,\n node;\n\n o = (o > 0) ? o : 0;\n\n if (el.visPropOld.strokecolor === rgba && el.visPropOld.strokeopacity === o) {\n return;\n }\n\n if (Type.exists(rgba) && rgba !== false) {\n if (rgba.length !== 9) { // RGB, not RGBA\n c = rgba;\n oo = o;\n } else { // True RGBA, not RGB\n rgbo = Color.rgba2rgbo(rgba);\n c = rgbo[0];\n oo = o * rgbo[1];\n }\n\n node = el.rendNode;\n\n if (el.elementClass === Const.OBJECT_CLASS_TEXT) {\n if (Type.evaluate(el.visProp.display) === 'html') {\n this._setAttribute(function () {\n node.style.color = c;\n node.style.opacity = oo;\n }, el.visPropOld.strokecolor);\n\n } else {\n this._setAttribute(function () {\n node.setAttributeNS(null, \"style\", \"fill:\" + c);\n node.setAttributeNS(null, \"style\", \"fill-opacity:\" + oo);\n }, el.visPropOld.strokecolor);\n }\n } else {\n this._setAttribute(function () {\n node.setAttributeNS(null, 'stroke', c);\n node.setAttributeNS(null, 'stroke-opacity', oo);\n }, el.visPropOld.strokecolor);\n }\n\n if (el.elementClass === Const.OBJECT_CLASS_CURVE ||\n el.elementClass === Const.OBJECT_CLASS_LINE) {\n if (Type.evaluate(el.visProp.firstarrow)) {\n this._setArrowColor(el.rendNodeTriangleStart, c, oo, el, el.visPropCalc.typeFirst);\n }\n\n if (Type.evaluate(el.visProp.lastarrow)) {\n this._setArrowColor(el.rendNodeTriangleEnd, c, oo, el, el.visPropCalc.typeLast);\n }\n }\n }\n\n el.visPropOld.strokecolor = rgba;\n el.visPropOld.strokeopacity = o;\n },\n\n // documented in JXG.AbstractRenderer\n setObjectStrokeWidth: function (el, width) {\n var node,\n w = Type.evaluate(width);\n\n if (isNaN(w) || el.visPropOld.strokewidth === w) {\n return;\n }\n\n node = el.rendNode;\n this.setPropertyPrim(node, 'stroked', 'true');\n if (Type.exists(w)) {\n this.setPropertyPrim(node, 'stroke-width', w + 'px');\n\n // if (el.elementClass === Const.OBJECT_CLASS_CURVE ||\n // el.elementClass === Const.OBJECT_CLASS_LINE) {\n // if (Type.evaluate(el.visProp.firstarrow)) {\n // this._setArrowWidth(el.rendNodeTriangleStart, w, el.rendNode);\n // }\n //\n // if (Type.evaluate(el.visProp.lastarrow)) {\n // this._setArrowWidth(el.rendNodeTriangleEnd, w, el.rendNode);\n // }\n // }\n }\n el.visPropOld.strokewidth = w;\n },\n\n // documented in JXG.AbstractRenderer\n setLineCap: function (el) {\n var capStyle = Type.evaluate(el.visProp.linecap);\n\n if (capStyle === undefined || capStyle === '' || el.visPropOld.linecap === capStyle ||\n !Type.exists(el.rendNode)) {\n return;\n }\n\n this.setPropertyPrim(el.rendNode, 'stroke-linecap', capStyle);\n el.visPropOld.linecap = capStyle;\n\n },\n\n // documented in JXG.AbstractRenderer\n setShadow: function (el) {\n var ev_s = Type.evaluate(el.visProp.shadow);\n if (el.visPropOld.shadow === ev_s) {\n return;\n }\n\n if (Type.exists(el.rendNode)) {\n if (ev_s) {\n el.rendNode.setAttributeNS(null, 'filter', 'url(#' + this.container.id + '_' + 'f1)');\n } else {\n el.rendNode.removeAttributeNS(null, 'filter');\n }\n }\n el.visPropOld.shadow = ev_s;\n },\n\n /* **************************\n * renderer control\n * **************************/\n\n // documented in JXG.AbstractRenderer\n suspendRedraw: function () {\n // It seems to be important for the Linux version of firefox\n //this.suspendHandle = this.svgRoot.suspendRedraw(10000);\n },\n\n // documented in JXG.AbstractRenderer\n unsuspendRedraw: function () {\n //this.svgRoot.unsuspendRedraw(this.suspendHandle);\n //this.svgRoot.unsuspendRedrawAll();\n //this.svgRoot.forceRedraw();\n },\n\n // documented in AbstractRenderer\n resize: function (w, h) {\n // this.svgRoot.style.width = parseFloat(w) + 'px';\n // this.svgRoot.style.height = parseFloat(h) + 'px';\n\n this.svgRoot.setAttribute('width', parseFloat(w));\n this.svgRoot.setAttribute('height', parseFloat(h));\n // this.svgRoot.setAttribute('width', '100%');\n // this.svgRoot.setAttribute('height', '100%');\n },\n\n // documented in JXG.AbstractRenderer\n createTouchpoints: function (n) {\n var i, na1, na2, node;\n this.touchpoints = [];\n for (i = 0; i < n; i++) {\n na1 = 'touchpoint1_' + i;\n node = this.createPrim('path', na1);\n this.appendChildPrim(node, 19);\n node.setAttributeNS(null, 'd', 'M 0 0');\n this.touchpoints.push(node);\n\n this.setPropertyPrim(node, 'stroked', 'true');\n this.setPropertyPrim(node, 'stroke-width', '1px');\n node.setAttributeNS(null, 'stroke', '#000000');\n node.setAttributeNS(null, 'stroke-opacity', 1.0);\n node.setAttributeNS(null, 'display', 'none');\n\n na2 = 'touchpoint2_' + i;\n node = this.createPrim('ellipse', na2);\n this.appendChildPrim(node, 19);\n this.updateEllipsePrim(node, 0, 0, 0, 0);\n this.touchpoints.push(node);\n\n this.setPropertyPrim(node, 'stroked', 'true');\n this.setPropertyPrim(node, 'stroke-width', '1px');\n node.setAttributeNS(null, 'stroke', '#000000');\n node.setAttributeNS(null, 'stroke-opacity', 1.0);\n node.setAttributeNS(null, 'fill', '#ffffff');\n node.setAttributeNS(null, 'fill-opacity', 0.0);\n\n node.setAttributeNS(null, 'display', 'none');\n }\n },\n\n // documented in JXG.AbstractRenderer\n showTouchpoint: function (i) {\n if (this.touchpoints && i >= 0 && 2 * i < this.touchpoints.length) {\n this.touchpoints[2 * i].setAttributeNS(null, 'display', 'inline');\n this.touchpoints[2 * i + 1].setAttributeNS(null, 'display', 'inline');\n }\n },\n\n // documented in JXG.AbstractRenderer\n hideTouchpoint: function (i) {\n if (this.touchpoints && i >= 0 && 2 * i < this.touchpoints.length) {\n this.touchpoints[2 * i].setAttributeNS(null, 'display', 'none');\n this.touchpoints[2 * i + 1].setAttributeNS(null, 'display', 'none');\n }\n },\n\n // documented in JXG.AbstractRenderer\n updateTouchpoint: function (i, pos) {\n var x, y,\n d = 37;\n\n if (this.touchpoints && i >= 0 && 2 * i < this.touchpoints.length) {\n x = pos[0];\n y = pos[1];\n\n this.touchpoints[2 * i].setAttributeNS(null, 'd', 'M ' + (x - d) + ' ' + y + ' ' +\n 'L ' + (x + d) + ' ' + y + ' ' +\n 'M ' + x + ' ' + (y - d) + ' ' +\n 'L ' + x + ' ' + (y + d));\n this.updateEllipsePrim(this.touchpoints[2 * i + 1], pos[0], pos[1], 25, 25);\n }\n },\n\n /**\n * Walk recursively through the DOM subtree of a node and collect all\n * value attributes together with the id of that node.\n * <b>Attention:</b> Only values of nodes having a valid id are taken.\n * @param {Node} node root node of DOM subtree that will be searched recursively.\n * @return {Array} Array with entries of the form [id, value]\n * @private\n */\n _getValuesOfDOMElements: function (node) {\n var values = [];\n if (node.nodeType === 1) {\n node = node.firstChild;\n while (node) {\n if (node.id !== undefined && node.value !== undefined) {\n values.push([node.id, node.value]);\n }\n values = values.concat(this._getValuesOfDOMElements(node));\n node = node.nextSibling;\n }\n }\n return values;\n },\n\n _getDataUri: function (url, callback) {\n var image = new Image();\n\n image.onload = function () {\n var canvas = document.createElement('canvas');\n canvas.width = this.naturalWidth; // or 'width' if you want a special/scaled size\n canvas.height = this.naturalHeight; // or 'height' if you want a special/scaled size\n\n canvas.getContext('2d').drawImage(this, 0, 0);\n\n callback(canvas.toDataURL('image/png'));\n canvas.remove();\n };\n\n image.src = url;\n },\n\n _getImgDataURL: function(svgRoot) {\n var images, len, canvas, ctx,\n ur, i;\n\n images = svgRoot.getElementsByTagName(\"image\");\n len = images.length;\n if (len > 0) {\n canvas = document.createElement('canvas');\n //img = new Image();\n for (i = 0; i < len; i++) {\n images[i].setAttribute(\"crossorigin\", \"anonymous\");\n //img.src = images[i].href;\n //img.onload = function() {\n // img.crossOrigin = \"anonymous\";\n ctx = canvas.getContext('2d');\n canvas.width = images[i].getAttribute(\"width\");\n canvas.height = images[i].getAttribute(\"height\");\n try {\n ctx.drawImage(images[i], 0, 0, canvas.width, canvas.height);\n\n // If the image is not png, the format must be specified here\n ur = canvas.toDataURL();\n images[i].setAttribute(\"xlink:href\", ur);\n } catch (err) {\n console.log(\"CORS problem! Image can not be used\", err);\n }\n }\n //canvas.remove();\n }\n return true;\n },\n\n /**\n * Return a data URI of the SVG code representeing the construction.\n * The SVG code of the construction is base64 encoded. The return string starts\n * with \"data:image/svg+xml;base64,...\".\n *\n * @param {Boolean} ignoreTexts If true, the foreignObject tag is set to display=none.\n * This is necessary for older versions of Safari. Default: false\n * @returns {String} data URI string\n */\n dumpToDataURI: function (ignoreTexts) {\n var svgRoot = this.svgRoot,\n btoa = window.btoa || Base64.encode,\n svg,\n virtualNode, doc,\n i, len,\n values = [];\n\n // Move all HTML tags (beside the SVG root) of the container\n // to the foreignObject element inside of the svgRoot node\n // Problem:\n // input values are not copied. This can be verified by looking at an innerHTML output\n // of an input element. Therefore, we do it \"by hand\".\n if (this.container.hasChildNodes() && Type.exists(this.foreignObjLayer)) {\n if (!ignoreTexts) {\n this.foreignObjLayer.setAttribute('display', 'inline');\n }\n while (svgRoot.nextSibling) {\n\n // Copy all value attributes\n values = values.concat(this._getValuesOfDOMElements(svgRoot.nextSibling));\n\n this.foreignObjLayer.appendChild(svgRoot.nextSibling);\n }\n }\n\n this._getImgDataURL(svgRoot);\n\n // Convert the SVG graphic into a string containing SVG code\n svgRoot.setAttribute(\"xmlns\", \"http://www.w3.org/2000/svg\");\n svg = new XMLSerializer().serializeToString(svgRoot);\n\n if (ignoreTexts !== true) {\n // Handle SVG texts\n // Insert all value attributes back into the svg string\n len = values.length;\n for (i = 0; i < len; i++) {\n svg = svg.replace('id=\"' + values[i][0] + '\"', 'id=\"' + values[i][0] + '\" value=\"' + values[i][1] + '\"');\n }\n }\n\n // if (false) {\n // // Debug: use example svg image\n // svg = '<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.0\" width=\"220\" height=\"220\"><rect width=\"66\" height=\"30\" x=\"21\" y=\"32\" stroke=\"#204a87\" stroke-width=\"2\" fill=\"none\" /></svg>';\n // }\n\n // In IE we have to remove the namespace again.\n if ((svg.match(/xmlns=\"http:\\/\\/www.w3.org\\/2000\\/svg\"/g) || []).length > 1) {\n svg = svg.replace(/xmlns=\"http:\\/\\/www.w3.org\\/2000\\/svg\"/g, '');\n }\n\n // Safari fails if the svg string contains a \" \"\n // Obsolete with Safari 12+\n svg = svg.replace(/ /g, ' ');\n\n // Move all HTML tags back from\n // the foreignObject element to the container\n if (Type.exists(this.foreignObjLayer) && this.foreignObjLayer.hasChildNodes()) {\n // Restore all HTML elements\n while (this.foreignObjLayer.firstChild) {\n this.container.appendChild(this.foreignObjLayer.firstChild);\n }\n this.foreignObjLayer.setAttribute(\"display\", \"none\");\n }\n\n return 'data:image/svg+xml;base64,' + btoa(unescape(encodeURIComponent(svg)));\n },\n\n /**\n * Convert the SVG construction into an HTML canvas image.\n * This works for all SVG supporting browsers. Implemented as Promise.\n * <p>\n * For IE, it is realized as function.\n * It works from version 9, with the exception that HTML texts\n * are ignored on IE. The drawing is done with a delay of\n * 200 ms. Otherwise there would be problems with IE.\n *\n * @param {String} canvasId Id of an HTML canvas element\n * @param {Number} w Width in pixel of the dumped image, i.e. of the canvas tag.\n * @param {Number} h Height in pixel of the dumped image, i.e. of the canvas tag.\n * @param {Boolean} ignoreTexts If true, the foreignObject tag is taken out from the SVG root.\n * This is necessary for older versions of Safari. Default: false\n * @returns {Promise} Promise object\n *\n * @example\n * \tboard.renderer.dumpToCanvas('canvas').then(function() { console.log('done'); });\n *\n * @example\n * // IE 11 example:\n * \tboard.renderer.dumpToCanvas('canvas');\n * \tsetTimeout(function() { console.log('done'); }, 400);\n */\n dumpToCanvas: function (canvasId, w, h, ignoreTexts) {\n var svg, tmpImg, cv, ctx,\n doc = this.container.ownerDocument;\n\n // Prepare the canvas element\n cv = doc.getElementById(canvasId);\n\n // Clear the canvas\n /* eslint-disable no-self-assign */\n cv.width = cv.width;\n /* eslint-enable no-self-assign */\n\n ctx = cv.getContext(\"2d\");\n if (w !== undefined && h !== undefined) {\n cv.style.width = parseFloat(w) + 'px';\n cv.style.height = parseFloat(h) + 'px';\n // Scale twice the CSS size to make the image crisp\n // cv.setAttribute('width', 2 * parseFloat(wOrg));\n // cv.setAttribute('height', 2 * parseFloat(hOrg));\n // ctx.scale(2 * wOrg / w, 2 * hOrg / h);\n cv.setAttribute('width', parseFloat(w));\n cv.setAttribute('height', parseFloat(h));\n }\n\n // Display the SVG string as data-uri in an HTML img.\n tmpImg = new Image();\n svg = this.dumpToDataURI(ignoreTexts);\n tmpImg.src = svg;\n\n // Finally, draw the HTML img in the canvas.\n if (!('Promise' in window)) {\n tmpImg.onload = function () {\n // IE needs a pause...\n // Seems to be broken\n window.setTimeout(function() {\n try {\n ctx.drawImage(tmpImg, 0, 0, w, h);\n } catch (err) {\n console.log(\"screenshots not longer supported on IE\");\n }\n }, 200);\n };\n return this;\n }\n\n return new Promise(function(resolve, reject) {\n try {\n tmpImg.onload = function () {\n ctx.drawImage(tmpImg, 0, 0, w, h);\n resolve();\n };\n } catch (e) {\n reject(e);\n }\n });\n\n },\n\n /**\n * Display SVG image in html img-tag which enables\n * easy download for the user.\n *\n * Support:\n * <ul>\n * <li> IE: No\n * <li> Edge: full\n * <li>Firefox: full\n * <li> Chrome: full\n * <li> Safari: full (No text support in versions prior to 12).\n * </ul>\n *\n * @param {JXG.Board} board Link to the board.\n * @param {String} imgId Optional id of an img object. If given and different from the empty string,\n * the screenshot is copied to this img object. The width and height will be set to the values of the\n * JSXGraph container.\n * @param {Boolean} ignoreTexts If set to true, the foreignObject is taken out of the\n * SVGRoot and texts are not displayed. This is mandatory for Safari. Default: false\n * @return {Object} the svg renderer object\n */\n screenshot: function (board, imgId, ignoreTexts) {\n var node,\n doc = this.container.ownerDocument,\n parent = this.container.parentNode,\n cPos,\n canvas, id,\n img,\n button, buttonText,\n w, h,\n bas = board.attr.screenshot,\n zbar, zbarDisplay, cssTxt,\n newImg = false,\n _copyCanvasToImg,\n isDebug = false;\n\n if (this.type === 'no') {\n return this;\n }\n\n w = bas.scale * this.container.getBoundingClientRect().width;\n h = bas.scale * this.container.getBoundingClientRect().height;\n\n if (imgId === undefined || imgId === '') {\n newImg = true;\n img = new Image(); //doc.createElement('img');\n img.style.width = w + 'px';\n img.style.height = h + 'px';\n } else {\n newImg = false;\n img = doc.getElementById(imgId);\n }\n // img.crossOrigin = 'anonymous';\n\n // Create div which contains canvas element and close button\n if (newImg) {\n node = doc.createElement('div');\n node.style.cssText = bas.css;\n node.style.width = (w) + 'px';\n node.style.height = (h) + 'px';\n node.style.zIndex = this.container.style.zIndex + 120;\n\n // Try to position the div exactly over the JSXGraph board\n node.style.position = 'absolute';\n node.style.top = this.container.offsetTop + 'px';\n node.style.left = this.container.offsetLeft + 'px';\n }\n\n if (!isDebug) {\n // Create canvas element and add it to the DOM\n // It will be removed after the image has been stored.\n canvas = doc.createElement('canvas');\n id = Math.random().toString(36).substr(2, 5);\n canvas.setAttribute('id', id);\n canvas.setAttribute('width', w);\n canvas.setAttribute('height', h);\n canvas.style.width = w + 'px';\n canvas.style.height = w + 'px';\n canvas.style.display = 'none';\n parent.appendChild(canvas);\n } else {\n // Debug: use canvas element 'jxgbox_canvas' from jsxdev/dump.html\n id = 'jxgbox_canvas';\n // canvas = document.getElementById(id);\n canvas = doc.getElementById(id);\n }\n\n if (newImg) {\n // Create close button\n button = doc.createElement('span');\n buttonText = doc.createTextNode('\\u2716');\n button.style.cssText = bas.cssButton;\n button.appendChild(buttonText);\n button.onclick = function () {\n node.parentNode.removeChild(node);\n };\n\n // Add all nodes\n node.appendChild(img);\n node.appendChild(button);\n parent.insertBefore(node, this.container.nextSibling);\n }\n\n // Hide navigation bar in board\n // zbar = document.getElementById(this.container.id + '_navigationbar');\n zbar = doc.getElementById(this.container.id + '_navigationbar');\n if (Type.exists(zbar)) {\n zbarDisplay = zbar.style.display;\n zbar.style.display = 'none';\n }\n\n _copyCanvasToImg = function() {\n // Show image in img tag\n img.src = canvas.toDataURL('image/png');\n\n // Remove canvas node\n if (!isDebug) {\n parent.removeChild(canvas);\n }\n };\n\n // Create screenshot in image element\n if ('Promise' in window) {\n this.dumpToCanvas(id, w, h, ignoreTexts).then(_copyCanvasToImg);\n } else {\n // IE\n this.dumpToCanvas(id, w, h, ignoreTexts);\n window.setTimeout(_copyCanvasToImg, 200);\n }\n\n // Show navigation bar in board\n if (Type.exists(zbar)) {\n zbar.style.display = zbarDisplay;\n }\n\n return this;\n }\n\n });\n\n return JXG.SVGRenderer;\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true, AMprocessNode: true, MathJax: true, document: true */\n/*jslint nomen: true, plusplus: true, newcap:true*/\n\n/* depends:\n jxg\n renderer/abstract\n base/constants\n utils/type\n utils/color\n math/math\n math/numerics\n*/\n\ndefine('renderer/vml',[\n 'jxg', 'renderer/abstract', 'base/constants', 'utils/type', 'utils/color', 'math/math', 'math/numerics'\n], function (JXG, AbstractRenderer, Const, Type, Color, Mat, Numerics) {\n\n \"use strict\";\n\n /**\n * Uses VML to implement the rendering methods defined in {@link JXG.AbstractRenderer}.\n * VML was used in very old Internet Explorer versions upto IE 8.\n * \n * \n * @class JXG.VMLRenderer\n * @augments JXG.AbstractRenderer\n * @param {Node} container Reference to a DOM node containing the board.\n * @see JXG.AbstractRenderer\n * @deprecated\n */\n JXG.VMLRenderer = function (container) {\n this.type = 'vml';\n\n this.container = container;\n this.container.style.overflow = 'hidden';\n if (this.container.style.position === '') {\n this.container.style.position = 'relative';\n }\n this.container.onselectstart = function () {\n return false;\n };\n\n this.resolution = 10; // Paths are drawn with a a resolution of this.resolution/pixel.\n\n // Add VML includes and namespace\n // Original: IE <=7\n //container.ownerDocument.createStyleSheet().addRule(\"v\\\\:*\", \"behavior: url(#default#VML);\");\n if (!Type.exists(JXG.vmlStylesheet)) {\n container.ownerDocument.namespaces.add(\"jxgvml\", \"urn:schemas-microsoft-com:vml\");\n JXG.vmlStylesheet = this.container.ownerDocument.createStyleSheet();\n JXG.vmlStylesheet.addRule(\".jxgvml\", \"behavior:url(#default#VML)\");\n }\n\n try {\n if (!container.ownerDocument.namespaces.jxgvml) {\n container.ownerDocument.namespaces.add(\"jxgvml\", \"urn:schemas-microsoft-com:vml\");\n }\n\n this.createNode = function (tagName) {\n return container.ownerDocument.createElement('<jxgvml:' + tagName + ' class=\"jxgvml\">');\n };\n } catch (e) {\n this.createNode = function (tagName) {\n return container.ownerDocument.createElement('<' + tagName + ' xmlns=\"urn:schemas-microsoft.com:vml\" class=\"jxgvml\">');\n };\n }\n\n // dash styles\n this.dashArray = ['Solid', '1 1', 'ShortDash', 'Dash', 'LongDash', 'ShortDashDot', 'LongDashDot'];\n };\n\n JXG.VMLRenderer.prototype = new AbstractRenderer();\n\n JXG.extend(JXG.VMLRenderer.prototype, /** @lends JXG.VMLRenderer.prototype */ {\n\n /**\n * Sets attribute <tt>key</tt> of node <tt>node</tt> to <tt>value</tt>.\n * @param {Node} node A DOM node.\n * @param {String} key Name of the attribute.\n * @param {String} val New value of the attribute.\n * @param {Boolean} [iFlag=false] If false, the attribute's name is case insensitive.\n */\n _setAttr: function (node, key, val, iFlag) {\n try {\n if (this.container.ownerDocument.documentMode === 8) {\n node[key] = val;\n } else {\n node.setAttribute(key, val, iFlag);\n }\n } catch (e) {\n JXG.debug('_setAttr:'/*node.id*/ + ' ' + key + ' ' + val + '<br>\\n');\n }\n },\n\n /* ******************************** *\n * This renderer does not need to\n * override draw/update* methods\n * since it provides draw/update*Prim\n * methods.\n * ******************************** */\n\n /* **************************\n * Lines\n * **************************/\n\n // documented in AbstractRenderer\n updateTicks: function (ticks) {\n var i, len, c, x, y,\n r = this.resolution,\n tickArr = [];\n\n len = ticks.ticks.length;\n for (i = 0; i < len; i++) {\n c = ticks.ticks[i];\n x = c[0];\n y = c[1];\n\n if (Type.isNumber(x[0]) && Type.isNumber(x[1])) {\n tickArr.push(' m ' + Math.round(r * x[0]) + ', ' + Math.round(r * y[0]) +\n ' l ' + Math.round(r * x[1]) + ', ' + Math.round(r * y[1]) + ' ');\n }\n }\n\n if (!Type.exists(ticks.rendNode)) {\n ticks.rendNode = this.createPrim('path', ticks.id);\n this.appendChildPrim(ticks.rendNode, Type.evaluate(ticks.visProp.layer));\n }\n\n this._setAttr(ticks.rendNode, 'stroked', 'true');\n this._setAttr(ticks.rendNode, 'strokecolor', Type.evaluate(ticks.visProp.strokecolor), 1);\n this._setAttr(ticks.rendNode, 'strokeweight', Type.evaluate(ticks.visProp.strokewidth));\n this._setAttr(ticks.rendNodeStroke, 'opacity', (Type.evaluate(ticks.visProp.strokeopacity) * 100) + '%');\n this.updatePathPrim(ticks.rendNode, tickArr, ticks.board);\n },\n\n /* **************************\n * Text related stuff\n * **************************/\n\n // Already documented in JXG.AbstractRenderer\n displayCopyright: function (str, fontsize) {\n var node, t;\n\n node = this.createNode('textbox');\n node.style.position = 'absolute';\n this._setAttr(node, 'id', this.container.id + '_' + 'licenseText');\n\n node.style.left = 20;\n node.style.top = 2;\n node.style.fontSize = fontsize;\n node.style.color = '#356AA0';\n node.style.fontFamily = 'Arial,Helvetica,sans-serif';\n this._setAttr(node, 'opacity', '30%');\n node.style.filter = \"progid:DXImageTransform.Microsoft.Matrix(M11='1.0', sizingMethod='auto expand', enabled = false) progid:DXImageTransform.Microsoft.Alpha(opacity = 30, enabled = true)\";\n\n t = this.container.ownerDocument.createTextNode(str);\n node.appendChild(t);\n this.appendChildPrim(node, 0);\n },\n\n // documented in AbstractRenderer\n drawInternalText: function (el) {\n var node;\n node = this.createNode('textbox');\n node.style.position = 'absolute';\n el.rendNodeText = this.container.ownerDocument.createTextNode('');\n node.appendChild(el.rendNodeText);\n this.appendChildPrim(node, 9);\n node.style.filter = \"progid:DXImageTransform.Microsoft.Matrix(M11='1.0', sizingMethod='auto expand', enabled = false) progid:DXImageTransform.Microsoft.Alpha(opacity = 100, enabled = false)\";\n\n return node;\n },\n\n // documented in AbstractRenderer\n updateInternalText: function (el) {\n var v, content = el.plaintext,\n m = this.joinTransforms(el, el.transformations),\n offset = [0, 0],\n maxX, maxY, minX, minY, i,\n node = el.rendNode,\n p = [],\n ev_ax = el.getAnchorX(),\n ev_ay = el.getAnchorY();\n\n if (!isNaN(el.coords.scrCoords[1] + el.coords.scrCoords[2])) {\n // Horizontal\n if (ev_ax === 'right') {\n offset[0] = 1;\n } else if (ev_ax === 'middle') {\n offset[0] = 0.5;\n } // default (ev_ax === 'left') offset[0] = 0;\n\n // Vertical\n if (ev_ay === 'bottom') {\n offset[1] = 1;\n } else if (ev_ay === 'middle') {\n offset[1] = 0.5;\n } // default (ev_ay === 'top') offset[1] = 0;\n\n // Compute maxX, maxY, minX, minY\n p[0] = Mat.matVecMult(m, [1,\n el.coords.scrCoords[1] - offset[0] * el.size[0],\n el.coords.scrCoords[2] + (1 - offset[1]) * el.size[1] + this.vOffsetText]);\n p[0][1] /= p[0][0];\n p[0][2] /= p[0][0];\n p[1] = Mat.matVecMult(m, [1,\n el.coords.scrCoords[1] + (1 - offset[0]) * el.size[0],\n el.coords.scrCoords[2] + (1 - offset[1]) * el.size[1] + this.vOffsetText]);\n p[1][1] /= p[1][0];\n p[1][2] /= p[1][0];\n p[2] = Mat.matVecMult(m, [1,\n el.coords.scrCoords[1] + (1 - offset[0]) * el.size[0],\n el.coords.scrCoords[2] - offset[1] * el.size[1] + this.vOffsetText]);\n p[2][1] /= p[2][0];\n p[2][2] /= p[2][0];\n p[3] = Mat.matVecMult(m, [1,\n el.coords.scrCoords[1] - offset[0] * el.size[0],\n el.coords.scrCoords[2] - offset[1] * el.size[1] + this.vOffsetText]);\n p[3][1] /= p[3][0];\n p[3][2] /= p[3][0];\n maxX = p[0][1];\n minX = p[0][1];\n maxY = p[0][2];\n minY = p[0][2];\n\n for (i = 1; i < 4; i++) {\n maxX = Math.max(maxX, p[i][1]);\n minX = Math.min(minX, p[i][1]);\n maxY = Math.max(maxY, p[i][2]);\n minY = Math.min(minY, p[i][2]);\n }\n\n // Horizontal\n v = offset[0] === 1 ? Math.floor(el.board.canvasWidth - maxX) : Math.floor(minX);\n if (el.visPropOld.left !== (ev_ax + v)) {\n if (offset[0] === 1) {\n el.rendNode.style.right = v + 'px';\n el.rendNode.style.left = 'auto';\n } else {\n el.rendNode.style.left = v + 'px';\n el.rendNode.style.right = 'auto';\n }\n el.visPropOld.left = ev_ax + v;\n }\n\n // Vertical\n v = offset[1] === 1 ? Math.floor(el.board.canvasHeight - maxY) : Math.floor(minY);\n if (el.visPropOld.top !== (ev_ay + v)) {\n if (offset[1] === 1) {\n el.rendNode.style.bottom = v + 'px';\n el.rendNode.style.top = 'auto';\n } else {\n el.rendNode.style.top = v + 'px';\n el.rendNode.style.bottom = 'auto';\n }\n el.visPropOld.top = ev_ay + v;\n }\n\n }\n\n if (el.htmlStr !== content) {\n el.rendNodeText.data = content;\n el.htmlStr = content;\n }\n\n //this.transformImage(el, el.transformations);\n node.filters.item(0).M11 = m[1][1];\n node.filters.item(0).M12 = m[1][2];\n node.filters.item(0).M21 = m[2][1];\n node.filters.item(0).M22 = m[2][2];\n node.filters.item(0).enabled = true;\n },\n\n /* **************************\n * Image related stuff\n * **************************/\n\n // Already documented in JXG.AbstractRenderer\n drawImage: function (el) {\n // IE 8: Bilder ueber data URIs werden bis 32kB unterstuetzt.\n var node;\n\n node = this.container.ownerDocument.createElement('img');\n node.style.position = 'absolute';\n this._setAttr(node, 'id', this.container.id + '_' + el.id);\n\n this.container.appendChild(node);\n this.appendChildPrim(node, Type.evaluate(el.visProp.layer));\n\n // Adding the rotation filter. This is always filter item 0:\n // node.filters.item(0), see transformImage\n // Also add the alpha filter. This is always filter item 1\n // node.filters.item(1), see setObjectFillColor and setObjectSTrokeColor\n //node.style.filter = node.style['-ms-filter'] = \"progid:DXImageTransform.Microsoft.Matrix(M11='1.0', sizingMethod='auto expand')\";\n node.style.filter = \"progid:DXImageTransform.Microsoft.Matrix(M11='1.0', sizingMethod='auto expand') progid:DXImageTransform.Microsoft.Alpha(opacity = 100, enabled = false)\";\n el.rendNode = node;\n this.updateImage(el);\n },\n\n // Already documented in JXG.AbstractRenderer\n transformImage: function (el, t) {\n var m, s, maxX, maxY, minX, minY, i, nt,\n node = el.rendNode,\n p = [],\n len = t.length;\n\n if (len > 0) {\n /*\n nt = el.rendNode.style.filter.toString();\n if (!nt.match(/DXImageTransform/)) {\n node.style.filter = \"progid:DXImageTransform.Microsoft.Matrix(M11='1.0', sizingMethod='auto expand') \" + nt;\n }\n */\n\n m = this.joinTransforms(el, t);\n p[0] = Mat.matVecMult(m, el.coords.scrCoords);\n p[0][1] /= p[0][0];\n p[0][2] /= p[0][0];\n p[1] = Mat.matVecMult(m, [1, el.coords.scrCoords[1] + el.size[0], el.coords.scrCoords[2]]);\n p[1][1] /= p[1][0];\n p[1][2] /= p[1][0];\n p[2] = Mat.matVecMult(m, [1, el.coords.scrCoords[1] + el.size[0], el.coords.scrCoords[2] - el.size[1]]);\n p[2][1] /= p[2][0];\n p[2][2] /= p[2][0];\n p[3] = Mat.matVecMult(m, [1, el.coords.scrCoords[1], el.coords.scrCoords[2] - el.size[1]]);\n p[3][1] /= p[3][0];\n p[3][2] /= p[3][0];\n maxX = p[0][1];\n minX = p[0][1];\n maxY = p[0][2];\n minY = p[0][2];\n\n for (i = 1; i < 4; i++) {\n maxX = Math.max(maxX, p[i][1]);\n minX = Math.min(minX, p[i][1]);\n maxY = Math.max(maxY, p[i][2]);\n minY = Math.min(minY, p[i][2]);\n }\n node.style.left = Math.floor(minX) + 'px';\n node.style.top = Math.floor(minY) + 'px';\n\n node.filters.item(0).M11 = m[1][1];\n node.filters.item(0).M12 = m[1][2];\n node.filters.item(0).M21 = m[2][1];\n node.filters.item(0).M22 = m[2][2];\n node.filters.item(0).enabled = true;\n }\n },\n\n // Already documented in JXG.AbstractRenderer\n updateImageURL: function (el) {\n var url = Type.evaluate(el.url);\n\n this._setAttr(el.rendNode, 'src', url);\n },\n\n /* **************************\n * Render primitive objects\n * **************************/\n\n // Already documented in JXG.AbstractRenderer\n appendChildPrim: function (node, level) {\n // For trace nodes\n if (!Type.exists(level)) {\n level = 0;\n }\n\n node.style.zIndex = level;\n this.container.appendChild(node);\n\n return node;\n },\n\n // Already documented in JXG.AbstractRenderer\n appendNodesToElement: function (el, type) {\n if (type === 'shape' || type === 'path' || type === 'polygon') {\n el.rendNodePath = this.getElementById(el.id + '_path');\n }\n el.rendNodeFill = this.getElementById(el.id + '_fill');\n el.rendNodeStroke = this.getElementById(el.id + '_stroke');\n el.rendNodeShadow = this.getElementById(el.id + '_shadow');\n el.rendNode = this.getElementById(el.id);\n },\n\n // Already documented in JXG.AbstractRenderer\n createPrim: function (type, id) {\n var node, pathNode,\n fillNode = this.createNode('fill'),\n strokeNode = this.createNode('stroke'),\n shadowNode = this.createNode('shadow');\n\n this._setAttr(fillNode, 'id', this.container.id + '_' + id + '_fill');\n this._setAttr(strokeNode, 'id', this.container.id + '_' + id + '_stroke');\n this._setAttr(shadowNode, 'id', this.container.id + '_' + id + '_shadow');\n\n if (type === 'circle' || type === 'ellipse') {\n node = this.createNode('oval');\n node.appendChild(fillNode);\n node.appendChild(strokeNode);\n node.appendChild(shadowNode);\n } else if (type === 'polygon' || type === 'path' || type === 'shape' || type === 'line') {\n node = this.createNode('shape');\n node.appendChild(fillNode);\n node.appendChild(strokeNode);\n node.appendChild(shadowNode);\n pathNode = this.createNode('path');\n this._setAttr(pathNode, 'id', this.container.id + '_' + id + '_path');\n node.appendChild(pathNode);\n } else {\n node = this.createNode(type);\n node.appendChild(fillNode);\n node.appendChild(strokeNode);\n node.appendChild(shadowNode);\n }\n\n node.style.position = 'absolute';\n node.style.left = '0px';\n node.style.top = '0px';\n this._setAttr(node, 'id', this.container.id + '_' + id);\n\n return node;\n },\n\n // Already documented in JXG.AbstractRenderer\n remove: function (node) {\n if (Type.exists(node)) {\n node.removeNode(true);\n }\n },\n\n // Already documented in JXG.AbstractRenderer\n makeArrows: function (el) {\n var nodeStroke,\n ev_fa = Type.evaluate(el.visProp.firstarrow),\n ev_la = Type.evaluate(el.visProp.lastarrow);\n\n if (el.visPropOld.firstarrow === ev_fa && el.visPropOld.lastarrow === ev_la) {\n return;\n }\n\n if (ev_fa) {\n nodeStroke = el.rendNodeStroke;\n this._setAttr(nodeStroke, 'startarrow', 'block');\n this._setAttr(nodeStroke, 'startarrowlength', 'long');\n } else {\n nodeStroke = el.rendNodeStroke;\n if (Type.exists(nodeStroke)) {\n this._setAttr(nodeStroke, 'startarrow', 'none');\n }\n }\n\n if (ev_la) {\n nodeStroke = el.rendNodeStroke;\n this._setAttr(nodeStroke, 'id', this.container.id + '_' + el.id + \"stroke\");\n this._setAttr(nodeStroke, 'endarrow', 'block');\n this._setAttr(nodeStroke, 'endarrowlength', 'long');\n } else {\n nodeStroke = el.rendNodeStroke;\n if (Type.exists(nodeStroke)) {\n this._setAttr(nodeStroke, 'endarrow', 'none');\n }\n }\n el.visPropOld.firstarrow = ev_fa;\n el.visPropOld.lastarrow = ev_la;\n },\n\n // Already documented in JXG.AbstractRenderer\n updateEllipsePrim: function (node, x, y, rx, ry) {\n node.style.left = Math.floor(x - rx) + 'px';\n node.style.top = Math.floor(y - ry) + 'px';\n node.style.width = Math.floor(Math.abs(rx) * 2) + 'px';\n node.style.height = Math.floor(Math.abs(ry) * 2) + 'px';\n },\n\n // Already documented in JXG.AbstractRenderer\n updateLinePrim: function (node, p1x, p1y, p2x, p2y, board) {\n var s, r = this.resolution;\n\n if (!isNaN(p1x + p1y + p2x + p2y)) {\n s = ['m ', Math.floor(r * p1x), ', ', Math.floor(r * p1y), ' l ', Math.floor(r * p2x), ', ', Math.floor(r * p2y)];\n this.updatePathPrim(node, s, board);\n }\n },\n\n // Already documented in JXG.AbstractRenderer\n updatePathPrim: function (node, pointString, board) {\n var x = board.canvasWidth,\n y = board.canvasHeight;\n if (pointString.length <= 0) {\n pointString = ['m 0,0'];\n }\n node.style.width = x;\n node.style.height = y;\n this._setAttr(node, 'coordsize', [Math.floor(this.resolution * x), Math.floor(this.resolution * y)].join(','));\n this._setAttr(node, 'path', pointString.join(\"\"));\n },\n\n // Already documented in JXG.AbstractRenderer\n updatePathStringPoint: function (el, size, type) {\n var s = [],\n mround = Math.round,\n scr = el.coords.scrCoords,\n sqrt32 = size * Math.sqrt(3) * 0.5,\n s05 = size * 0.5,\n r = this.resolution;\n\n if (type === 'x') {\n s.push([\n ' m ', mround(r * (scr[1] - size)), ', ', mround(r * (scr[2] - size)),\n ' l ', mround(r * (scr[1] + size)), ', ', mround(r * (scr[2] + size)),\n ' m ', mround(r * (scr[1] + size)), ', ', mround(r * (scr[2] - size)),\n ' l ', mround(r * (scr[1] - size)), ', ', mround(r * (scr[2] + size))\n ].join(''));\n } else if (type === '+') {\n s.push([\n ' m ', mround(r * (scr[1] - size)), ', ', mround(r * (scr[2])),\n ' l ', mround(r * (scr[1] + size)), ', ', mround(r * (scr[2])),\n ' m ', mround(r * (scr[1])), ', ', mround(r * (scr[2] - size)),\n ' l ', mround(r * (scr[1])), ', ', mround(r * (scr[2] + size))\n ].join(''));\n } else if (type === '<>') {\n\n s.push([\n ' m ', mround(r * (scr[1] - size)), ', ', mround(r * (scr[2])),\n ' l ', mround(r * (scr[1])), ', ', mround(r * (scr[2] + size)),\n ' l ', mround(r * (scr[1] + size)), ', ', mround(r * (scr[2])),\n ' l ', mround(r * (scr[1])), ', ', mround(r * (scr[2] - size)),\n ' x e '\n ].join(''));\n } else if (type === '^') {\n s.push([\n ' m ', mround(r * (scr[1])), ', ', mround(r * (scr[2] - size)),\n ' l ', mround(r * (scr[1] - sqrt32)), ', ', mround(r * (scr[2] + s05)),\n ' l ', mround(r * (scr[1] + sqrt32)), ', ', mround(r * (scr[2] + s05)),\n ' x e '\n ].join(''));\n } else if (type === 'v') {\n s.push([\n ' m ', mround(r * (scr[1])), ', ', mround(r * (scr[2] + size)),\n ' l ', mround(r * (scr[1] - sqrt32)), ', ', mround(r * (scr[2] - s05)),\n ' l ', mround(r * (scr[1] + sqrt32)), ', ', mround(r * (scr[2] - s05)),\n ' x e '\n ].join(''));\n } else if (type === '>') {\n s.push([\n ' m ', mround(r * (scr[1] + size)), ', ', mround(r * (scr[2])),\n ' l ', mround(r * (scr[1] - s05)), ', ', mround(r * (scr[2] - sqrt32)),\n ' l ', mround(r * (scr[1] - s05)), ', ', mround(r * (scr[2] + sqrt32)),\n ' l ', mround(r * (scr[1] + size)), ', ', mround(r * (scr[2]))\n ].join(''));\n } else if (type === '<') {\n s.push([\n ' m ', mround(r * (scr[1] - size)), ', ', mround(r * (scr[2])),\n ' l ', mround(r * (scr[1] + s05)), ', ', mround(r * (scr[2] - sqrt32)),\n ' l ', mround(r * (scr[1] + s05)), ', ', mround(r * (scr[2] + sqrt32)),\n ' x e '\n ].join(''));\n }\n\n return s;\n },\n\n // Already documented in JXG.AbstractRenderer\n updatePathStringPrim: function (el) {\n var i, scr,\n pStr = [],\n r = this.resolution,\n mround = Math.round,\n symbm = ' m ',\n symbl = ' l ',\n symbc = ' c ',\n nextSymb = symbm,\n len = Math.min(el.numberPoints, 8192); // otherwise IE 7 crashes in hilbert.html\n\n if (el.numberPoints <= 0) {\n return '';\n }\n len = Math.min(len, el.points.length);\n\n if (el.bezierDegree === 1) {\n /*\n if (isNotPlot && el.board.options.curve.RDPsmoothing) {\n el.points = Numerics.RamerDouglasPeucker(el.points, 1.0);\n }\n */\n\n for (i = 0; i < len; i++) {\n scr = el.points[i].scrCoords;\n if (isNaN(scr[1]) || isNaN(scr[2])) { // PenUp\n nextSymb = symbm;\n } else {\n // IE has problems with values being too far away.\n if (scr[1] > 20000.0) {\n scr[1] = 20000.0;\n } else if (scr[1] < -20000.0) {\n scr[1] = -20000.0;\n }\n\n if (scr[2] > 20000.0) {\n scr[2] = 20000.0;\n } else if (scr[2] < -20000.0) {\n scr[2] = -20000.0;\n }\n\n pStr.push([nextSymb, mround(r * scr[1]), ', ', mround(r * scr[2])].join(''));\n nextSymb = symbl;\n }\n }\n } else if (el.bezierDegree === 3) {\n i = 0;\n while (i < len) {\n scr = el.points[i].scrCoords;\n if (isNaN(scr[1]) || isNaN(scr[2])) { // PenUp\n nextSymb = symbm;\n } else {\n pStr.push([nextSymb, mround(r * scr[1]), ', ', mround(r * scr[2])].join(''));\n if (nextSymb === symbc) {\n i += 1;\n scr = el.points[i].scrCoords;\n pStr.push([' ', mround(r * scr[1]), ', ', mround(r * scr[2])].join(''));\n i += 1;\n scr = el.points[i].scrCoords;\n pStr.push([' ', mround(r * scr[1]), ', ', mround(r * scr[2])].join(''));\n }\n nextSymb = symbc;\n }\n i += 1;\n }\n }\n pStr.push(' e');\n return pStr;\n },\n\n // Already documented in JXG.AbstractRenderer\n updatePathStringBezierPrim: function (el) {\n var i, j, k, scr, lx, ly,\n pStr = [],\n f = Type.evaluate(el.visProp.strokewidth),\n r = this.resolution,\n mround = Math.round,\n symbm = ' m ',\n symbl = ' c ',\n nextSymb = symbm,\n isNoPlot = (Type.evaluate(el.visProp.curvetype) !== 'plot'),\n len = Math.min(el.numberPoints, 8192); // otherwise IE 7 crashes in hilbert.html\n\n if (el.numberPoints <= 0) {\n return '';\n }\n if (isNoPlot && el.board.options.curve.RDPsmoothing) {\n el.points = Numerics.RamerDouglasPeucker(el.points, 1.0);\n }\n len = Math.min(len, el.points.length);\n\n for (j = 1; j < 3; j++) {\n nextSymb = symbm;\n for (i = 0; i < len; i++) {\n scr = el.points[i].scrCoords;\n if (isNaN(scr[1]) || isNaN(scr[2])) { // PenUp\n nextSymb = symbm;\n } else {\n // IE has problems with values being too far away.\n if (scr[1] > 20000.0) {\n scr[1] = 20000.0;\n } else if (scr[1] < -20000.0) {\n scr[1] = -20000.0;\n }\n\n if (scr[2] > 20000.0) {\n scr[2] = 20000.0;\n } else if (scr[2] < -20000.0) {\n scr[2] = -20000.0;\n }\n\n if (nextSymb === symbm) {\n pStr.push([nextSymb,\n mround(r * (scr[1])), ' ', mround(r * (scr[2]))].join(''));\n } else {\n k = 2 * j;\n pStr.push([nextSymb,\n mround(r * (lx + (scr[1] - lx) * 0.333 + f * (k * Math.random() - j))), ' ',\n mround(r * (ly + (scr[2] - ly) * 0.333 + f * (k * Math.random() - j))), ' ',\n mround(r * (lx + (scr[1] - lx) * 0.666 + f * (k * Math.random() - j))), ' ',\n mround(r * (ly + (scr[2] - ly) * 0.666 + f * (k * Math.random() - j))), ' ',\n mround(r * scr[1]), ' ',\n mround(r * scr[2])].join(''));\n }\n nextSymb = symbl;\n lx = scr[1];\n ly = scr[2];\n }\n }\n }\n pStr.push(' e');\n return pStr;\n },\n\n // Already documented in JXG.AbstractRenderer\n updatePolygonPrim: function (node, el) {\n var i,\n len = el.vertices.length,\n r = this.resolution,\n scr,\n pStr = [];\n\n this._setAttr(node, 'stroked', 'false');\n scr = el.vertices[0].coords.scrCoords;\n\n if (isNaN(scr[1] + scr[2])) {\n return;\n }\n\n pStr.push([\"m \", Math.floor(r * scr[1]), \",\", Math.floor(r * scr[2]), \" l \"].join(''));\n\n for (i = 1; i < len - 1; i++) {\n if (el.vertices[i].isReal) {\n scr = el.vertices[i].coords.scrCoords;\n\n if (isNaN(scr[1] + scr[2])) {\n return;\n }\n\n pStr.push(Math.floor(r * scr[1]) + \",\" + Math.floor(r * scr[2]));\n } else {\n this.updatePathPrim(node, '', el.board);\n return;\n }\n if (i < len - 2) {\n pStr.push(\", \");\n }\n }\n pStr.push(\" x e\");\n this.updatePathPrim(node, pStr, el.board);\n },\n\n // Already documented in JXG.AbstractRenderer\n updateRectPrim: function (node, x, y, w, h) {\n node.style.left = Math.floor(x) + 'px';\n node.style.top = Math.floor(y) + 'px';\n\n if (w >= 0) {\n node.style.width = w + 'px';\n }\n\n if (h >= 0) {\n node.style.height = h + 'px';\n }\n },\n\n /* **************************\n * Set Attributes\n * **************************/\n\n // Already documented in JXG.AbstractRenderer\n setPropertyPrim: function (node, key, val) {\n var keyVml = '',\n v;\n\n switch (key) {\n case 'stroke':\n keyVml = 'strokecolor';\n break;\n case 'stroke-width':\n keyVml = 'strokeweight';\n break;\n case 'stroke-dasharray':\n keyVml = 'dashstyle';\n break;\n }\n\n if (keyVml !== '') {\n v = Type.evaluate(val);\n this._setAttr(node, keyVml, v);\n }\n },\n\n // Already documented in JXG.AbstractRenderer\n display: function(el, val) {\n if (el && el.rendNode) {\n el.visPropOld.visible = val;\n if (val) {\n el.rendNode.style.visibility = \"inherit\";\n } else {\n el.rendNode.style.visibility = \"hidden\";\n }\n }\n },\n\n // Already documented in JXG.AbstractRenderer\n show: function (el) {\n JXG.deprecated('Board.renderer.show()', 'Board.renderer.display()');\n\n if (el && el.rendNode) {\n el.rendNode.style.visibility = \"inherit\";\n }\n },\n\n // Already documented in JXG.AbstractRenderer\n hide: function (el) {\n JXG.deprecated('Board.renderer.hide()', 'Board.renderer.display()');\n\n if (el && el.rendNode) {\n el.rendNode.style.visibility = \"hidden\";\n }\n },\n\n // Already documented in JXG.AbstractRenderer\n setDashStyle: function (el, visProp) {\n var node;\n if (visProp.dash >= 0) {\n node = el.rendNodeStroke;\n this._setAttr(node, 'dashstyle', this.dashArray[visProp.dash]);\n }\n },\n\n // Already documented in JXG.AbstractRenderer\n setGradient: function (el) {\n var nodeFill = el.rendNodeFill,\n ev_g = Type.evaluate(el.visProp.gradient);\n\n if (ev_g === 'linear') {\n this._setAttr(nodeFill, 'type', 'gradient');\n this._setAttr(nodeFill, 'color2', Type.evaluate(el.visProp.gradientsecondcolor));\n this._setAttr(nodeFill, 'opacity2', Type.evaluate(el.visProp.gradientsecondopacity));\n this._setAttr(nodeFill, 'angle', Type.evaluate(el.visProp.gradientangle));\n } else if (ev_g === 'radial') {\n this._setAttr(nodeFill, 'type', 'gradientradial');\n this._setAttr(nodeFill, 'color2', Type.evaluate(el.visProp.gradientsecondcolor));\n this._setAttr(nodeFill, 'opacity2', Type.evaluate(el.visProp.gradientsecondopacity));\n this._setAttr(nodeFill, 'focusposition', Type.evaluate(el.visProp.gradientpositionx) * 100 + '%,' +\n Type.evaluate(el.visProp.gradientpositiony) * 100 + '%');\n this._setAttr(nodeFill, 'focussize', '0,0');\n } else {\n this._setAttr(nodeFill, 'type', 'solid');\n }\n },\n\n // Already documented in JXG.AbstractRenderer\n setObjectFillColor: function (el, color, opacity) {\n var rgba = Type.evaluate(color), c, rgbo,\n o = Type.evaluate(opacity), oo,\n node = el.rendNode,\n t;\n\n o = (o > 0) ? o : 0;\n\n if (el.visPropOld.fillcolor === rgba && el.visPropOld.fillopacity === o) {\n return;\n }\n\n if (Type.exists(rgba) && rgba !== false) {\n // RGB, not RGBA\n if (rgba.length !== 9) {\n c = rgba;\n oo = o;\n // True RGBA, not RGB\n } else {\n rgbo = Color.rgba2rgbo(rgba);\n c = rgbo[0];\n oo = o * rgbo[1];\n }\n if (c === 'none' || c === false) {\n this._setAttr(el.rendNode, 'filled', 'false');\n } else {\n this._setAttr(el.rendNode, 'filled', 'true');\n this._setAttr(el.rendNode, 'fillcolor', c);\n\n if (Type.exists(oo) && el.rendNodeFill) {\n this._setAttr(el.rendNodeFill, 'opacity', (oo * 100) + '%');\n }\n }\n if (el.type === Const.OBJECT_TYPE_IMAGE) {\n /*\n t = el.rendNode.style.filter.toString();\n if (t.match(/alpha/)) {\n el.rendNode.style.filter = t.replace(/alpha\\(opacity *= *[0-9\\.]+\\)/, 'alpha(opacity = ' + (oo * 100) + ')');\n } else {\n el.rendNode.style.filter += ' alpha(opacity = ' + (oo * 100) + ')';\n }\n */\n if (node.filters.length > 1) {\n // Why am I sometimes seeing node.filters.length==0 here when I move the pointer around near [0,0]?\n // Setting axes:true shows text labels!\n node.filters.item(1).opacity = Math.round(oo * 100); // Why does setObjectFillColor not use Math.round?\n node.filters.item(1).enabled = true;\n }\n }\n }\n el.visPropOld.fillcolor = rgba;\n el.visPropOld.fillopacity = o;\n },\n\n // Already documented in JXG.AbstractRenderer\n setObjectStrokeColor: function (el, color, opacity) {\n var rgba = Type.evaluate(color), c, rgbo, t,\n o = Type.evaluate(opacity), oo,\n node = el.rendNode, nodeStroke;\n\n o = (o > 0) ? o : 0;\n\n if (el.visPropOld.strokecolor === rgba && el.visPropOld.strokeopacity === o) {\n return;\n }\n\n // this looks like it could be merged with parts of VMLRenderer.setObjectFillColor\n\n if (Type.exists(rgba) && rgba !== false) {\n // RGB, not RGBA\n if (rgba.length !== 9) {\n c = rgba;\n oo = o;\n // True RGBA, not RGB\n } else {\n rgbo = color.rgba2rgbo(rgba);\n c = rgbo[0];\n oo = o * rgbo[1];\n }\n if (el.elementClass === Const.OBJECT_CLASS_TEXT) {\n //node.style.filter = ' alpha(opacity = ' + oo + ')';\n /*\n t = node.style.filter.toString();\n if (t.match(/alpha/)) {\n node.style.filter =\n t.replace(/alpha\\(opacity *= *[0-9\\.]+\\)/, 'alpha(opacity = ' + oo + ')');\n } else {\n node.style.filter += ' alpha(opacity = ' + oo + ')';\n }\n */\n if (node.filters.length > 1) {\n // Why am I sometimes seeing node.filters.length==0 here when I move the pointer around near [0,0]?\n // Setting axes:true shows text labels!\n node.filters.item(1).opacity = Math.round(oo * 100);\n node.filters.item(1).enabled = true;\n }\n\n node.style.color = c;\n } else {\n if (c !== false) {\n this._setAttr(node, 'stroked', 'true');\n this._setAttr(node, 'strokecolor', c);\n }\n\n nodeStroke = el.rendNodeStroke;\n if (Type.exists(oo) && el.type !== Const.OBJECT_TYPE_IMAGE) {\n this._setAttr(nodeStroke, 'opacity', (oo * 100) + '%');\n }\n }\n }\n el.visPropOld.strokecolor = rgba;\n el.visPropOld.strokeopacity = o;\n },\n\n // Already documented in JXG.AbstractRenderer\n setObjectStrokeWidth: function (el, width) {\n var w = Type.evaluate(width),\n node;\n\n if (isNaN(w) || el.visPropOld.strokewidth === w) {\n return;\n }\n\n node = el.rendNode;\n this.setPropertyPrim(node, 'stroked', 'true');\n\n if (Type.exists(w)) {\n\n this.setPropertyPrim(node, 'stroke-width', w);\n if (w === 0 && Type.exists(el.rendNodeStroke)) {\n this._setAttr(node, 'stroked', 'false');\n }\n }\n\n el.visPropOld.strokewidth = w;\n\n },\n\n // Already documented in JXG.AbstractRenderer\n setShadow: function (el) {\n var nodeShadow = el.rendNodeShadow,\n ev_s = Type.evaluate(el.visProp.shadow);\n\n if (!nodeShadow || el.visPropOld.shadow === ev_s) {\n return;\n }\n\n if (ev_s) {\n this._setAttr(nodeShadow, 'On', 'True');\n this._setAttr(nodeShadow, 'Offset', '3pt,3pt');\n this._setAttr(nodeShadow, 'Opacity', '60%');\n this._setAttr(nodeShadow, 'Color', '#aaaaaa');\n } else {\n this._setAttr(nodeShadow, 'On', 'False');\n }\n\n el.visPropOld.shadow = ev_s;\n },\n\n /* **************************\n * renderer control\n * **************************/\n\n // Already documented in JXG.AbstractRenderer\n suspendRedraw: function () {\n this.container.style.display = 'none';\n },\n\n // Already documented in JXG.AbstractRenderer\n unsuspendRedraw: function () {\n this.container.style.display = '';\n }\n });\n\n return JXG.VMLRenderer;\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true, AMprocessNode: true, document: true, Image: true, module: true, require: true */\n/*jslint nomen: true, plusplus: true, newcap:true*/\n\n/* depends:\n jxg\n renderer/abstract\n base/constants\n utils/env\n utils/type\n utils/uuid\n utils/color\n base/coords\n math/math\n math/geometry\n math/numerics\n*/\n\ndefine('renderer/canvas',[\n 'jxg', 'renderer/abstract', 'base/constants', 'utils/env', 'utils/type', 'utils/uuid', 'utils/color',\n 'base/coords', 'math/math', 'math/geometry', 'math/numerics'\n], function (JXG, AbstractRenderer, Const, Env, Type, UUID, Color, Coords, Mat, Geometry, Numerics) {\n\n \"use strict\";\n\n /**\n * Uses HTML Canvas to implement the rendering methods defined in {@link JXG.AbstractRenderer}.\n * \n * @class JXG.CanvasRenderer\n * @augments JXG.AbstractRenderer\n * @param {Node} container Reference to a DOM node containing the board.\n * @param {Object} dim The dimensions of the board\n * @param {Number} dim.width\n * @param {Number} dim.height\n * @see JXG.AbstractRenderer\n */\n JXG.CanvasRenderer = function (container, dim) {\n this.type = 'canvas';\n\n this.canvasRoot = null;\n this.suspendHandle = null;\n this.canvasId = UUID.genUUID();\n\n this.canvasNamespace = null;\n\n if (Env.isBrowser) {\n this.container = container;\n this.container.style.MozUserSelect = 'none';\n this.container.style.userSelect = 'none';\n\n this.container.style.overflow = 'hidden';\n if (this.container.style.position === '') {\n this.container.style.position = 'relative';\n }\n\n this.container.innerHTML = ['<canvas id=\"', this.canvasId,\n '\" width=\"', dim.width,\n 'px\" height=\"', dim.height,\n 'px\"><', '/canvas>'].join('');\n this.canvasRoot = this.container.ownerDocument.getElementById(this.canvasId);\n this.canvasRoot.style.display = 'block';\n this.context = this.canvasRoot.getContext('2d');\n\n } else if (Env.isNode()) {\n try {\n this.canvasId = (typeof module === 'object' ? module.require('canvas') : require('canvas'));\n this.canvasRoot = new this.canvasId(500, 500);\n this.context = this.canvasRoot.getContext('2d');\n } catch (err) {\n console.log(\"Warning: 'canvas' not found. You might need to call 'npm install canvas'\");\n }\n }\n\n this.dashArray = [[2, 2], [5, 5], [10, 10], [20, 20], [20, 10, 10, 10], [20, 5, 10, 5]];\n };\n\n JXG.CanvasRenderer.prototype = new AbstractRenderer();\n\n JXG.extend(JXG.CanvasRenderer.prototype, /** @lends JXG.CanvasRenderer.prototype */ {\n\n /* **************************\n * private methods only used\n * in this renderer. Should\n * not be called from outside.\n * **************************/\n\n /**\n * Draws a filled polygon.\n * @param {Array} shape A matrix presented by a two dimensional array of numbers.\n * @see JXG.AbstractRenderer#drawArrows\n * @private\n */\n _drawPolygon: function (shape, degree, doFill) {\n var i, len = shape.length,\n context = this.context;\n\n if (len > 0) {\n if (doFill) {\n context.lineWidth = 0;\n }\n context.beginPath();\n context.moveTo(shape[0][0], shape[0][1]);\n if (degree === 1) {\n for (i = 1; i < len; i++) {\n context.lineTo(shape[i][0], shape[i][1]);\n }\n } else {\n for (i = 1; i < len; i += 3) {\n context.bezierCurveTo(shape[i][0], shape[i][1], shape[i + 1][0], shape[i + 1][1], shape[i + 2][0], shape[i + 2][1]);\n }\n }\n if (doFill) {\n context.lineTo(shape[0][0], shape[0][1]);\n context.closePath();\n context.fill();\n } else {\n context.stroke();\n }\n }\n },\n\n /**\n * Sets the fill color and fills an area.\n * @param {JXG.GeometryElement} el An arbitrary JSXGraph element, preferably one with an area.\n * @private\n */\n _fill: function (el) {\n var context = this.context;\n\n context.save();\n if (this._setColor(el, 'fill')) {\n context.fill();\n }\n context.restore();\n },\n\n /**\n * Rotates a point around <tt>(0, 0)</tt> by a given angle.\n * @param {Number} angle An angle, given in rad.\n * @param {Number} x X coordinate of the point.\n * @param {Number} y Y coordinate of the point.\n * @returns {Array} An array containing the x and y coordinate of the rotated point.\n * @private\n */\n _rotatePoint: function (angle, x, y) {\n return [\n (x * Math.cos(angle)) - (y * Math.sin(angle)),\n (x * Math.sin(angle)) + (y * Math.cos(angle))\n ];\n },\n\n /**\n * Rotates an array of points around <tt>(0, 0)</tt>.\n * @param {Array} shape An array of array of point coordinates.\n * @param {Number} angle The angle in rad the points are rotated by.\n * @returns {Array} Array of array of two dimensional point coordinates.\n * @private\n */\n _rotateShape: function (shape, angle) {\n var i, rv = [], len = shape.length;\n\n if (len <= 0) {\n return shape;\n }\n\n for (i = 0; i < len; i++) {\n rv.push(this._rotatePoint(angle, shape[i][0], shape[i][1]));\n }\n\n return rv;\n },\n\n /**\n * Set the gradient angle for linear color gradients.\n *\n * @private\n * @param {JXG.GeometryElement} node An arbitrary JSXGraph element, preferably one with an area.\n * @param {Number} radians angle value in radians. 0 is horizontal from left to right, Pi/4 is vertical from top to bottom.\n */\n updateGradientAngle: function(el, radians) {\n // Angles:\n // 0: ->\n // 90: down\n // 180: <-\n // 90: up\n var f = 1.0,\n co = Math.cos(-radians),\n si = Math.sin(-radians),\n bb = el.getBoundingBox(),\n c1, c2, x1, x2, y1, y2, x1s, x2s, y1s, y2s, dx, dy;\n\n if (Math.abs(co) > Math.abs(si)) {\n f /= Math.abs(co);\n } else {\n f /= Math.abs(si);\n }\n if (co >= 0) {\n x1 = 0;\n x2 = co * f;\n } else {\n x1 = -co * f;\n x2 = 0;\n }\n if (si >= 0) {\n y1 = 0;\n y2 = si * f;\n } else {\n y1 = -si * f;\n y2 = 0;\n }\n\n c1 = new Coords(Const.COORDS_BY_USER, [bb[0], bb[1]], el.board);\n c2 = new Coords(Const.COORDS_BY_USER, [bb[2], bb[3]], el.board);\n dx = c2.scrCoords[1] - c1.scrCoords[1];\n dy = c2.scrCoords[2] - c1.scrCoords[2];\n x1s = c1.scrCoords[1] + dx * x1;\n y1s = c1.scrCoords[2] + dy * y1;\n x2s = c1.scrCoords[1] + dx * x2;\n y2s = c1.scrCoords[2] + dy * y2;\n\n return this.context.createLinearGradient(x1s, y1s, x2s, y2s);\n },\n\n /**\n * Set circles for radial color gradients.\n *\n * @private\n * @param {SVGnode} node SVG gradient node\n * @param {Number} cx Canvas value x1 (but value between 0 and 1)\n * @param {Number} cy Canvas value y1 (but value between 0 and 1)\n * @param {Number} r Canvas value r1 (but value between 0 and 1)\n * @param {Number} fx Canvas value x0 (but value between 0 and 1)\n * @param {Number} fy Canvas value x1 (but value between 0 and 1)\n * @param {Number} fr Canvas value r0 (but value between 0 and 1)\n */\n updateGradientCircle: function(el, cx, cy, r, fx, fy, fr) {\n var bb = el.getBoundingBox(),\n c1, c2, cxs, cys, rs, fxs, fys, frs, dx, dy;\n\n c1 = new Coords(Const.COORDS_BY_USER, [bb[0], bb[1]], el.board);\n c2 = new Coords(Const.COORDS_BY_USER, [bb[2], bb[3]], el.board);\n dx = c2.scrCoords[1] - c1.scrCoords[1];\n dy = c1.scrCoords[2] - c2.scrCoords[2];\n\n cxs = c1.scrCoords[1] + dx * cx;\n cys = c2.scrCoords[2] + dy * cy;\n fxs = c1.scrCoords[1] + dx * fx;\n fys = c2.scrCoords[2] + dy * fy;\n rs = r * (dx + dy) * 0.5;\n frs = fr * (dx + dy) * 0.5;\n\n return this.context.createRadialGradient(fxs, fys, frs, cxs, cys, rs);\n },\n\n // documented in JXG.AbstractRenderer\n updateGradient: function(el) {\n var col, op,\n ev_g = Type.evaluate(el.visProp.gradient),\n gradient;\n\n op = Type.evaluate(el.visProp.fillopacity);\n op = (op > 0) ? op : 0;\n col = Type.evaluate(el.visProp.fillcolor);\n\n if (ev_g === 'linear') {\n gradient = this.updateGradientAngle(el, Type.evaluate(el.visProp.gradientangle));\n } else if (ev_g === 'radial') {\n gradient = this.updateGradientCircle(el,\n Type.evaluate(el.visProp.gradientcx),\n Type.evaluate(el.visProp.gradientcy),\n Type.evaluate(el.visProp.gradientr),\n Type.evaluate(el.visProp.gradientfx),\n Type.evaluate(el.visProp.gradientfy),\n Type.evaluate(el.visProp.gradientfr)\n );\n }\n gradient.addColorStop(Type.evaluate(el.visProp.gradientstartoffset), col);\n gradient.addColorStop(Type.evaluate(el.visProp.gradientendoffset),\n Type.evaluate(el.visProp.gradientsecondcolor));\n return gradient;\n },\n\n /**\n * Sets color and opacity for filling and stroking.\n * type is the attribute from visProp and targetType the context[targetTypeStyle].\n * This is necessary, because the fill style of a text is set by the stroke attributes of the text element.\n * @param {JXG.GeometryElement} el Any JSXGraph element.\n * @param {String} [type='stroke'] Either <em>fill</em> or <em>stroke</em>.\n * @param {String} [targetType=type] (optional) Either <em>fill</em> or <em>stroke</em>.\n * @returns {Boolean} If the color could be set, <tt>true</tt> is returned.\n * @private\n */\n _setColor: function (el, type, targetType) {\n var hasColor = true,\n ev = el.visProp, hl, sw,\n rgba, rgbo, c, o, oo,\n grad;\n\n type = type || 'stroke';\n targetType = targetType || type;\n\n hl = this._getHighlighted(el);\n\n grad = Type.evaluate(el.visProp.gradient);\n if (grad === 'linear' || grad === 'radial') {\n // TODO: opacity\n this.context[targetType + 'Style'] = this.updateGradient(el);\n return hasColor;\n }\n\n // type is equal to 'fill' or 'stroke'\n rgba = Type.evaluate(ev[hl + type + 'color']);\n if (rgba !== 'none' && rgba !== false) {\n o = Type.evaluate(ev[hl + type + 'opacity']);\n o = (o > 0) ? o : 0;\n\n // RGB, not RGBA\n if (rgba.length !== 9) {\n c = rgba;\n oo = o;\n // True RGBA, not RGB\n } else {\n rgbo = Color.rgba2rgbo(rgba);\n c = rgbo[0];\n oo = o * rgbo[1];\n }\n this.context.globalAlpha = oo;\n\n this.context[targetType + 'Style'] = c;\n\n } else {\n hasColor = false;\n }\n\n sw = parseFloat(Type.evaluate(ev[hl + 'strokewidth']));\n if (type === 'stroke' && !isNaN(sw)) {\n if (sw === 0) {\n this.context.globalAlpha = 0;\n } else {\n this.context.lineWidth = sw;\n }\n }\n\n if (type === 'stroke' && ev.linecap !== undefined && ev.linecap !== '') {\n this.context.lineCap = ev.linecap;\n }\n\n return hasColor;\n },\n\n /**\n * Sets color and opacity for drawing paths and lines and draws the paths and lines.\n * @param {JXG.GeometryElement} el An JSXGraph element with a stroke.\n * @private\n */\n _stroke: function (el) {\n var context = this.context,\n ev_dash = Type.evaluate(el.visProp.dash);\n\n context.save();\n\n if (ev_dash > 0) {\n if (context.setLineDash) {\n context.setLineDash(this.dashArray[ev_dash]);\n }\n } else {\n this.context.lineDashArray = [];\n }\n\n if (this._setColor(el, 'stroke')) {\n context.stroke();\n }\n\n context.restore();\n },\n\n /**\n * Translates a set of points.\n * @param {Array} shape An array of point coordinates.\n * @param {Number} x Translation in X direction.\n * @param {Number} y Translation in Y direction.\n * @returns {Array} An array of translated point coordinates.\n * @private\n */\n _translateShape: function (shape, x, y) {\n var i, rv = [], len = shape.length;\n\n if (len <= 0) {\n return shape;\n }\n\n for (i = 0; i < len; i++) {\n rv.push([ shape[i][0] + x, shape[i][1] + y ]);\n }\n\n return rv;\n },\n\n /* ******************************** *\n * Point drawing and updating *\n * ******************************** */\n\n // documented in AbstractRenderer\n drawPoint: function (el) {\n var f = Type.evaluate(el.visProp.face),\n size = Type.evaluate(el.visProp.size),\n scr = el.coords.scrCoords,\n sqrt32 = size * Math.sqrt(3) * 0.5,\n s05 = size * 0.5,\n stroke05 = parseFloat(Type.evaluate(el.visProp.strokewidth)) / 2.0,\n context = this.context;\n\n if (!el.visPropCalc.visible) {\n return;\n }\n\n switch (f) {\n case 'cross': // x\n case 'x':\n context.beginPath();\n context.moveTo(scr[1] - size, scr[2] - size);\n context.lineTo(scr[1] + size, scr[2] + size);\n context.moveTo(scr[1] + size, scr[2] - size);\n context.lineTo(scr[1] - size, scr[2] + size);\n context.lineCap = 'round';\n context.lineJoin = 'round';\n context.closePath();\n this._stroke(el);\n break;\n case 'circle': // dot\n case 'o':\n context.beginPath();\n context.arc(scr[1], scr[2], size + 1 + stroke05, 0, 2 * Math.PI, false);\n context.closePath();\n this._fill(el);\n this._stroke(el);\n break;\n case 'square': // rectangle\n case '[]':\n if (size <= 0) {\n break;\n }\n\n context.save();\n if (this._setColor(el, 'stroke', 'fill')) {\n context.fillRect(scr[1] - size - stroke05, scr[2] - size - stroke05, size * 2 + 3 * stroke05, size * 2 + 3 * stroke05);\n }\n context.restore();\n context.save();\n this._setColor(el, 'fill');\n context.fillRect(scr[1] - size + stroke05, scr[2] - size + stroke05, size * 2 - stroke05, size * 2 - stroke05);\n context.restore();\n break;\n case 'plus': // +\n case '+':\n context.beginPath();\n context.moveTo(scr[1] - size, scr[2]);\n context.lineTo(scr[1] + size, scr[2]);\n context.moveTo(scr[1], scr[2] - size);\n context.lineTo(scr[1], scr[2] + size);\n context.lineCap = 'round';\n context.lineJoin = 'round';\n context.closePath();\n this._stroke(el);\n break;\n case 'diamond': // <>\n case '<>':\n context.beginPath();\n context.moveTo(scr[1] - size, scr[2]);\n context.lineTo(scr[1], scr[2] + size);\n context.lineTo(scr[1] + size, scr[2]);\n context.lineTo(scr[1], scr[2] - size);\n context.closePath();\n this._fill(el);\n this._stroke(el);\n break;\n case 'triangleup':\n case 'a':\n case '^':\n context.beginPath();\n context.moveTo(scr[1], scr[2] - size);\n context.lineTo(scr[1] - sqrt32, scr[2] + s05);\n context.lineTo(scr[1] + sqrt32, scr[2] + s05);\n context.closePath();\n this._fill(el);\n this._stroke(el);\n break;\n case 'triangledown':\n case 'v':\n context.beginPath();\n context.moveTo(scr[1], scr[2] + size);\n context.lineTo(scr[1] - sqrt32, scr[2] - s05);\n context.lineTo(scr[1] + sqrt32, scr[2] - s05);\n context.closePath();\n this._fill(el);\n this._stroke(el);\n break;\n case 'triangleleft':\n case '<':\n context.beginPath();\n context.moveTo(scr[1] - size, scr[2]);\n context.lineTo(scr[1] + s05, scr[2] - sqrt32);\n context.lineTo(scr[1] + s05, scr[2] + sqrt32);\n context.closePath();\n this._fill(el);\n this._stroke(el);\n break;\n case 'triangleright':\n case '>':\n context.beginPath();\n context.moveTo(scr[1] + size, scr[2]);\n context.lineTo(scr[1] - s05, scr[2] - sqrt32);\n context.lineTo(scr[1] - s05, scr[2] + sqrt32);\n context.closePath();\n this._fill(el);\n this._stroke(el);\n break;\n }\n },\n\n // documented in AbstractRenderer\n updatePoint: function (el) {\n this.drawPoint(el);\n },\n\n /* ******************************** *\n * Lines *\n * ******************************** */\n\n /**\n * Draws arrows of an element (usually a line) in canvas renderer.\n * @param {JXG.GeometryElement} el Line to be drawn.\n * @param {Array} scr1 Screen coordinates of the start position of the line or curve.\n * @param {Array} scr2 Screen coordinates of the end position of the line or curve.\n * @param {String} hl String which carries information if the element is highlighted. Used for getting the correct attribute.\n * @private\n */\n drawArrows: function (el, scr1, scr2, hl, a) {\n var x1, y1, x2, y2,\n w0, w,\n arrowHead,\n arrowTail,\n context = this.context,\n size = 6,\n type = 1,\n type_fa, type_la,\n degree_fa = 1,\n degree_la = 1,\n doFill,\n i, len,\n d1x, d1y, d2x, d2y, last,\n ang1, ang2,\n ev_fa = a.evFirst,\n ev_la = a.evLast;\n\n if (Type.evaluate(el.visProp.strokecolor) !== 'none' &&\n (ev_fa || ev_la)) {\n\n if (el.elementClass === Const.OBJECT_CLASS_LINE) {\n x1 = scr1.scrCoords[1];\n y1 = scr1.scrCoords[2];\n x2 = scr2.scrCoords[1];\n y2 = scr2.scrCoords[2];\n ang1 = ang2 = Math.atan2(y2 - y1, x2 - x1);\n } else {\n x1 = el.points[0].scrCoords[1];\n y1 = el.points[0].scrCoords[2];\n\n last = el.points.length - 1;\n if (last < 1) {\n // No arrows for curves consisting of 1 point\n return;\n }\n x2 = el.points[el.points.length - 1].scrCoords[1];\n y2 = el.points[el.points.length - 1].scrCoords[2];\n\n d1x = el.points[1].scrCoords[1] - el.points[0].scrCoords[1];\n d1y = el.points[1].scrCoords[2] - el.points[0].scrCoords[2];\n d2x = el.points[last].scrCoords[1] - el.points[last - 1].scrCoords[1];\n d2y = el.points[last].scrCoords[2] - el.points[last - 1].scrCoords[2];\n if (ev_fa) {\n ang1 = Math.atan2(d1y, d1x);\n }\n if (ev_la) {\n ang2 = Math.atan2(d2y, d2x);\n }\n }\n\n w0 = Type.evaluate(el.visProp[hl + 'strokewidth']);\n\n if (ev_fa) {\n size = a.sizeFirst;\n\n w = w0 * size;\n\n type = a.typeFirst;\n type_fa = type;\n\n if (type === 2) {\n arrowTail = [\n [ w, -w * 0.5],\n [ 0.0, 0.0],\n [ w, w * 0.5],\n [ w * 0.5, 0.0],\n ];\n } else if (type === 3) {\n arrowTail = [\n [ w / 3.0, -w * 0.5],\n [ 0.0, -w * 0.5],\n [ 0.0, w * 0.5],\n [ w / 3.0, w * 0.5]\n ];\n } else if (type === 4) {\n w /= 10;\n degree_fa = 3;\n arrowTail = [\n [10.00, 3.31],\n [6.47, 3.84],\n [2.87, 4.50],\n [0.00, 6.63],\n [0.67, 5.52],\n [1.33, 4.42],\n [2.00, 3.31],\n [1.33, 2.21],\n [0.67, 1.10],\n [0.00, 0.00],\n [2.87, 2.13],\n [6.47, 2.79],\n [10.00, 3.31]\n ];\n len = arrowTail.length;\n for (i = 0; i < len; i++) {\n arrowTail[i][0] *= -w;\n arrowTail[i][1] *= w;\n arrowTail[i][0] += 10 * w;\n arrowTail[i][1] -= 3.31 * w;\n }\n } else if (type === 5) {\n w /= 10;\n degree_fa = 3;\n arrowTail = [\n [10.00,3.28],\n [6.61,4.19],\n [3.19,5.07],\n [0.00,6.55],\n [0.62,5.56],\n [1.00,4.44],\n [1.00,3.28],\n [1.00,2.11],\n [0.62,0.99],\n [0.00,0.00],\n [3.19,1.49],\n [6.61,2.37],\n [10.00,3.28]\n ];\n len = arrowTail.length;\n for (i = 0; i < len; i++) {\n arrowTail[i][0] *= -w;\n arrowTail[i][1] *= w;\n arrowTail[i][0] += 10 * w;\n arrowTail[i][1] -= 3.28 * w;\n }\n } else if (type === 6) {\n w /= 10;\n degree_fa = 3;\n arrowTail = [\n [10.00,2.84],\n [6.61,3.59],\n [3.21,4.35],\n [0.00,5.68],\n [0.33,4.73],\n [0.67,3.78],\n [1.00,2.84],\n [0.67,1.89],\n [0.33,0.95],\n [0.00,0.00],\n [3.21,1.33],\n [6.61,2.09],\n [10.00,2.84]\n ];\n len = arrowTail.length;\n for (i = 0; i < len; i++) {\n arrowTail[i][0] *= -w;\n arrowTail[i][1] *= w;\n arrowTail[i][0] += 10 * w;\n arrowTail[i][1] -= 2.84 * w;\n }\n } else if (type === 7) {\n w = w0;\n degree_fa = 3;\n arrowTail = [\n [0.00,10.39],\n [2.01,6.92],\n [5.96,5.20],\n [10.00,5.20],\n [5.96,5.20],\n [2.01,3.47],\n [0.00,0.00]\n ];\n len = arrowTail.length;\n for (i = 0; i < len; i++) {\n arrowTail[i][0] *= -w;\n arrowTail[i][1] *= w;\n arrowTail[i][0] += 10 * w;\n arrowTail[i][1] -= 5.20 * w;\n }\n } else {\n arrowTail = [\n [ w, -w * 0.5],\n [ 0.0, 0.0],\n [ w, w * 0.5]\n ];\n }\n }\n\n if (ev_la) {\n size = a.sizeLast;\n w = w0 * size;\n\n type = a.typeLast;\n type_la = type;\n if (type === 2) {\n arrowHead = [\n [ -w, -w * 0.5],\n [ 0.0, 0.0],\n [ -w, w * 0.5],\n [ -w * 0.5, 0.0]\n ];\n } else if (type === 3) {\n arrowHead = [\n [-w / 3.0, -w * 0.5],\n [ 0.0, -w * 0.5],\n [ 0.0, w * 0.5],\n [-w / 3.0, w * 0.5]\n ];\n } else if (type === 4) {\n w /= 10;\n degree_la = 3;\n arrowHead = [\n [10.00, 3.31],\n [6.47, 3.84],\n [2.87, 4.50],\n [0.00, 6.63],\n [0.67, 5.52],\n [1.33, 4.42],\n [2.00, 3.31],\n [1.33, 2.21],\n [0.67, 1.10],\n [0.00, 0.00],\n [2.87, 2.13],\n [6.47, 2.79],\n [10.00, 3.31]\n ];\n len = arrowHead.length;\n for (i = 0; i < len; i++) {\n arrowHead[i][0] *= w;\n arrowHead[i][1] *= w;\n arrowHead[i][0] -= 10 * w;\n arrowHead[i][1] -= 3.31 * w;\n\n }\n } else if (type === 5) {\n w /= 10;\n degree_la = 3;\n arrowHead = [\n [10.00,3.28],\n [6.61,4.19],\n [3.19,5.07],\n [0.00,6.55],\n [0.62,5.56],\n [1.00,4.44],\n [1.00,3.28],\n [1.00,2.11],\n [0.62,0.99],\n [0.00,0.00],\n [3.19,1.49],\n [6.61,2.37],\n [10.00,3.28]\n ];\n len = arrowHead.length;\n for (i = 0; i < len; i++) {\n arrowHead[i][0] *= w;\n arrowHead[i][1] *= w;\n arrowHead[i][0] -= 10 * w;\n arrowHead[i][1] -= 3.28 * w;\n\n }\n } else if (type === 6) {\n w /= 10;\n degree_la = 3;\n arrowHead = [\n [10.00,2.84],\n [6.61,3.59],\n [3.21,4.35],\n [0.00,5.68],\n [0.33,4.73],\n [0.67,3.78],\n [1.00,2.84],\n [0.67,1.89],\n [0.33,0.95],\n [0.00,0.00],\n [3.21,1.33],\n [6.61,2.09],\n [10.00,2.84]\n ];\n len = arrowHead.length;\n for (i = 0; i < len; i++) {\n arrowHead[i][0] *= w;\n arrowHead[i][1] *= w;\n arrowHead[i][0] -= 10 * w;\n arrowHead[i][1] -= 2.84 * w;\n\n }\n\n } else if (type === 7) {\n w = w0;\n degree_la = 3;\n arrowHead = [\n [0.00,10.39],\n [2.01,6.92],\n [5.96,5.20],\n [10.00,5.20],\n [5.96,5.20],\n [2.01,3.47],\n [0.00,0.00]\n ];\n len = arrowHead.length;\n for (i = 0; i < len; i++) {\n arrowHead[i][0] *= w;\n arrowHead[i][1] *= w;\n arrowHead[i][0] -= 10 * w;\n arrowHead[i][1] -= 5.20 * w;\n\n }\n } else {\n arrowHead = [\n [ -w, -w * 0.5],\n [ 0.0, 0.0],\n [ -w, w * 0.5]\n ];\n }\n }\n\n context.save();\n if (this._setColor(el, 'stroke', 'fill')) {\n this._setColor(el, 'stroke');\n if (ev_fa) {\n if (type_fa === 7) {\n doFill = false;\n } else {\n doFill = true;\n }\n this._drawPolygon(this._translateShape(this._rotateShape(arrowTail, ang1), x1, y1), degree_fa, doFill);\n }\n if (ev_la) {\n if (type_la === 7) {\n doFill = false;\n } else {\n doFill = true;\n }\n this._drawPolygon(this._translateShape(this._rotateShape(arrowHead, ang2), x2, y2), degree_la, doFill);\n }\n }\n context.restore();\n }\n },\n\n // documented in AbstractRenderer\n drawLine: function (el) {\n var c1_org, c2_org,\n c1 = new Coords(Const.COORDS_BY_USER, el.point1.coords.usrCoords, el.board),\n c2 = new Coords(Const.COORDS_BY_USER, el.point2.coords.usrCoords, el.board),\n margin = null,\n hl, w, arrowData;\n\n if (!el.visPropCalc.visible) {\n return;\n }\n\n hl = this._getHighlighted(el);\n w = Type.evaluate(el.visProp[hl + 'strokewidth']);\n arrowData = this.getArrowHeadData(el, w, hl);\n\n if (arrowData.evFirst || arrowData.evLast) {\n margin = -4;\n }\n Geometry.calcStraight(el, c1, c2, margin);\n this.handleTouchpoints(el, c1, c2, arrowData);\n\n c1_org = new Coords(Const.COORDS_BY_USER, c1.usrCoords, el.board);\n c2_org = new Coords(Const.COORDS_BY_USER, c2.usrCoords, el.board);\n\n this.getPositionArrowHead(el, c1, c2, arrowData);\n\n this.context.beginPath();\n this.context.moveTo(c1.scrCoords[1], c1.scrCoords[2]);\n this.context.lineTo(c2.scrCoords[1], c2.scrCoords[2]);\n this._stroke(el);\n\n if ((arrowData.evFirst/* && obj.sFirst > 0*/) ||\n (arrowData.evLast/* && obj.sLast > 0*/)) {\n\n this.drawArrows(el, c1_org, c2_org, hl, arrowData);\n }\n },\n\n // documented in AbstractRenderer\n updateLine: function (el) {\n this.drawLine(el);\n },\n\n // documented in AbstractRenderer\n drawTicks: function () {\n // this function is supposed to initialize the svg/vml nodes in the SVG/VMLRenderer.\n // but in canvas there are no such nodes, hence we just do nothing and wait until\n // updateTicks is called.\n },\n\n // documented in AbstractRenderer\n updateTicks: function (ticks) {\n var i, c, x, y,\n len = ticks.ticks.length,\n len2, j,\n context = this.context;\n\n context.beginPath();\n for (i = 0; i < len; i++) {\n c = ticks.ticks[i];\n x = c[0];\n y = c[1];\n\n // context.moveTo(x[0], y[0]);\n // context.lineTo(x[1], y[1]);\n len2 = x.length;\n context.moveTo(x[0], y[0]);\n for (j = 1; j < len2; ++j) {\n context.lineTo(x[j], y[j]);\n }\n\n }\n // Labels\n // for (i = 0; i < len; i++) {\n // c = ticks.ticks[i].scrCoords;\n // if (ticks.ticks[i].major &&\n // (ticks.board.needsFullUpdate || ticks.needsRegularUpdate) &&\n // ticks.labels[i] &&\n // ticks.labels[i].visPropCalc.visible) {\n // this.updateText(ticks.labels[i]);\n // }\n // }\n context.lineCap = 'round';\n this._stroke(ticks);\n },\n\n /* **************************\n * Curves\n * **************************/\n\n // documented in AbstractRenderer\n drawCurve: function (el) {\n var hl, w, arrowData;\n\n if (Type.evaluate(el.visProp.handdrawing)) {\n this.updatePathStringBezierPrim(el);\n } else {\n this.updatePathStringPrim(el);\n }\n if (el.numberPoints > 1) {\n hl = this._getHighlighted(el);\n w = Type.evaluate(el.visProp[hl + 'strokewidth']);\n arrowData = this.getArrowHeadData(el, w, hl);\n if ((arrowData.evFirst/* && obj.sFirst > 0*/) ||\n (arrowData.evLast/* && obj.sLast > 0*/)) {\n this.drawArrows(el, null, null, hl, arrowData);\n }\n }\n },\n\n // documented in AbstractRenderer\n updateCurve: function (el) {\n this.drawCurve(el);\n },\n\n /* **************************\n * Circle related stuff\n * **************************/\n\n // documented in AbstractRenderer\n drawEllipse: function (el) {\n var m1 = el.center.coords.scrCoords[1],\n m2 = el.center.coords.scrCoords[2],\n sX = el.board.unitX,\n sY = el.board.unitY,\n rX = 2 * el.Radius(),\n rY = 2 * el.Radius(),\n aWidth = rX * sX,\n aHeight = rY * sY,\n aX = m1 - aWidth / 2,\n aY = m2 - aHeight / 2,\n hB = (aWidth / 2) * 0.5522848,\n vB = (aHeight / 2) * 0.5522848,\n eX = aX + aWidth,\n eY = aY + aHeight,\n mX = aX + aWidth / 2,\n mY = aY + aHeight / 2,\n context = this.context;\n\n if (rX > 0.0 && rY > 0.0 && !isNaN(m1 + m2)) {\n context.beginPath();\n context.moveTo(aX, mY);\n context.bezierCurveTo(aX, mY - vB, mX - hB, aY, mX, aY);\n context.bezierCurveTo(mX + hB, aY, eX, mY - vB, eX, mY);\n context.bezierCurveTo(eX, mY + vB, mX + hB, eY, mX, eY);\n context.bezierCurveTo(mX - hB, eY, aX, mY + vB, aX, mY);\n context.closePath();\n this._fill(el);\n this._stroke(el);\n }\n },\n\n // documented in AbstractRenderer\n updateEllipse: function (el) {\n return this.drawEllipse(el);\n },\n\n /* **************************\n * Polygon\n * **************************/\n\n // nothing here, using AbstractRenderer implementations\n\n /* **************************\n * Text related stuff\n * **************************/\n\n // Already documented in JXG.AbstractRenderer\n displayCopyright: function (str, fontSize) {\n var context = this.context;\n\n // this should be called on EVERY update, otherwise it won't be shown after the first update\n context.save();\n context.font = fontSize + 'px Arial';\n context.fillStyle = '#aaa';\n context.lineWidth = 0.5;\n context.fillText(str, 10, 2 + fontSize);\n context.restore();\n },\n\n // Already documented in JXG.AbstractRenderer\n drawInternalText: function (el) {\n var ev_fs = Type.evaluate(el.visProp.fontsize),\n fontUnit = Type.evaluate(el.visProp.fontunit),\n ev_ax = el.getAnchorX(),\n ev_ay = el.getAnchorY(),\n context = this.context;\n\n context.save();\n if (this._setColor(el, 'stroke', 'fill') &&\n !isNaN(el.coords.scrCoords[1] + el.coords.scrCoords[2])) {\n context.font = (ev_fs > 0 ? ev_fs : 0) + fontUnit + ' Arial';\n\n this.transformImage(el, el.transformations);\n if (ev_ax === 'left') {\n context.textAlign = 'left';\n } else if (ev_ax === 'right') {\n context.textAlign = 'right';\n } else if (ev_ax === 'middle') {\n context.textAlign = 'center';\n }\n if (ev_ay === 'bottom') {\n context.textBaseline = 'bottom';\n } else if (ev_ay === 'top') {\n context.textBaseline = 'top';\n } else if (ev_ay === 'middle') {\n context.textBaseline = 'middle';\n }\n context.fillText(el.plaintext, el.coords.scrCoords[1], el.coords.scrCoords[2]);\n }\n context.restore();\n return null;\n },\n\n // Already documented in JXG.AbstractRenderer\n updateInternalText: function (el) {\n this.drawInternalText(el);\n },\n\n // documented in JXG.AbstractRenderer\n // Only necessary for texts\n setObjectStrokeColor: function (el, color, opacity) {\n var rgba = Type.evaluate(color), c, rgbo,\n o = Type.evaluate(opacity), oo,\n node;\n\n o = (o > 0) ? o : 0;\n\n if (el.visPropOld.strokecolor === rgba && el.visPropOld.strokeopacity === o) {\n return;\n }\n\n // Check if this could be merged with _setColor\n\n if (Type.exists(rgba) && rgba !== false) {\n // RGB, not RGBA\n if (rgba.length !== 9) {\n c = rgba;\n oo = o;\n // True RGBA, not RGB\n } else {\n rgbo = Color.rgba2rgbo(rgba);\n c = rgbo[0];\n oo = o * rgbo[1];\n }\n node = el.rendNode;\n if (el.elementClass === Const.OBJECT_CLASS_TEXT && Type.evaluate(el.visProp.display) === 'html') {\n node.style.color = c;\n node.style.opacity = oo;\n }\n }\n\n el.visPropOld.strokecolor = rgba;\n el.visPropOld.strokeopacity = o;\n },\n\n /* **************************\n * Image related stuff\n * **************************/\n\n // Already documented in JXG.AbstractRenderer\n drawImage: function (el) {\n el.rendNode = new Image();\n // Store the file name of the image.\n // Before, this was done in el.rendNode.src\n // But there, the file name is expanded to\n // the full url. This may be different from\n // the url computed in updateImageURL().\n el._src = '';\n this.updateImage(el);\n },\n\n // Already documented in JXG.AbstractRenderer\n updateImage: function (el) {\n var context = this.context,\n o = Type.evaluate(el.visProp.fillopacity),\n paintImg = Type.bind(function () {\n el.imgIsLoaded = true;\n if (el.size[0] <= 0 || el.size[1] <= 0) {\n return;\n }\n context.save();\n context.globalAlpha = o;\n // If det(el.transformations)=0, FireFox 3.6. breaks down.\n // This is tested in transformImage\n this.transformImage(el, el.transformations);\n context.drawImage(el.rendNode,\n el.coords.scrCoords[1],\n el.coords.scrCoords[2] - el.size[1],\n el.size[0],\n el.size[1]);\n context.restore();\n }, this);\n\n if (this.updateImageURL(el)) {\n el.rendNode.onload = paintImg;\n } else {\n if (el.imgIsLoaded) {\n paintImg();\n }\n }\n },\n\n // Already documented in JXG.AbstractRenderer\n transformImage: function (el, t) {\n var m, len = t.length,\n ctx = this.context;\n\n if (len > 0) {\n m = this.joinTransforms(el, t);\n if (Math.abs(Numerics.det(m)) >= Mat.eps) {\n ctx.transform(m[1][1], m[2][1], m[1][2], m[2][2], m[1][0], m[2][0]);\n }\n }\n },\n\n // Already documented in JXG.AbstractRenderer\n updateImageURL: function (el) {\n var url;\n\n url = Type.evaluate(el.url);\n if (el._src !== url) {\n el.imgIsLoaded = false;\n el.rendNode.src = url;\n el._src = url;\n return true;\n }\n\n return false;\n },\n\n /* **************************\n * Render primitive objects\n * **************************/\n\n // documented in AbstractRenderer\n remove: function (shape) {\n // sounds odd for a pixel based renderer but we need this for html texts\n if (Type.exists(shape) && Type.exists(shape.parentNode)) {\n shape.parentNode.removeChild(shape);\n }\n },\n\n // documented in AbstractRenderer\n updatePathStringPrim: function (el) {\n var i, scr, scr1, scr2, len,\n symbm = 'M',\n symbl = 'L',\n symbc = 'C',\n nextSymb = symbm,\n maxSize = 5000.0,\n context = this.context;\n\n if (el.numberPoints <= 0) {\n return;\n }\n\n len = Math.min(el.points.length, el.numberPoints);\n context.beginPath();\n\n if (el.bezierDegree === 1) {\n /*\n if (isNotPlot && el.board.options.curve.RDPsmoothing) {\n el.points = Numerics.RamerDouglasPeucker(el.points, 0.5);\n }\n */\n\n for (i = 0; i < len; i++) {\n scr = el.points[i].scrCoords;\n\n if (isNaN(scr[1]) || isNaN(scr[2])) { // PenUp\n nextSymb = symbm;\n } else {\n // Chrome has problems with values being too far away.\n if (scr[1] > maxSize) {\n scr[1] = maxSize;\n } else if (scr[1] < -maxSize) {\n scr[1] = -maxSize;\n }\n\n if (scr[2] > maxSize) {\n scr[2] = maxSize;\n } else if (scr[2] < -maxSize) {\n scr[2] = -maxSize;\n }\n\n if (nextSymb === symbm) {\n context.moveTo(scr[1], scr[2]);\n } else {\n context.lineTo(scr[1], scr[2]);\n }\n nextSymb = symbl;\n }\n }\n } else if (el.bezierDegree === 3) {\n i = 0;\n while (i < len) {\n scr = el.points[i].scrCoords;\n if (isNaN(scr[1]) || isNaN(scr[2])) { // PenUp\n nextSymb = symbm;\n } else {\n if (nextSymb === symbm) {\n context.moveTo(scr[1], scr[2]);\n } else {\n i += 1;\n scr1 = el.points[i].scrCoords;\n i += 1;\n scr2 = el.points[i].scrCoords;\n context.bezierCurveTo(scr[1], scr[2], scr1[1], scr1[2], scr2[1], scr2[2]);\n }\n nextSymb = symbc;\n }\n i += 1;\n }\n }\n context.lineCap = 'round';\n this._fill(el);\n this._stroke(el);\n },\n\n // Already documented in JXG.AbstractRenderer\n updatePathStringBezierPrim: function (el) {\n var i, j, k, scr, lx, ly, len,\n symbm = 'M',\n symbl = 'C',\n nextSymb = symbm,\n maxSize = 5000.0,\n f = Type.evaluate(el.visProp.strokewidth),\n isNoPlot = (Type.evaluate(el.visProp.curvetype) !== 'plot'),\n context = this.context;\n\n if (el.numberPoints <= 0) {\n return;\n }\n\n if (isNoPlot && el.board.options.curve.RDPsmoothing) {\n el.points = Numerics.RamerDouglasPeucker(el.points, 0.5);\n }\n\n len = Math.min(el.points.length, el.numberPoints);\n context.beginPath();\n\n for (j = 1; j < 3; j++) {\n nextSymb = symbm;\n for (i = 0; i < len; i++) {\n scr = el.points[i].scrCoords;\n\n if (isNaN(scr[1]) || isNaN(scr[2])) { // PenUp\n nextSymb = symbm;\n } else {\n // Chrome has problems with values being too far away.\n if (scr[1] > maxSize) {\n scr[1] = maxSize;\n } else if (scr[1] < -maxSize) {\n scr[1] = -maxSize;\n }\n\n if (scr[2] > maxSize) {\n scr[2] = maxSize;\n } else if (scr[2] < -maxSize) {\n scr[2] = -maxSize;\n }\n\n if (nextSymb === symbm) {\n context.moveTo(scr[1], scr[2]);\n } else {\n k = 2 * j;\n context.bezierCurveTo(\n (lx + (scr[1] - lx) * 0.333 + f * (k * Math.random() - j)),\n (ly + (scr[2] - ly) * 0.333 + f * (k * Math.random() - j)),\n (lx + (scr[1] - lx) * 0.666 + f * (k * Math.random() - j)),\n (ly + (scr[2] - ly) * 0.666 + f * (k * Math.random() - j)),\n scr[1],\n scr[2]\n );\n }\n nextSymb = symbl;\n lx = scr[1];\n ly = scr[2];\n }\n }\n }\n context.lineCap = 'round';\n this._fill(el);\n this._stroke(el);\n },\n\n // documented in AbstractRenderer\n updatePolygonPrim: function (node, el) {\n var scrCoords, i, j,\n len = el.vertices.length,\n context = this.context,\n isReal = true;\n\n if (len <= 0 || !el.visPropCalc.visible) {\n return;\n }\n if (el.elType === 'polygonalchain') {\n len++;\n }\n\n context.beginPath();\n i = 0;\n while (!el.vertices[i].isReal && i < len - 1) {\n i++;\n isReal = false;\n }\n scrCoords = el.vertices[i].coords.scrCoords;\n context.moveTo(scrCoords[1], scrCoords[2]);\n\n for (j = i; j < len - 1; j++) {\n if (!el.vertices[j].isReal) {\n isReal = false;\n }\n scrCoords = el.vertices[j].coords.scrCoords;\n context.lineTo(scrCoords[1], scrCoords[2]);\n }\n context.closePath();\n\n if (isReal) {\n this._fill(el); // The edges of a polygon are displayed separately (as segments).\n }\n },\n\n // ************************** Set Attributes *************************\n\n // Already documented in JXG.AbstractRenderer\n display: function(el, val) {\n if (el && el.rendNode) {\n el.visPropOld.visible = val;\n if (val) {\n el.rendNode.style.visibility = \"inherit\";\n } else {\n el.rendNode.style.visibility = \"hidden\";\n }\n }\n },\n\n // documented in AbstractRenderer\n show: function (el) {\n JXG.deprecated('Board.renderer.show()', 'Board.renderer.display()');\n\n if (Type.exists(el.rendNode)) {\n el.rendNode.style.visibility = \"inherit\";\n }\n },\n\n // documented in AbstractRenderer\n hide: function (el) {\n JXG.deprecated('Board.renderer.hide()', 'Board.renderer.display()');\n\n if (Type.exists(el.rendNode)) {\n el.rendNode.style.visibility = \"hidden\";\n }\n },\n\n // documented in AbstractRenderer\n setGradient: function (el) {\n var // col,\n op;\n\n op = Type.evaluate(el.visProp.fillopacity);\n op = (op > 0) ? op : 0;\n\n // col = Type.evaluate(el.visProp.fillcolor);\n },\n\n // documented in AbstractRenderer\n setShadow: function (el) {\n if (el.visPropOld.shadow === el.visProp.shadow) {\n return;\n }\n\n // not implemented yet\n // we simply have to redraw the element\n // probably the best way to do so would be to call el.updateRenderer(), i think.\n\n el.visPropOld.shadow = el.visProp.shadow;\n },\n\n // documented in AbstractRenderer\n highlight: function (obj) {\n if (obj.elementClass === Const.OBJECT_CLASS_TEXT && Type.evaluate(obj.visProp.display) === 'html') {\n this.updateTextStyle(obj, true);\n } else {\n obj.board.prepareUpdate();\n obj.board.renderer.suspendRedraw(obj.board);\n obj.board.updateRenderer();\n obj.board.renderer.unsuspendRedraw();\n }\n return this;\n },\n\n // documented in AbstractRenderer\n noHighlight: function (obj) {\n if (obj.elementClass === Const.OBJECT_CLASS_TEXT && Type.evaluate(obj.visProp.display) === 'html') {\n this.updateTextStyle(obj, false);\n } else {\n obj.board.prepareUpdate();\n obj.board.renderer.suspendRedraw(obj.board);\n obj.board.updateRenderer();\n obj.board.renderer.unsuspendRedraw();\n }\n return this;\n },\n\n /* **************************\n * renderer control\n * **************************/\n\n // documented in AbstractRenderer\n suspendRedraw: function (board) {\n this.context.save();\n this.context.clearRect(0, 0, this.canvasRoot.width, this.canvasRoot.height);\n\n if (board && board.attr.showcopyright) {\n this.displayCopyright(JXG.licenseText, 12);\n }\n },\n\n // documented in AbstractRenderer\n unsuspendRedraw: function () {\n this.context.restore();\n },\n\n // document in AbstractRenderer\n resize: function (w, h) {\n if (this.container) {\n this.canvasRoot.style.width = parseFloat(w) + 'px';\n this.canvasRoot.style.height = parseFloat(h) + 'px';\n\n this.canvasRoot.setAttribute('width', (2 * parseFloat(w)) + 'px');\n this.canvasRoot.setAttribute('height',(2 * parseFloat(h)) + 'px');\n } else {\n this.canvasRoot.width = 2 * parseFloat(w);\n this.canvasRoot.height = 2 * parseFloat(h);\n }\n this.context = this.canvasRoot.getContext('2d');\n // The width and height of the canvas is set to twice the CSS values,\n // followed by an appropiate scaling.\n // See http://stackoverflow.com/questions/22416462/canvas-element-with-blurred-lines\n this.context.scale(2, 2);\n },\n\n removeToInsertLater: function () {\n return function () {};\n }\n });\n\n return JXG.CanvasRenderer;\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true, AMprocessNode: true, MathJax: true, document: true */\n/*jslint nomen: true, plusplus: true, newcap:true, unparam: true*/\n/*eslint no-unused-vars: \"off\"*/\n\n/* depends:\n jxg\n renderer/abstract\n*/\n\n/**\n * @fileoverview JSXGraph can use various technologies to render the contents of a construction, e.g.\n * SVG, VML, and HTML5 Canvas. To accomplish this, The rendering and the logic and control mechanisms\n * are completely separated from each other. Every rendering technology has it's own class, called\n * Renderer, e.g. SVGRenderer for SVG, the same for VML and Canvas. The common base for all available\n * renderers is the class AbstractRenderer.\n */\n\ndefine('renderer/no',['jxg', 'renderer/abstract'], function (JXG, AbstractRenderer) {\n\n \"use strict\";\n\n /**\n * This renderer draws nothing. It is intended to be used in environments where none of our rendering engines\n * are available, e.g. WebWorkers. All methods are empty.\n * \n * @class JXG.NoRenderer\n * @augments JXG.AbstractRenderer\n * @see JXG.AbstractRenderer\n */\n JXG.NoRenderer = function () {\n /**\n * If this property is set to <tt>true</tt> the visual properties of the elements are updated\n * on every update. Visual properties means: All the stuff stored in the\n * {@link JXG.GeometryElement#visProp} property won't be set if enhancedRendering is <tt>false</tt>\n * @type Boolean\n * @default true\n */\n this.enhancedRendering = false;\n\n /**\n * This is used to easily determine which renderer we are using\n * @example if (board.renderer.type === 'vml') {\n * // do something\n * }\n * @type String\n */\n this.type = 'no';\n };\n\n JXG.extend(JXG.NoRenderer.prototype, /** @lends JXG.NoRenderer.prototype */ {\n /* ******************************** *\n * Point drawing and updating *\n * ******************************** */\n\n /**\n * Draws a point on the {@link JXG.Board}.\n * @param {JXG.Point} element Reference to a {@link JXG.Point} object that has to be drawn.\n * @see Point\n * @see JXG.Point\n * @see JXG.AbstractRenderer#updatePoint\n * @see JXG.AbstractRenderer#changePointStyle\n */\n drawPoint: function (element) {},\n\n /**\n * Updates visual appearance of the renderer element assigned to the given {@link JXG.Point}.\n * @param {JXG.Point} element Reference to a {@link JXG.Point} object, that has to be updated.\n * @see Point\n * @see JXG.Point\n * @see JXG.AbstractRenderer#drawPoint\n * @see JXG.AbstractRenderer#changePointStyle\n */\n updatePoint: function (element) { },\n\n /**\n * Changes the style of a {@link JXG.Point}. This is required because the point styles differ in what\n * elements have to be drawn, e.g. if the point is marked by a \"x\" or a \"+\" two lines are drawn, if\n * it's marked by spot a circle is drawn. This method removes the old renderer element(s) and creates\n * the new one(s).\n * @param {JXG.Point} element Reference to a {@link JXG.Point} object, that's style is changed.\n * @see Point\n * @see JXG.Point\n * @see JXG.AbstractRenderer#updatePoint\n * @see JXG.AbstractRenderer#drawPoint\n */\n changePointStyle: function (element) { },\n\n /* ******************************** *\n * Lines *\n * ******************************** */\n\n /**\n * Draws a line on the {@link JXG.Board}.\n * @param {JXG.Line} element Reference to a line object, that has to be drawn.\n * @see Line\n * @see JXG.Line\n * @see JXG.AbstractRenderer#updateLine\n */\n drawLine: function (element) { },\n\n /**\n * Updates visual appearance of the renderer element assigned to the given {@link JXG.Line}.\n * @param {JXG.Line} element Reference to the {@link JXG.Line} object that has to be updated.\n * @see Line\n * @see JXG.Line\n * @see JXG.AbstractRenderer#drawLine\n */\n updateLine: function (element) { },\n\n /**\n * Creates a rendering node for ticks added to a line.\n * @param {JXG.Line} element A arbitrary line.\n * @see Line\n * @see Ticks\n * @see JXG.Line\n * @see JXG.Ticks\n * @see JXG.AbstractRenderer#updateTicks\n */\n drawTicks: function (element) { },\n\n /**\n * Update {@link Ticks} on a {@link JXG.Line}. This method is only a stub and has to be implemented\n * in any descendant renderer class.\n * @param {JXG.Line} element Reference of an line object, thats ticks have to be updated.\n * @see Line\n * @see Ticks\n * @see JXG.Line\n * @see JXG.Ticks\n * @see JXG.AbstractRenderer#drawTicks\n */\n updateTicks: function (element) { /* stub */ },\n\n /* **************************\n * Curves\n * **************************/\n\n /**\n * Draws a {@link JXG.Curve} on the {@link JXG.Board}.\n * @param {JXG.Curve} element Reference to a graph object, that has to be plotted.\n * @see Curve\n * @see JXG.Curve\n * @see JXG.AbstractRenderer#updateCurve\n */\n drawCurve: function (element) { },\n\n /**\n * Updates visual appearance of the renderer element assigned to the given {@link JXG.Curve}.\n * @param {JXG.Curve} element Reference to a {@link JXG.Curve} object, that has to be updated.\n * @see Curve\n * @see JXG.Curve\n * @see JXG.AbstractRenderer#drawCurve\n */\n updateCurve: function (element) { },\n\n /* **************************\n * Circle related stuff\n * **************************/\n\n /**\n * Draws a {@link JXG.Circle}\n * @param {JXG.Circle} element Reference to a {@link JXG.Circle} object that has to be drawn.\n * @see Circle\n * @see JXG.Circle\n * @see JXG.AbstractRenderer#updateEllipse\n */\n drawEllipse: function (element) { },\n\n /**\n * Updates visual appearance of a given {@link JXG.Circle} on the {@link JXG.Board}.\n * @param {JXG.Circle} element Reference to a {@link JXG.Circle} object, that has to be updated.\n * @see Circle\n * @see JXG.Circle\n * @see JXG.AbstractRenderer#drawEllipse\n */\n updateEllipse: function (element) { },\n\n\n /* **************************\n * Polygon related stuff\n * **************************/\n\n /**\n * Draws a {@link JXG.Polygon} on the {@link JXG.Board}.\n * @param {JXG.Polygon} element Reference to a Polygon object, that is to be drawn.\n * @see Polygon\n * @see JXG.Polygon\n * @see JXG.AbstractRenderer#updatePolygon\n */\n drawPolygon: function (element) { },\n\n /**\n * Updates properties of a {@link JXG.Polygon}'s rendering node.\n * @param {JXG.Polygon} element Reference to a {@link JXG.Polygon} object, that has to be updated.\n * @see Polygon\n * @see JXG.Polygon\n * @see JXG.AbstractRenderer#drawPolygon\n */\n updatePolygon: function (element) { },\n\n /* **************************\n * Text related stuff\n * **************************/\n\n /**\n * Shows a small copyright notice in the top left corner of the board.\n * @param {String} str The copyright notice itself\n * @param {Number} fontsize Size of the font the copyright notice is written in\n */\n displayCopyright: function (str, fontsize) { /* stub */ },\n\n /**\n * An internal text is a {@link JXG.Text} element which is drawn using only\n * the given renderer but no HTML. This method is only a stub, the drawing\n * is done in the special renderers.\n * @param {JXG.Text} element Reference to a {@link JXG.Text} object\n * @see Text\n * @see JXG.Text\n * @see JXG.AbstractRenderer#updateInternalText\n * @see JXG.AbstractRenderer#drawText\n * @see JXG.AbstractRenderer#updateText\n * @see JXG.AbstractRenderer#updateTextStyle\n */\n drawInternalText: function (element) { /* stub */ },\n\n /**\n * Updates visual properties of an already existing {@link JXG.Text} element.\n * @param {JXG.Text} element Reference to an {@link JXG.Text} object, that has to be updated.\n * @see Text\n * @see JXG.Text\n * @see JXG.AbstractRenderer#drawInternalText\n * @see JXG.AbstractRenderer#drawText\n * @see JXG.AbstractRenderer#updateText\n * @see JXG.AbstractRenderer#updateTextStyle\n */\n updateInternalText: function (element) { /* stub */ },\n\n /**\n * Displays a {@link JXG.Text} on the {@link JXG.Board} by putting a HTML div over it.\n * @param {JXG.Text} element Reference to an {@link JXG.Text} object, that has to be displayed\n * @see Text\n * @see JXG.Text\n * @see JXG.AbstractRenderer#drawInternalText\n * @see JXG.AbstractRenderer#updateText\n * @see JXG.AbstractRenderer#updateInternalText\n * @see JXG.AbstractRenderer#updateTextStyle\n */\n drawText: function (element) { },\n\n /**\n * Updates visual properties of an already existing {@link JXG.Text} element.\n * @param {JXG.Text} element Reference to an {@link JXG.Text} object, that has to be updated.\n * @see Text\n * @see JXG.Text\n * @see JXG.AbstractRenderer#drawText\n * @see JXG.AbstractRenderer#drawInternalText\n * @see JXG.AbstractRenderer#updateInternalText\n * @see JXG.AbstractRenderer#updateTextStyle\n */\n updateText: function (element) { },\n\n /**\n * Updates CSS style properties of a {@link JXG.Text} node.\n * @param {JXG.Text} element Reference to the {@link JXG.Text} object, that has to be updated.\n * @param {Boolean} doHighlight\n * @see Text\n * @see JXG.Text\n * @see JXG.AbstractRenderer#drawText\n * @see JXG.AbstractRenderer#drawInternalText\n * @see JXG.AbstractRenderer#updateText\n * @see JXG.AbstractRenderer#updateInternalText\n */\n updateTextStyle: function (element, doHighlight) { },\n\n /**\n * Set color and opacity of internal texts.\n * SVG needs its own version.\n * @private\n * @see JXG.AbstractRenderer#updateTextStyle\n * @see JXG.AbstractRenderer#updateInternalTextStyle\n */\n updateInternalTextStyle: function (element, strokeColor, strokeOpacity) { /* stub */ },\n\n /* **************************\n * Image related stuff\n * **************************/\n\n /**\n * Draws an {@link JXG.Image} on a board; This is just a template that has to be implemented by special renderers.\n * @param {JXG.Image} element Reference to the image object that is to be drawn\n * @see Image\n * @see JXG.Image\n * @see JXG.AbstractRenderer#updateImage\n */\n drawImage: function (element) { /* stub */ },\n\n /**\n * Updates the properties of an {@link JXG.Image} element.\n * @param {JXG.Image} element Reference to an {@link JXG.Image} object, that has to be updated.\n * @see Image\n * @see JXG.Image\n * @see JXG.AbstractRenderer#drawImage\n */\n updateImage: function (element) { },\n\n /**\n * Applies transformations on images and text elements. This method is just a stub and has to be implemented in all\n * descendant classes where text and image transformations are to be supported.\n * @param {JXG.Image|JXG.Text} element A {@link JXG.Image} or {@link JXG.Text} object.\n * @param {Array} transformations An array of {@link JXG.Transformation} objects. This is usually the transformations property\n * of the given element <tt>el</tt>.\n */\n transformImage: function (element, transformations) { /* stub */ },\n\n /**\n * If the URL of the image is provided by a function the URL has to be updated during updateImage()\n * @param {JXG.Image} element Reference to an image object.\n * @see JXG.AbstractRenderer#updateImage\n */\n updateImageURL: function (element) { /* stub */ },\n\n /* **************************\n * Render primitive objects\n * **************************/\n\n /**\n * Appends a node to a specific layer level. This is just an abstract method and has to be implemented\n * in all renderers that want to use the <tt>createPrim</tt> model to draw.\n * @param {Node} node A DOM tree node.\n * @param {Number} level The layer the node is attached to. This is the index of the layer in\n * {@link JXG.SVGRenderer#layer} or the <tt>z-index</tt> style property of the node in VMLRenderer.\n */\n appendChildPrim: function (node, level) { /* stub */ },\n\n /**\n * Stores the rendering nodes. This is an abstract method which has to be implemented in all renderers that use\n * the <tt>createPrim</tt> method.\n * @param {JXG.GeometryElement} element A JSXGraph element.\n * @param {String} type The XML node name. Only used in VMLRenderer.\n */\n appendNodesToElement: function (element, type) { /* stub */ },\n\n /**\n * Creates a node of a given type with a given id.\n * @param {String} type The type of the node to create.\n * @param {String} id Set the id attribute to this.\n * @returns {Node} Reference to the created node.\n */\n createPrim: function (type, id) {\n /* stub */\n return null;\n },\n\n /**\n * Removes an element node. Just a stub.\n * @param {Node} node The node to remove.\n */\n remove: function (node) { /* stub */ },\n\n /**\n * Can be used to create the nodes to display arrows. This is an abstract method which has to be implemented\n * in any descendant renderer.\n * @param {JXG.GeometryElement} element The element the arrows are to be attached to.\n */\n makeArrows: function (element) { /* stub */ },\n\n /**\n * Updates an ellipse node primitive. This is an abstract method which has to be implemented in all renderers\n * that use the <tt>createPrim</tt> method.\n * @param {Node} node Reference to the node.\n * @param {Number} x Centre X coordinate\n * @param {Number} y Centre Y coordinate\n * @param {Number} rx The x-axis radius.\n * @param {Number} ry The y-axis radius.\n */\n updateEllipsePrim: function (node, x, y, rx, ry) { /* stub */ },\n\n /**\n * Refreshes a line node. This is an abstract method which has to be implemented in all renderers that use\n * the <tt>createPrim</tt> method.\n * @param {Node} node The node to be refreshed.\n * @param {Number} p1x The first point's x coordinate.\n * @param {Number} p1y The first point's y coordinate.\n * @param {Number} p2x The second point's x coordinate.\n * @param {Number} p2y The second point's y coordinate.\n * @param {JXG.Board} board\n */\n updateLinePrim: function (node, p1x, p1y, p2x, p2y, board) { /* stub */ },\n\n /**\n * Updates a path element. This is an abstract method which has to be implemented in all renderers that use\n * the <tt>createPrim</tt> method.\n * @param {Node} node The path node.\n * @param {String} pathString A string formatted like e.g. <em>'M 1,2 L 3,1 L5,5'</em>. The format of the string\n * depends on the rendering engine.\n * @param {JXG.Board} board Reference to the element's board.\n */\n updatePathPrim: function (node, pathString, board) { /* stub */ },\n\n /**\n * Builds a path data string to draw a point with a face other than <em>rect</em> and <em>circle</em>. Since\n * the format of such a string usually depends on the renderer this method\n * is only an abstract method. Therefore, it has to be implemented in the descendant renderer itself unless\n * the renderer does not use the createPrim interface but the draw* interfaces to paint.\n * @param {JXG.Point} element The point element\n * @param {Number} size A positive number describing the size. Usually the half of the width and height of\n * the drawn point.\n * @param {String} type A string describing the point's face. This method only accepts the shortcut version of\n * each possible face: <tt>x, +, <>, ^, v, >, <\n */\n updatePathStringPoint: function (element, size, type) { /* stub */ },\n\n /**\n * Builds a path data string from a {@link JXG.Curve} element. Since the path data strings heavily depend on the\n * underlying rendering technique this method is just a stub. Although such a path string is of no use for the\n * CanvasRenderer, this method is used there to draw a path directly.\n * @param element\n */\n updatePathStringPrim: function (element) { /* stub */ },\n\n /**\n * Builds a path data string from a {@link JXG.Curve} element such that the curve looks like\n * hand drawn.\n * Since the path data strings heavily depend on the\n * underlying rendering technique this method is just a stub. Although such a path string is of no use for the\n * CanvasRenderer, this method is used there to draw a path directly.\n * @param element\n */\n updatePathStringBezierPrim: function (element) { /* stub */ },\n\n\n /**\n * Update a polygon primitive.\n * @param {Node} node\n * @param {JXG.Polygon} element A JSXGraph element of type {@link JXG.Polygon}\n */\n updatePolygonPrim: function (node, element) { /* stub */ },\n\n /**\n * Update a rectangle primitive. This is used only for points with face of type 'rect'.\n * @param {Node} node The node yearning to be updated.\n * @param {Number} x x coordinate of the top left vertex.\n * @param {Number} y y coordinate of the top left vertex.\n * @param {Number} w Width of the rectangle.\n * @param {Number} h The rectangle's height.\n */\n updateRectPrim: function (node, x, y, w, h) { /* stub */ },\n\n /* **************************\n * Set Attributes\n * **************************/\n\n /**\n * Sets a node's attribute.\n * @param {Node} node The node that is to be updated.\n * @param {String} key Name of the attribute.\n * @param {String} val New value for the attribute.\n */\n setPropertyPrim: function (node, key, val) { /* stub */ },\n\n /**\n * Shows or hides an element on the canvas; Only a stub, requires implementation in the derived renderer.\n * @param {JXG.GeometryElement} element Reference to the object that has to appear.\n * @param {Boolean} value true to show the element, false to hide the element.\n */\n display: function (element, value) {\n if (element) {\n element.visPropOld.visible = value;\n }\n },\n\n /**\n * Shows a hidden element on the canvas; Only a stub, requires implementation in the derived renderer.\n *\n * Please use JXG.AbstractRenderer#display instead\n * @param {JXG.GeometryElement} element Reference to the object that has to appear.\n * @see JXG.AbstractRenderer#hide\n * @deprecated\n */\n show: function (element) { /* stub */ },\n\n /**\n * Hides an element on the canvas; Only a stub, requires implementation in the derived renderer.\n *\n * Please use JXG.AbstractRenderer#display instead\n * @param {JXG.GeometryElement} element Reference to the geometry element that has to disappear.\n * @see JXG.AbstractRenderer#show\n * @deprecated\n */\n hide: function (element) { /* stub */ },\n\n /**\n * Sets the buffering as recommended by SVGWG. Until now only Opera supports this and will be ignored by\n * other browsers. Although this feature is only supported by SVG we have this method in {@link JXG.AbstractRenderer}\n * because it is called from outside the renderer.\n * @param {Node} node The SVG DOM Node which buffering type to update.\n * @param {String} type Either 'auto', 'dynamic', or 'static'. For an explanation see\n * {@link http://www.w3.org/TR/SVGTiny12/painting.html#BufferedRenderingProperty}.\n */\n setBuffering: function (node, type) { /* stub */ },\n\n /**\n * Sets an element's dash style.\n * @param {JXG.GeometryElement} element An JSXGraph element.\n */\n setDashStyle: function (element) { /* stub */ },\n\n /**\n * Puts an object into draft mode, i.e. it's visual appearance will be changed. For GEONE<sub>x</sub>T backwards compatibility.\n * @param {JXG.GeometryElement} element Reference of the object that is in draft mode.\n */\n setDraft: function (element) { },\n\n /**\n * Puts an object from draft mode back into normal mode.\n * @param {JXG.GeometryElement} element Reference of the object that no longer is in draft mode.\n */\n removeDraft: function (element) { },\n\n /**\n * Sets up nodes for rendering a gradient fill.\n * @param element\n */\n setGradient: function (element) { /* stub */ },\n\n /**\n * Updates the gradient fill.\n * @param {JXG.GeometryElement} element An JSXGraph element with an area that can be filled.\n */\n updateGradient: function (element) { /* stub */ },\n\n /**\n * Sets the transition duration (in milliseconds) for fill color and stroke\n * color and opacity.\n * @param {JXG.GeometryElement} element Reference of the object that wants a\n * new transition duration.\n * @param {Number} duration (Optional) duration in milliseconds. If not given,\n * element.visProp.transitionDuration is taken. This is the default.\n */\n setObjectTransition: function (element, duration) { /* stub */ },\n\n /**\n * Sets an objects fill color.\n * @param {JXG.GeometryElement} element Reference of the object that wants a new fill color.\n * @param {String} color Color in a HTML/CSS compatible format. If you don't want any fill color at all, choose 'none'.\n * @param {Number} opacity Opacity of the fill color. Must be between 0 and 1.\n */\n setObjectFillColor: function (element, color, opacity) { /* stub */ },\n\n /**\n * Changes an objects stroke color to the given color.\n * @param {JXG.GeometryElement} element Reference of the {@link JXG.GeometryElement} that gets a new stroke color.\n * @param {String} color Color value in a HTML compatible format, e.g. <strong>#00ff00</strong> or <strong>green</strong> for green.\n * @param {Number} opacity Opacity of the fill color. Must be between 0 and 1.\n */\n setObjectStrokeColor: function (element, color, opacity) { /* stub */ },\n\n /**\n * Sets an element's stroke width.\n * @param {JXG.GeometryElement} element Reference to the geometry element.\n * @param {Number} width The new stroke width to be assigned to the element.\n */\n setObjectStrokeWidth: function (element, width) { /* stub */ },\n\n /**\n * Sets the shadow properties to a geometry element. This method is only a stub, it is implemented in the actual renderers.\n * @param {JXG.GeometryElement} element Reference to a geometry object, that should get a shadow\n */\n setShadow: function (element) { /* stub */ },\n\n /**\n * Highlights an object, i.e. changes the current colors of the object to its highlighting colors\n * @param {JXG.GeometryElement} element Reference of the object that will be highlighted.\n * @returns {JXG.AbstractRenderer} Reference to the renderer\n */\n highlight: function (element) { },\n\n /**\n * Uses the normal colors of an object, i.e. the opposite of {@link JXG.AbstractRenderer#highlight}.\n * @param {JXG.GeometryElement} element Reference of the object that will get its normal colors.\n * @returns {JXG.AbstractRenderer} Reference to the renderer\n */\n noHighlight: function (element) { },\n\n\n /* **************************\n * renderer control\n * **************************/\n\n /**\n * Stop redraw. This method is called before every update, so a non-vector-graphics based renderer\n * can use this method to delete the contents of the drawing panel. This is an abstract method every\n * descendant renderer should implement, if appropriate.\n * @see JXG.AbstractRenderer#unsuspendRedraw\n */\n suspendRedraw: function () { /* stub */ },\n\n /**\n * Restart redraw. This method is called after updating all the rendering node attributes.\n * @see JXG.AbstractRenderer#suspendRedraw\n */\n unsuspendRedraw: function () { /* stub */ },\n\n /**\n * The tiny zoom bar shown on the bottom of a board (if showNavigation on board creation is true).\n * @param {JXG.Board} board Reference to a JSXGraph board.\n */\n drawZoomBar: function (board) { },\n\n /**\n * Wrapper for getElementById for maybe other renderers which elements are not directly accessible by DOM methods like document.getElementById().\n * @param {String} id Unique identifier for element.\n * @returns {Object} Reference to a JavaScript object. In case of SVG/VMLRenderer it's a reference to a SVG/VML node.\n */\n getElementById: function (id) {\n return null;\n },\n\n /**\n * Resizes the rendering element\n * @param {Number} w New width\n * @param {Number} h New height\n */\n resize: function (w, h) { /* stub */},\n\n removeToInsertLater: function () {\n return function () {};\n }\n\n });\n\n /**\n * @ignore\n */\n JXG.NoRenderer.prototype = new AbstractRenderer();\n\n return JXG.NoRenderer;\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, document:true, jQuery:true, define: true, window: true*/\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n jxg\n utils/env\n utils/type\n base/board\n reader/file\n options\n renderer/svg\n renderer/vml\n renderer/canvas\n renderer/no\n */\n\n/**\n * @fileoverview The JSXGraph object is defined in this file. JXG.JSXGraph controls all boards.\n * It has methods to create, save, load and free boards. Additionally some helper functions are\n * defined in this file directly in the JXG namespace.\n * @version 0.99\n */\n\ndefine('jsxgraph',[\n 'jxg', 'utils/env', 'utils/type', 'base/board', 'reader/file', 'options',\n 'renderer/svg', 'renderer/vml', 'renderer/canvas', 'renderer/no'\n], function (JXG, Env, Type, Board, FileReader, Options, SVGRenderer, VMLRenderer, CanvasRenderer, NoRenderer) {\n\n \"use strict\";\n\n /**\n * Constructs a new JSXGraph singleton object.\n * @class The JXG.JSXGraph singleton stores all properties required\n * to load, save, create and free a board.\n */\n JXG.JSXGraph = {\n /**\n * Stores the renderer that is used to draw the boards.\n * @type String\n */\n rendererType: (function () {\n Options.board.renderer = 'no';\n\n if (Env.supportsVML()) {\n Options.board.renderer = 'vml';\n // Ok, this is some real magic going on here. IE/VML always was so\n // terribly slow, except in one place: Examples placed in a moodle course\n // was almost as fast as in other browsers. So i grabbed all the css and\n // lib scripts from our moodle, added them to a jsxgraph example and it\n // worked. next step was to strip all the css/lib code which didn't affect\n // the VML update speed. The following five lines are what was left after\n // the last step and yes - it basically does nothing but reads two\n // properties of document.body on every mouse move. why? we don't know. if\n // you know, please let us know.\n //\n // If we want to use the strict mode we have to refactor this a little bit. Let's\n // hope the magic isn't gone now. Anywho... it's only useful in old versions of IE\n // which should not be used anymore.\n document.onmousemove = function () {\n var t;\n\n if (document.body) {\n t = document.body.scrollLeft;\n t += document.body.scrollTop;\n }\n\n return t;\n };\n }\n\n if (Env.supportsCanvas()) {\n Options.board.renderer = 'canvas';\n }\n\n if (Env.supportsSVG()) {\n Options.board.renderer = 'svg';\n }\n\n // we are inside node\n if (Env.isNode() && Env.supportsCanvas()) {\n Options.board.renderer = 'canvas';\n }\n\n if (Env.isNode() || Options.renderer === 'no') {\n Options.text.display = 'internal';\n Options.infobox.display = 'internal';\n }\n\n return Options.board.renderer;\n }()),\n\n /**\n * Initialize the rendering engine\n *\n * @param {String} box HTML id of the div-element which hosts the JSXGraph construction\n * @param {Object} dim The dimensions of the board\n * @param {Object} doc Usually, this is document object of the browser window. If false or null, this defaults\n * to the document object of the browser.\n * @param {Object} attrRenderer Attribute 'renderer', speficies the rendering engine. Possible values are 'auto', 'svg',\n * 'canvas', 'no', and 'vml'.\n * @returns {Object} Reference to the rendering engine object.\n * @private\n */\n initRenderer: function (box, dim, doc, attrRenderer) {\n var boxid, renderer;\n\n // Former version:\n // doc = doc || document\n if ((!Type.exists(doc) || doc === false) && typeof document === 'object') {\n doc = document;\n }\n\n if (typeof doc === 'object' && box !== null) {\n boxid = doc.getElementById(box);\n\n // Remove everything from the container before initializing the renderer and the board\n while (boxid.firstChild) {\n boxid.removeChild(boxid.firstChild);\n }\n } else {\n boxid = box;\n }\n\n // If attrRenderer is not supplied take the first available renderer\n if (attrRenderer === undefined || attrRenderer === 'auto') {\n attrRenderer = this.rendererType;\n }\n // create the renderer\n if (attrRenderer === 'svg') {\n renderer = new SVGRenderer(boxid, dim);\n } else if (attrRenderer === 'vml') {\n renderer = new VMLRenderer(boxid);\n } else if (attrRenderer === 'canvas') {\n renderer = new CanvasRenderer(boxid, dim);\n } else {\n renderer = new NoRenderer();\n }\n\n return renderer;\n },\n\n /**\n * Merge the user supplied attributes with the attributes in options.js\n *\n * @param {Object} attributes User supplied attributes\n * @returns {Object} Merged attributes for the board\n *\n * @private\n */\n _setAttributes: function(attributes) {\n // merge attributes\n var attr = Type.copyAttributes(attributes, Options, 'board');\n\n // The attributes which are objects have to be copied separately\n attr.zoom = Type.copyAttributes(attr, Options, 'board', 'zoom');\n attr.pan = Type.copyAttributes(attr, Options, 'board', 'pan');\n attr.drag = Type.copyAttributes(attr, Options, 'board', 'drag');\n attr.keyboard = Type.copyAttributes(attr, Options, 'board', 'keyboard');\n attr.selection = Type.copyAttributes(attr, Options, 'board', 'selection');\n attr.navbar = Type.copyAttributes(attr.navbar, Options, 'navbar');\n attr.screenshot = Type.copyAttributes(attr, Options, 'board', 'screenshot');\n attr.resize = Type.copyAttributes(attr, Options, 'board', 'resize');\n attr.fullscreen = Type.copyAttributes(attr, Options, 'board', 'fullscreen');\n\n // Treat moveTarget separately, because deepCopy will not work here.\n // Reason: moveTarget will be an HTML node and it is prevented that Type.deepCopy will copy it.\n attr.movetarget = attributes.moveTarget || attributes.movetarget || Options.board.moveTarget;\n\n return attr;\n },\n\n /**\n * Further initialization of the board. Set some properties from attribute values.\n *\n * @param {JXG.Board} board\n * @param {Object} attr attributes object\n * @param {Object} dimensions Object containing dimensions of the canvas\n *\n * @private\n */\n _fillBoard: function(board, attr, dimensions) {\n board.initInfobox();\n board.maxboundingbox = attr.maxboundingbox;\n board.resizeContainer(dimensions.width, dimensions.height, true, true);\n board._createSelectionPolygon(attr);\n board.renderer.drawZoomBar(board, attr.navbar);\n JXG.boards[board.id] = board;\n },\n\n /**\n *\n * @param {String} container HTML-ID to the HTML-element in which the board is painted.\n * @param {*} attr An object that sets some of the board properties.\n *\n * @private\n */\n _setARIA: function(container, attr) {\n var doc = attr.document || document,\n doc_glob,\n node_jsx, newNode, parent,\n id_label, id_description;\n\n if (typeof doc !== 'object') {\n return;\n }\n\n node_jsx = doc.getElementById(container);\n doc_glob = node_jsx.ownerDocument; // This is the window.document element, needed below.\n parent = node_jsx.parentNode;\n\n id_label = container + '_ARIAlabel';\n id_description = container + '_ARIAdescription';\n\n newNode = doc_glob.createElement('div');\n newNode.innerHTML = attr.title;\n newNode.setAttribute('id', id_label);\n newNode.style.display = 'none';\n parent.insertBefore(newNode, node_jsx);\n\n newNode = doc_glob.createElement('div');\n newNode.innerHTML = attr.description;\n newNode.setAttribute('id', id_description);\n newNode.style.display = 'none';\n parent.insertBefore(newNode, node_jsx);\n\n node_jsx.setAttribute('aria-labelledby', id_label);\n node_jsx.setAttribute('aria-describedby', id_description);\n },\n\n /**\n * Remove the two corresponding ARIA divs when freeing a board\n *\n * @param {JXG.Board} board\n *\n * @private\n */\n _removeARIANodes: function(board) {\n var node, id, doc;\n\n doc = board.document || document;\n if (typeof doc !== 'object') {\n return;\n }\n\n id = board.containerObj.getAttribute('aria-labelledby');\n node = doc.getElementById(id);\n if (node && node.parentNode) {\n node.parentNode.removeChild(node);\n }\n id = board.containerObj.getAttribute('aria-describedby');\n node = doc.getElementById(id);\n if (node && node.parentNode) {\n node.parentNode.removeChild(node);\n }\n },\n\n /**\n * Initialise a new board.\n * @param {String} box HTML-ID to the HTML-element in which the board is painted.\n * @param {Object} attributes An object that sets some of the board properties. Most of these properties can be set via JXG.Options.\n * @param {Array} [attributes.boundingbox=[-5, 5, 5, -5]] An array containing four numbers describing the left, top, right and bottom boundary of the board in user coordinates\n * @param {Boolean} [attributes.keepaspectratio=false] If <tt>true</tt>, the bounding box is adjusted to the same aspect ratio as the aspect ratio of the div containing the board.\n * @param {Boolean} [attributes.showCopyright=false] Show the copyright string in the top left corner.\n * @param {Boolean} [attributes.showNavigation=false] Show the navigation buttons in the bottom right corner.\n * @param {Object} [attributes.zoom] Allow the user to zoom with the mouse wheel or the two-fingers-zoom gesture.\n * @param {Object} [attributes.pan] Allow the user to pan with shift+drag mouse or two-fingers-pan gesture.\n * @param {Object} [attributes.drag] Allow the user to drag objects with a pointer device.\n * @param {Object} [attributes.keyboard] Allow the user to drag objects with arrow keys on keyboard.\n * @param {Boolean} [attributes.axis=false] If set to true, show the axis. Can also be set to an object that is given to both axes as an attribute object.\n * @param {Boolean|Object} [attributes.grid] If set to true, shows the grid. Can also be set to an object that is given to the grid as its attribute object.\n * @param {Boolean} [attributes.registerEvents=true] Register mouse / touch events.\n * @returns {JXG.Board} Reference to the created board.\n */\n initBoard: function (box, attributes) {\n var originX, originY, unitX, unitY,\n renderer,\n offX = 0,\n offY = 0,\n w, h, dimensions,\n bbox, attr, axattr, axattr_x, axattr_y,\n board;\n\n attributes = attributes || {};\n attr = this._setAttributes(attributes);\n\n dimensions = Env.getDimensions(box, attr.document);\n\n if (attr.unitx || attr.unity) {\n originX = Type.def(attr.originx, 150);\n originY = Type.def(attr.originy, 150);\n unitX = Type.def(attr.unitx, 50);\n unitY = Type.def(attr.unity, 50);\n } else {\n bbox = attr.boundingbox;\n if (bbox[0] < attr.maxboundingbox[0]) { bbox[0] = attr.maxboundingbox[0]; }\n if (bbox[1] > attr.maxboundingbox[1]) { bbox[1] = attr.maxboundingbox[1]; }\n if (bbox[2] > attr.maxboundingbox[2]) { bbox[2] = attr.maxboundingbox[2]; }\n if (bbox[3] < attr.maxboundingbox[3]) { bbox[3] = attr.maxboundingbox[3]; }\n\n w = parseInt(dimensions.width, 10);\n h = parseInt(dimensions.height, 10);\n\n if (Type.exists(bbox) && attr.keepaspectratio) {\n /*\n * If the boundingbox attribute is given and the ratio of height and width of the\n * sides defined by the bounding box and the ratio of the dimensions of the div tag\n * which contains the board do not coincide, then the smaller side is chosen.\n */\n unitX = w / (bbox[2] - bbox[0]);\n unitY = h / (bbox[1] - bbox[3]);\n\n if (Math.abs(unitX) < Math.abs(unitY)) {\n unitY = Math.abs(unitX) * unitY / Math.abs(unitY);\n // Add the additional units in equal portions above and below\n offY = (h / unitY - (bbox[1] - bbox[3])) * 0.5;\n } else {\n unitX = Math.abs(unitY) * unitX / Math.abs(unitX);\n // Add the additional units in equal portions left and right\n offX = (w / unitX - (bbox[2] - bbox[0])) * 0.5;\n }\n } else {\n unitX = w / (bbox[2] - bbox[0]);\n unitY = h / (bbox[1] - bbox[3]);\n }\n originX = -unitX * (bbox[0] - offX);\n originY = unitY * (bbox[1] + offY);\n }\n\n renderer = this.initRenderer(box, dimensions, attr.document, attr.renderer);\n this._setARIA(box, attr);\n\n // create the board\n board = new Board(box, renderer, attr.id, [originX, originY],\n attr.zoomfactor * attr.zoomx,\n attr.zoomfactor * attr.zoomy,\n unitX, unitY,\n dimensions.width, dimensions.height,\n attr);\n\n board.keepaspectratio = attr.keepaspectratio;\n\n this._fillBoard(board, attr, dimensions);\n\n // create elements like axes, grid, navigation, ...\n board.suspendUpdate();\n if (attr.axis) {\n axattr = typeof attr.axis === 'object' ? attr.axis : {};\n\n // The defaultAxes attributes are overwritten by user supplied axis object.\n axattr_x = Type.deepCopy(Options.board.defaultAxes.x, axattr);\n axattr_y = Type.deepCopy(Options.board.defaultAxes.y, axattr);\n // The user supplied defaultAxes attributes are merged in.\n if (attr.defaultaxes.x) {\n axattr_x = Type.deepCopy(axattr_x, attr.defaultaxes.x);\n }\n if (attr.defaultaxes.y) {\n axattr_y = Type.deepCopy(axattr_y, attr.defaultaxes.y);\n }\n\n board.defaultAxes = {};\n board.defaultAxes.x = board.create('axis', [[0, 0], [1, 0]], axattr_x);\n board.defaultAxes.y = board.create('axis', [[0, 0], [0, 1]], axattr_y);\n }\n if (attr.grid) {\n board.create('grid', [], (typeof attr.grid === 'object' ? attr.grid : {}));\n }\n board.unsuspendUpdate();\n\n return board;\n },\n\n /**\n * Load a board from a file containing a construction made with either GEONExT,\n * Intergeo, Geogebra, or Cinderella.\n * @param {String} box HTML-ID to the HTML-element in which the board is painted.\n * @param {String} file base64 encoded string.\n * @param {String} format containing the file format: 'Geonext' or 'Intergeo'.\n * @param {Object} attributes Attributes for the board and 'encoding'.\n * Compressed files need encoding 'iso-8859-1'. Otherwise it probably is 'utf-8'.\n * @param {Function} callback\n * @returns {JXG.Board} Reference to the created board.\n * @see JXG.FileReader\n * @see JXG.GeonextReader\n * @see JXG.GeogebraReader\n * @see JXG.IntergeoReader\n * @see JXG.CinderellaReader\n *\n * @example\n * // Uncompressed file\n * var board = JXG.JSXGraph.loadBoardFromFile('jxgbox', 'filename', 'geonext',\n * {encoding: 'utf-8'},\n * function (board) { console.log(\"Done loading\"); }\n * );\n * // Compressed file\n * var board = JXG.JSXGraph.loadBoardFromFile('jxgbox', 'filename', 'geonext',\n * {encoding: 'iso-8859-1'},\n * function (board) { console.log(\"Done loading\"); }\n * );\n *\n * @example\n * // From <input type=\"file\" id=\"localfile\" />\n * var file = document.getElementById('localfile').files[0];\n * JXG.JSXGraph.loadBoardFromFile('jxgbox', file, 'geonext',\n * {encoding: 'utf-8'},\n * function (board) { console.log(\"Done loading\"); }\n * );\n */\n loadBoardFromFile: function (box, file, format, attributes, callback) {\n var attr, renderer, board, dimensions, encoding;\n\n attributes = attributes || {};\n attr = this._setAttributes(attributes);\n\n dimensions = Env.getDimensions(box, attr.document);\n renderer = this.initRenderer(box, dimensions, attr.document, attr.renderer);\n this._setARIA(box, attr);\n\n /* User default parameters, in parse* the values in the gxt files are submitted to board */\n board = new Board(box, renderer, '', [150, 150], 1, 1, 50, 50, dimensions.width, dimensions.height, attr);\n this._fillBoard(board, attr, dimensions);\n encoding = attr.encoding || 'iso-8859-1';\n FileReader.parseFileContent(file, board, format, true, encoding, callback);\n\n return board;\n },\n\n /**\n * Load a board from a base64 encoded string containing a construction made with either GEONExT,\n * Intergeo, Geogebra, or Cinderella.\n * @param {String} box HTML-ID to the HTML-element in which the board is painted.\n * @param {String} string base64 encoded string.\n * @param {String} format containing the file format: 'Geonext', 'Intergeo', 'Geogebra'.\n * @param {Object} attributes Attributes for the board and 'encoding'.\n * Compressed files need encoding 'iso-8859-1'. Otherwise it probably is 'utf-8'.\n * @param {Function} callback\n * @returns {JXG.Board} Reference to the created board.\n * @see JXG.FileReader\n * @see JXG.GeonextReader\n * @see JXG.GeogebraReader\n * @see JXG.IntergeoReader\n * @see JXG.CinderellaReader\n */\n loadBoardFromString: function (box, string, format, attributes, callback) {\n var attr, renderer, board, dimensions;\n\n attributes = attributes || {};\n attr = this._setAttributes(attributes);\n\n dimensions = Env.getDimensions(box, attr.document);\n renderer = this.initRenderer(box, dimensions, attr.document);\n this._setARIA(box, attr);\n\n /* User default parameters, in parse* the values in the gxt files are submitted to board */\n board = new Board(box, renderer, '', [150, 150], 1.0, 1.0, 50, 50, dimensions.width, dimensions.height, attr);\n this._fillBoard(board, attr, dimensions);\n FileReader.parseString(string, board, format, true, callback);\n\n return board;\n },\n\n /**\n * Delete a board and all its contents.\n * @param {JXG.Board,String} board HTML-ID to the DOM-element in which the board is drawn.\n */\n freeBoard: function (board) {\n var el;\n\n if (typeof board === 'string') {\n board = JXG.boards[board];\n }\n\n this._removeARIANodes(board);\n board.removeEventHandlers();\n board.suspendUpdate();\n\n // Remove all objects from the board.\n for (el in board.objects) {\n if (board.objects.hasOwnProperty(el)) {\n board.objects[el].remove();\n }\n }\n\n // Remove all the other things, left on the board, XHTML save\n while (board.containerObj.firstChild) {\n board.containerObj.removeChild(board.containerObj.firstChild);\n }\n\n // Tell the browser the objects aren't needed anymore\n for (el in board.objects) {\n if (board.objects.hasOwnProperty(el)) {\n delete board.objects[el];\n }\n }\n\n // Free the renderer and the algebra object\n delete board.renderer;\n\n // clear the creator cache\n board.jc.creator.clearCache();\n delete board.jc;\n\n // Finally remove the board itself from the boards array\n delete JXG.boards[board.id];\n },\n\n /**\n * @deprecated Use JXG#registerElement\n * @param element\n * @param creator\n */\n registerElement: function (element, creator) {\n JXG.deprecated('JXG.JSXGraph.registerElement()', 'JXG.registerElement()');\n JXG.registerElement(element, creator);\n }\n };\n\n // JessieScript/JessieCode startup: Search for script tags of type text/jessiescript and interprete them.\n if (Env.isBrowser && typeof window === 'object' && typeof document === 'object') {\n Env.addEvent(window, 'load', function () {\n var type, i, j, div,\n id, board, txt,\n width, height, maxWidth, aspectRatio, cssClasses,\n bbox, axis, grid, code,\n src, request, postpone = false,\n scripts = document.getElementsByTagName('script'),\n init = function (code, type, bbox) {\n var board = JXG.JSXGraph.initBoard(id, {boundingbox: bbox, keepaspectratio: true, grid: grid, axis: axis, showReload: true});\n\n if (type.toLowerCase().indexOf('script') > -1) {\n board.construct(code);\n } else {\n try {\n board.jc.parse(code);\n } catch (e2) {\n JXG.debug(e2);\n }\n }\n\n return board;\n },\n makeReload = function (board, code, type, bbox) {\n return function () {\n var newBoard;\n\n JXG.JSXGraph.freeBoard(board);\n newBoard = init(code, type, bbox);\n newBoard.reload = makeReload(newBoard, code, type, bbox);\n };\n };\n\n for (i = 0; i < scripts.length; i++) {\n type = scripts[i].getAttribute('type', false);\n\n if (Type.exists(type) &&\n (type.toLowerCase() === 'text/jessiescript' || type.toLowerCase() === 'jessiescript' ||\n type.toLowerCase() === 'text/jessiecode' || type.toLowerCase() === 'jessiecode')) {\n cssClasses = scripts[i].getAttribute('class', false) || '';\n width = scripts[i].getAttribute('width', false) || '';\n height = scripts[i].getAttribute('height', false) || '';\n maxWidth = scripts[i].getAttribute('maxwidth', false) || '100%';\n aspectRatio = scripts[i].getAttribute('aspectratio', false) || '1/1';\n bbox = scripts[i].getAttribute('boundingbox', false) || '-5, 5, 5, -5';\n id = scripts[i].getAttribute('container', false);\n src = scripts[i].getAttribute('src', false);\n\n bbox = bbox.split(',');\n if (bbox.length !== 4) {\n bbox = [-5, 5, 5, -5];\n } else {\n for (j = 0; j < bbox.length; j++) {\n bbox[j] = parseFloat(bbox[j]);\n }\n }\n axis = Type.str2Bool(scripts[i].getAttribute('axis', false) || 'false');\n grid = Type.str2Bool(scripts[i].getAttribute('grid', false) || 'false');\n\n if (!Type.exists(id)) {\n id = 'jessiescript_autgen_jxg_' + i;\n div = document.createElement('div');\n div.setAttribute('id', id);\n\n txt = (width !== '') ? ('width:' + width + ';') : '';\n txt += (height !== '') ? ('height:' + height + ';') : '';\n txt += (maxWidth !== '') ? ('max-width:' + maxWidth + ';') : '';\n txt += (aspectRatio !== '') ? ('aspect-ratio:' + aspectRatio + ';') : '';\n\n div.setAttribute('style', txt);\n div.setAttribute('class', 'jxgbox ' + cssClasses);\n try {\n document.body.insertBefore(div, scripts[i]);\n } catch (e) {\n // there's probably jquery involved...\n if (typeof jQuery === 'object') {\n jQuery(div).insertBefore(scripts[i]);\n }\n }\n } else {\n div = document.getElementById(id);\n }\n\n code = '';\n\n if (Type.exists(src)) {\n postpone = true;\n request = new XMLHttpRequest();\n request.open(\"GET\", src);\n request.overrideMimeType(\"text/plain; charset=x-user-defined\");\n /* jshint ignore:start */\n request.addEventListener(\"load\", function() {\n if (this.status < 400) {\n code = this.responseText + '\\n' + code;\n board = init(code, type, bbox);\n board.reload = makeReload(board, code, type, bbox);\n } else {\n throw new Error(\"\\nJSXGraph: failed to load file\", src, \":\", this.responseText);\n }\n });\n request.addEventListener(\"error\", function(e) {\n throw new Error(\"\\nJSXGraph: failed to load file\", src, \":\", e);\n });\n /* jshint ignore:end */\n request.send();\n } else {\n postpone = false;\n }\n\n if (document.getElementById(id)) {\n code = scripts[i].innerHTML;\n code = code.replace(/<!\\[CDATA\\[/g, '').replace(/\\]\\]>/g, '');\n scripts[i].innerHTML = code;\n\n if (!postpone) {\n // Do no wait for data from \"src\" attribute\n board = init(code, type, bbox);\n board.reload = makeReload(board, code, type, bbox);\n }\n } else {\n JXG.debug('JSXGraph: Apparently the div injection failed. Can\\'t create a board, sorry.');\n }\n }\n }\n }, window);\n }\n\n return JXG.JSXGraph;\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true, console: true, window: true*/\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n jxg\n options\n math/math\n math/geometry\n math/numerics\n base/coords\n base/constants\n base/element\n parser/geonext\n utils/type\n elements:\n transform\n */\n\n/**\n * @fileoverview The geometry object Point is defined in this file. Point stores all\n * style and functional properties that are required to draw and move a point on\n * a board.\n */\n\ndefine('base/point',[\n 'jxg', 'options', 'math/math', 'math/geometry', 'base/constants', 'base/element',\n 'utils/type', 'base/coordselement'\n], function (JXG, Options, Mat, Geometry, Const, GeometryElement, Type, CoordsElement) {\n\n \"use strict\";\n\n /**\n * A point is the basic geometric element. Based on points lines and circles can be constructed which can be intersected\n * which in turn are points again which can be used to construct new lines, circles, polygons, etc. This class holds methods for\n * all kind of points like free points, gliders, and intersection points.\n * @class Creates a new point object. Do not use this constructor to create a point. Use {@link JXG.Board#create} with\n * type {@link Point}, {@link Glider}, or {@link Intersection} instead.\n * @augments JXG.GeometryElement\n * @augments JXG.CoordsElement\n * @param {string|JXG.Board} board The board the new point is drawn on.\n * @param {Array} coordinates An array with the user coordinates of the point.\n * @param {Object} attributes An object containing visual properties like in {@link JXG.Options#point} and\n * {@link JXG.Options#elements}, and optional a name and an id.\n * @see JXG.Board#generateName\n */\n JXG.Point = function (board, coordinates, attributes) {\n this.constructor(board, attributes, Const.OBJECT_TYPE_POINT, Const.OBJECT_CLASS_POINT);\n this.element = this.board.select(attributes.anchor);\n this.coordsConstructor(coordinates);\n\n this.elType = 'point';\n\n /* Register point at board. */\n this.id = this.board.setId(this, 'P');\n this.board.renderer.drawPoint(this);\n this.board.finalizeAdding(this);\n\n this.createGradient();\n this.createLabel();\n\n };\n\n /**\n * Inherits here from {@link JXG.GeometryElement}.\n */\n JXG.Point.prototype = new GeometryElement();\n Type.copyPrototypeMethods(JXG.Point, CoordsElement, 'coordsConstructor');\n\n JXG.extend(JXG.Point.prototype, /** @lends JXG.Point.prototype */ {\n /**\n * Checks whether (x,y) is near the point.\n * @param {Number} x Coordinate in x direction, screen coordinates.\n * @param {Number} y Coordinate in y direction, screen coordinates.\n * @returns {Boolean} True if (x,y) is near the point, False otherwise.\n * @private\n */\n hasPoint: function (x, y) {\n var coordsScr = this.coords.scrCoords, r,\n prec, type,\n unit = Type.evaluate(this.visProp.sizeunit);\n\n if (Type.isObject(Type.evaluate(this.visProp.precision))) {\n type = this.board._inputDevice;\n prec = Type.evaluate(this.visProp.precision[type]);\n } else {\n // 'inherit'\n prec = this.board.options.precision.hasPoint;\n }\n r = parseFloat(Type.evaluate(this.visProp.size));\n if (unit === 'user') {\n r *= Math.sqrt(this.board.unitX * this.board.unitY);\n }\n\n r += parseFloat(Type.evaluate(this.visProp.strokewidth)) * 0.5;\n if (r < prec) {\n r = prec;\n }\n\n return ((Math.abs(coordsScr[1] - x) < r + 2) && (Math.abs(coordsScr[2] - y) < r + 2));\n },\n\n /**\n * Updates the position of the point.\n */\n update: function (fromParent) {\n if (!this.needsUpdate) {\n return this;\n }\n\n this.updateCoords(fromParent);\n\n if (Type.evaluate(this.visProp.trace)) {\n this.cloneToBackground(true);\n }\n\n return this;\n },\n\n /**\n * Applies the transformations of the element to {@link JXG.Point#baseElement}.\n * Point transformations are relative to a base element.\n * @param {Boolean} fromParent True if the drag comes from a child element. This is the case if a line\n * through two points is dragged. Otherwise, the element is the drag element and we apply the\n * the inverse transformation to the baseElement if is different from the element.\n * @returns {JXG.CoordsElement} Reference to this object.\n */\n updateTransform: function (fromParent) {\n var c, i;\n\n if (this.transformations.length === 0 || this.baseElement === null) {\n return this;\n }\n\n if (this === this.baseElement) {\n // Case of bindTo\n c = this.transformations[0].apply(this.baseElement, 'self');\n this.coords.setCoordinates(Const.COORDS_BY_USER, c);\n } else {\n c = this.transformations[0].apply(this.baseElement);\n }\n this.coords.setCoordinates(Const.COORDS_BY_USER, c);\n\n for (i = 1; i < this.transformations.length; i++) {\n this.coords.setCoordinates(Const.COORDS_BY_USER, this.transformations[i].apply(this));\n }\n return this;\n },\n\n /**\n * Calls the renderer to update the drawing.\n * @private\n */\n updateRenderer: function () {\n this.updateRendererGeneric('updatePoint');\n return this;\n },\n\n // documented in JXG.GeometryElement\n bounds: function () {\n return this.coords.usrCoords.slice(1).concat(this.coords.usrCoords.slice(1));\n },\n\n /**\n * Convert the point to intersection point and update the construction.\n * To move the point visual onto the intersection, a call of board update is necessary.\n *\n * @param {String|Object} el1, el2, i, j The intersecting objects and the numbers.\n **/\n makeIntersection: function (el1, el2, i, j) {\n var func;\n\n el1 = this.board.select(el1);\n el2 = this.board.select(el2);\n\n func = Geometry.intersectionFunction(this.board, el1, el2, i, j,\n Type.evaluate(this.visProp.alwaysintersect));\n this.addConstraint([func]);\n\n try {\n el1.addChild(this);\n el2.addChild(this);\n } catch (e) {\n throw new Error(\"JSXGraph: Can't create 'intersection' with parent types '\" +\n (typeof el1) + \"' and '\" + (typeof el2) + \"'.\");\n }\n\n this.type = Const.OBJECT_TYPE_INTERSECTION;\n this.elType = 'intersection';\n this.parents = [el1.id, el2.id, i, j];\n\n this.generatePolynomial = function () {\n var poly1 = el1.generatePolynomial(this),\n poly2 = el2.generatePolynomial(this);\n\n if ((poly1.length === 0) || (poly2.length === 0)) {\n return [];\n }\n\n return [poly1[0], poly2[0]];\n };\n\n this.prepareUpdate().update();\n },\n\n /**\n * Set the style of a point.\n * Used for GEONExT import and should not be used to set the point's face and size.\n * @param {Number} i Integer to determine the style.\n * @private\n */\n setStyle: function (i) {\n var facemap = [\n // 0-2\n 'cross', 'cross', 'cross',\n // 3-6\n 'circle', 'circle', 'circle', 'circle',\n // 7-9\n 'square', 'square', 'square',\n // 10-12\n 'plus', 'plus', 'plus'\n ], sizemap = [\n // 0-2\n 2, 3, 4,\n // 3-6\n 1, 2, 3, 4,\n // 7-9\n 2, 3, 4,\n // 10-12\n 2, 3, 4\n ];\n\n this.visProp.face = facemap[i];\n this.visProp.size = sizemap[i];\n\n this.board.renderer.changePointStyle(this);\n return this;\n },\n\n /**\n * @deprecated Use JXG#normalizePointFace instead\n * @param s\n * @returns {*}\n */\n normalizeFace: function (s) {\n JXG.deprecated('Point.normalizeFace()', 'JXG.normalizePointFace()');\n return Options.normalizePointFace(s);\n },\n\n /**\n * Set the face of a point element.\n * @param {String} f String which determines the face of the point. See {@link JXG.GeometryElement#face} for a list of available faces.\n * @see JXG.GeometryElement#face\n * @deprecated Use setAttribute()\n */\n face: function (f) {\n JXG.deprecated('Point.face()', 'Point.setAttribute()');\n this.setAttribute({face: f});\n },\n\n /**\n * Set the size of a point element\n * @param {Number} s Integer which determines the size of the point.\n * @see JXG.GeometryElement#size\n * @deprecated Use setAttribute()\n */\n size: function (s) {\n JXG.deprecated('Point.size()', 'Point.setAttribute()');\n this.setAttribute({size: s});\n },\n\n /**\n * Test if the point is on (is incident with) element \"el\".\n *\n * @param {JXG.GeometryElement} el\n * @param {Number} tol\n * @returns {Boolean}\n *\n * @example\n * var circ = board.create('circle', [[-2, -2], 1]);\n * var seg = board.create('segment', [[-1, -3], [0,0]]);\n * var line = board.create('line', [[1, 3], [2, -2]]);\n * var po = board.create('point', [-1, 0], {color: 'blue'});\n * var curve = board.create('functiongraph', ['sin(x)'], {strokeColor: 'blue'});\n * var pol = board.create('polygon', [[2,2], [4,2], [4,3]], {strokeColor: 'blue'});\n *\n * var point = board.create('point', [-1, 1], {\n * attractors: [line, seg, circ, po, curve, pol],\n * attractorDistance: 0.2\n * });\n *\n * var txt = board.create('text', [-4, 3, function() {\n * return 'point on line: ' + point.isOn(line) + '<br>' +\n * 'point on seg: ' + point.isOn(seg) + '<br>' +\n * 'point on circ = ' + point.isOn(circ) + '<br>' +\n * 'point on point = ' + point.isOn(po) + '<br>' +\n * 'point on curve = ' + point.isOn(curve) + '<br>' +\n * 'point on polygon = ' + point.isOn(pol) + '<br>';\n * }]);\n *\n * </pre><div id=\"JXG6c7d7404-758a-44eb-802c-e9644b9fab71\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG6c7d7404-758a-44eb-802c-e9644b9fab71',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var circ = board.create('circle', [[-2, -2], 1]);\n * var seg = board.create('segment', [[-1, -3], [0,0]]);\n * var line = board.create('line', [[1, 3], [2, -2]]);\n * var po = board.create('point', [-1, 0], {color: 'blue'});\n * var curve = board.create('functiongraph', ['sin(x)'], {strokeColor: 'blue'});\n * var pol = board.create('polygon', [[2,2], [4,2], [4,3]], {strokeColor: 'blue'});\n *\n * var point = board.create('point', [-1, 1], {\n * attractors: [line, seg, circ, po, curve, pol],\n * attractorDistance: 0.2\n * });\n *\n * var txt = board.create('text', [-4, 3, function() {\n * return 'point on line: ' + point.isOn(line) + '<br>' +\n * 'point on seg: ' + point.isOn(seg) + '<br>' +\n * 'point on circ = ' + point.isOn(circ) + '<br>' +\n * 'point on point = ' + point.isOn(po) + '<br>' +\n * 'point on curve = ' + point.isOn(curve) + '<br>' +\n * 'point on polygon = ' + point.isOn(pol) + '<br>';\n * }]);\n *\n * })();\n *\n * </script><pre>\n *\n */\n isOn: function(el, tol) {\n var arr, crds;\n\n tol = tol || Mat.eps;\n\n if (Type.isPoint(el)) {\n return this.Dist(el) < tol;\n } else if (el.elementClass === Const.OBJECT_CLASS_LINE) {\n if (el.elType === 'segment' && !Type.evaluate(this.visProp.alwaysintersect)) {\n arr = JXG.Math.Geometry.projectCoordsToSegment(\n this.coords.usrCoords,\n el.point1.coords.usrCoords,\n el.point2.coords.usrCoords);\n if (arr[1] >= 0 && arr[1] <= 1 &&\n Geometry.distPointLine(this.coords.usrCoords, el.stdform) < tol) {\n return true;\n } else {\n return false;\n }\n } else {\n return Geometry.distPointLine(this.coords.usrCoords, el.stdform) < tol;\n }\n } else if (el.elementClass === Const.OBJECT_CLASS_CIRCLE) {\n if (Type.evaluate(el.visProp.hasinnerpoints)) {\n return this.Dist(el.center) < el.Radius() + tol;\n }\n return Math.abs(this.Dist(el.center) - el.Radius()) < tol;\n } else if (el.elementClass === Const.OBJECT_CLASS_CURVE) {\n crds = Geometry.projectPointToCurve(this, el, this.board)[0];\n return Geometry.distance(this.coords.usrCoords, crds.usrCoords, 3) < tol;\n } else if (el.type === Const.OBJECT_TYPE_POLYGON) {\n if (Type.evaluate(el.visProp.hasinnerpoints)) {\n if (el.pnpoly(this.coords.usrCoords[1], this.coords.usrCoords[2], JXG.COORDS_BY_USER)) {\n return true;\n }\n }\n arr = Geometry.projectCoordsToPolygon(this.coords.usrCoords, el);\n return Geometry.distance(this.coords.usrCoords, arr, 3) < tol;\n } else if (el.type === Const.OBJECT_TYPE_TURTLE) {\n crds = Geometry.projectPointToTurtle(this, el, this.board);\n return Geometry.distance(this.coords.usrCoords, crds.usrCoords, 3) < tol;\n }\n\n // TODO: Arc, Sector\n return false;\n },\n\n // Already documented in GeometryElement\n cloneToBackground: function () {\n var copy = {};\n\n copy.id = this.id + 'T' + this.numTraces;\n this.numTraces += 1;\n\n copy.coords = this.coords;\n copy.visProp = Type.deepCopy(this.visProp, this.visProp.traceattributes, true);\n copy.visProp.layer = this.board.options.layer.trace;\n copy.elementClass = Const.OBJECT_CLASS_POINT;\n copy.board = this.board;\n Type.clearVisPropOld(copy);\n\n copy.visPropCalc = {\n visible: Type.evaluate(copy.visProp.visible)\n };\n\n this.board.renderer.drawPoint(copy);\n this.traces[copy.id] = copy.rendNode;\n\n return this;\n }\n\n });\n\n /**\n * @class This element is used to provide a constructor for a general point. A free point is created if the given parent elements are all numbers\n * and the property fixed is not set or set to false. If one or more parent elements is not a number but a string containing a GEONE<sub>x</sub>T\n * constraint or a function the point will be considered as constrained). That means that the user won't be able to change the point's\n * position directly.\n * @pseudo\n * @description\n * @name Point\n * @augments JXG.Point\n * @constructor\n * @type JXG.Point\n * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {Number,string,function_Number,string,function_Number,string,function} z_,x,y Parent elements can be two or three elements of type number, a string containing a GEONE<sub>x</sub>T\n * constraint, or a function which takes no parameter and returns a number. Every parent element determines one coordinate. If a coordinate is\n * given by a number, the number determines the initial position of a free point. If given by a string or a function that coordinate will be constrained\n * that means the user won't be able to change the point's position directly by mouse because it will be calculated automatically depending on the string\n * or the function's return value. If two parent elements are given the coordinates will be interpreted as 2D affine Euclidean coordinates, if three such\n * parent elements are given they will be interpreted as homogeneous coordinates.\n * @param {JXG.Point_JXG.Transformation_Array} Point,Transformation A point can also be created providing a transformation or an array of transformations.\n * The resulting point is a clone of the base point transformed by the given Transformation. {@see JXG.Transformation}.\n *\n * @example\n * // Create a free point using affine Euclidean coordinates\n * var p1 = board.create('point', [3.5, 2.0]);\n * </pre><div class=\"jxgbox\" id=\"JXG672f1764-7dfa-4abc-a2c6-81fbbf83e44b\" style=\"width: 200px; height: 200px;\"></div>\n * <script type=\"text/javascript\">\n * var board = JXG.JSXGraph.initBoard('JXG672f1764-7dfa-4abc-a2c6-81fbbf83e44b', {boundingbox: [-1, 5, 5, -1], axis: true, showcopyright: false, shownavigation: false});\n * var p1 = board.create('point', [3.5, 2.0]);\n * </script><pre>\n * @example\n * // Create a constrained point using anonymous function\n * var p2 = board.create('point', [3.5, function () { return p1.X(); }]);\n * </pre><div class=\"jxgbox\" id=\"JXG4fd4410c-3383-4e80-b1bb-961f5eeef224\" style=\"width: 200px; height: 200px;\"></div>\n * <script type=\"text/javascript\">\n * var fpex1_board = JXG.JSXGraph.initBoard('JXG4fd4410c-3383-4e80-b1bb-961f5eeef224', {boundingbox: [-1, 5, 5, -1], axis: true, showcopyright: false, shownavigation: false});\n * var fpex1_p1 = fpex1_board.create('point', [3.5, 2.0]);\n * var fpex1_p2 = fpex1_board.create('point', [3.5, function () { return fpex1_p1.X(); }]);\n * </script><pre>\n * @example\n * // Create a point using transformations\n * var trans = board.create('transform', [2, 0.5], {type:'scale'});\n * var p3 = board.create('point', [p2, trans]);\n * </pre><div class=\"jxgbox\" id=\"JXG630afdf3-0a64-46e0-8a44-f51bd197bb8d\" style=\"width: 400px; height: 400px;\"></div>\n * <script type=\"text/javascript\">\n * var fpex2_board = JXG.JSXGraph.initBoard('JXG630afdf3-0a64-46e0-8a44-f51bd197bb8d', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});\n * var fpex2_trans = fpex2_board.create('transform', [2, 0.5], {type:'scale'});\n * var fpex2_p2 = fpex2_board.create('point', [3.5, 2.0]);\n * var fpex2_p3 = fpex2_board.create('point', [fpex2_p2, fpex2_trans]);\n * </script><pre>\n */\n JXG.createPoint = function (board, parents, attributes) {\n var el, attr;\n\n attr = Type.copyAttributes(attributes, board.options, 'point');\n el = CoordsElement.create(JXG.Point, board, parents, attr);\n if (!el) {\n throw new Error(\"JSXGraph: Can't create point with parent types '\" +\n (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"'.\" +\n \"\\nPossible parent types: [x,y], [z,x,y], [element,transformation]\");\n }\n\n return el;\n };\n\n /**\n * @class This element is used to provide a constructor for a glider point.\n * @pseudo\n * @description A glider is a point which lives on another geometric element like a line, circle, curve, turtle.\n * @name Glider\n * @augments JXG.Point\n * @constructor\n * @type JXG.Point\n * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {Number_Number_Number_JXG.GeometryElement} z_,x_,y_,GlideObject Parent elements can be two or three elements of type number and the object the glider lives on.\n * The coordinates are completely optional. If not given the origin is used. If you provide two numbers for coordinates they will be interpreted as affine Euclidean\n * coordinates, otherwise they will be interpreted as homogeneous coordinates. In any case the point will be projected on the glide object.\n * @example\n * // Create a glider with user defined coordinates. If the coordinates are not on\n * // the circle (like in this case) the point will be projected onto the circle.\n * var p1 = board.create('point', [2.0, 2.0]);\n * var c1 = board.create('circle', [p1, 2.0]);\n * var p2 = board.create('glider', [2.0, 1.5, c1]);\n * </pre><div class=\"jxgbox\" id=\"JXG4f65f32f-e50a-4b50-9b7c-f6ec41652930\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * var gpex1_board = JXG.JSXGraph.initBoard('JXG4f65f32f-e50a-4b50-9b7c-f6ec41652930', {boundingbox: [-1, 5, 5, -1], axis: true, showcopyright: false, shownavigation: false});\n * var gpex1_p1 = gpex1_board.create('point', [2.0, 2.0]);\n * var gpex1_c1 = gpex1_board.create('circle', [gpex1_p1, 2.0]);\n * var gpex1_p2 = gpex1_board.create('glider', [2.0, 1.5, gpex1_c1]);\n * </script><pre>\n * @example\n * // Create a glider with default coordinates (1,0,0). Same premises as above.\n * var p1 = board.create('point', [2.0, 2.0]);\n * var c1 = board.create('circle', [p1, 2.0]);\n * var p2 = board.create('glider', [c1]);\n * </pre><div class=\"jxgbox\" id=\"JXG4de7f181-631a-44b1-a12f-bc4d995609e8\" style=\"width: 200px; height: 200px;\"></div>\n * <script type=\"text/javascript\">\n * var gpex2_board = JXG.JSXGraph.initBoard('JXG4de7f181-631a-44b1-a12f-bc4d995609e8', {boundingbox: [-1, 5, 5, -1], axis: true, showcopyright: false, shownavigation: false});\n * var gpex2_p1 = gpex2_board.create('point', [2.0, 2.0]);\n * var gpex2_c1 = gpex2_board.create('circle', [gpex2_p1, 2.0]);\n * var gpex2_p2 = gpex2_board.create('glider', [gpex2_c1]);\n * </script><pre>\n *@example\n * //animate example 2\n * var p1 = board.create('point', [2.0, 2.0]);\n * var c1 = board.create('circle', [p1, 2.0]);\n * var p2 = board.create('glider', [c1]);\n * var button1 = board.create('button', [1, 7, 'start animation',function(){p2.startAnimation(1,4)}]);\n * var button2 = board.create('button', [1, 5, 'stop animation',function(){p2.stopAnimation()}]);\n * </pre><div class=\"jxgbox\" id=\"JXG4de7f181-631a-44b1-a12f-bc4d133709e8\" style=\"width: 200px; height: 200px;\"></div>\n * <script type=\"text/javascript\">\n * var gpex3_board = JXG.JSXGraph.initBoard('JXG4de7f181-631a-44b1-a12f-bc4d133709e8', {boundingbox: [-1, 10, 10, -1], axis: true, showcopyright: false, shownavigation: false});\n * var gpex3_p1 = gpex3_board.create('point', [2.0, 2.0]);\n * var gpex3_c1 = gpex3_board.create('circle', [gpex3_p1, 2.0]);\n * var gpex3_p2 = gpex3_board.create('glider', [gpex3_c1]);\n * gpex3_board.create('button', [1, 7, 'start animation',function(){gpex3_p2.startAnimation(1,4)}]);\n * gpex3_board.create('button', [1, 5, 'stop animation',function(){gpex3_p2.stopAnimation()}]);\n * </script><pre>\n */\n JXG.createGlider = function (board, parents, attributes) {\n var el, coords,\n attr = Type.copyAttributes(attributes, board.options, 'glider');\n\n if (parents.length === 1) {\n coords = [0, 0];\n } else {\n coords = parents.slice(0, 2);\n }\n el = board.create('point', coords, attr);\n\n // eltype is set in here\n el.makeGlider(parents[parents.length - 1]);\n\n return el;\n };\n\n\n /**\n * @class An intersection point is a point which lives on two JSXGraph elements, i.e. it is one point of the the set\n * consisting of the intersection points of the two elements. The following element types can be (mutually) intersected: line, circle,\n * curve, polygon, polygonal chain.\n *\n * @pseudo\n * @name Intersection\n * @augments JXG.Point\n * @constructor\n * @type JXG.Point\n * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {JXG.Line,JXG.Circle_JXG.Line,JXG.Circle_Number} el1,el2,i The result will be a intersection point on el1 and el2. i determines the\n * intersection point if two points are available: <ul>\n * <li>i==0: use the positive square root,</li>\n * <li>i==1: use the negative square root.</li></ul>\n * @example\n * // Create an intersection point of circle and line\n * var p1 = board.create('point', [2.0, 2.0]);\n * var c1 = board.create('circle', [p1, 2.0]);\n *\n * var p2 = board.create('point', [2.0, 2.0]);\n * var p3 = board.create('point', [2.0, 2.0]);\n * var l1 = board.create('line', [p2, p3]);\n *\n * var i = board.create('intersection', [c1, l1, 0]);\n * </pre><div class=\"jxgbox\" id=\"JXGe5b0e190-5200-4bc3-b995-b6cc53dc5dc0\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * var ipex1_board = JXG.JSXGraph.initBoard('JXGe5b0e190-5200-4bc3-b995-b6cc53dc5dc0', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false});\n * var ipex1_p1 = ipex1_board.create('point', [4.0, 4.0]);\n * var ipex1_c1 = ipex1_board.create('circle', [ipex1_p1, 2.0]);\n * var ipex1_p2 = ipex1_board.create('point', [1.0, 1.0]);\n * var ipex1_p3 = ipex1_board.create('point', [5.0, 3.0]);\n * var ipex1_l1 = ipex1_board.create('line', [ipex1_p2, ipex1_p3]);\n * var ipex1_i = ipex1_board.create('intersection', [ipex1_c1, ipex1_l1, 0]);\n * </script><pre>\n */\n JXG.createIntersectionPoint = function (board, parents, attributes) {\n var el, el1, el2, func, i, j,\n attr = Type.copyAttributes(attributes, board.options, 'intersection');\n\n // make sure we definitely have the indices\n parents.push(0, 0);\n\n el1 = board.select(parents[0]);\n el2 = board.select(parents[1]);\n\n i = parents[2] || 0;\n j = parents[3] || 0;\n\n el = board.create('point', [0, 0, 0], attr);\n\n // el.visProp.alwaysintersect is evaluated as late as in the returned function\n func = Geometry.intersectionFunction(board, el1, el2, i, j, el.visProp.alwaysintersect);\n el.addConstraint([func]);\n\n try {\n el1.addChild(el);\n el2.addChild(el);\n } catch (e) {\n throw new Error(\"JSXGraph: Can't create 'intersection' with parent types '\" +\n (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"'.\");\n }\n\n el.type = Const.OBJECT_TYPE_INTERSECTION;\n el.elType = 'intersection';\n el.setParents([el1.id, el2.id]);\n\n /**\n * Array of length 2 containing the numbers i and j.\n * The intersection point is i-th intersection point.\n * j is unused.\n * @type Array\n * @private\n */\n el.intersectionNumbers = [i, j];\n el.getParents = function() {\n return this.parents.concat(this.intersectionNumbers);\n };\n\n el.generatePolynomial = function () {\n var poly1 = el1.generatePolynomial(el),\n poly2 = el2.generatePolynomial(el);\n\n if ((poly1.length === 0) || (poly2.length === 0)) {\n return [];\n }\n\n return [poly1[0], poly2[0]];\n };\n\n return el;\n };\n\n /**\n * @class This element is used to provide a constructor for the \"other\" intersection point.\n * @pseudo\n * @description An intersection point is a point which lives on two Lines or Circles or one Line and one Circle at the same time, i.e.\n * an intersection point of the two elements. Additionally, one intersection point is provided. The function returns the other intersection point.\n * @name OtherIntersection\n * @augments JXG.Point\n * @constructor\n * @type JXG.Point\n * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {JXG.Line,JXG.Circle_JXG.Line,JXG.Circle_JXG.Point} el1,el2,p The result will be a intersection point on el1 and el2. i determines the\n * intersection point different from p:\n * @example\n * // Create an intersection point of circle and line\n * var p1 = board.create('point', [2.0, 2.0]);\n * var c1 = board.create('circle', [p1, 2.0]);\n *\n * var p2 = board.create('point', [2.0, 2.0]);\n * var p3 = board.create('point', [2.0, 2.0]);\n * var l1 = board.create('line', [p2, p3]);\n *\n * var i = board.create('intersection', [c1, l1, 0]);\n * var j = board.create('otherintersection', [c1, l1, i]);\n * </pre><div class=\"jxgbox\" id=\"JXG45e25f12-a1de-4257-a466-27a2ae73614c\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * var ipex2_board = JXG.JSXGraph.initBoard('JXG45e25f12-a1de-4257-a466-27a2ae73614c', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false});\n * var ipex2_p1 = ipex2_board.create('point', [4.0, 4.0]);\n * var ipex2_c1 = ipex2_board.create('circle', [ipex2_p1, 2.0]);\n * var ipex2_p2 = ipex2_board.create('point', [1.0, 1.0]);\n * var ipex2_p3 = ipex2_board.create('point', [5.0, 3.0]);\n * var ipex2_l1 = ipex2_board.create('line', [ipex2_p2, ipex2_p3]);\n * var ipex2_i = ipex2_board.create('intersection', [ipex2_c1, ipex2_l1, 0], {name:'D'});\n * var ipex2_j = ipex2_board.create('otherintersection', [ipex2_c1, ipex2_l1, ipex2_i], {name:'E'});\n * </script><pre>\n */\n JXG.createOtherIntersectionPoint = function (board, parents, attributes) {\n var el, el1, el2, other;\n\n if (parents.length !== 3 ||\n !Type.isPoint(parents[2]) ||\n (parents[0].elementClass !== Const.OBJECT_CLASS_LINE && parents[0].elementClass !== Const.OBJECT_CLASS_CIRCLE) ||\n (parents[1].elementClass !== Const.OBJECT_CLASS_LINE && parents[1].elementClass !== Const.OBJECT_CLASS_CIRCLE)) {\n // Failure\n throw new Error(\"JSXGraph: Can't create 'other intersection point' with parent types '\" +\n (typeof parents[0]) + \"', '\" + (typeof parents[1]) + \"'and '\" + (typeof parents[2]) + \"'.\" +\n \"\\nPossible parent types: [circle|line,circle|line,point]\");\n }\n\n el1 = board.select(parents[0]);\n el2 = board.select(parents[1]);\n other = board.select(parents[2]);\n\n el = board.create('point', [function () {\n var c = Geometry.meet(el1.stdform, el2.stdform, 0, el1.board);\n\n if (Math.abs(other.X() - c.usrCoords[1]) > Mat.eps ||\n Math.abs(other.Y() - c.usrCoords[2]) > Mat.eps ||\n Math.abs(other.Z() - c.usrCoords[0]) > Mat.eps) {\n return c;\n }\n\n return Geometry.meet(el1.stdform, el2.stdform, 1, el1.board);\n }], attributes);\n\n el.type = Const.OBJECT_TYPE_INTERSECTION;\n el.elType = 'otherintersection';\n el.setParents([el1.id, el2.id, other]);\n\n el1.addChild(el);\n el2.addChild(el);\n\n el.generatePolynomial = function () {\n var poly1 = el1.generatePolynomial(el),\n poly2 = el2.generatePolynomial(el);\n\n if ((poly1.length === 0) || (poly2.length === 0)) {\n return [];\n }\n\n return [poly1[0], poly2[0]];\n };\n\n return el;\n };\n\n /**\n * @class This element is used to provide a constructor for the pole point of a line with respect to a conic or a circle.\n * @pseudo\n * @description The pole point is the unique reciprocal relationship of a line with respect to a conic.\n * The lines tangent to the intersections of a conic and a line intersect at the pole point of that line with respect to that conic.\n * A line tangent to a conic has the pole point of that line with respect to that conic as the tangent point.\n * See {@link http://en.wikipedia.org/wiki/Pole_and_polar} for more information on pole and polar.\n * @name PolePoint\n * @augments JXG.Point\n * @constructor\n * @type JXG.Point\n * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {JXG.Conic,JXG.Circle_JXG.Point} el1,el2 or\n * @param {JXG.Point_JXG.Conic,JXG.Circle} el1,el2 The result will be the pole point of the line with respect to the conic or the circle.\n * @example\n * // Create the pole point of a line with respect to a conic\n * var p1 = board.create('point', [-1, 2]);\n * var p2 = board.create('point', [ 1, 4]);\n * var p3 = board.create('point', [-1,-2]);\n * var p4 = board.create('point', [ 0, 0]);\n * var p5 = board.create('point', [ 4,-2]);\n * var c1 = board.create('conic',[p1,p2,p3,p4,p5]);\n * var p6 = board.create('point', [-1, 4]);\n * var p7 = board.create('point', [2, -2]);\n * var l1 = board.create('line', [p6, p7]);\n * var p8 = board.create('polepoint', [c1, l1]);\n * </pre><div class=\"jxgbox\" id=\"JXG7b7233a0-f363-47dd-9df5-8018d0d17a98\" class=\"jxgbox\" style=\"width:400px; height:400px;\"></div>\n * <script type='text/javascript'>\n * var ppex1_board = JXG.JSXGraph.initBoard('JXG7b7233a0-f363-47dd-9df5-8018d0d17a98', {boundingbox: [-3, 5, 5, -3], axis: true, showcopyright: false, shownavigation: false});\n * var ppex1_p1 = ppex1_board.create('point', [-1, 2]);\n * var ppex1_p2 = ppex1_board.create('point', [ 1, 4]);\n * var ppex1_p3 = ppex1_board.create('point', [-1,-2]);\n * var ppex1_p4 = ppex1_board.create('point', [ 0, 0]);\n * var ppex1_p5 = ppex1_board.create('point', [ 4,-2]);\n * var ppex1_c1 = ppex1_board.create('conic',[ppex1_p1,ppex1_p2,ppex1_p3,ppex1_p4,ppex1_p5]);\n * var ppex1_p6 = ppex1_board.create('point', [-1, 4]);\n * var ppex1_p7 = ppex1_board.create('point', [2, -2]);\n * var ppex1_l1 = ppex1_board.create('line', [ppex1_p6, ppex1_p7]);\n * var ppex1_p8 = ppex1_board.create('polepoint', [ppex1_c1, ppex1_l1]);\n * </script><pre>\n * @example\n * // Create the pole point of a line with respect to a circle\n * var p1 = board.create('point', [1, 1]);\n * var p2 = board.create('point', [2, 3]);\n * var c1 = board.create('circle',[p1,p2]);\n * var p3 = board.create('point', [-1, 4]);\n * var p4 = board.create('point', [4, -1]);\n * var l1 = board.create('line', [p3, p4]);\n * var p5 = board.create('polepoint', [c1, l1]);\n * </pre><div class=\"jxgbox\" id=\"JXG7b7233a0-f363-47dd-9df5-9018d0d17a98\" class=\"jxgbox\" style=\"width:400px; height:400px;\"></div>\n * <script type='text/javascript'>\n * var ppex2_board = JXG.JSXGraph.initBoard('JXG7b7233a0-f363-47dd-9df5-9018d0d17a98', {boundingbox: [-3, 7, 7, -3], axis: true, showcopyright: false, shownavigation: false});\n * var ppex2_p1 = ppex2_board.create('point', [1, 1]);\n * var ppex2_p2 = ppex2_board.create('point', [2, 3]);\n * var ppex2_c1 = ppex2_board.create('circle',[ppex2_p1,ppex2_p2]);\n * var ppex2_p3 = ppex2_board.create('point', [-1, 4]);\n * var ppex2_p4 = ppex2_board.create('point', [4, -1]);\n * var ppex2_l1 = ppex2_board.create('line', [ppex2_p3, ppex2_p4]);\n * var ppex2_p5 = ppex2_board.create('polepoint', [ppex2_c1, ppex2_l1]);\n * </script><pre>\n */\n JXG.createPolePoint = function (board, parents, attributes) {\n var el, el1, el2,\n firstParentIsConic, secondParentIsConic,\n firstParentIsLine, secondParentIsLine;\n\n if (parents.length > 1) {\n firstParentIsConic = (parents[0].type === Const.OBJECT_TYPE_CONIC ||\n parents[0].elementClass === Const.OBJECT_CLASS_CIRCLE);\n secondParentIsConic = (parents[1].type === Const.OBJECT_TYPE_CONIC ||\n parents[1].elementClass === Const.OBJECT_CLASS_CIRCLE);\n\n firstParentIsLine = (parents[0].elementClass === Const.OBJECT_CLASS_LINE);\n secondParentIsLine = (parents[1].elementClass === Const.OBJECT_CLASS_LINE);\n }\n\n/* if (parents.length !== 2 || !((\n parents[0].type === Const.OBJECT_TYPE_CONIC ||\n parents[0].elementClass === Const.OBJECT_CLASS_CIRCLE) &&\n parents[1].elementClass === Const.OBJECT_CLASS_LINE ||\n parents[0].elementClass === Const.OBJECT_CLASS_LINE && (\n parents[1].type === Const.OBJECT_TYPE_CONIC ||\n parents[1].elementClass === Const.OBJECT_CLASS_CIRCLE))) {*/\n if (parents.length !== 2 ||\n !((firstParentIsConic && secondParentIsLine) ||\n (firstParentIsLine && secondParentIsConic))) {\n // Failure\n throw new Error(\"JSXGraph: Can't create 'pole point' with parent types '\" +\n (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"'.\" +\n \"\\nPossible parent type: [conic|circle,line], [line,conic|circle]\");\n }\n\n if (secondParentIsLine) {\n el1 = board.select(parents[0]);\n el2 = board.select(parents[1]);\n } else {\n el1 = board.select(parents[1]);\n el2 = board.select(parents[0]);\n }\n\n el = board.create('point',\n [function () {\n var q = el1.quadraticform,\n s = el2.stdform.slice(0, 3);\n\n return [JXG.Math.Numerics.det([s, q[1], q[2]]),\n JXG.Math.Numerics.det([q[0], s, q[2]]),\n JXG.Math.Numerics.det([q[0], q[1], s])];\n }], attributes);\n\n el.elType = 'polepoint';\n el.setParents([el1.id, el2.id]);\n\n el1.addChild(el);\n el2.addChild(el);\n\n return el;\n };\n\n JXG.registerElement('point', JXG.createPoint);\n JXG.registerElement('glider', JXG.createGlider);\n JXG.registerElement('intersection', JXG.createIntersectionPoint);\n JXG.registerElement('otherintersection', JXG.createOtherIntersectionPoint);\n JXG.registerElement('polepoint', JXG.createPolePoint);\n\n return {\n Point: JXG.Point,\n createPoint: JXG.createPoint,\n createGlider: JXG.createGlider,\n createIntersection: JXG.createIntersectionPoint,\n createOtherIntersection: JXG.createOtherIntersectionPoint,\n createPolePoint: JXG.createPolePoint\n };\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true*/\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n jxg\n math/math\n math/geometry\n math/numerics\n math/statistics\n base/constants\n base/coords\n base/element\n utils/type\n elements:\n transform\n point\n ticks\n */\n\n/**\n * @fileoverview The geometry object Line is defined in this file. Line stores all\n * style and functional properties that are required to draw and move a line on\n * a board.\n */\n\ndefine('base/line',[\n 'jxg', 'math/math', 'math/geometry', 'math/numerics', 'math/statistics', 'base/constants', 'base/coords',\n 'base/element', 'utils/type', 'base/point'\n], function (JXG, Mat, Geometry, Numerics, Statistics, Const, Coords, GeometryElement, Type, Point) {\n\n \"use strict\";\n\n /**\n * The Line class is a basic class for all kind of line objects, e.g. line, arrow, and axis. It is usually defined by two points and can\n * be intersected with some other geometry elements.\n * @class Creates a new basic line object. Do not use this constructor to create a line.\n * Use {@link JXG.Board#create} with\n * type {@link Line}, {@link Arrow}, or {@link Axis} instead.\n * @constructor\n * @augments JXG.GeometryElement\n * @param {String,JXG.Board} board The board the new line is drawn on.\n * @param {Point} p1 Startpoint of the line.\n * @param {Point} p2 Endpoint of the line.\n * @param {Object} attributes Javascript object containing attributes like name, id and colors.\n */\n JXG.Line = function (board, p1, p2, attributes) {\n this.constructor(board, attributes, Const.OBJECT_TYPE_LINE, Const.OBJECT_CLASS_LINE);\n\n /**\n * Startpoint of the line. You really should not set this field directly as it may break JSXGraph's\n * update system so your construction won't be updated properly.\n * @type JXG.Point\n */\n this.point1 = this.board.select(p1);\n\n /**\n * Endpoint of the line. Just like {@link JXG.Line.point1} you shouldn't write this field directly.\n * @type JXG.Point\n */\n this.point2 = this.board.select(p2);\n\n /**\n * Array of ticks storing all the ticks on this line. Do not set this field directly and use\n * {@link JXG.Line#addTicks} and {@link JXG.Line#removeTicks} to add and remove ticks to and from the line.\n * @type Array\n * @see JXG.Ticks\n */\n this.ticks = [];\n\n /**\n * Reference of the ticks created automatically when constructing an axis.\n * @type JXG.Ticks\n * @see JXG.Ticks\n */\n this.defaultTicks = null;\n\n /**\n * If the line is the border of a polygon, the polygon object is stored, otherwise null.\n * @type JXG.Polygon\n * @default null\n * @private\n */\n this.parentPolygon = null;\n\n /* Register line at board */\n this.id = this.board.setId(this, 'L');\n this.board.renderer.drawLine(this);\n this.board.finalizeAdding(this);\n\n this.elType = 'line';\n\n /* Add line as child to defining points */\n if (this.point1._is_new) {\n this.addChild(this.point1);\n delete this.point1._is_new;\n } else {\n this.point1.addChild(this);\n }\n if (this.point2._is_new) {\n this.addChild(this.point2);\n delete this.point2._is_new;\n } else {\n this.point2.addChild(this);\n }\n\n this.inherits.push(this.point1, this.point2);\n\n this.updateStdform(); // This is needed in the following situation:\n // * the line is defined by three coordinates\n // * and it will have a glider\n // * and board.suspendUpdate() has been called.\n\n // create Label\n this.createLabel();\n\n this.methodMap = JXG.deepCopy(this.methodMap, {\n point1: 'point1',\n point2: 'point2',\n getSlope: 'getSlope',\n getRise: 'getRise',\n getYIntersect: 'getRise',\n getAngle: 'getAngle',\n L: 'L',\n length: 'L'\n });\n };\n\n JXG.Line.prototype = new GeometryElement();\n\n JXG.extend(JXG.Line.prototype, /** @lends JXG.Line.prototype */ {\n /**\n * Checks whether (x,y) is near the line.\n * @param {Number} x Coordinate in x direction, screen coordinates.\n * @param {Number} y Coordinate in y direction, screen coordinates.\n * @returns {Boolean} True if (x,y) is near the line, False otherwise.\n */\n hasPoint: function (x, y) {\n // Compute the stdform of the line in screen coordinates.\n var c = [], s,\n v = [1, x, y],\n vnew,\n p1c, p2c, d, pos, i,\n prec, type,\n sw = Type.evaluate(this.visProp.strokewidth);\n\n if (Type.isObject(Type.evaluate(this.visProp.precision))) {\n type = this.board._inputDevice;\n prec = Type.evaluate(this.visProp.precision[type]);\n } else {\n // 'inherit'\n prec = this.board.options.precision.hasPoint;\n }\n prec += sw * 0.5;\n\n c[0] = this.stdform[0] -\n this.stdform[1] * this.board.origin.scrCoords[1] / this.board.unitX +\n this.stdform[2] * this.board.origin.scrCoords[2] / this.board.unitY;\n c[1] = this.stdform[1] / this.board.unitX;\n c[2] = this.stdform[2] / (-this.board.unitY);\n\n s = Geometry.distPointLine(v, c);\n if (isNaN(s) || s > prec) {\n return false;\n }\n\n if (Type.evaluate(this.visProp.straightfirst) &&\n Type.evaluate(this.visProp.straightlast)) {\n return true;\n }\n\n // If the line is a ray or segment we have to check if the projected point is between P1 and P2.\n p1c = this.point1.coords;\n p2c = this.point2.coords;\n\n // Project the point orthogonally onto the line\n vnew = [0, c[1], c[2]];\n // Orthogonal line to c through v\n vnew = Mat.crossProduct(vnew, v);\n // Intersect orthogonal line with line\n vnew = Mat.crossProduct(vnew, c);\n\n // Normalize the projected point\n vnew[1] /= vnew[0];\n vnew[2] /= vnew[0];\n vnew[0] = 1;\n\n vnew = (new Coords(Const.COORDS_BY_SCREEN, vnew.slice(1), this.board)).usrCoords;\n d = p1c.distance(Const.COORDS_BY_USER, p2c);\n p1c = p1c.usrCoords.slice(0);\n p2c = p2c.usrCoords.slice(0);\n\n // The defining points are identical\n if (d < Mat.eps) {\n pos = 0;\n } else {\n /*\n * Handle the cases, where one of the defining points is an ideal point.\n * d is set to something close to infinity, namely 1/eps.\n * The ideal point is (temporarily) replaced by a finite point which has\n * distance d from the other point.\n * This is accomplished by extracting the x- and y-coordinates (x,y)=:v of the ideal point.\n * v determines the direction of the line. v is normalized, i.e. set to length 1 by dividing through its length.\n * Finally, the new point is the sum of the other point and v*d.\n *\n */\n\n // At least one point is an ideal point\n if (d === Number.POSITIVE_INFINITY) {\n d = 1 / Mat.eps;\n\n // The second point is an ideal point\n if (Math.abs(p2c[0]) < Mat.eps) {\n d /= Geometry.distance([0, 0, 0], p2c);\n p2c = [1, p1c[1] + p2c[1] * d, p1c[2] + p2c[2] * d];\n // The first point is an ideal point\n } else {\n d /= Geometry.distance([0, 0, 0], p1c);\n p1c = [1, p2c[1] + p1c[1] * d, p2c[2] + p1c[2] * d];\n }\n }\n i = 1;\n d = p2c[i] - p1c[i];\n\n if (Math.abs(d) < Mat.eps) {\n i = 2;\n d = p2c[i] - p1c[i];\n }\n pos = (vnew[i] - p1c[i]) / d;\n }\n\n if (!Type.evaluate(this.visProp.straightfirst) && pos < 0) {\n return false;\n }\n\n return !(!Type.evaluate(this.visProp.straightlast) && pos > 1);\n\n },\n\n // documented in base/element\n update: function () {\n var funps;\n\n if (!this.needsUpdate) {\n return this;\n }\n\n if (this.constrained) {\n if (Type.isFunction(this.funps)) {\n funps = this.funps();\n if (funps && funps.length && funps.length === 2) {\n this.point1 = funps[0];\n this.point2 = funps[1];\n }\n } else {\n if (Type.isFunction(this.funp1)) {\n funps = this.funp1();\n if (Type.isPoint(funps)) {\n this.point1 = funps;\n } else if (funps && funps.length && funps.length === 2) {\n this.point1.setPositionDirectly(Const.COORDS_BY_USER, funps);\n }\n }\n\n if (Type.isFunction(this.funp2)) {\n funps = this.funp2();\n if (Type.isPoint(funps)) {\n this.point2 = funps;\n } else if (funps && funps.length && funps.length === 2) {\n this.point2.setPositionDirectly(Const.COORDS_BY_USER, funps);\n }\n }\n }\n }\n\n this.updateSegmentFixedLength();\n this.updateStdform();\n\n if (Type.evaluate(this.visProp.trace)) {\n this.cloneToBackground(true);\n }\n\n return this;\n },\n\n /**\n * Update segments with fixed length and at least one movable point.\n * @private\n */\n updateSegmentFixedLength: function () {\n var d, dnew, d1, d2, drag1, drag2, x, y;\n\n if (!this.hasFixedLength) {\n return this;\n }\n\n // Compute the actual length of the segment\n d = this.point1.Dist(this.point2);\n // Determine the length the segment ought to have\n dnew = this.fixedLength();\n // Distances between the two points and their respective\n // position before the update\n d1 = this.fixedLengthOldCoords[0].distance(Const.COORDS_BY_USER, this.point1.coords);\n d2 = this.fixedLengthOldCoords[1].distance(Const.COORDS_BY_USER, this.point2.coords);\n\n // If the position of the points or the fixed length function has been changed we have to work.\n if (d1 > Mat.eps || d2 > Mat.eps || d !== dnew) {\n drag1 = this.point1.isDraggable &&\n (this.point1.type !== Const.OBJECT_TYPE_GLIDER) &&\n !Type.evaluate(this.point1.visProp.fixed);\n drag2 = this.point2.isDraggable &&\n (this.point2.type !== Const.OBJECT_TYPE_GLIDER) &&\n !Type.evaluate(this.point2.visProp.fixed);\n\n // First case: the two points are different\n // Then we try to adapt the point that was not dragged\n // If this point can not be moved (e.g. because it is a glider)\n // we try move the other point\n if (d > Mat.eps) {\n if ((d1 > d2 && drag2) ||\n (d1 <= d2 && drag2 && !drag1)) {\n this.point2.setPositionDirectly(Const.COORDS_BY_USER, [\n this.point1.X() + (this.point2.X() - this.point1.X()) * dnew / d,\n this.point1.Y() + (this.point2.Y() - this.point1.Y()) * dnew / d\n ]);\n this.point2.fullUpdate();\n } else if ((d1 <= d2 && drag1) ||\n (d1 > d2 && drag1 && !drag2)) {\n this.point1.setPositionDirectly(Const.COORDS_BY_USER, [\n this.point2.X() + (this.point1.X() - this.point2.X()) * dnew / d,\n this.point2.Y() + (this.point1.Y() - this.point2.Y()) * dnew / d\n ]);\n this.point1.fullUpdate();\n }\n // Second case: the two points are identical. In this situation\n // we choose a random direction.\n } else {\n x = Math.random() - 0.5;\n y = Math.random() - 0.5;\n d = Math.sqrt(x * x + y * y);\n\n if (drag2) {\n this.point2.setPositionDirectly(Const.COORDS_BY_USER, [\n this.point1.X() + x * dnew / d,\n this.point1.Y() + y * dnew / d\n ]);\n this.point2.fullUpdate();\n } else if (drag1) {\n this.point1.setPositionDirectly(Const.COORDS_BY_USER, [\n this.point2.X() + x * dnew / d,\n this.point2.Y() + y * dnew / d\n ]);\n this.point1.fullUpdate();\n }\n }\n // Finally, we save the position of the two points.\n this.fixedLengthOldCoords[0].setCoordinates(Const.COORDS_BY_USER, this.point1.coords.usrCoords);\n this.fixedLengthOldCoords[1].setCoordinates(Const.COORDS_BY_USER, this.point2.coords.usrCoords);\n }\n return this;\n },\n\n /**\n * Updates the stdform derived from the parent point positions.\n * @private\n */\n updateStdform: function () {\n var v = Mat.crossProduct(this.point1.coords.usrCoords, this.point2.coords.usrCoords);\n\n this.stdform[0] = v[0];\n this.stdform[1] = v[1];\n this.stdform[2] = v[2];\n this.stdform[3] = 0;\n\n this.normalize();\n },\n\n /**\n * Uses the boards renderer to update the line.\n * @private\n */\n updateRenderer: function () {\n //var wasReal;\n\n if (!this.needsUpdate) {\n return this;\n }\n\n if (this.visPropCalc.visible) {\n // wasReal = this.isReal;\n this.isReal = (!isNaN(this.point1.coords.usrCoords[1] + this.point1.coords.usrCoords[2] +\n this.point2.coords.usrCoords[1] + this.point2.coords.usrCoords[2]) &&\n (Mat.innerProduct(this.stdform, this.stdform, 3) >= Mat.eps * Mat.eps));\n\n if (//wasReal &&\n !this.isReal) {\n this.updateVisibility(false);\n }\n }\n\n if (this.visPropCalc.visible) {\n this.board.renderer.updateLine(this);\n }\n\n /* Update the label if visible. */\n if (this.hasLabel && this.visPropCalc.visible && this.label &&\n this.label.visPropCalc.visible && this.isReal) {\n\n this.label.update();\n this.board.renderer.updateText(this.label);\n }\n\n // Update rendNode display\n this.setDisplayRendNode();\n // if (this.visPropCalc.visible !== this.visPropOld.visible) {\n // this.setDisplayRendNode(this.visPropCalc.visible);\n // if (this.hasLabel) {\n // this.board.renderer.display(this.label, this.label.visPropCalc.visible);\n // }\n // }\n\n this.needsUpdate = false;\n return this;\n },\n\n /**\n * Used to generate a polynomial for a point p that lies on this line, i.e. p is collinear to\n * {@link JXG.Line#point1} and {@link JXG.Line#point2}.\n *\n * @param {JXG.Point} p The point for that the polynomial is generated.\n * @returns {Array} An array containing the generated polynomial.\n * @private\n */\n generatePolynomial: function (p) {\n var u1 = this.point1.symbolic.x,\n u2 = this.point1.symbolic.y,\n v1 = this.point2.symbolic.x,\n v2 = this.point2.symbolic.y,\n w1 = p.symbolic.x,\n w2 = p.symbolic.y;\n\n /*\n * The polynomial in this case is determined by three points being collinear:\n *\n * U (u1,u2) W (w1,w2) V (v1,v2)\n * ----x--------------x------------------------x----------------\n *\n * The collinearity condition is\n *\n * u2-w2 w2-v2\n * ------- = ------- (1)\n * u1-w1 w1-v1\n *\n * Multiplying (1) with denominators and simplifying is\n *\n * u2w1 - u2v1 + w2v1 - u1w2 + u1v2 - w1v2 = 0\n */\n\n return [['(', u2, ')*(', w1, ')-(', u2, ')*(', v1, ')+(', w2, ')*(', v1, ')-(', u1, ')*(', w2, ')+(', u1, ')*(', v2, ')-(', w1, ')*(', v2, ')'].join('')];\n },\n\n /**\n * Calculates the y intersect of the line.\n * @returns {Number} The y intersect.\n */\n getRise: function () {\n if (Math.abs(this.stdform[2]) >= Mat.eps) {\n return -this.stdform[0] / this.stdform[2];\n }\n\n return Infinity;\n },\n\n /**\n * Calculates the slope of the line.\n * @returns {Number} The slope of the line or Infinity if the line is parallel to the y-axis.\n */\n getSlope: function () {\n if (Math.abs(this.stdform[2]) >= Mat.eps) {\n return -this.stdform[1] / this.stdform[2];\n }\n\n return Infinity;\n },\n\n /**\n * Determines the angle between the positive x axis and the line.\n * @returns {Number}\n */\n getAngle: function () {\n return Math.atan2(-this.stdform[1], this.stdform[2]);\n },\n\n /**\n * Determines whether the line is drawn beyond {@link JXG.Line#point1} and\n * {@link JXG.Line#point2} and updates the line.\n * @param {Boolean} straightFirst True if the Line shall be drawn beyond\n * {@link JXG.Line#point1}, false otherwise.\n * @param {Boolean} straightLast True if the Line shall be drawn beyond\n * {@link JXG.Line#point2}, false otherwise.\n * @see #straightFirst\n * @see #straightLast\n * @private\n */\n setStraight: function (straightFirst, straightLast) {\n this.visProp.straightfirst = straightFirst;\n this.visProp.straightlast = straightLast;\n\n this.board.renderer.updateLine(this);\n return this;\n },\n\n // documented in geometry element\n getTextAnchor: function () {\n return new Coords(Const.COORDS_BY_USER, [0.5 * (this.point2.X() + this.point1.X()), 0.5 * (this.point2.Y() + this.point1.Y())], this.board);\n },\n\n /**\n * Adjusts Label coords relative to Anchor. DESCRIPTION\n * @private\n */\n setLabelRelativeCoords: function (relCoords) {\n if (Type.exists(this.label)) {\n this.label.relativeCoords = new Coords(Const.COORDS_BY_SCREEN, [relCoords[0], -relCoords[1]], this.board);\n }\n },\n\n // documented in geometry element\n getLabelAnchor: function () {\n var x, y,\n fs = 0,\n c1 = new Coords(Const.COORDS_BY_USER, this.point1.coords.usrCoords, this.board),\n c2 = new Coords(Const.COORDS_BY_USER, this.point2.coords.usrCoords, this.board),\n ev_sf = Type.evaluate(this.visProp.straightfirst),\n ev_sl = Type.evaluate(this.visProp.straightlast);\n\n if (ev_sf || ev_sl) {\n Geometry.calcStraight(this, c1, c2, 0);\n }\n\n c1 = c1.scrCoords;\n c2 = c2.scrCoords;\n\n if (!Type.exists(this.label)) {\n return new Coords(Const.COORDS_BY_SCREEN, [NaN, NaN], this.board);\n }\n\n switch (Type.evaluate(this.label.visProp.position)) {\n case 'lft':\n case 'llft':\n case 'ulft':\n if (c1[1] <= c2[1]) {\n x = c1[1];\n y = c1[2];\n } else {\n x = c2[1];\n y = c2[2];\n }\n break;\n case 'rt':\n case 'lrt':\n case 'urt':\n if (c1[1] > c2[1]) {\n x = c1[1];\n y = c1[2];\n } else {\n x = c2[1];\n y = c2[2];\n }\n break;\n default:\n x = 0.5 * (c1[1] + c2[1]);\n y = 0.5 * (c1[2] + c2[2]);\n }\n\n // Correct coordinates if the label seems to be outside of canvas.\n if (ev_sf || ev_sl) {\n if (Type.exists(this.label)) { // Does not exist during createLabel\n fs = Type.evaluate(this.label.visProp.fontsize);\n }\n\n if (Math.abs(x) < Mat.eps) {\n x = fs;\n } else if (this.board.canvasWidth + Mat.eps > x &&\n x > this.board.canvasWidth - fs - Mat.eps) {\n x = this.board.canvasWidth - fs;\n }\n\n if (Mat.eps + fs > y && y > -Mat.eps) {\n y = fs;\n } else if (this.board.canvasHeight + Mat.eps > y &&\n y > this.board.canvasHeight - fs - Mat.eps) {\n y = this.board.canvasHeight - fs;\n }\n }\n\n return new Coords(Const.COORDS_BY_SCREEN, [x, y], this.board);\n },\n\n // documented in geometry element\n cloneToBackground: function () {\n var copy = {}, r, s, er;\n\n copy.id = this.id + 'T' + this.numTraces;\n copy.elementClass = Const.OBJECT_CLASS_LINE;\n this.numTraces++;\n copy.point1 = this.point1;\n copy.point2 = this.point2;\n\n copy.stdform = this.stdform;\n\n copy.board = this.board;\n\n copy.visProp = Type.deepCopy(this.visProp, this.visProp.traceattributes, true);\n copy.visProp.layer = this.board.options.layer.trace;\n Type.clearVisPropOld(copy);\n copy.visPropCalc = {\n visible: Type.evaluate(copy.visProp.visible)\n };\n\n s = this.getSlope();\n r = this.getRise();\n copy.getSlope = function () {\n return s;\n };\n copy.getRise = function () {\n return r;\n };\n\n er = this.board.renderer.enhancedRendering;\n this.board.renderer.enhancedRendering = true;\n this.board.renderer.drawLine(copy);\n this.board.renderer.enhancedRendering = er;\n this.traces[copy.id] = copy.rendNode;\n\n return this;\n },\n\n /**\n * Add transformations to this line.\n * @param {JXG.Transformation|Array} transform Either one {@link JXG.Transformation} or an array of\n * {@link JXG.Transformation}s.\n * @returns {JXG.Line} Reference to this line object.\n */\n addTransform: function (transform) {\n var i,\n list = Type.isArray(transform) ? transform : [transform],\n len = list.length;\n\n for (i = 0; i < len; i++) {\n this.point1.transformations.push(list[i]);\n this.point2.transformations.push(list[i]);\n }\n\n return this;\n },\n\n // see GeometryElement.js\n snapToGrid: function (pos) {\n var c1, c2, dc, t, ticks,\n x, y, sX, sY;\n\n if (Type.evaluate(this.visProp.snaptogrid)) {\n if (this.parents.length < 3) { // Line through two points\n this.point1.handleSnapToGrid(true, true);\n this.point2.handleSnapToGrid(true, true);\n } else if (Type.exists(pos)) { // Free line\n sX = Type.evaluate(this.visProp.snapsizex);\n sY = Type.evaluate(this.visProp.snapsizey);\n\n c1 = new Coords(Const.COORDS_BY_SCREEN, [pos.Xprev, pos.Yprev], this.board);\n\n x = c1.usrCoords[1];\n y = c1.usrCoords[2];\n\n if (sX <= 0 && this.board.defaultAxes && this.board.defaultAxes.x.defaultTicks) {\n ticks = this.board.defaultAxes.x.defaultTicks;\n sX = ticks.ticksDelta * (Type.evaluate(ticks.visProp.minorticks) + 1);\n }\n if (sY <= 0 && this.board.defaultAxes && this.board.defaultAxes.y.defaultTicks) {\n ticks = this.board.defaultAxes.y.defaultTicks;\n sY = ticks.ticksDelta * (Type.evaluate(ticks.visProp.minorticks) + 1);\n }\n\n // if no valid snap sizes are available, don't change the coords.\n if (sX > 0 && sY > 0) {\n // projectCoordsToLine\n /*\n v = [0, this.stdform[1], this.stdform[2]];\n v = Mat.crossProduct(v, c1.usrCoords);\n c2 = Geometry.meetLineLine(v, this.stdform, 0, this.board);\n */\n c2 = Geometry.projectPointToLine({coords: c1}, this, this.board);\n\n dc = Statistics.subtract([1, Math.round(x / sX) * sX, Math.round(y / sY) * sY], c2.usrCoords);\n t = this.board.create('transform', dc.slice(1), {type: 'translate'});\n t.applyOnce([this.point1, this.point2]);\n }\n }\n } else {\n this.point1.handleSnapToGrid(false, true);\n this.point2.handleSnapToGrid(false, true);\n }\n\n return this;\n },\n\n // see element.js\n snapToPoints: function () {\n var forceIt = Type.evaluate(this.visProp.snaptopoints);\n\n if (this.parents.length < 3) { // Line through two points\n this.point1.handleSnapToPoints(forceIt);\n this.point2.handleSnapToPoints(forceIt);\n }\n\n return this;\n },\n\n /**\n * Treat the line as parametric curve in homogeneous coordinates, where the parameter t runs from 0 to 1.\n * First we transform the interval [0,1] to [-1,1].\n * If the line has homogeneous coordinates [c, a, b] = stdform[] then the direction of the line is [b, -a].\n * Now, we take one finite point that defines the line, i.e. we take either point1 or point2\n * (in case the line is not the ideal line).\n * Let the coordinates of that point be [z, x, y].\n * Then, the curve runs linearly from\n * [0, b, -a] (t=-1) to [z, x, y] (t=0)\n * and\n * [z, x, y] (t=0) to [0, -b, a] (t=1)\n *\n * @param {Number} t Parameter running from 0 to 1.\n * @returns {Number} X(t) x-coordinate of the line treated as parametric curve.\n * */\n X: function (t) {\n var x,\n b = this.stdform[2];\n\n x = (Math.abs(this.point1.coords.usrCoords[0]) > Mat.eps) ?\n this.point1.coords.usrCoords[1] :\n this.point2.coords.usrCoords[1];\n\n t = (t - 0.5) * 2;\n\n return (1 - Math.abs(t)) * x - t * b;\n },\n\n /**\n * Treat the line as parametric curve in homogeneous coordinates.\n * See {@link JXG.Line#X} for a detailed description.\n * @param {Number} t Parameter running from 0 to 1.\n * @returns {Number} Y(t) y-coordinate of the line treated as parametric curve.\n */\n Y: function (t) {\n var y,\n a = this.stdform[1];\n\n y = (Math.abs(this.point1.coords.usrCoords[0]) > Mat.eps) ?\n this.point1.coords.usrCoords[2] :\n this.point2.coords.usrCoords[2];\n\n t = (t - 0.5) * 2;\n\n return (1 - Math.abs(t)) * y + t * a;\n },\n\n /**\n * Treat the line as parametric curve in homogeneous coordinates.\n * See {@link JXG.Line#X} for a detailed description.\n *\n * @param {Number} t Parameter running from 0 to 1.\n * @returns {Number} Z(t) z-coordinate of the line treated as parametric curve.\n */\n Z: function (t) {\n var z = (Math.abs(this.point1.coords.usrCoords[0]) > Mat.eps) ?\n this.point1.coords.usrCoords[0] :\n this.point2.coords.usrCoords[0];\n\n t = (t - 0.5) * 2;\n\n return (1 - Math.abs(t)) * z;\n },\n\n /**\n * The distance between the two points defining the line.\n * @returns {Number}\n */\n L: function () {\n return this.point1.Dist(this.point2);\n },\n\n /**\n * Treat the element as a parametric curve\n * @private\n */\n minX: function () {\n return 0.0;\n },\n\n /**\n * Treat the element as parametric curve\n * @private\n */\n maxX: function () {\n return 1.0;\n },\n\n // documented in geometry element\n bounds: function () {\n var p1c = this.point1.coords.usrCoords,\n p2c = this.point2.coords.usrCoords;\n\n return [Math.min(p1c[1], p2c[1]), Math.max(p1c[2], p2c[2]), Math.max(p1c[1], p2c[1]), Math.min(p1c[2], p2c[2])];\n },\n\n // documented in GeometryElement.js\n remove: function () {\n this.removeAllTicks();\n GeometryElement.prototype.remove.call(this);\n },\n\n // hideElement: function () {\n // var i;\n //\n // GeometryElement.prototype.hideElement.call(this);\n //\n // for (i = 0; i < this.ticks.length; i++) {\n // this.ticks[i].hideElement();\n // }\n // },\n //\n // showElement: function () {\n // var i;\n // GeometryElement.prototype.showElement.call(this);\n //\n // for (i = 0; i < this.ticks.length; i++) {\n // this.ticks[i].showElement();\n // }\n // }\n });\n\n /**\n * @class This element is used to provide a constructor for a general line. A general line is given by two points. By setting additional properties\n * a line can be used as an arrow and/or axis.\n * @pseudo\n * @description\n * @name Line\n * @augments JXG.Line\n * @constructor\n * @type JXG.Line\n * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {JXG.Point,array,function_JXG.Point,array,function} point1,point2 Parent elements can be two elements either of type {@link JXG.Point} or array of\n * numbers describing the coordinates of a point. In the latter case the point will be constructed automatically as a fixed invisible point.\n * It is possible to provide a function returning an array or a point, instead of providing an array or a point.\n * @param {Number,function_Number,function_Number,function} a,b,c A line can also be created providing three numbers. The line is then described by\n * the set of solutions of the equation <tt>a*z+b*x+c*y = 0</tt>. For all finite points, z is normalized to the value 1.\n * It is possible to provide three functions returning numbers, too.\n * @param {function} f This function must return an array containing three numbers forming the line's homogeneous coordinates.\n * <p>\n * Additionally, a line can be created by providing a line and a transformation (or an array of transformations).\n * Then, the result is a line which is the transformation of the supplied line.\n * @example\n * // Create a line using point and coordinates/\n * // The second point will be fixed and invisible.\n * var p1 = board.create('point', [4.5, 2.0]);\n * var l1 = board.create('line', [p1, [1.0, 1.0]]);\n * </pre><div class=\"jxgbox\" id=\"JXGc0ae3461-10c4-4d39-b9be-81d74759d122\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * var glex1_board = JXG.JSXGraph.initBoard('JXGc0ae3461-10c4-4d39-b9be-81d74759d122', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false});\n * var glex1_p1 = glex1_board.create('point', [4.5, 2.0]);\n * var glex1_l1 = glex1_board.create('line', [glex1_p1, [1.0, 1.0]]);\n * </script><pre>\n * @example\n * // Create a line using three coordinates\n * var l1 = board.create('line', [1.0, -2.0, 3.0]);\n * </pre><div class=\"jxgbox\" id=\"JXGcf45e462-f964-4ba4-be3a-c9db94e2593f\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * var glex2_board = JXG.JSXGraph.initBoard('JXGcf45e462-f964-4ba4-be3a-c9db94e2593f', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false});\n * var glex2_l1 = glex2_board.create('line', [1.0, -2.0, 3.0]);\n * </script><pre>\n * @example\n * // Create a line (l2) as reflection of another line (l1)\n * // reflection line\n * var li = board.create('line', [1,1,1], {strokeColor: '#aaaaaa'});\n * var reflect = board.create('transform', [li], {type: 'reflect'});\n *\n * var l1 = board.create('line', [1,-5,1]);\n * var l2 = board.create('line', [l1, reflect]);\n *\n * </pre><div id=\"JXGJXGa00d7dd6-d38c-11e7-93b3-901b0e1b8723\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXGJXGa00d7dd6-d38c-11e7-93b3-901b0e1b8723',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * // reflection line\n * var li = board.create('line', [1,1,1], {strokeColor: '#aaaaaa'});\n * var reflect = board.create('transform', [li], {type: 'reflect'});\n *\n * var l1 = board.create('line', [1,-5,1]);\n * var l2 = board.create('line', [l1, reflect]);\n * })();\n *\n * </script><pre>\n *\n * @example\n * var t = board.create('transform', [2, 1.5], {type: 'scale'});\n * var l1 = board.create('line', [1, -5, 1]);\n * var l2 = board.create('line', [l1, t]);\n *\n * </pre><div id=\"d16d5b58-6338-11e8-9fb9-901b0e1b8723\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('d16d5b58-6338-11e8-9fb9-901b0e1b8723',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var t = board.create('transform', [2, 1.5], {type: 'scale'});\n * var l1 = board.create('line', [1, -5, 1]);\n * var l2 = board.create('line', [l1, t]);\n *\n * })();\n *\n * </script><pre>\n *\n * @example\n * //create line between two points\n * var p1 = board.create('point', [0,0]);\n * var p2 = board.create('point', [2,2]);\n * var l1 = board.create('line', [p1,p2], {straightFirst:false, straightLast:false});\n * </pre><div id=\"d21d5b58-6338-11e8-9fb9-901b0e1b8723\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('d21d5b58-6338-11e8-9fb9-901b0e1b8723',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var ex5p1 = board.create('point', [0,0]);\n * var ex5p2 = board.create('point', [2,2]);\n * var ex5l1 = board.create('line', [ex5p1,ex5p2], {straightFirst:false, straightLast:false});\n * })();\n *\n * </script><pre>\n */\n JXG.createLine = function (board, parents, attributes) {\n var ps, el, p1, p2, i, attr,\n c = [],\n doTransform = false,\n constrained = false,\n isDraggable;\n\n /**\n * The line is defined by two points or coordinates of two points.\n * In the latter case, the points are created.\n */\n if (parents.length === 2) {\n // point 1 given by coordinates\n if (Type.isArray(parents[0]) && parents[0].length > 1) {\n attr = Type.copyAttributes(attributes, board.options, 'line', 'point1');\n p1 = board.create('point', parents[0], attr);\n } else if (Type.isString(parents[0]) || Type.isPoint(parents[0])) {\n p1 = board.select(parents[0]);\n } else if (Type.isFunction(parents[0]) && Type.isPoint(parents[0]())) {\n p1 = parents[0]();\n constrained = true;\n } else if (Type.isFunction(parents[0]) && parents[0]().length && parents[0]().length >= 2) {\n attr = Type.copyAttributes(attributes, board.options, 'line', 'point1');\n p1 = Point.createPoint(board, parents[0](), attr);\n constrained = true;\n } else if (Type.isObject(parents[0]) && Type.isTransformationOrArray(parents[1])) {\n doTransform = true;\n attr = Type.copyAttributes(attributes, board.options, 'line', 'point1');\n p1 = board.create('point', [parents[0].point1, parents[1]], attr);\n } else {\n throw new Error(\"JSXGraph: Can't create line with parent types '\" +\n (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"'.\" +\n \"\\nPossible parent types: [point,point], [[x1,y1],[x2,y2]], [a,b,c]\");\n }\n\n // point 2 given by coordinates\n if (doTransform) {\n attr = Type.copyAttributes(attributes, board.options, 'line', 'point2');\n p2 = board.create('point', [parents[0].point2, parents[1]], attr);\n } else if (Type.isArray(parents[1]) && parents[1].length > 1) {\n attr = Type.copyAttributes(attributes, board.options, 'line', 'point2');\n p2 = board.create('point', parents[1], attr);\n } else if (Type.isString(parents[1]) || Type.isPoint(parents[1])) {\n p2 = board.select(parents[1]);\n } else if (Type.isFunction(parents[1]) && Type.isPoint(parents[1]()) ) {\n p2 = parents[1]();\n constrained = true;\n } else if (Type.isFunction(parents[1]) && parents[1]().length && parents[1]().length >= 2) {\n attr = Type.copyAttributes(attributes, board.options, 'line', 'point2');\n p2 = Point.createPoint(board, parents[1](), attr);\n constrained = true;\n } else {\n throw new Error(\"JSXGraph: Can't create line with parent types '\" +\n (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"'.\" +\n \"\\nPossible parent types: [point,point], [[x1,y1],[x2,y2]], [a,b,c]\");\n }\n\n attr = Type.copyAttributes(attributes, board.options, 'line');\n\n el = new JXG.Line(board, p1, p2, attr);\n\n if (constrained) {\n el.constrained = true;\n el.funp1 = parents[0];\n el.funp2 = parents[1];\n } else if (!doTransform) {\n el.isDraggable = true;\n }\n\n //if (!el.constrained) {\n el.setParents([p1.id, p2.id]);\n //}\n\n // Line is defined by three homogeneous coordinates.\n // Also in this case points are created.\n } else if (parents.length === 3) {\n // free line\n isDraggable = true;\n for (i = 0; i < 3; i++) {\n if (Type.isNumber(parents[i])) {\n // createFunction will just wrap a function around our constant number\n // that does nothing else but to return that number.\n c[i] = Type.createFunction(parents[i]);\n } else if (Type.isFunction(parents[i])) {\n c[i] = parents[i];\n isDraggable = false;\n } else {\n throw new Error(\"JSXGraph: Can't create line with parent types '\" +\n (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"' and '\" + (typeof parents[2]) + \"'.\" +\n \"\\nPossible parent types: [point,point], [[x1,y1],[x2,y2]], [a,b,c]\");\n }\n }\n\n // point 1 is the midpoint between (0,c,-b) and point 2. => point1 is finite.\n attr = Type.copyAttributes(attributes, board.options, 'line', 'point1');\n if (isDraggable) {\n p1 = board.create('point', [\n c[2]() * c[2]() + c[1]() * c[1](),\n c[2]() - c[1]() * c[0]() + c[2](),\n -c[1]() - c[2]() * c[0]() - c[1]()\n ], attr);\n } else {\n p1 = board.create('point', [\n function () {\n return (c[2]() * c[2]() + c[1]() * c[1]()) * 0.5;\n },\n function () {\n return (c[2]() - c[1]() * c[0]() + c[2]()) * 0.5;\n },\n function () {\n return (-c[1]() - c[2]() * c[0]() - c[1]()) * 0.5;\n }], attr);\n }\n\n // point 2: (b^2+c^2,-ba+c,-ca-b)\n attr = Type.copyAttributes(attributes, board.options, 'line', 'point2');\n if (isDraggable) {\n p2 = board.create('point', [\n c[2]() * c[2]() + c[1]() * c[1](),\n -c[1]() * c[0]() + c[2](),\n -c[2]() * c[0]() - c[1]()\n ], attr);\n } else {\n p2 = board.create('point', [\n function () {\n return c[2]() * c[2]() + c[1]() * c[1]();\n },\n function () {\n return -c[1]() * c[0]() + c[2]();\n },\n function () {\n return -c[2]() * c[0]() - c[1]();\n }], attr);\n }\n\n // If the line will have a glider and board.suspendUpdate() has been called, we\n // need to compute the initial position of the two points p1 and p2.\n p1.prepareUpdate().update();\n p2.prepareUpdate().update();\n attr = Type.copyAttributes(attributes, board.options, 'line');\n el = new JXG.Line(board, p1, p2, attr);\n // Not yet working, because the points are not draggable.\n el.isDraggable = isDraggable;\n el.setParents([p1, p2]);\n\n // The parent array contains a function which returns two points.\n } else if (parents.length === 1 && Type.isFunction(parents[0]) && parents[0]().length === 2 &&\n Type.isPoint(parents[0]()[0]) &&\n Type.isPoint(parents[0]()[1])) {\n ps = parents[0]();\n attr = Type.copyAttributes(attributes, board.options, 'line');\n el = new JXG.Line(board, ps[0], ps[1], attr);\n el.constrained = true;\n el.funps = parents[0];\n el.setParents(ps);\n\n } else if (parents.length === 1 && Type.isFunction(parents[0]) && parents[0]().length === 3 &&\n Type.isNumber(parents[0]()[0]) &&\n Type.isNumber(parents[0]()[1]) &&\n Type.isNumber(parents[0]()[2])) {\n ps = parents[0];\n\n attr = Type.copyAttributes(attributes, board.options, 'line', 'point1');\n p1 = board.create('point', [\n function () {\n var c = ps();\n\n return [\n (c[2] * c[2] + c[1] * c[1]) * 0.5,\n (c[2] - c[1] * c[0] + c[2]) * 0.5,\n (-c[1] - c[2] * c[0] - c[1]) * 0.5\n ];\n }], attr);\n\n attr = Type.copyAttributes(attributes, board.options, 'line', 'point2');\n p2 = board.create('point', [\n function () {\n var c = ps();\n\n return [\n c[2] * c[2] + c[1] * c[1],\n -c[1] * c[0] + c[2],\n -c[2] * c[0] - c[1]\n ];\n }], attr);\n\n attr = Type.copyAttributes(attributes, board.options, 'line');\n el = new JXG.Line(board, p1, p2, attr);\n\n el.constrained = true;\n el.funps = parents[0];\n el.setParents([p1, p2]);\n\n } else {\n throw new Error(\"JSXGraph: Can't create line with parent types '\" +\n (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"'.\" +\n \"\\nPossible parent types: [point,point], [[x1,y1],[x2,y2]], [a,b,c]\");\n }\n\n return el;\n };\n\n JXG.registerElement('line', JXG.createLine);\n\n /**\n * @class This element is used to provide a constructor for a segment.\n * It's strictly spoken just a wrapper for element {@link Line} with {@link Line#straightFirst}\n * and {@link Line#straightLast} properties set to false. If there is a third variable then the\n * segment has a fixed length (which may be a function, too).\n * @pseudo\n * @description\n * @name Segment\n * @augments JXG.Line\n * @constructor\n * @type JXG.Line\n * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {JXG.Point,array_JXG.Point,array} point1,point2 Parent elements can be two elements either of type {@link JXG.Point}\n * or array of numbers describing the\n * coordinates of a point. In the latter case the point will be constructed automatically as a fixed invisible point.\n * @param {number,function} length (optional) The points are adapted - if possible - such that their distance\n * has this value.\n * @see Line\n * @example\n * // Create a segment providing two points.\n * var p1 = board.create('point', [4.5, 2.0]);\n * var p2 = board.create('point', [1.0, 1.0]);\n * var l1 = board.create('segment', [p1, p2]);\n * </pre><div class=\"jxgbox\" id=\"JXGd70e6aac-7c93-4525-a94c-a1820fa38e2f\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * var slex1_board = JXG.JSXGraph.initBoard('JXGd70e6aac-7c93-4525-a94c-a1820fa38e2f', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false});\n * var slex1_p1 = slex1_board.create('point', [4.5, 2.0]);\n * var slex1_p2 = slex1_board.create('point', [1.0, 1.0]);\n * var slex1_l1 = slex1_board.create('segment', [slex1_p1, slex1_p2]);\n * </script><pre>\n *\n * @example\n * // Create a segment providing two points.\n * var p1 = board.create('point', [4.0, 1.0]);\n * var p2 = board.create('point', [1.0, 1.0]);\n * var l1 = board.create('segment', [p1, p2]);\n * var p3 = board.create('point', [4.0, 2.0]);\n * var p4 = board.create('point', [1.0, 2.0]);\n * var l2 = board.create('segment', [p3, p4, 3]);\n * var p5 = board.create('point', [4.0, 3.0]);\n * var p6 = board.create('point', [1.0, 4.0]);\n * var l3 = board.create('segment', [p5, p6, function(){ return l1.L();} ]);\n * </pre><div class=\"jxgbox\" id=\"JXG617336ba-0705-4b2b-a236-c87c28ef25be\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * var slex2_board = JXG.JSXGraph.initBoard('JXG617336ba-0705-4b2b-a236-c87c28ef25be', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false});\n * var slex2_p1 = slex2_board.create('point', [4.0, 1.0]);\n * var slex2_p2 = slex2_board.create('point', [1.0, 1.0]);\n * var slex2_l1 = slex2_board.create('segment', [slex2_p1, slex2_p2]);\n * var slex2_p3 = slex2_board.create('point', [4.0, 2.0]);\n * var slex2_p4 = slex2_board.create('point', [1.0, 2.0]);\n * var slex2_l2 = slex2_board.create('segment', [slex2_p3, slex2_p4, 3]);\n * var slex2_p5 = slex2_board.create('point', [4.0, 2.0]);\n * var slex2_p6 = slex2_board.create('point', [1.0, 2.0]);\n * var slex2_l3 = slex2_board.create('segment', [slex2_p5, slex2_p6, function(){ return slex2_l1.L();}]);\n * </script><pre>\n *\n */\n JXG.createSegment = function (board, parents, attributes) {\n var el, attr;\n\n attributes.straightFirst = false;\n attributes.straightLast = false;\n attr = Type.copyAttributes(attributes, board.options, 'segment');\n\n el = board.create('line', parents.slice(0, 2), attr);\n\n if (parents.length === 3) {\n el.hasFixedLength = true;\n\n if (Type.isNumber(parents[2])) {\n el.fixedLength = function () {\n return parents[2];\n };\n } else if (Type.isFunction(parents[2])) {\n el.fixedLength = parents[2];\n } else {\n throw new Error(\"JSXGraph: Can't create segment with third parent type '\" +\n (typeof parents[2]) + \"'.\" +\n \"\\nPossible third parent types: number or function\");\n }\n\n el.getParents = function() {\n return this.parents.concat(this.fixedLength());\n };\n\n el.fixedLengthOldCoords = [];\n el.fixedLengthOldCoords[0] = new Coords(Const.COORDS_BY_USER, el.point1.coords.usrCoords.slice(1, 3), board);\n el.fixedLengthOldCoords[1] = new Coords(Const.COORDS_BY_USER, el.point2.coords.usrCoords.slice(1, 3), board);\n }\n\n el.elType = 'segment';\n\n return el;\n };\n\n JXG.registerElement('segment', JXG.createSegment);\n\n /**\n * @class This element is used to provide a constructor for arrow, which is just a wrapper for element\n * {@link Line} with {@link Line#straightFirst}\n * and {@link Line#straightLast} properties set to false and {@link Line#lastArrow} set to true.\n * @pseudo\n * @description\n * @name Arrow\n * @augments JXG.Line\n * @constructor\n * @type JXG.Line\n * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {JXG.Point,array_JXG.Point,array} point1,point2 Parent elements can be two elements either of type {@link JXG.Point} or array of numbers describing the\n * coordinates of a point. In the latter case the point will be constructed automatically as a fixed invisible point.\n * @param {Number_Number_Number} a,b,c A line can also be created providing three numbers. The line is then described by the set of solutions\n * of the equation <tt>a*x+b*y+c*z = 0</tt>.\n * @see Line\n * @example\n * // Create an arrow providing two points.\n * var p1 = board.create('point', [4.5, 2.0]);\n * var p2 = board.create('point', [1.0, 1.0]);\n * var l1 = board.create('arrow', [p1, p2]);\n * </pre><div class=\"jxgbox\" id=\"JXG1d26bd22-7d6d-4018-b164-4c8bc8d22ccf\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * var alex1_board = JXG.JSXGraph.initBoard('JXG1d26bd22-7d6d-4018-b164-4c8bc8d22ccf', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false});\n * var alex1_p1 = alex1_board.create('point', [4.5, 2.0]);\n * var alex1_p2 = alex1_board.create('point', [1.0, 1.0]);\n * var alex1_l1 = alex1_board.create('arrow', [alex1_p1, alex1_p2]);\n * </script><pre>\n */\n JXG.createArrow = function (board, parents, attributes) {\n var el, attr;\n\n attributes.straightFirst = false;\n attributes.straightLast = false;\n attr = Type.copyAttributes(attributes, board.options, 'arrow');\n el = board.create('line', parents, attr);\n //el.setArrow(false, true);\n el.type = Const.OBJECT_TYPE_VECTOR;\n el.elType = 'arrow';\n\n return el;\n };\n\n JXG.registerElement('arrow', JXG.createArrow);\n\n /**\n * @class This element is used to provide a constructor for an axis. It's strictly spoken just a wrapper for element {@link Line} with {@link Line#straightFirst}\n * and {@link Line#straightLast} properties set to true. Additionally {@link Line#lastArrow} is set to true and default {@link Ticks} will be created.\n * @pseudo\n * @description\n * @name Axis\n * @augments JXG.Line\n * @constructor\n * @type JXG.Line\n * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {JXG.Point,array_JXG.Point,array} point1,point2 Parent elements can be two elements either of type {@link JXG.Point} or array of numbers describing the\n * coordinates of a point. In the latter case, the point will be constructed automatically as a fixed invisible point.\n * @param {Number_Number_Number} a,b,c A line can also be created providing three numbers. The line is then described by the set of solutions\n * of the equation <tt>a*x+b*y+c*z = 0</tt>.\n * @example\n * // Create an axis providing two coord pairs.\n * var l1 = board.create('axis', [[0.0, 1.0], [1.0, 1.3]]);\n * </pre><div class=\"jxgbox\" id=\"JXG4f414733-624c-42e4-855c-11f5530383ae\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * var axex1_board = JXG.JSXGraph.initBoard('JXG4f414733-624c-42e4-855c-11f5530383ae', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false});\n * var axex1_l1 = axex1_board.create('axis', [[0.0, 1.0], [1.0, 1.3]]);\n * </script><pre>\n */\n JXG.createAxis = function (board, parents, attributes) {\n var attr, attr_ticks, el, els, dist;\n\n // Arrays or points, that is all we need.\n if ((Type.isArray(parents[0]) || Type.isPoint(parents[0])) && (Type.isArray(parents[1]) || Type.isPoint(parents[1]))) {\n\n // Create line\n attr = Type.copyAttributes(attributes, board.options, 'axis');\n el = board.create('line', parents, attr);\n el.type = Const.OBJECT_TYPE_AXIS;\n el.isDraggable = false;\n el.point1.isDraggable = false;\n el.point2.isDraggable = false;\n\n for (els in el.ancestors) {\n if (el.ancestors.hasOwnProperty(els)) {\n el.ancestors[els].type = Const.OBJECT_TYPE_AXISPOINT;\n }\n }\n\n // Create ticks\n attr_ticks = Type.copyAttributes(attributes, board.options, 'axis', 'ticks');\n if (Type.exists(attr_ticks.ticksdistance)) {\n dist = attr_ticks.ticksdistance;\n } else if (Type.isArray(attr_ticks.ticks)) {\n dist = attr_ticks.ticks;\n } else {\n dist = 1.0;\n }\n\n /**\n * The ticks attached to the axis.\n * @memberOf Axis.prototype\n * @name defaultTicks\n * @type JXG.Ticks\n */\n el.defaultTicks = board.create('ticks', [el, dist], attr_ticks);\n el.defaultTicks.dump = false;\n el.elType = 'axis';\n el.subs = {\n ticks: el.defaultTicks\n };\n el.inherits.push(el.defaultTicks);\n\n } else {\n throw new Error(\"JSXGraph: Can't create axis with parent types '\" +\n (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"'.\" +\n \"\\nPossible parent types: [point,point], [[x1,y1],[x2,y2]]\");\n }\n\n return el;\n };\n\n JXG.registerElement('axis', JXG.createAxis);\n\n /**\n * @class With the element tangent the slope of a line, circle, or curve in a certain point can be visualized. A tangent is always constructed\n * by a glider on a line, circle, or curve and describes the tangent in the glider point on that line, circle, or curve.\n * @pseudo\n * @description\n * @name Tangent\n * @augments JXG.Line\n * @constructor\n * @type JXG.Line\n * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {Glider} g A glider on a line, circle, or curve.\n * @example\n * // Create a tangent providing a glider on a function graph\n * var c1 = board.create('curve', [function(t){return t},function(t){return t*t*t;}]);\n * var g1 = board.create('glider', [0.6, 1.2, c1]);\n * var t1 = board.create('tangent', [g1]);\n * </pre><div class=\"jxgbox\" id=\"JXG7b7233a0-f363-47dd-9df5-4018d0d17a98\" style=\"width: 400px; height: 400px;\"></div>\n * <script type=\"text/javascript\">\n * var tlex1_board = JXG.JSXGraph.initBoard('JXG7b7233a0-f363-47dd-9df5-4018d0d17a98', {boundingbox: [-6, 6, 6, -6], axis: true, showcopyright: false, shownavigation: false});\n * var tlex1_c1 = tlex1_board.create('curve', [function(t){return t},function(t){return t*t*t;}]);\n * var tlex1_g1 = tlex1_board.create('glider', [0.6, 1.2, tlex1_c1]);\n * var tlex1_t1 = tlex1_board.create('tangent', [tlex1_g1]);\n * </script><pre>\n */\n JXG.createTangent = function (board, parents, attributes) {\n var p, c, j, el, tangent;\n\n // One argument: glider on line, circle or curve\n if (parents.length === 1) {\n p = parents[0];\n c = p.slideObject;\n // Two arguments: (point,F\"|conic) or (line|curve|circle|conic,point). // Not yet: curve!\n } else if (parents.length === 2) {\n // In fact, for circles and conics it is the polar\n if (Type.isPoint(parents[0])) {\n p = parents[0];\n c = parents[1];\n } else if (Type.isPoint(parents[1])) {\n c = parents[0];\n p = parents[1];\n } else {\n throw new Error(\"JSXGraph: Can't create tangent with parent types '\" +\n (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"'.\" +\n \"\\nPossible parent types: [glider], [point,line|curve|circle|conic]\");\n }\n } else {\n throw new Error(\"JSXGraph: Can't create tangent with parent types '\" +\n (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"'.\" +\n \"\\nPossible parent types: [glider], [point,line|curve|circle|conic]\");\n }\n\n if (c.elementClass === Const.OBJECT_CLASS_LINE) {\n tangent = board.create('line', [c.point1, c.point2], attributes);\n tangent.glider = p;\n } else if (c.elementClass === Const.OBJECT_CLASS_CURVE && c.type !== Const.OBJECT_TYPE_CONIC) {\n if (Type.evaluate(c.visProp.curvetype) !== 'plot') {\n tangent = board.create('line', [\n function () {\n var g = c.X,\n f = c.Y;\n return -p.X() * Numerics.D(f)(p.position) + p.Y() * Numerics.D(g)(p.position);\n },\n function () {\n return Numerics.D(c.Y)(p.position);\n },\n function () {\n return -Numerics.D(c.X)(p.position);\n }\n ], attributes);\n\n p.addChild(tangent);\n // this is required for the geogebra reader to display a slope\n tangent.glider = p;\n } else { // curveType 'plot'\n // In case of bezierDegree == 1:\n // Find two points p1, p2 enclosing the glider.\n // Then the equation of the line segment is: 0 = y*(x1-x2) + x*(y2-y1) + y1*x2-x1*y2,\n // which is the cross product of p1 and p2.\n //\n // In case of bezieDegree === 3:\n // The slope dy / dx of the tangent is determined. Then the\n // tangent is computed as cross product between\n // the glider p and [1, p.X() + dx, p.Y() + dy]\n //\n tangent = board.create('line', [\n function () {\n var i = Math.floor(p.position),\n p1, p2, t, A, B, C, D, dx, dy, d;\n\n if (c.bezierDegree === 1) {\n if (i === c.numberPoints - 1) {\n i--;\n }\n } else if (c.bezierDegree === 3) {\n // i is start of the Bezier segment\n // t is the position in the Bezier segment\n i = Math.floor(p.position * (c.numberPoints - 1) / 3) * 3;\n t = (p.position * (c.numberPoints - 1) - i) / 3;\n if (i >= c.numberPoints - 1) {\n i = c.numberPoints - 4;\n t = 1;\n }\n } else {\n return 0;\n }\n\n if (i < 0) {\n return 1;\n }\n\n // The curve points are transformed (if there is a transformation)\n // c.X(i) is not transformed.\n if (c.bezierDegree === 1) {\n p1 = c.points[i].usrCoords;\n p2 = c.points[i + 1].usrCoords;\n } else {\n A = c.points[i].usrCoords;\n B = c.points[i + 1].usrCoords;\n C = c.points[i + 2].usrCoords;\n D = c.points[i + 3].usrCoords;\n dx = (1 - t) * (1 - t) * (B[1] - A[1]) + 2 * (1 - t) * t * (C[1] - B[1]) + t * t * (D[1]- C[1]);\n dy = (1 - t) * (1 - t) * (B[2] - A[2]) + 2 * (1 - t) * t * (C[2] - B[2]) + t * t * (D[2]- C[2]);\n d = Math.sqrt(dx * dx + dy * dy);\n dx /= d;\n dy /= d;\n p1 = p.coords.usrCoords;\n p2 = [1, p1[1] + dx, p1[2] + dy];\n }\n return p1[2] * p2[1] - p1[1] * p2[2];\n },\n function () {\n var i = Math.floor(p.position),\n p1, p2, t, A, B, C, D, dx, dy, d;\n\n if (c.bezierDegree === 1) {\n if (i === c.numberPoints - 1) {\n i--;\n }\n } else if (c.bezierDegree === 3) {\n // i is start of the Bezier segment\n // t is the position in the Bezier segment\n i = Math.floor(p.position * (c.numberPoints - 1) / 3) * 3;\n t = (p.position * (c.numberPoints - 1) - i) / 3;\n if (i >= c.numberPoints - 1) {\n i = c.numberPoints - 4;\n t = 1;\n }\n } else {\n return 0;\n }\n\n if (i < 0) {\n return 0;\n }\n\n // The curve points are transformed (if there is a transformation)\n // c.X(i) is not transformed.\n if (c.bezierDegree === 1) {\n p1 = c.points[i].usrCoords;\n p2 = c.points[i + 1].usrCoords;\n } else {\n A = c.points[i].usrCoords;\n B = c.points[i + 1].usrCoords;\n C = c.points[i + 2].usrCoords;\n D = c.points[i + 3].usrCoords;\n dx = (1 - t) * (1 - t) * (B[1] - A[1]) + 2 * (1 - t) * t * (C[1] - B[1]) + t * t * (D[1]- C[1]);\n dy = (1 - t) * (1 - t) * (B[2] - A[2]) + 2 * (1 - t) * t * (C[2] - B[2]) + t * t * (D[2]- C[2]);\n d = Math.sqrt(dx * dx + dy * dy);\n dx /= d;\n dy /= d;\n p1 = p.coords.usrCoords;\n p2 = [1, p1[1] + dx, p1[2] + dy];\n }\n return p2[2] - p1[2];\n },\n function () {\n var i = Math.floor(p.position),\n p1, p2, t, A, B, C, D, dx, dy, d;\n\n if (c.bezierDegree === 1) {\n if (i === c.numberPoints - 1) {\n i--;\n }\n } else if (c.bezierDegree === 3) {\n // i is start of the Bezier segment\n // t is the position in the Bezier segment\n i = Math.floor(p.position * (c.numberPoints - 1) / 3) * 3;\n t = (p.position * (c.numberPoints - 1) - i) / 3;\n if (i >= c.numberPoints - 1) {\n i = c.numberPoints - 4;\n t = 1;\n }\n } else {\n return 0;\n }\n\n if (i < 0) {\n return 0.0;\n }\n\n // The curve points are transformed (if there is a transformation)\n // c.X(i) is not transformed.\n if (c.bezierDegree === 1) {\n p1 = c.points[i].usrCoords;\n p2 = c.points[i + 1].usrCoords;\n } else {\n A = c.points[i].usrCoords;\n B = c.points[i + 1].usrCoords;\n C = c.points[i + 2].usrCoords;\n D = c.points[i + 3].usrCoords;\n dx = (1 - t) * (1 - t) * (B[1] - A[1]) + 2 * (1 - t) * t * (C[1] - B[1]) + t * t * (D[1]- C[1]);\n dy = (1 - t) * (1 - t) * (B[2] - A[2]) + 2 * (1 - t) * t * (C[2] - B[2]) + t * t * (D[2]- C[2]);\n d = Math.sqrt(dx * dx + dy * dy);\n dx /= d;\n dy /= d;\n p1 = p.coords.usrCoords;\n p2 = [1, p1[1] + dx, p1[2] + dy];\n }\n return p1[1] - p2[1];\n }], attributes);\n\n p.addChild(tangent);\n // this is required for the geogebra reader to display a slope\n tangent.glider = p;\n }\n } else if (c.type === Const.OBJECT_TYPE_TURTLE) {\n tangent = board.create('line', [\n function () {\n var i = Math.floor(p.position);\n\n // run through all curves of this turtle\n for (j = 0; j < c.objects.length; j++) {\n el = c.objects[j];\n\n if (el.type === Const.OBJECT_TYPE_CURVE) {\n if (i < el.numberPoints) {\n break;\n }\n\n i -= el.numberPoints;\n }\n }\n\n if (i === el.numberPoints - 1) {\n i--;\n }\n\n if (i < 0) {\n return 1;\n }\n\n return el.Y(i) * el.X(i + 1) - el.X(i) * el.Y(i + 1);\n },\n function () {\n var i = Math.floor(p.position);\n\n // run through all curves of this turtle\n for (j = 0; j < c.objects.length; j++) {\n el = c.objects[j];\n\n if (el.type === Const.OBJECT_TYPE_CURVE) {\n if (i < el.numberPoints) {\n break;\n }\n\n i -= el.numberPoints;\n }\n }\n\n if (i === el.numberPoints - 1) {\n i--;\n }\n if (i < 0) {\n return 0;\n }\n\n return el.Y(i + 1) - el.Y(i);\n },\n function () {\n var i = Math.floor(p.position);\n\n // run through all curves of this turtle\n for (j = 0; j < c.objects.length; j++) {\n el = c.objects[j];\n if (el.type === Const.OBJECT_TYPE_CURVE) {\n if (i < el.numberPoints) {\n break;\n }\n i -= el.numberPoints;\n }\n }\n if (i === el.numberPoints - 1) {\n i--;\n }\n\n if (i < 0) {\n return 0;\n }\n\n return el.X(i) - el.X(i + 1);\n }], attributes);\n p.addChild(tangent);\n\n // this is required for the geogebra reader to display a slope\n tangent.glider = p;\n } else if (c.elementClass === Const.OBJECT_CLASS_CIRCLE || c.type === Const.OBJECT_TYPE_CONIC) {\n // If p is not on c, the tangent is the polar.\n // This construction should work on conics, too. p has to lie on c.\n tangent = board.create('line', [\n function () {\n return Mat.matVecMult(c.quadraticform, p.coords.usrCoords)[0];\n },\n function () {\n return Mat.matVecMult(c.quadraticform, p.coords.usrCoords)[1];\n },\n function () {\n return Mat.matVecMult(c.quadraticform, p.coords.usrCoords)[2];\n }], attributes);\n\n p.addChild(tangent);\n // this is required for the geogebra reader to display a slope\n tangent.glider = p;\n }\n\n if (!Type.exists(tangent)) {\n throw new Error('JSXGraph: Couldn\\'t create tangent with the given parents.');\n }\n\n tangent.elType = 'tangent';\n tangent.type = Const.OBJECT_TYPE_TANGENT;\n tangent.setParents(parents);\n\n return tangent;\n };\n\n /**\n * @class This element is used to provide a constructor for the radical axis with respect to two circles with distinct centers.\n * The angular bisector of the polar lines of the circle centers with respect to the other circle is always the radical axis.\n * The radical axis passes through the intersection points when the circles intersect.\n * When a circle about the midpoint of circle centers, passing through the circle centers, intersects the circles, the polar lines pass through those intersection points.\n * @pseudo\n * @description\n * @name RadicalAxis\n * @augments JXG.Line\n * @constructor\n * @type JXG.Line\n * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {JXG.Circle} circle Circle one of the two respective circles.\n * @param {JXG.Circle} circle Circle the other of the two respective circles.\n * @example\n * // Create the radical axis line with respect to two circles\n * var board = JXG.JSXGraph.initBoard('7b7233a0-f363-47dd-9df5-5018d0d17a98', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});\n * var p1 = board.create('point', [2, 3]);\n * var p2 = board.create('point', [1, 4]);\n * var c1 = board.create('circle', [p1, p2]);\n * var p3 = board.create('point', [6, 5]);\n * var p4 = board.create('point', [8, 6]);\n * var c2 = board.create('circle', [p3, p4]);\n * var r1 = board.create('radicalaxis', [c1, c2]);\n * </pre><div class=\"jxgbox\" id=\"JXG7b7233a0-f363-47dd-9df5-5018d0d17a98\" class=\"jxgbox\" style=\"width:400px; height:400px;\"></div>\n * <script type='text/javascript'>\n * var rlex1_board = JXG.JSXGraph.initBoard('JXG7b7233a0-f363-47dd-9df5-5018d0d17a98', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});\n * var rlex1_p1 = rlex1_board.create('point', [2, 3]);\n * var rlex1_p2 = rlex1_board.create('point', [1, 4]);\n * var rlex1_c1 = rlex1_board.create('circle', [rlex1_p1, rlex1_p2]);\n * var rlex1_p3 = rlex1_board.create('point', [6, 5]);\n * var rlex1_p4 = rlex1_board.create('point', [8, 6]);\n * var rlex1_c2 = rlex1_board.create('circle', [rlex1_p3, rlex1_p4]);\n * var rlex1_r1 = rlex1_board.create('radicalaxis', [rlex1_c1, rlex1_c2]);\n * </script><pre>\n */\n JXG.createRadicalAxis = function (board, parents, attributes) {\n var el, el1, el2;\n\n if (parents.length !== 2 ||\n parents[0].elementClass !== Const.OBJECT_CLASS_CIRCLE ||\n parents[1].elementClass !== Const.OBJECT_CLASS_CIRCLE) {\n // Failure\n throw new Error(\"JSXGraph: Can't create 'radical axis' with parent types '\" +\n (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"'.\" +\n \"\\nPossible parent type: [circle,circle]\");\n }\n\n el1 = board.select(parents[0]);\n el2 = board.select(parents[1]);\n\n el = board.create('line', [function () {\n var a = el1.stdform,\n b = el2.stdform;\n\n return Mat.matVecMult(Mat.transpose([a.slice(0, 3), b.slice(0, 3)]), [b[3], -a[3]]);\n }], attributes);\n\n el.elType = 'radicalaxis';\n el.setParents([el1.id, el2.id]);\n\n el1.addChild(el);\n el2.addChild(el);\n\n return el;\n };\n\n /**\n * @class This element is used to provide a constructor for the polar line of a point with respect to a conic or a circle.\n * @pseudo\n * @description The polar line is the unique reciprocal relationship of a point with respect to a conic.\n * The lines through the intersections of a conic and the polar line of a point with respect to that conic and through that point are tangent to the conic.\n * A point on a conic has the polar line of that point with respect to that conic as the tangent line to that conic at that point.\n * See {@link http://en.wikipedia.org/wiki/Pole_and_polar} for more information on pole and polar.\n * @name PolarLine\n * @augments JXG.Line\n * @constructor\n * @type JXG.Line\n * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {JXG.Conic,JXG.Circle_JXG.Point} el1,el2 or\n * @param {JXG.Point_JXG.Conic,JXG.Circle} el1,el2 The result will be the polar line of the point with respect to the conic or the circle.\n * @example\n * // Create the polar line of a point with respect to a conic\n * var p1 = board.create('point', [-1, 2]);\n * var p2 = board.create('point', [ 1, 4]);\n * var p3 = board.create('point', [-1,-2]);\n * var p4 = board.create('point', [ 0, 0]);\n * var p5 = board.create('point', [ 4,-2]);\n * var c1 = board.create('conic',[p1,p2,p3,p4,p5]);\n * var p6 = board.create('point', [-1, 1]);\n * var l1 = board.create('polarline', [c1, p6]);\n * </pre><div class=\"jxgbox\" id=\"JXG7b7233a0-f363-47dd-9df5-6018d0d17a98\" class=\"jxgbox\" style=\"width:400px; height:400px;\"></div>\n * <script type='text/javascript'>\n * var plex1_board = JXG.JSXGraph.initBoard('JXG7b7233a0-f363-47dd-9df5-6018d0d17a98', {boundingbox: [-3, 5, 5, -3], axis: true, showcopyright: false, shownavigation: false});\n * var plex1_p1 = plex1_board.create('point', [-1, 2]);\n * var plex1_p2 = plex1_board.create('point', [ 1, 4]);\n * var plex1_p3 = plex1_board.create('point', [-1,-2]);\n * var plex1_p4 = plex1_board.create('point', [ 0, 0]);\n * var plex1_p5 = plex1_board.create('point', [ 4,-2]);\n * var plex1_c1 = plex1_board.create('conic',[plex1_p1,plex1_p2,plex1_p3,plex1_p4,plex1_p5]);\n * var plex1_p6 = plex1_board.create('point', [-1, 1]);\n * var plex1_l1 = plex1_board.create('polarline', [plex1_c1, plex1_p6]);\n * </script><pre>\n * @example\n * // Create the polar line of a point with respect to a circle.\n * var p1 = board.create('point', [ 1, 1]);\n * var p2 = board.create('point', [ 2, 3]);\n * var c1 = board.create('circle',[p1,p2]);\n * var p3 = board.create('point', [ 6, 6]);\n * var l1 = board.create('polarline', [c1, p3]);\n * </pre><div class=\"jxgbox\" id=\"JXG7b7233a0-f363-47dd-9df5-7018d0d17a98\" class=\"jxgbox\" style=\"width:400px; height:400px;\"></div>\n * <script type='text/javascript'>\n * var plex2_board = JXG.JSXGraph.initBoard('JXG7b7233a0-f363-47dd-9df5-7018d0d17a98', {boundingbox: [-3, 7, 7, -3], axis: true, showcopyright: false, shownavigation: false});\n * var plex2_p1 = plex2_board.create('point', [ 1, 1]);\n * var plex2_p2 = plex2_board.create('point', [ 2, 3]);\n * var plex2_c1 = plex2_board.create('circle',[plex2_p1,plex2_p2]);\n * var plex2_p3 = plex2_board.create('point', [ 6, 6]);\n * var plex2_l1 = plex2_board.create('polarline', [plex2_c1, plex2_p3]);\n * </script><pre>\n */\n JXG.createPolarLine = function (board, parents, attributes) {\n var el, el1, el2,\n firstParentIsConic, secondParentIsConic,\n firstParentIsPoint, secondParentIsPoint;\n\n if (parents.length > 1) {\n firstParentIsConic = (parents[0].type === Const.OBJECT_TYPE_CONIC ||\n parents[0].elementClass === Const.OBJECT_CLASS_CIRCLE);\n secondParentIsConic = (parents[1].type === Const.OBJECT_TYPE_CONIC ||\n parents[1].elementClass === Const.OBJECT_CLASS_CIRCLE);\n\n firstParentIsPoint = (Type.isPoint(parents[0]));\n secondParentIsPoint = (Type.isPoint(parents[1]));\n }\n\n if (parents.length !== 2 ||\n !((firstParentIsConic && secondParentIsPoint) ||\n (firstParentIsPoint && secondParentIsConic))) {\n // Failure\n throw new Error(\"JSXGraph: Can't create 'polar line' with parent types '\" +\n (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"'.\" +\n \"\\nPossible parent type: [conic|circle,point], [point,conic|circle]\");\n }\n\n if (secondParentIsPoint) {\n el1 = board.select(parents[0]);\n el2 = board.select(parents[1]);\n } else {\n el1 = board.select(parents[1]);\n el2 = board.select(parents[0]);\n }\n\n // Polar lines have been already provided in the tangent element.\n el = board.create('tangent', [el1, el2], attributes);\n\n el.elType = 'polarline';\n return el;\n };\n\n /**\n * Register the element type tangent at JSXGraph\n * @private\n */\n JXG.registerElement('tangent', JXG.createTangent);\n JXG.registerElement('polar', JXG.createTangent);\n JXG.registerElement('radicalaxis', JXG.createRadicalAxis);\n JXG.registerElement('polarline', JXG.createPolarLine);\n\n return {\n Line: JXG.Line,\n createLine: JXG.createLine,\n createTangent: JXG.createTangent,\n createPolar: JXG.createTangent,\n createSegment: JXG.createSegment,\n createAxis: JXG.createAxis,\n createArrow: JXG.createArrow,\n createRadicalAxis: JXG.createRadicalAxis,\n createPolarLine: JXG.createPolarLine\n };\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true*/\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n jxg\n base/constants\n utils/type\n */\n\n/**\n * @fileoverview In this file the class Group is defined, a class for\n * managing grouping of points.\n */\n\ndefine('base/group',[\n 'jxg', 'base/constants', 'math/math', 'math/geometry', 'utils/type'\n], function (JXG, Const, Mat, Geometry, Type) {\n\n \"use strict\";\n\n /**\n * Creates a new instance of Group.\n * @class In this class all group management is done.\n * @param {JXG.Board} board\n * @param {String} id Unique identifier for this object. If null or an empty string is given,\n * an unique id will be generated by Board\n * @param {String} name Not necessarily unique name, displayed on the board. If null or an\n * empty string is given, an unique name will be generated.\n * @param {Array} objects Array of points to add to this group.\n * @param {Object} attributes Defines the visual appearance of the group.\n * @constructor\n */\n JXG.Group = function (board, id, name, objects, attributes) {\n var number, objArray, i, obj;\n\n this.board = board;\n this.objects = {};\n number = this.board.numObjects;\n this.board.numObjects += 1;\n\n if ((id === '') || !Type.exists(id)) {\n this.id = this.board.id + 'Group' + number;\n } else {\n this.id = id;\n }\n this.board.groups[this.id] = this;\n\n this.type = Const.OBJECT_TYPE_POINT;\n this.elementClass = Const.OBJECT_CLASS_POINT;\n\n if ((name === '') || !Type.exists(name)) {\n this.name = 'group_' + this.board.generateName(this);\n } else {\n this.name = name;\n }\n delete this.type;\n\n /**\n * Cache coordinates of points. From this and the actual position\n * of the points, the translation is determined.\n * It has to be kept updated in this class \"by hand\"-\n *\n * @private\n * @type Object\n * @see JXG.Group#_updateCoordsCache\n */\n this.coords = {};\n this.needsRegularUpdate = attributes.needsregularupdate;\n\n this.rotationCenter = 'centroid';\n this.scaleCenter = null;\n this.rotationPoints = [];\n this.translationPoints = [];\n this.scalePoints = [];\n this.scaleDirections = {};\n\n this.parents = [];\n\n if (Type.isArray(objects)) {\n objArray = objects;\n } else {\n objArray = Array.prototype.slice.call(arguments, 3);\n }\n\n for (i = 0; i < objArray.length; i++) {\n obj = this.board.select(objArray[i]);\n\n if ((!Type.evaluate(obj.visProp.fixed)) && Type.exists(obj.coords)) {\n this.addPoint(obj);\n }\n }\n\n this.methodMap = {\n ungroup: 'ungroup',\n add: 'addPoint',\n addPoint: 'addPoint',\n addPoints: 'addPoints',\n addGroup: 'addGroup',\n remove: 'removePoint',\n removePoint: 'removePoint',\n setAttribute: 'setAttribute',\n setProperty: 'setAttribute'\n };\n };\n\n JXG.extend(JXG.Group.prototype, /** @lends JXG.Group.prototype */ {\n /**\n * Releases all elements of this group.\n * @returns {JXG.Group} returns this (empty) group\n */\n ungroup: function () {\n var el, p, i;\n for (el in this.objects) {\n if (this.objects.hasOwnProperty(el)) {\n p = this.objects[el].point;\n if (Type.isArray(p.groups)) {\n i = Type.indexOf(p.groups, this.id);\n if (i >= 0) {\n delete p.groups[i];\n }\n }\n }\n }\n\n this.objects = {};\n return this;\n },\n\n /**\n * Adds ids of elements to the array this.parents. This is a copy\n * of {@link Element.addParents}.\n * @param {Array} parents Array of elements or ids of elements.\n * Alternatively, one can give a list of objects as parameters.\n * @returns {JXG.Object} reference to the object itself.\n **/\n addParents: function (parents) {\n var i, len, par;\n\n if (Type.isArray(parents)) {\n par = parents;\n } else {\n par = arguments;\n }\n\n len = par.length;\n for (i = 0; i < len; ++i) {\n if (Type.isId(this.board, par[i])) {\n this.parents.push(par[i]);\n } else if (Type.exists(par[i].id)) {\n this.parents.push(par[i].id);\n }\n }\n\n this.parents = Type.uniqueArray(this.parents);\n },\n\n /**\n * Sets ids of elements to the array this.parents. This is a copy\n * of {@link Element.setParents}\n * First, this.parents is cleared. See {@link Group#addParents}.\n * @param {Array} parents Array of elements or ids of elements.\n * Alternatively, one can give a list of objects as parameters.\n * @returns {JXG.Object} reference to the object itself.\n **/\n setParents: function(parents) {\n this.parents = [];\n this.addParents(parents);\n return this;\n },\n\n /**\n * List of the element ids resp. values used as parents in {@link JXG.Board#create}.\n * @returns {Array}\n */\n getParents: function () {\n return Type.isArray(this.parents) ? this.parents : [];\n },\n\n /**\n * Update the cached coordinates of a group element.\n * @param {String} el element id of the group element whose cached coordinates\n * are going to be updated.\n * @return null\n */\n _updateCoordsCache: function(el) {\n var obj;\n if (el !== \"\" && Type.exists(this.objects[el])) {\n obj = this.objects[el].point;\n this.coords[obj.id] = {usrCoords: obj.coords.usrCoords.slice(0)};\n }\n },\n\n /**\n * Sends an update to all group members.\n * This method is called from the points' coords object event listeners\n * and not by the board.\n * @returns {JXG.Group} returns this group\n */\n update: function () {\n var drag, el, actionCenter, desc, s, sx, sy, alpha, t, center, obj = null;\n\n if (!this.needsUpdate) {\n return this;\n }\n\n drag = this._update_find_drag_type();\n if (drag.action === 'nothing') {\n this._updateCoordsCache(drag.id);\n return this;\n }\n\n obj = this.objects[drag.id].point;\n\n // Prepare translation, scaling or rotation\n if (drag.action === 'translation') {\n t = [\n obj.coords.usrCoords[1] - this.coords[drag.id].usrCoords[1],\n obj.coords.usrCoords[2] - this.coords[drag.id].usrCoords[2]\n ];\n\n } else if (drag.action === 'rotation' || drag.action === 'scaling') {\n if (drag.action === 'rotation') {\n actionCenter = 'rotationCenter';\n } else {\n actionCenter = 'scaleCenter';\n }\n\n if (Type.isPoint(this[actionCenter])) {\n center = this[actionCenter].coords.usrCoords.slice(1);\n } else if (this[actionCenter] === 'centroid') {\n center = this._update_centroid_center();\n } else if (Type.isArray(this[actionCenter])) {\n center = this[actionCenter];\n } else if (Type.isFunction(this[actionCenter])) {\n center = this[actionCenter]();\n } else {\n return this;\n }\n\n if (drag.action === 'rotation') {\n alpha = Geometry.rad(this.coords[drag.id].usrCoords.slice(1), center, this.objects[drag.id].point);\n t = this.board.create('transform', [alpha, center[0], center[1]], {type: 'rotate'});\n t.update(); // This initializes t.matrix, which is needed if the action element is the first group element.\n } else if (drag.action === 'scaling') {\n s = Geometry.distance(this.coords[drag.id].usrCoords.slice(1), center);\n if (Math.abs(s) < Mat.eps) {\n return this;\n }\n s = Geometry.distance(obj.coords.usrCoords.slice(1), center) / s;\n sx = (this.scaleDirections[drag.id].indexOf('x') >= 0) ? s : 1.0;\n sy = (this.scaleDirections[drag.id].indexOf('y') >= 0) ? s : 1.0;\n\n // Shift scale center to origin, scale and shift the scale center back.\n t = this.board.create('transform',\n [1, 0, 0,\n center[0] * (1 - sx), sx, 0,\n center[1] * (1 - sy), 0, sy], {type: 'generic'});\n t.update(); // This initializes t.matrix, which is needed if the action element is the first group element.\n } else {\n return this;\n }\n }\n\n this._update_apply_transformation(drag, t);\n\n this.needsUpdate = false; // This is needed here to prevent infinite recursion because\n // of the board.updateElements call below,\n\n // Prepare dependent objects for update\n for (el in this.objects) {\n if (this.objects.hasOwnProperty(el)) {\n for (desc in this.objects[el].descendants) {\n if (this.objects[el].descendants.hasOwnProperty(desc)) {\n this.objects[el].descendants.needsUpdate = this.objects[el].descendants.needsRegularUpdate || this.board.needsFullUpdate;\n }\n }\n }\n }\n this.board.updateElements(drag);\n\n // Now, all group elements have their new position and\n // we can update the bookkeeping of the coordinates of the group elements.\n for (el in this.objects) {\n if (this.objects.hasOwnProperty(el)) {\n this._updateCoordsCache(el);\n }\n }\n\n return this;\n },\n\n /**\n * @private\n * Determine what the dragging of a group element should do:\n * rotation, translation, scaling or nothing.\n */\n _update_find_drag_type: function () {\n var el, obj,\n action = 'nothing',\n changed = [],\n dragObjId;\n\n // Determine how many elements have changed their position\n // If more than one element changed its position, it is a translation.\n // If exactly one element changed its position we have to find the type of the point.\n for (el in this.objects) {\n if (this.objects.hasOwnProperty(el)) {\n obj = this.objects[el].point;\n\n if (obj.coords.distance(Const.COORDS_BY_USER, this.coords[el]) > Mat.eps) {\n changed.push(obj.id);\n }\n }\n }\n\n // Determine type of action: translation, scaling or rotation\n if (changed.length === 0) {\n return {\n 'action': action,\n 'id': '',\n 'changed': changed\n };\n }\n\n dragObjId = changed[0];\n obj = this.objects[dragObjId].point;\n\n if (changed.length > 1) { // More than one point moved => translation\n action = 'translation';\n } else { // One point moved => we have to determine the type\n if (Type.isInArray(this.rotationPoints, obj) && Type.exists(this.rotationCenter)) {\n action = 'rotation';\n } else if (Type.isInArray(this.scalePoints, obj) && Type.exists(this.scaleCenter)) {\n action = 'scaling';\n } else if (Type.isInArray(this.translationPoints, obj)) {\n action = 'translation';\n }\n }\n\n return {\n 'action': action,\n 'id': dragObjId,\n 'changed': changed\n };\n },\n\n /**\n * @private\n * Determine the Euclidean coordinates of the centroid of the group.\n * @returns {Array} array of length two,\n */\n _update_centroid_center: function () {\n var center, len, el;\n\n center = [0, 0];\n len = 0;\n for (el in this.coords) {\n if (this.coords.hasOwnProperty(el)) {\n center[0] += this.coords[el].usrCoords[1];\n center[1] += this.coords[el].usrCoords[2];\n ++len;\n }\n }\n if (len > 0) {\n center[0] /= len;\n center[1] /= len;\n }\n\n return center;\n },\n\n /**\n * @private\n * Apply the transformation to all elements of the group\n */\n _update_apply_transformation: function (drag, t) {\n var el, obj;\n\n for (el in this.objects) {\n if (this.objects.hasOwnProperty(el)) {\n if (Type.exists(this.board.objects[el])) {\n obj = this.objects[el].point;\n\n // Here, it is important that we change the position\n // of elements by using setCoordinates.\n // Thus, we avoid the call of snapToGrid().\n // This is done in the subsequent call of board.updateElements()\n // in Group.update() above.\n if (obj.id !== drag.id) {\n if (drag.action === 'translation') {\n if (!Type.isInArray(drag.changed, obj.id)) {\n obj.coords.setCoordinates(Const.COORDS_BY_USER,\n [this.coords[el].usrCoords[1] + t[0],\n this.coords[el].usrCoords[2] + t[1]]);\n }\n } else if (drag.action === 'rotation' || drag.action === 'scaling') {\n t.applyOnce([obj]);\n }\n } else {\n if (drag.action === 'rotation' || drag.action === 'scaling') {\n obj.coords.setCoordinates(Const.COORDS_BY_USER,\n Mat.matVecMult(t.matrix, this.coords[obj.id].usrCoords));\n }\n }\n } else {\n delete this.objects[el];\n }\n }\n }\n },\n\n /**\n * Adds an Point to this group.\n * @param {JXG.Point} object The point added to the group.\n * @returns {JXG.Group} returns this group\n */\n addPoint: function (object) {\n this.objects[object.id] = {point: this.board.select(object)};\n this._updateCoordsCache(object.id);\n //this.coords[object.id] = {usrCoords: object.coords.usrCoords.slice(0) };\n this.translationPoints.push(object);\n\n object.groups.push(this.id);\n object.groups = Type.uniqueArray(object.groups);\n\n return this;\n },\n\n /**\n * Adds multiple points to this group.\n * @param {Array} objects An array of points to add to the group.\n * @returns {JXG.Group} returns this group\n */\n addPoints: function (objects) {\n var p;\n\n for (p = 0; p < objects.length; p++) {\n this.addPoint(objects[p]);\n }\n\n return this;\n },\n\n /**\n * Adds all points in a group to this group.\n * @param {JXG.Group} group The group added to this group.\n * @returns {JXG.Group} returns this group\n */\n addGroup: function (group) {\n var el;\n\n for (el in group.objects) {\n if (group.objects.hasOwnProperty(el)) {\n this.addPoint(group.objects[el].point);\n }\n }\n\n return this;\n },\n\n /**\n * Removes a point from the group.\n * @param {JXG.Point} point\n * @returns {JXG.Group} returns this group\n */\n removePoint: function (point) {\n delete this.objects[point.id];\n\n return this;\n },\n\n /**\n * Sets the center of rotation for the group. This is either a point or the centroid of the group.\n * @param {JXG.Point|String} object A point which will be the center of rotation, the string \"centroid\", or\n * an array of length two, or a function returning an array of length two.\n * @default 'centroid'\n * @returns {JXG.Group} returns this group\n */\n setRotationCenter: function (object) {\n this.rotationCenter = object;\n\n return this;\n },\n\n /**\n * Sets the rotation points of the group. Dragging at one of these points results into a rotation of the whole group around\n * the rotation center of the group {@see JXG.Group#setRotationCenter}.\n * @param {Array|JXG.Point} objects Array of {@link JXG.Point} or arbitrary number of {@link JXG.Point} elements.\n * @returns {JXG.Group} returns this group\n */\n setRotationPoints: function (objects) {\n return this._setActionPoints('rotation', objects);\n },\n\n /**\n * Adds a point to the set of rotation points of the group. Dragging at one of these points results into a rotation of the whole group around\n * the rotation center of the group {@see JXG.Group#setRotationCenter}.\n * @param {JXG.Point} point {@link JXG.Point} element.\n * @returns {JXG.Group} returns this group\n */\n addRotationPoint: function (point) {\n return this._addActionPoint('rotation', point);\n },\n\n /**\n * Removes the rotation property from a point of the group.\n * @param {JXG.Point} point {@link JXG.Point} element.\n * @returns {JXG.Group} returns this group\n */\n removeRotationPoint: function (point) {\n return this._removeActionPoint('rotation', point);\n },\n\n /**\n * Sets the translation points of the group. Dragging at one of these points results into a translation of the whole group.\n * @param {Array|JXG.Point} objects Array of {@link JXG.Point} or arbitrary number of {@link JXG.Point} elements.\n *\n * By default, all points of the group are translation points.\n * @returns {JXG.Group} returns this group\n */\n setTranslationPoints: function (objects) {\n return this._setActionPoints('translation', objects);\n },\n\n /**\n * Adds a point to the set of the translation points of the group.\n * Dragging one of these points results into a translation of the whole group.\n * @param {JXG.Point} point {@link JXG.Point} element.\n * @returns {JXG.Group} returns this group\n */\n addTranslationPoint: function (point) {\n return this._addActionPoint('translation', point);\n },\n\n /**\n * Removes the translation property from a point of the group.\n * @param {JXG.Point} point {@link JXG.Point} element.\n * @returns {JXG.Group} returns this group\n */\n removeTranslationPoint: function (point) {\n return this._removeActionPoint('translation', point);\n },\n\n /**\n * Sets the center of scaling for the group. This is either a point or the centroid of the group.\n * @param {JXG.Point|String} object A point which will be the center of scaling, the string \"centroid\", or\n * an array of length two, or a function returning an array of length two.\n * @returns {JXG.Group} returns this group\n */\n setScaleCenter: function (object) {\n this.scaleCenter = object;\n\n return this;\n },\n\n /**\n * Sets the scale points of the group. Dragging at one of these points results into a scaling of the whole group.\n * @param {Array|JXG.Point} objects Array of {@link JXG.Point} or arbitrary number of {@link JXG.Point} elements.\n * @param {String} direction Restricts the directions to be scaled. Possible values are 'x', 'y', 'xy'. Default value is 'xy'.\n *\n * By default, all points of the group are translation points.\n * @returns {JXG.Group} returns this group\n */\n setScalePoints: function (objects, direction) {\n var objs, i, len;\n if (Type.isArray(objects)) {\n objs = objects;\n } else {\n objs = arguments;\n }\n\n len = objs.length;\n for (i = 0; i < len; ++i) {\n this.scaleDirections[this.board.select(objs[i]).id] = direction || 'xy';\n }\n\n return this._setActionPoints('scale', objects);\n },\n\n /**\n * Adds a point to the set of the scale points of the group. Dragging at one of these points results into a scaling of the whole group.\n * @param {JXG.Point} point {@link JXG.Point} element.\n * @param {String} direction Restricts the directions to be scaled. Possible values are 'x', 'y', 'xy'. Default value is 'xy'.\n * @returns {JXG.Group} returns this group\n */\n addScalePoint: function (point, direction) {\n this._addActionPoint('scale', point);\n this.scaleDirections[this.board.select(point).id] = direction || 'xy';\n\n return this;\n },\n\n /**\n * Removes the scaling property from a point of the group.\n * @param {JXG.Point} point {@link JXG.Point} element.\n * @returns {JXG.Group} returns this group\n */\n removeScalePoint: function (point) {\n return this._removeActionPoint('scale', point);\n },\n\n /**\n * Generic method for {@link JXG.Group@setTranslationPoints} and {@link JXG.Group@setRotationPoints}\n * @private\n */\n _setActionPoints: function (action, objects) {\n var objs, i, len;\n if (Type.isArray(objects)) {\n objs = objects;\n } else {\n objs = arguments;\n }\n\n len = objs.length;\n this[action + 'Points'] = [];\n for (i = 0; i < len; ++i) {\n this._addActionPoint(action, objs[i]);\n }\n\n return this;\n },\n\n /**\n * Generic method for {@link JXG.Group@addTranslationPoint} and {@link JXG.Group@addRotationPoint}\n * @private\n */\n _addActionPoint: function (action, point) {\n this[action + 'Points'].push(this.board.select(point));\n\n return this;\n },\n\n /**\n * Generic method for {@link JXG.Group@removeTranslationPoint} and {@link JXG.Group@removeRotationPoint}\n * @private\n */\n _removeActionPoint: function (action, point) {\n var idx = this[action + 'Points'].indexOf(this.board.select(point));\n if (idx > -1) {\n this[action + 'Points'].splice(idx, 1);\n }\n\n return this;\n },\n\n /**\n * @deprecated\n * Use setAttribute\n */\n setProperty: function () {\n JXG.deprecated('Group.setProperty', 'Group.setAttribute()');\n this.setAttribute.apply(this, arguments);\n },\n\n setAttribute: function () {\n var el;\n\n for (el in this.objects) {\n if (this.objects.hasOwnProperty(el)) {\n this.objects[el].point.setAttribute.apply(this.objects[el].point, arguments);\n }\n }\n\n return this;\n }\n });\n\n /**\n * @class This element combines a given set of {@link JXG.Point} elements to a\n * group. The elements of the group and dependent elements can be translated, rotated and scaled by\n * dragging one of the group elements.\n *\n *\n * @pseudo\n * @description\n * @name Group\n * @augments JXG.Group\n * @constructor\n * @type JXG.Group\n * @param {JXG.Board} board The board the points are on.\n * @param {Array} parents Array of points to group.\n * @param {Object} attributes Visual properties (unused).\n * @returns {JXG.Group}\n *\n * @example\n *\n * // Create some free points. e.g. A, B, C, D\n * // Create a group\n *\n * var p, col, g;\n * col = 'blue';\n * p = [];\n * p.push(board.create('point',[-2, -1 ], {size: 5, strokeColor:col, fillColor:col}));\n * p.push(board.create('point',[2, -1 ], {size: 5, strokeColor:col, fillColor:col}));\n * p.push(board.create('point',[2, 1 ], {size: 5, strokeColor:col, fillColor:col}));\n * p.push(board.create('point',[-2, 1], {size: 5, strokeColor:col, fillColor:col}));\n * g = board.create('group', p);\n *\n * </pre><div class=\"jxgbox\" id=\"JXGa2204533-db91-4af9-b720-70394de4d367\" style=\"width: 400px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function () {\n * var board, p, col, g;\n * board = JXG.JSXGraph.initBoard('JXGa2204533-db91-4af9-b720-70394de4d367', {boundingbox:[-5,5,5,-5], keepaspectratio:true, axis:true, showcopyright: false});\n * col = 'blue';\n * p = [];\n * p.push(board.create('point',[-2, -1 ], {size: 5, strokeColor:col, fillColor:col}));\n * p.push(board.create('point',[2, -1 ], {size: 5, strokeColor:col, fillColor:col}));\n * p.push(board.create('point',[2, 1 ], {size: 5, strokeColor:col, fillColor:col}));\n * p.push(board.create('point',[-2, 1], {size: 5, strokeColor:col, fillColor:col}));\n * g = board.create('group', p);\n * })();\n * </script><pre>\n *\n *\n * @example\n *\n * // Create some free points. e.g. A, B, C, D\n * // Create a group\n * // If the points define a polygon and the polygon has the attribute hasInnerPoints:true,\n * // the polygon can be dragged around.\n *\n * var p, col, pol, g;\n * col = 'blue';\n * p = [];\n * p.push(board.create('point',[-2, -1 ], {size: 5, strokeColor:col, fillColor:col}));\n * p.push(board.create('point',[2, -1 ], {size: 5, strokeColor:col, fillColor:col}));\n * p.push(board.create('point',[2, 1 ], {size: 5, strokeColor:col, fillColor:col}));\n * p.push(board.create('point',[-2, 1], {size: 5, strokeColor:col, fillColor:col}));\n *\n * pol = board.create('polygon', p, {hasInnerPoints: true});\n * g = board.create('group', p);\n *\n * </pre><div class=\"jxgbox\" id=\"JXG781b5564-a671-4327-81c6-de915c8f924e\" style=\"width: 400px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function () {\n * var board, p, col, pol, g;\n * board = JXG.JSXGraph.initBoard('JXG781b5564-a671-4327-81c6-de915c8f924e', {boundingbox:[-5,5,5,-5], keepaspectratio:true, axis:true, showcopyright: false});\n * col = 'blue';\n * p = [];\n * p.push(board.create('point',[-2, -1 ], {size: 5, strokeColor:col, fillColor:col}));\n * p.push(board.create('point',[2, -1 ], {size: 5, strokeColor:col, fillColor:col}));\n * p.push(board.create('point',[2, 1 ], {size: 5, strokeColor:col, fillColor:col}));\n * p.push(board.create('point',[-2, 1], {size: 5, strokeColor:col, fillColor:col}));\n * pol = board.create('polygon', p, {hasInnerPoints: true});\n * g = board.create('group', p);\n * })();\n * </script><pre>\n *\n * @example\n *\n * // Allow rotations:\n * // Define a center of rotation and declare points of the group as \"rotation points\".\n *\n * var p, col, pol, g;\n * col = 'blue';\n * p = [];\n * p.push(board.create('point',[-2, -1 ], {size: 5, strokeColor:col, fillColor:col}));\n * p.push(board.create('point',[2, -1 ], {size: 5, strokeColor:'red', fillColor:'red'}));\n * p.push(board.create('point',[2, 1 ], {size: 5, strokeColor:'red', fillColor:'red'}));\n * p.push(board.create('point',[-2, 1], {size: 5, strokeColor:col, fillColor:col}));\n *\n * pol = board.create('polygon', p, {hasInnerPoints: true});\n * g = board.create('group', p);\n * g.setRotationCenter(p[0]);\n * g.setRotationPoints([p[1], p[2]]);\n *\n * </pre><div class=\"jxgbox\" id=\"JXGf0491b62-b377-42cb-b55c-4ef5374b39fc\" style=\"width: 400px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function () {\n * var board, p, col, pol, g;\n * board = JXG.JSXGraph.initBoard('JXGf0491b62-b377-42cb-b55c-4ef5374b39fc', {boundingbox:[-5,5,5,-5], keepaspectratio:true, axis:true, showcopyright: false});\n * col = 'blue';\n * p = [];\n * p.push(board.create('point',[-2, -1 ], {size: 5, strokeColor:col, fillColor:col}));\n * p.push(board.create('point',[2, -1 ], {size: 5, strokeColor:'red', fillColor:'red'}));\n * p.push(board.create('point',[2, 1 ], {size: 5, strokeColor:'red', fillColor:'red'}));\n * p.push(board.create('point',[-2, 1], {size: 5, strokeColor:col, fillColor:col}));\n * pol = board.create('polygon', p, {hasInnerPoints: true});\n * g = board.create('group', p);\n * g.setRotationCenter(p[0]);\n * g.setRotationPoints([p[1], p[2]]);\n * })();\n * </script><pre>\n *\n * @example\n *\n * // Allow rotations:\n * // As rotation center, arbitrary points, coordinate arrays,\n * // or functions returning coordinate arrays can be given.\n * // Another possibility is to use the predefined string 'centroid'.\n *\n * // The methods to define the rotation points can be chained.\n *\n * var p, col, pol, g;\n * col = 'blue';\n * p = [];\n * p.push(board.create('point',[-2, -1 ], {size: 5, strokeColor:col, fillColor:col}));\n * p.push(board.create('point',[2, -1 ], {size: 5, strokeColor:'red', fillColor:'red'}));\n * p.push(board.create('point',[2, 1 ], {size: 5, strokeColor:'red', fillColor:'red'}));\n * p.push(board.create('point',[-2, 1], {size: 5, strokeColor:col, fillColor:col}));\n *\n * pol = board.create('polygon', p, {hasInnerPoints: true});\n * g = board.create('group', p).setRotationCenter('centroid').setRotationPoints([p[1], p[2]]);\n *\n * </pre><div class=\"jxgbox\" id=\"JXG8785b099-a75e-4769-bfd8-47dd4376fe27\" style=\"width: 400px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function () {\n * var board, p, col, pol, g;\n * board = JXG.JSXGraph.initBoard('JXG8785b099-a75e-4769-bfd8-47dd4376fe27', {boundingbox:[-5,5,5,-5], keepaspectratio:true, axis:true, showcopyright: false});\n * col = 'blue';\n * p = [];\n * p.push(board.create('point',[-2, -1 ], {size: 5, strokeColor:col, fillColor:col}));\n * p.push(board.create('point',[2, -1 ], {size: 5, strokeColor:'red', fillColor:'red'}));\n * p.push(board.create('point',[2, 1 ], {size: 5, strokeColor:'red', fillColor:'red'}));\n * p.push(board.create('point',[-2, 1], {size: 5, strokeColor:col, fillColor:col}));\n * pol = board.create('polygon', p, {hasInnerPoints: true});\n * g = board.create('group', p).setRotationCenter('centroid').setRotationPoints([p[1], p[2]]);\n * })();\n * </script><pre>\n *\n * @example\n *\n * // Allow scaling:\n * // As for rotation one can declare points of the group to trigger a scaling operation.\n * // For this, one has to define a scaleCenter, in analogy to rotations.\n *\n * // Here, the yellow point enables scaling, the red point a rotation.\n *\n * var p, col, pol, g;\n * col = 'blue';\n * p = [];\n * p.push(board.create('point',[-2, -1 ], {size: 5, strokeColor:col, fillColor:col}));\n * p.push(board.create('point',[2, -1 ], {size: 5, strokeColor:'yellow', fillColor:'yellow'}));\n * p.push(board.create('point',[2, 1 ], {size: 5, strokeColor:'red', fillColor:'red'}));\n * p.push(board.create('point',[-2, 1], {size: 5, strokeColor:col, fillColor:col}));\n *\n * pol = board.create('polygon', p, {hasInnerPoints: true});\n * g = board.create('group', p).setRotationCenter('centroid').setRotationPoints([p[2]]);\n * g.setScaleCenter(p[0]).setScalePoints(p[1]);\n *\n * </pre><div class=\"jxgbox\" id=\"JXGc3ca436b-e4fc-4de5-bab4-09790140c675\" style=\"width: 400px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function () {\n * var board, p, col, pol, g;\n * board = JXG.JSXGraph.initBoard('JXGc3ca436b-e4fc-4de5-bab4-09790140c675', {boundingbox:[-5,5,5,-5], keepaspectratio:true, axis:true, showcopyright: false});\n * col = 'blue';\n * p = [];\n * p.push(board.create('point',[-2, -1 ], {size: 5, strokeColor:col, fillColor:col}));\n * p.push(board.create('point',[2, -1 ], {size: 5, strokeColor:'yellow', fillColor:'yellow'}));\n * p.push(board.create('point',[2, 1 ], {size: 5, strokeColor:'red', fillColor:'red'}));\n * p.push(board.create('point',[-2, 1], {size: 5, strokeColor:col, fillColor:col}));\n * pol = board.create('polygon', p, {hasInnerPoints: true});\n * g = board.create('group', p).setRotationCenter('centroid').setRotationPoints([p[2]]);\n * g.setScaleCenter(p[0]).setScalePoints(p[1]);\n * })();\n * </script><pre>\n *\n * @example\n *\n * // Allow Translations:\n * // By default, every point of a group triggers a translation.\n * // There may be situations, when this is not wanted.\n *\n * // In this example, E triggers nothing, but itself is rotation center\n * // and is translated, if other points are moved around.\n *\n * var p, q, col, pol, g;\n * col = 'blue';\n * p = [];\n * p.push(board.create('point',[-2, -1 ], {size: 5, strokeColor:col, fillColor:col}));\n * p.push(board.create('point',[2, -1 ], {size: 5, strokeColor:'yellow', fillColor:'yellow'}));\n * p.push(board.create('point',[2, 1 ], {size: 5, strokeColor:'red', fillColor:'red'}));\n * p.push(board.create('point',[-2, 1], {size: 5, strokeColor:col, fillColor:col}));\n * q = board.create('point',[0, 0], {size: 5, strokeColor:col, fillColor:col});\n *\n * pol = board.create('polygon', p, {hasInnerPoints: true});\n * g = board.create('group', p.concat(q)).setRotationCenter('centroid').setRotationPoints([p[2]]);\n * g.setScaleCenter(p[0]).setScalePoints(p[1]);\n * g.removeTranslationPoint(q);\n *\n * </pre><div class=\"jxgbox\" id=\"JXGd19b800a-57a9-4303-b49a-8f5b7a5488f0\" style=\"width: 400px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function () {\n * var board, p, q, col, pol, g;\n * board = JXG.JSXGraph.initBoard('JXGd19b800a-57a9-4303-b49a-8f5b7a5488f0', {boundingbox:[-5,5,5,-5], keepaspectratio:true, axis:true, showcopyright: false});\n * col = 'blue';\n * p = [];\n * p.push(board.create('point',[-2, -1 ], {size: 5, strokeColor:col, fillColor:col}));\n * p.push(board.create('point',[2, -1 ], {size: 5, strokeColor:'yellow', fillColor:'yellow'}));\n * p.push(board.create('point',[2, 1 ], {size: 5, strokeColor:'red', fillColor:'red'}));\n * p.push(board.create('point',[-2, 1], {size: 5, strokeColor:col, fillColor:col}));\n * q = board.create('point',[0, 0], {size: 5, strokeColor:col, fillColor:col});\n *\n * pol = board.create('polygon', p, {hasInnerPoints: true});\n * g = board.create('group', p.concat(q)).setRotationCenter('centroid').setRotationPoints([p[2]]);\n * g.setScaleCenter(p[0]).setScalePoints(p[1]);\n * g.removeTranslationPoint(q);\n * })();\n * </script><pre>\n *\n *\n */\n JXG.createGroup = function (board, parents, attributes) {\n var attr = Type.copyAttributes(attributes, board.options, 'group'),\n g = new JXG.Group(board, attr.id, attr.name, parents, attr);\n\n g.elType = 'group';\n g.setParents(parents);\n\n return g;\n };\n\n JXG.registerElement('group', JXG.createGroup);\n\n return {\n Group: JXG.Group,\n createGroup: JXG.createGroup\n };\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true*/\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n jxg\n base/constants\n math/math\n math/geometry\n math/numerics\n utils/type\n elements:\n point\n curve\n */\n\n/**\n * @fileoverview In this file the conic sections defined.\n */\n\ndefine('element/conic',[\n 'jxg', 'base/constants', 'base/coords', 'math/math', 'math/numerics', 'math/geometry', 'utils/type'\n], function (JXG, Const, Coords, Mat, Numerics, Geometry, Type) {\n\n \"use strict\";\n\n /**\n * @class This element is used to provide a constructor for an ellipse. An ellipse is given by two points (the foci) and a third point on the the ellipse or\n * the length of the major axis.\n * @pseudo\n * @description\n * @name Ellipse\n * @augments Conic\n * @constructor\n * @type JXG.Curve\n * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {JXG.Point,array_JXG.Point,array_JXG.Point,array} point1,point2,point3 Parent elements can be three elements either of type {@link JXG.Point} or array of\n * numbers describing the coordinates of a point. In the latter case the point will be constructed automatically as a fixed invisible point.\n * @param {JXG.Point,array_JXG.Point,array_number,function} point1,point2,number Parent elements can be two elements either of type {@link JXG.Point} or array of\n * numbers describing the coordinates of a point. The third parameter is a number/function which defines the length of the major axis\n * @param {Number} start (Optional) parameter of the curve start, default: 0.\n * @param {Number} end (Optional) parameter for the curve end, default: 2π.\n * @example\n * // Create an Ellipse by three points\n * var A = board.create('point', [-1,4]);\n * var B = board.create('point', [-1,-4]);\n * var C = board.create('point', [1,1]);\n * var el = board.create('ellipse',[A,B,C]);\n * </pre><div class=\"jxgbox\" id=\"JXGa4d7fb6f-8708-4e45-87f2-2379ae2bd2c0\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var glex1_board = JXG.JSXGraph.initBoard('JXGa4d7fb6f-8708-4e45-87f2-2379ae2bd2c0', {boundingbox:[-6,6,6,-6], keepaspectratio:true, showcopyright: false, shownavigation: false});\n * var A = glex1_board.create('point', [-1,4]);\n * var B = glex1_board.create('point', [-1,-4]);\n * var C = glex1_board.create('point', [1,1]);\n * var el = glex1_board.create('ellipse',[A,B,C]);\n * })();\n * </script><pre>\n *\n * @example\n * // Create an elliptical arc\n * var p1 = board.create('point', [-1, 2]);\n * var p2 = board.create('point', [ 1, 2]);\n * var p3 = board.create('point', [0, 3]);\n * \n * var ell = board.create('ellipse', [\n * p1, p2, p3, 0, Math.PI], {\n * lastArrow: {type: 7}\n * });\n * \n * </pre><div id=\"JXG950f7c07-27a4-4c67-9505-c73c22ce9345\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG950f7c07-27a4-4c67-9505-c73c22ce9345',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var p1 = board.create('point', [-1, 2]);\n * var p2 = board.create('point', [ 1, 2]);\n * var p3 = board.create('point', [0, 3]);\n * \n * var ell = board.create('ellipse', [\n * p1, p2, p3, 0, Math.PI], {\n * lastArrow: {type: 7}\n * });\n * \n * })();\n * \n * </script><pre>\n * \n*\n */\n JXG.createEllipse = function (board, parents, attributes) {\n var polarForm, curve, M, C, majorAxis, i,\n hasPointOrg,\n // focus 1 and focus 2\n F = [],\n attr_foci = Type.copyAttributes(attributes, board.options, 'conic', 'foci'),\n attr_center = Type.copyAttributes(attributes, board.options, 'conic', 'center'),\n attr_curve = Type.copyAttributes(attributes, board.options, 'conic');\n\n // The foci and the third point are either points or coordinate arrays.\n for (i = 0; i < 2; i++) {\n // focus i given by coordinates\n if (parents[i].length > 1) {\n F[i] = board.create('point', parents[i], attr_foci);\n // focus i given by point\n } else if (Type.isPoint(parents[i])) {\n F[i] = board.select(parents[i]);\n // given by function\n } else if (Type.isFunction(parents[i]) && Type.isPoint(parents[i]()) ) {\n F[i] = parents[i]();\n // focus i given by point name\n } else if (Type.isString(parents[i])) {\n F[i] = board.select(parents[i]);\n } else {\n throw new Error(\"JSXGraph: Can't create Ellipse with parent types '\" +\n (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"'.\" +\n \"\\nPossible parent types: [point,point,point], [point,point,number|function]\");\n }\n }\n\n // length of major axis\n if (Type.isNumber(parents[2])) {\n majorAxis = Type.createFunction(parents[2], board);\n } else if (Type.isFunction(parents[2]) && Type.isNumber(parents[2]())) {\n majorAxis = parents[2];\n } else {\n // point on ellipse\n if (Type.isPoint(parents[2])) {\n C = board.select(parents[2]);\n // point on ellipse given by coordinates\n } else if (parents[2].length > 1) {\n C = board.create('point', parents[2], attr_foci);\n // given by function\n } else if (Type.isFunction(parents[2]) && Type.isPoint(parents[2]()) ) {\n C = parents[2]();\n // focus i given by point name\n } else if (Type.isString(parents[2])) {\n C = board.select(parents[2]);\n } else {\n throw new Error(\"JSXGraph: Can't create Ellipse with parent types '\" +\n (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"' and '\" + (typeof parents[2]) + \"'.\" +\n \"\\nPossible parent types: [point,point,point], [point,point,number|function]\");\n }\n /** @ignore */\n majorAxis = function () {\n return C.Dist(F[0]) + C.Dist(F[1]);\n };\n }\n\n // to\n if (!Type.exists(parents[4])) {\n parents[4] = 2 * Math.PI;\n }\n\n // from\n if (!Type.exists(parents[3])) {\n parents[3] = 0.0;\n }\n\n M = board.create('point', [\n function () {\n return (F[0].X() + F[1].X()) * 0.5;\n },\n function () {\n return (F[0].Y() + F[1].Y()) * 0.5;\n }\n ], attr_center);\n\n curve = board.create('curve', [\n function (x) {\n return 0;\n },\n function (x) {\n return 0;\n },\n parents[3],\n parents[4]], attr_curve);\n\n curve.majorAxis = majorAxis;\n\n // Save the original hasPoint method. It will be called inside of the new hasPoint method.\n hasPointOrg = curve.hasPoint;\n\n /** @ignore */\n polarForm = function (phi, suspendUpdate) {\n var r, rr, ax, ay, bx, by, axbx, ayby, f;\n\n if (!suspendUpdate) {\n r = majorAxis();\n rr = r * r;\n ax = F[0].X();\n ay = F[0].Y();\n bx = F[1].X();\n by = F[1].Y();\n axbx = ax - bx;\n ayby = ay - by;\n f = (rr - ax * ax - ay * ay + bx * bx + by * by) / (2 * r);\n\n curve.quadraticform = [\n [f * f - bx * bx - by * by, f * axbx / r + bx, f * ayby / r + by],\n [f * axbx / r + bx, (axbx * axbx) / rr - 1, axbx * ayby / rr ],\n [f * ayby / r + by, axbx * ayby / rr, (ayby * ayby) / rr - 1]\n ];\n }\n };\n\n /** @ignore */\n curve.X = function (phi, suspendUpdate) {\n var r = majorAxis(),\n c = F[1].Dist(F[0]),\n b = 0.5 * (c * c - r * r) / (c * Math.cos(phi) - r),\n beta = Math.atan2(F[1].Y() - F[0].Y(), F[1].X() - F[0].X());\n\n if (!suspendUpdate) {\n polarForm(phi, suspendUpdate);\n }\n\n return F[0].X() + Math.cos(beta + phi) * b;\n };\n\n /** @ignore */\n curve.Y = function (phi, suspendUpdate) {\n var r = majorAxis(),\n c = F[1].Dist(F[0]),\n b = 0.5 * (c * c - r * r) / (c * Math.cos(phi) - r),\n beta = Math.atan2(F[1].Y() - F[0].Y(), F[1].X() - F[0].X());\n\n return F[0].Y() + Math.sin(beta + phi) * b;\n };\n\n curve.midpoint = curve.center = M;\n curve.type = Const.OBJECT_TYPE_CONIC;\n curve.subs = {\n center: curve.center\n };\n curve.inherits.push(curve.center, F[0], F[1]);\n if (Type.isPoint(C)) {\n curve.inherits.push(C);\n }\n\n /**\n * Checks whether (x,y) is near the ellipse line or inside of the ellipse\n * (in case JXG.Options.conic#hasInnerPoints is true).\n * @param {Number} x Coordinate in x direction, screen coordinates.\n * @param {Number} y Coordinate in y direction, screen coordinates.\n * @returns {Boolean} True if (x,y) is near the ellipse, False otherwise.\n * @private\n */\n curve.hasPoint = function (x, y) {\n var ac, bc, r, p, dist;\n\n if (Type.evaluate(this.visProp.hasinnerpoints)) {\n ac = F[0].coords;\n bc = F[1].coords;\n r = this.majorAxis();\n p = new Coords(Const.COORDS_BY_SCREEN, [x, y], this.board);\n dist = p.distance(Const.COORDS_BY_USER, ac) + p.distance(Const.COORDS_BY_USER, bc);\n\n return (dist <= r);\n }\n\n return hasPointOrg.apply(this, arguments);\n };\n\n M.addChild(curve);\n for (i = 0; i < 2; i++) {\n if (Type.isPoint(F[i])) {\n F[i].addChild(curve);\n }\n }\n if (Type.isPoint(C)) {\n C.addChild(curve);\n }\n curve.setParents(parents);\n\n return curve;\n };\n\n /**\n * @class This element is used to provide a constructor for an hyperbola. An hyperbola is given by two points (the foci) and a third point on the the hyperbola or\n * the length of the major axis.\n * @pseudo\n * @description\n * @name Hyperbola\n * @augments Conic\n * @constructor\n * @type JXG.Curve\n * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {JXG.Point,array_JXG.Point,array_JXG.Point,array} point1,point2,point3 Parent elements can be three elements either of type {@link JXG.Point} or array of\n * numbers describing the coordinates of a point. In the latter case the point will be constructed automatically as a fixed invisible point.\n * @param {JXG.Point,array_JXG.Point,array_number,function} point1,point2,number Parent elements can be two elements either of type {@link JXG.Point} or array of\n * numbers describing the coordinates of a point. The third parameter is a number/function which defines the length of the major axis\n * @param {Number} start (Optional) parameter of the curve start, default: -π.\n * @param {Number} end (Optional) parameter for the curve end, default: π.\n * @example\n * // Create an Hyperbola by three points\n * var A = board.create('point', [-1,4]);\n * var B = board.create('point', [-1,-4]);\n * var C = board.create('point', [1,1]);\n * var el = board.create('hyperbola',[A,B,C]);\n * </pre><div class=\"jxgbox\" id=\"JXGcf99049d-a3fe-407f-b936-27d76550f8c4\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function(){\n * var glex1_board = JXG.JSXGraph.initBoard('JXGcf99049d-a3fe-407f-b936-27d76550f8c4', {boundingbox:[-6,6,6,-6], keepaspectratio:true, showcopyright: false, shownavigation: false});\n * var A = glex1_board.create('point', [-1,4]);\n * var B = glex1_board.create('point', [-1,-4]);\n * var C = glex1_board.create('point', [1,1]);\n * var el = glex1_board.create('hyperbola',[A,B,C]);\n * })();\n * </script><pre>\n */\n JXG.createHyperbola = function (board, parents, attributes) {\n var polarForm, curve, M, C, majorAxis, i,\n // focus 1 and focus 2\n F = [],\n attr_foci = Type.copyAttributes(attributes, board.options, 'conic', 'foci'),\n attr_center = Type.copyAttributes(attributes, board.options, 'conic', 'center'),\n attr_curve = Type.copyAttributes(attributes, board.options, 'conic');\n\n // The foci and the third point are either points or coordinate arrays.\n for (i = 0; i < 2; i++) {\n // focus i given by coordinates\n if (parents[i].length > 1) {\n F[i] = board.create('point', parents[i], attr_foci);\n // focus i given by point\n } else if (Type.isPoint(parents[i])) {\n F[i] = board.select(parents[i]);\n // given by function\n } else if (Type.isFunction(parents[i]) && Type.isPoint(parents[i]()) ) {\n F[i] = parents[i]();\n // focus i given by point name\n } else if (Type.isString(parents[i])) {\n F[i] = board.select(parents[i]);\n } else {\n throw new Error(\"JSXGraph: Can't create Hyperbola with parent types '\" +\n (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"'.\" +\n \"\\nPossible parent types: [point,point,point], [point,point,number|function]\");\n }\n }\n\n // length of major axis\n if (Type.isNumber(parents[2])) {\n majorAxis = Type.createFunction(parents[2], board);\n } else if (Type.isFunction(parents[2]) && Type.isNumber(parents[2]())) {\n majorAxis = parents[2];\n } else {\n // point on ellipse\n if (Type.isPoint(parents[2])) {\n C = board.select(parents[2]);\n // point on ellipse given by coordinates\n } else if (parents[2].length > 1) {\n C = board.create('point', parents[2], attr_foci);\n // given by function\n } else if (Type.isFunction(parents[2]) && Type.isPoint(parents[2]())) {\n C = parents[2]();\n // focus i given by point name\n } else if (Type.isString(parents[2])) {\n C = board.select(parents[2]);\n } else {\n throw new Error(\"JSXGraph: Can't create Hyperbola with parent types '\" +\n (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"' and '\" + (typeof parents[2]) + \"'.\" +\n \"\\nPossible parent types: [point,point,point], [point,point,number|function]\");\n }\n /** @ignore */\n majorAxis = function () {\n return C.Dist(F[0]) - C.Dist(F[1]);\n };\n }\n\n // to\n if (!Type.exists(parents[4])) {\n parents[4] = 1.0001 * Math.PI;\n }\n\n // from\n if (!Type.exists(parents[3])) {\n parents[3] = -1.0001 * Math.PI;\n }\n\n M = board.create('point', [\n function () {\n return (F[0].X() + F[1].X()) * 0.5;\n },\n function () {\n return (F[0].Y() + F[1].Y()) * 0.5;\n }\n ], attr_center);\n\n curve = board.create('curve', [\n function (x) {\n return 0;\n },\n function (x) {\n return 0;\n }, parents[3], parents[4]], attr_curve);\n\n curve.majorAxis = majorAxis;\n\n // Hyperbola is defined by (a*sec(t),b*tan(t)) and sec(t) = 1/cos(t)\n /** @ignore */\n polarForm = function (phi, suspendUpdate) {\n var r, rr, ax, ay, bx, by, axbx, ayby, f;\n\n if (!suspendUpdate) {\n r = majorAxis();\n rr = r * r;\n ax = F[0].X();\n ay = F[0].Y();\n bx = F[1].X();\n by = F[1].Y();\n axbx = ax - bx;\n ayby = ay - by;\n f = (rr - ax * ax - ay * ay + bx * bx + by * by) / (2 * r);\n\n curve.quadraticform = [\n [f * f - bx * bx - by * by, f * axbx / r + bx, f * ayby / r + by],\n [f * axbx / r + bx, (axbx * axbx) / rr - 1, axbx * ayby / rr ],\n [f * ayby / r + by, axbx * ayby / rr, (ayby * ayby) / rr - 1]\n ];\n }\n };\n\n /** @ignore */\n curve.X = function (phi, suspendUpdate) {\n var r = majorAxis(),\n c = F[1].Dist(F[0]),\n b = 0.5 * (c * c - r * r) / (c * Math.cos(phi) + r),\n beta = Math.atan2(F[1].Y() - F[0].Y(), F[1].X() - F[0].X());\n\n if (!suspendUpdate) {\n polarForm(phi, suspendUpdate);\n }\n\n return F[0].X() + Math.cos(beta + phi) * b;\n };\n\n /** @ignore */\n curve.Y = function (phi, suspendUpdate) {\n var r = majorAxis(),\n c = F[1].Dist(F[0]),\n b = 0.5 * (c * c - r * r) / (c * Math.cos(phi) + r),\n beta = Math.atan2(F[1].Y() - F[0].Y(), F[1].X() - F[0].X());\n\n return F[0].Y() + Math.sin(beta + phi) * b;\n };\n\n curve.midpoint = curve.center = M;\n curve.subs = {\n center: curve.center\n };\n curve.inherits.push(curve.center, F[0], F[1]);\n if (Type.isPoint(C)) {\n curve.inherits.push(C);\n }\n curve.type = Const.OBJECT_TYPE_CONIC;\n\n M.addChild(curve);\n for (i = 0; i < 2; i++) {\n if (Type.isPoint(F[i])) {\n F[i].addChild(curve);\n }\n }\n if (Type.isPoint(C)) {\n C.addChild(curve);\n }\n curve.setParents(parents);\n\n return curve;\n };\n\n /**\n * @class This element is used to provide a constructor for a parabola. A parabola is given by one point (the focus) and a line (the directrix).\n * @pseudo\n * @description\n * @name Parabola\n * @augments Conic\n * @constructor\n * @type JXG.Curve\n * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {JXG.Point,array_JXG.Line} point,line Parent elements are a point and a line or a pair of coordinates.\n * Optional parameters three and four are numbers which define the curve length (e.g. start/end). Default values are -pi and pi.\n * @example\n * // Create a parabola by a point C and a line l.\n * var A = board.create('point', [-1,4]);\n * var B = board.create('point', [-1,-4]);\n * var l = board.create('line', [A,B]);\n * var C = board.create('point', [1,1]);\n * var el = board.create('parabola',[C,l]);\n * </pre><div class=\"jxgbox\" id=\"JXG524d1aae-217d-44d4-ac58-a19c7ab1de36\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var glex1_board = JXG.JSXGraph.initBoard('JXG524d1aae-217d-44d4-ac58-a19c7ab1de36', {boundingbox:[-6,6,6,-6], keepaspectratio:true, showcopyright: false, shownavigation: false});\n * var A = glex1_board.create('point', [-1,4]);\n * var B = glex1_board.create('point', [-1,-4]);\n * var l = glex1_board.create('line', [A,B]);\n * var C = glex1_board.create('point', [1,1]);\n * var el = glex1_board.create('parabola',[C,l]);\n * })();\n * </script><pre>\n *\n * @example\n * var par = board.create('parabola',[[3.25, 0], [[0.25, 1],[0.25, 0]]]);\n *\n * </pre><div id=\"JXG09252542-b77a-4990-a109-66ffb649a472\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG09252542-b77a-4990-a109-66ffb649a472',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var par = board.create('parabola',[[3.25, 0], [[0.25, 1],[0.25, 0]]]);\n *\n * })();\n *\n * </script><pre>\n *\n */\n JXG.createParabola = function (board, parents, attributes) {\n var polarForm, curve, M,\n // focus\n F1 = parents[0],\n // directrix\n l = parents[1],\n attr_foci = Type.copyAttributes(attributes, board.options, 'conic', 'foci'),\n attr_center = Type.copyAttributes(attributes, board.options, 'conic', 'center'),\n attr_curve = Type.copyAttributes(attributes, board.options, 'conic'),\n attr_line;\n\n // focus 1 given by coordinates\n if (parents[0].length > 1) {\n F1 = board.create('point', parents[0], attr_foci);\n // focus 1 given by point\n } else if (Type.isPoint(parents[0])) {\n F1 = board.select(parents[0]);\n // given by function\n } else if (Type.isFunction(parents[0]) && Type.isPoint(parents[0]()) ) {\n F1 = parents[0]();\n // focus 1 given by point name\n } else if (Type.isString(parents[0])) {\n F1 = board.select(parents[0]);\n } else {\n throw new Error(\"JSXGraph: Can't create Parabola with parent types '\" +\n (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"'.\" +\n \"\\nPossible parent types: [point,line]\");\n }\n\n // Create line if given as array of two points.\n if (Type.isArray(l) && l.length === 2) {\n attr_line = Type.copyAttributes(attributes, board.options, 'conic', 'line');\n l = board.create('line', l, attr_line);\n }\n\n // to\n if (!Type.exists(parents[3])) {\n parents[3] = 2 * Math.PI;\n }\n\n // from\n if (!Type.exists(parents[2])) {\n parents[2] = 0;\n }\n\n M = board.create('point', [\n function () {\n /*\n var v = [0, l.stdform[1], l.stdform[2]];\n v = Mat.crossProduct(v, F1.coords.usrCoords);\n return Geometry.meetLineLine(v, l.stdform, 0, board).usrCoords;\n */\n return Geometry.projectPointToLine(F1, l, board).usrCoords;\n }\n ], attr_center);\n\n /** @ignore */\n curve = board.create('curve', [\n function (x) {\n return 0;\n },\n function (x) {\n return 0;\n }, parents[2], parents[3]], attr_curve);\n\n curve.midpoint = curve.center = M;\n curve.subs = {\n center: curve.center\n };\n curve.inherits.push(curve.center);\n\n /** @ignore */\n polarForm = function (t, suspendUpdate) {\n var a, b, c, ab, px, py;\n\n if (!suspendUpdate) {\n a = l.stdform[1];\n b = l.stdform[2];\n c = l.stdform[0];\n ab = a * a + b * b;\n px = F1.X();\n py = F1.Y();\n\n curve.quadraticform = [\n [(c * c - ab * (px * px + py * py)), c * a + ab * px, c * b + ab * py],\n [c * a + ab * px, -b * b, a * b],\n [c * b + ab * py, a * b, -a * a]\n ];\n }\n };\n\n /** @ignore */\n curve.X = function (phi, suspendUpdate) {\n var a, det,\n beta = l.getAngle(),\n d = Geometry.distPointLine(F1.coords.usrCoords, l.stdform),\n A = l.point1.coords.usrCoords,\n B = l.point2.coords.usrCoords,\n M = F1.coords.usrCoords;\n\n // Handle the case if one of the two defining points of the line is an ideal point\n if (A[0] === 0) {\n A = [1, B[1] + l.stdform[2], B[2] - l.stdform[1]];\n } else if (B[0] === 0) {\n B = [1, A[1] + l.stdform[2], A[2] - l.stdform[1]];\n }\n det = ((B[1] - A[1]) * (M[2] - A[2]) - (B[2] - A[2]) * (M[1] - A[1]) >= 0) ? 1 : -1;\n a = det * d / (1 - Math.sin(phi));\n\n if (!suspendUpdate) {\n polarForm(phi, suspendUpdate);\n }\n\n return F1.X() + Math.cos(phi + beta) * a;\n };\n\n /** @ignore */\n curve.Y = function (phi, suspendUpdate) {\n var a, det,\n beta = l.getAngle(),\n d = Geometry.distPointLine(F1.coords.usrCoords, l.stdform),\n A = l.point1.coords.usrCoords,\n B = l.point2.coords.usrCoords,\n M = F1.coords.usrCoords;\n\n // Handle the case if one of the two defining points of the line is an ideal point\n if (A[0] === 0) {\n A = [1, B[1] + l.stdform[2], B[2] - l.stdform[1]];\n } else if (B[0] === 0) {\n B = [1, A[1] + l.stdform[2], A[2] - l.stdform[1]];\n }\n det = ((B[1] - A[1]) * (M[2] - A[2]) - (B[2] - A[2]) * (M[1] - A[1]) >= 0) ? 1 : -1;\n a = det * d / (1 - Math.sin(phi));\n\n return F1.Y() + Math.sin(phi + beta) * a;\n };\n\n curve.type = Const.OBJECT_TYPE_CONIC;\n M.addChild(curve);\n\n if (Type.isPoint(F1)) {\n F1.addChild(curve);\n curve.inherits.push(F1);\n }\n\n l.addChild(curve);\n curve.setParents(parents);\n\n return curve;\n };\n\n /**\n *\n * @class This element is used to provide a constructor for a generic conic section uniquely defined by five points or\n * a conic defined by the coefficients of the equation\n * <p><i>Ax<sup>2</sup>+ Bxy+Cy<sup>2</sup> + Dx + Ey + F = 0</i></p>.\n * Then the parameters are as follows:\n * <pre>\n * board.create('conic', [A, C, F, B/2, D/2, E/2]);\n * </pre>\n * @pseudo\n * @description\n * @name Conic\n * @augments JXG.Curve\n * @constructor\n * @type JXG.Conic\n * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {JXG.Point,Array_JXG.Point,Array_JXG.Point,Array_JXG.Point,Array_JXG.Point,Array} a,b,c,d,e Parent elements are five points.\n * @param {Number_Number_Number_Number_Number_Number} a_00,a_11,a_22,a_01,a_02,a_12 6 numbers, i.e. A, C, F, B/2, D/2, E/2\n * @example\n * // Create a conic section through the points A, B, C, D, and E.\n * var A = board.create('point', [1,5]);\n * var B = board.create('point', [1,2]);\n * var C = board.create('point', [2,0]);\n * var D = board.create('point', [0,0]);\n * var E = board.create('point', [-1,5]);\n * var conic = board.create('conic',[A,B,C,D,E]);\n * </pre><div class=\"jxgbox\" id=\"JXG2d79bd6a-db9b-423c-9cba-2497f0b06320\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function(){\n * var glex1_board = JXG.JSXGraph.initBoard('JXG2d79bd6a-db9b-423c-9cba-2497f0b06320', {boundingbox:[-6,6,6,-6], keepaspectratio:true, showcopyright: false, shownavigation: false});\n * var A = glex1_board.create('point', [1,5]);\n * var B = glex1_board.create('point', [1,2]);\n * var C = glex1_board.create('point', [2,0]);\n * var D = glex1_board.create('point', [0,0]);\n * var E = glex1_board.create('point', [-1,5]);\n * var conic = glex1_board.create('conic',[A,B,C,D,E]);\n * })();\n * </script><pre>\n *\n * @example\n * // Parameters: A, C, F, B/2, D/2, E/2\n * var conic = board.create('conic', [1, 2, -4, 0, 0, 0]s);\n *\n * </pre><div id=\"JXG8576a04a-52d8-4a7e-8d54-e32443910b97\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG8576a04a-52d8-4a7e-8d54-e32443910b97',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * // Parameters: A, C, F, B/2, D/2, E/2\n * var conic = board.create('conic', [1, 2, -4, 0, 0, 0]s);\n * })();\n *\n * </script><pre>\n *\n */\n JXG.createConic = function (board, parents, attributes) {\n var polarForm, curve, fitConic, degconic, sym,\n eigen, a, b, c, c1, c2,\n i, definingMat, givenByPoints,\n rotationMatrix = [\n [1, 0, 0],\n [0, 1, 0],\n [0, 0, 1]\n ],\n M = [\n [1, 0, 0],\n [0, 1, 0],\n [0, 0, 1]\n ],\n points = [],\n p = [],\n attr_point = Type.copyAttributes(attributes, board.options, 'conic', 'point'),\n attr_center = Type.copyAttributes(attributes, board.options, 'conic', 'center'),\n attr_curve = Type.copyAttributes(attributes, board.options, 'conic');\n\n if (parents.length === 5) {\n givenByPoints = true;\n } else if (parents.length === 6) {\n givenByPoints = false;\n } else {\n throw new Error(\"JSXGraph: Can't create generic Conic with \" + parents.length + \" parameters.\");\n }\n\n if (givenByPoints) {\n for (i = 0; i < 5; i++) {\n // point i given by coordinates\n if (parents[i].length > 1) {\n points[i] = board.create('point', parents[i], attr_point);\n // point i given by point\n } else if (Type.isPoint(parents[i])) {\n points[i] = board.select(parents[i]);\n // given by function\n } else if (Type.isFunction(parents[i]) && Type.isPoint(parents[i]()) ) {\n points[i] = parents[i]();\n // point i given by point name\n } else if (Type.isString(parents[i])) {\n points[i] = board.select(parents[i]);\n } else {\n throw new Error(\"JSXGraph: Can't create Conic section with parent types '\" + (typeof parents[i]) + \"'.\" +\n \"\\nPossible parent types: [point,point,point,point,point], [a00,a11,a22,a01,a02,a12]\");\n }\n }\n } else {\n /* Usual notation (x,y,z):\n * [[A0,A3,A4],\n * [A3,A1,A5],\n * [A4,A5,A2]].\n * Our notation (z,x,y):\n * [[A2, A4, A5],\n * [A4, A0, A3],\n * [A5, A3, A1]]\n */\n definingMat = [\n [0, 0, 0],\n [0, 0, 0],\n [0, 0, 0]\n ];\n definingMat[0][0] = (Type.isFunction(parents[2])) ? function () { return parents[2](); } : function () { return parents[2]; };\n definingMat[0][1] = (Type.isFunction(parents[4])) ? function () { return parents[4](); } : function () { return parents[4]; };\n definingMat[0][2] = (Type.isFunction(parents[5])) ? function () { return parents[5](); } : function () { return parents[5]; };\n definingMat[1][1] = (Type.isFunction(parents[0])) ? function () { return parents[0](); } : function () { return parents[0]; };\n definingMat[1][2] = (Type.isFunction(parents[3])) ? function () { return parents[3](); } : function () { return parents[3]; };\n definingMat[2][2] = (Type.isFunction(parents[1])) ? function () { return parents[1](); } : function () { return parents[1]; };\n }\n\n // sym(A) = A + A^t . Manipulates A in place.\n sym = function (A) {\n var i, j;\n for (i = 0; i < 3; i++) {\n for (j = i; j < 3; j++) {\n A[i][j] += A[j][i];\n }\n }\n for (i = 0; i < 3; i++) {\n for (j = 0; j < i; j++) {\n A[i][j] = A[j][i];\n }\n }\n return A;\n };\n\n // degconic(v,w) = sym(v*w^t)\n degconic = function (v, w) {\n var i, j, mat = [\n [0, 0, 0],\n [0, 0, 0],\n [0, 0, 0]\n ];\n\n for (i = 0; i < 3; i++) {\n for (j = 0; j < 3; j++) {\n mat[i][j] = v[i] * w[j];\n }\n }\n\n return sym(mat);\n };\n\n // (p^t*B*p)*A-(p^t*A*p)*B\n fitConic = function (A, B, p) {\n var i, j, pBp, pAp, Mv,\n mat = [\n [0, 0, 0],\n [0, 0, 0],\n [0, 0, 0]\n ];\n\n Mv = Mat.matVecMult(B, p);\n pBp = Mat.innerProduct(p, Mv);\n Mv = Mat.matVecMult(A, p);\n pAp = Mat.innerProduct(p, Mv);\n\n for (i = 0; i < 3; i++) {\n for (j = 0; j < 3; j++) {\n mat[i][j] = pBp * A[i][j] - pAp * B[i][j];\n }\n }\n return mat;\n };\n\n // Here, the defining functions for the curve are just dummy functions.\n // In polarForm there is a reference to curve.quadraticform.\n curve = board.create('curve', [\n function (x) {\n return 0;\n },\n function (x) {\n return 0;\n }, 0, 2 * Math.PI], attr_curve);\n\n /** @ignore */\n polarForm = function (phi, suspendUpdate) {\n var i, j, len, v;\n\n if (!suspendUpdate) {\n if (givenByPoints) {\n // Copy the point coordinate vectors\n for (i = 0; i < 5; i++) {\n p[i] = points[i].coords.usrCoords;\n }\n\n // Compute the quadratic form\n c1 = degconic(Mat.crossProduct(p[0], p[1]), Mat.crossProduct(p[2], p[3]));\n c2 = degconic(Mat.crossProduct(p[0], p[2]), Mat.crossProduct(p[1], p[3]));\n M = fitConic(c1, c2, p[4]);\n } else {\n for (i = 0; i < 3; i++) {\n for (j = i; j < 3; j++) {\n M[i][j] = definingMat[i][j]();\n if (j > i) {\n M[j][i] = M[i][j];\n }\n }\n }\n }\n\n // Here is the reference back to the curve.\n curve.quadraticform = M;\n\n // Compute Eigenvalues and Eigenvectors\n eigen = Numerics.Jacobi(M);\n\n // Scale the Eigenvalues such that the first Eigenvalue is positive\n if (eigen[0][0][0] < 0) {\n eigen[0][0][0] *= (-1);\n eigen[0][1][1] *= (-1);\n eigen[0][2][2] *= (-1);\n }\n\n // Normalize the Eigenvectors\n for (i = 0; i < 3; i++) {\n len = 0.0;\n for (j = 0; j < 3; j++) {\n len += eigen[1][j][i] * eigen[1][j][i];\n }\n len = Math.sqrt(len);\n /*for (j = 0; j < 3; j++) {\n //eigen[1][j][i] /= len;\n }*/\n }\n rotationMatrix = eigen[1];\n c = Math.sqrt(Math.abs(eigen[0][0][0]));\n a = Math.sqrt(Math.abs(eigen[0][1][1]));\n b = Math.sqrt(Math.abs(eigen[0][2][2]));\n\n }\n\n // The degenerate cases with eigen[0][i][i]==0 are not handled correct yet.\n if (eigen[0][1][1] <= 0.0 && eigen[0][2][2] <= 0.0) {\n v = Mat.matVecMult(rotationMatrix, [1 / c, Math.cos(phi) / a, Math.sin(phi) / b]);\n } else if (eigen[0][1][1] <= 0.0 && eigen[0][2][2] > 0.0) {\n v = Mat.matVecMult(rotationMatrix, [Math.cos(phi) / c, 1 / a, Math.sin(phi) / b]);\n } else if (eigen[0][2][2] < 0.0) {\n v = Mat.matVecMult(rotationMatrix, [Math.sin(phi) / c, Math.cos(phi) / a, 1 / b]);\n }\n\n if (Type.exists(v)) {\n // Normalize\n v[1] /= v[0];\n v[2] /= v[0];\n v[0] = 1.0;\n } else {\n v = [1, NaN, NaN];\n }\n\n return v;\n };\n\n /** @ignore */\n curve.X = function (phi, suspendUpdate) {\n return polarForm(phi, suspendUpdate)[1];\n };\n\n /** @ignore */\n curve.Y = function (phi, suspendUpdate) {\n return polarForm(phi, suspendUpdate)[2];\n };\n\n // Center coordinates see http://en.wikipedia.org/wiki/Matrix_representation_of_conic_sections\n curve.midpoint = board.create('point', [\n function () {\n var m = curve.quadraticform;\n\n return [\n m[1][1] * m[2][2] - m[1][2] * m[1][2],\n m[1][2] * m[0][2] - m[2][2] * m[0][1],\n m[0][1] * m[1][2] - m[1][1] * m[0][2]\n ];\n }\n ], attr_center);\n\n curve.type = Const.OBJECT_TYPE_CONIC;\n curve.center = curve.midpoint;\n curve.subs = {\n center: curve.center\n };\n curve.inherits.push(curve.center);\n curve.inherits = curve.inherits.concat(points);\n\n if (givenByPoints) {\n for (i = 0; i < 5; i++) {\n if (Type.isPoint(points[i])) {\n points[i].addChild(curve);\n }\n }\n curve.setParents(parents);\n }\n curve.addChild(curve.center);\n\n return curve;\n };\n\n JXG.registerElement('ellipse', JXG.createEllipse);\n JXG.registerElement('hyperbola', JXG.createHyperbola);\n JXG.registerElement('parabola', JXG.createParabola);\n JXG.registerElement('conic', JXG.createConic);\n\n return {\n createEllipse: JXG.createEllipse,\n createHyperbola: JXG.createHyperbola,\n createParabola: JXG.createParabola,\n createConic: JXG.createConic\n };\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true*/\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n jxg\n base/element\n base/constants\n base/coords\n parser/geonext\n math/geometry\n math/statistics\n utils/type\n elements:\n transform\n point\n */\n\n/**\n * @fileoverview The geometry object Circle is defined in this file. Circle stores all\n * style and functional properties that are required to draw and move a circle on\n * a board.\n */\n\ndefine('base/circle',[\n 'jxg', 'base/element', 'base/coords', 'base/constants', 'element/conic', 'parser/geonext', 'utils/type'\n], function (JXG, GeometryElement, Coords, Const, Conic, GeonextParser, Type) {\n\n \"use strict\";\n\n /**\n * A circle consists of all points with a given distance from one point. This point is called center, the distance is called radius.\n * A circle can be constructed by providing a center and a point on the circle or a center and a radius (given as a number, function,\n * line, or circle).\n * @class Creates a new circle object. Do not use this constructor to create a circle. Use {@link JXG.Board#create} with\n * type {@link Circle} instead.\n * @constructor\n * @augments JXG.GeometryElement\n * @param {JXG.Board} board The board the new circle is drawn on.\n * @param {String} method Can be\n * <ul><li> <b>'twoPoints'</b> which means the circle is defined by its center and a point on the circle.</li>\n * <li><b>'pointRadius'</b> which means the circle is defined by its center and its radius in user units</li>\n * <li><b>'pointLine'</b> which means the circle is defined by its center and its radius given by the distance from the startpoint and the endpoint of the line</li>\n * <li><b>'pointCircle'</b> which means the circle is defined by its center and its radius given by the radius of another circle</li></ul>\n * The parameters p1, p2 and radius must be set according to this method parameter.\n * @param {JXG.Point} par1 center of the circle.\n * @param {JXG.Point|JXG.Line|JXG.Circle} par2 Can be\n * <ul><li>a point on the circle if method is 'twoPoints'</li>\n * <li>a line if the method is 'pointLine'</li>\n * <li>a circle if the method is 'pointCircle'</li></ul>\n * @param {Object} attributes\n * @see JXG.Board#generateName\n */\n JXG.Circle = function (board, method, par1, par2, attributes) {\n // Call the constructor of GeometryElement\n this.constructor(board, attributes, Const.OBJECT_TYPE_CIRCLE, Const.OBJECT_CLASS_CIRCLE);\n\n /**\n * Stores the given method.\n * Can be\n * <ul><li><b>'twoPoints'</b> which means the circle is defined by its center and a point on the circle.</li>\n * <li><b>'pointRadius'</b> which means the circle is defined by its center and its radius given in user units or as term.</li>\n * <li><b>'pointLine'</b> which means the circle is defined by its center and its radius given by the distance from the startpoint and the endpoint of the line.</li>\n * <li><b>'pointCircle'</b> which means the circle is defined by its center and its radius given by the radius of another circle.</li></ul>\n * @type String\n * @see #center\n * @see #point2\n * @see #radius\n * @see #line\n * @see #circle\n */\n this.method = method;\n\n // this is kept so existing code won't ne broken\n this.midpoint = this.board.select(par1);\n\n /**\n * The circles center. Do not set this parameter directly as it will break JSXGraph's update system.\n * @type JXG.Point\n */\n this.center = this.board.select(par1);\n\n /** Point on the circle only set if method equals 'twoPoints'. Do not set this parameter directly as it will break JSXGraph's update system.\n * @type JXG.Point\n * @see #method\n */\n this.point2 = null;\n\n /** Radius of the circle\n * only set if method equals 'pointRadius'\n * @type Number\n * @default null\n * @see #method\n */\n this.radius = 0;\n\n /** Line defining the radius of the circle given by the distance from the startpoint and the endpoint of the line\n * only set if method equals 'pointLine'. Do not set this parameter directly as it will break JSXGraph's update system.\n * @type JXG.Line\n * @default null\n * @see #method\n */\n this.line = null;\n\n /** Circle defining the radius of the circle given by the radius of the other circle\n * only set if method equals 'pointLine'. Do not set this parameter directly as it will break JSXGraph's update system.\n * @type JXG.Circle\n * @default null\n * @see #method\n */\n this.circle = null;\n\n this.points = [];\n\n if (method === 'twoPoints') {\n this.point2 = board.select(par2);\n this.radius = this.Radius();\n } else if (method === 'pointRadius') {\n this.gxtterm = par2;\n // Converts GEONExT syntax into JavaScript syntax and generally ensures that the radius is a function\n this.updateRadius = Type.createFunction(par2, this.board, null, true);\n // First evaluation of the radius function\n this.updateRadius();\n } else if (method === 'pointLine') {\n // dann ist p2 die Id eines Objekts vom Typ Line!\n this.line = board.select(par2);\n this.radius = this.line.point1.coords.distance(Const.COORDS_BY_USER, this.line.point2.coords);\n } else if (method === 'pointCircle') {\n // dann ist p2 die Id eines Objekts vom Typ Circle!\n this.circle = board.select(par2);\n this.radius = this.circle.Radius();\n }\n\n // create Label\n this.id = this.board.setId(this, 'C');\n this.board.renderer.drawEllipse(this);\n this.board.finalizeAdding(this);\n\n this.createGradient();\n this.elType = 'circle';\n this.createLabel();\n\n if (Type.exists(this.center._is_new)) {\n this.addChild(this.center);\n delete this.center._is_new;\n } else {\n this.center.addChild(this);\n }\n\n if (method === 'pointRadius') {\n this.notifyParents(par2);\n } else if (method === 'pointLine') {\n this.line.addChild(this);\n } else if (method === 'pointCircle') {\n this.circle.addChild(this);\n } else if (method === 'twoPoints') {\n if (Type.exists(this.point2._is_new)) {\n this.addChild(this.point2);\n delete this.point2._is_new;\n } else {\n this.point2.addChild(this);\n }\n }\n\n this.methodMap = Type.deepCopy(this.methodMap, {\n setRadius: 'setRadius',\n getRadius: 'getRadius',\n Area: 'Area',\n area: 'Area',\n radius: 'Radius',\n center: 'center',\n line: 'line',\n point2: 'point2'\n });\n };\n\n JXG.Circle.prototype = new GeometryElement();\n\n JXG.extend(JXG.Circle.prototype, /** @lends JXG.Circle.prototype */ {\n /**\n * Checks whether (x,y) is near the circle line or inside of the ellipse\n * (in case JXG.Options.conic#hasInnerPoints is true).\n * @param {Number} x Coordinate in x direction, screen coordinates.\n * @param {Number} y Coordinate in y direction, screen coordinates.\n * @returns {Boolean} True if (x,y) is near the circle, False otherwise.\n * @private\n */\n hasPoint: function (x, y) {\n var prec, type,\n mp = this.center.coords.usrCoords,\n p = new Coords(Const.COORDS_BY_SCREEN, [x, y], this.board),\n r = this.Radius(),\n dx, dy, dist;\n\n\n if (Type.isObject(Type.evaluate(this.visProp.precision))) {\n type = this.board._inputDevice;\n prec = Type.evaluate(this.visProp.precision[type]);\n } else {\n // 'inherit'\n prec = this.board.options.precision.hasPoint;\n }\n dx = mp[1] - p.usrCoords[1];\n dy = mp[2] - p.usrCoords[2];\n dist = Math.sqrt(dx * dx + dy * dy);\n // We have to use usrCoords, since Radius is available in usrCoords only.\n prec += Type.evaluate(this.visProp.strokewidth) * 0.5;\n prec /= Math.sqrt(this.board.unitX * this.board.unitY);\n\n if (Type.evaluate(this.visProp.hasinnerpoints)) {\n return (dist < r + prec);\n }\n\n return (Math.abs(dist - r) < prec);\n },\n\n /**\n * Used to generate a polynomial for a point p that lies on this circle.\n * @param {JXG.Point} p The point for which the polynomial is generated.\n * @returns {Array} An array containing the generated polynomial.\n * @private\n */\n generatePolynomial: function (p) {\n /*\n * We have four methods to construct a circle:\n * (a) Two points\n * (b) center and radius\n * (c) center and radius given by length of a segment\n * (d) center and radius given by another circle\n *\n * In case (b) we have to distinguish two cases:\n * (i) radius is given as a number\n * (ii) radius is given as a function\n * In the latter case there's no guarantee the radius depends on other geometry elements\n * in a polynomial way so this case has to be omitted.\n *\n * Another tricky case is case (d):\n * The radius depends on another circle so we have to cycle through the ancestors of each circle\n * until we reach one that's radius does not depend on another circles radius.\n *\n *\n * All cases (a) to (d) vary only in calculation of the radius. So the basic formulae for\n * a glider G (g1,g2) on a circle with center M (m1,m2) and radius r is just:\n *\n * (g1-m1)^2 + (g2-m2)^2 - r^2 = 0\n *\n * So the easiest case is (b) with a fixed radius given as a number. The other two cases (a)\n * and (c) are quite the same: Euclidean distance between two points A (a1,a2) and B (b1,b2),\n * squared:\n *\n * r^2 = (a1-b1)^2 + (a2-b2)^2\n *\n * For case (d) we have to cycle recursively through all defining circles and finally return the\n * formulae for calculating r^2. For that we use JXG.Circle.symbolic.generateRadiusSquared().\n */\n var m1 = this.center.symbolic.x,\n m2 = this.center.symbolic.y,\n g1 = p.symbolic.x,\n g2 = p.symbolic.y,\n rsq = this.generateRadiusSquared();\n\n /* No radius can be calculated (Case b.ii) */\n if (rsq === '') {\n return [];\n }\n\n return ['((' + g1 + ')-(' + m1 + '))^2 + ((' + g2 + ')-(' + m2 + '))^2 - (' + rsq + ')'];\n },\n\n /**\n * Generate symbolic radius calculation for loci determination with Groebner-Basis algorithm.\n * @returns {String} String containing symbolic calculation of the circle's radius or an empty string\n * if the radius can't be expressed in a polynomial equation.\n * @private\n */\n generateRadiusSquared: function () {\n /*\n * Four cases:\n *\n * (a) Two points\n * (b) center and radius\n * (c) center and radius given by length of a segment\n * (d) center and radius given by another circle\n */\n var m1, m2, p1, p2, q1, q2,\n rsq = '';\n\n if (this.method === \"twoPoints\") {\n m1 = this.center.symbolic.x;\n m2 = this.center.symbolic.y;\n p1 = this.point2.symbolic.x;\n p2 = this.point2.symbolic.y;\n\n rsq = '((' + p1 + ')-(' + m1 + '))^2 + ((' + p2 + ')-(' + m2 + '))^2';\n } else if (this.method === \"pointRadius\") {\n if (Type.isNumber(this.radius)) {\n rsq = (this.radius * this.radius).toString();\n }\n } else if (this.method === \"pointLine\") {\n p1 = this.line.point1.symbolic.x;\n p2 = this.line.point1.symbolic.y;\n\n q1 = this.line.point2.symbolic.x;\n q2 = this.line.point2.symbolic.y;\n\n rsq = '((' + p1 + ')-(' + q1 + '))^2 + ((' + p2 + ')-(' + q2 + '))^2';\n } else if (this.method === \"pointCircle\") {\n rsq = this.circle.Radius();\n }\n\n return rsq;\n },\n\n /**\n * Uses the boards renderer to update the circle.\n */\n update: function () {\n var x, y, z, r, c, i;\n\n if (this.needsUpdate) {\n if (Type.evaluate(this.visProp.trace)) {\n this.cloneToBackground(true);\n }\n\n if (this.method === 'pointLine') {\n this.radius = this.line.point1.coords.distance(Const.COORDS_BY_USER, this.line.point2.coords);\n } else if (this.method === 'pointCircle') {\n this.radius = this.circle.Radius();\n } else if (this.method === 'pointRadius') {\n this.radius = this.updateRadius();\n }\n\n this.updateStdform();\n this.updateQuadraticform();\n\n // Approximate the circle by 4 Bezier segments\n // This will be used for intersections of type curve / circle.\n // See https://spencermortensen.com/articles/bezier-circle/\n z = this.center.coords.usrCoords[0];\n x = this.center.coords.usrCoords[1] / z;\n y = this.center.coords.usrCoords[2] / z;\n z /= z;\n r = this.Radius();\n c = 0.551915024494;\n\n this.numberPoints = 13;\n this.dataX = [x + r, x + r, x + r * c, x, x - r * c, x - r, x - r, x - r, x - r * c, x, x + r * c, x + r, x + r];\n this.dataY = [y, y + r * c, y + r, y + r, y + r, y + r * c, y, y - r * c, y - r, y - r, y - r, y - r * c, y];\n this.bezierDegree = 3;\n for (i = 0; i < this.numberPoints; i++) {\n this.points[i] = new Coords(Const.COORDS_BY_USER, [this.dataX[i], this.dataY[i]], this.board);\n }\n }\n\n return this;\n },\n\n /**\n * Updates this circle's {@link JXG.Circle#quadraticform}.\n * @private\n */\n updateQuadraticform: function () {\n var m = this.center,\n mX = m.X(),\n mY = m.Y(),\n r = this.Radius();\n\n this.quadraticform = [\n [mX * mX + mY * mY - r * r, -mX, -mY],\n [-mX, 1, 0],\n [-mY, 0, 1]\n ];\n },\n\n /**\n * Updates the stdform derived from the position of the center and the circle's radius.\n * @private\n */\n updateStdform: function () {\n this.stdform[3] = 0.5;\n this.stdform[4] = this.Radius();\n this.stdform[1] = -this.center.coords.usrCoords[1];\n this.stdform[2] = -this.center.coords.usrCoords[2];\n if (!isFinite(this.stdform[4])) {\n this.stdform[0] = Type.exists(this.point2) ? -(\n this.stdform[1] * this.point2.coords.usrCoords[1] +\n this.stdform[2] * this.point2.coords.usrCoords[2]\n ) : 0;\n }\n this.normalize();\n },\n\n /**\n * Uses the boards renderer to update the circle.\n * @private\n */\n updateRenderer: function () {\n // var wasReal;\n\n if (!this.needsUpdate) {\n return this;\n }\n\n if (this.visPropCalc.visible) {\n // wasReal = this.isReal;\n this.isReal = (!isNaN(this.center.coords.usrCoords[1] + this.center.coords.usrCoords[2] + this.Radius())) && this.center.isReal;\n\n if (//wasReal &&\n !this.isReal) {\n this.updateVisibility(false);\n }\n }\n\n // Update the position\n if (this.visPropCalc.visible) {\n this.board.renderer.updateEllipse(this);\n }\n\n // Update the label if visible.\n if (this.hasLabel && this.visPropCalc.visible && this.label &&\n this.label.visPropCalc.visible && this.isReal) {\n\n this.label.update();\n this.board.renderer.updateText(this.label);\n }\n\n // Update rendNode display\n this.setDisplayRendNode();\n // if (this.visPropCalc.visible !== this.visPropOld.visible) {\n // this.board.renderer.display(this, this.visPropCalc.visible);\n // this.visPropOld.visible = this.visPropCalc.visible;\n //\n // if (this.hasLabel) {\n // this.board.renderer.display(this.label, this.label.visPropCalc.visible);\n // }\n // }\n\n this.needsUpdate = false;\n return this;\n },\n\n /**\n * Finds dependencies in a given term and resolves them by adding the elements referenced in this\n * string to the circle's list of ancestors.\n * @param {String} contentStr\n * @private\n */\n notifyParents: function (contentStr) {\n if (Type.isString(contentStr)) {\n GeonextParser.findDependencies(this, contentStr, this.board);\n }\n },\n\n /**\n * Set a new radius, then update the board.\n * @param {String|Number|function} r A string, function or number describing the new radius.\n * @returns {JXG.Circle} Reference to this circle\n */\n setRadius: function (r) {\n this.updateRadius = Type.createFunction(r, this.board, null, true);\n this.board.update();\n\n return this;\n },\n\n /**\n * Calculates the radius of the circle.\n * @param {String|Number|function} [value] Set new radius\n * @returns {Number} The radius of the circle\n */\n Radius: function (value) {\n if (Type.exists(value)) {\n this.setRadius(value);\n return this.Radius();\n }\n\n if (this.method === 'twoPoints') {\n if (Type.cmpArrays(this.point2.coords.usrCoords, [0, 0, 0]) ||\n Type.cmpArrays(this.center.coords.usrCoords, [0, 0, 0])) {\n\n return NaN;\n }\n\n return this.center.Dist(this.point2);\n }\n\n if (this.method === 'pointLine' || this.method === 'pointCircle') {\n return this.radius;\n }\n\n if (this.method === 'pointRadius') {\n return this.updateRadius();\n }\n\n return NaN;\n },\n\n /**\n * Use {@link JXG.Circle#Radius}.\n * @deprecated\n */\n getRadius: function () {\n JXG.deprecated('Circle.getRadius()', 'Circle.Radius()');\n return this.Radius();\n },\n\n // documented in geometry element\n getTextAnchor: function () {\n return this.center.coords;\n },\n\n // documented in geometry element\n getLabelAnchor: function () {\n var x, y,\n r = this.Radius(),\n c = this.center.coords.usrCoords,\n SQRTH = 7.07106781186547524401E-1; // sqrt(2)/2\n\n switch (Type.evaluate(this.visProp.label.position)) {\n case 'lft':\n x = c[1] - r;\n y = c[2];\n break;\n case 'llft':\n x = c[1] - SQRTH * r;\n y = c[2] - SQRTH * r;\n break;\n case 'rt':\n x = c[1] + r;\n y = c[2];\n break;\n case 'lrt':\n x = c[1] + SQRTH * r;\n y = c[2] - SQRTH * r;\n break;\n case 'urt':\n x = c[1] + SQRTH * r;\n y = c[2] + SQRTH * r;\n break;\n case 'top':\n x = c[1];\n y = c[2] + r;\n break;\n case 'bot':\n x = c[1];\n y = c[2] - r;\n break;\n default:\n // includes case 'ulft'\n x = c[1] - SQRTH * r;\n y = c[2] + SQRTH * r;\n break;\n }\n\n return new Coords(Const.COORDS_BY_USER, [x, y], this.board);\n },\n\n // documented in geometry element\n cloneToBackground: function () {\n var er,\n r = this.Radius(),\n copy = {\n id: this.id + 'T' + this.numTraces,\n elementClass: Const.OBJECT_CLASS_CIRCLE,\n center: {\n coords: this.center.coords\n },\n Radius: function () {\n return r;\n },\n getRadius: function () {\n return r;\n },\n board: this.board,\n visProp: Type.deepCopy(this.visProp, this.visProp.traceattributes, true)\n };\n\n copy.visProp.layer = this.board.options.layer.trace;\n\n this.numTraces++;\n Type.clearVisPropOld(copy);\n copy.visPropCalc = {\n visible: Type.evaluate(copy.visProp.visible)\n };\n\n er = this.board.renderer.enhancedRendering;\n this.board.renderer.enhancedRendering = true;\n this.board.renderer.drawEllipse(copy);\n this.board.renderer.enhancedRendering = er;\n this.traces[copy.id] = copy.rendNode;\n\n return this;\n },\n\n /**\n * Add transformations to this circle.\n * @param {JXG.Transformation|Array} transform Either one {@link JXG.Transformation} or an array of {@link JXG.Transformation}s.\n * @returns {JXG.Circle} Reference to this circle object.\n */\n addTransform: function (transform) {\n var i,\n list = Type.isArray(transform) ? transform : [transform],\n len = list.length;\n\n for (i = 0; i < len; i++) {\n this.center.transformations.push(list[i]);\n\n if (this.method === 'twoPoints') {\n this.point2.transformations.push(list[i]);\n }\n }\n\n return this;\n },\n\n // see element.js\n snapToGrid: function () {\n var forceIt = Type.evaluate(this.visProp.snaptogrid);\n\n this.center.handleSnapToGrid(forceIt, true);\n if (this.method === 'twoPoints') {\n this.point2.handleSnapToGrid(forceIt, true);\n }\n\n return this;\n },\n\n // see element.js\n snapToPoints: function () {\n var forceIt = Type.evaluate(this.visProp.snaptopoints);\n\n this.center.handleSnapToPoints(forceIt);\n if (this.method === 'twoPoints') {\n this.point2.handleSnapToPoints(forceIt);\n }\n\n return this;\n },\n\n /**\n * Treats the circle as parametric curve and calculates its X coordinate.\n * @param {Number} t Number between 0 and 1.\n * @returns {Number} <tt>X(t)= radius*cos(t)+centerX</tt>.\n */\n X: function (t) {\n return this.Radius() * Math.cos(t * 2 * Math.PI) + this.center.coords.usrCoords[1];\n },\n\n /**\n * Treats the circle as parametric curve and calculates its Y coordinate.\n * @param {Number} t Number between 0 and 1.\n * @returns {Number} <tt>X(t)= radius*sin(t)+centerY</tt>.\n */\n Y: function (t) {\n return this.Radius() * Math.sin(t * 2 * Math.PI) + this.center.coords.usrCoords[2];\n },\n\n /**\n * Treat the circle as parametric curve and calculates its Z coordinate.\n * @param {Number} t ignored\n * @returns {Number} 1.0\n */\n Z: function (t) {\n return 1.0;\n },\n\n /**\n * Returns 0.\n * @private\n */\n minX: function () {\n return 0.0;\n },\n\n /**\n * Returns 1.\n * @private\n */\n maxX: function () {\n return 1.0;\n },\n\n /**\n * Circle area\n * @returns {Number} area of the circle.\n */\n Area: function () {\n var r = this.Radius();\n\n return r * r * Math.PI;\n },\n\n /**\n * Get bounding box of the circle.\n * @returns {Array} [x1, y1, x2, y2]\n */\n bounds: function () {\n var uc = this.center.coords.usrCoords,\n r = this.Radius();\n\n return [uc[1] - r, uc[2] + r, uc[1] + r, uc[2] - r];\n },\n\n /**\n * Get data to construct this element. Data consists of the parent elements\n * and static data like radius.\n * @returns {Array} data necessary to construct this element\n */\n getParents: function() {\n if (this.parents.length === 1) { // i.e. this.method === 'pointRadius'\n return this.parents.concat(this.radius);\n }\n return this.parents;\n }\n });\n\n /**\n * @class This element is used to provide a constructor for a circle.\n * @pseudo\n * @description A circle consists of all points with a given distance from one point. This point is called center, the distance is called radius.\n * A circle can be constructed by providing a center and a point on the circle or a center and a radius (given as a number, function,\n * line, or circle).\n * @name Circle\n * @augments JXG.Circle\n * @constructor\n * @type JXG.Circle\n * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {JXG.Point_number,JXG.Point,JXG.Line,JXG.Circle} center,radius The center must be given as a {@link JXG.Point}, see {@link JXG.providePoints}, but the radius can be given\n * as a number (which will create a circle with a fixed radius), another {@link JXG.Point}, a {@link JXG.Line} (the distance of start and end point of the\n * line will determine the radius), or another {@link JXG.Circle}.\n * @example\n * // Create a circle providing two points\n * var p1 = board.create('point', [2.0, 2.0]),\n * p2 = board.create('point', [2.0, 0.0]),\n * c1 = board.create('circle', [p1, p2]);\n *\n * // Create another circle using the above circle\n * var p3 = board.create('point', [3.0, 2.0]),\n * c2 = board.create('circle', [p3, c1]);\n * </pre><div class=\"jxgbox\" id=\"JXG5f304d31-ef20-4a8e-9c0e-ea1a2b6c79e0\" style=\"width: 400px; height: 400px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var cex1_board = JXG.JSXGraph.initBoard('JXG5f304d31-ef20-4a8e-9c0e-ea1a2b6c79e0', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});\n * cex1_p1 = cex1_board.create('point', [2.0, 2.0]),\n * cex1_p2 = cex1_board.create('point', [2.0, 0.0]),\n * cex1_c1 = cex1_board.create('circle', [cex1_p1, cex1_p2]),\n * cex1_p3 = cex1_board.create('point', [3.0, 2.0]),\n * cex1_c2 = cex1_board.create('circle', [cex1_p3, cex1_c1]);\n * })();\n * </script><pre>\n * @example\n * // Create a circle providing two points\n * var p1 = board.create('point', [2.0, 2.0]),\n * c1 = board.create('circle', [p1, 3]);\n *\n * // Create another circle using the above circle\n * var c2 = board.create('circle', [function() { return [p1.X(), p1.Y() + 1];}, function() { return c1.Radius(); }]);\n * </pre><div class=\"jxgbox\" id=\"JXG54165f60-93b9-441d-8979-ac5d0f193020\" style=\"width: 400px; height: 400px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG54165f60-93b9-441d-8979-ac5d0f193020', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});\n * var p1 = board.create('point', [2.0, 2.0]);\n * var c1 = board.create('circle', [p1, 3]);\n *\n * // Create another circle using the above circle\n * var c2 = board.create('circle', [function() { return [p1.X(), p1.Y() + 1];}, function() { return c1.Radius(); }]);\n * })();\n * </script><pre>\n * @example\n * var li = board.create('line', [1,1,1], {strokeColor: '#aaaaaa'});\n * var reflect = board.create('transform', [li], {type: 'reflect'});\n *\n * var c1 = board.create('circle', [[-2,-2], [-2, -1]], {center: {visible:true}});\n * var c2 = board.create('circle', [c1, reflect]);\n * * </pre><div id=\"JXGa2a5a870-5dbb-11e8-9fb9-901b0e1b8723\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXGa2a5a870-5dbb-11e8-9fb9-901b0e1b8723',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var li = board.create('line', [1,1,1], {strokeColor: '#aaaaaa'});\n * var reflect = board.create('transform', [li], {type: 'reflect'});\n *\n * var c1 = board.create('circle', [[-2,-2], [-2, -1]], {center: {visible:true}});\n * var c2 = board.create('circle', [c1, reflect]);\n * })();\n *\n * </script><pre>\n *\n * @example\n * var t = board.create('transform', [2, 1.5], {type: 'scale'});\n * var c1 = board.create('circle', [[1.3, 1.3], [0, 1.3]], {strokeColor: 'black', center: {visible:true}});\n * var c2 = board.create('circle', [c1, t], {strokeColor: 'black'});\n *\n * </pre><div id=\"JXG0686a222-6339-11e8-9fb9-901b0e1b8723\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG0686a222-6339-11e8-9fb9-901b0e1b8723',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var t = board.create('transform', [2, 1.5], {type: 'scale'});\n * var c1 = board.create('circle', [[1.3, 1.3], [0, 1.3]], {strokeColor: 'black', center: {visible:true}});\n * var c2 = board.create('circle', [c1, t], {strokeColor: 'black'});\n *\n * })();\n *\n * </script><pre>\n *\n */\n JXG.createCircle = function (board, parents, attributes) {\n var el, p, i, attr, obj,\n isDraggable = true,\n point_style = ['center', 'point2'];\n\n p = [];\n obj = board.select(parents[0]);\n if (Type.isObject(obj) && obj.elementClass === Const.OBJECT_CLASS_CIRCLE &&\n Type.isTransformationOrArray(parents[1])) {\n\n attr = Type.copyAttributes(attributes, board.options, 'circle');\n // if (!Type.exists(attr.type) || attr.type.toLowerCase() !== 'euclidean') {\n // // Create a circle element from a circle and a Euclidean transformation\n // el = JXG.createCircle(board, [obj.center, function() { return obj.Radius(); }], attr);\n // } else {\n // Create a conic element from a circle and a projective transformation\n el = Conic.createEllipse(board, [obj.center, obj.center, function() { return 2 * obj.Radius(); }], attr);\n // }\n el.addTransform(parents[1]);\n return el;\n\n }\n // Circle defined by points\n for (i = 0; i < parents.length; i++) {\n if (Type.isPointType(board, parents[i])) {\n p = p.concat(Type.providePoints(board, [parents[i]], attributes, 'circle', [point_style[i]]));\n if (p[p.length - 1] === false) {\n throw new Error('JSXGraph: Can\\'t create circle from this type. Please provide a point type.');\n }\n } else {\n p.push(parents[i]);\n }\n }\n\n attr = Type.copyAttributes(attributes, board.options, 'circle');\n\n if (p.length === 2 && Type.isPoint(p[0]) && Type.isPoint(p[1])) {\n // Point/Point\n el = new JXG.Circle(board, 'twoPoints', p[0], p[1], attr);\n } else if ((Type.isNumber(p[0]) || Type.isFunction(p[0]) || Type.isString(p[0])) &&\n Type.isPoint(p[1])) {\n // Number/Point\n el = new JXG.Circle(board, 'pointRadius', p[1], p[0], attr);\n } else if ((Type.isNumber(p[1]) || Type.isFunction(p[1]) || Type.isString(p[1])) &&\n Type.isPoint(p[0])) {\n // Point/Number\n el = new JXG.Circle(board, 'pointRadius', p[0], p[1], attr);\n } else if ((p[0].elementClass === Const.OBJECT_CLASS_CIRCLE) && Type.isPoint(p[1])) {\n // Circle/Point\n el = new JXG.Circle(board, 'pointCircle', p[1], p[0], attr);\n } else if ((p[1].elementClass === Const.OBJECT_CLASS_CIRCLE) && Type.isPoint(p[0])) {\n // Point/Circle\n el = new JXG.Circle(board, 'pointCircle', p[0], p[1], attr);\n } else if ((p[0].elementClass === Const.OBJECT_CLASS_LINE) && Type.isPoint(p[1])) {\n // Line/Point\n el = new JXG.Circle(board, 'pointLine', p[1], p[0], attr);\n } else if ((p[1].elementClass === Const.OBJECT_CLASS_LINE) && Type.isPoint(p[0])) {\n // Point/Line\n el = new JXG.Circle(board, 'pointLine', p[0], p[1], attr);\n } else if (parents.length === 3 && Type.isPoint(p[0]) && Type.isPoint(p[1]) && Type.isPoint(p[2])) {\n // Circle through three points\n // Check if circumcircle element is available\n if (JXG.elements.circumcircle) {\n el = JXG.elements.circumcircle(board, p, attr);\n } else {\n throw new Error('JSXGraph: Can\\'t create circle with three points. Please include the circumcircle element (element/composition).');\n }\n\n } else {\n throw new Error(\"JSXGraph: Can't create circle with parent types '\" +\n (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"'.\" +\n \"\\nPossible parent types: [point,point], [point,number], [point,function], [point,circle], [point,point,point], [circle,transformation]\");\n }\n\n el.isDraggable = isDraggable;\n el.setParents(p);\n el.elType = 'circle';\n for (i = 0; i < p.length; i++) {\n if (Type.isPoint(p[i])) {\n el.inherits.push(p[i]);\n }\n }\n return el;\n };\n\n JXG.registerElement('circle', JXG.createCircle);\n\n return {\n Circle: JXG.Circle,\n createCircle: JXG.createCircle\n };\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG:true, define: true*/\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n jxg\n base/constants\n base/coords\n math/statistics\n utils/type\n base/element\n elements:\n segment\n transform\n */\n\ndefine('base/polygon',[\n 'jxg', 'base/constants', 'base/coords', 'math/statistics', 'math/geometry', 'utils/type', 'base/element'\n], function (JXG, Const, Coords, Statistics, Geometry, Type, GeometryElement) {\n\n \"use strict\";\n\n /**\n * Creates a new instance of JXG.Polygon.\n * @class Polygon stores all style and functional properties that are required\n * to draw and to interactact with a polygon.\n * @param {JXG.Board} board Reference to the board the polygon is to be drawn on.\n * @param {Array} vertices Unique identifiers for the points defining the polygon.\n * Last point must be first point. Otherwise, the first point will be added at the list.\n * @param {Object} attributes An object which contains properties as given in {@link JXG.Options.elements}\n * and {@link JXG.Options.polygon}.\n * @constructor\n * @extends JXG.GeometryElement\n */\n\n JXG.Polygon = function (board, vertices, attributes) {\n this.constructor(board, attributes, Const.OBJECT_TYPE_POLYGON, Const.OBJECT_CLASS_AREA);\n\n var i, l, len, j, p,\n attr_line = Type.copyAttributes(attributes, board.options, 'polygon', 'borders');\n\n this.withLines = attributes.withlines;\n this.attr_line = attr_line;\n\n /**\n * References to the points defining the polygon. The last vertex is the same as the first vertex.\n * @type Array\n */\n this.vertices = [];\n for (i = 0; i < vertices.length; i++) {\n this.vertices[i] = this.board.select(vertices[i]);\n }\n\n // Close the polygon\n if (this.vertices.length > 0 && this.vertices[this.vertices.length - 1].id !== this.vertices[0].id) {\n this.vertices.push(this.vertices[0]);\n }\n\n /**\n * References to the border lines of the polygon.\n * @type Array\n */\n this.borders = [];\n\n if (this.withLines) {\n len = this.vertices.length - 1;\n for (j = 0; j < len; j++) {\n // This sets the \"correct\" labels for the first triangle of a construction.\n i = (j + 1) % len;\n attr_line.id = attr_line.ids && attr_line.ids[i];\n attr_line.name = attr_line.names && attr_line.names[i];\n attr_line.strokecolor = (Type.isArray(attr_line.colors) && attr_line.colors[i % attr_line.colors.length]) ||\n attr_line.strokecolor;\n attr_line.visible = Type.exists(attributes.borders.visible) ? attributes.borders.visible : attributes.visible;\n\n if (attr_line.strokecolor === false) {\n attr_line.strokecolor = 'none';\n }\n\n l = board.create('segment', [this.vertices[i], this.vertices[i + 1]], attr_line);\n l.dump = false;\n this.borders[i] = l;\n l.parentPolygon = this;\n }\n }\n\n this.inherits.push(this.vertices, this.borders);\n\n // Register polygon at board\n // This needs to be done BEFORE the points get this polygon added in their descendants list\n this.id = this.board.setId(this, 'Py');\n\n // Add dependencies: either\n // - add polygon as child to an existing point\n // or\n // - add points (supplied as coordinate arrays by the user and created by Type.providePoints) as children to the polygon\n for (i = 0; i < this.vertices.length - 1; i++) {\n p = this.board.select(this.vertices[i]);\n if (Type.exists(p._is_new)) {\n this.addChild(p);\n delete p._is_new;\n } else {\n p.addChild(this);\n }\n }\n\n this.board.renderer.drawPolygon(this);\n this.board.finalizeAdding(this);\n\n this.createGradient();\n this.elType = 'polygon';\n\n // create label\n this.createLabel();\n\n this.methodMap = JXG.deepCopy(this.methodMap, {\n borders: 'borders',\n vertices: 'vertices',\n A: 'Area',\n Area: 'Area',\n Perimeter: 'Perimeter',\n L: 'Perimeter',\n Length: 'Perimeter',\n boundingBox: 'boundingBox',\n bounds: 'bounds',\n addPoints: 'addPoints',\n insertPoints: 'insertPoints',\n removePoints: 'removePoints'\n });\n };\n\n JXG.Polygon.prototype = new GeometryElement();\n\n JXG.extend(JXG.Polygon.prototype, /** @lends JXG.Polygon.prototype */ {\n\n /**\n * Decides if a point (x,y) is inside of the polygon.\n * Implements W. Randolf Franklin's pnpoly method.\n *\n * See <a href=\"https://wrf.ecse.rpi.edu/Research/Short_Notes/pnpoly.html\">https://wrf.ecse.rpi.edu/Research/Short_Notes/pnpoly.html</a>.\n *\n * @param {Number} x_in x-coordinate (screen or user coordinates)\n * @param {Number} y_in y-coordinate (screen or user coordinates)\n * @param {Number} coord_type (Optional) the type of coordinates used here.\n * Possible values are <b>JXG.COORDS_BY_USER</b> and <b>JXG.COORDS_BY_SCREEN</b>.\n * Default value is JXG.COORDS_BY_SCREEN\n *\n * @returns {Boolean} if (x,y) is inside of the polygon.\n * @example\n * var pol = board.create('polygon', [[-1,2], [2,2], [-1,4]]);\n * var p = board.create('point', [4, 3]);\n * var txt = board.create('text', [-1, 0.5, function() {\n * return 'Point A is inside of the polygon = ' +\n * pol.pnpoly(p.X(), p.Y(), JXG.COORDS_BY_USER);\n * }]);\n *\n * </pre><div id=\"JXG7f96aec7-4e3d-4ffc-a3f5-d3f967b6691c\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG7f96aec7-4e3d-4ffc-a3f5-d3f967b6691c',\n * {boundingbox: [-2, 5, 5,-2], axis: true, showcopyright: false, shownavigation: false});\n * var pol = board.create('polygon', [[-1,2], [2,2], [-1,4]]);\n * var p = board.create('point', [4, 3]);\n * var txt = board.create('text', [-1, 0.5, function() {\n * \t\treturn 'Point A is inside of the polygon = ' + pol.pnpoly(p.X(), p.Y(), JXG.COORDS_BY_USER);\n * }]);\n *\n * })();\n *\n * </script><pre>\n *\n */\n pnpoly: function(x_in, y_in, coord_type) {\n var i, j, len,\n x, y, crds,\n v = this.vertices,\n isIn = false;\n\n if (coord_type === Const.COORDS_BY_USER) {\n crds = new Coords(Const.COORDS_BY_USER, [x_in, y_in], this.board);\n x = crds.scrCoords[1];\n y = crds.scrCoords[2];\n } else {\n x = x_in;\n y = y_in;\n }\n\n len = this.vertices.length;\n for (i = 0, j = len - 2; i < len - 1; j = i++) {\n if (((v[i].coords.scrCoords[2] > y) !== (v[j].coords.scrCoords[2] > y)) &&\n (x < (v[j].coords.scrCoords[1] - v[i].coords.scrCoords[1]) *\n (y - v[i].coords.scrCoords[2]) / (v[j].coords.scrCoords[2] - v[i].coords.scrCoords[2]) + v[i].coords.scrCoords[1])\n ) {\n isIn = !isIn;\n }\n }\n\n return isIn;\n },\n\n /**\n * Checks whether (x,y) is near the polygon.\n * @param {Number} x Coordinate in x direction, screen coordinates.\n * @param {Number} y Coordinate in y direction, screen coordinates.\n * @returns {Boolean} Returns true, if (x,y) is inside or at the boundary the polygon, otherwise false.\n */\n hasPoint: function (x, y) {\n var i, len;\n\n if (Type.evaluate(this.visProp.hasinnerpoints)) {\n // All points of the polygon trigger hasPoint: inner and boundary points\n if (this.pnpoly(x, y)) {\n return true;\n }\n }\n\n // Only boundary points trigger hasPoint\n // We additionally test the boundary also in case hasInnerPoints.\n // Since even if the above test has failed, the strokewidth may be large and (x, y) may\n // be inside of hasPoint() of a vertices.\n len = this.borders.length;\n for (i = 0; i < len; i++) {\n if (this.borders[i].hasPoint(x, y)) {\n return true;\n }\n }\n\n return false;\n },\n\n /**\n * Uses the boards renderer to update the polygon.\n */\n updateRenderer: function () {\n var i, len; // wasReal,\n\n\n if (!this.needsUpdate) {\n return this;\n }\n\n if (this.visPropCalc.visible) {\n // wasReal = this.isReal;\n\n len = this.vertices.length;\n this.isReal = true;\n for (i = 0; i < len; ++i) {\n if (!this.vertices[i].isReal) {\n this.isReal = false;\n break;\n }\n }\n\n if (//wasReal &&\n !this.isReal) {\n this.updateVisibility(false);\n }\n }\n\n if (this.visPropCalc.visible) {\n this.board.renderer.updatePolygon(this);\n }\n\n /* Update the label if visible. */\n if (this.hasLabel && this.visPropCalc.visible && this.label &&\n this.label.visPropCalc.visible && this.isReal) {\n\n this.label.update();\n this.board.renderer.updateText(this.label);\n }\n\n // Update rendNode display\n this.setDisplayRendNode();\n // if (this.visPropCalc.visible !== this.visPropOld.visible) {\n // this.board.renderer.display(this, this.visPropCalc.visible);\n // this.visPropOld.visible = this.visPropCalc.visible;\n //\n // if (this.hasLabel) {\n // this.board.renderer.display(this.label, this.label.visPropCalc.visible);\n // }\n // }\n\n this.needsUpdate = false;\n return this;\n },\n\n /**\n * return TextAnchor\n */\n getTextAnchor: function () {\n var a, b, x, y, i;\n\n if (this.vertices.length === 0) {\n return new Coords(Const.COORDS_BY_USER, [1, 0, 0], this.board);\n }\n\n a = this.vertices[0].X();\n b = this.vertices[0].Y();\n x = a;\n y = b;\n for (i = 0; i < this.vertices.length; i++) {\n if (this.vertices[i].X() < a) {\n a = this.vertices[i].X();\n }\n\n if (this.vertices[i].X() > x) {\n x = this.vertices[i].X();\n }\n\n if (this.vertices[i].Y() > b) {\n b = this.vertices[i].Y();\n }\n\n if (this.vertices[i].Y() < y) {\n y = this.vertices[i].Y();\n }\n }\n\n return new Coords(Const.COORDS_BY_USER, [(a + x) * 0.5, (b + y) * 0.5], this.board);\n },\n\n getLabelAnchor: JXG.shortcut(JXG.Polygon.prototype, 'getTextAnchor'),\n\n // documented in geometry element\n cloneToBackground: function () {\n var copy = {}, er;\n\n copy.id = this.id + 'T' + this.numTraces;\n this.numTraces++;\n copy.vertices = this.vertices;\n copy.visProp = Type.deepCopy(this.visProp, this.visProp.traceattributes, true);\n copy.visProp.layer = this.board.options.layer.trace;\n copy.board = this.board;\n Type.clearVisPropOld(copy);\n\n copy.visPropCalc = {\n visible: Type.evaluate(copy.visProp.visible)\n };\n\n er = this.board.renderer.enhancedRendering;\n this.board.renderer.enhancedRendering = true;\n this.board.renderer.drawPolygon(copy);\n this.board.renderer.enhancedRendering = er;\n this.traces[copy.id] = copy.rendNode;\n\n return this;\n },\n\n /**\n * Hide the polygon including its border lines. It will still exist but not visible on the board.\n * @param {Boolean} [borderless=false] If set to true, the polygon is treated as a polygon without\n * borders, i.e. the borders will not be hidden.\n */\n hideElement: function (borderless) {\n var i;\n\n JXG.deprecated('Element.hideElement()', 'Element.setDisplayRendNode()');\n\n this.visPropCalc.visible = false;\n this.board.renderer.display(this, false);\n\n if (!borderless) {\n for (i = 0; i < this.borders.length; i++) {\n this.borders[i].hideElement();\n }\n }\n\n if (this.hasLabel && Type.exists(this.label)) {\n this.label.hiddenByParent = true;\n if (this.label.visPropCalc.visible) {\n this.label.hideElement();\n }\n }\n },\n\n /**\n * Make the element visible.\n * @param {Boolean} [borderless=false] If set to true, the polygon is treated as a polygon without\n * borders, i.e. the borders will not be shown.\n */\n showElement: function (borderless) {\n var i;\n\n JXG.deprecated('Element.showElement()', 'Element.setDisplayRendNode()');\n\n this.visPropCalc.visible = true;\n this.board.renderer.display(this, true);\n\n if (!borderless) {\n for (i = 0; i < this.borders.length; i++) {\n this.borders[i].showElement().updateRenderer();\n }\n }\n\n if (Type.exists(this.label) && this.hasLabel && this.label.hiddenByParent) {\n this.label.hiddenByParent = false;\n if (!this.label.visPropCalc.visible) {\n this.label.showElement().updateRenderer();\n }\n }\n return this;\n },\n\n /**\n * Area of (not self-intersecting) polygon\n * @returns {Number} Area of (not self-intersecting) polygon\n */\n Area: function () {\n return Math.abs(Geometry.signedPolygon(this.vertices, true));\n },\n\n /**\n * Perimeter of polygon.\n * @returns {Number} Perimeter of polygon in user units.\n *\n * @example\n * var p = [[0.0, 2.0], [2.0, 1.0], [4.0, 6.0], [1.0, 3.0]];\n *\n * var pol = board.create('polygon', p, {hasInnerPoints: true});\n * var t = board.create('text', [5, 5, function() { return pol.Perimeter(); }]);\n * </pre><div class=\"jxgbox\" id=\"JXGb10b734d-89fc-4b9d-b4a7-e3f0c1c6bf77\" style=\"width: 400px; height: 400px;\"></div>\n * <script type=\"text/javascript\">\n * (function () {\n * var board = JXG.JSXGraph.initBoard('JXGb10b734d-89fc-4b9d-b4a7-e3f0c1c6bf77', {boundingbox: [-1, 9, 9, -1], axis: false, showcopyright: false, shownavigation: false}),\n * p = [[0.0, 2.0], [2.0, 1.0], [4.0, 6.0], [1.0, 4.0]],\n * cc1 = board.create('polygon', p, {hasInnerPoints: true}),\n * t = board.create('text', [5, 5, function() { return cc1.Perimeter(); }]);\n * })();\n * </script><pre>\n *\n */\n Perimeter: function() {\n var i,\n len = this.vertices.length,\n val = 0.0;\n\n for (i = 1; i < len; ++i) {\n val += this.vertices[i].Dist(this.vertices[i - 1]);\n }\n\n return val;\n },\n\n /**\n * Bounding box of a polygon. The bounding box is an array of four numbers: the first two numbers\n * determine the upper left corner, the last two number determine the lower right corner of the bounding box.\n *\n * The width and height of a polygon can then determined like this:\n * @example\n * var box = polygon.boundingBox();\n * var width = box[2] - box[0];\n * var height = box[1] - box[3];\n *\n * @returns {Array} Array containing four numbers: [minX, maxY, maxX, minY]\n */\n boundingBox: function () {\n var box = [0, 0, 0, 0], i, v,\n le = this.vertices.length - 1;\n\n if (le === 0) {\n return box;\n }\n box[0] = this.vertices[0].X();\n box[2] = box[0];\n box[1] = this.vertices[0].Y();\n box[3] = box[1];\n\n for (i = 1; i < le; ++i) {\n v = this.vertices[i].X();\n if (v < box[0]) {\n box[0] = v;\n } else if (v > box[2]) {\n box[2] = v;\n }\n\n v = this.vertices[i].Y();\n if (v > box[1]) {\n box[1] = v;\n } else if (v < box[3]) {\n box[3] = v;\n }\n }\n\n return box;\n },\n\n // Already documented in GeometryElement\n bounds: function () {\n return this.boundingBox();\n },\n\n /**\n * This method removes the SVG or VML nodes of the lines and the filled area from the renderer, to remove\n * the object completely you should use {@link JXG.Board#removeObject}.\n *\n * @private\n */\n remove: function () {\n var i;\n\n for (i = 0; i < this.borders.length; i++) {\n this.board.removeObject(this.borders[i]);\n }\n\n GeometryElement.prototype.remove.call(this);\n },\n\n /**\n * Finds the index to a given point reference.\n * @param {JXG.Point} p Reference to an element of type {@link JXG.Point}\n * @returns {Number} Index of the point or -1.\n */\n findPoint: function (p) {\n var i;\n\n if (!Type.isPoint(p)) {\n return -1;\n }\n\n for (i = 0; i < this.vertices.length; i++) {\n if (this.vertices[i].id === p.id) {\n return i;\n }\n }\n\n return -1;\n },\n\n /**\n * Add more points to the polygon. The new points will be inserted at the end.\n * The attributes of new border segments are set to the same values\n * as those used when the polygon was created.\n * If new vertices are supplied by coordinates, the default attributes of polygon\n * vertices are taken as their attributes. Therefore, the visual attributes of\n * new vertices and borders may have to be adapted afterwards.\n * @param {JXG.Point} p Arbitrary number of points or coordinate arrays\n * @returns {JXG.Polygon} Reference to the polygon\n * @example\n * const board = JXG.JSXGraph.initBoard('jxgbox', {axis:true});\n * var pg = board.create('polygon', [[1,2], [3,4], [-3,1]], {hasInnerPoints: true});\n * var newPoint = board.create('point', [-1, -1]);\n * var newPoint2 = board.create('point', [-1, -2]);\n * pg.addPoints(newPoint, newPoint2, [1, -2]);\n *\n * </pre><div id=\"JXG70eb0fd2-d20f-4ba9-9ab6-0eac92aabfa5\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG70eb0fd2-d20f-4ba9-9ab6-0eac92aabfa5',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * const board = JXG.JSXGraph.initBoard('jxgbox', {axis:true});\n * var pg = board.create('polygon', [[1,2], [3,4], [-3,1]], {hasInnerPoints: true});\n * var newPoint = board.create('point', [-1, -1]);\n * var newPoint2 = board.create('point', [-1, -2]);\n * pg.addPoints(newPoint, newPoint2, [1, -2]);\n *\n * })();\n *\n * </script><pre>\n *\n */\n addPoints: function (p) {\n var args = Array.prototype.slice.call(arguments);\n\n return this.insertPoints.apply(this, [this.vertices.length - 2].concat(args));\n },\n\n /**\n * Insert points to the vertex list of the polygon after index <tt><idx</tt>.\n * The attributes of new border segments are set to the same values\n * as those used when the polygon was created.\n * If new vertices are supplied by coordinates, the default attributes of polygon\n * vertices are taken as their attributes. Therefore, the visual attributes of\n * new vertices and borders may have to be adapted afterwards.\n *\n * @param {Number} idx The position after which the new vertices are inserted.\n * Setting idx to -1 inserts the new points at the front, i.e. at position 0.\n * @param {JXG.Point} p Arbitrary number of points or coordinate arrays to insert.\n * @returns {JXG.Polygon} Reference to the polygon object\n *\n * @example\n * const board = JXG.JSXGraph.initBoard('jxgbox', {axis:true});\n * var pg = board.create('polygon', [[1,2], [3,4], [-3,1]], {hasInnerPoints: true});\n * var newPoint = board.create('point', [-1, -1]);\n * pg.insertPoints(0, newPoint, newPoint, [1, -2]);\n *\n * </pre><div id=\"JXG17b84b2a-a851-4e3f-824f-7f6a60f166ca\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG17b84b2a-a851-4e3f-824f-7f6a60f166ca',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * const board = JXG.JSXGraph.initBoard('jxgbox', {axis:true});\n * var pg = board.create('polygon', [[1,2], [3,4], [-3,1]], {hasInnerPoints: true});\n * var newPoint = board.create('point', [-1, -1]);\n * pg.insertPoints(0, newPoint, newPoint, [1, -2]);\n *\n * })();\n *\n * </script><pre>\n *\n */\n insertPoints: function (idx, p) {\n var i, le;\n\n if (arguments.length === 0) {\n return this;\n }\n\n\n if (idx < -1 || idx > this.vertices.length - 2) {\n return this;\n }\n\n le = arguments.length - 1;\n for (i = 1; i < le + 1; i++) {\n this.vertices.splice(idx + i, 0,\n Type.providePoints(this.board, [arguments[i]], {}, 'polygon', ['vertices'])[0]\n );\n }\n if (idx === -1) {\n this.vertices[this.vertices.length - 1] = this.vertices[0];\n }\n if (this.withLines) {\n if (idx < 0) {\n this.borders[this.borders.length - 1].point2 = this.vertices[this.vertices.length - 1];\n } else {\n this.borders[idx].point2 = this.vertices[idx + 1];\n }\n for (i = idx + 1; i < idx + 1 + le; i++) {\n this.borders.splice(i, 0,\n this.board.create('segment', [this.vertices[i], this.vertices[i + 1]], this.attr_line)\n );\n }\n }\n this.board.update();\n\n return this;\n },\n\n /**\n * Removes given set of vertices from the polygon\n * @param {JXG.Point} p Arbitrary number of vertices as {@link JXG.Point} elements or index numbers\n * @returns {JXG.Polygon} Reference to the polygon\n */\n removePoints: function (p) {\n var i, j, idx, nvertices = [], nborders = [],\n nidx = [], partition = [];\n\n // Partition:\n // in order to keep the borders which could be recycled, we have to partition\n // the set of removed points. I.e. if the points 1, 2, 5, 6, 7, 10 are removed,\n // the partitions are\n // 1-2, 5-7, 10-10\n // this gives us the borders, that can be removed and the borders we have to create.\n\n\n // Remove the last vertex which is identical to the first\n this.vertices = this.vertices.slice(0, this.vertices.length - 1);\n\n // Collect all valid parameters as indices in nidx\n for (i = 0; i < arguments.length; i++) {\n idx = arguments[i];\n if (Type.isPoint(idx)) {\n idx = this.findPoint(idx);\n }\n\n if (Type.isNumber(idx) && idx > -1 && idx < this.vertices.length && Type.indexOf(nidx, idx) === -1) {\n nidx.push(idx);\n }\n }\n\n // Remove the polygon from each removed point's children\n for (i = 0; i < nidx.length; i++) {\n this.vertices[nidx[i]].removeChild(this);\n }\n\n // Sort the elements to be eliminated\n nidx = nidx.sort();\n nvertices = this.vertices.slice();\n nborders = this.borders.slice();\n\n // Initialize the partition\n if (this.withLines) {\n partition.push([nidx[nidx.length - 1]]);\n }\n\n // Run through all existing vertices and copy all remaining ones to nvertices,\n // compute the partition\n for (i = nidx.length - 1; i > -1; i--) {\n nvertices[nidx[i]] = -1;\n\n if (this.withLines && (nidx[i] - 1 > nidx[i - 1])) {\n partition[partition.length - 1][1] = nidx[i];\n partition.push([nidx[i - 1]]);\n }\n }\n\n // Finalize the partition computation\n if (this.withLines) {\n partition[partition.length - 1][1] = nidx[0];\n }\n\n // Update vertices\n this.vertices = [];\n for (i = 0; i < nvertices.length; i++) {\n if (Type.isPoint(nvertices[i])) {\n this.vertices.push(nvertices[i]);\n }\n }\n if (this.vertices[this.vertices.length - 1].id !== this.vertices[0].id) {\n this.vertices.push(this.vertices[0]);\n }\n\n // Delete obsolete and create missing borders\n if (this.withLines) {\n for (i = 0; i < partition.length; i++) {\n for (j = partition[i][1] - 1; j < partition[i][0] + 1; j++) {\n // special cases\n if (j < 0) {\n // first vertex is removed, so the last border has to be removed, too\n j = 0;\n this.board.removeObject(this.borders[nborders.length - 1]);\n nborders[nborders.length - 1] = -1;\n } else if (j > nborders.length - 1) {\n j = nborders.length - 1;\n }\n\n this.board.removeObject(this.borders[j]);\n nborders[j] = -1;\n }\n\n // only create the new segment if it's not the closing border. the closing border is getting a special treatment at the end\n // the if clause is newer than the min/max calls inside createSegment; i'm sure this makes the min/max calls obsolete, but\n // just to be sure...\n if (partition[i][1] !== 0 && partition[i][0] !== nvertices.length - 1) {\n nborders[partition[i][0] - 1] = this.board.create('segment', [nvertices[Math.max(partition[i][1] - 1, 0)], nvertices[Math.min(partition[i][0] + 1, this.vertices.length - 1)]], this.attr_line);\n }\n }\n\n this.borders = [];\n for (i = 0; i < nborders.length; i++) {\n if (nborders[i] !== -1) {\n this.borders.push(nborders[i]);\n }\n }\n\n // if the first and/or the last vertex is removed, the closing border is created at the end.\n if (partition[0][1] === this.vertices.length - 1 || partition[partition.length - 1][1] === 0) {\n this.borders.push(this.board.create('segment', [this.vertices[0], this.vertices[this.vertices.length - 2]], this.attr_line));\n }\n }\n\n this.board.update();\n\n return this;\n },\n\n // documented in element.js\n getParents: function () {\n this.setParents(this.vertices);\n return this.parents;\n },\n\n getAttributes: function () {\n var attr = GeometryElement.prototype.getAttributes.call(this), i;\n\n if (this.withLines) {\n attr.lines = attr.lines || {};\n attr.lines.ids = [];\n attr.lines.colors = [];\n\n for (i = 0; i < this.borders.length; i++) {\n attr.lines.ids.push(this.borders[i].id);\n attr.lines.colors.push(this.borders[i].visProp.strokecolor);\n }\n }\n\n return attr;\n },\n\n snapToGrid: function () {\n var i, force;\n\n if (Type.evaluate(this.visProp.snaptogrid)) {\n force = true;\n } else {\n force = false;\n }\n\n for (i = 0; i < this.vertices.length; i++) {\n this.vertices[i].handleSnapToGrid(force, true);\n }\n\n },\n\n /**\n * Moves the polygon by the difference of two coordinates.\n * @param {Number} method The type of coordinates used here. Possible values are {@link JXG.COORDS_BY_USER} and {@link JXG.COORDS_BY_SCREEN}.\n * @param {Array} coords coordinates in screen/user units\n * @param {Array} oldcoords previous coordinates in screen/user units\n * @returns {JXG.Polygon} this element\n */\n setPositionDirectly: function (method, coords, oldcoords) {\n var dc, t, i, len,\n c = new Coords(method, coords, this.board),\n oldc = new Coords(method, oldcoords, this.board);\n\n len = this.vertices.length - 1;\n for (i = 0; i < len; i++) {\n if (!this.vertices[i].draggable()) {\n return this;\n }\n }\n\n dc = Statistics.subtract(c.usrCoords, oldc.usrCoords);\n t = this.board.create('transform', dc.slice(1), {type: 'translate'});\n t.applyOnce(this.vertices.slice(0, -1));\n\n return this;\n },\n\n /**\n * Algorithm by Sutherland and Hodgman to compute the intersection of two convex polygons.\n * The polygon itself is the clipping polygon, it expects as parameter a polygon to be clipped.\n * See <a href=\"https://en.wikipedia.org/wiki/Sutherland%E2%80%93Hodgman_algorithm\">wikipedia entry</a>.\n * Called by {@link JXG.Polygon#intersect}.\n *\n * @private\n *\n * @param {JXG.Polygon} polygon Polygon which will be clipped.\n *\n * @returns {Array} of (normalized homogeneous user) coordinates (i.e. [z, x, y], where z==1 in most cases,\n * representing the vertices of the intersection polygon.\n *\n */\n sutherlandHodgman: function(polygon) {\n // First the two polygons are sorted counter clockwise\n var clip = JXG.Math.Geometry.sortVertices(this.vertices), // \"this\" is the clipping polygon\n subject = JXG.Math.Geometry.sortVertices(polygon.vertices), // \"polygon\" is the subject polygon\n\n lenClip = clip.length - 1,\n lenSubject = subject.length - 1,\n lenIn,\n\n outputList = [],\n inputList, i, j, S, E, cross,\n\n // Determines if the point c3 is right of the line through c1 and c2.\n // Since the polygons are sorted counter clockwise, \"right of\" and therefore >= is needed here\n isInside = function(c1, c2, c3) {\n return ((c2[1] - c1[1]) * (c3[2] - c1[2]) - (c2[2] - c1[2]) * (c3[1] - c1[1])) >= 0;\n };\n\n for (i = 0; i < lenSubject; i++) {\n outputList.push(subject[i]);\n }\n\n for (i = 0; i < lenClip; i++) {\n inputList = outputList.slice(0);\n lenIn = inputList.length;\n outputList = [];\n\n S = inputList[lenIn - 1];\n\n for (j = 0; j < lenIn; j++) {\n E = inputList[j];\n if (isInside(clip[i], clip[i + 1], E)) {\n if (!isInside(clip[i], clip[i + 1], S)) {\n cross = JXG.Math.Geometry.meetSegmentSegment(S, E, clip[i], clip[i + 1]);\n cross[0][1] /= cross[0][0];\n cross[0][2] /= cross[0][0];\n cross[0][0] = 1;\n outputList.push(cross[0]);\n }\n outputList.push(E);\n } else if (isInside(clip[i], clip[i + 1], S)) {\n cross = JXG.Math.Geometry.meetSegmentSegment(S, E, clip[i], clip[i + 1]);\n cross[0][1] /= cross[0][0];\n cross[0][2] /= cross[0][0];\n cross[0][0] = 1;\n outputList.push(cross[0]);\n }\n S = E;\n }\n }\n\n return outputList;\n },\n\n /**\n * Generic method for the intersection of this polygon with another polygon.\n * The parent object is the clipping polygon, it expects as parameter a polygon to be clipped.\n * Both polygons have to be convex.\n * Calls the algorithm by Sutherland, Hodgman, {@link JXG.Polygon#sutherlandHodgman}.\n * <p>\n * An alternative is to use the methods from {@link JXG.Math.Clip}, where the algorithm by Greiner and Hormann\n * is used.\n *\n * @param {JXG.Polygon} polygon Polygon which will be clipped.\n *\n * @returns {Array} of (normalized homogeneous user) coordinates (i.e. [z, x, y], where z==1 in most cases,\n * representing the vertices of the intersection polygon.\n *\n * @example\n * // Static intersection of two polygons pol1 and pol2\n * var pol1 = board.create('polygon', [[-2, 3], [-4, -3], [2, 0], [4, 4]], {\n * name:'pol1', withLabel: true,\n * fillColor: 'yellow'\n * });\n * var pol2 = board.create('polygon', [[-2, -3], [-4, 1], [0, 4], [5, 1]], {\n * name:'pol2', withLabel: true\n * });\n *\n * // Static version:\n * // the intersection polygon does not adapt to changes of pol1 or pol2.\n * var pol3 = board.create('polygon', pol1.intersect(pol2), {fillColor: 'blue'});\n * </pre><div class=\"jxgbox\" id=\"JXGd1fe5ea9-309f-494a-af07-ee3d033acb7c\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXGd1fe5ea9-309f-494a-af07-ee3d033acb7c', {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * // Intersect two polygons pol1 and pol2\n * var pol1 = board.create('polygon', [[-2, 3], [-4, -3], [2, 0], [4, 4]], {\n * name:'pol1', withLabel: true,\n * fillColor: 'yellow'\n * });\n * var pol2 = board.create('polygon', [[-2, -3], [-4, 1], [0, 4], [5, 1]], {\n * name:'pol2', withLabel: true\n * });\n *\n * // Static version: the intersection polygon does not adapt to changes of pol1 or pol2.\n * var pol3 = board.create('polygon', pol1.intersect(pol2), {fillColor: 'blue'});\n * })();\n * </script><pre>\n *\n * @example\n * // Dynamic intersection of two polygons pol1 and pol2\n * var pol1 = board.create('polygon', [[-2, 3], [-4, -3], [2, 0], [4, 4]], {\n * name:'pol1', withLabel: true,\n * fillColor: 'yellow'\n * });\n * var pol2 = board.create('polygon', [[-2, -3], [-4, 1], [0, 4], [5, 1]], {\n * name:'pol2', withLabel: true\n * });\n *\n * // Dynamic version:\n * // the intersection polygon does adapt to changes of pol1 or pol2.\n * // For this a curve element is used.\n * var curve = board.create('curve', [[],[]], {fillColor: 'blue', fillOpacity: 0.4});\n * curve.updateDataArray = function() {\n * var mat = JXG.Math.transpose(pol1.intersect(pol2));\n *\n * if (mat.length == 3) {\n * this.dataX = mat[1];\n * this.dataY = mat[2];\n * } else {\n * this.dataX = [];\n * this.dataY = [];\n * }\n * };\n * board.update();\n * </pre><div class=\"jxgbox\" id=\"JXGf870d516-ca1a-4140-8fe3-5d64fb42e5f2\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXGf870d516-ca1a-4140-8fe3-5d64fb42e5f2', {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * // Intersect two polygons pol1 and pol2\n * var pol1 = board.create('polygon', [[-2, 3], [-4, -3], [2, 0], [4, 4]], {\n * name:'pol1', withLabel: true,\n * fillColor: 'yellow'\n * });\n * var pol2 = board.create('polygon', [[-2, -3], [-4, 1], [0, 4], [5, 1]], {\n * name:'pol2', withLabel: true\n * });\n *\n * // Dynamic version:\n * // the intersection polygon does adapt to changes of pol1 or pol2.\n * // For this a curve element is used.\n * var curve = board.create('curve', [[],[]], {fillColor: 'blue', fillOpacity: 0.4});\n * curve.updateDataArray = function() {\n * var mat = JXG.Math.transpose(pol1.intersect(pol2));\n *\n * if (mat.length == 3) {\n * this.dataX = mat[1];\n * this.dataY = mat[2];\n * } else {\n * this.dataX = [];\n * this.dataY = [];\n * }\n * };\n * board.update();\n * })();\n * </script><pre>\n *\n */\n intersect: function(polygon) {\n return this.sutherlandHodgman(polygon);\n }\n\n\n });\n\n\n /**\n * @class A polygon is an area enclosed by a set of border lines which are determined by\n * <ul>\n * <li> a list of points or\n * <li> a list of coordinate arrays or\n * <li> a function returning a list of coordinate arrays.\n * </ul>\n * Each two consecutive points of the list define a line.\n * @pseudo\n * @constructor\n * @name Polygon\n * @type Polygon\n * @augments JXG.Polygon\n * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {Array} vertices The polygon's vertices. If the first and the last vertex don't match the first one will be\n * added to the array by the creator. Here, two points match if they have the same 'id' attribute.\n *\n * Additionally, a polygon can be created by providing a polygon and a transformation (or an array of transformations).\n * The result is a polygon which is the transformation of the supplied polygon.\n *\n * @example\n * var p1 = board.create('point', [0.0, 2.0]);\n * var p2 = board.create('point', [2.0, 1.0]);\n * var p3 = board.create('point', [4.0, 6.0]);\n * var p4 = board.create('point', [1.0, 4.0]);\n *\n * var pol = board.create('polygon', [p1, p2, p3, p4]);\n * </pre><div class=\"jxgbox\" id=\"JXG682069e9-9e2c-4f63-9b73-e26f8a2b2bb1\" style=\"width: 400px; height: 400px;\"></div>\n * <script type=\"text/javascript\">\n * (function () {\n * var board = JXG.JSXGraph.initBoard('JXG682069e9-9e2c-4f63-9b73-e26f8a2b2bb1', {boundingbox: [-1, 9, 9, -1], axis: false, showcopyright: false, shownavigation: false}),\n * p1 = board.create('point', [0.0, 2.0]),\n * p2 = board.create('point', [2.0, 1.0]),\n * p3 = board.create('point', [4.0, 6.0]),\n * p4 = board.create('point', [1.0, 4.0]),\n * cc1 = board.create('polygon', [p1, p2, p3, p4]);\n * })();\n * </script><pre>\n *\n * @example\n * var p = [[0.0, 2.0], [2.0, 1.0], [4.0, 6.0], [1.0, 3.0]];\n *\n * var pol = board.create('polygon', p, {hasInnerPoints: true});\n * </pre><div class=\"jxgbox\" id=\"JXG9f9a5946-112a-4768-99ca-f30792bcdefb\" style=\"width: 400px; height: 400px;\"></div>\n * <script type=\"text/javascript\">\n * (function () {\n * var board = JXG.JSXGraph.initBoard('JXG9f9a5946-112a-4768-99ca-f30792bcdefb', {boundingbox: [-1, 9, 9, -1], axis: false, showcopyright: false, shownavigation: false}),\n * p = [[0.0, 2.0], [2.0, 1.0], [4.0, 6.0], [1.0, 4.0]],\n * cc1 = board.create('polygon', p, {hasInnerPoints: true});\n * })();\n * </script><pre>\n *\n * @example\n * var f1 = function() { return [0.0, 2.0]; },\n * f2 = function() { return [2.0, 1.0]; },\n * f3 = function() { return [4.0, 6.0]; },\n * f4 = function() { return [1.0, 4.0]; },\n * cc1 = board.create('polygon', [f1, f2, f3, f4]);\n * board.update();\n *\n * </pre><div class=\"jxgbox\" id=\"JXGceb09915-b783-44db-adff-7877ae3534c8\" style=\"width: 400px; height: 400px;\"></div>\n * <script type=\"text/javascript\">\n * (function () {\n * var board = JXG.JSXGraph.initBoard('JXGceb09915-b783-44db-adff-7877ae3534c8', {boundingbox: [-1, 9, 9, -1], axis: false, showcopyright: false, shownavigation: false}),\n * f1 = function() { return [0.0, 2.0]; },\n * f2 = function() { return [2.0, 1.0]; },\n * f3 = function() { return [4.0, 6.0]; },\n * f4 = function() { return [1.0, 4.0]; },\n * cc1 = board.create('polygon', [f1, f2, f3, f4]);\n * board.update();\n * })();\n * </script><pre>\n *\n * @example\n * var t = board.create('transform', [2, 1.5], {type: 'scale'});\n * var a = board.create('point', [-3,-2], {name: 'a'});\n * var b = board.create('point', [-1,-4], {name: 'b'});\n * var c = board.create('point', [-2,-0.5], {name: 'c'});\n * var pol1 = board.create('polygon', [a,b,c], {vertices: {withLabel: false}});\n * var pol2 = board.create('polygon', [pol1, t], {vertices: {withLabel: true}});\n *\n * </pre><div id=\"JXG6530a69c-6339-11e8-9fb9-901b0e1b8723\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG6530a69c-6339-11e8-9fb9-901b0e1b8723',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var t = board.create('transform', [2, 1.5], {type: 'scale'});\n * var a = board.create('point', [-3,-2], {name: 'a'});\n * var b = board.create('point', [-1,-4], {name: 'b'});\n * var c = board.create('point', [-2,-0.5], {name: 'c'});\n * var pol1 = board.create('polygon', [a,b,c], {vertices: {withLabel: false}});\n * var pol2 = board.create('polygon', [pol1, t], {vertices: {withLabel: true}});\n *\n * })();\n *\n * </script><pre>\n *\n */\n JXG.createPolygon = function (board, parents, attributes) {\n var el, i, le, obj,\n points = [],\n attr, attr_points,\n is_transform = false;\n\n attr = Type.copyAttributes(attributes, board.options, 'polygon');\n obj = board.select(parents[0]);\n if (obj === null) {\n // This is necessary if the original polygon is defined in another board.\n obj = parents[0];\n }\n if (Type.isObject(obj) && obj.type === Const.OBJECT_TYPE_POLYGON &&\n Type.isTransformationOrArray(parents[1])) {\n\n is_transform = true;\n le = obj.vertices.length - 1;\n attr_points = Type.copyAttributes(attributes, board.options, 'polygon', 'vertices');\n for (i = 0; i < le; i++) {\n if (attr_points.withlabel) {\n attr_points.name = (obj.vertices[i].name === '') ? '' : (obj.vertices[i].name + \"'\");\n }\n points.push(board.create('point', [obj.vertices[i], parents[1]], attr_points));\n }\n } else {\n points = Type.providePoints(board, parents, attributes, 'polygon', ['vertices']);\n if (points === false) {\n throw new Error(\"JSXGraph: Can't create polygon / polygonalchain with parent types other than 'point' and 'coordinate arrays' or a function returning an array of coordinates. Alternatively, a polygon and a transformation can be supplied\");\n }\n }\n\n attr = Type.copyAttributes(attributes, board.options, 'polygon');\n el = new JXG.Polygon(board, points, attr);\n el.isDraggable = true;\n\n // Put the points to their position\n if (is_transform) {\n el.prepareUpdate().update().updateVisibility().updateRenderer();\n le = obj.vertices.length - 1;\n for (i = 0; i < le; i++) {\n points[i].prepareUpdate().update().updateVisibility().updateRenderer();\n }\n }\n\n return el;\n };\n\n /**\n * @class Constructs a regular polygon. It needs two points which define the base line and the number of vertices.\n * @pseudo\n * @description Constructs a regular polygon. It needs two points which define the base line and the number of vertices, or a set of points.\n * @constructor\n * @name RegularPolygon\n * @type Polygon\n * @augments Polygon\n * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {JXG.Point_JXG.Point_Number} p1,p2,n The constructed regular polygon has n vertices and the base line defined by p1 and p2.\n * @example\n * var p1 = board.create('point', [0.0, 2.0]);\n * var p2 = board.create('point', [2.0, 1.0]);\n *\n * var pol = board.create('regularpolygon', [p1, p2, 5]);\n * </pre><div class=\"jxgbox\" id=\"JXG682069e9-9e2c-4f63-9b73-e26f8a2b2bb1\" style=\"width: 400px; height: 400px;\"></div>\n * <script type=\"text/javascript\">\n * (function () {\n * var board = JXG.JSXGraph.initBoard('JXG682069e9-9e2c-4f63-9b73-e26f8a2b2bb1', {boundingbox: [-1, 9, 9, -1], axis: false, showcopyright: false, shownavigation: false}),\n * p1 = board.create('point', [0.0, 2.0]),\n * p2 = board.create('point', [2.0, 1.0]),\n * cc1 = board.create('regularpolygon', [p1, p2, 5]);\n * })();\n * </script><pre>\n * @example\n * var p1 = board.create('point', [0.0, 2.0]);\n * var p2 = board.create('point', [4.0,4.0]);\n * var p3 = board.create('point', [2.0,0.0]);\n *\n * var pol = board.create('regularpolygon', [p1, p2, p3]);\n * </pre><div class=\"jxgbox\" id=\"JXG096a78b3-bd50-4bac-b958-3be5e7df17ed\" style=\"width: 400px; height: 400px;\"></div>\n * <script type=\"text/javascript\">\n * (function () {\n * var board = JXG.JSXGraph.initBoard('JXG096a78b3-bd50-4bac-b958-3be5e7df17ed', {boundingbox: [-1, 9, 9, -1], axis: false, showcopyright: false, shownavigation: false}),\n * p1 = board.create('point', [0.0, 2.0]),\n * p2 = board.create('point', [4.0, 4.0]),\n * p3 = board.create('point', [2.0,0.0]),\n * cc1 = board.create('regularpolygon', [p1, p2, p3]);\n * })();\n * </script><pre>\n *\n * @example\n * // Line of reflection\n * var li = board.create('line', [1,1,1], {strokeColor: '#aaaaaa'});\n * var reflect = board.create('transform', [li], {type: 'reflect'});\n * var pol1 = board.create('polygon', [[-3,-2], [-1,-4], [-2,-0.5]]);\n * var pol2 = board.create('polygon', [pol1, reflect]);\n *\n * </pre><div id=\"JXG58fc3078-d8d1-11e7-93b3-901b0e1b8723\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG58fc3078-d8d1-11e7-93b3-901b0e1b8723',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var li = board.create('line', [1,1,1], {strokeColor: '#aaaaaa'});\n * var reflect = board.create('transform', [li], {type: 'reflect'});\n * var pol1 = board.create('polygon', [[-3,-2], [-1,-4], [-2,-0.5]]);\n * var pol2 = board.create('polygon', [pol1, reflect]);\n *\n * })();\n *\n * </script><pre>\n *\n */\n JXG.createRegularPolygon = function (board, parents, attributes) {\n var el, i, n,\n p = [], rot, len, pointsExist, attr;\n\n len = parents.length;\n n = parents[len - 1];\n\n if (Type.isNumber(n) && (parents.length !== 3 || n < 3)) {\n throw new Error(\"JSXGraph: A regular polygon needs two point types and a number > 2 as input.\");\n }\n\n if (Type.isNumber(board.select(n))) { // Regular polygon given by 2 points and a number\n len--;\n pointsExist = false;\n } else { // Regular polygon given by n points\n n = len;\n pointsExist = true;\n }\n\n p = Type.providePoints(board, parents.slice(0, len), attributes, 'regularpolygon', ['vertices']);\n if (p === false) {\n throw new Error(\"JSXGraph: Can't create regular polygon with parent types other than 'point' and 'coordinate arrays' or a function returning an array of coordinates\");\n }\n\n attr = Type.copyAttributes(attributes, board.options, 'regularpolygon', 'vertices');\n for (i = 2; i < n; i++) {\n rot = board.create('transform', [Math.PI * (2 - (n - 2) / n), p[i - 1]], {type: 'rotate'});\n if (pointsExist) {\n p[i].addTransform(p[i - 2], rot);\n p[i].fullUpdate();\n } else {\n if (Type.isArray(attr.ids) && attr.ids.length >= n - 2) {\n attr.id = attr.ids[i - 2];\n }\n p[i] = board.create('point', [p[i - 2], rot], attr);\n p[i].type = Const.OBJECT_TYPE_CAS;\n\n // The next two lines of code are needed to make regular polygones draggable\n // The new helper points are set to be draggable.\n p[i].isDraggable = true;\n p[i].visProp.fixed = false;\n }\n }\n\n attr = Type.copyAttributes(attributes, board.options, 'regularpolygon');\n el = board.create('polygon', p, attr);\n el.elType = 'regularpolygon';\n\n return el;\n };\n\n /**\n * @class A polygonal chain is a connected series of line segments determined by\n * <ul>\n * <li> a list of points or\n * <li> a list of coordinate arrays or\n * <li> a function returning a list of coordinate arrays.\n * </ul>\n * Each two consecutive points of the list define a line.\n * In JSXGraph, a polygonal chain is simply realized as polygon without the last - closing - point.\n * This may lead to unexpected results. Polygonal chains can be distinguished from polygons by the attribute 'elType' which\n * is 'polygonalchain' for the first and 'polygon' for the latter.\n * @pseudo\n * @constructor\n * @name PolygonalChain\n * @type Polygon\n * @augments JXG.Polygon\n * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {Array} vertices The polygon's vertices.\n *\n * Additionally, a polygonal chain can be created by providing a polygonal chain and a transformation (or an array of transformations).\n * The result is a polygonal chain which is the transformation of the supplied polygona chain.\n *\n * @example\n * var attr = {\n * snapToGrid: true\n * },\n * p = [];\n *\n * \tp.push(board.create('point', [-4, 0], attr));\n * \tp.push(board.create('point', [-1, -3], attr));\n * \tp.push(board.create('point', [0, 2], attr));\n * \tp.push(board.create('point', [2, 1], attr));\n * \tp.push(board.create('point', [4, -2], attr));\n *\n * var chain = board.create('polygonalchain', p, {borders: {strokeWidth: 3}});\n *\n * </pre><div id=\"JXG878f93d8-3e49-46cf-aca2-d3bb7d60c5ae\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG878f93d8-3e49-46cf-aca2-d3bb7d60c5ae',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var attr = {\n * snapToGrid: true\n * },\n * p = [];\n *\n * \tp.push(board.create('point', [-4, 0], attr));\n * \tp.push(board.create('point', [-1, -3], attr));\n * \tp.push(board.create('point', [0, 2], attr));\n * \tp.push(board.create('point', [2, 1], attr));\n * \tp.push(board.create('point', [4, -2], attr));\n *\n * var chain = board.create('polygonalchain', p, {borders: {strokeWidth: 3}});\n *\n * })();\n *\n * </script><pre>\n *\n */\n JXG.createPolygonalChain = function (board, parents, attributes) {\n var attr, el;\n\n attr = Type.copyAttributes(attributes, board.options, 'polygonalchain');\n el = board.create('polygon', parents, attr);\n el.elType = 'polygonalchain';\n\n // A polygonal chain is not necessarily closed.\n el.vertices.pop();\n board.removeObject(el.borders[el.borders.length - 1]);\n el.borders.pop();\n\n return el;\n };\n\n JXG.registerElement('polygon', JXG.createPolygon);\n JXG.registerElement('regularpolygon', JXG.createRegularPolygon);\n JXG.registerElement('polygonalchain', JXG.createPolygonalChain);\n\n return {\n Polygon: JXG.Polygon,\n createPolygon: JXG.createPolygon,\n createRegularPolygon: JXG.createRegularPolygon\n };\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true*/\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n jxg\n base/constants\n base/coords\n base/element\n math/math\n math/geometry\n math/statistics\n math/numerics\n parser/geonext\n utils/type\n elements:\n transform\n */\n\n/**\n * @fileoverview In this file the geometry element Curve is defined.\n */\n\ndefine('base/curve',[\n 'jxg', 'base/constants', 'base/coords', 'base/element', 'math/math', 'math/numerics',\n 'math/plot', 'math/geometry', 'parser/geonext', 'utils/type', 'math/qdt'\n], function (JXG, Const, Coords, GeometryElement, Mat, Numerics, Plot, Geometry, GeonextParser, Type, QDT) {\n\n \"use strict\";\n\n /**\n * Curves are the common object for function graphs, parametric curves, polar curves, and data plots.\n * @class Creates a new curve object. Do not use this constructor to create a curve. Use {@link JXG.Board#create} with\n * type {@link Curve}, or {@link Functiongraph} instead.\n * @augments JXG.GeometryElement\n * @param {String|JXG.Board} board The board the new curve is drawn on.\n * @param {Array} parents defining terms An array with the functon terms or the data points of the curve.\n * @param {Object} attributes Defines the visual appearance of the curve.\n * @see JXG.Board#generateName\n * @see JXG.Board#addCurve\n */\n JXG.Curve = function (board, parents, attributes) {\n this.constructor(board, attributes, Const.OBJECT_TYPE_CURVE, Const.OBJECT_CLASS_CURVE);\n\n this.points = [];\n /**\n * Number of points on curves. This value changes\n * between numberPointsLow and numberPointsHigh.\n * It is set in {@link JXG.Curve#updateCurve}.\n */\n this.numberPoints = Type.evaluate(this.visProp.numberpointshigh);\n\n this.bezierDegree = 1;\n\n /**\n * Array holding the x-coordinates of a data plot.\n * This array can be updated during run time by overwriting\n * the method {@link JXG.Curve#updateDataArray}.\n * @type array\n */\n this.dataX = null;\n\n /**\n * Array holding the y-coordinates of a data plot.\n * This array can be updated during run time by overwriting\n * the method {@link JXG.Curve#updateDataArray}.\n * @type array\n */\n this.dataY = null;\n\n /**\n * Array of ticks storing all the ticks on this curve. Do not set this field directly and use\n * {@link JXG.Curve#addTicks} and {@link JXG.Curve#removeTicks} to add and remove ticks to and\n * from the curve.\n * @type Array\n * @see JXG.Ticks\n */\n this.ticks = [];\n\n /**\n * Stores a quad tree if it is required. The quad tree is generated in the curve\n * updates and can be used to speed up the hasPoint method.\n * @type JXG.Math.Quadtree\n */\n this.qdt = null;\n\n if (Type.exists(parents[0])) {\n this.varname = parents[0];\n } else {\n this.varname = 'x';\n }\n\n // function graphs: \"x\"\n this.xterm = parents[1];\n // function graphs: e.g. \"x^2\"\n this.yterm = parents[2];\n\n // Converts GEONExT syntax into JavaScript syntax\n this.generateTerm(this.varname, this.xterm, this.yterm, parents[3], parents[4]);\n // First evaluation of the curve\n this.updateCurve();\n\n this.id = this.board.setId(this, 'G');\n this.board.renderer.drawCurve(this);\n\n this.board.finalizeAdding(this);\n\n this.createGradient();\n this.elType = 'curve';\n this.createLabel();\n\n if (Type.isString(this.xterm)) {\n this.notifyParents(this.xterm);\n }\n if (Type.isString(this.yterm)) {\n this.notifyParents(this.yterm);\n }\n\n this.methodMap = Type.deepCopy(this.methodMap, {\n generateTerm: 'generateTerm',\n setTerm: 'generateTerm',\n move: 'moveTo',\n moveTo: 'moveTo'\n });\n };\n\n JXG.Curve.prototype = new GeometryElement();\n\n JXG.extend(JXG.Curve.prototype, /** @lends JXG.Curve.prototype */ {\n\n /**\n * Gives the default value of the left bound for the curve.\n * May be overwritten in {@link JXG.Curve#generateTerm}.\n * @returns {Number} Left bound for the curve.\n */\n minX: function () {\n var leftCoords;\n\n if (Type.evaluate(this.visProp.curvetype) === 'polar') {\n return 0;\n }\n\n leftCoords = new Coords(Const.COORDS_BY_SCREEN, [-this.board.canvasWidth * 0.1, 0], this.board, false);\n return leftCoords.usrCoords[1];\n },\n\n /**\n * Gives the default value of the right bound for the curve.\n * May be overwritten in {@link JXG.Curve#generateTerm}.\n * @returns {Number} Right bound for the curve.\n */\n maxX: function () {\n var rightCoords;\n\n if (Type.evaluate(this.visProp.curvetype) === 'polar') {\n return 2 * Math.PI;\n }\n rightCoords = new Coords(Const.COORDS_BY_SCREEN, [this.board.canvasWidth * 1.1, 0], this.board, false);\n\n return rightCoords.usrCoords[1];\n },\n\n /**\n * The parametric function which defines the x-coordinate of the curve.\n * @param {Number} t A number between {@link JXG.Curve#minX} and {@link JXG.Curve#maxX}.\n * @param {Boolean} suspendUpdate A boolean flag which is false for the\n * first call of the function during a fresh plot of the curve and true\n * for all subsequent calls of the function. This may be used to speed up the\n * plotting of the curve, if the e.g. the curve depends on some input elements.\n * @returns {Number} x-coordinate of the curve at t.\n */\n X: function (t) {\n return NaN;\n },\n\n /**\n * The parametric function which defines the y-coordinate of the curve.\n * @param {Number} t A number between {@link JXG.Curve#minX} and {@link JXG.Curve#maxX}.\n * @param {Boolean} suspendUpdate A boolean flag which is false for the\n * first call of the function during a fresh plot of the curve and true\n * for all subsequent calls of the function. This may be used to speed up the\n * plotting of the curve, if the e.g. the curve depends on some input elements.\n * @returns {Number} y-coordinate of the curve at t.\n */\n Y: function (t) {\n return NaN;\n },\n\n /**\n * Treat the curve as curve with homogeneous coordinates.\n * @param {Number} t A number between {@link JXG.Curve#minX} and {@link JXG.Curve#maxX}.\n * @returns {Number} Always 1.0\n */\n Z: function (t) {\n return 1;\n },\n\n /**\n * Checks whether (x,y) is near the curve.\n * @param {Number} x Coordinate in x direction, screen coordinates.\n * @param {Number} y Coordinate in y direction, screen coordinates.\n * @param {Number} start Optional start index for search on data plots.\n * @returns {Boolean} True if (x,y) is near the curve, False otherwise.\n */\n hasPoint: function (x, y, start) {\n var t, checkPoint, len, invMat, c,\n i, tX, tY,\n res = [],\n points, qdt,\n steps = Type.evaluate(this.visProp.numberpointslow),\n d = (this.maxX() - this.minX()) / steps,\n prec, type,\n dist = Infinity,\n ux2, uy2,\n ev_ct,\n mi, ma,\n suspendUpdate = true;\n\n\n if (Type.isObject(Type.evaluate(this.visProp.precision))) {\n type = this.board._inputDevice;\n prec = Type.evaluate(this.visProp.precision[type]);\n } else {\n // 'inherit'\n prec = this.board.options.precision.hasPoint;\n }\n checkPoint = new Coords(Const.COORDS_BY_SCREEN, [x, y], this.board, false);\n x = checkPoint.usrCoords[1];\n y = checkPoint.usrCoords[2];\n\n // We use usrCoords. Only in the final distance calculation\n // screen coords are used\n prec += Type.evaluate(this.visProp.strokewidth) * 0.5;\n prec *= prec; // We do not want to take sqrt\n ux2 = this.board.unitX * this.board.unitX;\n uy2 = this.board.unitY * this.board.unitY;\n\n mi = this.minX();\n ma = this.maxX();\n if (Type.exists(this._visibleArea)) {\n mi = this._visibleArea[0];\n ma = this._visibleArea[1];\n d = (ma - mi) / steps;\n }\n\n ev_ct = Type.evaluate(this.visProp.curvetype);\n if (ev_ct === 'parameter' || ev_ct === 'polar') {\n if (this.transformations.length > 0) {\n /**\n * Transform the mouse/touch coordinates\n * back to the original position of the curve.\n */\n this.updateTransformMatrix();\n invMat = Mat.inverse(this.transformMat);\n c = Mat.matVecMult(invMat, [1, x, y]);\n x = c[1];\n y = c[2];\n }\n\n // Brute force search for a point on the curve close to the mouse pointer\n for (i = 0, t = mi; i < steps; i++) {\n tX = this.X(t, suspendUpdate);\n tY = this.Y(t, suspendUpdate);\n\n dist = (x - tX) * (x - tX) * ux2 + (y - tY) * (y - tY) * uy2;\n\n if (dist <= prec) {\n return true;\n }\n\n t += d;\n }\n } else if (ev_ct === 'plot' ||\n ev_ct === 'functiongraph') {\n\n if (!Type.exists(start) || start < 0) {\n start = 0;\n }\n\n if (Type.exists(this.qdt) &&\n Type.evaluate(this.visProp.useqdt) &&\n this.bezierDegree !== 3\n ) {\n qdt = this.qdt.query(new Coords(Const.COORDS_BY_USER, [x, y], this.board));\n points = qdt.points;\n len = points.length;\n } else {\n points = this.points;\n len = this.numberPoints - 1;\n }\n\n for (i = start; i < len; i++) {\n if (this.bezierDegree === 3) {\n res.push(Geometry.projectCoordsToBeziersegment([1, x, y], this, i));\n } else {\n if (qdt) {\n if (points[i].prev) {\n res = Geometry.projectCoordsToSegment(\n [1, x, y],\n points[i].prev.usrCoords,\n points[i].usrCoords\n );\n }\n\n // If the next point in the array is the same as the current points\n // next neighbor we don't have to project it onto that segment because\n // that will already be done in the next iteration of this loop.\n if (points[i].next && points[i + 1] !== points[i].next) {\n res = Geometry.projectCoordsToSegment(\n [1, x, y],\n points[i].usrCoords,\n points[i].next.usrCoords\n );\n }\n } else {\n res = Geometry.projectCoordsToSegment(\n [1, x, y],\n points[i].usrCoords,\n points[i + 1].usrCoords\n );\n }\n }\n\n if (res[1] >= 0 && res[1] <= 1 &&\n (x - res[0][1]) * (x - res[0][1]) * ux2 +\n (y - res[0][2]) * (y - res[0][2]) * uy2 <= prec) {\n return true;\n }\n }\n return false;\n }\n return (dist < prec);\n },\n\n /**\n * Allocate points in the Coords array this.points\n */\n allocatePoints: function () {\n var i, len;\n\n len = this.numberPoints;\n\n if (this.points.length < this.numberPoints) {\n for (i = this.points.length; i < len; i++) {\n this.points[i] = new Coords(Const.COORDS_BY_USER, [0, 0], this.board, false);\n }\n }\n },\n\n /**\n * Computes for equidistant points on the x-axis the values of the function\n * @returns {JXG.Curve} Reference to the curve object.\n * @see JXG.Curve#updateCurve\n */\n update: function () {\n if (this.needsUpdate) {\n if (Type.evaluate(this.visProp.trace)) {\n this.cloneToBackground(true);\n }\n this.updateCurve();\n }\n\n return this;\n },\n\n /**\n * Updates the visual contents of the curve.\n * @returns {JXG.Curve} Reference to the curve object.\n */\n updateRenderer: function () {\n //var wasReal;\n\n if (!this.needsUpdate) {\n return this;\n }\n\n if (this.visPropCalc.visible) {\n // wasReal = this.isReal;\n\n this.isReal = Plot.checkReal(this.points);\n\n if (//wasReal &&\n !this.isReal) {\n this.updateVisibility(false);\n }\n }\n\n if (this.visPropCalc.visible) {\n this.board.renderer.updateCurve(this);\n }\n\n /* Update the label if visible. */\n if (this.hasLabel && this.visPropCalc.visible && this.label &&\n this.label.visPropCalc.visible && this.isReal) {\n\n this.label.update();\n this.board.renderer.updateText(this.label);\n }\n\n // Update rendNode display\n this.setDisplayRendNode();\n // if (this.visPropCalc.visible !== this.visPropOld.visible) {\n // this.board.renderer.display(this, this.visPropCalc.visible);\n // this.visPropOld.visible = this.visPropCalc.visible;\n //\n // if (this.hasLabel) {\n // this.board.renderer.display(this.label, this.label.visPropCalc.visible);\n // }\n // }\n\n this.needsUpdate = false;\n return this;\n },\n\n /**\n * For dynamic dataplots updateCurve can be used to compute new entries\n * for the arrays {@link JXG.Curve#dataX} and {@link JXG.Curve#dataY}. It\n * is used in {@link JXG.Curve#updateCurve}. Default is an empty method, can\n * be overwritten by the user.\n *\n *\n * @example\n * // This example overwrites the updateDataArray method.\n * // There, new values for the arrays JXG.Curve.dataX and JXG.Curve.dataY\n * // are computed from the value of the slider N\n *\n * var N = board.create('slider', [[0,1.5],[3,1.5],[1,3,40]], {name:'n',snapWidth:1});\n * var circ = board.create('circle',[[4,-1.5],1],{strokeWidth:1, strokecolor:'black', strokeWidth:2,\n * \t\tfillColor:'#0055ff13'});\n *\n * var c = board.create('curve', [[0],[0]],{strokecolor:'red', strokeWidth:2});\n * c.updateDataArray = function() {\n * var r = 1, n = Math.floor(N.Value()),\n * x = [0], y = [0],\n * phi = Math.PI/n,\n * h = r*Math.cos(phi),\n * s = r*Math.sin(phi),\n * i, j,\n * px = 0, py = 0, sgn = 1,\n * d = 16,\n * dt = phi/d,\n * pt;\n *\n * for (i = 0; i < n; i++) {\n * for (j = -d; j <= d; j++) {\n * pt = dt*j;\n * x.push(px + r*Math.sin(pt));\n * y.push(sgn*r*Math.cos(pt) - (sgn-1)*h*0.5);\n * }\n * px += s;\n * sgn *= (-1);\n * }\n * x.push((n - 1)*s);\n * y.push(h + (sgn - 1)*h*0.5);\n * this.dataX = x;\n * this.dataY = y;\n * }\n *\n * var c2 = board.create('curve', [[0],[0]],{strokecolor:'red', strokeWidth:1});\n * c2.updateDataArray = function() {\n * var r = 1, n = Math.floor(N.Value()),\n * px = circ.midpoint.X(), py = circ.midpoint.Y(),\n * x = [px], y = [py],\n * phi = Math.PI/n,\n * s = r*Math.sin(phi),\n * i, j,\n * d = 16,\n * dt = phi/d,\n * pt = Math.PI*0.5+phi;\n *\n * for (i = 0; i < n; i++) {\n * for (j= -d; j <= d; j++) {\n * x.push(px + r*Math.cos(pt));\n * y.push(py + r*Math.sin(pt));\n * pt -= dt;\n * }\n * x.push(px);\n * y.push(py);\n * pt += dt;\n * }\n * this.dataX = x;\n * this.dataY = y;\n * }\n * board.update();\n *\n * </pre><div id=\"JXG20bc7802-e69e-11e5-b1bf-901b0e1b8723\" class=\"jxgbox\" style=\"width: 600px; height: 400px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG20bc7802-e69e-11e5-b1bf-901b0e1b8723',\n * {boundingbox: [-1.5,2,8,-3], keepaspectratio: true, axis: true, showcopyright: false, shownavigation: false});\n * var N = board.create('slider', [[0,1.5],[3,1.5],[1,3,40]], {name:'n',snapWidth:1});\n * var circ = board.create('circle',[[4,-1.5],1],{strokeWidth:1, strokecolor:'black',\n * strokeWidth:2, fillColor:'#0055ff13'});\n *\n * var c = board.create('curve', [[0],[0]],{strokecolor:'red', strokeWidth:2});\n * c.updateDataArray = function() {\n * var r = 1, n = Math.floor(N.Value()),\n * x = [0], y = [0],\n * phi = Math.PI/n,\n * h = r*Math.cos(phi),\n * s = r*Math.sin(phi),\n * i, j,\n * px = 0, py = 0, sgn = 1,\n * d = 16,\n * dt = phi/d,\n * pt;\n *\n * for (i=0;i<n;i++) {\n * for (j=-d;j<=d;j++) {\n * pt = dt*j;\n * x.push(px+r*Math.sin(pt));\n * y.push(sgn*r*Math.cos(pt)-(sgn-1)*h*0.5);\n * }\n * px += s;\n * sgn *= (-1);\n * }\n * x.push((n-1)*s);\n * y.push(h+(sgn-1)*h*0.5);\n * this.dataX = x;\n * this.dataY = y;\n * }\n *\n * var c2 = board.create('curve', [[0],[0]],{strokecolor:'red', strokeWidth:1});\n * c2.updateDataArray = function() {\n * var r = 1, n = Math.floor(N.Value()),\n * px = circ.midpoint.X(), py = circ.midpoint.Y(),\n * x = [px], y = [py],\n * phi = Math.PI/n,\n * s = r*Math.sin(phi),\n * i, j,\n * d = 16,\n * dt = phi/d,\n * pt = Math.PI*0.5+phi;\n *\n * for (i=0;i<n;i++) {\n * for (j=-d;j<=d;j++) {\n * x.push(px+r*Math.cos(pt));\n * y.push(py+r*Math.sin(pt));\n * pt -= dt;\n * }\n * x.push(px);\n * y.push(py);\n * pt += dt;\n * }\n * this.dataX = x;\n * this.dataY = y;\n * }\n * board.update();\n *\n * })();\n *\n * </script><pre>\n *\n * @example\n * // This is an example which overwrites updateDataArray and produces\n * // a Bezier curve of degree three.\n * var A = board.create('point', [-3,3]);\n * var B = board.create('point', [3,-2]);\n * var line = board.create('segment', [A,B]);\n *\n * var height = 0.5; // height of the curly brace\n *\n * // Curly brace\n * var crl = board.create('curve', [[0],[0]], {strokeWidth:1, strokeColor:'black'});\n * crl.bezierDegree = 3;\n * crl.updateDataArray = function() {\n * var d = [B.X()-A.X(), B.Y()-A.Y()],\n * dl = Math.sqrt(d[0]*d[0]+d[1]*d[1]),\n * mid = [(A.X()+B.X())*0.5, (A.Y()+B.Y())*0.5];\n *\n * d[0] *= height/dl;\n * d[1] *= height/dl;\n *\n * this.dataX = [ A.X(), A.X()-d[1], mid[0], mid[0]-d[1], mid[0], B.X()-d[1], B.X() ];\n * this.dataY = [ A.Y(), A.Y()+d[0], mid[1], mid[1]+d[0], mid[1], B.Y()+d[0], B.Y() ];\n * };\n *\n * // Text\n * var txt = board.create('text', [\n * function() {\n * var d = [B.X()-A.X(), B.Y()-A.Y()],\n * dl = Math.sqrt(d[0]*d[0]+d[1]*d[1]),\n * mid = (A.X()+B.X())*0.5;\n *\n * d[1] *= height/dl;\n * return mid-d[1]+0.1;\n * },\n * function() {\n * var d = [B.X()-A.X(), B.Y()-A.Y()],\n * dl = Math.sqrt(d[0]*d[0]+d[1]*d[1]),\n * mid = (A.Y()+B.Y())*0.5;\n *\n * d[0] *= height/dl;\n * return mid+d[0]+0.1;\n * },\n * function() { return \"length=\" + JXG.toFixed(B.Dist(A), 2); }\n * ]);\n *\n *\n * board.update(); // This update is necessary to call updateDataArray the first time.\n *\n * </pre><div id=\"JXGa61a4d66-e69f-11e5-b1bf-901b0e1b8723\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXGa61a4d66-e69f-11e5-b1bf-901b0e1b8723',\n * {boundingbox: [-4, 4, 4,-4], axis: true, showcopyright: false, shownavigation: false});\n * var A = board.create('point', [-3,3]);\n * var B = board.create('point', [3,-2]);\n * var line = board.create('segment', [A,B]);\n *\n * var height = 0.5; // height of the curly brace\n *\n * // Curly brace\n * var crl = board.create('curve', [[0],[0]], {strokeWidth:1, strokeColor:'black'});\n * crl.bezierDegree = 3;\n * crl.updateDataArray = function() {\n * var d = [B.X()-A.X(), B.Y()-A.Y()],\n * dl = Math.sqrt(d[0]*d[0]+d[1]*d[1]),\n * mid = [(A.X()+B.X())*0.5, (A.Y()+B.Y())*0.5];\n *\n * d[0] *= height/dl;\n * d[1] *= height/dl;\n *\n * this.dataX = [ A.X(), A.X()-d[1], mid[0], mid[0]-d[1], mid[0], B.X()-d[1], B.X() ];\n * this.dataY = [ A.Y(), A.Y()+d[0], mid[1], mid[1]+d[0], mid[1], B.Y()+d[0], B.Y() ];\n * };\n *\n * // Text\n * var txt = board.create('text', [\n * function() {\n * var d = [B.X()-A.X(), B.Y()-A.Y()],\n * dl = Math.sqrt(d[0]*d[0]+d[1]*d[1]),\n * mid = (A.X()+B.X())*0.5;\n *\n * d[1] *= height/dl;\n * return mid-d[1]+0.1;\n * },\n * function() {\n * var d = [B.X()-A.X(), B.Y()-A.Y()],\n * dl = Math.sqrt(d[0]*d[0]+d[1]*d[1]),\n * mid = (A.Y()+B.Y())*0.5;\n *\n * d[0] *= height/dl;\n * return mid+d[0]+0.1;\n * },\n * function() { return \"length=\"+JXG.toFixed(B.Dist(A), 2); }\n * ]);\n *\n *\n * board.update(); // This update is necessary to call updateDataArray the first time.\n *\n * })();\n *\n * </script><pre>\n *\n *\n */\n updateDataArray: function () {\n // this used to return this, but we shouldn't rely on the user to implement it.\n },\n\n /**\n * Computes the curve path\n * @see JXG.Curve#update\n * @returns {JXG.Curve} Reference to the curve object.\n */\n updateCurve: function () {\n var len, mi, ma, x, y, i,\n version = this.visProp.plotversion,\n //t1, t2, l1,\n suspendUpdate = false;\n\n this.updateTransformMatrix();\n this.updateDataArray();\n mi = this.minX();\n ma = this.maxX();\n\n // Discrete data points\n // x-coordinates are in an array\n if (Type.exists(this.dataX)) {\n this.numberPoints = this.dataX.length;\n len = this.numberPoints;\n\n // It is possible, that the array length has increased.\n this.allocatePoints();\n\n for (i = 0; i < len; i++) {\n x = i;\n\n // y-coordinates are in an array\n if (Type.exists(this.dataY)) {\n y = i;\n // The last parameter prevents rounding in usr2screen().\n this.points[i].setCoordinates(Const.COORDS_BY_USER, [this.dataX[i], this.dataY[i]], false);\n } else {\n // discrete x data, continuous y data\n y = this.X(x);\n // The last parameter prevents rounding in usr2screen().\n this.points[i].setCoordinates(Const.COORDS_BY_USER, [this.dataX[i], this.Y(y, suspendUpdate)], false);\n }\n this.points[i]._t = i;\n\n // this.updateTransform(this.points[i]);\n suspendUpdate = true;\n }\n // continuous x data\n } else {\n if (Type.evaluate(this.visProp.doadvancedplot)) {\n // console.time(\"plot\");\n\n if (version === 1 || Type.evaluate(this.visProp.doadvancedplotold)) {\n Plot.updateParametricCurveOld(this, mi, ma);\n } else if (version === 2) {\n Plot.updateParametricCurve_v2(this, mi, ma);\n } else if (version === 3) {\n Plot.updateParametricCurve_v3(this, mi, ma);\n } else if (version === 4) {\n Plot.updateParametricCurve_v4(this, mi, ma);\n } else {\n Plot.updateParametricCurve_v2(this, mi, ma);\n }\n // console.timeEnd(\"plot\");\n } else {\n if (this.board.updateQuality === this.board.BOARD_QUALITY_HIGH) {\n this.numberPoints = Type.evaluate(this.visProp.numberpointshigh);\n } else {\n this.numberPoints = Type.evaluate(this.visProp.numberpointslow);\n }\n\n // It is possible, that the array length has increased.\n this.allocatePoints();\n Plot.updateParametricCurveNaive(this, mi, ma, this.numberPoints);\n }\n len = this.numberPoints;\n\n if (Type.evaluate(this.visProp.useqdt) &&\n this.board.updateQuality === this.board.BOARD_QUALITY_HIGH) {\n this.qdt = new QDT(this.board.getBoundingBox());\n for (i = 0; i < this.points.length; i++) {\n this.qdt.insert(this.points[i]);\n\n if (i > 0) {\n this.points[i].prev = this.points[i - 1];\n }\n\n if (i < len - 1) {\n this.points[i].next = this.points[i + 1];\n }\n }\n }\n\n // for (i = 0; i < len; i++) {\n // this.updateTransform(this.points[i]);\n // }\n }\n\n if (Type.evaluate(this.visProp.curvetype) !== 'plot' &&\n Type.evaluate(this.visProp.rdpsmoothing)) {\n // console.time(\"rdp\");\n this.points = Numerics.RamerDouglasPeucker(this.points, 0.2);\n this.numberPoints = this.points.length;\n // console.timeEnd(\"rdp\");\n // console.log(this.numberPoints);\n }\n\n len = this.numberPoints;\n for (i = 0; i < len; i++) {\n this.updateTransform(this.points[i]);\n }\n\n return this;\n },\n\n updateTransformMatrix: function () {\n var t, i,\n len = this.transformations.length;\n\n this.transformMat = [[1, 0, 0], [0, 1, 0], [0, 0, 1]];\n\n for (i = 0; i < len; i++) {\n t = this.transformations[i];\n t.update();\n this.transformMat = Mat.matMatMult(t.matrix, this.transformMat);\n }\n\n return this;\n },\n\n /**\n * Applies the transformations of the curve to the given point <tt>p</tt>.\n * Before using it, {@link JXG.Curve#updateTransformMatrix} has to be called.\n * @param {JXG.Point} p\n * @returns {JXG.Point} The given point.\n */\n updateTransform: function (p) {\n var c,\n len = this.transformations.length;\n\n if (len > 0) {\n c = Mat.matVecMult(this.transformMat, p.usrCoords);\n p.setCoordinates(Const.COORDS_BY_USER, c, false, true);\n }\n\n return p;\n },\n\n /**\n * Add transformations to this curve.\n * @param {JXG.Transformation|Array} transform Either one {@link JXG.Transformation} or an array of {@link JXG.Transformation}s.\n * @returns {JXG.Curve} Reference to the curve object.\n */\n addTransform: function (transform) {\n var i,\n list = Type.isArray(transform) ? transform : [transform],\n len = list.length;\n\n for (i = 0; i < len; i++) {\n this.transformations.push(list[i]);\n }\n\n return this;\n },\n\n /**\n * Generate the method curve.X() in case curve.dataX is an array\n * and generate the method curve.Y() in case curve.dataY is an array.\n * @private\n * @param {String} which Either 'X' or 'Y'\n * @returns {function}\n **/\n interpolationFunctionFromArray: function (which) {\n var data = 'data' + which,\n that = this;\n\n return function (t, suspendedUpdate) {\n var i, j, t0, t1,\n arr = that[data],\n len = arr.length,\n last,\n f = [];\n\n if (isNaN(t)) {\n return NaN;\n }\n\n if (t < 0) {\n if (Type.isFunction(arr[0])) {\n return arr[0]();\n }\n\n return arr[0];\n }\n\n if (that.bezierDegree === 3) {\n last = (len - 1) / 3;\n\n if (t >= last) {\n if (Type.isFunction(arr[arr.length - 1])) {\n return arr[arr.length - 1]();\n }\n\n return arr[arr.length - 1];\n }\n\n i = Math.floor(t) * 3;\n t0 = t % 1;\n t1 = 1 - t0;\n\n for (j = 0; j < 4; j++) {\n if (Type.isFunction(arr[i + j])) {\n f[j] = arr[i + j]();\n } else {\n f[j] = arr[i + j];\n }\n }\n\n return t1 * t1 * (t1 * f[0] + 3 * t0 * f[1]) + (3 * t1 * f[2] + t0 * f[3]) * t0 * t0;\n }\n\n if (t > len - 2) {\n i = len - 2;\n } else {\n i = parseInt(Math.floor(t), 10);\n }\n\n if (i === t) {\n if (Type.isFunction(arr[i])) {\n return arr[i]();\n }\n return arr[i];\n }\n\n for (j = 0; j < 2; j++) {\n if (Type.isFunction(arr[i + j])) {\n f[j] = arr[i + j]();\n } else {\n f[j] = arr[i + j];\n }\n }\n return f[0] + (f[1] - f[0]) * (t - i);\n };\n },\n\n /**\n * Converts the JavaScript/JessieCode/GEONExT syntax of the defining function term into JavaScript.\n * New methods X() and Y() for the Curve object are generated, further\n * new methods for minX() and maxX().\n * @see JXG.GeonextParser.geonext2JS.\n */\n generateTerm: function (varname, xterm, yterm, mi, ma) {\n var fx, fy;\n\n // Generate the methods X() and Y()\n if (Type.isArray(xterm)) {\n // Discrete data\n this.dataX = xterm;\n\n this.numberPoints = this.dataX.length;\n this.X = this.interpolationFunctionFromArray.apply(this, ['X']);\n this.visProp.curvetype = 'plot';\n this.isDraggable = true;\n } else {\n // Continuous data\n this.X = Type.createFunction(xterm, this.board, varname);\n if (Type.isString(xterm)) {\n this.visProp.curvetype = 'functiongraph';\n } else if (Type.isFunction(xterm) || Type.isNumber(xterm)) {\n this.visProp.curvetype = 'parameter';\n }\n\n this.isDraggable = true;\n }\n\n if (Type.isArray(yterm)) {\n this.dataY = yterm;\n this.Y = this.interpolationFunctionFromArray.apply(this, ['Y']);\n } else {\n this.Y = Type.createFunction(yterm, this.board, varname);\n }\n\n /**\n * Polar form\n * Input data is function xterm() and offset coordinates yterm\n */\n if (Type.isFunction(xterm) && Type.isArray(yterm)) {\n // Xoffset, Yoffset\n fx = Type.createFunction(yterm[0], this.board, '');\n fy = Type.createFunction(yterm[1], this.board, '');\n\n this.X = function (phi) {\n return xterm(phi) * Math.cos(phi) + fx();\n };\n\n this.Y = function (phi) {\n return xterm(phi) * Math.sin(phi) + fy();\n };\n\n this.visProp.curvetype = 'polar';\n }\n\n // Set the bounds lower bound\n if (Type.exists(mi)) {\n this.minX = Type.createFunction(mi, this.board, '');\n }\n if (Type.exists(ma)) {\n this.maxX = Type.createFunction(ma, this.board, '');\n }\n },\n\n /**\n * Finds dependencies in a given term and notifies the parents by adding the\n * dependent object to the found objects child elements.\n * @param {String} contentStr String containing dependencies for the given object.\n */\n notifyParents: function (contentStr) {\n var fstr, dep,\n isJessieCode = false,\n obj;\n\n // Read dependencies found by the JessieCode parser\n obj = { 'xterm': 1, 'yterm': 1 };\n for (fstr in obj) {\n if (obj.hasOwnProperty(fstr) && this.hasOwnProperty(fstr) && this[fstr].origin) {\n isJessieCode = true;\n for (dep in this[fstr].origin.deps) {\n if (this[fstr].origin.deps.hasOwnProperty(dep)) {\n this[fstr].origin.deps[dep].addChild(this);\n }\n }\n }\n }\n\n if (!isJessieCode) {\n GeonextParser.findDependencies(this, contentStr, this.board);\n }\n },\n\n // documented in geometry element\n getLabelAnchor: function () {\n var c, x, y,\n ax = 0.05 * this.board.canvasWidth,\n ay = 0.05 * this.board.canvasHeight,\n bx = 0.95 * this.board.canvasWidth,\n by = 0.95 * this.board.canvasHeight;\n\n switch (Type.evaluate(this.visProp.label.position)) {\n case 'ulft':\n x = ax;\n y = ay;\n break;\n case 'llft':\n x = ax;\n y = by;\n break;\n case 'rt':\n x = bx;\n y = 0.5 * by;\n break;\n case 'lrt':\n x = bx;\n y = by;\n break;\n case 'urt':\n x = bx;\n y = ay;\n break;\n case 'top':\n x = 0.5 * bx;\n y = ay;\n break;\n case 'bot':\n x = 0.5 * bx;\n y = by;\n break;\n default:\n // includes case 'lft'\n x = ax;\n y = 0.5 * by;\n }\n\n c = new Coords(Const.COORDS_BY_SCREEN, [x, y], this.board, false);\n return Geometry.projectCoordsToCurve(c.usrCoords[1], c.usrCoords[2], 0, this, this.board)[0];\n },\n\n // documented in geometry element\n cloneToBackground: function () {\n var er,\n copy = {\n id: this.id + 'T' + this.numTraces,\n elementClass: Const.OBJECT_CLASS_CURVE,\n\n points: this.points.slice(0),\n bezierDegree: this.bezierDegree,\n numberPoints: this.numberPoints,\n board: this.board,\n visProp: Type.deepCopy(this.visProp, this.visProp.traceattributes, true)\n };\n\n copy.visProp.layer = this.board.options.layer.trace;\n copy.visProp.curvetype = this.visProp.curvetype;\n this.numTraces++;\n\n Type.clearVisPropOld(copy);\n copy.visPropCalc = {\n visible: Type.evaluate(copy.visProp.visible)\n };\n er = this.board.renderer.enhancedRendering;\n this.board.renderer.enhancedRendering = true;\n this.board.renderer.drawCurve(copy);\n this.board.renderer.enhancedRendering = er;\n this.traces[copy.id] = copy.rendNode;\n\n return this;\n },\n\n // Already documented in GeometryElement\n bounds: function () {\n var minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity,\n l = this.points.length, i,\n bezier, up;\n\n if (this.bezierDegree === 3) {\n // Add methods X(), Y()\n for (i = 0; i < l; i++) {\n this.points[i].X = Type.bind(function () { return this.usrCoords[1]; }, this.points[i]);\n this.points[i].Y = Type.bind(function () { return this.usrCoords[2]; }, this.points[i]);\n }\n bezier = Numerics.bezier(this.points);\n up = bezier[3]();\n minX = Numerics.fminbr(function (t) { return bezier[0](t); }, [0, up]);\n maxX = Numerics.fminbr(function (t) { return -bezier[0](t); }, [0, up]);\n minY = Numerics.fminbr(function (t) { return bezier[1](t); }, [0, up]);\n maxY = Numerics.fminbr(function (t) { return -bezier[1](t); }, [0, up]);\n\n minX = bezier[0](minX);\n maxX = bezier[0](maxX);\n minY = bezier[1](minY);\n maxY = bezier[1](maxY);\n return [minX, maxY, maxX, minY];\n }\n\n // Linear segments\n for (i = 0; i < l; i++) {\n if (minX > this.points[i].usrCoords[1]) {\n minX = this.points[i].usrCoords[1];\n }\n\n if (maxX < this.points[i].usrCoords[1]) {\n maxX = this.points[i].usrCoords[1];\n }\n\n if (minY > this.points[i].usrCoords[2]) {\n minY = this.points[i].usrCoords[2];\n }\n\n if (maxY < this.points[i].usrCoords[2]) {\n maxY = this.points[i].usrCoords[2];\n }\n }\n\n return [minX, maxY, maxX, minY];\n },\n\n // documented in element.js\n getParents: function () {\n var p = [this.xterm, this.yterm, this.minX(), this.maxX()];\n\n if (this.parents.length !== 0) {\n p = this.parents;\n }\n\n return p;\n },\n\n /**\n * Shift the curve by the vector 'where'.\n *\n * @param {Array} where Array containing the x and y coordinate of the target location.\n * @returns {JXG.Curve} Reference to itself.\n */\n moveTo: function (where) {\n // TODO add animation\n var delta = [], p;\n if (this.points.length > 0 && !Type.evaluate(this.visProp.fixed)) {\n p = this.points[0];\n if (where.length === 3) {\n delta = [where[0] - p.usrCoords[0],\n where[1] - p.usrCoords[1],\n where[2] - p.usrCoords[2]];\n } else {\n delta = [where[0] - p.usrCoords[1],\n where[1] - p.usrCoords[2]];\n }\n this.setPosition(Const.COORDS_BY_USER, delta);\n }\n return this;\n },\n\n /**\n * If the curve is the result of a transformation applied\n * to a continuous curve, the glider projection has to be done\n * on the original curve. Otherwise there will be problems\n * when changing between high and low precision plotting,\n * since there number of points changes.\n *\n * @private\n * @returns {Array} [Boolean, curve]: Array contining 'true' if curve is result of a transformation,\n * and the source curve of the transformation.\n */\n getTransformationSource: function () {\n var isTransformed, curve_org;\n if (Type.exists(this._transformationSource)) {\n curve_org = this._transformationSource;\n if (curve_org.elementClass === Const.OBJECT_CLASS_CURVE //&&\n //Type.evaluate(curve_org.visProp.curvetype) !== 'plot'\n ) {\n isTransformed = true;\n }\n }\n return [isTransformed, curve_org];\n }\n\n });\n\n /**\n * @class This element is used to provide a constructor for curve, which is just a wrapper for element {@link Curve}.\n * A curve is a mapping from R to R^2. t mapsto (x(t),y(t)). The graph is drawn for t in the interval [a,b].\n * <p>\n * The following types of curves can be plotted:\n * <ul>\n * <li> parametric curves: t mapsto (x(t),y(t)), where x() and y() are univariate functions.\n * <li> polar curves: curves commonly written with polar equations like spirals and cardioids.\n * <li> data plots: plot line segments through a given list of coordinates.\n * </ul>\n * @pseudo\n * @description\n * @name Curve\n * @augments JXG.Curve\n * @constructor\n * @type JXG.Curve\n *\n * @param {function,number_function,number_function,number_function,number} x,y,a_,b_ Parent elements for Parametric Curves.\n * <p>\n * x describes the x-coordinate of the curve. It may be a function term in one variable, e.g. x(t).\n * In case of x being of type number, x(t) is set to a constant function.\n * this function at the values of the array.\n * </p>\n * <p>\n * y describes the y-coordinate of the curve. In case of a number, y(t) is set to the constant function\n * returning this number.\n * </p>\n * <p>\n * Further parameters are an optional number or function for the left interval border a,\n * and an optional number or function for the right interval border b.\n * </p>\n * <p>\n * Default values are a=-10 and b=10.\n * </p>\n * @param {array_array,function,number} x,y Parent elements for Data Plots.\n * <p>\n * x and y are arrays contining the x and y coordinates of the data points which are connected by\n * line segments. The individual entries of x and y may also be functions.\n * In case of x being an array the curve type is data plot, regardless of the second parameter and\n * if additionally the second parameter y is a function term the data plot evaluates.\n * </p>\n * @param {function_array,function,number_function,number_function,number} r,offset_,a_,b_ Parent elements for Polar Curves.\n * <p>\n * The first parameter is a function term r(phi) describing the polar curve.\n * </p>\n * <p>\n * The second parameter is the offset of the curve. It has to be\n * an array containing numbers or functions describing the offset. Default value is the origin [0,0].\n * </p>\n * <p>\n * Further parameters are an optional number or function for the left interval border a,\n * and an optional number or function for the right interval border b.\n * </p>\n * <p>\n * Default values are a=-10 and b=10.\n * </p>\n * <p>\n * Additionally, a curve can be created by providing a curve and a transformation (or an array of transformations).\n * The result is a curve which is the transformation of the supplied curve.\n *\n * @see JXG.Curve\n * @example\n * // Parametric curve\n * // Create a curve of the form (t-sin(t), 1-cos(t), i.e.\n * // the cycloid curve.\n * var graph = board.create('curve',\n * [function(t){ return t-Math.sin(t);},\n * function(t){ return 1-Math.cos(t);},\n * 0, 2*Math.PI]\n * );\n * </pre><div class=\"jxgbox\" id=\"JXGaf9f818b-f3b6-4c4d-8c4c-e4a4078b726d\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * var c1_board = JXG.JSXGraph.initBoard('JXGaf9f818b-f3b6-4c4d-8c4c-e4a4078b726d', {boundingbox: [-1, 5, 7, -1], axis: true, showcopyright: false, shownavigation: false});\n * var graph1 = c1_board.create('curve', [function(t){ return t-Math.sin(t);},function(t){ return 1-Math.cos(t);},0, 2*Math.PI]);\n * </script><pre>\n * @example\n * // Data plots\n * // Connect a set of points given by coordinates with dashed line segments.\n * // The x- and y-coordinates of the points are given in two separate\n * // arrays.\n * var x = [0,1,2,3,4,5,6,7,8,9];\n * var y = [9.2,1.3,7.2,-1.2,4.0,5.3,0.2,6.5,1.1,0.0];\n * var graph = board.create('curve', [x,y], {dash:2});\n * </pre><div class=\"jxgbox\" id=\"JXG7dcbb00e-b6ff-481d-b4a8-887f5d8c6a83\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * var c3_board = JXG.JSXGraph.initBoard('JXG7dcbb00e-b6ff-481d-b4a8-887f5d8c6a83', {boundingbox: [-1,10,10,-1], axis: true, showcopyright: false, shownavigation: false});\n * var x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];\n * var y = [9.2, 1.3, 7.2, -1.2, 4.0, 5.3, 0.2, 6.5, 1.1, 0.0];\n * var graph3 = c3_board.create('curve', [x,y], {dash:2});\n * </script><pre>\n * @example\n * // Polar plot\n * // Create a curve with the equation r(phi)= a*(1+phi), i.e.\n * // a cardioid.\n * var a = board.create('slider',[[0,2],[2,2],[0,1,2]]);\n * var graph = board.create('curve',\n * [function(phi){ return a.Value()*(1-Math.cos(phi));},\n * [1,0],\n * 0, 2*Math.PI],\n * {curveType: 'polar'}\n * );\n * </pre><div class=\"jxgbox\" id=\"JXGd0bc7a2a-8124-45ca-a6e7-142321a8f8c2\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * var c2_board = JXG.JSXGraph.initBoard('JXGd0bc7a2a-8124-45ca-a6e7-142321a8f8c2', {boundingbox: [-3,3,3,-3], axis: true, showcopyright: false, shownavigation: false});\n * var a = c2_board.create('slider',[[0,2],[2,2],[0,1,2]]);\n * var graph2 = c2_board.create('curve', [function(phi){ return a.Value()*(1-Math.cos(phi));}, [1,0], 0, 2*Math.PI], {curveType: 'polar'});\n * </script><pre>\n *\n * @example\n * // Draggable Bezier curve\n * var col, p, c;\n * col = 'blue';\n * p = [];\n * p.push(board.create('point',[-2, -1 ], {size: 5, strokeColor:col, fillColor:col}));\n * p.push(board.create('point',[1, 2.5 ], {size: 5, strokeColor:col, fillColor:col}));\n * p.push(board.create('point',[-1, -2.5 ], {size: 5, strokeColor:col, fillColor:col}));\n * p.push(board.create('point',[2, -2], {size: 5, strokeColor:col, fillColor:col}));\n *\n * c = board.create('curve', JXG.Math.Numerics.bezier(p),\n * {strokeColor:'red', name:\"curve\", strokeWidth:5, fixed: false}); // Draggable curve\n * c.addParents(p);\n * </pre><div class=\"jxgbox\" id=\"JXG7bcc6280-f6eb-433e-8281-c837c3387849\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function(){\n * var board, col, p, c;\n * board = JXG.JSXGraph.initBoard('JXG7bcc6280-f6eb-433e-8281-c837c3387849', {boundingbox: [-3,3,3,-3], axis: true, showcopyright: false, shownavigation: false});\n * col = 'blue';\n * p = [];\n * p.push(board.create('point',[-2, -1 ], {size: 5, strokeColor:col, fillColor:col}));\n * p.push(board.create('point',[1, 2.5 ], {size: 5, strokeColor:col, fillColor:col}));\n * p.push(board.create('point',[-1, -2.5 ], {size: 5, strokeColor:col, fillColor:col}));\n * p.push(board.create('point',[2, -2], {size: 5, strokeColor:col, fillColor:col}));\n *\n * c = board.create('curve', JXG.Math.Numerics.bezier(p),\n * {strokeColor:'red', name:\"curve\", strokeWidth:5, fixed: false}); // Draggable curve\n * c.addParents(p);\n * })();\n * </script><pre>\n *\n * @example\n * // The curve cu2 is the reflection of cu1 against line li\n * var li = board.create('line', [1,1,1], {strokeColor: '#aaaaaa'});\n * var reflect = board.create('transform', [li], {type: 'reflect'});\n * var cu1 = board.create('curve', [[-1, -1, -0.5, -1, -1, -0.5], [-3, -2, -2, -2, -2.5, -2.5]]);\n * var cu2 = board.create('curve', [cu1, reflect], {strokeColor: 'red'});\n *\n * </pre><div id=\"JXG866dc7a2-d448-11e7-93b3-901b0e1b8723\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG866dc7a2-d448-11e7-93b3-901b0e1b8723',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var li = board.create('line', [1,1,1], {strokeColor: '#aaaaaa'});\n * var reflect = board.create('transform', [li], {type: 'reflect'});\n * var cu1 = board.create('curve', [[-1, -1, -0.5, -1, -1, -0.5], [-3, -2, -2, -2, -2.5, -2.5]]);\n * var cu2 = board.create('curve', [cu1, reflect], {strokeColor: 'red'});\n *\n * })();\n *\n * </script><pre>\n */\n JXG.createCurve = function (board, parents, attributes) {\n var obj, cu,\n attr = Type.copyAttributes(attributes, board.options, 'curve');\n\n obj = board.select(parents[0], true);\n if (Type.isObject(obj) &&\n (obj.type === Const.OBJECT_TYPE_CURVE ||\n obj.type === Const.OBJECT_TYPE_ANGLE ||\n obj.type === Const.OBJECT_TYPE_ARC ||\n obj.type === Const.OBJECT_TYPE_CONIC ||\n obj.type === Const.OBJECT_TYPE_SECTOR) &&\n Type.isTransformationOrArray(parents[1])) {\n\n if (obj.type === Const.OBJECT_TYPE_SECTOR) {\n attr = Type.copyAttributes(attributes, board.options, 'sector');\n } else if (obj.type === Const.OBJECT_TYPE_ARC) {\n attr = Type.copyAttributes(attributes, board.options, 'arc');\n } else if (obj.type === Const.OBJECT_TYPE_ANGLE) {\n if (!Type.exists(attributes.withLabel)) {\n attributes.withLabel = false;\n }\n attr = Type.copyAttributes(attributes, board.options, 'angle');\n } else {\n attr = Type.copyAttributes(attributes, board.options, 'curve');\n }\n attr = Type.copyAttributes(attr, board.options, 'curve');\n\n cu = new JXG.Curve(board, ['x', [], []], attr);\n cu.updateDataArray = function () {\n var i, le = obj.numberPoints;\n this.bezierDegree = obj.bezierDegree;\n this.dataX = [];\n this.dataY = [];\n for (i = 0; i < le; i++) {\n this.dataX.push(obj.points[i].usrCoords[1]);\n this.dataY.push(obj.points[i].usrCoords[2]);\n }\n return this;\n };\n cu.addTransform(parents[1]);\n obj.addChild(cu);\n cu.setParents([obj]);\n cu._transformationSource = obj;\n\n return cu;\n }\n attr = Type.copyAttributes(attributes, board.options, 'curve');\n return new JXG.Curve(board, ['x'].concat(parents), attr);\n };\n\n JXG.registerElement('curve', JXG.createCurve);\n\n /**\n * @class This element is used to provide a constructor for functiongraph,\n * which is just a wrapper for element {@link Curve} with {@link JXG.Curve#X}()\n * set to x. The graph is drawn for x in the interval [a,b].\n * @pseudo\n * @description\n * @name Functiongraph\n * @augments JXG.Curve\n * @constructor\n * @type JXG.Curve\n * @param {function_number,function_number,function} f,a_,b_ Parent elements are a function term f(x) describing the function graph.\n * <p>\n * Further, an optional number or function for the left interval border a,\n * and an optional number or function for the right interval border b.\n * <p>\n * Default values are a=-10 and b=10.\n * @see JXG.Curve\n * @example\n * // Create a function graph for f(x) = 0.5*x*x-2*x\n * var graph = board.create('functiongraph',\n * [function(x){ return 0.5*x*x-2*x;}, -2, 4]\n * );\n * </pre><div class=\"jxgbox\" id=\"JXGefd432b5-23a3-4846-ac5b-b471e668b437\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * var alex1_board = JXG.JSXGraph.initBoard('JXGefd432b5-23a3-4846-ac5b-b471e668b437', {boundingbox: [-3, 7, 5, -3], axis: true, showcopyright: false, shownavigation: false});\n * var graph = alex1_board.create('functiongraph', [function(x){ return 0.5*x*x-2*x;}, -2, 4]);\n * </script><pre>\n * @example\n * // Create a function graph for f(x) = 0.5*x*x-2*x with variable interval\n * var s = board.create('slider',[[0,4],[3,4],[-2,4,5]]);\n * var graph = board.create('functiongraph',\n * [function(x){ return 0.5*x*x-2*x;},\n * -2,\n * function(){return s.Value();}]\n * );\n * </pre><div class=\"jxgbox\" id=\"JXG4a203a84-bde5-4371-ad56-44619690bb50\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * var alex2_board = JXG.JSXGraph.initBoard('JXG4a203a84-bde5-4371-ad56-44619690bb50', {boundingbox: [-3, 7, 5, -3], axis: true, showcopyright: false, shownavigation: false});\n * var s = alex2_board.create('slider',[[0,4],[3,4],[-2,4,5]]);\n * var graph = alex2_board.create('functiongraph', [function(x){ return 0.5*x*x-2*x;}, -2, function(){return s.Value();}]);\n * </script><pre>\n */\n JXG.createFunctiongraph = function (board, parents, attributes) {\n var attr,\n par = ['x', 'x'].concat(parents);\n\n attr = Type.copyAttributes(attributes, board.options, 'curve');\n attr.curvetype = 'functiongraph';\n return new JXG.Curve(board, par, attr);\n };\n\n JXG.registerElement('functiongraph', JXG.createFunctiongraph);\n JXG.registerElement('plot', JXG.createFunctiongraph);\n\n /**\n * @class This element is used to provide a constructor for (natural) cubic spline curves.\n * Create a dynamic spline interpolated curve given by sample points p_1 to p_n.\n * @pseudo\n * @description\n * @name Spline\n * @augments JXG.Curve\n * @constructor\n * @type JXG.Curve\n * @param {JXG.Board} board Reference to the board the spline is drawn on.\n * @param {Array} parents Array of points the spline interpolates. This can be\n * <ul>\n * <li> an array of JXGGraph points</li>\n * <li> an array of coordinate pairs</li>\n * <li> an array of functions returning coordinate pairs</li>\n * <li> an array consisting of an array with x-coordinates and an array of y-coordinates</li>\n * </ul>\n * All individual entries of coordinates arrays may be numbers or functions returning numbers.\n * @param {Object} attributes Define color, width, ... of the spline\n * @returns {JXG.Curve} Returns reference to an object of type JXG.Curve.\n * @see JXG.Curve\n * @example\n *\n * var p = [];\n * p[0] = board.create('point', [-2,2], {size: 4, face: 'o'});\n * p[1] = board.create('point', [0,-1], {size: 4, face: 'o'});\n * p[2] = board.create('point', [2,0], {size: 4, face: 'o'});\n * p[3] = board.create('point', [4,1], {size: 4, face: 'o'});\n *\n * var c = board.create('spline', p, {strokeWidth:3});\n * </pre><div id=\"JXG6c197afc-e482-11e5-b1bf-901b0e1b8723\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG6c197afc-e482-11e5-b1bf-901b0e1b8723',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n *\n * var p = [];\n * p[0] = board.create('point', [-2,2], {size: 4, face: 'o'});\n * p[1] = board.create('point', [0,-1], {size: 4, face: 'o'});\n * p[2] = board.create('point', [2,0], {size: 4, face: 'o'});\n * p[3] = board.create('point', [4,1], {size: 4, face: 'o'});\n *\n * var c = board.create('spline', p, {strokeWidth:3});\n * })();\n *\n * </script><pre>\n *\n */\n JXG.createSpline = function (board, parents, attributes) {\n var el, funcs, ret;\n\n funcs = function () {\n var D, x = [], y = [];\n\n return [function (t, suspended) { // Function term\n var i, j, c;\n\n if (!suspended) {\n x = [];\n y = [];\n\n // given as [x[], y[]]\n if (parents.length === 2 && Type.isArray(parents[0]) && Type.isArray(parents[1]) && parents[0].length === parents[1].length) {\n for (i = 0; i < parents[0].length; i++) {\n if (Type.isFunction(parents[0][i])) {\n x.push(parents[0][i]());\n } else {\n x.push(parents[0][i]);\n }\n\n if (Type.isFunction(parents[1][i])) {\n y.push(parents[1][i]());\n } else {\n y.push(parents[1][i]);\n }\n }\n } else {\n for (i = 0; i < parents.length; i++) {\n if (Type.isPoint(parents[i])) {\n x.push(parents[i].X());\n y.push(parents[i].Y());\n // given as [[x1,y1], [x2, y2], ...]\n } else if (Type.isArray(parents[i]) && parents[i].length === 2) {\n for (j = 0; j < parents.length; j++) {\n if (Type.isFunction(parents[j][0])) {\n x.push(parents[j][0]());\n } else {\n x.push(parents[j][0]);\n }\n\n if (Type.isFunction(parents[j][1])) {\n y.push(parents[j][1]());\n } else {\n y.push(parents[j][1]);\n }\n }\n } else if (Type.isFunction(parents[i]) && parents[i]().length === 2) {\n c = parents[i]();\n x.push(c[0]);\n y.push(c[1]);\n }\n }\n }\n\n // The array D has only to be calculated when the position of one or more sample points\n // changes. Otherwise D is always the same for all points on the spline.\n D = Numerics.splineDef(x, y);\n }\n\n return Numerics.splineEval(t, x, y, D);\n },\n // minX()\n function () {\n return x[0];\n },\n //maxX()\n function () {\n return x[x.length - 1];\n }];\n\n };\n\n attributes = Type.copyAttributes(attributes, board.options, 'curve');\n attributes.curvetype = 'functiongraph';\n ret = funcs();\n el = new JXG.Curve(board, ['x', 'x', ret[0], ret[1], ret[2]], attributes);\n el.setParents(parents);\n el.elType = 'spline';\n\n return el;\n };\n\n /**\n * Register the element type spline at JSXGraph\n * @private\n */\n JXG.registerElement('spline', JXG.createSpline);\n\n /**\n * @class This element is used to provide a constructor for cardinal spline curves.\n * Create a dynamic cardinal spline interpolated curve given by sample points p_1 to p_n.\n * @pseudo\n * @description\n * @name Cardinalspline\n * @augments JXG.Curve\n * @constructor\n * @type JXG.Curve\n * @param {JXG.Board} board Reference to the board the cardinal spline is drawn on.\n * @param {Array} parents Array with three entries.\n * <p>\n * First entry: Array of points the spline interpolates. This can be\n * <ul>\n * <li> an array of JXGGraph points</li>\n * <li> an array of coordinate pairs</li>\n * <li> an array of functions returning coordinate pairs</li>\n * <li> an array consisting of an array with x-coordinates and an array of y-coordinates</li>\n * </ul>\n * All individual entries of coordinates arrays may be numbers or functions returning numbers.\n * <p>\n * Second entry: tau number or function\n * <p>\n * Third entry: type string containing 'uniform' (default) or 'centripetal'.\n * @param {Object} attributes Define color, width, ... of the cardinal spline\n * @returns {JXG.Curve} Returns reference to an object of type JXG.Curve.\n * @see JXG.Curve\n * @example\n * //create a cardinal spline out of an array of JXG points with adjustable tension\n * //create array of points\n * var p1 = board.create('point',[0,0])\n * var p2 = board.create('point',[1,4])\n * var p3 = board.create('point',[4,5])\n * var p4 = board.create('point',[2,3])\n * var p5 = board.create('point',[3,0])\n * var p = [p1,p2,p3,p4,p5]\n *\n * // tension\n * tau = board.create('slider', [[4,3],[9,3],[0.001,0.5,1]], {name:'tau'});\n * c = board.create('curve', JXG.Math.Numerics.CardinalSpline(p, function(){ return tau.Value();}), {strokeWidth:3});\n * </pre><div id=\"JXG6c197afc-e482-11e5-b2af-901b0e1b8723\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG6c197afc-e482-11e5-b2af-901b0e1b8723',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n *\n * var p = [];\n * p[0] = board.create('point', [-2,2], {size: 4, face: 'o'});\n * p[1] = board.create('point', [0,-1], {size: 4, face: 'o'});\n * p[2] = board.create('point', [2,0], {size: 4, face: 'o'});\n * p[3] = board.create('point', [4,1], {size: 4, face: 'o'});\n *\n * var c = board.create('spline', p, {strokeWidth:3});\n * })();\n *\n * </script><pre>\n */\n JXG.createCardinalSpline = function (board, parents, attributes) {\n var el, getPointLike,\n points, tau, type,\n p, q, i, le,\n splineArr,\n errStr = \"\\nPossible parent types: [points:array, tau:number|function, type:string]\";\n\n if (!Type.exists(parents[0]) || !Type.isArray(parents[0])) {\n throw new Error(\"JSXGraph: JXG.createCardinalSpline: argument 1 'points' has to be array of points or coordinate pairs\" + errStr);\n }\n if (!Type.exists(parents[1]) || (!Type.isNumber(parents[1]) && !Type.isFunction(parents[1]))) {\n throw new Error(\"JSXGraph: JXG.createCardinalSpline: argument 2 'tau' has to be number between [0,1] or function'\" + errStr);\n }\n if (!Type.exists(parents[2]) || !Type.isString(parents[2])) {\n throw new Error(\"JSXGraph: JXG.createCardinalSpline: argument 3 'type' has to be string 'uniform' or 'centripetal'\" + errStr);\n }\n\n attributes = Type.copyAttributes(attributes, board.options, 'curve');\n attributes = Type.copyAttributes(attributes, board.options, 'cardinalspline');\n attributes.curvetype = 'parameter';\n\n p = parents[0];\n q = [];\n\n // given as [x[], y[]]\n if (!attributes.isarrayofcoordinates &&\n p.length === 2 && Type.isArray(p[0]) && Type.isArray(p[1]) &&\n p[0].length === p[1].length) {\n for (i = 0; i < p[0].length; i++) {\n q[i] = [];\n if (Type.isFunction(p[0][i])) {\n q[i].push(p[0][i]());\n } else {\n q[i].push(p[0][i]);\n }\n\n if (Type.isFunction(p[1][i])) {\n q[i].push(p[1][i]());\n } else {\n q[i].push(p[1][i]);\n }\n }\n } else {\n // given as [[x0, y0], [x1, y1], point, ...]\n for (i = 0; i < p.length; i++) {\n if (Type.isString(p[i])) {\n q.push(board.select(p[i]));\n } else if (Type.isPoint(p[i])) {\n q.push(p[i]);\n // given as [[x0,y0], [x1, y2], ...]\n } else if (Type.isArray(p[i]) && p[i].length === 2) {\n q[i] = [];\n if (Type.isFunction(p[i][0])) {\n q[i].push(p[i][0]());\n } else {\n q[i].push(p[i][0]);\n }\n\n if (Type.isFunction(p[i][1])) {\n q[i].push(p[i][1]());\n } else {\n q[i].push(p[i][1]);\n }\n } else if (Type.isFunction(p[i]) && p[i]().length === 2) {\n q.push(parents[i]());\n }\n }\n }\n\n if (attributes.createpoints === true) {\n points = Type.providePoints(board, q, attributes, 'cardinalspline', ['points']);\n } else {\n points = [];\n\n /**\n * @ignore\n */\n getPointLike = function (ii) {\n return {\n X: function () { return q[ii][0]; },\n Y: function () { return q[ii][1]; },\n Dist: function (p) {\n var dx = this.X() - p.X(),\n dy = this.Y() - p.Y();\n return Math.sqrt(dx * dx + dy * dy);\n }\n };\n };\n\n for (i = 0; i < q.length; i++) {\n if (Type.isPoint(q[i])) {\n points.push(q[i]);\n } else {\n points.push(getPointLike(i));\n }\n }\n }\n\n tau = parents[1];\n type = parents[2];\n\n splineArr = ['x'].concat(Numerics.CardinalSpline(points, tau, type));\n\n el = new JXG.Curve(board, splineArr, attributes);\n le = points.length;\n el.setParents(points);\n for (i = 0; i < le; i++) {\n p = points[i];\n if (Type.isPoint(p)) {\n if (Type.exists(p._is_new)) {\n el.addChild(p);\n delete p._is_new;\n } else {\n p.addChild(el);\n }\n }\n }\n el.elType = 'cardinalspline';\n\n return el;\n };\n\n /**\n * Register the element type cardinalspline at JSXGraph\n * @private\n */\n JXG.registerElement('cardinalspline', JXG.createCardinalSpline);\n\n /**\n * @class This element is used to provide a constructor for metapost spline curves.\n * Create a dynamic metapost spline interpolated curve given by sample points p_1 to p_n.\n * @pseudo\n * @description\n * @name Metapostspline\n * @augments JXG.Curve\n * @constructor\n * @type JXG.Curve\n * @param {JXG.Board} board Reference to the board the metapost spline is drawn on.\n * @param {Array} parents Array with two entries.\n * <p>\n * First entry: Array of points the spline interpolates. This can be\n * <ul>\n * <li> an array of JXGGraph points</li>\n * <li> an object of coordinate pairs</li>\n * <li> an array of functions returning coordinate pairs</li>\n * <li> an array consisting of an array with x-coordinates and an array of y-coordinates</li>\n * </ul>\n * All individual entries of coordinates arrays may be numbers or functions returning numbers.\n * <p>\n * Second entry: JavaScript object containing the control values like tension, direction, curl.\n * @param {Object} attributes Define color, width, ... of the metapost spline\n * @returns {JXG.Curve} Returns reference to an object of type JXG.Curve.\n * @see JXG.Curve\n * @example\n * var po = [],\n * attr = {\n * size: 5,\n * color: 'red'\n * },\n * controls;\n *\n * var tension = board.create('slider', [[-3, 6], [3, 6], [0, 1, 20]], {name: 'tension'});\n * var curl = board.create('slider', [[-3, 5], [3, 5], [0, 1, 30]], {name: 'curl A, D'});\n * var dir = board.create('slider', [[-3, 4], [3, 4], [-180, 0, 180]], {name: 'direction B'});\n *\n * po.push(board.create('point', [-3, -3]));\n * po.push(board.create('point', [0, -3]));\n * po.push(board.create('point', [4, -5]));\n * po.push(board.create('point', [6, -2]));\n *\n * var controls = {\n * tension: function() {return tension.Value(); },\n * direction: { 1: function() {return dir.Value(); } },\n * curl: { 0: function() {return curl.Value(); },\n * 3: function() {return curl.Value(); }\n * },\n * isClosed: false\n * };\n *\n * // Plot a metapost curve\n * var cu = board.create('metapostspline', [po, controls], {strokeColor: 'blue', strokeWidth: 2});\n *\n *\n * </pre><div id=\"JXGb8c6ffed-7419-41a3-9e55-3754b2327ae9\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXGb8c6ffed-7419-41a3-9e55-3754b2327ae9',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var po = [],\n * attr = {\n * size: 5,\n * color: 'red'\n * },\n * controls;\n *\n * var tension = board.create('slider', [[-3, 6], [3, 6], [0, 1, 20]], {name: 'tension'});\n * var curl = board.create('slider', [[-3, 5], [3, 5], [0, 1, 30]], {name: 'curl A, D'});\n * var dir = board.create('slider', [[-3, 4], [3, 4], [-180, 0, 180]], {name: 'direction B'});\n *\n * po.push(board.create('point', [-3, -3]));\n * po.push(board.create('point', [0, -3]));\n * po.push(board.create('point', [4, -5]));\n * po.push(board.create('point', [6, -2]));\n *\n * var controls = {\n * tension: function() {return tension.Value(); },\n * direction: { 1: function() {return dir.Value(); } },\n * curl: { 0: function() {return curl.Value(); },\n * 3: function() {return curl.Value(); }\n * },\n * isClosed: false\n * };\n *\n * // Plot a metapost curve\n * var cu = board.create('metapostspline', [po, controls], {strokeColor: 'blue', strokeWidth: 2});\n *\n *\n * })();\n *\n * </script><pre>\n *\n */\n JXG.createMetapostSpline = function (board, parents, attributes) {\n var el, getPointLike,\n points, controls,\n p, q, i, le,\n errStr = \"\\nPossible parent types: [points:array, controls:object\";\n\n if (!Type.exists(parents[0]) || !Type.isArray(parents[0])) {\n throw new Error(\"JSXGraph: JXG.createMetapostSpline: argument 1 'points' has to be array of points or coordinate pairs\" + errStr);\n }\n if (!Type.exists(parents[1]) || !Type.isObject(parents[1])) {\n throw new Error(\"JSXGraph: JXG.createMetapostSpline: argument 2 'controls' has to be a JavaScript object'\" + errStr);\n }\n\n attributes = Type.copyAttributes(attributes, board.options, 'curve');\n attributes = Type.copyAttributes(attributes, board.options, 'metapostspline');\n attributes.curvetype = 'parameter';\n\n p = parents[0];\n q = [];\n\n // given as [x[], y[]]\n if (!attributes.isarrayofcoordinates &&\n p.length === 2 && Type.isArray(p[0]) && Type.isArray(p[1]) &&\n p[0].length === p[1].length) {\n for (i = 0; i < p[0].length; i++) {\n q[i] = [];\n if (Type.isFunction(p[0][i])) {\n q[i].push(p[0][i]());\n } else {\n q[i].push(p[0][i]);\n }\n\n if (Type.isFunction(p[1][i])) {\n q[i].push(p[1][i]());\n } else {\n q[i].push(p[1][i]);\n }\n }\n } else {\n // given as [[x0, y0], [x1, y1], point, ...]\n for (i = 0; i < p.length; i++) {\n if (Type.isString(p[i])) {\n q.push(board.select(p[i]));\n } else if (Type.isPoint(p[i])) {\n q.push(p[i]);\n // given as [[x0,y0], [x1, y2], ...]\n } else if (Type.isArray(p[i]) && p[i].length === 2) {\n q[i] = [];\n if (Type.isFunction(p[i][0])) {\n q[i].push(p[i][0]());\n } else {\n q[i].push(p[i][0]);\n }\n\n if (Type.isFunction(p[i][1])) {\n q[i].push(p[i][1]());\n } else {\n q[i].push(p[i][1]);\n }\n } else if (Type.isFunction(p[i]) && p[i]().length === 2) {\n q.push(parents[i]());\n }\n }\n }\n\n if (attributes.createpoints === true) {\n points = Type.providePoints(board, q, attributes, 'metapostspline', ['points']);\n } else {\n points = [];\n\n /**\n * @ignore\n */\n getPointLike = function (ii) {\n return {\n X: function () { return q[ii][0]; },\n Y: function () { return q[ii][1]; }\n };\n };\n\n for (i = 0; i < q.length; i++) {\n if (Type.isPoint(q[i])) {\n points.push(q[i]);\n } else {\n points.push(getPointLike);\n }\n }\n }\n\n controls = parents[1];\n\n el = new JXG.Curve(board, ['t', [], [], 0, p.length - 1], attributes);\n el.updateDataArray = function () {\n var res, i,\n len = points.length,\n p = [];\n\n for (i = 0; i < len; i++) {\n p.push([points[i].X(), points[i].Y()]);\n }\n\n res = JXG.Math.Metapost.curve(p, controls);\n this.dataX = res[0];\n this.dataY = res[1];\n };\n el.bezierDegree = 3;\n\n le = points.length;\n el.setParents(points);\n for (i = 0; i < le; i++) {\n if (Type.isPoint(points[i])) {\n points[i].addChild(el);\n }\n }\n el.elType = 'metapostspline';\n\n return el;\n };\n\n JXG.registerElement('metapostspline', JXG.createMetapostSpline);\n\n /**\n * @class This element is used to provide a constructor for Riemann sums, which is realized as a special curve.\n * The returned element has the method Value() which returns the sum of the areas of the bars.\n * @pseudo\n * @description\n * @name Riemannsum\n * @augments JXG.Curve\n * @constructor\n * @type JXG.Curve\n * @param {function,array_number,function_string,function_function,number_function,number} f,n,type_,a_,b_ Parent elements of Riemannsum are a\n * Either a function term f(x) describing the function graph which is filled by the Riemann bars, or\n * an array consisting of two functions and the area between is filled by the Riemann bars.\n * <p>\n * n determines the number of bars, it is either a fixed number or a function.\n * <p>\n * type is a string or function returning one of the values: 'left', 'right', 'middle', 'lower', 'upper', 'random', 'simpson', or 'trapezoidal'.\n * Default value is 'left'.\n * <p>\n * Further parameters are an optional number or function for the left interval border a,\n * and an optional number or function for the right interval border b.\n * <p>\n * Default values are a=-10 and b=10.\n * @see JXG.Curve\n * @example\n * // Create Riemann sums for f(x) = 0.5*x*x-2*x.\n * var s = board.create('slider',[[0,4],[3,4],[0,4,10]],{snapWidth:1});\n * var f = function(x) { return 0.5*x*x-2*x; };\n * var r = board.create('riemannsum',\n * [f, function(){return s.Value();}, 'upper', -2, 5],\n * {fillOpacity:0.4}\n * );\n * var g = board.create('functiongraph',[f, -2, 5]);\n * var t = board.create('text',[-2,-2, function(){ return 'Sum=' + JXG.toFixed(r.Value(), 4); }]);\n * </pre><div class=\"jxgbox\" id=\"JXG940f40cc-2015-420d-9191-c5d83de988cf\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function(){\n * var board = JXG.JSXGraph.initBoard('JXG940f40cc-2015-420d-9191-c5d83de988cf', {boundingbox: [-3, 7, 5, -3], axis: true, showcopyright: false, shownavigation: false});\n * var f = function(x) { return 0.5*x*x-2*x; };\n * var s = board.create('slider',[[0,4],[3,4],[0,4,10]],{snapWidth:1});\n * var r = board.create('riemannsum', [f, function(){return s.Value();}, 'upper', -2, 5], {fillOpacity:0.4});\n * var g = board.create('functiongraph', [f, -2, 5]);\n * var t = board.create('text',[-2,-2, function(){ return 'Sum=' + JXG.toFixed(r.Value(), 4); }]);\n * })();\n * </script><pre>\n *\n * @example\n * // Riemann sum between two functions\n * var s = board.create('slider',[[0,4],[3,4],[0,4,10]],{snapWidth:1});\n * var g = function(x) { return 0.5*x*x-2*x; };\n * var f = function(x) { return -x*(x-4); };\n * var r = board.create('riemannsum',\n * [[g,f], function(){return s.Value();}, 'lower', 0, 4],\n * {fillOpacity:0.4}\n * );\n * var f = board.create('functiongraph',[f, -2, 5]);\n * var g = board.create('functiongraph',[g, -2, 5]);\n * var t = board.create('text',[-2,-2, function(){ return 'Sum=' + JXG.toFixed(r.Value(), 4); }]);\n * </pre><div class=\"jxgbox\" id=\"JXGf9a7ba38-b50f-4a32-a873-2f3bf9caee79\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function(){\n * var board = JXG.JSXGraph.initBoard('JXGf9a7ba38-b50f-4a32-a873-2f3bf9caee79', {boundingbox: [-3, 7, 5, -3], axis: true, showcopyright: false, shownavigation: false});\n * var s = board.create('slider',[[0,4],[3,4],[0,4,10]],{snapWidth:1});\n * var g = function(x) { return 0.5*x*x-2*x; };\n * var f = function(x) { return -x*(x-4); };\n * var r = board.create('riemannsum',\n * [[g,f], function(){return s.Value();}, 'lower', 0, 4],\n * {fillOpacity:0.4}\n * );\n * var f = board.create('functiongraph',[f, -2, 5]);\n * var g = board.create('functiongraph',[g, -2, 5]);\n * var t = board.create('text',[-2,-2, function(){ return 'Sum=' + JXG.toFixed(r.Value(), 4); }]);\n * })();\n * </script><pre>\n */\n JXG.createRiemannsum = function (board, parents, attributes) {\n var n, type, f, par, c, attr;\n\n attr = Type.copyAttributes(attributes, board.options, 'riemannsum');\n attr.curvetype = 'plot';\n\n f = parents[0];\n n = Type.createFunction(parents[1], board, '');\n\n if (!Type.exists(n)) {\n throw new Error(\"JSXGraph: JXG.createRiemannsum: argument '2' n has to be number or function.\" +\n \"\\nPossible parent types: [function,n:number|function,type,start:number|function,end:number|function]\");\n }\n\n type = Type.createFunction(parents[2], board, '', false);\n if (!Type.exists(type)) {\n throw new Error(\"JSXGraph: JXG.createRiemannsum: argument 3 'type' has to be string or function.\" +\n \"\\nPossible parent types: [function,n:number|function,type,start:number|function,end:number|function]\");\n }\n\n par = [[0], [0]].concat(parents.slice(3));\n\n c = board.create('curve', par, attr);\n\n c.sum = 0.0;\n /**\n * Returns the value of the Riemann sum, i.e. the sum of the (signed) areas of the rectangles.\n * @name Value\n * @memberOf Riemann.prototype\n * @function\n * @returns {Number} value of Riemann sum.\n */\n c.Value = function () {\n return this.sum;\n };\n\n /**\n * @ignore\n */\n c.updateDataArray = function () {\n var u = Numerics.riemann(f, n(), type(), this.minX(), this.maxX());\n this.dataX = u[0];\n this.dataY = u[1];\n\n // Update \"Riemann sum\"\n this.sum = u[2];\n };\n\n return c;\n };\n\n JXG.registerElement('riemannsum', JXG.createRiemannsum);\n\n /**\n * @class This element is used to provide a constructor for trace curve (simple locus curve), which is realized as a special curve.\n * @pseudo\n * @description\n * @name Tracecurve\n * @augments JXG.Curve\n * @constructor\n * @type JXG.Curve\n * @param {Point,Point} Parent elements of Tracecurve are a\n * glider point and a point whose locus is traced.\n * @see JXG.Curve\n * @example\n * // Create trace curve.\n * var c1 = board.create('circle',[[0, 0], [2, 0]]),\n * p1 = board.create('point',[-3, 1]),\n * g1 = board.create('glider',[2, 1, c1]),\n * s1 = board.create('segment',[g1, p1]),\n * p2 = board.create('midpoint',[s1]),\n * curve = board.create('tracecurve', [g1, p2]);\n *\n * </pre><div class=\"jxgbox\" id=\"JXG5749fb7d-04fc-44d2-973e-45c1951e29ad\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * var tc1_board = JXG.JSXGraph.initBoard('JXG5749fb7d-04fc-44d2-973e-45c1951e29ad', {boundingbox: [-4, 4, 4, -4], axis: false, showcopyright: false, shownavigation: false});\n * var c1 = tc1_board.create('circle',[[0, 0], [2, 0]]),\n * p1 = tc1_board.create('point',[-3, 1]),\n * g1 = tc1_board.create('glider',[2, 1, c1]),\n * s1 = tc1_board.create('segment',[g1, p1]),\n * p2 = tc1_board.create('midpoint',[s1]),\n * curve = tc1_board.create('tracecurve', [g1, p2]);\n * </script><pre>\n */\n JXG.createTracecurve = function (board, parents, attributes) {\n var c, glider, tracepoint, attr;\n\n if (parents.length !== 2) {\n throw new Error(\"JSXGraph: Can't create trace curve with given parent'\" +\n \"\\nPossible parent types: [glider, point]\");\n }\n\n glider = board.select(parents[0]);\n tracepoint = board.select(parents[1]);\n\n if (glider.type !== Const.OBJECT_TYPE_GLIDER || !Type.isPoint(tracepoint)) {\n throw new Error(\"JSXGraph: Can't create trace curve with parent types '\" +\n (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"'.\" +\n \"\\nPossible parent types: [glider, point]\");\n }\n\n attr = Type.copyAttributes(attributes, board.options, 'tracecurve');\n attr.curvetype = 'plot';\n c = board.create('curve', [[0], [0]], attr);\n\n /**\n * @ignore\n */\n c.updateDataArray = function () {\n var i, step, t, el, pEl, x, y, from, savetrace,\n le = attr.numberpoints,\n savePos = glider.position,\n slideObj = glider.slideObject,\n mi = slideObj.minX(),\n ma = slideObj.maxX();\n\n // set step width\n step = (ma - mi) / le;\n this.dataX = [];\n this.dataY = [];\n\n /*\n * For gliders on circles and lines a closed curve is computed.\n * For gliders on curves the curve is not closed.\n */\n if (slideObj.elementClass !== Const.OBJECT_CLASS_CURVE) {\n le++;\n }\n\n // Loop over all steps\n for (i = 0; i < le; i++) {\n t = mi + i * step;\n x = slideObj.X(t) / slideObj.Z(t);\n y = slideObj.Y(t) / slideObj.Z(t);\n\n // Position the glider\n glider.setPositionDirectly(Const.COORDS_BY_USER, [x, y]);\n from = false;\n\n // Update all elements from the glider up to the trace element\n for (el in this.board.objects) {\n if (this.board.objects.hasOwnProperty(el)) {\n pEl = this.board.objects[el];\n\n if (pEl === glider) {\n from = true;\n }\n\n if (from && pEl.needsRegularUpdate) {\n // Save the trace mode of the element\n savetrace = pEl.visProp.trace;\n pEl.visProp.trace = false;\n pEl.needsUpdate = true;\n pEl.update(true);\n\n // Restore the trace mode\n pEl.visProp.trace = savetrace;\n if (pEl === tracepoint) {\n break;\n }\n }\n }\n }\n\n // Store the position of the trace point\n this.dataX[i] = tracepoint.X();\n this.dataY[i] = tracepoint.Y();\n }\n\n // Restore the original position of the glider\n glider.position = savePos;\n from = false;\n\n // Update all elements from the glider to the trace point\n for (el in this.board.objects) {\n if (this.board.objects.hasOwnProperty(el)) {\n pEl = this.board.objects[el];\n if (pEl === glider) {\n from = true;\n }\n\n if (from && pEl.needsRegularUpdate) {\n savetrace = pEl.visProp.trace;\n pEl.visProp.trace = false;\n pEl.needsUpdate = true;\n pEl.update(true);\n pEl.visProp.trace = savetrace;\n\n if (pEl === tracepoint) {\n break;\n }\n }\n }\n }\n };\n\n return c;\n };\n\n JXG.registerElement('tracecurve', JXG.createTracecurve);\n\n /**\n * @class This element is used to provide a constructor for step function, which is realized as a special curve.\n *\n * In case the data points should be updated after creation time, they can be accessed by curve.xterm and curve.yterm.\n * @pseudo\n * @description\n * @name Stepfunction\n * @augments JXG.Curve\n * @constructor\n * @type JXG.Curve\n * @param {Array,Array|Function} Parent elements of Stepfunction are two arrays containing the coordinates.\n * @see JXG.Curve\n * @example\n * // Create step function.\n var curve = board.create('stepfunction', [[0,1,2,3,4,5], [1,3,0,2,2,1]]);\n\n * </pre><div class=\"jxgbox\" id=\"JXG32342ec9-ad17-4339-8a97-ff23dc34f51a\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * var sf1_board = JXG.JSXGraph.initBoard('JXG32342ec9-ad17-4339-8a97-ff23dc34f51a', {boundingbox: [-1, 5, 6, -2], axis: true, showcopyright: false, shownavigation: false});\n * var curve = sf1_board.create('stepfunction', [[0,1,2,3,4,5], [1,3,0,2,2,1]]);\n * </script><pre>\n */\n JXG.createStepfunction = function (board, parents, attributes) {\n var c, attr;\n if (parents.length !== 2) {\n throw new Error(\"JSXGraph: Can't create step function with given parent'\" +\n \"\\nPossible parent types: [array, array|function]\");\n }\n\n attr = Type.copyAttributes(attributes, board.options, 'stepfunction');\n c = board.create('curve', parents, attr);\n /**\n * @ignore\n */\n c.updateDataArray = function () {\n var i, j = 0,\n len = this.xterm.length;\n\n this.dataX = [];\n this.dataY = [];\n\n if (len === 0) {\n return;\n }\n\n this.dataX[j] = this.xterm[0];\n this.dataY[j] = this.yterm[0];\n ++j;\n\n for (i = 1; i < len; ++i) {\n this.dataX[j] = this.xterm[i];\n this.dataY[j] = this.dataY[j - 1];\n ++j;\n this.dataX[j] = this.xterm[i];\n this.dataY[j] = this.yterm[i];\n ++j;\n }\n };\n\n return c;\n };\n\n JXG.registerElement('stepfunction', JXG.createStepfunction);\n\n /**\n * @class This element is used to provide a constructor for the graph showing\n * the (numerical) derivative of a given curve.\n *\n * @pseudo\n * @description\n * @name Derivative\n * @augments JXG.Curve\n * @constructor\n * @type JXG.Curve\n * @param {JXG.Curve} Parent Curve for which the derivative is generated.\n * @see JXG.Curve\n * @example\n * var cu = board.create('cardinalspline', [[[-3,0], [-1,2], [0,1], [2,0], [3,1]], 0.5, 'centripetal'], {createPoints: false});\n * var d = board.create('derivative', [cu], {dash: 2});\n *\n * </pre><div id=\"JXGb9600738-1656-11e8-8184-901b0e1b8723\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXGb9600738-1656-11e8-8184-901b0e1b8723',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var cu = board.create('cardinalspline', [[[-3,0], [-1,2], [0,1], [2,0], [3,1]], 0.5, 'centripetal'], {createPoints: false});\n * var d = board.create('derivative', [cu], {dash: 2});\n *\n * })();\n *\n * </script><pre>\n *\n */\n JXG.createDerivative = function (board, parents, attributes) {\n var c,\n curve, dx, dy,\n attr;\n\n if (parents.length !== 1 && parents[0].class !== Const.OBJECT_CLASS_CURVE) {\n throw new Error(\"JSXGraph: Can't create derivative curve with given parent'\" +\n \"\\nPossible parent types: [curve]\");\n }\n\n attr = Type.copyAttributes(attributes, board.options, 'curve');\n\n curve = parents[0];\n dx = Numerics.D(curve.X);\n dy = Numerics.D(curve.Y);\n\n c = board.create('curve', [\n function (t) { return curve.X(t); },\n function (t) { return dy(t) / dx(t); },\n curve.minX(), curve.maxX()\n ], attr);\n\n c.setParents(curve);\n\n return c;\n };\n\n JXG.registerElement('derivative', JXG.createDerivative);\n\n /**\n * @class Intersection of two closed path elements. The elements may be of type curve, circle, polygon, inequality.\n * If one element is a curve, it has to be closed.\n * The resulting element is of type curve.\n * @pseudo\n * @description\n * @name CurveIntersection\n * @param {JXG.Curve|JXG.Polygon|JXG.Circle} curve1 First element which is intersected\n * @param {JXG.Curve|JXG.Polygon|JXG.Circle} curve2 Second element which is intersected\n * @augments JXG.Curve\n * @constructor\n * @type JXG.Curve\n *\n * @example\n * var f = board.create('functiongraph', ['cos(x)']);\n * var ineq = board.create('inequality', [f], {inverse: true, fillOpacity: 0.1});\n * var circ = board.create('circle', [[0,0], 4]);\n * var clip = board.create('curveintersection', [ineq, circ], {fillColor: 'yellow', fillOpacity: 0.6});\n *\n * </pre><div id=\"JXGe2948257-8835-4276-9164-8acccb48e8d4\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXGe2948257-8835-4276-9164-8acccb48e8d4',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var f = board.create('functiongraph', ['cos(x)']);\n * var ineq = board.create('inequality', [f], {inverse: true, fillOpacity: 0.1});\n * var circ = board.create('circle', [[0,0], 4]);\n * var clip = board.create('curveintersection', [ineq, circ], {fillColor: 'yellow', fillOpacity: 0.6});\n *\n * })();\n *\n * </script><pre>\n *\n */\n JXG.createCurveIntersection = function (board, parents, attributes) {\n var c;\n\n if (parents.length !== 2) {\n throw new Error(\"JSXGraph: Can't create curve intersection with given parent'\" +\n \"\\nPossible parent types: [array, array|function]\");\n }\n\n c = board.create('curve', [[], []], attributes);\n /**\n * @ignore\n */\n c.updateDataArray = function () {\n var a = JXG.Math.Clip.intersection(parents[0], parents[1], this.board);\n this.dataX = a[0];\n this.dataY = a[1];\n };\n return c;\n };\n\n /**\n * @class Union of two closed path elements. The elements may be of type curve, circle, polygon, inequality.\n * If one element is a curve, it has to be closed.\n * The resulting element is of type curve.\n * @pseudo\n * @description\n * @name CurveUnion\n * @param {JXG.Curve|JXG.Polygon|JXG.Circle} curve1 First element defining the union\n * @param {JXG.Curve|JXG.Polygon|JXG.Circle} curve2 Second element defining the union\n * @augments JXG.Curve\n * @constructor\n * @type JXG.Curve\n *\n * @example\n * var f = board.create('functiongraph', ['cos(x)']);\n * var ineq = board.create('inequality', [f], {inverse: true, fillOpacity: 0.1});\n * var circ = board.create('circle', [[0,0], 4]);\n * var clip = board.create('curveunion', [ineq, circ], {fillColor: 'yellow', fillOpacity: 0.6});\n *\n * </pre><div id=\"JXGe2948257-8835-4276-9164-8acccb48e8d4\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXGe2948257-8835-4276-9164-8acccb48e8d4',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var f = board.create('functiongraph', ['cos(x)']);\n * var ineq = board.create('inequality', [f], {inverse: true, fillOpacity: 0.1});\n * var circ = board.create('circle', [[0,0], 4]);\n * var clip = board.create('curveunion', [ineq, circ], {fillColor: 'yellow', fillOpacity: 0.6});\n *\n * })();\n *\n * </script><pre>\n *\n */\n JXG.createCurveUnion = function (board, parents, attributes) {\n var c;\n\n if (parents.length !== 2) {\n throw new Error(\"JSXGraph: Can't create curve union with given parent'\" +\n \"\\nPossible parent types: [array, array|function]\");\n }\n\n c = board.create('curve', [[], []], attributes);\n /**\n * @ignore\n */\n c.updateDataArray = function () {\n var a = JXG.Math.Clip.union(parents[0], parents[1], this.board);\n this.dataX = a[0];\n this.dataY = a[1];\n };\n return c;\n };\n\n /**\n * @class Difference of two closed path elements. The elements may be of type curve, circle, polygon, inequality.\n * If one element is a curve, it has to be closed.\n * The resulting element is of type curve.\n * @pseudo\n * @description\n * @name CurveDifference\n * @param {JXG.Curve|JXG.Polygon|JXG.Circle} curve1 First element from which the second element is \"subtracted\"\n * @param {JXG.Curve|JXG.Polygon|JXG.Circle} curve2 Second element which is subtracted from the first element\n * @augments JXG.Curve\n * @constructor\n * @type JXG.Curve\n *\n * @example\n * var f = board.create('functiongraph', ['cos(x)']);\n * var ineq = board.create('inequality', [f], {inverse: true, fillOpacity: 0.1});\n * var circ = board.create('circle', [[0,0], 4]);\n * var clip = board.create('curvedifference', [ineq, circ], {fillColor: 'yellow', fillOpacity: 0.6});\n *\n * </pre><div id=\"JXGe2948257-8835-4276-9164-8acccb48e8d4\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXGe2948257-8835-4276-9164-8acccb48e8d4',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var f = board.create('functiongraph', ['cos(x)']);\n * var ineq = board.create('inequality', [f], {inverse: true, fillOpacity: 0.1});\n * var circ = board.create('circle', [[0,0], 4]);\n * var clip = board.create('curvedifference', [ineq, circ], {fillColor: 'yellow', fillOpacity: 0.6});\n *\n * })();\n *\n * </script><pre>\n *\n */\n JXG.createCurveDifference = function (board, parents, attributes) {\n var c;\n\n if (parents.length !== 2) {\n throw new Error(\"JSXGraph: Can't create curve difference with given parent'\" +\n \"\\nPossible parent types: [array, array|function]\");\n }\n\n c = board.create('curve', [[], []], attributes);\n /**\n * @ignore\n */\n c.updateDataArray = function () {\n var a = JXG.Math.Clip.difference(parents[0], parents[1], this.board);\n this.dataX = a[0];\n this.dataY = a[1];\n };\n return c;\n };\n\n JXG.registerElement('curvedifference', JXG.createCurveDifference);\n JXG.registerElement('curveintersection', JXG.createCurveIntersection);\n JXG.registerElement('curveunion', JXG.createCurveUnion);\n\n /**\n * @class Box plot curve. The direction of the box plot can be either vertical or horizontal which\n * is controlled by the attribute \"dir\".\n * @pseudo\n * @description\n * @name Boxplot\n * @param {Array} quantiles Array conatining at least five quantiles. The elements can be of type number, function or string.\n * @param {Number|Function} axis Axis position of the box plot\n * @param {Number|Function} width Width of the rectangle part of the box plot. The width of the first and 4th quantile\n * is relative to this width and can be controlled by the attribute \"smallWidth\".\n * @augments JXG.Curve\n * @constructor\n * @type JXG.Curve\n *\n * @example\n * var Q = [ -1, 2, 3, 3.5, 5 ];\n *\n * var b = board.create('boxplot', [Q, 2, 4], {strokeWidth: 3});\n *\n * </pre><div id=\"JXG13eb23a1-a641-41a2-be11-8e03e400a947\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG13eb23a1-a641-41a2-be11-8e03e400a947',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var Q = [ -1, 2, 3, 3.5, 5 ];\n * var b = board.create('boxplot', [Q, 2, 4], {strokeWidth: 3});\n *\n * })();\n *\n * </script><pre>\n *\n * @example\n * var Q = [ -1, 2, 3, 3.5, 5 ];\n * var b = board.create('boxplot', [Q, 3, 4], {dir: 'horizontal', smallWidth: 0.25, color:'red'});\n *\n * </pre><div id=\"JXG0deb9cb2-84bc-470d-a6db-8be9a5694813\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG0deb9cb2-84bc-470d-a6db-8be9a5694813',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var Q = [ -1, 2, 3, 3.5, 5 ];\n * var b = board.create('boxplot', [Q, 3, 4], {dir: 'horizontal', smallWidth: 0.25, color:'red'});\n *\n * })();\n *\n * </script><pre>\n *\n * @example\n * var data = [57, 57, 57, 58, 63, 66, 66, 67, 67, 68, 69, 70, 70, 70, 70, 72, 73, 75, 75, 76, 76, 78, 79, 81];\n * var Q = [];\n *\n * Q[0] = JXG.Math.Statistics.min(data);\n * Q = Q.concat(JXG.Math.Statistics.percentile(data, [25, 50, 75]));\n * Q[4] = JXG.Math.Statistics.max(data);\n *\n * var b = board.create('boxplot', [Q, 0, 3]);\n *\n * </pre><div id=\"JXGef079e76-ae99-41e4-af29-1d07d83bf85a\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXGef079e76-ae99-41e4-af29-1d07d83bf85a',\n * {boundingbox: [-5,90,5,30], axis: true, showcopyright: false, shownavigation: false});\n * var data = [57, 57, 57, 58, 63, 66, 66, 67, 67, 68, 69, 70, 70, 70, 70, 72, 73, 75, 75, 76, 76, 78, 79, 81];\n * var Q = [];\n *\n * Q[0] = JXG.Math.Statistics.min(data);\n * Q = Q.concat(JXG.Math.Statistics.percentile(data, [25, 50, 75]));\n * Q[4] = JXG.Math.Statistics.max(data);\n *\n * var b = board.create('boxplot', [Q, 0, 3]);\n *\n * })();\n *\n * </script><pre>\n *\n * @example\n * var mi = board.create('glider', [0, -1, board.defaultAxes.y]);\n * var ma = board.create('glider', [0, 5, board.defaultAxes.y]);\n * var Q = [function() { return mi.Y(); }, 2, 3, 3.5, function() { return ma.Y(); }];\n *\n * var b = board.create('boxplot', [Q, 0, 2]);\n *\n * </pre><div id=\"JXG3b3225da-52f0-42fe-8396-be9016bf289b\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG3b3225da-52f0-42fe-8396-be9016bf289b',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var mi = board.create('glider', [0, -1, board.defaultAxes.y]);\n * var ma = board.create('glider', [0, 5, board.defaultAxes.y]);\n * var Q = [function() { return mi.Y(); }, 2, 3, 3.5, function() { return ma.Y(); }];\n *\n * var b = board.create('boxplot', [Q, 0, 2]);\n *\n * })();\n *\n * </script><pre>\n *\n */\n JXG.createBoxPlot = function (board, parents, attributes) {\n var box, i, len, w2,\n attr = Type.copyAttributes(attributes, board.options, 'boxplot');\n\n if (parents.length !== 3) {\n throw new Error(\"JSXGraph: Can't create box plot with given parent'\" +\n \"\\nPossible parent types: [array, number|function, number|function] containing quantiles, axis, width\");\n }\n if (parents[0].length < 5) {\n throw new Error(\"JSXGraph: Can't create box plot with given parent[0]'\" +\n \"\\nparent[0] has to conatin at least 5 quantiles.\");\n }\n box = board.create('curve', [[],[]], attr);\n\n len = parents[0].length; // Quantiles\n box.Q = [];\n for (i = 0; i < len; i++) {\n box.Q[i] = Type.createFunction(parents[0][i], board, null, true);\n }\n box.x = Type.createFunction(parents[1], board, null, true);\n box.w = Type.createFunction(parents[2], board, null, true);\n\n box.updateDataArray = function() {\n var v1, v2, l1, l2, r1, r2, w2, dir, x;\n\n w2 = Type.evaluate(this.visProp.smallwidth);\n dir = Type.evaluate(this.visProp.dir);\n x = this.x();\n l1 = x - this.w() * 0.5;\n l2 = x - this.w() * 0.5 * w2;\n r1 = x + this.w() * 0.5;\n r2 = x + this.w() * 0.5 * w2;\n v1 = [x, l2, r2, x, x, l1, l1, r1, r1, x, NaN, l1, r1, NaN, x, x, l2, r2, x];\n v2 = [this.Q[0](),\n this.Q[0](),\n this.Q[0](),\n this.Q[0](),\n this.Q[1](),\n this.Q[1](),\n this.Q[3](),\n this.Q[3](),\n this.Q[1](),\n this.Q[1](),\n NaN,\n this.Q[2](),\n this.Q[2](),\n NaN,\n this.Q[3](),\n this.Q[4](),\n this.Q[4](),\n this.Q[4](),\n this.Q[4]()];\n if (dir === 'vertical') {\n this.dataX = v1;\n this.dataY = v2;\n } else {\n this.dataX = v2;\n this.dataY = v1;\n }\n };\n return box;\n };\n\n JXG.registerElement('boxplot', JXG.createBoxPlot);\n\n return {\n Curve: JXG.Curve,\n createCardinalSpline: JXG.createCardinalSpline,\n createCurve: JXG.createCurve,\n createCurveDifference: JXG.createCurveDifference,\n createCurveIntersection: JXG.createCurveIntersection,\n createCurveUnion: JXG.createCurveUnion,\n createDerivative: JXG.createDerivative,\n createFunctiongraph: JXG.createFunctiongraph,\n createMetapostSpline: JXG.createMetapostSpline,\n createPlot: JXG.createFunctiongraph,\n createSpline: JXG.createSpline,\n createRiemannsum: JXG.createRiemannsum,\n createStepfunction: JXG.createStepfunction,\n createTracecurve: JXG.createTracecurve\n };\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true*/\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n jxg\n math/geometry\n math/math\n base/coords\n base/circle\n utils/type\n base/constants\n elements:\n curve\n midpoint\n circumcenter\n */\n\n/**\n * @fileoverview In this file the geometry object Arc is defined. Arc stores all\n * style and functional properties that are required to draw an arc on a board.\n */\n\ndefine('element/arc',[\n 'jxg', 'math/geometry', 'math/math', 'base/coords', 'base/circle', 'utils/type', 'base/constants'\n], function (JXG, Geometry, Mat, Coords, Circle, Type, Const) {\n\n \"use strict\";\n\n /**\n * @class An arc is a segment of the circumference of a circle. It is defined by a center, one point that\n * defines the radius, and a third point that defines the angle of the arc.\n *\n * @pseudo\n * @name Arc\n * @augments Curve\n * @constructor\n * @type JXG.Curve\n * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The result will be an arc of a circle around p1 through p2. The arc is drawn\n * counter-clockwise from p2 to p3.\n * @example\n * // Create an arc out of three free points\n * var p1 = board.create('point', [2.0, 2.0]);\n * var p2 = board.create('point', [1.0, 0.5]);\n * var p3 = board.create('point', [3.5, 1.0]);\n *\n * var a = board.create('arc', [p1, p2, p3]);\n * board.create('text',[1,6,function(){return 'arclength: '+Math.round(a.Value()*100)/100}])\n * </pre><div class=\"jxgbox\" id=\"JXG114ef584-4a5e-4686-8392-c97501befb5b\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function () {\n * var board = JXG.JSXGraph.initBoard('JXG114ef584-4a5e-4686-8392-c97501befb5b', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}),\n * p1 = board.create('point', [2.0, 2.0]),\n * p2 = board.create('point', [1.0, 0.5]),\n * p3 = board.create('point', [3.5, 1.0]),\n *\n * a = board.create('arc', [p1, p2, p3]);\n * board.create('text',[1,6,function(){return 'arclength: '+Math.round(a.Value()*100)/100}])\n * })();\n * </script><pre>\n *\n * @example\n * var t = board.create('transform', [2, 1.5], {type: 'scale'});\n * var a1 = board.create('arc', [[1, 1], [0, 1], [1, 0]], {strokeColor: 'red'});\n * var a2 = board.create('curve', [a1, t], {strokeColor: 'red'});\n *\n * </pre><div id=\"JXG1949da46-6339-11e8-9fb9-901b0e1b8723\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG1949da46-6339-11e8-9fb9-901b0e1b8723',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var t = board.create('transform', [2, 1.5], {type: 'scale'});\n * var a1 = board.create('arc', [[1, 1], [0, 1], [1, 0]], {strokeColor: 'red'});\n * var a2 = board.create('curve', [a1, t], {strokeColor: 'red'});\n *\n * })();\n *\n * </script><pre>\n *\n */\n JXG.createArc = function (board, parents, attributes) {\n var el, attr, points;\n\n points = Type.providePoints(board, parents, attributes, 'arc', ['center', 'radiusPoint', 'anglePoint']);\n if (points === false || points.length < 3) {\n throw new Error(\"JSXGraph: Can't create Arc with parent types '\" +\n (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"' and '\" +\n (typeof parents[2]) + \"'.\" +\n \"\\nPossible parent types: [point,point,point], [arc, transformation]\");\n }\n\n attr = Type.copyAttributes(attributes, board.options, 'arc');\n el = board.create('curve', [[0], [0]], attr);\n\n el.elType = 'arc';\n el.setParents(points);\n\n /**\n * documented in JXG.GeometryElement\n * @ignore\n */\n el.type = Const.OBJECT_TYPE_ARC;\n\n /**\n * Center of the arc.\n * @memberOf Arc.prototype\n * @name center\n * @type JXG.Point\n */\n el.center = points[0];\n\n /**\n * Point defining the arc's radius.\n * @memberOf Arc.prototype\n * @name radiuspoint\n * @type JXG.Point\n */\n el.radiuspoint = points[1];\n el.point2 = el.radiuspoint;\n\n /**\n * The point defining the arc's angle.\n * @memberOf Arc.prototype\n * @name anglepoint\n * @type JXG.Point\n */\n el.anglepoint = points[2];\n el.point3 = el.anglepoint;\n\n // Add arc as child to defining points\n // or vice versa if the points are provided as coordinates\n if (Type.exists(el.center._is_new)) {\n el.addChild(el.center);\n delete el.center._is_new;\n } else {\n el.center.addChild(el);\n }\n if (Type.exists(el.radiuspoint._is_new)) {\n el.addChild(el.radiuspoint);\n delete el.radiuspoint._is_new;\n } else {\n el.radiuspoint.addChild(el);\n }\n if (Type.exists(el.anglepoint._is_new)) {\n el.addChild(el.anglepoint);\n delete el.anglepoint._is_new;\n } else {\n el.anglepoint.addChild(el);\n }\n\n // should be documented in options\n el.useDirection = attr.usedirection;\n\n // documented in JXG.Curve\n el.updateDataArray = function () {\n var ar, phi, det, p0c, p1c, p2c,\n sgn = 1,\n A = this.radiuspoint,\n B = this.center,\n C = this.anglepoint,\n ev_s = Type.evaluate(this.visProp.selection);\n\n phi = Geometry.rad(A, B, C);\n if ((ev_s === 'minor' && phi > Math.PI) ||\n (ev_s === 'major' && phi < Math.PI)) {\n sgn = -1;\n }\n\n // This is true for circumCircleArcs. In that case there is\n // a fourth parent element: [center, point1, point3, point2]\n if (this.useDirection) {\n p0c = points[1].coords.usrCoords;\n p1c = points[3].coords.usrCoords;\n p2c = points[2].coords.usrCoords;\n det = (p0c[1] - p2c[1]) * (p0c[2] - p1c[2]) - (p0c[2] - p2c[2]) * (p0c[1] - p1c[1]);\n\n if (det < 0) {\n this.radiuspoint = points[1];\n this.anglepoint = points[2];\n } else {\n this.radiuspoint = points[2];\n this.anglepoint = points[1];\n }\n }\n\n A = A.coords.usrCoords;\n B = B.coords.usrCoords;\n C = C.coords.usrCoords;\n\n ar = Geometry.bezierArc(A, B, C, false, sgn);\n\n this.dataX = ar[0];\n this.dataY = ar[1];\n\n this.bezierDegree = 3;\n\n this.updateStdform();\n this.updateQuadraticform();\n };\n\n /**\n * Determines the arc's current radius. I.e. the distance between {@link Arc#center} and {@link Arc#radiuspoint}.\n * @memberOf Arc.prototype\n * @name Radius\n * @function\n * @returns {Number} The arc's radius\n */\n el.Radius = function () {\n return this.radiuspoint.Dist(this.center);\n };\n\n /**\n * @deprecated Use {@link Arc#Radius}\n * @memberOf Arc.prototype\n * @name getRadius\n * @function\n * @returns {Number}\n */\n el.getRadius = function () {\n JXG.deprecated('Arc.getRadius()', 'Arc.Radius()');\n return this.Radius();\n };\n\n /**\n * Returns the length of the arc.\n * @memberOf Arc.prototype\n * @name Value\n * @function\n * @returns {Number} The arc length\n */\n el.Value = function () {\n return this.Radius() * Geometry.rad(this.radiuspoint, this.center, this.anglepoint);\n };\n\n // documented in geometry element\n el.hasPoint = function (x, y) {\n var dist, checkPoint,\n has,\n invMat, c,\n prec, type,\n r = this.Radius();\n\n if (Type.evaluate(this.visProp.hasinnerpoints)) {\n return this.hasPointSector(x, y);\n }\n\n if (Type.isObject(Type.evaluate(this.visProp.precision))) {\n type = this.board._inputDevice;\n prec = Type.evaluate(this.visProp.precision[type]);\n } else {\n // 'inherit'\n prec = this.board.options.precision.hasPoint;\n }\n prec /= Math.min(this.board.unitX, this.board.unitY);\n checkPoint = new Coords(Const.COORDS_BY_SCREEN, [x, y], this.board);\n\n if (this.transformations.length > 0) {\n // Transform the mouse/touch coordinates\n // back to the original position of the curve.\n this.updateTransformMatrix();\n invMat = Mat.inverse(this.transformMat);\n c = Mat.matVecMult(invMat, checkPoint.usrCoords);\n checkPoint = new Coords(Const.COORDS_BY_USER, c, this.board);\n }\n\n dist = this.center.coords.distance(Const.COORDS_BY_USER, checkPoint);\n has = (Math.abs(dist - r) < prec);\n\n /**\n * At that point we know that the user has touched the circle line.\n * Now, we have to check, if the user has hit the arc path.\n */\n if (has) {\n has = Geometry.coordsOnArc(this, checkPoint);\n }\n return has;\n };\n\n /**\n * Checks whether (x,y) is within the sector defined by the arc.\n * @memberOf Arc.prototype\n * @name hasPointSector\n * @function\n * @param {Number} x Coordinate in x direction, screen coordinates.\n * @param {Number} y Coordinate in y direction, screen coordinates.\n * @returns {Boolean} True if (x,y) is within the sector defined by the arc, False otherwise.\n */\n el.hasPointSector = function (x, y) {\n var checkPoint = new Coords(Const.COORDS_BY_SCREEN, [x, y], this.board),\n r = this.Radius(),\n dist = this.center.coords.distance(Const.COORDS_BY_USER, checkPoint),\n has = (dist < r);\n\n if (has) {\n has = Geometry.coordsOnArc(this, checkPoint);\n }\n return has;\n };\n\n // documented in geometry element\n el.getTextAnchor = function () {\n return this.center.coords;\n };\n\n // documented in geometry element\n el.getLabelAnchor = function () {\n var coords, vec, vecx, vecy, len,\n angle = Geometry.rad(this.radiuspoint, this.center, this.anglepoint),\n dx = 10 / this.board.unitX,\n dy = 10 / this.board.unitY,\n p2c = this.point2.coords.usrCoords,\n pmc = this.center.coords.usrCoords,\n bxminusax = p2c[1] - pmc[1],\n byminusay = p2c[2] - pmc[2],\n ev_s = Type.evaluate(this.visProp.selection),\n l_vp = this.label ? this.label.visProp : this.visProp.label;\n\n // If this is uncommented, the angle label can not be dragged\n //if (Type.exists(this.label)) {\n // this.label.relativeCoords = new Coords(Const.COORDS_BY_SCREEN, [0, 0], this.board);\n //}\n\n if ((ev_s === 'minor' && angle > Math.PI) ||\n (ev_s === 'major' && angle < Math.PI)) {\n angle = -(2 * Math.PI - angle);\n }\n\n coords = new Coords(Const.COORDS_BY_USER, [\n pmc[1] + Math.cos(angle * 0.5) * bxminusax - Math.sin(angle * 0.5) * byminusay,\n pmc[2] + Math.sin(angle * 0.5) * bxminusax + Math.cos(angle * 0.5) * byminusay\n ], this.board);\n\n vecx = coords.usrCoords[1] - pmc[1];\n vecy = coords.usrCoords[2] - pmc[2];\n\n len = Math.sqrt(vecx * vecx + vecy * vecy);\n vecx = vecx * (len + dx) / len;\n vecy = vecy * (len + dy) / len;\n vec = [pmc[1] + vecx, pmc[2] + vecy];\n\n l_vp.position = Geometry.calcLabelQuadrant(Geometry.rad([1,0],[0,0],vec));\n\n return new Coords(Const.COORDS_BY_USER, vec, this.board);\n };\n\n // documentation in jxg.circle\n el.updateQuadraticform = Circle.Circle.prototype.updateQuadraticform;\n\n // documentation in jxg.circle\n el.updateStdform = Circle.Circle.prototype.updateStdform;\n\n el.methodMap = JXG.deepCopy(el.methodMap, {\n getRadius: 'getRadius',\n radius: 'Radius',\n center: 'center',\n radiuspoint: 'radiuspoint',\n anglepoint: 'anglepoint',\n Value: 'Value'\n });\n\n el.prepareUpdate().update();\n return el;\n };\n\n JXG.registerElement('arc', JXG.createArc);\n\n /**\n * @class A semicircle is a special arc defined by two points. The arc hits both points.\n * @pseudo\n * @name Semicircle\n * @augments Arc\n * @constructor\n * @type Arc\n * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {JXG.Point_JXG.Point} p1,p2 The result will be a composition of an arc drawn clockwise from <tt>p1</tt> and\n * <tt>p2</tt> and the midpoint of <tt>p1</tt> and <tt>p2</tt>.\n * @example\n * // Create an arc out of three free points\n * var p1 = board.create('point', [4.5, 2.0]);\n * var p2 = board.create('point', [1.0, 0.5]);\n *\n * var a = board.create('semicircle', [p1, p2]);\n * </pre><div class=\"jxgbox\" id=\"JXG5385d349-75d7-4078-b732-9ae808db1b0e\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function () {\n * var board = JXG.JSXGraph.initBoard('JXG5385d349-75d7-4078-b732-9ae808db1b0e', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}),\n * p1 = board.create('point', [4.5, 2.0]),\n * p2 = board.create('point', [1.0, 0.5]),\n *\n * sc = board.create('semicircle', [p1, p2]);\n * })();\n * </script><pre>\n */\n JXG.createSemicircle = function (board, parents, attributes) {\n var el, mp, attr, points;\n\n // we need 2 points\n points = Type.providePoints(board, parents, attributes, 'point');\n if (points === false || points.length !== 2) {\n throw new Error(\"JSXGraph: Can't create Semicircle with parent types '\" +\n (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"'.\" +\n \"\\nPossible parent types: [point,point]\");\n }\n\n attr = Type.copyAttributes(attributes, board.options, 'semicircle', 'center');\n mp = board.create('midpoint', points, attr);\n mp.dump = false;\n\n attr = Type.copyAttributes(attributes, board.options, 'semicircle');\n el = board.create('arc', [mp, points[1], points[0]], attr);\n el.elType = 'semicircle';\n el.setParents([points[0].id, points[1].id]);\n el.subs = {\n midpoint: mp\n };\n el.inherits.push(mp);\n\n /**\n * The midpoint of the two defining points.\n * @memberOf Semicircle.prototype\n * @name midpoint\n * @type Midpoint\n */\n el.midpoint = el.center = mp;\n\n return el;\n };\n\n JXG.registerElement('semicircle', JXG.createSemicircle);\n\n /**\n * @class A circumcircle arc is an {@link Arc} defined by three points. All three points lie on the arc.\n * @pseudo\n * @name CircumcircleArc\n * @augments Arc\n * @constructor\n * @type Arc\n * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The result will be a composition of an arc of the circumcircle of\n * <tt>p1</tt>, <tt>p2</tt>, and <tt>p3</tt> and the midpoint of the circumcircle of the three points. The arc is drawn\n * counter-clockwise from <tt>p1</tt> over <tt>p2</tt> to <tt>p3</tt>.\n * @example\n * // Create a circum circle arc out of three free points\n * var p1 = board.create('point', [2.0, 2.0]);\n * var p2 = board.create('point', [1.0, 0.5]);\n * var p3 = board.create('point', [3.5, 1.0]);\n *\n * var a = board.create('circumcirclearc', [p1, p2, p3]);\n * </pre><div class=\"jxgbox\" id=\"JXG87125fd4-823a-41c1-88ef-d1a1369504e3\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function () {\n * var board = JXG.JSXGraph.initBoard('JXG87125fd4-823a-41c1-88ef-d1a1369504e3', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}),\n * p1 = board.create('point', [2.0, 2.0]),\n * p2 = board.create('point', [1.0, 0.5]),\n * p3 = board.create('point', [3.5, 1.0]),\n *\n * cca = board.create('circumcirclearc', [p1, p2, p3]);\n * })();\n * </script><pre>\n */\n JXG.createCircumcircleArc = function (board, parents, attributes) {\n var el, mp, attr, points;\n\n // We need three points\n points = Type.providePoints(board, parents, attributes, 'point');\n if (points === false || points.length !== 3) {\n throw new Error(\"JSXGraph: create Circumcircle Arc with parent types '\" +\n (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"' and '\" + (typeof parents[2]) + \"'.\" +\n \"\\nPossible parent types: [point,point,point]\");\n }\n\n attr = Type.copyAttributes(attributes, board.options, 'circumcirclearc', 'center');\n mp = board.create('circumcenter', points, attr);\n mp.dump = false;\n\n attr = Type.copyAttributes(attributes, board.options, 'circumcirclearc');\n attr.usedirection = true;\n el = board.create('arc', [mp, points[0], points[2], points[1]], attr);\n\n el.elType = 'circumcirclearc';\n el.setParents([points[0].id, points[1].id, points[2].id]);\n el.subs = {\n center: mp\n };\n el.inherits.push(mp);\n\n /**\n * The midpoint of the circumcircle of the three points defining the circumcircle arc.\n * @memberOf CircumcircleArc.prototype\n * @name center\n * @type Circumcenter\n */\n el.center = mp;\n\n return el;\n };\n\n JXG.registerElement('circumcirclearc', JXG.createCircumcircleArc);\n\n /**\n * @class A minor arc is a segment of the circumference of a circle having measure less than or equal to\n * 180 degrees (pi radians). It is defined by a center, one point that\n * defines the radius, and a third point that defines the angle of the arc.\n * @pseudo\n * @name MinorArc\n * @augments Curve\n * @constructor\n * @type JXG.Curve\n * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 . Minor arc is an arc of a circle around p1 having measure less than or equal to\n * 180 degrees (pi radians) and starts at p2. The radius is determined by p2, the angle by p3.\n * @example\n * // Create an arc out of three free points\n * var p1 = board.create('point', [2.0, 2.0]);\n * var p2 = board.create('point', [1.0, 0.5]);\n * var p3 = board.create('point', [3.5, 1.0]);\n *\n * var a = board.create('arc', [p1, p2, p3]);\n * </pre><div class=\"jxgbox\" id=\"JXG64ba7ca2-8728-45f3-96e5-3c7a4414de2f\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function () {\n * var board = JXG.JSXGraph.initBoard('JXG64ba7ca2-8728-45f3-96e5-3c7a4414de2f', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}),\n * p1 = board.create('point', [2.0, 2.0]),\n * p2 = board.create('point', [1.0, 0.5]),\n * p3 = board.create('point', [3.5, 1.0]),\n *\n * a = board.create('minorarc', [p1, p2, p3]);\n * })();\n * </script><pre>\n */\n\n JXG.createMinorArc = function (board, parents, attributes) {\n attributes.selection = 'minor';\n return JXG.createArc(board, parents, attributes);\n };\n\n JXG.registerElement('minorarc', JXG.createMinorArc);\n\n /**\n * @class A major arc is a segment of the circumference of a circle having measure greater than or equal to\n * 180 degrees (pi radians). It is defined by a center, one point that\n * defines the radius, and a third point that defines the angle of the arc.\n * @pseudo\n * @name MajorArc\n * @augments Curve\n * @constructor\n * @type JXG.Curve\n * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 . Major arc is an arc of a circle around p1 having measure greater than or equal to\n * 180 degrees (pi radians) and starts at p2. The radius is determined by p2, the angle by p3.\n * @example\n * // Create an arc out of three free points\n * var p1 = board.create('point', [2.0, 2.0]);\n * var p2 = board.create('point', [1.0, 0.5]);\n * var p3 = board.create('point', [3.5, 1.0]);\n *\n * var a = board.create('minorarc', [p1, p2, p3]);\n * </pre><div class=\"jxgbox\" id=\"JXG17a10d38-5629-40a4-b150-f41806edee9f\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function () {\n * var board = JXG.JSXGraph.initBoard('JXG17a10d38-5629-40a4-b150-f41806edee9f', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}),\n * p1 = board.create('point', [2.0, 2.0]),\n * p2 = board.create('point', [1.0, 0.5]),\n * p3 = board.create('point', [3.5, 1.0]),\n *\n * a = board.create('majorarc', [p1, p2, p3]);\n * })();\n * </script><pre>\n */\n JXG.createMajorArc = function (board, parents, attributes) {\n attributes.selection = 'major';\n return JXG.createArc(board, parents, attributes);\n };\n\n JXG.registerElement('majorarc', JXG.createMajorArc);\n\n return {\n createArc: JXG.createArc,\n createSemicircle: JXG.createSemicircle,\n createCircumcircleArc: JXG.createCircumcircleArc,\n createMinorArc: JXG.createMinorArc,\n createMajorArc: JXG.createMajorArc\n };\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true*/\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n jxg\n math/geometry\n math/math\n base/coords\n base/constants\n utils/type\n elements:\n point\n curve\n circumcentre\n transform\n */\n\ndefine('element/sector',[\n 'jxg', 'math/geometry', 'math/math', 'math/statistics', 'base/coords', 'base/constants', 'utils/type'\n], function (JXG, Geometry, Mat, Statistics, Coords, Const, Type) {\n\n \"use strict\";\n\n /**\n * @class A circular sector is a subarea of the area enclosed by a circle. It is enclosed by two radii and an arc.\n * @pseudo\n * @name Sector\n * @augments JXG.Curve\n * @constructor\n * @type JXG.Curve\n * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.\n *\n * First possiblity of input parameters are:\n * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 A sector is defined by three points: The sector's center <tt>p1</tt>,\n * a second point <tt>p2</tt> defining the radius and a third point <tt>p3</tt> defining the angle of the sector. The\n * Sector is always drawn counter clockwise from <tt>p2</tt> to <tt>p3</tt>\n * <p>\n * Second possibility of input parameters are:\n * @param {JXG.Line_JXG.Line_array,number_array,number_number,function} line, line2, coords1 or direction1, coords2 or direction2, radius The sector is defined by two lines.\n * The two legs which define the sector are given by two coordinates arrays which are project initially two the two lines or by two directions (+/- 1).\n * The last parameter is the radius of the sector.\n *\n *\n * @example\n * // Create a sector out of three free points\n * var p1 = board.create('point', [1.5, 5.0]),\n * p2 = board.create('point', [1.0, 0.5]),\n * p3 = board.create('point', [5.0, 3.0]),\n *\n * a = board.create('sector', [p1, p2, p3]);\n * </pre><div class=\"jxgbox\" id=\"JXG49f59123-f013-4681-bfd9-338b89893156\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function () {\n * var board = JXG.JSXGraph.initBoard('JXG49f59123-f013-4681-bfd9-338b89893156', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}),\n * p1 = board.create('point', [1.5, 5.0]),\n * p2 = board.create('point', [1.0, 0.5]),\n * p3 = board.create('point', [5.0, 3.0]),\n *\n * a = board.create('sector', [p1, p2, p3]);\n * })();\n * </script><pre>\n *\n * @example\n * // Create a sector out of two lines, two directions and a radius\n * var p1 = board.create('point', [-1, 4]),\n * p2 = board.create('point', [4, 1]),\n * q1 = board.create('point', [-2, -3]),\n * q2 = board.create('point', [4,3]),\n *\n * li1 = board.create('line', [p1,p2], {strokeColor:'black', lastArrow:true}),\n * li2 = board.create('line', [q1,q2], {lastArrow:true}),\n *\n * sec1 = board.create('sector', [li1, li2, [5.5, 0], [4, 3], 3]),\n * sec2 = board.create('sector', [li1, li2, 1, -1, 4]);\n *\n * </pre><div class=\"jxgbox\" id=\"JXGbb9e2809-9895-4ff1-adfa-c9c71d50aa53\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function () {\n * var board = JXG.JSXGraph.initBoard('JXGbb9e2809-9895-4ff1-adfa-c9c71d50aa53', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}),\n * p1 = board.create('point', [-1, 4]),\n * p2 = board.create('point', [4, 1]),\n * q1 = board.create('point', [-2, -3]),\n * q2 = board.create('point', [4,3]),\n *\n * li1 = board.create('line', [p1,p2], {strokeColor:'black', lastArrow:true}),\n * li2 = board.create('line', [q1,q2], {lastArrow:true}),\n *\n * sec1 = board.create('sector', [li1, li2, [5.5, 0], [4, 3], 3]),\n * sec2 = board.create('sector', [li1, li2, 1, -1, 4]);\n * })();\n * </script><pre>\n *\n * @example\n * var t = board.create('transform', [2, 1.5], {type: 'scale'});\n * var s1 = board.create('sector', [[-3.5,-3], [-3.5, -2], [-3.5,-4]], {\n * anglePoint: {visible:true}, center: {visible: true}, radiusPoint: {visible: true},\n * fillColor: 'yellow', strokeColor: 'black'});\n * var s2 = board.create('curve', [s1, t], {fillColor: 'yellow', strokeColor: 'black'});\n *\n * </pre><div id=\"JXG2e70ee14-6339-11e8-9fb9-901b0e1b8723\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG2e70ee14-6339-11e8-9fb9-901b0e1b8723',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var t = board.create('transform', [2, 1.5], {type: 'scale'});\n * var s1 = board.create('sector', [[-3.5,-3], [-3.5, -2], [-3.5,-4]], {\n * anglePoint: {visible:true}, center: {visible: true}, radiusPoint: {visible: true},\n * fillColor: 'yellow', strokeColor: 'black'});\n * var s2 = board.create('curve', [s1, t], {fillColor: 'yellow', strokeColor: 'black'});\n *\n * })();\n *\n * </script><pre>\n *\n */\n JXG.createSector = function (board, parents, attributes) {\n var el, attr, i,\n type = 'invalid',\n s, v,\n attrPoints = ['center', 'radiusPoint', 'anglePoint'],\n points;\n\n // Three points?\n if (parents[0].elementClass === Const.OBJECT_CLASS_LINE &&\n parents[1].elementClass === Const.OBJECT_CLASS_LINE &&\n (Type.isArray(parents[2]) || Type.isNumber(parents[2])) &&\n (Type.isArray(parents[3]) || Type.isNumber(parents[3])) &&\n (Type.isNumber(parents[4]) || Type.isFunction(parents[4]) || Type.isString(parents[4]))) {\n\n type = '2lines';\n } else {\n points = Type.providePoints(board, parents, attributes, 'sector', attrPoints);\n if (points === false) {\n throw new Error(\"JSXGraph: Can't create Sector with parent types '\" +\n (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"' and '\" +\n (typeof parents[2]) + \"'.\");\n }\n type = '3points';\n }\n\n\n attr = Type.copyAttributes(attributes, board.options, 'sector');\n el = board.create('curve', [[0], [0]], attr);\n el.type = Const.OBJECT_TYPE_SECTOR;\n el.elType = 'sector';\n\n /**\n * Set a radius if the attribute `radius` has value 'auto'.\n * Sets a radius between 20 and 50 points, depending on the distance\n * between the center and the radius point.\n * This function is used in {@link Angle}.\n *\n * @returns {Number} returns a radius value in user coordinates.\n */\n el.autoRadius = function() {\n var r1 = 20 / el.board.unitX, // 20px\n r2 = Infinity,\n r3 = 50 / el.board.unitX; // 50px\n\n if (Type.isPoint(el.center)) {\n // This does not work for 2-lines sectors / angles\n r2 = el.center.Dist(el.point2) * 0.3333;\n }\n\n return Math.max(r1, Math.min(r2, r3));\n };\n\n if (type === '2lines') {\n /**\n * @ignore\n */\n el.Radius = function () {\n var r = Type.evaluate(parents[4]);\n if (r === 'auto') {\n return this.autoRadius();\n }\n return r;\n };\n\n el.line1 = board.select(parents[0]);\n el.line2 = board.select(parents[1]);\n\n el.line1.addChild(el);\n el.line2.addChild(el);\n el.setParents(parents);\n\n el.point1 = {visProp: {}};\n el.point2 = {visProp: {}};\n el.point3 = {visProp: {}};\n\n /* Intersection point */\n s = Geometry.meetLineLine(el.line1.stdform, el.line2.stdform, 0, board);\n\n if (Type.isArray(parents[2])) {\n /* project p1 to l1 */\n if (parents[2].length === 2) {\n parents[2] = [1].concat(parents[2]);\n }\n /*\n v = [0, el.line1.stdform[1], el.line1.stdform[2]];\n v = Mat.crossProduct(v, parents[2]);\n v = Geometry.meetLineLine(v, el.line1.stdform, 0, board);\n */\n v = Geometry.projectPointToLine({coords: {usrCoords: parents[2]}}, el.line1, board);\n v = Statistics.subtract(v.usrCoords, s.usrCoords);\n el.direction1 = (Mat.innerProduct(v, [0, el.line1.stdform[2], -el.line1.stdform[1]], 3) >= 0) ? +1 : -1;\n } else {\n el.direction1 = (parents[2] >= 0) ? 1 : -1;\n }\n\n if (Type.isArray(parents[3])) {\n /* project p2 to l2 */\n if (parents[3].length === 2) {\n parents[3] = [1].concat(parents[3]);\n }\n /*\n v = [0, el.line2.stdform[1], el.line2.stdform[2]];\n v = Mat.crossProduct(v, parents[3]);\n v = Geometry.meetLineLine(v, el.line2.stdform, 0, board);\n */\n v = Geometry.projectPointToLine({coords: {usrCoords: parents[3]}}, el.line2, board);\n v = Statistics.subtract(v.usrCoords, s.usrCoords);\n el.direction2 = (Mat.innerProduct(v, [0, el.line2.stdform[2], -el.line2.stdform[1]], 3) >= 0) ? +1 : -1;\n } else {\n el.direction2 = (parents[3] >= 0) ? 1 : -1;\n }\n\n el.updateDataArray = function () {\n var r, l1, l2,\n A = [0, 0, 0],\n B = [0, 0, 0],\n C = [0, 0, 0],\n ar;\n\n l1 = this.line1;\n l2 = this.line2;\n\n // Intersection point of the lines\n B = Mat.crossProduct(l1.stdform, l2.stdform);\n\n if (Math.abs(B[0]) > Mat.eps * Mat.eps) {\n B[1] /= B[0];\n B[2] /= B[0];\n B[0] /= B[0];\n }\n // First point\n r = this.direction1 * this.Radius();\n A = Statistics.add(B, [0, r * l1.stdform[2], -r * l1.stdform[1]]);\n\n // Second point\n r = this.direction2 * this.Radius();\n C = Statistics.add(B, [0, r * l2.stdform[2], -r * l2.stdform[1]]);\n\n this.point2.coords = new Coords(Const.COORDS_BY_USER, A, el.board);\n this.point1.coords = new Coords(Const.COORDS_BY_USER, B, el.board);\n this.point3.coords = new Coords(Const.COORDS_BY_USER, C, el.board);\n\n if (Math.abs(A[0]) < Mat.eps || Math.abs(B[0]) < Mat.eps || Math.abs(C[0]) < Mat.eps) {\n this.dataX = [NaN];\n this.dataY = [NaN];\n return;\n }\n\n ar = Geometry.bezierArc(A, B, C, true, 1);\n\n this.dataX = ar[0];\n this.dataY = ar[1];\n\n this.bezierDegree = 3;\n };\n\n el.methodMap = JXG.deepCopy(el.methodMap, {\n radius: 'Radius',\n getRadius: 'Radius',\n setRadius: 'setRadius'\n });\n\n // el.prepareUpdate().update();\n\n // end '2lines'\n\n } else if (type === '3points') {\n\n /**\n * Midpoint of the sector.\n * @memberOf Sector.prototype\n * @name point1\n * @type JXG.Point\n */\n el.point1 = points[0];\n\n /**\n * This point together with {@link Sector#point1} defines the radius..\n * @memberOf Sector.prototype\n * @name point2\n * @type JXG.Point\n */\n el.point2 = points[1];\n\n /**\n * Defines the sector's angle.\n * @memberOf Sector.prototype\n * @name point3\n * @type JXG.Point\n */\n el.point3 = points[2];\n\n /* Add arc as child to defining points */\n for (i = 0; i < 3; i++) {\n if (Type.exists(points[i]._is_new)) {\n el.addChild(points[i]);\n delete points[i]._is_new;\n } else {\n points[i].addChild(el);\n }\n }\n\n // useDirection is necessary for circumCircleSectors\n el.useDirection = attributes.usedirection;\n el.setParents(points);\n\n /**\n * Defines the sectors orientation in case of circumCircleSectors.\n * @memberOf Sector.prototype\n * @name point4\n * @type JXG.Point\n */\n if (Type.exists(points[3])) {\n el.point4 = points[3];\n el.point4.addChild(el);\n }\n\n el.methodMap = JXG.deepCopy(el.methodMap, {\n arc: 'arc',\n center: 'center',\n radiuspoint: 'radiuspoint',\n anglepoint: 'anglepoint',\n radius: 'Radius',\n getRadius: 'Radius',\n setRadius: 'setRadius'\n });\n\n /**\n * documented in JXG.Curve\n * @ignore\n */\n el.updateDataArray = function () {\n var ar, det, p0c, p1c, p2c,\n A = this.point2,\n B = this.point1,\n C = this.point3,\n phi, sgn = 1,\n vp_s = Type.evaluate(this.visProp.selection);\n\n if (!A.isReal || !B.isReal || !C.isReal) {\n this.dataX = [NaN];\n this.dataY = [NaN];\n return;\n }\n\n phi = Geometry.rad(A, B, C);\n if ((vp_s === 'minor' && phi > Math.PI) ||\n (vp_s === 'major' && phi < Math.PI)) {\n sgn = -1;\n }\n\n // This is true for circumCircleSectors. In that case there is\n // a fourth parent element: [midpoint, point1, point3, point2]\n if (this.useDirection && Type.exists(this.point4)) {\n p0c = this.point2.coords.usrCoords;\n p1c = this.point4.coords.usrCoords;\n p2c = this.point3.coords.usrCoords;\n det = (p0c[1] - p2c[1]) * (p0c[2] - p1c[2]) - (p0c[2] - p2c[2]) * (p0c[1] - p1c[1]);\n\n if (det >= 0.0) {\n C = this.point2;\n A = this.point3;\n }\n }\n\n A = A.coords.usrCoords;\n B = B.coords.usrCoords;\n C = C.coords.usrCoords;\n\n ar = Geometry.bezierArc(A, B, C, true, sgn);\n\n this.dataX = ar[0];\n this.dataY = ar[1];\n this.bezierDegree = 3;\n };\n\n /**\n * Returns the radius of the sector.\n * @memberOf Sector.prototype\n * @name Radius\n * @function\n * @returns {Number} The distance between {@link Sector#point1} and {@link Sector#point2}.\n */\n el.Radius = function () {\n return this.point2.Dist(this.point1);\n };\n\n attr = Type.copyAttributes(attributes, board.options, 'sector', 'arc');\n attr.withLabel = false;\n attr.name += '_arc';\n el.arc = board.create('arc', [el.point1, el.point2, el.point3], attr);\n el.addChild(el.arc);\n } // end '3points'\n\n el.center = el.point1;\n el.radiuspoint = el.point2;\n el.anglepoint = el.point3;\n\n // Default hasPoint method. Documented in geometry element\n el.hasPointCurve = function (x, y) {\n var angle, alpha, beta,\n prec, type,\n checkPoint = new Coords(Const.COORDS_BY_SCREEN, [x, y], this.board),\n r = this.Radius(),\n dist = this.center.coords.distance(Const.COORDS_BY_USER, checkPoint),\n has,\n vp_s = Type.evaluate(this.visProp.selection);\n\n if (Type.isObject(Type.evaluate(this.visProp.precision))) {\n type = this.board._inputDevice;\n prec = Type.evaluate(this.visProp.precision[type]);\n } else {\n // 'inherit'\n prec = this.board.options.precision.hasPoint;\n }\n prec /= Math.min(this.board.unitX, this.board.unitY);\n has = (Math.abs(dist - r) < prec);\n if (has) {\n angle = Geometry.rad(this.point2, this.center, checkPoint.usrCoords.slice(1));\n alpha = 0;\n beta = Geometry.rad(this.point2, this.center, this.point3);\n\n if ((vp_s === 'minor' && beta > Math.PI) ||\n (vp_s === 'major' && beta < Math.PI)) {\n alpha = beta;\n beta = 2 * Math.PI;\n }\n\n if (angle < alpha || angle > beta) {\n has = false;\n }\n }\n\n return has;\n };\n\n /**\n * Checks whether (x,y) is within the area defined by the sector.\n * @memberOf Sector.prototype\n * @name hasPointSector\n * @function\n * @param {Number} x Coordinate in x direction, screen coordinates.\n * @param {Number} y Coordinate in y direction, screen coordinates.\n * @returns {Boolean} True if (x,y) is within the sector defined by the arc, False otherwise.\n */\n el.hasPointSector = function (x, y) {\n var angle,\n checkPoint = new Coords(Const.COORDS_BY_SCREEN, [x, y], this.board),\n r = this.Radius(),\n dist = this.point1.coords.distance(Const.COORDS_BY_USER, checkPoint),\n alpha,\n beta,\n has = (dist < r),\n vp_s = Type.evaluate(this.visProp.selection);\n\n if (has) {\n angle = Geometry.rad(this.radiuspoint, this.center, checkPoint.usrCoords.slice(1));\n alpha = 0.0;\n beta = Geometry.rad(this.radiuspoint, this.center, this.anglepoint);\n\n if ((vp_s === 'minor' && beta > Math.PI) ||\n (vp_s === 'major' && beta < Math.PI)) {\n alpha = beta;\n beta = 2 * Math.PI;\n }\n //if (angle > Geometry.rad(this.point2, this.point1, this.point3)) {\n if (angle < alpha || angle > beta) {\n has = false;\n }\n }\n return has;\n };\n\n el.hasPoint = function (x, y) {\n if (Type.evaluate(this.visProp.highlightonsector) ||\n Type.evaluate(this.visProp.hasinnerpoints)) {\n return this.hasPointSector(x, y);\n }\n\n return this.hasPointCurve(x, y);\n };\n\n // documented in GeometryElement\n el.getTextAnchor = function () {\n return this.point1.coords;\n };\n\n // documented in GeometryElement\n // this method is very similar to arc.getLabelAnchor()\n // there are some additions in the arc version though, mainly concerning\n // \"major\" and \"minor\" arcs. but maybe these methods can be merged.\n el.getLabelAnchor = function () {\n var coords, vec, vecx, vecy, len,\n angle = Geometry.rad(this.point2, this.point1, this.point3),\n dx = 13 / this.board.unitX,\n dy = 13 / this.board.unitY,\n p2c = this.point2.coords.usrCoords,\n pmc = this.point1.coords.usrCoords,\n bxminusax = p2c[1] - pmc[1],\n byminusay = p2c[2] - pmc[2],\n vp_s = Type.evaluate(this.visProp.selection),\n l_vp = this.label ? this.label.visProp : this.visProp.label;\n\n // If this is uncommented, the angle label can not be dragged\n //if (Type.exists(this.label)) {\n // this.label.relativeCoords = new Coords(Const.COORDS_BY_SCREEN, [0, 0], this.board);\n //}\n\n if ((vp_s === 'minor' && angle > Math.PI) ||\n (vp_s === 'major' && angle < Math.PI)) {\n angle = -(2 * Math.PI - angle);\n }\n\n coords = new Coords(Const.COORDS_BY_USER, [\n pmc[1] + Math.cos(angle * 0.5) * bxminusax - Math.sin(angle * 0.5) * byminusay,\n pmc[2] + Math.sin(angle * 0.5) * bxminusax + Math.cos(angle * 0.5) * byminusay\n ], this.board);\n\n vecx = coords.usrCoords[1] - pmc[1];\n vecy = coords.usrCoords[2] - pmc[2];\n\n len = Math.sqrt(vecx * vecx + vecy * vecy);\n vecx = vecx * (len + dx) / len;\n vecy = vecy * (len + dy) / len;\n vec = [pmc[1] + vecx, pmc[2] + vecy];\n\n l_vp.position = Geometry.calcLabelQuadrant(Geometry.rad([1,0],[0,0],vec));\n\n return new Coords(Const.COORDS_BY_USER, vec, this.board);\n };\n\n /**\n * Overwrite the Radius method of the sector.\n * Used in {@link GeometryElement#setAttribute}.\n * @param {Number, Function} value New radius.\n */\n el.setRadius = function (val) {\n /**\n * @ignore\n */\n el.Radius = function () {\n var r = Type.evaluate(val);\n if (r === 'auto') {\n return this.autoRadius();\n }\n return r;\n };\n };\n\n /**\n * @deprecated\n * @ignore\n */\n el.getRadius = function () {\n JXG.deprecated('Sector.getRadius()', 'Sector.Radius()');\n return this.Radius();\n };\n\n /**\n * Moves the sector by the difference of two coordinates.\n * @param {Number} method The type of coordinates used here. Possible values are {@link JXG.COORDS_BY_USER} and {@link JXG.COORDS_BY_SCREEN}.\n * @param {Array} coords coordinates in screen/user units\n * @param {Array} oldcoords previous coordinates in screen/user units\n * @returns {JXG.Curve} this element\n */\n if (type === '3points') {\n el.setPositionDirectly = function (method, coords, oldcoords) {\n var dc, t, i,\n c = new Coords(method, coords, this.board),\n oldc = new Coords(method, oldcoords, this.board);\n\n if (!el.point1.draggable() || !el.point2.draggable() || !el.point3.draggable()) {\n return this;\n }\n\n dc = Statistics.subtract(c.usrCoords, oldc.usrCoords);\n t = this.board.create('transform', dc.slice(1), {type: 'translate'});\n t.applyOnce([el.point1, el.point2, el.point3]);\n\n return this;\n };\n }\n\n el.prepareUpdate().update();\n\n return el;\n };\n\n JXG.registerElement('sector', JXG.createSector);\n\n /**\n * @class A circumcircle sector is different from a {@link Sector} mostly in the way the parent elements are interpreted.\n * At first, the circum centre is determined from the three given points. Then the sector is drawn from <tt>p1</tt> through\n * <tt>p2</tt> to <tt>p3</tt>.\n * @pseudo\n * @name CircumcircleSector\n * @augments Sector\n * @constructor\n * @type Sector\n * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p1 A circumcircle sector is defined by the circumcircle which is determined\n * by these three given points. The circumcircle sector is always drawn from <tt>p1</tt> through <tt>p2</tt> to <tt>p3</tt>.\n * @example\n * // Create an arc out of three free points\n * var p1 = board.create('point', [1.5, 5.0]),\n * p2 = board.create('point', [1.0, 0.5]),\n * p3 = board.create('point', [5.0, 3.0]),\n *\n * a = board.create('circumcirclesector', [p1, p2, p3]);\n * </pre><div class=\"jxgbox\" id=\"JXG695cf0d6-6d7a-4d4d-bfc9-34c6aa28cd04\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function () {\n * var board = JXG.JSXGraph.initBoard('JXG695cf0d6-6d7a-4d4d-bfc9-34c6aa28cd04', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}),\n * p1 = board.create('point', [1.5, 5.0]),\n * p2 = board.create('point', [1.0, 0.5]),\n * p3 = board.create('point', [5.0, 3.0]),\n *\n * a = board.create('circumcirclesector', [p1, p2, p3]);\n * })();\n * </script><pre>\n */\n JXG.createCircumcircleSector = function (board, parents, attributes) {\n var el, mp, attr, points, i;\n\n points = Type.providePoints(board, parents, attributes, 'point');\n if (points === false) {\n throw new Error(\"JSXGraph: Can't create circumcircle sector with parent types '\" +\n (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"' and '\" + (typeof parents[2]) + \"'.\");\n }\n\n mp = board.create('circumcenter', points.slice(0, 3), attr);\n mp.dump = false;\n\n attr = Type.copyAttributes(attributes, board.options, 'circumcirclesector');\n el = board.create('sector', [mp, points[0], points[2], points[1]], attr);\n\n el.elType = 'circumcirclesector';\n el.setParents(points);\n\n /**\n * Center of the circumcirclesector\n * @memberOf CircumcircleSector.prototype\n * @name center\n * @type Circumcenter\n */\n el.center = mp;\n el.subs = {\n center: mp\n };\n\n return el;\n };\n\n JXG.registerElement('circumcirclesector', JXG.createCircumcircleSector);\n\n /**\n * @class A minor sector is a sector of a circle having measure less than or equal to\n * 180 degrees (pi radians). It is defined by a center, one point that\n * defines the radius, and a third point that defines the angle of the sector.\n * @pseudo\n * @name MinorSector\n * @augments Curve\n * @constructor\n * @type JXG.Curve\n * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 . Minor sector is a sector of a circle around p1 having measure less than or equal to\n * 180 degrees (pi radians) and starts at p2. The radius is determined by p2, the angle by p3.\n * @example\n * // Create sector out of three free points\n * var p1 = board.create('point', [2.0, 2.0]);\n * var p2 = board.create('point', [1.0, 0.5]);\n * var p3 = board.create('point', [3.5, 1.0]);\n *\n * var a = board.create('minorsector', [p1, p2, p3]);\n * </pre><div class=\"jxgbox\" id=\"JXGaf27ddcc-265f-428f-90dd-d31ace945800\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function () {\n * var board = JXG.JSXGraph.initBoard('JXGaf27ddcc-265f-428f-90dd-d31ace945800', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}),\n * p1 = board.create('point', [2.0, 2.0]),\n * p2 = board.create('point', [1.0, 0.5]),\n * p3 = board.create('point', [3.5, 1.0]),\n *\n * a = board.create('minorsector', [p1, p2, p3]);\n * })();\n * </script><pre>\n */\n JXG.createMinorSector = function (board, parents, attributes) {\n attributes.selection = 'minor';\n return JXG.createSector(board, parents, attributes);\n };\n\n JXG.registerElement('minorsector', JXG.createMinorSector);\n\n /**\n * @class A major sector is a sector of a circle having measure greater than or equal to\n * 180 degrees (pi radians). It is defined by a center, one point that\n * defines the radius, and a third point that defines the angle of the sector.\n * @pseudo\n * @name MajorSector\n * @augments Curve\n * @constructor\n * @type JXG.Curve\n * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 . Major sector is a sector of a circle around p1 having measure greater than or equal to\n * 180 degrees (pi radians) and starts at p2. The radius is determined by p2, the angle by p3.\n * @example\n * // Create an arc out of three free points\n * var p1 = board.create('point', [2.0, 2.0]);\n * var p2 = board.create('point', [1.0, 0.5]);\n * var p3 = board.create('point', [3.5, 1.0]);\n *\n * var a = board.create('majorsector', [p1, p2, p3]);\n * </pre><div class=\"jxgbox\" id=\"JXG83c6561f-7561-4047-b98d-036248a00932\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function () {\n * var board = JXG.JSXGraph.initBoard('JXG83c6561f-7561-4047-b98d-036248a00932', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}),\n * p1 = board.create('point', [2.0, 2.0]),\n * p2 = board.create('point', [1.0, 0.5]),\n * p3 = board.create('point', [3.5, 1.0]),\n *\n * a = board.create('majorsector', [p1, p2, p3]);\n * })();\n * </script><pre>\n */\n JXG.createMajorSector = function (board, parents, attributes) {\n attributes.selection = 'major';\n return JXG.createSector(board, parents, attributes);\n };\n\n JXG.registerElement('majorsector', JXG.createMajorSector);\n\n /**\n * @class The angle element is used to denote an angle defined by three points. Visually it is just a {@link Sector}\n * element with a radius not defined by the parent elements but by an attribute <tt>radius</tt>. As opposed to the sector,\n * an angle has two angle points and no radius point.\n * Sector is displayed if type==\"sector\".\n * If type==\"square\", instead of a sector a parallelogram is displayed.\n * In case of type==\"auto\", a square is displayed if the angle is near orthogonal.\n * If no name is provided the angle label is automatically set to a lower greek letter.\n * @pseudo\n * @name Angle\n * @augments Sector\n * @constructor\n * @type Sector\n * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.\n * First possibility of input parameters are:\n * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p1 An angle is always drawn counterclockwise from <tt>p1</tt> to\n * <tt>p3</tt> around <tt>p2</tt>.\n *\n * Second possibility of input parameters are:\n * @param {JXG.Line_JXG.Line_array|number_array|number} line, line2, coords1 or direction1, coords2 or direction2, radius The angle is defined by two lines.\n * The two legs which define the angle are given by two coordinate arrays.\n * The points given by these coordinate arrays are projected initially (i.e. only once) onto the two lines.\n * The other possibility is to supply directions (+/- 1).\n *\n * @example\n * // Create an angle out of three free points\n * var p1 = board.create('point', [5.0, 3.0]),\n * p2 = board.create('point', [1.0, 0.5]),\n * p3 = board.create('point', [1.5, 5.0]),\n *\n * a = board.create('angle', [p1, p2, p3]),\n * t = board.create('text', [4, 4, function() { return JXG.toFixed(a.Value(), 2); }]);\n * </pre><div class=\"jxgbox\" id=\"JXGa34151f9-bb26-480a-8d6e-9b8cbf789ae5\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function () {\n * var board = JXG.JSXGraph.initBoard('JXGa34151f9-bb26-480a-8d6e-9b8cbf789ae5', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}),\n * p1 = board.create('point', [5.0, 3.0]),\n * p2 = board.create('point', [1.0, 0.5]),\n * p3 = board.create('point', [1.5, 5.0]),\n *\n * a = board.create('angle', [p1, p2, p3]),\n * t = board.create('text', [4, 4, function() { return JXG.toFixed(a.Value(), 2); }]);\n * })();\n * </script><pre>\n *\n * @example\n * // Create an angle out of two lines and two directions\n * var p1 = board.create('point', [-1, 4]),\n * p2 = board.create('point', [4, 1]),\n * q1 = board.create('point', [-2, -3]),\n * q2 = board.create('point', [4,3]),\n *\n * li1 = board.create('line', [p1,p2], {strokeColor:'black', lastArrow:true}),\n * li2 = board.create('line', [q1,q2], {lastArrow:true}),\n *\n * a1 = board.create('angle', [li1, li2, [5.5, 0], [4, 3]], { radius:1 }),\n * a2 = board.create('angle', [li1, li2, 1, -1], { radius:2 });\n *\n *\n * </pre><div class=\"jxgbox\" id=\"JXG3a667ddd-63dc-4594-b5f1-afac969b371f\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function () {\n * var board = JXG.JSXGraph.initBoard('JXG3a667ddd-63dc-4594-b5f1-afac969b371f', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}),\n * p1 = board.create('point', [-1, 4]),\n * p2 = board.create('point', [4, 1]),\n * q1 = board.create('point', [-2, -3]),\n * q2 = board.create('point', [4,3]),\n *\n * li1 = board.create('line', [p1,p2], {strokeColor:'black', lastArrow:true}),\n * li2 = board.create('line', [q1,q2], {lastArrow:true}),\n *\n * a1 = board.create('angle', [li1, li2, [5.5, 0], [4, 3]], { radius:1 }),\n * a2 = board.create('angle', [li1, li2, 1, -1], { radius:2 });\n * })();\n * </script><pre>\n *\n *\n * @example\n * // Display the angle value instead of the name\n * var p1 = board.create('point', [0,2]);\n * var p2 = board.create('point', [0,0]);\n * var p3 = board.create('point', [-2,0.2]);\n *\n * var a = board.create('angle', [p1, p2, p3], {\n * \t radius: 1,\n * name: function() {\n * \treturn JXG.Math.Geometry.trueAngle(p1, p2, p3).toFixed(1) + '°';\n * }});\n *\n * </pre><div id=\"JXGc813f601-8dd3-4030-9892-25c6d8671512\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXGc813f601-8dd3-4030-9892-25c6d8671512',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n *\n * var p1 = board.create('point', [0,2]);\n * var p2 = board.create('point', [0,0]);\n * var p3 = board.create('point', [-2,0.2]);\n *\n * var a = board.create('angle', [p1, p2, p3], {\n * \tradius: 1,\n * name: function() {\n * \treturn JXG.Math.Geometry.trueAngle(p1, p2, p3).toFixed(1) + '°';\n * }});\n *\n * })();\n *\n * </script><pre>\n *\n *\n * @example\n * // Apply a transformation to an angle.\n * var t = board.create('transform', [2, 1.5], {type: 'scale'});\n * var an1 = board.create('angle', [[-4,3.9], [-3, 4], [-3, 3]]);\n * var an2 = board.create('curve', [an1, t]);\n *\n * </pre><div id=\"JXG4c8d9ed8-6339-11e8-9fb9-901b0e1b8723\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG4c8d9ed8-6339-11e8-9fb9-901b0e1b8723',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var t = board.create('transform', [2, 1.5], {type: 'scale'});\n * var an1 = board.create('angle', [[-4,3.9], [-3, 4], [-3, 3]]);\n * var an2 = board.create('curve', [an1, t]);\n *\n * })();\n *\n * </script><pre>\n *\n */\n JXG.createAngle = function (board, parents, attributes) {\n var el, radius, attr, attrsub,\n i, points,\n type = 'invalid';\n\n // Two lines or three points?\n if (parents[0].elementClass === Const.OBJECT_CLASS_LINE &&\n parents[1].elementClass === Const.OBJECT_CLASS_LINE &&\n (Type.isArray(parents[2]) || Type.isNumber(parents[2])) &&\n (Type.isArray(parents[3]) || Type.isNumber(parents[3]))) {\n\n type = '2lines';\n } else {\n points = Type.providePoints(board, parents, attributes, 'point');\n if (points === false) {\n throw new Error(\"JSXGraph: Can't create angle with parent types '\" +\n (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"' and '\" + (typeof parents[2]) + \"'.\");\n }\n type = '3points';\n }\n\n attr = Type.copyAttributes(attributes, board.options, 'angle');\n\n // If empty, create a new name\n if (!Type.exists(attr.name) || attr.name === '') {\n attr.name = board.generateName({type: Const.OBJECT_TYPE_ANGLE});\n }\n\n if (Type.exists(attr.radius)) {\n radius = attr.radius;\n } else {\n radius = 0;\n }\n\n if (type === '2lines') {\n parents.push(radius);\n el = board.create('sector', parents, attr);\n el.updateDataArraySector = el.updateDataArray;\n\n // TODO\n el.setAngle = function (val) {};\n el.free = function (val) {};\n\n } else {\n el = board.create('sector', [points[1], points[0], points[2]], attr);\n el.arc.visProp.priv = true;\n\n /**\n * The point defining the radius of the angle element.\n * Alias for {@link Sector#radiuspoint}.\n * @type JXG.Point\n * @name point\n * @memberOf Angle.prototype\n *\n */\n el.point = el.point2 = el.radiuspoint = points[0];\n\n /**\n * Helper point for angles of type 'square'.\n * @type JXG.Point\n * @name pointsquare\n * @memberOf Angle.prototype\n */\n el.pointsquare = el.point3 = el.anglepoint = points[2];\n\n /**\n * @ignore\n */\n el.Radius = function () {\n // Set the angle radius, also @see @link Sector#autoRadius\n var r = Type.evaluate(radius);\n if (r === 'auto') {\n return el.autoRadius();\n }\n return r;\n };\n\n el.updateDataArraySector = function () {\n var A = this.point2,\n B = this.point1,\n C = this.point3,\n r = this.Radius(),\n d = B.Dist(A),\n ar,\n phi,\n sgn = 1,\n vp_s = Type.evaluate(this.visProp.selection);\n\n phi = Geometry.rad(A, B, C);\n if ((vp_s === 'minor' && phi > Math.PI) ||\n (vp_s === 'major' && phi < Math.PI)) {\n sgn = -1;\n }\n\n A = A.coords.usrCoords;\n B = B.coords.usrCoords;\n C = C.coords.usrCoords;\n\n A = [1, B[1] + (A[1] - B[1]) * r / d, B[2] + (A[2] - B[2]) * r / d];\n C = [1, B[1] + (C[1] - B[1]) * r / d, B[2] + (C[2] - B[2]) * r / d];\n\n ar = Geometry.bezierArc(A, B, C, true, sgn);\n\n this.dataX = ar[0];\n this.dataY = ar[1];\n this.bezierDegree = 3;\n };\n\n /**\n * Set an angle to a prescribed value given in radians.\n * This is only possible if the third point of the angle, i.e.\n * the anglepoint is a free point.\n * Removing the constraint again is done by calling \"angle.free()\".\n *\n * Changing the angle requires to call the method \"free()\":\n *\n * <pre>\n * angle.setAngle(Math.PI / 6);\n * // ...\n * angle.free().setAngle(Math.PI / 4);\n * </pre>\n *\n * @name setAngle\n * @function\n * @param {Number|Function} val Number or Function which returns the size of the angle in Radians\n * @returns {Object} Pointer to the angle element..\n * @memberOf Angle.prototype\n * @see Angle#free\n *\n * @example\n * var p1, p2, p3, c, a, s;\n *\n * p1 = board.create('point',[0,0]);\n * p2 = board.create('point',[5,0]);\n * p3 = board.create('point',[0,5]);\n *\n * c1 = board.create('circle',[p1, p2]);\n *\n * a = board.create('angle',[p2, p1, p3], {radius:3});\n *\n * a.setAngle(function() {\n * return Math.PI / 3;\n * });\n * board.update();\n *\n * </pre><div id=\"JXG987c-394f-11e6-af4a-901b0e1b8723\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG987c-394f-11e6-af4a-901b0e1b8723',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var p1, p2, p3, c, a, s;\n *\n * p1 = board.create('point',[0,0]);\n * p2 = board.create('point',[5,0]);\n * p3 = board.create('point',[0,5]);\n *\n * c1 = board.create('circle',[p1, p2]);\n *\n * a = board.create('angle',[p2, p1, p3], {radius: 3});\n *\n * a.setAngle(function() {\n * return Math.PI / 3;\n * });\n * board.update();\n *\n * })();\n *\n * </script><pre>\n *\n * @example\n * var p1, p2, p3, c, a, s;\n *\n * p1 = board.create('point',[0,0]);\n * p2 = board.create('point',[5,0]);\n * p3 = board.create('point',[0,5]);\n *\n * c1 = board.create('circle',[p1, p2]);\n *\n * a = board.create('angle',[p2, p1, p3], {radius:3});\n * s = board.create('slider',[[-2,1], [2,1], [0, Math.PI*0.5, 2*Math.PI]]);\n *\n * a.setAngle(function() {\n * return s.Value();\n * });\n * board.update();\n *\n * </pre><div id=\"JXG99957b1c-394f-11e6-af4a-901b0e1b8723\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG99957b1c-394f-11e6-af4a-901b0e1b8723',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var p1, p2, p3, c, a, s;\n *\n * p1 = board.create('point',[0,0]);\n * p2 = board.create('point',[5,0]);\n * p3 = board.create('point',[0,5]);\n *\n * c1 = board.create('circle',[p1, p2]);\n *\n * a = board.create('angle',[p2, p1, p3], {radius: 3});\n * s = board.create('slider',[[-2,1], [2,1], [0, Math.PI*0.5, 2*Math.PI]]);\n *\n * a.setAngle(function() {\n * return s.Value();\n * });\n * board.update();\n *\n * })();\n *\n * </script><pre>\n *\n */\n el.setAngle = function (val) {\n var t1, t2, val2,\n p = this.anglepoint,\n q = this.radiuspoint;\n\n if (p.draggable()) {\n t1 = this.board.create('transform', [val, this.center], {type: 'rotate'});\n p.addTransform(q, t1);\n // Immediately apply the transformation.\n // This prevents that jumping elements can be watched.\n t1.update();\n p.moveTo(Mat.matVecMult(t1.matrix, q.coords.usrCoords));\n\n if (Type.isFunction(val)) {\n /**\n * @ignore\n */\n val2 = function() { return Math.PI * 2 - val(); };\n } else {\n /**\n * @ignore\n */\n val2 = function() { return Math.PI * 2 - val; };\n }\n t2 = this.board.create('transform', [val2, this.center], {type: 'rotate'});\n p.coords.on('update', function() {\n t2.update();\n q.moveTo(Mat.matVecMult(t2.matrix, p.coords.usrCoords));\n });\n\n p.setParents(q);\n }\n return this;\n };\n\n /**\n * Frees an angle from a prescribed value. This is only relevant if the angle size has been set by\n * \"setAngle()\" previously. The anglepoint is set to a free point.\n * @name free\n * @function\n * @returns {Object} Pointer to the angle element..\n * @memberOf Angle.prototype\n * @see Angle#setAngle\n */\n el.free = function () {\n var p = this.anglepoint;\n\n if (p.transformations.length > 0) {\n p.transformations.pop();\n p.isDraggable = true;\n p.parents = [];\n\n p.coords.off('update');\n }\n\n return this;\n };\n\n el.setParents(points); // Important: This overwrites the parents order in underlying sector\n\n } // end '3points'\n\n // GEONExT compatible labels.\n if (Type.exists(el.visProp.text)) {\n el.label.setText(Type.evaluate(el.visProp.text));\n }\n\n el.elType = 'angle';\n el.type = Const.OBJECT_TYPE_ANGLE;\n el.subs = {};\n\n el.updateDataArraySquare = function () {\n var A, B, C,\n r = this.Radius(),\n d1, d2,\n v, l1, l2;\n\n\n if (type === '2lines') {\n // This is necessary to update this.point1, this.point2, this.point3.\n this.updateDataArraySector();\n }\n\n A = this.point2;\n B = this.point1;\n C = this.point3;\n\n A = A.coords.usrCoords;\n B = B.coords.usrCoords;\n C = C.coords.usrCoords;\n\n d1 = Geometry.distance(A, B, 3);\n d2 = Geometry.distance(C, B, 3);\n\n // In case of type=='2lines' this is redundant, because r == d1 == d2\n A = [1, B[1] + (A[1] - B[1]) * r / d1, B[2] + (A[2] - B[2]) * r / d1];\n C = [1, B[1] + (C[1] - B[1]) * r / d2, B[2] + (C[2] - B[2]) * r / d2];\n\n v = Mat.crossProduct(C, B);\n l1 = [-A[1] * v[1] - A[2] * v[2], A[0] * v[1], A[0] * v[2]];\n v = Mat.crossProduct(A, B);\n l2 = [-C[1] * v[1] - C[2] * v[2], C[0] * v[1], C[0] * v[2]];\n\n v = Mat.crossProduct(l1, l2);\n v[1] /= v[0];\n v[2] /= v[0];\n\n this.dataX = [B[1], A[1], v[1], C[1], B[1]];\n this.dataY = [B[2], A[2], v[2], C[2], B[2]];\n\n this.bezierDegree = 1;\n };\n\n el.updateDataArrayNone = function () {\n this.dataX = [NaN];\n this.dataY = [NaN];\n this.bezierDegree = 1;\n };\n\n el.updateDataArray = function () {\n var type = Type.evaluate(this.visProp.type),\n deg = Geometry.trueAngle(this.point2, this.point1, this.point3),\n vp_s = Type.evaluate(this.visProp.selection);\n\n if ((vp_s === 'minor' && deg > 180.0) ||\n (vp_s === 'major' && deg < 180.0)) {\n deg = 360.0 - deg;\n }\n\n if (Math.abs(deg - 90.0) < Type.evaluate(this.visProp.orthosensitivity) + Mat.eps) {\n type = Type.evaluate(this.visProp.orthotype);\n }\n\n if (type === 'none') {\n this.updateDataArrayNone();\n } else if (type === 'square') {\n this.updateDataArraySquare();\n } else if (type === 'sector') {\n this.updateDataArraySector();\n } else if (type === 'sectordot') {\n this.updateDataArraySector();\n if (!this.dot.visProp.visible) {\n this.dot.setAttribute({visible: true});\n }\n }\n\n if (!this.visProp.visible || (type !== 'sectordot' && this.dot.visProp.visible)) {\n this.dot.setAttribute({visible: false});\n }\n };\n\n /**\n * Indicates a right angle. Invisible by default, use <tt>dot.visible: true</tt> to show.\n * Though this dot indicates a right angle, it can be visible even if the angle is not a right\n * one.\n * @type JXG.Point\n * @name dot\n * @memberOf Angle.prototype\n */\n attrsub = Type.copyAttributes(attributes, board.options, 'angle', 'dot');\n el.dot = board.create('point', [function () {\n var A, B, r, d, a2, co, si, mat,\n vp_s;\n\n if (Type.exists(el.dot) && !el.dot.visProp.visible) {\n return [0, 0];\n }\n\n A = el.point2.coords.usrCoords;\n B = el.point1.coords.usrCoords;\n r = el.Radius();\n d = Geometry.distance(A, B, 3);\n a2 = Geometry.rad(el.point2, el.point1, el.point3);\n\n vp_s = Type.evaluate(el.visProp.selection);\n if ((vp_s === 'minor' && a2 > Math.PI) ||\n (vp_s === 'major' && a2 < Math.PI)) {\n a2 = -(2 * Math.PI - a2);\n }\n a2 *= 0.5;\n\n co = Math.cos(a2);\n si = Math.sin(a2);\n\n A = [1, B[1] + (A[1] - B[1]) * r / d, B[2] + (A[2] - B[2]) * r / d];\n\n mat = [\n [1, 0, 0],\n [B[1] - 0.5 * B[1] * co + 0.5 * B[2] * si, co * 0.5, -si * 0.5],\n [B[2] - 0.5 * B[1] * si - 0.5 * B[2] * co, si * 0.5, co * 0.5]\n ];\n return Mat.matVecMult(mat, A);\n }], attrsub);\n\n el.dot.dump = false;\n el.subs.dot = el.dot;\n\n if (type === '2lines') {\n for (i = 0; i < 2; i++) {\n board.select(parents[i]).addChild(el.dot);\n }\n } else {\n for (i = 0; i < 3; i++) {\n board.select(points[i]).addChild(el.dot);\n }\n }\n\n // documented in GeometryElement\n el.getLabelAnchor = function () {\n var vec, dx = 12,\n A, B, r, d, a2, co, si, mat,\n vp_s = Type.evaluate(el.visProp.selection),\n l_vp = this.label ? this.label.visProp : this.visProp.label;\n\n // If this is uncommented, the angle label can not be dragged\n //if (Type.exists(this.label)) {\n // this.label.relativeCoords = new Coords(Const.COORDS_BY_SCREEN, [0, 0], this.board);\n //}\n\n if (Type.exists(this.label.visProp.fontSize)) {\n dx = Type.evaluate(this.label.visProp.fontSize);\n }\n dx /= this.board.unitX;\n\n A = el.point2.coords.usrCoords;\n B = el.point1.coords.usrCoords;\n r = el.Radius();\n d = Geometry.distance(A, B, 3);\n a2 = Geometry.rad(el.point2, el.point1, el.point3);\n if ((vp_s === 'minor' && a2 > Math.PI) ||\n (vp_s === 'major' && a2 < Math.PI)) {\n a2 = -(2 * Math.PI - a2);\n }\n a2 *= 0.5;\n co = Math.cos(a2);\n si = Math.sin(a2);\n\n A = [1, B[1] + (A[1] - B[1]) * r / d, B[2] + (A[2] - B[2]) * r / d];\n\n mat = [\n [1, 0, 0],\n [B[1] - 0.5 * B[1] * co + 0.5 * B[2] * si, co * 0.5, -si * 0.5],\n [B[2] - 0.5 * B[1] * si - 0.5 * B[2] * co, si * 0.5, co * 0.5]\n ];\n vec = Mat.matVecMult(mat, A);\n vec[1] /= vec[0];\n vec[2] /= vec[0];\n vec[0] /= vec[0];\n\n d = Geometry.distance(vec, B, 3);\n vec = [vec[0], B[1] + (vec[1] - B[1]) * (r + dx) / d, B[2] + (vec[2] - B[2]) * (r + dx) / d];\n\n l_vp.position = Geometry.calcLabelQuadrant(Geometry.rad([1,0], [0,0], vec));\n\n return new Coords(Const.COORDS_BY_USER, vec, this.board);\n };\n\n /**\n * Returns the value of the angle in Radians.\n * @memberOf Angle.prototype\n * @name Value\n * @function\n * @returns {Number} The angle value in Radians\n */\n el.Value = function () {\n return Geometry.rad(this.point2, this.point1, this.point3);\n };\n\n el.methodMap = Type.deepCopy(el.methodMap, {\n Value: 'Value',\n setAngle: 'setAngle',\n free: 'free'\n });\n\n return el;\n };\n\n JXG.registerElement('angle', JXG.createAngle);\n\n /**\n * @class A non-reflex angle is the acute or obtuse instance of an angle.\n * It is defined by a center, one point that\n * defines the radius, and a third point that defines the angle of the sector.\n * @pseudo\n * @name NonReflexAngle\n * @augments Angle\n * @constructor\n * @type Sector\n * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 . Minor sector is a sector of a circle around p1 having measure less than or equal to\n * 180 degrees (pi radians) and starts at p2. The radius is determined by p2, the angle by p3.\n * @example\n * // Create a non-reflex angle out of three free points\n * var p1 = board.create('point', [5.0, 3.0]),\n * p2 = board.create('point', [1.0, 0.5]),\n * p3 = board.create('point', [1.5, 5.0]),\n *\n * a = board.create('nonreflexangle', [p1, p2, p3], {radius: 2}),\n * t = board.create('text', [4, 4, function() { return JXG.toFixed(a.Value(), 2); }]);\n * </pre><div class=\"jxgbox\" id=\"JXGd0ab6d6b-63a7-48b2-8749-b02bb5e744f9\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function () {\n * var board = JXG.JSXGraph.initBoard('JXGd0ab6d6b-63a7-48b2-8749-b02bb5e744f9', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}),\n * p1 = board.create('point', [5.0, 3.0]),\n * p2 = board.create('point', [1.0, 0.5]),\n * p3 = board.create('point', [1.5, 5.0]),\n *\n * a = board.create('nonreflexangle', [p1, p2, p3], {radius: 2}),\n * t = board.create('text', [4, 4, function() { return JXG.toFixed(a.Value(), 2); }]);\n * })();\n * </script><pre>\n */\n JXG.createNonreflexAngle = function (board, parents, attributes) {\n var el;\n\n attributes.selection = 'minor';\n el = JXG.createAngle(board, parents, attributes);\n\n // Documented in createAngle\n el.Value = function () {\n var v = Geometry.rad(this.point2, this.point1, this.point3);\n return (v < Math.PI) ? v : 2.0 * Math.PI - v;\n };\n return el;\n };\n\n JXG.registerElement('nonreflexangle', JXG.createNonreflexAngle);\n\n /**\n * @class A reflex angle is the neither acute nor obtuse instance of an angle.\n * It is defined by a center, one point that\n * defines the radius, and a third point that defines the angle of the sector.\n * @pseudo\n * @name ReflexAngle\n * @augments Angle\n * @constructor\n * @type Sector\n * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 . Minor sector is a sector of a circle around p1 having measure less than or equal to\n * 180 degrees (pi radians) and starts at p2. The radius is determined by p2, the angle by p3.\n * @example\n * // Create a non-reflex angle out of three free points\n * var p1 = board.create('point', [5.0, 3.0]),\n * p2 = board.create('point', [1.0, 0.5]),\n * p3 = board.create('point', [1.5, 5.0]),\n *\n * a = board.create('reflexangle', [p1, p2, p3], {radius: 2}),\n * t = board.create('text', [4, 4, function() { return JXG.toFixed(a.Value(), 2); }]);\n * </pre><div class=\"jxgbox\" id=\"JXGf2a577f2-553d-4f9f-a895-2d6d4b8c60e8\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function () {\n * var board = JXG.JSXGraph.initBoard('JXGf2a577f2-553d-4f9f-a895-2d6d4b8c60e8', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}),\n * p1 = board.create('point', [5.0, 3.0]),\n * p2 = board.create('point', [1.0, 0.5]),\n * p3 = board.create('point', [1.5, 5.0]),\n *\n * a = board.create('reflexangle', [p1, p2, p3], {radius: 2}),\n * t = board.create('text', [4, 4, function() { return JXG.toFixed(a.Value(), 2); }]);\n * })();\n * </script><pre>\n */\n JXG.createReflexAngle = function (board, parents, attributes) {\n var el;\n\n attributes.selection = 'major';\n el = JXG.createAngle(board, parents, attributes);\n\n // Documented in createAngle\n el.Value = function () {\n var v = Geometry.rad(this.point2, this.point1, this.point3);\n return (v >= Math.PI) ? v : 2.0 * Math.PI - v;\n };\n return el;\n };\n\n JXG.registerElement('reflexangle', JXG.createReflexAngle);\n\n return {\n createSector: JXG.createSector,\n createCircumcircleSector: JXG.createCircumcircleSector,\n createMinorSector: JXG.createMinorSector,\n createMajorSector: JXG.createMajorSector,\n createAngle: JXG.createAngle,\n createReflexAngle: JXG.createReflexAngle,\n createNonreflexAngle: JXG.createNonreflexAngle\n };\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true*/\n/*jslint nomen: true, plusplus: true*/\n\n/*depends:\n jxg\n base/constants\n math/math\n utils/type\n */\n\n/**\n * @fileoverview This file contains code for transformations of geometrical objects.\n */\n\ndefine('base/transformation',[\n 'jxg', 'base/constants', 'math/math', 'utils/type'\n], function (JXG, Const, Mat, Type) {\n\n \"use strict\";\n\n /**\n * A transformation consists of a 3x3 matrix, i.e. it is a projective transformation.\n * @class Creates a new transformation object. Do not use this constructor to create a transformation.\n * Use {@link JXG.Board#create} with\n * type {@link Transformation} instead.\n * @constructor\n * @param {JXG.Board} board The board the new circle is drawn on.\n * @param {String} type Can be\n * <ul><li> 'translate'\n * <li> 'scale'\n * <li> 'reflect'\n * <li> 'rotate'\n * <li> 'shear'\n * <li> 'generic'\n * </ul>\n * @param {Object} params The parameters depend on the transformation type\n *\n * <p>\n * Translation matrix:\n * <pre>\n * ( 1 0 0) ( z )\n * ( a 1 0) * ( x )\n * ( b 0 1) ( y )\n * </pre>\n *\n * <p>\n * Scale matrix:\n * <pre>\n * ( 1 0 0) ( z )\n * ( 0 a 0) * ( x )\n * ( 0 0 b) ( y )\n * </pre>\n *\n * <p>\n * A rotation matrix with angle a (in Radians)\n * <pre>\n * ( 1 0 0 ) ( z )\n * ( 0 cos(a) -sin(a)) * ( x )\n * ( 0 sin(a) cos(a) ) ( y )\n * </pre>\n *\n * <p>\n * Shear matrix:\n * <pre>\n * ( 1 0 0) ( z )\n * ( 0 1 a) * ( x )\n * ( 0 b 1) ( y )\n * </pre>\n *\n * <p>Generic transformation:\n * <pre>\n * ( a b c ) ( z )\n * ( d e f ) * ( x )\n * ( g h i ) ( y )\n * </pre>\n *\n */\n JXG.Transformation = function (board, type, params) {\n this.elementClass = Const.OBJECT_CLASS_OTHER;\n this.type = Const.OBJECT_TYPE_TRANSFORMATION;\n this.matrix = [\n [1, 0, 0],\n [0, 1, 0],\n [0, 0, 1]\n ];\n this.board = board;\n this.isNumericMatrix = false;\n this.setMatrix(board, type, params);\n\n this.methodMap = {\n apply: 'apply',\n applyOnce: 'applyOnce',\n bindTo: 'bindTo',\n bind: 'bindTo',\n melt: 'melt'\n };\n };\n\n JXG.Transformation.prototype = {};\n\n JXG.extend(JXG.Transformation.prototype, /** @lends JXG.Transformation.prototype */ {\n /**\n * Updates the numerical data for the transformation, i.e. the entry of the subobject matrix.\n * @returns {JXG.Transform} returns pointer to itself\n */\n update: function () {\n return this;\n },\n\n /**\n * Set the transformation matrix for different types of standard transforms.\n * @param {JXG.Board} board\n * @param {String} type Transformation type, possible values are\n * 'translate', 'scale', 'reflect', 'rotate',\n * 'shear', 'generic'.\n * @param {Array} params Parameters for the various transformation types.\n *\n * <p>These are\n * @param {Array} x,y Shift vector (number or function) in case of 'translate'.\n * @param {Array} scale_x,scale_y Scale vector (number or function) in case of 'scale'.\n * @param {Array} line|point_pair|\"four coordinates\" In case of 'reflect' the parameters could\n * be a line, a pair of points or four number (or functions) p_x, p_y, q_x, q_y,\n * determining a line through points (p_x, p_y) and (q_x, q_y).\n * @param {Array} angle,x,y|angle,[x,y] In case of 'rotate' the parameters are an angle or angle function,\n * returning the angle in Radians and - optionally - a coordinate pair or a point defining the\n * rotation center. If the rotation center is not given, the transformation rotates around (0,0).\n * @param {Array} shear_x,shear_y Shear vector (number or function) in case of 'shear'.\n * @param {Array} a,b,c,d,e,f,g,h,i Nine matrix entries (numbers or functions) for a generic\n * projective transformation in case of 'generic'.\n *\n * <p>A transformation with a generic matrix looks like:\n * <pre>\n * ( a b c ) ( z )\n * ( d e f ) * ( x )\n * ( g h i ) ( y )\n * </pre>\n *\n */\n setMatrix: function (board, type, params) {\n var i;\n\n this.isNumericMatrix = true;\n\n for (i = 0; i < params.length; i++) {\n if (typeof params[i] !== 'number') {\n this.isNumericMatrix = false;\n break;\n }\n }\n\n if (type === 'translate') {\n if (params.length !== 2) {\n throw new Error(\"JSXGraph: translate transformation needs 2 parameters.\");\n }\n this.evalParam = Type.createEvalFunction(board, params, 2);\n this.update = function () {\n this.matrix[1][0] = this.evalParam(0);\n this.matrix[2][0] = this.evalParam(1);\n };\n } else if (type === 'scale') {\n if (params.length !== 2) {\n throw new Error(\"JSXGraph: scale transformation needs 2 parameters.\");\n }\n this.evalParam = Type.createEvalFunction(board, params, 2);\n this.update = function () {\n this.matrix[1][1] = this.evalParam(0); // x\n this.matrix[2][2] = this.evalParam(1); // y\n };\n // Input: line or two points\n } else if (type === 'reflect') {\n // line or two points\n if (params.length < 4) {\n params[0] = board.select(params[0]);\n }\n\n // two points\n if (params.length === 2) {\n params[1] = board.select(params[1]);\n }\n\n // 4 coordinates [px,py,qx,qy]\n if (params.length === 4) {\n this.evalParam = Type.createEvalFunction(board, params, 4);\n }\n\n this.update = function () {\n var x, y, z, xoff, yoff, d,\n v, p;\n // Determine homogeneous coordinates of reflections axis\n // line\n if (params.length === 1) {\n v = params[0].stdform;\n // two points\n } else if (params.length === 2) {\n v = Mat.crossProduct(params[1].coords.usrCoords, params[0].coords.usrCoords);\n // two points coordinates [px,py,qx,qy]\n } else if (params.length === 4) {\n v = Mat.crossProduct(\n [1, this.evalParam(2), this.evalParam(3)],\n [1, this.evalParam(0), this.evalParam(1)]\n );\n }\n\n // Project origin to the line. This gives a finite point p\n x = v[1];\n y = v[2];\n z = v[0];\n p = [-z * x, -z * y, x * x + y * y];\n d = p[2];\n\n // Normalize p\n xoff = p[0] / p[2];\n yoff = p[1] / p[2];\n\n // x, y is the direction of the line\n x = -v[2];\n y = v[1];\n\n this.matrix[1][1] = (x * x - y * y) / d;\n this.matrix[1][2] = 2 * x * y / d;\n this.matrix[2][1] = this.matrix[1][2];\n this.matrix[2][2] = -this.matrix[1][1];\n this.matrix[1][0] = xoff * (1 - this.matrix[1][1]) - yoff * this.matrix[1][2];\n this.matrix[2][0] = yoff * (1 - this.matrix[2][2]) - xoff * this.matrix[2][1];\n };\n } else if (type === 'rotate') {\n // angle, x, y\n if (params.length === 3) {\n this.evalParam = Type.createEvalFunction(board, params, 3);\n // angle, p or angle\n } else if (params.length > 0 && params.length <= 2) {\n this.evalParam = Type.createEvalFunction(board, params, 1);\n\n if (params.length === 2 && !Type.isArray(params[1])) {\n params[1] = board.select(params[1]);\n }\n }\n\n this.update = function () {\n var x, y,\n beta = this.evalParam(0),\n co = Math.cos(beta),\n si = Math.sin(beta);\n\n this.matrix[1][1] = co;\n this.matrix[1][2] = -si;\n this.matrix[2][1] = si;\n this.matrix[2][2] = co;\n\n // rotate around [x,y] otherwise rotate around [0,0]\n if (params.length > 1) {\n if (params.length === 3) {\n x = this.evalParam(1);\n y = this.evalParam(2);\n } else {\n if (Type.isArray(params[1])) {\n x = params[1][0];\n y = params[1][1];\n } else {\n x = params[1].X();\n y = params[1].Y();\n }\n }\n this.matrix[1][0] = x * (1 - co) + y * si;\n this.matrix[2][0] = y * (1 - co) - x * si;\n }\n };\n } else if (type === 'shear') {\n if (params.length !== 2) {\n throw new Error(\"JSXGraph: shear transformation needs 2 parameters.\");\n }\n\n this.evalParam = Type.createEvalFunction(board, params, 2);\n this.update = function () {\n this.matrix[1][2] = this.evalParam(0);\n this.matrix[2][1] = this.evalParam(1);\n };\n } else if (type === 'generic') {\n if (params.length !== 9) {\n throw new Error(\"JSXGraph: generic transformation needs 9 parameters.\");\n }\n\n this.evalParam = Type.createEvalFunction(board, params, 9);\n\n this.update = function () {\n this.matrix[0][0] = this.evalParam(0);\n this.matrix[0][1] = this.evalParam(1);\n this.matrix[0][2] = this.evalParam(2);\n this.matrix[1][0] = this.evalParam(3);\n this.matrix[1][1] = this.evalParam(4);\n this.matrix[1][2] = this.evalParam(5);\n this.matrix[2][0] = this.evalParam(6);\n this.matrix[2][1] = this.evalParam(7);\n this.matrix[2][2] = this.evalParam(8);\n };\n }\n },\n\n /**\n * Transform a GeometryElement:\n * First, the transformation matrix is updated, then do the matrix-vector-multiplication.\n * @private\n * @param {JXG.GeometryElement} p element which is transformed\n * @param {String} 'self' Apply the transformation to the initialCoords instead of the coords if this is set.\n * @returns {Array}\n */\n apply: function (p, self) {\n this.update();\n\n if (Type.exists(self)) {\n return Mat.matVecMult(this.matrix, p.initialCoords.usrCoords);\n }\n return Mat.matVecMult(this.matrix, p.coords.usrCoords);\n },\n\n /**\n * Applies a transformation once to a GeometryElement or an array of elements.\n * If it is a free point, then it can be dragged around later\n * and will overwrite the transformed coordinates.\n * @param {JXG.Point,Array} p\n */\n applyOnce: function (p) {\n var c, len, i;\n\n if (!Type.isArray(p)) {\n p = [p];\n }\n\n len = p.length;\n\n for (i = 0; i < len; i++) {\n this.update();\n c = Mat.matVecMult(this.matrix, p[i].coords.usrCoords);\n p[i].coords.setCoordinates(Const.COORDS_BY_USER, c);\n }\n },\n\n /**\n * Binds a transformation to a GeometryElement or an array of elements. In every update of the\n * GeometryElement(s), the transformation is executed. That means, in order to immediately\n * apply the transformation, a call of board.update() has to follow.\n * @param {Array,JXG.Object} p JXG.Object or array of JXG.Object to\n * which the transformation is bound to.\n */\n bindTo: function (p) {\n var i, len;\n if (Type.isArray(p)) {\n len = p.length;\n\n for (i = 0; i < len; i++) {\n p[i].transformations.push(this);\n }\n } else {\n p.transformations.push(this);\n }\n },\n\n /**\n * Unused\n * @deprecated Use setAttribute\n * @param term\n */\n setProperty: function (term) {\n JXG.deprecated('Transformation.setProperty()', 'Transformation.setAttribute()');\n },\n\n /**\n * Empty method. Unused.\n * @param {Object} term Key-value pairs of the attributes.\n */\n setAttribute: function (term) { },\n\n /**\n * Combine two transformations to one transformation. This only works if\n * both of transformation matrices consist solely of numbers, and do not\n * contain functions.\n *\n * Multiplies the transformation with a transformation t from the left.\n * i.e. (this) = (t) join (this)\n * @param {JXG.Transform} t Transformation which is the left multiplicand\n * @returns {JXG.Transform} the transformation object.\n */\n melt: function (t) {\n var res = [], i, len, len0, k, s, j;\n\n len = t.matrix.length;\n len0 = this.matrix[0].length;\n\n for (i = 0; i < len; i++) {\n res[i] = [];\n }\n\n this.update();\n t.update();\n\n for (i = 0; i < len; i++) {\n for (j = 0; j < len0; j++) {\n s = 0;\n for (k = 0; k < len; k++) {\n s += t.matrix[i][k] * this.matrix[k][j];\n }\n res[i][j] = s;\n }\n }\n\n this.update = function () {\n var len = this.matrix.length,\n len0 = this.matrix[0].length;\n\n for (i = 0; i < len; i++) {\n for (j = 0; j < len0; j++) {\n this.matrix[i][j] = res[i][j];\n }\n }\n };\n return this;\n },\n\n // documented in element.js\n // Not yet, since transformations are not listed in board.objects.\n getParents: function () {\n var p = [[].concat.apply([], this.matrix)];\n\n if (this.parents.length !== 0) {\n p = this.parents;\n }\n\n return p;\n }\n\n });\n\n /**\n * @class This element is used to provide projective transformations.\n * @pseudo\n * @description A transformation consists of a 3x3 matrix, i.e. it is a projective transformation.\n * @name Transformation\n * @augments JXG.Transformation\n * @constructor\n * @type JXG.Transformation\n * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {numbers,functions} parameters The parameters depend on the transformation type, supplied as attribute 'type'.\n * Possible transformation types are\n * <ul><li> 'translate'\n * <li> 'scale'\n * <li> 'reflect'\n * <li> 'rotate'\n * <li> 'shear'\n * <li> 'generic'\n * </ul>\n * The transformation matrix then looks like:\n * <p>\n * Translation matrix:\n * <pre>\n * ( 1 0 0) ( z )\n * ( a 1 0) * ( x )\n * ( b 0 1) ( y )\n * </pre>\n *\n * <p>\n * Scale matrix:\n * <pre>\n * ( 1 0 0) ( z )\n * ( 0 a 0) * ( x )\n * ( 0 0 b) ( y )\n * </pre>\n *\n * <p>\n * A rotation matrix with angle a (in Radians)\n * <pre>\n * ( 1 0 0 ) ( z )\n * ( 0 cos(a) -sin(a)) * ( x )\n * ( 0 sin(a) cos(a) ) ( y )\n * </pre>\n *\n * <p>\n * Shear matrix:\n * <pre>\n * ( 1 0 0) ( z )\n * ( 0 1 a) * ( x )\n * ( 0 b 1) ( y )\n * </pre>\n *\n * <p>Generic transformation:\n * <pre>\n * ( a b c ) ( z )\n * ( d e f ) * ( x )\n * ( g h i ) ( y )\n * </pre>\n *\n * @see JXG.Transformation#setMatrix\n *\n * @example\n * // The point B is determined by taking twice the vector A from the origin\n *\n * var p0 = board.create('point', [0, 3], {name: 'A'}),\n * t = board.create('transform', [function(){ return p0.X(); }, \"Y(A)\"], {type: 'translate'}),\n * p1 = board.create('point', [p0, t], {color: 'blue'});\n *\n * </pre><div class=\"jxgbox\" id=\"JXG14167b0c-2ad3-11e5-8dd9-901b0e1b8723\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG14167b0c-2ad3-11e5-8dd9-901b0e1b8723',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var p0 = board.create('point', [0, 3], {name: 'A'}),\n * t = board.create('transform', [function(){ return p0.X(); }, \"Y(A)\"], {type:'translate'}),\n * p1 = board.create('point', [p0, t], {color: 'blue'});\n *\n * })();\n *\n * </script><pre>\n *\n * @example\n * // The point B is the result of scaling the point A with factor 2 in horizontal direction\n * // and with factor 0.5 in vertical direction.\n *\n * var p1 = board.create('point', [1, 1]),\n * t = board.create('transform', [2, 0.5], {type: 'scale'}),\n * p2 = board.create('point', [p1, t], {color: 'blue'});\n *\n * </pre><div class=\"jxgbox\" id=\"JXGa6827a72-2ad3-11e5-8dd9-901b0e1b8723\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXGa6827a72-2ad3-11e5-8dd9-901b0e1b8723',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var p1 = board.create('point', [1, 1]),\n * t = board.create('transform', [2, 0.5], {type: 'scale'}),\n * p2 = board.create('point', [p1, t], {color: 'blue'});\n *\n * })();\n *\n * </script><pre>\n *\n * @example\n * // The point B is rotated around C which gives point D. The angle is determined\n * // by the vertical height of point A.\n *\n * var p0 = board.create('point', [0, 3], {name: 'A'}),\n * p1 = board.create('point', [1, 1]),\n * p2 = board.create('point', [2, 1], {name:'C', fixed: true}),\n *\n * // angle, rotation center:\n * t = board.create('transform', ['Y(A)', p2], {type: 'rotate'}),\n * p3 = board.create('point', [p1, t], {color: 'blue'});\n *\n * </pre><div class=\"jxgbox\" id=\"JXG747cf11e-2ad4-11e5-8dd9-901b0e1b8723\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG747cf11e-2ad4-11e5-8dd9-901b0e1b8723',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var p0 = board.create('point', [0, 3], {name: 'A'}),\n * p1 = board.create('point', [1, 1]),\n * p2 = board.create('point', [2, 1], {name:'C', fixed: true}),\n *\n * // angle, rotation center:\n * t = board.create('transform', ['Y(A)', p2], {type: 'rotate'}),\n * p3 = board.create('point', [p1, t], {color: 'blue'});\n *\n * })();\n *\n * </script><pre>\n *\n * @example\n * // A concatenation of several transformations.\n * var p1 = board.create('point', [1, 1]),\n * t1 = board.create('transform', [-2, -1], {type: 'translate'}),\n * t2 = board.create('transform', [Math.PI/4], {type: 'rotate'}),\n * t3 = board.create('transform', [2, 1], {type: 'translate'}),\n * p2 = board.create('point', [p1, [t1, t2, t3]], {color: 'blue'});\n *\n * </pre><div class=\"jxgbox\" id=\"JXGf516d3de-2ad5-11e5-8dd9-901b0e1b8723\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXGf516d3de-2ad5-11e5-8dd9-901b0e1b8723',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var p1 = board.create('point', [1, 1]),\n * t1 = board.create('transform', [-2, -1], {type:'translate'}),\n * t2 = board.create('transform', [Math.PI/4], {type:'rotate'}),\n * t3 = board.create('transform', [2, 1], {type:'translate'}),\n * p2 = board.create('point', [p1, [t1, t2, t3]], {color: 'blue'});\n *\n * })();\n *\n * </script><pre>\n *\n * @example\n * // Reflection of point A\n * var p1 = board.create('point', [1, 1]),\n * p2 = board.create('point', [1, 3]),\n * p3 = board.create('point', [-2, 0]),\n * l = board.create('line', [p2, p3]),\n * t = board.create('transform', [l], {type: 'reflect'}), // Possible are l, l.id, l.name\n * p4 = board.create('point', [p1, t], {color: 'blue'});\n *\n * </pre><div class=\"jxgbox\" id=\"JXG6f374a04-2ad6-11e5-8dd9-901b0e1b8723\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG6f374a04-2ad6-11e5-8dd9-901b0e1b8723',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var p1 = board.create('point', [1, 1]),\n * p2 = board.create('point', [1, 3]),\n * p3 = board.create('point', [-2, 0]),\n * l = board.create('line', [p2, p3]),\n * t = board.create('transform', [l], {type:'reflect'}), // Possible are l, l.id, l.name\n * p4 = board.create('point', [p1, t], {color: 'blue'});\n *\n * })();\n *\n * </script><pre>\n *\n * @example\n * // One time application of a transform to points A, B\n * var p1 = board.create('point', [1, 1]),\n * p2 = board.create('point', [1, 1]),\n * t = board.create('transform', [3, 2], {type: 'shear'});\n * t.applyOnce([p1, p2]);\n *\n * </pre><div class=\"jxgbox\" id=\"JXGb6cee1c4-2ad6-11e5-8dd9-901b0e1b8723\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXGb6cee1c4-2ad6-11e5-8dd9-901b0e1b8723',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var p1 = board.create('point', [1, 1]),\n * p2 = board.create('point', [-1, -2]),\n * t = board.create('transform', [3, 2], {type: 'shear'});\n * t.applyOnce([p1, p2]);\n *\n * })();\n *\n * </script><pre>\n *\n * @example\n * // Construct a square of side length 2 with the\n * // help of transformations\n * var sq = [],\n * right = board.create('transform', [2, 0], {type: 'translate'}),\n * up = board.create('transform', [0, 2], {type: 'translate'}),\n * pol, rot, p0;\n *\n * // The first point is free\n * sq[0] = board.create('point', [0, 0], {name: 'Drag me'}),\n *\n * // Construct the other free points by transformations\n * sq[1] = board.create('point', [sq[0], right]),\n * sq[2] = board.create('point', [sq[0], [right, up]]),\n * sq[3] = board.create('point', [sq[0], up]),\n *\n * // Polygon through these four points\n * pol = board.create('polygon', sq, {\n * fillColor:'blue',\n * gradient:'radial',\n * gradientsecondcolor:'white',\n * gradientSecondOpacity:'0'\n * }),\n *\n * p0 = board.create('point', [0, 3], {name: 'angle'}),\n * // Rotate the square around point sq[0] by dragging A\n * rot = board.create('transform', ['Y(angle)', sq[0]], {type: 'rotate'});\n *\n * // Apply the rotation to all but the first point of the square\n * rot.bindTo(sq.slice(1));\n *\n * </pre><div class=\"jxgbox\" id=\"JXGc7f9097e-2ad7-11e5-8dd9-901b0e1b8723\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXGc7f9097e-2ad7-11e5-8dd9-901b0e1b8723',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * // Construct a square of side length 2 with the\n * // help of transformations\n * var sq = [],\n * right = board.create('transform', [2, 0], {type: 'translate'}),\n * up = board.create('transform', [0, 2], {type: 'translate'}),\n * pol, rot, p0;\n *\n * // The first point is free\n * sq[0] = board.create('point', [0, 0], {name: 'Drag me'}),\n *\n * // Construct the other free points by transformations\n * sq[1] = board.create('point', [sq[0], right]),\n * sq[2] = board.create('point', [sq[0], [right, up]]),\n * sq[3] = board.create('point', [sq[0], up]),\n *\n * // Polygon through these four points\n * pol = board.create('polygon', sq, {\n * fillColor:'blue',\n * gradient:'radial',\n * gradientsecondcolor:'white',\n * gradientSecondOpacity:'0'\n * }),\n *\n * p0 = board.create('point', [0, 3], {name: 'angle'}),\n * // Rotate the square around point sq[0] by dragging A\n * rot = board.create('transform', ['Y(angle)', sq[0]], {type: 'rotate'});\n *\n * // Apply the rotation to all but the first point of the square\n * rot.bindTo(sq.slice(1));\n *\n * })();\n *\n * </script><pre>\n *\n */\n JXG.createTransform = function (board, parents, attributes) {\n return new JXG.Transformation(board, attributes.type, parents);\n };\n\n JXG.registerElement('transform', JXG.createTransform);\n\n return {\n Transformation: JXG.Transformation,\n createTransform: JXG.createTransform\n };\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true*/\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n jxg\n math/math\n math/geometry\n math/numerics\n math/statistics\n math/symbolic\n base/composition\n base/coords\n base/constants\n utils/type\n elements:\n line\n circle\n transform\n point\n glider\n text\n curve\n */\n\n/**\n * @fileoverview This file contains our composition elements, i.e. these elements are mostly put together\n * from one or more {@link JXG.GeometryElement} but with a special meaning. E.g. the midpoint element is contained here\n * and this is just a {@link JXG.Point} with coordinates dependent from two other points. Currently in this file the\n * following compositions can be found: <ul>\n * <li>{@link Arrowparallel} (currently private)</li>\n * <li>{@link Bisector}</li>\n * <li>{@link Msector}</li>\n * <li>{@link Circumcircle}</li>\n * <li>{@link Circumcirclemidpoint}</li>\n * <li>{@link Integral}</li>\n * <li>{@link Midpoint}</li>\n * <li>{@link Mirrorpoint}</li>\n * <li>{@link Normal}</li>\n * <li>{@link Orthogonalprojection}</li>\n * <li>{@link Parallel}</li>\n * <li>{@link Perpendicular}</li>\n * <li>{@link Perpendicularpoint}</li>\n * <li>{@link Perpendicularsegment}</li>\n * <li>{@link Reflection}</li></ul>\n */\n\ndefine('element/composition',[\n 'jxg', 'math/math', 'math/geometry', 'math/numerics', 'base/coords',\n 'utils/type', 'base/constants', 'base/point', 'base/line', 'base/circle', 'base/transformation',\n 'base/composition', 'base/curve', 'base/polygon'\n], function (JXG, Mat, Geometry, Numerics, Coords,\n Type, Const, Point, Line, Circle, Transform,\n Composition, Curve, Polygon) {\n\n \"use strict\";\n\n /**\n * @class This is used to construct a point that is the orthogonal projection of a point to a line.\n * @pseudo\n * @description An orthogonal projection is given by a point and a line. It is determined by projecting the given point\n * orthogonal onto the given line.\n * @constructor\n * @name Orthogonalprojection\n * @type JXG.Point\n * @augments JXG.Point\n * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {JXG.Line_JXG.Point} p,l The constructed point is the orthogonal projection of p onto l.\n * @example\n * var p1 = board.create('point', [0.0, 4.0]);\n * var p2 = board.create('point', [6.0, 1.0]);\n * var l1 = board.create('line', [p1, p2]);\n * var p3 = board.create('point', [3.0, 3.0]);\n *\n * var pp1 = board.create('orthogonalprojection', [p3, l1]);\n * </pre><div class=\"jxgbox\" id=\"JXG7708b215-39fa-41b6-b972-19d73d77d791\" style=\"width: 400px; height: 400px;\"></div>\n * <script type=\"text/javascript\">\n * var ppex1_board = JXG.JSXGraph.initBoard('JXG7708b215-39fa-41b6-b972-19d73d77d791', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});\n * var ppex1_p1 = ppex1_board.create('point', [0.0, 4.0]);\n * var ppex1_p2 = ppex1_board.create('point', [6.0, 1.0]);\n * var ppex1_l1 = ppex1_board.create('line', [ppex1_p1, ppex1_p2]);\n * var ppex1_p3 = ppex1_board.create('point', [3.0, 3.0]);\n * var ppex1_pp1 = ppex1_board.create('orthogonalprojection', [ppex1_p3, ppex1_l1]);\n * </script><pre>\n */\n JXG.createOrthogonalProjection = function (board, parents, attributes) {\n var l, p, t, attr;\n\n parents[0] = board.select(parents[0]);\n parents[1] = board.select(parents[1]);\n\n if (Type.isPointType(board, parents[0]) && parents[1].elementClass === Const.OBJECT_CLASS_LINE) {\n p = Type.providePoints(board, [parents[0]], attributes, 'point')[0];\n l = parents[1];\n } else if (Type.isPointType(board, parents[1]) && parents[0].elementClass === Const.OBJECT_CLASS_LINE) {\n p = Type.providePoints(board, [parents[1]], attributes, 'point')[0];\n l = parents[0];\n } else {\n throw new Error(\"JSXGraph: Can't create perpendicular point with parent types '\" +\n (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"'.\" +\n \"\\nPossible parent types: [point,line]\");\n }\n\n attr = Type.copyAttributes(attributes, board.options, 'orthogonalprojection');\n\n t = board.create('point', [\n function () {\n return Geometry.projectPointToLine(p, l, board);\n }\n ], attr);\n\n if (Type.exists(p._is_new)) {\n t.addChild(p);\n delete p._is_new;\n } else {\n p.addChild(t);\n }\n l.addChild(t);\n\n t.elType = 'orthogonalprojection';\n t.setParents([p.id, t.id]);\n\n t.update();\n\n /**\n * Used to generate a polynomial for the orthogonal projection\n * @name Orthogonalprojection#generatePolynomial\n * @returns {Array} An array containing the generated polynomial.\n * @private\n */\n t.generatePolynomial = function () {\n /*\n * Perpendicular takes point P and line L and creates point T and line M:\n *\n * | M\n * |\n * x P (p1,p2)\n * |\n * |\n * L |\n * ----------x-------------x------------------------x--------\n * A (a1,a2) |T (t1,t2) B (b1,b2)\n * |\n * |\n *\n * So we have two conditions:\n *\n * (a) AT || TB (collinearity condition)\n * (b) PT _|_ AB (orthogonality condition)\n *\n * a2-t2 t2-b2\n * ------- = ------- (1)\n * a1-t1 t1-b1\n *\n * p2-t2 a1-b1\n * ------- = - ------- (2)\n * p1-t1 a2-b2\n *\n * Multiplying (1) and (2) with denominators and simplifying gives\n *\n * a2t1 - a2b1 + t2b1 - a1t2 + a1b2 - t1b2 = 0 (1')\n *\n * p2a2 - p2b2 - t2a2 + t2b2 + p1a1 - p1b1 - t1a1 + t1b1 = 0 (2')\n *\n */\n\n var a1 = l.point1.symbolic.x,\n a2 = l.point1.symbolic.y,\n b1 = l.point2.symbolic.x,\n b2 = l.point2.symbolic.y,\n\n p1 = p.symbolic.x,\n p2 = p.symbolic.y,\n t1 = t.symbolic.x,\n t2 = t.symbolic.y,\n\n poly1 = '(' + a2 + ')*(' + t1 + ')-(' + a2 + ')*(' + b1 + ')+(' + t2 + ')*(' + b1 + ')-(' +\n a1 + ')*(' + t2 + ')+(' + a1 + ')*(' + b2 + ')-(' + t1 + ')*(' + b2 + ')',\n poly2 = '(' + p2 + ')*(' + a2 + ')-(' + p2 + ')*(' + b2 + ')-(' + t2 + ')*(' + a2 + ')+(' +\n t2 + ')*(' + b2 + ')+(' + p1 + ')*(' + a1 + ')-(' + p1 + ')*(' + b1 + ')-(' + t1 + ')*(' +\n a1 + ')+(' + t1 + ')*(' + b1 + ')';\n\n return [poly1, poly2];\n };\n\n return t;\n };\n\n /**\n\n * @class This element is used to provide a constructor for a perpendicular.\n * @pseudo\n * @description A perpendicular is a composition of two elements: a line and a point. The line is orthogonal\n * to a given line and contains a given point.\n * @name Perpendicular\n * @constructor\n * @type JXG.Line\n * @augments Segment\n * @returns A {@link JXG.Line} object through the given point that is orthogonal to the given line.\n * @throws {Error} If the elements cannot be constructed with the given parent objects an exception is thrown.\n * @param {JXG.Line_JXG.Point} l,p The perpendicular line will be orthogonal to l and\n * will contain p.\n * @example\n * // Create a perpendicular\n * var p1 = board.create('point', [0.0, 2.0]);\n * var p2 = board.create('point', [2.0, 1.0]);\n * var l1 = board.create('line', [p1, p2]);\n *\n * var p3 = board.create('point', [3.0, 3.0]);\n * var perp1 = board.create('perpendicular', [l1, p3]);\n * </pre><div class=\"jxgbox\" id=\"JXGd5b78842-7b27-4d37-b608-d02519e6cd03\" style=\"width: 400px; height: 400px;\"></div>\n * <script type=\"text/javascript\">\n * var pex1_board = JXG.JSXGraph.initBoard('JXGd5b78842-7b27-4d37-b608-d02519e6cd03', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});\n * var pex1_p1 = pex1_board.create('point', [0.0, 2.0]);\n * var pex1_p2 = pex1_board.create('point', [2.0, 1.0]);\n * var pex1_l1 = pex1_board.create('line', [pex1_p1, pex1_p2]);\n * var pex1_p3 = pex1_board.create('point', [3.0, 3.0]);\n * var pex1_perp1 = pex1_board.create('perpendicular', [pex1_l1, pex1_p3]);\n * </script><pre>\n */\n JXG.createPerpendicular = function (board, parents, attributes) {\n var p, l, pd, attr;\n\n parents[0] = board.select(parents[0]);\n parents[1] = board.select(parents[1]);\n\n if (Type.isPointType(board, parents[0]) && parents[1].elementClass === Const.OBJECT_CLASS_LINE) {\n l = parents[1];\n p = Type.providePoints(board, [parents[0]], attributes, 'point')[0];\n } else if (Type.isPointType(board, parents[1]) && parents[0].elementClass === Const.OBJECT_CLASS_LINE) {\n l = parents[0];\n p = Type.providePoints(board, [parents[1]], attributes, 'point')[0];\n } else {\n throw new Error(\"JSXGraph: Can't create perpendicular with parent types '\" +\n (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"'.\" +\n \"\\nPossible parent types: [line,point]\");\n }\n\n attr = Type.copyAttributes(attributes, board.options, 'perpendicular');\n pd = Line.createLine(board, [\n function () {\n return l.stdform[2] * p.X() - l.stdform[1] * p.Y();\n },\n function () {\n return -l.stdform[2] * p.Z();\n },\n function () {\n return l.stdform[1] * p.Z();\n }\n ], attr);\n\n pd.elType = 'perpendicular';\n pd.setParents([l.id, p.id]);\n\n if (Type.exists(p._is_new)) {\n pd.addChild(p);\n delete p._is_new;\n } else {\n p.addChild(pd);\n }\n l.addChild(pd);\n\n return pd;\n };\n\n /**\n * @class This is used to construct a perpendicular point.\n * @pseudo\n * @description A perpendicular point is given by a point and a line. It is determined by projecting the given point\n * orthogonal onto the given line. This element should be used in GEONExTReader only. All other applications should\n * use orthogonal projection {@link Orthogonalprojection}.\n * @constructor\n * @name PerpendicularPoint\n * @type JXG.Point\n * @augments JXG.Point\n * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {JXG.Line_JXG.Point} p,l The constructed point is the orthogonal projection of p onto l.\n * @example\n * var p1 = board.create('point', [0.0, 4.0]);\n * var p2 = board.create('point', [6.0, 1.0]);\n * var l1 = board.create('line', [p1, p2]);\n * var p3 = board.create('point', [3.0, 3.0]);\n *\n * var pp1 = board.create('perpendicularpoint', [p3, l1]);\n * </pre><div class=\"jxgbox\" id=\"JXGded148c9-3536-44c0-ab81-1bb8fa48f3f4\" style=\"width: 400px; height: 400px;\"></div>\n * <script type=\"text/javascript\">\n * var ppex1_board = JXG.JSXGraph.initBoard('JXGded148c9-3536-44c0-ab81-1bb8fa48f3f4', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});\n * var ppex1_p1 = ppex1_board.create('point', [0.0, 4.0]);\n * var ppex1_p2 = ppex1_board.create('point', [6.0, 1.0]);\n * var ppex1_l1 = ppex1_board.create('line', [ppex1_p1, ppex1_p2]);\n * var ppex1_p3 = ppex1_board.create('point', [3.0, 3.0]);\n * var ppex1_pp1 = ppex1_board.create('perpendicularpoint', [ppex1_p3, ppex1_l1]);\n * </script><pre>\n */\n JXG.createPerpendicularPoint = function (board, parents, attributes) {\n var l, p, t;\n\n parents[0] = board.select(parents[0]);\n parents[1] = board.select(parents[1]);\n if (Type.isPointType(board, parents[0]) && parents[1].elementClass === Const.OBJECT_CLASS_LINE) {\n p = Type.providePoints(board, [parents[0]], attributes, 'point')[0];\n l = parents[1];\n } else if (Type.isPointType(board, parents[1]) && parents[0].elementClass === Const.OBJECT_CLASS_LINE) {\n p = Type.providePoints(board, [parents[1]], attributes, 'point')[0];\n l = parents[0];\n } else {\n throw new Error(\"JSXGraph: Can't create perpendicular point with parent types '\" +\n (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"'.\" +\n \"\\nPossible parent types: [point,line]\");\n }\n\n t = board.create('point', [\n function () {\n return Geometry.perpendicular(l, p, board)[0];\n }\n ], attributes);\n\n if (Type.exists(p._is_new)) {\n t.addChild(p);\n delete p._is_new;\n } else {\n p.addChild(t);\n }\n l.addChild(t);\n\n t.elType = 'perpendicularpoint';\n t.setParents([p.id, l.id]);\n\n t.update();\n\n /**\n * Used to generate a polynomial for the perpendicular point\n * @name PerpendicularPoint#generatePolynomial\n * @returns {Array} An array containing the generated polynomial.\n * @private\n */\n t.generatePolynomial = function () {\n /*\n * Perpendicular takes point P and line L and creates point T and line M:\n *\n * | M\n * |\n * x P (p1,p2)\n * |\n * |\n * L |\n * ----------x-------------x------------------------x--------\n * A (a1,a2) |T (t1,t2) B (b1,b2)\n * |\n * |\n *\n * So we have two conditions:\n *\n * (a) AT || TB (collinearity condition)\n * (b) PT _|_ AB (orthogonality condition)\n *\n * a2-t2 t2-b2\n * ------- = ------- (1)\n * a1-t1 t1-b1\n *\n * p2-t2 a1-b1\n * ------- = - ------- (2)\n * p1-t1 a2-b2\n *\n * Multiplying (1) and (2) with denominators and simplifying gives\n *\n * a2t1 - a2b1 + t2b1 - a1t2 + a1b2 - t1b2 = 0 (1')\n *\n * p2a2 - p2b2 - t2a2 + t2b2 + p1a1 - p1b1 - t1a1 + t1b1 = 0 (2')\n *\n */\n var a1 = l.point1.symbolic.x,\n a2 = l.point1.symbolic.y,\n b1 = l.point2.symbolic.x,\n b2 = l.point2.symbolic.y,\n p1 = p.symbolic.x,\n p2 = p.symbolic.y,\n t1 = t.symbolic.x,\n t2 = t.symbolic.y,\n\n poly1 = '(' + a2 + ')*(' + t1 + ')-(' + a2 + ')*(' + b1 + ')+(' + t2 + ')*(' + b1 + ')-(' +\n a1 + ')*(' + t2 + ')+(' + a1 + ')*(' + b2 + ')-(' + t1 + ')*(' + b2 + ')',\n poly2 = '(' + p2 + ')*(' + a2 + ')-(' + p2 + ')*(' + b2 + ')-(' + t2 + ')*(' + a2 + ')+(' +\n t2 + ')*(' + b2 + ')+(' + p1 + ')*(' + a1 + ')-(' + p1 + ')*(' + b1 + ')-(' + t1 + ')*(' +\n a1 + ')+(' + t1 + ')*(' + b1 + ')';\n\n return [poly1, poly2];\n };\n\n return t;\n };\n\n /**\n * @class This element is used to provide a constructor for a perpendicular segment.\n * @pseudo\n * @description A perpendicular is a composition of two elements: a line segment and a point. The line segment is orthogonal\n * to a given line and contains a given point and meets the given line in the perpendicular point.\n * @name PerpendicularSegment\n * @constructor\n * @type JXG.Line\n * @augments Segment\n * @returns An array containing two elements: A {@link JXG.Line} object in the first component and a\n * {@link JXG.Point} element in the second component. The line segment is orthogonal to the given line and meets it\n * in the returned point.\n * @throws {Error} If the elements cannot be constructed with the given parent objects an exception is thrown.\n * @param {JXG.Line_JXG.Point} l,p The perpendicular line will be orthogonal to l and\n * will contain p. The perpendicular point is the intersection point of the two lines.\n * @example\n * // Create a perpendicular\n * var p1 = board.create('point', [0.0, 2.0]);\n * var p2 = board.create('point', [2.0, 1.0]);\n * var l1 = board.create('line', [p1, p2]);\n *\n * var p3 = board.create('point', [3.0, 3.0]);\n * var perp1 = board.create('perpendicularsegment', [l1, p3]);\n * </pre><div class=\"jxgbox\" id=\"JXG037a6eb2-781d-4b71-b286-763619a63f22\" style=\"width: 400px; height: 400px;\"></div>\n * <script type=\"text/javascript\">\n * var pex1_board = JXG.JSXGraph.initBoard('JXG037a6eb2-781d-4b71-b286-763619a63f22', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});\n * var pex1_p1 = pex1_board.create('point', [0.0, 2.0]);\n * var pex1_p2 = pex1_board.create('point', [2.0, 1.0]);\n * var pex1_l1 = pex1_board.create('line', [pex1_p1, pex1_p2]);\n * var pex1_p3 = pex1_board.create('point', [3.0, 3.0]);\n * var pex1_perp1 = pex1_board.create('perpendicularsegment', [pex1_l1, pex1_p3]);\n * </script><pre>\n */\n JXG.createPerpendicularSegment = function (board, parents, attributes) {\n var p, l, pd, t, attr;\n\n parents[0] = board.select(parents[0]);\n parents[1] = board.select(parents[1]);\n if (Type.isPointType(board, parents[0]) && parents[1].elementClass === Const.OBJECT_CLASS_LINE) {\n l = parents[1];\n p = Type.providePoints(board, [parents[0]], attributes, 'point')[0];\n } else if (Type.isPointType(board, parents[1]) && parents[0].elementClass === Const.OBJECT_CLASS_LINE) {\n l = parents[0];\n p = Type.providePoints(board, [parents[1]], attributes, 'point')[0];\n } else {\n throw new Error(\"JSXGraph: Can't create perpendicular with parent types '\" +\n (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"'.\" +\n \"\\nPossible parent types: [line,point]\");\n }\n attr = Type.copyAttributes(attributes, board.options, 'perpendicularsegment', 'point');\n t = JXG.createPerpendicularPoint(board, [l, p], attr);\n t.dump = false;\n\n if (!Type.exists(attributes.layer)) {\n attributes.layer = board.options.layer.line;\n }\n\n attr = Type.copyAttributes(attributes, board.options, 'perpendicularsegment');\n pd = Line.createLine(board, [\n function () {\n return (Geometry.perpendicular(l, p, board)[1] ? [t, p] : [p, t]);\n }\n ], attr);\n\n /**\n * Helper point\n * @memberOf PerpendicularSegment.prototype\n * @type PerpendicularPoint\n * @name point\n */\n pd.point = t;\n\n if (Type.exists(p._is_new)) {\n pd.addChild(p);\n delete p._is_new;\n } else {\n p.addChild(pd);\n }\n l.addChild(pd);\n\n pd.elType = 'perpendicularsegment';\n pd.setParents([p.id, l.id]);\n pd.subs = {\n point: t\n };\n pd.inherits.push(t);\n\n return pd;\n };\n\n /**\n * @class The midpoint element constructs a point in the middle of two given points.\n * @pseudo\n * @description A midpoint is given by two points. It is collinear to the given points and the distance\n * is the same to each of the given points, i.e. it is in the middle of the given points.\n * @constructor\n * @name Midpoint\n * @type JXG.Point\n * @augments JXG.Point\n * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {JXG.Point_JXG.Point} p1,p2 The constructed point will be in the middle of p1 and p2.\n * @param {JXG.Line} l The midpoint will be in the middle of {@link JXG.Line#point1} and {@link JXG.Line#point2} of\n * the given line l.\n * @example\n * // Create base elements: 2 points and 1 line\n * var p1 = board.create('point', [0.0, 2.0]);\n * var p2 = board.create('point', [2.0, 1.0]);\n * var l1 = board.create('segment', [[0.0, 3.0], [3.0, 3.0]]);\n *\n * var mp1 = board.create('midpoint', [p1, p2]);\n * var mp2 = board.create('midpoint', [l1]);\n * </pre><div class=\"jxgbox\" id=\"JXG7927ef86-24ae-40cc-afb0-91ff61dd0de7\" style=\"width: 400px; height: 400px;\"></div>\n * <script type=\"text/javascript\">\n * var mpex1_board = JXG.JSXGraph.initBoard('JXG7927ef86-24ae-40cc-afb0-91ff61dd0de7', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});\n * var mpex1_p1 = mpex1_board.create('point', [0.0, 2.0]);\n * var mpex1_p2 = mpex1_board.create('point', [2.0, 1.0]);\n * var mpex1_l1 = mpex1_board.create('segment', [[0.0, 3.0], [3.0, 3.0]]);\n * var mpex1_mp1 = mpex1_board.create('midpoint', [mpex1_p1, mpex1_p2]);\n * var mpex1_mp2 = mpex1_board.create('midpoint', [mpex1_l1]);\n * </script><pre>\n */\n JXG.createMidpoint = function (board, parents, attributes) {\n var a, b, t, i,\n attr;\n\n for (i = 0; i < parents.length; ++i) {\n parents[i] = board.select(parents[i]);\n }\n if (parents.length === 2 && Type.isPointType(board, parents[0]) && Type.isPointType(board, parents[1])) {\n parents = Type.providePoints(board, parents, attributes, 'point');\n a = parents[0];\n b = parents[1];\n } else if (parents.length === 1 && parents[0].elementClass === Const.OBJECT_CLASS_LINE) {\n a = parents[0].point1;\n b = parents[0].point2;\n } else {\n throw new Error(\"JSXGraph: Can't create midpoint.\" +\n \"\\nPossible parent types: [point,point], [line]\");\n }\n\n attr = Type.copyAttributes(attributes, board.options, 'midpoint');\n t = board.create('point', [\n function () {\n var x = a.coords.usrCoords[1] + b.coords.usrCoords[1];\n if (isNaN(x) || Math.abs(a.coords.usrCoords[0]) < Mat.eps || Math.abs(b.coords.usrCoords[0]) < Mat.eps) {\n return NaN;\n }\n\n return x * 0.5;\n },\n function () {\n var y = a.coords.usrCoords[2] + b.coords.usrCoords[2];\n if (isNaN(y) || Math.abs(a.coords.usrCoords[0]) < Mat.eps || Math.abs(b.coords.usrCoords[0]) < Mat.eps) {\n return NaN;\n }\n\n return y * 0.5;\n }], attr);\n if (Type.exists(a._is_new)) {\n t.addChild(a);\n delete a._is_new;\n } else {\n a.addChild(t);\n }\n if (Type.exists(b._is_new)) {\n t.addChild(b);\n delete b._is_new;\n } else {\n b.addChild(t);\n }\n\n t.elType = 'midpoint';\n t.setParents([a.id, b.id]);\n\n t.prepareUpdate().update();\n\n /**\n * Used to generate a polynomial for the midpoint.\n * @name Midpoint#generatePolynomial\n * @returns {Array} An array containing the generated polynomial.\n * @private\n */\n t.generatePolynomial = function () {\n /*\n * Midpoint takes two point A and B or line L (with points P and Q) and creates point T:\n *\n * L (not necessarily)\n * ----------x------------------x------------------x--------\n * A (a1,a2) T (t1,t2) B (b1,b2)\n *\n * So we have two conditions:\n *\n * (a) AT || TB (collinearity condition)\n * (b) [AT] == [TB] (equidistant condition)\n *\n * a2-t2 t2-b2\n * ------- = ------- (1)\n * a1-t1 t1-b1\n *\n * (a1 - t1)^2 + (a2 - t2)^2 = (b1 - t1)^2 + (b2 - t2)^2 (2)\n *\n *\n * Multiplying (1) with denominators and simplifying (1) and (2) gives\n *\n * a2t1 - a2b1 + t2b1 - a1t2 + a1b2 - t1b2 = 0 (1')\n *\n * a1^2 - 2a1t1 + a2^2 - 2a2t2 - b1^2 + 2b1t1 - b2^2 + 2b2t2 = 0 (2')\n *\n */\n var a1 = a.symbolic.x,\n a2 = a.symbolic.y,\n b1 = b.symbolic.x,\n b2 = b.symbolic.y,\n t1 = t.symbolic.x,\n t2 = t.symbolic.y,\n\n poly1 = '(' + a2 + ')*(' + t1 + ')-(' + a2 + ')*(' + b1 + ')+(' + t2 + ')*(' + b1 + ')-(' +\n a1 + ')*(' + t2 + ')+(' + a1 + ')*(' + b2 + ')-(' + t1 + ')*(' + b2 + ')',\n poly2 = '(' + a1 + ')^2 - 2*(' + a1 + ')*(' + t1 + ')+(' + a2 + ')^2-2*(' + a2 + ')*(' +\n t2 + ')-(' + b1 + ')^2+2*(' + b1 + ')*(' + t1 + ')-(' + b2 + ')^2+2*(' + b2 + ')*(' + t2 + ')';\n\n return [poly1, poly2];\n };\n\n return t;\n };\n\n /**\n * @class This element is used to construct a parallel point.\n * @pseudo\n * @description A parallel point is given by three points. Taking the Euclidean vector from the first to the\n * second point, the parallel point is determined by adding that vector to the third point.\n * The line determined by the first two points is parallel to the line determined by the third point and the constructed point.\n * @constructor\n * @name Parallelpoint\n * @type JXG.Point\n * @augments JXG.Point\n * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 Taking the Euclidean vector <tt>v=p2-p1</tt> the parallel point is determined by\n * <tt>p4 = p3+v</tt>\n * @param {JXG.Line_JXG.Point} l,p The resulting point will together with p specify a line which is parallel to l.\n * @example\n * var p1 = board.create('point', [0.0, 2.0]);\n * var p2 = board.create('point', [2.0, 1.0]);\n * var p3 = board.create('point', [3.0, 3.0]);\n *\n * var pp1 = board.create('parallelpoint', [p1, p2, p3]);\n * </pre><div class=\"jxgbox\" id=\"JXG488c4be9-274f-40f0-a469-c5f70abe1f0e\" style=\"width: 400px; height: 400px;\"></div>\n * <script type=\"text/javascript\">\n * var ppex1_board = JXG.JSXGraph.initBoard('JXG488c4be9-274f-40f0-a469-c5f70abe1f0e', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});\n * var ppex1_p1 = ppex1_board.create('point', [0.0, 2.0]);\n * var ppex1_p2 = ppex1_board.create('point', [2.0, 1.0]);\n * var ppex1_p3 = ppex1_board.create('point', [3.0, 3.0]);\n * var ppex1_pp1 = ppex1_board.create('parallelpoint', [ppex1_p1, ppex1_p2, ppex1_p3]);\n * </script><pre>\n */\n JXG.createParallelPoint = function (board, parents, attributes) {\n var a, b, c, p, i;\n\n for (i = 0; i < parents.length; ++i) {\n parents[i] = board.select(parents[i]);\n }\n if (parents.length === 3 &&\n Type.isPointType(board, parents[0]) &&\n Type.isPointType(board, parents[1]) &&\n Type.isPointType(board, parents[2])) {\n parents = Type.providePoints(board, parents, attributes, 'point');\n a = parents[0];\n b = parents[1];\n c = parents[2];\n } else if (Type.isPointType(board, parents[0]) &&\n parents[1].elementClass === Const.OBJECT_CLASS_LINE) {\n c = Type.providePoints(board, [parents[0]], attributes, 'point')[0];\n a = parents[1].point1;\n b = parents[1].point2;\n } else if (Type.isPointType(board, parents[1]) &&\n parents[0].elementClass === Const.OBJECT_CLASS_LINE) {\n c = Type.providePoints(board, [parents[1]], attributes, 'point')[0];\n a = parents[0].point1;\n b = parents[0].point2;\n } else {\n throw new Error(\"JSXGraph: Can't create parallel point with parent types '\" +\n (typeof parents[0]) + \"', '\" + (typeof parents[1]) + \"' and '\" + (typeof parents[2]) + \"'.\" +\n \"\\nPossible parent types: [line,point], [point,point,point]\");\n }\n\n p = board.create('point', [\n function () {\n return c.coords.usrCoords[1] + b.coords.usrCoords[1] - a.coords.usrCoords[1];\n },\n function () {\n return c.coords.usrCoords[2] + b.coords.usrCoords[2] - a.coords.usrCoords[2];\n }\n ], attributes);\n\n // required for algorithms requiring dependencies between elements\n if (Type.exists(a._is_new)) {\n p.addChild(a);\n delete a._is_new;\n } else {\n a.addChild(p);\n }\n if (Type.exists(b._is_new)) {\n p.addChild(b);\n delete b._is_new;\n } else {\n b.addChild(p);\n }\n if (Type.exists(c._is_new)) {\n p.addChild(c);\n delete c._is_new;\n } else {\n c.addChild(p);\n }\n\n p.elType = 'parallelpoint';\n p.setParents([a.id, b.id, c.id]);\n\n // required to set the coordinates because functions are considered as constraints. hence, the coordinates get set first after an update.\n // can be removed if the above issue is resolved.\n p.prepareUpdate().update();\n\n p.generatePolynomial = function () {\n /*\n * Parallelpoint takes three points A, B and C or line L (with points B and C) and creates point T:\n *\n *\n * C (c1,c2) T (t1,t2)\n * x x\n * / /\n * / /\n * / /\n * / /\n * / /\n * / /\n * / /\n * / /\n * L (opt) / /\n * ----------x-------------------------------------x--------\n * A (a1,a2) B (b1,b2)\n *\n * So we have two conditions:\n *\n * (a) CT || AB (collinearity condition I)\n * (b) BT || AC (collinearity condition II)\n *\n * The corresponding equations are\n *\n * (b2 - a2)(t1 - c1) - (t2 - c2)(b1 - a1) = 0 (1)\n * (t2 - b2)(a1 - c1) - (t1 - b1)(a2 - c2) = 0 (2)\n *\n * Simplifying (1) and (2) gives\n *\n * b2t1 - b2c1 - a2t1 + a2c1 - t2b1 + t2a1 + c2b1 - c2a1 = 0 (1')\n * t2a1 - t2c1 - b2a1 + b2c1 - t1a2 + t1c2 + b1a2 - b1c2 = 0 (2')\n *\n */\n var a1 = a.symbolic.x,\n a2 = a.symbolic.y,\n b1 = b.symbolic.x,\n b2 = b.symbolic.y,\n c1 = c.symbolic.x,\n c2 = c.symbolic.y,\n t1 = p.symbolic.x,\n t2 = p.symbolic.y,\n\n poly1 = '(' + b2 + ')*(' + t1 + ')-(' + b2 + ')*(' + c1 + ')-(' + a2 + ')*(' + t1 + ')+(' +\n a2 + ')*(' + c1 + ')-(' + t2 + ')*(' + b1 + ')+(' + t2 + ')*(' + a1 + ')+(' + c2 + ')*(' +\n b1 + ')-(' + c2 + ')*(' + a1 + ')',\n poly2 = '(' + t2 + ')*(' + a1 + ')-(' + t2 + ')*(' + c1 + ')-(' + b2 + ')*(' + a1 + ')+(' +\n b2 + ')*(' + c1 + ')-(' + t1 + ')*(' + a2 + ')+(' + t1 + ')*(' + c2 + ')+(' + b1 + ')*(' +\n a2 + ')-(' + b1 + ')*(' + c2 + ')';\n\n return [poly1, poly2];\n };\n\n return p;\n };\n\n /**\n * @class A parallel is a line through a given point with the same slope as a given line or\n * the line through two given point.\n * <p>\n * If original line is given as a JSXGraph line object, the resulting parallel line will be defined by the given point and an\n * infinitely far away point (an ideal point). That means, the line can not be shortened to a segment.\n * <p>\n * If the original line is given as two points, the resulting parallel line can be shortened to a a segment.\n * @pseudo\n * @name Parallel\n * @augments Line\n * @constructor\n * @type JXG.Line\n * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {JXG.Line_JXG.Point} l,p The constructed line contains p and has the same slope as l. Alternative parameters are p1, p2, p: The\n * constructed line contains p and has the same slope as the line through p1 and p2.\n * @example\n * // Create a parallel\n * var p1 = board.create('point', [0.0, 2.0]);\n * var p2 = board.create('point', [2.0, 1.0]);\n * var l1 = board.create('line', [p1, p2]);\n *\n * var p3 = board.create('point', [3.0, 3.0]);\n * var pl1 = board.create('parallel', [l1, p3]);\n * </pre><div class=\"jxgbox\" id=\"JXG24e54f9e-5c4e-4afb-9228-0ef27a59d627\" style=\"width: 400px; height: 400px;\"></div>\n * <script type=\"text/javascript\">\n * var plex1_board = JXG.JSXGraph.initBoard('JXG24e54f9e-5c4e-4afb-9228-0ef27a59d627', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});\n * var plex1_p1 = plex1_board.create('point', [0.0, 2.0]);\n * var plex1_p2 = plex1_board.create('point', [2.0, 1.0]);\n * var plex1_l1 = plex1_board.create('line', [plex1_p1, plex1_p2]);\n * var plex1_p3 = plex1_board.create('point', [3.0, 3.0]);\n * var plex1_pl1 = plex1_board.create('parallel', [plex1_l1, plex1_p3]);\n * </script><pre>\n * @example\n * var p1, p2, p3, l1, pl1;\n *\n * p1 = board.create('point', [0.0, 2.0]);\n * p2 = board.create('point', [2.0, 1.0]);\n * l1 = board.create('line', [p1, p2]);\n *\n * p3 = board.create('point', [1.0, 3.0]);\n * pl1 = board.create('parallel', [p1, p2, p3], {straightFirst: false, straightLast: false});\n *\n * </pre><div id=\"JXGd643305d-20c3-4a88-91f9-8d0c4448594f\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXGd643305d-20c3-4a88-91f9-8d0c4448594f',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var p1, p2, p3, l1, pl1;\n *\n * p1 = board.create('point', [0.0, 2.0]);\n * p2 = board.create('point', [2.0, 1.0]);\n * l1 = board.create('line', [p1, p2]);\n *\n * p3 = board.create('point', [1.0, 3.0]);\n * pl1 = board.create('parallel', [p1, p2, p3], {straightFirst: false, straightLast: false});\n *\n * })();\n *\n * </script><pre>\n *\n */\n JXG.createParallel = function (board, parents, attributes) {\n var p, pp, pl, li, i, attr, ty = 1;\n\n for (i = 0; i < parents.length; ++i) {\n parents[i] = board.select(parents[i]);\n }\n p = null;\n if (parents.length === 3) {\n // Line / segment through point parents[2] which is parallel to line through parents[0] and parents[1]\n parents = Type.providePoints(board, parents, attributes, 'point');\n p = parents[2];\n ty = 0;\n } else if (Type.isPointType(board, parents[0])) {\n // Parallel to line parents[1] through point parents[0]\n p = Type.providePoints(board, [parents[0]], attributes, 'point')[0];\n /** @ignore */\n li = function () {\n return parents[1].stdform;\n };\n } else if (Type.isPointType(board, parents[1])) {\n // Parallel to line parents[0] through point parents[1]\n p = Type.providePoints(board, [parents[1]], attributes, 'point')[0];\n /** @ignore */\n li = function () {\n return parents[0].stdform;\n };\n }\n\n if (!Type.exists(attributes.layer)) {\n attributes.layer = board.options.layer.line;\n }\n\n attr = Type.copyAttributes(attributes, board.options, 'parallel', 'point');\n if (ty === 1) {\n // Line is given by line element. The parallel line is\n // constructed as line through an ideal point.\n pp = board.create('point', [\n function () {\n return Mat.crossProduct([1, 0, 0], li());\n }\n ], attr);\n } else {\n // Line is given by two points. The parallel line is\n // constructed as line through two finite point.\n pp = board.create('parallelpoint', parents, attr);\n }\n pp.isDraggable = true;\n\n attr = Type.copyAttributes(attributes, board.options, 'parallel');\n // line creator also calls addChild\n pl = board.create('line', [p, pp], attr);\n\n pl.elType = 'parallel';\n pl.subs = {\n point: pp\n };\n\n pl.inherits.push(pp);\n pl.setParents([parents[0].id, parents[1].id]);\n if (parents.length === 3) {\n pl.addParents(parents[2].id);\n }\n\n // p.addChild(pl);\n\n /**\n * Helper point used to create the parallel line. This point lies on the line at infinity, hence it's not visible,\n * not even with visible set to <tt>true</tt>. Creating another line through this point would make that other line\n * parallel to the create parallel.\n * @memberOf Parallel.prototype\n * @name point\n * @type JXG.Point\n */\n pl.point = pp;\n\n return pl;\n };\n\n /**\n * @class An arrow parallel is a segment with an arrow attached which is parallel through a given segment, given by its defining two points,\n * through a given point.\n * <p>\n * @pseudo\n * @constructor\n * @name Arrowparallel\n * @type Parallel\n * @augments Parallel\n * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param JXG.Point_JXG.Point_JXG.Point} p1, p2,p3 The constructed arrow contains p3 and has the same slope as the line through p1 and p2.\n * @example\n * // Create a parallel\n * var p1 = board.create('point', [0.0, 2.0]);\n * var p2 = board.create('point', [2.0, 1.0]);\n * var l1 = board.create('segment', [p1, p2]);\n *\n * var p3 = board.create('point', [3.0, 3.0]);\n * var pl1 = board.create('arrowparallel', [p1, p2, p3]);\n * </pre><div class=\"jxgbox\" id=\"JXGeeacdf99-036f-4e83-aeb6-f7388423e369\" style=\"width: 400px; height: 400px;\"></div>\n * <script type=\"text/javascript\">\n * (function () {\n * var plex1_board = JXG.JSXGraph.initBoard('JXGeeacdf99-036f-4e83-aeb6-f7388423e369', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});\n * var plex1_p1 = plex1_board.create('point', [0.0, 2.0]);\n * var plex1_p2 = plex1_board.create('point', [2.0, 1.0]);\n * var plex1_l1 = plex1_board.create('segment', [plex1_p1, plex1_p2]);\n * var plex1_p3 = plex1_board.create('point', [3.0, 3.0]);\n * var plex1_pl1 = plex1_board.create('arrowparallel', [plex1_p1, plex1_p2, plex1_p3]);\n * })();\n * </script><pre>\n */\n JXG.createArrowParallel = function (board, parents, attributes) {\n var p;\n\n /* parallel arrow point polynomials are done in createParallelPoint */\n try {\n attributes.firstArrow = false;\n attributes.lastArrow = true;\n p = JXG.createParallel(board, parents, attributes).setAttribute({straightFirst: false, straightLast: false});\n p.elType = 'arrowparallel';\n\n // parents are set in createParallel\n\n return p;\n } catch (e) {\n throw new Error(\"JSXGraph: Can't create arrowparallel with parent types '\" +\n (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"'.\" +\n \"\\nPossible parent types: [line,point], [point,point,point]\");\n }\n };\n\n /**\n * @class Constructs a normal.\n * @pseudo\n * @description A normal is a line through a given point on a element of type line, circle, curve, or turtle and orthogonal to that object.\n * @constructor\n * @name Normal\n * @type JXG.Line\n * @augments JXG.Line\n * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {JXG.Line,JXG.Circle,JXG.Curve,JXG.Turtle_JXG.Point} o,p The constructed line contains p which lies on the object and is orthogonal\n * to the tangent to the object in the given point.\n * @param {Glider} p Works like above, however the object is given by {@link JXG.CoordsElement#slideObject}.\n * @example\n * // Create a normal to a circle.\n * var p1 = board.create('point', [2.0, 2.0]);\n * var p2 = board.create('point', [3.0, 2.0]);\n * var c1 = board.create('circle', [p1, p2]);\n *\n * var norm1 = board.create('normal', [c1, p2]);\n * </pre><div class=\"jxgbox\" id=\"JXG4154753d-3d29-40fb-a860-0b08aa4f3743\" style=\"width: 400px; height: 400px;\"></div>\n * <script type=\"text/javascript\">\n * var nlex1_board = JXG.JSXGraph.initBoard('JXG4154753d-3d29-40fb-a860-0b08aa4f3743', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});\n * var nlex1_p1 = nlex1_board.create('point', [2.0, 2.0]);\n * var nlex1_p2 = nlex1_board.create('point', [3.0, 2.0]);\n * var nlex1_c1 = nlex1_board.create('circle', [nlex1_p1, nlex1_p2]);\n *\n * // var nlex1_p3 = nlex1_board.create('point', [1.0, 2.0]);\n * var nlex1_norm1 = nlex1_board.create('normal', [nlex1_c1, nlex1_p2]);\n * </script><pre>\n */\n JXG.createNormal = function (board, parents, attributes) {\n var p, c, l, i, g, f, attr, pp, attrp;\n\n for (i = 0; i < parents.length; ++i) {\n parents[i] = board.select(parents[i]);\n }\n // One arguments: glider on line, circle or curve\n if (parents.length === 1) {\n p = parents[0];\n c = p.slideObject;\n // Two arguments: (point,line), (point,circle), (line,point) or (circle,point)\n } else if (parents.length === 2) {\n if (Type.isPointType(board, parents[0])) {\n p = Type.providePoints(board, [parents[0]], attributes, 'point')[0];\n c = parents[1];\n } else if (Type.isPointType(board, parents[1])) {\n c = parents[0];\n p = Type.providePoints(board, [parents[1]], attributes, 'point')[0];\n } else {\n throw new Error(\"JSXGraph: Can't create normal with parent types '\" +\n (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"'.\" +\n \"\\nPossible parent types: [point,line], [point,circle], [glider]\");\n }\n } else {\n throw new Error(\"JSXGraph: Can't create normal with parent types '\" +\n (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"'.\" +\n \"\\nPossible parent types: [point,line], [point,circle], [glider]\");\n }\n\n attr = Type.copyAttributes(attributes, board.options, 'normal');\n if (c.elementClass === Const.OBJECT_CLASS_LINE) {\n // Private point\n attrp = Type.copyAttributes(attributes, board.options, 'normal', 'point');\n pp = board.create('point', [\n function () {\n var p = Mat.crossProduct([1, 0, 0], c.stdform);\n return [p[0], -p[2], p[1]];\n }\n ], attrp);\n pp.isDraggable = true;\n\n l = board.create('line', [p, pp], attr);\n\n /**\n * A helper point used to create a normal to a {@link JXG.Line} object. For normals to circles or curves this\n * element is <tt>undefined</tt>.\n * @type JXG.Point\n * @name point\n * @memberOf Normal.prototype\n */\n l.point = pp;\n l.subs = {\n point: pp\n };\n l.inherits.push(pp);\n } else if (c.elementClass === Const.OBJECT_CLASS_CIRCLE) {\n l = board.create('line', [c.midpoint, p], attr);\n } else if (c.elementClass === Const.OBJECT_CLASS_CURVE) {\n if (Type.evaluate(c.visProp.curvetype) !== 'plot') {\n g = c.X;\n f = c.Y;\n l = board.create('line', [\n function () {\n return -p.X() * Numerics.D(g)(p.position) - p.Y() * Numerics.D(f)(p.position);\n },\n function () {\n return Numerics.D(g)(p.position);\n },\n function () {\n return Numerics.D(f)(p.position);\n }\n ], attr);\n } else { // curveType 'plot'\n l = board.create('line', [\n function () {\n var i = Math.floor(p.position),\n lbda = p.position - i,\n p1, p2, t, A, B, C, D, dx, dy, d;\n\n if (c.bezierdegree === 1) {\n if (i === c.numberPoints - 1) {\n i -= 1;\n lbda = 1;\n }\n } else if (c.bezierDegree === 3) {\n // i is start of the Bezier segment\n // t is the position in the Bezier segment\n i = Math.floor(p.position * (c.numberPoints - 1) / 3) * 3;\n t = (p.position * (c.numberPoints - 1) - i) / 3;\n if (i >= c.numberPoints - 1) {\n i = c.numberPoints - 4;\n t = 1;\n }\n } else {\n return 0;\n }\n\n if (i < 0) {\n return 1;\n }\n\n if (c.bezierDegree === 1) {\n return (c.Y(i) + lbda * (c.Y(i + 1) - c.Y(i))) * (c.Y(i) - c.Y(i + 1)) - (c.X(i) + lbda * (c.X(i + 1) - c.X(i))) * (c.X(i + 1) - c.X(i));\n } else {\n A = c.points[i].usrCoords;\n B = c.points[i + 1].usrCoords;\n C = c.points[i + 2].usrCoords;\n D = c.points[i + 3].usrCoords;\n dx = (1 - t) * (1 - t) * (B[1] - A[1]) + 2 * (1 - t) * t * (C[1] - B[1]) + t * t * (D[1]- C[1]);\n dy = (1 - t) * (1 - t) * (B[2] - A[2]) + 2 * (1 - t) * t * (C[2] - B[2]) + t * t * (D[2]- C[2]);\n d = Math.sqrt(dx * dx + dy * dy);\n dx /= d;\n dy /= d;\n p1 = p.coords.usrCoords;\n p2 = [1, p1[1] - dy, p1[2] + dx];\n return p1[2] * p2[1] - p1[1] * p2[2];\n }\n },\n function () {\n var i = Math.floor(p.position),\n p1, p2, t, A, B, C, D, dx, dy, d;\n\n if (c.bezierdegree === 1) {\n if (i === c.numberPoints - 1) {\n i -= 1;\n }\n } else if (c.bezierDegree === 3) {\n // i is start of the Bezier segment\n // t is the position in the Bezier segment\n i = Math.floor(p.position * (c.numberPoints - 1) / 3) * 3;\n t = (p.position * (c.numberPoints - 1) - i) / 3;\n if (i >= c.numberPoints - 1) {\n i = c.numberPoints - 4;\n t = 1;\n }\n } else {\n return 0;\n }\n\n if (i < 0) {\n return 0;\n }\n if (c.bezierDegree === 1) {\n return c.X(i + 1) - c.X(i);\n } else {\n A = c.points[i].usrCoords;\n B = c.points[i + 1].usrCoords;\n C = c.points[i + 2].usrCoords;\n D = c.points[i + 3].usrCoords;\n dx = (1 - t) * (1 - t) * (B[1] - A[1]) + 2 * (1 - t) * t * (C[1] - B[1]) + t * t * (D[1]- C[1]);\n dy = (1 - t) * (1 - t) * (B[2] - A[2]) + 2 * (1 - t) * t * (C[2] - B[2]) + t * t * (D[2]- C[2]);\n d = Math.sqrt(dx * dx + dy * dy);\n dx /= d;\n dy /= d;\n p1 = p.coords.usrCoords;\n p2 = [1, p1[1] - dy, p1[2] + dx];\n return p2[2] - p1[2];\n }\n\n },\n function () {\n var i = Math.floor(p.position),\n p1, p2, t, A, B, C, D, dx, dy, d;\n\n if (c.bezierdegree === 1) {\n if (i === c.numberPoints - 1) {\n i -= 1;\n }\n } else if (c.bezierDegree === 3) {\n // i is start of the Bezier segment\n // t is the position in the Bezier segment\n i = Math.floor(p.position * (c.numberPoints - 1) / 3) * 3;\n t = (p.position * (c.numberPoints - 1) - i) / 3;\n if (i >= c.numberPoints - 1) {\n i = c.numberPoints - 4;\n t = 1;\n }\n } else {\n return 0;\n }\n\n if (i < 0) {\n return 0;\n }\n\n if (c.bezierDegree === 1) {\n return c.Y(i + 1) - c.Y(i);\n } else {\n A = c.points[i].usrCoords;\n B = c.points[i + 1].usrCoords;\n C = c.points[i + 2].usrCoords;\n D = c.points[i + 3].usrCoords;\n dx = (1 - t) * (1 - t) * (B[1] - A[1]) + 2 * (1 - t) * t * (C[1] - B[1]) + t * t * (D[1]- C[1]);\n dy = (1 - t) * (1 - t) * (B[2] - A[2]) + 2 * (1 - t) * t * (C[2] - B[2]) + t * t * (D[2]- C[2]);\n d = Math.sqrt(dx * dx + dy * dy);\n dx /= d;\n dy /= d;\n p1 = p.coords.usrCoords;\n p2 = [1, p1[1] - dy, p1[2] + dx];\n return p1[1] - p2[1];\n }\n }\n ], attr);\n }\n } else if (c.type === Const.OBJECT_TYPE_TURTLE) {\n l = board.create('line', [\n function () {\n var el, j,\n i = Math.floor(p.position),\n lbda = p.position - i;\n\n // run through all curves of this turtle\n for (j = 0; j < c.objects.length; j++) {\n el = c.objects[j];\n\n if (el.type === Const.OBJECT_TYPE_CURVE) {\n if (i < el.numberPoints) {\n break;\n }\n\n i -= el.numberPoints;\n }\n }\n\n if (i === el.numberPoints - 1) {\n i -= 1;\n lbda = 1;\n }\n\n if (i < 0) {\n return 1;\n }\n\n return (el.Y(i) + lbda * (el.Y(i + 1) - el.Y(i))) * (el.Y(i) - el.Y(i + 1)) - (el.X(i) + lbda * (el.X(i + 1) - el.X(i))) * (el.X(i + 1) - el.X(i));\n },\n function () {\n var el, j,\n i = Math.floor(p.position);\n\n // run through all curves of this turtle\n for (j = 0; j < c.objects.length; j++) {\n el = c.objects[j];\n if (el.type === Const.OBJECT_TYPE_CURVE) {\n if (i < el.numberPoints) {\n break;\n }\n\n i -= el.numberPoints;\n }\n }\n\n if (i === el.numberPoints - 1) {\n i -= 1;\n }\n\n if (i < 0) {\n return 0;\n }\n\n return el.X(i + 1) - el.X(i);\n },\n function () {\n var el, j,\n i = Math.floor(p.position);\n\n // run through all curves of this turtle\n for (j = 0; j < c.objects.length; j++) {\n el = c.objects[j];\n if (el.type === Const.OBJECT_TYPE_CURVE) {\n if (i < el.numberPoints) {\n break;\n }\n\n i -= el.numberPoints;\n }\n }\n\n if (i === el.numberPoints - 1) {\n i -= 1;\n }\n\n if (i < 0) {\n return 0;\n }\n\n return el.Y(i + 1) - el.Y(i);\n }\n ], attr);\n } else {\n throw new Error(\"JSXGraph: Can't create normal with parent types '\" +\n (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"'.\" +\n \"\\nPossible parent types: [point,line], [point,circle], [glider]\");\n }\n\n l.elType = 'normal';\n l.setParents(parents);\n\n if (Type.exists(p._is_new)) {\n l.addChild(p);\n delete p._is_new;\n } else {\n p.addChild(l);\n }\n c.addChild(l);\n\n return l;\n };\n\n /**\n * @class A bisector is a line which divides an angle into two equal angles. It is given by three points A, B, and\n * C and divides the angle ABC into two equal sized parts.\n * @pseudo\n * @constructor\n * @name Bisector\n * @type JXG.Line\n * @augments JXG.Line\n * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The angle described by <tt>p1</tt>, <tt>p2</tt> and <tt>p3</tt> will\n * be divided into two equal angles.\n * @example\n * var p1 = board.create('point', [6.0, 4.0]);\n * var p2 = board.create('point', [3.0, 2.0]);\n * var p3 = board.create('point', [1.0, 7.0]);\n *\n * var bi1 = board.create('bisector', [p1, p2, p3]);\n * </pre><div class=\"jxgbox\" id=\"JXG0d58cea8-b06a-407c-b27c-0908f508f5a4\" style=\"width: 400px; height: 400px;\"></div>\n * <script type=\"text/javascript\">\n * (function () {\n * var board = JXG.JSXGraph.initBoard('JXG0d58cea8-b06a-407c-b27c-0908f508f5a4', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});\n * var p1 = board.create('point', [6.0, 4.0]);\n * var p2 = board.create('point', [3.0, 2.0]);\n * var p3 = board.create('point', [1.0, 7.0]);\n * var bi1 = board.create('bisector', [p1, p2, p3]);\n * })();\n * </script><pre>\n */\n JXG.createBisector = function (board, parents, attributes) {\n var p, l, i, attr;\n\n parents = Type.providePoints(board, parents, attributes, 'point');\n if (Type.isPoint(parents[0]) && Type.isPoint(parents[1]) && Type.isPoint(parents[2])) {\n // hidden and fixed helper\n attr = Type.copyAttributes(attributes, board.options, 'bisector', 'point');\n attr.snapToGrid = false;\n\n p = board.create('point', [\n function () {\n return Geometry.angleBisector(parents[0], parents[1], parents[2], board);\n }\n ], attr);\n p.dump = false;\n\n for (i = 0; i < 3; i++) {\n // required for algorithm requiring dependencies between elements\n if (Type.exists(parents[i]._is_new)) {\n p.addChild(parents[i]);\n delete parents[i]._is_new;\n } else {\n parents[i].addChild(p);\n }\n }\n\n if (!Type.exists(attributes.layer)) {\n attributes.layer = board.options.layer.line;\n }\n\n attr = Type.copyAttributes(attributes, board.options, 'bisector');\n l = Line.createLine(board, [parents[1], p], attr);\n\n /**\n * Helper point\n * @memberOf Bisector.prototype\n * @type Point\n * @name point\n */\n l.point = p;\n\n l.elType = 'bisector';\n l.setParents(parents);\n l.subs = {\n point: p\n };\n l.inherits.push(p);\n\n return l;\n }\n\n throw new Error(\"JSXGraph: Can't create angle bisector with parent types '\" +\n (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"'.\" +\n \"\\nPossible parent types: [point,point,point]\");\n };\n\n /**\n * @class Bisector lines are similar to {@link Bisector} but take two lines as parent elements. The resulting element is\n * a composition of two lines.\n * @pseudo\n * @constructor\n * @name Bisectorlines\n * @type JXG.Composition\n * @augments JXG.Composition\n * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {JXG.Line_JXG.Line} l1,l2 The four angles described by the lines <tt>l1</tt> and <tt>l2</tt> will each\n * be divided into two equal angles.\n * @example\n * var p1 = board.create('point', [6.0, 4.0]);\n * var p2 = board.create('point', [3.0, 2.0]);\n * var p3 = board.create('point', [1.0, 7.0]);\n * var p4 = board.create('point', [3.0, 0.0]);\n * var l1 = board.create('line', [p1, p2]);\n * var l2 = board.create('line', [p3, p4]);\n *\n * var bi1 = board.create('bisectorlines', [l1, l2]);\n * </pre><div class=\"jxgbox\" id=\"JXG3121ff67-44f0-4dda-bb10-9cda0b80bf18\" style=\"width: 400px; height: 400px;\"></div>\n * <script type=\"text/javascript\">\n * (function () {\n * var board = JXG.JSXGraph.initBoard('JXG3121ff67-44f0-4dda-bb10-9cda0b80bf18', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});\n * var p1 = board.create('point', [6.0, 4.0]);\n * var p2 = board.create('point', [3.0, 2.0]);\n * var p3 = board.create('point', [1.0, 7.0]);\n * var p4 = board.create('point', [3.0, 0.0]);\n * var l1 = board.create('line', [p1, p2]);\n * var l2 = board.create('line', [p3, p4]);\n * var bi1 = board.create('bisectorlines', [l1, l2]);\n * })();\n * </script><pre>\n */\n JXG.createAngularBisectorsOfTwoLines = function (board, parents, attributes) {\n // The angular bisectors of two line [c1,a1,b1] and [c2,a2,b2] are determined by the equation:\n // (a1*x+b1*y+c1*z)/sqrt(a1^2+b1^2) = +/- (a2*x+b2*y+c2*z)/sqrt(a2^2+b2^2)\n\n var g1, g2, attr, ret,\n l1 = board.select(parents[0]),\n l2 = board.select(parents[1]);\n\n if (l1.elementClass !== Const.OBJECT_CLASS_LINE || l2.elementClass !== Const.OBJECT_CLASS_LINE) {\n throw new Error(\"JSXGraph: Can't create angle bisectors of two lines with parent types '\" +\n (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"'.\" +\n \"\\nPossible parent types: [line,line]\");\n }\n\n if (!Type.exists(attributes.layer)) {\n attributes.layer = board.options.layer.line;\n }\n\n attr = Type.copyAttributes(attributes, board.options, 'bisectorlines', 'line1');\n g1 = board.create('line', [\n function () {\n var d1 = Math.sqrt(l1.stdform[1] * l1.stdform[1] + l1.stdform[2] * l1.stdform[2]),\n d2 = Math.sqrt(l2.stdform[1] * l2.stdform[1] + l2.stdform[2] * l2.stdform[2]);\n\n return l1.stdform[0] / d1 - l2.stdform[0] / d2;\n },\n function () {\n var d1 = Math.sqrt(l1.stdform[1] * l1.stdform[1] + l1.stdform[2] * l1.stdform[2]),\n d2 = Math.sqrt(l2.stdform[1] * l2.stdform[1] + l2.stdform[2] * l2.stdform[2]);\n\n return l1.stdform[1] / d1 - l2.stdform[1] / d2;\n },\n function () {\n var d1 = Math.sqrt(l1.stdform[1] * l1.stdform[1] + l1.stdform[2] * l1.stdform[2]),\n d2 = Math.sqrt(l2.stdform[1] * l2.stdform[1] + l2.stdform[2] * l2.stdform[2]);\n\n return l1.stdform[2] / d1 - l2.stdform[2] / d2;\n }\n ], attr);\n\n if (!Type.exists(attributes.layer)) {\n attributes.layer = board.options.layer.line;\n }\n attr = Type.copyAttributes(attributes, board.options, 'bisectorlines', 'line2');\n g2 = board.create('line', [\n function () {\n var d1 = Math.sqrt(l1.stdform[1] * l1.stdform[1] + l1.stdform[2] * l1.stdform[2]),\n d2 = Math.sqrt(l2.stdform[1] * l2.stdform[1] + l2.stdform[2] * l2.stdform[2]);\n\n return l1.stdform[0] / d1 + l2.stdform[0] / d2;\n },\n function () {\n var d1 = Math.sqrt(l1.stdform[1] * l1.stdform[1] + l1.stdform[2] * l1.stdform[2]),\n d2 = Math.sqrt(l2.stdform[1] * l2.stdform[1] + l2.stdform[2] * l2.stdform[2]);\n\n return l1.stdform[1] / d1 + l2.stdform[1] / d2;\n },\n function () {\n var d1 = Math.sqrt(l1.stdform[1] * l1.stdform[1] + l1.stdform[2] * l1.stdform[2]),\n d2 = Math.sqrt(l2.stdform[1] * l2.stdform[1] + l2.stdform[2] * l2.stdform[2]);\n\n return l1.stdform[2] / d1 + l2.stdform[2] / d2;\n }\n ], attr);\n\n // documentation\n /**\n * First line.\n * @memberOf Bisectorlines.prototype\n * @name line1\n * @type Line\n */\n\n /**\n * Second line.\n * @memberOf Bisectorlines.prototype\n * @name line2\n * @type Line\n */\n\n ret = new Composition({line1: g1, line2: g2});\n\n g1.dump = false;\n g2.dump = false;\n\n ret.elType = 'bisectorlines';\n ret.setParents([l1.id, l2.id]);\n ret.subs = {\n line1: g1,\n line2: g2\n };\n // ret.inherits.push(g1, g2);\n\n return ret;\n };\n\n // /**\n // * @class An m-sector is a line which divides an angle into two angles. It is given by three points A, B, and\n // * C and a real number m, and divides an angle into two angles, an angle with amplitude m and an angle with\n // * amplitude (1-m)\n // * @pseudo\n // * @constructor\n // * @name Msector\n // * @type JXG.Line\n // * @augments JXG.Line\n // * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.\n // * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The angle described by <tt>p1</tt>, <tt>p2</tt> and <tt>p3</tt> will\n // * be divided into two angles according to the value of <tt>m</tt>.\n // * @example\n // * var p1 = board.create('point', [6.0, 4.0]);\n // * var p2 = board.create('point', [3.0, 2.0]);\n // * var p3 = board.create('point', [1.0, 7.0]);\n // *\n // * var bi1 = board.create('msector', [p1, p2, p3], 1/5);\n // * </pre><div id=\"JXG0d58cea8-b06a-407c-b27c-0908f508f5a4\" style=\"width: 400px; height: 400px;\"></div>\n // * <script type=\"text/javascript\">\n // * (function () {\n // * var board = JXG.JSXGraph.initBoard('JXG0d58cea8-b06a-407c-b27c-0908f508f5a4', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});\n // * var p1 = board.create('point', [6.0, 4.0]);\n // * var p2 = board.create('point', [3.0, 2.0]);\n // * var p3 = board.create('point', [1.0, 7.0]);\n // * var bi1 = board.create('msector', [p1, p2, p3], 1/5);\n // * })();\n // * </script><pre>\n // */\n // JXG.createMsector = function (board, parents, attributes) {\n // var p, l, i, attr;\n\n // if (parents[0].elementClass === Const.OBJECT_CLASS_POINT &&\n // parents[1].elementClass === Const.OBJECT_CLASS_POINT &&\n // parents[2].elementClass === Const.OBJECT_CLASS_POINT) {\n // // hidden and fixed helper\n // attr = Type.copyAttributes(attributes, board.options, 'msector', 'point');\n // p = board.create('point', [\n // function () {\n // return Geometry.angleMsector(parents[0], parents[1], parents[2], parents[3], board);\n // }\n // ], attr);\n // p.dump = false;\n\n // for (i = 0; i < 3; i++) {\n // // required for algorithm requiring dependencies between elements\n // parents[i].addChild(p);\n // }\n\n // if (!Type.exists(attributes.layer)) {\n // attributes.layer = board.options.layer.line;\n // }\n\n // attr = Type.copyAttributes(attributes, board.options, 'msector');\n // l = Line.createLine(board, [parents[1], p], attr);\n\n // /**\n // * Helper point\n // * @memberOf Msector.prototype\n // * @type Point\n // * @name point\n // */\n // l.point = p;\n\n // l.elType = 'msector';\n // l.parents = [parents[0].id, parents[1].id, parents[2].id];\n // l.subs = {\n // point: p\n // };\n // l.inherits.push(p);\n\n // return l;\n // }\n\n // throw new Error(\"JSXGraph: Can't create angle msector with parent types '\" +\n // (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"'.\" +\n // \"\\nPossible parent types: [point,point,point,Number]\");\n // };\n\n /**\n * @class Constructs the midpoint of a {@link Circumcircle}. Like the circumcircle the circumcenter\n * is constructed by providing three points.\n * @pseudo\n * @description A circumcenter is given by three points which are all lying on the circle with the\n * constructed circumcenter as the midpoint.\n * @constructor\n * @name Circumcenter\n * @type JXG.Point\n * @augments JXG.Point\n * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The constructed point is the midpoint of the circle determined\n * by p1, p2, and p3.\n * @example\n * var p1 = board.create('point', [0.0, 2.0]);\n * var p2 = board.create('point', [2.0, 1.0]);\n * var p3 = board.create('point', [3.0, 3.0]);\n *\n * var cc1 = board.create('circumcenter', [p1, p2, p3]);\n * </pre><div class=\"jxgbox\" id=\"JXGe8a40f95-bf30-4eb4-88a8-f4d5495261fd\" style=\"width: 400px; height: 400px;\"></div>\n * <script type=\"text/javascript\">\n * var ccmex1_board = JXG.JSXGraph.initBoard('JXGe8a40f95-bf30-4eb4-88a8-f4d5495261fd', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});\n * var ccmex1_p1 = ccmex1_board.create('point', [0.0, 2.0]);\n * var ccmex1_p2 = ccmex1_board.create('point', [6.0, 1.0]);\n * var ccmex1_p3 = ccmex1_board.create('point', [3.0, 7.0]);\n * var ccmex1_cc1 = ccmex1_board.create('circumcenter', [ccmex1_p1, ccmex1_p2, ccmex1_p3]);\n * </script><pre>\n */\n JXG.createCircumcenter = function (board, parents, attributes) {\n var p, i, a, b, c;\n\n parents = Type.providePoints(board, parents, attributes, 'point');\n if (Type.isPoint(parents[0]) && Type.isPoint(parents[1]) && Type.isPoint(parents[2])) {\n\n a = parents[0];\n b = parents[1];\n c = parents[2];\n\n p = Point.createPoint(board, [\n function () {\n return Geometry.circumcenter(a, b, c, board);\n }\n ], attributes);\n\n for (i = 0; i < 3; i++) {\n if (Type.exists(parents[i]._is_new)) {\n p.addChild(parents[i]);\n delete parents[i]._is_new;\n } else {\n parents[i].addChild(p);\n }\n }\n\n p.elType = 'circumcenter';\n p.setParents(parents);\n\n p.generatePolynomial = function () {\n /*\n * CircumcircleMidpoint takes three points A, B and C and creates point M, which is the circumcenter of A, B, and C.\n *\n *\n * So we have two conditions:\n *\n * (a) CT == AT (distance condition I)\n * (b) BT == AT (distance condition II)\n *\n */\n var a1 = a.symbolic.x,\n a2 = a.symbolic.y,\n b1 = b.symbolic.x,\n b2 = b.symbolic.y,\n c1 = c.symbolic.x,\n c2 = c.symbolic.y,\n t1 = p.symbolic.x,\n t2 = p.symbolic.y,\n\n poly1 = ['((', t1, ')-(', a1, '))^2+((', t2, ')-(', a2, '))^2-((', t1, ')-(', b1, '))^2-((', t2, ')-(', b2, '))^2'].join(''),\n poly2 = ['((', t1, ')-(', a1, '))^2+((', t2, ')-(', a2, '))^2-((', t1, ')-(', c1, '))^2-((', t2, ')-(', c2, '))^2'].join('');\n\n return [poly1, poly2];\n };\n\n return p;\n }\n\n throw new Error(\"JSXGraph: Can't create circumcircle midpoint with parent types '\" +\n (typeof parents[0]) + \"', '\" + (typeof parents[1]) + \"' and '\" + (typeof parents[2]) + \"'.\" +\n \"\\nPossible parent types: [point,point,point]\");\n };\n\n /**\n * @class Constructs the incenter of the triangle described by the three given points.{@link http://mathworld.wolfram.com/Incenter.html}\n * @pseudo\n * @constructor\n * @name Incenter\n * @type JXG.Point\n * @augments JXG.Point\n * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The constructed point is the incenter of the triangle described\n * by p1, p2, and p3.\n * @example\n * var p1 = board.create('point', [0.0, 2.0]);\n * var p2 = board.create('point', [2.0, 1.0]);\n * var p3 = board.create('point', [3.0, 3.0]);\n *\n * var ic1 = board.create('incenter', [p1, p2, p3]);\n * </pre><div class=\"jxgbox\" id=\"JXGe8a40f95-bf30-4eb4-88a8-a2d5495261fd\" style=\"width: 400px; height: 400px;\"></div>\n * <script type=\"text/javascript\">\n * var icmex1_board = JXG.JSXGraph.initBoard('JXGe8a40f95-bf30-4eb4-88a8-a2d5495261fd', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});\n * var icmex1_p1 = icmex1_board.create('point', [0.0, 2.0]);\n * var icmex1_p2 = icmex1_board.create('point', [6.0, 1.0]);\n * var icmex1_p3 = icmex1_board.create('point', [3.0, 7.0]);\n * var icmex1_ic1 = icmex1_board.create('incenter', [icmex1_p1, icmex1_p2, icmex1_p3]);\n * </script><pre>\n */\n JXG.createIncenter = function (board, parents, attributes) {\n var p, A, B, C, i;\n\n parents = Type.providePoints(board, parents, attributes, 'point');\n if (parents.length >= 3 && Type.isPoint(parents[0]) && Type.isPoint(parents[1]) && Type.isPoint(parents[2])) {\n A = parents[0];\n B = parents[1];\n C = parents[2];\n\n p = board.create('point', [function () {\n var a, b, c;\n\n a = Math.sqrt((B.X() - C.X()) * (B.X() - C.X()) + (B.Y() - C.Y()) * (B.Y() - C.Y()));\n b = Math.sqrt((A.X() - C.X()) * (A.X() - C.X()) + (A.Y() - C.Y()) * (A.Y() - C.Y()));\n c = Math.sqrt((B.X() - A.X()) * (B.X() - A.X()) + (B.Y() - A.Y()) * (B.Y() - A.Y()));\n\n return new Coords(Const.COORDS_BY_USER, [(a * A.X() + b * B.X() + c * C.X()) / (a + b + c), (a * A.Y() + b * B.Y() + c * C.Y()) / (a + b + c)], board);\n }], attributes);\n\n for (i = 0; i < 3; i++) {\n if (Type.exists(parents[i]._is_new)) {\n p.addChild(parents[i]);\n delete parents[i]._is_new;\n } else {\n parents[i].addChild(p);\n }\n }\n\n p.elType = 'incenter';\n p.setParents(parents);\n\n } else {\n throw new Error(\"JSXGraph: Can't create incenter with parent types '\" +\n (typeof parents[0]) + \"', '\" + (typeof parents[1]) + \"' and '\" + (typeof parents[2]) + \"'.\" +\n \"\\nPossible parent types: [point,point,point]\");\n }\n\n return p;\n };\n\n /**\n * @class A circumcircle is given by three points which are all lying on the circle.\n * @pseudo\n * @constructor\n * @name Circumcircle\n * @type JXG.Circle\n * @augments JXG.Circle\n * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The constructed element is the circle determined by <tt>p1</tt>, <tt>p2</tt>, and <tt>p3</tt>.\n * @example\n * var p1 = board.create('point', [0.0, 2.0]);\n * var p2 = board.create('point', [2.0, 1.0]);\n * var p3 = board.create('point', [3.0, 3.0]);\n *\n * var cc1 = board.create('circumcircle', [p1, p2, p3]);\n * </pre><div class=\"jxgbox\" id=\"JXGe65c9861-0bf0-402d-af57-3ab11962f5ac\" style=\"width: 400px; height: 400px;\"></div>\n * <script type=\"text/javascript\">\n * var ccex1_board = JXG.JSXGraph.initBoard('JXGe65c9861-0bf0-402d-af57-3ab11962f5ac', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});\n * var ccex1_p1 = ccex1_board.create('point', [0.0, 2.0]);\n * var ccex1_p2 = ccex1_board.create('point', [6.0, 1.0]);\n * var ccex1_p3 = ccex1_board.create('point', [3.0, 7.0]);\n * var ccex1_cc1 = ccex1_board.create('circumcircle', [ccex1_p1, ccex1_p2, ccex1_p3]);\n * </script><pre>\n */\n JXG.createCircumcircle = function (board, parents, attributes) {\n var p, c, attr, i;\n\n parents = Type.providePoints(board, parents, attributes, 'point');\n if (parents === false) {\n throw new Error(\"JSXGraph: Can't create circumcircle with parent types '\" +\n (typeof parents[0]) + \"', '\" + (typeof parents[1]) + \"' and '\" + (typeof parents[2]) + \"'.\" +\n \"\\nPossible parent types: [point,point,point]\");\n }\n\n try {\n attr = Type.copyAttributes(attributes, board.options, 'circumcircle', 'center');\n p = JXG.createCircumcenter(board, parents, attr);\n\n p.dump = false;\n\n if (!Type.exists(attributes.layer)) {\n attributes.layer = board.options.layer.circle;\n }\n attr = Type.copyAttributes(attributes, board.options, 'circumcircle');\n c = Circle.createCircle(board, [p, parents[0]], attr);\n\n c.elType = 'circumcircle';\n c.setParents(parents);\n c.subs = {\n center: p\n };\n c.inherits.push(c);\n for (i = 0; i < 3; i++) {\n if (Type.exists(parents[i]._is_new)) {\n c.addChild(parents[i]);\n delete parents[i]._is_new;\n } else {\n parents[i].addChild(c);\n }\n }\n\n } catch (e) {\n throw new Error(\"JSXGraph: Can't create circumcircle with parent types '\" +\n (typeof parents[0]) + \"', '\" + (typeof parents[1]) + \"' and '\" + (typeof parents[2]) + \"'.\" +\n \"\\nPossible parent types: [point,point,point]\");\n }\n\n // p is already stored as midpoint in c so there's no need to store it explicitly.\n\n return c;\n };\n\n /**\n * @class An incircle is given by three points.\n * @pseudo\n * @constructor\n * @name Incircle\n * @type JXG.Circle\n * @augments JXG.Circle\n * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The constructed point is the midpoint of the incircle of\n * <tt>p1</tt>, <tt>p2</tt>, and <tt>p3</tt>.\n * @example\n * var p1 = board.create('point', [0.0, 2.0]);\n * var p2 = board.create('point', [2.0, 1.0]);\n * var p3 = board.create('point', [3.0, 3.0]);\n *\n * var ic1 = board.create('incircle', [p1, p2, p3]);\n * </pre><div class=\"jxgbox\" id=\"JXGe65c9861-0bf0-402d-af57-2ab12962f8ac\" style=\"width: 400px; height: 400px;\"></div>\n * <script type=\"text/javascript\">\n * var icex1_board = JXG.JSXGraph.initBoard('JXGe65c9861-0bf0-402d-af57-2ab12962f8ac', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});\n * var icex1_p1 = icex1_board.create('point', [0.0, 2.0]);\n * var icex1_p2 = icex1_board.create('point', [6.0, 1.0]);\n * var icex1_p3 = icex1_board.create('point', [3.0, 7.0]);\n * var icex1_ic1 = icex1_board.create('incircle', [icex1_p1, icex1_p2, icex1_p3]);\n * </script><pre>\n */\n JXG.createIncircle = function (board, parents, attributes) {\n var i, p, c, attr;\n\n parents = Type.providePoints(board, parents, attributes, 'point');\n if (parents === false) {\n throw new Error(\"JSXGraph: Can't create circumcircle with parent types '\" +\n (typeof parents[0]) + \"', '\" + (typeof parents[1]) + \"' and '\" + (typeof parents[2]) + \"'.\" +\n \"\\nPossible parent types: [point,point,point]\");\n }\n try {\n attr = Type.copyAttributes(attributes, board.options, 'incircle', 'center');\n p = JXG.createIncenter(board, parents, attr);\n\n p.dump = false;\n\n if (!Type.exists(attributes.layer)) {\n attributes.layer = board.options.layer.circle;\n }\n attr = Type.copyAttributes(attributes, board.options, 'incircle');\n c = Circle.createCircle(board, [p, function () {\n var a = Math.sqrt((parents[1].X() - parents[2].X()) * (parents[1].X() - parents[2].X()) + (parents[1].Y() - parents[2].Y()) * (parents[1].Y() - parents[2].Y())),\n b = Math.sqrt((parents[0].X() - parents[2].X()) * (parents[0].X() - parents[2].X()) + (parents[0].Y() - parents[2].Y()) * (parents[0].Y() - parents[2].Y())),\n c = Math.sqrt((parents[1].X() - parents[0].X()) * (parents[1].X() - parents[0].X()) + (parents[1].Y() - parents[0].Y()) * (parents[1].Y() - parents[0].Y())),\n s = (a + b + c) / 2;\n\n return Math.sqrt(((s - a) * (s - b) * (s - c)) / s);\n }], attr);\n\n c.elType = 'incircle';\n c.setParents(parents);\n for (i = 0; i < 3; i++) {\n if (Type.exists(parents[i]._is_new)) {\n c.addChild(parents[i]);\n delete parents[i]._is_new;\n } else {\n parents[i].addChild(c);\n }\n }\n\n /**\n * The center of the incircle\n * @memberOf Incircle.prototype\n * @type Incenter\n * @name center\n */\n c.center = p;\n\n c.subs = {\n center: c.center\n };\n c.inherits.push(p);\n\n } catch (e) {\n throw new Error(\"JSXGraph: Can't create circumcircle with parent types '\" +\n (typeof parents[0]) + \"', '\" + (typeof parents[1]) + \"' and '\" + (typeof parents[2]) + \"'.\" +\n \"\\nPossible parent types: [point,point,point]\");\n }\n\n // p is already stored as midpoint in c so there's no need to store it explicitly.\n\n return c;\n };\n\n /**\n * @class This element is used to construct reflected elements (points, lines, circles, curves, polygons).\n * @pseudo\n * @description A reflected element (point, polygon, line or curve) is given by a given\n * object of the same type and a line of reflection.\n * It is determined by the reflection of the given element\n * across the given line.\n * @constructor\n * @name Reflection\n * @type JXG.GeometryElement\n * @augments JXG.GeometryElement\n * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {JXG.Point|JXG.Line|JXG.Curve|JXG.Polygon_JXG.Line} p,l The reflection element is the reflection of p across the line l.\n * @example\n * var p1 = board.create('point', [0.0, 4.0]);\n * var p2 = board.create('point', [6.0, 1.0]);\n * var l1 = board.create('line', [p1, p2]);\n * var p3 = board.create('point', [3.0, 3.0]);\n *\n * var rp1 = board.create('reflection', [p3, l1]);\n * </pre><div class=\"jxgbox\" id=\"JXG087a798e-a36a-4f52-a2b4-29a23a69393b\" style=\"width: 400px; height: 400px;\"></div>\n * <script type=\"text/javascript\">\n * var rpex1_board = JXG.JSXGraph.initBoard('JXG087a798e-a36a-4f52-a2b4-29a23a69393b', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});\n * var rpex1_p1 = rpex1_board.create('point', [0.0, 4.0]);\n * var rpex1_p2 = rpex1_board.create('point', [6.0, 1.0]);\n * var rpex1_l1 = rpex1_board.create('line', [rpex1_p1, rpex1_p2]);\n * var rpex1_p3 = rpex1_board.create('point', [3.0, 3.0]);\n * var rpex1_rp1 = rpex1_board.create('reflection', [rpex1_p3, rpex1_l1]);\n * </script><pre>\n * @example\n * // Reflection of more elements\n * // reflection line\n * var li = board.create('line', [1,1,1], {strokeColor: '#aaaaaa'});\n *\n * var p1 = board.create('point', [-3,-1], {name: \"A\"});\n * var q1 = board.create('reflection', [p1, li], {name: \"A'\"});\n *\n * var l1 = board.create('line', [1,-5,1]);\n * var l2 = board.create('reflection', [l1, li]);\n *\n * var cu1 = board.create('curve', [[-3, -3, -2.5, -3, -3, -2.5], [-3, -2, -2, -2, -2.5, -2.5]], {strokeWidth:3});\n * var cu2 = board.create('reflection', [cu1, li], {strokeColor: 'red', strokeWidth:3});\n *\n * var pol1 = board.create('polygon', [[-6,-3], [-4,-5], [-5,-1.5]]);\n * var pol2 = board.create('reflection', [pol1, li]);\n *\n * var c1 = board.create('circle', [[-2,-2], [-2, -1]]);\n * var c2 = board.create('reflection', [c1, li]);\n *\n * var a1 = board.create('arc', [[1, 1], [0, 1], [1, 0]], {strokeColor: 'red'});\n * var a2 = board.create('reflection', [a1, li], {strokeColor: 'red'});\n *\n * var s1 = board.create('sector', [[-3.5,-3], [-3.5, -2], [-3.5,-4]], {\n * anglePoint: {visible:true}, center: {visible: true}, radiusPoint: {visible: true},\n * fillColor: 'yellow', strokeColor: 'black'});\n * var s2 = board.create('reflection', [s1, li], {fillColor: 'yellow', strokeColor: 'black', fillOpacity: 0.5});\n *\n * var an1 = board.create('angle', [[-4,3.9], [-3, 4], [-3, 3]]);\n * var an2 = board.create('reflection', [an1, li]);\n *\n * </pre><div id=\"JXG8f763af4-d449-11e7-93b3-901b0e1b8723\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG8f763af4-d449-11e7-93b3-901b0e1b8723',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * // reflection line\n * var li = board.create('line', [1,1,1], {strokeColor: '#aaaaaa'});\n *\n * var p1 = board.create('point', [-3,-1], {name: \"A\"});\n * var q1 = board.create('reflection', [p1, li], {name: \"A'\"});\n *\n * var l1 = board.create('line', [1,-5,1]);\n * var l2 = board.create('reflection', [l1, li]);\n *\n * var cu1 = board.create('curve', [[-3, -3, -2.5, -3, -3, -2.5], [-3, -2, -2, -2, -2.5, -2.5]], {strokeWidth:3});\n * var cu2 = board.create('reflection', [cu1, li], {strokeColor: 'red', strokeWidth:3});\n *\n * var pol1 = board.create('polygon', [[-6,-3], [-4,-5], [-5,-1.5]]);\n * var pol2 = board.create('reflection', [pol1, li]);\n *\n * var c1 = board.create('circle', [[-2,-2], [-2, -1]]);\n * var c2 = board.create('reflection', [c1, li]);\n *\n * var a1 = board.create('arc', [[1, 1], [0, 1], [1, 0]], {strokeColor: 'red'});\n * var a2 = board.create('reflection', [a1, li], {strokeColor: 'red'});\n *\n * var s1 = board.create('sector', [[-3.5,-3], [-3.5, -2], [-3.5,-4]], {\n * anglePoint: {visible:true}, center: {visible: true}, radiusPoint: {visible: true},\n * fillColor: 'yellow', strokeColor: 'black'});\n * var s2 = board.create('reflection', [s1, li], {fillColor: 'yellow', strokeColor: 'black', fillOpacity: 0.5});\n *\n * var an1 = board.create('angle', [[-4,3.9], [-3, 4], [-3, 3]]);\n * var an2 = board.create('reflection', [an1, li]);\n *\n * })();\n *\n * </script><pre>\n *\n */\n JXG.createReflection = function (board, parents, attributes) {\n var l, org, r, r_c, t, i,\n attr, attr2,\n errStr = \"\\nPossible parent types: [point|line|curve|polygon|circle|arc|sector, line]\";\n\n for (i = 0; i < parents.length; ++i) {\n parents[i] = board.select(parents[i]);\n }\n\n attr = Type.copyAttributes(attributes, board.options, 'reflection');\n\n if (Type.isPoint(parents[0])) {\n org = Type.providePoints(board, [parents[0]], attr2)[0];\n } else if (parents[0].elementClass === Const.OBJECT_CLASS_CURVE ||\n parents[0].elementClass === Const.OBJECT_CLASS_LINE ||\n parents[0].type === Const.OBJECT_TYPE_POLYGON ||\n parents[0].elementClass === Const.OBJECT_CLASS_CIRCLE) {\n org = parents[0];\n } else {\n throw new Error(\"JSXGraph: Can't create reflection element with parent types '\" +\n (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"'.\" + errStr);\n }\n\n if (parents[1].elementClass === Const.OBJECT_CLASS_LINE) {\n l = parents[1];\n } else {\n throw new Error(\"JSXGraph: Can't create reflected element with parent types '\" +\n (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"'.\" + errStr);\n }\n\n t = Transform.createTransform(board, [l], {type: 'reflect'});\n if (Type.isPoint(org)) {\n r = Point.createPoint(board, [org, t], attr);\n // Arcs and sectors are treated as curves\n } else if (org.elementClass === Const.OBJECT_CLASS_CURVE){\n r = Curve.createCurve(board, [org, t], attr);\n } else if (org.elementClass === Const.OBJECT_CLASS_LINE){\n r = Line.createLine(board, [org, t], attr);\n } else if (org.type === Const.OBJECT_TYPE_POLYGON){\n r = Polygon.createPolygon(board, [org, t], attr);\n } else if (org.elementClass === Const.OBJECT_CLASS_CIRCLE) {\n if (attr.type.toLowerCase() === 'euclidean') {\n // Create a circle element from a circle and a Euclidean transformation\n attr2 = Type.copyAttributes(attributes, board.options, 'reflection', 'center');\n r_c = Point.createPoint(board, [org.center, t], attr2);\n r_c.prepareUpdate().update().updateVisibility(Type.evaluate(r_c.visProp.visible)).updateRenderer();\n r = Circle.createCircle(board, [r_c, function() {return org.Radius(); }], attr);\n } else {\n // Create a conic element from a circle and a projective transformation\n r = Circle.createCircle(board, [org, t], attr);\n }\n } else {\n throw new Error(\"JSXGraph: Can't create reflected element with parent types '\" +\n (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"'.\" + errStr);\n }\n if (Type.exists(org._is_new)) {\n r.addChild(org);\n delete org._is_new;\n } else {\n // org.addChild(r);\n }\n l.addChild(r);\n\n r.elType = 'reflection';\n r.addParents(l);\n r.prepareUpdate().update(); //.updateVisibility(Type.evaluate(r.visProp.visible)).updateRenderer();\n\n if (Type.isPoint(r)) {\n r.generatePolynomial = function () {\n /*\n * Reflection takes a point R and a line L and creates point P, which is the reflection of R on L.\n * L is defined by two points A and B.\n *\n * So we have two conditions:\n *\n * (a) RP _|_ AB (orthogonality condition)\n * (b) AR == AP (distance condition)\n *\n */\n var a1 = l.point1.symbolic.x,\n a2 = l.point1.symbolic.y,\n b1 = l.point2.symbolic.x,\n b2 = l.point2.symbolic.y,\n p1 = org.symbolic.x,\n p2 = org.symbolic.y,\n r1 = r.symbolic.x,\n r2 = r.symbolic.y,\n\n poly1 = ['((', r2, ')-(', p2, '))*((', a2, ')-(', b2, '))+((', a1, ')-(', b1, '))*((', r1, ')-(', p1, '))'].join(''),\n poly2 = ['((', r1, ')-(', a1, '))^2+((', r2, ')-(', a2, '))^2-((', p1, ')-(', a1, '))^2-((', p2, ')-(', a2, '))^2'].join('');\n\n return [poly1, poly2];\n };\n }\n\n return r;\n };\n\n /**\n * @class A mirror element of a point, line, circle, curve, polygon will be constructed.\n * @pseudo\n * @description A mirror element is determined by the reflection of a given point, line, circle, curve, polygon across another given point.\n * @constructor\n * @name Mirrorelement\n * @type JXG.GeometryElement\n * @augments JXG.GeometryElement\n * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {JXG.Point|JXG.Line|JXG.Curve|JXG.Ppolygon_JXG.Point} p1,p2 The constructed element is the mirror image of p2 across p1.\n * @example\n * // point of reflection\n * var mirr = board.create('point', [-1,-1], {color: '#aaaaaa'});\n *\n * var p1 = board.create('point', [-3,-1], {name: \"A\"});\n * var q1 = board.create('mirrorelement', [p1, mirr], {name: \"A'\"});\n *\n * var l1 = board.create('line', [1, -5, 1]);\n * var l2 = board.create('mirrorelement', [l1, mirr]);\n *\n * var cu1 = board.create('curve', [[-3, -3, -2.5, -3, -3, -2.5], [-3, -2, -2, -2, -2.5, -2.5]], {strokeWidth:3});\n * var cu2 = board.create('mirrorelement', [cu1, mirr], {strokeColor: 'red', strokeWidth:3});\n *\n * var pol1 = board.create('polygon', [[-6,-2], [-4,-4], [-5,-0.5]]);\n * var pol2 = board.create('mirrorelement', [pol1, mirr]);\n *\n * var c1 = board.create('circle', [[-6,-6], [-6, -5]]);\n * var c2 = board.create('mirrorelement', [c1, mirr]);\n *\n * var a1 = board.create('arc', [[1, 1], [0, 1], [1, 0]], {strokeColor: 'red'});\n * var a2 = board.create('mirrorelement', [a1, mirr], {strokeColor: 'red'});\n *\n * var s1 = board.create('sector', [[-3.5,-3], [-3.5, -2], [-3.5,-4]], {\n * anglePoint: {visible:true}, center: {visible: true}, radiusPoint: {visible: true},\n * fillColor: 'yellow', strokeColor: 'black'});\n * var s2 = board.create('mirrorelement', [s1, mirr], {fillColor: 'yellow', strokeColor: 'black', fillOpacity: 0.5});\n *\n * var an1 = board.create('angle', [[-4,3.9], [-3, 4], [-3, 3]]);\n * var an2 = board.create('mirrorelement', [an1, mirr]);\n *\n *\n * </pre><div id=\"JXG026c779c-d8d9-11e7-93b3-901b0e1b8723\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG026c779c-d8d9-11e7-93b3-901b0e1b8723',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * // point of reflection\n * var mirr = board.create('point', [-1,-1], {color: '#aaaaaa'});\n *\n * var p1 = board.create('point', [-3,-1], {name: \"A\"});\n * var q1 = board.create('mirrorelement', [p1, mirr], {name: \"A'\"});\n *\n * var l1 = board.create('line', [1,-5, 1]);\n * var l2 = board.create('mirrorelement', [l1, mirr]);\n *\n * var cu1 = board.create('curve', [[-3, -3, -2.5, -3, -3, -2.5], [-3, -2, -2, -2, -2.5, -2.5]], {strokeWidth:3});\n * var cu2 = board.create('mirrorelement', [cu1, mirr], {strokeColor: 'red', strokeWidth:3});\n *\n * var pol1 = board.create('polygon', [[-6,-2], [-4,-4], [-5,-0.5]]);\n * var pol2 = board.create('mirrorelement', [pol1, mirr]);\n *\n * var c1 = board.create('circle', [[-6,-6], [-6, -5]]);\n * var c2 = board.create('mirrorelement', [c1, mirr]);\n *\n * var a1 = board.create('arc', [[1, 1], [0, 1], [1, 0]], {strokeColor: 'red'});\n * var a2 = board.create('mirrorelement', [a1, mirr], {strokeColor: 'red'});\n *\n * var s1 = board.create('sector', [[-3.5,-3], [-3.5, -2], [-3.5,-4]], {\n * anglePoint: {visible:true}, center: {visible: true}, radiusPoint: {visible: true},\n * fillColor: 'yellow', strokeColor: 'black'});\n * var s2 = board.create('mirrorelement', [s1, mirr], {fillColor: 'yellow', strokeColor: 'black', fillOpacity: 0.5});\n *\n * var an1 = board.create('angle', [[-4,3.9], [-3, 4], [-3, 3]]);\n * var an2 = board.create('mirrorelement', [an1, mirr]);\n *\n * })();\n *\n * </script><pre>\n */\n JXG.createMirrorElement = function (board, parents, attributes) {\n var org, i, m, r, r_c, t,\n attr, attr2,\n errStr = \"\\nPossible parent types: [point|line|curve|polygon|circle|arc|sector, point]\";\n\n for (i = 0; i < parents.length; ++i) {\n parents[i] = board.select(parents[i]);\n }\n\n attr = Type.copyAttributes(attributes, board.options, 'mirrorelement');\n if (Type.isPoint(parents[0])) {\n // Create point to be mirrored if supplied by coords array.\n org = Type.providePoints(board, [parents[0]], attr)[0];\n } else if (parents[0].elementClass === Const.OBJECT_CLASS_CURVE ||\n parents[0].elementClass === Const.OBJECT_CLASS_LINE ||\n parents[0].type === Const.OBJECT_TYPE_POLYGON ||\n parents[0].elementClass === Const.OBJECT_CLASS_CIRCLE) {\n org = parents[0];\n } else {\n throw new Error(\"JSXGraph: Can't create mirror element with parent types '\" +\n (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"'.\" + errStr);\n }\n\n if (Type.isPoint(parents[1])) {\n attr2 = Type.copyAttributes(attributes, board.options, 'mirrorelement', 'point');\n // Create mirror point if supplied by coords array.\n m = Type.providePoints(board, [parents[1]], attr2)[0];\n } else {\n throw new Error(\"JSXGraph: Can't create mirror element with parent types '\" +\n (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"'.\" + errStr);\n }\n\n t = Transform.createTransform(board, [Math.PI, m], {type: 'rotate'});\n if (Type.isPoint(org)) {\n r = Point.createPoint(board, [org, t], attr);\n\n // Arcs and sectors are treated as curves\n } else if (org.elementClass === Const.OBJECT_CLASS_CURVE){\n r = Curve.createCurve(board, [org, t], attr);\n } else if (org.elementClass === Const.OBJECT_CLASS_LINE){\n r = Line.createLine(board, [org, t], attr);\n } else if (org.type === Const.OBJECT_TYPE_POLYGON){\n r = Polygon.createPolygon(board, [org, t], attr);\n } else if (org.elementClass === Const.OBJECT_CLASS_CIRCLE){\n if (attr.type.toLowerCase() === 'euclidean') {\n // Create a circle element from a circle and a Euclidean transformation\n attr2 = Type.copyAttributes(attributes, board.options, 'mirrorelement', 'center');\n r_c = Point.createPoint(board, [org.center, t], attr2);\n r_c.prepareUpdate().update().updateVisibility(Type.evaluate(r_c.visProp.visible)).updateRenderer();\n r = Circle.createCircle(board, [r_c, function() {return org.Radius(); }], attr);\n } else {\n // Create a conic element from a circle and a projective transformation\n r = Circle.createCircle(board, [org, t], attr);\n }\n } else {\n throw new Error(\"JSXGraph: Can't create mirror element with parent types '\" +\n (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"'.\" + errStr);\n }\n\n if (Type.exists(org._is_new)) {\n r.addChild(org);\n delete org._is_new;\n } else {\n // org.addChild(r);\n }\n m.addChild(r);\n\n r.elType = 'mirrorelement';\n r.addParents(m);\n r.prepareUpdate().update();\n\n return r;\n };\n\n /**\n * @class A mirror point will be constructed.\n * @pseudo\n * @description A mirror point is determined by the reflection of a given point against another given point.\n * @constructor\n * @name Mirrorpoint\n * @type JXG.Point\n * @augments JXG.Point\n * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {JXG.Point_JXG.Point} p1,p2 The constructed point is the reflection of p2 against p1.\n *\n * This method is superseeded by the more general {@link JXG.createMirrorElement}.\n * @example\n * var p1 = board.create('point', [3.0, 3.0]);\n * var p2 = board.create('point', [6.0, 1.0]);\n *\n * var mp1 = board.create('mirrorpoint', [p1, p2]);\n * </pre><div class=\"jxgbox\" id=\"JXG7eb2a814-6c4b-4caa-8cfa-4183a948d25b\" style=\"width: 400px; height: 400px;\"></div>\n * <script type=\"text/javascript\">\n * var mpex1_board = JXG.JSXGraph.initBoard('JXG7eb2a814-6c4b-4caa-8cfa-4183a948d25b', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false});\n * var mpex1_p1 = mpex1_board.create('point', [3.0, 3.0]);\n * var mpex1_p2 = mpex1_board.create('point', [6.0, 1.0]);\n * var mpex1_mp1 = mpex1_board.create('mirrorpoint', [mpex1_p1, mpex1_p2]);\n * </script><pre>\n */\n JXG.createMirrorPoint = function (board, parents, attributes) {\n var el = JXG.createMirrorElement(board, parents, attributes);\n el.elType = 'mirrorpoint';\n return el;\n };\n\n /**\n * @class This element is used to visualize the integral of a given curve over a given interval.\n * @pseudo\n * @description The Integral element is used to visualize the area under a given curve over a given interval\n * and to calculate the area's value. For that a polygon and gliders are used. The polygon displays the area,\n * the gliders are used to change the interval dynamically.\n * @constructor\n * @name Integral\n * @type JXG.Curve\n * @augments JXG.Curve\n * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {Array_JXG.Curve} i,c The constructed element covers the area between the curve <tt>c</tt> and the x-axis\n * within the interval <tt>i</tt>.\n * @example\n * var c1 = board.create('functiongraph', [function (t) { return t*t*t; }]);\n * var i1 = board.create('integral', [[-2.0, 2.0], c1]);\n * </pre><div class=\"jxgbox\" id=\"JXGd45d7188-6624-4d6e-bebb-1efa2a305c8a\" style=\"width: 400px; height: 400px;\"></div>\n * <script type=\"text/javascript\">\n * var intex1_board = JXG.JSXGraph.initBoard('JXGd45d7188-6624-4d6e-bebb-1efa2a305c8a', {boundingbox: [-5, 5, 5, -5], axis: true, showcopyright: false, shownavigation: false});\n * var intex1_c1 = intex1_board.create('functiongraph', [function (t) { return Math.cos(t)*t; }]);\n * var intex1_i1 = intex1_board.create('integral', [[-2.0, 2.0], intex1_c1]);\n * </script><pre>\n */\n JXG.createIntegral = function (board, parents, attributes) {\n var interval, curve, attr,\n start, end, startx, starty, endx, endy,\n pa_on_curve, pa_on_axis, pb_on_curve, pb_on_axis,\n t = null, p;\n\n if (Type.isArray(parents[0]) && parents[1].elementClass === Const.OBJECT_CLASS_CURVE) {\n interval = parents[0];\n curve = parents[1];\n } else if (Type.isArray(parents[1]) && parents[0].elementClass === Const.OBJECT_CLASS_CURVE) {\n interval = parents[1];\n curve = parents[0];\n } else {\n throw new Error(\"JSXGraph: Can't create integral with parent types '\" +\n (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"'.\" +\n \"\\nPossible parent types: [[number|function,number|function],curve]\");\n }\n\n attr = Type.copyAttributes(attributes, board.options, 'integral');\n attr.withLabel = false; // There is a custom 'label' below.\n p = board.create('curve', [[0], [0]], attr);\n\n // Correct the interval if necessary - NOT ANYMORE, GGB's fault\n start = interval[0];\n end = interval[1];\n\n if (Type.isFunction(start)) {\n startx = start;\n starty = function () { return curve.Y(startx()); };\n start = startx();\n } else {\n startx = start;\n starty = curve.Y(start);\n }\n\n if (Type.isFunction(end)) {\n endx = end;\n endy = function () { return curve.Y(endx()); };\n end = endx();\n } else {\n endx = end;\n endy = curve.Y(end);\n }\n\n attr = Type.copyAttributes(attributes, board.options, 'integral', 'curveLeft');\n pa_on_curve = board.create('glider', [startx, starty, curve], attr);\n if (Type.isFunction(startx)) {\n pa_on_curve.hideElement();\n }\n\n attr = Type.copyAttributes(attributes, board.options, 'integral', 'baseLeft');\n pa_on_axis = board.create('point', [\n function () {\n if (Type.evaluate(p.visProp.axis) === 'y') {\n return 0;\n }\n\n return pa_on_curve.X();\n },\n function () {\n if (Type.evaluate(p.visProp.axis) === 'y') {\n return pa_on_curve.Y();\n }\n\n return 0;\n }\n ], attr);\n\n attr = Type.copyAttributes(attributes, board.options, 'integral', 'curveRight');\n pb_on_curve = board.create('glider', [endx, endy, curve], attr);\n if (Type.isFunction(endx)) {\n pb_on_curve.hideElement();\n }\n\n attr = Type.copyAttributes(attributes, board.options, 'integral', 'baseRight');\n pb_on_axis = board.create('point', [\n function () {\n if (Type.evaluate(p.visProp.axis) === 'y') {\n return 0;\n }\n return pb_on_curve.X();\n },\n function () {\n if (Type.evaluate(p.visProp.axis) === 'y') {\n return pb_on_curve.Y();\n }\n\n return 0;\n }\n ], attr);\n\n attr = Type.copyAttributes(attributes, board.options, 'integral');\n if (attr.withlabel !== false && attr.axis !== 'y') {\n attr = Type.copyAttributes(attributes, board.options, 'integral', 'label');\n attr = Type.copyAttributes(attr, board.options, 'label');\n\n t = board.create('text', [\n function () {\n var off = new Coords(Const.COORDS_BY_SCREEN, [\n Type.evaluate(this.visProp.offset[0]) + this.board.origin.scrCoords[1],\n 0\n ], this.board, false),\n bb = this.board.getBoundingBox(),\n dx = (bb[2] - bb[0]) * 0.1,\n x = pb_on_curve.X();\n\n if (x < bb[0]) {\n x = bb[0] + dx;\n } else if (x > bb[2]) {\n x = bb[2] - dx;\n }\n\n return x + off.usrCoords[1];\n },\n function () {\n var off = new Coords(Const.COORDS_BY_SCREEN, [\n 0,\n Type.evaluate(this.visProp.offset[1]) + this.board.origin.scrCoords[2]\n ], this.board, false),\n bb = this.board.getBoundingBox(),\n dy = (bb[1] - bb[3]) * 0.1,\n y = pb_on_curve.Y();\n\n if (y > bb[1]) {\n y = bb[1] - dy;\n } else if (y < bb[3]) {\n y = bb[3] + dy;\n }\n\n return y + off.usrCoords[2];\n },\n function () {\n var Int = Numerics.NewtonCotes([pa_on_axis.X(), pb_on_axis.X()], curve.Y);\n return '∫ = ' + Type.toFixed(Int, 4);\n }\n ], attr);\n\n t.dump = false;\n\n pa_on_curve.addChild(t);\n pb_on_curve.addChild(t);\n }\n\n // dump stuff\n pa_on_curve.dump = false;\n pa_on_axis.dump = false;\n\n pb_on_curve.dump = false;\n pb_on_axis.dump = false;\n\n p.elType = 'integral';\n p.setParents([curve.id, interval]);\n p.subs = {\n curveLeft: pa_on_curve,\n baseLeft: pa_on_axis,\n curveRight: pb_on_curve,\n baseRight: pb_on_axis\n };\n p.inherits.push(pa_on_curve, pa_on_axis, pb_on_curve, pb_on_axis);\n\n if (attr.withLabel) {\n p.subs.label = t;\n p.inherits.push(t);\n }\n\n /**\n * Returns the current value of the integral.\n * @memberOf Integral\n * @name Value\n * @function\n * @returns {Number}\n */\n p.Value = function () {\n return Numerics.I([pa_on_axis.X(), pb_on_axis.X()], curve.Y);\n };\n\n /**\n * documented in JXG.Curve\n * @ignore\n */\n p.updateDataArray = function () {\n var x, y,\n i, left, right,\n lowx, upx,\n lowy, upy;\n\n if (Type.evaluate(this.visProp.axis) === 'y') {\n if (pa_on_curve.Y() < pb_on_curve.Y()) {\n lowx = pa_on_curve.X();\n lowy = pa_on_curve.Y();\n upx = pb_on_curve.X();\n upy = pb_on_curve.Y();\n } else {\n lowx = pb_on_curve.X();\n lowy = pb_on_curve.Y();\n upx = pa_on_curve.X();\n upy = pa_on_curve.Y();\n }\n left = Math.min(lowx, upx);\n right = Math.max(lowx, upx);\n\n x = [0, lowx];\n y = [lowy, lowy];\n\n for (i = 0; i < curve.numberPoints; i++) {\n if (lowy <= curve.points[i].usrCoords[2] &&\n left <= curve.points[i].usrCoords[1] &&\n curve.points[i].usrCoords[2] <= upy &&\n curve.points[i].usrCoords[1] <= right) {\n x.push(curve.points[i].usrCoords[1]);\n y.push(curve.points[i].usrCoords[2]);\n }\n }\n x.push(upx);\n y.push(upy);\n x.push(0);\n y.push(upy);\n\n // close the curve\n x.push(0);\n y.push(lowy);\n } else {\n if (pa_on_axis.X() < pb_on_axis.X()) {\n left = pa_on_axis.X();\n right = pb_on_axis.X();\n } else {\n left = pb_on_axis.X();\n right = pa_on_axis.X();\n }\n\n x = [left, left];\n y = [0, curve.Y(left)];\n\n for (i = 0; i < curve.numberPoints; i++) {\n if ((left <= curve.points[i].usrCoords[1]) && (curve.points[i].usrCoords[1] <= right)) {\n x.push(curve.points[i].usrCoords[1]);\n y.push(curve.points[i].usrCoords[2]);\n }\n }\n x.push(right);\n y.push(curve.Y(right));\n x.push(right);\n y.push(0);\n\n // close the curve\n x.push(left);\n y.push(0);\n }\n\n this.dataX = x;\n this.dataY = y;\n };\n\n pa_on_curve.addChild(p);\n pb_on_curve.addChild(p);\n pa_on_axis.addChild(p);\n pb_on_axis.addChild(p);\n\n /**\n * The point on the axis initially corresponding to the lower value of the interval.\n *\n * @name baseLeft\n * @memberOf Integral\n * @type JXG.Point\n */\n p.baseLeft = pa_on_axis;\n\n /**\n * The point on the axis initially corresponding to the higher value of the interval.\n *\n * @name baseRight\n * @memberOf Integral\n * @type JXG.Point\n */\n p.baseRight = pb_on_axis;\n\n /**\n * The glider on the curve corresponding to the lower value of the interval.\n *\n * @name curveLeft\n * @memberOf Integral\n * @type Glider\n */\n p.curveLeft = pa_on_curve;\n\n /**\n * The glider on the axis corresponding to the higher value of the interval.\n *\n * @name curveRight\n * @memberOf Integral\n * @type Glider\n */\n p.curveRight = pb_on_curve;\n\n p.methodMap = JXG.deepCopy(p.methodMap, {\n curveLeft: 'curveLeft',\n baseLeft: 'baseLeft',\n curveRight: 'curveRight',\n baseRight: 'baseRight',\n Value: 'Value'\n });\n\n /**\n * documented in GeometryElement\n * @ignore\n */\n p.label = t;\n\n return p;\n };\n\n /**\n * @class Creates a grid to support the user with element placement.\n * @pseudo\n * @description A grid is a set of vertical and horizontal lines to support the user with element placement. This method\n * draws such a grid on the given board. This method does not\n * take any parent elements. It is usually instantiated on the board's creation via the attribute <tt>grid</tt> set\n * to true.\n * @parameter None.\n * @constructor\n * @name Grid\n * @type JXG.Curve\n * @augments JXG.Curve\n * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @example\n * grid = board.create('grid', []);\n * </pre><div class=\"jxgbox\" id=\"JXGa9a0671f-7a51-4fa2-8697-241142c00940\" style=\"width: 400px; height: 400px;\"></div>\n * <script type=\"text/javascript\">\n * (function () {\n * board = JXG.JSXGraph.initBoard('JXGa9a0671f-7a51-4fa2-8697-241142c00940', {boundingbox:[-4, 6, 10, -6], axis: false, grid: false, keepaspectratio: true});\n * grid = board.create('grid', []);\n * })();\n * </script><pre>\n */\n JXG.createGrid = function (board, parents, attributes) {\n var c, attr;\n\n attr = Type.copyAttributes(attributes, board.options, 'grid');\n c = board.create('curve', [[null], [null]], attr);\n\n c.elType = 'grid';\n c.type = Const.OBJECT_TYPE_GRID;\n\n /**\n * @ignore\n */\n c.updateDataArray = function () {\n var start, end, i, topLeft, bottomRight,\n gridX = Type.evaluate(this.visProp.gridx),\n gridY = Type.evaluate(this.visProp.gridy);\n\n if (Type.isArray(this.visProp.topleft)) {\n topLeft = new Coords(Type.evaluate(this.visProp.tltype) || Const.COORDS_BY_USER,\n this.visProp.topleft, board);\n } else {\n topLeft = new Coords(Const.COORDS_BY_SCREEN, [0, 0], board);\n }\n\n if (Type.isArray(this.visProp.bottomright)) {\n bottomRight = new Coords(Type.evaluate(this.visProp.brtype) || Const.COORDS_BY_USER,\n this.visProp.bottomright, board);\n } else {\n bottomRight = new Coords(Const.COORDS_BY_SCREEN, [board.canvasWidth, board.canvasHeight], board);\n }\n\n\n //\n // | | |\n // ----+---------+---------+-----\n // | /| |\n // | gridY| <---+------ Grid Cell\n // | \\| |\n // ----+---------+---------+-----\n // | |\\ gridX /|\n // | | |\n //\n // uc: usercoordinates\n //\n // currently one grid cell is 1/JXG.Options.grid.gridX uc wide and 1/JXG.Options.grid.gridY uc high.\n // this may work perfectly with GeonextReader (#readGeonext, initialization of gridX and gridY) but it\n // is absolutely not user friendly when it comes to use it as an API interface.\n // i changed this to use gridX and gridY as the actual width and height of the grid cell. for this i\n // had to refactor these methods:\n //\n // DONE JXG.Board.calculateSnapSizes (init p1, p2)\n // DONE JXG.GeonextReader.readGeonext (init gridX, gridY)\n //\n\n board.options.grid.hasGrid = true;\n\n\t\t\t// fix_grid: adding integer function to calculation of start and end values, and adding to calculation of start and end values below\n\t\t\t// To allow this:\n\t\t\t// (axes on the outside, min value of grid = 0.25)\n //\n // | | | |\n // 1.5 -+----+---------+----------+-----\n // | | | |\n // | | | |\n // | | | |\n // 1 -+----+---------+----------+-----\n // | | | |\n // | | | |\n // | | | |\n // 0.5 -+----+---------+----------+-----\n // | | | |\n // +----+---------+----------+-----\n // | | |\n // 0.5 1 1.5\n //\n // fix_grid: these lines disabled:\n // topLeft.setCoordinates(Const.COORDS_BY_USER, [Math.ceil(topLeft.usrCoords[1] / gridX) * gridX, Math.floor(topLeft.usrCoords[2] / gridY) * gridY]);\n // bottomRight.setCoordinates(Const.COORDS_BY_USER, [Math.floor(bottomRight.usrCoords[1] / gridX) * gridX, Math.ceil(bottomRight.usrCoords[2] / gridY) * gridY]);\n\n c.dataX = [];\n c.dataY = [];\n\n // Sometimes the bounding box is used to invert the axis. We have to take this into account here.\n // fix_grid: adding integer function to calculation of start and end values\n start = Math.floor(topLeft.usrCoords[2] / gridY) * gridY;\n end = Math.ceil(bottomRight.usrCoords[2] / gridY) * gridY;\n\n if (topLeft.usrCoords[2] < bottomRight.usrCoords[2]) {\n start = Math.ceil(bottomRight.usrCoords[2] / gridY) * gridY; // bottomRight.usrCoords[2];\n end = Math.floor(topLeft.usrCoords[2] / gridY) * gridY;\n }\n\n // start with the horizontal grid:\n for (i = start; i > end - gridY; i -= gridY) {\n c.dataX.push(topLeft.usrCoords[1], bottomRight.usrCoords[1], NaN);\n c.dataY.push(i, i, NaN);\n }\n\n // fix_grid: adding integer function to calculation of start and end values\n start = Math.ceil(topLeft.usrCoords[1] / gridX) * gridX;\n end = Math.floor(bottomRight.usrCoords[1] / gridX) * gridX;\n\n if (topLeft.usrCoords[1] > bottomRight.usrCoords[1]) {\n\t\t\t\tstart = Math.floor(bottomRight.usrCoords[1] / gridX) * gridX;\n\t\t\t\tend = Math.ceil(topLeft.usrCoords[1] / gridX) * gridX;\n }\n\n // build vertical grid\n for (i = start; i < end + gridX; i += gridX) {\n c.dataX.push(i, i, NaN);\n c.dataY.push(topLeft.usrCoords[2], bottomRight.usrCoords[2], NaN);\n }\n\n };\n\n // we don't care about highlighting so we turn it off completely to save a lot of\n // time on every mouse move\n c.hasPoint = function () {\n return false;\n };\n\n board.grids.push(c);\n\n return c;\n };\n\n /**\n * @class Creates an area indicating the solution of a linear inequality or an inequality\n * of a function graph, i.e. an inequality of type y <= f(x).\n * @pseudo\n * @description Display the solution set of a linear inequality (less than or equal to).\n * To be precise, the solution set of the inequality <i>y <= b/a * x + c/a</i> is shown.\n * In case <i>a = 0</i>, that is if the equation of the line is <i>bx + c = 0</i>,\n * the area of the inequality <i>bx + c <= 0</i> is shown.\n * <p>\n * For function graphs the area below the function graph is filled, i.e. the\n * area of the inequality y <= f(x).\n * With the attribute inverse:true the area of the inequality y >= f(x) is filled.\n *\n * @param {JXG.Line} l The area drawn will be the area below this line. With the attribute\n * inverse:true, the inequality 'greater than or equal to' is shown.\n * @constructor\n * @name Inequality\n * @type JXG.Curve\n * @augments JXG.Curve\n * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @example\n * var p = board.create('point', [1, 3]),\n * q = board.create('point', [-2, -4]),\n * l = board.create('line', [p, q]),\n * ineq = board.create('inequality', [l]);\n * ineq = board.create('inequality', [l]);\n * </pre><div class=\"jxgbox\" id=\"JXG2b703006-fd98-11e1-b79e-ef9e591c002e\" style=\"width: 400px; height: 400px;\"></div>\n * <script type=\"text/javascript\">\n * (function () {\n * var board = JXG.JSXGraph.initBoard('JXG2b703006-fd98-11e1-b79e-ef9e591c002e', {boundingbox:[-4, 6, 10, -6], axis: false, grid: false, keepaspectratio: true}),\n * p = board.create('point', [1, 3]),\n * q = board.create('point', [-2, -4]),\n * l = board.create('line', [p, q]),\n * ineq = board.create('inequality', [l]);\n * })();\n * </script><pre>\n *\n * @example\n * // Plot the inequality\n * // y >= 2/3 x + 1\n * // or\n * // 0 >= -3y + 2x +1\n * var l = board.create('line', [1, 2, -3]),\n * ineq = board.create('inequality', [l], {inverse:true});\n * </pre><div class=\"jxgbox\" id=\"JXG1ded3812-2da4-4323-abaf-1db4bad1bfbd\" style=\"width: 400px; height: 400px;\"></div>\n * <script type=\"text/javascript\">\n * (function () {\n * var board = JXG.JSXGraph.initBoard('JXG1ded3812-2da4-4323-abaf-1db4bad1bfbd', {boundingbox:[-4, 6, 10, -6], axis: false, grid: false, keepaspectratio: true}),\n * l = board.create('line', [1, 2, -3]),\n * ineq = board.create('inequality', [l], {inverse:true});\n * })();\n * </script><pre>\n *\n * @example\n * var f = board.create('functiongraph', ['sin(x)', -2*Math.PI, 2*Math.PI]);\n *\n * var ineq_lower = board.create('inequality', [f]);\n * var ineq_greater = board.create('inequality', [f], {inverse: true, fillColor: 'yellow'});\n *\n *\n * </pre><div id=\"JXGdb68c574-414c-11e8-839a-901b0e1b8723\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXGdb68c574-414c-11e8-839a-901b0e1b8723',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var f = board.create('functiongraph', ['sin(x)', -2*Math.PI, 2*Math.PI]);\n *\n * var ineq_lower = board.create('inequality', [f]);\n * var ineq_greater = board.create('inequality', [f], {inverse: true, fillColor: 'yellow'});\n *\n *\n * })();\n *\n * </script><pre>\n *\n */\n JXG.createInequality = function (board, parents, attributes) {\n var f, a, attr;\n\n attr = Type.copyAttributes(attributes, board.options, 'inequality');\n if (parents[0].elementClass === Const.OBJECT_CLASS_LINE) {\n a = board.create('curve', [[], []], attr);\n a.hasPoint = function () {\n return false;\n };\n a.updateDataArray = function () {\n var i1, i2,\n // This will be the height of the area. We mustn't rely upon the board height because if we pan the view\n // such that the line is not visible anymore, the borders of the area will get visible in some cases.\n h,\n bb = board.getBoundingBox(),\n factor = attr.inverse ? -1 : 1,\n expansion = 1.5,\n w = expansion * Math.max(bb[2] - bb[0], bb[1] - bb[3]),\n // Fake a point (for Math.Geometry.perpendicular)\n // contains centroid of the board\n dp = {\n coords: {\n usrCoords: [1, (bb[0] + bb[2]) / 2, attr.inverse ? bb[1] : bb[3]]\n }\n },\n\n slope1 = parents[0].stdform.slice(1),\n slope2 = slope1;\n\n // This is wrong. Example:\n // var line = board.create('line', [0, -1, -1]);\n // var ineq = board.create('inequality', [line]);\n //\n // if (slope1[1] > 0) {\n // slope1 = Statistics.multiply(slope1, -1);\n // slope2 = slope1;\n // }\n\n // Calculate the area height as\n // expansion times the distance of the line to the\n // point in the middle of the top/bottom border.\n h = expansion * Math.max(Geometry.perpendicular(parents[0], dp, board)[0].distance(Const.COORDS_BY_USER, dp.coords), w);\n h *= factor;\n\n // reuse dp\n dp = {\n coords: {\n usrCoords: [1, (bb[0] + bb[2]) / 2, (bb[1] + bb[3]) / 2]\n }\n };\n\n // If dp is on the line, Geometry.perpendicular will return a point not on the line.\n // Since this somewhat odd behavior of Geometry.perpendicular is needed in GEONExT,\n // it is circumvented here.\n if (Math.abs(Mat.innerProduct(dp.coords.usrCoords, parents[0].stdform, 3)) >= Mat.eps) {\n dp = Geometry.perpendicular(parents[0], dp, board)[0].usrCoords;\n } else {\n dp = dp.coords.usrCoords;\n }\n i1 = [1, dp[1] + slope1[1] * w, dp[2] - slope1[0] * w];\n i2 = [1, dp[1] - slope2[1] * w, dp[2] + slope2[0] * w];\n\n // One of the vectors based in i1 and orthogonal to the parent line has the direction d1 = (slope1, -1)\n // We will go from i1 to to i1 + h*d1, from there to i2 + h*d2 (with d2 calculated equivalent to d1) and\n // end up in i2.\n this.dataX = [i1[1], i1[1] + slope1[0] * h, i2[1] + slope2[0] * h, i2[1], i1[1]];\n this.dataY = [i1[2], i1[2] + slope1[1] * h, i2[2] + slope2[1] * h, i2[2], i1[2]];\n };\n } else if (parents[0].elementClass === Const.OBJECT_CLASS_CURVE &&\n parents[0].visProp.curvetype === 'functiongraph') {\n\n a = board.create('curve', [[], []], attr);\n a.updateDataArray = function() {\n var bbox = this.board.getBoundingBox(),\n points = [],\n infty, first, last,\n len, i,\n mi = parents[0].minX(),\n ma = parents[0].maxX(),\n curve_mi, curve_ma,\n firstx,\n lastx,\n enlarge = (bbox[1] - bbox[3]) * 0.3, // enlarge the bbox vertically by this amount\n inverse = Type.evaluate(this.visProp.inverse);\n\n // inverse == true <=> Fill area with y >= f(x)\n infty = (inverse) ? 1 : 3; // we will use either bbox[1] or bbox[3] below\n\n this.dataX = [];\n this.dataY = [];\n len = parents[0].points.length;\n if (len === 0) {\n return;\n }\n\n bbox[1] += enlarge;\n bbox[3] -= enlarge;\n\n last = -1;\n while (last < len - 1) {\n\n // Find the first point with real coordinates on this curve segment\n for (i = last + 1, first = len; i < len; i++) {\n if (parents[0].points[i].isReal()) {\n first = i;\n break;\n }\n }\n // No real points found -> exit\n if (first >= len) {\n break;\n }\n\n // Find the last point with real coordinates on this curve segment\n for (i = first, last = len - 1; i < len - 1; i++) {\n if (!parents[0].points[i + 1].isReal()) {\n last = i;\n break;\n }\n }\n\n firstx = parents[0].points[first].usrCoords[1];\n lastx = parents[0].points[last].usrCoords[1];\n\n // Restrict the plot interval if the function ends inside of the board\n curve_mi = (bbox[0] < mi) ? mi : bbox[0];\n curve_ma = (bbox[2] > ma) ? ma : bbox[2];\n\n // Found NaNs\n curve_mi = (first === 0) ? curve_mi : Math.max(curve_mi, firstx);\n curve_ma = (last === len - 1) ? curve_ma : Math.min(curve_ma, lastx);\n\n // First and last relevant x-coordinate of the curve\n curve_mi = (first === 0) ? mi: firstx;\n curve_ma = (last === len - 1)? ma: lastx;\n\n\n // Copy the curve points\n points = [];\n\n points.push([1, curve_mi, bbox[infty]]);\n points.push([1, curve_mi, parents[0].points[first].usrCoords[2]]);\n for (i = first; i <= last; i++) {\n points.push(parents[0].points[i].usrCoords);\n }\n points.push([1, curve_ma, parents[0].points[last].usrCoords[2]]);\n points.push([1, curve_ma, bbox[infty]]);\n points.push(points[0]);\n\n for (i = 0; i < points.length; i++) {\n this.dataX.push(points[i][1]);\n this.dataY.push(points[i][2]);\n }\n\n\n if (last < len - 1) {\n this.dataX.push(NaN);\n this.dataY.push(NaN);\n }\n }\n\n };\n\n // Previous code:\n a.hasPoint = function () {\n return false;\n };\n } else {\n // Not yet practical?\n f = Type.createFunction(parents[0]);\n if (!Type.exists(f)) {\n throw new Error(\"JSXGraph: Can't create area with the given parents.\" +\n \"\\nPossible parent types: [line], [function]\");\n }\n }\n\n a.addParents(parents[0]);\n return a;\n };\n\n\n JXG.registerElement('arrowparallel', JXG.createArrowParallel);\n JXG.registerElement('bisector', JXG.createBisector);\n JXG.registerElement('bisectorlines', JXG.createAngularBisectorsOfTwoLines);\n JXG.registerElement('msector', JXG.createMsector);\n JXG.registerElement('circumcircle', JXG.createCircumcircle);\n JXG.registerElement('circumcirclemidpoint', JXG.createCircumcenter);\n JXG.registerElement('circumcenter', JXG.createCircumcenter);\n JXG.registerElement('incenter', JXG.createIncenter);\n JXG.registerElement('incircle', JXG.createIncircle);\n JXG.registerElement('integral', JXG.createIntegral);\n JXG.registerElement('midpoint', JXG.createMidpoint);\n JXG.registerElement('mirrorelement', JXG.createMirrorElement);\n JXG.registerElement('mirrorpoint', JXG.createMirrorPoint);\n JXG.registerElement('normal', JXG.createNormal);\n JXG.registerElement('orthogonalprojection', JXG.createOrthogonalProjection);\n JXG.registerElement('parallel', JXG.createParallel);\n JXG.registerElement('parallelpoint', JXG.createParallelPoint);\n JXG.registerElement('perpendicular', JXG.createPerpendicular);\n JXG.registerElement('perpendicularpoint', JXG.createPerpendicularPoint);\n JXG.registerElement('perpendicularsegment', JXG.createPerpendicularSegment);\n JXG.registerElement('reflection', JXG.createReflection);\n JXG.registerElement('grid', JXG.createGrid);\n JXG.registerElement('inequality', JXG.createInequality);\n\n return {\n createArrowParallel: JXG.createArrowParallel,\n createBisector: JXG.createBisector,\n createAngularBisectorOfTwoLines: JXG.createAngularBisectorsOfTwoLines,\n createCircumcircle: JXG.createCircumcircle,\n createCircumcenter: JXG.createCircumcenter,\n createIncenter: JXG.createIncenter,\n createIncircle: JXG.createIncircle,\n createIntegral: JXG.createIntegral,\n createMidpoint: JXG.createMidpoint,\n createMirrorElement: JXG.createMirrorElement,\n createMirrorPoint: JXG.createMirrorPoint,\n createNormal: JXG.createNormal,\n createOrthogonalProjection: JXG.createOrthogonalProjection,\n createParallel: JXG.createParallel,\n createParallelPoint: JXG.createParallelPoint,\n createPerpendicular: JXG.createPerpendicular,\n createPerpendicularPoint: JXG.createPerpendicularPoint,\n createPerpendicularSegmen: JXG.createPerpendicularSegment,\n createReflection: JXG.createReflection,\n createGrid: JXG.createGrid,\n createInequality: JXG.createInequality\n };\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true*/\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n jxg\n math/math\n math/geometry\n math/numerics\n math/statistics\n math/symbolic\n base/composition\n base/coords\n base/constants\n utils/type\n elements:\n line\n circle\n transform\n point\n glider\n text\n curve\n */\n\ndefine('element/locus',[\n 'jxg', 'math/symbolic', 'utils/type'\n], function (JXG, Symbolic, Type) {\n\n \"use strict\";\n\n /**\n * @class This element is used to visualize the locus of a given dependent point.\n * @pseudo\n * @description The locus element is used to visualize the curve a given point describes.\n * @constructor\n * @name Locus\n * @type JXG.Curve\n * @augments JXG.Curve\n * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {JXG.Point} p The constructed curve is the geometric locus of the given point.\n * @example\n * // This examples needs JXG.Server up and running, otherwise it won't work.\n * p1 = board.create('point', [0, 0]);\n * p2 = board.create('point', [6, -1]);\n * c1 = board.create('circle', [p1, 2]);\n * c2 = board.create('circle', [p2, 1.5]);\n * g1 = board.create('glider', [6, 3, c1]);\n * c3 = board.create('circle', [g1, 4]);\n * g2 = board.create('intersection', [c2,c3,0]);\n * m1 = board.create('midpoint', [g1,g2]);\n * loc = board.create('locus', [m1], {strokeColor: 'red'});\n * </pre><div class=\"jxgbox\" id=\"JXGd45d7188-6624-4d6e-bebb-1efa2a305c8a\" style=\"width: 400px; height: 400px;\"></div>\n * <script type=\"text/javascript\">\n * lcex_board = JXG.JSXGraph.initBoard('JXGd45d7188-6624-4d6e-bebb-1efa2a305c8a', {boundingbox:[-4, 6, 10, -6], axis: true, grid: false, keepaspectratio: true});\n * lcex_p1 = lcex_board.create('point', [0, 0]);\n * lcex_p2 = lcex_board.create('point', [6, -1]);\n * lcex_c1 = lcex_board.create('circle', [lcex_p1, 2]);\n * lcex_c2 = lcex_board.create('circle', [lcex_p2, 1.5]);\n * lcex_g1 = lcex_board.create('glider', [6, 3, lcex_c1]);\n * lcex_c3 = lcex_board.create('circle', [lcex_g1, 4]);\n * lcex_g2 = lcex_board.create('intersection', [lcex_c2,lcex_c3,0]);\n * lcex_m1 = lcex_board.create('midpoint', [lcex_g1,lcex_g2]);\n * lcex_loc = board.create('locus', [lcex_m1], {strokeColor: 'red'});\n * </script><pre>\n */\n JXG.createLocus = function (board, parents, attributes) {\n var c, p;\n\n if (Type.isArray(parents) && parents.length === 1 && Type.isPoint(parents[0])) {\n p = parents[0];\n } else {\n throw new Error(\"JSXGraph: Can't create locus with parent of type other than point.\" +\n \"\\nPossible parent types: [point]\");\n }\n\n c = board.create('curve', [[null], [null]], attributes);\n c.dontCallServer = false;\n\n c.elType = 'locus';\n c.setParents([p.id]);\n\n /**\n * Should be documented in JXG.Curve\n * @ignore\n */\n c.updateDataArray = function () {\n var spe, cb, data;\n\n if (c.board.mode > 0) {\n return;\n }\n\n spe = Symbolic.generatePolynomials(board, p, true).join('|');\n if (spe === c.spe) {\n return;\n }\n\n c.spe = spe;\n\n cb = function (x, y, eq, t) {\n c.dataX = x;\n c.dataY = y;\n\n /**\n * The implicit definition of the locus.\n * @memberOf Locus.prototype\n * @name eq\n * @type String\n */\n c.eq = eq;\n\n /**\n * The time it took to calculate the locus\n * @memberOf Locus.prototype\n * @name ctime\n * @type Number\n */\n c.ctime = t;\n\n // convert equation and use it to build a generatePolynomial-method\n c.generatePolynomial = (function (equations) {\n return function (point) {\n var i,\n x = '(' + point.symbolic.x + ')',\n y = '(' + point.symbolic.y + ')',\n res = [];\n\n for (i = 0; i < equations.length; i++) {\n res[i] = equations[i].replace(/\\*\\*/g, '^').replace(/x/g, x).replace(/y/g, y);\n }\n\n return res;\n };\n }(eq));\n };\n data = Symbolic.geometricLocusByGroebnerBase(board, p, cb);\n\n cb(data.datax, data.datay, data.polynomial, data.exectime);\n };\n return c;\n };\n\n JXG.registerElement('locus', JXG.createLocus);\n\n return {\n createLocus: JXG.createLocus\n };\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true*/\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n jxg\n base/constants\n base/coords\n base/element\n math/math\n utils/type\n */\n\n/**\n * @fileoverview In this file the geometry element Image is defined.\n */\n\ndefine('base/image',[\n 'jxg', 'base/constants', 'base/coords', 'base/element', 'math/math', 'utils/type', 'base/coordselement'\n], function (JXG, Const, Coords, GeometryElement, Mat, Type, CoordsElement) {\n\n \"use strict\";\n\n /**\n * Construct and handle images\n *\n * The image can be supplied as an URL or an base64 encoded inline image\n * like \"data:image/png;base64, /9j/4AAQSkZJRgA...\" or a function returning\n * an URL: function(){ return 'xxx.png; }.\n *\n * @class Creates a new image object. Do not use this constructor to create a image. Use {@link JXG.Board#create} with\n * type {@link Image} instead.\n * @augments JXG.GeometryElement\n * @augments JXG.CoordsElement\n * @param {string|JXG.Board} board The board the new image is drawn on.\n * @param {Array} coordinates An array with the user coordinates of the image.\n * @param {Object} attributes An object containing visual and - optionally - a name and an id.\n * @param {string|function} url An URL string or a function returning an URL string.\n * @param {Array} size Array containing width and height of the image in user coordinates.\n *\n */\n JXG.Image = function (board, coords, attributes, url, size) {\n this.constructor(board, attributes, Const.OBJECT_TYPE_IMAGE, Const.OBJECT_CLASS_OTHER);\n this.element = this.board.select(attributes.anchor);\n this.coordsConstructor(coords);\n\n this.W = Type.createFunction(size[0], this.board, '');\n this.H = Type.createFunction(size[1], this.board, '');\n\n this.usrSize = [this.W(), this.H()];\n\n /**\n * Array of length two containing [width, height] of the image in pixel.\n * @type array\n */\n this.size = [Math.abs(this.usrSize[0] * board.unitX), Math.abs(this.usrSize[1] * board.unitY)];\n\n /**\n * 'href' of the image. This might be an URL, but also a data-uri is allowed.\n * @type string\n */\n this.url = url;\n\n this.elType = 'image';\n\n // span contains the anchor point and the two vectors\n // spanning the image rectangle.\n this.span = [\n this.coords.usrCoords.slice(0),\n [this.coords.usrCoords[0], this.W(), 0],\n [this.coords.usrCoords[0], 0, this.H()]\n ];\n\n //this.parent = board.select(attributes.anchor);\n this.id = this.board.setId(this, 'Im');\n\n this.board.renderer.drawImage(this);\n this.board.finalizeAdding(this);\n\n this.methodMap = JXG.deepCopy(this.methodMap, {\n addTransformation: 'addTransform',\n trans: 'addTransform'\n });\n };\n\n JXG.Image.prototype = new GeometryElement();\n Type.copyPrototypeMethods(JXG.Image, CoordsElement, 'coordsConstructor');\n\n JXG.extend(JXG.Image.prototype, /** @lends JXG.Image.prototype */ {\n\n /**\n * Checks whether (x,y) is over or near the image;\n * @param {Number} x Coordinate in x direction, screen coordinates.\n * @param {Number} y Coordinate in y direction, screen coordinates.\n * @returns {Boolean} True if (x,y) is over the image, False otherwise.\n */\n hasPoint: function (x, y) {\n var dx, dy, r, type, prec,\n c, v, p, dot,\n len = this.transformations.length;\n\n if (Type.isObject(Type.evaluate(this.visProp.precision))) {\n type = this.board._inputDevice;\n prec = Type.evaluate(this.visProp.precision[type]);\n } else {\n // 'inherit'\n prec = this.board.options.precision.hasPoint;\n }\n\n // Easy case: no transformation\n if (len === 0) {\n dx = x - this.coords.scrCoords[1];\n dy = this.coords.scrCoords[2] - y;\n r = prec;\n\n return dx >= -r && dx - this.size[0] <= r &&\n dy >= -r && dy - this.size[1] <= r;\n }\n\n // Image is transformed\n c = new Coords(Const.COORDS_BY_SCREEN, [x, y], this.board);\n // v is the vector from anchor point to the drag point\n c = c.usrCoords;\n v = [c[0] - this.span[0][0],\n c[1] - this.span[0][1],\n c[2] - this.span[0][2]];\n dot = Mat.innerProduct; // shortcut\n\n // Project the drag point to the sides.\n p = dot(v, this.span[1]);\n if (0 <= p && p <= dot(this.span[1], this.span[1])) {\n p = dot(v, this.span[2]);\n\n if (0 <= p && p <= dot(this.span[2], this.span[2])) {\n return true;\n }\n }\n return false;\n },\n\n /**\n * Recalculate the coordinates of lower left corner and the width and height.\n *\n * @returns {JXG.GeometryElement} A reference to the element\n * @private\n */\n update: function (fromParent) {\n if (!this.needsUpdate) {\n return this;\n }\n\n this.updateCoords(fromParent);\n this.updateSize();\n this.updateSpan();\n\n return this;\n },\n\n /**\n * Send an update request to the renderer.\n * @private\n */\n updateRenderer: function () {\n return this.updateRendererGeneric('updateImage');\n },\n\n /**\n * Updates the internal arrays containing size of the image.\n * @returns {JXG.GeometryElement} A reference to the element\n * @private\n */\n updateSize: function () {\n this.usrSize = [this.W(), this.H()];\n this.size = [Math.abs(this.usrSize[0] * this.board.unitX), Math.abs(this.usrSize[1] * this.board.unitY)];\n\n return this;\n },\n\n /**\n * Update the anchor point of the image, i.e. the lower left corner\n * and the two vectors which span the rectangle.\n * @returns {JXG.GeometryElement} A reference to the element\n * @private\n *\n */\n updateSpan: function () {\n var i, j, len = this.transformations.length, v = [];\n\n if (len === 0) {\n this.span = [[this.Z(), this.X(), this.Y()],\n [this.Z(), this.W(), 0],\n [this.Z(), 0, this.H()]];\n } else {\n // v contains the three defining corners of the rectangle/image\n v[0] = [this.Z(), this.X(), this.Y()];\n v[1] = [this.Z(), this.X() + this.W(), this.Y()];\n v[2] = [this.Z(), this.X(), this.Y() + this.H()];\n\n // Transform the three corners\n for (i = 0; i < len; i++) {\n for (j = 0; j < 3; j++) {\n v[j] = Mat.matVecMult(this.transformations[i].matrix, v[j]);\n }\n }\n // Normalize the vectors\n for (j = 0; j < 3; j++) {\n v[j][1] /= v[j][0];\n v[j][2] /= v[j][0];\n v[j][0] /= v[j][0];\n }\n // Compute the two vectors spanning the rectangle\n // by subtracting the anchor point.\n for (j = 1; j < 3; j++) {\n v[j][0] -= v[0][0];\n v[j][1] -= v[0][1];\n v[j][2] -= v[0][2];\n }\n this.span = v;\n }\n\n return this;\n },\n\n addTransform: function (transform) {\n var i;\n\n if (Type.isArray(transform)) {\n for (i = 0; i < transform.length; i++) {\n this.transformations.push(transform[i]);\n }\n } else {\n this.transformations.push(transform);\n }\n\n return this;\n },\n\n // Documented in element.js\n getParents: function () {\n var p = [this.url, [this.Z(), this.X(), this.Y()], this.usrSize];\n\n if (this.parents.length !== 0) {\n p = this.parents;\n }\n\n return p;\n },\n\n /**\n * Set the width and height of the image. After setting a new size,\n * board.update() or image.fullUpdate()\n * has to be called to make the change visible.\n * @param {number, function, string} width Number, function or string\n * that determines the new width of the image\n * @param {number, function, string} height Number, function or string\n * that determines the new height of the image\n * @returns {JXG.GeometryElement} A reference to the element\n *\n * @example\n * var im = board.create('image', ['https://jsxgraph.org/distrib/images/uccellino.jpg',\n * [-3,-2], [3,3]]);\n * im.setSize(4, 4);\n * board.update();\n *\n * </pre><div id=\"JXG8411e60c-f009-11e5-b1bf-901b0e1b8723\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG8411e60c-f009-11e5-b1bf-901b0e1b8723',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var im = board.create('image', ['https://jsxgraph.org/distrib/images/uccellino.jpg', [-3,-2], [3,3]]);\n * //im.setSize(4, 4);\n * //board.update();\n *\n * })();\n *\n * </script><pre>\n *\n * @example\n * var p0 = board.create('point', [-3, -2]),\n * im = board.create('image', ['https://jsxgraph.org/distrib/images/uccellino.jpg',\n * [function(){ return p0.X(); }, function(){ return p0.Y(); }],\n * [3,3]]),\n * p1 = board.create('point', [1, 2]);\n *\n * im.setSize(function(){ return p1.X() - p0.X(); }, function(){ return p1.Y() - p0.Y(); });\n * board.update();\n *\n * </pre><div id=\"JXG4ce706c0-f00a-11e5-b1bf-901b0e1b8723\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG4ce706c0-f00a-11e5-b1bf-901b0e1b8723',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var p0 = board.create('point', [-3, -2]),\n * im = board.create('image', ['https://jsxgraph.org/distrib/images/uccellino.jpg',\n * [function(){ return p0.X(); }, function(){ return p0.Y(); }],\n * [3,3]]),\n * p1 = board.create('point', [1, 2]);\n *\n * im.setSize(function(){ return p1.X() - p0.X(); }, function(){ return p1.Y() - p0.Y(); });\n * board.update();\n *\n * })();\n *\n * </script><pre>\n *\n */\n setSize: function(width, height) {\n this.W = Type.createFunction(width, this.board, '');\n this.H = Type.createFunction(height, this.board, '');\n\n // this.fullUpdate();\n\n return this;\n },\n\n /**\n * Returns the width of the image in user coordinates.\n * @returns {number} width of the image in user coordinates\n */\n W: function() {}, // Needed for docs, defined in constructor\n\n /**\n * Returns the height of the image in user coordinates.\n * @returns {number} height of the image in user coordinates\n */\n H: function() {} // Needed for docs, defined in constructor\n\n });\n\n /**\n * @class Displays an image.\n * @pseudo\n * @description\n * @name Image\n * @type JXG.Image\n * @augments JXG.Image\n * @constructor\n * @constructor\n * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {string,function_Array_Array} url,coords,size url defines the location of the image data. The array coords contains the user coordinates\n * of the lower left corner of the image.\n * It can consist of two or three elements of type number, a string containing a GEONE<sub>x</sub>T\n * constraint, or a function which takes no parameter and returns a number. Every element determines one coordinate. If a coordinate is\n * given by a number, the number determines the initial position of a free image. If given by a string or a function that coordinate will be constrained\n * that means the user won't be able to change the image's position directly by mouse because it will be calculated automatically depending on the string\n * or the function's return value. If two parent elements are given the coordinates will be interpreted as 2D affine Euclidean coordinates, if three such\n * parent elements are given they will be interpreted as homogeneous coordinates.\n * <p>\n * The array size defines the image's width and height in user coordinates.\n * @example\n * var im = board.create('image', ['https://jsxgraph.org/jsxgraph/distrib/images/uccellino.jpg', [-3,-2], [3,3]]);\n *\n * </pre><div class=\"jxgbox\" id=\"JXG9850cda0-7ea0-4750-981c-68bacf9cca57\" style=\"width: 400px; height: 400px;\"></div>\n * <script type=\"text/javascript\">\n * var image_board = JXG.JSXGraph.initBoard('JXG9850cda0-7ea0-4750-981c-68bacf9cca57', {boundingbox: [-4, 4, 4, -4], axis: true, showcopyright: false, shownavigation: false});\n * var image_im = image_board.create('image', ['https://jsxgraph.org/distrib/images/uccellino.jpg', [-3,-2],[3,3]]);\n * </script><pre>\n */\n JXG.createImage = function (board, parents, attributes) {\n var attr, im,\n url = parents[0],\n coords = parents[1],\n size = parents[2];\n\n attr = Type.copyAttributes(attributes, board.options, 'image');\n im = CoordsElement.create(JXG.Image, board, coords, attr, url, size);\n if (!im) {\n throw new Error(\"JSXGraph: Can't create image with parent types '\" +\n (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"'.\" +\n \"\\nPossible parent types: [x,y], [z,x,y], [element,transformation]\");\n }\n\n if (attr.rotate !== 0) { // This is the default value, i.e. no rotation\n im.addRotation(attr.rotate);\n }\n\n return im;\n };\n\n JXG.registerElement('image', JXG.createImage);\n\n return {\n Image: JXG.Image,\n createImage: JXG.createImage\n };\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true*/\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n jxg\n math/math\n base/constants\n base/point\n utils/type\n elements:\n point\n group\n segment\n ticks\n glider\n text\n */\n\n/**\n * @fileoverview The geometry object slider is defined in this file. Slider stores all\n * style and functional properties that are required to draw and use a slider on\n * a board.\n */\n\ndefine('element/slider',[\n 'jxg', 'math/math', 'base/constants', 'base/coords', 'utils/type', 'base/point'\n], function (JXG, Mat, Const, Coords, Type, Point) {\n\n \"use strict\";\n\n /**\n * @class A slider can be used to choose values from a given range of numbers.\n * @pseudo\n * @description\n * @name Slider\n * @augments Glider\n * @constructor\n * @type JXG.Point\n * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {Array_Array_Array} start,end,data The first two arrays give the start and the end where the slider is drawn\n * on the board. The third array gives the start and the end of the range the slider operates as the first resp. the\n * third component of the array. The second component of the third array gives its start value.\n * @example\n * // Create a slider with values between 1 and 10, initial position is 5.\n * var s = board.create('slider', [[1, 2], [3, 2], [1, 5, 10]]);\n * </pre><div class=\"jxgbox\" id=\"JXGcfb51cde-2603-4f18-9cc4-1afb452b374d\" style=\"width: 200px; height: 200px;\"></div>\n * <script type=\"text/javascript\">\n * (function () {\n * var board = JXG.JSXGraph.initBoard('JXGcfb51cde-2603-4f18-9cc4-1afb452b374d', {boundingbox: [-1, 5, 5, -1], axis: true, showcopyright: false, shownavigation: false});\n * var s = board.create('slider', [[1, 2], [3, 2], [1, 5, 10]]);\n * })();\n * </script><pre>\n * @example\n * // Create a slider taking integer values between 1 and 50. Initial value is 50.\n * var s = board.create('slider', [[1, 3], [3, 1], [0, 10, 50]], {snapWidth: 1, ticks: { drawLabels: true }});\n * </pre><div class=\"jxgbox\" id=\"JXGe17128e6-a25d-462a-9074-49460b0d66f4\" style=\"width: 200px; height: 200px;\"></div>\n * <script type=\"text/javascript\">\n * (function () {\n * var board = JXG.JSXGraph.initBoard('JXGe17128e6-a25d-462a-9074-49460b0d66f4', {boundingbox: [-1, 5, 5, -1], axis: true, showcopyright: false, shownavigation: false});\n * var s = board.create('slider', [[1, 3], [3, 1], [1, 10, 50]], {snapWidth: 1, ticks: { drawLabels: true }});\n * })();\n * </script><pre>\n * @example\n * // Draggable slider\n * var s1 = board.create('slider', [[-3,1], [2,1],[-10,1,10]], {\n * visible: true,\n * snapWidth: 2,\n * point1: {fixed: false},\n * point2: {fixed: false},\n * baseline: {fixed: false, needsRegularUpdate: true}\n * });\n *\n * </pre><div id=\"JXGbfc67817-2827-44a1-bc22-40bf312e76f8\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXGbfc67817-2827-44a1-bc22-40bf312e76f8',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var s1 = board.create('slider', [[-3,1], [2,1],[-10,1,10]], {\n * visible: true,\n * snapWidth: 2,\n * point1: {fixed: false},\n * point2: {fixed: false},\n * baseline: {fixed: false, needsRegularUpdate: true}\n * });\n *\n * })();\n *\n * </script><pre>\n *\n * @example\n * // Set the slider by clicking on the base line: attribute 'moveOnUp'\n * var s1 = board.create('slider', [[-3,1], [2,1],[-10,1,10]], {\n * snapWidth: 2,\n * moveOnUp: true // default value\n * });\n *\n * </pre><div id=\"JXGc0477c8a-b1a7-4111-992e-4ceb366fbccc\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXGc0477c8a-b1a7-4111-992e-4ceb366fbccc',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var s1 = board.create('slider', [[-3,1], [2,1],[-10,1,10]], {\n * snapWidth: 2,\n * moveOnUp: true // default value\n * });\n *\n * })();\n *\n * </script><pre>\n *\n * @example\n * // Set colors\n * var sl = board.create('slider', [[-3, 1], [1, 1], [-10, 1, 10]], {\n *\n * baseline: { strokeColor: 'blue'},\n * highline: { strokeColor: 'red'},\n * fillColor: 'yellow',\n * label: {fontSize: 24, strokeColor: 'orange'},\n * name: 'xyz', // Not shown, if suffixLabel is set\n * suffixLabel: 'x = ',\n * postLabel: ' u'\n *\n * });\n *\n * </pre><div id=\"JXGd96c9e2c-2c25-4131-b6cf-9dbb80819401\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXGd96c9e2c-2c25-4131-b6cf-9dbb80819401',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var sl = board.create('slider', [[-3, 1], [1, 1], [-10, 1, 10]], {\n *\n * baseline: { strokeColor: 'blue'},\n * highline: { strokeColor: 'red'},\n * fillColor: 'yellow',\n * label: {fontSize: 24, strokeColor: 'orange'},\n * name: 'xyz', // Not shown, if suffixLabel is set\n * suffixLabel: 'x = ',\n * postLabel: ' u'\n *\n * });\n *\n * })();\n *\n * </script><pre>\n *\n */\n JXG.createSlider = function (board, parents, attributes) {\n var pos0, pos1, smin, start, smax, sdiff,\n p1, p2, l1, ticks, ti, startx, starty, p3, l2, t,\n withText, withTicks, snapWidth, sw, s, attr, digits;\n\n attr = Type.copyAttributes(attributes, board.options, 'slider');\n withTicks = attr.withticks;\n withText = attr.withlabel;\n snapWidth = attr.snapwidth;\n\n // start point\n attr = Type.copyAttributes(attributes, board.options, 'slider', 'point1');\n p1 = board.create('point', parents[0], attr);\n\n // end point\n attr = Type.copyAttributes(attributes, board.options, 'slider', 'point2');\n p2 = board.create('point', parents[1], attr);\n //g = board.create('group', [p1, p2]);\n\n // Base line\n attr = Type.copyAttributes(attributes, board.options, 'slider', 'baseline');\n l1 = board.create('segment', [p1, p2], attr);\n\n // This is required for a correct projection of the glider onto the segment below\n l1.updateStdform();\n\n pos0 = p1.coords.usrCoords.slice(1);\n pos1 = p2.coords.usrCoords.slice(1);\n smin = parents[2][0];\n start = parents[2][1];\n smax = parents[2][2];\n sdiff = smax - smin;\n\n sw = Type.evaluate(snapWidth);\n s = (sw === -1) ? start : Math.round(start / sw) * sw;\n startx = pos0[0] + (pos1[0] - pos0[0]) * (s - smin) / (smax - smin);\n starty = pos0[1] + (pos1[1] - pos0[1]) * (s - smin) / (smax - smin);\n\n // glider point\n attr = Type.copyAttributes(attributes, board.options, 'slider');\n // overwrite this in any case; the sliders label is a special text element, not the gliders label.\n // this will be set back to true after the text was created (and only if withlabel was true initially).\n attr.withLabel = false;\n // gliders set snapwidth=-1 by default (i.e. deactivate them)\n p3 = board.create('glider', [startx, starty, l1], attr);\n p3.setAttribute({snapwidth: snapWidth});\n\n // Segment from start point to glider point: highline\n attr = Type.copyAttributes(attributes, board.options, 'slider', 'highline');\n l2 = board.create('segment', [p1, p3], attr);\n\n /**\n * Returns the current slider value.\n * @memberOf Slider.prototype\n * @name Value\n * @function\n * @returns {Number}\n */\n p3.Value = function () {\n var sdiff = this._smax - this._smin,\n ev_sw = Type.evaluate(this.visProp.snapwidth);\n\n return ev_sw === -1 ?\n this.position * sdiff + this._smin :\n Math.round((this.position * sdiff + this._smin) / ev_sw) * ev_sw;\n };\n\n p3.methodMap = Type.deepCopy(p3.methodMap, {\n Value: 'Value',\n setValue: 'setValue',\n smax: '_smax',\n smin: '_smin',\n setMax: 'setMax',\n setMin: 'setMin'\n });\n\n /**\n * End value of the slider range.\n * @memberOf Slider.prototype\n * @name _smax\n * @type Number\n */\n p3._smax = smax;\n\n /**\n * Start value of the slider range.\n * @memberOf Slider.prototype\n * @name _smin\n * @type Number\n */\n p3._smin = smin;\n\n /**\n * Sets the maximum value of the slider.\n * @memberOf Slider.prototype\n * @name setMax\n * @param {Number} val New maximum value\n * @returns {Object} this object\n */\n p3.setMax = function(val) {\n this._smax = val;\n return this;\n };\n\n /**\n * Sets the value of the slider. This call must be followed\n * by a board update call.\n * @memberOf Slider.prototype\n * @name setValue\n * @param {Number} val New value\n * @returns {Object} this object\n */\n p3.setValue = function(val) {\n var sdiff = this._smax - this._smin;\n\n if (Math.abs(sdiff) > Mat.eps) {\n this.position = (val - this._smin) / sdiff;\n } else {\n this.position = 0.0; //this._smin;\n }\n this.position = Math.max(0.0, Math.min(1.0, this.position));\n return this;\n };\n\n /**\n * Sets the minimum value of the slider.\n * @memberOf Slider.prototype\n * @name setMin\n * @param {Number} val New minimum value\n * @returns {Object} this object\n */\n p3.setMin = function(val) {\n this._smin = val;\n return this;\n };\n\n if (withText) {\n attr = Type.copyAttributes(attributes, board.options, 'slider', 'label');\n t = board.create('text', [\n function () {\n return (p2.X() - p1.X()) * 0.05 + p2.X();\n },\n function () {\n return (p2.Y() - p1.Y()) * 0.05 + p2.Y();\n },\n function () {\n var n,\n d = Type.evaluate(p3.visProp.digits),\n sl = Type.evaluate(p3.visProp.suffixlabel),\n ul = Type.evaluate(p3.visProp.unitlabel),\n pl = Type.evaluate(p3.visProp.postlabel);\n\n if (d === 2 && Type.evaluate(p3.visProp.precision) !== 2) {\n // Backwards compatibility\n d = Type.evaluate(p3.visProp.precision);\n }\n\n if (sl !== null) {\n n = sl;\n } else if (p3.name && p3.name !== '') {\n n = p3.name + ' = ';\n } else {\n n = '';\n }\n\n n += Type.toFixed(p3.Value(), d);\n\n if (ul !== null) {\n n += ul;\n }\n if (pl !== null) {\n n += pl;\n }\n\n return n;\n }\n ], attr);\n\n /**\n * The text element to the right of the slider, indicating its current value.\n * @memberOf Slider.prototype\n * @name label\n * @type JXG.Text\n */\n p3.label = t;\n\n // reset the withlabel attribute\n p3.visProp.withlabel = true;\n p3.hasLabel = true;\n }\n\n /**\n * Start point of the base line.\n * @memberOf Slider.prototype\n * @name point1\n * @type JXG.Point\n */\n p3.point1 = p1;\n\n /**\n * End point of the base line.\n * @memberOf Slider.prototype\n * @name point2\n * @type JXG.Point\n */\n p3.point2 = p2;\n\n /**\n * The baseline the glider is bound to.\n * @memberOf Slider.prototype\n * @name baseline\n * @type JXG.Line\n */\n p3.baseline = l1;\n\n /**\n * A line on top of the baseline, indicating the slider's progress.\n * @memberOf Slider.prototype\n * @name highline\n * @type JXG.Line\n */\n p3.highline = l2;\n\n if (withTicks) {\n // Function to generate correct label texts\n\n attr = Type.copyAttributes(attributes, board.options, 'slider', 'ticks');\n if (!Type.exists(attr.generatelabeltext)) {\n attr.generateLabelText = function(tick, zero, value) {\n var labelText,\n dFull = p3.point1.Dist(p3.point2),\n smin = p3._smin, smax = p3._smax,\n val = this.getDistanceFromZero(zero, tick) * (smax - smin) / dFull + smin;\n\n if (dFull < Mat.eps || Math.abs(val) < Mat.eps) { // Point is zero\n labelText = '0';\n } else {\n labelText = this.formatLabelText(val);\n }\n return labelText;\n };\n }\n ticks = 2;\n ti = board.create('ticks', [\n p3.baseline,\n p3.point1.Dist(p1) / ticks,\n\n function (tick) {\n var dFull = p3.point1.Dist(p3.point2),\n d = p3.point1.coords.distance(Const.COORDS_BY_USER, tick);\n\n if (dFull < Mat.eps) {\n return 0;\n }\n\n return d / dFull * sdiff + smin;\n }\n ], attr);\n\n /**\n * Ticks give a rough indication about the slider's current value.\n * @memberOf Slider.prototype\n * @name ticks\n * @type JXG.Ticks\n */\n p3.ticks = ti;\n }\n\n // override the point's remove method to ensure the removal of all elements\n p3.remove = function () {\n if (withText) {\n board.removeObject(t);\n }\n\n board.removeObject(l2);\n board.removeObject(l1);\n board.removeObject(p2);\n board.removeObject(p1);\n\n\n Point.Point.prototype.remove.call(p3);\n };\n\n p1.dump = false;\n p2.dump = false;\n l1.dump = false;\n l2.dump = false;\n if (withText) {\n t.dump = false;\n }\n\n\n p3.elType = 'slider';\n p3.parents = parents;\n p3.subs = {\n point1: p1,\n point2: p2,\n baseLine: l1,\n highLine: l2\n };\n p3.inherits.push(p1, p2, l1, l2);\n\n if (withTicks) {\n ti.dump = false;\n p3.subs.ticks = ti;\n p3.inherits.push(ti);\n }\n\n p3.getParents = function() {\n return [\n this.point1.coords.usrCoords.slice(1),\n this.point2.coords.usrCoords.slice(1),\n [this._smin, this.position * (this._smax - this._smin) + this._smin, this._smax]\n ];\n };\n\n p3.baseline.on('up', function(evt) {\n var pos, c;\n\n if (Type.evaluate(p3.visProp.moveonup) && !Type.evaluate(p3.visProp.fixed) ) {\n pos = l1.board.getMousePosition(evt, 0);\n c = new Coords(Const.COORDS_BY_SCREEN, pos, this.board);\n p3.moveTo([c.usrCoords[1], c.usrCoords[2]]);\n }\n });\n\n // Save the visibility attribute of the sub-elements\n // for (el in p3.subs) {\n // p3.subs[el].status = {\n // visible: p3.subs[el].visProp.visible\n // };\n // }\n\n // p3.hideElement = function () {\n // var el;\n // GeometryElement.prototype.hideElement.call(this);\n //\n // for (el in this.subs) {\n // // this.subs[el].status.visible = this.subs[el].visProp.visible;\n // this.subs[el].hideElement();\n // }\n // };\n\n// p3.showElement = function () {\n// var el;\n// GeometryElement.prototype.showElement.call(this);\n//\n// for (el in this.subs) {\n// // if (this.subs[el].status.visible) {\n// this.subs[el].showElement();\n// // }\n// }\n// };\n\n\n\n // This is necessary to show baseline, highline and ticks\n // when opening the board in case the visible attributes are set\n // to 'inherit'.\n p3.prepareUpdate().update();\n if (!board.isSuspendedUpdate) {\n p3.updateVisibility().updateRenderer();\n p3.baseline.updateVisibility().updateRenderer();\n p3.highline.updateVisibility().updateRenderer();\n if (withTicks) {\n p3.ticks.updateVisibility().updateRenderer();\n }\n }\n\n return p3;\n };\n\n JXG.registerElement('slider', JXG.createSlider);\n\n return {\n createSlider: JXG.createSlider\n };\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true*/\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n jxg\n utils/type\n base/element\n elements:\n point\n segment\n ticks\n */\n\n/**\n * @fileoverview Geometry objects for measurements are defined in this file. This file stores all\n * style and functional properties that are required to use a tape measure on\n * a board.\n */\n\ndefine('element/measure',[\n 'jxg', 'utils/type', 'base/element'\n], function (JXG, Type, GeometryElement) {\n\n \"use strict\";\n\n /**\n * @class A tape measure can be used to measure distances between points.\n * @pseudo\n * @description\n * @name Tapemeasure\n * @augments Segment\n * @constructor\n * @type JXG.Segment\n * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {Array_Array} start,end, The two arrays give the initial position where the tape measure\n * is drawn on the board.\n * @example\n * // Create a tape measure\n * var p1 = board.create('point', [0,0]);\n * var p2 = board.create('point', [1,1]);\n * var p3 = board.create('point', [3,1]);\n * var tape = board.create('tapemeasure', [[1, 2], [4, 2]], {name:'dist'});\n * </pre><div class=\"jxgbox\" id=\"JXG6d9a2cda-22fe-4cd1-9d94-34283b1bdc01\" style=\"width: 200px; height: 200px;\"></div>\n * <script type=\"text/javascript\">\n * (function () {\n * var board = JXG.JSXGraph.initBoard('JXG6d9a2cda-22fe-4cd1-9d94-34283b1bdc01', {boundingbox: [-1, 5, 5, -1], axis: true, showcopyright: false, shownavigation: false});\n * var p1 = board.create('point', [0,0]);\n * var p2 = board.create('point', [1,1]);\n * var p3 = board.create('point', [3,1]);\n * var tape = board.create('tapemeasure', [[1, 2], [4, 2]], {name:'dist'} );\n * })();\n * </script><pre>\n */\n JXG.createTapemeasure = function (board, parents, attributes) {\n var pos0, pos1,\n attr, withTicks, withText, digits,\n li, p1, p2, n, ti;\n\n pos0 = parents[0];\n pos1 = parents[1];\n\n // start point\n attr = Type.copyAttributes(attributes, board.options, 'tapemeasure', 'point1');\n p1 = board.create('point', pos0, attr);\n\n // end point\n attr = Type.copyAttributes(attributes, board.options, 'tapemeasure', 'point2');\n p2 = board.create('point', pos1, attr);\n\n p1.setAttribute({ignoredSnapToPoints: [p2]});\n p2.setAttribute({ignoredSnapToPoints: [p1]});\n\n // tape measure line\n attr = Type.copyAttributes(attributes, board.options, 'tapemeasure');\n withTicks = attr.withticks;\n withText = attr.withlabel;\n digits = attr.digits;\n\n if (digits === 2 && attr.precision !== 2) {\n // Backward compatibility\n digits = attr.precision;\n }\n\n // Below, we will replace the label by the measurement function.\n if (withText) {\n attr.withlabel = true;\n }\n li = board.create('segment', [p1, p2], attr);\n // p1, p2 are already added to li.inherits\n\n if (withText) {\n if (attributes.name && attributes.name !== '') {\n n = attributes.name + ' = ';\n } else {\n n = '';\n }\n li.label.setText(function () {\n return n + Type.toFixed(p1.Dist(p2), digits);\n });\n }\n\n if (withTicks) {\n attr = Type.copyAttributes(attributes, board.options, 'tapemeasure', 'ticks');\n //ticks = 2;\n ti = board.create('ticks', [li, 0.1], attr);\n li.inherits.push(ti);\n }\n\n // override the segments's remove method to ensure the removal of all elements\n /** @ignore */\n li.remove = function () {\n if (withTicks) {\n li.removeTicks(ti);\n }\n\n board.removeObject(p2);\n board.removeObject(p1);\n\n GeometryElement.prototype.remove.call(this);\n };\n\n /**\n * Returns the length of the tape measure.\n * @name Value\n * @memberOf Tapemeasure.prototype\n * @function\n * @returns {Number} length of tape measure.\n */\n li.Value = function () {\n return p1.Dist(p2);\n };\n\n p1.dump = false;\n p2.dump = false;\n\n li.elType = 'tapemeasure';\n li.getParents = function() {\n return [[p1.X(), p1.Y()], [p2.X(), p2.Y()]];\n };\n\n li.subs = {\n point1: p1,\n point2: p2\n };\n\n if (withTicks) {\n ti.dump = false;\n }\n\n li.methodMap = JXG.deepCopy(li.methodMap, {\n Value: 'Value'\n });\n\n li.prepareUpdate().update();\n if (!board.isSuspendedUpdate) {\n li.updateVisibility().updateRenderer();\n // The point updates are necessary in case of snapToGrid==true\n li.point1.updateVisibility().updateRenderer();\n li.point2.updateVisibility().updateRenderer();\n }\n\n return li;\n };\n\n JXG.registerElement('tapemeasure', JXG.createTapemeasure);\n\n return {\n createTapemeasure: JXG.createTapemeasure\n };\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true, document: true*/\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n jxg\n utils/type\n */\n\n/**\n * @fileoverview The JXG.DataSource is a helper class for data organization. Currently supported data sources are\n * javascript arrays and HTML tables.\n */\n\ndefine('parser/datasource',['jxg', 'utils/type'], function (JXG, Type) {\n\n \"use strict\";\n\n JXG.DataSource = function () {\n this.data = [];\n this.columnHeaders = [];\n this.rowHeaders = [];\n\n return this;\n };\n\n JXG.extend(JXG.DataSource.prototype, /** @lends JXG.DataSource.prototype */ {\n loadFromArray: function (table, columnHeader, rowHeader) {\n var i, j, cell;\n\n if (Type.isArray(columnHeader)) {\n this.columnHeaders = columnHeader;\n columnHeader = false;\n }\n\n if (Type.isArray(rowHeader)) {\n this.rowHeaders = rowHeader;\n rowHeader = false;\n }\n\n this.data = [];\n\n if (columnHeader) {\n this.columnHeaders = [];\n }\n\n if (rowHeader) {\n this.rowHeaders = [];\n }\n\n if (Type.exists(table)) {\n // extract the data\n this.data = [];\n\n for (i = 0; i < table.length; i++) {\n this.data[i] = [];\n\n for (j = 0; j < table[i].length; j++) {\n cell = table[i][j];\n if (parseFloat(cell).toString() === cell) {\n this.data[i][j] = parseFloat(cell);\n } else if (cell !== '-') {\n this.data[i][j] = cell;\n } else {\n this.data[i][j] = NaN;\n }\n }\n }\n\n if (columnHeader) {\n this.columnHeaders = this.data[0].slice(1);\n this.data = this.data.slice(1);\n }\n\n if (rowHeader) {\n this.rowHeaders = [];\n for (i = 0; i < this.data.length; i++) {\n this.rowHeaders.push(this.data[i][0]);\n this.data[i] = this.data[i].slice(1);\n }\n }\n }\n\n return this;\n },\n\n loadFromTable: function (table, columnHeader, rowHeader) {\n var row, i, j, col, cell, name;\n\n if (Type.isArray(columnHeader)) {\n this.columnHeaders = columnHeader;\n columnHeader = false;\n }\n\n if (Type.isArray(rowHeader)) {\n this.rowHeaders = rowHeader;\n rowHeader = false;\n }\n\n this.data = [];\n\n if (columnHeader) {\n this.columnHeaders = [];\n }\n\n if (rowHeader) {\n this.rowHeaders = [];\n }\n\n // to adjust: examples in examples folder & wiki\n table = document.getElementById(table);\n\n if (Type.exists(table)) {\n // extract the data\n row = table.getElementsByTagName('tr');\n this.data = [];\n\n for (i = 0; i < row.length; i++) {\n col = row[i].getElementsByTagName('td');\n this.data[i] = [];\n\n for (j = 0; j < col.length; j++) {\n cell = col[j].innerHTML;\n\n if (parseFloat(cell).toString() === cell) {\n this.data[i][j] = parseFloat(cell);\n } else if (cell !== '-') {\n this.data[i][j] = cell;\n } else {\n this.data[i][j] = NaN;\n }\n }\n }\n\n if (columnHeader) {\n this.columnHeaders = this.data[0].slice(1);\n this.data = this.data.slice(1);\n }\n\n if (rowHeader) {\n this.rowHeaders = [];\n for (i = 0; i < this.data.length; i++) {\n this.rowHeaders.push(this.data[i][0]);\n this.data[i] = this.data[i].slice(1);\n }\n }\n }\n\n return this;\n },\n\n addColumn: function (name, pos, data) {\n throw new Error('not implemented');\n },\n\n addRow: function (name, pos, data) {\n throw new Error('not implemented');\n },\n\n getColumn: function (col) {\n var i,\n result = [];\n\n // get column index if column is given as column header title\n if (Type.isString(col)) {\n for (i = 0; i < this.columnHeaders.length; i++) {\n if (col === this.columnHeaders[i]) {\n col = i;\n break;\n }\n }\n }\n\n // build column array\n for (i = 0; i < this.data.length; i++) {\n if (this.data[i].length > col) {\n result[i] = parseFloat(this.data[i][col]);\n }\n }\n\n return result;\n },\n\n getRow: function (row) {\n var result, i;\n\n // get column index if column is given as column header title\n if (Type.isString(row)) {\n for (i = 0; i < this.rowHeaders.length; i++) {\n if (row === this.rowHeaders[i]) {\n row = i;\n break;\n }\n }\n }\n\n // allocate memory for result array\n result = [];\n\n // build column array. result = this.data[row] is a flat copy and will\n // destroy our local data copy, that's why we're copying it element wise.\n for (i = 0; i < this.data[row].length; i++) {\n result[i] = this.data[row][i];\n }\n\n return result;\n }\n });\n\n return JXG.DataSource;\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true, document: true*/\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n jxg\n math/numerics\n math/statistics\n base/constants\n base/coords\n base/element\n parser/datasource\n utils/color\n utils/type\n utils/env\n elements:\n curve\n spline\n functiongraph\n point\n text\n polygon\n sector\n transform\n line\n legend\n circle\n */\n\ndefine('base/chart',[\n 'jxg', 'math/numerics', 'math/statistics', 'base/constants', 'base/coords', 'base/element', 'parser/datasource',\n 'utils/color', 'utils/type', 'utils/env', 'base/curve', 'base/point', 'base/text', 'base/polygon', 'element/sector',\n 'base/transformation', 'base/line', 'base/circle'\n], function (JXG, Numerics, Statistics, Const, Coords, GeometryElement, DataSource, Color, Type, Env, Curve, Point, Text,\n Polygon, Sector, Transform, Line, Circle) {\n\n \"use strict\";\n\n /**\n *\n * The Chart class is a basic class for the chart object.\n * @class Creates a new basic chart object. Do not use this constructor to create a chart.\n * Use {@link JXG.Board#create} with type {@link Chart} instead.\n * @constructor\n * @augments JXG.GeometryElement\n * @param {String,JXG.Board} board The board the new chart is drawn on.\n * @param {Array} parent data arrays for the chart\n * @param {Object} attributes Javascript object containing attributes like name, id and colors.\n *\n */\n JXG.Chart = function (board, parents, attributes) {\n this.constructor(board, attributes);\n\n var x, y, i, c, style, len;\n\n if (!Type.isArray(parents) || parents.length === 0) {\n throw new Error('JSXGraph: Can\\'t create a chart without data');\n }\n\n /**\n * Contains pointers to the various subelements of the chart.\n */\n this.elements = [];\n\n if (Type.isNumber(parents[0])) {\n // parents looks like [a,b,c,..]\n // x has to be filled\n\n y = parents;\n x = [];\n for (i = 0; i < y.length; i++) {\n x[i] = i + 1;\n }\n } else if (parents.length === 1 && Type.isArray(parents[0])) {\n // parents looks like [[a,b,c,..]]\n // x has to be filled\n\n y = parents[0];\n x = [];\n\n len = Type.evaluate(y).length;\n for (i = 0; i < len; i++) {\n x[i] = i + 1;\n }\n } else if (parents.length === 2) {\n // parents looks like [[x0,x1,x2,...],[y1,y2,y3,...]]\n len = Math.min(parents[0].length, parents[1].length);\n x = parents[0].slice(0, len);\n y = parents[1].slice(0, len);\n }\n\n if (Type.isArray(y) && y.length === 0) {\n throw new Error('JSXGraph: Can\\'t create charts without data.');\n }\n\n // does this really need to be done here? this should be done in createChart and then\n // there should be an extra chart for each chartstyle\n style = attributes.chartstyle.replace(/ /g, '').split(',');\n for (i = 0; i < style.length; i++) {\n switch (style[i]) {\n case 'bar':\n c = this.drawBar(board, x, y, attributes);\n break;\n case 'line':\n c = this.drawLine(board, x, y, attributes);\n break;\n case 'fit':\n c = this.drawFit(board, x, y, attributes);\n break;\n case 'spline':\n c = this.drawSpline(board, x, y, attributes);\n break;\n case 'pie':\n c = this.drawPie(board, y, attributes);\n break;\n case 'point':\n c = this.drawPoints(board, x, y, attributes);\n break;\n case 'radar':\n c = this.drawRadar(board, parents, attributes);\n break;\n }\n this.elements.push(c);\n }\n this.id = this.board.setId(this, 'Chart');\n\n return this.elements;\n };\n\n JXG.Chart.prototype = new GeometryElement();\n\n JXG.extend(JXG.Chart.prototype, /** @lends JXG.Chart.prototype */ {\n /**\n * Create line chart defined by two data arrays.\n *\n * @param {String,JXG.Board} board The board the chart is drawn on\n * @param {Array} x Array of x-coordinates\n * @param {Array} y Array of y-coordinates\n * @param {Object} attributes Javascript object containing attributes like colors\n * @returns {JXG.Curve} JSXGraph curve\n */\n drawLine: function (board, x, y, attributes) {\n // we don't want the line chart to be filled\n attributes.fillcolor = 'none';\n attributes.highlightfillcolor = 'none';\n\n return board.create('curve', [x, y], attributes);\n },\n\n /**\n * Create line chart that consists of a natural spline curve\n * defined by two data arrays.\n *\n * @param {String,JXG.Board} board The board the chart is drawn on\n * @param {Array} x Array of x-coordinates\n * @param {Array} y Array of y-coordinates\n * @param {Object} attributes Javascript object containing attributes like colors\n * @returns {JXG.Curve} JSXGraph (natural) spline curve\n */\n drawSpline: function (board, x, y, attributes) {\n // we don't want the spline chart to be filled\n attributes.fillColor = 'none';\n attributes.highlightfillcolor = 'none';\n\n return board.create('spline', [x, y], attributes);\n },\n\n /**\n * Create line chart where the curve is given by a regression polynomial\n * defined by two data arrays. The degree of the polynomial is supplied\n * through the attribute \"degree\" in attributes.\n *\n * @param {String,JXG.Board} board The board the chart is drawn on\n * @param {Array} x Array of x-coordinates\n * @param {Array} y Array of y-coordinates\n * @param {Object} attributes Javascript object containing attributes like colors\n * @returns {JXG.Curve} JSXGraph function graph object\n */\n drawFit: function (board, x, y, attributes) {\n var deg = attributes.degree;\n\n deg = Math.max(parseInt(deg, 10), 1) || 1;\n\n // never fill\n attributes.fillcolor = 'none';\n attributes.highlightfillcolor = 'none';\n\n return board.create('functiongraph', [Numerics.regressionPolynomial(deg, x, y)], attributes);\n },\n\n /**\n * Create bar chart defined by two data arrays.\n * Attributes to change the layout of the bar chart are:\n * <ul>\n * <li> width (optional)\n * <li> dir: 'horizontal' or 'vertical'\n * <li> colors: array of colors\n * <li> labels: array of labels\n * </ul>\n *\n * @param {String,JXG.Board} board The board the chart is drawn on\n * @param {Array} x Array of x-coordinates\n * @param {Array} y Array of y-coordinates\n * @param {Object} attributes Javascript object containing attributes like colors\n * @returns {Array} Array of JXG polygons defining the bars\n */\n drawBar: function (board, x, y, attributes) {\n var i, strwidth, text, w, xp0, xp1, xp2, yp, colors,\n pols = [],\n p = [],\n attr, attrSub,\n makeXpFun = function (i, f) {\n return function () {\n return x[i]() - f * w;\n };\n },\n hiddenPoint = {\n fixed: true,\n withLabel: false,\n visible: false,\n name: ''\n };\n\n attr = Type.copyAttributes(attributes, board.options, 'chart');\n\n // Determine the width of the bars\n if (attr && attr.width) { // width given\n w = attr.width;\n } else {\n if (x.length <= 1) {\n w = 1;\n } else {\n // Find minimum distance between to bars.\n w = x[1] - x[0];\n for (i = 1; i < x.length - 1; i++) {\n w = (x[i + 1] - x[i] < w) ? x[i + 1] - x[i] : w;\n }\n }\n w *= 0.8;\n }\n\n attrSub = Type.copyAttributes(attributes, board.options, 'chart', 'label');\n\n for (i = 0; i < x.length; i++) {\n if (Type.isFunction(x[i])) {\n xp0 = makeXpFun(i, -0.5);\n xp1 = makeXpFun(i, 0);\n xp2 = makeXpFun(i, 0.5);\n } else {\n xp0 = x[i] - w * 0.5;\n xp1 = x[i];\n xp2 = x[i] + w * 0.5;\n }\n if (Type.isFunction(y[i])) {\n yp = y[i]();\n } else {\n yp = y[i];\n }\n yp = y[i];\n\n if (attr.dir === 'horizontal') { // horizontal bars\n p[0] = board.create('point', [0, xp0], hiddenPoint);\n p[1] = board.create('point', [yp, xp0], hiddenPoint);\n p[2] = board.create('point', [yp, xp2], hiddenPoint);\n p[3] = board.create('point', [0, xp2], hiddenPoint);\n\n if (Type.exists(attr.labels) && Type.exists(attr.labels[i])) {\n attrSub.anchorY = 'middle';\n text = board.create('text', [\n yp,\n xp1,\n attr.labels[i]], attrSub);\n text.visProp.anchorx = (function(txt) { return function() {\n return (txt.X() >= 0) ? 'left' : 'right';\n }; })(text);\n\n }\n } else { // vertical bars\n p[0] = board.create('point', [xp0, 0], hiddenPoint);\n p[1] = board.create('point', [xp0, yp], hiddenPoint);\n p[2] = board.create('point', [xp2, yp], hiddenPoint);\n p[3] = board.create('point', [xp2, 0], hiddenPoint);\n\n if (Type.exists(attr.labels) && Type.exists(attr.labels[i])) {\n attrSub.anchorX = 'middle';\n\n text = board.create('text', [\n xp1,\n yp,\n attr.labels[i]], attrSub);\n\n text.visProp.anchory = (function(txt) {\n return function() {\n return (txt.Y() >= 0) ? 'bottom' : 'top';\n };\n })(text);\n\n }\n }\n\n if (Type.isArray(attr.colors)) {\n colors = attr.colors;\n attr.fillcolor = colors[i % colors.length];\n }\n\n pols[i] = board.create('polygon', p, attr);\n if (Type.exists(attr.labels) && Type.exists(attr.labels[i])) {\n pols[i].text = text;\n }\n }\n\n return pols;\n },\n\n /**\n * Create chart consisting of JSXGraph points.\n * Attributes to change the layout of the point chart are:\n * <ul>\n * <li> fixed (Boolean)\n * <li> infoboxArray (Array): Texts for the infobox\n * </ul>\n *\n * @param {String,JXG.Board} board The board the chart is drawn on\n * @param {Array} x Array of x-coordinates\n * @param {Array} y Array of y-coordinates\n * @param {Object} attributes Javascript object containing attributes like colors\n * @returns {Array} Array of JSXGraph points\n */\n drawPoints: function (board, x, y, attributes) {\n var i,\n points = [],\n infoboxArray = attributes.infoboxarray;\n\n attributes.fixed = true;\n attributes.name = '';\n\n for (i = 0; i < x.length; i++) {\n attributes.infoboxtext = infoboxArray ? infoboxArray[i % infoboxArray.length] : false;\n points[i] = board.create('point', [x[i], y[i]], attributes);\n }\n\n return points;\n },\n\n /**\n * Create pie chart.\n * Attributes to change the layout of the pie chart are:\n * <ul>\n * <li> labels: array of labels\n * <li> colors: (Array)\n * <li> highlightColors (Array)\n * <li> radius\n * <li> center (coordinate array)\n * <li> highlightOnSector (Boolean)\n * </ul>\n *\n * @param {String,JXG.Board} board The board the chart is drawn on\n * @param {Array} y Array of x-coordinates\n * @param {Object} attributes Javascript object containing attributes like colors\n * @returns {Object} with keys: \"{sectors, points, midpoint}\"\n */\n drawPie: function (board, y, attributes) {\n var i, center,\n p = [],\n sector = [],\n s = Statistics.sum(y),\n colorArray = attributes.colors,\n highlightColorArray = attributes.highlightcolors,\n labelArray = attributes.labels,\n r = attributes.radius || 4,\n radius = r,\n cent = attributes.center || [0, 0],\n xc = cent[0],\n yc = cent[1],\n\n makeRadPointFun = function (j, fun, xc) {\n return function () {\n var s, i, rad,\n t = 0;\n\n for (i = 0; i <= j; i++) {\n t += parseFloat(Type.evaluate(y[i]));\n }\n\n s = t;\n for (i = j + 1; i < y.length; i++) {\n s += parseFloat(Type.evaluate(y[i]));\n }\n rad = (s !== 0) ? (2 * Math.PI * t / s) : 0;\n\n return radius() * Math[fun](rad) + xc;\n };\n },\n\n highlightHandleLabel = function (f, s) {\n var dx = -this.point1.coords.usrCoords[1] + this.point2.coords.usrCoords[1],\n dy = -this.point1.coords.usrCoords[2] + this.point2.coords.usrCoords[2];\n\n if (Type.exists(this.label)) {\n this.label.rendNode.style.fontSize = (s * Type.evaluate(this.label.visProp.fontsize)) + 'px';\n this.label.fullUpdate();\n }\n\n this.point2.coords = new Coords(Const.COORDS_BY_USER, [\n this.point1.coords.usrCoords[1] + dx * f,\n this.point1.coords.usrCoords[2] + dy * f\n ], this.board);\n this.fullUpdate();\n },\n\n highlightFun = function () {\n if (!this.highlighted) {\n this.highlighted = true;\n this.board.highlightedObjects[this.id] = this;\n this.board.renderer.highlight(this);\n\n highlightHandleLabel.call(this, 1.1, 2);\n }\n },\n\n noHighlightFun = function () {\n if (this.highlighted) {\n this.highlighted = false;\n this.board.renderer.noHighlight(this);\n\n highlightHandleLabel.call(this, 0.90909090, 1);\n }\n },\n\n hiddenPoint = {\n fixed: true,\n withLabel: false,\n visible: false,\n name: ''\n };\n\n if (!Type.isArray(labelArray)) {\n labelArray = [];\n for (i = 0; i < y.length; i++) {\n labelArray[i] = '';\n }\n }\n\n if (!Type.isFunction(r)) {\n radius = function () {\n return r;\n };\n }\n\n attributes.highlightonsector = attributes.highlightonsector || false;\n attributes.straightfirst = false;\n attributes.straightlast = false;\n\n center = board.create('point', [xc, yc], hiddenPoint);\n p[0] = board.create('point', [\n function () {\n return radius() + xc;\n },\n function () {\n return yc;\n }\n ], hiddenPoint);\n\n for (i = 0; i < y.length; i++) {\n p[i + 1] = board.create('point', [makeRadPointFun(i, 'cos', xc), makeRadPointFun(i, 'sin', yc)], hiddenPoint);\n\n attributes.name = labelArray[i];\n attributes.withlabel = attributes.name !== '';\n attributes.fillcolor = colorArray && colorArray[i % colorArray.length];\n attributes.labelcolor = colorArray && colorArray[i % colorArray.length];\n attributes.highlightfillcolor = highlightColorArray && highlightColorArray[i % highlightColorArray.length];\n\n sector[i] = board.create('sector', [center, p[i], p[i + 1]], attributes);\n\n if (attributes.highlightonsector) {\n // overwrite hasPoint so that the whole sector is used for highlighting\n sector[i].hasPoint = sector[i].hasPointSector;\n }\n if (attributes.highlightbysize) {\n sector[i].highlight = highlightFun;\n\n sector[i].noHighlight = noHighlightFun;\n }\n\n }\n\n // Not enough! We need points, but this gives an error in setAttribute.\n return {sectors: sector, points: p, midpoint: center};\n },\n\n /**\n * Create radar chart.\n * Attributes to change the layout of the pie chart are:\n * <ul>\n * <li> paramArray: labels for axes, [ paramx, paramy, paramz ]\n * <li> startShiftRatio: 0 <= offset from chart center <=1\n * <li> endShiftRatio: 0 <= offset from chart radius <=1\n * <li> startShiftArray: Adjust offsets per each axis\n * <li> endShiftArray: Adjust offsets per each axis\n * <li> startArray: Values for inner circle. Default values: minimums\n * <li> start: one value to overwrite all startArray values\n * <li> endArray: Values for outer circle, maximums by default\n * <li> end: one value to overwrite all endArray values\n * <li> labelArray\n * <li> polyStrokeWidth\n * <li> colors\n * <li> highlightcolors\n * <li> labelArray: [ row1, row2, row3 ]\n * <li> radius\n * <li> legendPosition\n * <li> showCircles\n * <li> circleLabelArray\n * <li> circleStrokeWidth\n * </ul>\n *\n * @param {String,JXG.Board} board The board the chart is drawn on\n * @param {Array} parents Array of coordinates, e.g. [[x1, y1, z1], [x2, y2, z2], [x3, y3, z3]]\n * @param {Object} attributes Javascript object containing attributes like colors\n * @returns {Object} with keys \"{circles, lines, points, midpoint, polygons}\"\n */\n drawRadar: function (board, parents, attributes) {\n var i, j, paramArray, numofparams, maxes, mins,\n la, pdata, ssa, esa, ssratio, esratio,\n sshifts, eshifts, starts, ends,\n labelArray, colorArray, highlightColorArray, radius, myAtts,\n cent, xc, yc, center, start_angle, rad, p, line, t,\n xcoord, ycoord, polygons, legend_position, circles, lxoff, lyoff,\n cla, clabelArray, ncircles, pcircles, angle, dr, sw, data,\n len = parents.length,\n\n get_anchor = function () {\n var x1, x2, y1, y2,\n relCoords = Type.evaluate(this.visProp.label.offset).slice(0);\n\n x1 = this.point1.X();\n x2 = this.point2.X();\n y1 = this.point1.Y();\n y2 = this.point2.Y();\n if (x2 < x1) {\n relCoords[0] = -relCoords[0];\n }\n\n if (y2 < y1) {\n relCoords[1] = -relCoords[1];\n }\n\n this.setLabelRelativeCoords(relCoords);\n\n return new Coords(Const.COORDS_BY_USER, [this.point2.X(), this.point2.Y()], this.board);\n },\n\n get_transform = function (angle, i) {\n var t, tscale, trot;\n\n t = board.create('transform', [-(starts[i] - sshifts[i]), 0], {type: 'translate'});\n tscale = board.create('transform', [radius / ((ends[i] + eshifts[i]) - (starts[i] - sshifts[i])), 1], {type: 'scale'});\n t.melt(tscale);\n trot = board.create('transform', [angle], {type: 'rotate'});\n t.melt(trot);\n\n return t;\n };\n\n if (len <= 0) {\n throw new Error('JSXGraph radar chart: no data');\n }\n // labels for axes\n paramArray = attributes.paramarray;\n if (!Type.exists(paramArray)) {\n throw new Error('JSXGraph radar chart: need paramArray attribute');\n }\n numofparams = paramArray.length;\n if (numofparams <= 1) {\n throw new Error('JSXGraph radar chart: need more than one param in paramArray');\n }\n\n for (i = 0; i < len; i++) {\n if (numofparams !== parents[i].length) {\n throw new Error('JSXGraph radar chart: use data length equal to number of params (' + parents[i].length + ' != ' + numofparams + ')');\n }\n }\n\n maxes = [];\n mins = [];\n\n for (j = 0; j < numofparams; j++) {\n maxes[j] = parents[0][j];\n mins[j] = maxes[j];\n }\n\n for (i = 1; i < len; i++) {\n for (j = 0; j < numofparams; j++) {\n if (parents[i][j] > maxes[j]) {\n maxes[j] = parents[i][j];\n }\n\n if (parents[i][j] < mins[j]) {\n mins[j] = parents[i][j];\n }\n }\n }\n\n la = [];\n pdata = [];\n\n for (i = 0; i < len; i++) {\n la[i] = '';\n pdata[i] = [];\n }\n\n ssa = [];\n esa = [];\n\n // 0 <= Offset from chart center <=1\n ssratio = attributes.startshiftratio || 0;\n // 0 <= Offset from chart radius <=1\n esratio = attributes.endshiftratio || 0;\n\n for (i = 0; i < numofparams; i++) {\n ssa[i] = (maxes[i] - mins[i]) * ssratio;\n esa[i] = (maxes[i] - mins[i]) * esratio;\n }\n\n // Adjust offsets per each axis\n sshifts = attributes.startshiftarray || ssa;\n eshifts = attributes.endshiftarray || esa;\n // Values for inner circle, minimums by default\n starts = attributes.startarray || mins;\n\n if (Type.exists(attributes.start)) {\n for (i = 0; i < numofparams; i++) {\n starts[i] = attributes.start;\n }\n }\n\n // Values for outer circle, maximums by default\n ends = attributes.endarray || maxes;\n if (Type.exists(attributes.end)) {\n for (i = 0; i < numofparams; i++) {\n ends[i] = attributes.end;\n }\n }\n\n if (sshifts.length !== numofparams) {\n throw new Error('JSXGraph radar chart: start shifts length is not equal to number of parameters');\n }\n\n if (eshifts.length !== numofparams) {\n throw new Error('JSXGraph radar chart: end shifts length is not equal to number of parameters');\n }\n\n if (starts.length !== numofparams) {\n throw new Error('JSXGraph radar chart: starts length is not equal to number of parameters');\n }\n\n if (ends.length !== numofparams) {\n throw new Error('JSXGraph radar chart: snds length is not equal to number of parameters');\n }\n\n // labels for legend\n labelArray = attributes.labelarray || la;\n colorArray = attributes.colors;\n highlightColorArray = attributes.highlightcolors;\n radius = attributes.radius || 10;\n sw = attributes.strokewidth || 1;\n\n if (!Type.exists(attributes.highlightonsector)) {\n attributes.highlightonsector = false;\n }\n\n myAtts = {\n name: attributes.name,\n id: attributes.id,\n strokewidth: sw,\n polystrokewidth: attributes.polystrokewidth || sw,\n strokecolor: attributes.strokecolor || 'black',\n straightfirst: false,\n straightlast: false,\n fillcolor: attributes.fillColor || '#FFFF88',\n fillopacity: attributes.fillOpacity || 0.4,\n highlightfillcolor: attributes.highlightFillColor || '#FF7400',\n highlightstrokecolor: attributes.highlightStrokeColor || 'black',\n gradient: attributes.gradient || 'none'\n };\n\n cent = attributes.center || [0, 0];\n xc = cent[0];\n yc = cent[1];\n center = board.create('point', [xc, yc], {name: '', fixed: true, withlabel: false, visible: false});\n start_angle = Math.PI / 2 - Math.PI / numofparams;\n start_angle = attributes.startangle || 0;\n rad = start_angle;\n p = [];\n line = [];\n\n for (i = 0; i < numofparams; i++) {\n rad += 2 * Math.PI / numofparams;\n xcoord = radius * Math.cos(rad) + xc;\n ycoord = radius * Math.sin(rad) + yc;\n\n p[i] = board.create('point', [xcoord, ycoord], {name: '', fixed: true, withlabel: false, visible: false});\n line[i] = board.create('line', [center, p[i]], {\n name: paramArray[i],\n strokeColor: myAtts.strokecolor,\n strokeWidth: myAtts.strokewidth,\n strokeOpacity: 1.0,\n straightFirst: false,\n straightLast: false,\n withLabel: true,\n highlightStrokeColor: myAtts.highlightstrokecolor\n });\n line[i].getLabelAnchor = get_anchor;\n t = get_transform(rad, i);\n\n for (j = 0; j < parents.length; j++) {\n data = parents[j][i];\n pdata[j][i] = board.create('point', [data, 0], {name: '', fixed: true, withlabel: false, visible: false});\n pdata[j][i].addTransform(pdata[j][i], t);\n }\n }\n\n polygons = [];\n for (i = 0; i < len; i++) {\n myAtts.labelcolor = colorArray && colorArray[i % colorArray.length];\n myAtts.strokecolor = colorArray && colorArray[i % colorArray.length];\n myAtts.fillcolor = colorArray && colorArray[i % colorArray.length];\n polygons[i] = board.create('polygon', pdata[i], {\n withLines: true,\n withLabel: false,\n fillColor: myAtts.fillcolor,\n fillOpacity: myAtts.fillopacity,\n highlightFillColor: myAtts.highlightfillcolor\n });\n\n for (j = 0; j < numofparams; j++) {\n polygons[i].borders[j].setAttribute('strokecolor:' + colorArray[i % colorArray.length]);\n polygons[i].borders[j].setAttribute('strokewidth:' + myAtts.polystrokewidth);\n }\n }\n\n legend_position = attributes.legendposition || 'none';\n switch (legend_position) {\n case 'right':\n lxoff = attributes.legendleftoffset || 2;\n lyoff = attributes.legendtopoffset || 1;\n\n this.legend = board.create('legend', [xc + radius + lxoff, yc + radius - lyoff], {\n labels: labelArray,\n colors: colorArray\n });\n break;\n case 'none':\n break;\n default:\n JXG.debug('Unknown legend position');\n }\n\n circles = [];\n if (attributes.showcircles) {\n cla = [];\n for (i = 0; i < 6; i++) {\n cla[i] = 20 * i;\n }\n cla[0] = \"0\";\n clabelArray = attributes.circlelabelarray || cla;\n ncircles = clabelArray.length;\n\n if (ncircles < 2) {\n throw new Error('JSXGraph radar chart: too less circles in circleLabelArray');\n }\n\n pcircles = [];\n angle = start_angle + Math.PI / numofparams;\n t = get_transform(angle, 0);\n\n myAtts.fillcolor = 'none';\n myAtts.highlightfillcolor = 'none';\n myAtts.strokecolor = attributes.strokecolor || 'black';\n myAtts.strokewidth = attributes.circlestrokewidth || 0.5;\n myAtts.layer = 0;\n\n // we have ncircles-1 intervals between ncircles circles\n dr = (ends[0] - starts[0]) / (ncircles - 1);\n\n for (i = 0; i < ncircles; i++) {\n pcircles[i] = board.create('point', [starts[0] + i * dr, 0], {\n name: clabelArray[i],\n size: 0,\n fixed: true,\n withLabel: true,\n visible: true\n });\n pcircles[i].addTransform(pcircles[i], t);\n circles[i] = board.create('circle', [center, pcircles[i]], myAtts);\n }\n\n }\n this.rendNode = polygons[0].rendNode;\n return {\n circles: circles,\n lines: line,\n points: pdata,\n midpoint: center,\n polygons: polygons\n };\n },\n\n /**\n * Uses the boards renderer to update the chart.\n * @private\n */\n updateRenderer: function () {\n return this;\n },\n\n // documented in base/element\n update: function () {\n if (this.needsUpdate) {\n this.updateDataArray();\n }\n\n return this;\n },\n\n /**\n * Template for dynamic charts update.\n * This method is used to compute new entries\n * for the arrays this.dataX and\n * this.dataY. It is used in update.\n * Default is an empty method, can be overwritten\n * by the user.\n *\n * @returns {JXG.Chart} Reference to this chart object.\n */\n updateDataArray: function () { return this; }\n });\n\n /**\n * @class Constructor for a chart.\n * @pseudo\n * @description\n * @name Chart\n * @augments JXG.Chart\n * @constructor\n * @type JXG.Chart\n * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {Array} x Array of x-coordinates (default case, see below for alternatives)\n * @param {Array} y Array of y-coordinates (default case, see below for alternatives)\n * <p>\n * The parent array may be of one of the following forms:\n * <ol>\n * <li> Parents array looks like [number, number, number, ...]. It is interpreted as array of y-coordinates.\n * The x coordinates are automatically set to [1, 2, ...]\n * <li> Parents array looks like [[number, number, number, ...]]. The content is interpreted as array of y-coordinates.\n * The x coordinates are automatically set to [1, 2, ...]x coordinates are automatically set to [1, 2, ...]\n * Default case: [[x0,x1,x2,...],[y1,y2,y3,...]]\n * </ol>\n *\n * The attribute value for the key 'chartStyle' determines the type(s) of the chart. 'chartStyle' is a comma\n * separated list of strings of the possible chart types\n * 'bar', 'fit', 'line', 'pie', 'point', 'radar', 'spline'.\n *\n * @see JXG.Chart#drawBar\n * @see JXG.Chart#drawFit\n * @see JXG.Chart#drawLine\n * @see JXG.Chart#drawPie\n * @see JXG.Chart#drawPoints\n * @see JXG.Chart#drawRadar\n * @see JXG.Chart#drawSpline\n *\n * @example\n * board = JXG.JSXGraph.initBoard('jxgbox', {boundingbox:[-0.5,8,9,-2],axis:true});\n *\n * var f = [4, 2, -1, 3, 6, 7, 2];\n * var chart = board.create('chart', f,\n * {chartStyle:'bar',\n * width:0.8,\n * labels:f,\n * colorArray:['#8E1B77','#BE1679','#DC1765','#DA2130','#DB311B','#DF4917','#E36317','#E87F1A',\n * '#F1B112','#FCF302','#C1E212'],\n * label: {fontSize:30, display:'internal', anchorX:'left', rotate:90}\n * });\n *\n * </pre><div id=\"JXG1528c395-9fa4-4210-ada6-7fc5652ed920\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG1528c395-9fa4-4210-ada6-7fc5652ed920',\n * {boundingbox: [-0.5,8,9,-2], axis: true, showcopyright: false, shownavigation: false});\n * var f = [4,2,-1,3,6,7,2];\n * var chart = board.create('chart', f,\n * {chartStyle:'bar',\n * width:0.8,\n * labels:f,\n * colorArray:['#8E1B77','#BE1679','#DC1765','#DA2130','#DB311B','#DF4917','#E36317','#E87F1A',\n * '#F1B112','#FCF302','#C1E212'],\n * label: {fontSize:30, display:'internal', anchorX:'left', rotate:90}\n * });\n *\n * })();\n *\n * </script><pre>\n *\n * @example\n * board = JXG.JSXGraph.initBoard('jxgbox', {boundingbox: [-1, 9, 13, -3], axis:true});\n *\n * var s = board.create('slider', [[4,7],[8,7],[1,1,1.5]], {name:'S', strokeColor:'black', fillColor:'white'});\n * var f = [function(){return (s.Value()*4.5).toFixed(2);},\n * function(){return (s.Value()*(-1)).toFixed(2);},\n * function(){return (s.Value()*3).toFixed(2);},\n * function(){return (s.Value()*2).toFixed(2);},\n * function(){return (s.Value()*(-0.5)).toFixed(2);},\n * function(){return (s.Value()*5.5).toFixed(2);},\n * function(){return (s.Value()*2.5).toFixed(2);},\n * function(){return (s.Value()*(-0.75)).toFixed(2);},\n * function(){return (s.Value()*3.5).toFixed(2);},\n * function(){return (s.Value()*2).toFixed(2);},\n * function(){return (s.Value()*(-1.25)).toFixed(2);}\n * ];\n * var chart = board.create('chart', [f],\n * {chartStyle:'bar',width:0.8,labels:f,\n * colorArray:['#8E1B77','#BE1679','#DC1765','#DA2130','#DB311B','#DF4917','#E36317','#E87F1A',\n * '#F1B112','#FCF302','#C1E212']});\n *\n * var dataArr = [4,1,3,2,5,6.5,1.5,2,0.5,1.5,-1];\n * var chart2 = board.create('chart', dataArr, {chartStyle:'line,point'});\n * chart2[0].setAttribute('strokeColor:black','strokeWidth:2pt');\n * for(var i=0; i<11;i++) {\n * chart2[1][i].setAttribute({strokeColor:'black',fillColor:'white',face:'[]', size:4, strokeWidth:'2pt'});\n * }\n * board.unsuspendUpdate();\n *\n * </pre><div id=\"JXG22deb158-48c6-41c3-8157-b88b4b968a55\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG22deb158-48c6-41c3-8157-b88b4b968a55',\n * {boundingbox: [-1, 9, 13, -3], axis: true, showcopyright: false, shownavigation: false});\n * var s = board.create('slider', [[4,7],[8,7],[1,1,1.5]], {name:'S', strokeColor:'black', fillColor:'white'});\n * var f = [function(){return (s.Value()*4.5).toFixed(2);},\n * function(){return (s.Value()*(-1)).toFixed(2);},\n * function(){return (s.Value()*3).toFixed(2);},\n * function(){return (s.Value()*2).toFixed(2);},\n * function(){return (s.Value()*(-0.5)).toFixed(2);},\n * function(){return (s.Value()*5.5).toFixed(2);},\n * function(){return (s.Value()*2.5).toFixed(2);},\n * function(){return (s.Value()*(-0.75)).toFixed(2);},\n * function(){return (s.Value()*3.5).toFixed(2);},\n * function(){return (s.Value()*2).toFixed(2);},\n * function(){return (s.Value()*(-1.25)).toFixed(2);}\n * ];\n * var chart = board.create('chart', [f],\n * {chartStyle:'bar',width:0.8,labels:f,\n * colorArray:['#8E1B77','#BE1679','#DC1765','#DA2130','#DB311B','#DF4917','#E36317','#E87F1A',\n * '#F1B112','#FCF302','#C1E212']});\n *\n * var dataArr = [4,1,3,2,5,6.5,1.5,2,0.5,1.5,-1];\n * var chart2 = board.create('chart', dataArr, {chartStyle:'line,point'});\n * chart2[0].setAttribute('strokeColor:black','strokeWidth:2pt');\n * for(var i=0; i<11;i++) {\n * chart2[1][i].setAttribute({strokeColor:'black',fillColor:'white',face:'[]', size:4, strokeWidth:'2pt'});\n * }\n * board.unsuspendUpdate();\n *\n * })();\n *\n * </script><pre>\n *\n * @example\n * var dataArr = [4, 1.2, 3, 7, 5, 4, 1.54, function () { return 2; }];\n * var a = board.create('chart', dataArr, {\n * chartStyle:'pie', colors:['#B02B2C','#3F4C6B','#C79810','#D15600'],\n * fillOpacity:0.9,\n * center:[5,2],\n * strokeColor:'#ffffff',\n * strokeWidth:6,\n * highlightBySize:true,\n * highlightOnSector:true\n * });\n *\n * </pre><div id=\"JXG1180b7dd-b048-436a-a5ad-87ffa82d5aff\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG1180b7dd-b048-436a-a5ad-87ffa82d5aff',\n * {boundingbox: [0, 8, 12, -4], axis: true, showcopyright: false, shownavigation: false});\n * var dataArr = [4, 1.2, 3, 7, 5, 4, 1.54, function () { return 2; }];\n * var a = board.create('chart', dataArr, {\n * chartStyle:'pie', colors:['#B02B2C','#3F4C6B','#C79810','#D15600'],\n * fillOpacity:0.9,\n * center:[5,2],\n * strokeColor:'#ffffff',\n * strokeWidth:6,\n * highlightBySize:true,\n * highlightOnSector:true\n * });\n *\n * })();\n *\n * </script><pre>\n *\n * @example\n * board = JXG.JSXGraph.initBoard('jxgbox', {boundingbox: [-12, 12, 20, -12], axis: false});\n * board.suspendUpdate();\n * // See labelArray and paramArray\n * var dataArr = [[23, 14, 15.0], [60, 8, 25.0], [0, 11.0, 25.0], [10, 15, 20.0]];\n *\n * var a = board.create('chart', dataArr, {\n * chartStyle:'radar',\n * colorArray:['#0F408D','#6F1B75','#CA147A','#DA2228','#E8801B','#FCF302','#8DC922','#15993C','#87CCEE','#0092CE'],\n * //fillOpacity:0.5,\n * //strokeColor:'black',\n * //strokeWidth:1,\n * //polyStrokeWidth:1,\n * paramArray:['Speed','Flexibility', 'Costs'],\n * labelArray:['Ruby','JavaScript', 'PHP', 'Python'],\n * //startAngle:Math.PI/4,\n * legendPosition:'right',\n * //\"startShiftRatio\": 0.1,\n * //endShiftRatio:0.1,\n * //startShiftArray:[0,0,0],\n * //endShiftArray:[0.5,0.5,0.5],\n * start:0\n * //end:70,\n * //startArray:[0,0,0],\n * //endArray:[7,7,7],\n * //radius:3,\n * //showCircles:true,\n * //circleLabelArray:[1,2,3,4,5],\n * //highlightColorArray:['#E46F6A','#F9DF82','#F7FA7B','#B0D990','#69BF8E','#BDDDE4','#92C2DF','#637CB0','#AB91BC','#EB8EBF'],\n * });\n * board.unsuspendUpdate();\n *\n * </pre><div id=\"JXG985fbbe6-0488-4073-b73b-cb3ebaea488a\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG985fbbe6-0488-4073-b73b-cb3ebaea488a',\n * {boundingbox: [-12, 12, 20, -12], axis: false, showcopyright: false, shownavigation: false});\n * board.suspendUpdate();\n * // See labelArray and paramArray\n * var dataArr = [[23, 14, 15.0], [60, 8, 25.0], [0, 11.0, 25.0], [10, 15, 20.0]];\n *\n * var a = board.create('chart', dataArr, {\n * chartStyle:'radar',\n * colorArray:['#0F408D','#6F1B75','#CA147A','#DA2228','#E8801B','#FCF302','#8DC922','#15993C','#87CCEE','#0092CE'],\n * //fillOpacity:0.5,\n * //strokeColor:'black',\n * //strokeWidth:1,\n * //polyStrokeWidth:1,\n * paramArray:['Speed','Flexibility', 'Costs'],\n * labelArray:['Ruby','JavaScript', 'PHP', 'Python'],\n * //startAngle:Math.PI/4,\n * legendPosition:'right',\n * //\"startShiftRatio\": 0.1,\n * //endShiftRatio:0.1,\n * //startShiftArray:[0,0,0],\n * //endShiftArray:[0.5,0.5,0.5],\n * start:0\n * //end:70,\n * //startArray:[0,0,0],\n * //endArray:[7,7,7],\n * //radius:3,\n * //showCircles:true,\n * //circleLabelArray:[1,2,3,4,5],\n * //highlightColorArray:['#E46F6A','#F9DF82','#F7FA7B','#B0D990','#69BF8E','#BDDDE4','#92C2DF','#637CB0','#AB91BC','#EB8EBF'],\n * });\n * board.unsuspendUpdate();\n *\n * })();\n *\n * </script><pre>\n *\n * For more examples see\n * <ul>\n * <li><a href=\"https://jsxgraph.org/wiki/index.php/Charts_from_HTML_tables_-_tutorial\">JSXgraph wiki: Charts from HTML tables - tutorial</a>\n * <li><a href=\"https://jsxgraph.org/wiki/index.php/Pie_chart\">JSXgraph wiki: Pie chart</a>\n * <li><a href=\"https://jsxgraph.org/wiki/index.php/Different_chart_styles\">JSXgraph wiki: Various chart styles</a>\n * <li><a href=\"https://jsxgraph.org/wiki/index.php/Dynamic_bar_chart\">JSXgraph wiki: Dynamic bar chart</a>\n * </ul>\n */\n JXG.createChart = function (board, parents, attributes) {\n var data, row, i, j, col,\n charts = [],\n w, x, showRows, attr,\n originalWidth, name, strokeColor, fillColor,\n hStrokeColor, hFillColor, len,\n table = Env.isBrowser ? board.document.getElementById(parents[0]) : null;\n\n if ((parents.length === 1) && (Type.isString(parents[0]))) {\n if (Type.exists(table)) {\n // extract the data\n attr = Type.copyAttributes(attributes, board.options, 'chart');\n\n table = (new DataSource()).loadFromTable(parents[0], attr.withheaders, attr.withheaders);\n data = table.data;\n col = table.columnHeaders;\n row = table.rowHeaders;\n\n originalWidth = attr.width;\n name = attr.name;\n strokeColor = attr.strokecolor;\n fillColor = attr.fillcolor;\n hStrokeColor = attr.highlightstrokecolor;\n hFillColor = attr.highlightfillcolor;\n\n board.suspendUpdate();\n\n len = data.length;\n showRows = [];\n if (attr.rows && Type.isArray(attr.rows)) {\n for (i = 0; i < len; i++) {\n for (j = 0; j < attr.rows.length; j++) {\n if ((attr.rows[j] === i) || (attr.withheaders && attr.rows[j] === row[i])) {\n showRows.push(data[i]);\n break;\n }\n }\n }\n } else {\n showRows = data;\n }\n\n len = showRows.length;\n\n for (i = 0; i < len; i++) {\n\n x = [];\n if (attr.chartstyle && attr.chartstyle.indexOf('bar') !== -1) {\n if (originalWidth) {\n w = originalWidth;\n } else {\n w = 0.8;\n }\n\n x.push(1 - w / 2 + (i + 0.5) * w / len);\n\n for (j = 1; j < showRows[i].length; j++) {\n x.push(x[j - 1] + 1);\n }\n\n attr.width = w / len;\n }\n\n if (name && name.length === len) {\n attr.name = name[i];\n } else if (attr.withheaders) {\n attr.name = col[i];\n }\n\n if (strokeColor && strokeColor.length === len) {\n attr.strokecolor = strokeColor[i];\n } else {\n attr.strokecolor = Color.hsv2rgb(((i + 1) / len) * 360, 0.9, 0.6);\n }\n\n if (fillColor && fillColor.length === len) {\n attr.fillcolor = fillColor[i];\n } else {\n attr.fillcolor = Color.hsv2rgb(((i + 1) / len) * 360, 0.9, 1.0);\n }\n\n if (hStrokeColor && hStrokeColor.length === len) {\n attr.highlightstrokecolor = hStrokeColor[i];\n } else {\n attr.highlightstrokecolor = Color.hsv2rgb(((i + 1) / len) * 360, 0.9, 1.0);\n }\n\n if (hFillColor && hFillColor.length === len) {\n attr.highlightfillcolor = hFillColor[i];\n } else {\n attr.highlightfillcolor = Color.hsv2rgb(((i + 1) / len) * 360, 0.9, 0.6);\n }\n\n if (attr.chartstyle && attr.chartstyle.indexOf('bar') !== -1) {\n charts.push(new JXG.Chart(board, [x, showRows[i]], attr));\n } else {\n charts.push(new JXG.Chart(board, [showRows[i]], attr));\n }\n }\n\n board.unsuspendUpdate();\n\n }\n return charts;\n }\n\n attr = Type.copyAttributes(attributes, board.options, 'chart');\n return new JXG.Chart(board, parents, attr);\n };\n\n JXG.registerElement('chart', JXG.createChart);\n\n /**\n * Legend for chart\n * TODO\n *\n * The Legend class is a basic class for legends.\n * @class Creates a new Lgend object. Do not use this constructor to create a legend.\n * Use {@link JXG.Board#create} with type {@link Legend} instead.\n * <p>\n * The legend object consists of segements with labels. These lines can be\n * access with the property \"lines\" of the element.\n * @constructor\n * @augments JXG.GeometryElement\n * @param {String,JXG.Board} board The board the new legend is drawn on.\n * @param {Array} coords Coordinates of the left top point of the legend.\n * @param {Object} attributes Attributes of the legend\n */\n JXG.Legend = function (board, coords, attributes) {\n var attr;\n\n /* Call the constructor of GeometryElement */\n this.constructor();\n\n attr = Type.copyAttributes(attributes, board.options, 'legend');\n\n this.board = board;\n this.coords = new Coords(Const.COORDS_BY_USER, coords, this.board);\n this.myAtts = {};\n this.label_array = attr.labelarray || attr.labels;\n this.color_array = attr.colorarray || attr.colors;\n this.lines = [];\n this.myAtts.strokewidth = attr.strokewidth || 5;\n this.myAtts.straightfirst = false;\n this.myAtts.straightlast = false;\n this.myAtts.withlabel = true;\n this.myAtts.fixed = true;\n this.style = attr.legendstyle || attr.style;\n\n if (this.style === 'vertical') {\n this.drawVerticalLegend(board, attr);\n } else {\n throw new Error('JSXGraph: Unknown legend style: ' + this.style);\n }\n };\n\n JXG.Legend.prototype = new GeometryElement();\n\n /**\n * Draw a vertical legend.\n *\n * @private\n * @param {String,JXG.Board} board The board the legend is drawn on\n * @param {Object} attributes Attributes of the legend\n */\n JXG.Legend.prototype.drawVerticalLegend = function (board, attributes) {\n var i,\n line_length = attributes.linelength || 1,\n offy = (attributes.rowheight || 20) / this.board.unitY,\n\n getLabelAnchor = function () {\n this.setLabelRelativeCoords(this.visProp.label.offset);\n return new Coords(Const.COORDS_BY_USER, [this.point2.X(), this.point2.Y()], this.board);\n };\n\n for (i = 0; i < this.label_array.length; i++) {\n this.myAtts.name = this.label_array[i];\n this.myAtts.strokecolor = this.color_array[i % this.color_array.length];\n this.myAtts.highlightstrokecolor = this.color_array[i % this.color_array.length];\n this.myAtts.label = {\n offset: [10, 0],\n strokeColor: this.color_array[i % this.color_array.length ],\n strokeWidth: this.myAtts.strokewidth\n };\n\n this.lines[i] = board.create('line', [\n [this.coords.usrCoords[1], this.coords.usrCoords[2] - i * offy],\n [this.coords.usrCoords[1] + line_length, this.coords.usrCoords[2] - i * offy]],\n this.myAtts);\n\n this.lines[i].getLabelAnchor = getLabelAnchor;\n this.lines[i].prepareUpdate().update().updateVisibility(Type.evaluate(this.lines[i].visProp.visible)).updateRenderer();\n }\n };\n\n /**\n * @class This element is used to provide a constructor for a chart legend.\n * Parameter is a pair of coordinates. The label names and the label colors are\n * supplied in the attributes:\n * <ul>\n * <li> labels (Array): array of strings containing label names\n * <li> labelArray (Array): alternative array for label names (has precedence over 'labels')\n * <li> colors (Array): array of color values\n * <li> colorArray (Array): alternative array for color values (has precedence over 'colors')\n * <li> legendStyle or style: at the time being only 'vertical' is supported.\n * <li> rowHeight.\n * </ul>\n *\n * @pseudo\n * @description\n * @name Legend\n * @augments JXG.Legend\n * @constructor\n * @type JXG.Legend\n * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {Number} x Horizontal coordinate of the left top point of the legend\n * @param {Number} y Vertical coordinate of the left top point of the legend\n *\n * @example\n * var board = JXG.JSXGraph.initBoard('jxgbox', {axis:true,boundingbox:[-4,48.3,12.0,-2.3]});\n * var x = [-3,-2,-1,0,1,2,3,4,5,6,7,8];\n * var dataArr = [4,7,7,27,33,37,46,22,11,4,1,0];\n *\n * colors = ['green', 'yellow', 'red', 'blue'];\n * board.create('chart', [x,dataArr], {chartStyle:'bar', width:1.0, labels:dataArr, colors: colors} );\n * board.create('legend', [8, 45], {labels:dataArr, colors: colors, strokeWidth:5} );\n *\n * </pre><div id=\"JXGeeb588d9-a4fd-41bf-93f4-cd6f7a016682\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXGeeb588d9-a4fd-41bf-93f4-cd6f7a016682',\n * {boundingbox: [-4,48.3,12.0,-2.3], axis: true, showcopyright: false, shownavigation: false});\n * var x = [-3,-2,-1,0,1,2,3,4,5,6,7,8];\n * var dataArr = [4,7,7,27,33,37,46,22,11,4,1,0];\n *\n * colors = ['green', 'yellow', 'red', 'blue'];\n * board.create('chart', [x,dataArr], {chartStyle:'bar', width:1.0, labels:dataArr, colors: colors} );\n * board.create('legend', [8, 45], {labels:dataArr, colors: colors, strokeWidth:5} );\n *\n * })();\n *\n * </script><pre>\n *\n *\n */\n JXG.createLegend = function (board, parents, attributes) {\n //parents are coords of left top point of the legend\n var start_from = [0, 0];\n\n if (Type.exists(parents) && parents.length === 2) {\n start_from = parents;\n } else {\n throw new Error('JSXGraph: Legend element needs two numbers as parameters');\n }\n\n return new JXG.Legend(board, start_from, attributes);\n };\n\n JXG.registerElement('legend', JXG.createLegend);\n\n return {\n Chart: JXG.Chart,\n Legend: JXG.Legend,\n createChart: JXG.createChart,\n createLegend: JXG.createLegend\n };\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true*/\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n jxg\n base/constants\n base/element\n utils/type\n elements:\n curve\n point\n line\n transform\n */\n\n/**\n * @fileoverview The JSXGraph object Turtle is defined. It acts like\n * \"turtle graphics\".\n * @author A.W.\n */\n\ndefine('base/turtle',[\n 'jxg', 'base/constants', 'base/element', 'utils/type'\n], function (JXG, Const, GeometryElement, Type) {\n\n \"use strict\";\n\n /**\n * Constructs a new Turtle object.\n * @class This is the Turtle class.\n * It is derived from {@link JXG.GeometryElement}.\n * It stores all properties required\n * to move a turtle.\n * @constructor\n * @param {JXG.Board} board The board the new turtle is drawn on.\n * @param {Array} parents Start position and start direction of the turtle. Possible values are\n * [x, y, angle]\n * [[x, y], angle]\n * [x, y]\n * [[x, y]]\n * @param {Object} attributes Attributes to change the visual properties of the turtle object\n * All angles are in degrees.\n *\n * @example\n *\n * //creates a figure 8 animation\n * var board = JXG.JSXGraph.initBoard('jxgbox',{boundingbox: [-250, 250, 250, -250]});\n * var t = board.create('turtle',[0, 0], {strokeOpacity:0.5});\n * t.setPenSize(3);\n * t.right(90);\n * var alpha = 0;\n *\n * var run = function() {\n * t.forward(2);\n * if (Math.floor(alpha / 360) % 2 === 0) {\n * t.left(1); // turn left by 1 degree\n * } else {\n * t.right(1); // turn right by 1 degree\n * }\n * alpha += 1;\n *\n * if (alpha < 1440) { // stop after two rounds\n * setTimeout(run, 20);\n * }\n * }\n *\n *run();\n *\n * </pre><div class=\"jxgbox\" id=\"JXG14167b1c-2ad3-11e5-8dd9-901b0e1b8723\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var brd = JXG.JSXGraph.initBoard('JXG14167b1c-2ad3-11e5-8dd9-901b0e1b8723',\n * {boundingbox: [-250, 250, 250, -250], axis: true, showcopyright: false, shownavigation: false});\n * var t = brd.create('turtle',[0, 0], {strokeOpacity:0.5});\n * t.setPenSize(3);\n * t.right(90);\n * var alpha = 0;\n *\n * var run = function() {\n * t.forward(2);\n * if (Math.floor(alpha / 360) % 2 === 0) {\n * t.left(1); // turn left by 1 degree\n * } else {\n * t.right(1); // turn right by 1 degree\n * }\n * alpha += 1;\n *\n * if (alpha < 1440) { // stop after two rounds\n * setTimeout(run, 20);\n * }\n * }\n *\n * run();\n *\n * })();\n *\n * </script><pre>\n */\n JXG.Turtle = function (board, parents, attributes) {\n var x, y, dir;\n\n this.constructor(board, attributes, Const.OBJECT_TYPE_TURTLE, Const.OBJECT_CLASS_OTHER);\n\n this.turtleIsHidden = false;\n this.board = board;\n this.visProp.curveType = 'plot';\n\n // Save visProp in this._attributes.\n // this._attributes is overwritten by setPenSize, setPenColor...\n // Setting the color or size affects the turtle from the time of\n // calling the method,\n // whereas Turtle.setAttribute affects all turtle curves.\n this._attributes = Type.copyAttributes(this.visProp, board.options, 'turtle');\n delete this._attributes.id;\n\n x = 0;\n y = 0;\n dir = 90;\n\n if (parents.length !== 0) {\n // [x,y,dir]\n if (parents.length === 3) {\n // Only numbers are accepted at the moment\n x = parents[0];\n y = parents[1];\n dir = parents[2];\n } else if (parents.length === 2) {\n // [[x,y],dir]\n if (Type.isArray(parents[0])) {\n x = parents[0][0];\n y = parents[0][1];\n dir = parents[1];\n // [x,y]\n } else {\n x = parents[0];\n y = parents[1];\n }\n // [[x,y]]\n } else {\n x = parents[0][0];\n y = parents[0][1];\n }\n }\n\n this.init(x, y, dir);\n\n this.methodMap = Type.deepCopy(this.methodMap, {\n forward: 'forward',\n fd: 'forward',\n back: 'back',\n bk: 'back',\n right: 'right',\n rt: 'right',\n left: 'left',\n lt: 'left',\n penUp: 'penUp',\n pu: 'penUp',\n penDown: 'penDown',\n pd: 'penDown',\n clearScreen: 'clearScreen',\n cs: 'clearScreen',\n clean: 'clean',\n setPos: 'setPos',\n home: 'home',\n hideTurtle: 'hideTurtle',\n ht: 'hideTurtle',\n showTurtle: 'showTurtle',\n st: 'showTurtle',\n penSize: 'setPenSize',\n penColor: 'setPenColor',\n pushTurtle: 'pushTurtle',\n push: 'pushTurtle',\n popTurtle: 'popTurtle',\n pop: 'popTurtle',\n lookTo: 'lookTo',\n pos: 'pos',\n moveTo: 'moveTo',\n X: 'X',\n Y: 'Y'\n });\n\n return this;\n };\n\n JXG.Turtle.prototype = new GeometryElement();\n\n JXG.extend(JXG.Turtle.prototype, /** @lends JXG.Turtle.prototype */ {\n /**\n * Initialize a new turtle or reinitialize a turtle after {@link JXG.Turtle#clearScreen}.\n * @private\n */\n init: function (x, y, dir) {\n var hiddenPointAttr = {\n fixed: true,\n name: '',\n visible: false,\n withLabel: false\n };\n\n this.arrowLen = 20 / Math.sqrt(this.board.unitX * this.board.unitX + this.board.unitY * this.board.unitY);\n\n this.pos = [x, y];\n this.isPenDown = true;\n this.dir = 90;\n this.stack = [];\n this.objects = [];\n this.curve = this.board.create('curve', [[this.pos[0]], [this.pos[1]]], this._attributes);\n this.objects.push(this.curve);\n\n this.turtle = this.board.create('point', this.pos, hiddenPointAttr);\n this.objects.push(this.turtle);\n\n this.turtle2 = this.board.create('point', [this.pos[0], this.pos[1] + this.arrowLen], hiddenPointAttr);\n this.objects.push(this.turtle2);\n\n this.visProp.arrow.lastArrow = true;\n this.visProp.arrow.straightFirst = false;\n this.visProp.arrow.straightLast = false;\n this.arrow = this.board.create('line', [this.turtle, this.turtle2], this.visProp.arrow);\n this.objects.push(this.arrow);\n\n this.subs = {\n arrow: this.arrow\n };\n this.inherits.push(this.arrow);\n\n this.right(90 - dir);\n this.board.update();\n },\n\n /**\n * Move the turtle forward.\n * @param {Number} len of forward move in user coordinates\n * @returns {JXG.Turtle} pointer to the turtle object\n */\n forward: function (len) {\n if (len === 0) {\n return this;\n }\n\n var t,\n dx = len * Math.cos(this.dir * Math.PI / 180),\n dy = len * Math.sin(this.dir * Math.PI / 180);\n\n if (!this.turtleIsHidden) {\n t = this.board.create('transform', [dx, dy], {type: 'translate'});\n\n t.applyOnce(this.turtle);\n t.applyOnce(this.turtle2);\n }\n\n if (this.isPenDown) {\n // IE workaround\n if (this.curve.dataX.length >= 8192) {\n this.curve = this.board.create('curve', [[this.pos[0]], [this.pos[1]]], this._attributes);\n this.objects.push(this.curve);\n }\n }\n\n this.pos[0] += dx;\n this.pos[1] += dy;\n\n if (this.isPenDown) {\n this.curve.dataX.push(this.pos[0]);\n this.curve.dataY.push(this.pos[1]);\n }\n\n this.board.update();\n return this;\n },\n\n /**\n * Move the turtle backwards.\n * @param {Number} len of backwards move in user coordinates\n * @returns {JXG.Turtle} pointer to the turtle object\n */\n back: function (len) {\n return this.forward(-len);\n },\n\n /**\n * Rotate the turtle direction to the right\n * @param {Number} angle of the rotation in degrees\n * @returns {JXG.Turtle} pointer to the turtle object\n */\n right: function (angle) {\n this.dir -= angle;\n this.dir %= 360;\n\n if (!this.turtleIsHidden) {\n var t = this.board.create('transform', [-angle * Math.PI / 180, this.turtle], {type: 'rotate'});\n t.applyOnce(this.turtle2);\n }\n\n this.board.update();\n return this;\n },\n\n /**\n * Rotate the turtle direction to the right.\n * @param {Number} angle of the rotation in degrees\n * @returns {JXG.Turtle} pointer to the turtle object\n */\n left: function (angle) {\n return this.right(-angle);\n },\n\n /**\n * Pen up, stops visible drawing\n * @returns {JXG.Turtle} pointer to the turtle object\n */\n penUp: function () {\n this.isPenDown = false;\n return this;\n },\n\n /**\n * Pen down, continues visible drawing\n * @returns {JXG.Turtle} pointer to the turtle object\n */\n penDown: function () {\n this.isPenDown = true;\n this.curve = this.board.create('curve', [[this.pos[0]], [this.pos[1]]], this._attributes);\n this.objects.push(this.curve);\n\n return this;\n },\n\n /**\n * Removes the turtle curve from the board. The turtle stays in its position.\n * @returns {JXG.Turtle} pointer to the turtle object\n */\n clean: function () {\n var i, el;\n\n for (i = 0; i < this.objects.length; i++) {\n el = this.objects[i];\n if (el.type === Const.OBJECT_TYPE_CURVE) {\n this.board.removeObject(el);\n this.objects.splice(i, 1);\n }\n }\n\n this.curve = this.board.create('curve', [[this.pos[0]], [this.pos[1]]], this._attributes);\n this.objects.push(this.curve);\n this.board.update();\n\n return this;\n },\n\n /**\n * Removes the turtle completely and resets it to its initial position and direction.\n * @returns {JXG.Turtle} pointer to the turtle object\n */\n clearScreen: function () {\n var i, el,\n len = this.objects.length;\n\n for (i = 0; i < len; i++) {\n el = this.objects[i];\n this.board.removeObject(el);\n }\n\n this.init(0, 0, 90);\n return this;\n },\n\n /**\n * Moves the turtle without drawing to a new position\n * @param {Number} x new x- coordinate\n * @param {Number} y new y- coordinate\n * @returns {JXG.Turtle} pointer to the turtle object\n */\n setPos: function (x, y) {\n var t;\n\n if (Type.isArray(x)) {\n this.pos = x;\n } else {\n this.pos = [x, y];\n }\n\n if (!this.turtleIsHidden) {\n this.turtle.setPositionDirectly(Const.COORDS_BY_USER, [x, y]);\n this.turtle2.setPositionDirectly(Const.COORDS_BY_USER, [x, y + this.arrowLen]);\n t = this.board.create('transform', [-(this.dir - 90) * Math.PI / 180, this.turtle], {type: 'rotate'});\n t.applyOnce(this.turtle2);\n }\n\n this.curve = this.board.create('curve', [[this.pos[0]], [this.pos[1]]], this._attributes);\n this.objects.push(this.curve);\n this.board.update();\n\n return this;\n },\n\n /**\n * Sets the pen size. Equivalent to setAttribute({strokeWidth:size})\n * but affects only the future turtle.\n * @param {Number} size\n * @returns {JXG.Turtle} pointer to the turtle object\n */\n setPenSize: function (size) {\n //this.visProp.strokewidth = size;\n this.curve = this.board.create('curve', [[this.pos[0]], [this.pos[1]]], this.copyAttr('strokeWidth', size));\n this.objects.push(this.curve);\n return this;\n },\n\n /**\n * Sets the pen color. Equivalent to setAttribute({strokeColor:color})\n * but affects only the future turtle.\n * @param {String} color\n * @returns {JXG.Turtle} pointer to the turtle object\n */\n setPenColor: function (color) {\n this.curve = this.board.create('curve', [[this.pos[0]], [this.pos[1]]], this.copyAttr('strokeColor', color));\n this.objects.push(this.curve);\n\n return this;\n },\n\n /**\n * Sets the highlight pen color. Equivalent to setAttribute({highlightStrokeColor:color})\n * but affects only the future turtle.\n * @param {String} color\n * @returns {JXG.Turtle} pointer to the turtle object\n */\n setHighlightPenColor: function (color) {\n //this.visProp.highlightstrokecolor = colStr;\n this.curve = this.board.create('curve', [[this.pos[0]], [this.pos[1]]], this.copyAttr('highlightStrokeColor', color));\n this.objects.push(this.curve);\n return this;\n },\n\n /**\n * Sets properties of the turtle, see also {@link JXG.GeometryElement#setAttribute}.\n * Sets the property for all curves of the turtle in the past and in the future.\n * @param {Object} attributes key:value pairs\n * @returns {JXG.Turtle} pointer to the turtle object\n */\n setAttribute: function (attributes) {\n var i, el, tmp,\n len = this.objects.length;\n\n for (i = 0; i < len; i++) {\n el = this.objects[i];\n if (el.type === Const.OBJECT_TYPE_CURVE) {\n el.setAttribute(attributes);\n }\n }\n\n // Set visProp of turtle\n tmp = this.visProp.id;\n this.visProp = Type.deepCopy(this.curve.visProp);\n this.visProp.id = tmp;\n this._attributes = Type.deepCopy(this.visProp);\n delete this._attributes.id;\n\n return this;\n },\n\n /**\n * Set a future attribute of the turtle.\n * @private\n * @param {String} key\n * @param {Number|String} val\n * @returns {Object} pointer to the attributes object\n */\n copyAttr: function (key, val) {\n this._attributes[key.toLowerCase()] = val;\n return this._attributes;\n },\n\n /**\n * Sets the visibility of the turtle head to true,\n * @returns {JXG.Turtle} pointer to the turtle object\n */\n showTurtle: function () {\n this.turtleIsHidden = false;\n this.arrow.setAttribute({visible: true});\n this.visProp.arrow.visible = false;\n this.setPos(this.pos[0], this.pos[1]);\n this.board.update();\n\n return this;\n },\n\n /**\n * Sets the visibility of the turtle head to false,\n * @returns {JXG.Turtle} pointer to the turtle object\n */\n hideTurtle: function () {\n this.turtleIsHidden = true;\n this.arrow.setAttribute({visible: false});\n this.visProp.arrow.visible = false;\n this.board.update();\n\n return this;\n },\n\n /**\n * Moves the turtle to position [0,0].\n * @returns {JXG.Turtle} pointer to the turtle object\n */\n home: function () {\n this.pos = [0, 0];\n this.setPos(this.pos[0], this.pos[1]);\n\n return this;\n },\n\n /**\n * Pushes the position of the turtle on the stack.\n * @returns {JXG.Turtle} pointer to the turtle object\n */\n pushTurtle: function () {\n this.stack.push([this.pos[0], this.pos[1], this.dir]);\n\n return this;\n },\n\n /**\n * Gets the last position of the turtle on the stack, sets the turtle to this position and removes this\n * position from the stack.\n * @returns {JXG.Turtle} pointer to the turtle object\n */\n popTurtle: function () {\n var status = this.stack.pop();\n this.pos[0] = status[0];\n this.pos[1] = status[1];\n this.dir = status[2];\n this.setPos(this.pos[0], this.pos[1]);\n\n return this;\n },\n\n /**\n * Rotates the turtle into a new direction.\n * There are two possibilities:\n * @param {Number|Array} target If a number is given, it is interpreted as the new direction to look to; If an array\n * consisting of two Numbers is given targeted is used as a pair coordinates.\n * @returns {JXG.Turtle} pointer to the turtle object\n */\n lookTo: function (target) {\n var ax, ay, bx, by, beta;\n\n if (Type.isArray(target)) {\n ax = this.pos[0];\n ay = this.pos[1];\n bx = target[0];\n by = target[1];\n\n // Rotate by the slope of the line [this.pos, target]\n beta = Math.atan2(by - ay, bx - ax);\n this.right(this.dir - (beta * 180 / Math.PI));\n } else if (Type.isNumber(target)) {\n this.right(this.dir - target);\n }\n return this;\n },\n\n /**\n * Moves the turtle to a given coordinate pair.\n * The direction is not changed.\n * @param {Array} target Coordinates of the point where the turtle looks to.\n * @returns {JXG.Turtle} pointer to the turtle object\n */\n moveTo: function (target) {\n var dx, dy, t;\n\n if (Type.isArray(target)) {\n dx = target[0] - this.pos[0];\n dy = target[1] - this.pos[1];\n\n if (!this.turtleIsHidden) {\n t = this.board.create('transform', [dx, dy], {type: 'translate'});\n t.applyOnce(this.turtle);\n t.applyOnce(this.turtle2);\n }\n\n if (this.isPenDown) {\n // IE workaround\n if (this.curve.dataX.length >= 8192) {\n this.curve = this.board.create('curve', [[this.pos[0]], [this.pos[1]]], this._attributes);\n this.objects.push(this.curve);\n }\n }\n\n this.pos[0] = target[0];\n this.pos[1] = target[1];\n\n if (this.isPenDown) {\n this.curve.dataX.push(this.pos[0]);\n this.curve.dataY.push(this.pos[1]);\n }\n this.board.update();\n }\n\n return this;\n },\n\n /**\n * Alias for {@link JXG.Turtle#forward}\n */\n fd: function (len) { return this.forward(len); },\n /**\n * Alias for {@link JXG.Turtle#back}\n */\n bk: function (len) { return this.back(len); },\n /**\n * Alias for {@link JXG.Turtle#left}\n */\n lt: function (angle) { return this.left(angle); },\n /**\n * Alias for {@link JXG.Turtle#right}\n */\n rt: function (angle) { return this.right(angle); },\n /**\n * Alias for {@link JXG.Turtle#penUp}\n */\n pu: function () { return this.penUp(); },\n /**\n * Alias for {@link JXG.Turtle#penDown}\n */\n pd: function () { return this.penDown(); },\n /**\n * Alias for {@link JXG.Turtle#hideTurtle}\n */\n ht: function () { return this.hideTurtle(); },\n /**\n * Alias for {@link JXG.Turtle#showTurtle}\n */\n st: function () { return this.showTurtle(); },\n /**\n * Alias for {@link JXG.Turtle#clearScreen}\n */\n cs: function () { return this.clearScreen(); },\n /**\n * Alias for {@link JXG.Turtle#pushTurtle}\n */\n push: function () { return this.pushTurtle(); },\n /**\n * Alias for {@link JXG.Turtle#popTurtle}\n */\n pop: function () { return this.popTurtle(); },\n\n /**\n * The \"co\"-coordinate of the turtle curve at position t is returned.\n *\n * @param {Number} t parameter\n * @param {String} co. Either 'X' or 'Y'.\n * @returns {Number} x-coordinate of the turtle position or x-coordinate of turtle at position t\n */\n evalAt: function (t, co) {\n var i, j, el, tc,\n len = this.objects.length;\n\n for (i = 0, j = 0; i < len; i++) {\n el = this.objects[i];\n\n if (el.elementClass === Const.OBJECT_CLASS_CURVE) {\n if (j <= t && t < j + el.numberPoints) {\n tc = (t - j);\n return el[co](tc);\n }\n j += el.numberPoints;\n }\n }\n\n return this[co]();\n },\n\n /**\n * if t is not supplied the x-coordinate of the turtle is returned. Otherwise\n * the x-coordinate of the turtle curve at position t is returned.\n * @param {Number} t parameter\n * @returns {Number} x-coordinate of the turtle position or x-coordinate of turtle at position t\n */\n X: function (t) {\n if (!Type.exists(t)) {\n return this.pos[0];\n }\n\n return this.evalAt(t, 'X');\n },\n\n /**\n * if t is not supplied the y-coordinate of the turtle is returned. Otherwise\n * the y-coordinate of the turtle curve at position t is returned.\n * @param {Number} t parameter\n * @returns {Number} x-coordinate of the turtle position or x-coordinate of turtle at position t\n */\n Y: function (t) {\n if (!Type.exists(t)) {\n return this.pos[1];\n }\n return this.evalAt(t, 'Y');\n },\n\n /**\n * @returns {Number} z-coordinate of the turtle position\n */\n Z: function (t) {\n return 1.0;\n },\n\n /**\n * Gives the lower bound of the parameter if the the turtle is treated as parametric curve.\n */\n minX: function () {\n return 0;\n },\n\n /**\n * Gives the upper bound of the parameter if the the turtle is treated as parametric curve.\n * May be overwritten in @see generateTerm.\n */\n maxX: function () {\n var i, el,\n len = this.objects.length,\n np = 0;\n\n for (i = 0; i < len; i++) {\n el = this.objects[i];\n if (el.elementClass === Const.OBJECT_CLASS_CURVE) {\n np += this.objects[i].numberPoints;\n }\n }\n return np;\n },\n\n /**\n * Checks whether (x,y) is near the curve.\n * @param {Number} x Coordinate in x direction, screen coordinates.\n * @param {Number} y Coordinate in y direction, screen coordinates.\n * @returns {Boolean} True if (x,y) is near the curve, False otherwise.\n */\n hasPoint: function (x, y) {\n var i, el;\n\n // run through all curves of this turtle\n for (i = 0; i < this.objects.length; i++) {\n el = this.objects[i];\n\n if (el.type === Const.OBJECT_TYPE_CURVE) {\n if (el.hasPoint(x, y)) {\n // So what??? All other curves have to be notified now (for highlighting)\n return true;\n // This has to be done, yet.\n }\n }\n }\n return false;\n }\n });\n\n /**\n * @class This element is used to provide a constructor for a turtle.\n * @pseudo\n * @description Creates a new turtle\n * @name Turtle\n * @augments JXG.Turtle\n * @constructor\n * @type JXG.Turtle\n *\n * @param {JXG.Board} board The board the turtle is put on.\n * @param {Array} parents\n * @param {Object} attributes Object containing properties for the element such as stroke-color and visibility. See {@link JXG.GeometryElement#setAttribute}\n * @returns {JXG.Turtle} Reference to the created turtle object.\n */\n JXG.createTurtle = function (board, parents, attributes) {\n var attr;\n parents = parents || [];\n\n attr = Type.copyAttributes(attributes, board.options, 'turtle');\n return new JXG.Turtle(board, parents, attr);\n };\n\n JXG.registerElement('turtle', JXG.createTurtle);\n\n return {\n Turtle: JXG.Turtle,\n createTurtle: JXG.createTurtle\n };\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true*/\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n jxg\n math/math\n math/geometry\n base/constants\n base/element\n base/coords\n utils/type\n elements:\n text\n */\n\n/**\n * @fileoverview In this file the geometry object Ticks is defined. Ticks provides\n * methods for creation and management of ticks on an axis.\n * @author graphjs\n * @version 0.1\n */\n\ndefine('base/ticks',[\n 'jxg', 'math/math', 'math/geometry', 'math/numerics', 'base/constants', 'base/element', 'base/coords', 'utils/type', 'base/text'\n], function (JXG, Mat, Geometry, Numerics, Const, GeometryElement, Coords, Type, Text) {\n\n \"use strict\";\n\n /**\n * Creates ticks for an axis.\n * @class Ticks provides methods for creation and management\n * of ticks on an axis.\n * @param {JXG.Line} line Reference to the axis the ticks are drawn on.\n * @param {Number|Array} ticks Number defining the distance between two major ticks or an array defining static ticks.\n * @param {Object} attributes Properties\n * @see JXG.Line#addTicks\n * @constructor\n * @extends JXG.GeometryElement\n */\n JXG.Ticks = function (line, ticks, attributes) {\n this.constructor(line.board, attributes, Const.OBJECT_TYPE_TICKS, Const.OBJECT_CLASS_OTHER);\n\n /**\n * The line the ticks belong to.\n * @type JXG.Line\n */\n this.line = line;\n\n /**\n * The board the ticks line is drawn on.\n * @type JXG.Board\n */\n this.board = this.line.board;\n\n /**\n * A function calculating ticks delta depending on the ticks number.\n * @type Function\n */\n this.ticksFunction = null;\n\n /**\n * Array of fixed ticks.\n * @type Array\n */\n this.fixedTicks = null;\n\n /**\n * Equidistant ticks. Distance is defined by ticksFunction\n * @type Boolean\n */\n this.equidistant = false;\n\n this.labelsData = [];\n\n if (Type.isFunction(ticks)) {\n this.ticksFunction = ticks;\n throw new Error(\"Function arguments are no longer supported.\");\n }\n\n if (Type.isArray(ticks)) {\n this.fixedTicks = ticks;\n } else {\n if (Math.abs(ticks) < Mat.eps || ticks < 0) {\n ticks = attributes.defaultdistance;\n }\n\n /*\n * Ticks function:\n * determines the distance (in user units) of two major ticks\n */\n this.ticksFunction = this.makeTicksFunction(ticks);\n\n this.equidistant = true;\n }\n\n /**\n * Least distance between two ticks, measured in pixels.\n * @type int\n */\n this.minTicksDistance = attributes.minticksdistance;\n\n /**\n * Stores the ticks coordinates\n * @type Array\n */\n this.ticks = [];\n\n /**\n * Distance between two major ticks in user coordinates\n * @type Number\n */\n this.ticksDelta = 1;\n\n /**\n * Array where the labels are saved. There is an array element for every tick,\n * even for minor ticks which don't have labels. In this case the array element\n * contains just <tt>null</tt>.\n * @type Array\n */\n this.labels = [];\n\n /**\n * A list of labels which have to be displayed in updateRenderer.\n * @type Array\n */\n this.labelData = [];\n\n /**\n * To ensure the uniqueness of label ids this counter is used.\n * @type number\n */\n this.labelCounter = 0;\n\n this.id = this.line.addTicks(this);\n this.elType = 'ticks';\n this.inherits.push(this.labels);\n this.board.setId(this, 'Ti');\n };\n\n JXG.Ticks.prototype = new GeometryElement();\n\n JXG.extend(JXG.Ticks.prototype, /** @lends JXG.Ticks.prototype */ {\n\n /**\n * Ticks function:\n * determines the distance (in user units) of two major ticks.\n * See above in constructor and in @see JXG.GeometryElement#setAttribute\n *\n * @private\n * @param {Number} ticks Distance between two major ticks\n * @returns {Function} returns method ticksFunction\n */\n makeTicksFunction: function (ticks) {\n return function () {\n var delta, b, dist;\n\n if (Type.evaluate(this.visProp.insertticks)) {\n b = this.getLowerAndUpperBounds(this.getZeroCoordinates(), 'ticksdistance');\n dist = b.upper - b.lower;\n\n delta = Math.pow(10, Math.floor(Math.log(0.6 * dist) / Math.LN10));\n if (dist <= 6 * delta) {\n delta *= 0.5;\n }\n return delta;\n }\n\n // upto 0.99.1:\n return ticks;\n };\n },\n\n /**\n * Checks whether (x,y) is near the line.\n * Only available for line elements, not for ticks on curves.\n * @param {Number} x Coordinate in x direction, screen coordinates.\n * @param {Number} y Coordinate in y direction, screen coordinates.\n * @returns {Boolean} True if (x,y) is near the line, False otherwise.\n */\n hasPoint: function (x, y) {\n var i, t,\n len = (this.ticks && this.ticks.length) || 0,\n r, type;\n\n if (Type.isObject(Type.evaluate(this.visProp.precision))) {\n type = this.board._inputDevice;\n r = Type.evaluate(this.visProp.precision[type]);\n } else {\n // 'inherit'\n r = this.board.options.precision.hasPoint;\n }\n r += Type.evaluate(this.visProp.strokewidth) * 0.5;\n if (!Type.evaluate(this.line.visProp.scalable) ||\n this.line.elementClass === Const.OBJECT_CLASS_CURVE) {\n return false;\n }\n\n // Ignore non-axes and axes that are not horizontal or vertical\n if (this.line.stdform[1] !== 0 && this.line.stdform[2] !== 0 && this.line.type !== Const.OBJECT_TYPE_AXIS) {\n return false;\n }\n\n for (i = 0; i < len; i++) {\n t = this.ticks[i];\n\n // Skip minor ticks\n if (t[2]) {\n // Ignore ticks at zero\n if (!((this.line.stdform[1] === 0 && Math.abs(t[0][0] - this.line.point1.coords.scrCoords[1]) < Mat.eps) ||\n (this.line.stdform[2] === 0 && Math.abs(t[1][0] - this.line.point1.coords.scrCoords[2]) < Mat.eps))) {\n // tick length is not zero, ie. at least one pixel\n if (Math.abs(t[0][0] - t[0][1]) >= 1 || Math.abs(t[1][0] - t[1][1]) >= 1) {\n if (this.line.stdform[1] === 0) {\n // Allow dragging near axes only.\n if (Math.abs(y - (t[1][0] + t[1][1]) * 0.5) < 2 * r && t[0][0] - r < x && x < t[0][1] + r) {\n return true;\n }\n } else if (this.line.stdform[2] === 0) {\n if (Math.abs(x - (t[0][0] + t[0][1]) * 0.5) < 2 * r && t[1][0] - r < y && y < t[1][1] + r) {\n return true;\n }\n }\n }\n }\n }\n }\n\n return false;\n },\n\n /**\n * Sets x and y coordinate of the tick.\n * @param {number} method The type of coordinates used here. Possible values are {@link JXG.COORDS_BY_USER} and {@link JXG.COORDS_BY_SCREEN}.\n * @param {Array} coords coordinates in screen/user units\n * @param {Array} oldcoords previous coordinates in screen/user units\n * @returns {JXG.Ticks} this element\n */\n setPositionDirectly: function (method, coords, oldcoords) {\n var dx, dy,\n c = new Coords(method, coords, this.board),\n oldc = new Coords(method, oldcoords, this.board),\n bb = this.board.getBoundingBox();\n\n if (this.line.type !== Const.OBJECT_TYPE_AXIS ||\n !Type.evaluate(this.line.visProp.scalable)) {\n\n return this;\n }\n\n if (Math.abs(this.line.stdform[1]) < Mat.eps &&\n Math.abs(c.usrCoords[1] * oldc.usrCoords[1]) > Mat.eps) {\n\n // Horizontal line\n dx = oldc.usrCoords[1] / c.usrCoords[1];\n bb[0] *= dx;\n bb[2] *= dx;\n this.board.setBoundingBox(bb, this.board.keepaspectratio, 'update');\n\n } else if (Math.abs(this.line.stdform[2]) < Mat.eps &&\n Math.abs(c.usrCoords[2] * oldc.usrCoords[2]) > Mat.eps) {\n\n // Vertical line\n dy = oldc.usrCoords[2] / c.usrCoords[2];\n bb[3] *= dy;\n bb[1] *= dy;\n this.board.setBoundingBox(bb, this.board.keepaspectratio, 'update');\n }\n\n return this;\n },\n\n /**\n * (Re-)calculates the ticks coordinates.\n * @private\n */\n calculateTicksCoordinates: function () {\n var coordsZero, bounds,\n r_max, bb;\n\n if (this.line.elementClass === Const.OBJECT_CLASS_LINE) {\n // Calculate Ticks width and height in Screen and User Coordinates\n this.setTicksSizeVariables();\n\n // If the parent line is not finite, we can stop here.\n if (Math.abs(this.dx) < Mat.eps &&\n Math.abs(this.dy) < Mat.eps) {\n return;\n }\n }\n\n // Get Zero (coords element for lines , number for curves)\n coordsZero = this.getZeroCoordinates();\n\n // Calculate lower bound and upper bound limits based on distance\n // between p1 and center and p2 and center\n if (this.line.elementClass === Const.OBJECT_CLASS_LINE) {\n bounds = this.getLowerAndUpperBounds(coordsZero);\n } else {\n bounds = {\n lower: this.line.minX(),\n upper: this.line.maxX()\n };\n }\n\n if (Type.evaluate(this.visProp.type) === 'polar') {\n bb = this.board.getBoundingBox();\n r_max = Math.max(Math.sqrt(bb[0] * bb[0] + bb[1] * bb[1]),\n Math.sqrt(bb[2] * bb[2] + bb[3] * bb[3]));\n bounds.upper = r_max;\n }\n\n // Clean up\n this.ticks = [];\n this.labelsData = [];\n // Create Ticks Coordinates and Labels\n if (this.equidistant) {\n this.generateEquidistantTicks(coordsZero, bounds);\n } else {\n this.generateFixedTicks(coordsZero, bounds);\n }\n\n return this;\n },\n\n /**\n * Sets the variables used to set the height and slope of each tick.\n *\n * @private\n */\n setTicksSizeVariables: function (pos) {\n var d, mi, ma, len,\n distMaj = Type.evaluate(this.visProp.majorheight) * 0.5,\n distMin = Type.evaluate(this.visProp.minorheight) * 0.5;\n\n // For curves:\n if (Type.exists(pos)) {\n mi = this.line.minX();\n ma = this.line.maxX();\n len = this.line.points.length;\n if (len < 2) {\n this.dxMaj = 0;\n this.dyMaj = 0;\n } else if (Mat.relDif(pos, mi) < Mat.eps) {\n this.dxMaj = this.line.points[0].usrCoords[2] - this.line.points[1].usrCoords[2];\n this.dyMaj = this.line.points[1].usrCoords[1] - this.line.points[0].usrCoords[1];\n } else if (Mat.relDif(pos, ma) < Mat.eps) {\n this.dxMaj = this.line.points[len - 2].usrCoords[2] - this.line.points[len - 1].usrCoords[2];\n this.dyMaj = this.line.points[len - 1].usrCoords[1] - this.line.points[len - 2].usrCoords[1];\n } else {\n this.dxMaj = -Numerics.D(this.line.Y)(pos);\n this.dyMaj = Numerics.D(this.line.X)(pos);\n }\n } else {\n // ticks width and height in screen units\n this.dxMaj = this.line.stdform[1];\n this.dyMaj = this.line.stdform[2];\n }\n this.dxMin = this.dxMaj;\n this.dyMin = this.dyMaj;\n\n // ticks width and height in user units\n this.dx = this.dxMaj;\n this.dy = this.dyMaj;\n\n // After this, the length of the vector (dxMaj, dyMaj) in screen coordinates is equal to distMaj pixel.\n d = Math.sqrt(\n this.dxMaj * this.dxMaj * this.board.unitX * this.board.unitX +\n this.dyMaj * this.dyMaj * this.board.unitY * this.board.unitY\n );\n this.dxMaj *= distMaj / d * this.board.unitX;\n this.dyMaj *= distMaj / d * this.board.unitY;\n this.dxMin *= distMin / d * this.board.unitX;\n this.dyMin *= distMin / d * this.board.unitY;\n\n // Grid-like ticks?\n this.minStyle= (Type.evaluate(this.visProp.minorheight) < 0) ? 'infinite' : 'finite';\n this.majStyle= (Type.evaluate(this.visProp.majorheight) < 0) ? 'infinite' : 'finite';\n },\n\n /**\n * Returns the coordinates of the point zero of the line.\n *\n * If the line is an {@link Axis}, the coordinates of the projection of the board's zero point is returned\n *\n * Otherwise, the coordinates of the point that acts as zero are\n * established depending on the value of {@link JXG.Ticks#anchor}\n *\n * @returns {JXG.Coords} Coords object for the zero point on the line\n * @private\n */\n getZeroCoordinates: function () {\n var c1x, c1y, c1z, c2x, c2y, c2z, t, mi, ma,\n ev_a = Type.evaluate(this.visProp.anchor);\n\n if (this.line.elementClass === Const.OBJECT_CLASS_LINE) {\n if (this.line.type === Const.OBJECT_TYPE_AXIS) {\n return Geometry.projectPointToLine({\n coords: {\n usrCoords: [1, 0, 0]\n }\n }, this.line, this.board);\n }\n c1z = this.line.point1.coords.usrCoords[0];\n c1x = this.line.point1.coords.usrCoords[1];\n c1y = this.line.point1.coords.usrCoords[2];\n c2z = this.line.point2.coords.usrCoords[0];\n c2x = this.line.point2.coords.usrCoords[1];\n c2y = this.line.point2.coords.usrCoords[2];\n\n if (ev_a === 'right') {\n return this.line.point2.coords;\n }\n if (ev_a === 'middle') {\n return new Coords(Const.COORDS_BY_USER, [\n (c1z + c2z) * 0.5,\n (c1x + c2x) * 0.5,\n (c1y + c2y) * 0.5\n ], this.board);\n }\n if (Type.isNumber(ev_a)) {\n return new Coords(Const.COORDS_BY_USER, [\n c1z + (c2z - c1z) * ev_a,\n c1x + (c2x - c1x) * ev_a,\n c1y + (c2y - c1y) * ev_a\n ], this.board);\n }\n return this.line.point1.coords;\n }\n mi = this.line.minX();\n ma = this.line.maxX();\n if (ev_a === 'right') {\n t = ma;\n } else if (ev_a === 'middle') {\n t = (mi + ma) * 0.5;\n } else if (Type.isNumber(ev_a)) {\n t = mi * (1 - ev_a) + ma * ev_a;\n // t = ev_a;\n } else {\n t = mi;\n }\n return t;\n },\n\n /**\n * Calculate the lower and upper bounds for tick rendering\n * If {@link JXG.Ticks#includeBoundaries} is false, the boundaries will exclude point1 and point2\n *\n * @param {JXG.Coords} coordsZero\n * @returns {String} type (Optional) If type=='ticksdistance' the bounds are\n * the intersection of the line with the bounding box of the board.\n * Otherwise, it is the projection of the corners of the bounding box\n * to the line. The first case is needed to automatically\n * generate ticks. The second case is for drawing of the ticks.\n * @returns {Object} contains the lower and upper bounds\n *\n * @private\n */\n getLowerAndUpperBounds: function (coordsZero, type) {\n var lowerBound, upperBound,\n fA, lA,\n point1, point2, isPoint1inBoard, isPoint2inBoard,\n // We use the distance from zero to P1 and P2 to establish lower and higher points\n dZeroPoint1, dZeroPoint2,\n ev_sf = Type.evaluate(this.line.visProp.straightfirst),\n ev_sl = Type.evaluate(this.line.visProp.straightlast),\n ev_i = Type.evaluate(this.visProp.includeboundaries);\n\n // The line's defining points that will be adjusted to be within the board limits\n if (this.line.elementClass === Const.OBJECT_CLASS_CURVE) {\n return {\n lower: this.line.minX(),\n upper: this.line.maxX()\n };\n }\n\n point1 = new Coords(Const.COORDS_BY_USER, this.line.point1.coords.usrCoords, this.board);\n point2 = new Coords(Const.COORDS_BY_USER, this.line.point2.coords.usrCoords, this.board);\n // Are the original defining points within the board?\n isPoint1inBoard = (Math.abs(point1.usrCoords[0]) >= Mat.eps &&\n point1.scrCoords[1] >= 0.0 && point1.scrCoords[1] <= this.board.canvasWidth &&\n point1.scrCoords[2] >= 0.0 && point1.scrCoords[2] <= this.board.canvasHeight);\n isPoint2inBoard = (Math.abs(point2.usrCoords[0]) >= Mat.eps &&\n point2.scrCoords[1] >= 0.0 && point2.scrCoords[1] <= this.board.canvasWidth &&\n point2.scrCoords[2] >= 0.0 && point2.scrCoords[2] <= this.board.canvasHeight);\n\n // Adjust line limit points to be within the board\n if (Type.exists(type) || type === 'tickdistance') {\n // The good old calcStraight is needed for determining the distance between major ticks.\n // Here, only the visual area is of importance\n Geometry.calcStraight(this.line, point1, point2, Type.evaluate(this.line.visProp.margin));\n } else {\n // This function projects the corners of the board to the line.\n // This is important for diagonal lines with infinite tick lines.\n Geometry.calcLineDelimitingPoints(this.line, point1, point2);\n }\n\n // Shorten ticks bounds such that ticks are not through arrow heads\n fA = Type.evaluate(this.line.visProp.firstarrow);\n lA = Type.evaluate(this.line.visProp.lastarrow);\n if (fA || lA) {\n this.board.renderer.getPositionArrowHead(this.line, point1, point2,\n Type.evaluate(this.line.visProp.strokewidth));\n\n if (fA) {\n point1.setCoordinates(Const.COORDS_BY_SCREEN, [\n point1.scrCoords[1],\n point1.scrCoords[2]\n ]);\n }\n if (lA) {\n point2.setCoordinates(Const.COORDS_BY_SCREEN, [\n point2.scrCoords[1],\n point2.scrCoords[2]\n ]);\n }\n // if (fA) {\n // point1.setCoordinates(Const.COORDS_BY_SCREEN, [\n // point1.scrCoords[1] - obj.d1x,\n // point1.scrCoords[2] - obj.d1y\n // ]);\n // }\n // if (lA) {\n // point2.setCoordinates(Const.COORDS_BY_SCREEN, [\n // point2.scrCoords[1] - obj.d2x,\n // point2.scrCoords[2] - obj.d2y\n // ]);\n // }\n }\n\n\n // Calculate (signed) distance from Zero to P1 and to P2\n dZeroPoint1 = this.getDistanceFromZero(coordsZero, point1);\n dZeroPoint2 = this.getDistanceFromZero(coordsZero, point2);\n\n // We have to establish if the direction is P1->P2 or P2->P1 to set the lower and upper\n // boundaries appropriately. As the distances contain also a sign to indicate direction,\n // we can compare dZeroPoint1 and dZeroPoint2 to establish the line direction\n if (dZeroPoint1 < dZeroPoint2) { // Line goes P1->P2\n lowerBound = dZeroPoint1;\n if (!ev_sf && isPoint1inBoard && !ev_i) {\n lowerBound += Mat.eps;\n }\n upperBound = dZeroPoint2;\n if (!ev_sl && isPoint2inBoard && !ev_i) {\n upperBound -= Mat.eps;\n }\n } else if (dZeroPoint2 < dZeroPoint1) { // Line goes P2->P1\n lowerBound = dZeroPoint2;\n if (!ev_sl && isPoint2inBoard && !ev_i) {\n lowerBound += Mat.eps;\n }\n upperBound = dZeroPoint1;\n if (!ev_sf && isPoint1inBoard && !ev_i) {\n upperBound -= Mat.eps;\n }\n } else { // P1 = P2 = Zero, we can't do a thing\n lowerBound = 0;\n upperBound = 0;\n }\n\n return {\n lower: lowerBound,\n upper: upperBound\n };\n },\n\n /**\n * Calculates the distance in user coordinates from zero to a given point including its sign.\n * Sign is positive, if the direction from zero to point is the same as the direction\n * zero to point2 of the line.\n *\n * @param {JXG.Coords} zero coordinates of the point considered zero\n * @param {JXG.Coords} point coordinates of the point to find out the distance\n * @returns {Number} distance between zero and point, including its sign\n * @private\n */\n getDistanceFromZero: function (zero, point) {\n var p1, p2,\n dirLine, dirPoint,\n distance;\n\n p1 = this.line.point1.coords;\n p2 = this.line.point2.coords;\n distance = zero.distance(Const.COORDS_BY_USER, point);\n\n // Establish sign\n dirLine = [p2.usrCoords[0] - p1.usrCoords[0],\n p2.usrCoords[1] - p1.usrCoords[1],\n p2.usrCoords[2] - p1.usrCoords[2]];\n dirPoint = [point.usrCoords[0] - zero.usrCoords[0],\n point.usrCoords[1] - zero.usrCoords[1],\n point.usrCoords[2] - zero.usrCoords[2]];\n if (Mat.innerProduct(dirLine, dirPoint, 3) < 0) {\n distance *= -1;\n }\n\n return distance;\n },\n\n /**\n * Creates ticks coordinates and labels automatically.\n * The frequency of ticks is affected by the values of {@link JXG.Ticks#insertTicks} and {@link JXG.Ticks#ticksDistance}\n *\n * @param {JXG.Coords} coordsZero coordinates of the point considered zero\n * @param {Object} bounds contains the lower and upper boundaries for ticks placement\n * @private\n */\n generateEquidistantTicks: function (coordsZero, bounds) {\n var tickPosition,\n eps2 = Mat.eps,\n deltas,\n // Distance between two major ticks in user coordinates\n ticksDelta = (this.equidistant ? this.ticksFunction(1) : this.ticksDelta),\n ev_it = Type.evaluate(this.visProp.insertticks),\n ev_mt = Type.evaluate(this.visProp.minorticks);\n\n if (this.line.elementClass === Const.OBJECT_CLASS_LINE) {\n // Calculate X and Y distance between two major ticks\n deltas = this.getXandYdeltas();\n }\n\n // adjust ticks distance\n ticksDelta *= Type.evaluate(this.visProp.scale);\n if (ev_it && this.minTicksDistance > Mat.eps) {\n ticksDelta = this.adjustTickDistance(ticksDelta, coordsZero, deltas);\n ticksDelta /= (ev_mt + 1);\n } else if (!ev_it) {\n ticksDelta /= (ev_mt + 1);\n }\n this.ticksDelta = ticksDelta;\n\n if (ticksDelta < Mat.eps) {\n return;\n }\n\n // Position ticks from zero to the positive side while not reaching the upper boundary\n tickPosition = 0;\n if (!Type.evaluate(this.visProp.drawzero)) {\n tickPosition = ticksDelta;\n }\n while (tickPosition <= bounds.upper + eps2) {\n // Only draw ticks when we are within bounds, ignore case where tickPosition < lower < upper\n if (tickPosition >= bounds.lower - eps2) {\n this.processTickPosition(coordsZero, tickPosition, ticksDelta, deltas);\n }\n tickPosition += ticksDelta;\n\n // Emergency out\n if ((bounds.upper - tickPosition) > ticksDelta * 10000) {\n break;\n }\n }\n\n // Position ticks from zero (not inclusive) to the negative side while not reaching the lower boundary\n tickPosition = -ticksDelta;\n while (tickPosition >= bounds.lower - eps2) {\n // Only draw ticks when we are within bounds, ignore case where lower < upper < tickPosition\n if (tickPosition <= bounds.upper + eps2) {\n this.processTickPosition(coordsZero, tickPosition, ticksDelta, deltas);\n }\n tickPosition -= ticksDelta;\n\n // Emergency out\n if ((tickPosition - bounds.lower) > ticksDelta * 10000) {\n break;\n }\n }\n },\n\n /**\n * Auxiliary method used by {@link JXG.Ticks#generateEquidistantTicks} to adjust the\n * distance between two ticks depending on {@link JXG.Ticks#minTicksDistance} value\n *\n * @param {Number} ticksDelta distance between two major ticks in user coordinates\n * @param {JXG.Coords} coordsZero coordinates of the point considered zero\n * @param {Object} deltas x and y distance in pixel between two user units\n * @param {Object} bounds upper and lower bound of the tick positions in user units.\n * @private\n */\n adjustTickDistance: function (ticksDelta, coordsZero, deltas) {\n var nx, ny, bounds,\n distScr,\n sgn = 1,\n ev_minti = Type.evaluate(this.visProp.minorticks);\n\n if (this.line.elementClass === Const.OBJECT_CLASS_CURVE) {\n return ticksDelta;\n }\n bounds = this.getLowerAndUpperBounds(coordsZero, 'ticksdistance');\n nx = coordsZero.usrCoords[1] + deltas.x * ticksDelta;\n ny = coordsZero.usrCoords[2] + deltas.y * ticksDelta;\n distScr = coordsZero.distance(Const.COORDS_BY_SCREEN, new Coords(Const.COORDS_BY_USER, [nx, ny], this.board));\n\n if (ticksDelta === 0.0) {\n return 0.0;\n }\n\n while (distScr / (ev_minti + 1) < this.minTicksDistance) {\n if (sgn === 1) {\n ticksDelta *= 2;\n } else {\n ticksDelta *= 5;\n }\n sgn *= -1;\n\n nx = coordsZero.usrCoords[1] + deltas.x * ticksDelta;\n ny = coordsZero.usrCoords[2] + deltas.y * ticksDelta;\n distScr = coordsZero.distance(Const.COORDS_BY_SCREEN, new Coords(Const.COORDS_BY_USER, [nx, ny], this.board));\n }\n return ticksDelta;\n },\n\n /**\n * Auxiliary method used by {@link JXG.Ticks#generateEquidistantTicks} to create a tick\n * in the line at the given tickPosition.\n *\n * @param {JXG.Coords} coordsZero coordinates of the point considered zero\n * @param {Number} tickPosition current tick position relative to zero\n * @param {Number} ticksDelta distance between two major ticks in user coordinates\n * @param {Object} deltas x and y distance between two major ticks\n * @private\n */\n processTickPosition: function (coordsZero, tickPosition, ticksDelta, deltas) {\n var x, y, tickCoords, ti,\n labelVal = null;\n\n // Calculates tick coordinates\n if (this.line.elementClass === Const.OBJECT_CLASS_LINE) {\n x = coordsZero.usrCoords[1] + tickPosition * deltas.x;\n y = coordsZero.usrCoords[2] + tickPosition * deltas.y;\n } else {\n x = this.line.X(coordsZero + tickPosition);\n y = this.line.Y(coordsZero + tickPosition);\n }\n tickCoords = new Coords(Const.COORDS_BY_USER, [x, y], this.board);\n if (this.line.elementClass === Const.OBJECT_CLASS_CURVE) {\n labelVal = coordsZero + tickPosition;\n this.setTicksSizeVariables(labelVal);\n\n }\n\n // Test if tick is a major tick.\n // This is the case if tickPosition/ticksDelta is\n // a multiple of the number of minorticks+1\n tickCoords.major = Math.round(tickPosition / ticksDelta) % (Type.evaluate(this.visProp.minorticks) + 1) === 0;\n\n // Compute the start position and the end position of a tick.\n // If both positions are out of the canvas, ti is empty.\n ti = this.createTickPath(tickCoords, tickCoords.major);\n if (ti.length === 3) {\n this.ticks.push(ti);\n if (tickCoords.major && Type.evaluate(this.visProp.drawlabels)) {\n // major tick label\n this.labelsData.push(\n this.generateLabelData(\n this.generateLabelText(tickCoords, coordsZero, labelVal),\n tickCoords,\n this.ticks.length\n )\n );\n } else {\n // minor ticks have no labels\n this.labelsData.push(null);\n }\n }\n },\n\n /**\n * Creates ticks coordinates and labels based on {@link JXG.Ticks#fixedTicks} and {@link JXG.Ticks#labels}.\n *\n * @param {JXG.Coords} coordsZero Coordinates of the point considered zero\n * @param {Object} bounds contains the lower and upper boundaries for ticks placement\n * @private\n */\n generateFixedTicks: function (coordsZero, bounds) {\n var tickCoords, labelText, i, ti,\n x, y,\n eps2 = Mat.eps, fixedTick,\n hasLabelOverrides = Type.isArray(this.visProp.labels),\n deltas,\n ev_dl = Type.evaluate(this.visProp.drawlabels);\n\n // Calculate X and Y distance between two major points in the line\n if (this.line.elementClass === Const.OBJECT_CLASS_LINE) {\n deltas = this.getXandYdeltas();\n }\n for (i = 0; i < this.fixedTicks.length; i++) {\n if (this.line.elementClass === Const.OBJECT_CLASS_LINE) {\n fixedTick = this.fixedTicks[i];\n x = coordsZero.usrCoords[1] + fixedTick * deltas.x;\n y = coordsZero.usrCoords[2] + fixedTick * deltas.y;\n } else {\n fixedTick = coordsZero + this.fixedTicks[i];\n x = this.line.X(fixedTick);\n y = this.line.Y(fixedTick);\n }\n tickCoords = new Coords(Const.COORDS_BY_USER, [x, y], this.board);\n\n if (this.line.elementClass === Const.OBJECT_CLASS_CURVE) {\n this.setTicksSizeVariables(fixedTick);\n }\n\n // Compute the start position and the end position of a tick.\n // If tick is out of the canvas, ti is empty.\n ti = this.createTickPath(tickCoords, true);\n if (ti.length === 3 && fixedTick >= bounds.lower - eps2 &&\n fixedTick <= bounds.upper + eps2) {\n this.ticks.push(ti);\n\n if (ev_dl &&\n (hasLabelOverrides || Type.exists(this.visProp.labels[i]))) {\n labelText = hasLabelOverrides ?\n Type.evaluate(this.visProp.labels[i]) : fixedTick;\n this.labelsData.push(\n this.generateLabelData(\n this.generateLabelText(tickCoords, coordsZero, labelText),\n tickCoords,\n i\n )\n );\n } else {\n this.labelsData.push(null);\n }\n }\n }\n },\n\n /**\n * Calculates the x and y distance in pixel between two units in user space.\n *\n * @returns {Object}\n * @private\n */\n getXandYdeltas: function () {\n var\n // Auxiliary points to store the start and end of the line according to its direction\n point1UsrCoords, point2UsrCoords,\n distP1P2 = this.line.point1.Dist(this.line.point2);\n\n if (this.line.type === Const.OBJECT_TYPE_AXIS) {\n // When line is an Axis, direction depends on Board Coordinates system\n\n // assume line.point1 and line.point2 are in correct order\n point1UsrCoords = this.line.point1.coords.usrCoords;\n point2UsrCoords = this.line.point2.coords.usrCoords;\n\n // Check if direction is incorrect, then swap\n if (point1UsrCoords[1] > point2UsrCoords[1] ||\n (Math.abs(point1UsrCoords[1] - point2UsrCoords[1]) < Mat.eps &&\n point1UsrCoords[2] > point2UsrCoords[2])) {\n point1UsrCoords = this.line.point2.coords.usrCoords;\n point2UsrCoords = this.line.point1.coords.usrCoords;\n }\n } else /* if (this.line.elementClass === Const.OBJECT_CLASS_LINE)*/ {\n // line direction is always from P1 to P2 for non Axis types\n point1UsrCoords = this.line.point1.coords.usrCoords;\n point2UsrCoords = this.line.point2.coords.usrCoords;\n }\n return {\n x: (point2UsrCoords[1] - point1UsrCoords[1]) / distP1P2,\n y: (point2UsrCoords[2] - point1UsrCoords[2]) / distP1P2\n };\n },\n\n /**\n * Check if (parts of) the tick is inside the canvas. The tick intersects the boundary\n * at two positions: [x[0], y[0]] and [x[1], y[1]] in screen coordinates.\n * @param {Array} x Array of length two\n * @param {Array} y Array of length two\n * @return {Boolean} true if parts of the tick are inside of the canvas or on the boundary.\n */\n _isInsideCanvas: function(x, y, m) {\n var cw = this.board.canvasWidth,\n ch = this.board.canvasHeight;\n\n if (m === undefined) {\n m = 0;\n }\n return (x[0] >= m && x[0] <= cw - m && y[0] >= m && y[0] <= ch - m) ||\n (x[1] >= m && x[1] <= cw - m && y[1] >= m && y[1] <= ch - m);\n },\n\n /**\n * @param {JXG.Coords} coords Coordinates of the tick on the line.\n * @param {Boolean} major True if tick is major tick.\n * @returns {Array} Array of length 3 containing path coordinates in screen coordinates\n * of the tick (arrays of length 2). 3rd entry is true if major tick otherwise false.\n * If the tick is outside of the canvas, the return array is empty.\n * @private\n */\n createTickPath: function (coords, major) {\n var c, lineStdForm, intersection,\n dxs, dys, dxr, dyr, alpha,\n style,\n x = [-2000000, -2000000],\n y = [-2000000, -2000000],\n i, r, r_max, bb, full, delta;\n\n c = coords.scrCoords;\n if (major) {\n dxs = this.dxMaj;\n dys = this.dyMaj;\n style = this.majStyle;\n } else {\n dxs = this.dxMin;\n dys = this.dyMin;\n style = this.minStyle;\n }\n lineStdForm = [-dys * c[1] - dxs * c[2], dys, dxs];\n\n // For all ticks regardless if of finite or infinite\n // tick length the intersection with the canvas border is\n // computed.\n if (major && Type.evaluate(this.visProp.type) === 'polar') {\n // polar style\n bb = this.board.getBoundingBox();\n full = 2.0 * Math.PI;\n delta = full / 180;\n //ratio = this.board.unitY / this.board.X;\n\n // usrCoords: Test if 'circle' is inside of the canvas\n c = coords.usrCoords;\n r = Math.sqrt(c[1] * c[1] + c[2] * c[2]);\n r_max = Math.max(Math.sqrt(bb[0] * bb[0] + bb[1] * bb[1]),\n Math.sqrt(bb[2] * bb[2] + bb[3] * bb[3]));\n\n if (r < r_max) {\n // Now, switch to screen coords\n x = [];\n y = [];\n for (i = 0; i <= full; i += delta) {\n x.push(this.board.origin.scrCoords[1] + r * Math.cos(i) * this.board.unitX);\n y.push(this.board.origin.scrCoords[2] + r * Math.sin(i) * this.board.unitY);\n }\n return [x, y, major];\n }\n\n } else {\n // line style\n if (style === 'infinite') {\n intersection = Geometry.meetLineBoard(lineStdForm, this.board);\n x[0] = intersection[0].scrCoords[1];\n x[1] = intersection[1].scrCoords[1];\n y[0] = intersection[0].scrCoords[2];\n y[1] = intersection[1].scrCoords[2];\n } else {\n if (Type.evaluate(this.visProp.face) === '>') {\n alpha = Math.PI/4;\n } else if (Type.evaluate(this.visProp.face) === '<') {\n alpha = -Math.PI/4;\n } else {\n alpha = 0;\n }\n dxr = Math.cos(alpha) * dxs - Math.sin(alpha) * dys;\n dyr = Math.sin(alpha) * dxs + Math.cos(alpha) * dys;\n\n x[0] = c[1] + dxr * Type.evaluate(this.visProp.tickendings[0]);\n y[0] = c[2] - dyr * Type.evaluate(this.visProp.tickendings[0]);\n x[1] = c[1];\n y[1] = c[2];\n\n alpha = -alpha;\n dxr = Math.cos(alpha) * dxs - Math.sin(alpha) * dys;\n dyr = Math.sin(alpha) * dxs + Math.cos(alpha) * dys;\n\n x[2] = c[1] - dxr * Type.evaluate(this.visProp.tickendings[1]);\n y[2] = c[2] + dyr * Type.evaluate(this.visProp.tickendings[1]);\n }\n\n // Check if (parts of) the tick is inside the canvas.\n if (this._isInsideCanvas(x, y)) {\n return [x, y, major];\n }\n }\n\n return [];\n },\n\n /**\n * Format label texts. Show the desired number of digits\n * and use utf-8 minus sign.\n * @param {Number} value Number to be displayed\n * @return {String} The value converted into a string.\n * @private\n */\n formatLabelText: function(value) {\n var labelText,\n digits,\n ev_s = Type.evaluate(this.visProp.scalesymbol);\n\n // if value is Number\n if (Type.isNumber(value)) {\n labelText = (Math.round(value * 1.e13) / 1.e13).toString();\n if (labelText.length > Type.evaluate(this.visProp.maxlabellength) ||\n labelText.indexOf('e') !== -1) {\n\n digits = Type.evaluate(this.visProp.digits);\n if (Type.evaluate(this.visProp.precision) !== 3 && digits === 3) {\n // Use the deprecated attribute \"precision\"\n digits = Type.evaluate(this.visProp.precision);\n }\n\n //labelText = value.toPrecision(digits).toString();\n labelText = value.toExponential(digits).toString();\n }\n\n if (Type.evaluate(this.visProp.beautifulscientificticklabels)) {\n labelText = this.beautifyScientificNotationLabel(labelText);\n }\n\n if (labelText.indexOf('.') > -1 && labelText.indexOf('e') === -1) {\n // trim trailing zeros\n labelText = labelText.replace(/0+$/, '');\n // trim trailing .\n labelText = labelText.replace(/\\.$/, '');\n }\n } else {\n labelText = value.toString();\n }\n\n if (ev_s.length > 0) {\n if (labelText === '1') {\n labelText = ev_s;\n } else if (labelText === '-1') {\n labelText = '-' + ev_s;\n } else if (labelText !== '0') {\n labelText = labelText + ev_s;\n }\n }\n\n if (Type.evaluate(this.visProp.useunicodeminus)) {\n labelText = labelText.replace(/-/g, '\\u2212');\n }\n return labelText;\n },\n\n /**\n * Formats label texts to make labels displayed in scientific notation look beautiful.\n * For example, label 5.00e+6 will become 5•10⁶, label -1.00e-7 will become into -1•10⁻⁷\n * @param {String} labelText - The label that we want to convert\n * @returns {String} If labelText was not in scientific notation, return labelText without modifications.\n * Otherwise returns beautified labelText with proper superscript notation.\n */\n beautifyScientificNotationLabel: function(labelText) {\n var returnString;\n\n if (labelText.indexOf('e') === -1) {\n return labelText;\n }\n\n // Clean up trailing 0's, so numbers like 5.00e+6.0 for example become into 5e+6\n returnString = parseFloat(labelText.substring(0, labelText.indexOf('e'))) +\n labelText.substring(labelText.indexOf('e'));\n\n // Replace symbols like -,0,1,2,3,4,5,6,7,8,9 with their superscript version.\n // Gets rid of + symbol since there is no need for it anymore.\n returnString = returnString.replace(/e(.*)$/g, function(match,$1){\n var temp = '\\u2022' + '10';\n // Note: Since board ticks do not support HTTP elements like <sub>, we need to replace\n // all the numbers with superscript Unicode characters.\n temp += $1\n .replace(/-/g, \"\\u207B\")\n .replace(/\\+/g, '')\n .replace(/0/g,'\\u2070')\n .replace(/1/g,'\\u00B9')\n .replace(/2/g,'\\u00B2')\n .replace(/3/g,'\\u00B3')\n .replace(/4/g,'\\u2074')\n .replace(/5/g,'\\u2075')\n .replace(/6/g,'\\u2076')\n .replace(/7/g,'\\u2077')\n .replace(/8/g,'\\u2078')\n .replace(/9/g,'\\u2079');\n\n return temp;\n });\n\n return returnString;\n },\n\n /**\n * Creates the label text for a given tick. A value for the text can be provided as a number or string\n *\n * @param {JXG.Coords} tick The Coords-object of the tick to create a label for\n * @param {JXG.Coords} zero The Coords-object of line's zero\n * @param {Number|String} value A predefined value for this tick\n * @returns {String}\n * @private\n */\n generateLabelText: function (tick, zero, value) {\n var labelText, distance;\n\n // No value provided, equidistant, so assign distance as value\n if (!Type.exists(value)) { // could be null or undefined\n distance = this.getDistanceFromZero(zero, tick);\n if (Math.abs(distance) < Mat.eps) { // Point is zero\n return '0';\n }\n value = distance / Type.evaluate(this.visProp.scale);\n }\n labelText = this.formatLabelText(value);\n\n return labelText;\n },\n\n /**\n * Create a tick label data, i.e. text and coordinates\n * @param {String} labelText\n * @param {JXG.Coords} tick\n * @param {Number} tickNumber\n * @returns {Object} with properties 'x', 'y', 't' (text), 'i' (tick number) or null in case of o label\n * @private\n */\n generateLabelData: function (labelText, tick, tickNumber) {\n var xa, ya, m, fs;\n\n // Test if large portions of the label are inside of the canvas\n // This is the last chance to abandon the creation of the label if it is mostly\n // outside of the canvas.\n fs = Type.evaluate(this.visProp.label.fontsize);\n xa = [tick.scrCoords[1], tick.scrCoords[1]];\n ya = [tick.scrCoords[2], tick.scrCoords[2]];\n m = (fs === undefined) ? 12 : fs;\n m *= 0.5;\n if (!this._isInsideCanvas(xa, ya, m)) {\n return null;\n }\n\n xa = Type.evaluate(this.visProp.label.offset[0]);\n ya = Type.evaluate(this.visProp.label.offset[1]);\n\n return {\n x: tick.usrCoords[1] + xa / (this.board.unitX),\n y: tick.usrCoords[2] + ya / (this.board.unitY),\n t: labelText,\n i: tickNumber\n };\n },\n\n /**\n * Recalculate the tick positions and the labels.\n * @returns {JXG.Ticks}\n */\n update: function () {\n if (this.needsUpdate) {\n //this.visPropCalc.visible = Type.evaluate(this.visProp.visible);\n // A canvas with no width or height will create an endless loop, so ignore it\n if (this.board.canvasWidth !== 0 && this.board.canvasHeight !== 0) {\n this.calculateTicksCoordinates();\n }\n // this.updateVisibility(this.line.visPropCalc.visible);\n //\n // for (var i = 0; i < this.labels.length; i++) {\n // if (this.labels[i] !== null) {\n // this.labels[i].prepareUpdate()\n // .updateVisibility(this.line.visPropCalc.visible)\n // .updateRenderer();\n // }\n // }\n }\n\n return this;\n },\n\n /**\n * Uses the boards renderer to update the arc.\n * @returns {JXG.Ticks} Reference to the object.\n */\n updateRenderer: function () {\n if (!this.needsUpdate) {\n return this;\n }\n\n if (this.visPropCalc.visible) {\n this.board.renderer.updateTicks(this);\n }\n this.updateRendererLabels();\n\n this.setDisplayRendNode();\n // if (this.visPropCalc.visible != this.visPropOld.visible) {\n // this.board.renderer.display(this, this.visPropCalc.visible);\n // this.visPropOld.visible = this.visPropCalc.visible;\n // }\n\n this.needsUpdate = false;\n return this;\n },\n\n /**\n * Updates the label elements of the major ticks.\n *\n * @private\n * @returns {JXG.Ticks} Reference to the object.\n */\n updateRendererLabels: function() {\n var i, j,\n lenData, lenLabels,\n attr,\n label, ld,\n visible;\n\n // The number of labels needed\n lenData = this.labelsData.length;\n // The number of labels which already exist\n // The existing labels are stored in this.labels[]\n // The new label positions and label values are stored in this.labelsData[]\n lenLabels = this.labels.length;\n\n for (i = 0, j = 0; i < lenData; i++) {\n if (this.labelsData[i] === null) {\n // This is a tick without label\n continue;\n }\n\n ld = this.labelsData[i];\n if (j < lenLabels) {\n // Take an already existing text element\n label = this.labels[j];\n label.setText(ld.t);\n label.setCoords(ld.x, ld.y);\n j++;\n } else {\n // A new text element is needed\n this.labelCounter += 1;\n\n attr = {\n isLabel: true,\n layer: this.board.options.layer.line,\n highlightStrokeColor: this.board.options.text.strokeColor,\n highlightStrokeWidth: this.board.options.text.strokeWidth,\n highlightStrokeOpacity: this.board.options.text.strokeOpacity,\n priv: this.visProp.priv\n };\n attr = Type.deepCopy(attr, this.visProp.label);\n attr.id = this.id + ld.i + 'Label' + this.labelCounter;\n\n label = Text.createText(this.board, [ld.x, ld.y, ld.t], attr);\n this.addChild(label);\n label.setParents(this);\n label.isDraggable = false;\n label.dump = false;\n this.labels.push(label);\n }\n\n // Look-ahead if the label inherits visiblity.\n // If yes, update label.\n visible = Type.evaluate(this.visProp.label.visible);\n if (visible === 'inherit') {\n visible = this.visPropCalc.visible;\n }\n\n label.prepareUpdate()\n .updateVisibility(visible)\n .updateRenderer();\n\n label.distanceX = Type.evaluate(this.visProp.label.offset[0]);\n label.distanceY = Type.evaluate(this.visProp.label.offset[1]);\n }\n\n // Hide unused labels\n lenData = j;\n for (j = lenData; j < lenLabels; j++) {\n this.board.renderer.display(this.labels[j], false);\n // Tick labels have the attribute \"visible: 'inherit'\"\n // This must explicitely set to false, otherwise\n // this labels would be set to visible in the upcoming\n // update of the labels.\n this.labels[j].visProp.visible = this.labels[j].visPropCalc.visible = false;\n }\n\n return this;\n },\n\n hideElement: function () {\n var i;\n\n JXG.deprecated('Element.hideElement()', 'Element.setDisplayRendNode()');\n\n this.visPropCalc.visible = false;\n this.board.renderer.display(this, false);\n for (i = 0; i < this.labels.length; i++) {\n if (Type.exists(this.labels[i])) {\n this.labels[i].hideElement();\n }\n }\n\n return this;\n },\n\n showElement: function () {\n var i;\n\n JXG.deprecated('Element.showElement()', 'Element.setDisplayRendNode()');\n\n this.visPropCalc.visible = true;\n this.board.renderer.display(this, false);\n\n for (i = 0; i < this.labels.length; i++) {\n if (Type.exists(this.labels[i])) {\n this.labels[i].showElement();\n }\n }\n\n return this;\n }\n });\n\n /**\n * @class Ticks are used as distance markers on a line or curve.\n * They are\n * mainly used for axis elements and slider elements. Ticks may stretch infinitely\n * or finitely, which can be set with {@link Ticks#majorHeight} and {@link Ticks#minorHeight}.\n *\n * @pseudo\n * @description Ticks are markers on straight line elements or curves.\n * @name Ticks\n * @augments JXG.Ticks\n * @constructor\n * @type JXG.Ticks\n * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {JXG.Line|JXG.Curve} line The parents consist of the line or curve the ticks are going to be attached to.\n * @param {Number|Array} distance Number defining the distance between two major ticks or an\n * array defining static ticks. In case a number is specified, the ticks are <i>equidistant</i>,\n * in case of an array, a fixed number of static ticks is created at user-supplied positions.\n * Alternatively, the distance can be specified with the attribute\n * \"ticksDistance\". For arbitrary lines (and not axes) a \"zero coordinate\" is determined\n * which defines where the first tick is positioned. This zero coordinate\n * can be altered with the attribute \"anchor\". Possible values are \"left\", \"middle\", \"right\" or a number.\n * The default value is \"left\".\n *\n * @example\n * // Create an axis providing two coordinate pairs.\n * var p1 = board.create('point', [0, 3]);\n * var p2 = board.create('point', [1, 3]);\n * var l1 = board.create('line', [p1, p2]);\n * var t = board.create('ticks', [l1], {ticksDistance: 2});\n * </pre><div class=\"jxgbox\" id=\"JXGee7f2d68-75fc-4ec0-9931-c76918427e63\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function () {\n * var board = JXG.JSXGraph.initBoard('JXGee7f2d68-75fc-4ec0-9931-c76918427e63', {boundingbox: [-1, 7, 7, -1], showcopyright: false, shownavigation: false});\n * var p1 = board.create('point', [0, 3]);\n * var p2 = board.create('point', [1, 3]);\n * var l1 = board.create('line', [p1, p2]);\n * var t = board.create('ticks', [l1, 2], {ticksDistance: 2});\n * })();\n * </script><pre>\n */\n JXG.createTicks = function (board, parents, attributes) {\n var el, dist,\n attr = Type.copyAttributes(attributes, board.options, 'ticks');\n\n if (parents.length < 2) {\n dist = attr.ticksdistance;\n } else {\n dist = parents[1];\n }\n\n if (parents[0].elementClass === Const.OBJECT_CLASS_LINE ||\n parents[0].elementClass === Const.OBJECT_CLASS_CURVE) {\n el = new JXG.Ticks(parents[0], dist, attr);\n } else {\n throw new Error(\"JSXGraph: Can't create Ticks with parent types '\" + (typeof parents[0]) + \"'.\");\n }\n\n // deprecated\n if (Type.isFunction(attr.generatelabelvalue)) {\n el.generateLabelText = attr.generatelabelvalue;\n }\n if (Type.isFunction(attr.generatelabeltext)) {\n el.generateLabelText = attr.generatelabeltext;\n }\n\n el.setParents(parents[0]);\n el.isDraggable = true;\n el.fullUpdate(parents[0].visPropCalc.visible);\n\n return el;\n };\n\n /**\n * @class Hatches can be used to mark congruent lines or curves.\n * @pseudo\n * @description\n * @name Hatch\n * @augments JXG.Ticks\n * @constructor\n * @type JXG.Ticks\n * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {JXG.Line|JXG.curve} line The line or curve the hatch marks are going to be attached to.\n * @param {Number} numberofhashes Number of dashes.\n * @example\n * // Create an axis providing two coords pairs.\n * var p1 = board.create('point', [0, 3]);\n * var p2 = board.create('point', [1, 3]);\n * var l1 = board.create('line', [p1, p2]);\n * var t = board.create('hatch', [l1, 3]);\n * </pre><div class=\"jxgbox\" id=\"JXG4a20af06-4395-451c-b7d1-002757cf01be\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function () {\n * var board = JXG.JSXGraph.initBoard('JXG4a20af06-4395-451c-b7d1-002757cf01be', {boundingbox: [-1, 7, 7, -1], showcopyright: false, shownavigation: false});\n * var p1 = board.create('point', [0, 3]);\n * var p2 = board.create('point', [1, 3]);\n * var l1 = board.create('line', [p1, p2]);\n * var t = board.create('hatch', [l1, 3]);\n * })();\n * </script><pre>\n *\n * @example\n * // Alter the position of the hatch\n *\n * var p = board.create('point', [-5, 0]);\n * var q = board.create('point', [5, 0]);\n * var li = board.create('line', [p, q]);\n * var h = board.create('hatch', [li, 2], {anchor: 0.2});\n *\n * </pre><div id=\"JXG05d720ee-99c9-11e6-a9c7-901b0e1b8723\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG05d720ee-99c9-11e6-a9c7-901b0e1b8723',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n *\n * var p = board.create('point', [-5, 0]);\n * var q = board.create('point', [5, 0]);\n * var li = board.create('line', [p, q]);\n * var h = board.create('hatch', [li, 2], {anchor: 0.2});\n *\n * })();\n *\n * </script><pre>\n *\n * @example\n * // Alternative hatch faces\n *\n * var li = board.create('line', [[-6,0], [6,3]]);\n * var h1 = board.create('hatch', [li, 2], {tickEndings: [1,1], face:'|'});\n * var h2 = board.create('hatch', [li, 2], {tickEndings: [1,1], face:'>', anchor: 0.3});\n * var h3 = board.create('hatch', [li, 2], {tickEndings: [1,1], face:'<', anchor: 0.7});\n *\n * </pre><div id=\"JXG974f7e89-eac8-4187-9aa3-fb8068e8384b\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG974f7e89-eac8-4187-9aa3-fb8068e8384b',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * // Alternative hatch faces\n *\n * var li = board.create('line', [[-6,0], [6,3]]);\n * var h1 = board.create('hatch', [li, 2], {tickEndings: [1,1], face:'|'});\n * var h2 = board.create('hatch', [li, 2], {tickEndings: [1,1], face:'>', anchor: 0.3});\n * var h3 = board.create('hatch', [li, 2], {tickEndings: [1,1], face:'<', anchor: 0.7});\n *\n * })();\n *\n * </script><pre>\n *\n */\n JXG.createHatchmark = function (board, parents, attributes) {\n var num, i, base, width, totalwidth, el,\n pos = [],\n attr = Type.copyAttributes(attributes, board.options, 'hatch');\n\n if ((parents[0].elementClass !== Const.OBJECT_CLASS_LINE &&\n parents[0].elementClass !== Const.OBJECT_CLASS_CURVE) || typeof parents[1] !== 'number') {\n throw new Error(\"JSXGraph: Can't create Hatch mark with parent types '\" + (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \" and ''\" + (typeof parents[2]) + \"'.\");\n }\n\n num = parents[1];\n width = attr.ticksdistance;\n totalwidth = (num - 1) * width;\n base = -totalwidth * 0.5;\n\n for (i = 0; i < num; i++) {\n pos[i] = base + i * width;\n }\n\n el = board.create('ticks', [parents[0], pos], attr);\n el.elType = 'hatch';\n\n return el;\n };\n\n JXG.registerElement('ticks', JXG.createTicks);\n JXG.registerElement('hash', JXG.createHatchmark);\n JXG.registerElement('hatch', JXG.createHatchmark);\n\n return {\n Ticks: JXG.Ticks,\n createTicks: JXG.createTicks,\n createHashmark: JXG.createHatchmark,\n createHatchmark: JXG.createHatchmark\n };\n});\n\n/*\n JessieCode Computer algebra algorithms\n\n Copyright 2011-2019\n Michael Gerhaeuser,\n Alfred Wassermann\n\n JessieCode is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JessieCode is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JessieCode. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n/*global JXG: true, define: true, window: true, console: true, self: true, document: true, parser: true*/\n/*jslint nomen: true, plusplus: true*/\n/*eslint eqeqeq: \"off\"*/\n\n/* depends:\n jxg\n parser/geonext\n base/constants\n base/text\n math/math\n math/geometry\n math/statistics\n utils/type\n utils/uuid\n */\n\n/**\n * @fileoverview Here, the computer algebra algorithms are implemented.\n */\n\ndefine('parser/ca',[\n 'jxg', 'base/constants', 'base/text', 'math/math', 'math/geometry', 'math/statistics', 'utils/type', 'utils/env'\n], function (JXG, Const, Text, Mat, Geometry, Statistics, Type, Env) {\n\n \"use strict\";\n\n /**\n * A JessieCode object provides an interface to the parser and stores all variables and objects used within a JessieCode script.\n * The optional argument <tt>code</tt> is interpreted after initializing. To evaluate more code after initializing a JessieCode instance\n * please use {@link JXG.JessieCode#parse}. For code snippets like single expressions use {@link JXG.JessieCode#snippet}.\n * @constructor\n * @param {String} [code] Code to parse.\n * @param {Boolean} [geonext=false] Geonext compatibility mode.\n */\n JXG.CA = function (node, createNode, parser) {\n this.node = node;\n this.createNode = createNode;\n this.parser = parser;\n };\n\n JXG.extend(JXG.CA.prototype, /** @lends JXG.CA.prototype */ {\n findMapNode: function (mapname, node) {\n var i, len, ret;\n\n //console.log(\"FINDMAP\", node);\n if (node.value === 'op_assign' && node.children[0].value === mapname) {\n return node.children[1];\n } else if (node.children) {\n len = node.children.length;\n for (i = 0; i < len; ++i) {\n ret = this.findMapNode(mapname, node.children[i]);\n if (ret !== null) {\n return ret;\n }\n }\n }\n return null;\n },\n\n /**\n * Declare all subnodes as math nodes,\n * i.e recursively set node.isMath = true;\n */\n setMath: function (node) {\n var i, len;\n\n if ((node.type == 'node_op' && (\n node.value == 'op_add' || node.value == 'op_sub' ||\n node.value == 'op_mul' || node.value == 'op_div' ||\n node.value == 'op_neg' || node.value == 'op_execfun' ||\n node.value == 'op_exp')) ||\n node.type == 'node_var' || node.type == 'node_const') {\n\n node.isMath = true;\n }\n if (node.children) {\n len = node.children.length;\n for (i = 0; i < len; ++i) {\n this.setMath(node.children[i]);\n }\n }\n },\n\n deriveElementary: function (node, varname) {\n var fun = node.children[0].value,\n arg = node.children[1],\n newNode;\n\n\n switch (fun) {\n case 'abs':\n // x / sqrt(x * x)\n newNode = this.createNode('node_op', 'op_div',\n arg[0],\n this.createNode('node_op', 'op_execfun',\n this.createNode('node_var', 'sqrt'),\n [this.createNode('node_op', 'op_mul',\n Type.deepCopy(arg[0]),\n Type.deepCopy(arg[0])\n )]\n )\n );\n break;\n\n case 'sqrt':\n newNode = this.createNode('node_op', 'op_div',\n this.createNode('node_const', 1.0),\n this.createNode('node_op', 'op_mul',\n this.createNode('node_const', 2.0),\n this.createNode(node.type, node.value,\n Type.deepCopy(node.children[0]),\n Type.deepCopy(node.children[1])\n )\n )\n );\n break;\n\n case 'sin':\n newNode = this.createNode('node_op', 'op_execfun',\n this.createNode('node_var', 'cos'),\n Type.deepCopy(arg)\n );\n break;\n\n case 'cos':\n newNode = this.createNode('node_op', 'op_neg',\n this.createNode('node_op', 'op_execfun',\n this.createNode('node_var', 'sin'),\n Type.deepCopy(arg)\n )\n );\n break;\n\n case 'tan':\n newNode = this.createNode('node_op', 'op_div',\n this.createNode('node_const', 1.0),\n this.createNode('node_op', 'op_exp',\n this.createNode('node_op', 'op_execfun',\n this.createNode('node_var', 'cos'),\n Type.deepCopy(arg)\n ),\n this.createNode('node_const', 2)\n )\n );\n break;\n\n case 'cot':\n newNode = this.createNode('node_op', 'op_neg',\n this.createNode('node_op', 'op_div',\n this.createNode('node_const', 1.0),\n this.createNode('node_op', 'op_exp',\n this.createNode('node_op', 'op_execfun',\n this.createNode('node_var', 'sin'),\n Type.deepCopy(arg)\n ),\n this.createNode('node_const', 2)\n )\n )\n );\n break;\n\n case 'exp':\n newNode = this.createNode(node.type, node.value,\n Type.deepCopy(node.children[0]),\n Type.deepCopy(node.children[1])\n );\n break;\n\n case 'pow':\n // (f^g)' = f^g*(f'g/f + g' log(f))\n newNode = this.createNode('node_op', 'op_mul',\n this.createNode('node_op', 'op_execfun',\n Type.deepCopy(node.children[0]),\n Type.deepCopy(node.children[1])\n ),\n this.createNode('node_op', 'op_add',\n this.createNode('node_op', 'op_mul',\n this.derivative(node.children[1][0], varname),\n this.createNode('node_op', 'op_div',\n Type.deepCopy(node.children[1][1]),\n Type.deepCopy(node.children[1][0])\n )\n ),\n this.createNode('node_op', 'op_mul',\n this.derivative(node.children[1][1], varname),\n this.createNode('node_op', 'op_execfun',\n this.createNode('node_var', 'log'),\n [Type.deepCopy(node.children[1][0])]\n )\n )\n )\n );\n break;\n\n case 'log':\n case 'ln':\n newNode = this.createNode('node_op', 'op_div',\n this.createNode('node_const', 1.0),\n // Attention: single variable mode\n Type.deepCopy(arg[0])\n );\n break;\n\n case 'log2':\n case 'lb':\n case 'ld':\n newNode = this.createNode('node_op', 'op_mul',\n this.createNode('node_op', 'op_div',\n this.createNode('node_const', 1.0),\n // Attention: single variable mode\n Type.deepCopy(arg[0])\n ),\n this.createNode('node_const', 1.4426950408889634) // 1/log(2)\n );\n break;\n\n case 'log10':\n case 'lg':\n newNode = this.createNode('node_op', 'op_mul',\n this.createNode('node_op', 'op_div',\n this.createNode('node_const', 1.0),\n // Attention: single variable mode\n Type.deepCopy(arg[0])\n ),\n this.createNode('node_const', 0.43429448190325176) // 1/log(10)\n );\n break;\n\n case 'asin':\n newNode = this.createNode('node_op', 'op_div',\n this.createNode('node_const', 1.0),\n this.createNode('node_op', 'op_execfun',\n this.createNode('node_var', 'sqrt'),\n [\n this.createNode('node_op', 'op_sub',\n this.createNode('node_const', 1.0),\n this.createNode('node_op', 'op_mul',\n Type.deepCopy(arg[0]),\n Type.deepCopy(arg[0])\n )\n )\n ]\n )\n );\n break;\n\n case 'acos':\n newNode = this.createNode('node_op', 'op_neg',\n this.createNode('node_op', 'op_div',\n this.createNode('node_const', 1.0),\n this.createNode('node_op', 'op_execfun',\n this.createNode('node_var', 'sqrt'),\n [\n this.createNode('node_op', 'op_sub',\n this.createNode('node_const', 1.0),\n this.createNode('node_op', 'op_mul',\n Type.deepCopy(arg[0]),\n Type.deepCopy(arg[0])\n )\n )\n ]\n )\n )\n );\n break;\n\n //case 'atan2':\n\n case 'atan':\n newNode = this.createNode('node_op', 'op_div',\n this.createNode('node_const', 1.0),\n this.createNode('node_op', 'op_add',\n this.createNode('node_const', 1.0),\n this.createNode('node_op', 'op_mul',\n Type.deepCopy(arg[0]),\n Type.deepCopy(arg[0])\n )\n )\n );\n break;\n\n case 'acot':\n newNode = this.createNode('node_op', 'op_neg',\n this.createNode('node_op', 'op_div',\n this.createNode('node_const', 1.0),\n this.createNode('node_op', 'op_add',\n this.createNode('node_const', 1.0),\n this.createNode('node_op', 'op_mul',\n Type.deepCopy(arg[0]),\n Type.deepCopy(arg[0])\n )\n )\n )\n );\n break;\n\n case 'sinh':\n newNode = this.createNode('node_op', 'op_execfun',\n this.createNode('node_var', 'cosh'),\n [Type.deepCopy(arg[0])]\n );\n break;\n\n case 'cosh':\n newNode = this.createNode('node_op', 'op_execfun',\n this.createNode('node_var', 'sinh'),\n [Type.deepCopy(arg[0])]\n );\n break;\n\n case 'tanh':\n newNode = this.createNode('node_op', 'op_sub',\n this.createNode('node_const', 1.0),\n this.createNode('node_op', 'op_exp',\n this.createNode('node_op', 'op_execfun',\n this.createNode('node_var', 'tanh'),\n [Type.deepCopy(arg[0])]\n ),\n this.createNode('node_const', 2.0)\n )\n );\n break;\n\n case 'asinh':\n newNode = this.createNode('node_op', 'op_div',\n this.createNode('node_const', 1.0),\n this.createNode('node_op', 'op_execfun',\n this.createNode('node_var', 'sqrt'),\n [\n this.createNode('node_op', 'op_add',\n this.createNode('node_op', 'op_mul',\n Type.deepCopy(arg[0]),\n Type.deepCopy(arg[0])\n ),\n this.createNode('node_const', 1.0)\n )\n ]\n )\n );\n break;\n\n case 'acosh':\n newNode = this.createNode('node_op', 'op_div',\n this.createNode('node_const', 1.0),\n this.createNode('node_op', 'op_execfun',\n this.createNode('node_var', 'sqrt'),\n [\n this.createNode('node_op', 'op_sub',\n this.createNode('node_op', 'op_mul',\n Type.deepCopy(arg[0]),\n Type.deepCopy(arg[0])\n ),\n this.createNode('node_const', 1.0)\n )\n ]\n )\n );\n break;\n\n case 'atanh':\n newNode = this.createNode('node_op', 'op_div',\n this.createNode('node_const', 1.0),\n this.createNode('node_op', 'op_sub',\n this.createNode('node_const', 1.0),\n this.createNode('node_op', 'op_mul',\n Type.deepCopy(arg[0]),\n Type.deepCopy(arg[0])\n )\n )\n );\n break;\n\n default:\n newNode = this.createNode('node_const', 0.0);\n console.log('Derivative of \"' + fun + '\" not yet implemented');\n throw new Error('Error(' + this.line + '): ');\n // this._error('Derivative of \"' + fun + '\" not yet implemented');\n\n }\n\n return newNode;\n },\n\n derivative: function (node, varname) {\n var newNode;\n\n switch (node.type) {\n case 'node_op':\n switch (node.value) {\n /*\n case 'op_map':\n if (true) {\n newNode = this.createNode('node_op', 'op_map',\n Type.deepCopy(node.children[0]),\n this.derivative(node.children[1], varname)\n );\n } else {\n newNode = this.derivative(node.children[1], varname);\n }\n break;\n */\n case 'op_execfun':\n // f'(g(x))g'(x)\n if (node.children[0].value == 'pow') {\n newNode = this.deriveElementary(node, varname);\n } else {\n if (node.children[1].length === 0) {\n newNode = this.createNode('node_const', 0.0);\n } else {\n newNode = this.createNode('node_op', 'op_mul',\n this.deriveElementary(node, varname),\n // Warning: single variable mode\n this.derivative(node.children[1][0], varname)\n );\n }\n }\n break;\n\n case 'op_div':\n // (f'g − g'f )/(g*g)\n newNode = this.createNode('node_op', 'op_div',\n this.createNode('node_op', 'op_sub',\n this.createNode('node_op', 'op_mul',\n this.derivative(node.children[0], varname),\n Type.deepCopy(node.children[1])\n ),\n this.createNode('node_op', 'op_mul',\n Type.deepCopy(node.children[0]),\n this.derivative(node.children[1], varname)\n )\n ),\n this.createNode('node_op', 'op_mul',\n Type.deepCopy(node.children[1]),\n Type.deepCopy(node.children[1])\n )\n );\n break;\n\n case 'op_mul':\n // fg' + f'g\n newNode = this.createNode('node_op', 'op_add',\n this.createNode('node_op', 'op_mul',\n Type.deepCopy(node.children[0]),\n this.derivative(node.children[1], varname)),\n this.createNode('node_op', 'op_mul',\n this.derivative(node.children[0], varname),\n Type.deepCopy(node.children[1]))\n );\n break;\n\n case 'op_neg':\n newNode = this.createNode('node_op', 'op_neg',\n this.derivative(node.children[0], varname)\n );\n break;\n\n case 'op_add':\n case 'op_sub':\n newNode = this.createNode('node_op', node.value,\n this.derivative(node.children[0], varname),\n this.derivative(node.children[1], varname)\n );\n break;\n\n case 'op_exp':\n // (f^g)' = f^g*(f'g/f + g' log(f))\n newNode = this.createNode('node_op', 'op_mul',\n Type.deepCopy(node),\n this.createNode('node_op', 'op_add',\n this.createNode('node_op', 'op_mul',\n this.derivative(node.children[0], varname),\n this.createNode('node_op', 'op_div',\n Type.deepCopy(node.children[1]),\n Type.deepCopy(node.children[0])\n )\n ),\n this.createNode('node_op', 'op_mul',\n this.derivative(node.children[1], varname),\n this.createNode('node_op', 'op_execfun',\n this.createNode('node_var', 'log'),\n [Type.deepCopy(node.children[0])]\n )\n )\n )\n );\n break;\n }\n break;\n\n case 'node_var':\n //console.log('node_var', node);\n if (node.value === varname) {\n newNode = this.createNode('node_const', 1.0);\n } else {\n newNode = this.createNode('node_const', 0.0);\n }\n break;\n\n case 'node_const':\n newNode = this.createNode('node_const', 0.0);\n break;\n\n case 'node_const_bool':\n break;\n\n case 'node_str':\n break;\n\n }\n\n return newNode;\n },\n\n /**\n * f = map (x) -> x*sin(x);\n * Usages:\n * h = D(f, x);\n * h = map (x) -> D(f, x);\n *\n */\n expandDerivatives: function (node, parent, ast) {\n var len, i, j, mapNode, codeNode, ret, node2, newNode,\n mapName, varname, vArray, order;\n\n ret = 0;\n if (!node) {\n return ret;\n }\n\n this.line = node.line;\n this.col = node.col;\n\n // First we have to go down in the tree.\n // This ensures that in cases like D(D(f,x),x) the inner D is expanded first.\n len = node.children.length;\n for (i = 0; i < len; ++i) {\n if (node.children[i] && node.children[i].type) {\n node.children[i] = this.expandDerivatives(node.children[i], node, ast);\n } else if (Type.isArray(node.children[i])) {\n for (j = 0; j < node.children[i].length; ++j) {\n if (node.children[i][j] && node.children[i][j].type) {\n node.children[i][j] = this.expandDerivatives(node.children[i][j], node, ast);\n }\n }\n }\n }\n\n switch (node.type) {\n case 'node_op':\n switch (node.value) {\n case 'op_execfun':\n if (node.children[0] && node.children[0].value === 'D') {\n if (node.children[1][0].type == 'node_var') {\n /*\n * Derive map, that is compute D(f,x)\n * where e.g. f = map (x) -> x^2\n *\n * First step: find node where the map is defined\n */\n mapName = node.children[1][0].value;\n mapNode = this.findMapNode(mapName, ast);\n vArray = mapNode.children[0];\n\n // Variable name for differentiation\n if (node.children[1].length >= 2) {\n varname = node.children[1][1].value;\n } else {\n varname = mapNode.children[0][0]; // Usually it's 'x'\n }\n codeNode = mapNode.children[1];\n } else {\n /*\n * Derive expression, e.g.\n * D(2*x, x)\n */\n codeNode = node.children[1][0];\n vArray = ['x'];\n\n // Variable name for differentiation and order\n if (node.children[1].length >= 2) {\n varname = node.children[1][1].value;\n } else {\n varname = 'x';\n }\n }\n\n // Differentiation order\n if (node.children[1].length >= 3) {\n order = node.children[1][2].value;\n } else {\n order = 1;\n }\n\n // Create node which contains the derivative\n newNode = codeNode;\n //newNode = this.removeTrivialNodes(newNode);\n if (order >= 1) {\n while (order >= 1) {\n newNode = this.derivative(newNode, varname);\n newNode = this.removeTrivialNodes(newNode);\n order--;\n }\n }\n\n // Replace the node containing e.g. D(f,x) by the derivative.\n if (parent.type == 'node_op' && parent.value == 'op_assign') {\n // If D is an assignment it has to be replaced by a map\n // h = D(f, x)\n node2 = this.createNode('node_op', 'op_map',\n vArray,\n newNode\n );\n } else {\n node2 = newNode;\n }\n\n this.setMath(node2);\n node.type = node2.type;\n node.value = node2.value;\n node.children[0] = node2.children[0];\n node.children[1] = node2.children[1];\n }\n }\n break;\n\n case 'node_var':\n case 'node_const':\n case 'node_const_bool':\n case 'node_str':\n break;\n }\n\n return node;\n },\n\n removeTrivialNodes: function (node) {\n var i, len, n0, n1, swap;\n\n // In case of 'op_execfun' the children[1] node is an array.\n if (Type.isArray(node)) {\n len = node.length;\n for (i = 0; i < len; ++i) {\n node[i] = this.removeTrivialNodes(node[i]);\n }\n }\n if (node.type != 'node_op' || !node.children) {\n return node;\n }\n\n len = node.children.length;\n for (i = 0; i < len; ++i) {\n this.mayNotBeSimplified = false;\n do {\n node.children[i] = this.removeTrivialNodes(node.children[i]);\n } while (this.mayNotBeSimplified);\n\n }\n\n switch (node.value) {\n // Allow maps of the form\n // map (x) -> x;\n case 'op_map':\n n0 = node.children[0];\n n1 = node.children[1];\n if (n1.type == 'node_var') {\n for (i = 0; i < n0.length; ++i) {\n // Allow maps of the form map(x) -> x\n if (n0[i] == n1.value) {\n n1.isMath = true;\n break;\n }\n }\n }\n break;\n\n // a + 0 -> a\n // 0 + a -> a\n case 'op_add':\n n0 = node.children[0];\n n1 = node.children[1];\n if (n0.type == 'node_const' && n0.value === 0.0) {\n return n1;\n }\n if (n1.type == 'node_const' && n1.value === 0.0) {\n return n0;\n }\n\n // const + const -> const\n if (n0.type == 'node_const' && n1.type == 'node_const') {\n n0.value += n1.value;\n return n0;\n }\n break;\n\n // 1 * a = a\n // a * 1 = a\n // a * 0 = 0\n // 0 * a = 0\n // - * - = +\n // Order children\n case 'op_mul':\n n0 = node.children[0];\n n1 = node.children[1];\n if (n0.type == 'node_const' && n0.value == 1.0) {\n return n1;\n }\n if (n1.type == 'node_const' && n1.value == 1.0) {\n return n0;\n }\n if (n0.type == 'node_const' && n0.value === 0.0) {\n return n0;\n }\n if (n1.type == 'node_const' && n1.value === 0.0) {\n return n1;\n }\n if (n1.type == 'node_const' && n1.value === 0.0) {\n return n1;\n }\n\n // (-a) * (-b) -> a*b\n if (n0.type == 'node_op' && n0.value == 'op_neg' &&\n n1.type == 'node_op' && n1.value == 'op_neg') {\n node.children = [n0.children[0], n1.children[0]];\n this.mayNotBeSimplified = true;\n return node;\n }\n // (-a) * b -> -(a*b)\n if (n0.value == 'op_neg' && n1.value != 'op_neg') {\n node.type = 'node_op';\n node.value = 'op_neg';\n node.children = [this.createNode('node_op', 'op_mul', n0.children[0], n1)];\n this.mayNotBeSimplified = true;\n return node;\n }\n // a * (-b) -> -(a*b)\n if (n0.value != 'op_neg' && n1.value == 'op_neg') {\n node.type = 'node_op';\n node.value = 'op_neg';\n node.children = [this.createNode('node_op', 'op_mul', n0, n1.children[0])];\n this.mayNotBeSimplified = true;\n return node;\n }\n // (1 / a) * b -> a / b\n if (n0.value == 'op_div' &&\n n0.children[0].type == 'node_const' && n0.children[0].value == 1.0) {\n node.type = 'node_op';\n node.value = 'op_div';\n node.children = [n1, n0.children[1]];\n this.mayNotBeSimplified = true;\n return node;\n }\n // a * (1 / b) -> a / b\n if (n1.value == 'op_div' &&\n n1.children[0].type == 'node_const' && n1.children[0].value == 1.0) {\n node.type = 'node_op';\n node.value = 'op_div';\n node.children = [n0, n1.children[1]];\n this.mayNotBeSimplified = true;\n return node;\n }\n\n // Order children\n // a * const -> const * a\n if (n0.type != 'node_const' && n1.type == 'node_const') {\n node.children = [n1, n0];\n this.mayNotBeSimplified = true;\n return node;\n }\n // a + (-const) -> -const * a\n if (n0.type != 'node_const' && n1.type == 'node_op' &&\n n1.value == 'op_neg' && n1.children[0].type == 'node_const') {\n node.children = [n1, n0];\n this.mayNotBeSimplified = true;\n return node;\n }\n\n // a * var -> var * a\n // a * fun -> fun * a\n if (n0.type == 'node_op' && n0.value != 'op_execfun' &&\n (n1.type == 'node_var' || (n1.type == 'node_op' && n1.value == 'op_execfun'))) {\n node.children = [n1, n0];\n this.mayNotBeSimplified = true;\n return node;\n }\n\n // a + (-var) -> -var * a\n if (n0.type != 'node_op' && n1.type == 'node_op' &&\n n1.value == 'op_neg' && n1.children[0].type == 'node_var') {\n node.children = [n1, n0];\n this.mayNotBeSimplified = true;\n return node;\n }\n // a * (const * b) -> const * (a*b)\n // a * (const / b) -> const * (a/b)\n if (n0.type != 'node_const' && n1.type == 'node_op' &&\n (n1.value == 'op_mul' || n1.value == 'op_div') &&\n n1.children[0].type == 'node_const') {\n swap = n1.children[0];\n n1.children[0] = n0;\n node.children = [swap, n1];\n this.mayNotBeSimplified = true;\n return node;\n }\n\n // (const * a) * b -> const * (a * b)\n if (n1.type != 'node_const' && n0.type == 'node_op' &&\n n0.value == 'op_mul' &&\n n0.children[0].type == 'node_const') {\n node.children = [\n n0.children[0],\n this.createNode('node_op', 'op_mul', n0.children[1], n1)\n ];\n this.mayNotBeSimplified = true;\n return node;\n }\n\n // const * const -> const\n if (n0.type == 'node_const' && n1.type == 'node_const') {\n n0.value *= n1.value;\n return n0;\n }\n\n // const * (const * a) -> const * a\n // const * (const / a) -> const / a\n if (n0.type == 'node_const' && n1.type == 'node_op' &&\n (n1.value == 'op_mul' || n1.value == 'op_div') &&\n n1.children[0].type == 'node_const') {\n n1.children[0].value *= n0.value;\n return n1;\n }\n\n // a * a-> a^2\n n0.hash = this.parser.compile(n0);\n n1.hash = this.parser.compile(n1);\n if (n0.hash === n1.hash) {\n node.value = 'op_exp';\n node.children[1] = this.createNode('node_const', 2.0);\n return node;\n }\n\n if (n0.type == 'node_const' && n1.type == 'node_op' &&\n (n1.value == 'op_mul' || n1.value == 'op_div') &&\n n1.children[0].type == 'node_const') {\n n1.children[0].value *= n0.value;\n return n1;\n }\n\n // a * a^b -> a^(b+1)\n if (n1.type == 'node_op' && n1.value == 'op_exp') {\n if (!n0.hash) {\n n0.hash = this.parser.compile(n0);\n }\n if (!n1.children[0].hash) {\n n1.children[0].hash = this.parser.compile(n1.children[0]);\n }\n if (n0.hash === n1.children[0].hash) {\n n1.children[1] = this.createNode('node_op', 'op_add',\n n1.children[1],\n this.createNode('node_const', 1.0)\n );\n this.mayNotBeSimplified = true;\n return n1;\n }\n }\n\n // a^b * a^c -> a^(b+c)\n if (n0.type == 'node_op' && n0.value == 'op_exp' &&\n n1.type == 'node_op' && n1.value == 'op_exp') {\n n0.children[0].hash = this.parser.compile(n0.children[0]);\n n1.children[0].hash = this.parser.compile(n1.children[0]);\n if (n0.children[0].hash === n1.children[0].hash) {\n n0.children[1] = this.createNode('node_op', 'op_add',\n n0.children[1],\n n1.children[1]\n );\n this.mayNotBeSimplified = true;\n return n0;\n }\n }\n\n break;\n\n // 0 - a -> -a\n // a - 0 -> a\n // a - a -> 0\n case 'op_sub':\n n0 = node.children[0];\n n1 = node.children[1];\n if (n0.type == 'node_const' && n0.value === 0.0) {\n node.value = 'op_neg';\n node.children[0] = n1;\n return node;\n }\n if (n1.type == 'node_const' && n1.value === 0.0) {\n return n0;\n }\n if (n0.type == 'node_const' && n1.type == 'node_const' &&\n n0.value == n1.value) {\n return this.createNode('node_const', 0.0);\n }\n if (n0.type == 'node_var' && n1.type == 'node_var' &&\n n0.value == n1.value) {\n return this.createNode('node_const', 0.0);\n }\n\n // const - const -> const\n if (n0.type == 'node_const' && n1.type == 'node_const') {\n n0.value -= n1.value;\n return n0;\n }\n\n // const * a - const * a -> const * a\n if (n0.type == 'node_op' && n0.value == 'op_mul' &&\n n1.type == 'node_op' && n1.value == 'op_mul') {\n\n n0.children[1].hash = this.parser.compile(n0.children[1]);\n n1.children[1].hash = this.parser.compile(n1.children[1]);\n if (n0.children[1].hash === n1.children[1].hash) {\n\n node.value = 'op_mul';\n node.children = [\n this.createNode('node_op', 'op_sub',\n n0.children[0],\n n1.children[0]),\n n0.children[1]\n ];\n this.mayNotBeSimplified = true;\n return node;\n }\n }\n // const * a - a -> (const - 1) * a\n if (n0.type == 'node_op' && n0.value == 'op_mul') {\n\n n0.children[1].hash = this.parser.compile(n0.children[1]);\n n1.hash = this.parser.compile(n1);\n if (n0.children[1].hash === n1.hash) {\n\n node.value = 'op_mul';\n node.children = [\n this.createNode('node_op', 'op_sub',\n n0.children[0],\n this.createNode('node_const', 1.0)),\n n1\n ];\n this.mayNotBeSimplified = true;\n return node;\n }\n }\n // a - const*a -> (const - 1) * a\n if (n1.type == 'node_op' && n1.value == 'op_mul') {\n\n n1.children[1].hash = this.parser.compile(n1.children[1]);\n n0.hash = this.parser.compile(n0);\n if (n1.children[1].hash === n0.hash) {\n\n node.value = 'op_mul';\n node.children = [\n this.createNode('node_op', 'op_sub',\n this.createNode('node_const', 1.0),\n n1.children[0]),\n n0\n ];\n this.mayNotBeSimplified = true;\n return node;\n }\n }\n\n break;\n\n // -0 -> 0\n // -(-b) = b\n case 'op_neg':\n n0 = node.children[0];\n if (n0.type == 'node_const' && n0.value === 0.0) {\n return n0;\n }\n if (n0.type == 'node_op' && n0.value == 'op_neg') {\n return n0.children[0];\n }\n break;\n\n // a / a -> 1, a != 0\n // 0 / a -> 0, a != 0\n // a / 0 -> Infinity, a != 0\n // 0 / 0 -> NaN, a == 0\n case 'op_div':\n n0 = node.children[0];\n n1 = node.children[1];\n if (n0.type == 'node_const' && n1.type == 'node_const' &&\n n0.value == n1.value && n0.value !== 0) {\n n0.value = 1.0;\n return n0;\n }\n if (n0.type == 'node_const' && n0.value === 0 &&\n n1.type == 'node_const' && n1.value !== 0) {\n n0.value = 0.0;\n return n0;\n }\n\n // Risky: 0 / (something != 0) -> 0.0\n if (n0.type == 'node_const' && n0.value === 0 &&\n (n1.type == 'node_op' || n1.type == 'node_var')) {\n node.type = 'node_const';\n node.value = 0.0;\n return node;\n }\n\n if (n0.type == 'node_var' && n1.type == 'node_var' &&\n n0.value == n1.value) {\n return this.createNode('node_const', 1.0);\n }\n if (n0.type == 'node_const' && n0.value !== 0 &&\n n1.type == 'node_const' && n1.value === 0) {\n if (n0.value > 0.0) {\n n0.value = Infinity;\n } else {\n n0.value = -Infinity; // Do we ever need this?\n }\n return n0;\n }\n\n // (-a) / (-b) -> a/b\n if (n0.type == 'node_op' && n0.value == 'op_neg' &&\n n1.type == 'node_op' && n1.value == 'op_neg') {\n node.children = [n0.children[0], n1.children[0]];\n this.mayNotBeSimplified = true;\n return node;\n }\n // (-a) / b -> -(a/b)\n if (n0.value == 'op_neg' && n1.value != 'op_neg') {\n node.type = 'node_op';\n node.value = 'op_neg';\n node.children = [this.createNode('node_op', 'op_div', n0.children[0], n1)];\n this.mayNotBeSimplified = true;\n return node;\n }\n // a / (-b) -> -(a/b)\n if (n0.value != 'op_neg' && n1.value == 'op_neg') {\n node.type = 'node_op';\n node.value = 'op_neg';\n node.children = [this.createNode('node_op', 'op_div', n0, n1.children[0])];\n this.mayNotBeSimplified = true;\n return node;\n }\n\n // a^b / a -> a^(b-1)\n if (n0.type == 'node_op' && n0.value == 'op_exp') {\n if (!n1.hash) {\n n1.hash = this.parser.compile(n1);\n }\n if (!n0.children[0].hash) {\n n0.children[0].hash = this.parser.compile(n0.children[0]);\n }\n if (n1.hash === n0.children[0].hash) {\n n0.children[1] = this.createNode('node_op', 'op_sub',\n n0.children[1],\n this.createNode('node_const', 1.0)\n );\n this.mayNotBeSimplified = true;\n return n0;\n }\n }\n\n // (const * a) / b -> const * (a / b)\n if (n1.type != 'node_const' && n0.type == 'node_op' &&\n n0.value == 'op_mul' &&\n n0.children[0].type == 'node_const') {\n node.value = 'op_mul';\n node.children = [\n n0.children[0],\n this.createNode('node_op', 'op_div', n0.children[1], n1)\n ];\n this.mayNotBeSimplified = true;\n return node;\n }\n\n // a^b / a^c -> a^(b-c)\n if (n0.type == 'node_op' && n0.value == 'op_exp' &&\n n1.type == 'node_op' && n1.value == 'op_exp') {\n n0.children[0].hash = this.parser.compile(n0.children[0]);\n n1.children[0].hash = this.parser.compile(n1.children[0]);\n if (n0.children[0].hash === n1.children[0].hash) {\n n0.children[1] = this.createNode('node_op', 'op_sub',\n n0.children[1],\n n1.children[1]\n );\n this.mayNotBeSimplified = true;\n return n0;\n }\n }\n\n\n break;\n\n // a^0 = 1\n // a^1 -> a\n // 1^a -> 1\n // 0^a -> 0: a const != 0\n case 'op_exp':\n n0 = node.children[0];\n n1 = node.children[1];\n if (n1.type == 'node_const' && n1.value === 0.0) {\n n1.value = 1.0;\n return n1;\n }\n if (n1.type == 'node_const' && n1.value == 1.0) {\n return n0;\n }\n if (n0.type == 'node_const' && n0.value == 1.0) {\n return n0;\n }\n if (n0.type == 'node_const' && n0.value === 0.0 &&\n n1.type == 'node_const' && n1.value !== 0.0) {\n return n0;\n }\n\n // (a^b)^c -> a^(b*c)\n if (n0.type == 'node_op' && n0.value == 'op_exp') {\n node.children = [\n n0.children[0],\n this.createNode('node_op', 'op_mul',\n n0.children[1],\n n1)\n ];\n return node;\n }\n break;\n }\n\n switch (node.value) {\n // const_1 + const_2 -> (const_1 + const_2)\n // a + a -> 2*a\n // a + (-b) = a - b\n case 'op_add':\n n0 = node.children[0];\n n1 = node.children[1];\n if (n0.type == 'node_const' && n1.type == 'node_const' &&\n n0.value == n1.value) {\n n0.value += n1.value;\n return n0;\n }\n\n if (n0.type == 'node_var' && n1.type == 'node_var' &&\n n0.value == n1.value) {\n node.children[0] = this.createNode('node_const', 2.0);\n node.value = 'op_mul';\n return node;\n }\n\n if (n0.type == 'node_op' && n0.value == 'op_neg') {\n node.value = 'op_sub';\n node.children[0] = n1;\n node.children[1] = n0.children[0];\n this.mayNotBeSimplified = true;\n return node;\n }\n\n if (n1.type == 'node_op' && n1.value == 'op_neg') {\n node.value = 'op_sub';\n node.children[1] = n1.children[0];\n this.mayNotBeSimplified = true;\n return node;\n }\n\n // const * a + const * a -> const * a\n if (n0.type == 'node_op' && n0.value == 'op_mul' &&\n n1.type == 'node_op' && n1.value == 'op_mul') {\n\n n0.children[1].hash = this.parser.compile(n0.children[1]);\n n1.children[1].hash = this.parser.compile(n1.children[1]);\n if (n0.children[1].hash === n1.children[1].hash) {\n\n node.value = 'op_mul';\n node.children = [\n this.createNode('node_op', 'op_add',\n n0.children[0],\n n1.children[0]),\n n0.children[1]\n ];\n this.mayNotBeSimplified = true;\n return node;\n }\n }\n // const * a + a -> (const + 1) * a\n if (n0.type == 'node_op' && n0.value == 'op_mul') {\n\n n0.children[1].hash = this.parser.compile(n0.children[1]);\n n1.hash = this.parser.compile(n1);\n if (n0.children[1].hash === n1.hash) {\n\n node.value = 'op_mul';\n node.children = [\n this.createNode('node_op', 'op_add',\n n0.children[0],\n this.createNode('node_const', 1.0)),\n n1\n ];\n this.mayNotBeSimplified = true;\n return node;\n }\n }\n // a + const*a -> (const + 1) * a\n if (n1.type == 'node_op' && n1.value == 'op_mul') {\n\n n1.children[1].hash = this.parser.compile(n1.children[1]);\n n0.hash = this.parser.compile(n0);\n if (n1.children[1].hash === n0.hash) {\n\n node.value = 'op_mul';\n node.children = [\n this.createNode('node_op', 'op_add',\n this.createNode('node_const', 1.0),\n n1.children[0]),\n n0\n ];\n this.mayNotBeSimplified = true;\n return node;\n }\n }\n\n break;\n\n // a - (-b) = a + b\n case 'op_sub':\n n0 = node.children[0];\n n1 = node.children[1];\n if (n1.type == 'node_op' && n1.value == 'op_neg') {\n node.value = 'op_add';\n node.children[1] = n1.children[0];\n this.mayNotBeSimplified = true;\n return node;\n }\n break;\n\n case 'op_execfun':\n return this.simplifyElementary(node);\n }\n\n return node;\n },\n\n simplifyElementary: function (node) {\n var fun = node.children[0].value,\n arg = node.children[1];\n\n // Catch errors of the form sin()\n if (arg.length == 0) {\n return node;\n }\n\n switch (fun) {\n // sin(0) -> 0\n // sin(PI) -> 0\n // sin (int * PI) -> 0\n // sin (PI * int) -> 0\n // Same for tan()\n case 'sin':\n case 'tan':\n if (arg[0].type == 'node_const' && arg[0].value === 0) {\n node.type = 'node_const';\n node.value = 0.0;\n return node;\n }\n if (arg[0].type == 'node_var' && arg[0].value == 'PI') {\n node.type = 'node_const';\n node.value = 0.0;\n return node;\n }\n if (arg[0].type == 'node_op' && arg[0].value == 'op_mul' &&\n arg[0].children[0].type == 'node_const' && arg[0].children[0].value % 1 === 0 &&\n arg[0].children[1].type == 'node_var' && arg[0].children[1].value == 'PI') {\n node.type = 'node_const';\n node.value = 0.0;\n return node;\n }\n break;\n\n // cos(0) -> 1.0\n // cos(PI) -> -1.0\n // cos(int * PI) -> +/- 1.0\n // cos(PI * int) -> +/- 1.0\n case 'cos':\n if (arg[0].type == 'node_const' && arg[0].value === 0) {\n node.type = 'node_const';\n node.value = 1.0;\n return node;\n }\n if (arg[0].type == 'node_var' && arg[0].value == 'PI') {\n node.type = 'node_op';\n node.value = 'op_neg';\n node.children = [this.createNode('node_const', 1.0)];\n return node;\n }\n /*\n if (arg[0].type == 'node_op' && arg[0].value == 'op_mul' &&\n ((arg[0].children[0].type == 'node_const' && arg[0].children[0].value % 1 === 0 &&\n arg[0].children[1].type == 'node_var' && arg[0].children[1].value == 'PI') ||\n (arg[0].children[1].type == 'node_const' && arg[0].children[1].value % 1 === 0 &&\n arg[0].children[0].type == 'node_var' && arg[0].children[0].value == 'PI'))) {\n node.type = 'node_const';\n node.value = 1.0;\n return node;\n }\n */\n break;\n\n // exp(0) -> 1\n case 'exp':\n if (arg[0].type == 'node_const' && arg[0].value === 0) {\n node.type = 'node_const';\n node.value = 1.0;\n return node;\n }\n break;\n\n // pow(a, 0) -> 1\n case 'pow':\n if (arg[1].type == 'node_const' && arg[1].value === 0) {\n node.type = 'node_const';\n node.value = 1.0;\n return node;\n }\n break;\n\n }\n\n return node;\n }\n\n });\n\n return JXG.CA;\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true*/\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n jxg\n utils/type\n */\n\n/**\n * @fileoverview The JXG.Dump namespace provides methods to save a board to javascript.\n */\n\ndefine('utils/dump',['jxg', 'utils/type'], function (JXG, Type) {\n\n \"use strict\";\n\n /**\n * The JXG.Dump namespace provides classes and methods to save a board to javascript.\n * @namespace\n */\n JXG.Dump = {\n\n /**\n * Adds markers to every element of the board\n * @param {JXG.Board} board\n * @param {Array|String} markers\n * @param {Array} values\n */\n addMarkers: function (board, markers, values) {\n var e, l, i;\n\n if (!Type.isArray(markers)) {\n markers = [markers];\n }\n\n if (!Type.isArray(values)) {\n values = [values];\n }\n\n l = Math.min(markers.length, values.length);\n\n markers.length = l;\n values.length = l;\n\n for (e in board.objects) {\n if (board.objects.hasOwnProperty(e)) {\n for (i = 0; i < l; i++) {\n board.objects[e][markers[i]] = values[i];\n }\n }\n }\n },\n\n /**\n * Removes markers from every element on the board.\n * @param {JXG.Board} board\n * @param {Array|String} markers\n */\n deleteMarkers: function (board, markers) {\n var e, l, i;\n\n if (!Type.isArray(markers)) {\n markers = [markers];\n }\n\n l = markers.length;\n\n markers.length = l;\n\n for (e in board.objects) {\n if (board.objects.hasOwnProperty(e)) {\n for (i = 0; i < l; i++) {\n delete board.objects[e][markers[i]];\n }\n }\n }\n },\n\n /**\n * Stringifies a string, i.e. puts some quotation marks around <tt>s</tt> if it is of type string.\n * @param {*} s\n * @returns {String} \" + s + \"\n */\n str: function (s) {\n if (typeof s === 'string' && s.substr(0, 7) !== 'function') {\n s = '\"' + s + '\"';\n }\n\n return s;\n },\n\n /**\n * Eliminate default values given by {@link JXG.Options} from the attributes object.\n * @param {Object} instance Attribute object of the element\n * @param {Object} s Arbitrary number of objects <tt>instance</tt> will be compared to. Usually these are\n * sub-objects of the {@link JXG.Board#options} structure.\n * @returns {Object} Minimal attributes object\n */\n minimizeObject: function (instance, s) {\n var p, pl, i,\n def = {},\n copy = Type.deepCopy(instance),\n defaults = [];\n\n for (i = 1; i < arguments.length; i++) {\n defaults.push(arguments[i]);\n }\n\n def = Type.deepCopy(def, JXG.Options.elements, true);\n for (i = defaults.length; i > 0; i--) {\n def = Type.deepCopy(def, defaults[i - 1], true);\n }\n\n for (p in def) {\n if (def.hasOwnProperty(p)) {\n pl = p.toLowerCase();\n\n if (typeof def[p] !== 'object' && def[p] === copy[pl]) {\n // console.log(\"delete\", p);\n delete copy[pl];\n }\n }\n }\n\n return copy;\n },\n\n /**\n * Prepare the attributes object for an element to be dumped as JavaScript or JessieCode code.\n * @param {JXG.Board} board\n * @param {JXG.GeometryElement} obj Geometry element which attributes object is generated\n * @returns {Object} An attributes object.\n */\n prepareAttributes: function (board, obj) {\n var a, s;\n\n a = this.minimizeObject(obj.getAttributes(), JXG.Options[obj.elType]);\n\n for (s in obj.subs) {\n if (obj.subs.hasOwnProperty(s)) {\n a[s] = this.minimizeObject(obj.subs[s].getAttributes(),\n JXG.Options[obj.elType][s],\n JXG.Options[obj.subs[s].elType]);\n a[s].id = obj.subs[s].id;\n a[s].name = obj.subs[s].name;\n }\n }\n\n a.id = obj.id;\n a.name = obj.name;\n\n return a;\n },\n\n setBoundingBox: function(methods, board, boardVarName) {\n methods.push({\n obj: boardVarName,\n method: 'setBoundingBox',\n params: [board.getBoundingBox(), board.keepaspectratio]\n });\n\n return methods;\n },\n\n /**\n * Generate a save-able structure with all elements. This is used by {@link JXG.Dump#toJessie} and\n * {@link JXG.Dump#toJavaScript} to generate the script.\n * @param {JXG.Board} board\n * @returns {Array} An array with all metadata necessary to save the construction.\n */\n dump: function (board) {\n var e, obj, element, s,\n props = [],\n methods = [],\n elementList = [],\n len = board.objectsList.length;\n\n this.addMarkers(board, 'dumped', false);\n\n for (e = 0; e < len; e++) {\n obj = board.objectsList[e];\n element = {};\n\n if (!obj.dumped && obj.dump) {\n element.type = obj.getType();\n element.parents = obj.getParents().slice();\n\n // Extract coordinates of a point\n if (element.type === 'point' && element.parents[0] === 1) {\n element.parents = element.parents.slice(1);\n }\n\n for (s = 0; s < element.parents.length; s++) {\n if (Type.isString(element.parents[s]) &&\n element.parents[s][0] !== \"'\" &&\n element.parents[s][0] !== '\"') {\n\n element.parents[s] = '\"' + element.parents[s] + '\"';\n } else if (Type.isArray( element.parents[s]) ) {\n element.parents[s] = '[' + element.parents[s].toString() + ']';\n }\n }\n\n element.attributes = this.prepareAttributes(board, obj);\n if (element.type === 'glider' && obj.onPolygon) {\n props.push({\n obj: obj.id,\n prop: 'onPolygon',\n val: true\n });\n }\n\n elementList.push(element);\n }\n }\n\n this.deleteMarkers(board, 'dumped');\n\n return {\n elements: elementList,\n props: props,\n methods: methods\n };\n },\n\n /**\n * Converts an array of different values into a parameter string that can be used by the code generators.\n * @param {Array} a\n * @param {function} converter A function that is used to transform the elements of <tt>a</tt>. Usually\n * {@link JXG.toJSON} or {@link JXG.Dump.toJCAN} are used.\n * @returns {String}\n */\n arrayToParamStr: function (a, converter) {\n var i,\n s = [];\n\n for (i = 0; i < a.length; i++) {\n s.push(converter.call(this, a[i]));\n }\n\n return s.join(', ');\n },\n\n /**\n * Converts a JavaScript object into a JCAN (JessieCode Attribute Notation) string.\n * @param {Object} obj A JavaScript object, functions will be ignored.\n * @returns {String} The given object stored in a JCAN string.\n */\n toJCAN: function (obj) {\n var i, list, prop;\n\n switch (typeof obj) {\n case 'object':\n if (obj) {\n list = [];\n\n if (Type.isArray(obj)) {\n for (i = 0; i < obj.length; i++) {\n list.push(this.toJCAN(obj[i]));\n }\n\n return '[' + list.join(',') + ']';\n }\n\n for (prop in obj) {\n if (obj.hasOwnProperty(prop)) {\n list.push(prop + ': ' + this.toJCAN(obj[prop]));\n }\n }\n\n return '<<' + list.join(', ') + '>> ';\n }\n return 'null';\n case 'string':\n return '\\'' + obj.replace(/\\\\/g,'\\\\\\\\').replace(/([\"'])/g, '\\\\$1') + '\\'';\n case 'number':\n case 'boolean':\n return obj.toString();\n case 'null':\n return 'null';\n }\n },\n\n /**\n * Saves the construction in <tt>board</tt> to JessieCode.\n * @param {JXG.Board} board\n * @returns {String} JessieCode\n */\n toJessie: function (board) {\n var i, elements, id,\n dump = this.dump(board),\n script = [];\n\n dump.methods = this.setBoundingBox(dump.methods, board, '$board');\n\n elements = dump.elements;\n\n for (i = 0; i < elements.length; i++) {\n if (elements[i].attributes.name.length > 0) {\n script.push('// ' + elements[i].attributes.name);\n }\n script.push('s' + i + ' = ' + elements[i].type + '(' + elements[i].parents.join(', ') + ') ' + this.toJCAN(elements[i].attributes).replace(/\\n/, '\\\\n') + ';');\n\n if (elements[i].type === 'axis') {\n // Handle the case that remove[All]Ticks had been called.\n id = elements[i].attributes.id;\n if (board.objects[id].defaultTicks === null) {\n script.push('s' + i + '.removeAllTicks();');\n }\n }\n script.push('');\n }\n\n for (i = 0; i < dump.methods.length; i++) {\n script.push(dump.methods[i].obj + '.' + dump.methods[i].method + '(' + this.arrayToParamStr(dump.methods[i].params, this.toJCAN) + ');');\n script.push('');\n }\n\n for (i = 0; i < dump.props.length; i++) {\n script.push(dump.props[i].obj + '.' + dump.props[i].prop + ' = ' + this.toJCAN(dump.props[i].val) + ';');\n script.push('');\n }\n\n return script.join('\\n');\n },\n\n /**\n * Saves the construction in <tt>board</tt> to JavaScript.\n * @param {JXG.Board} board\n * @returns {String} JavaScript\n */\n toJavaScript: function (board) {\n var i, elements, id,\n dump = this.dump(board),\n script = [];\n\n dump.methods = this.setBoundingBox(dump.methods, board, 'board');\n\n elements = dump.elements;\n\n for (i = 0; i < elements.length; i++) {\n script.push('board.create(\"' + elements[i].type + '\", [' + elements[i].parents.join(', ') + '], ' + Type.toJSON(elements[i].attributes) + ');');\n\n if (elements[i].type === 'axis') {\n // Handle the case that remove[All]Ticks had been called.\n id = elements[i].attributes.id;\n if (board.objects[id].defaultTicks === null) {\n script.push('board.objects[\"' + id + '\"].removeTicks(board.objects[\"' + id + '\"].defaultTicks);');\n }\n }\n }\n\n for (i = 0; i < dump.methods.length; i++) {\n script.push(dump.methods[i].obj + '.' + dump.methods[i].method + '(' + this.arrayToParamStr(dump.methods[i].params, Type.toJSON) + ');');\n script.push('');\n }\n\n for (i = 0; i < dump.props.length; i++) {\n script.push(dump.props[i].obj + '.' + dump.props[i].prop + ' = ' + Type.toJSON(dump.props[i].val) + ';');\n script.push('');\n }\n\n return script.join('\\n');\n }\n };\n\n return JXG.Dump;\n});\n\n/*\n Copyright 2018-2022\n Alfred Wassermann,\n Tigran Saluev\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true*/\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n see define call\n */\n\n/**\n * @fileoverview In this file the Comb element is defined.\n */\n\ndefine('element/comb',[\n 'jxg', 'utils/type', 'base/point'\n], function (JXG, Type, Point) {\n\n \"use strict\";\n\n /**\n * @class A comb to display domains of inequalities.\n * @pseudo\n * @name Comb\n * @augments JXG.Curve\n * @constructor\n * @type JXG.Curve\n * @throws {Error} If the element cannot be constructed with the given parent\n * objects an exception is thrown.\n * Parameter options:\n * @param {JXG.Point,array,function_JXG.Point,array,function} point1,point2 Parent elements\n * can be two elements either of type {@link JXG.Point} or array of\n * numbers describing the coordinates of a point. In the latter case the point\n * will be constructed automatically as a fixed invisible point.\n * It is possible to provide a function returning an array or a point,\n * instead of providing an array or a point.\n * @example\n * // Create a simple horizontal comb with invisible endpoints\n * var c = board.create('comb', [[1, 0], [3, 0]]);\n *\n * </pre><div class=\"jxgbox\" id=\"JXG951ccb6a-52bc-4dc2-80e9-43db064f0f1b\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function () {\n * var board = JXG.JSXGraph.initBoard('JXG951ccb6a-52bc-4dc2-80e9-43db064f0f1b', {boundingbox: [-5, 5, 5, -5], axis: true, showcopyright: false, shownavigation: false}),\n * c = board.create('comb', [[1, 0], [3, 0]]);\n * })();\n * </script><pre>\n *\n * @example\n * var p1 = board.create('glider', [-3, 0, board.defaultAxes.x]);\n * var p2 = board.create('glider', [-1, 0, board.defaultAxes.x]);\n * var c1 = board.create('comb', [p1, p2], {width: 0.2, frequency: 0.1, angle: Math.PI / 4});\n *\n * </pre><div id=\"JXG04186fd2-6340-11e8-9fb9-901b0e1b8723\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG04186fd2-6340-11e8-9fb9-901b0e1b8723',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var p1 = board.create('glider', [-3, 0, board.defaultAxes.x]);\n * var p2 = board.create('glider', [-1, 0, board.defaultAxes.x]);\n * var c1 = board.create('comb', [p1, p2], {width: 0.2, frequency: 0.1, angle: Math.PI / 4});\n *\n * })();\n *\n * </script><pre>\n *\n * @example\n * var s = board.create('slider', [[1,3], [4,3], [0.1, 0.3, 0.8]]);\n * var p1 = board.create('glider', [-3, 0, board.defaultAxes.x]);\n * var p2 = board.create('glider', [-1, 0, board.defaultAxes.x]);\n * var c1 = board.create('comb', [p1, p2], {\n * width: function(){ return 4*s.Value(); },\n * reverse: function(){ return (s.Value()<0.5) ? false : true; },\n * frequency: function(){ return s.Value(); },\n * angle: function(){ return s.Value() * Math.PI / 2; },\n * curve: {\n * strokeColor: 'red'\n * }\n * });\n *\n * </pre><div id=\"JXG6eb1bcd1-407e-4f13-8f0c-45ef39a0cfb3\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG6eb1bcd1-407e-4f13-8f0c-45ef39a0cfb3',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var s = board.create('slider', [[1,3], [4,3], [0.1, 0.3, 0.8]]);\n * var p1 = board.create('glider', [-3, 0, board.defaultAxes.x]);\n * var p2 = board.create('glider', [-1, 0, board.defaultAxes.x]);\n * var c1 = board.create('comb', [p1, p2], {\n * width: function(){ return 4*s.Value(); },\n * reverse: function(){ return (s.Value()<0.5) ? false : true; },\n * frequency: function(){ return s.Value(); },\n * angle: function(){ return s.Value() * Math.PI / 2; },\n * curve: {\n * strokeColor: 'red'\n * }\n * });\n *\n * })();\n *\n * </script><pre>\n *\n */\n JXG.createComb = function(board, parents, attributes) {\n var p1, p2, c, attr, parent_types;\n //ds, angle, width, p;\n\n if (parents.length === 2) {\n // point 1 given by coordinates\n if (Type.isArray(parents[0]) && parents[0].length > 1) {\n attr = Type.copyAttributes(attributes, board.options, 'comb', 'point1');\n p1 = board.create('point', parents[0], attr);\n } else if (Type.isString(parents[0]) || Type.isPoint(parents[0])) {\n p1 = board.select(parents[0]);\n } else if (Type.isFunction(parents[0]) && Type.isPoint(parents[0]())) {\n p1 = parents[0]();\n } else if (Type.isFunction(parents[0]) && parents[0]().length && parents[0]().length >= 2) {\n attr = Type.copyAttributes(attributes, board.options, 'comb', 'point1');\n p1 = Point.createPoint(board, parents[0](), attr);\n } else {\n throw new Error(\"JSXGraph: Can't create comb with parent types '\" +\n (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"'.\" +\n \"\\nPossible parent types: [point,point], [[x1,y1],[x2,y2]]\");\n }\n\n // point 2 given by coordinates\n if (Type.isArray(parents[1]) && parents[1].length > 1) {\n attr = Type.copyAttributes(attributes, board.options, 'comb', 'point2');\n p2 = board.create('point', parents[1], attr);\n } else if (Type.isString(parents[1]) || Type.isPoint(parents[1])) {\n p2 = board.select(parents[1]);\n } else if (Type.isFunction(parents[1]) && Type.isPoint(parents[1]()) ) {\n p2 = parents[1]();\n } else if (Type.isFunction(parents[1]) && parents[1]().length && parents[1]().length >= 2) {\n attr = Type.copyAttributes(attributes, board.options, 'comb', 'point2');\n p2 = Point.createPoint(board, parents[1](), attr);\n } else {\n throw new Error(\"JSXGraph: Can't create comb with parent types '\" +\n (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"'.\" +\n \"\\nPossible parent types: [point,point], [[x1,y1],[x2,y2]]\");\n }\n } else {\n parent_types = parents.map(function(parent) { return \"'\" + (typeof parent) + \"'\"; });\n throw new Error(\"JSXGraph: Can't create comb with parent types \" +\n parent_types.join(\", \") + \".\" +\n \"\\nPossible parent types: [point,point], [[x1,y1],[x2,y2]]\");\n }\n\n // attr = Type.copyAttributes(attributes, board.options, 'comb', 'curve');\n attr = Type.copyAttributes(attributes, board.options, 'comb');\n Type.merge(attr, Type.copyAttributes(attributes, board.options, 'comb', 'curve'));\n c = board.create('curve', [[0], [0]], attr);\n\n /**\n * @ignore\n */\n c.updateDataArray = function() {\n var s = 0,\n max_s = p1.Dist(p2),\n cs, sn, dx, dy,\n x, y, f,\n p1_inner = p1,\n p2_inner = p2,\n ds, angle, width;\n\n ds = Type.evaluate(c.visProp.frequency);\n angle = -Type.evaluate(c.visProp.angle);\n width = Type.evaluate(c.visProp.width);\n if (Type.evaluate(c.visProp.reverse)) {\n p1_inner = p2;\n p2_inner = p1;\n angle = -angle;\n }\n cs = Math.cos(angle);\n sn = Math.sin(angle);\n dx = (p2_inner.X() - p1_inner.X()) / max_s;\n dy = (p2_inner.Y() - p1_inner.Y()) / max_s;\n\n // But instead of lifting by sin(angle), we want lifting by width.\n cs *= width / Math.abs(sn);\n sn *= width / Math.abs(sn);\n\n this.dataX = [];\n this.dataY = [];\n // TODO Handle infinite boundaries?\n while (s < max_s) {\n x = p1_inner.X() + dx * s;\n y = p1_inner.Y() + dy * s;\n\n // We may need to cut the last piece of a comb.\n f = Math.min(cs, max_s - s) / Math.abs(cs);\n sn *= f;\n cs *= f;\n\n this.dataX.push(x);\n this.dataY.push(y);\n\n this.dataX.push(x + dx * cs + dy * sn);\n this.dataY.push(y - dx * sn + dy * cs);\n\n this.dataX.push(NaN); // Force a jump\n this.dataY.push(NaN);\n s += ds;\n }\n };\n\n return c;\n };\n\n JXG.registerElement('comb', JXG.createComb);\n\n return {\n createComb: JXG.createComb\n };\n\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true*/\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n see define call\n */\n\n/**\n * @fileoverview Example file for a triangle implemented as a extension to JSXGraph.\n */\n\ndefine('element/slopetriangle',[\n 'jxg', 'utils/type', 'base/constants', 'base/polygon'\n], function (JXG, Type, Const, Polygon) {\n\n \"use strict\";\n\n var priv = {\n removeSlopeTriangle: function () {\n Polygon.Polygon.prototype.remove.call(this);\n\n this.board.removeObject(this.toppoint);\n this.board.removeObject(this.glider);\n\n this.board.removeObject(this.baseline);\n this.board.removeObject(this.basepoint);\n\n this.board.removeObject(this.label);\n\n if (this._isPrivateTangent) {\n this.board.removeObject(this.tangent);\n }\n },\n Value: function () {\n return this.tangent.getSlope();\n }\n };\n\n /**\n * @class Slope triangle for a point on a line.\n * @pseudo\n * @name Slopetriangle\n * @augments JXG.Line\n * @constructor\n * @type JXG.Polygon\n * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.\n * Parameter options:\n * @param {JXG.Line} t A tangent based on a glider on some object, e.g. curve, circle, line or turtle.\n * @param {JXG.Line_JXG.Point} li, p A line and a point on that line.\n * The user has to take care that the point is a member of the line.\n * @example\n * // Create a slopetriangle on a tangent\n * var f = board.create('plot', ['sin(x)']),\n * g = board.create('glider', [1, 2, f]),\n * t = board.create('tangent', [g]),\n *\n * st = board.create('slopetriangle', [t]);\n *\n * </pre><div class=\"jxgbox\" id=\"JXG951ccb6a-52bc-4dc2-80e9-43db064f0f1b\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function () {\n * var board = JXG.JSXGraph.initBoard('JXG951ccb6a-52bc-4dc2-80e9-43db064f0f1b', {boundingbox: [-5, 5, 5, -5], axis: true, showcopyright: false, shownavigation: false}),\n * f = board.create('plot', ['sin(x)']),\n * g = board.create('glider', [1, 2, f]),\n * t = board.create('tangent', [g]),\n *\n * st = board.create('slopetriangle', [t]);\n * })();\n * </script><pre>\n *\n * @example\n * // Create a on a line and a point on that line\n * var p1 = board.create('point', [-2, 3]),\n * p2 = board.create('point', [2, -3]),\n * li = board.create('line', [p1, p2]),\n * p = board.create('glider', [0, 0, li]),\n *\n * st = board.create('slopetriangle', [li, p]);\n *\n * </pre><div class=\"jxgbox\" id=\"JXGb52f451c-22cf-4677-852a-0bb9d764ee95\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function () {\n * var board = JXG.JSXGraph.initBoard('JXGb52f451c-22cf-4677-852a-0bb9d764ee95', {boundingbox: [-5, 5, 5, -5], axis: true, showcopyright: false, shownavigation: false}),\n * p1 = board.create('point', [-2, 3]),\n * p2 = board.create('point', [2, -3]),\n * li = board.create('line', [p1, p2]),\n * p = board.create('glider', [0, 0, li]),\n *\n * st = board.create('slopetriangle', [li, p]);\n * })();\n * </script><pre>\n */\n JXG.createSlopeTriangle = function (board, parents, attributes) {\n var el, tangent, tglide, glider, toppoint, baseline, basepoint, label, attr,\n isPrivateTangent = false;\n\n if (parents.length === 1 && parents[0].type === Const.OBJECT_TYPE_TANGENT) {\n tangent = parents[0];\n tglide = tangent.glider;\n } else if (parents.length === 1 && parents[0].type === Const.OBJECT_TYPE_GLIDER) {\n tglide = parents[0];\n attr = Type.copyAttributes(attributes, board.options, 'slopetriangle', 'tangent');\n tangent = board.create('tangent', [tglide], attr);\n isPrivateTangent = true;\n } else if (parents.length === 2 &&\n parents[0].elementClass === Const.OBJECT_CLASS_LINE && Type.isPoint(parents[1])) {\n tangent = parents[0];\n tglide = parents[1];\n } else {\n throw new Error(\"JSXGraph: Can't create slope triangle with parent types '\" + (typeof parents[0]) + \"'.\");\n }\n\n attr = Type.copyAttributes(attributes, board.options, 'slopetriangle', 'basepoint');\n basepoint = board.create('point', [function () {\n return [tglide.X() + 1, tglide.Y()];\n }], attr);\n\n attr = Type.copyAttributes(attributes, board.options, 'slopetriangle', 'baseline');\n baseline = board.create('line', [tglide, basepoint], attr);\n\n attr = Type.copyAttributes(attributes, board.options, 'slopetriangle', 'glider');\n glider = board.create('glider', [tglide.X() + 1, tglide.Y(), baseline], attr);\n\n attr = Type.copyAttributes(attributes, board.options, 'slopetriangle', 'toppoint');\n toppoint = board.create('point', [function () {\n return [glider.X(), glider.Y() + (glider.X() - tglide.X()) * tangent.getSlope()];\n }], attr);\n\n attr = Type.copyAttributes(attributes, board.options, 'slopetriangle');\n attr.borders = Type.copyAttributes(attr.borders, board.options, 'slopetriangle', 'borders');\n el = board.create('polygon', [tglide, glider, toppoint], attr);\n\n /**\n * Returns the value of the slope triangle, that is the slope of the tangent.\n * @name Value\n * @memberOf Slopetriangle.prototype\n * @function\n * @returns {Number} slope of the tangent.\n */\n el.Value = priv.Value;\n el.tangent = tangent;\n el._isPrivateTangent = isPrivateTangent;\n\n //el.borders[0].setArrow(false, {type: 2, size: 10});\n //el.borders[1].setArrow(false, {type: 2, size: 10});\n el.borders[2].setArrow(false, false);\n\n attr = Type.copyAttributes(attributes, board.options, 'slopetriangle', 'label');\n label = board.create('text', [\n function () { return glider.X() + 0.1; },\n function () { return (glider.Y() + toppoint.Y()) * 0.5; },\n function () { return ''; }\n ], attr);\n\n label._setText(function () {\n return Type.toFixed(el.Value(), Type.evaluate(label.visProp.digits));\n });\n label.fullUpdate();\n\n el.glider = glider;\n el.basepoint = basepoint;\n el.baseline = baseline;\n el.toppoint = toppoint;\n el.label = label;\n\n el.subs = {\n glider: glider,\n basePoint: basepoint,\n baseLine: baseline,\n topPoint: toppoint,\n label: label\n };\n el.inherits.push(glider, basepoint, baseline, toppoint, label);\n\n el.methodMap = JXG.deepCopy(el.methodMap, {\n tangent: 'tangent',\n glider: 'glider',\n basepoint: 'basepoint',\n baseline: 'baseline',\n toppoint: 'toppoint',\n label: 'label',\n Value: 'Value',\n V: 'Value'\n });\n\n el.remove = priv.removeSlopeTriangle;\n\n return el;\n };\n\n JXG.registerElement('slopetriangle', JXG.createSlopeTriangle);\n\n return {\n createSlopeTriangle: JXG.createSlopeTriangle\n };\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true, window: true*/\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n jxg\n utils/env\n utils/type\n */\n\n/**\n * @fileoverview In this file the Text element is defined.\n */\n\ndefine('element/checkbox',[\n 'jxg', 'utils/env', 'utils/type'\n], function (JXG, Env, Type) {\n\n \"use strict\";\n\n var priv = {\n CheckboxChangeEventHandler: function () {\n this._value = this.rendNodeCheckbox.checked;\n this.board.update();\n }\n };\n\n /**\n * @class This element is used to provide a constructor for special texts containing a\n * form checkbox element.\n * <p>\n * For this element, the attribute \"display\" has to have the value 'html' (which is the default).\n *\n * @pseudo\n * @description\n * @name Checkbox\n * @augments Text\n * @constructor\n * @type JXG.Text\n *\n * @param {number,function_number,function_String_String} x,y,label Parent elements for checkbox elements.\n * <p>\n * x and y are the coordinates of the lower left corner of the text box.\n * The position of the text is fixed,\n * x and y are numbers. The position is variable if x or y are functions.\n * <p>\n * The label of the input element may be given as string.\n * <p>\n * The value of the checkbox can be controlled with the attribute <tt>checked</tt>\n * <p>The HTML node can be accessed with <tt>element.rendNodeCheckbox</tt>\n *\n * @example\n * // Create a checkbox element at position [0,3].\n * var checkbox = board.create('checkbox', [0, 3, 'Change Y'], {});\n * var p = board.create('point', [\n * function(){ return 0.5;}, // X-coordinate\n * function() {\n * y = 0.5;\n * if (checkbox.Value()) {\n * y += 0.5;\n * }\n * return y;\n * }]);\n * </pre><div class=\"jxgbox\" id=\"JXG0e835e0b-ed0c-4b85-b682-78158c0e6f5c\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var t1_board = JXG.JSXGraph.initBoard('JXG0e835e0b-ed0c-4b85-b682-78158c0e6f5c', {boundingbox: [-3, 6, 5, -3], axis: true, showcopyright: false, shownavigation: false});\n * var checkbox = t1_board.create('checkbox', [0, 3, 'Change Y'], {});\n * var p = t1_board.create('point', [\n * function(){ return 0.5;}, // X-coordinate\n * function() {\n * y = 0.5;\n * if (checkbox.Value()) {\n * y += 0.5;\n * }\n * return y;\n * }]);\n * })();\n * </script><pre>\n *\n * The checkbox can be supplied with custom-made events by using the property rendNodeCheckbox.\n * @example\n * var checkbox = board.create('checkbox', [0, 4, 'Click me']),\n * p = board.create('point', [1, 1]);\n *\n * JXG.addEvent(checkbox.rendNodeCheckbox, 'change', function() {\n * if (this.Value()) {\n * p.moveTo([4, 1]);\n * } else {\n * p.moveTo([1, 1]);\n * }\n * }, checkbox);\n * </pre><div class=\"jxgbox\" id=\"JXGb2f2345a-057d-44ce-bd7a-6aaff70bc810\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXGb2f2345a-057d-44ce-bd7a-6aaff70bc810', {boundingbox: [-3, 6, 5, -3], axis: true, showcopyright: false, shownavigation: false});\n * var checkbox = board.create('checkbox', [0, 4, 'Click me']),\n * p = board.create('point', [1, 1]);\n *\n * JXG.addEvent(checkbox.rendNodeCheckbox, 'change', function() {\n * if (this.Value()) {\n * p.moveTo([4, 1]);\n * } else {\n * p.moveTo([1, 1]);\n * }\n * }, checkbox);\n * })();\n * </script><pre>\n *\n * @example\n * var i1 = board.create('input', [-3, 4, 'sin(x)', 'f(x)='], {cssStyle: 'width:4em', maxlength: 2});\n * var c1 = board.create('checkbox', [-3, 2, 'label 1'], {});\n * var b1 = board.create('button', [-3, -1, 'Change texts', function () {\n * i1.setText('g(x)');\n * i1.set('cos(x)');\n * c1.setText('label 2');\n * b1.setText('Texts are changed');\n * }],\n * {cssStyle: 'width:400px'});\n *\n * </pre><div id=\"JXG11cac8gg-2354-47e7-9da4-eb298e53de05\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG11cac8gg-2354-47e7-9da4-eb298e53de05',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var i1 = board.create('input', [-3, 4, 'sin(x)', 'f(x)='], {cssStyle: 'width:4em', maxlength: 2});\n * var c1 = board.create('checkbox', [-3, 2, 'label 1'], {});\n * var b1 = board.create('button', [-3, -1, 'Change texts', function () {\n * i1.setText('g(x)');\n * i1.set('cos(x)');\n * c1.setText('label 2');\n * b1.setText('Texts are changed');\n * }],\n * {cssStyle: 'width:400px'});\n *\n * })();\n *\n * </script><pre>\n */\n JXG.createCheckbox = function (board, parents, attributes) {\n var t, par,\n attr = Type.copyAttributes(attributes, board.options, 'checkbox');\n\n //if (parents.length !== 3) {\n //throw new Error(\"JSXGraph: Can't create checkbox with parent types '\" +\n // (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"'.\" +\n // \"\\nPossible parents are: [[x,y], label]\");\n //}\n\n par = [parents[0], parents[1],\n '<span style=\"display:inline\">' +\n '<input type=\"checkbox\" /><label for=\"\"></label>' +\n '</span>'\n ];\n\n //t = JXG.createText(board, par, attr);\n t = board.create('text', par, attr);\n t.type = Type.OBJECT_TYPE_CHECKBOX;\n\n t.rendNodeCheckbox = t.rendNode.childNodes[0].childNodes[0];\n t.rendNodeLabel = t.rendNode.childNodes[0].childNodes[1];\n\n t.rendNodeTag = t.rendNodeCheckbox; // Needed for unified treatment in setAttribute\n t.rendNodeTag.disabled = !!attr.disabled;\n\n t.rendNodeLabel.innerHTML = parents[2];\n t.rendNodeCheckbox.id = t.rendNode.id + '_checkbox';\n t.rendNodeLabel.id = t.rendNode.id + '_label';\n t.rendNodeLabel.setAttribute('for', t.rendNodeCheckbox.id);\n\n // This sets the font-size of the checkbox itself\n t.visPropOld.fontsize = \"0px\";\n board.renderer.updateTextStyle(t, false);\n\n t.rendNodeCheckbox.checked = attr.checked;\n\n t._value = attr.checked;\n\n /**\n * Returns the value of the checkbox element\n * @name Value\n * @memberOf Checkbox.prototype\n * @function\n * @returns {String} value of the checkbox.\n */\n t.Value = function () {\n return this._value;\n };\n\n t.update = function () {\n if (this.needsUpdate) {\n JXG.Text.prototype.update.call(this);\n this._value = this.rendNodeCheckbox.checked;\n }\n return this;\n };\n\n Env.addEvent(t.rendNodeCheckbox, 'change', priv.CheckboxChangeEventHandler, t);\n\n return t;\n };\n\n JXG.registerElement('checkbox', JXG.createCheckbox);\n\n return {\n createCheckbox: JXG.createCheckbox\n };\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true, window: true*/\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n jxg\n utils/env\n utils/type\n */\n\n/**\n * @fileoverview In this file the Text element is defined.\n */\n\ndefine('element/input',[\n 'jxg', 'utils/env', 'utils/type'\n], function (JXG, Env, Type) {\n\n \"use strict\";\n\n var priv = {\n InputInputEventHandler: function (evt) {\n this._value = this.rendNodeInput.value;\n this.board.update();\n }\n };\n\n /**\n * @class This element is used to provide a constructor for special texts containing a\n * HTML form input element.\n * <p>\n * If the width of element is set with the attribute \"cssStyle\", the width of the\n * label must be added.\n * <p>\n * For this element, the attribute \"display\" has to have the value 'html' (which is the default).\n * @pseudo\n * @description\n * @name Input\n * @augments Text\n * @constructor\n * @type JXG.Text\n *\n * @param {number,function_number,function_String_String} x,y,value,label Parent elements for input elements.\n * <p>\n * x and y are the coordinates of the lower left corner of the text box. The position of the text is fixed,\n * x and y are numbers. The position is variable if x or y are functions.\n * <p>\n * The default value of the input element may be given as string.\n * <p>\n * The label of the input element may be given as string.\n *\n * @example\n * // Create an input element at position [1,4].\n * var input = board.create('input', [0, 1, 'sin(x)*x', 'f(x)='], {cssStyle: 'width: 100px'});\n * var f = board.jc.snippet(input.Value(), true, 'x', false);\n * var graph = board.create('functiongraph',[f,\n * function() {\n * var c = new JXG.Coords(JXG.COORDS_BY_SCREEN,[0,0],board);\n * return c.usrCoords[1];\n * },\n * function() {\n * var c = new JXG.Coords(JXG.COORDS_BY_SCREEN,[board.canvasWidth,0],board);\n * return c.usrCoords[1];\n * }\n * ]);\n *\n * board.create('text', [1, 3, '<button onclick=\"updateGraph()\">Update graph</button>']);\n *\n * var updateGraph = function() {\n * graph.Y = board.jc.snippet(input.Value(), true, 'x', false);\n * graph.updateCurve();\n * board.update();\n * }\n * </pre><div class=\"jxgbox\" id=\"JXGc70f55f1-21ba-4719-a37d-a93ae2943faa\" style=\"width: 500px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * var t1_board = JXG.JSXGraph.initBoard('JXGc70f55f1-21ba-4719-a37d-a93ae2943faa', {boundingbox: [-3, 6, 5, -3], axis: true, showcopyright: false, shownavigation: false});\n * var input = t1_board.create('input', [1, 4, 'sin(x)*x', 'f(x)='], {cssStyle: 'width: 100px'});\n * var f = t1_board.jc.snippet(input.Value(), true, 'x', false);\n * var graph = t1_board.create('functiongraph',[f,\n * function() {\n * var c = new JXG.Coords(JXG.COORDS_BY_SCREEN,[0,0],t1_board);\n * return c.usrCoords[1];\n * },\n * function() {\n * var c = new JXG.Coords(JXG.COORDS_BY_SCREEN,[t1_board.canvasWidth,0],t1_board);\n * return c.usrCoords[1];\n * }\n * ]);\n *\n * t1_board.create('text', [1, 3, '<button onclick=\"updateGraph()\">Update graph</button>']);\n *\n * var updateGraph = function() {\n * graph.Y = t1_board.jc.snippet(input.Value(), true, 'x', false);\n * graph.updateCurve();\n * t1_board.update();\n * }\n * </script><pre>\n */\n JXG.createInput = function (board, parents, attributes) {\n var t, par,\n attr = Type.copyAttributes(attributes, board.options, 'input');\n\n par = [parents[0], parents[1],\n '<span style=\"display:inline; white-space:nowrap; padding:0px;\">' +\n '<span></span><input type=\"text\" maxlength=\"' +\n attr.maxlength +\n '\" style=\"width:100%\"/>' +\n '</span>'\n ];\n\n //t = JXG.createText(board, par, attr);\n t = board.create('text', par, attr);\n t.type = Type.OBJECT_TYPE_INPUT;\n\n t.rendNodeLabel = t.rendNode.childNodes[0].childNodes[0];\n t.rendNodeInput = t.rendNode.childNodes[0].childNodes[1];\n t.rendNodeLabel.innerHTML = parents[3];\n t.rendNodeInput.value = parents[2];\n t.rendNodeTag = t.rendNodeInput; // Needed for unified treatment in setAttribute\n t.rendNodeTag.disabled = !!attr.disabled;\n t.rendNodeLabel.id = t.rendNode.id + '_label';\n t.rendNodeInput.id = t.rendNode.id + '_input';\n\n t._value = parents[2];\n t.update = function () {\n if (this.needsUpdate) {\n JXG.Text.prototype.update.call(this);\n this._value = this.rendNodeInput.value;\n }\n return this;\n };\n\n /**\n * Returns the value (content) of the input element\n * @name Value\n * @memberOf Input.prototype\n * @function\n * @returns {String} content of the input field.\n */\n t.Value = function () {\n return this._value;\n };\n\n /**\n * Sets value of the input element.\n * @name set\n * @memberOf Input.prototype\n * @function\n *\n * @param {String} val\n * @returns {JXG.GeometryElement} Reference to the element.\n *\n * @example\n * var i1 = board.create('input', [-3, 4, 'sin(x)', 'f(x)='], {cssStyle: 'width:4em', maxlength: 2});\n * var c1 = board.create('checkbox', [-3, 2, 'label 1'], {});\n * var b1 = board.create('button', [-3, -1, 'Change texts', function () {\n * i1.setText('g(x)');\n * i1.set('cos(x)');\n * c1.setText('label 2');\n * b1.setText('Texts are changed');\n * }],\n * {cssStyle: 'width:400px'});\n *\n * </pre><div id=\"JXG11cac8ff-2354-47e7-9da4-eb298e53de05\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG11cac8ff-2354-47e7-9da4-eb298e53de05',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var i1 = board.create('input', [-3, 4, 'sin(x)', 'f(x)='], {cssStyle: 'width:4em', maxlength: 2});\n * var c1 = board.create('checkbox', [-3, 2, 'label 1'], {});\n * var b1 = board.create('button', [-3, -1, 'Change texts', function () {\n * i1.setText('g(x)');\n * i1.set('cos(x)');\n * c1.setText('label 2');\n * b1.setText('Texts are changed');\n * }],\n * {cssStyle: 'width:400px'});\n *\n * })();\n *\n * </script><pre>\n *\n */\n t.set = function (val) {\n this._value = val;\n this.rendNodeInput.value = val;\n return this;\n };\n\n Env.addEvent(t.rendNodeInput, 'input', priv.InputInputEventHandler, t);\n Env.addEvent(t.rendNodeInput, 'mousedown', function(evt) { if (Type.exists(evt.stopPropagation)) { evt.stopPropagation(); } }, t);\n Env.addEvent(t.rendNodeInput, 'touchstart', function(evt) { if (Type.exists(evt.stopPropagation)) { evt.stopPropagation(); } }, t);\n Env.addEvent(t.rendNodeInput, 'pointerdown', function(evt) { if (Type.exists(evt.stopPropagation)) { evt.stopPropagation(); } }, t);\n\n // This sets the font-size of the input HTML element\n t.visPropOld.fontsize = \"0px\";\n board.renderer.updateTextStyle(t, false);\n\n return t;\n };\n\n JXG.registerElement('input', JXG.createInput);\n\n return {\n createInput: JXG.createInput\n };\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true, window: true*/\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n jxg\n utils/env\n utils/type\n */\n\n/**\n * @fileoverview In this file the Text element is defined.\n */\n\ndefine('element/button',[\n 'jxg', 'utils/env', 'utils/type'\n], function (JXG, Env, Type) {\n\n \"use strict\";\n\n var priv = {\n ButtonClickEventHandler: function () {\n if (this._handler) {\n this._handler();\n }\n this.board.update();\n }\n };\n\n /**\n * @class This element is used to provide a constructor for special texts containing a\n * form button element.\n * <p>\n * For this element, the attribute \"display\" has to have the value 'html' (which is the default).\n *\n * @pseudo\n * @description\n * @name Button\n * @augments Text\n * @constructor\n * @type JXG.Text\n *\n * @param {number,function_number,function_String_function} x,y,label,handler Parent elements for button elements.\n * <p>\n * x and y are the coordinates of the lower left corner of the text box.\n * The position of the text is fixed,\n * x and y are numbers. The position is variable if x or y are functions.\n * <p>\n * The label of the input element may be given as string.\n * <p>\n * The (optional) handler function which is called when the button is pressed.\n *\n * @example\n * var p = board.create('point', [0.5, 0.5], {id: 'p1'});\n *\n * // Create a button element at position [1,2].\n * var button1 = board.create('button', [1, 2, 'Change Y with JavaScript', function() {\n * p.moveTo([p.X(), p.Y() + 0.5], 100);\n * }], {});\n *\n * // Create a button element at position [1,4].\n * var button2 = board.create('button', [1, 4, 'Change Y with JessieCode',\n * \"$('p1').Y = $('p1').Y() - 0.5;\"\n * ], {});\n *\n * </pre><div class=\"jxgbox\" id=\"JXGf19b1bce-dd00-4e35-be97-ff1817d11514\" style=\"width: 500px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * var t1_board = JXG.JSXGraph.initBoard('JXGf19b1bce-dd00-4e35-be97-ff1817d11514', {boundingbox: [-3, 6, 5, -3], axis: true, showcopyright: false, shownavigation: false});\n * var p = t1_board.create('point', [0, -1], {id: 'p1'});\n *\n * // Create a button element at position [1,2].\n * var button1 = t1_board.create('button', [1, 2, 'Change Y with JavaScript', function() {\n * p.moveTo([p.X(), p.Y() + 0.5], 100);\n * }], {});\n *\n * // Create a button element at position [1,4].\n * var button2 = t1_board.create('button', [1, 4, 'Change Y with JessieCode',\n * \"$('p1').Y = $('p1').Y() - 0.5;\"\n * ], {});\n *\n * </script><pre>\n *\n * @example\n * // A toggle button\n * var butt = board.create('button', [-2, -2, 'Off', function() {\n * var txt;\n * butt.value = !butt.value;\n * if (butt.value) {\n * \ttxt = 'On';\n * } else {\n * \ttxt = 'Off';\n * }\n * \tbutt.rendNodeButton.innerHTML = txt;\n * }]);\n *\n * // Set initial value for the button\n * if (!JXG.exists(butt.value)) {\n * \tbutt.value = false;\n * }\n *\n * var p = board.create('point', [2, -2], {\n * \tvisible: () => butt.value\n * });\n *\n *\n *\n * </pre><div id=\"JXGa1eaab8f-c73b-4660-96ce-4ca17bcac4d6\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXGa1eaab8f-c73b-4660-96ce-4ca17bcac4d6',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var butt = board.create('button', [-2, -2, 'Off', function() {\n * var txt;\n * butt.value = !butt.value;\n * if (butt.value) {\n * \ttxt = 'On';\n * } else {\n * \ttxt = 'Off';\n * }\n * \tbutt.rendNodeButton.innerHTML = txt;\n * }]);\n *\n * // Set initial value for the button\n * if (!JXG.exists(butt.value)) {\n * \tbutt.value = false;\n * }\n *\n * var p = board.create('point', [2, -2], {\n * \tvisible: () => butt.value\n * });\n *\n * })();\n *\n * </script><pre>\n *\n * @example\n * var i1 = board.create('input', [-3, 4, 'sin(x)', 'f(x)='], {cssStyle: 'width:4em', maxlength: 2});\n * var c1 = board.create('checkbox', [-3, 2, 'label 1'], {});\n * var b1 = board.create('button', [-3, -1, 'Change texts', function () {\n * i1.setText('g(x)');\n * i1.set('cos(x)');\n * c1.setText('label 2');\n * b1.setText('Texts are changed');\n * }],\n * {cssStyle: 'width:400px'});\n *\n * </pre><div id=\"JXG11cac8ff-2354-47e7-9da4-eb928e53de05\" class=\"jxgbox\" style=\"width: 300px; height: 300px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG11cac8ff-2354-47e7-9da4-eb928e53de05',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var i1 = board.create('input', [-3, 4, 'sin(x)', 'f(x)='], {cssStyle: 'width:4em', maxlength: 2});\n * var c1 = board.create('checkbox', [-3, 2, 'label 1'], {});\n * var b1 = board.create('button', [-3, -1, 'Change texts', function () {\n * i1.setText('g(x)');\n * i1.set('cos(x)');\n * c1.setText('label 2');\n * b1.setText('Texts are changed');\n * }],\n * {cssStyle: 'width:400px'});\n *\n * })();\n *\n * </script><pre>\n *\n */\n JXG.createButton = function (board, parents, attributes) {\n var t, par,\n attr = Type.copyAttributes(attributes, board.options, 'button');\n\n //if (parents.length < 3) {\n //throw new Error(\"JSXGraph: Can't create button with parent types '\" +\n // (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"'.\" +\n // \"\\nPossible parents are: [x, y, label, handler]\");\n //}\n\n par = [parents[0], parents[1], '<button type=\"button\" style=\"width:100%;\"></button>'];\n\n t = board.create('text', par, attr);\n t.type = Type.OBJECT_TYPE_BUTTON;\n\n t.rendNodeButton = t.rendNode.childNodes[0];\n t.rendNodeButton.id = t.rendNode.id + '_button';\n t.rendNodeButton.innerHTML = parents[2];\n\n t.rendNodeTag = t.rendNodeButton; // Needed for unified treatment in setAttribute\n t.rendNodeTag.disabled = !!attr.disabled;\n\n // This sets the font-size of the button text\n t.visPropOld.fontsize = \"0px\";\n board.renderer.updateTextStyle(t, false);\n\n if (parents[3]) {\n if (Type.isString(parents[3])) {\n t._jc = new JXG.JessieCode();\n t._jc.use(board);\n t._handler = function () {\n t._jc.parse(parents[3]);\n };\n } else {\n t._handler = parents[3];\n }\n }\n\n Env.addEvent(t.rendNodeButton, 'click', priv.ButtonClickEventHandler, t);\n Env.addEvent(t.rendNodeButton, 'mousedown', function (evt) { if (Type.exists(evt.stopPropagation)) { evt.stopPropagation(); } }, t);\n Env.addEvent(t.rendNodeButton, 'touchstart', function (evt) { if (Type.exists(evt.stopPropagation)) { evt.stopPropagation(); } }, t);\n Env.addEvent(t.rendNodeButton, 'pointerdown', function (evt) { if (Type.exists(evt.stopPropagation)) { evt.stopPropagation(); } }, t);\n\n return t;\n };\n\n JXG.registerElement('button', JXG.createButton);\n\n return {\n createButton: JXG.createButton\n };\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Michael Gerhaeuser,\n Carsten Miller,\n Bianca Valentin,\n Alfred Wassermann,\n Peter Wilfahrt\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n\n\n/*global JXG: true, define: true, window: true*/\n/*jslint nomen: true, plusplus: true*/\n\n/* depends:\n jxg\n base/constants\n base/coords\n base/element\n math/math\n utils/type\n */\n\n/**\n * @fileoverview In this file the ForeignObject element is defined.\n */\n\n define('base/foreignobject',[\n 'jxg', 'base/constants', 'base/coords', 'base/element', 'math/math', 'utils/type', 'base/coordselement'\n], function (JXG, Const, Coords, GeometryElement, Mat, Type, CoordsElement) {\n\n \"use strict\";\n\n /**\n * Construct and handle SVG foreignObjects.\n *\n * @class Creates a new foreignObject object. Do not use this constructor to create a foreignObject. Use {@link JXG.Board#create} with\n * type {@link foreignobject} instead.\n * @augments JXG.GeometryElement\n * @augments JXG.CoordsElement\n * @param {string|JXG.Board} board The board the new foreignObject is drawn on.\n * @param {Array} coordinates An array with the user coordinates of the foreignObject.\n * @param {Object} attributes An object containing visual and - optionally - a name and an id.\n * @param {string|function} url An URL string or a function returning an URL string.\n * @param {Array} size Array containing width and height of the foreignObject in user coordinates.\n *\n */\n JXG.ForeignObject = function (board, coords, attributes, content, size) {\n this.constructor(board, attributes, Const.OBJECT_TYPE_FOREIGNOBJECT, Const.OBJECT_CLASS_OTHER);\n this.element = this.board.select(attributes.anchor);\n this.coordsConstructor(coords);\n\n this._useUserSize = false;\n\n /**\n * Array of length two containing [width, height] of the foreignObject in pixel.\n * @type Array\n */\n this.size = [1, 1];\n if (Type.exists(size) && size.length > 0) {\n this._useUserSize = true;\n\n this.W = Type.createFunction(size[0], this.board, '');\n this.H = Type.createFunction(size[1], this.board, '');\n this.usrSize = [this.W(), this.H()];\n }\n\n // this.size = [Math.abs(this.usrSize[0] * board.unitX), Math.abs(this.usrSize[1] * board.unitY)];\n\n /**\n * 'href' of the foreignObject.\n * @type {string}\n */\n this.content = content;\n\n this.elType = 'foreignobject';\n\n // span contains the anchor point and the two vectors\n // spanning the foreignObject rectangle.\n // this.span = [\n // this.coords.usrCoords.slice(0),\n // [this.coords.usrCoords[0], this.W(), 0],\n // [this.coords.usrCoords[0], 0, this.H()]\n // ];\n //this.parent = board.select(attributes.anchor);\n\n this.id = this.board.setId(this, 'Im');\n\n this.board.renderer.drawForeignObject(this);\n this.board.finalizeAdding(this);\n\n this.methodMap = JXG.deepCopy(this.methodMap, {\n addTransformation: 'addTransform',\n trans: 'addTransform'\n });\n };\n\n JXG.ForeignObject.prototype = new GeometryElement();\n Type.copyPrototypeMethods(JXG.ForeignObject, CoordsElement, 'coordsConstructor');\n\n JXG.extend(JXG.ForeignObject.prototype, /** @lends JXG.ForeignObject.prototype */ {\n\n /**\n * Checks whether (x,y) is over or near the image;\n * @param {Number} x Coordinate in x direction, screen coordinates.\n * @param {Number} y Coordinate in y direction, screen coordinates.\n * @returns {Boolean} True if (x,y) is over the image, False otherwise.\n */\n hasPoint: function (x, y) {\n var dx, dy, r, type, prec,\n c, v, p, dot,\n len = this.transformations.length;\n\n if (Type.isObject(Type.evaluate(this.visProp.precision))) {\n type = this.board._inputDevice;\n prec = Type.evaluate(this.visProp.precision[type]);\n } else {\n // 'inherit'\n prec = this.board.options.precision.hasPoint;\n }\n\n // Easy case: no transformation\n if (len === 0) {\n dx = x - this.coords.scrCoords[1];\n dy = this.coords.scrCoords[2] - y;\n r = prec;\n\n return dx >= -r && dx - this.size[0] <= r &&\n dy >= -r && dy - this.size[1] <= r;\n }\n\n // foreignObject is transformed\n c = new Coords(Const.COORDS_BY_SCREEN, [x, y], this.board);\n // v is the vector from anchor point to the drag point\n c = c.usrCoords;\n v = [c[0] - this.span[0][0],\n c[1] - this.span[0][1],\n c[2] - this.span[0][2]];\n dot = Mat.innerProduct; // shortcut\n\n // Project the drag point to the sides.\n p = dot(v, this.span[1]);\n if (0 <= p && p <= dot(this.span[1], this.span[1])) {\n p = dot(v, this.span[2]);\n\n if (0 <= p && p <= dot(this.span[2], this.span[2])) {\n return true;\n }\n }\n return false;\n },\n\n /**\n * Recalculate the coordinates of lower left corner and the width and height.\n *\n * @returns {JXG.ForeignObject} A reference to the element\n * @private\n */\n update: function (fromParent) {\n if (!this.needsUpdate) {\n return this;\n }\n this.updateCoords(fromParent);\n this.updateSize();\n // this.updateSpan();\n return this;\n },\n\n /**\n * Send an update request to the renderer.\n * @private\n */\n updateRenderer: function () {\n return this.updateRendererGeneric('updateForeignObject');\n },\n\n /**\n * Updates the internal arrays containing size of the foreignObject.\n * @returns {JXG.ForeignObject} A reference to the element\n * @private\n */\n updateSize: function () {\n var bb = [0, 0];\n\n if (this._useUserSize) {\n this.usrSize = [this.W(), this.H()];\n this.size = [Math.abs(this.usrSize[0] * this.board.unitX),\n Math.abs(this.usrSize[1] * this.board.unitY)];\n } else {\n if (this.rendNode.hasChildNodes()) {\n bb = this.rendNode.childNodes[0].getBoundingClientRect();\n this.size = [bb.width, bb.height];\n }\n }\n\n return this;\n },\n\n /**\n * Update the anchor point of the foreignObject, i.e. the lower left corner\n * and the two vectors which span the rectangle.\n * @returns {JXG.ForeignObject} A reference to the element\n * @private\n *\n */\n updateSpan: function () {\n var i, j, len = this.transformations.length, v = [];\n\n if (len === 0) {\n this.span = [[this.Z(), this.X(), this.Y()],\n [this.Z(), this.W(), 0],\n [this.Z(), 0, this.H()]];\n } else {\n // v contains the three defining corners of the rectangle/image\n v[0] = [this.Z(), this.X(), this.Y()];\n v[1] = [this.Z(), this.X() + this.W(), this.Y()];\n v[2] = [this.Z(), this.X(), this.Y() + this.H()];\n\n // Transform the three corners\n for (i = 0; i < len; i++) {\n for (j = 0; j < 3; j++) {\n v[j] = Mat.matVecMult(this.transformations[i].matrix, v[j]);\n }\n }\n // Normalize the vectors\n for (j = 0; j < 3; j++) {\n v[j][1] /= v[j][0];\n v[j][2] /= v[j][0];\n v[j][0] /= v[j][0];\n }\n // Compute the two vectors spanning the rectangle\n // by subtracting the anchor point.\n for (j = 1; j < 3; j++) {\n v[j][0] -= v[0][0];\n v[j][1] -= v[0][1];\n v[j][2] -= v[0][2];\n }\n this.span = v;\n }\n\n return this;\n },\n\n addTransform: function (transform) {\n var i;\n\n if (Type.isArray(transform)) {\n for (i = 0; i < transform.length; i++) {\n this.transformations.push(transform[i]);\n }\n } else {\n this.transformations.push(transform);\n }\n\n return this;\n },\n\n // Documented in element.js\n getParents: function () {\n var p = [this.url, [this.Z(), this.X(), this.Y()], this.usrSize];\n\n if (this.parents.length !== 0) {\n p = this.parents;\n }\n\n return p;\n },\n\n /**\n * Set the width and height of the foreignObject. After setting a new size,\n * board.update() or foreignobject.fullUpdate()\n * has to be called to make the change visible.\n * @param {number, function, string} width Number, function or string\n * that determines the new width of the foreignObject\n * @param {number, function, string} height Number, function or string\n * that determines the new height of the foreignObject\n * @returns {JXG.ForeignObject} A reference to the element\n *\n */\n setSize: function(width, height) {\n this.W = Type.createFunction(width, this.board, '');\n this.H = Type.createFunction(height, this.board, '');\n this._useUserSize = true;\n\n return this;\n },\n\n /**\n * Returns the width of the foreignObject in user coordinates.\n * @returns {number} width of the image in user coordinates\n */\n W: function() {}, // Needed for docs, defined in constructor\n\n /**\n * Returns the height of the foreignObject in user coordinates.\n * @returns {number} height of the image in user coordinates\n */\n H: function() {} // Needed for docs, defined in constructor\n });\n\n /**\n * @class This element is used to provide a constructor for arbitrary content in\n * an SVG foreignObject container.\n * <p>\n * Instead of board.create('foreignobject') the shortcut board.create('fo') may be used.\n * \n * <p style=\"background-color:#dddddd; padding:10px\"><b>NOTE:</b> In Safari up to version 15, a foreignObject does not obey the layer structure\n * if it contains <video> or <iframe> tags, as well as elements which are \n * positioned with <tt>position:absolute|relative|fixed</tt>. In this case, the foreignobject will be \n * \"above\" the JSXGraph construction.\n * </p>\n * \n * @pseudo\n * @description\n * @name ForeignObject\n * @augments JXG.ForeignObject\n * @constructor\n * @type JXG.ForeignObject\n *\n * @param {String} content HTML content of the foreignObject. May also be <video> or <iframe>\n * @param {Array} position Position of the foreignObject given by [x, y] in user coordinates. Same as for images.\n * @param {Array} [size] (Optional) argument size of the foreignObject in user coordinates. If not given, size is specified by the HTML attributes\n * or CSS properties of the content.\n *\n * @see Image\n *\n * @example\n * var p = board.create('point', [1, 7], {size: 16});\n * var fo = board.create('foreignobject', [\n * '<video width=\"300\" height=\"200\" src=\"https://eucbeniki.sio.si/vega2/278/Video_metanje_oge_.mp4\" type=\"html5video\" controls>',\n * [0, -3], [9, 6]],\n * {layer: 8, fixed: true}\n * );\n *\n * </pre><div id=\"JXG0c122f2c-3671-4a28-80a9-f4c523eeda89\" class=\"jxgbox\" style=\"width: 500px; height: 500px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG0c122f2c-3671-4a28-80a9-f4c523eeda89',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var p = board.create('point', [1, 7], {size: 16});\n * var fo = board.create('foreignobject', [\n * '<video width=\"300\" height=\"200\" src=\"https://eucbeniki.sio.si/vega2/278/Video_metanje_oge_.mp4\" type=\"html5video\" controls>',\n * [0, -3], [9, 6]],\n * {layer: 8, fixed: true}\n * );\n *\n * })();\n *\n * </script><pre>\n *\n * @example\n * var p = board.create('point', [1, 7], {size: 16});\n * var fo = board.create('fo', [\n * '<div style=\"background-color:blue; color: yellow; padding:20px; width:200px; height:50px; \">Hello</div>',\n * [-7, -6]],\n * {layer: 1, fixed: false}\n * );\n *\n * </pre><div id=\"JXG1759c868-1a4a-4767-802c-91f84902e3ec\" class=\"jxgbox\" style=\"width: 500px; height: 500px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG1759c868-1a4a-4767-802c-91f84902e3ec',\n * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});\n * var p = board.create('point', [1, 7], {size: 16});\n * var fo = board.create('foreignobject', [\n * '<div style=\"background-color:blue; color: yellow; padding:20px; width:200px; height:50px; \">Hello</div>',\n * [-7, -6]],\n * {layer: 1, fixed: false}\n * );\n *\n * })();\n *\n * </script><pre>\n *\n * @example\n * board.renderer.container.style.backgroundColor = 'lightblue';\n * var points = [];\n * points.push( board.create('point', [-2, 3.5], {fixed:false,color: 'yellow', size: 6,name:'6 am'}) );\n * points.push( board.create('point', [0, 3.5], {fixed:false,color: 'yellow', size: 6,name:'12 pm'}) );\n * points.push( board.create('point', [2, 3.5], {fixed:false,color: 'yellow', size: 6,name:'6 pm'}) );\n *\n * var fo = board.create('fo', [\n * '<video width=\"100%\" height=\"100%\" src=\"https://benedu.net/moodle/aaimg/ajx_img/astro/tr/1vd.mp4\" type=\"html5video\" controls>',\n * [-6, -4], [12, 8]],\n * {layer: 0, fixed: true}\n * );\n *\n * var f = JXG.Math.Numerics.lagrangePolynomial(points);\n * var graph = board.create('functiongraph', [f, -10, 10], {fixed:true,strokeWidth:3, layer: 8});\n *\n * </pre><div id=\"JXGc3fc5520-13aa-4f66-abaa-42e9dc3fbf3f\" class=\"jxgbox\" style=\"width: 500px; height: 500px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXGc3fc5520-13aa-4f66-abaa-42e9dc3fbf3f',\n * {boundingbox: [-6,4,6,-4], axis: true, showcopyright: false, shownavigation: false});\n * board.renderer.container.style.backgroundColor = 'lightblue';\n * var points = [];\n * points.push( board.create('point', [-2, 3.5], {fixed:false,color: 'yellow', size: 6,name:'6 am'}) );\n * points.push( board.create('point', [0, 3.5], {fixed:false,color: 'yellow', size: 6,name:'12 pm'}) );\n * points.push( board.create('point', [2, 3.5], {fixed:false,color: 'yellow', size: 6,name:'6 pm'}) );\n *\n * var fo = board.create('fo', [\n * '<video width=\"100%\" height=\"100%\" src=\"https://benedu.net/moodle/aaimg/ajx_img/astro/tr/1vd.mp4\" type=\"html5video\" controls>',\n * [-6, -4], [12, 8]],\n * {layer: 0, fixed: true}\n * );\n *\n * var f = JXG.Math.Numerics.lagrangePolynomial(points);\n * var graph = board.create('functiongraph', [f, -10, 10], {fixed:true,strokeWidth:3, layer: 8});\n *\n * })();\n *\n * </script><pre>\n *\n * Video \"24-hour time-lapse in Cascais, Portugal. Produced by Nuno Miguel Duarte\" adapted from\n * <a href=\"https://www.pbslearningmedia.org/resource/buac18-k2-sci-ess-sunposition/changing-position-of-the-sun-in-the-sky/\">https://www.pbslearningmedia.org/resource/buac18-k2-sci-ess-sunposition/changing-position-of-the-sun-in-the-sky/</a>,\n * ©2016 Nuno Miguel Duarte.\n *\n */\n JXG.createForeignObject = function (board, parents, attributes) {\n var attr, fo,\n content = parents[0],\n coords = parents[1],\n size = [];\n\n if (parents.length >= 2) {\n size = parents[2];\n }\n\n attr = Type.copyAttributes(attributes, board.options, 'foreignobject');\n fo = CoordsElement.create(JXG.ForeignObject, board, coords, attr, content, size);\n if (!fo) {\n throw new Error(\"JSXGraph: Can't create foreignObject with parent types '\" +\n (typeof parents[0]) + \"' and '\" + (typeof parents[1]) + \"'.\" +\n \"\\nPossible parent types: [string, [x, y], [w, h]], [string, [x, y]], [element,transformation]\");\n }\n\n return fo;\n };\n\n JXG.registerElement('foreignobject', JXG.createForeignObject);\n JXG.registerElement('fo', JXG.createForeignObject);\n\n return {\n ForeignObject: JXG.ForeignObject,\n createForeignobject: JXG.createForeignObject\n };\n});\n\n/*global JXG:true, define: true*/\n\ndefine('options3d',[\n 'jxg', 'options'\n], function (JXG, Options) {\n\n \"use strict\";\n\n JXG.extend(Options, {\n\n infobox: {\n strokeColor: 'black'\n },\n\n axes3d: {\n /**#@+\n * @visprop\n */\n\n /**\n * Position of the main axes in a View3D element. Possible values are\n * 'center' and 'border'.\n *\n * @type String\n * @name View3D#axesPosition\n * @default 'center'\n */\n axesPosition: 'center', // Possible values: 'center', otherwise: border\n\n // Main axes\n\n /**\n * Attributes of the 3D x-axis.\n *\n * @type Line3D\n * @name View3D#xAxis\n */\n xAxis: { visible: true, point2: {name: 'x'}},\n\n /**\n * Attributes of the 3D y-axis.\n *\n * @type Line3D\n * @name View3D#yAxis\n */\n yAxis: { visible: true, point2: {name: 'y'}},\n\n /**\n * Attributes of the 3D z-axis.\n *\n * @type Line3D\n * @name View3D#zAxis\n */\n zAxis: { visible: true, point2: {name: 'z'}},\n\n // Planes\n /**\n * Attributes of the 3D plane orthogonal to the x-axis at the \"rear\" of the cube.\n * @type Plane3D\n * @name View3D#xPlaneRear\n */\n xPlaneRear: { visible: true, layer: 0, mesh3d: { layer: 1 } },\n /**\n * Attributes of the 3D plane orthogonal to the y-axis at the \"rear\" of the cube.\n * @type Plane3D\n * @name View3D#yPlaneRear\n */\n yPlaneRear: { visible: true, layer: 0, mesh3d: { layer: 1 } },\n /**\n * Attributes of the 3D plane orthogonal to the z-axis at the \"rear\" of the cube.\n * @type Plane3D\n * @name View3D#zPlaneRear\n */\n zPlaneRear: { visible: true, layer: 0, mesh3d: { layer: 1 } },\n\n /**\n * Attributes of the 3D plane orthogonal to the x-axis at the \"front\" of the cube.\n * @type Plane3D\n * @name View3D#xPlaneFront\n */\n xPlaneFront: { visible: false, layer: 0, mesh3d: { layer: 1 } },\n /**\n * Attributes of the 3D plane orthogonal to the y-axis at the \"front\" of the cube.\n * @type Plane3D\n * @name View3D#yPlaneFront\n */\n yPlaneFront: { visible: false, layer: 0, mesh3d: { layer: 1 } },\n /**\n * Attributes of the 3D plane orthogonal to the z-axis at the \"front\" of the cube.\n * @type Plane3D\n * @name View3D#zPlaneFront\n */\n zPlaneFront: { visible: false, layer: 0, mesh3d: { layer: 1 } },\n\n // Axes on the planes\n /**\n * Attributes of the 3D y-axis on the 3D plane orthogonal to the x-axis at the \"rear\" of the cube.\n * @type Plane3D\n * @name View3D#xPlaneRearYAxis\n */\n xPlaneRearYAxis: {visible: 'inherit', strokeColor: '#888888', strokeWidth: 1},\n /**\n * Attributes of the 3D z-axis on the 3D plane orthogonal to the x-axis at the \"rear\" of the cube.\n * @type Plane3D\n * @name View3D#xPlaneRearZAxis\n */\n xPlaneRearZAxis: {visible: 'inherit', strokeColor: '#888888', strokeWidth: 1},\n /**\n * Attributes of the 3D y-axis on the 3D plane orthogonal to the x-axis at the \"front\" of the cube.\n * @type Plane3D\n * @name View3D#xPlaneFrontYAxis\n */\n xPlaneFrontYAxis: {visible: 'inherit', strokeColor: '#888888', strokeWidth: 1},\n /**\n * Attributes of the 3D z-axis on the 3D plane orthogonal to the x-axis at the \"front\" of the cube.\n * @type Plane3D\n * @name View3D#xPlaneFrontZAxis\n */\n xPlaneFrontZAxis: {visible: 'inherit', strokeColor: '#888888', strokeWidth: 1},\n\n /**\n * Attributes of the 3D x-axis on the 3D plane orthogonal to the y-axis at the \"rear\" of the cube.\n * @type Plane3D\n * @name View3D#yPlaneRearXAxis\n */\n yPlaneRearXAxis: {visible: 'inherit', strokeColor: '#888888', strokeWidth: 1},\n /**\n * Attributes of the 3D z-axis on the 3D plane orthogonal to the y-axis at the \"rear\" of the cube.\n * @type Plane3D\n * @name View3D#yPlaneRearZAxis\n */\n yPlaneRearZAxis: {visible: 'inherit', strokeColor: '#888888', strokeWidth: 1},\n /**\n * Attributes of the 3D x-axis on the 3D plane orthogonal to the y-axis at the \"front\" of the cube.\n * @type Plane3D\n * @name View3D#yPlaneFrontXAxis\n */\n yPlaneFrontXAxis: {visible: 'inherit', strokeColor: '#888888', strokeWidth: 1},\n /**\n * Attributes of the 3D z-axis on the 3D plane orthogonal to the y-axis at the \"front\" of the cube.\n * @type Plane3D\n * @name View3D#yPlaneFrontZAxis\n */\n yPlaneFrontZAxis: {visible: 'inherit', strokeColor: '#888888', strokeWidth: 1},\n\n /**\n * Attributes of the 3D x-axis on the 3D plane orthogonal to the z-axis at the \"rear\" of the cube.\n * @type Plane3D\n * @name View3D#zPlaneRearXAxis\n */\n zPlaneRearXAxis: {visible: 'inherit', strokeColor: '#888888', strokeWidth: 1},\n /**\n * Attributes of the 3D y-axis on the 3D plane orthogonal to the z-axis at the \"rear\" of the cube.\n * @type Plane3D\n * @name View3D#zPlaneRearYAxis\n */\n zPlaneRearYAxis: {visible: 'inherit', strokeColor: '#888888', strokeWidth: 1},\n /**\n * Attributes of the 3D x-axis on the 3D plane orthogonal to the z-axis at the \"front\" of the cube.\n * @type Plane3D\n * @name View3D#zPlaneFrontXAxis\n */\n zPlaneFrontXAxis: {visible: 'inherit', strokeColor: '#888888', strokeWidth: 1},\n /**\n * Attributes of the 3D y-axis on the 3D plane orthogonal to the z-axis at the \"front\" of the cube.\n * @type Plane3D\n * @name View3D#zPlaneFrontYAxis\n */\n zPlaneFrontYAxis: {visible: 'inherit', strokeColor: '#888888', strokeWidth: 1}\n\n /**#@-*/\n },\n\n axis3d: {\n highlight: false,\n strokecolor: 'black',\n strokeWidth: 1,\n tabindex: null,\n\n point1: { visible: false, name: '' },\n point2: { visible: false, name: '', label: { visible: true } }\n },\n\n mesh3d: {\n strokeWidth: 1,\n strokeColor: '#9a9a9a',\n strokeOpacity: 0.6,\n highlight: false,\n fillColor: '#9a9a9a',\n fillOpacity: 0.1,\n tabindex: null,\n\n visible: 'inherit'\n },\n\n line3d: {\n strokeWidth: 1,\n strokeColor: 'black',\n fixed: true,\n tabindex: null,\n\n gradient: 'linear',\n gradientSecondColor: '#ffffff',\n\n point1: {visible: false, name: ''},\n point2: {visible: false, name: ''}\n },\n\n plane3d: {\n strokeWidth: 0,\n strokeColor: 'black',\n strokeOpacity: 1,\n highlight: false,\n tabindex: null,\n\n gradient: 'linear',\n gradientSecondColor: '#ffffff',\n gradientAngle: Math.PI,\n fillColor: '#a7a7a7',\n fillOpacity: 0.6\n },\n\n point3d: {\n strokeWidth: 0,\n gradient: 'radial',\n gradientSecondColor: '#555555',\n fillColor: 'yellow',\n highlightStrokeColor: '#555555'\n },\n\n surface3d: {\n /**#@+\n * @visprop\n */\n\n highlight: false,\n tabindex: -1,\n strokeWidth: 1,\n\n /**\n * Number of intervals the mesh is divided into in direction of parameter u.\n * @type Number\n * @name Surface3D#stepsU\n */\n stepsU: 30,\n\n /**\n * Number of intervals the mesh is divided into in direction of parameter v.\n * @type Number\n * @name Surface3D#stepsV\n */\n stepsV: 30\n\n /**#@-*/\n },\n\n view3d: {\n needsRegularUpdate: true\n }\n\n });\n\n return JXG.Options;\n});\n\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Carsten Miller,\n Andreas Walter,\n Alfred Wassermann\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n/*global JXG:true, define: true*/\n\ndefine('3d/threed',['jxg'\n], function (JXG) {\n \"use strict\";\n\n JXG.ThreeD = {};\n\n return JXG.ThreeD;\n});\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Carsten Miller,\n Andreas Walter,\n Alfred Wassermann\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n/*global JXG:true, define: true*/\n\ndefine('3d/view3d',['jxg', 'options', 'base/constants', 'utils/type', 'math/math', 'base/element', '3d/threed',\n], function (JXG, Options, Const, Type, Mat, GeometryElement, ThreeD) {\n \"use strict\";\n\n ThreeD.View3D = function (board, parents, attributes) {\n var bbox3d, coords, size;\n this.constructor(board, attributes, Const.OBJECT_TYPE_VIEW3D, Const.OBJECT_CLASS_CURVE);\n\n bbox3d = parents[2]; // [[x1, x2], [y1,y2], [z1,z2]]\n coords = parents[0]; // llft corner\n size = parents[1]; // [w, h]\n\n /**\n * \"Namespace\" for all 3D handling\n */\n this.D3 = {};\n\n /**\n * An associative array containing all geometric objects belonging to the view.\n * Key is the id of the object and value is a reference to the object.\n * @type Object\n */\n this.D3.objects = {};\n\n /**\n * An array containing all geometric objects in this view in the order of construction.\n * @type Array\n */\n this.D3.objectsList = [];\n\n /**\n * @type {Object} contains the axes of the view or null\n * @default null\n */\n this.D3.defaultAxes = null;\n\n /**\n * 3D-to-2D transformation matrix\n * @type {Array} 3 x 4 mattrix\n */\n this.D3.matrix = [\n [1, 0, 0, 0],\n [0, 1, 0, 0],\n [0, 0, 1, 0]\n ];\n\n // Bounding box (cube) [[x1, x2], [y1,y2], [z1,z2]]:\n this.D3.bbox3d = bbox3d;\n this.D3.coords = coords;\n this.D3.size = size;\n\n /**\n * Distance of the view to the origin. In other words, its\n * the radius of the sphere where the camera sits.\n */\n this.D3.r = -1;\n\n this.timeoutAzimuth = null;\n\n this.id = this.board.setId(this, 'V');\n this.board.finalizeAdding(this);\n this.elType = 'view3d';\n this.methodMap = Type.deepCopy(this.methodMap, {\n });\n };\n ThreeD.View3D.prototype = new GeometryElement();\n\n JXG.extend(ThreeD.View3D.prototype, /** @lends ThreeD.View3D.prototype */ {\n create: function (elementType, parents, attributes) {\n var prefix = [],\n is3D = false,\n el;\n\n if (elementType.indexOf('3d') > 0) {\n is3D = true;\n prefix.push(this);\n }\n el = this.board.create(elementType, prefix.concat(parents), attributes);\n if (true || is3D) {\n this.add(el);\n }\n return el;\n },\n\n add: function (el) {\n this.D3.objects[el.id] = el;\n this.D3.objectsList.push(el);\n },\n\n /**\n * Update 3D-to-2D transformation matrix with the actual\n * elevation and azimuth angles.\n *\n * @private\n */\n update: function () {\n var D3 = this.D3,\n e, r, a, f, mat;\n\n if (!Type.exists(D3.el_slide) ||\n !Type.exists(D3.az_slide) ||\n !this.needsUpdate) {\n return this;\n }\n\n e = D3.el_slide.Value();\n r = D3.r;\n a = D3.az_slide.Value();\n f = r * Math.sin(e);\n mat = [[1, 0, 0,], [0, 1, 0], [0, 0, 1]];\n\n D3.matrix = [\n [1, 0, 0, 0],\n [0, 1, 0, 0],\n [0, 0, 1, 0]\n ];\n\n D3.matrix[1][1] = r * Math.cos(a);\n D3.matrix[1][2] = -r * Math.sin(a);\n D3.matrix[2][1] = f * Math.sin(a);\n D3.matrix[2][2] = f * Math.cos(a);\n D3.matrix[2][3] = Math.cos(e);\n\n if (true) {\n mat[1][1] = D3.size[0] / (D3.bbox3d[0][1] - D3.bbox3d[0][0]); // w / d_x\n mat[2][2] = D3.size[1] / (D3.bbox3d[1][1] - D3.bbox3d[1][0]); // h / d_y\n mat[1][0] = D3.coords[0] - mat[1][1] * D3.bbox3d[0][0]; // llft_x\n mat[2][0] = D3.coords[1] - mat[2][2] * D3.bbox3d[1][0]; // llft_y\n\n D3.matrix = Mat.matMatMult(mat, D3.matrix);\n }\n\n return this;\n },\n\n updateRenderer: function () {\n this.needsUpdate = false;\n return this;\n },\n\n /**\n * Project 3D coordinates to 2D board coordinates\n * The 3D coordinates are provides as three numbers x, y, z or one array of length 3.\n *\n * @param {Number|Array} x\n * @param {[Number]} y\n * @param {[Number]} z\n * @returns {Array} Array of length 3 containing the projection on to the board\n * in homogeneous user coordinates.\n */\n project3DTo2D: function (x, y, z) {\n var vec;\n if (arguments.length === 3) {\n vec = [1, x, y, z];\n } else {\n // Argument is an array\n if (x.length === 3) {\n vec = [1].concat(x);\n } else {\n vec = x;\n }\n }\n return Mat.matVecMult(this.D3.matrix, vec);\n },\n\n /**\n * Project a 2D coordinate to the plane through the origin\n * defined by its normal vector `normal`.\n *\n * @param {JXG.Point} point\n * @param {Array} normal\n * @returns Array of length 4 containing the projected\n * point in homogeneous coordinates.\n */\n project2DTo3DPlane: function (point, normal, foot) {\n var mat, rhs, d, le,\n n = normal.slice(1),\n sol = [1, 0, 0, 0];\n\n foot = foot || [1, 0, 0, 0];\n le = Mat.norm(n, 3);\n d = Mat.innerProduct(foot.slice(1), n, 3) / le;\n\n mat = this.D3.matrix.slice(0, 3); // True copy\n mat.push([0].concat(n));\n\n // 2D coordinates of point:\n rhs = point.coords.usrCoords.concat([d]);\n try {\n // Prevent singularity in case elevation angle is zero\n if (mat[2][3] === 1.0) {\n mat[2][1] = mat[2][2] = Mat.eps * 0.001;\n }\n sol = Mat.Numerics.Gauss(mat, rhs);\n } catch (err) {\n sol = [0, NaN, NaN, NaN];\n }\n\n return sol;\n },\n\n project3DToCube: function (c3d) {\n var cube = this.D3.bbox3d;\n if (c3d[1] < cube[0][0]) { c3d[1] = cube[0][0]; }\n if (c3d[1] > cube[0][1]) { c3d[1] = cube[0][1]; }\n if (c3d[2] < cube[1][0]) { c3d[2] = cube[1][0]; }\n if (c3d[2] > cube[1][1]) { c3d[2] = cube[1][1]; }\n if (c3d[3] < cube[2][0]) { c3d[3] = cube[2][0]; }\n if (c3d[3] > cube[2][1]) { c3d[3] = cube[2][1]; }\n\n return c3d;\n },\n\n intersectionLineCube: function (p, d, r) {\n var rnew, i, r0, r1;\n\n rnew = r;\n for (i = 0; i < 3; i++) {\n if (d[i] !== 0) {\n r0 = (this.D3.bbox3d[i][0] - p[i]) / d[i];\n r1 = (this.D3.bbox3d[i][1] - p[i]) / d[i];\n if (r < 0) {\n rnew = Math.max(rnew, Math.min(r0, r1));\n } else {\n rnew = Math.min(rnew, Math.max(r0, r1));\n }\n }\n }\n return rnew;\n },\n\n isInCube: function (q) {\n return q[0] > this.D3.bbox3d[0][0] - Mat.eps && q[0] < this.D3.bbox3d[0][1] + Mat.eps &&\n q[1] > this.D3.bbox3d[1][0] - Mat.eps && q[1] < this.D3.bbox3d[1][1] + Mat.eps &&\n q[2] > this.D3.bbox3d[2][0] - Mat.eps && q[2] < this.D3.bbox3d[2][1] + Mat.eps;\n },\n\n /**\n *\n * @param {*} plane1\n * @param {*} plane2\n * @param {*} d\n * @returns Array of length 2 containing the coordinates of the defining points of\n * of the intersection segment.\n */\n intersectionPlanePlane: function(plane1, plane2, d) {\n var ret = [[], []],\n p, dir, r, q;\n\n d = d || plane2.D3.d;\n\n p = Mat.Geometry.meet3Planes(plane1.D3.normal, plane1.D3.d, plane2.D3.normal, d,\n Mat.crossProduct(plane1.D3.normal, plane2.D3.normal), 0);\n dir = Mat.Geometry.meetPlanePlane(plane1.D3.dir1, plane1.D3.dir2, plane2.D3.dir1, plane2.D3.dir2);\n r = this.intersectionLineCube(p, dir, Infinity);\n q = Mat.axpy(r, dir, p);\n if (this.isInCube(q)) {\n ret[0] = q;\n }\n r = this.intersectionLineCube(p, dir, -Infinity);\n q = Mat.axpy(r, dir, p);\n if (this.isInCube(q) ) {\n ret[1] = q;\n }\n return ret;\n },\n\n getMesh: function (X, Y, Z, interval_u, interval_v) {\n var i_u, i_v, u, v, c2d,\n delta_u, delta_v,\n p = [0, 0, 0],\n steps_u = interval_u[2],\n steps_v = interval_v[2],\n\n dataX = [],\n dataY = [];\n\n delta_u = (Type.evaluate(interval_u[1]) - Type.evaluate(interval_u[0])) / (steps_u);\n delta_v = (Type.evaluate(interval_v[1]) - Type.evaluate(interval_v[0])) / (steps_v);\n\n for (i_u = 0; i_u <= steps_u; i_u++) {\n u = interval_u[0] + delta_u * i_u;\n for (i_v = 0; i_v <= steps_v; i_v++) {\n v = interval_v[0] + delta_v * i_v;\n p[0] = X(u, v);\n p[1] = Y(u, v);\n p[2] = Z(u, v);\n c2d = this.project3DTo2D(p);\n dataX.push(c2d[1]);\n dataY.push(c2d[2]);\n }\n dataX.push(NaN);\n dataY.push(NaN);\n }\n\n for (i_v = 0; i_v <= steps_v; i_v++) {\n v = interval_v[0] + delta_v * i_v;\n for (i_u = 0; i_u <= steps_u; i_u++) {\n u = interval_u[0] + delta_u * i_u;\n p[0] = X(u, v);\n p[1] = Y(u, v);\n p[2] = Z(u, v);\n c2d = this.project3DTo2D(p);\n dataX.push(c2d[1]);\n dataY.push(c2d[2]);\n }\n dataX.push(NaN);\n dataY.push(NaN);\n }\n\n return [dataX, dataY];\n },\n\n animateAzimuth: function () {\n var s = this.D3.az_slide._smin,\n e = this.D3.az_slide._smax,\n sdiff = e - s,\n newVal = this.D3.az_slide.Value() + 0.1;\n\n this.D3.az_slide.position = ((newVal - s) / sdiff);\n if (this.D3.az_slide.position > 1) {\n this.D3.az_slide.position = 0.0;\n }\n this.board.update();\n\n this.timeoutAzimuth = setTimeout(function () { this.animateAzimuth(); }.bind(this), 200);\n },\n\n stopAzimuth: function () {\n clearTimeout(this.timeoutAzimuth);\n this.timeoutAzimuth = null;\n }\n });\n\n /**\n * @class This element creates a 3D view.\n * @pseudo\n * @description A View3D element provides the container and the methods to create and display 3D elements.\n * It is contained in a JSXGraph board.\n * @name View3D\n * @augments JXG.View3D\n * @constructor\n * @type Object\n * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {Array_Array_Array} lower,dim,cube Here, lower is an array of the form [x, y] and\n * dim is an array of the form [w, h].\n * The arrays [x, y] and [w, h] define the 2D frame into which the 3D cube is\n * (roughly) projected.\n * cube is an array of the form [[x1, x2], [y1, y2], [z1, z2]]\n * which determines the coordinate ranges of the 3D cube.\n *\n * @example\n * var bound = [-5, 5];\n * var view = board.create('view3d',\n * [[-6, -3],\n * [8, 8],\n * [bound, bound, bound]],\n * {\n * // Main axes\n * axesPosition: 'center',\n * xAxis: { strokeColor: 'blue', strokeWidth: 3},\n *\n * // Planes\n * xPlaneRear: { fillColor: 'yellow', mesh3d: {visible: false}},\n * yPlaneFront: { visible: true, fillColor: 'blue'},\n *\n * // Axes on planes\n * xPlaneRearYAxis: {strokeColor: 'red'},\n * xPlaneRearZAxis: {strokeColor: 'red'},\n *\n * yPlaneFrontXAxis: {strokeColor: 'blue'},\n * yPlaneFrontZAxis: {strokeColor: 'blue'},\n *\n * zPlaneFrontXAxis: {visible: false},\n * zPlaneFrontYAxis: {visible: false}\n * });\n *\n * </pre><div id=\"JXGdd06d90e-be5d-4531-8f0b-65fc30b1a7c7\" class=\"jxgbox\" style=\"width: 500px; height: 500px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXGdd06d90e-be5d-4531-8f0b-65fc30b1a7c7',\n * {boundingbox: [-8, 8, 8,-8], axis: false, showcopyright: false, shownavigation: false});\n * var bound = [-5, 5];\n * var view = board.create('view3d',\n * [[-6, -3], [8, 8],\n * [bound, bound, bound]],\n * {\n * // Main axes\n * axesPosition: 'center',\n * xAxis: { strokeColor: 'blue', strokeWidth: 3},\n *\n * // Planes\n * xPlaneRear: { fillColor: 'yellow', mesh3d: {visible: false}},\n * yPlaneFront: { visible: true, fillColor: 'blue'},\n *\n * // Axes on planes\n * xPlaneRearYAxis: {strokeColor: 'red'},\n * xPlaneRearZAxis: {strokeColor: 'red'},\n *\n * yPlaneFrontXAxis: {strokeColor: 'blue'},\n * yPlaneFrontZAxis: {strokeColor: 'blue'},\n *\n * zPlaneFrontXAxis: {visible: false},\n * zPlaneFrontYAxis: {visible: false}\n * });\n *\n * })();\n *\n * </script><pre>\n *\n */\n ThreeD.createView3D = function (board, parents, attributes) {\n var view, frame, attr,\n x, y, w, h,\n coords = parents[0], // llft corner\n size = parents[1]; // [w, h]\n\n attr = Type.copyAttributes(attributes, board.options, 'view3d');\n view = new ThreeD.View3D(board, parents, attr);\n view.defaultAxes = view.create('axes3d', parents, attributes);\n\n x = coords[0];\n y = coords[1];\n w = size[0];\n h = size[1];\n\n /**\n * Frame around the view object\n */\n if (false) {\n frame = board.create('polygon', [\n [coords[0], coords[1] + size[1]], // ulft\n [coords[0], coords[1]], // llft\n [coords[0] + size[0], coords[1]], // lrt\n [coords[0] + size[0], coords[1] + size[1]], // urt\n ], {\n fillColor: 'none',\n highlightFillColor: 'none',\n highlight: false,\n vertices: {\n fixed: true,\n visible: false\n },\n borders: {\n strokeColor: 'black',\n highlight: false,\n strokeWidth: 0.5,\n dash: 4\n }\n });\n //view.add(frame);\n }\n\n /**\n * Slider to adapt azimuth angle\n */\n view.D3.az_slide = board.create('slider', [[x - 1, y - 2], [x + w + 1, y - 2], [0, 1.0, 2 * Math.PI]], {\n style: 6, name: 'az',\n point1: { frozen: true },\n point2: { frozen: true }\n });\n\n /**\n * Slider to adapt elevation angle\n */\n view.D3.el_slide = board.create('slider', [[x - 1, y], [x - 1, y + h], [0, 0.30, Math.PI / 2]], {\n style: 6, name: 'el',\n point1: { frozen: true },\n point2: { frozen: true }\n });\n\n view.board.highlightInfobox = function (x, y, el) {\n var d;\n\n if (Type.exists(el.D3)) {\n d = Type.evaluate(el.visProp.infoboxdigits);\n if (d === 'auto') {\n view.board.highlightCustomInfobox('(' +\n Type.autoDigits(el.D3.X()) + ' | ' +\n Type.autoDigits(el.D3.Y()) + ' | ' +\n Type.autoDigits(el.D3.Z()) + ')', el);\n } else {\n view.board.highlightCustomInfobox('(' +\n Type.toFixed(el.D3.X(), d) + ' | ' +\n Type.toFixed(el.D3.Y(), d) + ' | ' +\n Type.toFixed(el.D3.Z(), d) + ')', el);\n }\n } else {\n view.board.highlightCustomInfobox('(' + x + ', ' + y + ')', el);\n }\n };\n\n return view;\n };\n JXG.registerElement('view3d', ThreeD.createView3D);\n\n return ThreeD.View3D;\n});\n\n\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Carsten Miller,\n Andreas Walter,\n Alfred Wassermann\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n/*global JXG:true, define: true*/\n\n/**\n * Create axes and rear and front walls of the\n * view3d bounding box bbox3d.\n */\ndefine('3d/box3d',['jxg', 'utils/type', 'math/math', 'math/geometry', '3d/view3d'\n], function (JXG, Type, Mat, Geometry, ThreeD) {\n \"use strict\";\n\n ThreeD.createAxes = function (board, parents, attributes) {\n var view = parents[0],\n i, j, k, i1, i2,\n attr,\n pos,\n directions = ['x', 'y', 'z'],\n suffixAxis = 'Axis',\n dir, dir1,\n sides = ['Rear', 'Front'],\n rear = [0, 0, 0], // x, y, z\n front = [0, 0, 0], // x, y, z\n from, to,\n vec1, vec2, range1, range2,\n na, na_parent,\n ticks_attr,\n axes = {};\n\n if (Type.exists(view.D3)) {\n for (i = 0; i < directions.length; i++) {\n rear[i] = view.D3.bbox3d[i][0];\n front[i] = view.D3.bbox3d[i][1];\n }\n } else {\n for (i = 0; i < directions.length; i++) {\n rear[i] = parents[1][i];\n front[i] = parents[2][1];\n }\n }\n\n // Main 3D axes\n attr = Type.copyAttributes(attributes, board.options, 'axes3d');\n pos = attr.axesposition;\n for (i = 0; i < directions.length; i++) {\n // Run through ['x', 'y', 'z']\n dir = directions[i];\n na = dir + suffixAxis;\n\n if (pos === 'center') { // Axes centered\n from = [0, 0, 0];\n to = [0, 0, 0];\n to[i] = front[i];\n axes[na] = view.create('axis3d', [from, to], attr[na.toLowerCase()]);\n } else {\n na += 'Border'; // Axes bordered\n from = rear.slice();\n to = front.slice();\n if (i === 2) {\n from[1] = front[1];\n to[0] = rear[0];\n } else {\n from[i] = front[i];\n to[2] = rear[2];\n }\n to[i] = front[i];\n attr[na.toLowerCase()].lastArrow = false;\n axes[na] = view.create('axis3d', [from, to], attr[na.toLowerCase()]);\n\n // TODO\n ticks_attr = {\n visible: true, // Für z-Ticks wird path nicht berechnet\n minorTicks: 0,\n tickEndings: [0, 1],\n drawLabels: false\n };\n if (i === 2) {\n ticks_attr.tickEndings = [1, 0];\n }\n axes[na + 'Ticks'] = view.create('ticks', [axes[na], 1], ticks_attr);\n }\n }\n\n // Origin (2D point)\n axes.O = board.create('intersection', [\n axes[directions[0] + suffixAxis],\n axes[directions[1] + suffixAxis]\n ], {\n name: '', visible: false, withLabel: false\n });\n\n // Front and rear planes\n for (i = 0; i < directions.length; i++) {\n // Run through ['x', 'y', 'z']\n i1 = (i + 1) % 3;\n i2 = (i + 2) % 3;\n\n dir = directions[i];\n for (j = 0; j < sides.length; j++) {\n // Run through ['Rear', 'Front']\n\n from = [0, 0, 0];\n from[i] = (j === 0) ? rear[i] : front[i];\n vec1 = [0, 0, 0];\n vec2 = [0, 0, 0];\n vec1[i1] = 1;\n vec2[i2] = 1;\n range1 = [rear[i1], front[i1]];\n range2 = [rear[i2], front[i2]];\n na = dir + 'Plane' + sides[j];\n\n attr = Type.copyAttributes(attributes, board.options, 'axes3d', na);\n axes[na] =\n view.create('plane3d', [from, vec1, vec2, range1, range2], attr);\n axes[na].D3.elType = 'axisplane3d';\n }\n }\n\n // Axes on front and rear planes\n for (i = 0; i < directions.length; i++) {\n // Run through ['x', 'y', 'z']\n dir = directions[i];\n for (j = 0; j < sides.length; j++) {\n for (k = 1; k <= 2; k++) {\n i1 = (i + k) % 3;\n dir1 = directions[i1];\n na = dir + 'Plane' + sides[j] + dir1.toUpperCase() + 'Axis';\n na_parent = dir + 'Plane' + sides[j];\n\n from = [0, 0, 0];\n to = [0, 0, 0];\n from[i] = to[i] = (j === 0) ? rear[i] : front[i];\n\n from[i1] = rear[i1];\n to[i1] = front[i1];\n\n attr = Type.copyAttributes(attributes, board.options, 'axes3d', na);\n axes[na] = view.create('axis3d', [from, to], attr);\n axes[na_parent].addChild(axes[na]);\n axes[na_parent].inherits.push(axes[na]);\n }\n }\n }\n\n return axes;\n };\n JXG.registerElement('axes3d', ThreeD.createAxes);\n\n ThreeD.createAxis = function (board, parents, attributes) {\n var view = parents[0],\n attr,\n start = parents[1],\n end = parents[2],\n el_start, el_end, el;\n\n // Use 2D points to create axis\n attr = Type.copyAttributes(attributes.point1, board.options, 'axis3d', 'point1');\n el_start = board.create('point', [\n (function (xx, yy, zz) {\n return function () { return view.project3DTo2D(xx, yy, zz)[1]; };\n })(start[0], start[1], start[2]),\n (function (xx, yy, zz) {\n return function () { return view.project3DTo2D(xx, yy, zz)[2]; };\n })(start[0], start[1], start[2])\n ], attr);\n\n attr = Type.copyAttributes(attributes.point2, board.options, 'axis3d', 'point2');\n el_end = board.create('point', [\n (function (xx, yy, zz) {\n return function () { return view.project3DTo2D(xx, yy, zz)[1]; };\n })(end[0], end[1], end[2]),\n (function (xx, yy, zz) {\n return function () { return view.project3DTo2D(xx, yy, zz)[2]; };\n })(end[0], end[1], end[2])\n ], attr);\n\n attr = Type.copyAttributes(attributes, board.options, 'axis3d');\n el = board.create('arrow', [el_start, el_end], attr);\n\n return el;\n };\n JXG.registerElement('axis3d', ThreeD.createAxis);\n\n ThreeD.createMesh = function (board, parents, attr) {\n var view = parents[0],\n point = parents[1],\n vec1 = parents[2],\n range1 = parents[3],\n vec2 = parents[4],\n range2 = parents[5],\n el;\n\n el = board.create('curve', [[], []], attr);\n el.updateDataArray = function () {\n var s1 = range1[0],\n e1 = range1[1],\n s2 = range2[0],\n e2 = range2[1],\n l1, l2, res, i, sol,\n v1 = [0, 0, 0],\n v2 = [0, 0, 0],\n step = 1,\n q = [0, 0, 0];\n\n this.dataX = [];\n this.dataY = [];\n\n for (i = 0; i < 3; i++) {\n q[i] = Type.evaluate(point[i]);\n v1[i] = Type.evaluate(vec1[i]);\n v2[i] = Type.evaluate(vec2[i]);\n }\n l1 = JXG.Math.norm(v1, 3);\n l2 = JXG.Math.norm(v2, 3);\n for (i = 0; i < 3; i++) {\n v1[i] /= l1;\n v2[i] /= l2;\n }\n if (false) {\n sol = Mat.Geometry.getPlaneBounds(v1, v2, q, s1, e1);\n if (sol !== null) {\n s1 = sol[0];\n e1 = sol[1];\n s2 = sol[2];\n e2 = sol[3];\n }\n }\n\n res = view.getMesh(\n function(u, v) { return q[0] + u * v1[0] + v * v2[0]; },\n function(u, v) { return q[1] + u * v1[1] + v * v2[1]; },\n function(u, v) { return q[2] + u * v1[2] + v * v2[2]; },\n [Math.ceil(s1), Math.floor(e1), (Math.ceil(e1) - Math.floor(s1)) / step],\n [Math.ceil(s2), Math.floor(e2), (Math.ceil(e2) - Math.floor(s2)) / step]);\n this.dataX = res[0];\n this.dataY = res[1];\n };\n return el;\n };\n JXG.registerElement('mesh3d', ThreeD.createMesh);\n\n});\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Carsten Miller,\n Andreas Walter,\n Alfred Wassermann\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n/*global JXG:true, define: true*/\n\ndefine('3d/curve3d',['jxg', 'utils/type', '3d/view3d'\n], function (JXG, Type, ThreeD) {\n \"use strict\";\n\n ThreeD.createCurve = function (board, parents, attr) {\n var view = parents[0],\n D3, el;\n\n D3 = {\n elType: 'curve3D',\n X: parents[1],\n Y: parents[2],\n Z: parents[3],\n };\n D3.F = [D3.X, D3.Y, D3.Z];\n\n el = board.create('curve', [[], []], attr);\n el.D3 = D3;\n\n if (Type.isFunction(el.D3.X)) {\n // 3D curve given as t -> [X(t), Y(t), Z(t)]\n\n el.D3.range = parents[4];\n el.updateDataArray = function () {\n var steps = Type.evaluate(this.visProp.numberpointshigh),\n s = Type.evaluate(this.D3.range[0]),\n e = Type.evaluate(this.D3.range[1]),\n delta = (e - s) / (steps - 1),\n c2d, t, i,\n p = [0, 0, 0];\n\n this.dataX = [];\n this.dataY = [];\n\n for (t = s; t <= e; t += delta) {\n for (i = 0; i < 3; i++) {\n p[i] = this.D3.F[i](t);\n }\n c2d = view.project3DTo2D(p);\n this.dataX.push(c2d[1]);\n this.dataY.push(c2d[2]);\n }\n };\n } else if (Type.isArray(el.D3.X)) {\n // 3D curve given as array of 3D points\n\n el.updateDataArray = function () {\n var i,\n le = this.D3.X.length,\n c2d;\n\n this.dataX = [];\n this.dataY = [];\n\n for (i = 0; i < le; i++) {\n c2d = view.project3DTo2D([this.D3.X[i], this.D3.Y[i], this.D3.Z[i]]);\n this.dataX.push(c2d[1]);\n this.dataY.push(c2d[2]);\n }\n };\n }\n\n return el;\n };\n JXG.registerElement('curve3d', ThreeD.createCurve);\n\n});\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Carsten Miller,\n Andreas Walter,\n Alfred Wassermann\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n/*global JXG:true, define: true*/\n\n/**\n * Create linear spaces of dimension at least one,\n * i.e. lines and planes.\n */\ndefine('3d/linspace3d',['jxg', 'utils/type', 'math/math', 'math/geometry', '3d/view3d'\n], function (JXG, Type, Mat, Geometry, ThreeD) {\n \"use strict\";\n\n /**\n * @class This element is used to provide a constructor for a 3D line.\n * @pseudo\n * @description There are two possibilities to create a Line3D object.\n * <p>\n * First: the line in 3D is defined by two points in 3D (Point3D).\n * The points can be either existing points or coordinate arrays of\n * the form [x, y, z].\n * <p>Second: the line in 3D is defined by a point (or coordinate array [x, y, z])\n * a direction given as array [x, y, z] and an optional range\n * given as array [s, e]. The default value for the range is [-Infinity, Infinity].\n * <p>\n * All numbers can also be provided as functions returning a number.\n *\n * @name Line3D\n * @augments JXG.Curve\n * @constructor\n * @type JXG.Curve\n * @throws {Exception} If the element cannot be constructed with the given parent\n * objects an exception is thrown.\n * @param {JXG.Point_number,JXG.Point,JXG.Line,JXG.Circle} center,radius The center must be given as a {@link JXG.Point}, see {@link JXG.providePoints}, but the radius can be given\n * as a number (which will create a circle with a fixed radius), another {@link JXG.Point}, a {@link JXG.Line} (the distance of start and end point of the\n * line will determine the radius), or another {@link JXG.Circle}.\n *\n */\n ThreeD.createLine = function (board, parents, attributes) {\n var view = parents[0],\n attr, D3, point, point1, point2,\n el;\n\n // Range\n D3 = {\n elType: 'line3d',\n range: parents[3] || [-Infinity, Infinity]\n };\n\n // Point\n if (Type.isPoint(parents[1])) {\n point = parents[1];\n } else {\n point = view.create('point3d', parents[1], { visible: false, name: '', withLabel: false });\n }\n D3.point = point;\n\n // Direction\n if (Type.isPoint(parents[2]) && Type.exists(parents[2].D3)) {\n // Line defined by two points\n\n point1 = point;\n point2 = parents[2];\n D3.direction = function () {\n return [\n point2.D3.X() - point.D3.X(),\n point2.D3.Y() - point.D3.Y(),\n point2.D3.Z() - point.D3.Z()\n ];\n };\n D3.range = [0, 1];\n } else {\n // Line defined by point, direction and range\n\n // Directions are handled as arrays of length 4,\n // i.e. with homogeneous coordinates.\n if (Type.isFunction(parents[2])) {\n D3.direction = parents[2];\n } else if (parents[2].length === 3) {\n D3.direction = [1].concat(parents[2]);\n } else if (parents[2].length === 4) {\n D3.direction = parents[2];\n } else {\n // Throw error\n }\n\n // Direction given as array\n D3.getPointCoords = function (r) {\n var p = [],\n d = [],\n i;\n\n p.push(point.D3.X());\n p.push(point.D3.Y());\n p.push(point.D3.Z());\n\n if (Type.isFunction(D3.direction)) {\n d = D3.direction();\n } else {\n for (i = 1; i < 4; i++) {\n d.push(Type.evaluate(D3.direction[i]));\n }\n }\n if (Math.abs(r) === Infinity) {\n r = view.intersectionLineCube(p, d, r);\n }\n return [\n p[0] + d[0] * r,\n p[1] + d[1] * r,\n p[2] + d[2] * r\n ];\n\n };\n\n attr = Type.copyAttributes(attributes, board.options, 'line3d', 'point1');\n point1 = view.create('point3d', [\n function () {\n return D3.getPointCoords(Type.evaluate(D3.range[0]));\n }\n ], attr);\n attr = Type.copyAttributes(attributes, board.options, 'line3d', 'point2');\n point2 = view.create('point3d', [\n function () {\n return D3.getPointCoords(Type.evaluate(D3.range[1]));\n }\n ], attr);\n }\n\n attr = Type.copyAttributes(attributes, board.options, 'line3d');\n el = view.create('segment', [point1, point2], attr);\n el.point1 = point1;\n el.point2 = point2;\n point1.addChild(el);\n point2.addChild(el);\n el.D3 = D3;\n\n return el;\n };\n JXG.registerElement('line3d', ThreeD.createLine);\n\n ThreeD.createPlane = function (board, parents, attributes) {\n var view = parents[0],\n attr, D3,\n point,\n vec1 = parents[2],\n vec2 = parents[3],\n el, grid, update;\n\n // D3: {\n // point,\n // vec1,\n // vec2,\n // poin1,\n // point2,\n // normal array of len 3\n // d\n // }\n D3 = {\n elType: 'plane3d',\n dir1: [],\n dir2: [],\n range1: parents[4],\n range2: parents[5],\n vec1: vec1,\n vec2: vec2\n };\n\n if (Type.isPoint(parents[1])) {\n point = parents[1];\n } else {\n point = view.create('point3d', parents[1], { visible: false, name: '', withLabel: false });\n }\n D3.point = point;\n\n D3.updateNormal = function () {\n var i;\n for (i = 0; i < 3; i++) {\n D3.dir1[i] = Type.evaluate(D3.vec1[i]);\n D3.dir2[i] = Type.evaluate(D3.vec2[i]);\n }\n D3.normal = Mat.crossProduct(D3.dir1, D3.dir2);\n D3.d = Mat.innerProduct(D3.point.D3.coords.slice(1), D3.normal, 3);\n };\n D3.updateNormal();\n\n attr = Type.copyAttributes(attributes, board.options, 'plane3d');\n el = board.create('curve', [[], []], attr);\n el.D3 = D3;\n\n el.updateDataArray = function () {\n var s1, e1, s2, e2,\n c2d, l1, l2,\n planes = ['xPlaneRear', 'yPlaneRear', 'zPlaneRear'],\n points = [],\n v1 = [0, 0, 0],\n v2 = [0, 0, 0],\n q = [0, 0, 0],\n p = [0, 0, 0], d, i, j, a, b, first, pos, pos_akt;\n\n this.dataX = [];\n this.dataY = [];\n\n this.D3.updateNormal();\n\n // Infinite plane\n if (this.D3.elType !== 'axisplane3d' && view.defaultAxes &&\n (!D3.range1 || !D3.range2)\n ) {\n\n // Start with the rear plane.\n // Determine the intersections with the view bbox3d\n // For each face of the bbox3d we determine two points\n // which are the ends of the intersection line.\n // We start with the three rear planes.\n for (j = 0; j < planes.length; j++) {\n p = view.intersectionPlanePlane(this, view.defaultAxes[planes[j]]);\n\n if (p[0].length === 3 && p[1].length === 3) {\n // This test is necessary to filter out intersection lines which are\n // identical to intersections of axis planes (they would occur twice).\n for (i = 0; i < points.length; i++) {\n if ((Geometry.distance(p[0], points[i][0], 3) < Mat.eps && Geometry.distance(p[1], points[i][1], 3) < Mat.eps) ||\n (Geometry.distance(p[0], points[i][1], 3) < Mat.eps && Geometry.distance(p[1], points[i][0], 3) < Mat.eps)) {\n break;\n }\n }\n if (i === points.length) {\n points.push(p.slice());\n }\n }\n\n // Point on the front plane of the bbox3d\n p = [0, 0, 0];\n p[j] = view.D3.bbox3d[j][1];\n\n // d is the rhs of the Hesse normal form of the front plane.\n d = Mat.innerProduct(p, view.defaultAxes[planes[j]].D3.normal, 3);\n p = view.intersectionPlanePlane(this, view.defaultAxes[planes[j]], d);\n\n if (p[0].length === 3 && p[1].length === 3) {\n // Do the same test as above\n for (i = 0; i < points.length; i++) {\n if ((Geometry.distance(p[0], points[i][0], 3) < Mat.eps && Geometry.distance(p[1], points[i][1], 3) < Mat.eps) ||\n (Geometry.distance(p[0], points[i][1], 3) < Mat.eps && Geometry.distance(p[1], points[i][0], 3) < Mat.eps)) {\n break;\n }\n }\n if (i === points.length) {\n points.push(p.slice());\n }\n }\n }\n\n // Concatenate the intersection points to a polygon.\n // If all wents well, each intersection should appear\n // twice in the list.\n first = 0;\n pos = first;\n i = 0;\n do {\n p = points[pos][i];\n if (p.length === 3) {\n c2d = view.project3DTo2D(p);\n this.dataX.push(c2d[1]);\n this.dataY.push(c2d[2]);\n }\n i = (i + 1) % 2;\n p = points[pos][i];\n\n pos_akt = pos;\n for (j = 0; j < points.length; j++) {\n if (j !== pos && Geometry.distance(p, points[j][0]) < Mat.eps) {\n pos = j;\n i = 0;\n break;\n }\n if (j !== pos && Geometry.distance(p, points[j][1]) < Mat.eps) {\n pos = j;\n i = 1;\n break;\n }\n }\n if (pos === pos_akt) {\n console.log(\"Error: update plane3d: did not find next\", pos);\n break;\n }\n } while (pos !== first);\n c2d = view.project3DTo2D(points[first][0]);\n this.dataX.push(c2d[1]);\n this.dataY.push(c2d[2]);\n\n } else {\n // 3D bounded flat\n s1 = Type.evaluate(this.D3.range1[0]);\n e1 = Type.evaluate(this.D3.range1[1]);\n s2 = Type.evaluate(this.D3.range2[0]);\n e2 = Type.evaluate(this.D3.range2[1]);\n\n q = this.D3.point.D3.coords.slice(1);\n\n v1 = this.D3.dir1.slice();\n v2 = this.D3.dir2.slice();\n l1 = Mat.norm(v1, 3);\n l2 = Mat.norm(v2, 3);\n for (i = 0; i < 3; i++) {\n v1[i] /= l1;\n v2[i] /= l2;\n }\n\n for (j = 0; j < 4; j++) {\n switch (j) {\n case 0: a = s1; b = s2; break;\n case 1: a = e1; b = s2; break;\n case 2: a = e1; b = e2; break;\n case 3: a = s1; b = e2;\n }\n for (i = 0; i < 3; i++) {\n p[i] = q[i] + a * v1[i] + b * v2[i];\n }\n c2d = view.project3DTo2D(p);\n this.dataX.push(c2d[1]);\n this.dataY.push(c2d[2]);\n }\n // Close the curve\n this.dataX.push(this.dataX[0]);\n this.dataY.push(this.dataY[0]);\n }\n };\n\n attr = Type.copyAttributes(attributes.mesh3d, board.options, 'mesh3d');\n\n if (D3.range1 && D3.range2) {\n grid = view.create('mesh3d', [point.D3.coords.slice(1), vec1, D3.range1, vec2, D3.range2], attr);\n el.grid = grid;\n el.inherits.push(grid);\n }\n\n // update = el.update;\n // el.update = function () {\n // if (el.needsUpdate) {\n // update.apply(el);\n // }\n // return this;\n // };\n\n return el;\n };\n JXG.registerElement('plane3d', ThreeD.createPlane);\n\n});\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Carsten Miller,\n Andreas Walter,\n Alfred Wassermann\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n/*global JXG:true, define: true*/\n\ndefine('3d/point3d',['jxg', 'base/constants', 'math/math', 'math/geometry', 'utils/type', '3d/view3d'\n], function (JXG, Const, Mat, Geometry, Type, ThreeD) {\n \"use strict\";\n\n /**\n * @class This element is used to provide a constructor for a 3D Point.\n * @pseudo\n * @description There are two possibilities to create a Line3D object.\n * <p>\n * First: the line in 3D is defined by two points in 3D (Point3D).\n * The points can be either existing points or coordinate arrays of\n * the form [x, y, z].\n * <p>Second: the line in 3D is defined by a point (or coordinate array [x, y, z])\n * a direction given as array [x, y, z] and an optional range\n * given as array [s, e]. The default value for the range is [-Infinity, Infinity].\n * <p>\n * All numbers can also be provided as functions returning a number.\n *\n * @name Point3D\n * @augments JXG.Point\n * @constructor\n * @type JXG.Point\n * @throws {Exception} If the element cannot be constructed with the given parent\n * objects an exception is thrown.\n * @param {JXG.Point_number,JXG.Point,JXG.Line,JXG.Circle} center,radius The center must be given as a {@link JXG.Point}, see {@link JXG.providePoints}, but the radius can be given\n * as a number (which will create a circle with a fixed radius), another {@link JXG.Point}, a {@link JXG.Line} (the distance of start and end point of the\n * line will determine the radius), or another {@link JXG.Circle}.\n *\n */\n ThreeD.createPoint = function (board, parents, attributes) {\n var view = parents[0],\n attr, update2D, D3,\n i, c2d,\n el;\n\n attr = Type.copyAttributes(attributes, board.options, 'point3d');\n\n D3 = {\n elType: 'point3d',\n coords: [1, 0, 0, 0],\n X: function () { return this.coords[1]; },\n Y: function () { return this.coords[2]; },\n Z: function () { return this.coords[3]; }\n };\n\n // If the last element of partents is a 3D object, the point is a glider\n // on that element.\n if (parents.length > 2 && Type.exists(parents[parents.length - 1].D3)) {\n D3.slide = parents.pop();\n } else {\n D3.slide = null;\n }\n\n if (parents.length === 2) {\n D3.F = parents[1]; // (Array [x, y, z] | function) returning [x, y, z]\n D3.coords = [1].concat(Type.evaluate(D3.F));\n } else if (parents.length === 4) {\n D3.F = parents.slice(1); // 3 numbers | functions\n for (i = 0; i < 3; i++) {\n D3.coords[i + 1] = Type.evaluate(D3.F[i]);\n }\n } else {\n // Throw error\n }\n\n /**\n * Update the 4D coords array\n * @returns Object\n */\n D3.updateCoords = function () {\n var res, i;\n if (Type.isFunction(this.F)) {\n res = Type.evaluate(this.F);\n this.coords = [1, res[0], res[1], res[2]];\n } else {\n this.coords[0] = 1;\n for (i = 0; i < 3; i++) {\n if (Type.isFunction(this.F[i])) {\n this.coords[i + 1] = Type.evaluate(this.F[i]);\n }\n }\n }\n return this;\n };\n D3.updateCoords();\n\n c2d = view.project3DTo2D(D3.coords);\n el = board.create('point', c2d, attr);\n el.D3 = D3;\n el.D3.c2d = el.coords.usrCoords.slice(); // Copy of the coordinates to detect dragging\n update2D = el.update;\n\n if (el.D3.slide) {\n el._minFunc = function (n, m, x, con) {\n var surface = el.D3.slide.D3,\n c3d = [1, surface.X(x[0], x[1]), surface.Y(x[0], x[1]), surface.Z(x[0], x[1])],\n c2d = view.project3DTo2D(c3d);\n\n con[0] = el.X() - c2d[1];\n con[1] = el.Y() - c2d[2];\n\n return con[0] * con[0] + con[1] * con[1];\n };\n\n el.projectCoords2Surface = function () {\n var n = 2,\t\t// # of variables\n m = 2, \t\t// number of constraints\n x = [0, 0],\n // Various Cobyla constants, see Cobyla docs in Cobyja.js\n rhobeg = 5.0,\n rhoend = 1.0e-6,\n iprint = 0,\n maxfun = 200,\n surface = this.D3.slide.D3,\n r, c3d, c2d;\n\n if (Type.exists(this.D3.params)) {\n x = this.D3.params.slice();\n }\n r = Mat.Nlp.FindMinimum(this._minFunc, n, m, x, rhobeg, rhoend, iprint, maxfun);\n\n c3d = [1, surface.X(x[0], x[1]), surface.Y(x[0], x[1]), surface.Z(x[0], x[1])];\n c2d = view.project3DTo2D(c3d);\n this.D3.params = x;\n this.D3.coords = c3d;\n this.coords.setCoordinates(Const.COORDS_BY_USER, c2d);\n this.D3.c2d = c2d;\n };\n }\n\n el.update = function (drag) {\n var c3d, foot;\n if (!this.needsUpdate) {\n return this;\n }\n\n // Update is called in from two methods:\n // Once in setToPositionDirectly and\n // once in the subsequent board.update\n if (this.draggable() &&\n Geometry.distance(this.D3.c2d, this.coords.usrCoords) !== 0) {\n\n if (this.D3.slide) {\n this.projectCoords2Surface();\n } else {\n // Drag the point in its xy plane\n foot = [1, 0, 0, this.D3.coords[3]];\n c3d = view.project2DTo3DPlane(el, [1, 0, 0, 1], foot);\n if (c3d[0] !== 0) {\n this.D3.coords = view.project3DToCube(c3d);\n }\n }\n } else {\n this.D3.updateCoords();\n // Update 2D point from its 3D view\n el.coords.setCoordinates(Const.COORDS_BY_USER,\n view.project3DTo2D([1, this.D3.X(), this.D3.Y(), this.D3.Z()])\n );\n }\n this.D3.c2d = el.coords.usrCoords.slice();\n\n update2D.apply(this, [drag]);\n return this;\n };\n\n return el;\n };\n JXG.registerElement('point3d', ThreeD.createPoint);\n\n});\n/*\n Copyright 2008-2022\n Matthias Ehmann,\n Carsten Miller,\n Andreas Walter,\n Alfred Wassermann\n\n This file is part of JSXGraph.\n\n JSXGraph is free software dual licensed under the GNU LGPL or MIT License.\n\n You can redistribute it and/or modify it under the terms of the\n\n * GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version\n OR\n * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT\n\n JSXGraph is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License and\n the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>\n and <http://opensource.org/licenses/MIT/>.\n */\n/*global JXG:true, define: true*/\n\ndefine('3d/surface3d',['jxg', 'utils/type', '3d/view3d'\n], function (JXG, Type, ThreeD) {\n \"use strict\";\n\n\n /**\n * @class This element creates a 3D parametric surface.\n * @pseudo\n * @description A 3D parametric surface is defined by a function\n * <i>F: R<sup>2</sup> → R<sup>3</sup></i>.\n *\n * @name ParametricSurface3D\n * @augments Curve\n * @constructor\n * @type Object\n * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {Function_Function_Function_Array_Array} F<sub>X</sub>,F<sub>Y</sub>,F<sub>Z</sub>,rangeX,rangeY\n * F<sub>X</sub>(u,v), F<sub>Y</sub>(u,v), F<sub>Z</sub>(u,v) are functions returning a number, rangeU is the array containing\n * lower and upper bound for the range of parameter u, rangeV is the array containing\n * lower and upper bound for the range of parameter v. rangeU and rangeV may also be functions returning an array of length two.\n * @example\n * var view = board.create('view3d',\n * \t\t [[-6, -3], [8, 8],\n * \t\t [[-5, 5], [-5, 5], [-5, 5]]]);\n *\n * // Sphere\n * var c = view.create('parametricsurface3d', [\n * (u, v) => 2 * Math.sin(u) * Math.cos(v),\n * (u, v) => 2 * Math.sin(u) * Math.sin(v),\n * (u, v) => 2 * Math.cos(u),\n * [0, 2 * Math.PI],\n * [0, Math.PI]\n * ], {\n * strokeColor: '#ff0000',\n * stepsU: 30,\n * stepsV: 30\n * });\n *\n * </pre><div id=\"JXG52da0ecc-1ba9-4d41-850c-36e5120025a5\" class=\"jxgbox\" style=\"width: 500px; height: 500px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG52da0ecc-1ba9-4d41-850c-36e5120025a5',\n * {boundingbox: [-8, 8, 8,-8], axis: false, showcopyright: false, shownavigation: false});\n * var view = board.create('view3d',\n * \t\t [[-6, -3], [8, 8],\n * \t\t [[-5, 5], [-5, 5], [-5, 5]]]);\n *\n * // Sphere\n * var c = view.create('parametricsurface3d', [\n * (u, v) => 2 * Math.sin(u) * Math.cos(v),\n * (u, v) => 2 * Math.sin(u) * Math.sin(v),\n * (u, v) => 2 * Math.cos(u),\n * [0, 2 * Math.PI],\n * [0, Math.PI]\n * ], {\n * strokeColor: '#ff0000',\n * stepsU: 20,\n * stepsV: 20\n * });\n *\n * })();\n *\n * </script><pre>\n *\n */\n ThreeD.createParametricSurface = function (board, parents, attributes) {\n var view = parents[0],\n attr,\n X = parents[1],\n Y = parents[2],\n Z = parents[3],\n range_u = parents[4],\n range_v = parents[5],\n D3, el;\n\n D3 = {\n elType: 'surface3d',\n X: X,\n Y: Y,\n Z: Z,\n range_u: range_u,\n range_v: range_v\n };\n attr = Type.copyAttributes(attributes, board.options, 'surface3d');\n el = board.create('curve', [[], []], attr);\n el.updateDataArray = function () {\n var steps_u = Type.evaluate(this.visProp.stepsu),\n steps_v = Type.evaluate(this.visProp.stepsv),\n r_u = Type.evaluate(this.D3.range_u), // Type.evaluate(range_u),\n r_v = Type.evaluate(this.D3.range_v), // Type.evaluate(range_v),\n res = view.getMesh(this.D3.X, this.D3.Y, this.D3.Z,\n r_u.concat([steps_u]),\n r_v.concat([steps_v]));\n this.dataX = res[0];\n this.dataY = res[1];\n };\n el.D3 = D3;\n\n return el;\n };\n JXG.registerElement('parametricsurface3d', ThreeD.createParametricSurface);\n\n /**\n * @class This element creates a 3D function graph.\n * @pseudo\n * @description A 3D function graph is defined by a function\n * <i>F: R<sup>2</sup> → R</i>.\n *\n * @name Functiongraph3D\n * @augments ParametricSurface3D\n * @constructor\n * @type Object\n * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown.\n * @param {Function_Array_Array} F,rangeX,rangeY F(x,y) is a function returning a number, rangeX is the array containing\n * lower and upper bound for the range of x, rangeY is the array containing\n * lower and upper bound for the range of y.\n * @example\n * var box = [-5, 5];\n * var view = board.create('view3d',\n * [\n * [-6, -3], [8, 8],\n * [box, box, box]\n * ],\n * {\n * xPlaneRear: {visible: false},\n * yPlaneRear: {visible: false},\n * });\n *\n * // Function F to be plotted\n * var F = (x, y) => Math.sin(x * y / 4);\n *\n * // 3D surface\n * var c = view.create('functiongraph3d', [\n * F,\n * box, // () => [-s.Value()*5, s.Value() * 5],\n * box, // () => [-s.Value()*5, s.Value() * 5],\n * ], {\n * strokeWidth: 0.5,\n * stepsU: 70,\n * stepsV: 70\n * });\n *\n * </pre><div id=\"JXG87646dd4-9fe5-4c21-8734-089abc612515\" class=\"jxgbox\" style=\"width: 500px; height: 500px;\"></div>\n * <script type=\"text/javascript\">\n * (function() {\n * var board = JXG.JSXGraph.initBoard('JXG87646dd4-9fe5-4c21-8734-089abc612515',\n * {boundingbox: [-8, 8, 8,-8], axis: false, showcopyright: false, shownavigation: false});\n * var box = [-5, 5];\n * var view = board.create('view3d',\n * [\n * [-6, -3], [8, 8],\n * [box, box, box]\n * ],\n * {\n * xPlaneRear: {visible: false},\n * yPlaneRear: {visible: false},\n * });\n *\n * // Function F to be plotted\n * var F = (x, y) => Math.sin(x * y / 4);\n *\n * // 3D surface\n * var c = view.create('functiongraph3d', [\n * F,\n * box, // () => [-s.Value()*5, s.Value() * 5],\n * box, // () => [-s.Value()*5, s.Value() * 5],\n * ], {\n * strokeWidth: 0.5,\n * stepsU: 70,\n * stepsV: 70\n * });\n *\n * })();\n *\n * </script><pre>\n *\n */\n ThreeD.createFunctiongraph = function (board, parents, attributes) {\n var view = parents[0],\n X = function(u, v) { return u; },\n Y = function(u, v) { return v; },\n Z = parents[1],\n range_u = parents[2],\n range_v = parents[3];\n\n return view.create('parametricsurface3d', [X, Y, Z, range_u, range_v], attributes);\n };\n JXG.registerElement('functiongraph3d', ThreeD.createFunctiongraph);\n\n});\n\n/*global define: true*/\ndefine('../build/core.deps.js',[\n 'jxg',\n 'utils/env',\n 'base/constants',\n 'utils/type',\n 'utils/xml',\n 'utils/event',\n 'utils/expect',\n 'math/math',\n 'math/probfuncs',\n 'math/ia',\n 'math/extrapolate',\n 'math/qdt',\n 'math/numerics',\n 'math/nlp',\n 'math/plot',\n 'math/metapost',\n 'math/statistics',\n 'math/symbolic',\n 'math/geometry',\n 'math/clip',\n 'math/poly',\n 'math/complex',\n 'renderer/abstract',\n 'reader/file',\n 'parser/geonext',\n 'base/board',\n 'options',\n 'jsxgraph',\n 'base/element',\n 'base/coords',\n 'base/coordselement',\n 'base/point',\n 'base/line',\n 'base/group',\n 'base/circle',\n 'element/conic',\n 'base/polygon',\n 'base/curve',\n 'element/arc',\n 'element/sector',\n 'base/composition',\n 'element/composition',\n 'element/locus',\n 'base/text',\n 'base/image',\n 'element/slider',\n 'element/measure',\n 'base/chart',\n 'base/transformation',\n 'base/turtle',\n 'utils/color',\n 'base/ticks',\n 'utils/zip',\n 'utils/base64',\n 'utils/uuid',\n 'utils/encoding',\n 'server/server',\n 'parser/datasource',\n 'parser/jessiecode',\n 'parser/ca',\n 'utils/dump',\n 'renderer/svg',\n 'renderer/vml',\n 'renderer/canvas',\n 'renderer/no',\n 'element/comb',\n 'element/slopetriangle',\n 'element/checkbox',\n 'element/input',\n 'element/button',\n 'base/foreignobject',\n 'options3d',\n '3d/box3d',\n '3d/curve3d',\n '3d/linspace3d',\n '3d/point3d',\n '3d/surface3d',\n '3d/threed',\n '3d/view3d'\n], function (JXG, Env) {\n \"use strict\";\n\n // We're in the browser, export JXG to the global JXG symbol for backwards compatibility\n if (Env.isBrowser) {\n window.JXG = JXG;\n\n // In node there are two cases:\n // 1) jsxgraph is used without requirejs (e.g. as jsxgraphcore.js)\n // 2) jsxgraph is loaded using requirejs (e.g. the dev version)\n //\n // in case 2) module is undefined, the export is set in src/jsxgraphnode.js using\n // the return value of this factory function\n } else if (Env.isNode() && typeof module === 'object') {\n module.exports = JXG;\n } else if (Env.isWebWorker()) {\n self.JXG = JXG;\n }\n\n return JXG;\n});\n\n return require('../build/core.deps.js');\n}());\n"],"names":["define","requirejs","require","undef","main","req","makeMap","handlers","defined","waiting","config","defining","hasOwn","Object","prototype","hasOwnProperty","aps","slice","jsSuffixRegExp","hasProp","obj","prop","call","normalize","name","baseName","nameParts","nameSegment","mapValue","foundMap","lastIndex","foundI","foundStarMap","starI","i","j","part","baseParts","split","map","starMap","length","nodeIdCompat","test","replace","charAt","concat","splice","join","makeRequire","relName","forceSync","args","arguments","push","apply","makeLoad","depName","value","callDep","Error","splitPrefix","prefix","index","indexOf","substring","makeRelParts","makeConfig","relParts","plugin","parts","relResourceName","f","n","pr","p","exports","e","module","id","uri","deps","callback","cjsModule","ret","usingExports","callbackType","load","undefined","alt","setTimeout","cfg","_defined","amd","jQuery","jxg","JXG","extend","object","extension","onlyOwn","toLower","toLowerCase","defineConstant","ignoreRedefine","exists","defineProperty","writable","enumerable","configurable","extendConstants","constants","toUpper","e2","toUpperCase","boards","readers","elements","registerElement","element","creator","registerReader","reader","ext","this","shortcut","fun","getRef","board","s","deprecated","select","getReference","getBoardByContainerId","b","container","what","replacement","warning","warn","window","console","document","getElementById","innerHTML","debugInt","log","debugWST","stack","debugLine","debug","version","major","licenseText","COORDS_BY_USER","COORDS_BY_SCREEN","OBJECT_TYPE_ARC","OBJECT_TYPE_ARROW","OBJECT_TYPE_AXIS","OBJECT_TYPE_AXISPOINT","OBJECT_TYPE_TICKS","OBJECT_TYPE_CIRCLE","OBJECT_TYPE_CONIC","OBJECT_TYPE_CURVE","OBJECT_TYPE_GLIDER","OBJECT_TYPE_IMAGE","OBJECT_TYPE_LINE","OBJECT_TYPE_POINT","OBJECT_TYPE_SLIDER","OBJECT_TYPE_CAS","OBJECT_TYPE_GXTCAS","OBJECT_TYPE_POLYGON","OBJECT_TYPE_SECTOR","OBJECT_TYPE_TEXT","OBJECT_TYPE_ANGLE","OBJECT_TYPE_INTERSECTION","OBJECT_TYPE_TURTLE","OBJECT_TYPE_VECTOR","OBJECT_TYPE_OPROJECT","OBJECT_TYPE_GRID","OBJECT_TYPE_TANGENT","OBJECT_TYPE_HTMLSLIDER","OBJECT_TYPE_CHECKBOX","OBJECT_TYPE_INPUT","OBJECT_TYPE_BUTTON","OBJECT_TYPE_TRANSFORMATION","OBJECT_TYPE_FOREIGNOBJECT","OBJECT_TYPE_VIEW3D","OBJECT_CLASS_POINT","OBJECT_CLASS_LINE","OBJECT_CLASS_CIRCLE","OBJECT_CLASS_CURVE","OBJECT_CLASS_AREA","OBJECT_CLASS_OTHER","OBJECT_CLASS_TEXT","GENTYPE_ABC","GENTYPE_AXIS","GENTYPE_MID","GENTYPE_REFLECTION","GENTYPE_MIRRORELEMENT","GENTYPE_REFLECTION_ON_LINE","GENTYPE_REFLECTION_ON_POINT","GENTYPE_TANGENT","GENTYPE_PARALLEL","GENTYPE_BISECTORLINES","GENTYPE_BOARDIMG","GENTYPE_BISECTOR","GENTYPE_NORMAL","GENTYPE_POINT","GENTYPE_GLIDER","GENTYPE_INTERSECTION","GENTYPE_CIRCLE","GENTYPE_CIRCLE2POINTS","GENTYPE_LINE","GENTYPE_TRIANGLE","GENTYPE_QUADRILATERAL","GENTYPE_TEXT","GENTYPE_POLYGON","GENTYPE_REGULARPOLYGON","GENTYPE_SECTOR","GENTYPE_ANGLE","GENTYPE_PLOT","GENTYPE_SLIDER","GENTYPE_TRUNCATE","GENTYPE_JCODE","GENTYPE_MOVEMENT","GENTYPE_COMBINED","GENTYPE_RULER","GENTYPE_SLOPETRIANGLE","GENTYPE_PERPSEGMENT","GENTYPE_LABELMOVEMENT","GENTYPE_VECTOR","GENTYPE_NONREFLEXANGLE","GENTYPE_REFLEXANGLE","GENTYPE_PATH","GENTYPE_DERIVATIVE","GENTYPE_DELETE","GENTYPE_COPY","GENTYPE_MIRROR","GENTYPE_ROTATE","GENTYPE_ABLATION","GENTYPE_MIGRATE","GENTYPE_VECTORCOPY","GENTYPE_POLYGONCOPY","GENTYPE_CTX_TYPE_G","GENTYPE_CTX_TYPE_P","GENTYPE_CTX_TRACE","GENTYPE_CTX_VISIBILITY","GENTYPE_CTX_CCVISIBILITY","GENTYPE_CTX_MPVISIBILITY","GENTYPE_CTX_WITHLABEL","GENTYPE_CTX_LABEL","GENTYPE_CTX_FIXED","GENTYPE_CTX_STROKEWIDTH","GENTYPE_CTX_LABELSIZE","GENTYPE_CTX_SIZE","GENTYPE_CTX_FACE","GENTYPE_CTX_STRAIGHT","GENTYPE_CTX_ARROW","GENTYPE_CTX_COLOR","GENTYPE_CTX_RADIUS","GENTYPE_CTX_COORDS","GENTYPE_CTX_TEXT","GENTYPE_CTX_ANGLERADIUS","GENTYPE_CTX_DOTVISIBILITY","GENTYPE_CTX_FILLOPACITY","GENTYPE_CTX_PLOT","GENTYPE_CTX_SCALE","GENTYPE_CTX_INTVAL","GENTYPE_CTX_POINT1","GENTYPE_CTX_POINT2","GENTYPE_CTX_LABELSTICKY","GENTYPE_CTX_TYPE_I","GENTYPE_CTX_HASINNERPOINTS","GENTYPE_CTX_SNAPWIDTH","GENTYPE_CTX_SNAPTOGRID","Const","isId","objects","isName","elementsByName","isGroup","groups","isString","v","isNumber","toString","isFunction","isArray","Array","_typeof","isObject","isPoint","elementClass","isPointType","val","isTransformationOrArray","type","checkEmptyString","result","isEmpty","keys","def","d","str2Bool","createEvalFunction","param","createFunction","k","term","variableName","evalGeonext","jc","snippet","origin","providePoints","parents","attributes","attrClass","attrArray","len","attr","lenAttr","points","copyAttributes","options","Math","min","create","_is_new","bind","fn","owner","evaluate","array","sub","eliminateDuplicates","a","swap","arr","tmp","uniqueArray","cmpArrays","isInArray","coordsArrayToMatrix","coords","x","m","usrCoords","a1","a2","removeElementFromArray","ar","el","trunc","toFixed","_decimalAdjust","exp","isNaN","NaN","_round10","_floor10","_ceil10","num","digits","autoDigits","abs","property","clone","cObj","cloneAndCopy","obj2","r","merge","obj1","deepCopy","c","i2","o","isAvail","primitives","layer","label","copyPrototypeMethods","subObject","superObject","constructorName","key","constructor","toJSON","noquote","list","JSON","stringify","clearVisPropOld","visPropOld","cssclass","cssdefaultstyle","cssstyle","fillcolor","fillopacity","firstarrow","fontsize","lastarrow","left","linecap","shadow","strokecolor","strokeopacity","strokewidth","tabindex","transitionduration","top","visible","isInObject","escapeHTML","str","unescapeHTML","capitalize","trimNumber","filterElements","filter","item","flower","visPropValue","pass","l","visProp","trim","sanitizeHTML","caja","html_sanitize","evalSlider","Value","Type","touchProperty","isTouchEvent","evt","isPointerEvent","pointerId","isMouseEvent","getNumberOfTouchPoints","isFirstTouch","touchPoints","isPrimary","isBrowser","supportsES6","Function","err","supportsVML","namespaces","supportsSVG","implementation","hasFeature","supportsCanvas","hasCanvas","isNode","createElement","getContext","global","requirejsVars","isWebWorker","self","postMessage","supportsPointerEvents","navigator","PointerEvent","pointerEnabled","msPointerEnabled","isTouchDevice","ontouchstart","isAndroid","userAgent","isWebkitAndroid","isApple","isWebkitApple","search","isMetroApp","clientInformation","appVersion","isMozilla","isFirefoxOS","ieVersion","div","all","getElementsByTagName","getDimensions","elementId","doc","display","els","originalVisibility","originalPosition","originalDisplay","originalWidth","originalHeight","style","pixelDimRegExp","width","height","clientWidth","clientHeight","getComputedStyle","parseFloat","visibility","position","addEvent","addEventListener","attachEvent","removeEvent","removeEventListener","detachEvent","removeAllEvents","getPosition","evtTouches","posx","posy","event","changedTouches","clientX","clientY","getOffset","cPos","o2","offsetLeft","scrollLeft","t","offsetTop","scrollTop","getCSSTransform","offsetParent","clientLeft","clientTop","parentNode","getStyle","stylename","ownerDocument","defaultView","getPropertyValue","currentStyle","letter","getProp","css","parseInt","start","len2","zoom","getCSSTransformMatrix","st","mat","timedChunk","items","process","context","todo","timerFun","Date","shift","_getScaleFactors","node","getBoundingClientRect","r_w","screen","r_h","vshift","scale","matchMedia","matches","scaleJSXGraphDiv","wrap_id","inner_id","styleSheets","pseudo_keys","len_pseudo","rule_inner","regex","RegExp","appendChild","createTextNode","body","cssRules","cssText","deleteRule","insertRule","XML","cleanWhitespace","cur","firstChild","nodeType","nodeValue","removeChild","nextSibling","parse","tree","DP","DOMParser","parseFromString","ActiveXObject","loadXML","EventEmitter","eventHandlers","suspended","trigger","h","len1","handler","on","off","eventify","triggerEventHandlers","memoizer","cache","memo","eps","relDif","max","mod","floor","vector","init","matrix","identity","frustum","projection","fov","ratio","tan","matVecMult","vec","res","matMatMult","mat1","mat2","m2","transpose","M","MT","inverse","Ain","ma","swp","A","hv","innerProduct","crossProduct","c1","c2","norm","sum","sqrt","axpy","y","le","factorial","binomial","round","cosh","sinh","acosh","asinh","Infinity","cot","acot","PI","atan","nthroot","inv","cbrt","pow","base","exponent","ratpow","g","gcd","log10","log2","sign","squampow","temp","lcm","erf","ProbFuncs","erfc","erfi","ndtr","ndtri","lt","leq","gt","geq","eq","neq","and","not","or","xor","stdform","signr","isFinite","toGL","Float32Array","Vieta","Mat","Coords","method","coordinates","emitter","scrCoords","setCoordinates","normalizeUsrCoords","usr2screen","doRound","mround","uc","oc","unitX","unitY","screen2usr","sc","distance","coord_type","ucr","scr","Number","POSITIVE_INFINITY","noevent","ou","os","copy","offset","isReal","__evt__update","__evt","Expect","each","format","coord","coordsArray","unshift","MAXNUM","SQRTH","SQRT2","MAXLOG","P","Q","R","S","T","U","MINV","expx2","u","u1","polevl","coef","N","ans","reduce","acc","p1evl","z","erfce","_underflow","q","s2pi","P0","Q0","P1","Q1","P2","Q2","y0","y2","code","DoubleBits","doubleBitsLE","toDoubleLE","lowUintLE","highUintLE","doubleBitsBE","toDoubleBE","lowUintBE","highUintBE","DOUBLE_VIEW","Float64Array","UINT_VIEW","Uint32Array","buffer","lo","hi","doubleBits","pack","fraction","denormalized","MatInterval","IntervalArithmetic","isInterval","isSingleton","TypeError","print","set","bounded","prev","next","boundedSingleton","assign","setEmpty","NEGATIVE_INFINITY","setWhole","open","halfOpenLeft","halfOpenRight","toArray","Interval","add","addLo","addHi","subLo","subHi","mul","xl","xh","yl","yh","out","EMPTY","mulLo","mulHi","zeroIn","divZero","divNegative","divPositive","divNonZero","positive","negative","isWhole","hasValue","hasInterval","intervalsOverlap","divLo","divHi","WHOLE","fmod","yb","ceil","multiplicativeInverse","power","ONE","powLo","powHi","nthRoot","yp","yn","expLo","expHi","logLo","logHi","ln","hull","badX","badY","intersection","union","difference","onlyInfinity","_handleNegative","interval","piTwiceLow","cos","pi2","cosv","rlo","rhi","PI_TWICE","piHigh","cosLo","cosHi","piLow","sin","PI_HALF","pi","piHalfLow","tanLo","tanHi","asin","piHalfHigh","asinLo","asinHi","acos","acosLo","acosHi","atanLo","atanHi","sinhLo","sinhHi","coshLo","coshHi","tanh","tanhLo","tanhHi","equal","notEqual","piTwiceHigh","_prev","nextafter","_next","toInteger","intLo","intHi","sinLo","sinHi","sqrtLo","sqrtHi","disable","enable","SMALLEST_DENORM","UINT_MAX","ZERO","Extrapolate","upper","infty","wynnEps","s_n","aux1","aux2","diff","estlim","aitken","denom","lowmax","brezinski","d0","d1","d2","iteration","x0","h0","step_type","w","E","levin","omega","beta","numer","fact","iteration_levin","v_prev","delta","limit","Quadtree","bbox","capacity","xlb","xub","ylb","yub","northWest","northEast","southEast","southWest","contains","insert","subdivide","mx","my","_query","query","xp","_x","_y","Env","predefinedButcher","rk4","heun","euler","Numerics","Gauss","Acopy","backwardSolve","canModify","gaussBareiss","det","Jacobi","aa","si","co","tt","ssum","amax","V","nloops","atan2","NewtonCotes","evaluation_point","number_of_intervals","integral_value","number_of_nodes","available_types","trapez","simpson","milne","integration_type","step_size","Romberg","integral","last","max_iterations","GaussLegendre","xm","xi","table_xi","table_w","_rescale_error","result_abs","result_asc","min_err","DBL_MIN","_gaussKronrod","xgk","wg","wgk","resultObj","up","mean","jtw","abscissa","fval1","fval2","fsum","jtwm1","center","half_length","abs_half_length","f_center","result_gauss","result_kronrod","fv1","fv2","abserr","resabs","resasc","GaussKronrod15","GaussKronrod21","GaussKronrod31","_workspace","size","nrmax","alist","blist","rlist","elist","order","level","qpsrt","errmax","errmin","i_nrmax","i_maxerr","set_initial_result","error","update","b1","area1","error1","b2","area2","error2","i_max","i_new","new_level","maximum_level","retrieve","sum_results","nn","result_sum","subinterval_too_small","Qag","area","errsum","result0","abserr0","resabs0","resasc0","tolerance","a_i","b_i","r_i","e_i","resasc1","wsObj","ws","epsrel","epsabs","roundoff_type1","roundoff_type2","error_type","area12","error12","I","Newton","df","newf","D","random","root","chandrupatla","generalizedNewton","t1ini","t2ini","t1","t2","disc","F","D00","D01","D10","D11","count","t1memo","t2memo","X","Y","Neville","makeFct","suspendedUpdate","bin","splineDef","pair","diag","data","dx","sort","splineEval","x_","asArray","generatePolynomialTerm","coeffs","deg","varname","prec","toPrecision","lagrangePolynomial","that","fct","getTerm","dot","lagrangePolynomialTerm","zeroes","coeffs_sum","isLeading","_initCubicPoly","x1","x2","CardinalSpline","tau_param","tau","_tau","which","first","dt0","dt1","dt2","Dist","dy","CatmullRomSpline","regressionPolynomial","degree","dataX","dataY","dX","dY","inputType","B","bezier","flen","t0","bspline","knots","kn","_knotVector","den","_evalBasisFuncs","_riemannValue","y1","delta1","riemann","gf","end","ylow","yup","xarr","yarr","riemannsum","rungeKutta","butcher","dim","maxIterationsRoot","maxIterationsMinimize","findBracket","fa","fb","fu","fzero","fc","prev_step","cb","tol_act","new_step","maxiter","niter","fminbr","x3","f1","f2","f3","fm","tl","ph","fl","fh","rand","fx","fv","fw","range","middle_range","ft","tol","sqrteps","RamerDouglasPeucker","pts","allPts","newPts","RDP","ci","cj","ck","lbda","dist","findSplit","RamerDouglasPeuker","Visvalingam","numPoints","vol","lastVol","lft","rt","lft2","rt2","linkedList","heap","used","idx","pop","Nlp","arr2","arraycopy","iox","Normal","MaxIterationsReached","DivergingRoundingErrors","FindMinimum","calcfc","rhobeg","rhoend","iprint","maxfun","status","fcalcfc","mpp","thisx","con","ocon","ix","cobylb","total","tempa","nfvals","jdrop","ibrnch","skipVertexIdent","phimin","nbest","pareta","wsig","weta","cvmaxp","cvmaxm","dxsign","resnew","barmu","phi","trured","edgmax","cmin","cmax","resmax","np","mp","rho","parmu","iflag","ifull","parsig","prerec","prerem","sim","simi","datmat","vsig","veta","sigbar","L_40","PrintIterationResult","L_140","L_550","DOT_PRODUCT","PART","ROW","COL","trstlp","icon","optold","icount","step","stpful","optnew","isave","vsave","kp","kk","sp","alpha","tot","spabs","acca","accb","zdotv","zdvabs","kw","dd","ss","sd","zdotw","zdwabs","sumabs","nactx","resold","zdota","vmultc","sdirn","dxnew","vmultd","iact","mcon","nact","L_60","L_70","src","rowidx","colidx","row","rows","dest","from","to","FORMAT","lhs","rhs","Statistics","prod","median","ArrayBuffer","isView","percentile","per","variance","weightedMean","multiply","arr1","divide","math","subtract","TheilSenRegression","slopes","tmpslopes","yintercepts","generateGaussian","stdDev","hasSpare","spare","Geometry","angle","C","trueAngle","rad","ax","ay","bx","by","cx","cy","angleBisector","phiA","phiC","Ac","Bc","Cc","reflection","line","point","mu","pc","p1c","point1","p2c","point2","rotation","rotpoint","rotpc","perpendicular","change","circumcenterMidpoint","circumcenter","point3","m1","array1","array2","affineDistance","affineRatio","sortVertices","ll","ps","lastPoint","signedTriangle","p1","p2","p3","signedPolygon","GrahamScan","calcStraight","margin","takePoint1","takePoint2","intersect1","intersect2","straightFirst","straightLast","straightfirst","straightlast","canvasWidth","canvasHeight","meetLineBoard","isSameDirection","isSameDir","calcLineDelimitingPoints","distP1P2","boundingBox","getBoundingBox","getSlope","projectPointToLine","calcLabelQuadrant","i1","dpx","dpy","dix","diy","sx","sy","intersectionFunction","el1","el2","alwaysintersect","el1_isArcType","el2_isArcType","meetCurveLine","meetPolygonLine","meetPathPath","first1","last1","first2","last2","meet","meetSegmentSegment","has","coordsOnArc","meetCurveCurve","arc","radiuspoint","anglepoint","ev_s","selection","meetLineLine","meetLineCircle","meetCircleCircle","l1","l2","lin","circ","circ1","circ2","radicalAxis","nr","bezierDegree","meetBezierCurveRedBlueSegments","meetCurveRedBlueSegments","alwaysIntersect","cu","li","meetCurveLineDiscrete","meetCurveLineContinuous","testSegment","func0","func1","tnew","tmin","fmin","epsLow","maxX","minX","lip1","lip2","cnt","numberPoints","ev_sf","ev_sl","meetBeziersegmentBeziersegment","red","blue","red1","red2","blue1","blue2","iFound","lenBlue","lenRed","q1","q2","li1","li2","path1","path2","intersections","Clip","_getPath","isEmptyCase","makeDoublyLinkedList","findIntersections","path","border","crds","borders","_bezierSplit","curve","p0","p00","p22","p000","_bezierBbox","bb","_bezierOverlap","bb1","bb2","_bezierListConcat","L","Lnew","t2exists","_bezierMeetSubdivision","bbb","bbr","b0","r0","r1","q0","_bezierLineMeetSubdivision","L2","po","redArr","blueArr","startRed","startBlue","bezierSegmentEval","bezierArc","withLegs","sgn","p4","PI2","projectPointToCircle","circle","factor","Radius","projectCoordsToSegment","projectCoordsToBeziersegment","pos","projectPointToCurve","projectCoordsToCurve","newCoords","newCoordsObj","mindist","minfunc","t_new","f_new","f_old","curvetype","Z","updateTransform","projectCoordsToPolygon","pol","proj","bestprojection","vertices","d_best","projectPointToTurtle","turtle","minEl","newPos","npmin","projectPointToPoint","projectPointToBoard","brd","distPointLine","nom","reuleauxPolygon","pi2_n","trig","suspendUpdate","meet3Planes","n1","n2","n3","d3","n31","n12","n23","meetPlanePlane","v11","v12","v21","v22","no1","no2","project3DTo3DPlane","normal","foot","getPlaneBounds","v1","v2","s1","s2","sol","Plot","checkReal","updateParametricCurveNaive","mi","stepSize","_t","isSegmentOutside","isDistOK","MAXX","MAXY","isSegmentDefined","updateParametricCurveOld","depth","MAX_DEPTH","MAX_XDIST","MAX_YDIST","dyadicStack","depthStack","pointStack","divisors","distOK","distFromLine","updateQuality","BOARD_QUALITY_LOW","_insertPoint_v2","pnt","lastReal","_lastCrds","newReal","cw","ch","neighborhood_isNaN_v2","_borderCase","ta","tb","tc","t_nan","t_real","t_real2","p_good","is_undef","_plotRecursive_v2","ds","isSmooth","isJump","mindepth","nanLevel","_isUndefined","_isOutside","_triangleDists","smoothLevel","jumpLevel","updateParametricCurve_v2","w2","ret_arr","pa","pb","recursiondepthlow","recursiondepthhigh","xterm","_findStartPoint","_visibleArea","_insertLimesPoint","limes","_lastUsrCrds","left_x","left_y","right_x","right_y","_lastScrCrds","_insertPoint","last_is_real","point_is_real","_isOutsidePoint","_getBorderPos","t_good","t_bad","_getCuspPos","_getJumpPos","_getLimits","x_l","x_r","y_l","y_r","_getLimes","may_be_special","_plotNonRecursive","a_nan","b_nan","ds0","stack_length","cusp_threshold","jump_threshold","smooth_threshold","testLevel","updateParametricCurve_v3","_criticalInterval","le1","med","sgnChange","abs_vec","very_small","smooth","group","types","positions","criticalThreshold","Component","left_isNaN","right_isNaN","left_t","right_t","t_values","x_values","y_values","findComponents","steps","comp","components","comp_nr","cntNaNs","comp_started","getPointType","t_approx","x_table","y_table","full_len","newtonApprox","table","thiele","recip","differenceMethodExperiments","component","numerator","x_diffs","y_diffs","x_slopes","y_slopes","x_recip","y_recip","foundCriticalPoint","criticalPoints","_criticalPoints","getCenterOfCriticalInterval","pos_mean","differenceMethod","res_x","res_y","degree_x","degree_y","_insertPoint_v4","doLog","getInterval","t_int","y_int","mathLib","mathLibJXG","handleBorder","components2","_seconditeration_v4","comp2","groups2","x_table2","y_table2","handleSingularity","_recurse_v4","d_lft","d_rgt","plot_v4","Ypl","Ymi","h2","good","updateParametricCurve_v4","updateParametricCurve","Metapost","MP_ENDPOINT","MP_EXPLICIT","MP_GIVEN","MP_CURL","MP_OPEN","MP_END_CYCLE","UNITY","FRACTION_ONE","FRACTION_THREE","ONE_EIGHTY_DEG","THREE_SIXTY_DEG","EPS_SQ","make_choices","dely","delx","cosine","sine","delta_x","delta_y","psi","rtype","ltype","set_left_curl","set_right_curl","rx","lx","ry","ly","mp_pyth_add","set_left_given","set_right_given","mp_solve_choices","vv","ldelta","ee","ww","uu","ff","theta","cc","ct_st","ct","cf_sf","cf","sf","k_idx","mp_n_sin_cos","right_given","left_given","mp_set_controls","reduce_angle","left_tension","right_tension","right_curl","mp_curl_ratio","left_curl","rr","mp_velocity","mp_ab_vs_cd","gamma","a_tension","b_tension","makeknots","tension","cycle","point_list","controls","direction","curl","isClosed","bitReverse","cplens","cplext","cpdist","cpdext","Util","Unzip","barray","gpflags","fileout","flens","fmax","outputArr","files","unzipped","buf32k","bIdx","modeZIP","barraylen","bytepos","literalTree","distanceTree","treepos","Places","fpos","nameBuf","readByte","byteAlign","readBit","carry","readBits","flushBuffer","addBuffer","String","fromCharCode","HufNode","jump","jumppos","isPat","rec","curplace","createTree","currentTree","numval","lengths","show","decodeValue","xtreepos","deflateLoop","ll2","blockLen","cSum","literalCodes","distCodes","lenCodes","nextFile","extralen","filelen","skipdir","NAMEMAX","unzipFile","unzip","UTF8D","UTF8","encode","string","utftext","unescape","encodeURIComponent","charCodeAt","decode","charCode","codepoint","state","chars","results","asciiCharCodeAt","Encoding","alphabet","_getByte","_getIndex","Base64","input","padLen","encInput","utf8","output","decodeAsArray","dec","Zip","Server","modules","runningCalls","handleError","message","callServer","action","sync","fileurl","passdata","AJAX","dataJSONStr","escape","serverBase","cbp","inject","paramlist","fields","namespace","parameters","XMLHttpRequest","overrideMimeType","setRequestHeader","onreadystatechange","readyState","responseText","send","loadModule_cb","loadModule","Symbolic","generateSymbolicCoordinatesPartial","variable","append","t_num","ancestors","makeCoords","listOfFreePoints","listOfDependantPoints","symbolic","clearSymbolicCoordinates","clear","generatePolynomials","generateCoords","number_of_ancestors","pgs","generatePolynomial","geometricLocusByGroebnerBase","polyStr","xs","xe","ys","ye","tx","bol","locus","oldRadius","numDependent","xsye","COORDS_BY_USR","xeys","transx","transy","rot","geoloci","translateToOrigin","toOrigin","translateTo10","to10","stretch","objectsList","radius","lociCoCoA","_isSeparator","_end","windingNumber","wn","Vertex","pathname","done","neighbour","entry_exit","_addToList","sortIntersections","P_crossings","next_node","P_intersect","P_le","_inbetween","px","py","qx","qy","_print_array","_print_list","_noOverlap","minp","maxp","minq","maxq","no_overlap","Si","Si1","Cj","Cj1","IS","IC","S_le","C_le","S_intersect","S_crossings","C_crossings","hasMultCompsS","hasMultCompsC","_getPosition","_classifyDegenerateIntersections","Pp","Pm","Qp","Qm","side","oppositeDir","s3","s4","_tours","delayedStatus","_handleIntersectionChains","P_start","start_status","intersection_chain","wait_for_exit","_handleFullyDegenerateCase","le2","is_on_Q","is_fully_degenerated","_getStatus","markEntryExit","starters","chain_start","_starter","_stayOnPath","stay","_addVertex","vertex","DEBUG","tracing","clip_type","current","S_idx","_getCoordsArrays","doClose","pathX","pathY","handleEmptyIntersection","reverse","_countCrossingIntersections","greinerHormann","subject","clip","S_starters","C_starters","Poly","Ring","variables","vars","Monomial","ring","coefficient","exponents","Polynomial","mons","monomials","findSignature","sig","addSubMonomial","Complex","isComplex","imaginary","real","absval","mult","re","im","conj","z1","z2","simpleColors","aliceblue","antiquewhite","aqua","aquamarine","azure","beige","bisque","black","blanchedalmond","blueviolet","brown","burlywood","cadetblue","chartreuse","chocolate","coral","cornflowerblue","cornsilk","crimson","cyan","darkblue","darkcyan","darkgoldenrod","darkgray","darkgreen","darkkhaki","darkmagenta","darkolivegreen","darkorange","darkorchid","darkred","darksalmon","darkseagreen","darkslateblue","darkslategray","darkturquoise","darkviolet","deeppink","deepskyblue","dimgray","dodgerblue","feldspar","firebrick","floralwhite","forestgreen","fuchsia","gainsboro","ghostwhite","gold","goldenrod","gray","green","greenyellow","honeydew","hotpink","indianred","indigo","ivory","khaki","lavender","lavenderblush","lawngreen","lemonchiffon","lightblue","lightcoral","lightcyan","lightgoldenrodyellow","lightgrey","lightgreen","lightpink","lightsalmon","lightseagreen","lightskyblue","lightslateblue","lightslategray","lightsteelblue","lightyellow","lime","limegreen","linen","magenta","maroon","mediumaquamarine","mediumblue","mediumorchid","mediumpurple","mediumseagreen","mediumslateblue","mediumspringgreen","mediumturquoise","mediumvioletred","midnightblue","mintcream","mistyrose","moccasin","navajowhite","navy","oldlace","olive","olivedrab","orange","orangered","orchid","palegoldenrod","palegreen","paleturquoise","palevioletred","papayawhip","peachpuff","peru","pink","plum","powderblue","purple","rosybrown","royalblue","saddlebrown","salmon","sandybrown","seagreen","seashell","sienna","silver","skyblue","slateblue","slategray","snow","springgreen","steelblue","teal","thistle","tomato","turquoise","violet","violetred","wheat","white","whitesmoke","yellow","yellowgreen","colorDefs","example","bits","rgbParser","color","ag","ab","color_string","channels","processor","testFloat","values","substr","exec","rgb2css","rgb2hex","hex2rgb","hex","hsv2rgb","H","G","hTemp","rgb2hsv","fr","fg","rgb2LMS","LMS2rgb","lut_lookup","rgba2rgbo","rgba","opacity","rgbo2rgba","rgb","rgb2bw","rgb2cb","deficiency","lms","HexChars","autoHighlight","colstr","col","opa","contrast","hexColor","darkColor","lightColor","threshold","rgbBlack","contrastRatio","setClassicColors","Options","strokeColor","fillColor","hatch","highlightFillColor","circumcircle","circumcirclearc","circumcirclesector","conic","incircle","inequality","curveLeft","curveRight","polygon","regularpolygon","sector","semicircle","slopetriangle","arrow","paletteWong","bluishgreen","vermillion","reddishpurple","palette","Color","enabled","compile","maxBoundingBox","zoomFactor","zoomX","zoomY","title","description","showCopyright","axis","defaultAxes","ticks","anchorX","anchorY","fontSize","drawZero","tickEndings","showNavigation","showZoom","showReload","showScreenshot","screenshot","symbol","cssButton","showFullscreen","fullscreen","showClearTraces","keepAspectRatio","ignoreLabels","maxNameLength","takeFirst","takeSizeFromFile","renderer","animationDelay","maxFrameRate","registerEvents","minimizeReflow","offsetX","offsetY","factorX","factorY","wheel","needShift","pinchHorizontal","pinchVertical","pinchSensitivity","pan","needTwoFingers","drag","keyboard","panShift","panCtrl","resize","throttle","moveTarget","needCtrl","withLines","showInfobox","navbar","padding","cursor","zIndex","right","bottom","highlightStrokeColor","strokeOpacity","highlightStrokeOpacity","fillOpacity","highlightFillOpacity","gradient","gradientSecondColor","gradientSecondOpacity","gradientStartOffset","gradientEndOffset","gradientAngle","gradientCX","gradientCY","gradientR","gradientFX","gradientFY","gradientFR","transitionDuration","strokeWidth","highlightStrokeWidth","fixed","frozen","withLabel","priv","dash","trace","traceAttributes","highlight","needsRegularUpdate","snapToGrid","scalable","dragToTopOfLayer","precision","draft","isLabel","generateLabelText","generateLabelValue","drawLabels","beautifulScientificTickLabels","useUnicodeMinus","anchor","insertTicks","minTicksDistance","minorHeight","majorHeight","minorTicks","scaleSymbol","labels","maxLabelLength","ticksDistance","face","includeBoundaries","touch","touchMax","mouse","pen","epsilon","hasPoint","numlayers","unused9","unused8","unused7","unused6","unused5","unused4","unused3","unused2","unused1","unused0","text","glider","grid","image","orthoType","orthoSensitivity","pointsquare","hasInnerPoints","firstArrow","lastArrow","useDirection","radiusPoint","anglePoint","highlightSize","withTicks","bisector","bisectorlines","line1","line2","boxplot","dir","smallWidth","button","disabled","cardinalspline","createPoints","isArrayOfCoordinates","chart","chartStyle","colors","highlightcolors","highlightonsector","highlightbysize","checkbox","checked","foci","useQDT","handDrawing","curveType","RDPsmoothing","numberPointsHigh","numberPointsLow","doAdvancedPlot","recursionDepthHigh","recursionDepthLow","doAdvancedPlotOld","plotVersion","foreignobject","attractors","hasGrid","gridX","gridY","snapSizeX","snapSizeY","htmlslider","widthRange","widthOut","imageString","cssClass","highlightCssClass","rotate","infobox","baseLeft","baseRight","maxlength","autoPosition","legend","rowHeight","defaultDistance","touchFirstPoint","touchLastPoint","lineCap","metapostspline","mirrorelement","orthogonalprojection","parallel","perpendicularsegment","sizeUnit","infoboxDigits","attractorUnit","attractorDistance","snatchDistance","attractToGrid","snapToPoints","ignoredSnapToPoints","polygonalchain","prescribedangle","highlightOnSector","segment","slider","snapWidth","suffixLabel","unitLabel","postLabel","baseline","highline","moveOnUp","comb","frequency","basepoint","tangent","toppoint","stepfunction","tapemeasure","fontUnit","useCaja","cssDefaultStyle","highlightCssDefaultStyle","cssStyle","highlightCssStyle","useASCIIMathML","useMathJax","useKatex","dragArea","tracecurve","shortcuts","highlightColor","highlightOpacity","Validator","validateColor","validateInteger","validatePositiveInteger","validatePositive","validateNotNegative","validators","normalizePointFace","cross","square","plus","diamond","triangleup","triangledown","triangleleft","triangleright","useStandardOptions","copyProps","boardHadGrid","gridColor","gridOpacity","gridDash","SnapSizeX","SnapSizeY","highlightfillcolor","highlightstrokecolor","majorTicks","minorheight","majorheight","highlightfillopacity","fullUpdate","removeGrids","useBlackWhiteOptions","AbstractRenderer","vOffsetText","enhancedRendering","supportsForeignObject","_updateVisual","enhanced","setObjectTransition","setDraft","stroke","highlighted","setObjectStrokeColor","highlightstrokeopacity","setObjectStrokeWidth","highlightstrokewidth","fill","setObjectFillColor","setDashStyle","setShadow","setTabindex","_getHighlighted","isTrace","highlightedObjects","drawPoint","prim","rendNode","appendChildPrim","createPrim","appendNodesToElement","updatePoint","unit","sizeunit","updateEllipsePrim","updateRectPrim","updatePathPrim","updatePathStringPoint","changePointStyle","remove","visPropCalc","drawLine","updateLine","updatePathWithArrowHeads","setLineCap","drawCurve","updateCurve","doHighlight","arrowData","ev","hl","getArrowHeadData","makeArrows","updateLineWithEndings","updatePath","setArrowSize","typeFirst","typeLast","minlen","offFirst","offLast","sizeFirst","sizeLast","ev_fa","ev_la","evFirst","evLast","showFirst","showLast","minLen","handleTouchpoints","getPositionArrowHead","updateLinePrim","handdrawing","updatePathStringBezierPrim","updatePathStringPrim","d1x","d1y","d2x","d2y","touchfirstpoint","touchlastpoint","_setArrowWidth","rendNodeTriangleStart","rendNodeTriangleEnd","drawTicks","updateTicks","drawEllipse","updateEllipse","drawPolygon","updatePolygon","updatePolygonPrim","displayCopyright","drawInternalText","updateInternalText","drawText","ev_visible","className","setAttribute","htmlStr","islabel","prepareUpdate","updateVisibility","updateText","content","plaintext","updateTextStyle","getAnchorX","getAnchorY","rendNodeButton","rendNodeLabel","usemathjax","MathJax","typeset","Hub","Queue","containerObj","_cssFullscreenStore","usekatex","katex","render","throwOnError","useasciimathml","AMprocessNode","transformImage","transformations","_css2js","cssString","pairs","match","char","fs","so","cssList","nodeList","lenN","fontunit","styleList","lenS","highlightcssclass","needsSizeUpdate","updateInternalTextStyle","drawImage","updateImage","updateImageURL","joinTransforms","ox","oy","ux","uy","updateImageStyle","drawForeignObject","updateForeignObject","p1x","p1y","p2x","p2y","pathString","setPropertyPrim","hide","setBuffering","draftColor","draftOpacity","removeDraft","setGradient","updateGradient","duration","sw","noHighlight","suspendRedraw","unsuspendRedraw","drawZoomBar","cancelbubble","stopPropagation","cancelBubble","createButton","paddingLeft","paddingRight","classList","backgroundColor","zindex","showfullscreen","toFullscreen","showscreenshot","showreload","reload","showcleartraces","clearTraces","shownavigation","showzoom","zoomOut","zoom100","zoomIn","clickLeftArrow","clickUpArrow","clickDownArrow","clickRightArrow","removeToInsertLater","insertBefore","createTouchpoints","showTouchpoint","hideTouchpoint","updateTouchpoint","dumpToDataURI","_ignoreTexts","dumpToCanvas","canvasId","setLayer","FileReader","handleRemoteFile","url","async","encoding","request","ex","exc","responseStream","jxgBinFileReader","parseString","ex2","handleLocalFile","target","onload","readAsText","parseFileContent","Reader","read","write","GeonextParser","replacePow","te","previousIndex","leftop","rightop","pre","expr","$1","replaceIf","k1","k2","meat","second","third","replaceNameById","elName","funcs","printId","replaceIdByObj","geonext2JS","newterm","findDependencies","me","elmask","addChild","gxt2jc","GeometryElement","oclass","needsUpdate","isDraggable","childElements","hasLabel","notExistingParents","traces","numTraces","baseElement","descendants","elType","dump","subs","inherits","_pos","methodMap","setLabel","setName","getName","addTransform","setProperty","animate","addTicks","removeTicks","removeAllTicks","quadraticform","mouseover","lastDragTime","_org_type","generateName","needsregularupdate","resolveShortcuts","_set","addDescendants","addParents","par","setParents","removeDescendants","countChildren","transform","draggable","setPosition","applyOnce","isNumericMatrix","melt","updateGlider","setPositionDirectly","oldcoords","oldc","dc","hash","time","delay","animationdelay","animateColor","startRGB","endRGB","hsv1","hsv2","sh","sv","animationData","animateFloat","animationCallback","addAnimation","cloneToBackground","updateRenderer","setDisplayRendNode","len_s","hideElement","showElement","parent_val","hiddenByParent","toLocaleLowerCase","subattr","setLabelText","setText","arg","oldvalue","properties","infoboxText","updateSize","clearTrace","gradientsecondcolor","gradientsecondopacity","withlabel","createLabel","setRadius","addRotation","ticksFunction","makeTicksFunction","onPolygon","rendNodeTag","rendNodeCheckbox","getProperty","getAttribute","setDash","getTextAnchor","getLabelAnchor","setArrow","createGradient","ev_g","force","bounds","vis","json","tOffInv","tOff","tS","tSInv","tRot","bindTo","sColor","fColor","labelColor","lColor","getType","getParents","getAttributes","cleanThis","tick","defaultTicks","removeObject","getSnapSizes","sX","sY","snapsizex","snapsizey","ticksDelta","minorticks","handleSnapToGrid","fromParent","rcoords","boardBB","attracttogrid","ev_au","attractorunit","ev_ad","attractordistance","snaptogrid","__evt__over","__evt__mouseover","__evt__out","__evt__mouseout","__evt__move","__evt__mousemove","__evt__drag","__evt__mousedrag","__evt__pendrag","__evt__touchdrag","__evt__down","__evt__mousedown","__evt__pendown","__evt__touchdown","__evt__up","__evt__mouseup","__evt__penup","__evt__touchup","__evt__attribute","__evt__attribute_","nval","CoordsElement","initialCoords","isConstrained","slideObject","slideObjects","needsUpdateFromParent","Xjc","Yjc","move","moveTo","moveAlong","visit","glide","makeGlider","intersect","makeIntersection","free","setGliderPosition","addConstraint","addAnchor","updateConstraint","updateCoords","updateGliderFromParent","poly","cp","invMat","ev_sw","isTransformed","slide","slides","isgeonext","parentPolygon","snapwidth","_smax","_smin","getTransformationSource","_transformationSource","updateTransformMatrix","transformMat","baseangle","updateRendererGeneric","rendererMethod","XEval","YEval","ZEval","handleSnapToPoints","pEl","pCoords","dMax","ev_is2p","ignoredsnaptopoints","ignore","snaptopoints","handleAttractors","projCoords","ev_sd","snatchdistance","ev_a","popSlideObject","oldCoords","relativeCoords","isSuspendedUpdate","setPositionByTransform","tv","slideobj","MAX_VALUE","ancestorId","ancestor","terms","newfuncs","makeConstFunction","makeSliderFunction","ev_o","startAnimation","stepCount","intervalCode","setInterval","_anim","intervalCount","stopAnimation","clearInterval","neville","interpath","makeFakeFunction","interpolate","animationPath","animationStart","getTime","where","stepFun","effect","repeat","startPoint","newX","sp1c","sp2c","Callback","arg1","arg2","slideobject","_val","rendNodeRange","rendNodeOut","Text","coordsConstructor","plaintextOld","orgText","setId","finalizeAdding","notifyParents","bot","_inputDevice","dragarea","_createFctUpdateText","resolvedText","ev_p","ev_um","ev_uk","replaceSub","replaceSup","convertGeonextAndSketchometry2CSS","generateTerm","_setText","setTextJessieCode","castext","ev_d","offsetWidth","offsetHeight","crudeSizeEstimate","getBBox","ev_fs","utf8_decode","getSize","setCoords","coordsAnchor","checkForSizeUpdate","autoposition","setAutoPosition","expandShortMath","contentStr","expand","avoidGeonext2JS","convertGeonext2CSS","convertSketchometry2CSS","anchorx","anchory","getNumberofConflicts","savePointPrecision","anchorCoords","start_angle","delta_r","conflicts","optimum","createText","parent","createHTMLSlider","rendNodeForm","childNodes","widthrange","verticalAlign","widthout","uuidChars","genUUID","uuid","rnd","UUID","_ccache","JessieCode","geonext","scope","hasChild","locals","previous","scopes","dpstack","pscope","propstack","propscope","isLHS","warnLog","$log","builtIn","defineBuiltIn","operands","getPossibleOperands","lineToElement","parCurLine","parCurColumn","CA","createNode","children","isMath","pushScope","popScope","vname","clearCache","letvar","_warn","isLocalVariable","isParameter","isCreator","isMathMethod","isBuiltIn","getvar","local","isFunctionName","resolve","getvarJS","withProps","_error","isMap","functionCodeJS","bo","bc","defineFunction","_that","replaceNames","$jc$","eval","argtypes","resolveType","_pstack","oldscope","execute","toJS","replaceIDs","collectDependencies","mergeAttributes","setProp","_genericParse","cmd","dontstore","setTextBackup","ast","ccode","cleaned","parser","expandDerivatives","removeTrivialNodes","manipulate","getAST","funwrap","replaced","createReplacementNode","resolveProperty","getLHS","getLHSCompiler","js","ilist","_isFunctionName","ecol","jcLineStart","jcLineEnd","eline","debugParents","use","del","neg","needsBrackets","useId","Area","Intervalt","randint","DDD","ifthen","cond","ref","found","$board","findSymbol","importModule","EULER","lb","ld","lg","IfThen","$","funcsJC","consts","FORBIDDEN","jessiecode","localeCompare","includes","numParams","getOwnPropertyNames","functions","functions_jessiecode","_debug","msg","_log","$V0","$V1","$V2","$V3","$V4","$V5","$V6","$V7","$V8","$V9","$Va","$Vb","$Vc","$Vd","$Ve","$Vf","$Vg","$Vh","$Vi","$Vj","$Vk","$Vl","$Vm","$Vn","$Vo","$Vp","$Vq","$Vr","$Vs","$Vt","$Vu","$Vv","$Vw","$Vx","$Vy","$Vz","$VA","$VB","$VC","$VD","$VE","$VF","$VG","$VH","$VI","$VJ","$VK","$VL","$VM","$VN","$VO","$VP","$VQ","$VR","$VS","$VT","$VU","$VV","$VW","$VX","yy","symbols_","terminals_","productions_","performAction","yytext","yyleng","yylineno","yystate","$$","_$","$0","AST","lc","defaultActions","parseError","recoverable","vstack","lstack","recovering","TERROR","EOF","lexer","sharedState","setInput","yylloc","yyloc","ranges","getPrototypeOf","preErrorSymbol","newState","expected","lex","token","yyval","errStr","showPosition","loc","first_line","last_line","first_column","last_column","lc1","_input","_more","_backtrack","matched","conditionStack","unput","lines","oldLines","more","reject","backtrack_lexer","less","pastInput","past","upcomingInput","test_match","indexed_rule","backup","tempMatch","rules","_currentRules","flex","begin","condition","popState","conditions","topState","pushState","stateStackSize","yy_","$avoiding_name_collisions","YY_START","Parser","exit","source","readFileSync","argv","Composition","genericMethods","generateMethod","nameListener","oval","Board","BOARD_MODE_NONE","BOARD_MODE_DRAG","BOARD_MODE_MOVE_ORIGIN","BOARD_MODE_ZOOM","BOARD_QUALITY_HIGH","grids","dimension","keepaspectratio","generateId","hooks","dependentBoards","inUpdate","animationObjects","numObjects","mode","isSuspendedRedraw","calculateSnapSizes","drag_dx","drag_dy","drag_position","touches","xmlString","touchMoveLast","touchMoveLastId","positionAccessLast","downObjects","showcopyright","needsFullUpdate","reducedUpdate","currentCBDef","geonextCompatibilityMode","translateASCIIMath","hasMouseHandlers","hasTouchHandlers","hasPointerHandlers","hasMouseUp","hasTouchEnd","hasPointerUp","_drag_offset","_board_touches","selectingMode","isSelecting","_isScrolling","_isResizing","selectingBox","registerevents","addEventHandlers","setView","setBoundingBox","migratePoint","colorblind","unsuspendUpdate","down","zoomElements","possibleNames","maxnamelength","post","indices","randomNumber","elId","finalizeLabel","checkFrameRate","handleEvt","maxframerate","getCoordsTopLeftCorner","crect","ownerDoc","docElement","documentElement","docBody","google","translate","offsetx","offsety","getMousePosition","absPos","cssTransMat","updateCSSTransforms","initMoveOrigin","initMoveObject","haspoint","collect","dragEl","ignorelabels","takefirst","dragtotopoflayer","previousRotation","previousScale","moveObject","dragScrCoords","newDragScrCoords","getScrCoordsOfMouse","displayInfobox","targets","Xprev","Yprev","updateInfobox","twoFingerMove","twoFingerTouchObject","twoFingerTouchCircle","tar","op","nd","od","t3","t4","t5","fixEl","moveEl","fix","updateRadius","highlightElements","pId","overObjects","saveStartPos","xy","Zstart","Xstart","Ystart","mouseOriginMoveStart","_isRequiredKeyPressed","mouseOriginMove","moveOrigin","touchStartMoveOriginOneFinger","needtwofingers","touchOriginMove","originMoveEnd","addPointerEventHandlers","addMouseEventHandlers","addTouchEventHandlers","oncontextmenu","preventDefault","addFullscreenEventHandlers","addKeyboardEventHandlers","startResizeObserver","resizeListener","startIntersectionObserver","scrollListener","removeEventHandlers","removeMouseEventHandlers","removeTouchEventHandlers","removePointerEventHandlers","removeFullscreenEventHandlers","removeKeyboardEventHandlers","resizeObserver","stopResizeObserver","stopIntersectionObserver","movetarget","pointerDownListener","pointerMoveListener","mouseWheelListener","touchAction","mouseDownListener","mouseMoveListener","appleGestures","touchStartListener","touchMoveListener","events","hasFullsceenEventHandlers","fullscreenListener","hasKeyboardHandlers","keyDownListener","keyFocusInListener","keyFocusOutListener","pointerUpListener","mouseUpListener","touchEndListener","gestureChangeListener","dir1","dir2","bound","isPinch","zx","factorx","zy","factory","prevDist","prevCoords","isPreviousGesture","prevScale","pinchhorizontal","pinchvertical","pinchsensitivity","gestureStartListener","needshift","shiftKey","needctrl","ctrlKey","_isPointerRegistered","_pointerStorePosition","_pointerRemoveTouches","_pointerClearTouches","dehighlightAll","_getPointerInputDevice","pointerType","msMaxTouchPoints","sel","target_obj","empty","getSelection","removeAllRanges","_testForSelection","_startSelecting","returnValue","touchTargets","_moveSelecting","_stopSelecting","stopSelectionMode","jxg_isused","screenX","screenY","pos1","pos2","foundNumber","tmpTouches","wd","detail","wheelDelta","actPos","id_node","doZoom","panshift","panctrl","keyCode","updateContainerDims","boundingbox","_prevDim","resizeContainer","ResizeObserver","entries","observe","unobserve","intersectionObserver","IntersectionObserver","rootMargin","initInfobox","distanceX","distanceY","xc","yc","vpinfoboxdigits","vpsi","showinfobox","infoboxdigits","highlightInfobox","highlightCustomInfobox","needsDehighlight","getUsrCoordsOfMouse","getAllUnderMouse","elList","getAllObjectsUnderMouse","ob","ul","lr","maxboundingbox","addConditions","xyFun","visFun","colFun","posFun","styleFun","setStyle","updateConditions","updateElements","applyZoom","zX","zY","tr","zoomAllPoints","borderX","borderY","minY","maxY","box","newBBox","setZoom","fX","fY","oX","oY","saveMethod","removeAncestors","anc","initGeonextBoard","dontset","dontSetBoundingBox","showDependencies","close","showXML","updateRendererCanvas","mini","la","olen","layers","addHook","hook","removeHook","updateHooks","storeActiveEl","minimizereflow","activeElement","svgRoot","focus","addGrid","elementType","offX","offY","zoomx","zoomy","animationIntervalCode","stopAllAnimation","props","cbtmp","copyName","child","childId","srcLabelId","srcHasLabel","emulateColorblindness","visPropOriginal","onlyByIdOrName","flist","olist","host","startSelectionMode","selectionPolygon","_setSelectionPolygonFromBox","_createSelectionPolygon","selectionattr","__evt__pointerdown","__evt__touchstart","__evt__pointerup","__evt__touchend","__evt__penmove","__evt__pointermove","__evt__touchmove","__evt__hit","__evt__mousehit","__evt__boundingbox","__evt__startselecting","__evt__mousestartselecting","__evt__pointerstartselecting","__evt__touchstartselecting","__evt__stopselecting","__evt__mousestopselecting","__evt__pointerstopselecting","__evt__touchstopselecting","__evt__moveselecting","__evt__mousemoveselecting","__evt__pointermoveselecting","__evt__touchmoveselecting","wrap_node","inner_node","_fullscreen_inner_id","_fullscreen_res","requestFullscreen","webkitRequestFullscreen","mozRequestFullScreen","msRequestFullscreen","fullscreenElement","webkitFullscreenElement","mozFullscreenElement","msFullscreenElement","isFullscreen","createRoulette","start_c1","stepsize","pointlist","c1dist","Tx","Ty","c1x","c1y","c2x","c2y","t1_new","t2_new","rotationLocal","arclen","cpxa","cpya","cpxb","cpyb","cpxab","cpyab","exactDist","beta9","rolling","hp","gp","stop","SVGRenderer","isIE","svgNamespace","xlinkNamespace","MozUserSelect","userSelect","overflow","createElementNS","defs","setAttributeNS","feOffset","feGaussianBlur","feBlend","foreignObjLayer","dashArray","_createArrowHead","idAppendix","node2","node3","_setArrowColor","_setAttribute","tickStr","whiteSpace","rendNodeText","ev_ax","ev_ay","getAttributeNS","_src","imgIsLoaded","_useUserSize","shape","huge","pointString","sqrt32","s05","nextSymb","pStr","isNoPlot","dashStyle","hasAttributeNS","removeAttributeNS","fillNode","gradNode1","gradNode2","gradNode","updateGradientAngle","radians","updateGradientCircle","fy","gradientstartoffset","gradientendoffset","gradientangle","gradientcx","gradientcy","gradientr","gradientfx","gradientfy","gradientfr","transitionStr","nodes","transition","setFunc","testAttribute","rgbo","oo","grad","capStyle","na1","na2","touchpoints","_getValuesOfDOMElements","_getDataUri","Image","canvas","naturalWidth","naturalHeight","toDataURL","_getImgDataURL","images","ctx","ur","ignoreTexts","svg","btoa","hasChildNodes","XMLSerializer","serializeToString","tmpImg","cv","Promise","imgId","img","buttonText","zbar","zbarDisplay","_copyCanvasToImg","bas","newImg","onclick","then","VMLRenderer","onselectstart","resolution","vmlStylesheet","createStyleSheet","addRule","jxgvml","tagName","_setAttr","iFlag","documentMode","tickArr","rendNodeStroke","fontFamily","filters","M11","M12","M21","M22","rendNodePath","rendNodeFill","rendNodeShadow","pathNode","strokeNode","shadowNode","removeNode","nodeStroke","keyVml","nodeFill","gradientpositionx","gradientpositiony","nodeShadow","CanvasRenderer","canvasRoot","suspendHandle","canvasNamespace","_drawPolygon","doFill","lineWidth","beginPath","lineTo","bezierCurveTo","closePath","_fill","save","_setColor","restore","_rotatePoint","_rotateShape","rv","x1s","x2s","y1s","y2s","createLinearGradient","cxs","cys","rs","fxs","fys","frs","createRadialGradient","addColorStop","targetType","hasColor","globalAlpha","_stroke","ev_dash","setLineDash","lineDashArray","_translateShape","stroke05","lineJoin","fillRect","drawArrows","scr1","scr2","w0","arrowHead","arrowTail","type_fa","type_la","ang1","ang2","degree_fa","degree_la","c1_org","c2_org","rX","rY","aWidth","aHeight","aX","aY","hB","vB","eX","eY","mX","mY","font","fillStyle","fillText","textAlign","textBaseline","paintImg","clearRect","NoRenderer","JSXGraph","rendererType","onmousemove","initRenderer","attrRenderer","boxid","_setAttributes","_fillBoard","dimensions","_setARIA","doc_glob","node_jsx","newNode","id_label","id_description","_removeARIANodes","initBoard","originX","originY","axattr","axattr_x","axattr_y","unitx","unity","originx","originy","zoomfactor","defaultaxes","loadBoardFromFile","file","loadBoardFromString","freeBoard","txt","maxWidth","aspectRatio","cssClasses","postpone","scripts","construct","makeReload","newBoard","Point","coordsScr","func","poly1","poly2","normalizeFace","isOn","hasinnerpoints","pnpoly","traceattributes","createPoint","createGlider","createIntersectionPoint","intersectionNumbers","createOtherIntersectionPoint","other","createPolePoint","firstParentIsConic","secondParentIsConic","firstParentIsLine","secondParentIsLine","createIntersection","createOtherIntersection","Line","updateStdform","getRise","getYIntersect","getAngle","vnew","funps","constrained","funp1","funp2","updateSegmentFixedLength","dnew","drag1","drag2","hasFixedLength","fixedLength","fixedLengthOldCoords","u2","w1","setStraight","setLabelRelativeCoords","relCoords","er","forceIt","createLine","doTransform","createSegment","createArrow","createAxis","attr_ticks","ticksdistance","createTangent","createRadicalAxis","createPolarLine","firstParentIsPoint","secondParentIsPoint","createPolar","Group","number","objArray","rotationCenter","scaleCenter","rotationPoints","translationPoints","scalePoints","scaleDirections","addPoint","ungroup","addPoints","addGroup","removePoint","_updateCoordsCache","actionCenter","desc","_update_find_drag_type","_update_centroid_center","_update_apply_transformation","dragObjId","changed","setRotationCenter","setRotationPoints","_setActionPoints","addRotationPoint","_addActionPoint","removeRotationPoint","_removeActionPoint","setTranslationPoints","addTranslationPoint","removeTranslationPoint","setScaleCenter","setScalePoints","objs","addScalePoint","removeScalePoint","createGroup","createEllipse","polarForm","majorAxis","hasPointOrg","attr_foci","attr_center","attr_curve","axbx","ayby","midpoint","ac","createHyperbola","createParabola","attr_line","F1","createConic","fitConic","degconic","sym","eigen","definingMat","givenByPoints","rotationMatrix","attr_point","pBp","pAp","Mv","Conic","Circle","par1","par2","gxtterm","getRadius","g1","g2","rsq","generateRadiusSquared","updateQuadraticform","createCircle","point_style","Polygon","withlines","ids","names","Perimeter","Length","insertPoints","removePoints","x_in","y_in","isIn","borderless","findPoint","nvertices","nborders","nidx","partition","sutherlandHodgman","lenIn","inputList","lenClip","lenSubject","outputList","isInside","c3","createPolygon","attr_points","is_transform","createRegularPolygon","pointsExist","createPolygonalChain","QDT","Curve","numberpointshigh","qdt","yterm","setTerm","checkPoint","tX","tY","ux2","uy2","ev_ct","numberpointslow","useqdt","allocatePoints","updateDataArray","plotversion","doadvancedplot","doadvancedplotold","rdpsmoothing","interpolationFunctionFromArray","fstr","dep","isJessieCode","curve_org","createCurve","createFunctiongraph","createSpline","createCardinalSpline","getPointLike","splineArr","isarrayofcoordinates","createpoints","ii","createMetapostSpline","createRiemannsum","createTracecurve","tracepoint","savetrace","numberpoints","savePos","slideObj","createStepfunction","createDerivative","class","createCurveIntersection","createCurveUnion","createCurveDifference","createBoxPlot","r2","smallwidth","createPlot","createArc","usedirection","p0c","hasPointSector","vecx","vecy","pmc","bxminusax","byminusay","l_vp","createSemicircle","createCircumcircleArc","createMinorArc","createMajorArc","createSector","autoRadius","r3","direction1","direction2","point4","vp_s","hasPointCurve","createCircumcircleSector","createMinorSector","createMajorSector","createAngle","attrsub","updateDataArraySector","setAngle","val2","updateDataArraySquare","updateDataArrayNone","orthosensitivity","orthotype","createNonreflexAngle","createReflexAngle","Transformation","params","setMatrix","evalParam","xoff","yoff","len0","createTransform","Transform","createOrthogonalProjection","createPerpendicular","pd","createPerpendicularPoint","createPerpendicularSegment","createMidpoint","createParallelPoint","createParallel","pp","pl","ty","createArrowParallel","createNormal","attrp","bezierdegree","createBisector","createAngularBisectorsOfTwoLines","createCircumcenter","createIncenter","createCircumcircle","createIncircle","createReflection","org","r_c","attr2","createMirrorElement","createMirrorPoint","createIntegral","startx","starty","endx","endy","pa_on_curve","pa_on_axis","pb_on_curve","pb_on_axis","Int","lowx","upx","lowy","upy","createGrid","topLeft","bottomRight","gridx","gridy","topleft","tltype","bottomright","brtype","createInequality","dp","slope1","slope2","curve_mi","curve_ma","firstx","lastx","enlarge","createMsector","createAngularBisectorOfTwoLines","createPerpendicularSegmen","createLocus","dontCallServer","spe","equations","ctime","datax","datay","polynomial","exectime","W","usrSize","span","addTransformation","trans","updateSpan","setSize","createImage","createSlider","pos0","smin","smax","sdiff","ti","withText","withticks","setValue","setMax","setMin","sl","suffixlabel","unitlabel","postlabel","generatelabeltext","zero","dFull","getDistanceFromZero","formatLabelText","baseLine","highLine","moveonup","createTapemeasure","DataSource","columnHeaders","rowHeaders","loadFromArray","columnHeader","rowHeader","cell","loadFromTable","addColumn","addRow","getColumn","getRow","Sector","Chart","chartstyle","drawBar","drawFit","drawSpline","drawPie","drawPoints","drawRadar","xp0","xp1","xp2","attrSub","pols","makeXpFun","hiddenPoint","infoboxArray","infoboxarray","infoboxtext","colorArray","highlightColorArray","labelArray","cent","makeRadPointFun","highlightHandleLabel","highlightFun","noHighlightFun","labelcolor","sectors","paramArray","numofparams","maxes","mins","pdata","ssa","esa","ssratio","esratio","sshifts","eshifts","starts","ends","myAtts","xcoord","ycoord","polygons","circles","lxoff","lyoff","cla","clabelArray","ncircles","pcircles","dr","get_anchor","get_transform","tscale","trot","paramarray","startshiftratio","endshiftratio","startshiftarray","endshiftarray","startarray","endarray","labelarray","polystrokewidth","startangle","legendposition","legendleftoffset","legendtopoffset","showcircles","circlelabelarray","circlestrokewidth","createChart","showRows","hStrokeColor","hFillColor","charts","withheaders","Legend","label_array","color_array","colorarray","legendstyle","drawVerticalLegend","line_length","linelength","offy","rowheight","createLegend","start_from","Turtle","turtleIsHidden","_attributes","forward","fd","back","bk","penUp","pu","penDown","clearScreen","cs","clean","setPos","home","hideTurtle","ht","showTurtle","penSize","penColor","pushTurtle","popTurtle","lookTo","hiddenPointAttr","arrowLen","isPenDown","turtle2","setPenSize","copyAttr","setPenColor","setHighlightPenColor","evalAt","createTurtle","Ticks","fixedTicks","equidistant","labelsData","defaultdistance","minticksdistance","labelData","labelCounter","insertticks","getLowerAndUpperBounds","getZeroCoordinates","lower","LN10","calculateTicksCoordinates","coordsZero","r_max","setTicksSizeVariables","generateEquidistantTicks","generateFixedTicks","distMaj","distMin","dxMaj","dyMaj","dxMin","dyMin","minStyle","majStyle","c1z","c2z","lowerBound","upperBound","fA","lA","isPoint1inBoard","isPoint2inBoard","dZeroPoint1","dZeroPoint2","ev_i","includeboundaries","dirLine","dirPoint","tickPosition","deltas","eps2","ev_it","ev_mt","getXandYdeltas","adjustTickDistance","drawzero","processTickPosition","nx","ny","distScr","ev_minti","tickCoords","labelVal","createTickPath","drawlabels","generateLabelData","labelText","fixedTick","hasLabelOverrides","ev_dl","point1UsrCoords","point2UsrCoords","_isInsideCanvas","lineStdForm","dxs","dys","dxr","dyr","full","tickendings","scalesymbol","maxlabellength","toExponential","beautifulscientificticklabels","beautifyScientificNotationLabel","useunicodeminus","tickNumber","xa","ya","updateRendererLabels","lenData","lenLabels","createTicks","generatelabelvalue","createHatchmark","createHashmark","findMapNode","mapname","setMath","deriveElementary","derivative","mapNode","codeNode","mapName","vArray","n0","mayNotBeSimplified","simplifyElementary","Dump","addMarkers","markers","deleteMarkers","minimizeObject","instance","defaults","prepareAttributes","methods","boardVarName","elementList","dumped","arrayToParamStr","converter","toJCAN","toJessie","script","toJavaScript","createComb","parent_types","sn","max_s","p1_inner","p2_inner","_isPrivateTangent","createSlopeTriangle","tglide","isPrivateTangent","basePoint","topPoint","_value","createCheckbox","rendNodeInput","createInput","_handler","_jc","ForeignObject","createForeignObject","fo","createForeignobject","axes3d","axesPosition","xAxis","yAxis","zAxis","xPlaneRear","mesh3d","yPlaneRear","zPlaneRear","xPlaneFront","yPlaneFront","zPlaneFront","xPlaneRearYAxis","xPlaneRearZAxis","xPlaneFrontYAxis","xPlaneFrontZAxis","yPlaneRearXAxis","yPlaneRearZAxis","yPlaneFrontXAxis","yPlaneFrontZAxis","zPlaneRearXAxis","zPlaneRearYAxis","zPlaneFrontXAxis","zPlaneFrontYAxis","axis3d","line3d","plane3d","point3d","surface3d","stepsU","stepsV","view3d","ThreeD","View3D","bbox3d","D3","timeoutAzimuth","el_slide","az_slide","project3DTo2D","project2DTo3DPlane","project3DToCube","c3d","cube","intersectionLineCube","rnew","isInCube","intersectionPlanePlane","plane1","plane2","getMesh","interval_u","interval_v","i_u","i_v","c2d","delta_u","delta_v","steps_u","steps_v","animateAzimuth","newVal","stopAzimuth","clearTimeout","createView3D","view","createAxes","vec1","vec2","range1","range2","na","na_parent","ticks_attr","directions","sides","rear","front","axes","axesposition","O","el_start","el_end","xx","zz","createMesh","e1","getPointCoords","createPlane","updateNormal","pos_akt","planes","update2D","_minFunc","surface","projectCoords2Surface","createParametricSurface","range_u","range_v","stepsu","stepsv","r_u","r_v"],"mappings":"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AAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAK,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAC/F,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAK,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAC/F,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAK,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAC/F,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAK,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAC/F,GAAI,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAI,GAAI,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAIhG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAK,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAC5F,GAAK,EAAG,GAAI,GAAI,GAAI,GAAI,GAAK,EAAG,GAAK,EAAG,GAAI,GAAK,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAC7F,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAK,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAC7F,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAK,GAAI,GAA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AAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,IAAIC,IAAI,CAAC,EAAE,IAAIC,IAAI,CAAC,EAAE,IAAIC,IAAI,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,IAAIC,IAAI,CAAC,EAAE,IAAIC,IAAI,CAAC,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,IAAIC,IAAI,CAAC,EAAE,IAAIC,IAAI,CAAC,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,IAAIC,IAAI,CAAC,EAAE,IAAIC,IAAI,CAAC,EAAE,IAAIC,IAAI,CAAC,EAAE,IAAIC,IAAI,CAAC,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,IAAIC,IAAI,CAAC,EAAE,IAAIC,IAAI,CAAC,EAAE,IAAIC,IAAI,CAAC,EAAE,IAAIC,IAAI,CAAC,EAAE,IAAIC,IAAI,CAAC,EAAE,IAAIC,IAAI,CAAC,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,IAAIC,IAAI,CAAC,EAAE,KAAKC,IAAI,CAAC,EAAE,KAAKC,IAAI,CAAC,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,IAAIC,IAAI,CAAC,EAAE,KAAKC,IAAI,CAAC,EAAE,KAAKC,IAAI,CAAC,EAAE,KAAKC,IAAI,CAAC,EAAE,KAAKC,IAAI,CAAC,EAAE,KAAKC,IAAI,CAAC,GAAG,IAAIC,IAAI,CAAC,EAAE,KAAKC,IAAI,CAAC,GAAG,GAAG,IAAIC,IAAI,CAAC,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,IAAIC,IAAI,CAAC,EAAE,KAAKC,IAAI,CAAC,GAAG,IAC/4CjH,OAAS,CAAC70B,MAAO,aACrB+7B,GAAI,GACJC,SAAU,OAAS,UAAY,gBAAkB,MAAQ,cAAgB,KAAO,MAAM,aAAe,MAAM,aAAe,QAAU,iBAAmB,SAAW,OAAS,OAAO,MAAQ,kBAAoB,OAAS,cAAgB,UAAY,mBAAqB,UAAY,kBAAoB,kBAAoB,OAAO,OAAO,uBAAyB,wBAA0B,yBAA2B,0BAA4B,OAAO,uBAAyB,OAAO,OAAO,wBAA0B,QAAQ,sBAAwB,QAAQ,wBAA0B,QAAQ,QAAQ,QAAQ,sBAAwB,OAAO,OAAO,QAAQ,QAAQ,4BAA8B,OAAO,OAAO,mBAAqB,OAAO,OAAO,OAAO,sBAAwB,OAAO,OAAO,oBAAsB,kBAAoB,qBAAuB,sBAAwB,iBAAmB,OAAO,OAAO,OAAO,gBAAkB,iBAAmB,gBAAkB,eAAiB,kBAAoB,iBAAmB,iBAAmB,QAAU,QAAU,SAAW,UAAY,UAAY,OAAS,YAAc,eAAiB,QAAQ,QAAQ,gBAAkB,YAAc,OAAO,gBAAkB,aAAe,iBAAmB,aAAe,YAAc,2BAA6B,OAAS,QAAQ,WAAa,OAAS,GACtzCC,WAAY,GAAG,UAAU,QAAQ,OAAO,OAAO,OAAO,UAAU,WAAW,SAAS,OAAO,QAAQ,SAAS,gBAAgB,YAAY,YAAY,OAAO,OAAO,OAAO,OAAO,OAAO,QAAQ,QAAQ,QAAQ,QAAQ,QAAQ,OAAO,OAAO,QAAQ,QAAQ,OAAO,OAAO,OAAO,OAAO,OAAO,OAAO,OAAO,OAAO,OAAO,OAAO,UAAU,UAAU,WAAW,YAAY,YAAY,SAAS,cAAc,QAAQ,QAAQ,OAAO,cAAc,SAAS,MAC/bC,aAAc,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,GAAG,CAAC,EAAE,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,EAAE,GAAG,CAAC,EAAE,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,EAAE,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,IACvuBC,cAAe,SAAmBC,OAAQC,OAAQC,SAAUP,GAAIQ,QAAyBC,GAAiBC,QAGtGC,GAAKF,GAAG30G,OAAS,SACb00G,cACH,SACGC,GAAGE,GAAG,QAET,OACCrF,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,GAAG,IAAK,UAAW,QAASF,GAAGE,GAAG,GAAIF,GAAGE,gBAEnE,OACCrF,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,GAAG,IAAK,UAAW,aAAcF,GAAGE,GAAG,GAAIF,GAAGE,GAAG,GAAIF,GAAGE,gBAElF,OACCrF,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,GAAG,IAAK,UAAW,WAAYF,GAAGE,GAAG,GAAIF,GAAGE,gBAEtE,OACCrF,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,GAAG,IAAK,UAAW,SAAUF,GAAGE,GAAG,GAAIF,GAAGE,GAAG,GAAIF,GAAGE,GAAG,GAAIF,GAAGE,gBAExF,OACCrF,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,GAAG,IAAK,UAAW,QAASF,GAAGE,GAAG,GAAIF,GAAGE,GAAG,eAEtE,OACCrF,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,GAAG,IAAK,UAAW,SAAUF,GAAGE,gBAE1D,OACCrF,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,GAAG,IAAK,UAAW,YAAaF,GAAGE,gBAE7D,OACCrF,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,GAAG,IAAK,UAAW,iBAAa9xG,cAE1D,QACCysG,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,GAAG,IAAK,UAAW,YAAaF,GAAGE,GAAG,eAEhE,QAAS,QACRrF,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,KAAM,UAAW,sBAE3C,QACCrF,EAAImF,GAAGE,GAAG,QAASrF,EAAElB,eAAgB,aAEtC,QACCkB,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,GAAG,IAAK,UAAW,UAAWF,GAAGE,GAAG,GAAIF,GAAGE,gBAErE,QAAS,QAAS,QAAS,QAAS,QAAS,QAAS,QAAS,QAAS,QAAS,QAAS,QAAS,QAAS,QAAS,QAAS,QAAS,QAAS,QAAS,QAAS,QAAS,QAAS,QAAS,QAAS,QAAS,QAAS,QAAS,QAAS,QAAS,QAClPrF,EAAImF,GAAGE,eAER,QAAS,QAAS,QACjBrF,EAAImF,GAAGE,GAAG,cAEX,QACCrF,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,GAAG,IAAK,UAAW,YAAaF,GAAGE,GAAG,GAAIF,GAAGE,UAAWrF,EAAErF,QAAS,aAE7F,QACCqF,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,GAAG,IAAK,UAAW,iBAAkBF,GAAGE,GAAG,GAAIF,GAAGE,GAAG,GAAIF,GAAGE,UAAWrF,EAAErF,QAAS,aAE5G,QACCqF,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,GAAG,IAAK,UAAW,QAASF,GAAGE,GAAG,GAAIF,GAAGE,UAAWrF,EAAErF,QAAS,aAEzF,QACCqF,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,GAAG,IAAK,UAAW,SAAUF,GAAGE,GAAG,GAAIF,GAAGE,UAAWrF,EAAErF,QAAS,aAE1F,QACCqF,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,GAAG,IAAK,UAAW,QAASF,GAAGE,GAAG,GAAIF,GAAGE,UAAWrF,EAAErF,QAAS,aAEzF,QACCqF,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,GAAG,IAAK,UAAW,SAAUF,GAAGE,GAAG,GAAIF,GAAGE,UAAWrF,EAAErF,QAAS,aAE1F,QACCqF,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,GAAG,IAAK,UAAW,YAAaF,GAAGE,GAAG,GAAIF,GAAGE,UAAWrF,EAAErF,QAAS,aAE7F,QACCqF,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,GAAG,IAAK,UAAW,QAASF,GAAGE,GAAG,GAAIF,GAAGE,UAAWrF,EAAErF,QAAS,aAEzF,QACCqF,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,GAAG,IAAK,UAAW,QAASF,GAAGE,GAAG,GAAIF,GAAGE,UAAWrF,EAAErF,QAAS,aAEzF,QACCqF,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,GAAG,IAAK,UAAW,SAAUF,GAAGE,GAAG,GAAIF,GAAGE,UAAWrF,EAAErF,QAAS,aAE1F,QACCqF,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,GAAG,IAAK,UAAW,SAAUF,GAAGE,GAAG,GAAIF,GAAGE,UAAWrF,EAAErF,QAAS,aAE1F,QACCqF,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,GAAG,IAAK,UAAW,SAAUF,GAAGE,GAAG,GAAIF,GAAGE,UAAWrF,EAAErF,QAAS,aAE1F,QACCqF,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,GAAG,IAAK,UAAW,SAAUF,GAAGE,GAAG,GAAIF,GAAGE,UAAWrF,EAAErF,QAAS,aAE1F,QACCqF,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,GAAG,IAAK,UAAW,SAAUF,GAAGE,GAAG,GAAIF,GAAGE,UAAWrF,EAAErF,QAAS,aAE1F,QACCqF,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,GAAG,IAAK,UAAW,SAAUF,GAAGE,GAAG,GAAIF,GAAGE,UAAWrF,EAAErF,QAAS,aAE1F,QACCqF,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,GAAG,IAAK,UAAW,SAAUF,GAAGE,GAAG,GAAIF,GAAGE,UAAWrF,EAAErF,QAAS,aAE1F,QACCqF,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,GAAG,IAAK,UAAW,SAAUF,GAAGE,GAAG,GAAIF,GAAGE,UAAWrF,EAAErF,QAAS,aAE1F,QACCqF,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,GAAG,IAAK,UAAW,SAAUF,GAAGE,UAAWrF,EAAErF,QAAS,aAEhF,QACCqF,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,GAAG,IAAK,UAAW,SAAUF,GAAGE,UAAWrF,EAAErF,QAAS,aAEhF,QAAS,QAAS,QAAS,QAAS,QAAS,QAAS,QACrDqF,EAAImF,GAAGE,SAAUrF,EAAErF,QAAS,aAE7B,QAAS,QACRqF,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,GAAG,IAAK,UAAW,cAAeF,GAAGE,GAAG,GAAIF,GAAGE,UAAWrF,EAAErF,QAAS,aAE/F,QAAS,QACRqF,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,GAAG,IAAK,UAAW,cAAeF,GAAGE,GAAG,GAAIF,GAAGE,GAAG,SAAUrF,EAAErF,QAAS,aAEjG,QACCqF,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,KAAM,WAAYF,GAAGE,gBAE/C,QACCrF,EAAImF,GAAGE,SAAUrF,EAAErF,QAAS,aAE7B,QACCqF,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,KAAM,aAAc,iBAE9C,QACCrF,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,KAAM,mBAAmB,cAEnD,QACCrF,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,KAAM,mBAAmB,cAEnD,QACCrF,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,KAAM,WAAYF,GAAGE,IAAIrzG,UAAU,EAAGmzG,GAAGE,IAAI70G,OAAS,eAEhF,QACCwvG,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,KAAM,aAAc/3F,WAAW63F,GAAGE,iBAE5D,QACCrF,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,KAAM,aAAc/gG,gBAE9C,QACC07F,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,KAAM,aAAcluF,EAAAA,cAE9C,QACC6oF,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,GAAG,IAAK,UAAW,WAAY,eAEzD,QACCrF,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,GAAG,IAAK,UAAW,WAAYF,GAAGE,GAAG,eAE/D,QACCrF,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,GAAG,IAAK,UAAW,iBAAkB,SAAUrF,EAAElB,eAAgB,aAE3F,QACCkB,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,GAAG,IAAK,UAAW,iBAAkBF,GAAGE,GAAG,SAAUrF,EAAElB,eAAgB,aAEjG,QACCkB,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,GAAG,IAAK,UAAW,aAAcF,GAAGE,GAAG,GAAIF,GAAGE,gBAExE,QACCrF,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,GAAG,IAAK,UAAW,UAAWF,GAAGE,GAAG,GAAIF,GAAGE,gBAErE,QAAS,QACRrF,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,GAAG,IAAK,UAAW,aAAcF,GAAGE,GAAG,GAAIF,GAAGE,UAAWrF,EAAErF,QAAS,aAE9F,QACCqF,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,GAAG,IAAK,UAAW,aAAcF,GAAGE,GAAG,GAAIF,GAAGE,GAAG,GAAIF,GAAGE,KAAK,QAAYrF,EAAErF,QAAS,aAE9G,QACCqF,EAAI,cAEL,QAAS,QAAS,SACjBA,EAAI,CAACmF,GAAGE,gBAET,QAAS,QAAS,SACjBrF,EAAImF,GAAGE,GAAG,GAAGx0G,OAAOs0G,GAAGE,gBAExB,QACCrF,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,KAAM,WAAYF,GAAGE,UAAWrF,EAAErF,QAAS,aAErE,SACCqF,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,GAAG,IAAK,UAAW,cAAe,GAAIF,GAAGE,UAAWrF,EAAErF,QAAS,aAEzF,SACCqF,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,GAAG,IAAK,UAAW,cAAeF,GAAGE,GAAG,GAAIF,GAAGE,UAAWrF,EAAErF,QAAS,aAE/F,SACCqF,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,GAAG,IAAK,UAAW,SAAU,GAAIF,GAAGE,gBAE9D,SACCrF,EAAIsF,IAAI7K,WAAW8K,GAAGH,GAAGC,GAAG,IAAK,UAAW,SAAUF,GAAGE,GAAG,GAAIF,GAAGE,OAIzEpoD,MAAO,CAACx3C,EAAE,CAAC,EAAE,EAAE,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,IAAIq7F,IAAI,GAAG,IAAI,IAAI,GAAG,CAAC,IAAI,GAAG,CAAC,EAAE,KAAK,IAAIC,MAAMC,MAAM,MAAM,KAAK,KAAKC,OAAOC,OAAOC,OAAOC,OAAO,KAAKC,OAAOC,OAAOC,OAAO,KAAKC,OAAO,MAAM,KAAKC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAO,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,KAAK,GAAG,CAAC,EAAE,IAAI98F,EAAE+8F,IAAI,CAAC,EAAE,KAAK/8F,EAAEg9F,IAAI,CAAC,EAAE,KAAKh9F,EAAEg9F,IAAI,CAAC,EAAE,KAAKh9F,EAAEg9F,IAAI,CAAC,EAAE,KAAKh9F,EAAEg9F,IAAI,CAAC,EAAE,KAAKh9F,EAAEg9F,IAAI,CAAC,EAAE,KAAKh9F,EAAEg9F,IAAI,CAAC,EAAE,KAAKh9F,EAAEg9F,IAAI,CAAC,EAAE,KAAKh9F,EAAE,CAAC,EAAE,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,IAAIq7F,IAAI,GAAG,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,IAAIC,MAAMC,MAAM,MAAM,MAAM,KAAKC,OAAOC,OAAOC,OAAOC,OAAO,KAAKC,OAAOC,OAAOC,OAAO,KAAKC,OAAO,MAAM,KAAKC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAO,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,KAAK,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,KAAK,GAAGvB,MAAM,MAAM,CAAC,EAAE,OAAOM,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMI,OAAOC,OAAO,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,KAAK,IAAI,CAAC,EAAE,KAAK98F,EAAEg9F,IAAI,CAAC,EAAE,KAAKh9F,EAAEi9F,IAAI,CAAC,EAAE,KAAKj9F,EAAEi9F,IAAI,CAAC,EAAE,KAAKj9F,EAAE,CAAC,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,IAAIk9F,IAAI,IAAI,CAAC,EAAE,OAAOC,MAAMn9F,EAAE,CAAC,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,EAAE,OAAO,CAAC,EAAE,MAAMA,EAAEo9F,IAAI,CAAC,EAAE,IAAI,IAAI,KAAKC,OAAO,CAAC,EAAE,OAAO,CAAC,EAAE,MAAMr9F,EAAEo9F,IAAI,CAAC,EAAE,IAAI,IAAI,KAAKC,OAAO,CAAC,EAAE,OAAO,CAAC,EAAE,MAAMr9F,EAAEs9F,IAAI,CAAC,EAAE,IAAI,IAAIC,MAAMv9F,EAAEi9F,IAAI,CAAC,EAAE,KAAKj9F,EAAEi9F,IAAI,CAAC,EAAE,KAAKj9F,EAAEi9F,IAAI,CAAC,EAAE,KAAKj9F,EAAEw9F,IAAI,CAAC,EAAE,IAAI,IAAIC,OAAOC,OAAOC,MAAM39F,EAAEi9F,IAAI,CAAC,EAAE,KAAKj9F,EAAEi9F,IAAI,CAAC,EAAE,KAAKj9F,EAAEi9F,IAAI,CAAC,EAAE,KAAKj9F,EAAEi9F,IAAI,CAAC,EAAE,KAAK,GAAG1B,MAAM,MAAMM,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMI,OAAOC,OAAO,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,CAAC,EAAE,KAAK98F,EAAE49F,IAAI,CAAC,EAAE,IAAI,IAAIC,OAAOC,OAAOC,OAAOC,MAAMh+F,EAAEi9F,IAAI,CAAC,EAAE,KAAKj9F,EAAEi9F,IAAI,CAAC,EAAE,KAAKj9F,EAAEi9F,IAAI,CAAC,EAAE,KAAKj9F,EAAEi9F,IAAI,CAAC,EAAE,KAAK,IAAIgB,OAAO,MAAM,MAAMzB,OAAOC,OAAOC,OAAOC,OAAO,CAAC,EAAE,OAAO,MAAM,MAAM,IAAI,GAAGpB,OAAOM,OAAO,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMI,OAAOC,OAAO,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAO,CAAC,EAAE,QAAQ,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAO,OAAOC,OAAOC,OAAOC,KAAK98F,EAAEk+F,IAAI,CAAC,EAAE,IAAI,IAAIC,OAAOC,MAAMp+F,EAAEi9F,IAAI,CAAC,EAAE,KAAKj9F,EAAEi9F,IAAI,CAAC,EAAE,KAAKj9F,EAAEi9F,IAAI,CAAC,EAAE,KAAKj9F,EAAEi9F,IAAI,CAAC,EAAE,KAAKj9F,EAAEi9F,IAAI,CAAC,EAAE,KAAKj9F,EAAEi9F,IAAI,CAAC,EAAE,KAAKj9F,EAAEi9F,IAAI,CAAC,EAAE,KAAKj9F,EAAEq+F,IAAI,CAAC,EAAE,IAAI,IAAIC,OAAOC,OAAOC,MAAMx+F,EAAEi9F,IAAI,CAAC,EAAE,KAAKj9F,EAAEi9F,IAAI,CAAC,EAAE,KAAK,GAAG1B,OAAOM,OAAO,OAAOI,OAAOC,OAAO,OAAO,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,KAAK,GAAGvB,OAAOM,OAAO,OAAOI,OAAOC,OAAO,OAAO,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,KAAK,GAAGvB,OAAOM,OAAO,OAAOI,OAAOC,OAAO,OAAO,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,KAAK,GAAG,IAAIxB,MAAMC,MAAM,MAAM,KAAK,KAAKC,OAAOC,OAAOC,OAAOC,OAAO,KAAKC,OAAOC,OAAOC,OAAO,KAAKC,OAAO,MAAM,KAAKC,OAAO,CAAC,EAAE,QAAQ,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAO,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,KAAK,GAAGvB,MAAM,OAAOM,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMI,OAAOC,OAAO,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,KAAK,GAAGvB,MAAM,OAAOM,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMI,OAAOC,OAAO,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,KAAK,GAAGvB,MAAM,OAAOM,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMI,OAAOC,OAAO,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,KAAK,IAAI,CAAC,EAAE,MAAM98F,EAAEg9F,IAAI,CAAC,EAAE,IAAIh9F,EAAEg9F,IAAI,CAAC,EAAE,IAAIh9F,EAAEg9F,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,EAAE,MAAMh9F,EAAEg9F,IAAI,CAAC,EAAE,KAAK,GAAGzB,OAAOM,OAAO,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMI,OAAOC,OAAO,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,KAAK,GAAGvB,OAAOM,OAAO,OAAOI,OAAOC,OAAO,OAAO,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,KAAK,GAAGvB,OAAOM,OAAO,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMI,OAAOC,OAAO,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,KAAK,GAAGvB,OAAOM,OAAO,OAAO,OAAO,MAAM,MAAM,MAAM,MAAMI,OAAOC,OAAO,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,KAAK,IAAI,CAAC,EAAE,MAAM,GAAGvB,MAAM,OAAOM,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMI,OAAOC,OAAO,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,KAAK98F,EAAEi9F,IAAI,CAAC,EAAE,IAAI,IAAI,OAAO,OAAO,OAAOwB,OAAO7B,MAAM,GAAGrB,OAAO,CAAC,EAAE,QAAQM,OAAO,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMI,OAAOC,OAAO,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAO,OAAOC,OAAOC,OAAOC,KAAK98F,EAAEi9F,IAAI,CAAC,EAAE,KAAK,GAAG1B,MAAM,OAAOM,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMI,OAAOC,OAAO,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,KAAK,IAAI,CAAC,EAAE,MAAM,GAAGvB,OAAOM,OAAO,OAAO,OAAO,MAAM,MAAM,MAAMI,OAAOC,OAAO,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,KAAK,GAAGvB,OAAOM,OAAO,OAAO,OAAO,MAAM,MAAMI,OAAOC,OAAO,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,KAAK,GAAGvB,OAAOM,OAAO,OAAO,OAAO,MAAM,MAAMI,OAAOC,OAAO,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,KAAK,GAAGvB,OAAOM,OAAO,OAAO,OAAO,MAAM,MAAMI,OAAOC,OAAO,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,KAAK,IAAI,CAAC,EAAE,MAAM,IAAI,CAAC,EAAE,QAAQ4B,OAAO,KAAK,IAAI,CAAC,EAAE,QAAQA,OAAO,KAAK,GAAGnD,OAAOM,OAAO,OAAO,OAAO,MAAMI,OAAOC,OAAO,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,KAAK,GAAGvB,OAAOM,OAAO,OAAO,OAAO,MAAMI,OAAOC,OAAO,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,KAAK,GAAGvB,OAAOM,OAAO,OAAO,OAAO,MAAMI,OAAOC,OAAO,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,KAAK,GAAGvB,OAAOM,OAAO,OAAO,OAAO,MAAMI,OAAOC,OAAO,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,KAAK98F,EAAEi9F,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,QAAQ,CAAC,EAAE,MAAMj9F,EAAE2+F,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,MAAM,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,KAAK3+F,EAAEi9F,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,QAAQ2B,KAAK5+F,EAAE6+F,IAAI,CAAC,EAAE,KAAK,GAAGtD,OAAOM,OAAO,OAAO,OAAOI,OAAOC,OAAO,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,KAAK,GAAGvB,OAAOM,OAAO,OAAO,OAAOI,OAAOC,OAAO,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,KAAK,GAAGvB,OAAOM,OAAO,OAAOI,OAAOC,OAAO,OAAO,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,KAAK,GAAGvB,OAAOM,OAAO,OAAOI,OAAOC,OAAO,OAAO,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,KAAK,GAAGvB,OAAOM,OAAO,OAAOI,OAAOC,OAAO,OAAO,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,KAAK98F,EAAEi9F,IAAI,CAAC,EAAE,KAAKj9F,EAAE,CAAC,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,IAAIk9F,IAAI,IAAIC,MAAMn9F,EAAEi9F,IAAI,CAAC,EAAE,KAAKj9F,EAAEi9F,IAAI,CAAC,EAAE,KAAKj9F,EAAE,CAAC,EAAE,EAAE,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,MAAM,IAAI,CAAC,EAAE,MAAM,IAAI,CAAC,EAAE,MAAM,GAAG,CAAC,EAAE,MAAMA,EAAEg9F,IAAI,CAAC,EAAE,KAAKh9F,EAAEi9F,IAAI,CAAC,EAAE,KAAKj9F,EAAEi9F,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,MAAMj9F,EAAEs9F,IAAI,CAAC,EAAE,IAAI,IAAIC,MAAMv9F,EAAEi9F,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,MAAMj9F,EAAE,CAAC,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,EAAE,OAAOA,EAAEi9F,IAAI,CAAC,EAAE,KAAKj9F,EAAEi9F,IAAI,CAAC,EAAE,KAAKj9F,EAAEi9F,IAAI,CAAC,EAAE,KAAKj9F,EAAE8+F,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,QAAQF,KAAK,IAAI,CAAC,EAAE,MAAM5+F,EAAEi9F,IAAI,CAAC,EAAE,KAAKj9F,EAAEw9F,IAAI,CAAC,EAAE,IAAI,IAAIC,OAAOC,OAAOC,MAAM39F,EAAE49F,IAAI,CAAC,EAAE,IAAI,IAAIC,OAAOC,OAAOC,OAAOC,MAAMh+F,EAAE49F,IAAI,CAAC,EAAE,IAAI,IAAIC,OAAOC,OAAOC,OAAOC,MAAMh+F,EAAE49F,IAAI,CAAC,EAAE,IAAI,IAAIC,OAAOC,OAAOC,OAAOC,MAAMh+F,EAAEi9F,IAAI,CAAC,EAAE,KAAK,IAAI,OAAOjB,KAAK,IAAI,CAAC,EAAE,QAAQ+C,KAAK/+F,EAAEg/F,IAAI,CAAC,EAAE,MAAM,IAAI,CAAC,EAAE,MAAM,IAAI,CAAC,EAAE,QAAQD,KAAK/+F,EAAEk+F,IAAI,CAAC,EAAE,IAAI,IAAIC,OAAOC,MAAMp+F,EAAEk+F,IAAI,CAAC,EAAE,IAAI,IAAIC,OAAOC,MAAMp+F,EAAEk+F,IAAI,CAAC,EAAE,IAAI,IAAIC,OAAOC,MAAMp+F,EAAEk+F,IAAI,CAAC,EAAE,IAAI,IAAIC,OAAOC,MAAMp+F,EAAEi9F,IAAI,CAAC,EAAE,KAAK,IAAIgB,OAAO,MAAM,MAAMzB,OAAOC,OAAOC,OAAOC,OAAO,OAAO,IAAI,GAAGpB,OAAOM,OAAO,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMI,OAAOC,OAAO,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,KAAK98F,EAAEi9F,IAAI,CAAC,EAAE,KAAK,GAAG1B,OAAOM,OAAO,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMI,OAAOC,OAAO,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,KAAK98F,EAAEq+F,IAAI,CAAC,EAAE,IAAI,IAAIC,OAAOC,OAAOC,MAAMx+F,EAAEq+F,IAAI,CAAC,EAAE,IAAI,IAAIC,OAAOC,OAAOC,MAAMx+F,EAAEi9F,IAAI,CAAC,EAAE,KAAKj9F,EAAEi9F,IAAI,CAAC,EAAE,KAAKj9F,EAAEi9F,IAAI,CAAC,EAAE,KAAK,GAAG,IAAI3B,MAAMC,MAAM,MAAM,OAAO,KAAKC,OAAOC,OAAOC,OAAOC,OAAO,KAAKC,OAAOC,OAAOC,OAAO,KAAKC,OAAO,MAAM,KAAKC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAO,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,KAAK,GAAG,IAAIxB,MAAMC,MAAM,MAAM,OAAO,KAAKC,OAAOC,OAAOC,OAAOC,OAAO,KAAKC,OAAOC,OAAOC,OAAO,KAAKC,OAAO,MAAM,KAAKC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAO,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,KAAK,GAAGvB,MAAM,OAAOM,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMI,OAAOC,OAAO,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,KAAK,GAAGvB,MAAM,OAAOM,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMI,OAAOC,OAAO,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,KAAK,GAAGvB,OAAOM,OAAO,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMI,OAAOC,OAAO,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,KAAK98F,EAAEi9F,IAAI,CAAC,EAAE,KAAK,IAAIwB,OAAO,OAAO7B,OAAO,KAAK58F,EAAE8+F,IAAI,CAAC,EAAE,KAAK9+F,EAAEi9F,IAAI,CAAC,EAAE,KAAKj9F,EAAEi9F,IAAI,CAAC,EAAE,MAAM,IAAI,OAAOjB,KAAK,IAAI,CAAC,EAAE,MAAM,GAAGT,MAAM,OAAOM,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMI,OAAOC,OAAO,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,KAAK,IAAI,CAAC,EAAE,MAAM98F,EAAE2+F,IAAI,CAAC,EAAE,KAAK3+F,EAAE2+F,IAAI,CAAC,EAAE,KAAK3+F,EAAE6+F,IAAI,CAAC,EAAE,KAAK7+F,EAAE+8F,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,EAAE,OAAO/8F,EAAEg9F,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,EAAE,MAAM,IAAI,CAAC,EAAE,MAAMh9F,EAAEi9F,IAAI,CAAC,EAAE,KAAKj9F,EAAEi9F,IAAI,CAAC,EAAE,KAAKj9F,EAAEi9F,IAAI,CAAC,EAAE,MAAMj9F,EAAEg/F,IAAI,CAAC,EAAE,MAAMh/F,EAAEi9F,IAAI,CAAC,EAAE,MAAM,GAAG1B,MAAM,OAAOM,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMI,OAAOC,OAAO,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,KAAK,GAAG,IAAIxB,MAAMC,MAAM,MAAM,OAAO,KAAKC,OAAOC,OAAOC,OAAOC,OAAO,KAAKC,OAAOC,OAAOC,OAAO,KAAKC,OAAO,MAAM,KAAKC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAO,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,KAAK,GAAGvB,MAAM,OAAOM,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMI,OAAOC,OAAO,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,KAAK,IAAI,CAAC,EAAE,MAAM98F,EAAEi9F,IAAI,CAAC,EAAE,MAAMj9F,EAAEg9F,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,EAAE,MAAMh9F,EAAEg9F,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI1B,MAAMC,MAAM,MAAM,OAAO,KAAKC,OAAOC,OAAOC,OAAOC,OAAO,KAAKC,OAAOC,OAAOC,OAAO,KAAKC,OAAO,MAAM,KAAKC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAO,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAMC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,OAAOC,KAAK98F,EAAEg9F,IAAI,CAAC,EAAE,KAC5vc+C,eAAgB,GAAG,CAAC,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,EAAE,KACnDC,WAAY,SAAqB19F,IAAK8/E,UAC9BA,KAAK6d,YAEF,KACCx1E,MAAQ,IAAIv+B,MAAMoW,WACtBmoB,MAAM23D,KAAOA,KACP33D,WAJDy4C,MAAM5gE,MAOnBgL,MAAO,SAAe02C,WACd5+C,KAAOlV,KAAMwB,MAAQ,CAAC,GAAiBwuG,OAAS,CAAC,MAAOC,OAAS,GAAI3oD,MAAQtnD,KAAKsnD,MAAO8nD,OAAS,GAAIE,SAAW,EAAGD,OAAS,EAAGa,WAAa,EAAGC,OAAS,EAAGC,IAAM,EAClK50G,KAAOy0G,OAAO52G,MAAMK,KAAK+B,UAAW,GACpC40G,MAAQp3G,OAAO2T,OAAO5M,KAAKqwG,OAC3BC,YAAc,CAAEvB,GAAI,QACnB,IAAIvjG,KAAKxL,KAAK+uG,GACX91G,OAAOC,UAAUC,eAAeO,KAAKsG,KAAK+uG,GAAIvjG,KAC9C8kG,YAAYvB,GAAGvjG,GAAKxL,KAAK+uG,GAAGvjG,IAGpC6kG,MAAME,SAASz8C,MAAOw8C,YAAYvB,IAClCuB,YAAYvB,GAAGsB,MAAQA,MACvBC,YAAYvB,GAAGlH,OAAS7nG,UACG,IAAhBqwG,MAAMG,SACbH,MAAMG,OAAS,QAEfC,MAAQJ,MAAMG,OAClBP,OAAOv0G,KAAK+0G,WACRC,OAASL,MAAM5jG,SAAW4jG,MAAM5jG,QAAQikG,OACH,mBAA9BJ,YAAYvB,GAAGe,gBACjBA,WAAaQ,YAAYvB,GAAGe,gBAE5BA,WAAa72G,OAAO03G,eAAe3wG,MAAM8vG,eAQ9C,IAQAjhC,OAAQ+hC,eAAgBv9C,MAAOuB,OAAWplD,EAAezS,EAAGqP,IAAKykG,SAAUC,SARvEC,IAAM,eACFC,YAEiB,iBADrBA,MAAQX,MAAMU,OAASX,OAEnBY,MAAQ97F,KAAK85F,SAASgC,QAAUA,OAE7BA,OAEkCC,MAAQ,KAC5C,IACT59C,MAAQ7xD,MAAMA,MAAM3G,OAAS,GACzBmF,KAAK6vG,eAAex8C,OACpBuB,OAAS50D,KAAK6vG,eAAex8C,QAEzBwb,MAAAA,SACAA,OAASkiC,OAEbn8C,OAAStN,MAAM+L,QAAU/L,MAAM+L,OAAOwb,cAER,IAAXja,SAA2BA,OAAO/5D,SAAW+5D,OAAO,GAAI,KACnEs8C,OAAS,OAERn0G,KADL+zG,SAAW,GACDxpD,MAAM+L,OACRrzD,KAAKivG,WAAWlyG,IAAMA,EAAIozG,QAC1BW,SAASp1G,KAAK,IAAOsE,KAAKivG,WAAWlyG,GAAK,KAI9Cm0G,OADAb,MAAMc,aACG,wBAA0B7B,SAAW,GAAK,MAAQe,MAAMc,eAAiB,eAAiBL,SAAS11G,KAAK,MAAQ,WAAc4E,KAAKivG,WAAWpgC,SAAWA,QAAU,IAEnK,wBAA0BygC,SAAW,GAAK,iBAAmBzgC,QAAUuhC,IAAM,eAAiB,KAAQpwG,KAAKivG,WAAWpgC,SAAWA,QAAU,UAEnJihC,WAAWoB,OAAQ,CACpBt7B,KAAMy6B,MAAMppB,MACZ+pB,MAAOhxG,KAAKivG,WAAWpgC,SAAWA,OAClCx+B,KAAMggE,MAAMf,SACZ8B,IAAKX,MACLK,SAAUA,cAGlBl8C,OAAO,aAAcvqD,OAASuqD,OAAO/5D,OAAS,QACxC,IAAImB,MAAM,oDAAsDq3D,MAAQ,YAAcwb,eAExFja,OAAO,SACV,EACDpzD,MAAM9F,KAAKmzE,QACXmhC,OAAOt0G,KAAK20G,MAAMjB,QAClBa,OAAOv0G,KAAK20G,MAAMG,QAClBhvG,MAAM9F,KAAKk5D,OAAO,IAClBia,OAAS,KACJ+hC,gBASD/hC,OAAS+hC,eACTA,eAAiB,OATjBvB,OAASgB,MAAMhB,OACfD,OAASiB,MAAMjB,OACfE,SAAWe,MAAMf,SACjBmB,MAAQJ,MAAMG,OACVN,WAAa,GACbA,yBAOP,KACD9jG,IAAMpM,KAAKkvG,aAAat6C,OAAO,IAAI,GACnCq8C,MAAM5G,EAAI2F,OAAOA,OAAOn1G,OAASuR,KACjC6kG,MAAMxB,GAAK,CACP4B,WAAYpB,OAAOA,OAAOp1G,QAAUuR,KAAO,IAAIilG,WAC/CC,UAAWrB,OAAOA,OAAOp1G,OAAS,GAAGy2G,UACrCC,aAActB,OAAOA,OAAOp1G,QAAUuR,KAAO,IAAImlG,aACjDC,YAAavB,OAAOA,OAAOp1G,OAAS,GAAG22G,aAEvCd,SACAO,MAAMxB,GAAG7qE,MAAQ,CACbqrE,OAAOA,OAAOp1G,QAAUuR,KAAO,IAAIw4B,MAAM,GACzCqrE,OAAOA,OAAOp1G,OAAS,GAAG+pC,MAAM,UAYvB,KATjBp1B,EAAIxP,KAAKmvG,cAAcxzG,MAAMs1G,MAAO,CAChC7B,OACAC,OACAC,SACAgB,YAAYvB,GACZn6C,OAAO,GACPo7C,OACAC,QACF/0G,OAAOM,eAEEgU,EAEPpD,MACA5K,MAAQA,MAAMnI,MAAM,GAAI,EAAI+S,IAAM,GAClC4jG,OAASA,OAAO32G,MAAM,GAAI,EAAI+S,KAC9B6jG,OAASA,OAAO52G,MAAM,GAAI,EAAI+S,MAElC5K,MAAM9F,KAAKsE,KAAKkvG,aAAat6C,OAAO,IAAI,IACxCo7C,OAAOt0G,KAAKu1G,MAAM5G,GAClB4F,OAAOv0G,KAAKu1G,MAAMxB,IAClBoB,SAAWvpD,MAAM9lD,MAAMA,MAAM3G,OAAS,IAAI2G,MAAMA,MAAM3G,OAAS,IAC/D2G,MAAM9F,KAAKm1G,qBAEV,SACM,UAGR,IAIHlB,IAAM,CACNx0F,KAAM,SAAUtQ,KAAM/O,MAAOipG,gBAClB,CACHl6F,KAAMA,KACN/O,MAAOA,MACPipG,SAAUA,WAIlBD,WAAY,SAAUjpD,IAAKhxC,KAAM/O,MAAOipG,cAChCzqG,EACAuC,EAAImD,KAAKmb,KAAKtQ,KAAM/O,MAAO,QAE1BxB,EAAI,EAAGA,EAAImB,UAAUZ,OAAQP,IAC9BuC,EAAEkoG,SAASrpG,KAAKD,UAAUnB,WAG9BuC,EAAEwzC,KAAOwL,IAAI,GACbh/C,EAAEuuE,IAAMvvB,IAAI,GACZh/C,EAAEisG,MAAQjtD,IAAI,GACdh/C,EAAE8rG,KAAO9sD,IAAI,GAENh/C,IAIX+yG,GAAK,SAAU6B,WACR,CAACA,IAAIJ,WAAYI,IAAIF,aAAcE,IAAIH,UAAWG,IAAID,cAIjEnB,MAAS,eACTA,MAAS,CAEbD,IAAI,EAEJN,WAAW,SAAoB19F,IAAK8/E,UACxBlyF,KAAK+uG,GAAGlH,aAGF,IAAI7rG,MAAMoW,UAFX28F,GAAGlH,OAAOiI,WAAW19F,IAAK8/E,OAO3Cqe,SAAS,SAAUz8C,MAAOi7C,gBACbA,GAAKA,IAAM/uG,KAAK+uG,IAAM,QACtB2C,OAAS59C,WACT69C,MAAQ3xG,KAAK4xG,WAAa5xG,KAAKo5D,MAAO,OACtCk2C,SAAWtvG,KAAKqvG,OAAS,OACzBD,OAASpvG,KAAK6xG,QAAU7xG,KAAKinF,MAAQ,QACrC6qB,eAAiB,CAAC,gBAClBtB,OAAS,CACVa,WAAY,EACZE,aAAc,EACdD,UAAW,EACXE,YAAa,GAEbxxG,KAAKyM,QAAQikG,cACRF,OAAO5rE,MAAQ,CAAC,EAAE,SAEtB/e,OAAS,EACP7lB,MAIf8zD,MAAM,eACM1S,GAAKphD,KAAK0xG,OAAO,eAChBtC,QAAUhuD,QACViuD,cACAxpF,cACAohE,OAAS7lC,QACTywD,SAAWzwD,GACJA,GAAG6lC,MAAM,yBAEZqoB,gBACAkB,OAAOc,kBAEPd,OAAOgB,cAEZxxG,KAAKyM,QAAQikG,aACRF,OAAO5rE,MAAM,UAGjB8sE,OAAS1xG,KAAK0xG,OAAOr4G,MAAM,GACzB+nD,IAIf2wD,MAAM,SAAU3wD,QACJh1C,IAAMg1C,GAAGvmD,OACTm3G,MAAQ5wD,GAAG1mD,MAAM,sBAEhBg3G,OAAStwD,GAAKphD,KAAK0xG,YACnBtC,OAASpvG,KAAKovG,OAAO5lC,OAAO,EAAGxpE,KAAKovG,OAAOv0G,OAASuR,UAEpDyZ,QAAUzZ,QACX6lG,SAAWjyG,KAAKinF,MAAMvsF,MAAM,sBAC3BusF,MAAQjnF,KAAKinF,MAAMzd,OAAO,EAAGxpE,KAAKinF,MAAMpsF,OAAS,QACjDg3G,QAAU7xG,KAAK6xG,QAAQroC,OAAO,EAAGxpE,KAAK6xG,QAAQh3G,OAAS,GAExDm3G,MAAMn3G,OAAS,SACVy0G,UAAY0C,MAAMn3G,OAAS,OAEhC2U,EAAIxP,KAAKwwG,OAAO5rE,kBAEf4rE,OAAS,CACVa,WAAYrxG,KAAKwwG,OAAOa,WACxBC,UAAWtxG,KAAKsvG,SAAW,EAC3BiC,aAAcvxG,KAAKwwG,OAAOe,aAC1BC,YAAaQ,OACRA,MAAMn3G,SAAWo3G,SAASp3G,OAASmF,KAAKwwG,OAAOe,aAAe,GAC5DU,SAASA,SAASp3G,OAASm3G,MAAMn3G,QAAQA,OAASm3G,MAAM,GAAGn3G,OAChEmF,KAAKwwG,OAAOe,aAAenlG,KAG7BpM,KAAKyM,QAAQikG,cACRF,OAAO5rE,MAAQ,CAACp1B,EAAE,GAAIA,EAAE,GAAKxP,KAAKqvG,OAASjjG,WAE/CijG,OAASrvG,KAAKovG,OAAOv0G,OACnBmF,MAIfkyG,KAAK,uBACQP,OAAQ,EACN3xG,MAIfmyG,OAAO,kBACKnyG,KAAKyM,QAAQ2lG,sBACRR,YAAa,EASf5xG,MAPIA,KAAK8vG,WAAW,0BAA4B9vG,KAAKsvG,SAAW,GAAK,mIAAqItvG,KAAKmxG,eAAgB,CAC9Nv7B,KAAM,GACNo7B,MAAO,KACP3gE,KAAMrwC,KAAKsvG,YAQ3B+C,KAAK,SAAUx1G,QACFk1G,MAAM/xG,KAAKinF,MAAM5tF,MAAMwD,KAIpCy1G,UAAU,eACEC,KAAOvyG,KAAK6xG,QAAQroC,OAAO,EAAGxpE,KAAK6xG,QAAQh3G,OAASmF,KAAKinF,MAAMpsF,eAC3D03G,KAAK13G,OAAS,GAAK,MAAM,IAAM03G,KAAK/oC,QAAQ,IAAIxuE,QAAQ,MAAO,KAI/Ew3G,cAAc,eACFjoF,KAAOvqB,KAAKinF,aACZ18D,KAAK1vB,OAAS,KACd0vB,MAAQvqB,KAAK0xG,OAAOloC,OAAO,EAAG,GAAGj/C,KAAK1vB,UAElC0vB,KAAKi/C,OAAO,EAAE,KAAOj/C,KAAK1vB,OAAS,GAAK,MAAQ,KAAKG,QAAQ,MAAO,KAIpFm2G,aAAa,eACDzjB,IAAM1tF,KAAKsyG,YACX1iG,EAAI,IAAIvF,MAAMqjF,IAAI7yF,OAAS,GAAGO,KAAK,YAChCsyF,IAAM1tF,KAAKwyG,gBAAkB,KAAO5iG,EAAI,KAIvD6iG,WAAW,SAASxrB,MAAOyrB,kBACf1B,MACAgB,MACAW,UAEA3yG,KAAKyM,QAAQ2lG,kBAEbO,OAAS,CACLrD,SAAUtvG,KAAKsvG,SACfkB,OAAQ,CACJa,WAAYrxG,KAAKwwG,OAAOa,WACxBC,UAAWtxG,KAAKsxG,UAChBC,aAAcvxG,KAAKwwG,OAAOe,aAC1BC,YAAaxxG,KAAKwwG,OAAOgB,aAE7BpC,OAAQpvG,KAAKovG,OACbnoB,MAAOjnF,KAAKinF,MACZtrE,QAAS3b,KAAK2b,QACdk2F,QAAS7xG,KAAK6xG,QACdxC,OAAQrvG,KAAKqvG,OACbxpF,OAAQ7lB,KAAK6lB,OACb8rF,MAAO3xG,KAAK2xG,MACZD,OAAQ1xG,KAAK0xG,OACb3C,GAAI/uG,KAAK+uG,GACT+C,eAAgB9xG,KAAK8xG,eAAez4G,MAAM,GAC1C+/D,KAAMp5D,KAAKo5D,MAEXp5D,KAAKyM,QAAQikG,SACbiC,OAAOnC,OAAO5rE,MAAQ5kC,KAAKwwG,OAAO5rE,MAAMvrC,MAAM,MAItD24G,MAAQ/qB,MAAM,GAAGA,MAAM,2BAEdqoB,UAAY0C,MAAMn3G,aAEtB21G,OAAS,CACVa,WAAYrxG,KAAKwwG,OAAOc,UACxBA,UAAWtxG,KAAKsvG,SAAW,EAC3BiC,aAAcvxG,KAAKwwG,OAAOgB,YAC1BA,YAAaQ,MACAA,MAAMA,MAAMn3G,OAAS,GAAGA,OAASm3G,MAAMA,MAAMn3G,OAAS,GAAGosF,MAAM,UAAU,GAAGpsF,OAC5EmF,KAAKwwG,OAAOgB,YAAcvqB,MAAM,GAAGpsF,aAE/Cu0G,QAAUnoB,MAAM,QAChBA,OAASA,MAAM,QACftrE,QAAUsrE,WACVooB,OAASrvG,KAAKovG,OAAOv0G,OACtBmF,KAAKyM,QAAQikG,cACRF,OAAO5rE,MAAQ,CAAC5kC,KAAK6lB,OAAQ7lB,KAAK6lB,QAAU7lB,KAAKqvG,cAErDsC,OAAQ,OACRC,YAAa,OACbF,OAAS1xG,KAAK0xG,OAAOr4G,MAAM4tF,MAAM,GAAGpsF,aACpCg3G,SAAW5qB,MAAM,GACtB+pB,MAAQhxG,KAAKmvG,cAAcz1G,KAAKsG,KAAMA,KAAK+uG,GAAI/uG,KAAM0yG,aAAc1yG,KAAK8xG,eAAe9xG,KAAK8xG,eAAej3G,OAAS,IAChHmF,KAAKo5D,MAAQp5D,KAAK0xG,cACbt4C,MAAO,GAEZ43C,aACOA,MACJ,GAAIhxG,KAAK4xG,WAAY,KAEnB,IAAIpmG,KAAKmnG,YACLnnG,GAAKmnG,OAAOnnG,UAEd,SAEJ,GAIf+e,KAAK,cACOvqB,KAAKo5D,YACEp5D,KAAKowG,QAMZY,MACA/pB,MACA2rB,UACAz2G,MAPC6D,KAAK0xG,cACDt4C,MAAO,GAOXp5D,KAAK2xG,aACDvC,OAAS,QACTnoB,MAAQ,YAEb4rB,MAAQ7yG,KAAK8yG,gBACRx4G,EAAI,EAAGA,EAAIu4G,MAAMh4G,OAAQP,QAC9Bs4G,UAAY5yG,KAAK0xG,OAAOzqB,MAAMjnF,KAAK6yG,MAAMA,MAAMv4G,SAC5B2sF,OAAS2rB,UAAU,GAAG/3G,OAASosF,MAAM,GAAGpsF,QAAS,IAChEosF,MAAQ2rB,UACRz2G,MAAQ7B,EACJ0F,KAAKyM,QAAQ2lG,gBAAiB,KAEhB,KADdpB,MAAQhxG,KAAKyyG,WAAWG,UAAWC,MAAMv4G,YAE9B02G,MACJ,GAAIhxG,KAAK4xG,WAAY,CACxB3qB,OAAQ,kBAID,EAER,IAAKjnF,KAAKyM,QAAQsmG,kBAK7B9rB,OAEc,KADd+pB,MAAQhxG,KAAKyyG,WAAWxrB,MAAO4rB,MAAM12G,UAE1B60G,MAKK,KAAhBhxG,KAAK0xG,OACE1xG,KAAKowG,IAELpwG,KAAK8vG,WAAW,0BAA4B9vG,KAAKsvG,SAAW,GAAK,yBAA2BtvG,KAAKmxG,eAAgB,CACpHv7B,KAAM,GACNo7B,MAAO,KACP3gE,KAAMrwC,KAAKsvG,YAM3ByB,IAAI,eACQvhG,EAAIxP,KAAKuqB,cACT/a,GAGOxP,KAAK+wG,OAKxBiC,MAAM,SAAgBC,gBACTnB,eAAep2G,KAAKu3G,YAIjCC,SAAS,kBACOlzG,KAAK8xG,eAAej3G,OAAS,EAC7B,EACGmF,KAAK8xG,eAAerrE,MAEpBzmC,KAAK8xG,eAAe,IAKvCgB,cAAc,kBACF9yG,KAAK8xG,eAAej3G,QAAUmF,KAAK8xG,eAAe9xG,KAAK8xG,eAAej3G,OAAS,GACxEmF,KAAKmzG,WAAWnzG,KAAK8xG,eAAe9xG,KAAK8xG,eAAej3G,OAAS,IAAIg4G,MAErE7yG,KAAKmzG,WAAL,QAA2BN,OAK9CO,SAAS,SAAmBv2G,UACpBA,EAAImD,KAAK8xG,eAAej3G,OAAS,EAAI6R,KAAKwC,IAAIrS,GAAK,KAC1C,EACEmD,KAAK8xG,eAAej1G,GAEpB,WAKnBw2G,UAAU,SAAoBJ,gBACjBD,MAAMC,YAInBK,eAAe,kBACAtzG,KAAK8xG,eAAej3G,QAEnC4R,QAAS,GACT0iG,cAAe,SAAmBJ,GAAGwE,IAAIC,0BAA0BC,iBAE5DD,gCACF,OAUA,OAEA,aAVA,OAEA,SAAS,QAET,OAEA,SAAU,QAMV,SAAS,OAET,SAAS,QAET,SAAS,QAET,UAAU,QAEV,UAAU,QAEV,UAAU,QAEV,UAAU,QAEV,UAAU,QAEV,UAAU,QAEV,UAAU,QAEV,UAAU,QAEV,UAAU,QAEV,UAAU,QAEV,UAAU,QAEV,QAEA,UAAU,QAEV,UAAU,QAEV,UAAU,QAEV,UAAU,QAEV,UAAU,QAEV,UAAU,QAEV,SAAU,SAEV,UAAU,QAEV,UAAU,QAEV,UAAU,QAEV,UAAU,QAEV,UAAU,QAEV,UAAU,QAEV,UAAU,OAEV,UAAU,QAEV,UAAU,QAEV,UAAU,QAEV,UAAU,QAEV,UAAU,QAEV,UAAU,QAEV,UAAU,QAEV,UAAU,QAEV,UAAU,QAEV,UAAU,QAEV,UAAU,QAEV,UAAU,QAEV,UAAU,QAEV,UAAU,QAEV,UAAU,QAEV,UAAU,QAEV,UAAU,QAEV,UAAU,QAEV,UAAU,QAEV,UAAU,OAEV,UAAU,QAEV,SAAU,YAIfX,MAAO,CAAC,WAAW,uCAAuC,cAAc,uBAAuB,uBAAuB,cAAc,2BAA2B,YAAY,cAAc,eAAe,YAAY,aAAa,kBAAkB,aAAa,aAAa,gBAAgB,gBAAgB,cAAc,eAAe,cAAc,kBAAkB,UAAU,UAAU,UAAU,UAAU,UAAU,UAAU,SAAS,SAAS,UAAU,SAAS,aAAa,UAAU,UAAU,UAAU,UAAU,UAAU,SAAS,UAAU,UAAU,UAAU,SAAS,UAAU,SAAS,UAAU,SAAS,UAAU,SAAS,UAAU,UAAU,UAAU,UAAU,YAAY,SAAS,SAAS,SAAS,gCAAgC,UACluBM,WAAY,SAAW,OAAS,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,eAAgB,YAE3M9C,MAhcM,YAmcJqD,cACF3E,GAAK,UAFZlH,OAAOwI,MAAQA,MAIfqD,OAAOx6G,UAAY2uG,OAAOA,OAAO6L,OAASA,OACnC,IAAIA,OAp0BG,eAw0BS,IAAZp7G,SAA8C,oBAAZ0E,UAC7CA,QAAQ6qG,OAASA,OACjB7qG,QAAQ02G,OAAS7L,OAAO6L,OACxB12G,QAAQogB,MAAQ,kBAAqByqF,OAAOzqF,MAAMzhB,MAAMksG,OAAQpsG,YAChEuB,QAAQxE,KAAO,SAAuBgD,MAC7BA,KAAK,KACNyF,QAAQK,IAAI,UAAU9F,KAAK,GAAG,SAC9Bof,QAAQ+4F,KAAK,QAEbC,OAASt7G,QAAQ,MAAMu7G,aAAav7G,QAAQ,QAAQqB,UAAU6B,KAAK,IAAK,eACrEwB,QAAQ6qG,OAAOzqF,MAAMw2F,SAEV,oBAAX12G,QAA0B5E,QAAQE,OAAS0E,QACpDF,QAAQxE,KAAKoiB,QAAQk5F,KAAKz6G,MAAM,KAI9BwuG,OAAOkH,GAAGe,WAAajI,OAAOiI,WAEvB1xG,IAAIolG,cA2CfprG,OAAO,mBAAmB,CAAC,MAAO,eAAe,SAAUgG,IAAKkV,aAoB5DlV,IAAI21G,YAAc,SAAUt0G,cACpBxC,EACAyiC,KAAO1/B,KACPg0G,eAAiB,CAQb,eASA,aASA,gBASA,iBASA,SASA,aASA,YASA,eAEJC,eAAiB,SAAUrzG,aAChB,eACCtG,MAECA,KAAKolC,KAAKjgC,SACPigC,KAAKjgC,SAAStG,eAAemB,IACzBgZ,KAAKzU,OAAO6gC,KAAKjgC,SAASnF,GAAGsG,QAC7B8+B,KAAKjgC,SAASnF,GAAGsG,MAAMjF,MAAM+jC,KAAKjgC,SAASnF,GAAImB,kBAIpDikC,WAIdziC,EAAI,EAAGA,EAAI+2G,eAAen5G,OAAQoC,SAC9B+2G,eAAe/2G,IAAMg3G,eAAeD,eAAe/2G,QAqBvDA,UAlBAwC,SAAW,QACXiK,QAAU1J,KAAKP,cAEfmK,eAAiB,QACjB+uD,YAAc,QAGd7uD,OAAS,QAETimF,UAAY,CACb7K,aAAc,eACdkL,YAAa,eACbgB,WAAY,aACZlmE,IAAK,MACLq2D,OAAQ,SACRhhF,OAAQ,UAGFd,SACFA,SAAStG,eAAe8D,SACnBiuB,IAAIjuB,EAAGwC,SAASxC,SAIxB0yF,MAAO,OACPC,KAAO,IAGhBxxF,IAAIC,OAAOD,IAAI21G,YAAY76G,UAAmD,CAa1EgyB,IAAK,SAAUtqB,KAAMjB,iBACZ2T,KAAKzU,OAAOmB,KAAKY,SAAU0S,KAAKzU,OAAOc,YACpC2T,KAAKzU,OAAOc,QAAQxC,SACfsC,SAASE,QAAQxC,IAAMwC,aAEvBF,SAASmB,MAAQjB,QAGtB2T,KAAKzU,OAAOc,QAAQ/F,aACfgQ,eAAejK,QAAQ/F,MAAQ+F,SAGxCA,QAAQue,GAAG,iBAAkBle,KAAKk0G,aAAcl0G,WAE3C24D,YAAYj9D,KAAKiE,cACjBiB,MAAQjB,aACRowF,UAAUnvF,MAAQjB,SAEhB,IAWf4hF,OAAQ,SAAU3gF,UAEV3D,EADA2sG,OAAQ,MAGP3sG,KAAK+C,KAAKP,YACPO,KAAKP,SAAStG,eAAe8D,IACzB+C,KAAKP,SAASxC,GAAGE,KAAO6C,KAAKY,MAAMzD,GAAI,CACvCysG,OAAQ,eAMhBA,eACO5pG,KAAKP,SAASO,KAAKY,MAAMzD,WACzB6C,KAAKY,OAGTgpG,OAGXsK,aAAc,SAAUC,KAAMnb,KAAM3qF,WACzBrO,KAAK4J,eAAeuqG,WACtBvqG,eAAeovF,MAAQ3qF,IAGhC9N,OAAQ,SAAUkS,eAEVa,KAAKzU,OAAOT,IAAIg2G,OACTh2G,IAAIg2G,MAAMl7G,UAAUqH,OAAO7G,KAAKsG,KAAMyS,QAG1C,IAAIrU,IAAI21G,aAGnB1d,WAAY,kBACDr2F,KAAKgM,SAGhBoqF,QAAS,kBACEp2F,KAAK0vF,QAGhB4G,cAAe,eAEPr5F,EADAoP,KAAO,OAGNpP,KAAK+C,KAAK4vF,KACP5vF,KAAK4vF,KAAKz2F,eAAe8D,KACzBoP,KAAKpP,GAAK+C,KAAK4vF,KAAK3yF,GAAG8V,gBAIxB/S,KAAKqM,QAIbjO,IAAI21G,eAmEf37G,OAAO,aAAa,CAChB,MAAO,iBAAkB,cAAe,UAAW,gBAAiB,YAAa,gBAAiB,eAClG,kBACA,oBAAqB,cAAe,aAAc,cAAe,YACjE,qBACD,SAAUgG,IAAKoL,MAAO2a,OAAQ2nD,QAAS32C,SAAUjR,IAAKirB,SAAUiwB,QAASvxB,WAAY21D,WAAYl2B,MAAOh6D,KAC3FqK,aAAcmX,IAAKi/E,oBA0B/B31G,IAAIg2G,MAAQ,SAAUzzG,UAAW4uE,SAAUpyE,GAAI2O,OAAQ6hE,MAAOC,MAAO7oD,MAAOC,MAAO8tB,YAAaC,aAAc9mC,oBAOrGooG,gBAAkB,OASlBC,gBAAkB,OAOlBC,uBAAyB,OAQzBC,gBAAkB,QAQlB3zD,kBAAoB,OAQpB4zD,mBAAqB,EAQtBnhG,KAAKzU,OAAOoN,WAAW/K,YAAqC,IAAxB+K,WAAW/K,cAC1CA,SAAW+K,WAAW/K,cACPtD,IAAbsD,UAA0BoS,KAAK/I,SAASrJ,iBAC1CA,SAAWA,eAOfP,UAAYA,eAMZylF,aAAgBtxD,IAAI7gB,UAAYjU,KAAKkB,SAASC,eAAenB,KAAKW,WAAa,KAEhFm0B,IAAI7gB,WAA+B,OAAlBs7D,SAAS1kE,MAAuC,OAAtB7K,KAAKomF,mBAC1C,IAAIpqF,MAAM,uCAAyC2E,UAAY,qBAUpE4uE,SAAWA,cAOXmlC,MAAQ,QAMRjoG,QAAU6G,KAAK3D,SAASm8D,cACxBz/D,KAAOJ,gBAOP0oG,UAAY,OAEZ/oG,GAAK,IAAI43F,gBACT53F,GAAGo9F,IAAIhpG,WASP8L,OAAS,QACTA,OAAOkC,UAAY,CAAC,EAAG,EAAG,QAC1BlC,OAAOyY,UAAY,CAAC,EAAGzY,OAAO,GAAIA,OAAO,SAUzC6hE,MAAQA,WAURC,MAAQA,WAOR7oD,MAAQA,MAAQ/kB,KAAK2tE,WAOrB3oD,MAAQA,MAAQhlB,KAAK4tE,WAQrBgnC,iBAAkB,OAOlB9hE,YAAcA,iBAOdC,aAAeA,aAGhBz/B,KAAKzU,OAAO1B,KAAc,KAAPA,IAAa23B,IAAI7gB,YAAcX,KAAKzU,OAAOmB,KAAKkB,SAASC,eAAehE,UACtFA,GAAKA,QAELA,GAAK6C,KAAK60G,aAGnBl3F,aAAaS,SAASpe,WAEjB80G,MAAQ,QAQRC,gBAAkB,QAOlBC,UAAW,OAMXtrG,QAAU,QAMVivD,YAAc,QAMd7uD,OAAS,QAMTmrG,iBAAmB,QAMnBz0B,mBAAqB,QAMrB00B,WAAa,OAMbtrG,eAAiB,QAWjBurG,KAAOn1G,KAAKq0G,qBAcZzzD,cAAgB5gD,KAAKy0G,wBAMrBW,mBAAoB,OAEpBC,0BAQAC,QAAU,OAQVC,QAAU,OAOVC,cAAgB,CAAC,EAAG,QAOpB3gC,MAAQ,QAOR4gC,QAAU,QAQVC,UAAY,QAMZ58F,KAAO,QAOP68F,cAAgB,OAOfC,gBAAkBp0F,EAAAA,OAMnBq0F,mBAAqB,OAMrBC,YAAc,GAEf91G,KAAKqM,KAAK0pG,oBACLxmC,SAASqV,iBAAiBp7E,MAAM3H,YAAasY,SAASna,KAAKyM,QAAQmpE,KAAKvH,SAAU,UAQtF2nC,iBAAkB,OASlBC,eAAgB,OAMhBC,aAAe,YAUfC,0BAA2B,EAE5Bn2G,KAAKyM,QAAQmpE,KAAK8G,gBAAkB05B,mBACpCr3F,YAEKtS,QAAQmpE,KAAK8G,gBAAiB,OAQlC25B,kBAAmB,OAOnBC,kBAAmB,OAOnBC,oBAAqB,OAOrBC,YAAa,OAObC,aAAc,OAOdC,cAAe,OAQfC,aAAe,CAAC,EAAG,QAQnB3W,aAAe,aAOf4W,eAAiB,QAOjBC,eAAgB,OAOhBC,aAAc,OASdC,cAAe,OASfC,aAAc,OAOdC,aAAe,CAAC,CAAC,EAAG,GAAI,CAAC,EAAG,SAE5BhuD,QAAUv8C,UACVw8C,WAAa9qD,IAAIsO,KAElB1M,KAAKqM,KAAK6qG,qBACLC,wBAGJpnB,UAAY,CACbv1D,OAAQ,SACRwkD,WAAY,aACZ9gE,GAAI,KACJC,IAAK,MACLL,QAAS,UACTs5F,QAAS,iBACTC,eAAgB,iBAChBC,aAAc,eACdC,WAAY,wBACZ15D,cAAe,gBACf25D,gBAAiB,kBACjB7sB,YAAa,cACbn5E,KAAM,iBACN6/D,MAAO,kBACPn5C,GAAI,eACJu/E,KAAM,iBACNzsB,OAAQ,SACRF,QAAS,UACTC,QAAS,UACT2sB,aAAc,eACdn2B,OAAQ,eACRmV,aAAc,iBAItBt4F,IAAIC,OAAOD,IAAIg2G,MAAMl7G,UAA6C,CAY9D23F,aAAc,SAAUvyF,YAChBq5G,cAAer9G,EACf80E,cAAgBpvE,KAAKqM,KAAKurG,cAC1BlqB,IAAM,GACNmqB,KAAO,GACPC,QAAU,GACVl+G,KAAO,MAEP0E,OAAOuM,OAASrB,MAAMpH,wBACf,OAKPu1G,cAFArkG,KAAK9I,QAAQlM,QAEG,CAAC,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IACvF,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,KAC/CA,OAAOuM,OAASrB,MAAMtG,kBACb,CAAC,GAAI,UAAW,SAAU,UAAW,UAAW,YAAa,SAAU,QAAS,UAC5F,SAAU,UAAW,WAAY,OAAQ,OAAQ,OAAQ,YAAa,OAAQ,QAC9E,UAAW,QAAS,YAAa,QAAS,QAAS,QAAS,WAGhD,CAAC,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IACvF,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,KAGrDoQ,KAAK9I,QAAQlM,SACVA,OAAOmM,eAAiBjB,MAAMvF,mBAC9B3F,OAAOuM,OAASrB,MAAMtG,oBAEtBwqF,IADApvF,OAAOuM,OAASrB,MAAMzG,oBAChB,MACCzE,OAAOmM,eAAiBjB,MAAMtF,oBAC/B,MACC5F,OAAOmM,eAAiBjB,MAAMlF,kBAC/B,MAEA,MAEVuzG,KAAO,KAGNv9G,EAAI,EAAGA,EAAI80E,cAAe90E,IAC3Bw9G,QAAQx9G,GAAK,OAGVw9G,QAAQ1oC,cAAgB,GAAKuoC,cAAc98G,QAAQ,KACjDi9G,QAAQ,GAAK,EAAGA,QAAQ,GAAKH,cAAc98G,OAAQi9G,QAAQ,KAAM,KAClEl+G,KAAO8zF,IAEFpzF,EAAI80E,cAAe90E,EAAI,EAAGA,IAC3BV,MAAQ+9G,cAAcG,QAAQx9G,EAAI,QAGjCgZ,KAAKzU,OAAOmB,KAAK4J,eAAehQ,KAAOi+G,cACjCj+G,KAAOi+G,SAItBC,QAAQ,GAAKH,cAAc98G,OAEtBP,EAAI,EAAGA,EAAI80E,cAAe90E,IACvBw9G,QAAQx9G,EAAI,KAAOq9G,cAAc98G,SACjCi9G,QAAQx9G,EAAI,GAAK,EACjBw9G,QAAQx9G,IAAM,SAKnB,IAOXu6G,WAAY,mBACJrlG,EAAI,EAGD8D,KAAKzU,OAAOT,IAAImB,OAAO,WAAaiQ,KACvCA,EAAI9C,KAAKyU,MAAsB,MAAhBzU,KAAKywB,gBAGhB,WAAa3tB,GAWzBowF,MAAO,SAAUpmG,IAAKqR,UACdktG,aACAhpG,IAAM/O,KAAKk1G,WACX8C,KAAOx+G,IAAI2D,WAEV+3G,YAAc,EAGN,KAAT8C,OAAgB1kG,KAAKzU,OAAOm5G,UAC5BA,KAAOh4G,KAAK7C,GAAK0N,KAAOkE,IACjBuE,KAAKzU,OAAOmB,KAAK0J,QAAQsuG,QAC5BD,aAAerrG,KAAKyU,MAAsB,MAAhBzU,KAAKywB,UAC/B66E,KAAOh4G,KAAK7C,GAAK0N,KAAOkE,IAAM,IAAMgpG,oBAI5Cv+G,IAAI2D,GAAK66G,UACJtuG,QAAQsuG,MAAQx+G,IACrBA,IAAIs2F,KAAO9vF,KAAK24D,YAAY99D,YACvB89D,YAAY34D,KAAK24D,YAAY99D,QAAUrB,IAErCw+G,MAQXnY,eAAgB,SAAUrmG,MACqB,IAAvC8Z,KAAKrG,SAASzT,IAAIuZ,QAAQd,eACrBs9D,SAAS14D,QAAQrd,KAAK,IAInCy+G,cAAe,SAAUz+G,KACjBA,IAAI41F,WACH97E,KAAKrG,SAASzT,IAAI0W,MAAM6C,QAAQqyE,WACY,IAA7C9xE,KAAKrG,SAASzT,IAAI0W,MAAM6C,QAAQd,eAC3Bs9D,SAAS14D,QAAQrd,IAAI0W,OAAO,IAoBzCgoG,eAAgB,SAASzkG,SACjB0kG,WAAY,EACZhmB,MAAO,IAAIn3E,MAAOwjF,iBAElBlrF,KAAKzU,OAAO4U,IAAIE,YAAc3T,KAAK41G,kBAAoBniG,IAAIE,YAC3DwkG,WAAY,OACPvC,gBAAkBniG,IAAIE,YAE1BwkG,YAAchmB,KAAOnyF,KAAK21G,eAAiB31G,KAAKqM,KAAK+rG,cAAgB,MACtED,WAAY,GAEZA,iBACKxC,cAAgBxjB,MAElBgmB,WAOXE,uBAAwB,eAChBv/F,KAAMlC,IAAK0hG,MASXh+F,KAAMxK,EALNyoG,SAAWv4G,KAAKkB,SAAS0Y,eAAiB5Z,KAAKkB,SAC/Cs3G,WAAaD,SAASE,iBAAmBz4G,KAAKkB,SAASqb,KAAK9C,WAC5Di/F,QAAUH,SAASh8F,KACnB5b,UAAYX,KAAKomF,gBAQjBpmF,KAAK8Y,KAAKje,OAAS,IACdmF,KAAKm1G,OAASn1G,KAAKs0G,iBAAmBt0G,KAAKm1G,OAASn1G,KAAKu0G,yBACzD,IAAIv5F,MAAQwjF,UAAYx+F,KAAK61G,mBAAqB,YAChD71G,KAAK8Y,aAEX+8F,oBAAsB,IAAI76F,MAAQwjF,UAMnC79F,UAAUya,sBAAuB,KACjCk9F,MAAQ33G,UAAUya,wBAGlBd,KAAO,EAIPxK,EAAInP,UACGmP,GAAKwD,KAAKzU,OAAOiR,EAAE2J,aAClBnG,KAAKzU,OAAOiR,EAAEsH,QAAU9D,KAAKzU,OAAOiR,EAAEsH,MAAMkD,OAA0B,KAAjBxK,EAAEsH,MAAMkD,OAC7DA,MAAQ3C,WAAW7H,EAAEsH,MAAMkD,OAE/BxK,EAAIA,EAAE2J,kBAEVX,KAAO,CAACw/F,MAAM9mG,KAAO8I,KAAMg+F,MAAMtmG,IAAMsI,OAGlC,IAAMwa,IAAI7a,QAAQtZ,UAAW,qBAClCmY,KAAK,IAAMgc,IAAI7a,QAAQtZ,UAAW,oBAGP,QAAvBX,KAAKuvE,SAAS1kE,OAEdiO,KAAK,IAAMgc,IAAI7a,QAAQtZ,UAAW,gBAClCmY,KAAK,IAAMgc,IAAI7a,QAAQtZ,UAAW,qBAGjCmY,KAAOA,KAAKzf,QACV2G,KAAK8Y,YAOhBA,KAAOgc,IAAIjc,UAAUlY,WACrBiW,IAAM5W,KAAKkB,SAASu3G,gBAAgB7+F,eAE/B5Z,KAAKomF,aAAarsE,cAAgBnD,IAAIiD,cAKvCf,KAAK,IAAMgc,IAAI7a,QAAQu+F,WAAY,eACnC1/F,KAAK,IAAMgc,IAAI7a,QAAQu+F,WAAY,cAEnC1/F,KAAK,IAAMgc,IAAI7a,QAAQu+F,WAAY,qBACnC1/F,KAAK,IAAMgc,IAAI7a,QAAQu+F,WAAY,oBAEnC1/F,KAAK,IAAMgc,IAAI7a,QAAQu+F,WAAY,gBACnC1/F,KAAK,IAAMgc,IAAI7a,QAAQu+F,WAAY,gBAGnCE,UACA5/F,KAAK,IAAMgc,IAAI7a,QAAQy+F,QAAS,QAChC5/F,KAAK,IAAMgc,IAAI7a,QAAQy+F,QAAS,QAOd,gCAAXC,2BAAAA,UAAuBA,OAAOC,YACrC9/F,KAAK,IAAM,GACXA,KAAK,IAAM,IAIfA,KAAK,IAAMgc,IAAI7a,QAAQtZ,UAAW,qBAClCmY,KAAK,IAAMgc,IAAI7a,QAAQtZ,UAAW,oBAGP,QAAvBX,KAAKuvE,SAAS1kE,OAEdiO,KAAK,IAAMgc,IAAI7a,QAAQtZ,UAAW,gBAClCmY,KAAK,IAAMgc,IAAI7a,QAAQtZ,UAAW,gBAGtCmY,KAAK,IAAM9Y,KAAKqM,KAAKwsG,QACrB//F,KAAK,IAAM9Y,KAAKqM,KAAKysG,aAEhBhgG,KAAOA,KAAKzf,QACV2G,KAAK8Y,MAWhBigG,iBAAkB,SAAU97G,EAAG3C,OAEvB0+G,OACAhvG,EAFA8O,KAAO9Y,KAAKq4G,gCAKhBW,OAASlkF,IAAIzc,YAAYpb,EAAG3C,EAAG0F,KAAKkB,UAK/BoS,KAAKzU,OAAOmB,KAAKi5G,mBACbC,sBAGTlvG,EAAI,CAAC,EAAGgvG,OAAO,GAAKlgG,KAAK,GAAIkgG,OAAO,GAAKlgG,KAAK,KAC9C9O,EAAIka,IAAI3E,WAAWvf,KAAKi5G,YAAajvG,IACnC,IAAMA,EAAE,GACVA,EAAE,IAAMA,EAAE,GACH,CAACA,EAAE,GAAIA,EAAE,KAapBmvG,eAAgB,SAAUrrG,EAAGiT,QACpBu0F,QAAUxnG,EAAI9N,KAAK8L,OAAOyY,UAAU,QACpCgxF,QAAUx0F,EAAI/gB,KAAK8L,OAAOyY,UAAU,QAEpC4wF,KAAOn1G,KAAKu0G,4BACZ3zD,cAAgB5gD,KAAK6gD,mBAY9Bu4D,eAAgB,SAAUtrG,EAAGiT,EAAGtN,IAAK5I,UAC7BkxF,IACA1tF,GAGAgrG,SAFAC,QAAU,GACVzzF,OAAS,GAETzZ,IAAMpM,KAAK24D,YAAY99D,OACvB0+G,OAAS,CAACxmG,QAAS,CAAC9C,OAAQ,UAG3B5B,GAAK,EAAGA,GAAKjC,IAAKiC,KAEnBgrG,UADAtd,IAAM/7F,KAAK24D,YAAYtqD,KACR2mE,UAAY+mB,IAAI/mB,SAASlnE,EAAGiT,GAEvCg7E,IAAIva,YAAYvvE,SAAWonG,WAC3Btd,IAAI19E,qBAAqB,CAACxT,KAAO,OAAQ,QAAS,CAAC4I,WAC9CqiG,YAAYp6G,KAAKqgG,MAGtBsd,UACAtd,IAAI7M,aACJ6M,IAAIva,YAAYvvE,UACdjS,KAAKm2G,2BACF7iG,KAAK9I,QAAQuxF,MACbA,IAAItxF,eAAiBjB,MAAMlF,qBAE9BtE,KAAKm2G,4BAEN7iG,KAAKrG,SAAS8uF,IAAIhpF,QAAQ4/D,SAKvBopB,IAAIhpF,QAAQ9C,MAAQspG,OAAOxmG,QAAQ9C,OAC9B8rF,IAAIhpF,QAAQ9C,QAAUspG,OAAOxmG,QAAQ9C,OACrC8rF,IAAIpL,aAAa6N,WAAa+a,OAAO5oB,aAAa6N,aAOlDx+F,KAAKqM,KAAKmtG,cACTlmG,KAAKzU,OAAO06G,OAAOrpG,QAAU6rF,MAAQwd,OAAOrpG,QAC9CqpG,OAASxd,IACTud,QAAQ59G,KAAK69G,QAGTjmG,KAAKzU,OAAO06G,OAAO1rG,QACnBgY,OAAOnqB,KAAKmyC,WAAWa,SAAS6qE,OAAO1rG,OAAO0W,UAAUlrB,MAAM,GAAI,CAACyU,EAAGiT,KAEtE8E,OAAOnqB,KAAK,CAAC,EAAG,aAYhCsE,KAAKqM,KAAKkkE,KAAKhD,SAAW+rC,QAAQz+G,OAAS,SACtCs6G,KAAOn1G,KAAKs0G,iBAIjBt0G,KAAKqM,KAAKotG,WACVH,QAAQz+G,OAAS,OACZ87G,aAAe9wF,OAAO,KAE3ByzF,QAAUA,QAAQjgH,OAAO,QACpBs9G,aAAe9wF,OAAOA,OAAOhrB,OAAS,IAG1CmF,KAAK22G,oBACDA,aAAe,CAAC,EAAG,IAID,QAAvB32G,KAAKuvE,SAAS1kE,MACdyI,KAAKzU,OAAOy6G,QAAQ,KACpBhmG,KAAKrG,SAASqsG,QAAQ,GAAGvmG,QAAQ2mG,mBACd,IAAnBJ,QAAQz+G,QACRyY,KAAKzU,OAAOy6G,QAAQ,GAAG34B,WAEvB24B,QAAQ,GAAG34B,SAASlnE,WAAW4C,YAAYi9F,QAAQ,GAAG34B,eAIrDg5B,iBAAmB,OACnBC,cAAgB,EAEjBN,QAAQz+G,QAAU,IAClBy+G,QAAQ,GAAGpmC,WAAU,QAChB70D,qBAAqB,CAAC,WAAY,OAAQ,CAAC5K,IAAK6lG,QAAQ,MAG1DA,SAWXO,WAAY,SAAU/rG,EAAGiT,EAAGjR,EAAG2D,IAAK5I,UAE5B0lE,KACAupC,cAAeC,iBAFf58D,OAAS,IAAIh5B,OAAO3a,MAAMzH,iBAAkB/B,KAAKg6G,oBAAoBlsG,EAAGiT,GAAI/gB,MAI1E8P,GAAKA,EAAEtW,OAGb+2E,KAAOzgE,EAAEtW,KAGAqU,SACLisG,cAAgBvpC,KAAK1iE,OAAO0W,UAAUlrB,cAMrCm8G,cAAgB,CAACr4D,OAAO54B,UAAU,GAAI44B,OAAO54B,UAAU,SACvDixF,cAAgB3nE,WAAW3iB,IAAIlrB,KAAKw1G,cAAex1G,KAAK22G,cAIzDrjG,KAAKzU,OAAO0xE,KAAK1iE,QACjB0iE,KAAKuhB,oBAAoBtoF,MAAMzH,iBAAkB/B,KAAKw1G,qBAEjDyE,gBAAe,GAIfvrG,MAAMoB,EAAEoqG,QAAQ,GAAGC,MAAQrqG,EAAEoqG,QAAQ,GAAGE,QACzC7pC,KAAKuhB,oBAAoBtoF,MAAMzH,iBAC3B,CAACo7C,OAAO54B,UAAU,GAAI44B,OAAO54B,UAAU,IACvC,CAACzU,EAAEoqG,QAAQ,GAAGC,MAAOrqG,EAAEoqG,QAAQ,GAAGE,QAK1CtqG,EAAEoqG,QAAQ,GAAGC,MAAQh9D,OAAO54B,UAAU,GACtCzU,EAAEoqG,QAAQ,GAAGE,MAAQj9D,OAAO54B,UAAU,IAGtCjR,KAAKzU,OAAO0xE,KAAK1iE,UACjB0iE,KAAK8U,gBAAgB7qD,QAAO,GAAO04D,sBAC9BmnB,cAAc9pC,MACnBA,KAAK8U,gBAAgB7qD,QAAO,GAAM04D,kBAGlC3iB,KAAK1iE,SACLksG,iBAAmBxpC,KAAK1iE,OAAO0W,WAG9BgsD,KAAK1iE,QACNisG,cAAc,KAAOC,iBAAiB,IACtCD,cAAc,KAAOC,iBAAiB,KAEtCxpC,KAAKlyD,qBAAqB,CAACxT,KAAO,OAAQ,QAAS,CAAC4I,WAE/C+mB,UAET+1C,KAAK2C,WAAU,QACV70D,qBAAqB,CAAC,WAAY,OAAQ,CAAC5K,IAAK88D,OAErDA,KAAKogB,aAAe,IAAI31E,OAU5Bs/F,cAAe,SAAUxqG,EAAG3S,GAAIsW,SACxB88D,KAEAj9D,KAAKzU,OAAOiR,IAAMwD,KAAKzU,OAAOiR,EAAEtW,QAChC+2E,KAAOzgE,EAAEtW,KAKJiR,eAAiBjB,MAAMvF,mBAC5BssE,KAAK1lE,OAASrB,MAAMzG,yBACfw3G,qBAAqBzqG,EAAEoqG,QAAS3pC,KAAMpzE,IACpCozE,KAAK9lE,eAAiBjB,MAAMtF,0BAC9Bs2G,qBAAqB1qG,EAAEoqG,QAAS3pC,KAAMpzE,IAG3CsW,KACA88D,KAAKlyD,qBAAqB,CAAC,YAAa,QAAS,CAAC5K,QAU1D8mG,qBAAsB,SAAUE,IAAKlqC,KAAMpzE,QACnCksC,GAAIqxE,GAAIC,GAAIC,GACZzvG,EAAGqgC,MACH1kB,EAAG2W,GAAIo9E,GAAIC,GAAIC,GACf3sG,GAAI9T,EAAG8R,IACP4uG,MAAOC,OAAQC,OAEf5nG,KAAKzU,OAAO47G,IAAI,KAAOnnG,KAAKzU,OAAO47G,IAAI,MACtC/rG,MAAM+rG,IAAI,GAAGN,MAAQM,IAAI,GAAGL,MAAQK,IAAI,GAAGN,MAAQM,IAAI,GAAGL,OAAQ,IAE/Dj9G,KAAOs9G,IAAI,GAAG1rG,KACdisG,MAASP,IAAI,GACbQ,OAASR,IAAI,KAEbO,MAASP,IAAI,GACbQ,OAASR,IAAI,IAGjBS,IAAO,IAAI/2F,OAAO3a,MAAMzH,iBAAkB,CAACi5G,MAAMb,MAAOa,MAAMZ,OAAQp6G,MAAOgO,UAE7E0sG,GAAM,IAAIv2F,OAAO3a,MAAMzH,iBAAkB,CAACk5G,OAAOd,MAAOc,OAAOb,OAAQp6G,MAAOgO,UAE9Eq7B,GAAM,IAAIllB,OAAO3a,MAAMzH,iBAAkB,CAACk5G,OAAO78E,EAAG68E,OAAO58E,GAAIr+B,MAAOgO,UAGtE4sG,GAAK12F,IAAI1D,aAAa06F,IAAKR,IAC3BC,GAAKz2F,IAAI1D,aAAa06F,IAAK7xE,IAG3BviB,EAAI5C,IAAI1D,aAAao6F,GAAID,IAGrBjuG,KAAKwC,IAAI4X,EAAE,IAAM5C,IAAIzF,cAIzB+sB,MAAQ2D,SAASI,IAAImrE,GAAGrhH,MAAM,GAAI6hH,IAAI7hH,MAAM,GAAIgwC,GAAGhwC,MAAM,KAEzDokC,GAAKz9B,KAAK4M,OAAO,YAAa,CAAC4+B,MAAO,CAAC0vE,IAAI,GAAIA,IAAI,KAAM,CAACrwG,KAAM,YAC7D2vB,SAEClnB,KAAKrG,SAASsjE,KAAKx9D,QAAQsgE,YAE3BloE,EAAIgkC,SAAShqB,SAASkkB,GAAI6xE,KAAO/rE,SAAShqB,SAASu1F,GAAIQ,KAEvDL,GAAK76G,KAAK4M,OAAO,YAAa,EAAEsuG,IAAI,IAAKA,IAAI,IAAK,CAACrwG,KAAM,cACzDiwG,GAAK96G,KAAK4M,OAAO,YAAa,CAACzB,EAAGA,GAAI,CAACN,KAAM,UAC7CkwG,GAAK/6G,KAAK4M,OAAO,YAAa,CAACsuG,IAAI,GAAIA,IAAI,IAAK,CAACrwG,KAAM,cACvD4yB,GAAGm0D,KAAKipB,IAAIjpB,KAAKkpB,IAAIlpB,KAAKmpB,KAG1BxqC,KAAK9lE,eAAiBjB,MAAMvF,kBAC5BmK,GAAK,GACDmiE,KAAK7/B,OAAO8gD,aACZpjF,GAAG1S,KAAK60E,KAAK7/B,QAEb6/B,KAAK3/B,OAAO4gD,aACZpjF,GAAG1S,KAAK60E,KAAK3/B,QAEjBnT,GAAGi0D,UAAUtjF,SACV,GAAImiE,KAAK1lE,OAASrB,MAAMzG,oBAAqB,KAChDqL,GAAK,GACLhC,IAAMmkE,KAAKzzB,SAASjiD,OAAS,EACxBP,EAAI,EAAGA,EAAI8R,MAAO9R,EACfi2E,KAAKzzB,SAASxiD,GAAGk3F,aACjBpjF,GAAG1S,KAAK60E,KAAKzzB,SAASxiD,IAG9BmjC,GAAGi0D,UAAUtjF,SAGZosB,SACL+1C,KAAK2C,WAAU,KAUvBsnC,qBAAsB,SAAUC,IAAKlqC,KAAMpzE,QACnC69G,MAAOC,OAAQ5xE,GAAIqxE,GAAIQ,IACvB/vG,EAAGqgC,MAAO/N,GAAIC,GAAIm9E,GAAIC,GAEN,gBAAhBvqC,KAAKnsD,QAA4C,cAAhBmsD,KAAKnsD,QAItC9Q,KAAKzU,OAAO47G,IAAI,KAAOnnG,KAAKzU,OAAO47G,IAAI,MACtC/rG,MAAM+rG,IAAI,GAAGN,MAAQM,IAAI,GAAGL,MAAQK,IAAI,GAAGN,MAAQM,IAAI,GAAGL,SAEvDj9G,KAAOs9G,IAAI,GAAG1rG,KACdisG,MAASP,IAAI,GACbQ,OAASR,IAAI,KAEbO,MAASP,IAAI,GACbQ,OAASR,IAAI,IAGjBS,IAAO,IAAI/2F,OAAO3a,MAAMzH,iBAAkB,CAACi5G,MAAMb,MAAOa,MAAMZ,OAAQp6G,MAAOgO,UAE7E0sG,GAAM,IAAIv2F,OAAO3a,MAAMzH,iBAAkB,CAACk5G,OAAOd,MAAOc,OAAOb,OAAQp6G,MAAOgO,UAE9Eq7B,GAAM,IAAIllB,OAAO3a,MAAMzH,iBAAkB,CAACk5G,OAAO78E,EAAG68E,OAAO58E,GAAIr+B,MAAOgO,UAEtEw9B,MAAQ2D,SAASI,IAAImrE,GAAGrhH,MAAM,GAAI6hH,IAAI7hH,MAAM,GAAIgwC,GAAGhwC,MAAM,IAGzDokC,GAAKz9B,KAAK4M,OAAO,YAAa,EAAEsuG,IAAI,IAAKA,IAAI,IAAK,CAACrwG,KAAM,cACzD6yB,GAAK19B,KAAK4M,OAAO,YAAa,CAAC4+B,OAAQ,CAAC3gC,KAAM,WAC9C4yB,GAAGm0D,KAAKl0D,IACJpqB,KAAKrG,SAASsjE,KAAKx9D,QAAQsgE,YAC3BloE,EAAIgkC,SAAShqB,SAAS+1F,IAAK7xE,IAAM8F,SAAShqB,SAAS+1F,IAAKR,IACxDG,GAAK76G,KAAK4M,OAAO,YAAa,CAACzB,EAAGA,GAAI,CAACN,KAAM,UAC7C4yB,GAAGm0D,KAAKipB,KAEZC,GAAK96G,KAAK4M,OAAO,YAAa,CAACsuG,IAAI,GAAIA,IAAI,IAAK,CAACrwG,KAAM,cACvD4yB,GAAGm0D,KAAKkpB,IAEJvqC,KAAK73C,OAAO84D,aACZ/zD,GAAGi0D,UAAU,CAACnhB,KAAK73C,SAGH,cAAhB63C,KAAKnsD,OACDmsD,KAAK3/B,OAAO4gD,aACZ/zD,GAAGi0D,UAAU,CAACnhB,KAAK3/B,SAEA,gBAAhB2/B,KAAKnsD,QACR9Q,KAAKrJ,SAASsmE,KAAK4qC,aAAarvG,SAChCykE,KAAKgkB,UAAUhkB,KAAK3X,OAASztD,QAIhCqvB,OAAO+1C,KAAK73C,QACjB63C,KAAK2C,WAAU,KAIvBkoC,kBAAmB,SAAUttG,EAAGiT,EAAGtN,IAAKo5E,YAChCx+E,GAAI0tF,IAAKsf,IACTC,YAAc,GACdlvG,IAAMpM,KAAK24D,YAAY99D,WAGtBwT,GAAK,EAAGA,GAAKjC,IAAKiC,KAEnBgtG,KADAtf,IAAM/7F,KAAK24D,YAAYtqD,KACblR,GACNmW,KAAKzU,OAAOk9F,IAAI/mB,WAAa+mB,IAAIva,YAAYvvE,SAAW8pF,IAAI/mB,SAASlnE,EAAGiT,UAEnEs5F,cAActe,KAEdzoF,KAAKzU,OAAOmB,KAAKwgF,mBAAmB66B,QACrCC,YAAYD,KAAOtf,IACnBA,IAAI7oB,iBAEC70D,qBAAqB,CAAC,WAAY,OAAQ,CAAC5K,IAAKsoF,IAAKlP,UAG1DkP,IAAIrL,UACJqL,IAAI19E,qBAAqB,CAAC,YAAa,QAAS,CAAC5K,OAEjDsoF,IAAI19E,qBAAqB,CAAC,YAAa,QAAS,CAAC5K,MACjDsoF,IAAIrL,WAAY,QAKvBriF,GAAK,EAAGA,GAAKjC,IAAKiC,KAEnBgtG,KADAtf,IAAM/7F,KAAK24D,YAAYtqD,KACblR,GACN4+F,IAAIrL,YACC4qB,YAAYD,OACbtf,IAAI19E,qBAAqB,CAAC,WAAY,OAAQ,CAAC5K,MAC/CsoF,IAAIrL,WAAY,KAahC6qB,aAAc,SAAU/hH,IAAK0gH,aACZ5/G,EAAG8R,IAAZovG,GAAK,MAELhiH,IAAIqR,OAASrB,MAAMpH,kBACnBo5G,GAAG9/G,KAAK,CAAC,EAAGiT,IAAKA,WACd,GAAInV,IAAIiR,eAAiBjB,MAAMvF,kBAClCu3G,GAAG9/G,KAAKlC,IAAIk3C,OAAO7iC,OAAOG,WAC1BwtG,GAAG9/G,KAAKlC,IAAIo3C,OAAO/iC,OAAOG,gBACvB,GAAIxU,IAAIiR,eAAiBjB,MAAMtF,oBAClCs3G,GAAG9/G,KAAKlC,IAAIk/B,OAAO7qB,OAAOG,WACP,cAAfxU,IAAI4qB,QACJo3F,GAAG9/G,KAAKlC,IAAIo3C,OAAO/iC,OAAOG,gBAE3B,GAAIxU,IAAIqR,OAASrB,MAAMzG,wBAC1BqJ,IAAM5S,IAAIsjD,SAASjiD,OAAS,EACvBP,EAAI,EAAGA,EAAI8R,IAAK9R,IACjBkhH,GAAG9/G,KAAKlC,IAAIsjD,SAASxiD,GAAGuT,OAAOG,gBAEhC,GAAIxU,IAAIqR,OAASrB,MAAMxG,mBAC1Bw4G,GAAG9/G,KAAKlC,IAAIk3C,OAAO7iC,OAAOG,WAC1BwtG,GAAG9/G,KAAKlC,IAAIo3C,OAAO/iC,OAAOG,WAC1BwtG,GAAG9/G,KAAKlC,IAAI43C,OAAOvjC,OAAOG,gBACvB,GAAIsF,KAAK9I,QAAQhR,MAAQA,IAAIqR,OAASrB,MAAMhH,mBAC/Cg5G,GAAG9/G,KAAKlC,IAAIqU,OAAOG,gBAChB,GAAIxU,IAAIiR,eAAiBjB,MAAMrF,mBAS9B3K,IAAI+S,OAAO1R,OAAS,GACpB2gH,GAAG9/G,KAAKlC,IAAI+S,OAAO,GAAGyB,oBAItBwtG,GAAG9/G,KAAKlC,IAAIqU,OAAOG,WACrB,MAAO/Q,GACLmB,IAAIsD,MAAM,+DAAiEzE,OAInFmP,IAAMovG,GAAG3gH,OACJP,EAAI,EAAGA,EAAI8R,IAAK9R,IACjB4/G,QAAQuB,OAAO//G,KAAK8/G,GAAGlhH,GAAG,IAC1B4/G,QAAQwB,OAAOhgH,KAAK8/G,GAAGlhH,GAAG,IAC1B4/G,QAAQyB,OAAOjgH,KAAK8/G,GAAGlhH,GAAG,KAIlCshH,qBAAsB,SAAUnoG,SACxBjE,EAAGqsC,WAEPrsC,EAAIxP,KAAK67G,sBAAsBpoG,IAAK,UAEhCooC,IAAM77C,KAAK+4G,iBAAiBtlG,UACvB0lG,eAAet9D,IAAI,GAAIA,IAAI,KAG7BrsC,GAGXssG,gBAAiB,SAAUroG,SAEnBooC,IADArsC,EAAKxP,KAAKm1G,OAASn1G,KAAKu0G,8BAGxB/kG,IACAqsC,IAAM77C,KAAK+4G,iBAAiBtlG,UACvBsoG,WAAWlgE,IAAI,GAAIA,IAAI,IAAI,IAG7BrsC,GASXwsG,8BAA+B,SAAUvoG,SAEjC0/F,WAAYt3D,IADZ45D,QAAUhiG,IAAIrV,IAAImV,sBAGtB4/F,WAAanzG,KAAKqM,KAAKgkE,IAAI9C,UACtBvtE,KAAKqM,KAAKgkE,IAAI4rC,gBACI,IAAnBxG,QAAQ56G,UAGRghD,IAAM77C,KAAK+4G,iBAAiBtlG,IAAK,QAC5B0lG,eAAet9D,IAAI,GAAIA,IAAI,KAG7Bs3D,YASX+I,gBAAiB,SAAUzoG,SAEnBooC,IADArsC,EAAKxP,KAAKm1G,OAASn1G,KAAKu0G,8BAGxB/kG,IACAqsC,IAAM77C,KAAK+4G,iBAAiBtlG,IAAK,QAC5BsoG,WAAWlgE,IAAI,GAAIA,IAAI,IAAI,IAG7BrsC,GAQX2sG,cAAe,gBACNv7D,cAAgB5gD,KAAKy0G,wBACrBU,KAAOn1G,KAAKq0G,iBAYrB8C,iBAAkB,cACVriF,IAAI1f,6BACCgnG,gCAEAC,6BACAC,yBAOiB,OAAtBt8G,KAAKomF,oBACAA,aAAam2B,cAAgB,SAAUt/G,UACpCqW,KAAKzU,OAAO5B,IACZA,EAAEu/G,kBAEC,SAIVC,kCACAC,2BAED5nF,IAAI7gB,UAAW,UAGN0oG,sBACP,MAAOvoG,KAEL0gB,IAAIhd,SAAS9W,OAAQ,SAAUhB,KAAK48G,eAAgB58G,WAE/C68G,4BAKT/nF,IAAIhd,SAAS9W,OAAQ,SAAUhB,KAAK88G,eAAgB98G,QAO5D+8G,oBAAqB,gBACZC,gCACAC,gCACAC,kCAEAC,qCACAC,8BACDtoF,IAAI7gB,YACAX,KAAKzU,OAAOmB,KAAKq9G,qBACZC,sBAELxoF,IAAI7c,YAAYjX,OAAQ,SAAUhB,KAAK48G,eAAgB58G,WAClDu9G,4BAETzoF,IAAI7c,YAAYjX,OAAQ,SAAUhB,KAAK88G,eAAgB98G,QAO/Do8G,wBAAyB,eAChBp8G,KAAKu2G,oBAAsBzhF,IAAI7gB,UAAW,KACvC48D,WAAa7wE,KAAKqM,KAAKmxG,YAAcx9G,KAAKomF,aAE1CplF,OAAOqU,UAAUG,kBACjBsf,IAAIhd,SAAS9X,KAAKomF,aAAc,gBAAiBpmF,KAAKy9G,oBAAqBz9G,MAC3E80B,IAAIhd,SAAS+4D,WAAY,gBAAiB7wE,KAAK09G,oBAAqB19G,QAEpE80B,IAAIhd,SAAS9X,KAAKomF,aAAc,cAAepmF,KAAKy9G,oBAAqBz9G,MACzE80B,IAAIhd,SAAS+4D,WAAY,cAAe7wE,KAAK09G,oBAAqB19G,OAEtE80B,IAAIhd,SAAS9X,KAAKomF,aAAc,aAAcpmF,KAAK29G,mBAAoB39G,MACvE80B,IAAIhd,SAAS9X,KAAKomF,aAAc,iBAAkBpmF,KAAK29G,mBAAoB39G,MAEjD,OAAtBA,KAAKomF,oBAGAA,aAAahvE,MAAMwmG,YAAc,aAGrCrH,oBAAqB,IAOlC8F,sBAAuB,eACdr8G,KAAKq2G,kBAAoBvhF,IAAI7gB,UAAW,KACrC48D,WAAa7wE,KAAKqM,KAAKmxG,YAAcx9G,KAAKomF,aAE9CtxD,IAAIhd,SAAS9X,KAAKomF,aAAc,YAAapmF,KAAK69G,kBAAmB79G,MACrE80B,IAAIhd,SAAS+4D,WAAY,YAAa7wE,KAAK89G,kBAAmB99G,MAE9D80B,IAAIhd,SAAS9X,KAAKomF,aAAc,aAAcpmF,KAAK29G,mBAAoB39G,MACvE80B,IAAIhd,SAAS9X,KAAKomF,aAAc,iBAAkBpmF,KAAK29G,mBAAoB39G,WAEtEq2G,kBAAmB,IAWhCiG,sBAAuB,SAAUyB,mBACxB/9G,KAAKs2G,kBAAoBxhF,IAAI7gB,UAAW,KACrC48D,WAAa7wE,KAAKqM,KAAKmxG,YAAcx9G,KAAKomF,aAE9CtxD,IAAIhd,SAAS9X,KAAKomF,aAAc,aAAcpmF,KAAKg+G,mBAAoBh+G,MACvE80B,IAAIhd,SAAS+4D,WAAY,YAAa7wE,KAAKi+G,kBAAmBj+G,WAUzDs2G,kBAAmB,IAQhCmG,2BAA4B,eACpBniH,EAEA4jH,OAAS,CAAC,mBAAoB,sBAAuB,yBAA0B,sBAC/El9F,GAAKk9F,OAAOrjH,WAEXmF,KAAKm+G,2BAA6BrpF,IAAI7gB,UAAW,KAC7C3Z,EAAI,EAAGA,EAAI0mB,GAAI1mB,IAChBw6B,IAAIhd,SAAS9X,KAAKkB,SAAUg9G,OAAO5jH,GAAI0F,KAAKo+G,mBAAoBp+G,WAE/Dm+G,2BAA4B,IAIzCzB,yBAA0B,WAClB18G,KAAKqM,KAAKmkE,SAASjD,UAAYvtE,KAAKq+G,qBAAuBvpF,IAAI7gB,YAC/D6gB,IAAIhd,SAAS9X,KAAKomF,aAAc,UAAWpmF,KAAKs+G,gBAAiBt+G,MACjE80B,IAAIhd,SAAS9X,KAAKomF,aAAc,UAAWpmF,KAAKu+G,mBAAoBv+G,MACpE80B,IAAIhd,SAAS9X,KAAKomF,aAAc,WAAYpmF,KAAKw+G,oBAAqBx+G,WACjEq+G,qBAAsB,IAOnCjB,4BAA6B,WACrBp9G,KAAKq+G,qBAAuBvpF,IAAI7gB,YAChC6gB,IAAI7c,YAAYjY,KAAKomF,aAAc,UAAWpmF,KAAKs+G,gBAAiBt+G,MACpE80B,IAAI7c,YAAYjY,KAAKomF,aAAc,UAAWpmF,KAAKu+G,mBAAoBv+G,MACvE80B,IAAI7c,YAAYjY,KAAKomF,aAAc,WAAYpmF,KAAKw+G,oBAAqBx+G,WACpEq+G,qBAAsB,IAOnClB,8BAA+B,eACvB7iH,EAEA4jH,OAAS,CAAC,mBAAoB,sBAAuB,yBAA0B,sBAC/El9F,GAAKk9F,OAAOrjH,UAEZmF,KAAKm+G,2BAA6BrpF,IAAI7gB,UAAW,KAC5C3Z,EAAI,EAAGA,EAAI0mB,GAAI1mB,IAChBw6B,IAAI7c,YAAYjY,KAAKkB,SAAUg9G,OAAO5jH,GAAI0F,KAAKo+G,mBAAoBp+G,WAElEm+G,2BAA4B,IAOzCjB,2BAA4B,cACpBl9G,KAAKu2G,oBAAsBzhF,IAAI7gB,UAAW,KACtC48D,WAAa7wE,KAAKqM,KAAKmxG,YAAcx9G,KAAKomF,aAE1CplF,OAAOqU,UAAUG,kBACjBsf,IAAI7c,YAAYjY,KAAKomF,aAAc,gBAAiBpmF,KAAKy9G,oBAAqBz9G,MAC9E80B,IAAI7c,YAAY44D,WAAY,gBAAiB7wE,KAAK09G,oBAAqB19G,QAEvE80B,IAAI7c,YAAYjY,KAAKomF,aAAc,cAAepmF,KAAKy9G,oBAAqBz9G,MAC5E80B,IAAI7c,YAAY44D,WAAY,cAAe7wE,KAAK09G,oBAAqB19G,OAGzE80B,IAAI7c,YAAYjY,KAAKomF,aAAc,aAAcpmF,KAAK29G,mBAAoB39G,MAC1E80B,IAAI7c,YAAYjY,KAAKomF,aAAc,iBAAkBpmF,KAAK29G,mBAAoB39G,MAE1EA,KAAK02G,eACD11G,OAAOqU,UAAUG,iBACjBsf,IAAI7c,YAAYjY,KAAKkB,SAAU,cAAiBlB,KAAKy+G,kBAAmBz+G,OAExE80B,IAAI7c,YAAYjY,KAAKkB,SAAU,YAAiBlB,KAAKy+G,kBAAmBz+G,MACxE80B,IAAI7c,YAAYjY,KAAKkB,SAAU,gBAAiBlB,KAAKy+G,kBAAmBz+G,YAEvE02G,cAAe,QAGnBH,oBAAqB,IAOlCyG,yBAA0B,cAClBh9G,KAAKq2G,kBAAoBvhF,IAAI7gB,UAAW,KACpC48D,WAAa7wE,KAAKqM,KAAKmxG,YAAcx9G,KAAKomF,aAE9CtxD,IAAI7c,YAAYjY,KAAKomF,aAAc,YAAapmF,KAAK69G,kBAAmB79G,MACxE80B,IAAI7c,YAAY44D,WAAY,YAAa7wE,KAAK89G,kBAAmB99G,MAE7DA,KAAKw2G,aACL1hF,IAAI7c,YAAYjY,KAAKkB,SAAU,UAAWlB,KAAK0+G,gBAAiB1+G,WAC3Dw2G,YAAa,GAGtB1hF,IAAI7c,YAAYjY,KAAKomF,aAAc,aAAcpmF,KAAK29G,mBAAoB39G,MAC1E80B,IAAI7c,YAAYjY,KAAKomF,aAAc,iBAAkBpmF,KAAK29G,mBAAoB39G,WAEzEq2G,kBAAmB,IAOhC4G,yBAA0B,cAClBj9G,KAAKs2G,kBAAoBxhF,IAAI7gB,UAAW,KACpC48D,WAAa7wE,KAAKqM,KAAKmxG,YAAcx9G,KAAKomF,aAE9CtxD,IAAI7c,YAAYjY,KAAKomF,aAAc,aAAcpmF,KAAKg+G,mBAAoBh+G,MAC1E80B,IAAI7c,YAAY44D,WAAY,YAAa7wE,KAAKi+G,kBAAmBj+G,MAE7DA,KAAKy2G,cACL3hF,IAAI7c,YAAYjY,KAAKkB,SAAU,WAAYlB,KAAK2+G,iBAAkB3+G,WAC7Dy2G,aAAc,QAGlBH,kBAAmB,IAQhCrrB,eAAgB,uBACP8wB,WAAW/7G,KAAK8L,OAAOyY,UAAU,GAAwB,GAAnBvkB,KAAK8yC,YAAmB9yC,KAAK8L,OAAOyY,UAAU,IAClFvkB,MAOXorF,gBAAiB,uBACR2wB,WAAW/7G,KAAK8L,OAAOyY,UAAU,GAAwB,GAAnBvkB,KAAK8yC,YAAmB9yC,KAAK8L,OAAOyY,UAAU,IAClFvkB,MAOXkrF,aAAc,uBACL6wB,WAAW/7G,KAAK8L,OAAOyY,UAAU,GAAIvkB,KAAK8L,OAAOyY,UAAU,GAAyB,GAApBvkB,KAAK+yC,cACnE/yC,MAOXmrF,eAAgB,uBACP4wB,WAAW/7G,KAAK8L,OAAOyY,UAAU,GAAIvkB,KAAK8L,OAAOyY,UAAU,GAAyB,GAApBvkB,KAAK+yC,cACnE/yC,MASX4+G,sBAAuB,SAAUnrG,SACzB7D,EACAivG,KACAC,KACA1vE,MAMAqM,OACA/V,KACA5G,GAAIiC,GAAI6rB,MAAOhd,GAAIC,GAAIkvE,MANvBC,SAAU,EAEVC,GAAKj/G,KAAKqM,KAAKiO,KAAK4kG,QACpBC,GAAKn/G,KAAKqM,KAAKiO,KAAK8kG,eAKpBp/G,KAAKm1G,OAASn1G,KAAKw0G,kBAGvB/gG,IAAI+oG,iBAEJ92E,KAAOyJ,SAAShqB,SAAS,CAAC1R,IAAIgiG,QAAQ,GAAG98F,QAASlF,IAAIgiG,QAAQ,GAAG78F,SAC7D,CAACnF,IAAIgiG,QAAQ,GAAG98F,QAASlF,IAAIgiG,QAAQ,GAAG78F,SAAU,QAKpChb,IAAd6V,IAAIgI,QACJhI,IAAIgI,MAAQiqB,KAAO1lC,KAAKq/G,YAGvB/rG,KAAKzU,OAAOmB,KAAKs/G,cAItBT,KAAO,CAACprG,IAAIgiG,QAAQ,GAAG98F,QAAU3Y,KAAKs/G,WAAW,GAAG,GAC5C7rG,IAAIgiG,QAAQ,GAAG78F,QAAU5Y,KAAKs/G,WAAW,GAAG,IACpDR,KAAO,CAACrrG,IAAIgiG,QAAQ,GAAG98F,QAAU3Y,KAAKs/G,WAAW,GAAG,GAC5C7rG,IAAIgiG,QAAQ,GAAG78F,QAAU5Y,KAAKs/G,WAAW,GAAG,IAE/CT,KAAK,GAAKA,KAAK,GAAKA,KAAK,GAAKA,KAAK,GAAKp/D,KACxCq/D,KAAK,GAAKA,KAAK,GAAKA,KAAK,GAAKA,KAAK,GAAKr/D,MAI7CrQ,MAAQD,SAASI,IAAIsvE,KAAM,CAAC,EAAE,GAAIC,MACH,QAA3B9+G,KAAKu/G,mBACL7yG,KAAKwC,IAAIkgC,OAAmB,GAAV1iC,KAAKiV,IACvBjV,KAAKwC,IAAIkgC,OAAmB,IAAV1iC,KAAKiV,KACvBq9F,SAAU,GAGiB,QAA3Bh/G,KAAKu/G,mBAAgCP,UACjCtyG,KAAKwC,IAAIuE,IAAIgI,OAAS,KAAQ/O,KAAKwC,IAAIuE,IAAIgI,OAAS,OACpDujG,SAAU,GAIlBvjE,OAAShoC,IAAIgI,MAAQzb,KAAKw/G,eACrBA,UAAY/rG,IAAIgI,WAChB6jG,WAAa,CAAC,CAAC7rG,IAAIgiG,QAAQ,GAAG98F,QAASlF,IAAIgiG,QAAQ,GAAG78F,SACxC,CAACnF,IAAIgiG,QAAQ,GAAG98F,QAASlF,IAAIgiG,QAAQ,GAAG78F,UAE3DhJ,EAAI,IAAIuU,OAAO3a,MAAMzH,iBAAkB/B,KAAK+4G,iBAAiBtlG,IAAK,GAAIzT,MAElEA,KAAKqM,KAAKgkE,IAAI9C,SACdvtE,KAAKqM,KAAKgkE,IAAI4rC,iBACb+C,cAGIO,kBAAoB,WAEpBxD,WAAWnsG,EAAE2U,UAAU,GAAI3U,EAAE2U,UAAU,IAAI,IACzCvkB,KAAKqM,KAAKiO,KAAKizD,SACd7gE,KAAKwC,IAAIusC,OAAS,GAAO,MAG7Bz7C,KAAKqM,KAAKiO,KAAKmlG,iBAAmBz/G,KAAKqM,KAAKiO,KAAKolG,iBACjD5gF,GAAKpyB,KAAKwC,IAAIuE,IAAIgiG,QAAQ,GAAG98F,QAAUlF,IAAIgiG,QAAQ,GAAG98F,SACtDooB,GAAKr0B,KAAKwC,IAAIuE,IAAIgiG,QAAQ,GAAG78F,QAAUnF,IAAIgiG,QAAQ,GAAG78F,SACtDg0C,MAAQlgD,KAAKwC,IAAIxC,KAAKypB,MAAM4K,GAAIjC,KAChCigF,MAAQryG,KAAKiV,GAAK3hB,KAAKqM,KAAKiO,KAAKqlG,iBAAmB,IAGpD3/G,KAAKqM,KAAKiO,KAAKmlG,iBAAmB7yD,MAAQmyD,YACrC1yG,KAAKiO,KAAK4kG,QAAUzjE,YACpBpvC,KAAKiO,KAAK8kG,QAAU,EACzBxvE,GAAK,EACLC,GAAK,GACE7vC,KAAKqM,KAAKiO,KAAKolG,eAAiBhzG,KAAKwC,IAAI09C,MAAkB,GAAVlgD,KAAKiV,IAAYo9F,YACpE1yG,KAAKiO,KAAK4kG,QAAU,OACpB7yG,KAAKiO,KAAK8kG,QAAU3jE,OACzB7L,GAAK,EACLC,GAAK,SAEAxjC,KAAKiO,KAAK4kG,QAAUzjE,YACpBpvC,KAAKiO,KAAK8kG,QAAU3jE,OACzB7L,GAAKhgC,EAAE5B,UAAU,GACjB6hC,GAAKjgC,EAAE5B,UAAU,SAGhBg9E,OAAOp7C,GAAIC,SAGXxjC,KAAKiO,KAAK4kG,QAAUD,QACpB5yG,KAAKiO,KAAK8kG,QAAUD,MA/Dd,KA2EnBS,qBAAsB,SAAUnsG,SACxBooC,WAEJpoC,IAAI+oG,sBACCgD,UAAY,OAEZH,SAAWlwE,SAAShqB,SAAS,CAAC1R,IAAIgiG,QAAQ,GAAG98F,QAASlF,IAAIgiG,QAAQ,GAAG78F,SAC1D,CAACnF,IAAIgiG,QAAQ,GAAG98F,QAASlF,IAAIgiG,QAAQ,GAAG78F,SAAU,QAC7D0mG,WAAa,CAAC,CAAC7rG,IAAIgiG,QAAQ,GAAG98F,QAASlF,IAAIgiG,QAAQ,GAAG78F,SACxC,CAACnF,IAAIgiG,QAAQ,GAAG98F,QAASlF,IAAIgiG,QAAQ,GAAG78F,eACtD2mG,kBAAoB,OAIzB1jE,IAAM77C,KAAK+4G,iBAAiBtlG,IAAK,QAC5B0lG,eAAet9D,IAAI,GAAIA,IAAI,SAE3Bs5D,KAAOn1G,KAAKw0G,iBACV,GAYXqH,sBAAuB,SAAUpoG,IAAKmhD,YAC9Bp7D,IAAMwG,KAAKqM,KAAKuoD,gBACfp7D,IAAI+zE,aAIH/zE,IAAIqmH,WAAapsG,IAAIqsG,WAAetmH,IAAIqmH,YAAcpsG,IAAIqsG,aAC1DtmH,IAAIumH,UAAYtsG,IAAIusG,UAAcxmH,IAAIumH,WAAatsG,IAAIusG,WAoBhEC,qBAAsB,SAASxsG,SACxBnZ,EAAG8R,IAAMpM,KAAK42G,eAAe/7G,WAE5BP,EAAI,EAAGA,EAAI8R,IAAK9R,OACb0F,KAAK42G,eAAet8G,GAAGqZ,YAAcF,IAAIE,iBAClC,SAGR,GAcVusG,sBAAuB,SAAUzsG,SAC1BnZ,EAAGsvG,UAEFtvG,EAAI,EAAGsvG,OAAQ,EAAOtvG,EAAI0F,KAAK42G,eAAe/7G,OAAQP,OACnD0F,KAAK42G,eAAet8G,GAAGqZ,YAAcF,IAAIE,UAAW,MAC/CijG,eAAet8G,GAAGqe,QAAUlF,IAAIkF,aAChCi+F,eAAet8G,GAAGse,QAAUnF,IAAImF,QACrCgxF,OAAQ,eAMXA,OAAS5pG,KAAK42G,eAAe/7G,OAAS,QAClC+7G,eAAel7G,KAAK,CACrBiY,UAAWF,IAAIE,UACfgF,QAASlF,IAAIkF,QACbC,QAASnF,IAAImF,UAId5Y,MAWXmgH,sBAAuB,SAAU1sG,SACzBnZ,MACCA,EAAI,EAAGA,EAAI0F,KAAK42G,eAAe/7G,OAAQP,OACpC0F,KAAK42G,eAAet8G,GAAGqZ,YAAcF,IAAIE,UAAW,MAC/CijG,eAAez7G,OAAOb,EAAG,gBAK/B0F,MASXogH,qBAAsB,WACdpgH,KAAK42G,eAAe/7G,OAAS,QACxBwlH,sBAEJz/D,cAAgB5gD,KAAKy0G,wBACrBU,KAAOn1G,KAAKq0G,qBACZuC,eAAiB,QACjBnB,QAAU,IAkBnB6K,uBAAwB,SAAS7sG,QACzBqhB,IAAI7gB,UAAW,IACS,UAApBR,IAAI8sG,aACHv/G,OAAOqU,UAAUmrG,kBACdx/G,OAAOqU,UAAUmrG,iBAAmB,QACjC,WAEa,UAApB/sG,IAAI8sG,kBACG,WAEa,QAApB9sG,IAAI8sG,kBACG,YAGR,SASX9C,oBAAqB,SAAUhqG,IAAKnV,YAC5BhE,EAAGC,EAAGiR,EAAGqwC,IAAKp8C,SAAUghH,IACxBC,WACA71G,KACA++F,MAAO/c,WAINvuF,QAAU0B,KAAKigH,qBAAqBxsG,YAC9B,MAGNnV,QAAUmV,IAAIO,gBAEVosG,uBAGJpgH,KAAK02G,eACF11G,OAAOqU,UAAUG,iBACjBsf,IAAIhd,SAAS9X,KAAKkB,SAAU,cAAiBlB,KAAKy+G,kBAAmBz+G,OAGrE80B,IAAIhd,SAAS9X,KAAKkB,SAAU,YAAiBlB,KAAKy+G,kBAAmBz+G,MACrE80B,IAAIhd,SAAS9X,KAAKkB,SAAU,gBAAiBlB,KAAKy+G,kBAAmBz+G,YAEpE02G,cAAe,GAGpB12G,KAAKq2G,uBACA2G,2BAGLh9G,KAAKs2G,uBACA2G,2BAILj9G,KAAKkB,SAASq0C,WAAajiC,KAAKnJ,WAAWnK,KAAKkB,SAASq0C,UAAUorE,YAC9Dz/G,SAASq0C,UAAUorE,aACrB,GAAI3/G,OAAO4/G,eACdH,IAAMz/G,OAAO4/G,gBACLC,oBAEAJ,IAAII,kBACN,MAAO5jH,YAKZ+iG,aAAehgG,KAAKsgH,uBAAuB7sG,KAChD5I,KAAO7K,KAAKggG,kBACPvzF,QAAQ8mE,UAAUyB,SAAWh1E,KAAKyM,QAAQ8mE,UAAU1oE,MAUzDgxC,IAAM77C,KAAK+4G,iBAAiBtlG,UAGvBqtG,kBAAkBrtG,KACnBzT,KAAK62G,0BACAkK,gBAAgBllE,eAChBx9B,qBAAqB,CAAC,sBAAuB,wBAAyB,kBAAmB,CAAC5K,SAI/FzT,KAAKqM,KAAKkkE,KAAKhD,SAAWjvE,QAC1BmB,SAAW,CAAEnB,aACR62G,KAAOn1G,KAAKs0G,iBAEjB70G,SAAWO,KAAKo5G,eAAev9D,IAAI,GAAIA,IAAI,GAAIpoC,IAAK5I,MAGxD61G,WAAa,CACT3xG,IAAK0E,IAAIE,UACTyqB,EAAGyd,IAAI,GACPxd,EAAGwd,IAAI,GACPs+D,MAAOxrG,IACPyrG,MAAOzrG,IACP+sG,OAAQ,GACRC,OAAQ,GACRF,OAAQ,IAIRh8G,SAAS5E,OAAS,EAAG,KAErBgyF,OAASptF,SAASA,SAAS5E,OAAS,GACpC+uG,OAAQ,EAIHtvG,EAAI,EAAGA,EAAI0F,KAAKy1G,QAAQ56G,OAAQP,OAG7B0F,KAAKy1G,QAAQn7G,GAAGd,MAAQqzF,OAAQ,CAChCtyF,EAAID,EACJkR,EAAIxL,KAAKy1G,QAAQn7G,GAAG4/G,QAAQx+G,KAAKglH,YAAc,EAC/C9W,OAAQ,QAIXA,QAEDp+F,EAAI,EACJjR,EAAIyF,KAAKy1G,QAAQ/5G,KAAK,CAClBlC,IAAKqzF,OACLqtB,QAAS,CAACwG,cACT,QAGJL,iBACLxzB,OAAO3Z,WAAU,QAEZqoC,aAAa1uB,OAAQ7sF,KAAKy1G,QAAQl7G,GAAG2/G,QAAQ1uG,IAK9CiI,KAAOA,IAAI+oG,eACX/oG,IAAI+oG,iBACGx7G,OAAOyX,QACdzX,OAAOyX,MAAMuoG,aAAc,UAI/BhhH,KAAKy1G,QAAQ56G,OAAS,IACtB4Y,IAAI+oG,iBACJ/oG,IAAIo2E,qBAGH/0D,IAAI7gB,YAGgC,UAArCjU,KAAKsgH,uBAAuB7sG,KACxBzT,KAAKm1G,OAASn1G,KAAKq0G,sBACduH,qBAAqBnoG,WAGzBysG,sBAAsBzsG,KAC3BA,IAAIgiG,QAAUz1G,KAAK42G,eAIQ,IAAvBnjG,IAAIgiG,QAAQ56G,QACZmF,KAAKm1G,OAASn1G,KAAKq0G,iBACnBr0G,KAAKg8G,8BAA8BvoG,MAEL,IAAvBA,IAAIgiG,QAAQ56G,QACVmF,KAAKm1G,OAASn1G,KAAKq0G,iBAAmBr0G,KAAKm1G,OAASn1G,KAAKu0G,yBAK9Dv0G,KAAKm1G,OAASn1G,KAAKu0G,6BACd4H,qBAGJyD,qBAAqBnsG,YAI7B4K,qBAAqB,CAAC,aAAc,OAAQ,cAAe,iBAAkB,CAAC5K,OAC5E,IAuBXiqG,oBAAqB,SAAUjqG,SACvBnZ,EAAGC,EAAGshD,IAAKolE,aACXp2G,QAEqC,UAArC7K,KAAKsgH,uBAAuB7sG,OAAqBzT,KAAKigH,qBAAqBxsG,YAIpEzT,KAAKq0G,oBAGXr0G,KAAKk4G,eAAezkG,YACd,KAGPzT,KAAKm1G,OAASn1G,KAAKs0G,uBACd+L,sBACApG,gBAAe,IAGpBj6G,KAAKm1G,OAASn1G,KAAKq0G,kBACnB5gG,IAAI+oG,iBACJ/oG,IAAIo2E,wBAGHjpC,cAAgB5gD,KAAK6gD,uBAErBm/C,aAAehgG,KAAKsgH,uBAAuB7sG,KAChD5I,KAAO7K,KAAKggG,kBACPvzF,QAAQ8mE,UAAUyB,SAAWh1E,KAAKyM,QAAQ8mE,UAAU1oE,MAGrD7K,KAAK62G,cACLh7D,IAAM77C,KAAK+4G,iBAAiBtlG,UACvBytG,eAAerlE,UACfx9B,qBAAqB,CAAC,qBAAsB,gBAAiB,wBAAyB,CAAC5K,IAAKzT,KAAKm1G,YACnG,IAAKn1G,KAAK87G,gBAAgBroG,QACzBzT,KAAKm1G,OAASn1G,KAAKs0G,qBAEdh6G,EAAI,EAAGA,EAAI0F,KAAKy1G,QAAQ56G,OAAQP,QACjC2mH,aAAejhH,KAAKy1G,QAAQn7G,GAAG4/G,QAE1B3/G,EAAI,EAAGA,EAAI0mH,aAAapmH,OAAQN,OAC7B0mH,aAAa1mH,GAAGwU,MAAQ0E,IAAIE,UAAW,CAEvCkoC,IAAM77C,KAAK+4G,iBAAiBtlG,KAC5BwtG,aAAa1mH,GAAG6jC,EAAIyd,IAAI,GACxBolE,aAAa1mH,GAAG8jC,EAAIwd,IAAI,GAEI,IAAxBolE,aAAapmH,YAERg/G,WAAWh+D,IAAI,GAAIA,IAAI,GAAI77C,KAAKy1G,QAAQn7G,GAAImZ,IAAK5I,MACvB,IAAxBo2G,aAAapmH,cAEfy/G,cAAct6G,KAAKy1G,QAAQn7G,GAAImZ,IAAIE,UAAWF,KAEnDwtG,aAAa1mH,GAAG4/G,MAAQt+D,IAAI,GAC5BolE,aAAa1mH,GAAG6/G,MAAQv+D,IAAI,eASH,UAArC77C,KAAKsgH,uBAAuB7sG,YACvBysG,sBAAsBzsG,KAEQ,IAA/BzT,KAAK42G,eAAe/7G,SACpB4Y,IAAIgiG,QAAUz1G,KAAK42G,oBACdgI,sBAAsBnrG,OAKnCooC,IAAM77C,KAAK+4G,iBAAiBtlG,UACvB2nG,kBAAkBv/D,IAAI,GAAIA,IAAI,GAAIpoC,KAAM,eAShD4K,qBAAqB,CAAC,YAAa,OAAQ,cAAe,iBAAkB,CAAC5K,IAAKzT,KAAKm1G,YACvFv0D,cAAgB5gD,KAAKy0G,mBAEnBz0G,KAAKm1G,OAASn1G,KAAKq0G,iBAQ9BoK,kBAAmB,SAAUhrG,SACrBnZ,EAAGC,EAAGqvG,MAAOqX,qBAEZ5iG,qBAAqB,CAAC,WAAY,KAAM,YAAa,eAAgB,CAAC5K,WACtEwmG,gBAAe,GAEhBxmG,QACKnZ,EAAI,EAAGA,EAAI0F,KAAKy1G,QAAQ56G,OAAQP,QACjC2mH,aAAejhH,KAAKy1G,QAAQn7G,GAAG4/G,QAC1B3/G,EAAI,EAAGA,EAAI0mH,aAAapmH,OAAQN,OAC7B0mH,aAAa1mH,GAAGwU,MAAQ0E,IAAIE,UAAW,CACvCstG,aAAa9lH,OAAOZ,EAAG,GACK,IAAxB0mH,aAAapmH,aACR46G,QAAQt6G,OAAOb,EAAG,iBAQtC6hH,qBACA3hF,SAGDx6B,KAAK62G,mBACAsK,eAAe1tG,UACf4K,qBAAqB,CAAC,qBAAsB,uBAAwB,iBAAkB,CAAC5K,WACvF2tG,6BAEA9mH,EAAI0F,KAAK81G,YAAYj7G,OAAS,EAAGP,GAAK,EAAGA,IAAK,KAC/CsvG,OAAQ,EACHrvG,EAAI,EAAGA,EAAIyF,KAAKy1G,QAAQ56G,OAAQN,IAC7ByF,KAAKy1G,QAAQl7G,GAAGf,IAAI2D,KAAO6C,KAAK81G,YAAYx7G,GAAG6C,KAC/CysG,OAAQ,GAGXA,aACIkM,YAAYx7G,GAAG+jB,qBAAqB,CAAC,WAAY,KAAM,YAAa,eAAgB,CAAC5K,WAGrFqiG,YAAY36G,OAAOb,EAAG,WAKnC0F,KAAK02G,eACD11G,OAAOqU,UAAUG,iBACjBsf,IAAI7c,YAAYjY,KAAKkB,SAAU,cAAiBlB,KAAKy+G,kBAAmBz+G,OAExE80B,IAAI7c,YAAYjY,KAAKkB,SAAU,YAAiBlB,KAAKy+G,kBAAmBz+G,MACxE80B,IAAI7c,YAAYjY,KAAKkB,SAAU,gBAAiBlB,KAAKy+G,kBAAmBz+G,YAEvE02G,cAAe,QAWnB0J,wBACE,GAYXpC,mBAAoB,SAAUvqG,SACtBnZ,EAAGuhD,IAAKp8C,SAAUlF,EAAGiR,EAErBhS,IAAKowG,MAAOsQ,QAEZrtB,OAAQo0B,aAHRxiG,IAAMze,KAAKyM,QAAQ8mE,UAAUoB,MAE7Br8D,WAAa7E,IAAIrV,IAAImV,mBAGpBvT,KAAKy2G,cACN3hF,IAAIhd,SAAS9X,KAAKkB,SAAU,WAAYlB,KAAK2+G,iBAAkB3+G,WAC1Dy2G,aAAc,GAOnBz2G,KAAKkB,SAASq0C,WAAajiC,KAAKnJ,WAAWnK,KAAKkB,SAASq0C,UAAUorE,YAC9Dz/G,SAASq0C,UAAUorE,QACjB3/G,OAAO4/G,cACd5/G,OAAO4/G,eAAeC,uBAIrB7gB,aAAe,aACfvzF,QAAQ8mE,UAAUyB,SAAWh1E,KAAKyM,QAAQ8mE,UAAUoB,MAwBpDr6E,EAAI,EAAGA,EAAIge,WAAWzd,OAAQP,IAC/Bge,WAAWhe,GAAG+mH,YAAa,MAG1B/mH,EAAI,EAAGA,EAAI0F,KAAKy1G,QAAQ56G,OAAQP,QACjC2mH,aAAejhH,KAAKy1G,QAAQn7G,GAAG4/G,QAC1B3/G,EAAI,EAAGA,EAAI0mH,aAAapmH,OAAQN,IAAK,CACtC0mH,aAAa1mH,GAAGwU,KAAO,EACvB0P,IAAMze,KAAKyM,QAAQ8mE,UAAUoB,QAE1B,KACMnpE,EAAI,EAAGA,EAAI8M,WAAWzd,OAAQ2Q,OAE3BkB,KAAKwC,IAAIxC,KAAKsV,IAAI1J,WAAW9M,GAAG81G,QAAUL,aAAa1mH,GAAG6jC,EAAG,GACzD1xB,KAAKsV,IAAI1J,WAAW9M,GAAG+1G,QAAUN,aAAa1mH,GAAG8jC,EAAG,IAAM5f,IAAMA,IAAK,CACzEwiG,aAAa1mH,GAAGwU,IAAMvD,EACtBy1G,aAAa1mH,GAAG6jC,EAAI9lB,WAAW9M,GAAG81G,QAClCL,aAAa1mH,GAAG8jC,EAAI/lB,WAAW9M,GAAG+1G,QAClCjpG,WAAW9M,GAAG61G,YAAa,QAKnC5iG,KAAO,SAEuB,IAAzBwiG,aAAa1mH,GAAGwU,KAChB0P,IAAMze,KAAKyM,QAAQ8mE,UAAUqB,WAET,IAAzBqsC,aAAa1mH,GAAGwU,MAChB3Q,IAAIsD,MAAM,iDAAoDnH,EAAI,OAASyF,KAAKy1G,QAAQn7G,GAAGd,IAAII,KAAO,KAAOoG,KAAKy1G,QAAQn7G,GAAGd,IAAI2D,GAAK,0BACtIiB,IAAIsD,MAAM,SAAW+c,IAAM,gBAAkBqtD,QAAQyH,UAAUqB,UAC/DqsC,aAAa9lH,OAAOb,EAAG,QAQ9BA,EAAI,EAAGA,EAAIge,WAAWzd,OAAQP,QAC1Bge,WAAWhe,GAAG+mH,WAAY,IAE3BxlE,IAAM77C,KAAK+4G,iBAAiBtlG,IAAKnZ,GAG7B0F,KAAK62G,0BACAkK,gBAAgBllE,UAChBx9B,qBAAqB,CAAC,sBAAuB,kBAAmB,CAAC5K,MACtEA,IAAI+oG,iBACJ/oG,IAAIo2E,uBACCp9E,QAAQ8mE,UAAUyB,SAAWh1E,KAAKyM,QAAQ8mE,UAAUsB,MAClD70E,KAAKy1G,QAAQ56G,OAAS,KAIT,KADxB4E,SAAWO,KAAKo5G,eAAev9D,IAAI,GAAIA,IAAI,GAAIpoC,IAAK,UACvC5Y,UACTrB,IAAMiG,SAASA,SAAS5E,OAAS,GACjCgyF,OAAS,CAAC99E,IAAKzU,EACX8jC,EAAG9lB,WAAWhe,GAAGgnH,QACjBjjF,EAAG/lB,WAAWhe,GAAGinH,QACjBpH,MAAOxrG,IACPyrG,MAAOzrG,IACP+sG,OAAQ,GACRC,OAAQ,GACRF,OAAQ,IAGRnoG,KAAK9I,QAAQhR,MACTA,IAAIiR,eAAiBjB,MAAMlF,mBAC3B9K,IAAIqR,OAASrB,MAAMpH,mBACnB5I,IAAIqR,OAASrB,MAAM/G,kBAEvBy3G,QAAU,CAACrtB,aAGN0uB,aAAa/hH,IAAK0gH,QAAQ,SAE1BzE,QAAQ/5G,KAAK,CAAElC,IAAKA,IAAK0gH,QAASA,UACvC1gH,IAAI05E,WAAU,QAEX,GAAI15E,IAAIiR,eAAiBjB,MAAMvF,mBAC9BzK,IAAIiR,eAAiBjB,MAAMtF,qBAC3B1K,IAAIiR,eAAiBjB,MAAMrF,oBAC3B3K,IAAIqR,OAASrB,MAAMzG,oBAAqB,KAC5C6mG,OAAQ,EAGHrvG,EAAI,EAAGA,EAAIyF,KAAKy1G,QAAQ56G,OAAQN,IAC7Bf,IAAI2D,KAAO6C,KAAKy1G,QAAQl7G,GAAGf,IAAI2D,KAC/BysG,OAAQ,EAE+B,IAAnC5pG,KAAKy1G,QAAQl7G,GAAG2/G,QAAQr/G,cAEnB0gH,aAAa/hH,IAAKqzF,aAClB4oB,QAAQl7G,GAAG2/G,QAAQx+G,KAAKmxF,SAGjCv0E,WAAWhe,GAAG+mH,YAAa,GAO9BzX,QACDsQ,QAAU,CAACrtB,aAGN0uB,aAAa/hH,IAAK0gH,QAAQ,SAC1BzE,QAAQ/5G,KAAK,CAAElC,IAAKA,IAAK0gH,QAASA,UACvC1gH,IAAI05E,WAAU,IAK1B56D,WAAWhe,GAAG+mH,YAAa,SAI/BrhH,KAAKy1G,QAAQ56G,OAAS,IACtB4Y,IAAI+oG,iBACJ/oG,IAAIo2E,mBAKkB,IAAtBvxE,WAAWzd,QAAgBmF,KAAKm1G,OAASn1G,KAAKq0G,iBAAmBr0G,KAAKg8G,8BAA8BvoG,MACvE,IAAtB6E,WAAWzd,QACTmF,KAAKm1G,OAASn1G,KAAKq0G,iBAAmBr0G,KAAKm1G,OAASn1G,KAAKu0G,yBAK9Dv0G,KAAKm1G,OAASn1G,KAAKu0G,6BACd4H,qBAEJyD,qBAAqBnsG,WAGzBhH,QAAQ8mE,UAAUyB,SAAWh1E,KAAKyM,QAAQ8mE,UAAUsB,WACpDx2D,qBAAqB,CAAC,aAAc,QAAS,CAAC5K,OAE5C,GASXwqG,kBAAmB,SAAUxqG,SACrBnZ,EAAGknH,KAAMC,KACTR,aACA3oG,WAAa7E,IAAIrV,IAAImV,mBAEpBvT,KAAKk4G,eAAezkG,YACd,KAGPzT,KAAKm1G,OAASn1G,KAAKq0G,kBACnB5gG,IAAI+oG,iBACJ/oG,IAAIo2E,mBAGJ7pF,KAAKm1G,OAASn1G,KAAKs0G,uBACd+L,sBACApG,gBAAe,SAGnBja,aAAe,aACfvzF,QAAQ8mE,UAAUyB,SAAWh1E,KAAKyM,QAAQ8mE,UAAUoB,WACpD/zB,cAAgB5gD,KAAK6gD,kBAGtB7gD,KAAK62G,mBACAv8G,EAAI,EAAGA,EAAIge,WAAWzd,OAAQP,QAC1Bge,WAAWhe,GAAG+mH,WAAY,CAC3BG,KAAOxhH,KAAK+4G,iBAAiBtlG,IAAKnZ,QAC7B4mH,eAAeM,WACfnjG,qBAAqB,CAAC,aAAc,iBAAkB,CAAC5K,IAAKzT,KAAKm1G,uBAKzEn1G,KAAKk8G,gBAAgBzoG,QAClBzT,KAAKm1G,OAASn1G,KAAKs0G,qBAGdh6G,EAAI,EAAGA,EAAI0F,KAAKy1G,QAAQ56G,OAAQP,OAEL,KAD5B2mH,aAAejhH,KAAKy1G,QAAQn7G,GAAG4/G,SACdr/G,WAITyd,WAAW2oG,aAAa,GAAGlyG,KAAM,KACjCyyG,KAAOxhH,KAAK+4G,iBAAiBtlG,IAAKwtG,aAAa,GAAGlyG,MACzC,GAAK,GAAKyyG,KAAK,GAAKxhH,KAAK8yC,aAC9B0uE,KAAK,GAAK,GAAKA,KAAK,GAAKxhH,KAAK+yC,oBAGlCkuE,aAAa,GAAG7iF,EAAIojF,KAAK,GACzBP,aAAa,GAAG5iF,EAAImjF,KAAK,QACpB3H,WAAW2H,KAAK,GAAIA,KAAK,GAAIxhH,KAAKy1G,QAAQn7G,GAAImZ,IAAK,eAGzD,GAA4B,IAAxBwtG,aAAapmH,QACpBomH,aAAa,GAAGlyG,KAAO,GACvBkyG,aAAa,GAAGlyG,KAAO,GAGnBuJ,WAAW2oG,aAAa,GAAGlyG,MAC3BuJ,WAAW2oG,aAAa,GAAGlyG,KAAM,IAGjCyyG,KAAOxhH,KAAK+4G,iBAAiBtlG,IAAKwtG,aAAa,GAAGlyG,KAClD0yG,KAAOzhH,KAAK+4G,iBAAiBtlG,IAAKwtG,aAAa,GAAGlyG,KAC9CyyG,KAAK,GAAK,GAAKA,KAAK,GAAKxhH,KAAK8yC,aAC9B0uE,KAAK,GAAK,GAAKA,KAAK,GAAKxhH,KAAK+yC,cAC9B0uE,KAAK,GAAK,GAAKA,KAAK,GAAKzhH,KAAK8yC,aAC9B2uE,KAAK,GAAK,GAAKA,KAAK,GAAKzhH,KAAK+yC,oBAIlCkuE,aAAa,GAAG7iF,EAAIojF,KAAK,GACzBP,aAAa,GAAG5iF,EAAImjF,KAAK,GACzBP,aAAa,GAAG7iF,EAAIqjF,KAAK,GACzBR,aAAa,GAAG5iF,EAAIojF,KAAK,QAEpBnH,cAAct6G,KAAKy1G,QAAQn7G,GAAI2mH,aAAa,GAAGlyG,IAAK0E,UACpD6mG,cAAct6G,KAAKy1G,QAAQn7G,GAAI2mH,aAAa,GAAGlyG,KAEpDkyG,aAAa,GAAG9G,MAAQqH,KAAK,GAC7BP,aAAa,GAAG7G,MAAQoH,KAAK,GAC7BP,aAAa,GAAG9G,MAAQsH,KAAK,GAC7BR,aAAa,GAAG7G,MAAQqH,KAAK,SAKf,IAAtBnpG,WAAWzd,aACN+jH,sBAAsBnrG,KAG/B+tG,KAAOxhH,KAAK+4G,iBAAiBtlG,IAAK,QAC7B2nG,kBAAkBoG,KAAK,GAAIA,KAAK,GAAI/tG,KAAM,UAKvDzT,KAAKm1G,OAASn1G,KAAKs0G,sBACd2F,gBAAe,QAGnB57F,qBAAqB,CAAC,YAAa,QAAS,CAAC5K,IAAKzT,KAAKm1G,YACvD1oG,QAAQ8mE,UAAUyB,SAAWh1E,KAAKyM,QAAQ8mE,UAAUsB,WACpDj0B,cAAgB5gD,KAAKy0G,mBAEnBz0G,KAAKm1G,OAASn1G,KAAKq0G,iBAQ9BsK,iBAAkB,SAAUlrG,SACpBnZ,EAAGC,EAAGiR,EAEWo+F,MAAO8X,YAExBT,aAHAxiG,IAAMze,KAAKyM,QAAQ8mE,UAAUoB,MAC7BgtC,WAAa,GACbrpG,WAAa7E,KAAOA,IAAIrV,IAAImV,uBAG3B8K,qBAAqB,CAAC,WAAY,MAAO,CAAC5K,WAC1CwmG,gBAAe,GAGhBj6G,KAAK62G,mBACAsK,eAAe1tG,UACf4K,qBAAqB,CAAC,qBAAsB,iBAAkB,CAAC5K,WAC/D2tG,yBACF,GAAI9oG,YAAcA,WAAWzd,OAAS,EAAG,KACvCP,EAAI,EAAGA,EAAI0F,KAAKy1G,QAAQ56G,OAAQP,IACjCqnH,WAAWrnH,GAAK0F,KAAKy1G,QAAQn7G,YAE5Bm7G,QAAQ56G,OAAS,EAejBP,EAAI,EAAGA,EAAIge,WAAWzd,OAAQP,IAC/Bge,WAAWhe,GAAG+mH,YAAa,MAG1B/mH,EAAI,EAAGA,EAAIqnH,WAAW9mH,OAAQP,IAAK,KAEpCsvG,OAAQ,EACR8X,YAAc,EACdT,aAAeU,WAAWrnH,GAAG4/G,QAExB3/G,EAAI,EAAGA,EAAI0mH,aAAapmH,OAAQN,QACjC0mH,aAAa1mH,GAAGqvG,OAAQ,EACnBp+F,EAAI,EAAGA,EAAI8M,WAAWzd,OAAQ2Q,OAC3BkB,KAAKwC,IAAIxC,KAAKsV,IAAI1J,WAAW9M,GAAG81G,QAAUL,aAAa1mH,GAAG6jC,EAAG,GAAK1xB,KAAKsV,IAAI1J,WAAW9M,GAAG+1G,QAAUN,aAAa1mH,GAAG8jC,EAAG,IAAM5f,IAAMA,IAAK,CACvIwiG,aAAa1mH,GAAGqvG,OAAQ,EACxBqX,aAAa1mH,GAAGwU,IAAMvD,EACtBy1G,aAAa1mH,GAAG6jC,EAAI9lB,WAAW9M,GAAG81G,QAClCL,aAAa1mH,GAAG8jC,EAAI/lB,WAAW9M,GAAG+1G,QAClCG,aAAe,WAMvBpuG,KAAK9I,QAAQm3G,WAAWrnH,GAAGd,KAC3BowG,MAASqX,aAAa,IAAMA,aAAa,GAAGrX,MACrC+X,WAAWrnH,GAAGd,IAAIiR,eAAiBjB,MAAMvF,kBAChD2lG,MAASqX,aAAa,IAAMA,aAAa,GAAGrX,OAAWqX,aAAa,IAAMA,aAAa,GAAGrX,MACnF+X,WAAWrnH,GAAGd,IAAIiR,eAAiBjB,MAAMtF,sBAChD0lG,MAAwB,IAAhB8X,aAAqC,IAAhBA,aAI7B9X,eACK6L,QAAQ/5G,KAAK,CACdlC,IAAKmoH,WAAWrnH,GAAGd,IACnB0gH,QAAS,KAGR3/G,EAAI,EAAGA,EAAI0mH,aAAapmH,OAAQN,IAC7B0mH,aAAa1mH,GAAGqvG,YACX6L,QAAQz1G,KAAKy1G,QAAQ56G,OAAS,GAAGq/G,QAAQx+G,KAAK,CAC/CqT,IAAKkyG,aAAa1mH,GAAGwU,IACrBqvB,EAAG6iF,aAAa1mH,GAAG+mH,QACnBjjF,EAAG4iF,aAAa1mH,GAAGgnH,QACnBpH,MAAOxrG,IACPyrG,MAAOzrG,IACP+sG,OAAQuF,aAAa1mH,GAAGmhH,OACxBC,OAAQsF,aAAa1mH,GAAGohH,OACxBF,OAAQwF,aAAa1mH,GAAGkhH,cAMpCkG,WAAWrnH,GAAGd,IAAIgwF,yBAKrBisB,QAAQ56G,OAAS,MAGrBP,EAAI0F,KAAK81G,YAAYj7G,OAAS,EAAGP,GAAK,EAAGA,IAAK,KAC/CsvG,OAAQ,EACHrvG,EAAI,EAAGA,EAAIyF,KAAKy1G,QAAQ56G,OAAQN,IAC7ByF,KAAKy1G,QAAQl7G,GAAGf,IAAI2D,KAAO6C,KAAK81G,YAAYx7G,GAAG6C,KAC/CysG,OAAQ,GAGXA,aACIkM,YAAYx7G,GAAG+jB,qBAAqB,CAAC,UAAW,MAAO,CAAC5K,WAGxDqiG,YAAY36G,OAAOb,EAAG,WAI9Bge,YAAoC,IAAtBA,WAAWzd,SAEtBmF,KAAKy2G,cACL3hF,IAAI7c,YAAYjY,KAAKkB,SAAU,WAAYlB,KAAK2+G,iBAAkB3+G,WAC7Dy2G,aAAc,QAGlB4J,sBACAz/D,cAAgB5gD,KAAKy0G,wBAErB0H,qBACA3hF,WAGF,GAQXqjF,kBAAmB,SAAUpqG,SACrBooC,IAAKp8C,SAAUsL,UAGf/K,KAAKkB,SAASq0C,WAAajiC,KAAKnJ,WAAWnK,KAAKkB,SAASq0C,UAAUorE,YAC9Dz/G,SAASq0C,UAAUorE,QACjB3/G,OAAO4/G,cACd5/G,OAAO4/G,eAAeC,mBAGrB7gH,KAAKw2G,kBACN1hF,IAAIhd,SAAS9X,KAAKkB,SAAU,UAAWlB,KAAK0+G,gBAAiB1+G,WACxDw2G,YAAa,OAQjBxW,aAAe,aACfvzF,QAAQ8mE,UAAUyB,SAAWh1E,KAAKyM,QAAQ8mE,UAAUsB,MACzDh5B,IAAM77C,KAAK+4G,iBAAiBtlG,UAGvBqtG,kBAAkBrtG,KACnBzT,KAAK62G,oBACAkK,gBAAgBllE,eAChBx9B,qBAAqB,CAAC,sBAAuB,kBAAmB,CAAC5K,QAOlD,KAHxBhU,SAAWO,KAAKo5G,eAAev9D,IAAI,GAAIA,IAAI,GAAIpoC,IAAK,UAGvC5Y,aACJs6G,KAAOn1G,KAAKq0G,gBACjBtpG,QAAS,SAGJ8pE,MAAQ,CACTr7E,IAAK,KACL0gH,QAAS,CAAC,CACN97E,EAAGyd,IAAI,GACPxd,EAAGwd,IAAI,GACPs+D,MAAOxrG,IACPyrG,MAAOzrG,YAGVkmE,MAAMr7E,IAAMiG,SAASA,SAAS5E,OAAS,QAEvCwlH,sBACAxrC,MAAMr7E,IAAI05E,WAAU,QAEpB2B,MAAMqlC,QAAQ,GAAGwB,OAAS,QAC1B7mC,MAAMqlC,QAAQ,GAAGyB,OAAS,QAC1B9mC,MAAMqlC,QAAQ,GAAGuB,OAAS,QAE1BF,aAAav7G,KAAK60E,MAAMr7E,IAAKwG,KAAK60E,MAAMqlC,QAAQ,IAKjDzmG,KAAOA,IAAI+oG,eACX/oG,IAAI+oG,iBACGx7G,OAAOyX,QACdzX,OAAOyX,MAAMuoG,aAAc,IAI/BhhH,KAAKm1G,OAASn1G,KAAKq0G,kBACnBtpG,OAAS/K,KAAK47G,qBAAqBnoG,WAGlC4K,qBAAqB,CAAC,YAAa,QAAS,CAAC5K,MAE3C1I,SAOX+yG,kBAAmB,SAAUrqG,SACrBooC,QAEC77C,KAAKk4G,eAAezkG,YACd,EAGXooC,IAAM77C,KAAK+4G,iBAAiBtlG,UAEvBmtC,cAAgB5gD,KAAK6gD,kBAEtB7gD,KAAKm1G,OAASn1G,KAAKs0G,uBACd+L,sBACApG,gBAAe,IAWpBj6G,KAAK62G,oBACAqK,eAAerlE,UACfx9B,qBAAqB,CAAC,qBAAsB,iBAAkB,CAAC5K,IAAKzT,KAAKm1G,QACtEn1G,KAAK87G,gBAAgBroG,OACzBzT,KAAKm1G,OAASn1G,KAAKs0G,qBACduF,WAAWh+D,IAAI,GAAIA,IAAI,GAAI77C,KAAK60E,MAAOphE,IAAK,cAG5C2nG,kBAAkBv/D,IAAI,GAAIA,IAAI,GAAIpoC,KAAM,QAE5C4K,qBAAqB,CAAC,YAAa,QAAS,CAAC5K,IAAKzT,KAAKm1G,aAE3Dv0D,cAAgB5gD,KAAKy0G,oBAO9BiK,gBAAiB,SAAUjrG,SACnBnZ,MAEuB,IAAvB0F,KAAK62G,oBACAx4F,qBAAqB,CAAC,UAAW,MAAO,CAAC5K,WAI7CmtC,cAAgB5gD,KAAKy0G,wBAQrB0H,qBACAkE,sBACA7lF,SAGDx6B,KAAK62G,mBACAsK,eAAe1tG,UACf4K,qBAAqB,CAAC,qBAAsB,iBAAkB,CAAC5K,WAC/D2tG,6BAEA9mH,EAAI,EAAGA,EAAI0F,KAAK81G,YAAYj7G,OAAQP,SAChCw7G,YAAYx7G,GAAG+jB,qBAAqB,CAAC,UAAW,MAAO,CAAC5K,WAIhEqiG,YAAYj7G,OAAS,EAEtBmF,KAAKw2G,aACL1hF,IAAI7c,YAAYjY,KAAKkB,SAAU,UAAWlB,KAAK0+G,gBAAiB1+G,WAC3Dw2G,YAAa,QAKjB3hC,MAAQ,MAQjB8oC,mBAAoB,SAAUlqG,SACrBzT,KAAKqM,KAAKiO,KAAK01D,QAAUhwE,KAAK67G,sBAAsBpoG,IAAK,eACnD,MAIPmuG,IADJnuG,IAAMA,KAAOzS,OAAOyX,OACPopG,QAAUpuG,IAAIouG,OAASpuG,IAAIquG,WAAa,GACjDjmE,IAAM,IAAI13B,OAAO3a,MAAMzH,iBAAkB/B,KAAK+4G,iBAAiBtlG,KAAMzT,aAErE4hH,GAAK,OACA52B,OAAOnvC,IAAI7tC,UAAU,GAAI6tC,IAAI7tC,UAAU,SAEvC88E,QAAQjvC,IAAI7tC,UAAU,GAAI6tC,IAAI7tC,UAAU,SAG5CqQ,qBAAqB,CAAC,cAAe,CAAC5K,MAE3CA,IAAI+oG,kBACG,GAiBX8B,gBAAiB,SAAU7qG,SAEnBtW,GAAIkR,GAAIoR,IASRu3D,IAAK+qC,OAVLC,QAAUvuG,IAAIo5E,OAAO1vF,GAErBy5F,GAAK,EACLC,GAAK,EAGL/3D,GAAKxrB,KAAKrG,SAASjN,KAAKqM,KAAKmkE,SAAS1xC,IAAM9+B,KAAK+kB,MACjDgc,GAAKztB,KAAKrG,SAASjN,KAAKqM,KAAKmkE,SAASzvC,IAAM/gC,KAAKglB,MACjDi9F,QAAS,EACT7oD,MAAO,WAGNp5D,KAAKqM,KAAKmkE,SAASjD,SAAuB,KAAZy0C,WAKnC7kH,GAAK6kH,QAAQhnH,QAAQgF,KAAKomF,aAAajpF,GAAK,IAAK,IACjDkR,GAAKrO,KAAKO,OAAOpD,IAEbmW,KAAKzU,OAAOwP,GAAGR,UACfk0G,OAAS1zG,GAAGR,OAAOG,UAAU3U,MAAM,KAGnCia,KAAKrG,SAASjN,KAAKqM,KAAKmkE,SAAS0xC,WAAa5uG,KAAKrG,SAASjN,KAAKqM,KAAKmkE,SAAS2xC,YAC/EF,QAAS,GAGR3uG,KAAKrG,SAASjN,KAAKqM,KAAKmkE,SAAS0xC,WAAazuG,IAAIqsG,UAClDxsG,KAAKrG,SAASjN,KAAKqM,KAAKmkE,SAAS2xC,UAAY1uG,IAAIusG,QAC9B,KAAhBvsG,IAAI2uG,aACCl3B,eACkB,KAAhBz3E,IAAI2uG,aACNj3B,iBACkB,KAAhB13E,IAAI2uG,aACNn3B,iBACkB,KAAhBx3E,IAAI2uG,aACNh3B,kBAELhyB,MAAO,GAKP9lD,KAAKzU,OAAOwP,GAAG0E,WACXO,KAAKzU,OAAOwP,GAAG0E,QAAQ4kF,aACvBtpF,GAAG0E,QAAQ4kF,YACXrkF,KAAKrG,SAASoB,GAAG0E,QAAQ+jF,YACzBxjF,KAAKrG,SAASoB,GAAG0E,QAAQgkF,YAIzBH,IADAn3E,IAAMpR,GAAGsoF,gBACA,GACTE,GAAKp3E,IAAI,GACTqf,GAAKpyB,KAAKiS,IAAIi4E,GAAI93D,IAClBiC,GAAKr0B,KAAKiS,IAAIk4E,GAAI91D,KAEXztB,KAAKzU,OAAOwP,GAAG0E,QAAQukF,gBAC9BjpF,GAAG0E,QAAQukF,eACXhkF,KAAKrG,SAASoB,GAAG0E,QAAQ2kF,oBACzBpkF,KAAKrG,SAASoB,GAAG0E,QAAQykF,iBAIzBX,GADAD,GAAK,IAAMtjF,KAAKrG,SAASoB,GAAG0E,QAAQ2kF,mBAGY,WAA5CpkF,KAAKrG,SAASoB,GAAG0E,QAAQykF,iBACzBZ,IAAM52F,KAAK+kB,MACX8xE,IAAM72F,KAAK+kB,OAEf+Z,GAAKpyB,KAAKiS,IAAIi4E,GAAI93D,IAClBiC,GAAKr0B,KAAKiS,IAAIk4E,GAAI91D,MAKN,KAAhBttB,IAAI2uG,QACJprC,IAAM,CAAC,EAAGj2C,IACa,KAAhBttB,IAAI2uG,QACXprC,IAAM,CAAC,GAAIj2C,IACY,KAAhBttB,IAAI2uG,QACXprC,IAAM,EAAEl4C,GAAI,GACW,KAAhBrrB,IAAI2uG,QACXprC,IAAM,CAACl4C,GAAI,GAGJmjF,QAAsB,MAAZxuG,IAAIlD,SAChBy6E,SACEi3B,QAAsB,MAAZxuG,IAAIlD,SAChBu6E,UACEm3B,QAAsB,MAAZxuG,IAAIlD,SAChBw6E,UAEL3xB,MAAO,EAGP4d,KAAO3oE,GAAG6gF,aACN7gF,GAAGmzE,YAAYvvE,UACbjS,KAAKm2G,2BACF7iG,KAAK9I,QAAQ6D,KACdA,GAAG5D,eAAiBjB,MAAMlF,qBACxBtE,KAAKm2G,4BACV7iG,KAAKrG,SAASoB,GAAG0E,QAAQ4/D,SAG1Br/D,KAAKzU,OAAOwP,GAAGR,UACfmpE,IAAI,IAAM+qC,OAAO,GACjB/qC,IAAI,IAAM+qC,OAAO,IAIrB1zG,GAAGojF,YAAYrzF,IAAI0D,eAAgBk1E,KAC/B1jE,KAAKzU,OAAOwP,GAAGR,cACVwsG,cAAchsG,SAElBgQ,qBAAqB,CAAC,OAAQ,CAAC5K,IAAKpF,YAI5CmsB,SAED4+B,MAAQ9lD,KAAKzU,OAAO4U,IAAI+oG,iBACxB/oG,IAAI+oG,kBAED,IAaX+B,mBAAoB,SAAU9qG,SAEtBtW,GAAIkR,GADJ2zG,QAAUvuG,IAAIo5E,OAAO1vF,OAGpB6C,KAAKqM,KAAKmkE,SAASjD,SAAuB,KAAZy0C,eACxB,EAGX7kH,GAAK6kH,QAAQhnH,QAAQgF,KAAKomF,aAAajpF,GAAK,IAAK,IACjDkR,GAAKrO,KAAKO,OAAOpD,IACbmW,KAAKzU,OAAOwP,GAAG6kE,YACf7kE,GAAG6kE,WAAU,GAEb5/D,KAAKzU,OAAOwP,GAAGR,cACVwsG,cAAchsG,SAElBgQ,qBAAqB,CAAC,OAAQ,CAAC5K,IAAKpF,MAa7CmwG,oBAAqB,SAAU/qG,SACtBzT,KAAKqM,KAAKmkE,SAASjD,eACb,OAON8yC,sBACApG,gBAAe,IAgBxBoI,oBAAqB,eACbvvF,EAAG/U,EACH47B,GAAIz/B,IAIR4Y,GADA6mB,GAAK35C,KAAKomF,aAAahrE,yBAChB9D,MACPyG,EAAI47B,GAAGpiC,OAGHvW,QAAUA,OAAO0W,mBACjBwC,IAAMlZ,OAAO0W,iBAAiB1X,KAAKomF,aAAc,MACjDtzD,GAAKnb,WAAWuC,IAAIJ,iBAAiB,sBAAwBnC,WAAWuC,IAAIJ,iBAAiB,uBAC7FiE,GAAKpG,WAAWuC,IAAIJ,iBAAiB,qBAAwBnC,WAAWuC,IAAIJ,iBAAiB,yBAI7FgZ,GAAK,GAAK/U,GAAK,GAAKzK,KAAK5E,MAAMokB,IAAMxf,KAAK5E,MAAMqP,KAKhDrP,MAAM1O,KAAKszC,iBAAiB,UACvB+jE,eAAer3G,KAAKqM,KAAKi2G,YAAatiH,KAAK40G,gBAAiB,QAMjEthG,KAAKzU,OAAOmB,KAAKuiH,WACjBviH,KAAKuiH,SAASzvF,IAAMA,GAAK9yB,KAAKuiH,SAASxkG,IAAMA,SAK5CykG,gBAAgB1vF,EAAG/U,GAAG,QACtBwkG,SAAW,CACZzvF,EAAGA,EACH/U,EAAGA,MAmBX4+F,oBAAqB,eACbj9E,KAAO1/B,KAEN80B,IAAI7gB,WAAcjU,KAAKqM,KAAKskE,QAAW3wE,KAAKqM,KAAKskE,OAAOpD,eAIxD8vC,eAAiB,IAAIoF,gBAAe,SAASC,SACzChjF,KAAKs3E,cACNt3E,KAAKs3E,aAAc,EACnBh2G,OAAOlD,YAAW,eAEV4hC,KAAK2iF,sBACP,MAAOjuG,KACLsrB,KAAK49E,6BAEL59E,KAAKs3E,aAAc,KAExBt3E,KAAKrzB,KAAKskE,OAAOC,mBAGvBysC,eAAesF,QAAQ3iH,KAAKomF,gBAQrCk3B,mBAAoB,WACXxoF,IAAI7gB,WAAcjU,KAAKqM,KAAKskE,QAAW3wE,KAAKqM,KAAKskE,OAAOpD,SAIzDj6D,KAAKzU,OAAOmB,KAAKq9G,sBACZA,eAAeuF,UAAU5iH,KAAKomF,eAe3Cw2B,eAAgB,eACRl9E,KAAO1/B,KAEN80B,IAAI7gB,WAAcjU,KAAKqM,KAAKskE,QAAW3wE,KAAKqM,KAAKskE,OAAOpD,UAGxDvtE,KAAK+2G,cAAiB/2G,KAAKg3G,mBACvBA,aAAc,EACnBh2G,OAAOlD,YAAW,WACd4hC,KAAK2iF,sBACL3iF,KAAKs3E,aAAc,IACpBh3G,KAAKqM,KAAKskE,OAAOC,aAY5BksC,eAAgB,SAASrpG,SACjBisB,KAAO1/B,KAEN80B,IAAI7gB,YAGJjU,KAAK+2G,oBACDA,cAAe,EACpB/1G,OAAOlD,YAAW,WACd4hC,KAAKq3E,cAAe,IACrB,OAWX8F,0BAA2B,eACnBn9E,KAAO1/B,cAQF6iH,qBAAuB,IAAIC,sBAAqB,SAASJ,SAEtDh0G,MAAMgxB,KAAK4T,iBAAiB,KAC5B5T,KAAK2iF,wBAVH,CACNjlF,KAAM,KACN2lF,WAAY,MACZr3C,UAAW,UAUVm3C,qBAAqBF,QAAQjjF,KAAK0mD,cACzC,MAAOhyE,KACLnT,QAAQK,IAAI,mEAUpBi8G,yBAA0B,WAClBjqG,KAAKzU,OAAOmB,KAAK6iH,4BACZA,qBAAqBD,UAAU5iH,KAAKomF,eAejD48B,YAAa,eACJ32G,KAAOiH,KAAK9G,eAAe,GAAIxM,KAAKyM,QAAS,kBAElDJ,KAAKlP,GAAK6C,KAAK7C,GAAK,gBAQfs8E,QAAUz5E,KAAK4M,OAAO,OAAQ,CAAC,EAAG,EAAG,OAAQP,WAE7CotE,QAAQwpC,WAAa,QACrBxpC,QAAQypC,UAAY,QAGpBzpC,QAAQkW,MAAO,OAEfsqB,gBAAe,GACbj6G,MAYXq6G,cAAe,SAAUhsG,QACjBP,EAAGiT,EAAGoiG,GAAIC,GACdC,gBACAC,KAAOhwG,KAAKrG,SAASoB,GAAG0E,QAAQwwG,oBAE1BjwG,KAAKrG,SAASjN,KAAKqM,KAAKk3G,cAA0B,YAATD,OAC1CA,MAIDhwG,KAAK9I,QAAQ6D,MACb80G,GAAK90G,GAAGR,OAAOG,UAAU,GACzBo1G,GAAK/0G,GAAGR,OAAOG,UAAU,GAEzBq1G,gBAAkB/vG,KAAKrG,SAASoB,GAAG0E,QAAQywG,oBACtC/pC,QAAQ6nB,UAAU6hB,GAAKnjH,KAAKy5E,QAAQwpC,UAAYjjH,KAAK+kB,MACnCq+F,GAAKpjH,KAAKy5E,QAAQypC,UAAYljH,KAAKglB,OAE5B,iBAAnB3W,GAAG2lF,aACc,SAApBqvB,iBACAv1G,EAAIwF,KAAKrE,WAAWk0G,IACpBpiG,EAAIzN,KAAKrE,WAAWm0G,KACb9vG,KAAKrJ,SAASo5G,kBACrBv1G,EAAIwF,KAAK/E,QAAQ40G,GAAIE,iBACrBtiG,EAAIzN,KAAK/E,QAAQ60G,GAAIC,mBAErBv1G,EAAIq1G,GACJpiG,EAAIqiG,SAGHK,iBAAiB31G,EAAGiT,EAAG1S,UAEvBq1G,uBAAuBr1G,GAAG2lF,YAAa3lF,SAG3C4rG,gBAAe,IA5Bbj6G,MA4Cfi6G,eAAgB,SAAStvG,YACjB3K,KAAKy5E,QAAQ+Z,iBAAmB7oF,WAC3B8uE,QAAQ+Z,gBAAkB7oF,SAC1B8uE,QAAQ4L,gBAAgBC,iBAAiB36E,KAAKuoF,kBAEhDlzF,MAKXgxE,YAAa,SAASrmE,YACX3K,KAAKi6G,eAAetvG,MAU/B84G,iBAAkB,SAAU31G,EAAGiT,EAAG1S,gBACzBq1G,uBAAuB,IAAM51G,EAAI,KAAOiT,EAAI,IAAK1S,IAC/CrO,MASX0jH,uBAAwB,SAAU9tC,KAAMvnE,gBAC/BorE,QAAQma,QAAQhe,MACd51E,MAOXqgH,eAAgB,eACRhyG,GAAI0tF,IAAK4nB,kBAAmB,MAE3Bt1G,MAAMrO,KAAKwgF,mBACRxgF,KAAKwgF,mBAAmBrnF,eAAekV,MACvC0tF,IAAM/7F,KAAKwgF,mBAAmBnyE,KAE1BrO,KAAKq2G,kBAAoBr2G,KAAKu2G,qBAC9Bxa,IAAIvS,cAGRm6B,kBAAmB,eAStBnjC,mBAAqB,GAMC,WAAvBxgF,KAAKuvE,SAAS1kE,MAAqB84G,wBAC9Bt+B,qBACA9V,SAASka,cAAczpF,WACvBkzF,sBACA3jB,SAASma,mBAGX1pF,MAYXg6G,oBAAqB,SAAUlsG,EAAGiT,SACvB,CAACjT,EAAGiT,IAsCf6iG,oBAAqB,SAAUnwG,SACvBqF,KAAO9Y,KAAKq4G,yBACZW,OAASlkF,IAAIzc,YAAY5E,IAAK,KAAMzT,KAAKkB,UACzC4M,EAAIkrG,OAAO,GAAKlgG,KAAK,GACrBiI,EAAIi4F,OAAO,GAAKlgG,KAAK,UACT,IAAIqL,OAAO3a,MAAMzH,iBAAkB,CAAC+L,EAAGiT,GAAI/gB,MAE1CgO,UAAU3U,MAAM,IAUrCwqH,iBAAkB,SAAUpwG,SACpBqwG,OAAS9jH,KAAK+jH,wBAAwBtwG,YAC1CqwG,OAAOpoH,KAAKsE,KAAK4jH,oBAAoBnwG,MAE9BqwG,QASXC,wBAAyB,SAAUtwG,SAM3BpF,GACA0tF,IANAjjF,KAAO9Y,KAAKq4G,yBACZW,OAASlkF,IAAIzc,YAAY5E,IAAK,KAAMzT,KAAKkB,UACzC49B,GAAKk6E,OAAO,GAAKlgG,KAAK,GACtBioB,GAAKi4E,OAAO,GAAKlgG,KAAK,GACtBgrG,OAAS,GAGT13G,IAAMpM,KAAK24D,YAAY99D,WAEtBwT,GAAK,EAAGA,GAAKjC,IAAKiC,MACnB0tF,IAAM/7F,KAAK24D,YAAYtqD,KACfmzE,YAAYvvE,SAAW8pF,IAAI/mB,UAAY+mB,IAAI/mB,SAASl2C,GAAIiC,MAC5D+iF,OAAOA,OAAOjpH,QAAUkhG,YAIzB+nB,QAQXxpB,aAAc,eACNjsF,GAAI21G,GAAI53G,IAAMpM,KAAK24D,YAAY99D,WAE9BmpH,GAAK,EAAGA,GAAK53G,IAAK43G,KACnB31G,GAAKrO,KAAK24D,YAAYqrD,IAElB1wG,KAAKzU,OAAOwP,GAAGR,UACXyF,KAAKrG,SAASoB,GAAG0E,QAAQ6/D,QACzBvkE,GAAGR,OAAOoX,aAEV5W,GAAGR,OAAO6W,qBAIf1kB,MAUX+7G,WAAY,SAAUjuG,EAAGiT,EAAGkR,UACpBi2D,GAAIC,GAAI87B,GAAIC,UACZ5wG,KAAKzU,OAAOiP,IAAMwF,KAAKzU,OAAOkiB,KAC9BmnE,GAAKloF,KAAK8L,OAAOyY,UAAU,GAC3B4jE,GAAKnoF,KAAK8L,OAAOyY,UAAU,QAEtBzY,OAAOyY,UAAU,GAAKzW,OACtBhC,OAAOyY,UAAU,GAAKxD,EAEvBkR,YACKnmB,OAAOyY,UAAU,IAAMvkB,KAAKs1G,aAC5BxpG,OAAOyY,UAAU,IAAMvkB,KAAKu1G,SAGrC0O,GAAM,IAAI9/F,OAAO3a,MAAMzH,iBAAkB,CAAC,EAAG,GAAI/B,MAAOgO,UACxDk2G,GAAM,IAAI//F,OAAO3a,MAAMzH,iBAAkB,CAAC/B,KAAK8yC,YAAa9yC,KAAK+yC,cAAe/yC,MAAOgO,WACnFi2G,GAAG,GAAKjkH,KAAKmkH,eAAe,IAC5BF,GAAG,GAAKjkH,KAAKmkH,eAAe,IAC5BD,GAAG,GAAKlkH,KAAKmkH,eAAe,IAC5BD,GAAG,GAAKlkH,KAAKmkH,eAAe,WAEvBr4G,OAAOyY,UAAU,GAAK2jE,QACtBp8E,OAAOyY,UAAU,GAAK4jE,UAI9BmS,eAAe3P,cAAc3L,kBAC7B3gE,qBAAqB,CAAC,gBAEpBre,MAOXokH,cAAe,SAAUhyG,SACjB3G,KAAMsC,EAAGyD,KAAM6/D,MAAOz3E,KAAMyU,GAAIc,SAChC27F,UAAY,GAEZxwG,EAAI8X,IAAIhW,QAAQ,UAChB7B,EAAI6X,IAAIhW,QAAQ,WAEhBioH,MAAQ,SAAUjkH,MAAOiO,GAAIzR,EAAGgE,aACrB,eACC3D,EAAGic,EAGPA,GADAjc,EAAImD,MAAMG,OAAO8N,GAAGlR,KACd0Q,OAAOG,UAAUpN,MAEV,IAATA,KACA3D,EAAE60F,oBAAoBtoF,MAAM1H,eAAgB,CAAClF,IAAKsc,IAElDjc,EAAE60F,oBAAoBtoF,MAAM1H,eAAgB,CAACoX,EAAGtc,MAEpDK,EAAEooF,gBAAgB7qD,WAI1B8pF,OAAS,SAAUlkH,MAAOiO,GAAIzR,UACnB,eACCK,EAAG+M,EAEP/M,EAAImD,MAAMG,OAAO8N,GAAGlR,IACpB6M,EAAIpN,IAEJK,EAAEioF,aAAa,CAACjzE,QAASjI,MAIjCu6G,OAAS,SAAUnkH,MAAOiO,GAAIzR,EAAGgE,aACtB,eACC3D,EAAG+M,EAEP/M,EAAImD,MAAMG,OAAO8N,GAAGlR,IACpB6M,EAAIpN,IAES,gBAATgE,KACA3D,EAAE8V,QAAQlB,YAAc7H,GAExBA,EAAIsjE,MAAM9C,UAAUxgE,GACpB/M,EAAE8V,QAAQnS,KAAO,SAAWoJ,EAAE,GAC9B/M,EAAE8V,QAAQnS,KAAO,WAAaoJ,EAAE,MAK5Cw6G,OAAS,SAAUpkH,MAAOiO,GAAIzR,UACnB,WACKwD,MAAMG,OAAO8N,GAAGlR,IAEtB0a,SAAWjb,MAIrB6nH,SAAW,SAAUrkH,MAAOiO,GAAIzR,UACrB,WACKwD,MAAMG,OAAO8N,GAAGlR,IAEtBunH,SAAS9nH,YAInBtC,EAAI,SAIDA,GAAK,GAAG,IAEXyT,GADAtC,KAAO2G,IAAI/Y,MAAMiB,EAAI,EAAGC,IACf6B,QAAQ,KACjBoV,KAAO/F,KAAKpS,MAAM,EAAG0U,GACrBsjE,MAAQ5lE,KAAKpS,MAAM0U,EAAI,GACvBA,EAAIyD,KAAKpV,QAAQ,KACjBxC,KAAO4X,KAAKnY,MAAM,EAAG0U,GACrBM,GAAKrO,KAAK4J,eAAe0J,KAAKjB,aAAazY,OAE3CuV,SAAWqC,KAAKnY,MAAM0U,EAAI,GAAG/S,QAAQ,OAAQ,IAAI0D,cACjD2yE,MAAQ/9D,KAAK/H,eAAgB8lE,MAAOrxE,KAAM,IAAI,GAGzCsT,KAAKzU,OAAOmB,KAAK4J,eAAehQ,cAKzBuV,cACH,IACD27F,UAAUpvG,KAAK2oH,MAAMrkH,KAAMqO,GAAIgjE,MAAO,cAErC,IACDy5B,UAAUpvG,KAAK2oH,MAAMrkH,KAAMqO,GAAIgjE,MAAO,cAErC,UACDy5B,UAAUpvG,KAAK4oH,OAAOtkH,KAAMqO,GAAIgjE,kBAE/B,WACDy5B,UAAUpvG,KAAK8oH,OAAOxkH,KAAMqO,GAAIgjE,kBAE/B,SACDy5B,UAAUpvG,KAAK6oH,OAAOvkH,KAAMqO,GAAIgjE,MAAO,qBAEtC,QACDy5B,UAAUpvG,KAAK+oH,SAASzkH,KAAMqO,GAAIgjE,kBAEjC,cACDy5B,UAAUpvG,KAAK6oH,OAAOvkH,KAAMqO,GAAIgjE,MAAO,0BAEtC,OACDy5B,UAAUpvG,KAAK6oH,OAAOvkH,KAAMqO,GAAIgjE,MAAO,mBAEtC,sBAGDjzE,IAAIsD,MAAM,aAAeyN,SAAW,uCAAyCkiE,YAhCjFjzE,IAAIsD,MAAM,sBAAwB9H,KAAO,eAqC7CU,GADA8X,IAAMA,IAAI/Y,MAAMkB,EAAI,IACZ6B,QAAQ,UAChB7B,EAAI6X,IAAIhW,QAAQ,gBAGfuoH,iBAAmB,eAChBrqH,MAECA,EAAI,EAAGA,EAAIwwG,UAAUjwG,OAAQP,IAC9BwwG,UAAUxwG,iBAGT+qF,gBAAgBu/B,kBACd,QAEND,qBAUTA,iBAAkB,kBACP,GAOXtP,mBAAoB,eACZtjE,GAAK,IAAI5tB,OAAO3a,MAAM1H,eAAgB,CAAC,EAAG,GAAI9B,MAC9CgyC,GAAK,IAAI7tB,OAAO3a,MAAM1H,eAAgB,CAAC9B,KAAKyM,QAAQqpE,KAAKgD,MAAO94E,KAAKyM,QAAQqpE,KAAKiD,OAAQ/4E,MAC1F8N,EAAIikC,GAAGxtB,UAAU,GAAKytB,GAAGztB,UAAU,GACnCxD,EAAIgxB,GAAGxtB,UAAU,GAAKytB,GAAGztB,UAAU,YAElC9X,QAAQqpE,KAAKkD,UAAYh5E,KAAKyM,QAAQqpE,KAAKgD,MACzCpsE,KAAKwC,IAAIpB,GAAK,SACZrB,QAAQqpE,KAAKkD,WAAa,EAC/BlrE,GAAK,WAGJrB,QAAQqpE,KAAKmD,UAAYj5E,KAAKyM,QAAQqpE,KAAKiD,MACzCrsE,KAAKwC,IAAI6R,GAAK,SACZtU,QAAQqpE,KAAKmD,WAAa,EAC/Bl4D,GAAK,SAGF/gB,MAOX6kH,UAAW,uBACFvqB,eAAe+a,qBAAqB1qB,cAAc3L,aAEhDh/E,MAUXgrF,OAAQ,SAAUl9E,EAAGiT,OACb44B,GAAK35C,KAAKszC,iBACVwxE,GAAK9kH,KAAKqM,KAAKiO,KAAK4kG,QACpB6F,GAAK/kH,KAAKqM,KAAKiO,KAAK8kG,QACpB/9E,IAAMsY,GAAG,GAAKA,GAAG,KAAO,EAAM,EAAMmrE,IACpCxjF,IAAMqY,GAAG,GAAKA,GAAG,KAAO,EAAM,EAAMorE,IACpCb,GAAK,GACLc,GAAK,GACLvlE,GAAKz/C,KAAKqM,KAAKiO,KAAKmE,KAAOze,KAAKqM,KAAKiO,KAAK3N,KAAO,YAEhD3M,KAAK2tE,MAAQ3tE,KAAKqM,KAAKiO,KAAKqE,KAAOmmG,GAAK,GACxC9kH,KAAK4tE,MAAQ5tE,KAAKqM,KAAKiO,KAAKqE,KAAOomG,GAAK,GACxC/kH,KAAK2tE,MAAQluB,IAAMqlE,GAAK,GACxB9kH,KAAK4tE,MAAQnuB,IAAMslE,GAAK,EAClB/kH,MAGPsT,KAAKrJ,SAAS6D,IAAMwF,KAAKrJ,SAAS8W,KAClCmjG,IAAMp2G,EAAI6rC,GAAG,KAAOA,GAAG,GAAKA,GAAG,IAC/BqrE,IAAMrrE,GAAG,GAAK54B,IAAM44B,GAAG,GAAKA,GAAG,UAG9B09D,eAAe,CAAC19D,GAAG,GAAKtY,GAAK6iF,GAAIvqE,GAAG,GAAKrY,GAAK0jF,GAAIrrE,GAAG,GAAKtY,IAAM,EAAI6iF,IAAKvqE,GAAG,GAAKrY,IAAM,EAAI0jF,KAAMhlH,KAAK40G,gBAAiB,UACrH50G,KAAK6kH,cAWhB/5B,QAAS,SAAUh9E,EAAGiT,OACd44B,GAAK35C,KAAKszC,iBACVwxE,GAAK9kH,KAAKqM,KAAKiO,KAAK4kG,QACpB6F,GAAK/kH,KAAKqM,KAAKiO,KAAK8kG,QACpB/9E,IAAMsY,GAAG,GAAKA,GAAG,KAAO,EAAMmrE,IAC9BxjF,IAAMqY,GAAG,GAAKA,GAAG,KAAO,EAAMorE,IAC9Bb,GAAK,GACLc,GAAK,GACLvlE,GAAKz/C,KAAKqM,KAAKiO,KAAKmE,KAAOze,KAAKqM,KAAKiO,KAAK3N,KAAO,YAEjD3M,KAAK2tE,MAAQluB,IAAMz/C,KAAK4tE,MAAQnuB,GACzBz/C,MAGPsT,KAAKrJ,SAAS6D,IAAMwF,KAAKrJ,SAAS8W,KAClCmjG,IAAMp2G,EAAI6rC,GAAG,KAAOA,GAAG,GAAKA,GAAG,IAC/BqrE,IAAMrrE,GAAG,GAAK54B,IAAM44B,GAAG,GAAKA,GAAG,UAG9B09D,eAAe,CAAC19D,GAAG,GAAKtY,GAAK6iF,GAAIvqE,GAAG,GAAKrY,GAAK0jF,GAAIrrE,GAAG,GAAKtY,IAAM,EAAI6iF,IAAKvqE,GAAG,GAAKrY,IAAM,EAAI0jF,KAAMhlH,KAAK40G,gBAAiB,UAErH50G,KAAK6kH,cAYhB95B,QAAS,eACDpxC,GAAItY,GAAIC,UAERhuB,KAAKzU,OAAOmB,KAAKqM,KAAKi2G,kBACjBjL,eAAer3G,KAAKqM,KAAKi2G,YAAatiH,KAAK40G,gBAAiB,UAIjEvzE,KADAsY,GAAK35C,KAAKszC,kBACD,GAAKqG,GAAG,KAAO,EAAM35C,KAAK2tE,OAAS,GAC5CrsC,IAAMqY,GAAG,GAAKA,GAAG,KAAO,EAAM35C,KAAK4tE,OAAS,QACvCypC,eAAe,CAAC19D,GAAG,GAAKtY,GAAIsY,GAAG,GAAKrY,GAAIqY,GAAG,GAAKtY,GAAIsY,GAAG,GAAKrY,IAAKthC,KAAK40G,gBAAiB,UAEzF50G,KAAK6kH,aAOhBI,cAAe,eACP52G,GAAY62G,QAASC,QAASppB,IAC9B5kD,KAAO,EACPD,KAAO,EACPkuE,KAAO,EACPC,KAAO,EACPj5G,IAAMpM,KAAK24D,YAAY99D,WAEtBwT,GAAK,EAAGA,GAAKjC,IAAKiC,KACnB0tF,IAAM/7F,KAAK24D,YAAYtqD,IAEnBiF,KAAK9I,QAAQuxF,MAAQA,IAAIva,YAAYvvE,UACjC8pF,IAAIluF,OAAOG,UAAU,GAAKmpC,KAC1BA,KAAO4kD,IAAIluF,OAAOG,UAAU,GACrB+tF,IAAIluF,OAAOG,UAAU,GAAKkpC,OACjCA,KAAO6kD,IAAIluF,OAAOG,UAAU,IAE5B+tF,IAAIluF,OAAOG,UAAU,GAAKq3G,KAC1BA,KAAOtpB,IAAIluF,OAAOG,UAAU,GACrB+tF,IAAIluF,OAAOG,UAAU,GAAKo3G,OACjCA,KAAOrpB,IAAIluF,OAAOG,UAAU,YAK/B,GACTk3G,QADS,GACUllH,KAAK+kB,MACxBogG,QAFS,GAEUnlH,KAAKglB,WAEnBqyF,eAAe,CAAClgE,KAAO+tE,QAASG,KAAOF,QAASjuE,KAAOguE,QAASE,KAAOD,SAAUnlH,KAAK40G,gBAAiB,UAErG50G,KAAK6kH,aAShBnN,aAAc,SAAUj4G,cAChBnF,EAAMgrH,IAEN11E,GAAIC,GAAI/Q,GAAIiC,GAAI51B,EADhBo6G,QAAU,CAAC/jG,EAAAA,GAAWA,EAAAA,GAAWA,EAAAA,EAAUA,EAAAA,OAG1ClO,KAAKlJ,QAAQ3K,WAAiC,IAApBA,SAAS5E,cAC7BmF,SAGN1F,EAAI,EAAGA,EAAImF,SAAS5E,OAAQP,IAG7BgrH,IAFItlH,KAAKO,OAAOd,SAASnF,IAEjBi7F,SACJjiF,KAAKlJ,QAAQk7G,OACTA,IAAI,GAAKC,QAAQ,KAAMA,QAAQ,GAAKD,IAAI,IACxCA,IAAI,GAAKC,QAAQ,KAAMA,QAAQ,GAAKD,IAAI,IACxCA,IAAI,GAAKC,QAAQ,KAAMA,QAAQ,GAAKD,IAAI,IACxCA,IAAI,GAAKC,QAAQ,KAAMA,QAAQ,GAAKD,IAAI,YAIhDhyG,KAAKlJ,QAAQm7G,WACb31E,GAAK,IAAO21E,QAAQ,GAAKA,QAAQ,IACjC11E,GAAK,IAAO01E,QAAQ,GAAKA,QAAQ,IACjCzmF,GAAK,KAAOymF,QAAQ,GAAKA,QAAQ,IAAM,GACvCxkF,GAAK,KAAOwkF,QAAQ,GAAKA,QAAQ,IAAM,GACvCp6G,EAAIuB,KAAKiS,IAAImgB,GAAIiC,SACZs2E,eAAe,CAACznE,GAAKzkC,EAAG0kC,GAAK1kC,EAAGykC,GAAKzkC,EAAG0kC,GAAK1kC,GAAInL,KAAK40G,gBAAiB,WAGzE50G,MASXwlH,QAAS,SAAUC,GAAIC,QACfC,GAAK3lH,KAAKqM,KAAKiO,KAAK4kG,QACpB0G,GAAK5lH,KAAKqM,KAAKiO,KAAK8kG,oBAEnB/yG,KAAKiO,KAAK4kG,QAAUuG,GAAKzlH,KAAK2tE,WAC9BthE,KAAKiO,KAAK8kG,QAAUsG,GAAK1lH,KAAK4tE,WAE9Bod,cAEA3+E,KAAKiO,KAAK4kG,QAAUyG,QACpBt5G,KAAKiO,KAAK8kG,QAAUwG,GAElB5lH,MAqBX02F,aAAc,SAAUp4F,OAAQunH,gBACxBx3G,GAAI/T,KAEJgZ,KAAKlJ,QAAQ9L,QAAS,KACjBhE,EAAI,EAAGA,EAAIgE,OAAOzD,OAAQP,SACtBo8F,aAAap4F,OAAOhE,WAGtB0F,QAGX1B,OAAS0B,KAAKO,OAAOjC,SAIhBgV,KAAKzU,OAAOP,SAAWgV,KAAKvJ,SAASzL,eAC/B0B,aAKFqO,MAAM/P,OAAO6wF,cACV7wF,OAAO6wF,cAAch2F,eAAekV,KACpC/P,OAAO6wF,cAAc9gF,IAAIjO,MAAMs2F,aAAap4F,OAAO6wF,cAAc9gF,SAKpEA,MAAM/P,OAAOoL,QACVpL,OAAOoL,QAAQvQ,eAAekV,KAC9B/P,OAAOoL,QAAQ2E,IAAIjO,MAAMs2F,aAAap4F,OAAOoL,QAAQ2E,QAKzDw3G,eAEKx3G,MAAMrO,KAAK0J,QACR1J,KAAK0J,QAAQvQ,eAAekV,KACxBiF,KAAKzU,OAAOmB,KAAK0J,QAAQ2E,IAAI8gF,gBAC7B77E,KAAKzU,OAAOmB,KAAK0J,QAAQ2E,IAAI8gF,cAAch2F,eAAemF,OAAOnB,cAE1D6C,KAAK0J,QAAQ2E,IAAI8gF,cAAc7wF,OAAOnB,WACtC6C,KAAK0J,QAAQ2E,IAAIohF,YAAYnxF,OAAOnB,UAIpD,GAAImW,KAAKzU,OAAOP,OAAOk4D,eAErBnoD,MAAM/P,OAAOk4D,UACVl4D,OAAOk4D,UAAUr9D,eAAekV,KAC5BiF,KAAKzU,OAAOP,OAAOk4D,UAAUnoD,IAAI8gF,gBACjC77E,KAAKzU,OAAOP,OAAOk4D,UAAUnoD,IAAI8gF,cAAch2F,eAAemF,OAAOnB,cAE9DmB,OAAOk4D,UAAUnoD,IAAI8gF,cAAc7wF,OAAOnB,WAC1CmB,OAAOk4D,UAAUnoD,IAAIohF,YAAYnxF,OAAOnB,QAO3DmB,OAAOwxF,MAAQ,WACVn3B,YAAYx9D,OAAOmD,OAAOwxF,KAAM,GAChCzhF,GAAK/P,OAAOwxF,KAAMzhF,GAAKrO,KAAK24D,YAAY99D,OAAQwT,UAC5CsqD,YAAYtqD,IAAIyhF,YAElBxxF,OAAOuM,OAASrB,MAAMpG,oBAC7BhF,IAAIsD,MAAM,8BAAgCpD,OAAOnB,GAAK,8BAGnD6C,KAAK0J,QAAQpL,OAAOnB,WACpB6C,KAAK4J,eAAetL,OAAO1E,MAE9B0E,OAAOyU,SAAWO,KAAKrG,SAAS3O,OAAOyU,QAAQigE,QAC/C10E,OAAO41F,aAIP5gF,KAAKzU,OAAOP,OAAOijF,SACnBjjF,OAAOijF,SAEb,MAAOtkF,GACLmB,IAAIsD,MAAMpD,OAAOnB,GAAK,2BAA6BF,eAGlDu9B,SAEEx6B,MAQX8lH,gBAAiB,SAAUxnH,YACnBynH,QAECA,OAAOznH,OAAOk4D,UACXl4D,OAAOk4D,UAAUr9D,eAAe4sH,WAC3BD,gBAAgBxnH,OAAOk4D,UAAUuvD,kBAIzCrvB,aAAap4F,QAEX0B,MAQXgmH,iBAAkB,eACVj0E,GAAIC,GAAIC,UAEZF,GAAK/xC,KAAK4M,OAAO,QAAS,CAAC,EAAG,GAAI,CAC9BzP,GAAI6C,KAAK7C,GAAK,QACdvD,KAAM,WACNi5E,WAAW,EACX5gE,SAAS,EACT0gE,OAAO,IAGX3gC,GAAKhyC,KAAK4M,OAAO,QAAS,CAAC,EAAG,GAAI,CAC9BzP,GAAI6C,KAAK7C,GAAK,QACdvD,KAAM,YACNi5E,WAAW,EACX5gE,SAAS,EACT0gE,OAAO,IAGX1gC,GAAKjyC,KAAK4M,OAAO,QAAS,CAAC,EAAG,GAAI,CAC9BzP,GAAI6C,KAAK7C,GAAK,QACdvD,KAAM,YACNi5E,WAAW,EACX5gE,SAAS,EACT0gE,OAAO,SAGN/lE,OAAO,OAAQ,CAACmlC,GAAIC,IAAK,CAC1B70C,GAAI6C,KAAK7C,GAAK,QACdvD,KAAM,UACNi5E,WAAW,EACX5gE,SAAS,SAGRrF,OAAO,OAAQ,CAACmlC,GAAIE,IAAK,CAC1B90C,GAAI6C,KAAK7C,GAAK,QACdvD,KAAM,UACNi5E,WAAW,EACX5gE,SAAS,IAGNjS,MAeXwiH,gBAAiB,SAAU1vE,YAAaC,aAAckzE,QAASC,wBACvDZ,WAMCY,qBAEDZ,IAAMtlH,KAAKszC,uBAGVR,YAAcn7B,WAAWm7B,kBACzBC,aAAep7B,WAAWo7B,cAqB1BkzE,eACI7/B,aAAahvE,MAAME,MAAStX,KAAK8yC,YAAe,UAChDszC,aAAahvE,MAAMG,OAAUvX,KAAK+yC,aAAgB,WAEtDw8B,SAASoB,OAAO3wE,KAAK8yC,YAAa9yC,KAAK+yC,cAEvCmzE,yBACI7O,eAAeiO,IAAKtlH,KAAK40G,gBAAiB,QAG5C50G,MAOXmmH,iBAAkB,eACV93G,GAAI6K,EAAGtJ,EAAGhT,EAAGtC,MAGZ+T,MADL6K,EAAI,QACOlZ,KAAK0J,WACR1J,KAAK0J,QAAQvQ,eAAekV,IAAK,KAE5BuB,KADLtV,EAAI,EACM0F,KAAK0J,QAAQ2E,IAAI8gF,cACnBnvF,KAAK0J,QAAQ2E,IAAI8gF,cAAch2F,eAAeyW,KAC9CtV,GAAK,OAORsV,KAJDtV,GAAK,IACL4e,GAAK,WAAalZ,KAAK0J,QAAQ2E,IAAIlR,GAA9B,eAGC6C,KAAK0J,QAAQ2E,IAAI8gF,cACnBnvF,KAAK0J,QAAQ2E,IAAI8gF,cAAch2F,eAAeyW,KAC9CsJ,GAAKlZ,KAAK0J,QAAQ2E,IAAI8gF,cAAcv/E,GAAGzS,GAAK,IAAM6C,KAAK0J,QAAQ2E,IAAI8gF,cAAcv/E,GAAGhW,KAA/EoG,OAGbkZ,GAAK,eAGbA,GAAK,UACLtc,EAAIoE,OAAO6pB,QACT3pB,SAAS2pB,OACXjuB,EAAEsE,SAASisF,MAAMj0E,GACjBtc,EAAEsE,SAASklH,QACJpmH,MAOXqmH,QAAS,eACDzpH,EAAIoE,OAAO6pB,KAAK,WACpBjuB,EAAEsE,SAAS2pB,OACXjuB,EAAEsE,SAASisF,MAAM,QAAU75E,KAAKnB,WAAWnS,KAAK01G,WAA/B,UACjB94G,EAAEsE,SAASklH,QACJpmH,MAOXqlF,cAAe,eACPh3E,GAAI0tF,IAAK3vF,IAAMpM,KAAK24D,YAAY99D,WAQ/BwT,GAAK,EAAGA,GAAKjC,IAAKiC,MACnB0tF,IAAM/7F,KAAK24D,YAAYtqD,KACnB4gF,YAAc8M,IAAI5oB,oBAAsBnzE,KAAKg2G,oBAGhD3nG,MAAMrO,KAAK8J,OACR9J,KAAK8J,OAAO3Q,eAAekV,OAC3B0tF,IAAM/7F,KAAK8J,OAAOuE,KACd4gF,YAAc8M,IAAI5oB,oBAAsBnzE,KAAKg2G,wBAIlDh2G,MAQX4kH,eAAgB,SAAUr0C,UAClBliE,GAAI0tF,QAGRxrB,KAAOvwE,KAAKO,OAAOgwE,MAcdliE,GAAK,EAAGA,GAAKrO,KAAK24D,YAAY99D,OAAQwT,KACvC0tF,IAAM/7F,KAAK24D,YAAYtqD,IACnBrO,KAAKg2G,iBAAmBja,IAAItxF,eAAiBjB,MAAMlF,mBACnDy3F,IAAI9H,aAMR8H,IAAIvhE,QAAQlnB,KAAKzU,OAAO0xE,OAASwrB,IAAI5+F,KAAOozE,KAAKpzE,IAC7CmoF,uBAIHj3E,MAAMrO,KAAK8J,OACR9J,KAAK8J,OAAO3Q,eAAekV,UACtBvE,OAAOuE,IAAImsB,OAAO+1C,aAIxBvwE,MAOXkzF,eAAgB,eACR7kF,GACAjC,IAAMpM,KAAK24D,YAAY99D,UAeA,WAAvBmF,KAAKuvE,SAAS1kE,UACTy7G,gCAEAj4G,GAAK,EAAGA,GAAKjC,IAAKiC,UACdsqD,YAAYtqD,IAAI6kF,wBAGtBlzF,MASXsmH,qBAAsB,eACdj4G,GAAI0tF,IAAKzhG,EAAGisH,KAAMC,GAClBC,KAAOzmH,KAAK24D,YAAY99D,OACxB6rH,OAAS1mH,KAAKyM,QAAQwD,MACtB7D,IAAMpM,KAAKyM,QAAQwD,MAAMglE,UACzBh+C,KAAO1R,OAAOoF,sBAEbrwB,EAAI,EAAGA,EAAI8R,IAAK9R,IAAK,KAGjBksH,MAFLD,KAAOhhG,OAAOC,kBAEHkhG,OACHA,OAAOvtH,eAAeqtH,KAClBE,OAAOF,IAAMvvF,MAAQyvF,OAAOF,IAAMD,OAClCA,KAAOG,OAAOF,SAK1BvvF,KAAOsvF,KAEFl4G,GAAK,EAAGA,GAAKo4G,KAAMp4G,MACpB0tF,IAAM/7F,KAAK24D,YAAYtqD,KAEf0E,QAAQ9C,QAAUs2G,MACtBxqB,IAAI1W,gBAAgB6N,wBAIzBlzF,MAYX2mH,QAAS,SAAUC,KAAM74G,EAAG8M,gBACxBzc,IAAIkC,WAAW,kBAAmB,cAClCyN,EAAIuF,KAAKpI,IAAI6C,EAAG,UAEhB8M,QAAUvH,KAAKpI,IAAI2P,QAAS7a,WAEvB80G,MAAMp5G,KAAK,CAACqS,EAAG64G,YACf1oG,GAAGnQ,EAAG64G,KAAM/rG,SAEV7a,KAAK80G,MAAMj6G,OAAS,GAM/Bid,SAAU1Z,IAAI6B,SAAS7B,IAAIg2G,MAAMl7G,UAAW,MAQ5C2tH,WAAY,SAAU1pH,WAClBiB,IAAIkC,WAAW,qBAAsB,eACjCN,KAAK80G,MAAM33G,WACNghB,IAAIne,KAAK80G,MAAM33G,IAAI,GAAI6C,KAAK80G,MAAM33G,IAAI,SACtC23G,MAAM33G,IAAM,MAGd6C,MAMXiY,YAAa7Z,IAAI6B,SAAS7B,IAAIg2G,MAAMl7G,UAAW,OAO/C4tH,YAAa,SAAU/4G,OACf8lF,IAAMxpF,MAAMnR,UAAUG,MAAMK,KAAK+B,UAAW,UAEhD2C,IAAIkC,WAAW,sBAAuB,gCAEtCuzF,IAAI,GAAKvgF,KAAKpI,IAAI2oF,IAAI,GAAI,eACrBx1E,qBAAqB,CAACw1E,IAAI,IAAKp4F,WAE7BuE,MAQX6uF,SAAU,SAAUzuF,cACZkT,KAAKzU,OAAOuB,QAAUkT,KAAKzU,OAAOuB,MAAMgmF,qBACnC2uB,gBAAgBr5G,KAAK0E,YACrBo6B,UAEFx6B,MAQXkd,YAAa,SAAU9c,WACf9F,MAECA,EAAI0F,KAAK+0G,gBAAgBl6G,OAAS,EAAGP,GAAK,EAAGA,IAC1C0F,KAAK+0G,gBAAgBz6G,KAAO8F,YACvB20G,gBAAgB55G,OAAOb,EAAG,UAGhC0F,MAQXw6B,OAAQ,SAAU+1C,UACVj2E,EAAG8R,IAAK1L,EAAG2zB,OACX0yF,iBAEA/mH,KAAKg1G,UAAYh1G,KAAK88F,yBACf98F,cAENg1G,UAAW,EAEiB,QAA7Bh1G,KAAKqM,KAAK26G,gBAA4BhnH,KAAKomF,cAAuC,QAAvBpmF,KAAKuvE,SAAS1kE,OACzEk8G,cAAgB/mH,KAAKkB,SAAS+lH,cAC9B5yF,OAASr0B,KAAKuvE,SAAS8b,oBAAoBrrF,KAAKomF,eAGnB,QAA7BpmF,KAAKqM,KAAK26G,gBAAmD,QAAvBhnH,KAAKuvE,SAAS1kE,OACpDk8G,cAAgB/mH,KAAKkB,SAAS+lH,cAC9B5yF,OAASr0B,KAAKuvE,SAAS8b,oBAAoBrrF,KAAKuvE,SAAS23C,eAGxD7hC,gBAAgBu/B,eAAer0C,MAAMo0C,wBACrCp1C,SAASka,cAAczpF,WACvBkzF,sBACA3jB,SAASma,uBACTrrE,qBAAqB,CAAC,UAAW,IAElCgW,SACAA,SACA0yF,cAAcI,SAKlB/6G,IAAMpM,KAAK+0G,gBAAgBl6G,OACtBP,EAAI,EAAGA,EAAI8R,IAAK9R,IACjBoG,EAAIV,KAAK+0G,gBAAgBz6G,GACrBgZ,KAAKzU,OAAO6B,IAAMA,IAAMV,OACxBU,EAAEkgD,cAAgB5gD,KAAK4gD,cACvBlgD,EAAE2kF,gBAAgBu/B,iBAAiBD,mBACnCjkH,EAAE6uE,SAASka,gBACX/oF,EAAEwyF,iBACFxyF,EAAE6uE,SAASma,kBACXhpF,EAAE2d,qBAAqB,CAAC,UAAW,iBAKtC22F,UAAW,EACTh1G,MAQXg/E,WAAY,uBACHg3B,iBAAkB,OAClBx7E,cACAw7E,iBAAkB,EAChBh2G,MAOXonH,QAAS,uBACAx6G,OAAO,OAAQ,IAEb5M,MAQXi/E,YAAa,eACL3kF,MAECA,EAAI,EAAGA,EAAI0F,KAAK00G,MAAM75G,OAAQP,SAC1Bo8F,aAAa12F,KAAK00G,MAAMp6G,gBAG5Bo6G,MAAM75G,OAAS,OACf2/B,SAEEx6B,MAcX4M,OAAQ,SAAUy6G,YAAar7G,QAASC,gBAChCoC,GAAI/T,MAER+sH,YAAcA,YAAY3oH,cAErB4U,KAAKzU,OAAOmN,WACbA,QAAU,IAGTsH,KAAKzU,OAAOoN,cACbA,WAAa,IAGZ3R,EAAI,EAAGA,EAAI0R,QAAQnR,OAAQP,KACxBgZ,KAAKvJ,SAASiC,QAAQ1R,KACJ,SAAhB+sH,aAAgC,IAAN/sH,GACV,wBAAhB+sH,aAA+C,IAAN/sH,KACxB,UAAhB+sH,aAA2C,aAAhBA,aAA8C,WAAhBA,aACnD,IAAN/sH,GAAiB,IAANA,IACI,UAAhB+sH,aAA2B/sH,EAAI,IAEjC0R,QAAQ1R,GAAK0F,KAAKO,OAAOyL,QAAQ1R,SAIrCgZ,KAAKnJ,WAAW/L,IAAIqB,SAAS4nH,oBAGvB,IAAIrrH,MAAM,iDAAmDqrH,oBAFnEh5G,GAAKjQ,IAAIqB,SAAS4nH,aAAarnH,KAAMgM,QAASC,YAK7CqH,KAAKzU,OAAOwP,KAKbA,GAAGg3E,eAAiBh3E,GAAGmsB,QAAUnsB,GAAG6kF,gBACpC7kF,GAAG2wE,aAEA3wE,KAPHjQ,IAAIsD,MAAM,sCAAwC2lH,aAC3Ch5G,KAafwG,cAAe,kBACXzW,IAAIkC,WAAW,wBAAyB,kBACjCN,KAAK4M,OAAOjR,MAAMqE,KAAMvE,YAOnCkvF,YAAa,eACLt8E,OAECA,GAAK,EAAGA,GAAKrO,KAAK24D,YAAY99D,OAAQwT,UAClCsqD,YAAYtqD,IAAI6lF,yBAGpB3E,UAAY,EACVvvF,MAOX69C,cAAe,kBACN79C,KAAKg1G,gBACDlY,mBAAoB,GAEtB98F,MAOXw3G,gBAAiB,kBACTx3G,KAAK88F,yBACAA,mBAAoB,OACpB9d,cAEFh/E,MAaXq3G,eAAgB,SAAU3jF,KAAMkhF,gBAAiB4Q,aACzCznG,EAAG+U,EAAGs1D,GAAIC,GACVi/B,KAAO,EACPC,KAAO,EACPxkF,IAAMjO,IAAIpe,cAAc1W,KAAKW,UAAWX,KAAKkB,iBAE5CoS,KAAKlJ,QAAQspB,OAIdA,KAAK,GAAK1zB,KAAKmkH,eAAe,IAC9BzwF,KAAK,GAAK1zB,KAAKmkH,eAAe,IAC9BzwF,KAAK,GAAK1zB,KAAKmkH,eAAe,IAC9BzwF,KAAK,GAAK1zB,KAAKmkH,eAAe,KAI7B7wG,KAAKzU,OAAO2mH,WACbA,QAAU,SAGdp9B,GAAKpoF,KAAK+kB,MACVsjE,GAAKroF,KAAKglB,WAEL8tB,YAAc34B,SAAS4oB,IAAIzrB,MAAO,SAClCy7B,aAAe54B,SAAS4oB,IAAIxrB,OAAQ,IACzCub,EAAI9yB,KAAK8yC,YACT/0B,EAAI/d,KAAK+yC,aACL6hE,sBACK7vF,MAAQ+N,GAAKY,KAAK,GAAKA,KAAK,SAC5B1O,MAAQjH,GAAK2V,KAAK,GAAKA,KAAK,IAC7BhnB,KAAKwC,IAAIlP,KAAK+kB,OAASrY,KAAKwC,IAAIlP,KAAKglB,aAChCA,MAAQtY,KAAKwC,IAAIlP,KAAK+kB,OAAS/kB,KAAKglB,MAAQtY,KAAKwC,IAAIlP,KAAKglB,OAE/DuiG,KAAgD,IAAxCxpG,EAAI/d,KAAKglB,OAAS0O,KAAK,GAAKA,KAAK,YAEpC3O,MAAQrY,KAAKwC,IAAIlP,KAAKglB,OAAShlB,KAAK+kB,MAAQrY,KAAKwC,IAAIlP,KAAK+kB,OAE/DuiG,KAAgD,IAAxCx0F,EAAI9yB,KAAK+kB,OAAS2O,KAAK,GAAKA,KAAK,WAExCkhF,iBAAkB,SAElB7vF,MAAQ+N,GAAKY,KAAK,GAAKA,KAAK,SAC5B1O,MAAQjH,GAAK2V,KAAK,GAAKA,KAAK,SAC5BkhF,iBAAkB,QAGtBmH,YAAY/7G,KAAK+kB,OAAS2O,KAAK,GAAK4zF,MAAOtnH,KAAKglB,OAAS0O,KAAK,GAAK6zF,OAExD,WAAZ/B,cACK73C,OAAS3tE,KAAK+kB,MAAQqjE,QACtBxa,OAAS5tE,KAAKglB,MAAQqjE,IACR,UAAZm9B,eACF73C,MAAQr6D,KAAKzU,OAAOmB,KAAKqM,KAAKm7G,OAASxnH,KAAKqM,KAAKm7G,MAAQ,OACzD55C,MAAQt6D,KAAKzU,OAAOmB,KAAKqM,KAAKo7G,OAASznH,KAAKqM,KAAKo7G,MAAQ,IAxCvDznH,MAPAA,MAyDfszC,eAAgB,eACR2wE,GAAM,IAAI9/F,OAAO3a,MAAMzH,iBAAkB,CAAC,EAAG,GAAI/B,MAAOgO,UACxDk2G,GAAM,IAAI//F,OAAO3a,MAAMzH,iBAAkB,CAAC/B,KAAK8yC,YAAa9yC,KAAK+yC,cAAe/yC,MAAOgO,gBAEpF,CAACi2G,GAAG,GAAIA,GAAG,GAAIC,GAAG,GAAIA,GAAG,KASpClxB,aAAc,SAAUrzF,aAChB+/B,KAAO1/B,iBAENi1G,iBAAiBt1G,QAAQxC,IAAMwC,QAE/BK,KAAK0nH,6BACDA,sBAAwB1mH,OAAO68F,aAAY,WAC5Cn+D,KAAK2wD,YACN1wF,QAAQS,MAAMiM,KAAKgmF,iBAGnBryF,MAOX2nH,iBAAkB,eACVt5G,OAECA,MAAMrO,KAAKi1G,iBACRj1G,KAAKi1G,iBAAiB97G,eAAekV,KAAOiF,KAAKzU,OAAOmB,KAAKi1G,iBAAiB5mG,YACzE4mG,iBAAiB5mG,IAAM,YACrBrO,KAAKi1G,iBAAiB5mG,YAIrCrN,OAAOi9F,cAAcj+F,KAAK0nH,8BACnB1nH,KAAK0nH,sBAEL1nH,MAQXqwF,QAAS,eACDu3B,MAAOv5G,GAAIyB,EAAGksC,UAAWxsC,EAAGzS,EAAG6S,EAAGi4G,MAClC5pF,MAAQ,EACRzkC,IAAM,SAEL6U,MAAMrO,KAAKi1G,oBACRj1G,KAAKi1G,iBAAiB97G,eAAekV,KAAOiF,KAAKzU,OAAOmB,KAAKi1G,iBAAiB5mG,KAAM,IACpF4vB,OAAS,GACTnuB,EAAI9P,KAAKi1G,iBAAiB5mG,KAEpBiwF,gBAEEtiD,UADA1oC,KAAKnJ,WAAW2F,EAAEwuF,eACNxuF,EAAEwuF,eAAc,IAAItjF,MAAOwjF,UAAY1uF,EAAEyuF,gBAEzCzuF,EAAEwuF,cAAc73D,OAG1BnzB,KAAKzU,OAAOm9C,aAAiB1oC,KAAKlJ,QAAQ4xC,YAActtC,MAAMstC,kBACzDlsC,EAAEwuF,eAETxuF,EAAEgiF,oBAAoBtoF,MAAM1H,eAAgBk6C,WAC5ClsC,EAAEkvE,aACFxlF,IAAMsW,IAGVA,EAAE+iF,cAAe,KAGZrjF,KAFLI,EAAI,EAEME,EAAE+iF,cACJ/iF,EAAE+iF,cAAc15F,eAAeqW,KAC/BzS,EAAI+S,EAAE+iF,cAAcrjF,GAAGi3B,MAElBnzB,KAAKzU,OAAO9B,IAGb6S,GAAK,GACLg4G,MAAQ,IACFp4G,GAAKzS,EACX+S,EAAEo1E,aAAa0iC,eALR93G,EAAE+iF,cAAc91F,IAUzB,IAAN6S,UACOE,EAAE+iF,cAIZv/E,KAAKzU,OAAOiR,EAAE+iF,gBAAmBv/E,KAAKzU,OAAOiR,EAAEwuF,sBAC3C2W,iBAAiB5mG,IAAM,YACrBrO,KAAKi1G,iBAAiB5mG,IAEzBiF,KAAKzU,OAAOiR,EAAEijF,qBACd80B,MAAQ/3G,EAAEijF,kBACVjjF,EAAEijF,kBAAoB,KACtB80B,iBAMF,IAAV5pF,OACAj9B,OAAOi9F,cAAcj+F,KAAK0nH,8BACnB1nH,KAAK0nH,4BAEPltF,OAAOhhC,KAGTwG,MAeXs3G,aAAc,SAAUpqE,IAAKK,KAAMu6E,cAC3BC,MAAOC,QAASvuH,KAAMmwG,MAAOtvG,EAAG2tH,WAAYC,aAAc,MAWzDF,WATL96E,IAAMltC,KAAKO,OAAO2sC,KAClBK,KAAOvtC,KAAKO,OAAOgtC,MAEfj6B,KAAKzU,OAAOquC,IAAIh9B,SAChB+3G,WAAa/6E,IAAIh9B,MAAM/S,GACvB+qH,aAAc,OACTxxB,aAAaxpD,IAAIh9B,QAGVg9B,IAAIiiD,iBACZjiD,IAAIiiD,cAAch2F,eAAe6uH,SAAU,KAItCvuH,QAFLmwG,OAAQ,EADRme,MAAQ76E,IAAIiiD,cAAc64B,SAIlBD,MAAM5uH,eAAeM,OACjBsuH,MAAMtuH,QAAWyzC,MACjB66E,MAAMtuH,MAAQ8zC,KACdq8D,OAAQ,OAKhBA,cACO18D,IAAIiiD,cAAc64B,SAGxB1tH,EAAI,EAAGA,EAAIytH,MAAM/7G,QAAQnR,OAAQP,IAC9BytH,MAAM/7G,QAAQ1R,KAAO4yC,IAAI/vC,KACzB4qH,MAAM/7G,QAAQ1R,GAAKizC,KAAKpwC,IAIhCowC,KAAKshD,SAASk5B,cAMlBD,WACII,qBACO36E,KAAK4hD,cAAc84B,mBACnB16E,KAAKkiD,YAAYw4B,aAGxB16E,KAAKr9B,YACAwmF,aAAanpD,KAAKr9B,cAGpBlQ,KAAK4J,eAAe2jC,KAAK3zC,MAChC2zC,KAAK3zC,KAAOszC,IAAItzC,KACZsuH,aACA36E,KAAK+mD,oBAIRoC,aAAaxpD,KAEd55B,KAAKzU,OAAO0uC,KAAK3zC,OAAuB,KAAd2zC,KAAK3zC,YAC1BgQ,eAAe2jC,KAAK3zC,MAAQ2zC,WAGhCyxC,aAEEh/E,MAQXmoH,sBAAuB,SAAUp9C,gBACzB9tE,EAAG6S,KAEFwD,KAAKzU,OAAOksE,cACbA,WAAa,QAGb/qE,KAAKk2G,eAAiBnrC,kBACf/qE,SAGN/C,KAAK+C,KAAK0J,QACP1J,KAAK0J,QAAQvQ,eAAe8D,KAC5B6S,EAAI9P,KAAK0J,QAAQzM,GAEE,SAAf8tE,YAC0B,SAAtB/qE,KAAKk2G,eAKLpmG,EAAEs4G,gBAAkB,CAChBz2G,YAAa7B,EAAEiD,QAAQpB,YACvBR,UAAWrB,EAAEiD,QAAQ5B,UACrBwtE,qBAAsB7uE,EAAEiD,QAAQ4rE,qBAChCD,mBAAoB5uE,EAAEiD,QAAQ2rE,qBAGtC5uE,EAAEo1E,aAAa,CACXvzE,YAAa27D,MAAMxC,OAAOx3D,KAAKrG,SAAS6C,EAAEs4G,gBAAgBz2G,aAAco5D,YACxE55D,UAAWm8D,MAAMxC,OAAOx3D,KAAKrG,SAAS6C,EAAEs4G,gBAAgBj3G,WAAY45D,YACpE4T,qBAAsBrR,MAAMxC,OAAOx3D,KAAKrG,SAAS6C,EAAEs4G,gBAAgBzpC,sBAAuB5T,YAC1F2T,mBAAoBpR,MAAMxC,OAAOx3D,KAAKrG,SAAS6C,EAAEs4G,gBAAgB1pC,oBAAqB3T,eAEnFz3D,KAAKzU,OAAOiR,EAAEs4G,kBACrBhqH,IAAIC,OAAOyR,EAAEiD,QAASjD,EAAEs4G,8BAI/BlS,aAAenrC,gBACfvwC,SAEEx6B,MAgCXO,OAAQ,SAAU6R,IAAKi2G,oBACfC,MAAOC,MAAOjuH,EAAGwY,EACjBzS,EAAI+R,OAEE,OAAN/R,SACOA,KAIPiT,KAAKvJ,SAAS1J,IAAY,KAANA,EAEhBiT,KAAKzU,OAAOmB,KAAK0J,QAAQrJ,IACzBA,EAAIL,KAAK0J,QAAQrJ,GAEViT,KAAKzU,OAAOmB,KAAK4J,eAAevJ,IACvCA,EAAIL,KAAK4J,eAAevJ,GAEjBiT,KAAKzU,OAAOmB,KAAK8J,OAAOzJ,MAC/BA,EAAIL,KAAK8J,OAAOzJ,SAGjB,IAAKgoH,iBACP/0G,KAAKnJ,WAAW9J,IACfiT,KAAK/I,SAASlK,KAAOiT,KAAKnJ,WAAW9J,EAAE6kF,eACtC,KAGHqjC,MAAQ,GACRz1G,GAHAw1G,MAAQh1G,KAAKd,eAAexS,KAAK24D,YAAat4D,IAGpCxF,OACLP,EAAI,EAAGA,EAAIwY,EAAGxY,IACfiuH,MAAMD,MAAMhuH,GAAG6C,IAAMmrH,MAAMhuH,GAE/B+F,EAAI,IAAI0zG,YAAYwU,YAEbj1G,KAAK/I,SAASlK,IAAMiT,KAAKzU,OAAOwB,EAAElD,MAAQmW,KAAKzU,OAAOmB,KAAK0J,QAAQrJ,EAAElD,OAC5EkD,EAAI,aAGDA,GASX20E,SAAU,SAAUlnE,EAAGiT,OACf+4C,GAAKhsD,EACLisD,GAAKh5C,EACL2S,KAAO1zB,KAAKszC,wBAEZhgC,KAAKzU,OAAOiP,IAAMwF,KAAKlJ,QAAQ0D,EAAEE,aACjC8rD,GAAKhsD,EAAEE,UAAU,GACjB+rD,GAAKjsD,EAAEE,UAAU,OAGXsF,KAAKrJ,SAAS6vD,KAAOxmD,KAAKrJ,SAAS8vD,KACzCrmC,KAAK,GAAKomC,IAAMA,GAAKpmC,KAAK,IAAMA,KAAK,GAAKqmC,IAAMA,GAAKrmC,KAAK,KAWlEwlF,oBAAqB,eACb1/G,IAAMwG,KAAKomF,aACXt2E,EAAItW,IACJuf,GAAKvf,aAEJy/G,YAAcnkF,IAAIva,sBAAsBzK,GAS7CA,EAAIA,EAAEwJ,aACCxJ,GAAG,UACDmpG,YAAc/0F,IAAIxE,WAAWoV,IAAIva,sBAAsBzK,GAAI9P,KAAKi5G,aAErElgG,GAAKA,GAAGU,WACDV,KAAOjJ,QACLmpG,YAAc/0F,IAAIxE,WAAWoV,IAAIva,sBAAsBzK,GAAI9P,KAAKi5G,aACrElgG,GAAKA,GAAGU,YAAcV,GAAGyvG,KAG7B14G,EAAIA,EAAEwJ,yBAEL2/F,YAAc/0F,IAAIjE,QAAQjgB,KAAKi5G,aAE7Bj5G,MAyFXyoH,mBAAoB,gBACX5R,eAAgB,OAChB6R,iBAAiBxjC,aAAa,CAACjzE,SAAS,SACxCglG,aAAe,CAAC,CAAC,EAAG,GAAI,CAAC,EAAG,SAC5B0R,mCACAD,iBAAiB1pC,cAU1BoiC,kBAAmB,uBACVvK,eAAgB,OAChB6R,iBAAiBxjC,aAAa,CAACjzE,SAAS,IACtC,CAACjS,KAAK0oH,iBAAiB5rE,SAAS,GAAGjvC,OAAQ7N,KAAK0oH,iBAAiB5rE,SAAS,GAAGjvC,SASxFkzG,gBAAiB,SAAUllE,UAClBi7D,aAAc,OACdG,aAAe,CAAE,CAACp7D,IAAI,GAAIA,IAAI,IAAK,CAACA,IAAI,GAAIA,IAAI,UAChD8sE,+BAQTzH,eAAgB,SAAUrlE,KAClB77C,KAAK82G,mBACAG,aAAa,GAAK,CAACp7D,IAAI,GAAIA,IAAI,SAC/B8sE,mCACAD,iBAAiB1pC,eAS9BmiC,eAAiB,SAAU1tG,SACnBooC,IAAM77C,KAAK+4G,iBAAiBtlG,UAE3BqjG,aAAc,OACdG,aAAa,GAAK,CAACp7D,IAAI,GAAIA,IAAI,SAC/B8sE,+BAOTA,4BAA6B,eAClBtoG,EAAIrgB,KAAKi3G,aAAa,GACzBz1E,EAAIxhC,KAAKi3G,aAAa,QAElByR,iBAAiB5rE,SAAS,GAAGg1C,oBAAoB1zF,IAAI2D,iBAAkB,CAACse,EAAE,GAAIA,EAAE,UAChFqoG,iBAAiB5rE,SAAS,GAAGg1C,oBAAoB1zF,IAAI2D,iBAAkB,CAACse,EAAE,GAAImhB,EAAE,UAChFknF,iBAAiB5rE,SAAS,GAAGg1C,oBAAoB1zF,IAAI2D,iBAAkB,CAACy/B,EAAE,GAAIA,EAAE,UAChFknF,iBAAiB5rE,SAAS,GAAGg1C,oBAAoB1zF,IAAI2D,iBAAkB,CAACy/B,EAAE,GAAInhB,EAAE,MAQ5FygG,kBAAmB,SAAUrtG,KACrBzT,KAAK67G,sBAAsBpoG,IAAK,eAC3BH,KAAKzU,OAAOmB,KAAK0oH,wBACbE,wBAAwB5oH,KAAKqM,WAEjCo8G,uBAUbG,wBAAyB,SAASv8G,UAC1Bw8G,qBAECv1G,KAAKzU,OAAOmB,KAAK0oH,oBAEY,KAD9BG,cAAgBv1G,KAAK9G,eAAeH,KAAMy/D,QAAS,QAAS,cAC1CyB,eACTm7C,iBAAmB1oH,KAAK4M,OAAO,UAAW,CAAC,CAAC,EAAG,GAAI,CAAC,EAAG,GAAI,CAAC,EAAG,GAAI,CAAC,EAAG,IAAKi8G,gBAIlF7oH,MAgBXs4F,YAAa,SAAUr7F,KAQvBs7F,iBAAkB,SAAUt7F,KAQ5Bu7F,eAAgB,SAAUv7F,KAS1B6rH,mBAAoB,SAAU7rH,KAQ9B8rH,kBAAmB,SAAU9rH,KAQ7By7F,UAAW,SAAUz7F,KAQrB07F,eAAgB,SAAU17F,KAS1B+rH,iBAAkB,SAAU/rH,KAQ5BgsH,gBAAiB,SAAUhsH,KAU3B+6F,YAAa,SAAU/6F,EAAGk4G,QAU1Bld,iBAAkB,SAAUh7F,EAAGk4G,QAU/B+T,eAAgB,SAAUjsH,EAAGk4G,QAW7BgU,mBAAoB,SAAUlsH,EAAGk4G,QAUjCiU,iBAAkB,SAAUnsH,EAAGk4G,QA8B/BkU,WAAY,SAAUpsH,EAAGoR,GAAIw+E,UAW7By8B,gBAAiB,SAAUrsH,EAAGoR,GAAIw+E,UAOlC9mE,cAAe,aAOfwjG,mBAAoB,aAQnBC,sBAAuB,aASvBC,2BAA4B,aAS5BC,6BAA8B,aAS9BC,2BAA4B,aAO5BC,qBAAsB,aAQtBC,0BAA2B,aAQ3BC,4BAA6B,aAQ7BC,0BAA2B,aAO3BC,qBAAsB,aAQtBC,0BAA2B,aAQ3BC,4BAA6B,aAQ7BC,0BAA2B,aAK5BnkG,MAAO,aA4EPskE,aAAc,SAAUntF,QAChB0e,QAASuuG,UAAWC,kBAExBltH,GAAKA,IAAM6C,KAAKW,eACX2pH,qBAAuBntH,GAC5BktH,WAAarqH,KAAKkB,SAASC,eAAehE,IAC1C0e,QAAU,kBAAoB1e,GAG1B6C,KAAKkB,SAASC,eAAe0a,SAC7BuuG,UAAYpqH,KAAKkB,SAASC,eAAe0a,WAEzCuuG,UAAYlpH,SAAS2T,cAAc,QACzBq1E,UAAUh/D,IAAI,oBACxBk/F,UAAUllC,aAAa,KAAMrpE,SAC7BwuG,WAAW5wG,WAAW6xE,aAAa8+B,UAAWC,YAC9CD,UAAU/tG,YAAYguG,kBAKrBE,gBAAkBz1F,IAAI5Z,iBAAiBmvG,YAG5CD,UAAUI,kBAAoBJ,UAAUI,mBACpCJ,UAAUK,yBACVL,UAAUM,sBACVN,UAAUO,oBAEVP,UAAUI,mBACVJ,UAAUI,oBAGPxqH,MAUXo+G,mBAAoB,SAAU3qG,SACtBgM,IAAK3D,SAAUuuG,cAEnBvuG,SAAW9b,KAAKsqH,qBACXh3G,KAAKzU,OAAOid,mBAIZ5a,SAAS0pH,kBAAoB5qH,KAAKkB,SAAS0pH,mBACxC5qH,KAAKkB,SAAS2pH,yBACd7qH,KAAKkB,SAAS4pH,sBACd9qH,KAAKkB,SAAS6pH,oBAEtBV,WAAarqH,KAAKkB,SAASC,eAAe2a,UAItC9b,KAAKkB,SAAS0pH,kBAIdnrG,IAAMzf,KAAKuqH,gBAOXF,WAAWhkC,oBAAsB,CAC7BlpF,GAAI6C,KAAKkB,SAAS0pH,kBAAkBztH,GACpC6tH,cAAc,EACd34E,OAAQg4E,WAAWjzG,MAAMi7B,OACzB/6B,MAAO+yG,WAAWjzG,MAAME,MACxBmE,MAAOgE,IAAIhE,MACXD,OAAQiE,IAAIjE,QAGhB6uG,WAAWjzG,MAAMi7B,OAAS,GAC1Bg4E,WAAWjzG,MAAME,MAAQmI,IAAInI,MAAQ,KAKrCwd,IAAIlZ,iBAAiB1a,SAAS0pH,kBAAkBztH,GAAI2e,SAAU2D,IAAIhE,MAAOgE,IAAIjE,aAIxEta,SAAS0pH,kBAAoB,UAE/B,GAAIt3G,KAAKzU,OAAOwrH,WAAWhkC,qBAAsB,UAK3CnlF,SAAS6a,YAAY/b,KAAKkB,SAAS6a,YAAYlhB,OAAS,GAAG6hB,WAAW,GAC7E,MAAOtI,KACLnT,QAAQK,IAAI,6DAGhB+oH,WAAWhkC,oBAAoB2kC,cAAe,EAC9CX,WAAWjzG,MAAMi7B,OAASg4E,WAAWhkC,oBAAoBh0C,OACzDg4E,WAAWjzG,MAAME,MAAQ+yG,WAAWhkC,oBAAoB/uE,WAGvD4hG,wBAyET+R,eAAgB,SAAUxqG,GAAIC,GAAIwqG,SAAUC,SAAU18D,UAAW0jC,KAAMi5B,eAC/D7tE,IAAMv9C,YAkIH,IAjIQ,eAeHqrH,OAdA7/E,MAAQ,EAAG8/E,GAAK,EAAGC,GAAK,EACxB9tF,GAAKytF,SACLxtF,GAAKvI,SAASiI,MACV,SAAUlkB,OACFsyG,IAAM/qG,GAAG2d,EAAEX,IACXguF,IAAMhrG,GAAG4d,EAAEZ,IACXiuF,IAAMhrG,GAAG0d,EAAEllB,GACXyyG,IAAMjrG,GAAG2d,EAAEnlB,UAEPsyG,IAAME,MAAQF,IAAME,MAAQD,IAAME,MAAQF,IAAME,OAE5D,CAAC,EAAa,EAAVj/G,KAAKiV,KAEbiqG,OAAS,EAAKC,OAAS,EAGvBh7E,SAAW0M,IAAI3wC,OAAO,YAAa,CAC/B,kBACW4+B,QAEZ,CAAC3gC,KAAM,WAEVihH,cAAgBvuE,IAAI3wC,OAAO,YAAa,CACpC,kBACW4+B,OAEX,kBACW/qB,GAAG2d,EAAEX,KAEhB,kBACWhd,GAAG4d,EAAEZ,MAEjB,CAAC5yB,KAAM,WAEV+tG,UAAYr7D,IAAI3wC,OAAO,YAAa,CAChC,kBACW0+G,IAEX,kBACWC,KAEZ,CAAC1gH,KAAM,cAGVkhH,OAAS,SAAUn8G,EAAGvC,EAAG3M,OACjBsrH,KAAO72F,SAAS+H,EAAEttB,EAAEwuB,EAAbjJ,CAAgB9nB,GACvB4+G,KAAO92F,SAAS+H,EAAEttB,EAAEyuB,EAAblJ,CAAgB9nB,GACvB6+G,KAAO/2F,SAAS+H,EAAEttB,EAAEwuB,EAAbjJ,CAAgBz0B,GACvByrH,KAAOh3F,SAAS+H,EAAEttB,EAAEyuB,EAAblJ,CAAgBz0B,GACvB0rH,MAAQj3F,SAAS+H,EAAEttB,EAAEwuB,EAAbjJ,CAA0B,IAAT9nB,EAAI3M,IAC7B2rH,MAAQl3F,SAAS+H,EAAEttB,EAAEyuB,EAAblJ,CAA0B,IAAT9nB,EAAI3M,IAE7ByiC,GAAKz2B,KAAKmU,KAAKmrG,KAAOA,KAAOC,KAAOA,MACpC7oF,GAAK12B,KAAKmU,KAAKqrG,KAAOA,KAAOC,KAAOA,aAGhChpF,GAAK,EAFHz2B,KAAKmU,KAAKurG,MAAQA,MAAQC,MAAQA,OAErBjpF,KAAO1iC,EAAI2M,GAAK,GAG3Ci/G,UAAY,SAAUpzG,UACXmyG,OAASU,OAAOrrG,GAAIgd,GAAIxkB,IAGnCga,KAAOxmB,KAAKiV,GAAK,GACjB4qG,MAAe,EAAPr5F,KACR5E,SAAW,iBAEVk+F,QAAU,eACPzuG,EAAGqE,EAAGqqG,GAAIC,GAAI9kG,EAKlByjG,OAASU,OAAOtrG,GAAIgd,GAHpBmuF,OAASnuF,GAAKgxB,UAAY08D,UAM1BU,OAAS12F,SAASiI,KAAKkvF,UAAW5uF,IAGlC3f,EAAI,IAAIqhD,QAAQ3+C,GAAG2d,EAAEwtF,QAASnrG,GAAG4d,EAAEutF,SAGnCxpG,EAAI,IAAIg9C,QAAQ1+C,GAAG0d,EAAEytF,QAASnrG,GAAG2d,EAAEwtF,SAEnCY,GAAK,IAAIrtD,QAAQjqC,SAAS+H,EAAEzc,GAAG2d,EAAdjJ,CAAiBy2F,QAASz2F,SAAS+H,EAAEzc,GAAG4d,EAAdlJ,CAAiBy2F,SAC5Dc,GAAK,IAAIttD,QAAQjqC,SAAS+H,EAAExc,GAAG0d,EAAdjJ,CAAiB02F,QAAS12F,SAAS+H,EAAExc,GAAG2d,EAAdlJ,CAAiB02F,SAG5DjkG,EAAIw3C,QAAQ/vB,EAAE94B,IAAIk2G,GAAIC,IAEtBlhF,MAAQ9+B,KAAKypB,MAAMvO,EAAE03C,UAAW13C,EAAE23C,MAElC33C,EAAErR,IAAI6oD,QAAQ/vB,EAAEngC,IAAI0Y,IACpBA,EAAE63C,KAAKr9C,GACPkpG,GAAKvtG,EAAEwhD,KAAO33C,EAAE23C,KAGhBgsD,GAAKxtG,EAAEuhD,UAAY13C,EAAE03C,UAGjB9zB,OAAStY,MAAQsY,OAAS+gF,OAC1B/gF,OAAStY,KACT44F,cAAcp6B,UAAU05B,YACjB5/E,MAAQtY,MAAQsY,MAAQ+gF,OAC/B/gF,MAAQtY,KACR44F,cAAcp6B,UAAU05B,aAExBv6E,SAAS6gD,UAAU05B,WACnBxS,UAAUlnB,UAAU05B,WACpB3tF,GAAKmuF,OACLluF,GAAKmuF,QAETtuE,IAAI/iB,eAGHpgB,MAAQ,kBACL+3E,KAAO,IACP7jE,SAAWttB,OAAO68F,YAAY79F,KAAKwsH,QAASr6B,OAEzCnyF,WAGN2sH,KAAO,kBACR3rH,OAAOi9F,cAAc3vE,UACdtuB,MAEJA,SAMhB5B,IAAIg2G,SAgDfh8G,OAAO,eAAe,CAClB,MAAO,UAAW,oBAAqB,iBAAkB,aAAc,cAAe,eAAgB,kBACvG,SAAUgG,IAAK0tE,QAASqT,iBAAkB31E,MAAO8J,KAAMg6D,MAAOzZ,OAAQ1+B,iBAcrE/2B,IAAIwuH,YAAc,SAAUjsH,UAAWoiC,SAC/BzoC,WAGCuQ,KAAO,WAEPgiH,MAAiD,IAA1Cx3G,UAAUc,WAAW/Z,QAAQ,SAAkBiZ,UAAUO,UAAUqxE,MAAM,kBAMhFigC,QAAU,UAQV4F,aAAe,kCAQfC,eAAiB,oCAGjBpsH,UAAYA,eAGZA,UAAUyW,MAAM41G,cAAgB,YAChCrsH,UAAUyW,MAAM61G,WAAa,YAE7BtsH,UAAUyW,MAAM81G,SAAW,SACM,KAAlCltH,KAAKW,UAAUyW,MAAMS,gBAChBlX,UAAUyW,MAAMS,SAAW,iBAG/BqvG,QAAUlnH,KAAKW,UAAUiZ,cAAcuzG,gBAAgBntH,KAAK8sH,aAAc,YAC1E5F,QAAQ9vG,MAAM81G,SAAW,cACzBhG,QAAQ9vG,MAAMP,QAAU,aAExB85D,OAAO5tC,IAAIzrB,MAAOyrB,IAAIxrB,aAItB5W,UAAU0b,YAAYrc,KAAKknH,cAO3BkG,KAAOptH,KAAKW,UAAUiZ,cAAcuzG,gBAAgBntH,KAAK8sH,aAAc,aACvE5F,QAAQ7qG,YAAYrc,KAAKotH,WAOzB36G,OAASzS,KAAKW,UAAUiZ,cAAcuzG,gBAAgBntH,KAAK8sH,aAAc,eACzEr6G,OAAO46G,eAAe,KAAM,KAAMrtH,KAAKW,UAAUxD,GAAf6C,YAQlCyS,OAAO46G,eAAe,KAAM,QAAS,aACrC56G,OAAO46G,eAAe,KAAM,SAAU,aACtC56G,OAAO46G,eAAe,KAAM,cAAe,uBAE3CC,SAAWttH,KAAKW,UAAUiZ,cAAcuzG,gBAAgBntH,KAAK8sH,aAAc,iBAC3EQ,SAASD,eAAe,KAAM,SAAU,eACxCC,SAASD,eAAe,KAAM,KAAM,oBACpCC,SAASD,eAAe,KAAM,KAAM,UACpCC,SAASD,eAAe,KAAM,KAAM,UACpC56G,OAAO4J,YAAYrc,KAAKstH,eAExBC,eAAiBvtH,KAAKW,UAAUiZ,cAAcuzG,gBAAgBntH,KAAK8sH,aAAc,uBACjFS,eAAeF,eAAe,KAAM,SAAU,gBAC9CE,eAAeF,eAAe,KAAM,KAAM,eAC1CE,eAAeF,eAAe,KAAM,eAAgB,UACpD56G,OAAO4J,YAAYrc,KAAKutH,qBAExBC,QAAUxtH,KAAKW,UAAUiZ,cAAcuzG,gBAAgBntH,KAAK8sH,aAAc,gBAC1EU,QAAQH,eAAe,KAAM,KAAM,sBACnCG,QAAQH,eAAe,KAAM,MAAO,gBACpCG,QAAQH,eAAe,KAAM,OAAQ,eACrC56G,OAAO4J,YAAYrc,KAAKwtH,cAExBJ,KAAK/wG,YAAYrc,KAAKyS,aAQtBxC,MAAQ,GACR3V,EAAI,EAAGA,EAAIwxE,QAAQ77D,MAAMglE,UAAW36E,SAChC2V,MAAM3V,GAAK0F,KAAKW,UAAUiZ,cAAcuzG,gBAAgBntH,KAAK8sH,aAAc,UAC3E5F,QAAQ7qG,YAAYrc,KAAKiQ,MAAM3V,SAInCglF,sBAAwBp+E,SAASsT,eAAeC,WAAW,+CAAgD,OAE5GzU,KAAKs/E,6BACAmuC,gBAAkBztH,KAAKW,UAAUiZ,cAAcuzG,gBAAgBntH,KAAK8sH,aAAc,sBAClFW,gBAAgBvoC,aAAa,UAAW,aACxCuoC,gBAAgBvoC,aAAa,IAAK,QAClCuoC,gBAAgBvoC,aAAa,IAAK,QAClCuoC,gBAAgBvoC,aAAa,QAAS,aACtCuoC,gBAAgBvoC,aAAa,SAAU,aACvCuoC,gBAAgBvoC,aAAa,KAAMllF,KAAKW,UAAUxD,GAAK,oBACvD+pH,QAAQ7qG,YAAYrc,KAAKytH,uBAe7BC,UAAY,CAAC,OAAQ,OAAQ,SAAU,SAAU,iBAAkB,iBAG5EtvH,IAAIwuH,YAAY1zH,UAAY,IAAIimF,iBAEhC/gF,IAAIC,OAAOD,IAAIwuH,YAAY1zH,UAAmD,CAS1Ey0H,iBAAkB,SAAUt/G,GAAIu/G,WAAY/iH,UACpCgjH,MAAOC,MAGP9jH,EAAG+T,EAFH5gB,GAAKkR,GAAGlR,GAAK,kBAIbmW,KAAKzU,OAAO+uH,cACZzwH,IAAMywH,aAEVC,MAAQ7tH,KAAK6gF,WAAW,SAAU1jF,KAE5BkwH,eAAe,KAAM,SAAU/5G,KAAKrG,SAASoB,GAAG0E,QAAQpB,cAC9Dk8G,MAAMR,eAAe,KAAM,iBAAkB/5G,KAAKrG,SAASoB,GAAG0E,QAAQnB,gBACtEi8G,MAAMR,eAAe,KAAM,OAAQ/5G,KAAKrG,SAASoB,GAAG0E,QAAQpB,cAC5Dk8G,MAAMR,eAAe,KAAM,eAAgB/5G,KAAKrG,SAASoB,GAAG0E,QAAQnB,gBACpEi8G,MAAMR,eAAe,KAAM,eAAgB,GAG3CQ,MAAMR,eAAe,KAAM,SAAU,QACrCQ,MAAMR,eAAe,KAAM,cAAe,eAyB1CS,MAAQ9tH,KAAKW,UAAUiZ,cAAcuzG,gBAAgBntH,KAAK8sH,aAAc,QACxE/uG,EAAI,EACe,QAAf6vG,YAOA5jH,EAAI,EACS,IAATa,KACAijH,MAAMT,eAAe,KAAM,IAAK,gCAChB,IAATxiH,KACPijH,MAAMT,eAAe,KAAM,IAAK,qCAChB,IAATxiH,MAEPkT,EAAI,KACJ+vG,MAAMT,eAAe,KAAM,IAAK,kJAChB,IAATxiH,MAEPkT,EAAI,KACJ+vG,MAAMT,eAAe,KAAM,IAAK,kJAChB,IAATxiH,MAEPkT,EAAI,KACJ+vG,MAAMT,eAAe,KAAM,IAAK,kJAChB,IAATxiH,MAEPkT,EAAI,IACJ+vG,MAAMT,eAAe,KAAM,IAAK,+FAGhCS,MAAMT,eAAe,KAAM,IAAK,0BAEgBh/G,GAAG5D,eAAiBjB,MAAMvF,oBAEtE+F,EADS,IAATa,KACI,IACY,IAATA,KACH,IACY,IAATA,MAAuB,IAATA,MAAuB,IAATA,KAC/B,KACY,IAATA,KACH,EAEA,MAUZb,EAAI,GACS,IAATa,KACAijH,MAAMT,eAAe,KAAM,IAAK,+BAChB,IAATxiH,MACPb,EAAI,IACJ8jH,MAAMT,eAAe,KAAM,IAAK,sCAChB,IAATxiH,MAEPkT,EAAI,KACJ+vG,MAAMT,eAAe,KAAM,IAAK,kJAChB,IAATxiH,MAEPkT,EAAI,KACJ+vG,MAAMT,eAAe,KAAM,IAAK,kJAChB,IAATxiH,MAEPkT,EAAI,KACJ+vG,MAAMT,eAAe,KAAM,IAAK,kJAChB,IAATxiH,MAEPkT,EAAI,IACJ+vG,MAAMT,eAAe,KAAM,IAAK,+FAGhCS,MAAMT,eAAe,KAAM,IAAK,yBAEgBh/G,GAAG5D,eAAiBjB,MAAMvF,oBAEtE+F,EADS,IAATa,KACI,IACY,IAATA,KACH,IACY,IAATA,MAAuB,IAATA,MAAuB,IAATA,KAC/B,KACY,IAATA,KACH,GAEA,MAIH,IAATA,OACAgjH,MAAMR,eAAe,KAAM,OAAQ,QACnCQ,MAAMR,eAAe,KAAM,eAAgB,IAE/CQ,MAAMR,eAAe,KAAM,OAAQtvG,GACnC8vG,MAAMR,eAAe,KAAM,OAAQrjH,GAEnC6jH,MAAMxxG,YAAYyxG,OACXD,OAUXE,eAAgB,SAAU5yG,KAAM6tD,MAAO0B,QAASr8D,GAAIxD,MAC5CsQ,OACI7H,KAAKvJ,SAASi/D,SACD,IAATn+D,UACKmjH,eAAc,WACf7yG,KAAKkyG,eAAe,KAAM,SAAUrkD,OACpC7tD,KAAKkyG,eAAe,KAAM,OAAQrkD,OAClC7tD,KAAKkyG,eAAe,KAAM,iBAAkB3iD,SAC5CvvD,KAAKkyG,eAAe,KAAM,eAAgB3iD,WAC3Cr8D,GAAG0C,WAAWI,gBAEZ68G,eAAc,WACf7yG,KAAKkyG,eAAe,KAAM,OAAQ,QAClClyG,KAAKkyG,eAAe,KAAM,SAAUrkD,OACpC7tD,KAAKkyG,eAAe,KAAM,iBAAkB3iD,WAC7Cr8D,GAAG0C,WAAWI,YAIrBnR,KAAK6sH,MACLx+G,GAAGsyE,SAASlnE,WAAW6xE,aAAaj9E,GAAGsyE,SAAUtyE,GAAGsyE,YAOhEuD,eAAgB,SAAU/oE,KAAM7D,MAAOmC,WAAYggB,UAC3Cp5B,EAAG8K,EAEHgQ,OAMIhQ,GADA9K,EAAIiX,OACImiB,KACRte,KAAKkyG,eAAe,KAAM,UAAY,OAA4B,GAAJhtH,EAAU,IAAW,GAAJA,GAC/E8a,KAAKkyG,eAAe,KAAM,eAAgBliH,GAC1CgQ,KAAKkyG,eAAe,KAAM,cAAeliH,GACzCgQ,KAAKkyG,eAAe,KAAM,UAAW,WAGrCrtH,KAAK6sH,MACLpzG,WAAWA,WAAW6xE,aAAa7xE,WAAYA,cAkB3D6qE,YAAa,SAAUpW,WACf5zE,EAAGC,EAAGqV,EAAGuL,KAAMrN,EAAGiT,EAGlB1G,KAAMjI,IAFN67G,QAAU,GACV7hH,IAAM8hE,MAAMA,MAAMrzE,OAElBirB,QAAS,MAERxrB,EAAI,EAAGA,EAAI8R,IAAK9R,IAAK,KAEtBwT,GADA8B,EAAIs+D,MAAMA,MAAM5zE,IACV,GACNymB,EAAInR,EAAE,GAENyK,KAAOvM,EAAEjT,OACTuX,IAAM,MAAQtE,EAAE,GAAK,IAAMiT,EAAE,GACxBzN,KAAKrJ,SAAS6D,EAAE,MACjBgY,QAAS,GAERvrB,EAAI,EAAGurB,QAAUvrB,EAAI8f,OAAQ9f,EAC1B+Y,KAAKrJ,SAAS6D,EAAEvT,IAChB6X,KAAO,MAAQtE,EAAEvT,GAAK,IAAMwmB,EAAExmB,GAE9BurB,QAAS,EAIbA,SACAmoG,SAAW77G,KAInB+I,KAAO+yD,MAAMyS,SAERrtE,KAAKzU,OAAOsc,QACbA,KAAOnb,KAAK6gF,WAAW,OAAQ3S,MAAM/wE,SAChCyjF,gBAAgBzlE,KAAM7H,KAAKrG,SAASihE,MAAMn7D,QAAQ9C,QACvDi+D,MAAMyS,SAAWxlE,MAGrBA,KAAKkyG,eAAe,KAAM,SAAU/5G,KAAKrG,SAASihE,MAAMn7D,QAAQpB,cAChEwJ,KAAKkyG,eAAe,KAAM,OAAQ,QAGlClyG,KAAKkyG,eAAe,KAAM,iBAAkB/5G,KAAKrG,SAASihE,MAAMn7D,QAAQnB,gBACxEuJ,KAAKkyG,eAAe,KAAM,eAAgB/5G,KAAKrG,SAASihE,MAAMn7D,QAAQlB,mBACjEuvE,eAAejmE,KAAM8yG,QAAS//C,MAAM9tE,QAQ7CwkF,iBAAkB,SAAUxyE,IAAKd,cAEzB4H,EADAiC,KAAOnb,KAAK6gF,WAAW,OAAQ,eAEnC1lE,KAAKkyG,eAAe,KAAM,IAAK,QAC/BlyG,KAAKkyG,eAAe,KAAM,IAAM,EAAI/7G,SAAY,MAChD6J,KAAKkyG,eAAe,KAAM,QAAS,qDAAuD/7G,SAAW,mCACrG4H,EAAIlZ,KAAKW,UAAUiZ,cAAc0C,eAAelK,KAChD+I,KAAKkB,YAAYnD,QACZ0nE,gBAAgBzlE,KAAM,IAI/B0pE,iBAAkB,SAAUx2E,QACpB8M,KAAOnb,KAAK6gF,WAAW,OAAQxyE,GAAGlR,WAKtCge,KAAK/D,MAAM82G,WAAa,SAExB7/G,GAAG8/G,aAAenuH,KAAKW,UAAUiZ,cAAc0C,eAAe,IAC9DnB,KAAKkB,YAAYhO,GAAG8/G,mBACfvtC,gBAAgBzlE,KAAM7H,KAAKrG,SAASoB,GAAG0E,QAAQ9C,QAE7CkL,MAIX2pE,mBAAoB,SAAUz2E,QACErE,EAAxBw7E,QAAUn3E,GAAGo3E,UACb2oC,MAAQ//G,GAAGs3E,aACX0oC,MAAQhgH,GAAGu3E,aAEXv3E,GAAGsyE,SAAS2tC,eAAe,KAAM,WAAajgH,GAAG0E,QAAQ/B,WACzD3C,GAAGsyE,SAAS0sC,eAAe,KAAM,QAAS/5G,KAAKrG,SAASoB,GAAG0E,QAAQ/B,WACnE3C,GAAGu5E,iBAAkB,GAGpBl5E,MAAML,GAAGR,OAAO0W,UAAU,GAAKlW,GAAGR,OAAO0W,UAAU,MAEpDva,EAAIqE,GAAGR,OAAO0W,UAAU,GACpBlW,GAAG0C,WAAWS,OAAU48G,MAAQpkH,IAChCqE,GAAGsyE,SAAS0sC,eAAe,KAAM,IAAKrjH,EAAI,MAE5B,SAAVokH,MACA//G,GAAGsyE,SAAS0sC,eAAe,KAAM,cAAe,SAC/B,UAAVe,MACP//G,GAAGsyE,SAAS0sC,eAAe,KAAM,cAAe,OAC/B,WAAVe,OACP//G,GAAGsyE,SAAS0sC,eAAe,KAAM,cAAe,UAEpDh/G,GAAG0C,WAAWS,KAAO48G,MAAQpkH,GAIjCA,EAAIqE,GAAGR,OAAO0W,UAAU,GACpBlW,GAAG0C,WAAWiB,MAASq8G,MAAQrkH,IAC/BqE,GAAGsyE,SAAS0sC,eAAe,KAAM,IAAMrjH,EAAuB,GAAnBhK,KAAKo/E,YAAqB,MAEvD,WAAVivC,MACAhgH,GAAGsyE,SAAS0sC,eAAe,KAAM,oBAAqB,mBACrC,QAAVgB,MACPhgH,GAAGsyE,SAAS0sC,eAAe,KAAM,KAAM,SAEtB,WAAVgB,OAEPhgH,GAAGsyE,SAAS0sC,eAAe,KAAM,KAAM,SAE3Ch/G,GAAG0C,WAAWiB,IAAMq8G,MAAQrkH,IAGhCqE,GAAG82E,UAAYK,UACfn3E,GAAG8/G,aAAatvF,KAAO2mD,QACvBn3E,GAAG82E,QAAUK,cAEZoB,eAAev4E,GAAIA,GAAGw4E,kBAU/BgB,wBAAyB,SAAUx5E,GAAI09D,YAAayF,cAAe8X,eAC1DpJ,mBAAmB7xE,GAAI09D,YAAayF,gBAQ7CsW,UAAW,SAAUz5E,QACb8M,KAAOnb,KAAK6gF,WAAW,QAASxyE,GAAGlR,IAEvCge,KAAKkyG,eAAe,KAAM,sBAAuB,aAC5CzsC,gBAAgBzlE,KAAM7H,KAAKrG,SAASoB,GAAG0E,QAAQ9C,QACpD5B,GAAGsyE,SAAWxlE,UAET4sE,YAAY15E,KAIrBu4E,eAAgB,SAAUv4E,GAAI6K,OACnBnL,EACHoN,KAAO9M,GAAGsyE,SACVvuE,IAAM,GACA8G,EAAEre,OAEF,IAGNuX,KAAO,WADH,EADJrE,EAAI/N,KAAKioF,eAAe55E,GAAI6K,IACrB,GAAG,GAAInL,EAAE,GAAG,GAAIA,EAAE,GAAG,GAAIA,EAAE,GAAG,GAAIA,EAAE,GAAG,GAAIA,EAAE,GAAG,IAAI3S,KAAK,KACxC,KACxB+f,KAAKkyG,eAAe,KAAM,YAAaj7G,OAK/C41E,eAAgB,SAAU35E,QAClB69E,IAAM54E,KAAKrG,SAASoB,GAAG69E,YAEvB79E,GAAGkgH,OAASriC,MACZ79E,GAAGmgH,aAAc,EACjBngH,GAAGsyE,SAAS0sC,eAAertH,KAAK+sH,eAAgB,aAAc7gC,KAC9D79E,GAAGkgH,KAAOriC,KAEH,IAOf5D,iBAAkB,SAAUj6E,GAAI0zE,iBACxB7nE,IAAM5G,KAAKrG,SAAS80E,YAAc1zE,GAAG0E,QAAQ40E,kBAAoBt5E,GAAG0E,QAAQ/B,UAEhF3C,GAAGsyE,SAAS0sC,eAAe,KAAM,QAASnzG,MAI9CquE,kBAAmB,SAAUl6E,IACzBA,GAAGsyE,SAAW3gF,KAAK4gF,gBAAgB5gF,KAAK6gF,WAAW,gBAAiBxyE,GAAGlR,IAC/CmW,KAAKrG,SAASoB,GAAG0E,QAAQ9C,aAE5C6wE,qBAAqBzyE,GAAI,sBACzBm6E,oBAAoBn6E,KAI7Bm6E,oBAAqB,SAASn6E,IACtBA,GAAGogH,aACHpgH,GAAGsyE,SAASvpE,MAAM81G,SAAW,SAE7B7+G,GAAGsyE,SAASvpE,MAAM81G,SAAW,eAG5B/rC,eAAe9yE,GAAGsyE,SAAUtyE,GAAGR,OAAO0W,UAAU,GACjDlW,GAAGR,OAAO0W,UAAU,GAAKlW,GAAGorB,KAAK,GAAIprB,GAAGorB,KAAK,GAAIprB,GAAGorB,KAAK,IAE7DprB,GAAGsyE,SAASv/E,UAAYiN,GAAGm3E,aACtBjG,cAAclxE,GAAI,CAACsxE,QAAQ,EAAM5M,MAAM,IAAO,IAQvD6N,gBAAiB,SAAUzlE,KAAM6e,cACxB1mB,KAAKzU,OAAOm7B,OAENA,OAAS8xC,QAAQ77D,MAAMglE,YAC9Bj7C,MAAQ8xC,QAAQ77D,MAAMglE,UAAY,GAFlCj7C,MAAQ,OAKP/pB,MAAM+pB,OAAO3d,YAAYlB,MAEvBA,MAIX0lE,WAAY,SAAUh2E,KAAM1N,QACpBge,KAAOnb,KAAKW,UAAUiZ,cAAcuzG,gBAAgBntH,KAAK8sH,aAAcjiH,aAC3EsQ,KAAKkyG,eAAe,KAAM,KAAMrtH,KAAKW,UAAUxD,GAAK,IAAMA,IAC1Dge,KAAK/D,MAAMS,SAAW,WACT,SAAThN,OACAsQ,KAAKkyG,eAAe,KAAM,iBAAkB,SAC5ClyG,KAAKkyG,eAAe,KAAM,kBAAmB,SAC7ClyG,KAAKkyG,eAAe,KAAM,YAAa,YAEpClyG,MAIXomE,OAAQ,SAAUmtC,OACVp7G,KAAKzU,OAAO6vH,QAAUp7G,KAAKzU,OAAO6vH,MAAMj1G,aACxCi1G,MAAMj1G,WAAWyD,YAAYwxG,QAKrC3iC,SAAU,SAAU19E,GAAI2rB,OACf1mB,KAAKzU,OAAOm7B,OAENA,OAAS8xC,QAAQ77D,MAAMglE,YAC9Bj7C,MAAQ8xC,QAAQ77D,MAAMglE,UAAY,GAFlCj7C,MAAQ,OAKP/pB,MAAM+pB,OAAO3d,YAAYhO,GAAGsyE,WAIrCyB,WAAY,SAAU/zE,GAAIhB,OAClBwgH,MACA9qC,MAAQ11E,EAAE41E,QACVD,MAAQ31E,EAAE61E,OAGV70E,GAAG0C,WAAWM,aAAe0xE,OAC7B10E,GAAG0C,WAAWQ,YAAcyxE,OAQ5BD,OACA8qC,MAAQx/G,GAAG81E,sBACN7wE,KAAKzU,OAAOgvH,YAMRT,KAAK/wG,YAAYwxG,QALtBA,MAAQ7tH,KAAK2tH,iBAAiBt/G,GAAI,MAAOhB,EAAEm1E,gBACtC4qC,KAAK/wG,YAAYwxG,OACtBx/G,GAAG81E,sBAAwB0pC,MAC3Bx/G,GAAGsyE,SAAS0sC,eAAe,KAAM,eAAgB,QAAUrtH,KAAKW,UAAUxD,GAAK,IAAMkR,GAAGlR,GAAK,mBAKjG0wH,MAAQx/G,GAAG81E,sBACP7wE,KAAKzU,OAAOgvH,aACPtsC,OAAOssC,QAGhB7qC,OACA6qC,MAAQx/G,GAAG+1E,oBACN9wE,KAAKzU,OAAOgvH,YAMRT,KAAK/wG,YAAYwxG,QALtBA,MAAQ7tH,KAAK2tH,iBAAiBt/G,GAAI,QAAShB,EAAEo1E,eACxC2qC,KAAK/wG,YAAYwxG,OACtBx/G,GAAG+1E,oBAAsBypC,MACzBx/G,GAAGsyE,SAAS0sC,eAAe,KAAM,aAAc,QAAUrtH,KAAKW,UAAUxD,GAAK,IAAMkR,GAAGlR,GAAK,qBAK/F0wH,MAAQx/G,GAAG+1E,oBACP9wE,KAAKzU,OAAOgvH,aACPtsC,OAAOssC,QAGpBx/G,GAAG0C,WAAWM,WAAa0xE,MAC3B10E,GAAG0C,WAAWQ,UAAYyxE,OAxClBhjF,KAAK6sH,MAAQx+G,GAAGmzE,YAAYvvE,UAC3B8wE,OAASC,QACV30E,GAAGsyE,SAASlnE,WAAW6xE,aAAaj9E,GAAGsyE,SAAUtyE,GAAGsyE,WA0ChEO,kBAAmB,SAAU/lE,KAAMrN,EAAGiT,EAAG+qC,GAAIE,QACrC2iE,KAEJA,KAAO,IAGP7gH,EAAIpB,KAAKwC,IAAIpB,GAAK6gH,KAAO7gH,EAAI6gH,KAAO7gH,EAAIpB,KAAKwC,IAAIpB,GACjDiT,EAAIrU,KAAKwC,IAAI6R,GAAK4tG,KAAO5tG,EAAI4tG,KAAO5tG,EAAIrU,KAAKwC,IAAI6R,GACjD+qC,GAAKp/C,KAAKwC,IAAI48C,IAAM6iE,KAAO7iE,GAAK6iE,KAAO7iE,GAAKp/C,KAAKwC,IAAI48C,IACrDE,GAAKt/C,KAAKwC,IAAI88C,IAAM2iE,KAAO3iE,GAAK2iE,KAAO3iE,GAAKt/C,KAAKwC,IAAI88C,IAErD7wC,KAAKkyG,eAAe,KAAM,KAAMv/G,GAChCqN,KAAKkyG,eAAe,KAAM,KAAMtsG,GAChC5F,KAAKkyG,eAAe,KAAM,KAAM3gH,KAAKwC,IAAI48C,KACzC3wC,KAAKkyG,eAAe,KAAM,KAAM3gH,KAAKwC,IAAI88C,MAI7Cw3B,eAAgB,SAAUroE,KAAMstE,IAAKC,IAAKC,IAAKC,SACvC+lC,KAEJA,KAAO,IACFjgH,MAAM+5E,IAAMC,IAAMC,IAAMC,OAGzBH,IAAM/7E,KAAKwC,IAAIu5E,KAAOkmC,KAAOlmC,IAAMkmC,KAAOlmC,IAAM/7E,KAAKwC,IAAIu5E,KACzDC,IAAMh8E,KAAKwC,IAAIw5E,KAAOimC,KAAOjmC,IAAMimC,KAAOjmC,IAAMh8E,KAAKwC,IAAIw5E,KACzDC,IAAMj8E,KAAKwC,IAAIy5E,KAAOgmC,KAAOhmC,IAAMgmC,KAAOhmC,IAAMj8E,KAAKwC,IAAIy5E,KACzDC,IAAMl8E,KAAKwC,IAAI05E,KAAO+lC,KAAO/lC,IAAM+lC,KAAO/lC,IAAMl8E,KAAKwC,IAAI05E,KAEzDztE,KAAKkyG,eAAe,KAAM,KAAM5kC,KAChCttE,KAAKkyG,eAAe,KAAM,KAAM3kC,KAChCvtE,KAAKkyG,eAAe,KAAM,KAAM1kC,KAChCxtE,KAAKkyG,eAAe,KAAM,KAAMzkC,OAKxCxH,eAAgB,SAAUjmE,KAAMyzG,aACR,KAAhBA,cACAA,YAAc,SAElBzzG,KAAKkyG,eAAe,KAAM,IAAKuB,cAInCvtC,sBAAuB,SAAUhzE,GAAIorB,KAAM5uB,UACnCxK,EAAI,GACJilB,IAAMjX,GAAGR,OAAO0W,UAChBsqG,OAASp1F,KAAO/sB,KAAKmU,KAAK,GAAK,GAC/BiuG,IAAa,GAAPr1F,WAEG,MAAT5uB,KACAxK,EAAI,OAASilB,IAAI,GAAKmU,MAAQ,KAAOnU,IAAI,GAAKmU,MAC1C,OAASnU,IAAI,GAAKmU,MAAQ,KAAOnU,IAAI,GAAKmU,MAC1C,OAASnU,IAAI,GAAKmU,MAAQ,KAAOnU,IAAI,GAAKmU,MAC1C,OAASnU,IAAI,GAAKmU,MAAQ,KAAOnU,IAAI,GAAKmU,MAC9B,MAAT5uB,KACPxK,EAAI,OAASilB,IAAI,GAAKmU,MAAQ,IAAOnU,IAAI,GACrC,OAASA,IAAI,GAAKmU,MAAQ,IAAOnU,IAAI,GACrC,MAASA,IAAI,GAAM,KAAOA,IAAI,GAAKmU,MACnC,MAASnU,IAAI,GAAM,KAAOA,IAAI,GAAKmU,MACvB,OAAT5uB,KACPxK,EAAI,OAASilB,IAAI,GAAKmU,MAAQ,IAAOnU,IAAI,GACrC,MAASA,IAAI,GAAM,KAAOA,IAAI,GAAKmU,MACnC,OAASnU,IAAI,GAAKmU,MAAQ,IAAOnU,IAAI,GACrC,MAASA,IAAI,GAAM,KAAOA,IAAI,GAAKmU,MAAQ,MAC/B,MAAT5uB,KACPxK,EAAI,MAASilB,IAAI,GAAM,KAAOA,IAAI,GAAKmU,MACnC,OAASnU,IAAI,GAAKupG,QAAU,KAAOvpG,IAAI,GAAKwpG,KAC5C,OAASxpG,IAAI,GAAKupG,QAAU,KAAOvpG,IAAI,GAAKwpG,KAC5C,MACY,MAATjkH,KACPxK,EAAI,MAASilB,IAAI,GAAM,KAAOA,IAAI,GAAKmU,MACnC,OAASnU,IAAI,GAAKupG,QAAU,KAAOvpG,IAAI,GAAKwpG,KAC5C,OAASxpG,IAAI,GAAKupG,QAAU,KAAOvpG,IAAI,GAAKwpG,KAC5C,MACY,MAATjkH,KACPxK,EAAI,OAASilB,IAAI,GAAKmU,MAAQ,IAAOnU,IAAI,GACrC,OAASA,IAAI,GAAKwpG,KAAO,KAAOxpG,IAAI,GAAKupG,QACzC,OAASvpG,IAAI,GAAKwpG,KAAO,KAAOxpG,IAAI,GAAKupG,QACzC,MACY,MAAThkH,OACPxK,EAAI,OAASilB,IAAI,GAAKmU,MAAQ,IAAOnU,IAAI,GACrC,OAASA,IAAI,GAAKwpG,KAAO,KAAOxpG,IAAI,GAAKupG,QACzC,OAASvpG,IAAI,GAAKwpG,KAAO,KAAOxpG,IAAI,GAAKupG,QACzC,OAEDxuH,GAIXsjF,qBAAsB,SAAUt1E,QACxB/T,EAAGgrB,IAAKlZ,IAIR2iH,SAHQ,MAKRC,KAAO,MAEP3gH,GAAGkpC,cAAgB,QACZ,MAGXnrC,IAAMM,KAAKC,IAAI0B,GAAG9B,OAAO1R,OAAQwT,GAAGkpC,cAEZ,IAApBlpC,GAAG8nC,iBACE77C,EAAI,EAAGA,EAAI8R,IAAK9R,IACjBgrB,IAAMjX,GAAG9B,OAAOjS,GAAGiqB,UACf7V,MAAM4W,IAAI,KAAO5W,MAAM4W,IAAI,IAC3BypG,SAjBA,OAoBAzpG,IAAI,GAAK5Y,KAAKiS,IAAIjS,KAAKC,IAAI2Y,IAAI,GAhB7B,MAAA,KAiBFA,IAAI,GAAK5Y,KAAKiS,IAAIjS,KAAKC,IAAI2Y,IAAI,GAjB7B,MAAA,KAqBF0pG,MAAQD,SAAWzpG,IAAI,GAAK,IAAMA,IAAI,GACtCypG,SAzBA,YA4BL,GAAwB,IAApB1gH,GAAG8nC,iBACV77C,EAAI,EACGA,EAAI8R,KACPkZ,IAAMjX,GAAG9B,OAAOjS,GAAGiqB,UACf7V,MAAM4W,IAAI,KAAO5W,MAAM4W,IAAI,IAC3BypG,SAlCA,OAoCAC,MAAQD,SAAWzpG,IAAI,GAAK,IAAMA,IAAI,GAlCtC,QAmCIypG,WACAz0H,GAAK,EAEL00H,MAAQ,KADR1pG,IAAMjX,GAAG9B,OAAOjS,GAAGiqB,WACD,GAAK,IAAMe,IAAI,GACjChrB,GAAK,EAEL00H,MAAQ,KADR1pG,IAAMjX,GAAG9B,OAAOjS,GAAGiqB,WACD,GAAK,IAAMe,IAAI,IAErCypG,SA3CA,OA6CJz0H,GAAK,SAGN00H,MAIXtrC,2BAA4B,SAAUr1E,QAC9B/T,EAAGC,EAAGiR,EAAG8Z,IAAKymC,GAAIE,GAAI7/C,IAGtB2iH,SAFQ,MAIRC,KAAO,GACPpyH,EAAI0W,KAAKrG,SAASoB,GAAG0E,QAAQlB,aAC7Bo9G,SAAoD,SAAxC37G,KAAKrG,SAASoB,GAAG0E,QAAQwpC,cAErCluC,GAAGkpC,cAAgB,QACZ,OAGP03E,UAAY5gH,GAAGjO,MAAMqM,QAAQ4sC,MAAM8+B,eACnC9pE,GAAG9B,OAAS4oB,SAAS8P,oBAAoB52B,GAAG9B,OAAQ,KAGxDH,IAAMM,KAAKC,IAAI0B,GAAG9B,OAAO1R,OAAQwT,GAAGkpC,cAC/Bh9C,EAAI,EAAGA,EAAI,EAAGA,QACfw0H,SAlBQ,MAmBHz0H,EAAI,EAAGA,EAAI8R,IAAK9R,IACjBgrB,IAAMjX,GAAG9B,OAAOjS,GAAGiqB,UAEf7V,MAAM4W,IAAI,KAAO5W,MAAM4W,IAAI,IAC3BypG,SAvBA,OA0BAzpG,IAAI,GAAK5Y,KAAKiS,IAAIjS,KAAKC,IAAI2Y,IAAI,GAvB7B,MAAA,KAwBFA,IAAI,GAAK5Y,KAAKiS,IAAIjS,KAAKC,IAAI2Y,IAAI,GAxB7B,MAAA,KAHF,QA8BIypG,SAEAC,MAAQD,SAAWzpG,IAAI,GAAK,IAAMA,IAAI,IAEtC9Z,EAAI,EAAIjR,EACRy0H,MAAQ,CAACD,SACJhjE,GAAqB,MAAfzmC,IAAI,GAAKymC,IAAcnvD,GAAK4O,EAAIkB,KAAKywB,SAAW5iC,GAAK,IAC3D0xD,GAAqB,MAAf3mC,IAAI,GAAK2mC,IAAcrvD,GAAK4O,EAAIkB,KAAKywB,SAAW5iC,GAAK,IAC3DwxD,GAAqB,MAAfzmC,IAAI,GAAKymC,IAAcnvD,GAAK4O,EAAIkB,KAAKywB,SAAW5iC,GAAK,IAC3D0xD,GAAqB,MAAf3mC,IAAI,GAAK2mC,IAAcrvD,GAAK4O,EAAIkB,KAAKywB,SAAW5iC,GAAK,IAC5D+qB,IAAI,GAAI,IAAKA,IAAI,IAAIlqB,KAAK,KAGlC2zH,SA1CA,MA2CAhjE,GAAKzmC,IAAI,GACT2mC,GAAK3mC,IAAI,WAId0pG,MAIXrqC,kBAAmB,SAAUxpE,KAAM9M,QAC3B/T,EAEAiqB,UADAyqG,KAAO,GAEP5iH,IAAMiC,GAAGyuC,SAASjiD,WAEtBsgB,KAAKkyG,eAAe,KAAM,SAAU,QAClB,mBAAdh/G,GAAGqhF,QACHtjF,MAGC9R,EAAI,EAAGA,EAAI8R,IAAM,EAAG9R,IAAK,KACtB+T,GAAGyuC,SAASxiD,GAAGwrB,mBAIf3K,KAAKkyG,eAAe,KAAM,SAAU,IAFpC2B,KAAOA,MADPzqG,UAAYlW,GAAGyuC,SAASxiD,GAAGuT,OAAO0W,WACV,GAAK,IAAMA,UAAU,GAM7CjqB,EAAI8R,IAAM,IACV4iH,MAAQ,MAGa,IAAzBA,KAAK5yH,QAAQ,QACb+e,KAAKkyG,eAAe,KAAM,SAAU2B,OAK5C7tC,eAAgB,SAAUhmE,KAAMrN,EAAGiT,EAAG+R,EAAG/U,GACrC5C,KAAKkyG,eAAe,KAAM,IAAKv/G,GAC/BqN,KAAKkyG,eAAe,KAAM,IAAKtsG,GAC/B5F,KAAKkyG,eAAe,KAAM,QAASv6F,GACnC3X,KAAKkyG,eAAe,KAAM,SAAUtvG,IAQxC+qE,gBAAiB,SAAU3tE,KAAM5K,IAAK5F,KACtB,YAAR4F,KAGJ4K,KAAKkyG,eAAe,KAAM98G,IAAK5F,MAGnCkM,QAAS,SAAUxI,GAAI1D,SACfwQ,KAEA9M,IAAMA,GAAGsyE,WACTtyE,GAAG0C,WAAWkB,QAAUtH,IACxBwQ,KAAO9M,GAAGsyE,SACNh2E,KACAwQ,KAAKkyG,eAAe,KAAM,UAAW,UACrClyG,KAAK/D,MAAMQ,WAAa,YAExBuD,KAAKkyG,eAAe,KAAM,UAAW,QACrClyG,KAAK/D,MAAMQ,WAAa,YAMpC65C,KAAM,SAAUpjD,IACZjQ,IAAIkC,WAAW,wBAAyB,iCACnCuW,QAAQxI,IAAI,IAWrB06E,KAAM,SAAU16E,IACZjQ,IAAIkC,WAAW,wBAAyB,iCACnCuW,QAAQxI,IAAI,IAWrB26E,aAAc,SAAU36E,GAAIxD,MACxBwD,GAAGsyE,SAASuE,aAAa,qBAAsBr6E,OAInDs1E,aAAc,SAAU9xE,QAChB6gH,UAAY57G,KAAKrG,SAASoB,GAAG0E,QAAQggE,MACrC53D,KAAO9M,GAAGsyE,SAEVuuC,UAAY,EACZ/zG,KAAKkyG,eAAe,KAAM,mBAAoBrtH,KAAK0tH,UAAUwB,UAAY,IAErE/zG,KAAKg0G,eAAe,KAAM,qBAC1Bh0G,KAAKi0G,kBAAkB,KAAM,qBAMzChmC,YAAa,SAAU/6E,QAEf8M,KAAM0yG,MAAOC,MADbuB,SAAWhhH,GAAGsyE,SAEd0U,KAAO/hF,KAAKrG,SAASoB,GAAG0E,QAAQ6+D,UAEvB,WAATyjB,MAA8B,WAATA,MACrBl6E,KAAOnb,KAAK6gF,WAAWwU,KAAO,WAAYhnF,GAAGlR,GAAK,aAClD0wH,MAAQ7tH,KAAK6gF,WAAW,OAAQxyE,GAAGlR,GAAK,cACxC2wH,MAAQ9tH,KAAK6gF,WAAW,OAAQxyE,GAAGlR,GAAK,cACxCge,KAAKkB,YAAYwxG,OACjB1yG,KAAKkB,YAAYyxG,YACZV,KAAK/wG,YAAYlB,MACtBk0G,SAAShC,eAAe,KAAM,QAAS,aAAertH,KAAKW,UAAUxD,GAAK,IAAMkR,GAAGlR,GAAK,cACxFkR,GAAGihH,UAAYzB,MACfx/G,GAAGkhH,UAAYzB,MACfz/G,GAAGmhH,SAAWr0G,MAEdk0G,SAASD,kBAAkB,KAAM,UAWzCK,oBAAqB,SAASt0G,KAAMu0G,aAM5B9yH,EAAI,EACJi5B,GAAKnpB,KAAK8hB,IAAIkhG,SACd95F,GAAKlpB,KAAKwiB,IAAIwgG,SAEdhjH,KAAKwC,IAAI2mB,IAAMnpB,KAAKwC,IAAI0mB,IACxBh5B,GAAK8P,KAAKwC,IAAI2mB,IAEdj5B,GAAK8P,KAAKwC,IAAI0mB,IAGdC,IAAM,GACN1a,KAAKkyG,eAAe,KAAM,KAAM,GAChClyG,KAAKkyG,eAAe,KAAM,KAAMx3F,GAAKj5B,KAErCue,KAAKkyG,eAAe,KAAM,MAAOx3F,GAAKj5B,GACtCue,KAAKkyG,eAAe,KAAM,KAAM,IAEhCz3F,IAAM,GACNza,KAAKkyG,eAAe,KAAM,KAAM,GAChClyG,KAAKkyG,eAAe,KAAM,KAAMz3F,GAAKh5B,KAErCue,KAAKkyG,eAAe,KAAM,MAAOz3F,GAAKh5B,GACtCue,KAAKkyG,eAAe,KAAM,KAAM,KAgBxCsC,qBAAsB,SAASx0G,KAAMy0B,GAAIC,GAAIrgC,EAAGi1B,GAAImrF,GAAIzlD,IACpDhvD,KAAKkyG,eAAe,KAAM,KAAW,IAALz9E,GAAW,KAC3Cz0B,KAAKkyG,eAAe,KAAM,KAAW,IAALx9E,GAAW,KAC3C10B,KAAKkyG,eAAe,KAAM,IAAS,IAAJ79G,EAAU,KACzC2L,KAAKkyG,eAAe,KAAM,KAAW,IAAL5oF,GAAW,KAC3CtpB,KAAKkyG,eAAe,KAAM,KAAW,IAALuC,GAAW,KAC3Cz0G,KAAKkyG,eAAe,KAAM,KAAW,IAALljD,GAAW,MAI/Ckf,eAAgB,SAAUh7E,QAClB+8D,IAAKsvC,GACLmT,MAAQx/G,GAAGihH,UACXxB,MAAQz/G,GAAGkhH,UACXl6B,KAAO/hF,KAAKrG,SAASoB,GAAG0E,QAAQ6+D,UAE/Bt+D,KAAKzU,OAAOgvH,QAAWv6G,KAAKzU,OAAOivH,SAKxCpT,IADAA,GAAKpnG,KAAKrG,SAASoB,GAAG0E,QAAQ3B,cACnB,EAAKspG,GAAK,EACrBtvC,IAAM93D,KAAKrG,SAASoB,GAAG0E,QAAQ5B,WAE/B08G,MAAMR,eAAe,KAAM,QAAS,cAAgBjiD,IAAM,iBAAmBsvC,IAC7EoT,MAAMT,eAAe,KAAM,QACnB,cAAmB/5G,KAAKrG,SAASoB,GAAG0E,QAAQohF,qBAC5C,iBAAmB7gF,KAAKrG,SAASoB,GAAG0E,QAAQqhF,wBAEpDy5B,MAAMR,eAAe,KAAM,SAA0D,IAAhD/5G,KAAKrG,SAASoB,GAAG0E,QAAQ88G,qBAA6B,KAC3F/B,MAAMT,eAAe,KAAM,SAAwD,IAA9C/5G,KAAKrG,SAASoB,GAAG0E,QAAQ+8G,mBAA2B,KAC5E,WAATz6B,UACKo6B,oBAAoBphH,GAAGmhH,SAAUl8G,KAAKrG,SAASoB,GAAG0E,QAAQg9G,gBAC/C,WAAT16B,WACFs6B,qBAAqBthH,GAAGmhH,SACzBl8G,KAAKrG,SAASoB,GAAG0E,QAAQi9G,YACzB18G,KAAKrG,SAASoB,GAAG0E,QAAQk9G,YACzB38G,KAAKrG,SAASoB,GAAG0E,QAAQm9G,WACzB58G,KAAKrG,SAASoB,GAAG0E,QAAQo9G,YACzB78G,KAAKrG,SAASoB,GAAG0E,QAAQq9G,YACzB98G,KAAKrG,SAASoB,GAAG0E,QAAQs9G,eAMrC5wC,oBAAqB,SAAUpxE,GAAIi7E,cACrBgnC,cACNh2H,EAAG8R,IACHmkH,MAAQ,CAAC,WACL,wBACA,+BAES3yH,IAAb0rF,WACAA,SAAWh2E,KAAKrG,SAASoB,GAAG0E,QAAQhB,qBAGpCu3E,WAAaj7E,GAAG0C,WAAWgB,wBAM3Bu+G,cAFAjiH,GAAG5D,eAAiBjB,MAAMlF,mBACY,SAAtCgP,KAAKrG,SAASoB,GAAG0E,QAAQ8D,SACT,UAAYyyE,SAAZ,eACEA,SAAW,KAEb,SAAWA,SAAX,oBACOA,SADP,cAECA,SAFD,sBAGSA,SAAW,KAGxCl9E,IAAMmkH,MAAM11H,OACPP,EAAI,EAAGA,EAAI8R,MAAO9R,EACf+T,GAAGkiH,MAAMj2H,MACF+T,GAAGkiH,MAAMj2H,IACX8c,MAAMo5G,WAAaF,eAIhCjiH,GAAG0C,WAAWgB,mBAAqBu3E,WAsBvC0kC,cAAe,SAAUyC,QAASC,eACR,KAAlBA,cACAD,UAEAzvH,OAAOlD,WAAW2yH,QAAS,IAKnCvwC,mBAAoB,SAAU7xE,GAAI26D,MAAO0B,QAASiW,cAC1CxlE,KAAMvL,EAAG+gH,KAAMC,GACfnmD,KAAOn3D,KAAKrG,SAAS+7D,OACrBl5D,EAAIwD,KAAKrG,SAASy9D,SAClBmmD,KAAOv9G,KAAKrG,SAASoB,GAAG0E,QAAQ6+D,UAEpC9hE,EAAKA,EAAI,EAAKA,EAAI,EAGdzB,GAAG0C,WAAWI,YAAcs5D,MAAQp8D,GAAG0C,WAAWK,cAAgBtB,GAAc,OAAT+gH,OAIvEv9G,KAAKzU,OAAO4rE,QAAkB,IAATA,OACD,IAAhBA,KAAK5vE,QACL+U,EAAI66D,KACJmmD,GAAK9gH,IAEL6gH,KAAOrjD,MAAM9C,UAAUC,MACvB76D,EAAI+gH,KAAK,GACTC,GAAK9gH,EAAI6gH,KAAK,IAIdx1G,UADavd,IAAb+iF,SACOtyE,GAAGsyE,SAEHA,SAGD,SAAN/wE,QACKo+G,eAAc,WACf7yG,KAAKkyG,eAAe,KAAM,OAAQz9G,KACnCvB,GAAG0C,WAAWI,WAGjB9C,GAAGxD,OAASzM,IAAIqE,uBACXurH,eAAc,WACf7yG,KAAKkyG,eAAe,KAAM,UAAWuD,MACtCviH,GAAG0C,WAAWK,cAGP,SAANxB,GAEAghH,GAAK,EAELz1G,KAAKkyG,eAAe,KAAM,iBAAkB,kBAG5ClyG,KAAKkyG,eAAe,KAAM,iBAAkB,uBAE3CW,eAAc,WACf7yG,KAAKkyG,eAAe,KAAM,eAAgBuD,MAC3CviH,GAAG0C,WAAWK,cAGR,WAATy/G,MAA8B,WAATA,WAChBxnC,eAAeh7E,KAG5BA,GAAG0C,WAAWI,UAAYs5D,KAC1Bp8D,GAAG0C,WAAWK,YAActB,IAIhC+vE,qBAAsB,SAAUxxE,GAAI26D,MAAO0B,aACN96D,EAAG+gH,KACJC,GAC5Bz1G,KAFAsvD,KAAOn3D,KAAKrG,SAAS+7D,OACrBl5D,EAAIwD,KAAKrG,SAASy9D,SAGtB56D,EAAKA,EAAI,EAAKA,EAAI,EAEdzB,GAAG0C,WAAWY,cAAgB84D,MAAQp8D,GAAG0C,WAAWa,gBAAkB9B,IAItEwD,KAAKzU,OAAO4rE,QAAkB,IAATA,OACD,IAAhBA,KAAK5vE,QACL+U,EAAI66D,KACJmmD,GAAK9gH,IAEL6gH,KAAOrjD,MAAM9C,UAAUC,MACvB76D,EAAI+gH,KAAK,GACTC,GAAK9gH,EAAI6gH,KAAK,IAGlBx1G,KAAO9M,GAAGsyE,SAENtyE,GAAG5D,eAAiBjB,MAAMlF,kBACgB,SAAtCgP,KAAKrG,SAASoB,GAAG0E,QAAQ8D,cACpBm3G,eAAc,WACf7yG,KAAK/D,MAAM4xD,MAAQp5D,EACnBuL,KAAK/D,MAAMszD,QAAUkmD,KACtBviH,GAAG0C,WAAWY,kBAGZq8G,eAAc,WACf7yG,KAAKkyG,eAAe,KAAM,QAAS,QAAUz9G,GAC7CuL,KAAKkyG,eAAe,KAAM,QAAS,gBAAkBuD,MACtDviH,GAAG0C,WAAWY,kBAGhBq8G,eAAc,WACf7yG,KAAKkyG,eAAe,KAAM,SAAUz9G,GACpCuL,KAAKkyG,eAAe,KAAM,iBAAkBuD,MAC7CviH,GAAG0C,WAAWY,aAGjBtD,GAAG5D,eAAiBjB,MAAMrF,oBAC1BkK,GAAG5D,eAAiBjB,MAAMvF,oBACtBqP,KAAKrG,SAASoB,GAAG0E,QAAQ1B,kBACpB08G,eAAe1/G,GAAG81E,sBAAuBv0E,EAAGghH,GAAIviH,GAAIA,GAAGmzE,YAAYgB,WAGxElvE,KAAKrG,SAASoB,GAAG0E,QAAQxB,iBACpBw8G,eAAe1/G,GAAG+1E,oBAAqBx0E,EAAGghH,GAAIviH,GAAIA,GAAGmzE,YAAYiB,YAKlFp0E,GAAG0C,WAAWY,YAAc84D,KAC5Bp8D,GAAG0C,WAAWa,cAAgB9B,IAIlCiwE,qBAAsB,SAAU1xE,GAAIiJ,WAC5B6D,KACA2X,EAAIxf,KAAKrG,SAASqK,OAElB5I,MAAMokB,IAAMzkB,GAAG0C,WAAWc,cAAgBihB,IAI9C3X,KAAO9M,GAAGsyE,cACLmI,gBAAgB3tE,KAAM,UAAW,QAClC7H,KAAKzU,OAAOi0B,SACPg2D,gBAAgB3tE,KAAM,eAAgB2X,EAAI,MAanDzkB,GAAG0C,WAAWc,YAAcihB,IAIhC8uD,WAAY,SAAUvzE,QACdyiH,SAAWx9G,KAAKrG,SAASoB,GAAG0E,QAAQtB,cAEvB7T,IAAbkzH,UAAuC,KAAbA,UAAmBziH,GAAG0C,WAAWU,UAAYq/G,UACtEx9G,KAAKzU,OAAOwP,GAAGsyE,iBAIfmI,gBAAgBz6E,GAAGsyE,SAAU,iBAAkBmwC,UACpDziH,GAAG0C,WAAWU,QAAUq/G,WAK5B1wC,UAAW,SAAU/xE,QACbinC,KAAOhiC,KAAKrG,SAASoB,GAAG0E,QAAQrB,QAChCrD,GAAG0C,WAAWW,SAAW4jC,OAIzBhiC,KAAKzU,OAAOwP,GAAGsyE,YACXrrC,KACAjnC,GAAGsyE,SAAS0sC,eAAe,KAAM,SAAU,QAAUrtH,KAAKW,UAAUxD,GAAzB,QAE3CkR,GAAGsyE,SAASyuC,kBAAkB,KAAM,WAG5C/gH,GAAG0C,WAAWW,OAAS4jC,OAQ3Bm0C,cAAe,aAMfC,gBAAiB,aAOjB/Y,OAAQ,SAAU79C,EAAG/U,QAIZmpG,QAAQhiC,aAAa,QAAUvtE,WAAWmb,SAC1Co0F,QAAQhiC,aAAa,SAAUvtE,WAAWoG,KAMnDwtE,kBAAmB,SAAU1uF,OACrBvC,EAAGy2H,IAAKC,IAAK71G,cACZ81G,YAAc,GACd32H,EAAI,EAAGA,EAAIuC,EAAGvC,IACfy2H,IAAM,eAAiBz2H,EACvB6gB,KAAOnb,KAAK6gF,WAAW,OAAQkwC,UAC1BnwC,gBAAgBzlE,KAAM,IAC3BA,KAAKkyG,eAAe,KAAM,IAAK,cAC1B4D,YAAYv1H,KAAKyf,WAEjB2tE,gBAAgB3tE,KAAM,UAAW,aACjC2tE,gBAAgB3tE,KAAM,eAAgB,OAC3CA,KAAKkyG,eAAe,KAAM,SAAU,WACpClyG,KAAKkyG,eAAe,KAAM,iBAAkB,GAC5ClyG,KAAKkyG,eAAe,KAAM,UAAW,QAErC2D,IAAM,eAAiB12H,EACvB6gB,KAAOnb,KAAK6gF,WAAW,UAAWmwC,UAC7BpwC,gBAAgBzlE,KAAM,SACtB+lE,kBAAkB/lE,KAAM,EAAG,EAAG,EAAG,QACjC81G,YAAYv1H,KAAKyf,WAEjB2tE,gBAAgB3tE,KAAM,UAAW,aACjC2tE,gBAAgB3tE,KAAM,eAAgB,OAC3CA,KAAKkyG,eAAe,KAAM,SAAU,WACpClyG,KAAKkyG,eAAe,KAAM,iBAAkB,GAC5ClyG,KAAKkyG,eAAe,KAAM,OAAQ,WAClClyG,KAAKkyG,eAAe,KAAM,eAAgB,GAE1ClyG,KAAKkyG,eAAe,KAAM,UAAW,SAK7C7hC,eAAgB,SAAUlxF,GAClB0F,KAAKixH,aAAe32H,GAAK,GAAK,EAAIA,EAAI0F,KAAKixH,YAAYp2H,cAClDo2H,YAAY,EAAI32H,GAAG+yH,eAAe,KAAM,UAAW,eACnD4D,YAAY,EAAI32H,EAAI,GAAG+yH,eAAe,KAAM,UAAW,YAKpE5hC,eAAgB,SAAUnxF,GAClB0F,KAAKixH,aAAe32H,GAAK,GAAK,EAAIA,EAAI0F,KAAKixH,YAAYp2H,cAClDo2H,YAAY,EAAI32H,GAAG+yH,eAAe,KAAM,UAAW,aACnD4D,YAAY,EAAI32H,EAAI,GAAG+yH,eAAe,KAAM,UAAW,UAKpE3hC,iBAAkB,SAAUpxF,EAAGuhD,SACvB/tC,EAAGiT,EAGH/gB,KAAKixH,aAAe32H,GAAK,GAAK,EAAIA,EAAI0F,KAAKixH,YAAYp2H,SACvDiT,EAAI+tC,IAAI,GACR96B,EAAI86B,IAAI,QAEHo1E,YAAY,EAAI32H,GAAG+yH,eAAe,KAAM,IAAK,MAAQv/G,EANtD,IAM+D,IAAMiT,EAAvB,OACtCjT,EAPR,IAOiB,IAAMiT,EADuB,MAEvCjT,EAAI,KAAOiT,EARlB,IAM8C,MAGvCjT,EAAI,KAAOiT,EATlB,UAUCmgE,kBAAkBlhF,KAAKixH,YAAY,EAAI32H,EAAI,GAAIuhD,IAAI,GAAIA,IAAI,GAAI,GAAI,MAYhFq1E,wBAAyB,SAAU/1G,UAC3BouD,OAAS,MACS,IAAlBpuD,KAAK6B,aACL7B,KAAOA,KAAK4B,WACL5B,WACavd,IAAZud,KAAKhe,SAAmCS,IAAfud,KAAKrf,OAC9BytE,OAAO7tE,KAAK,CAACyf,KAAKhe,GAAIge,KAAKrf,QAE/BytE,OAASA,OAAOruE,OAAO8E,KAAKkxH,wBAAwB/1G,OACpDA,KAAOA,KAAKgC,mBAGbosD,QAGX4nD,YAAa,SAAUjlC,IAAK5uF,cACpBy4E,MAAQ,IAAIq7C,MAEhBr7C,MAAM+W,OAAS,eACPukC,OAASnwH,SAAS2T,cAAc,UACpCw8G,OAAO/5G,MAAQtX,KAAKsxH,aACpBD,OAAO95G,OAASvX,KAAKuxH,cAErBF,OAAOv8G,WAAW,MAAMgzE,UAAU9nF,KAAM,EAAG,GAE3C1C,SAAS+zH,OAAOG,UAAU,cAC1BH,OAAO9vC,UAGXxL,MAAM7oC,IAAMg/C,KAGhBulC,eAAgB,SAASvK,aACjBwK,OAAQtlH,IAAKilH,OAAQM,IACrBC,GAAIt3H,MAGR8R,KADAslH,OAASxK,QAAQzwG,qBAAqB,UACzB5b,QACH,MACNw2H,OAASnwH,SAAS2T,cAAc,UAE3Bva,EAAI,EAAGA,EAAI8R,IAAK9R,IAAK,CACtBo3H,OAAOp3H,GAAG4qF,aAAa,cAAe,aAItCysC,IAAMN,OAAOv8G,WAAW,MACxBu8G,OAAO/5G,MAAQo6G,OAAOp3H,GAAGy6F,aAAa,SACtCs8B,OAAO95G,OAASm6G,OAAOp3H,GAAGy6F,aAAa,cAEnC48B,IAAI7pC,UAAU4pC,OAAOp3H,GAAI,EAAG,EAAG+2H,OAAO/5G,MAAO+5G,OAAO95G,QAGpDq6G,GAAKP,OAAOG,YACZE,OAAOp3H,GAAG4qF,aAAa,aAAc0sC,IACvC,MAAOx9G,KACLnT,QAAQK,IAAI,sCAAuC8S,aAKxD,GAYXu3E,cAAe,SAAUkmC,iBAGjBC,IAEAx3H,EAAG8R,IAJH86G,QAAUlnH,KAAKknH,QACf6K,KAAO/wH,OAAO+wH,MAAQl+D,OAAOjB,OAI7B2W,OAAS,MAOTvpE,KAAKW,UAAUqxH,iBAAmB1+G,KAAKzU,OAAOmB,KAAKytH,qBAC9CoE,kBACIpE,gBAAgBvoC,aAAa,UAAW,UAE1CgiC,QAAQ/pG,aAGXosD,OAASA,OAAOruE,OAAO8E,KAAKkxH,wBAAwBhK,QAAQ/pG,mBAEvDswG,gBAAgBpxG,YAAY6qG,QAAQ/pG,qBAI5Cs0G,eAAevK,SAGpBA,QAAQhiC,aAAa,QAAS,8BAC9B4sC,KAAM,IAAIG,eAAgBC,kBAAkBhL,UAExB,IAAhB2K,gBAGAzlH,IAAMm9D,OAAO1uE,OACRP,EAAI,EAAGA,EAAI8R,IAAK9R,IACjBw3H,IAAMA,IAAI92H,QAAQ,OAASuuE,OAAOjvE,GAAG,GAAK,IAAK,OAASivE,OAAOjvE,GAAG,GAAK,YAAcivE,OAAOjvE,GAAG,GAAK,SAUvGw3H,IAAI7qC,MAAM,4CAA8C,IAAIpsF,OAAS,IACtEi3H,IAAMA,IAAI92H,QAAQ,0CAA2C,KAKjE82H,IAAMA,IAAI92H,QAAQ,UAAW,KAIzBsY,KAAKzU,OAAOmB,KAAKytH,kBAAoBztH,KAAKytH,gBAAgBuE,gBAAiB,MAEpEhyH,KAAKytH,gBAAgB1wG,iBACnBpc,UAAU0b,YAAYrc,KAAKytH,gBAAgB1wG,iBAE/C0wG,gBAAgBvoC,aAAa,UAAW,cAG1C,6BAA+B6sC,KAAKh/D,SAASC,mBAAmB8+D,QA2B3EjmC,aAAc,SAAUC,SAAUh5D,EAAG/U,EAAG8zG,iBAChCC,IAAKK,OAAQC,GAAIT,WAIrBS,GAHUpyH,KAAKW,UAAUiZ,cAGhBzY,eAAe2qF,WAIrBx0E,MAAQ86G,GAAG96G,MAGdq6G,IAAMS,GAAGt9G,WAAW,WACVlX,IAANk1B,QAAyBl1B,IAANmgB,IACnBq0G,GAAGh7G,MAAME,MAAQK,WAAWmb,GAAK,KACjCs/F,GAAGh7G,MAAMG,OAASI,WAAWoG,GAAK,KAKlCq0G,GAAGltC,aAAa,QAASvtE,WAAWmb,IACpCs/F,GAAGltC,aAAa,SAAUvtE,WAAWoG,KAIzCo0G,OAAS,IAAIf,MACbU,IAAM9xH,KAAK2rF,cAAckmC,aACzBM,OAAOjlF,IAAM4kF,IAGP,YAAa9wH,OAeZ,IAAIqxH,SAAQ,SAAStsB,QAASoM,YAE7BggB,OAAOrlC,OAAS,WACZ6kC,IAAI7pC,UAAUqqC,OAAQ,EAAG,EAAGr/F,EAAG/U,GAC/BgoF,WAEN,MAAO9oG,GACLk1G,OAAOl1G,QArBXk1H,OAAOrlC,OAAS,WAGZ9rF,OAAOlD,YAAW,eAEV6zH,IAAI7pC,UAAUqqC,OAAQ,EAAG,EAAGr/F,EAAG/U,GACjC,MAAO3J,KACLnT,QAAQK,IAAI,6CAEjB,MAEAtB,OAqCf4uE,WAAY,SAAUxuE,MAAOkyH,MAAOT,iBAC5B12G,KAIAk2G,OAAQl0H,GACRo1H,IACAr7C,OAAQs7C,WACR1/F,EAAG/U,EAEH00G,KAAMC,YAENC,iBAVA/7G,IAAM5W,KAAKW,UAAUiZ,cACrB+oF,OAAS3iG,KAAKW,UAAU8Y,WAMxBm5G,IAAMxyH,MAAMiM,KAAKuiE,WAEjBikD,QAAS,QAIK,OAAd7yH,KAAK6K,OAITioB,EAAI8/F,IAAIn3G,MAAQzb,KAAKW,UAAUya,wBAAwB9D,MACvDyG,EAAI60G,IAAIn3G,MAAQzb,KAAKW,UAAUya,wBAAwB7D,YAEzC3Z,IAAV00H,OAAiC,KAAVA,OACvBO,QAAS,GACTN,IAAM,IAAInB,OACNh6G,MAAME,MAAQwb,EAAI,KACtBy/F,IAAIn7G,MAAMG,OAASwG,EAAI,OAEvB80G,QAAS,EACTN,IAAM37G,IAAIzV,eAAemxH,QAKzBO,UACA13G,KAAOvE,IAAI/B,cAAc,QACpBuC,MAAMqF,QAAUm2G,IAAI14G,IACzBiB,KAAK/D,MAAME,MAASwb,EAAK,KACzB3X,KAAK/D,MAAMG,OAAUwG,EAAK,KAC1B5C,KAAK/D,MAAMg6D,OAASpxE,KAAKW,UAAUyW,MAAMg6D,OAAS,IAGlDj2D,KAAK/D,MAAMS,SAAW,WACtBsD,KAAK/D,MAAMpF,IAAMhS,KAAKW,UAAUwY,UAAY,KAC5CgC,KAAK/D,MAAM5F,KAAOxR,KAAKW,UAAUqY,WAAa,MAM9Cq4G,OAASz6G,IAAI/B,cAAc,UAC3B1X,GAAKuP,KAAKywB,SAASjzB,SAAS,IAAIs/D,OAAO,EAAG,GAC1C6nD,OAAOnsC,aAAa,KAAM/nF,IAC1Bk0H,OAAOnsC,aAAa,QAASpyD,GAC7Bu+F,OAAOnsC,aAAa,SAAUnnE,GAC9BszG,OAAOj6G,MAAME,MAAQwb,EAAI,KACzBu+F,OAAOj6G,MAAMG,OAASub,EAAI,KAC1Bu+F,OAAOj6G,MAAMP,QAAU,OACvB8rF,OAAOtmF,YAAYg1G,QAQnBwB,SAEA37C,OAAStgE,IAAI/B,cAAc,QAC3B29G,WAAa57G,IAAI0F,eAAe,KAChC46D,OAAO9/D,MAAMqF,QAAUm2G,IAAI9jD,UAC3BoI,OAAO76D,YAAYm2G,YACnBt7C,OAAO47C,QAAU,WACb33G,KAAK1B,WAAWyD,YAAY/B,OAIhCA,KAAKkB,YAAYk2G,KACjBp3G,KAAKkB,YAAY66D,QACjByrB,OAAOrX,aAAanwE,KAAMnb,KAAKW,UAAUwc,cAK7Cs1G,KAAO77G,IAAIzV,eAAenB,KAAKW,UAAUxD,GAAK,kBAC1CmW,KAAKzU,OAAO4zH,QACZC,YAAcD,KAAKr7G,MAAMP,QACzB47G,KAAKr7G,MAAMP,QAAU,QAGzB87G,iBAAmB,WAEfJ,IAAIrlF,IAAMmkF,OAAOG,UAAU,aAIvB7uB,OAAOzlF,YAAYm0G,SAKvB,YAAarwH,YACR6qF,aAAa1uF,GAAI21B,EAAG/U,EAAG8zG,aAAakB,KAAKJ,wBAGzC9mC,aAAa1uF,GAAI21B,EAAG/U,EAAG8zG,aAC5B7wH,OAAOlD,WAAW60H,iBAAkB,MAIpCr/G,KAAKzU,OAAO4zH,QACZA,KAAKr7G,MAAMP,QAAU67G,cA/Fd1yH,QAuGZ5B,IAAIwuH,eAgDfx0H,OAAO,eAAe,CAClB,MAAO,oBAAqB,iBAAkB,aAAc,cAAe,YAAa,kBACzF,SAAUgG,IAAK+gF,iBAAkB31E,MAAO8J,KAAMg6D,MAAOppD,IAAKiR,iBAezD/2B,IAAI40H,YAAc,SAAUryH,gBACnBkK,KAAO,WAEPlK,UAAYA,eACZA,UAAUyW,MAAM81G,SAAW,SACM,KAAlCltH,KAAKW,UAAUyW,MAAMS,gBAChBlX,UAAUyW,MAAMS,SAAW,iBAE/BlX,UAAUsyH,cAAgB,kBACpB,QAGNC,WAAa,GAKb5/G,KAAKzU,OAAOT,IAAI+0H,iBACjBxyH,UAAUiZ,cAActF,WAAW4W,IAAI,SAAU,iCACjD9sB,IAAI+0H,cAAgBnzH,KAAKW,UAAUiZ,cAAcw5G,mBACjDh1H,IAAI+0H,cAAcE,QAAQ,UAAW,mCAIhC1yH,UAAUiZ,cAActF,WAAWg/G,QACpC3yH,UAAUiZ,cAActF,WAAW4W,IAAI,SAAU,sCAGhD45E,WAAa,SAAUyuB,gBACjB5yH,UAAUiZ,cAAc/E,cAAc,WAAa0+G,QAAU,qBAE1E,MAAOt2H,QACA6nG,WAAa,SAAUyuB,gBACjB5yH,UAAUiZ,cAAc/E,cAAc,IAAM0+G,QAAU,gEAKhE7F,UAAY,CAAC,QAAS,MAAO,YAAa,OAAQ,WAAY,eAAgB,gBAGvFtvH,IAAI40H,YAAY95H,UAAY,IAAIimF,iBAEhC/gF,IAAIC,OAAOD,IAAI40H,YAAY95H,UAAmD,CAS1Es6H,SAAU,SAAUr4G,KAAM5K,IAAK5F,IAAK8oH,WAEsB,IAA9CzzH,KAAKW,UAAUiZ,cAAc85G,aAC7Bv4G,KAAK5K,KAAO5F,IAEZwQ,KAAK+pE,aAAa30E,IAAK5F,IAAK8oH,OAElC,MAAOx2H,GACLmB,IAAIsD,MAAM,aAA+B6O,IAAM,IAAM5F,IAAM,YAgBnE25E,YAAa,SAAUpW,WACf5zE,EAAG8R,IAAKwD,EAAG9B,EAAGiT,EACdvR,EAAIxP,KAAKkzH,WACTS,QAAU,OAEdvnH,IAAM8hE,MAAMA,MAAMrzE,OACbP,EAAI,EAAGA,EAAI8R,IAAK9R,IAEjBwT,GADA8B,EAAIs+D,MAAMA,MAAM5zE,IACV,GACNymB,EAAInR,EAAE,GAEF0D,KAAKrJ,SAAS6D,EAAE,KAAOwF,KAAKrJ,SAAS6D,EAAE,KACvC6lH,QAAQj4H,KAAK,MAAQgR,KAAKyU,MAAM3R,EAAI1B,EAAE,IAAM,KAAOpB,KAAKyU,MAAM3R,EAAIuR,EAAE,IAChE,MAAQrU,KAAKyU,MAAM3R,EAAI1B,EAAE,IAAM,KAAOpB,KAAKyU,MAAM3R,EAAIuR,EAAE,IAAM,KAIpEzN,KAAKzU,OAAOqvE,MAAMyS,YACnBzS,MAAMyS,SAAW3gF,KAAK6gF,WAAW,OAAQ3S,MAAM/wE,SAC1CyjF,gBAAgB1S,MAAMyS,SAAUrtE,KAAKrG,SAASihE,MAAMn7D,QAAQ9C,cAGhEujH,SAAStlD,MAAMyS,SAAU,UAAW,aACpC6yC,SAAStlD,MAAMyS,SAAU,cAAertE,KAAKrG,SAASihE,MAAMn7D,QAAQpB,aAAc,QAClF6hH,SAAStlD,MAAMyS,SAAU,eAAgBrtE,KAAKrG,SAASihE,MAAMn7D,QAAQlB,mBACrE2hH,SAAStlD,MAAM0lD,eAAgB,UAAyD,IAA7CtgH,KAAKrG,SAASihE,MAAMn7D,QAAQnB,eAAwB,UAC/FwvE,eAAelT,MAAMyS,SAAUgzC,QAASzlD,MAAM9tE,QAQvDwkF,iBAAkB,SAAUxyE,IAAKd,cACzB6J,KAAMjC,GAEViC,KAAOnb,KAAK8kG,WAAW,YAClB1tF,MAAMS,SAAW,gBACjB27G,SAASr4G,KAAM,KAAMnb,KAAKW,UAAUxD,GAAf6C,gBAE1Bmb,KAAK/D,MAAM5F,KAAO,GAClB2J,KAAK/D,MAAMpF,IAAM,EACjBmJ,KAAK/D,MAAMi3D,SAAW/8D,SACtB6J,KAAK/D,MAAM4xD,MAAQ,UACnB7tD,KAAK/D,MAAMy8G,WAAa,kCACnBL,SAASr4G,KAAM,UAAW,OAC/BA,KAAK/D,MAAM3E,OAAS,yKAEpByG,EAAIlZ,KAAKW,UAAUiZ,cAAc0C,eAAelK,KAChD+I,KAAKkB,YAAYnD,QACZ0nE,gBAAgBzlE,KAAM,IAI/B0pE,iBAAkB,SAAUx2E,QACpB8M,YACJA,KAAOnb,KAAK8kG,WAAW,YAClB1tF,MAAMS,SAAW,WACtBxJ,GAAG8/G,aAAenuH,KAAKW,UAAUiZ,cAAc0C,eAAe,IAC9DnB,KAAKkB,YAAYhO,GAAG8/G,mBACfvtC,gBAAgBzlE,KAAM,GAC3BA,KAAK/D,MAAM3E,OAAS,2KAEb0I,MAIX2pE,mBAAoB,SAAUz2E,QACtBrE,EAGAktC,KAAMmuE,KAAMluE,KAAMiuE,KAAM9qH,EAHrBkrF,QAAUn3E,GAAGo3E,UAChB13E,EAAI/N,KAAKioF,eAAe55E,GAAIA,GAAGw4E,iBAC/BhhE,OAAS,CAAC,EAAG,GAEb1K,KAAO9M,GAAGsyE,SACV5jF,EAAI,GACJqxH,MAAQ//G,GAAGs3E,aACX0oC,MAAQhgH,GAAGu3E,iBAEVl3E,MAAML,GAAGR,OAAO0W,UAAU,GAAKlW,GAAGR,OAAO0W,UAAU,IAAK,KAE3C,UAAV6pG,MACAvoG,OAAO,GAAK,EACK,WAAVuoG,QACPvoG,OAAO,GAAK,IAIF,WAAVwoG,MACAxoG,OAAO,GAAK,EACK,WAAVwoG,QACPxoG,OAAO,GAAK,IAIhB9oB,EAAE,GAAKmnB,IAAI3E,WAAWxR,EAAG,CAAC,EACAM,GAAGR,OAAO0W,UAAU,GAAKsB,OAAO,GAAKxX,GAAGorB,KAAK,GAC7CprB,GAAGR,OAAO0W,UAAU,IAAM,EAAIsB,OAAO,IAAMxX,GAAGorB,KAAK,GAAKz5B,KAAKo/E,cACvFriF,EAAE,GAAG,IAAMA,EAAE,GAAG,GAChBA,EAAE,GAAG,IAAMA,EAAE,GAAG,GAChBA,EAAE,GAAKmnB,IAAI3E,WAAWxR,EAAG,CAAC,EACAM,GAAGR,OAAO0W,UAAU,IAAM,EAAIsB,OAAO,IAAMxX,GAAGorB,KAAK,GACnDprB,GAAGR,OAAO0W,UAAU,IAAM,EAAIsB,OAAO,IAAMxX,GAAGorB,KAAK,GAAKz5B,KAAKo/E,cACvFriF,EAAE,GAAG,IAAMA,EAAE,GAAG,GAChBA,EAAE,GAAG,IAAMA,EAAE,GAAG,GAChBA,EAAE,GAAKmnB,IAAI3E,WAAWxR,EAAG,CAAC,EACAM,GAAGR,OAAO0W,UAAU,IAAM,EAAIsB,OAAO,IAAMxX,GAAGorB,KAAK,GACnDprB,GAAGR,OAAO0W,UAAU,GAAKsB,OAAO,GAAKxX,GAAGorB,KAAK,GAAKz5B,KAAKo/E,cACjFriF,EAAE,GAAG,IAAMA,EAAE,GAAG,GAChBA,EAAE,GAAG,IAAMA,EAAE,GAAG,GAChBA,EAAE,GAAKmnB,IAAI3E,WAAWxR,EAAG,CAAC,EACAM,GAAGR,OAAO0W,UAAU,GAAKsB,OAAO,GAAKxX,GAAGorB,KAAK,GAC7CprB,GAAGR,OAAO0W,UAAU,GAAKsB,OAAO,GAAKxX,GAAGorB,KAAK,GAAKz5B,KAAKo/E,cACjFriF,EAAE,GAAG,IAAMA,EAAE,GAAG,GAChBA,EAAE,GAAG,IAAMA,EAAE,GAAG,GAChBm6C,KAAOn6C,EAAE,GAAG,GACZo6C,KAAOp6C,EAAE,GAAG,GACZsoH,KAAOtoH,EAAE,GAAG,GACZqoH,KAAOroH,EAAE,GAAG,GAEPzC,EAAI,EAAGA,EAAI,EAAGA,IACf48C,KAAOxqC,KAAKiS,IAAIu4B,KAAMn6C,EAAEzC,GAAG,IAC3B68C,KAAOzqC,KAAKC,IAAIwqC,KAAMp6C,EAAEzC,GAAG,IAC3B+qH,KAAO34G,KAAKiS,IAAI0mG,KAAMtoH,EAAEzC,GAAG,IAC3B8qH,KAAO14G,KAAKC,IAAIy4G,KAAMroH,EAAEzC,GAAG,IAI/B0P,EAAkB,IAAd6b,OAAO,GAAWnZ,KAAKmS,MAAMxQ,GAAGjO,MAAM0yC,YAAcoE,MAAQxqC,KAAKmS,MAAMs4B,MACvE9oC,GAAG0C,WAAWS,OAAU48G,MAAQpkH,IACd,IAAd6b,OAAO,IACPxX,GAAGsyE,SAASvpE,MAAMi6D,MAAQrnE,EAAI,KAC9BqE,GAAGsyE,SAASvpE,MAAM5F,KAAO,SAEzBnD,GAAGsyE,SAASvpE,MAAM5F,KAAOxH,EAAI,KAC7BqE,GAAGsyE,SAASvpE,MAAMi6D,MAAQ,QAE9BhjE,GAAG0C,WAAWS,KAAO48G,MAAQpkH,GAIjCA,EAAkB,IAAd6b,OAAO,GAAWnZ,KAAKmS,MAAMxQ,GAAGjO,MAAM2yC,aAAesyE,MAAQ34G,KAAKmS,MAAMumG,MACxE/2G,GAAG0C,WAAWiB,MAASq8G,MAAQrkH,IACb,IAAd6b,OAAO,IACPxX,GAAGsyE,SAASvpE,MAAMk6D,OAAStnE,EAAI,KAC/BqE,GAAGsyE,SAASvpE,MAAMpF,IAAM,SAExB3D,GAAGsyE,SAASvpE,MAAMpF,IAAMhI,EAAI,KAC5BqE,GAAGsyE,SAASvpE,MAAMk6D,OAAS,QAE/BjjE,GAAG0C,WAAWiB,IAAMq8G,MAAQrkH,GAKhCqE,GAAG82E,UAAYK,UACfn3E,GAAG8/G,aAAatvF,KAAO2mD,QACvBn3E,GAAG82E,QAAUK,SAIjBrqE,KAAK24G,QAAQphH,KAAK,GAAGqhH,IAAMhmH,EAAE,GAAG,GAChCoN,KAAK24G,QAAQphH,KAAK,GAAGshH,IAAMjmH,EAAE,GAAG,GAChCoN,KAAK24G,QAAQphH,KAAK,GAAGuhH,IAAMlmH,EAAE,GAAG,GAChCoN,KAAK24G,QAAQphH,KAAK,GAAGwhH,IAAMnmH,EAAE,GAAG,GAChCoN,KAAK24G,QAAQphH,KAAK,GAAG66D,SAAU,GAQnCua,UAAW,SAAUz5E,QAEb8M,MAEJA,KAAOnb,KAAKW,UAAUiZ,cAAc/E,cAAc,QAC7CuC,MAAMS,SAAW,gBACjB27G,SAASr4G,KAAM,KAAMnb,KAAKW,UAAUxD,GAAK,IAAMkR,GAAGlR,SAElDwD,UAAU0b,YAAYlB,WACtBylE,gBAAgBzlE,KAAM7H,KAAKrG,SAASoB,GAAG0E,QAAQ9C,QAOpDkL,KAAK/D,MAAM3E,OAAS,0JACpBpE,GAAGsyE,SAAWxlE,UACT4sE,YAAY15E,KAIrBu4E,eAAgB,SAAUv4E,GAAI6K,OACtBnL,EAAMmpC,KAAMmuE,KAAMluE,KAAMiuE,KAAM9qH,EAC9B6gB,KAAO9M,GAAGsyE,SACV5jF,EAAI,MACEmc,EAAEre,OAEF,EAAG,KAQTkT,EAAI/N,KAAKioF,eAAe55E,GAAI6K,GAC5Bnc,EAAE,GAAKmnB,IAAI3E,WAAWxR,EAAGM,GAAGR,OAAO0W,WACnCxnB,EAAE,GAAG,IAAMA,EAAE,GAAG,GAChBA,EAAE,GAAG,IAAMA,EAAE,GAAG,GAChBA,EAAE,GAAKmnB,IAAI3E,WAAWxR,EAAG,CAAC,EAAGM,GAAGR,OAAO0W,UAAU,GAAKlW,GAAGorB,KAAK,GAAIprB,GAAGR,OAAO0W,UAAU,KACtFxnB,EAAE,GAAG,IAAMA,EAAE,GAAG,GAChBA,EAAE,GAAG,IAAMA,EAAE,GAAG,GAChBA,EAAE,GAAKmnB,IAAI3E,WAAWxR,EAAG,CAAC,EAAGM,GAAGR,OAAO0W,UAAU,GAAKlW,GAAGorB,KAAK,GAAIprB,GAAGR,OAAO0W,UAAU,GAAKlW,GAAGorB,KAAK,KACnG18B,EAAE,GAAG,IAAMA,EAAE,GAAG,GAChBA,EAAE,GAAG,IAAMA,EAAE,GAAG,GAChBA,EAAE,GAAKmnB,IAAI3E,WAAWxR,EAAG,CAAC,EAAGM,GAAGR,OAAO0W,UAAU,GAAIlW,GAAGR,OAAO0W,UAAU,GAAKlW,GAAGorB,KAAK,KACtF18B,EAAE,GAAG,IAAMA,EAAE,GAAG,GAChBA,EAAE,GAAG,IAAMA,EAAE,GAAG,GAChBm6C,KAAOn6C,EAAE,GAAG,GACZo6C,KAAOp6C,EAAE,GAAG,GACZsoH,KAAOtoH,EAAE,GAAG,GACZqoH,KAAOroH,EAAE,GAAG,GAEPzC,EAAI,EAAGA,EAAI,EAAGA,IACf48C,KAAOxqC,KAAKiS,IAAIu4B,KAAMn6C,EAAEzC,GAAG,IAC3B68C,KAAOzqC,KAAKC,IAAIwqC,KAAMp6C,EAAEzC,GAAG,IAC3B+qH,KAAO34G,KAAKiS,IAAI0mG,KAAMtoH,EAAEzC,GAAG,IAC3B8qH,KAAO14G,KAAKC,IAAIy4G,KAAMroH,EAAEzC,GAAG,IAE/B6gB,KAAK/D,MAAM5F,KAAO9E,KAAKmS,MAAMs4B,MAAQ,KACrCh8B,KAAK/D,MAAMpF,IAAOtF,KAAKmS,MAAMumG,MAAQ,KAErCjqG,KAAK24G,QAAQphH,KAAK,GAAGqhH,IAAMhmH,EAAE,GAAG,GAChCoN,KAAK24G,QAAQphH,KAAK,GAAGshH,IAAMjmH,EAAE,GAAG,GAChCoN,KAAK24G,QAAQphH,KAAK,GAAGuhH,IAAMlmH,EAAE,GAAG,GAChCoN,KAAK24G,QAAQphH,KAAK,GAAGwhH,IAAMnmH,EAAE,GAAG,GAChCoN,KAAK24G,QAAQphH,KAAK,GAAG66D,SAAU,IAKvCya,eAAgB,SAAU35E,QAClB69E,IAAM54E,KAAKrG,SAASoB,GAAG69E,UAEtBsnC,SAASnlH,GAAGsyE,SAAU,MAAOuL,MAQtCtL,gBAAiB,SAAUzlE,KAAM6e,cAExB1mB,KAAKzU,OAAOm7B,SACbA,MAAQ,GAGZ7e,KAAK/D,MAAMg6D,OAASp3C,WACfr5B,UAAU0b,YAAYlB,MAEpBA,MAIX2lE,qBAAsB,SAAUzyE,GAAIxD,MACnB,UAATA,MAA6B,SAATA,MAA4B,YAATA,OACvCwD,GAAG8lH,aAAen0H,KAAKmB,eAAekN,GAAGlR,GAAK,UAElDkR,GAAG+lH,aAAep0H,KAAKmB,eAAekN,GAAGlR,GAAK,SAC9CkR,GAAGulH,eAAiB5zH,KAAKmB,eAAekN,GAAGlR,GAAK,WAChDkR,GAAGgmH,eAAiBr0H,KAAKmB,eAAekN,GAAGlR,GAAK,WAChDkR,GAAGsyE,SAAW3gF,KAAKmB,eAAekN,GAAGlR,KAIzC0jF,WAAY,SAAUh2E,KAAM1N,QACpBge,KAAMm5G,SACNjF,SAAWrvH,KAAK8kG,WAAW,QAC3ByvB,WAAav0H,KAAK8kG,WAAW,UAC7B0vB,WAAax0H,KAAK8kG,WAAW,sBAE5B0uB,SAASnE,SAAU,KAAMrvH,KAAKW,UAAUxD,GAAK,IAAMA,GAAK,cACxDq2H,SAASe,WAAY,KAAMv0H,KAAKW,UAAUxD,GAAK,IAAMA,GAAK,gBAC1Dq2H,SAASgB,WAAY,KAAMx0H,KAAKW,UAAUxD,GAAK,IAAMA,GAAK,WAElD,WAAT0N,MAA8B,YAATA,OACrBsQ,KAAOnb,KAAK8kG,WAAW,SAClBzoF,YAAYgzG,UACjBl0G,KAAKkB,YAAYk4G,YACjBp5G,KAAKkB,YAAYm4G,aACD,YAAT3pH,MAA+B,SAATA,MAA4B,UAATA,MAA6B,SAATA,OACpEsQ,KAAOnb,KAAK8kG,WAAW,UAClBzoF,YAAYgzG,UACjBl0G,KAAKkB,YAAYk4G,YACjBp5G,KAAKkB,YAAYm4G,YACjBF,SAAWt0H,KAAK8kG,WAAW,aACtB0uB,SAASc,SAAU,KAAMt0H,KAAKW,UAAUxD,GAAK,IAAMA,GAAK,SAC7Dge,KAAKkB,YAAYi4G,aAEjBn5G,KAAOnb,KAAK8kG,WAAWj6F,OAClBwR,YAAYgzG,UACjBl0G,KAAKkB,YAAYk4G,YACjBp5G,KAAKkB,YAAYm4G,aAGrBr5G,KAAK/D,MAAMS,SAAW,WACtBsD,KAAK/D,MAAM5F,KAAO,MAClB2J,KAAK/D,MAAMpF,IAAM,WACZwhH,SAASr4G,KAAM,KAAMnb,KAAKW,UAAUxD,GAAK,IAAMA,IAE7Cge,MAIXomE,OAAQ,SAAUpmE,MACV7H,KAAKzU,OAAOsc,OACZA,KAAKs5G,YAAW,IAKxBryC,WAAY,SAAU/zE,QACdqmH,WACA3xC,MAAQzvE,KAAKrG,SAASoB,GAAG0E,QAAQ1B,YACjC2xE,MAAQ1vE,KAAKrG,SAASoB,GAAG0E,QAAQxB,WAEjClD,GAAG0C,WAAWM,aAAe0xE,OAAS10E,GAAG0C,WAAWQ,YAAcyxE,QAIlED,OACA2xC,WAAarmH,GAAGulH,oBACXJ,SAASkB,WAAY,aAAc,cACnClB,SAASkB,WAAY,mBAAoB,UAE9CA,WAAarmH,GAAGulH,eACZtgH,KAAKzU,OAAO61H,kBACPlB,SAASkB,WAAY,aAAc,SAI5C1xC,OACA0xC,WAAarmH,GAAGulH,oBACXJ,SAASkB,WAAY,KAAM10H,KAAKW,UAAUxD,GAAK,IAAMkR,GAAGlR,GAAK,eAC7Dq2H,SAASkB,WAAY,WAAY,cACjClB,SAASkB,WAAY,iBAAkB,UAE5CA,WAAarmH,GAAGulH,eACZtgH,KAAKzU,OAAO61H,kBACPlB,SAASkB,WAAY,WAAY,SAG9CrmH,GAAG0C,WAAWM,WAAa0xE,MAC3B10E,GAAG0C,WAAWQ,UAAYyxE,QAI9B9B,kBAAmB,SAAU/lE,KAAMrN,EAAGiT,EAAG+qC,GAAIE,IACzC7wC,KAAK/D,MAAM5F,KAAO9E,KAAKmS,MAAM/Q,EAAIg+C,IAAM,KACvC3wC,KAAK/D,MAAMpF,IAAOtF,KAAKmS,MAAMkC,EAAIirC,IAAM,KACvC7wC,KAAK/D,MAAME,MAAQ5K,KAAKmS,MAAqB,EAAfnS,KAAKwC,IAAI48C,KAAW,KAClD3wC,KAAK/D,MAAMG,OAAS7K,KAAKmS,MAAqB,EAAfnS,KAAKwC,IAAI88C,KAAW,MAIvDw3B,eAAgB,SAAUroE,KAAMstE,IAAKC,IAAKC,IAAKC,IAAKxoF,WAC5CC,EAAGmP,EAAIxP,KAAKkzH,WAEXxkH,MAAM+5E,IAAMC,IAAMC,IAAMC,OACzBvoF,EAAI,CAAC,KAAMqM,KAAKmS,MAAMrP,EAAIi5E,KAAM,KAAM/7E,KAAKmS,MAAMrP,EAAIk5E,KAAM,MAAOh8E,KAAKmS,MAAMrP,EAAIm5E,KAAM,KAAMj8E,KAAKmS,MAAMrP,EAAIo5E,WACvGxH,eAAejmE,KAAM9a,EAAGD,SAKrCghF,eAAgB,SAAUjmE,KAAMyzG,YAAaxuH,WACrC0N,EAAI1N,MAAM0yC,YACV/xB,EAAI3gB,MAAM2yC,aACV67E,YAAY/zH,QAAU,IACtB+zH,YAAc,CAAC,UAEnBzzG,KAAK/D,MAAME,MAAQxJ,EACnBqN,KAAK/D,MAAMG,OAASwJ,OACfyyG,SAASr4G,KAAM,YAAa,CAACzO,KAAKmS,MAAM7e,KAAKkzH,WAAaplH,GAAIpB,KAAKmS,MAAM7e,KAAKkzH,WAAanyG,IAAI3lB,KAAK,WACpGo4H,SAASr4G,KAAM,OAAQyzG,YAAYxzH,KAAK,MAIjDimF,sBAAuB,SAAUhzE,GAAIorB,KAAM5uB,UACnCxK,EAAI,GACJukB,OAASlY,KAAKyU,MACdmE,IAAMjX,GAAGR,OAAO0W,UAChBsqG,OAASp1F,KAAO/sB,KAAKmU,KAAK,GAAK,GAC/BiuG,IAAa,GAAPr1F,KACNjqB,EAAIxP,KAAKkzH,iBAEA,MAATroH,KACAxK,EAAE3E,KAAK,CACH,MAAOkpB,OAAOpV,GAAK8V,IAAI,GAAKmU,OAAQ,KAAM7U,OAAOpV,GAAK8V,IAAI,GAAKmU,OAC/D,MAAO7U,OAAOpV,GAAK8V,IAAI,GAAKmU,OAAQ,KAAM7U,OAAOpV,GAAK8V,IAAI,GAAKmU,OAC/D,MAAO7U,OAAOpV,GAAK8V,IAAI,GAAKmU,OAAQ,KAAM7U,OAAOpV,GAAK8V,IAAI,GAAKmU,OAC/D,MAAO7U,OAAOpV,GAAK8V,IAAI,GAAKmU,OAAQ,KAAM7U,OAAOpV,GAAK8V,IAAI,GAAKmU,QACjEr+B,KAAK,KACS,MAATyP,KACPxK,EAAE3E,KAAK,CACH,MAAOkpB,OAAOpV,GAAK8V,IAAI,GAAKmU,OAAQ,KAAM7U,OAAOpV,EAAK8V,IAAI,IAC1D,MAAOV,OAAOpV,GAAK8V,IAAI,GAAKmU,OAAQ,KAAM7U,OAAOpV,EAAK8V,IAAI,IAC1D,MAAOV,OAAOpV,EAAK8V,IAAI,IAAa,KAAMV,OAAOpV,GAAK8V,IAAI,GAAKmU,OAC/D,MAAO7U,OAAOpV,EAAK8V,IAAI,IAAa,KAAMV,OAAOpV,GAAK8V,IAAI,GAAKmU,QACjEr+B,KAAK,KACS,OAATyP,KAEPxK,EAAE3E,KAAK,CACH,MAAOkpB,OAAOpV,GAAK8V,IAAI,GAAKmU,OAAQ,KAAM7U,OAAOpV,EAAK8V,IAAI,IAC1D,MAAOV,OAAOpV,EAAK8V,IAAI,IAAa,KAAMV,OAAOpV,GAAK8V,IAAI,GAAKmU,OAC/D,MAAO7U,OAAOpV,GAAK8V,IAAI,GAAKmU,OAAQ,KAAM7U,OAAOpV,EAAK8V,IAAI,IAC1D,MAAOV,OAAOpV,EAAK8V,IAAI,IAAa,KAAMV,OAAOpV,GAAK8V,IAAI,GAAKmU,OAC/D,SACFr+B,KAAK,KACS,MAATyP,KACPxK,EAAE3E,KAAK,CACH,MAAOkpB,OAAOpV,EAAK8V,IAAI,IAAe,KAAMV,OAAOpV,GAAK8V,IAAI,GAAKmU,OACjE,MAAO7U,OAAOpV,GAAK8V,IAAI,GAAKupG,SAAU,KAAMjqG,OAAOpV,GAAK8V,IAAI,GAAKwpG,MACjE,MAAOlqG,OAAOpV,GAAK8V,IAAI,GAAKupG,SAAU,KAAMjqG,OAAOpV,GAAK8V,IAAI,GAAKwpG,MACjE,SACF1zH,KAAK,KACS,MAATyP,KACPxK,EAAE3E,KAAK,CACH,MAAOkpB,OAAOpV,EAAK8V,IAAI,IAAe,KAAMV,OAAOpV,GAAK8V,IAAI,GAAKmU,OACjE,MAAO7U,OAAOpV,GAAK8V,IAAI,GAAKupG,SAAU,KAAMjqG,OAAOpV,GAAK8V,IAAI,GAAKwpG,MACjE,MAAOlqG,OAAOpV,GAAK8V,IAAI,GAAKupG,SAAU,KAAMjqG,OAAOpV,GAAK8V,IAAI,GAAKwpG,MACjE,SACF1zH,KAAK,KACS,MAATyP,KACPxK,EAAE3E,KAAK,CACH,MAAOkpB,OAAOpV,GAAK8V,IAAI,GAAKmU,OAAQ,KAAM7U,OAAOpV,EAAK8V,IAAI,IAC1D,MAAOV,OAAOpV,GAAK8V,IAAI,GAAKwpG,MAAQ,KAAMlqG,OAAOpV,GAAK8V,IAAI,GAAKupG,SAC/D,MAAOjqG,OAAOpV,GAAK8V,IAAI,GAAKwpG,MAAQ,KAAMlqG,OAAOpV,GAAK8V,IAAI,GAAKupG,SAC/D,MAAOjqG,OAAOpV,GAAK8V,IAAI,GAAKmU,OAAQ,KAAM7U,OAAOpV,EAAK8V,IAAI,KAC5DlqB,KAAK,KACS,MAATyP,MACPxK,EAAE3E,KAAK,CACH,MAAOkpB,OAAOpV,GAAK8V,IAAI,GAAKmU,OAAQ,KAAM7U,OAAOpV,EAAK8V,IAAI,IAC1D,MAAOV,OAAOpV,GAAK8V,IAAI,GAAKwpG,MAAQ,KAAMlqG,OAAOpV,GAAK8V,IAAI,GAAKupG,SAC/D,MAAOjqG,OAAOpV,GAAK8V,IAAI,GAAKwpG,MAAQ,KAAMlqG,OAAOpV,GAAK8V,IAAI,GAAKupG,SAC/D,SACFzzH,KAAK,KAGJiF,GAIXsjF,qBAAsB,SAAUt1E,QACxB/T,EAAGgrB,IACH0pG,KAAO,GACPx/G,EAAIxP,KAAKkzH,WACTtuG,OAASlY,KAAKyU,MAId4tG,SAHQ,MAIR3iH,IAAMM,KAAKC,IAAI0B,GAAGkpC,aAAc,SAEhClpC,GAAGkpC,cAAgB,QACZ,MAEXnrC,IAAMM,KAAKC,IAAIP,IAAKiC,GAAG9B,OAAO1R,QAEN,IAApBwT,GAAG8nC,iBAOE77C,EAAI,EAAGA,EAAI8R,IAAK9R,IACjBgrB,IAAMjX,GAAG9B,OAAOjS,GAAGiqB,UACf7V,MAAM4W,IAAI,KAAO5W,MAAM4W,IAAI,IAC3BypG,SArBA,OAwBIzpG,IAAI,GAAK,IACTA,IAAI,GAAK,IACFA,IAAI,IAAM,MACjBA,IAAI,IAAM,KAGVA,IAAI,GAAK,IACTA,IAAI,GAAK,IACFA,IAAI,IAAM,MACjBA,IAAI,IAAM,KAGd0pG,KAAKtzH,KAAK,CAACqzH,SAAUnqG,OAAOpV,EAAI8V,IAAI,IAAK,KAAMV,OAAOpV,EAAI8V,IAAI,KAAKlqB,KAAK,KACxE2zH,SApCA,YAuCL,GAAwB,IAApB1gH,GAAG8nC,iBACV77C,EAAI,EACGA,EAAI8R,KACPkZ,IAAMjX,GAAG9B,OAAOjS,GAAGiqB,UACf7V,MAAM4W,IAAI,KAAO5W,MAAM4W,IAAI,IAC3BypG,SA7CA,OA+CAC,KAAKtzH,KAAK,CAACqzH,SAAUnqG,OAAOpV,EAAI8V,IAAI,IAAK,KAAMV,OAAOpV,EAAI8V,IAAI,KAAKlqB,KAAK,KA7CxE,QA8CI2zH,WACAz0H,GAAK,EACLgrB,IAAMjX,GAAG9B,OAAOjS,GAAGiqB,UACnByqG,KAAKtzH,KAAK,CAAC,IAAKkpB,OAAOpV,EAAI8V,IAAI,IAAK,KAAMV,OAAOpV,EAAI8V,IAAI,KAAKlqB,KAAK,KACnEd,GAAK,EACLgrB,IAAMjX,GAAG9B,OAAOjS,GAAGiqB,UACnByqG,KAAKtzH,KAAK,CAAC,IAAKkpB,OAAOpV,EAAI8V,IAAI,IAAK,KAAMV,OAAOpV,EAAI8V,IAAI,KAAKlqB,KAAK,MAEvE2zH,SAtDA,OAwDJz0H,GAAK,SAGb00H,KAAKtzH,KAAK,MACHszH,MAIXtrC,2BAA4B,SAAUr1E,QAC9B/T,EAAGC,EAAGiR,EAAG8Z,IAAKymC,GAAIE,GAClB+iE,KAAO,GACPpyH,EAAI0W,KAAKrG,SAASoB,GAAG0E,QAAQlB,aAC7BrC,EAAIxP,KAAKkzH,WACTtuG,OAASlY,KAAKyU,MAGd4tG,SAFQ,MAGRE,SAAoD,SAAxC37G,KAAKrG,SAASoB,GAAG0E,QAAQwpC,WACrCnwC,IAAMM,KAAKC,IAAI0B,GAAGkpC,aAAc,SAEhClpC,GAAGkpC,cAAgB,QACZ,OAEP03E,UAAY5gH,GAAGjO,MAAMqM,QAAQ4sC,MAAM8+B,eACnC9pE,GAAG9B,OAAS4oB,SAAS8P,oBAAoB52B,GAAG9B,OAAQ,IAExDH,IAAMM,KAAKC,IAAIP,IAAKiC,GAAG9B,OAAO1R,QAEzBN,EAAI,EAAGA,EAAI,EAAGA,QACfw0H,SAfQ,MAgBHz0H,EAAI,EAAGA,EAAI8R,IAAK9R,IACjBgrB,IAAMjX,GAAG9B,OAAOjS,GAAGiqB,UACf7V,MAAM4W,IAAI,KAAO5W,MAAM4W,IAAI,IAC3BypG,SAnBA,OAsBIzpG,IAAI,GAAK,IACTA,IAAI,GAAK,IACFA,IAAI,IAAM,MACjBA,IAAI,IAAM,KAGVA,IAAI,GAAK,IACTA,IAAI,GAAK,IACFA,IAAI,IAAM,MACjBA,IAAI,IAAM,KA/Bd,QAkCIypG,SACAC,KAAKtzH,KAAK,CAACqzH,SACPnqG,OAAOpV,EAAK8V,IAAI,IAAM,IAAKV,OAAOpV,EAAK8V,IAAI,KAAMlqB,KAAK,MAE1DoQ,EAAI,EAAIjR,EACRy0H,KAAKtzH,KAAK,CAACqzH,SACPnqG,OAAOpV,GAAKu8C,GAAqB,MAAfzmC,IAAI,GAAKymC,IAAcnvD,GAAK4O,EAAIkB,KAAKywB,SAAW5iC,KAAM,IACxEqqB,OAAOpV,GAAKy8C,GAAqB,MAAf3mC,IAAI,GAAK2mC,IAAcrvD,GAAK4O,EAAIkB,KAAKywB,SAAW5iC,KAAM,IACxEqqB,OAAOpV,GAAKu8C,GAAqB,MAAfzmC,IAAI,GAAKymC,IAAcnvD,GAAK4O,EAAIkB,KAAKywB,SAAW5iC,KAAM,IACxEqqB,OAAOpV,GAAKy8C,GAAqB,MAAf3mC,IAAI,GAAK2mC,IAAcrvD,GAAK4O,EAAIkB,KAAKywB,SAAW5iC,KAAM,IACxEqqB,OAAOpV,EAAI8V,IAAI,IAAK,IACpBV,OAAOpV,EAAI8V,IAAI,KAAKlqB,KAAK,MAEjC2zH,SA9CA,MA+CAhjE,GAAKzmC,IAAI,GACT2mC,GAAK3mC,IAAI,WAIrB0pG,KAAKtzH,KAAK,MACHszH,MAIXrqC,kBAAmB,SAAUxpE,KAAM9M,QAC3B/T,EAGAgrB,IAFAlZ,IAAMiC,GAAGyuC,SAASjiD,OAClB2U,EAAIxP,KAAKkzH,WAETlE,KAAO,WAENwE,SAASr4G,KAAM,UAAW,SAC/BmK,IAAMjX,GAAGyuC,SAAS,GAAGjvC,OAAO0W,WAExB7V,MAAM4W,IAAI,GAAKA,IAAI,SAIvB0pG,KAAKtzH,KAAK,CAAC,KAAMgR,KAAKmS,MAAMrP,EAAI8V,IAAI,IAAK,IAAK5Y,KAAKmS,MAAMrP,EAAI8V,IAAI,IAAK,OAAOlqB,KAAK,KAE7Ed,EAAI,EAAGA,EAAI8R,IAAM,EAAG9R,IAAK,KACtB+T,GAAGyuC,SAASxiD,GAAGwrB,wBASVs7D,eAAejmE,KAAM,GAAI9M,GAAGjO,UARjCklB,IAAMjX,GAAGyuC,SAASxiD,GAAGuT,OAAO0W,UAExB7V,MAAM4W,IAAI,GAAKA,IAAI,WAIvB0pG,KAAKtzH,KAAKgR,KAAKmS,MAAMrP,EAAI8V,IAAI,IAAM,IAAM5Y,KAAKmS,MAAMrP,EAAI8V,IAAI,KAK5DhrB,EAAI8R,IAAM,GACV4iH,KAAKtzH,KAAK,MAGlBszH,KAAKtzH,KAAK,aACL0lF,eAAejmE,KAAM6zG,KAAM3gH,GAAGjO,SAIvC+gF,eAAgB,SAAUhmE,KAAMrN,EAAGiT,EAAG+R,EAAG/U,GACrC5C,KAAK/D,MAAM5F,KAAO9E,KAAKmS,MAAM/Q,GAAK,KAClCqN,KAAK/D,MAAMpF,IAAMtF,KAAKmS,MAAMkC,GAAK,KAE7B+R,GAAK,IACL3X,KAAK/D,MAAME,MAAQwb,EAAI,MAGvB/U,GAAK,IACL5C,KAAK/D,MAAMG,OAASwG,EAAI,OAShC+qE,gBAAiB,SAAU3tE,KAAM5K,IAAK5F,SAE9BX,EADA2qH,OAAS,UAGLpkH,SACH,SACDokH,OAAS,wBAER,eACDA,OAAS,yBAER,mBACDA,OAAS,YAIE,KAAXA,SACA3qH,EAAIsJ,KAAKrG,SAAStC,UACb6oH,SAASr4G,KAAMw5G,OAAQ3qH,KAKpC6M,QAAS,SAASxI,GAAI1D,KACd0D,IAAMA,GAAGsyE,WACTtyE,GAAG0C,WAAWkB,QAAUtH,IAEpB0D,GAAGsyE,SAASvpE,MAAMQ,WADlBjN,IAC+B,UAEA,WAM3C8mD,KAAM,SAAUpjD,IACZjQ,IAAIkC,WAAW,wBAAyB,4BAEpC+N,IAAMA,GAAGsyE,WACTtyE,GAAGsyE,SAASvpE,MAAMQ,WAAa,YAKvCmxE,KAAM,SAAU16E,IACZjQ,IAAIkC,WAAW,wBAAyB,4BAEpC+N,IAAMA,GAAGsyE,WACTtyE,GAAGsyE,SAASvpE,MAAMQ,WAAa,WAKvCuoE,aAAc,SAAU9xE,GAAI0E,aACpBoI,KACApI,QAAQggE,MAAQ,IAChB53D,KAAO9M,GAAGulH,oBACLJ,SAASr4G,KAAM,YAAanb,KAAK0tH,UAAU36G,QAAQggE,SAKhEqW,YAAa,SAAU/6E,QACfumH,SAAWvmH,GAAG+lH,aACd/+B,KAAO/hF,KAAKrG,SAASoB,GAAG0E,QAAQ6+D,UAEvB,WAATyjB,WACKm+B,SAASoB,SAAU,OAAQ,iBAC3BpB,SAASoB,SAAU,SAAUthH,KAAKrG,SAASoB,GAAG0E,QAAQohF,2BACtDq/B,SAASoB,SAAU,WAAYthH,KAAKrG,SAASoB,GAAG0E,QAAQqhF,6BACxDo/B,SAASoB,SAAU,QAASthH,KAAKrG,SAASoB,GAAG0E,QAAQg9G,iBAC1C,WAAT16B,WACFm+B,SAASoB,SAAU,OAAQ,uBAC3BpB,SAASoB,SAAU,SAAUthH,KAAKrG,SAASoB,GAAG0E,QAAQohF,2BACtDq/B,SAASoB,SAAU,WAAYthH,KAAKrG,SAASoB,GAAG0E,QAAQqhF,6BACxDo/B,SAASoB,SAAU,gBAA+D,IAA9CthH,KAAKrG,SAASoB,GAAG0E,QAAQ8hH,mBAA2B,KACnC,IAA9CvhH,KAAKrG,SAASoB,GAAG0E,QAAQ+hH,mBAA2B,UAC3DtB,SAASoB,SAAU,YAAa,aAEhCpB,SAASoB,SAAU,OAAQ,UAKxC10C,mBAAoB,SAAU7xE,GAAI26D,MAAO0B,aACJ96D,EAAG+gH,KACJC,GAD5BnmD,KAAOn3D,KAAKrG,SAAS+7D,OACrBl5D,EAAIwD,KAAKrG,SAASy9D,SAClBvvD,KAAO9M,GAAGsyE,SAGd7wE,EAAKA,EAAI,EAAKA,EAAI,EAEdzB,GAAG0C,WAAWI,YAAcs5D,MAAQp8D,GAAG0C,WAAWK,cAAgBtB,IAIlEwD,KAAKzU,OAAO4rE,QAAkB,IAATA,OAED,IAAhBA,KAAK5vE,QACL+U,EAAI66D,KACJmmD,GAAK9gH,IAILF,GADA+gH,KAAOrjD,MAAM9C,UAAUC,OACd,GACTmmD,GAAK9gH,EAAI6gH,KAAK,IAER,SAAN/gH,IAAsB,IAANA,OACX4jH,SAASnlH,GAAGsyE,SAAU,SAAU,eAEhC6yC,SAASnlH,GAAGsyE,SAAU,SAAU,aAChC6yC,SAASnlH,GAAGsyE,SAAU,YAAa/wE,GAEpC0D,KAAKzU,OAAO+xH,KAAOviH,GAAG+lH,mBACjBZ,SAASnlH,GAAG+lH,aAAc,UAAiB,IAALxD,GAAY,MAG3DviH,GAAGxD,OAASrB,MAAM/G,mBASd0Y,KAAK24G,QAAQj5H,OAAS,IAGtBsgB,KAAK24G,QAAQphH,KAAK,GAAGg4D,QAAUh+D,KAAKyU,MAAW,IAALyvG,IAC1Cz1G,KAAK24G,QAAQphH,KAAK,GAAG66D,SAAU,IAI3Cl/D,GAAG0C,WAAWI,UAAYs5D,KAC1Bp8D,GAAG0C,WAAWK,YAActB,IAIhC+vE,qBAAsB,SAAUxxE,GAAI26D,MAAO0B,aACN96D,EAAG+gH,KACJC,GACR8D,WAFpBjqD,KAAOn3D,KAAKrG,SAAS+7D,OACrBl5D,EAAIwD,KAAKrG,SAASy9D,SAClBvvD,KAAO9M,GAAGsyE,SAEd7wE,EAAKA,EAAI,EAAKA,EAAI,EAEdzB,GAAG0C,WAAWY,cAAgB84D,MAAQp8D,GAAG0C,WAAWa,gBAAkB9B,IAMtEwD,KAAKzU,OAAO4rE,QAAkB,IAATA,OAED,IAAhBA,KAAK5vE,QACL+U,EAAI66D,KACJmmD,GAAK9gH,IAILF,GADA+gH,KAAO3nD,MAAMwB,UAAUC,OACd,GACTmmD,GAAK9gH,EAAI6gH,KAAK,IAEdtiH,GAAG5D,eAAiBjB,MAAMlF,mBAWtB6W,KAAK24G,QAAQj5H,OAAS,IAGtBsgB,KAAK24G,QAAQphH,KAAK,GAAGg4D,QAAUh+D,KAAKyU,MAAW,IAALyvG,IAC1Cz1G,KAAK24G,QAAQphH,KAAK,GAAG66D,SAAU,GAGnCpyD,KAAK/D,MAAM4xD,MAAQp5D,KAET,IAANA,SACK4jH,SAASr4G,KAAM,UAAW,aAC1Bq4G,SAASr4G,KAAM,cAAevL,IAGvC8kH,WAAarmH,GAAGulH,eACZtgH,KAAKzU,OAAO+xH,KAAOviH,GAAGxD,OAASrB,MAAM/G,wBAChC+wH,SAASkB,WAAY,UAAiB,IAAL9D,GAAY,OAI9DviH,GAAG0C,WAAWY,YAAc84D,KAC5Bp8D,GAAG0C,WAAWa,cAAgB9B,IAIlCiwE,qBAAsB,SAAU1xE,GAAIiJ,WAE5B6D,KADA2X,EAAIxf,KAAKrG,SAASqK,OAGlB5I,MAAMokB,IAAMzkB,GAAG0C,WAAWc,cAAgBihB,IAI9C3X,KAAO9M,GAAGsyE,cACLmI,gBAAgB3tE,KAAM,UAAW,QAElC7H,KAAKzU,OAAOi0B,UAEPg2D,gBAAgB3tE,KAAM,eAAgB2X,GACjC,IAANA,GAAWxf,KAAKzU,OAAOwP,GAAGulH,sBACrBJ,SAASr4G,KAAM,UAAW,UAIvC9M,GAAG0C,WAAWc,YAAcihB,IAKhCstD,UAAW,SAAU/xE,QACb0mH,WAAa1mH,GAAGgmH,eAChB/+E,KAAOhiC,KAAKrG,SAASoB,GAAG0E,QAAQrB,QAE/BqjH,YAAc1mH,GAAG0C,WAAWW,SAAW4jC,OAIxCA,WACKk+E,SAASuB,WAAY,KAAM,aAC3BvB,SAASuB,WAAY,SAAU,gBAC/BvB,SAASuB,WAAY,UAAW,YAChCvB,SAASuB,WAAY,QAAS,iBAE9BvB,SAASuB,WAAY,KAAM,SAGpC1mH,GAAG0C,WAAWW,OAAS4jC,OAQ3Bm0C,cAAe,gBACN9oF,UAAUyW,MAAMP,QAAU,QAInC6yE,gBAAiB,gBACR/oF,UAAUyW,MAAMP,QAAU,MAIhCzY,IAAI40H,eAoDf56H,OAAO,kBAAkB,CACrB,MAAO,oBAAqB,iBAAkB,YAAa,aAAc,aAAc,cACvF,cAAe,YAAa,gBAAiB,kBAC9C,SAAUgG,IAAK+gF,iBAAkB31E,MAAOsrB,IAAKxhB,KAAMgwF,KAAMh2B,MAAOnpD,OAAQD,IAAKirB,SAAUha,iBAetF/2B,IAAI42H,eAAiB,SAAUr0H,UAAWoiC,aACjCl4B,KAAO,cAEPoqH,WAAa,UACbC,cAAgB,UAChBppC,SAAWwX,KAAKH,eAEhBgyB,gBAAkB,KAEnBrgG,IAAI7gB,eACCtT,UAAYA,eACZA,UAAUyW,MAAM41G,cAAgB,YAChCrsH,UAAUyW,MAAM61G,WAAa,YAE7BtsH,UAAUyW,MAAM81G,SAAW,SACM,KAAlCltH,KAAKW,UAAUyW,MAAMS,gBAChBlX,UAAUyW,MAAMS,SAAW,iBAG/BlX,UAAUS,UAAY,CAAC,eAAgBpB,KAAK8rF,SAC7C,YAAa/oD,IAAIzrB,MACjB,eAAgByrB,IAAIxrB,OACpB,QAAS,YAAYnc,KAAK,SACzB65H,WAAaj1H,KAAKW,UAAUiZ,cAAczY,eAAenB,KAAK8rF,eAC9DmpC,WAAW79G,MAAMP,QAAU,aAC3BgE,QAAU7a,KAAKi1H,WAAWngH,WAAW,WAEvC,GAAIggB,IAAIlgB,kBAEFk3E,SAA8B,gCAAX5uF,2BAAAA,SAAsBA,OAAO5E,QAAQ,UAAYA,QAAQ,eAC5E28H,WAAa,IAAIj1H,KAAK8rF,SAAS,IAAK,UACpCjxE,QAAU7a,KAAKi1H,WAAWngH,WAAW,MAC5C,MAAOV,KACLnT,QAAQK,IAAI,iFAIfosH,UAAY,CAAC,CAAC,EAAG,GAAI,CAAC,EAAG,GAAI,CAAC,GAAI,IAAK,CAAC,GAAI,IAAK,CAAC,GAAI,GAAI,GAAI,IAAK,CAAC,GAAI,EAAG,GAAI,KAGxFtvH,IAAI42H,eAAe97H,UAAY,IAAIimF,iBAEnC/gF,IAAIC,OAAOD,IAAI42H,eAAe97H,UAAsD,CAchFk8H,aAAc,SAAU1G,MAAOxtF,OAAQm0F,YAC/B/6H,EAAG8R,IAAMsiH,MAAM7zH,OACfggB,QAAU7a,KAAK6a,WAEfzO,IAAM,EAAG,IACLipH,SACAx6G,QAAQy6G,UAAY,GAExBz6G,QAAQ06G,YACR16G,QAAQ6+E,OAAOg1B,MAAM,GAAG,GAAIA,MAAM,GAAG,IACtB,IAAXxtF,WACK5mC,EAAI,EAAGA,EAAI8R,IAAK9R,IACjBugB,QAAQ26G,OAAO9G,MAAMp0H,GAAG,GAAIo0H,MAAMp0H,GAAG,aAGpCA,EAAI,EAAGA,EAAI8R,IAAK9R,GAAK,EACtBugB,QAAQ46G,cAAc/G,MAAMp0H,GAAG,GAAIo0H,MAAMp0H,GAAG,GAAIo0H,MAAMp0H,EAAI,GAAG,GAAIo0H,MAAMp0H,EAAI,GAAG,GAAIo0H,MAAMp0H,EAAI,GAAG,GAAIo0H,MAAMp0H,EAAI,GAAG,IAGpH+6H,QACAx6G,QAAQ26G,OAAO9G,MAAM,GAAG,GAAIA,MAAM,GAAG,IACrC7zG,QAAQ66G,YACR76G,QAAQolE,QAERplE,QAAQ8kE,WAUpBg2C,MAAO,SAAUtnH,QACTwM,QAAU7a,KAAK6a,QAEnBA,QAAQ+6G,OACJ51H,KAAK61H,UAAUxnH,GAAI,SACnBwM,QAAQolE,OAEZplE,QAAQi7G,WAWZC,aAAc,SAAU3mF,MAAOthC,EAAGiT,SACvB,CACFjT,EAAIpB,KAAK8hB,IAAI4gB,OAAWruB,EAAIrU,KAAKwiB,IAAIkgB,OACrCthC,EAAIpB,KAAKwiB,IAAIkgB,OAAWruB,EAAIrU,KAAK8hB,IAAI4gB,SAW9C4mF,aAAc,SAAUtH,MAAOt/E,WACvB90C,EAAG27H,GAAK,GAAI7pH,IAAMsiH,MAAM7zH,UAExBuR,KAAO,SACAsiH,UAGNp0H,EAAI,EAAGA,EAAI8R,IAAK9R,IACjB27H,GAAGv6H,KAAKsE,KAAK+1H,aAAa3mF,MAAOs/E,MAAMp0H,GAAG,GAAIo0H,MAAMp0H,GAAG,YAGpD27H,IAUXxG,oBAAqB,SAASphH,GAAIqhH,aAU1BjvG,GAAIC,GAAIyf,GAAIC,GAAI+B,GAAI3Z,GAAI0tG,IAAKC,IAAKC,IAAKC,IAAKv3F,GAAIiC,GAJhDnkC,EAAI,EACJi5B,GAAKnpB,KAAK8hB,KAAKkhG,SACf95F,GAAKlpB,KAAKwiB,KAAKwgG,SACf/1E,GAAKtrC,GAAGilC,wBAGR5mC,KAAKwC,IAAI2mB,IAAMnpB,KAAKwC,IAAI0mB,IACxBh5B,GAAK8P,KAAKwC,IAAI2mB,IAEdj5B,GAAK8P,KAAKwC,IAAI0mB,IAEdC,IAAM,GACNsK,GAAK,EACLC,GAAKvK,GAAKj5B,IAEVujC,IAAMtK,GAAKj5B,EACXwjC,GAAK,GAELxK,IAAM,GACNuM,GAAK,EACL3Z,GAAKoN,GAAKh5B,IAEVulC,IAAMvM,GAAKh5B,EACX4rB,GAAK,GAGT/H,GAAK,IAAI0D,OAAO3a,MAAM1H,eAAgB,CAAC63C,GAAG,GAAIA,GAAG,IAAKtrC,GAAGjO,OAEzD0+B,IADApe,GAAK,IAAIyD,OAAO3a,MAAM1H,eAAgB,CAAC63C,GAAG,GAAIA,GAAG,IAAKtrC,GAAGjO,QACjDmkB,UAAU,GAAK9D,GAAG8D,UAAU,GACpCwc,GAAKrgB,GAAG6D,UAAU,GAAK9D,GAAG8D,UAAU,GACpC2xG,IAAMz1G,GAAG8D,UAAU,GAAKua,GAAKqB,GAC7Bi2F,IAAM31G,GAAG8D,UAAU,GAAKwc,GAAKoB,GAC7Bg0F,IAAM11G,GAAG8D,UAAU,GAAKua,GAAKsB,GAC7Bi2F,IAAM51G,GAAG8D,UAAU,GAAKwc,GAAKvY,GAEtBxoB,KAAK6a,QAAQy7G,qBAAqBJ,IAAKE,IAAKD,IAAKE,MAe5D1G,qBAAsB,SAASthH,GAAIuhC,GAAIC,GAAIrgC,EAAGi1B,GAAImrF,GAAIzlD,QAE9C1pD,GAAIC,GAAI61G,IAAKC,IAAKC,GAAIC,IAAKC,IAAKC,IAAK93F,GAAIiC,GADzC4Y,GAAKtrC,GAAGilC,wBAGZ7yB,GAAK,IAAI0D,OAAO3a,MAAM1H,eAAgB,CAAC63C,GAAG,GAAIA,GAAG,IAAKtrC,GAAGjO,OAEzD0+B,IADApe,GAAK,IAAIyD,OAAO3a,MAAM1H,eAAgB,CAAC63C,GAAG,GAAIA,GAAG,IAAKtrC,GAAGjO,QACjDmkB,UAAU,GAAK9D,GAAG8D,UAAU,GACpCwc,GAAKtgB,GAAG8D,UAAU,GAAK7D,GAAG6D,UAAU,GAEpCgyG,IAAM91G,GAAG8D,UAAU,GAAKua,GAAK8Q,GAC7B4mF,IAAM91G,GAAG6D,UAAU,GAAKwc,GAAK8O,GAC7B6mF,IAAMj2G,GAAG8D,UAAU,GAAKua,GAAK2F,GAC7BkyF,IAAMj2G,GAAG6D,UAAU,GAAKwc,GAAK6uF,GAC7B6G,GAAKjnH,GAAKsvB,GAAKiC,IAAM,GACrB61F,IAAMzsD,IAAMrrC,GAAKiC,IAAM,GAEhB/gC,KAAK6a,QAAQg8G,qBAAqBH,IAAKC,IAAKC,IAAKL,IAAKC,IAAKC,KAItEptC,eAAgB,SAASh7E,QACjB+8D,IAAKsvC,GAEL9oC,SADAyjB,KAAO/hF,KAAKrG,SAASoB,GAAG0E,QAAQ6+D,iBAIpC8oC,IADAA,GAAKpnG,KAAKrG,SAASoB,GAAG0E,QAAQ3B,cACnB,EAAKspG,GAAK,EACrBtvC,IAAM93D,KAAKrG,SAASoB,GAAG0E,QAAQ5B,WAElB,WAATkkF,KACAzjB,SAAW5xE,KAAKyvH,oBAAoBphH,GAAIiF,KAAKrG,SAASoB,GAAG0E,QAAQg9G,gBACjD,WAAT16B,OACPzjB,SAAW5xE,KAAK2vH,qBAAqBthH,GACjCiF,KAAKrG,SAASoB,GAAG0E,QAAQi9G,YACzB18G,KAAKrG,SAASoB,GAAG0E,QAAQk9G,YACzB38G,KAAKrG,SAASoB,GAAG0E,QAAQm9G,WACzB58G,KAAKrG,SAASoB,GAAG0E,QAAQo9G,YACzB78G,KAAKrG,SAASoB,GAAG0E,QAAQq9G,YACzB98G,KAAKrG,SAASoB,GAAG0E,QAAQs9G,cAGjCz+C,SAASklD,aAAaxjH,KAAKrG,SAASoB,GAAG0E,QAAQ88G,qBAAsBzkD,KACrEwG,SAASklD,aAAaxjH,KAAKrG,SAASoB,GAAG0E,QAAQ+8G,mBACzBx8G,KAAKrG,SAASoB,GAAG0E,QAAQohF,sBAC5CviB,UAaPikD,UAAW,SAAUxnH,GAAIxD,KAAMksH,gBAEN70C,GAAIqH,GACrB9e,KAAMkmD,KAAM/gH,EAAGE,EAAG8gH,GAClBC,KAHAmG,UAAW,EACX/0C,GAAK5zE,GAAG0E,eAIZlI,KAAOA,MAAQ,SACfksH,WAAaA,YAAclsH,KAE3Bq3E,GAAKliF,KAAKsgF,gBAAgBjyE,IAGb,YADbwiH,KAAOv9G,KAAKrG,SAASoB,GAAG0E,QAAQ6+D,YACE,WAATi/C,WAEhBh2G,QAAQk8G,WAAa,SAAW/2H,KAAKqpF,eAAeh7E,IAClD2oH,WAKE,UADbvsD,KAAOn3D,KAAKrG,SAASg1E,GAAGC,GAAKr3E,KAAO,aACJ,IAAT4/D,MAEnB36D,GADAA,EAAIwD,KAAKrG,SAASg1E,GAAGC,GAAKr3E,KAAO,aACxB,EAAKiF,EAAI,EAGE,IAAhB26D,KAAK5vE,QACL+U,EAAI66D,KACJmmD,GAAK9gH,IAILF,GADA+gH,KAAOrjD,MAAM9C,UAAUC,OACd,GACTmmD,GAAK9gH,EAAI6gH,KAAK,SAEb91G,QAAQo8G,YAAcrG,QAEtB/1G,QAAQk8G,WAAa,SAAWnnH,GAGrConH,UAAW,EAGfztC,GAAK5xE,WAAWrE,KAAKrG,SAASg1E,GAAGC,GAAK,iBACzB,WAATr3E,MAAsB6D,MAAM66E,MACjB,IAAPA,QACK1uE,QAAQo8G,YAAc,OAEtBp8G,QAAQy6G,UAAY/rC,IAIpB,WAAT1+E,WAAoCjN,IAAfqkF,GAAGxwE,SAAwC,KAAfwwE,GAAGxwE,eAC/CoJ,QAAQs/D,QAAU8H,GAAGxwE,SAGvBulH,WAQXE,QAAS,SAAU7oH,QACXwM,QAAU7a,KAAK6a,QACfs8G,QAAU7jH,KAAKrG,SAASoB,GAAG0E,QAAQggE,MAEvCl4D,QAAQ+6G,OAEJuB,QAAU,EACNt8G,QAAQu8G,aACRv8G,QAAQu8G,YAAYp3H,KAAK0tH,UAAUyJ,eAGlCt8G,QAAQw8G,cAAgB,GAG7Br3H,KAAK61H,UAAUxnH,GAAI,WACnBwM,QAAQ8kE,SAGZ9kE,QAAQi7G,WAWZwB,gBAAiB,SAAU5I,MAAO5gH,EAAGiT,OAC7BzmB,EAAG27H,GAAK,GAAI7pH,IAAMsiH,MAAM7zH,UAExBuR,KAAO,SACAsiH,UAGNp0H,EAAI,EAAGA,EAAI8R,IAAK9R,IACjB27H,GAAGv6H,KAAK,CAAEgzH,MAAMp0H,GAAG,GAAKwT,EAAG4gH,MAAMp0H,GAAG,GAAKymB,WAGtCk1G,IAQXx1C,UAAW,SAAUpyE,QACbzR,EAAI0W,KAAKrG,SAASoB,GAAG0E,QAAQ0hE,MAC7Bh7C,KAAOnmB,KAAKrG,SAASoB,GAAG0E,QAAQ0mB,MAChCnU,IAAMjX,GAAGR,OAAO0W,UAChBsqG,OAASp1F,KAAO/sB,KAAKmU,KAAK,GAAK,GAC/BiuG,IAAa,GAAPr1F,KACN89F,SAAW5/G,WAAWrE,KAAKrG,SAASoB,GAAG0E,QAAQlB,cAAgB,EAC/DgJ,QAAU7a,KAAK6a,WAEdxM,GAAGmzE,YAAYvvE,eAIZrV,OACH,YACA,IACDie,QAAQ06G,YACR16G,QAAQ6+E,OAAOp0E,IAAI,GAAKmU,KAAMnU,IAAI,GAAKmU,MACvC5e,QAAQ26G,OAAOlwG,IAAI,GAAKmU,KAAMnU,IAAI,GAAKmU,MACvC5e,QAAQ6+E,OAAOp0E,IAAI,GAAKmU,KAAMnU,IAAI,GAAKmU,MACvC5e,QAAQ26G,OAAOlwG,IAAI,GAAKmU,KAAMnU,IAAI,GAAKmU,MACvC5e,QAAQs/D,QAAU,QAClBt/D,QAAQ28G,SAAW,QACnB38G,QAAQ66G,iBACHwB,QAAQ7oH,cAEZ,aACA,IACDwM,QAAQ06G,YACR16G,QAAQs6B,IAAI7vB,IAAI,GAAIA,IAAI,GAAImU,KAAO,EAAI89F,SAAU,EAAG,EAAI7qH,KAAKiV,IAAI,GACjE9G,QAAQ66G,iBACHC,MAAMtnH,SACN6oH,QAAQ7oH,cAEZ,aACA,QACGorB,MAAQ,QAIZ5e,QAAQ+6G,OACJ51H,KAAK61H,UAAUxnH,GAAI,SAAU,SAC7BwM,QAAQ48G,SAASnyG,IAAI,GAAKmU,KAAO89F,SAAUjyG,IAAI,GAAKmU,KAAO89F,SAAiB,EAAP99F,KAAW,EAAI89F,SAAiB,EAAP99F,KAAW,EAAI89F,UAEjH18G,QAAQi7G,UACRj7G,QAAQ+6G,YACHC,UAAUxnH,GAAI,QACnBwM,QAAQ48G,SAASnyG,IAAI,GAAKmU,KAAO89F,SAAUjyG,IAAI,GAAKmU,KAAO89F,SAAiB,EAAP99F,KAAW89F,SAAiB,EAAP99F,KAAW89F,UACrG18G,QAAQi7G,oBAEP,WACA,IACDj7G,QAAQ06G,YACR16G,QAAQ6+E,OAAOp0E,IAAI,GAAKmU,KAAMnU,IAAI,IAClCzK,QAAQ26G,OAAOlwG,IAAI,GAAKmU,KAAMnU,IAAI,IAClCzK,QAAQ6+E,OAAOp0E,IAAI,GAAIA,IAAI,GAAKmU,MAChC5e,QAAQ26G,OAAOlwG,IAAI,GAAIA,IAAI,GAAKmU,MAChC5e,QAAQs/D,QAAU,QAClBt/D,QAAQ28G,SAAW,QACnB38G,QAAQ66G,iBACHwB,QAAQ7oH,cAEZ,cACA,KACDwM,QAAQ06G,YACR16G,QAAQ6+E,OAAOp0E,IAAI,GAAKmU,KAAMnU,IAAI,IAClCzK,QAAQ26G,OAAOlwG,IAAI,GAAIA,IAAI,GAAKmU,MAChC5e,QAAQ26G,OAAOlwG,IAAI,GAAKmU,KAAMnU,IAAI,IAClCzK,QAAQ26G,OAAOlwG,IAAI,GAAIA,IAAI,GAAKmU,MAChC5e,QAAQ66G,iBACHC,MAAMtnH,SACN6oH,QAAQ7oH,cAEZ,iBACA,QACA,IACDwM,QAAQ06G,YACR16G,QAAQ6+E,OAAOp0E,IAAI,GAAIA,IAAI,GAAKmU,MAChC5e,QAAQ26G,OAAOlwG,IAAI,GAAKupG,OAAQvpG,IAAI,GAAKwpG,KACzCj0G,QAAQ26G,OAAOlwG,IAAI,GAAKupG,OAAQvpG,IAAI,GAAKwpG,KACzCj0G,QAAQ66G,iBACHC,MAAMtnH,SACN6oH,QAAQ7oH,cAEZ,mBACA,IACDwM,QAAQ06G,YACR16G,QAAQ6+E,OAAOp0E,IAAI,GAAIA,IAAI,GAAKmU,MAChC5e,QAAQ26G,OAAOlwG,IAAI,GAAKupG,OAAQvpG,IAAI,GAAKwpG,KACzCj0G,QAAQ26G,OAAOlwG,IAAI,GAAKupG,OAAQvpG,IAAI,GAAKwpG,KACzCj0G,QAAQ66G,iBACHC,MAAMtnH,SACN6oH,QAAQ7oH,cAEZ,mBACA,IACDwM,QAAQ06G,YACR16G,QAAQ6+E,OAAOp0E,IAAI,GAAKmU,KAAMnU,IAAI,IAClCzK,QAAQ26G,OAAOlwG,IAAI,GAAKwpG,IAAKxpG,IAAI,GAAKupG,QACtCh0G,QAAQ26G,OAAOlwG,IAAI,GAAKwpG,IAAKxpG,IAAI,GAAKupG,QACtCh0G,QAAQ66G,iBACHC,MAAMtnH,SACN6oH,QAAQ7oH,cAEZ,oBACA,IACDwM,QAAQ06G,YACR16G,QAAQ6+E,OAAOp0E,IAAI,GAAKmU,KAAMnU,IAAI,IAClCzK,QAAQ26G,OAAOlwG,IAAI,GAAKwpG,IAAKxpG,IAAI,GAAKupG,QACtCh0G,QAAQ26G,OAAOlwG,IAAI,GAAKwpG,IAAKxpG,IAAI,GAAKupG,QACtCh0G,QAAQ66G,iBACHC,MAAMtnH,SACN6oH,QAAQ7oH,MAMrB0yE,YAAa,SAAU1yE,SACdoyE,UAAUpyE,KAenBqpH,WAAY,SAAUrpH,GAAIspH,KAAMC,KAAM11C,GAAI70E,OACjC8yB,GAAIgC,GAAI/B,GAAI5X,GACZqvG,GAAI/kG,EACJglG,UACAC,UAIAC,QAASC,QAGT5C,OACA/6H,EAAG8R,IACHw3E,IAAKC,IAAKC,IAAKC,IAAK9sD,KACpBihG,KAAMC,KATNt9G,QAAU7a,KAAK6a,QAEfhQ,KAAO,EAEPutH,UAAY,EACZC,UAAY,EAKZt1C,MAAQ11E,EAAE41E,QACVD,MAAQ31E,EAAE61E,UAE+B,SAA1C5vE,KAAKrG,SAASoB,GAAG0E,QAAQpB,eACnBoxE,OAASC,OAAQ,IAEnB30E,GAAG5D,eAAiBjB,MAAMvF,kBAC1Bk8B,GAAKw3F,KAAKpzG,UAAU,GACpB4d,GAAKw1F,KAAKpzG,UAAU,GACpB6b,GAAKw3F,KAAKrzG,UAAU,GACpBiE,GAAKovG,KAAKrzG,UAAU,GACpB2zG,KAAOC,KAAOzrH,KAAKypB,MAAM3N,GAAK2Z,GAAI/B,GAAKD,QACpC,IACHA,GAAK9xB,GAAG9B,OAAO,GAAGgY,UAAU,GAC5B4d,GAAK9zB,GAAG9B,OAAO,GAAGgY,UAAU,IAE5B0S,KAAO5oB,GAAG9B,OAAO1R,OAAS,GACf,SAIXulC,GAAK/xB,GAAG9B,OAAO8B,GAAG9B,OAAO1R,OAAS,GAAG0pB,UAAU,GAC/CiE,GAAKna,GAAG9B,OAAO8B,GAAG9B,OAAO1R,OAAS,GAAG0pB,UAAU,GAE/Cq/D,IAAMv1E,GAAG9B,OAAO,GAAGgY,UAAU,GAAKlW,GAAG9B,OAAO,GAAGgY,UAAU,GACzDs/D,IAAMx1E,GAAG9B,OAAO,GAAGgY,UAAU,GAAKlW,GAAG9B,OAAO,GAAGgY,UAAU,GACzDu/D,IAAMz1E,GAAG9B,OAAO0qB,MAAM1S,UAAU,GAAKlW,GAAG9B,OAAO0qB,KAAO,GAAG1S,UAAU,GACnEw/D,IAAM11E,GAAG9B,OAAO0qB,MAAM1S,UAAU,GAAKlW,GAAG9B,OAAO0qB,KAAO,GAAG1S,UAAU,GAC/Dw+D,QACAm1C,KAAOxrH,KAAKypB,MAAM0tD,IAAKD,MAEvBZ,QACAm1C,KAAOzrH,KAAKypB,MAAM4tD,IAAKD,SAI/B+zC,GAAKvkH,KAAKrG,SAASoB,GAAG0E,QAAQmvE,GAAK,gBAE/Ba,SAGAjwD,EAAI+kG,GAFGxqH,EAAEw1E,UAKTm1C,QADAntH,KAAOwC,EAAEm1E,UAGI,IAAT33E,KACAktH,UAAY,CACH,CAAEjlG,EAAa,IAAJA,GACX,CAAE,EAAa,GACf,CAAEA,EAAa,GAAJA,GACX,CAAM,GAAJA,EAAa,SAErB,GAAa,IAATjoB,KACPktH,UAAY,CACH,CAAEjlG,EAAI,EAAY,IAAJA,GACd,CAAE,EAAgB,IAAJA,GACd,CAAE,EAAgB,GAAJA,GACd,CAAEA,EAAI,EAAY,GAAJA,SAEpB,GAAa,IAATjoB,SACPioB,GAAK,GACLslG,UAAY,EAgBZhsH,KAfA2rH,UAAY,CACR,CAAC,GAAO,MACR,CAAC,KAAM,MACP,CAAC,KAAM,KACP,CAAC,EAAM,MACP,CAAC,IAAM,MACP,CAAC,KAAM,MACP,CAAC,EAAM,MACP,CAAC,KAAM,MACP,CAAC,IAAM,KACP,CAAC,EAAM,GACP,CAAC,KAAM,MACP,CAAC,KAAM,MACP,CAAC,GAAO,QAEIl9H,OACXP,EAAI,EAAGA,EAAI8R,IAAK9R,IACjBy9H,UAAUz9H,GAAG,KAAOw4B,EACpBilG,UAAUz9H,GAAG,IAAMw4B,EACnBilG,UAAUz9H,GAAG,IAAM,GAAKw4B,EACxBilG,UAAUz9H,GAAG,IAAM,KAAOw4B,OAE3B,GAAa,IAATjoB,SACPioB,GAAK,GACLslG,UAAY,EAgBZhsH,KAfA2rH,UAAY,CACR,CAAC,GAAM,MACP,CAAC,KAAK,MACN,CAAC,KAAK,MACN,CAAC,EAAK,MACN,CAAC,IAAK,MACN,CAAC,EAAK,MACN,CAAC,EAAK,MACN,CAAC,EAAK,MACN,CAAC,IAAK,KACN,CAAC,EAAK,GACN,CAAC,KAAK,MACN,CAAC,KAAK,MACN,CAAC,GAAM,QAEKl9H,OACXP,EAAI,EAAGA,EAAI8R,IAAK9R,IACjBy9H,UAAUz9H,GAAG,KAAOw4B,EACpBilG,UAAUz9H,GAAG,IAAMw4B,EACnBilG,UAAUz9H,GAAG,IAAM,GAAKw4B,EACxBilG,UAAUz9H,GAAG,IAAM,KAAOw4B,OAE3B,GAAa,IAATjoB,SACPioB,GAAK,GACLslG,UAAY,EAgBZhsH,KAfA2rH,UAAY,CACR,CAAC,GAAM,MACP,CAAC,KAAK,MACN,CAAC,KAAK,MACN,CAAC,EAAK,MACN,CAAC,IAAK,MACN,CAAC,IAAK,MACN,CAAC,EAAK,MACN,CAAC,IAAK,MACN,CAAC,IAAK,KACN,CAAC,EAAK,GACN,CAAC,KAAK,MACN,CAAC,KAAK,MACN,CAAC,GAAM,QAEKl9H,OACXP,EAAI,EAAGA,EAAI8R,IAAK9R,IACjBy9H,UAAUz9H,GAAG,KAAOw4B,EACpBilG,UAAUz9H,GAAG,IAAMw4B,EACnBilG,UAAUz9H,GAAG,IAAM,GAAKw4B,EACxBilG,UAAUz9H,GAAG,IAAM,KAAOw4B,OAE3B,GAAa,IAATjoB,SACPioB,EAAI+kG,GACJO,UAAY,EAUZhsH,KATA2rH,UAAY,CACR,CAAC,EAAK,OACN,CAAC,KAAK,MACN,CAAC,KAAK,KACN,CAAC,GAAM,KACP,CAAC,KAAK,KACN,CAAC,KAAK,MACN,CAAC,EAAK,KAEMl9H,OACXP,EAAI,EAAGA,EAAI8R,IAAK9R,IACjBy9H,UAAUz9H,GAAG,KAAOw4B,EACpBilG,UAAUz9H,GAAG,IAAMw4B,EACnBilG,UAAUz9H,GAAG,IAAM,GAAKw4B,EACxBilG,UAAUz9H,GAAG,IAAM,IAAOw4B,OAG9BilG,UAAY,CACP,CAAEjlG,EAAU,IAAJA,GACR,CAAE,EAAU,GACZ,CAAEA,EAAU,GAAJA,OAKjBkwD,SAEAlwD,EAAI+kG,GADGxqH,EAAEy1E,SAITm1C,QADAptH,KAAOwC,EAAEo1E,SAEI,IAAT53E,KACAitH,UAAY,CACP,EAAGhlG,EAAQ,IAAJA,GACP,CAAE,EAAS,GACX,EAAGA,EAAQ,GAAJA,GACP,CAAO,IAAJA,EAAS,SAEd,GAAa,IAATjoB,KACPitH,UAAY,CACH,EAAEhlG,EAAI,EAAY,IAAJA,GACd,CAAE,EAAgB,IAAJA,GACd,CAAE,EAAgB,GAAJA,GACd,EAAEA,EAAI,EAAY,GAAJA,SAEpB,GAAa,IAATjoB,SACPioB,GAAK,GACLulG,UAAY,EAgBZjsH,KAfA0rH,UAAY,CACR,CAAC,GAAO,MACR,CAAC,KAAM,MACP,CAAC,KAAM,KACP,CAAC,EAAM,MACP,CAAC,IAAM,MACP,CAAC,KAAM,MACP,CAAC,EAAM,MACP,CAAC,KAAM,MACP,CAAC,IAAM,KACP,CAAC,EAAM,GACP,CAAC,KAAM,MACP,CAAC,KAAM,MACP,CAAC,GAAO,QAEIj9H,OACXP,EAAI,EAAGA,EAAI8R,IAAK9R,IACjBw9H,UAAUx9H,GAAG,IAAMw4B,EACnBglG,UAAUx9H,GAAG,IAAMw4B,EACnBglG,UAAUx9H,GAAG,IAAM,GAAKw4B,EACxBglG,UAAUx9H,GAAG,IAAM,KAAOw4B,OAG3B,GAAa,IAATjoB,SACPioB,GAAK,GACLulG,UAAY,EAgBZjsH,KAfA0rH,UAAY,CACR,CAAC,GAAM,MACP,CAAC,KAAK,MACN,CAAC,KAAK,MACN,CAAC,EAAK,MACN,CAAC,IAAK,MACN,CAAC,EAAK,MACN,CAAC,EAAK,MACN,CAAC,EAAK,MACN,CAAC,IAAK,KACN,CAAC,EAAK,GACN,CAAC,KAAK,MACN,CAAC,KAAK,MACN,CAAC,GAAM,QAEKj9H,OACXP,EAAI,EAAGA,EAAI8R,IAAK9R,IACjBw9H,UAAUx9H,GAAG,IAAMw4B,EACnBglG,UAAUx9H,GAAG,IAAMw4B,EACnBglG,UAAUx9H,GAAG,IAAM,GAAKw4B,EACxBglG,UAAUx9H,GAAG,IAAM,KAAOw4B,OAG3B,GAAa,IAATjoB,SACPioB,GAAK,GACLulG,UAAY,EAgBZjsH,KAfA0rH,UAAY,CACR,CAAC,GAAM,MACP,CAAC,KAAK,MACN,CAAC,KAAK,MACN,CAAC,EAAK,MACN,CAAC,IAAK,MACN,CAAC,IAAK,MACN,CAAC,EAAK,MACN,CAAC,IAAK,MACN,CAAC,IAAK,KACN,CAAC,EAAK,GACN,CAAC,KAAK,MACN,CAAC,KAAK,MACN,CAAC,GAAM,QAEKj9H,OACXP,EAAI,EAAGA,EAAI8R,IAAK9R,IACjBw9H,UAAUx9H,GAAG,IAAMw4B,EACnBglG,UAAUx9H,GAAG,IAAMw4B,EACnBglG,UAAUx9H,GAAG,IAAM,GAAKw4B,EACxBglG,UAAUx9H,GAAG,IAAM,KAAOw4B,OAI3B,GAAa,IAATjoB,SACPioB,EAAI+kG,GACJQ,UAAY,EAUZjsH,KATA0rH,UAAY,CACR,CAAC,EAAK,OACN,CAAC,KAAK,MACN,CAAC,KAAK,KACN,CAAC,GAAM,KACP,CAAC,KAAK,KACN,CAAC,KAAK,MACN,CAAC,EAAK,KAEMj9H,OACXP,EAAI,EAAGA,EAAI8R,IAAK9R,IACjBw9H,UAAUx9H,GAAG,IAAMw4B,EACnBglG,UAAUx9H,GAAG,IAAMw4B,EACnBglG,UAAUx9H,GAAG,IAAM,GAAKw4B,EACxBglG,UAAUx9H,GAAG,IAAM,IAAOw4B,OAI9BglG,UAAY,CACP,EAAGhlG,EAAQ,IAAJA,GACP,CAAE,EAAS,GACX,EAAGA,EAAQ,GAAJA,IAKpBjY,QAAQ+6G,OACJ51H,KAAK61H,UAAUxnH,GAAI,SAAU,eACxBwnH,UAAUxnH,GAAI,UACf00E,QAEIsyC,OADY,IAAZ2C,aAKC5C,aAAap1H,KAAKs3H,gBAAgBt3H,KAAKg2H,aAAa+B,UAAWG,MAAO/3F,GAAIgC,IAAKi2F,UAAW/C,SAE/FryC,QAEIqyC,OADY,IAAZ4C,aAKC7C,aAAap1H,KAAKs3H,gBAAgBt3H,KAAKg2H,aAAa8B,UAAWK,MAAO/3F,GAAI5X,IAAK6vG,UAAWhD,UAGvGx6G,QAAQi7G,YAKhBr0C,SAAU,SAAUpzE,QACZiqH,OAAQC,OAIRr2C,GAAIpvD,EAAGkvD,UAHPvhE,GAAK,IAAI0D,OAAO3a,MAAM1H,eAAgBuM,GAAGqiC,OAAO7iC,OAAOG,UAAWK,GAAGjO,OACrEsgB,GAAK,IAAIyD,OAAO3a,MAAM1H,eAAgBuM,GAAGuiC,OAAO/iC,OAAOG,UAAWK,GAAGjO,OACrEiyC,OAAS,KAGRhkC,GAAGmzE,YAAYvvE,UAIpBiwE,GAAKliF,KAAKsgF,gBAAgBjyE,IAC1BykB,EAAIxf,KAAKrG,SAASoB,GAAG0E,QAAQmvE,GAAK,kBAClCF,UAAYhiF,KAAKmiF,iBAAiB9zE,GAAIykB,EAAGovD,KAE3Be,SAAWjB,UAAUkB,UAC/B7wC,QAAU,GAEdlD,SAASiD,aAAa/jC,GAAIoS,GAAIC,GAAI2xB,aAC7BixC,kBAAkBj1E,GAAIoS,GAAIC,GAAIshE,WAEnCs2C,OAAS,IAAIn0G,OAAO3a,MAAM1H,eAAgB2e,GAAGzS,UAAWK,GAAGjO,OAC3Dm4H,OAAS,IAAIp0G,OAAO3a,MAAM1H,eAAgB4e,GAAG1S,UAAWK,GAAGjO,YAEtDmjF,qBAAqBl1E,GAAIoS,GAAIC,GAAIshE,gBAEjCnnE,QAAQ06G,iBACR16G,QAAQ6+E,OAAOj5E,GAAG8D,UAAU,GAAI9D,GAAG8D,UAAU,SAC7C1J,QAAQ26G,OAAO90G,GAAG6D,UAAU,GAAI7D,GAAG6D,UAAU,SAC7C2yG,QAAQ7oH,KAER2zE,UAAUiB,SACVjB,UAAUkB,cAENw0C,WAAWrpH,GAAIiqH,OAAQC,OAAQr2C,GAAIF,aAKhDN,WAAY,SAAUrzE,SACbozE,SAASpzE,KAIlBg2E,UAAW,aAOXC,YAAa,SAAUpW,WACf5zE,EAAGsV,EAAG9B,EAAGiT,EAET1G,KAAM9f,EADN6R,IAAM8hE,MAAMA,MAAMrzE,OAElBggB,QAAU7a,KAAK6a,YAEnBA,QAAQ06G,YACHj7H,EAAI,EAAGA,EAAI8R,IAAK9R,QAEjBwT,GADA8B,EAAIs+D,MAAMA,MAAM5zE,IACV,GACNymB,EAAInR,EAAE,GAINyK,KAAOvM,EAAEjT,OACTggB,QAAQ6+E,OAAO5rF,EAAE,GAAIiT,EAAE,IAClBxmB,EAAI,EAAGA,EAAI8f,OAAQ9f,EACpBsgB,QAAQ26G,OAAO1nH,EAAEvT,GAAIwmB,EAAExmB,IAc/BsgB,QAAQs/D,QAAU,aACb+8C,QAAQhpD,QAQjB2T,UAAW,SAAUxzE,QACb6zE,GAAIpvD,EAAGkvD,UAEP1uE,KAAKrG,SAASoB,GAAG0E,QAAQ0wE,kBACpBC,2BAA2Br1E,SAE3Bs1E,qBAAqBt1E,IAE1BA,GAAGkpC,aAAe,IAClB2qC,GAAKliF,KAAKsgF,gBAAgBjyE,IAC1BykB,EAAIxf,KAAKrG,SAASoB,GAAG0E,QAAQmvE,GAAK,kBAClCF,UAAYhiF,KAAKmiF,iBAAiB9zE,GAAIykB,EAAGovD,KAC1Be,SACVjB,UAAUkB,cACNw0C,WAAWrpH,GAAI,KAAM,KAAM6zE,GAAIF,aAMhDF,YAAa,SAAUzzE,SACdwzE,UAAUxzE,KAQnBk2E,YAAa,SAAUl2E,QACfgjC,GAAKhjC,GAAGqqB,OAAO7qB,OAAO0W,UAAU,GAChC1E,GAAKxR,GAAGqqB,OAAO7qB,OAAO0W,UAAU,GAChCqyE,GAAKvoF,GAAGjO,MAAM2kB,MACd8xE,GAAKxoF,GAAGjO,MAAM4kB,MACdwzG,GAAK,EAAInqH,GAAGqtC,SACZ+8E,GAAK,EAAIpqH,GAAGqtC,SACZg9E,OAASF,GAAK5hC,GACd+hC,QAAUF,GAAK5hC,GACf+hC,GAAKvnF,GAAKqnF,OAAS,EACnBG,GAAKh5G,GAAK84G,QAAU,EACpBG,GAAMJ,OAAS,EAAK,SACpBK,GAAMJ,QAAU,EAAK,SACrBK,GAAKJ,GAAKF,OACVO,GAAKJ,GAAKF,QACVO,GAAKN,GAAKF,OAAS,EACnBS,GAAKN,GAAKF,QAAU,EACpB99G,QAAU7a,KAAK6a,QAEf29G,GAAK,GAAOC,GAAK,IAAQ/pH,MAAM2iC,GAAKxxB,MACpChF,QAAQ06G,YACR16G,QAAQ6+E,OAAOk/B,GAAIO,IACnBt+G,QAAQ46G,cAAcmD,GAAIO,GAAKJ,GAAIG,GAAKJ,GAAID,GAAIK,GAAIL,IACpDh+G,QAAQ46G,cAAcyD,GAAKJ,GAAID,GAAIG,GAAIG,GAAKJ,GAAIC,GAAIG,IACpDt+G,QAAQ46G,cAAcuD,GAAIG,GAAKJ,GAAIG,GAAKJ,GAAIG,GAAIC,GAAID,IACpDp+G,QAAQ46G,cAAcyD,GAAKJ,GAAIG,GAAIL,GAAIO,GAAKJ,GAAIH,GAAIO,IACpDt+G,QAAQ66G,iBACHC,MAAMtnH,SACN6oH,QAAQ7oH,MAKrBm2E,cAAe,SAAUn2E,WACdrO,KAAKukF,YAAYl2E,KAc5Bu2E,iBAAkB,SAAUxyE,IAAKi8D,cACzBxzD,QAAU7a,KAAK6a,QAGnBA,QAAQ+6G,OACR/6G,QAAQu+G,KAAO/qD,SAAW,WAC1BxzD,QAAQw+G,UAAY,OACpBx+G,QAAQy6G,UAAY,GACpBz6G,QAAQy+G,SAASlnH,IAAK,GAAI,EAAIi8D,UAC9BxzD,QAAQi7G,WAIZjxC,iBAAkB,SAAUx2E,QACpB8yF,MAAQ7tF,KAAKrG,SAASoB,GAAG0E,QAAQzB,UACjC8qE,SAAW9oE,KAAKrG,SAASoB,GAAG0E,QAAQy0E,UACpC4mC,MAAQ//G,GAAGs3E,aACX0oC,MAAQhgH,GAAGu3E,aACX/qE,QAAU7a,KAAK6a,eAEnBA,QAAQ+6G,OACJ51H,KAAK61H,UAAUxnH,GAAI,SAAU,UACxBK,MAAML,GAAGR,OAAO0W,UAAU,GAAKlW,GAAGR,OAAO0W,UAAU,MACxD1J,QAAQu+G,MAAQj4B,MAAQ,EAAIA,MAAQ,GAAK/kB,SAAW,cAE/CwK,eAAev4E,GAAIA,GAAGw4E,iBACb,SAAVunC,MACAvzG,QAAQ0+G,UAAY,OACH,UAAVnL,MACPvzG,QAAQ0+G,UAAY,QACH,WAAVnL,QACPvzG,QAAQ0+G,UAAY,UAEV,WAAVlL,MACAxzG,QAAQ2+G,aAAe,SACN,QAAVnL,MACPxzG,QAAQ2+G,aAAe,MACN,WAAVnL,QACPxzG,QAAQ2+G,aAAe,UAE3B3+G,QAAQy+G,SAASjrH,GAAGo3E,UAAWp3E,GAAGR,OAAO0W,UAAU,GAAIlW,GAAGR,OAAO0W,UAAU,KAE/E1J,QAAQi7G,UACD,MAIXhxC,mBAAoB,SAAUz2E,SACrBw2E,iBAAiBx2E,KAK1BwxE,qBAAsB,SAAUxxE,GAAI26D,MAAO0B,aACN96D,EAAG+gH,KACJC,GAC5Bz1G,KAFAsvD,KAAOn3D,KAAKrG,SAAS+7D,OACrBl5D,EAAIwD,KAAKrG,SAASy9D,SAGtB56D,EAAKA,EAAI,EAAKA,EAAI,EAEdzB,GAAG0C,WAAWY,cAAgB84D,MAAQp8D,GAAG0C,WAAWa,gBAAkB9B,IAMtEwD,KAAKzU,OAAO4rE,QAAkB,IAATA,OAED,IAAhBA,KAAK5vE,QACL+U,EAAI66D,KACJmmD,GAAK9gH,IAILF,GADA+gH,KAAOrjD,MAAM9C,UAAUC,OACd,GACTmmD,GAAK9gH,EAAI6gH,KAAK,IAElBx1G,KAAO9M,GAAGsyE,SACNtyE,GAAG5D,eAAiBjB,MAAMlF,mBAA2D,SAAtCgP,KAAKrG,SAASoB,GAAG0E,QAAQ8D,WACxEsE,KAAK/D,MAAM4xD,MAAQp5D,EACnBuL,KAAK/D,MAAMszD,QAAUkmD,KAI7BviH,GAAG0C,WAAWY,YAAc84D,KAC5Bp8D,GAAG0C,WAAWa,cAAgB9B,IAQlCg4E,UAAW,SAAUz5E,IACjBA,GAAGsyE,SAAW,IAAIywC,MAMlB/iH,GAAGkgH,KAAO,QACLxmC,YAAY15E,KAIrB05E,YAAa,SAAU15E,QACfwM,QAAU7a,KAAK6a,QACf/K,EAAIwD,KAAKrG,SAASoB,GAAG0E,QAAQ3B,aAC7BqoH,SAAWnmH,KAAKxG,MAAK,WACjBuB,GAAGmgH,aAAc,EACbngH,GAAGorB,KAAK,IAAM,GAAKprB,GAAGorB,KAAK,IAAM,IAGrC5e,QAAQ+6G,OACR/6G,QAAQo8G,YAAcnnH,OAGjB82E,eAAev4E,GAAIA,GAAGw4E,iBAC3BhsE,QAAQitE,UAAUz5E,GAAGsyE,SACjBtyE,GAAGR,OAAO0W,UAAU,GACpBlW,GAAGR,OAAO0W,UAAU,GAAKlW,GAAGorB,KAAK,GACjCprB,GAAGorB,KAAK,GACRprB,GAAGorB,KAAK,IACZ5e,QAAQi7G,aACT91H,MAEHA,KAAKgoF,eAAe35E,IACpBA,GAAGsyE,SAASmM,OAAS2sC,SAEjBprH,GAAGmgH,aACHiL,YAMZ7yC,eAAgB,SAAUv4E,GAAI6K,OACtBnL,EAAG3B,IAAM8M,EAAEre,OACX82H,IAAM3xH,KAAK6a,QAEXzO,IAAM,IACN2B,EAAI/N,KAAKioF,eAAe55E,GAAI6K,GACxBxM,KAAKwC,IAAIimB,SAASM,IAAI1nB,KAAOmW,IAAIzF,KACjCkzG,IAAIpgC,UAAUxjF,EAAE,GAAG,GAAIA,EAAE,GAAG,GAAIA,EAAE,GAAG,GAAIA,EAAE,GAAG,GAAIA,EAAE,GAAG,GAAIA,EAAE,GAAG,MAM5Ei6E,eAAgB,SAAU35E,QAClB69E,WAEJA,IAAM54E,KAAKrG,SAASoB,GAAG69E,KACnB79E,GAAGkgH,OAASriC,MACZ79E,GAAGmgH,aAAc,EACjBngH,GAAGsyE,SAASzzC,IAAMg/C,IAClB79E,GAAGkgH,KAAOriC,KACH,IAWf3K,OAAQ,SAAUmtC,OAEVp7G,KAAKzU,OAAO6vH,QAAUp7G,KAAKzU,OAAO6vH,MAAMj1G,aACxCi1G,MAAMj1G,WAAWyD,YAAYwxG,QAKrC/qC,qBAAsB,SAAUt1E,QACxB/T,EAAGgrB,IAAKqyG,KAAMC,KAAMxrH,IAIpB2iH,SAHQ,IAKRl0G,QAAU7a,KAAK6a,aAEfxM,GAAGkpC,cAAgB,OAIvBnrC,IAAMM,KAAKC,IAAI0B,GAAG9B,OAAO1R,OAAQwT,GAAGkpC,cACpC18B,QAAQ06G,YAEgB,IAApBlnH,GAAG8nC,iBAOE77C,EAAI,EAAGA,EAAI8R,IAAK9R,IACjBgrB,IAAMjX,GAAG9B,OAAOjS,GAAGiqB,UAEf7V,MAAM4W,IAAI,KAAO5W,MAAM4W,IAAI,IAC3BypG,SAzBA,KA4BIzpG,IAAI,GAxBN,IAyBEA,IAAI,GAzBN,IA0BSA,IAAI,IA1Bb,MA2BEA,IAAI,IA3BN,KA8BEA,IAAI,GA9BN,IA+BEA,IAAI,GA/BN,IAgCSA,IAAI,IAhCb,MAiCEA,IAAI,IAjCN,KAJF,MAwCIypG,SACAl0G,QAAQ6+E,OAAOp0E,IAAI,GAAIA,IAAI,IAE3BzK,QAAQ26G,OAAOlwG,IAAI,GAAIA,IAAI,IAE/BypG,SA5CA,UA+CL,GAAwB,IAApB1gH,GAAG8nC,iBACV77C,EAAI,EACGA,EAAI8R,KACPkZ,IAAMjX,GAAG9B,OAAOjS,GAAGiqB,UACf7V,MAAM4W,IAAI,KAAO5W,MAAM4W,IAAI,IAC3BypG,SArDA,KAAA,MAuDIA,SACAl0G,QAAQ6+E,OAAOp0E,IAAI,GAAIA,IAAI,KAE3BhrB,GAAK,EACLq9H,KAAOtpH,GAAG9B,OAAOjS,GAAGiqB,UACpBjqB,GAAK,EACLs9H,KAAOvpH,GAAG9B,OAAOjS,GAAGiqB,UACpB1J,QAAQ46G,cAAcnwG,IAAI,GAAIA,IAAI,GAAIqyG,KAAK,GAAIA,KAAK,GAAIC,KAAK,GAAIA,KAAK,KAE1E7I,SA9DA,KAgEJz0H,GAAK,EAGbugB,QAAQs/D,QAAU,aACbw7C,MAAMtnH,SACN6oH,QAAQ7oH,MAIjBq1E,2BAA4B,SAAUr1E,QAC9B/T,EAAGC,EAAGiR,EAAG8Z,IAAKymC,GAAIE,GAAI7/C,IAGtB2iH,SAFQ,IAIRnyH,EAAI0W,KAAKrG,SAASoB,GAAG0E,QAAQlB,aAC7Bo9G,SAAoD,SAAxC37G,KAAKrG,SAASoB,GAAG0E,QAAQwpC,WACrC1hC,QAAU7a,KAAK6a,aAEfxM,GAAGkpC,cAAgB,QAInB03E,UAAY5gH,GAAGjO,MAAMqM,QAAQ4sC,MAAM8+B,eACnC9pE,GAAG9B,OAAS4oB,SAAS8P,oBAAoB52B,GAAG9B,OAAQ,KAGxDH,IAAMM,KAAKC,IAAI0B,GAAG9B,OAAO1R,OAAQwT,GAAGkpC,cACpC18B,QAAQ06G,YAEHh7H,EAAI,EAAGA,EAAI,EAAGA,QACfw0H,SApBQ,IAqBHz0H,EAAI,EAAGA,EAAI8R,IAAK9R,IACjBgrB,IAAMjX,GAAG9B,OAAOjS,GAAGiqB,UAEf7V,MAAM4W,IAAI,KAAO5W,MAAM4W,IAAI,IAC3BypG,SAzBA,KA4BIzpG,IAAI,GAzBN,IA0BEA,IAAI,GA1BN,IA2BSA,IAAI,IA3Bb,MA4BEA,IAAI,IA5BN,KA+BEA,IAAI,GA/BN,IAgCEA,IAAI,GAhCN,IAiCSA,IAAI,IAjCb,MAkCEA,IAAI,IAlCN,KAHF,MAwCIypG,SACAl0G,QAAQ6+E,OAAOp0E,IAAI,GAAIA,IAAI,KAE3B9Z,EAAI,EAAIjR,EACRsgB,QAAQ46G,cACH1pE,GAAqB,MAAfzmC,IAAI,GAAKymC,IAAcnvD,GAAK4O,EAAIkB,KAAKywB,SAAW5iC,GACtD0xD,GAAqB,MAAf3mC,IAAI,GAAK2mC,IAAcrvD,GAAK4O,EAAIkB,KAAKywB,SAAW5iC,GACtDwxD,GAAqB,MAAfzmC,IAAI,GAAKymC,IAAcnvD,GAAK4O,EAAIkB,KAAKywB,SAAW5iC,GACtD0xD,GAAqB,MAAf3mC,IAAI,GAAK2mC,IAAcrvD,GAAK4O,EAAIkB,KAAKywB,SAAW5iC,GACvD+qB,IAAI,GACJA,IAAI,KAGZypG,SApDA,IAqDAhjE,GAAKzmC,IAAI,GACT2mC,GAAK3mC,IAAI,IAIrBzK,QAAQs/D,QAAU,aACbw7C,MAAMtnH,SACN6oH,QAAQ7oH,MAIjBs2E,kBAAmB,SAAUxpE,KAAM9M,QAC3BkW,UAAWjqB,EAAGC,EACd6R,IAAMiC,GAAGyuC,SAASjiD,OAClBggB,QAAU7a,KAAK6a,QACfiL,QAAS,OAET1Z,KAAO,IAAMiC,GAAGmzE,YAAYvvE,aAGd,mBAAd5D,GAAGqhF,QACHtjF,MAGJyO,QAAQ06G,YACRj7H,EAAI,GACI+T,GAAGyuC,SAASxiD,GAAGwrB,QAAUxrB,EAAI8R,IAAM,GACvC9R,IACAwrB,QAAS,MAEbvB,UAAYlW,GAAGyuC,SAASxiD,GAAGuT,OAAO0W,UAClC1J,QAAQ6+E,OAAOn1E,UAAU,GAAIA,UAAU,IAElChqB,EAAID,EAAGC,EAAI6R,IAAM,EAAG7R,IAChB8T,GAAGyuC,SAASviD,GAAGurB,SAChBA,QAAS,GAEbvB,UAAYlW,GAAGyuC,SAASviD,GAAGsT,OAAO0W,UAClC1J,QAAQ26G,OAAOjxG,UAAU,GAAIA,UAAU,IAE3C1J,QAAQ66G,YAEJ5vG,aACK6vG,MAAMtnH,MAOnBwI,QAAS,SAASxI,GAAI1D,KACb0D,IAAMA,GAAGsyE,WACTtyE,GAAG0C,WAAWkB,QAAUtH,IAEpB0D,GAAGsyE,SAASvpE,MAAMQ,WADlBjN,IAC+B,UAEA,WAM5C8mD,KAAM,SAAUpjD,IACZjQ,IAAIkC,WAAW,wBAAyB,4BAEpCgT,KAAKzU,OAAOwP,GAAGsyE,YACftyE,GAAGsyE,SAASvpE,MAAMQ,WAAa,YAKvCmxE,KAAM,SAAU16E,IACZjQ,IAAIkC,WAAW,wBAAyB,4BAEpCgT,KAAKzU,OAAOwP,GAAGsyE,YACftyE,GAAGsyE,SAASvpE,MAAMQ,WAAa,WAKvCwxE,YAAa,SAAU/6E,QAEfqsG,GAGJA,IADAA,GAAKpnG,KAAKrG,SAASoB,GAAG0E,QAAQ3B,cACnB,EAAKspG,GAAK,GAMzBt6B,UAAW,SAAU/xE,IACbA,GAAG0C,WAAWW,SAAWrD,GAAG0E,QAAQrB,SAQxCrD,GAAG0C,WAAWW,OAASrD,GAAG0E,QAAQrB,SAItCwhE,UAAW,SAAU15E,YACbA,IAAIiR,eAAiBjB,MAAMlF,mBAA4D,SAAvCgP,KAAKrG,SAASzT,IAAIuZ,QAAQ8D,cACrE6uE,gBAAgBlsF,KAAK,IAE1BA,IAAI4G,MAAMilF,gBACV7rF,IAAI4G,MAAMmvE,SAASka,cAAcjwF,IAAI4G,OACrC5G,IAAI4G,MAAM8yF,iBACV15F,IAAI4G,MAAMmvE,SAASma,mBAEhB1pF,MAIXwpF,YAAa,SAAUhwF,YACfA,IAAIiR,eAAiBjB,MAAMlF,mBAA4D,SAAvCgP,KAAKrG,SAASzT,IAAIuZ,QAAQ8D,cACrE6uE,gBAAgBlsF,KAAK,IAE1BA,IAAI4G,MAAMilF,gBACV7rF,IAAI4G,MAAMmvE,SAASka,cAAcjwF,IAAI4G,OACrC5G,IAAI4G,MAAM8yF,iBACV15F,IAAI4G,MAAMmvE,SAASma,mBAEhB1pF,MAQXypF,cAAe,SAAUrpF,YAChBya,QAAQ+6G,YACR/6G,QAAQ6+G,UAAU,EAAG,EAAG15H,KAAKi1H,WAAW39G,MAAOtX,KAAKi1H,WAAW19G,QAEhEnX,OAASA,MAAMiM,KAAK0pG,oBACfnxB,iBAAiBxmF,IAAIyD,YAAa,KAK/C6nF,gBAAiB,gBACR7uE,QAAQi7G,WAIjBnlD,OAAQ,SAAU79C,EAAG/U,GACb/d,KAAKW,gBACAs0H,WAAW79G,MAAME,MAAQK,WAAWmb,GAAK,UACzCmiG,WAAW79G,MAAMG,OAASI,WAAWoG,GAAK,UAE1Ck3G,WAAW/vC,aAAa,QAAU,EAAIvtE,WAAWmb,GAAM,WACvDmiG,WAAW/vC,aAAa,SAAU,EAAIvtE,WAAWoG,GAAM,aAEvDk3G,WAAW39G,MAAQ,EAAIK,WAAWmb,QAClCmiG,WAAW19G,OAAS,EAAII,WAAWoG,SAEvClD,QAAU7a,KAAKi1H,WAAWngH,WAAW,WAIrC+F,QAAQY,MAAM,EAAG,IAG1B4vE,oBAAqB,kBACV,gBAIRjtF,IAAI42H,kBAoDf58H,OAAO,cAAc,CAAC,MAAO,sBAAsB,SAAUgG,IAAK+gF,yBAY9D/gF,IAAIu7H,WAAa,gBAQRt6C,mBAAoB,OASpBx0E,KAAO,MAGhBzM,IAAIC,OAAOD,IAAIu7H,WAAWzgI,UAAkD,CAaxEunF,UAAW,SAAU9gF,WAUrBohF,YAAa,SAAUphF,WAavB2hF,iBAAkB,SAAU3hF,WAa5B8hF,SAAU,SAAU9hF,WASpB+hF,WAAY,SAAU/hF,WAWtB0kF,UAAW,SAAU1kF,WAYrB2kF,YAAa,SAAU3kF,WAavBkiF,UAAW,SAAUliF,WASrBmiF,YAAa,SAAUniF,WAavB4kF,YAAa,SAAU5kF,WASvB6kF,cAAe,SAAU7kF,WAczB8kF,YAAa,SAAU9kF,WASvB+kF,cAAe,SAAU/kF,WAWzBilF,iBAAkB,SAAUxyE,IAAKd,YAcjCuzE,iBAAkB,SAAUllF,WAY5BmlF,mBAAoB,SAAUnlF,WAY9BolF,SAAU,SAAUplF,WAYpB4lF,WAAY,SAAU5lF,WAatB+lF,gBAAiB,SAAU/lF,QAASoiF,eASpC8F,wBAAyB,SAAUloF,QAASosE,YAAayF,iBAazDsW,UAAW,SAAUnoF,WASrBooF,YAAa,SAAUpoF,WASvBinF,eAAgB,SAAUjnF,QAASknF,mBAOnCmB,eAAgB,SAAUroF,WAa1BihF,gBAAiB,SAAUzlE,KAAM6e,SAQjC8mD,qBAAsB,SAAUnhF,QAASkL,QAQzCg2E,WAAY,SAAUh2E,KAAM1N,WAEjB,MAOXokF,OAAQ,SAAUpmE,QAOlBinE,WAAY,SAAUziF,WAWtBuhF,kBAAmB,SAAU/lE,KAAMrN,EAAGiT,EAAG+qC,GAAIE,MAY7Cw3B,eAAgB,SAAUroE,KAAMstE,IAAKC,IAAKC,IAAKC,IAAKxoF,SAUpDghF,eAAgB,SAAUjmE,KAAM0tE,WAAYzoF,SAa5CihF,sBAAuB,SAAU1hF,QAAS85B,KAAM5uB,QAQhD84E,qBAAsB,SAAUhkF,WAUhC+jF,2BAA4B,SAAU/jF,WAQtCglF,kBAAmB,SAAUxpE,KAAMxb,WAUnCwhF,eAAgB,SAAUhmE,KAAMrN,EAAGiT,EAAG+R,EAAG/U,KAYzC+qE,gBAAiB,SAAU3tE,KAAM5K,IAAK5F,OAOtCkM,QAAS,SAAUlX,QAAS7D,OACpB6D,UACAA,QAAQoR,WAAWkB,QAAUnW,QAYrC21D,KAAM,SAAU9xD,WAUhBopF,KAAM,SAAUppF,WAUhBqpF,aAAc,SAAU7tE,KAAMtQ,QAM9Bs1E,aAAc,SAAUxgF,WAMxB+/E,SAAU,SAAU//E,WAMpBwpF,YAAa,SAAUxpF,WAMvBypF,YAAa,SAAUzpF,WAMvB0pF,eAAgB,SAAU1pF,WAU1B8/E,oBAAqB,SAAU9/E,QAAS2pF,YAQxCpJ,mBAAoB,SAAUvgF,QAASqpE,MAAO0B,WAQ9CmV,qBAAsB,SAAUlgF,QAASqpE,MAAO0B,WAOhDqV,qBAAsB,SAAUpgF,QAAS2X,SAMzC8oE,UAAW,SAAUzgF,WAOrBuzE,UAAW,SAAUvzE,WAOrB6pF,YAAa,SAAU7pF,WAavB8pF,cAAe,aAMfC,gBAAiB,aAMjBC,YAAa,SAAUvpF,SAOvBe,eAAgB,SAAUhE,WACf,MAQXwzE,OAAQ,SAAU79C,EAAG/U,KAErBstE,oBAAqB,kBACV,gBAQfjtF,IAAIu7H,WAAWzgI,UAAY,IAAIimF,iBAExB/gF,IAAIu7H,cA0DfvhI,OAAO,WAAW,CACd,MAAO,YAAa,aAAc,aAAc,cAAe,UAC/D,eAAgB,eAAgB,kBAAmB,gBACpD,SAAUgG,IAAK02B,IAAKxhB,KAAM8gG,MAAOpoB,WAAYlgB,QAAS8gD,YAAaoG,YAAagC,eAAgB2E,mBAS/Fv7H,IAAIw7H,SAAW,CAKXC,cACI/tD,QAAQ1rE,MAAMmvE,SAAW,KAErBz6C,IAAIzgB,gBACJy3D,QAAQ1rE,MAAMmvE,SAAW,MAczBruE,SAAS44H,YAAc,eACf5gH,SAEAhY,SAASqb,OACTrD,EAAIhY,SAASqb,KAAKtD,WAClBC,GAAKhY,SAASqb,KAAKnD,WAGhBF,IAIX4b,IAAIpgB,mBACJo3D,QAAQ1rE,MAAMmvE,SAAW,UAGzBz6C,IAAIvgB,gBACJu3D,QAAQ1rE,MAAMmvE,SAAW,OAIzBz6C,IAAIlgB,UAAYkgB,IAAIpgB,mBACpBo3D,QAAQ1rE,MAAMmvE,SAAW,WAGzBz6C,IAAIlgB,UAAiC,OAArBk3D,QAAQyD,YACxBzD,QAAQ8J,KAAK/+D,QAAU,WACvBi1D,QAAQ2N,QAAQ5iE,QAAU,YAGvBi1D,QAAQ1rE,MAAMmvE,UAezBwqD,aAAc,SAAUzU,IAAKviF,IAAKnsB,IAAKojH,kBAC/BC,SAIE3mH,KAAKzU,OAAO+X,OAAgB,IAARA,KAAsC,gCAAb1V,6BAAAA,aAC/C0V,IAAM1V,UAGS,WAAfoJ,QAAOsM,MAA4B,OAAR0uG,QAC3B2U,MAAQrjH,IAAIzV,eAAemkH,KAGpB2U,MAAMl9G,YACTk9G,MAAM/8G,YAAY+8G,MAAMl9G,iBAG5Bk9G,MAAQ3U,gBAIS1nH,IAAjBo8H,cAA+C,SAAjBA,eAC9BA,aAAeh6H,KAAK65H,cAGH,QAAjBG,aACW,IAAIpN,YAAYqN,MAAOl3F,KACV,QAAjBi3F,aACI,IAAIhH,YAAYiH,OACH,WAAjBD,aACI,IAAIhF,eAAeiF,MAAOl3F,KAE1B,IAAI42F,YAcvBO,eAAgB,SAASjuH,gBAEjBI,KAAOiH,KAAK9G,eAAeP,WAAY6/D,QAAS,gBAGpDz/D,KAAKiO,KAAOhH,KAAK9G,eAAeH,KAAMy/D,QAAS,QAAS,QACxDz/D,KAAKgkE,IAAM/8D,KAAK9G,eAAeH,KAAMy/D,QAAS,QAAS,OACvDz/D,KAAKkkE,KAAOj9D,KAAK9G,eAAeH,KAAMy/D,QAAS,QAAS,QACxDz/D,KAAKmkE,SAAWl9D,KAAK9G,eAAeH,KAAMy/D,QAAS,QAAS,YAC5Dz/D,KAAKkpC,UAAYjiC,KAAK9G,eAAeH,KAAMy/D,QAAS,QAAS,aAC7Dz/D,KAAK4kE,OAAS39D,KAAK9G,eAAeH,KAAK4kE,OAAQnF,QAAS,UACxDz/D,KAAKuiE,WAAat7D,KAAK9G,eAAeH,KAAMy/D,QAAS,QAAS,cAC9Dz/D,KAAKskE,OAASr9D,KAAK9G,eAAeH,KAAMy/D,QAAS,QAAS,UAC1Dz/D,KAAK2iE,WAAa17D,KAAK9G,eAAeH,KAAMy/D,QAAS,QAAS,cAI9Dz/D,KAAKmxG,WAAavxG,WAAW4kE,YAAc5kE,WAAWuxG,YAAc1xC,QAAQ1rE,MAAMywE,WAE3ExkE,MAYX8tH,WAAY,SAAS/5H,MAAOiM,KAAM+tH,YAC9Bh6H,MAAM4iH,cACN5iH,MAAM+jH,eAAiB93G,KAAK83G,eAC5B/jH,MAAMoiH,gBAAgB4X,WAAW9iH,MAAO8iH,WAAW7iH,QAAQ,GAAM,GACjEnX,MAAMwoH,wBAAwBv8G,MAC9BjM,MAAMmvE,SAASoa,YAAYvpF,MAAOiM,KAAK4kE,QACvC7yE,IAAImB,OAAOa,MAAMjD,IAAMiD,OAU3Bi6H,SAAU,SAAS15H,UAAW0L,UAEtBiuH,SACAC,SAAUC,QAAS73B,OACnB83B,SAAUC,eAHV9jH,IAAMvK,KAAKnL,UAAYA,SAKR,WAAfoJ,QAAOsM,OAKX0jH,UADAC,SAAW3jH,IAAIzV,eAAeR,YACViZ,cACpB+oF,OAAS43B,SAAS9gH,WAElBghH,SAAW95H,UAAY,aACvB+5H,eAAiB/5H,UAAY,oBAE7B65H,QAAUF,SAASzlH,cAAc,QACzBzT,UAAYiL,KAAKwhE,MACzB2sD,QAAQt1C,aAAa,KAAMu1C,UAC3BD,QAAQpjH,MAAMP,QAAU,OACxB8rF,OAAOrX,aAAakvC,QAASD,WAE7BC,QAAUF,SAASzlH,cAAc,QACzBzT,UAAYiL,KAAKyhE,YACzB0sD,QAAQt1C,aAAa,KAAMw1C,gBAC3BF,QAAQpjH,MAAMP,QAAU,OACxB8rF,OAAOrX,aAAakvC,QAASD,UAE7BA,SAASr1C,aAAa,kBAAmBu1C,UACzCF,SAASr1C,aAAa,mBAAoBw1C,kBAU9CC,iBAAkB,SAASv6H,WACnB+a,KAAMhe,GAAIyZ,IAGK,WAAftM,QADJsM,IAAMxW,MAAMc,UAAYA,YAKxB/D,GAAKiD,MAAMgmF,aAAa2O,aAAa,oBACrC55E,KAAOvE,IAAIzV,eAAehE,MACdge,KAAK1B,YACb0B,KAAK1B,WAAWyD,YAAY/B,MAEhChe,GAAKiD,MAAMgmF,aAAa2O,aAAa,qBACrC55E,KAAOvE,IAAIzV,eAAehE,MACdge,KAAK1B,YACb0B,KAAK1B,WAAWyD,YAAY/B,QAqBpCy/G,UAAW,SAAUtV,IAAKr5G,gBAClB4uH,QAASC,QAAS/1G,MAAOC,MACzBuqD,SAGAz8C,EAAG/U,EAAGq8G,WACN1mG,KAAMrnB,KAAM0uH,OAAQC,SAAUC,SAC9B76H,MAJAknH,KAAO,EACPC,KAAO,SAKXt7G,WAAaA,YAAc,GAC3BI,KAAOrM,KAAKk6H,eAAejuH,YAE3BmuH,WAAatlG,IAAIpe,cAAc4uG,IAAKj5G,KAAKnL,UAErCmL,KAAK6uH,OAAS7uH,KAAK8uH,OACnBN,QAAUvnH,KAAKpI,IAAImB,KAAK+uH,QAAS,KACjCN,QAAUxnH,KAAKpI,IAAImB,KAAKgvH,QAAS,KACjCt2G,MAAQzR,KAAKpI,IAAImB,KAAK6uH,MAAO,IAC7Bl2G,MAAQ1R,KAAKpI,IAAImB,KAAK8uH,MAAO,OAE7BznG,KAAOrnB,KAAKi2G,aACH,GAAKj2G,KAAK83G,eAAe,KAAMzwF,KAAK,GAAKrnB,KAAK83G,eAAe,IAClEzwF,KAAK,GAAKrnB,KAAK83G,eAAe,KAAMzwF,KAAK,GAAKrnB,KAAK83G,eAAe,IAClEzwF,KAAK,GAAKrnB,KAAK83G,eAAe,KAAMzwF,KAAK,GAAKrnB,KAAK83G,eAAe,IAClEzwF,KAAK,GAAKrnB,KAAK83G,eAAe,KAAMzwF,KAAK,GAAKrnB,KAAK83G,eAAe,IAEtErxF,EAAI3Y,SAASigH,WAAW9iH,MAAO,IAC/ByG,EAAI5D,SAASigH,WAAW7iH,OAAQ,IAE5BjE,KAAKzU,OAAO60B,OAASrnB,KAAKuoG,iBAM1B7vF,MAAQ+N,GAAKY,KAAK,GAAKA,KAAK,IAC5B1O,MAAQjH,GAAK2V,KAAK,GAAKA,KAAK,IAExBhnB,KAAKwC,IAAI6V,OAASrY,KAAKwC,IAAI8V,OAG3BuiG,KAA2C,IAAnCxpG,GAFRiH,MAAQtY,KAAKwC,IAAI6V,OAASC,MAAQtY,KAAKwC,IAAI8V,SAEtB0O,KAAK,GAAKA,KAAK,KAIpC4zF,KAA2C,IAAnCx0F,GAFR/N,MAAQrY,KAAKwC,IAAI8V,OAASD,MAAQrY,KAAKwC,IAAI6V,SAEtB2O,KAAK,GAAKA,KAAK,OAGxC3O,MAAQ+N,GAAKY,KAAK,GAAKA,KAAK,IAC5B1O,MAAQjH,GAAK2V,KAAK,GAAKA,KAAK,KAEhCmnG,SAAW91G,OAAS2O,KAAK,GAAK4zF,MAC9BwT,QAAU91G,OAAS0O,KAAK,GAAK6zF,OAGjCh4C,SAAWvvE,KAAK+5H,aAAazU,IAAK8U,WAAY/tH,KAAKnL,SAAUmL,KAAKkjE,eAC7D8qD,SAAS/U,IAAKj5G,OAGnBjM,MAAQ,IAAIg0G,MAAMkR,IAAK/1C,SAAUljE,KAAKlP,GAAI,CAAC09H,QAASC,SACxCzuH,KAAKivH,WAAajvH,KAAKm7G,MACvBn7G,KAAKivH,WAAajvH,KAAKo7G,MACvB1iG,MAAOC,MACPo1G,WAAW9iH,MAAO8iH,WAAW7iH,OAC7BlL,OAENuoG,gBAAkBvoG,KAAKuoG,qBAExBulB,WAAW/5H,MAAOiM,KAAM+tH,YAG7Bh6H,MAAMy9C,gBACFxxC,KAAK2hE,OACL+sD,OAA8B,WAArBzwH,QAAO+B,KAAK2hE,MAAoB3hE,KAAK2hE,KAAO,GAGrDgtD,SAAW1nH,KAAK3D,SAASm8D,QAAQ1rE,MAAM6tE,YAAYngE,EAAGitH,QACtDE,SAAW3nH,KAAK3D,SAASm8D,QAAQ1rE,MAAM6tE,YAAYltD,EAAGg6G,QAElD1uH,KAAKkvH,YAAYztH,IACjBktH,SAAW1nH,KAAK3D,SAASqrH,SAAU3uH,KAAKkvH,YAAYztH,IAEpDzB,KAAKkvH,YAAYx6G,IACjBk6G,SAAW3nH,KAAK3D,SAASsrH,SAAU5uH,KAAKkvH,YAAYx6G,IAGxD3gB,MAAM6tE,YAAc,GACpB7tE,MAAM6tE,YAAYngE,EAAI1N,MAAMwM,OAAO,OAAQ,CAAC,CAAC,EAAG,GAAI,CAAC,EAAG,IAAKouH,UAC7D56H,MAAM6tE,YAAYltD,EAAI3gB,MAAMwM,OAAO,OAAQ,CAAC,CAAC,EAAG,GAAI,CAAC,EAAG,IAAKquH,WAE7D5uH,KAAKypE,MACL11E,MAAMwM,OAAO,OAAQ,GAA0B,WAArBtC,QAAO+B,KAAKypE,MAAoBzpE,KAAKypE,KAAO,IAE1E11E,MAAMo3G,kBAECp3G,OAuCXo7H,kBAAmB,SAAUlW,IAAKmW,KAAMt1G,OAAQla,WAAY3O,cACpD+O,KAAMkjE,SAAUnvE,MAAOg6H,WAAYhuC,gBAEvCngF,WAAaA,YAAc,GAC3BI,KAAOrM,KAAKk6H,eAAejuH,YAE3BmuH,WAAatlG,IAAIpe,cAAc4uG,IAAKj5G,KAAKnL,UACzCquE,SAAWvvE,KAAK+5H,aAAazU,IAAK8U,WAAY/tH,KAAKnL,SAAUmL,KAAKkjE,eAC7D8qD,SAAS/U,IAAKj5G,MAGnBjM,MAAQ,IAAIg0G,MAAMkR,IAAK/1C,SAAU,GAAI,CAAC,IAAK,KAAM,EAAG,EAAG,GAAI,GAAI6qD,WAAW9iH,MAAO8iH,WAAW7iH,OAAQlL,WAC/F8tH,WAAW/5H,MAAOiM,KAAM+tH,YAC7BhuC,SAAW//E,KAAK+/E,UAAY,aAC5BJ,WAAWgB,iBAAiByuC,KAAMr7H,MAAO+lB,QAAQ,EAAMimE,SAAU9uF,UAE1D8C,OAmBXs7H,oBAAqB,SAAUpW,IAAKzyD,OAAQ1sC,OAAQla,WAAY3O,cACxD+O,KAAMkjE,SAAUnvE,MAAOg6H,kBAE3BnuH,WAAaA,YAAc,GAC3BI,KAAOrM,KAAKk6H,eAAejuH,YAE3BmuH,WAAatlG,IAAIpe,cAAc4uG,IAAKj5G,KAAKnL,UACzCquE,SAAWvvE,KAAK+5H,aAAazU,IAAK8U,WAAY/tH,KAAKnL,eAC9Cm5H,SAAS/U,IAAKj5G,MAGnBjM,MAAQ,IAAIg0G,MAAMkR,IAAK/1C,SAAU,GAAI,CAAC,IAAK,KAAM,EAAK,EAAK,GAAI,GAAI6qD,WAAW9iH,MAAO8iH,WAAW7iH,OAAQlL,WACnG8tH,WAAW/5H,MAAOiM,KAAM+tH,YAC7BpuC,WAAWU,YAAY75B,OAAQzyD,MAAO+lB,QAAQ,EAAM7oB,UAE7C8C,OAOXu7H,UAAW,SAAUv7H,WACbiO,OAWCA,KATgB,iBAAVjO,QACPA,MAAQhC,IAAImB,OAAOa,aAGlBu6H,iBAAiBv6H,OACtBA,MAAM28G,sBACN38G,MAAMy9C,gBAGKz9C,MAAMsJ,QACTtJ,MAAMsJ,QAAQvQ,eAAekV,KAC7BjO,MAAMsJ,QAAQ2E,IAAIkzE,cAKnBnhF,MAAMgmF,aAAarpE,YACtB3c,MAAMgmF,aAAalpE,YAAY9c,MAAMgmF,aAAarpE,gBAIjD1O,MAAMjO,MAAMsJ,QACTtJ,MAAMsJ,QAAQvQ,eAAekV,YACtBjO,MAAMsJ,QAAQ2E,WAKtBjO,MAAMmvE,SAGbnvE,MAAMwL,GAAGhM,QAAQwlG,oBACVhlG,MAAMwL,UAGNxN,IAAImB,OAAOa,MAAMjD,KAQ5BuC,gBAAiB,SAAUC,QAASC,SAChCxB,IAAIkC,WAAW,iCAAkC,yBACjDlC,IAAIsB,gBAAgBC,QAASC,WAKjCk1B,IAAI7gB,WAA+B,gCAAXjT,2BAAAA,UAA2C,gCAAbE,6BAAAA,YACtD4zB,IAAIhd,SAAS9W,OAAQ,QAAQ,eACrB6J,KAAMvQ,EAAGC,EAAGgc,IACZpZ,GAAIiD,MAAOw7H,IACXtkH,MAAOC,OAAQskH,SAAUC,YAAaC,WACtCroG,KAAMs6C,KAAM8H,KAAMrtD,KAClBykB,IAAKm/C,QAAS2vC,UAAW,EACzBC,QAAU/6H,SAASuV,qBAAqB,UACxCsI,KAAO,SAAU0J,KAAM5d,KAAM6oB,UACrBtzB,MAAQhC,IAAIw7H,SAASgB,UAAUz9H,GAAI,CAACmlH,YAAa5uF,KAAMkhF,iBAAiB,EAAM9+B,KAAMA,KAAM9H,KAAMA,KAAMU,YAAY,OAElH7jE,KAAKnM,cAActC,QAAQ,WAAa,EACxCgE,MAAM87H,UAAUzzG,eAGZroB,MAAMwL,GAAGwR,MAAMqL,MACjB,MAAOppB,IACLjB,IAAIsD,MAAMrC,WAIXe,OAEX+7H,WAAa,SAAbA,WAAuB/7H,MAAOqoB,KAAM5d,KAAM6oB,aAC/B,eACC0oG,SAEJh+H,IAAIw7H,SAAS+B,UAAUv7H,QACvBg8H,SAAWr9G,KAAK0J,KAAM5d,KAAM6oB,OACnB+2D,OAAS0xC,WAAWC,SAAU3zG,KAAM5d,KAAM6oB,YAI1Dp5B,EAAI,EAAGA,EAAI2hI,QAAQphI,OAAQP,OAC5BuQ,KAAOoxH,QAAQ3hI,GAAGy6F,aAAa,QAAQ,GAEnCzhF,KAAKzU,OAAOgM,QACY,sBAAvBA,KAAKnM,eAAgE,iBAAvBmM,KAAKnM,eAC5B,oBAAvBmM,KAAKnM,eAA8D,eAAvBmM,KAAKnM,eAAiC,IACnFq9H,WAAaE,QAAQ3hI,GAAGy6F,aAAa,SAAS,IAAU,GACxDz9E,MAAQ2kH,QAAQ3hI,GAAGy6F,aAAa,SAAS,IAAU,GACnDx9E,OAAS0kH,QAAQ3hI,GAAGy6F,aAAa,UAAU,IAAU,GACrD8mC,SAAWI,QAAQ3hI,GAAGy6F,aAAa,YAAY,IAAU,OACzD+mC,YAAcG,QAAQ3hI,GAAGy6F,aAAa,eAAe,IAAU,MAC/DrhE,KAAOuoG,QAAQ3hI,GAAGy6F,aAAa,eAAe,IAAU,eACxD53F,GAAK8+H,QAAQ3hI,GAAGy6F,aAAa,aAAa,GAC1C7nD,IAAM+uF,QAAQ3hI,GAAGy6F,aAAa,OAAO,GAGjB,KADpBrhE,KAAOA,KAAKh5B,MAAM,MACTG,OACL64B,KAAO,EAAE,EAAG,EAAG,GAAI,YAEdn5B,EAAI,EAAGA,EAAIm5B,KAAK74B,OAAQN,IACzBm5B,KAAKn5B,GAAKod,WAAW+b,KAAKn5B,OAGlCyzE,KAAO16D,KAAKlI,SAAS6wH,QAAQ3hI,GAAGy6F,aAAa,QAAQ,IAAU,SAC/Djf,KAAOxiE,KAAKlI,SAAS6wH,QAAQ3hI,GAAGy6F,aAAa,QAAQ,IAAU,SAE1DzhF,KAAKzU,OAAO1B,IAqBboZ,IAAMrV,SAASC,eAAehE,QArBZ,CAClBA,GAAK,2BAA6B7C,GAClCic,IAAMrV,SAAS2T,cAAc,QACzBqwE,aAAa,KAAM/nF,IAEvBy+H,IAAiB,KAAVtkH,MAAiB,SAAWA,MAAQ,IAAO,GAClDskH,KAAmB,KAAXrkH,OAAkB,UAAYA,OAAS,IAAO,GACtDqkH,KAAqB,KAAbC,SAAoB,aAAeA,SAAW,IAAO,GAC7DD,KAAwB,KAAhBE,YAAuB,gBAAkBA,YAAc,IAAO,GAEtEvlH,IAAI2uE,aAAa,QAAS02C,KAC1BrlH,IAAI2uE,aAAa,QAAS,UAAY62C,gBAElC76H,SAASqb,KAAK+uE,aAAa/0E,IAAK0lH,QAAQ3hI,IAC1C,MAAO2C,GAEiB,gCAAXiB,2BAAAA,UACPA,OAAOqY,KAAK+0E,aAAa2wC,QAAQ3hI,KAO7CmuB,KAAO,GAEHnV,KAAKzU,OAAOquC,MACZ8uF,UAAW,GACX3vC,QAAU,IAAI32B,gBACN7qC,KAAK,MAAOqiB,KACpBm/C,QAAQ12B,iBAAiB,sCAEzB02B,QAAQt0E,iBAAiB,QAAQ,gBACzB/X,KAAKunC,OAAS,WAKR,IAAIvrC,MAAM,kCAAmCkxC,IAAK,IAAKltC,KAAK+1D,cAJlEttC,KAAOzoB,KAAK+1D,aAAe,KAAOttC,MAClCroB,MAAQ2e,KAAK0J,KAAM5d,KAAM6oB,OACnB+2D,OAAS0xC,WAAW/7H,MAAOqoB,KAAM5d,KAAM6oB,SAKrD24D,QAAQt0E,iBAAiB,SAAS,SAAS9a,SACjC,IAAIjB,MAAM,kCAAmCkxC,IAAK,IAAKjwC,MAGjEovF,QAAQr2B,QAERgmE,UAAW,EAGX96H,SAASC,eAAehE,KAExBsrB,MADAA,KAAOwzG,QAAQ3hI,GAAG8G,WACNpG,QAAQ,eAAgB,IAAIA,QAAQ,SAAU,IAC1DihI,QAAQ3hI,GAAG8G,UAAYqnB,KAElBuzG,YAED57H,MAAQ2e,KAAK0J,KAAM5d,KAAM6oB,OACnB+2D,OAAS0xC,WAAW/7H,MAAOqoB,KAAM5d,KAAM6oB,QAGjDt1B,IAAIsD,MAAM,kFAIvBV,QAGA5C,IAAIw7H,YA2DfxhI,OAAO,aAAa,CAChB,MAAO,UAAW,YAAa,gBAAiB,iBAAkB,eAClE,aAAc,uBACf,SAAUgG,IAAK0tE,QAAS5nD,IAAKirB,SAAU3lC,MAAOulF,gBAAiBz7E,KAAM2lF,sBAkBpE76F,IAAIi+H,MAAQ,SAAUj8H,MAAOikB,YAAapY,iBACjCuE,YAAYpQ,MAAO6L,WAAYzC,MAAM7G,kBAAmB6G,MAAMxF,yBAC9DrE,QAAUK,KAAKI,MAAMG,OAAO0L,WAAW8nE,aACvC0rB,kBAAkBp7E,kBAElBqrE,OAAS,aAGTvyF,GAAK6C,KAAKI,MAAMw/F,MAAM5/F,KAAM,UAC5BI,MAAMmvE,SAASkR,UAAUzgF,WACzBI,MAAMy/F,eAAe7/F,WAErBo1F,sBACAd,eAOTl2F,IAAIi+H,MAAMnjI,UAAY,IAAI61F,gBAC1Bz7E,KAAKnD,qBAAqB/R,IAAIi+H,MAAOpjC,cAAe,qBAEpD76F,IAAIC,OAAOD,IAAIi+H,MAAMnjI,UAA6C,CAQ9D87E,SAAU,SAAUlnE,EAAGiT,OACoBvR,EACnC+vB,KAAM10B,KADNyxH,UAAYt8H,KAAK6N,OAAO0W,UAExBy8D,KAAO1tE,KAAKrG,SAASjN,KAAK+S,QAAQkuE,iBAElC3tE,KAAK/I,SAAS+I,KAAKrG,SAASjN,KAAK+S,QAAQwgE,aACzC1oE,KAAO7K,KAAKI,MAAM4/F,aAClBzgE,KAAOjsB,KAAKrG,SAASjN,KAAK+S,QAAQwgE,UAAU1oE,QAG5C00B,KAAOv/B,KAAKI,MAAMqM,QAAQ8mE,UAAUyB,SAExCxlE,EAAImI,WAAWrE,KAAKrG,SAASjN,KAAK+S,QAAQ0mB,OAC7B,SAATunD,OACAxxE,GAAK9C,KAAKmU,KAAK7gB,KAAKI,MAAM2kB,MAAQ/kB,KAAKI,MAAM4kB,SAGjDxV,GAA2D,GAAtDmI,WAAWrE,KAAKrG,SAASjN,KAAK+S,QAAQlB,eACnC0tB,OACJ/vB,EAAI+vB,MAGC7yB,KAAKwC,IAAIotH,UAAU,GAAKxuH,GAAK0B,EAAI,GAAO9C,KAAKwC,IAAIotH,UAAU,GAAKv7G,GAAKvR,EAAI,GAMtFgrB,OAAQ,SAAU28D,mBACTn3F,KAAKivF,kBAILqL,aAAanD,YAEd7jF,KAAKrG,SAASjN,KAAK+S,QAAQigE,aACtBigB,mBAAkB,GAGpBjzF,MATIA,MAoBfy8C,gBAAiB,SAAU06C,gBACnBvnF,EAAGtV,KAE6B,IAAhC0F,KAAK6mF,gBAAgBhsF,QAAqC,OAArBmF,KAAKwvF,mBACnCxvF,SAGPA,OAASA,KAAKwvF,aAEd5/E,EAAI5P,KAAK6mF,gBAAgB,GAAGlrF,MAAMqE,KAAKwvF,YAAa,aAC/C3hF,OAAO2W,eAAehb,MAAM1H,eAAgB8N,IAEjDA,EAAI5P,KAAK6mF,gBAAgB,GAAGlrF,MAAMqE,KAAKwvF,kBAEtC3hF,OAAO2W,eAAehb,MAAM1H,eAAgB8N,GAE5CtV,EAAI,EAAGA,EAAI0F,KAAK6mF,gBAAgBhsF,OAAQP,SACpCuT,OAAO2W,eAAehb,MAAM1H,eAAgB9B,KAAK6mF,gBAAgBvsF,GAAGqB,MAAMqE,cAE5EA,MAOXkzF,eAAgB,uBACPuI,sBAAsB,eACpBz7F,MAIXu1F,OAAQ,kBACGv1F,KAAK6N,OAAOG,UAAU3U,MAAM,GAAG6B,OAAO8E,KAAK6N,OAAOG,UAAU3U,MAAM,KAS7E2gG,iBAAkB,SAAU9lD,IAAKC,IAAK75C,EAAGC,OACjCgiI,KAEJroF,IAAMl0C,KAAKI,MAAMG,OAAO2zC,KACxBC,IAAMn0C,KAAKI,MAAMG,OAAO4zC,KAExBooF,KAAOptF,SAAS8E,qBAAqBj0C,KAAKI,MAAO8zC,IAAKC,IAAK75C,EAAGC,EACtD+Y,KAAKrG,SAASjN,KAAK+S,QAAQqhC,uBAC9B+lD,cAAc,CAACoiC,WAGhBroF,IAAI26C,SAAS7uF,MACbm0C,IAAI06C,SAAS7uF,MACf,MAAO/C,SACC,IAAIjB,MAAM,oEACJk4C,KAAO,kBAAoBC,KAAO,WAG7CtpC,KAAOrB,MAAMrG,8BACbusF,OAAS,oBACT1jF,QAAU,CAACkoC,IAAI/2C,GAAIg3C,IAAIh3C,GAAI7C,EAAGC,QAE9B48D,mBAAqB,eAClBqlE,MAAQtoF,IAAIijB,mBAAmBn3D,MAC/By8H,MAAQtoF,IAAIgjB,mBAAmBn3D,aAEb,IAAjBw8H,MAAM3hI,QAAmC,IAAjB4hI,MAAM5hI,OACxB,GAGJ,CAAC2hI,MAAM,GAAIC,MAAM,UAGvBp3C,gBAAgB7qD,UASzBkqF,SAAU,SAAUpqH,eAqBXyY,QAAQ0hE,KApBC,CAEV,QAAS,QAAS,QAElB,SAAU,SAAU,SAAU,SAE9B,SAAU,SAAU,SAEpB,OAAQ,OAAQ,QAYQn6E,QACvByY,QAAQ0mB,KAZA,CAET,EAAG,EAAG,EAEN,EAAG,EAAG,EAAG,EAET,EAAG,EAAG,EAEN,EAAG,EAAG,GAIkBn/B,QAEvB8F,MAAMmvE,SAAS+R,iBAAiBthF,MAC9BA,MAQX08H,cAAe,SAAUr8H,UACrBjC,IAAIkC,WAAW,wBAAyB,4BACjCwrE,QAAQ2R,mBAAmBp9E,IAStCo0E,KAAM,SAAU73E,GACZwB,IAAIkC,WAAW,eAAgB,6BAC1B4kF,aAAa,CAACzQ,KAAM73E,KAS7B68B,KAAM,SAAUp5B,GACZjC,IAAIkC,WAAW,eAAgB,6BAC1B4kF,aAAa,CAACzrD,KAAMp5B,KA+D7Bs8H,KAAM,SAAStuH,GAAI02B,SACXx3B,IAAK2rC,YAETnU,IAAMA,KAAO7gB,IAAIzF,IAEbnL,KAAK9I,QAAQ6D,IACNrO,KAAK8gC,KAAKzyB,IAAM02B,IAChB12B,GAAG5D,eAAiBjB,MAAMvF,mBACf,YAAdoK,GAAGqhF,QAAyBp8E,KAAKrG,SAASjN,KAAK+S,QAAQqhC,mBACvD7mC,IAAMnP,IAAIsO,KAAKyiC,SAASwM,uBACZ37C,KAAK6N,OAAOG,UACZK,GAAGqiC,OAAO7iC,OAAOG,UACjBK,GAAGuiC,OAAO/iC,OAAOG,YACrB,IAAM,GAAKT,IAAI,IAAM,IAOtB4hC,SAASqO,cAAcx9C,KAAK6N,OAAOG,UAAWK,GAAGuV,SAAWmhB,IAEhE12B,GAAG5D,eAAiBjB,MAAMtF,oBAC7BoP,KAAKrG,SAASoB,GAAG0E,QAAQ6pH,gBAClB58H,KAAK8gC,KAAKzyB,GAAGqqB,QAAUrqB,GAAGqtC,SAAW3W,IAEzCr4B,KAAKwC,IAAIlP,KAAK8gC,KAAKzyB,GAAGqqB,QAAUrqB,GAAGqtC,UAAY3W,IAC/C12B,GAAG5D,eAAiBjB,MAAMrF,oBACjC+0C,KAAO/J,SAAS2M,oBAAoB97C,KAAMqO,GAAIrO,KAAKI,OAAO,GACnD+uC,SAAShqB,SAASnlB,KAAK6N,OAAOG,UAAWkrC,KAAKlrC,UAAW,GAAK+2B,KAC9D12B,GAAGxD,OAASrB,MAAMzG,uBACrBuQ,KAAKrG,SAASoB,GAAG0E,QAAQ6pH,kBACrBvuH,GAAGwuH,OAAO78H,KAAK6N,OAAOG,UAAU,GAAIhO,KAAK6N,OAAOG,UAAU,GAAI5P,IAAI0D,mBAI1EyL,IAAM4hC,SAASuN,uBAAuB18C,KAAK6N,OAAOG,UAAWK,IACtD8gC,SAAShqB,SAASnlB,KAAK6N,OAAOG,UAAWT,IAAK,GAAKw3B,KACnD12B,GAAGxD,OAASrB,MAAMpG,qBACzB81C,KAAO/J,SAAS6N,qBAAqBh9C,KAAMqO,GAAIrO,KAAKI,OAC7C+uC,SAAShqB,SAASnlB,KAAK6N,OAAOG,UAAWkrC,KAAKlrC,UAAW,GAAK+2B,MAQ7EkuD,kBAAmB,eACXrtE,KAAO,UAEXA,KAAKzoB,GAAK6C,KAAK7C,GAAK,IAAM6C,KAAKuvF,eAC1BA,WAAa,EAElB3pE,KAAK/X,OAAS7N,KAAK6N,OACnB+X,KAAK7S,QAAUO,KAAK3D,SAAS3P,KAAK+S,QAAS/S,KAAK+S,QAAQ+pH,iBAAiB,GACzEl3G,KAAK7S,QAAQ9C,MAAQjQ,KAAKI,MAAMqM,QAAQwD,MAAM+iE,MAC9CptD,KAAKnb,aAAejB,MAAMxF,mBAC1B4hB,KAAKxlB,MAAQJ,KAAKI,MAClBkT,KAAKxC,gBAAgB8U,MAErBA,KAAK47D,YAAc,CACfvvE,QAASqB,KAAKrG,SAAS2Y,KAAK7S,QAAQd,eAGnC7R,MAAMmvE,SAASkR,UAAU76D,WACzB0pE,OAAO1pE,KAAKzoB,IAAMyoB,KAAK+6D,SAErB3gF,QAuDf5B,IAAI2+H,YAAc,SAAU38H,MAAO4L,QAASC,gBACpCoC,GAAIhC,QAERA,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,WACtD4B,GAAK4qF,cAAcrsF,OAAOxO,IAAIi+H,MAAOj8H,MAAO4L,QAASK,aAE3C,IAAIrQ,MAAM,2DACAgQ,QAAQ,IAAM,kBAAoBA,QAAQ,IAD1C,8EAKbqC,IAyDXjQ,IAAI4+H,aAAe,SAAU58H,MAAO4L,QAASC,gBACrCoC,GAAIR,OACJxB,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,iBAGtDoB,OADmB,IAAnB7B,QAAQnR,OACC,CAAC,EAAG,GAEJmR,QAAQ3S,MAAM,EAAG,IAE9BgV,GAAKjO,MAAMwM,OAAO,QAASiB,OAAQxB,OAGhCytF,WAAW9tF,QAAQA,QAAQnR,OAAS,IAEhCwT,IAwCXjQ,IAAI6+H,wBAA0B,SAAU78H,MAAO4L,QAASC,gBAChDoC,GAAI6lC,IAAKC,IAAKooF,KAAMjiI,EAAGC,EACvB8R,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,gBAG1DT,QAAQtQ,KAAK,EAAG,GAEhBw4C,IAAM9zC,MAAMG,OAAOyL,QAAQ,IAC3BmoC,IAAM/zC,MAAMG,OAAOyL,QAAQ,IAE3B1R,EAAI0R,QAAQ,IAAM,EAClBzR,EAAIyR,QAAQ,IAAM,EAElBqC,GAAKjO,MAAMwM,OAAO,QAAS,CAAC,EAAG,EAAG,GAAIP,MAGtCkwH,KAAOptF,SAAS8E,qBAAqB7zC,MAAO8zC,IAAKC,IAAK75C,EAAGC,EAAG8T,GAAG0E,QAAQqhC,iBACvE/lC,GAAG8rF,cAAc,CAACoiC,WAGdroF,IAAI26C,SAASxgF,IACb8lC,IAAI06C,SAASxgF,IACf,MAAOpR,SACC,IAAIjB,MAAM,oEACJgQ,QAAQ,IAAM,kBAAoBA,QAAQ,IAAM,aAGhEqC,GAAGxD,KAAOrB,MAAMrG,yBAChBkL,GAAGqhF,OAAS,eACZrhF,GAAG+iF,WAAW,CAACl9C,IAAI/2C,GAAIg3C,IAAIh3C,KAS3BkR,GAAG6uH,oBAAsB,CAAC5iI,EAAGC,GAC7B8T,GAAGgoF,WAAa,kBACLr2F,KAAKgM,QAAQ9Q,OAAO8E,KAAKk9H,sBAGpC7uH,GAAG8oD,mBAAqB,eAChBqlE,MAAQtoF,IAAIijB,mBAAmB9oD,IAC/BouH,MAAQtoF,IAAIgjB,mBAAmB9oD,WAEb,IAAjBmuH,MAAM3hI,QAAmC,IAAjB4hI,MAAM5hI,OACxB,GAGJ,CAAC2hI,MAAM,GAAIC,MAAM,KAGrBpuH,IAsCXjQ,IAAI++H,6BAA+B,SAAU/8H,MAAO4L,QAASC,gBACrDoC,GAAI6lC,IAAKC,IAAKipF,SAEK,IAAnBpxH,QAAQnR,SACHyY,KAAK9I,QAAQwB,QAAQ,KACrBA,QAAQ,GAAGvB,eAAiBjB,MAAMvF,mBAAqB+H,QAAQ,GAAGvB,eAAiBjB,MAAMtF,qBACzF8H,QAAQ,GAAGvB,eAAiBjB,MAAMvF,mBAAqB+H,QAAQ,GAAGvB,eAAiBjB,MAAMtF,0BAExF,IAAIlI,MAAM,gFACJgQ,QAAQ,IAAM,gBAAkBA,QAAQ,IAAM,kBAAoBA,QAAQ,IADtE,qEAKpBkoC,IAAM9zC,MAAMG,OAAOyL,QAAQ,IAC3BmoC,IAAM/zC,MAAMG,OAAOyL,QAAQ,IAC3BoxH,MAAQh9H,MAAMG,OAAOyL,QAAQ,KAE7BqC,GAAKjO,MAAMwM,OAAO,QAAS,CAAC,eACpBgD,EAAIu/B,SAAS2F,KAAKZ,IAAItwB,QAASuwB,IAAIvwB,QAAS,EAAGswB,IAAI9zC,cAEnDsM,KAAKwC,IAAIkuH,MAAMh/F,IAAMxuB,EAAE5B,UAAU,IAAMkW,IAAIzF,KACvC/R,KAAKwC,IAAIkuH,MAAM/+F,IAAMzuB,EAAE5B,UAAU,IAAMkW,IAAIzF,KAC3C/R,KAAKwC,IAAIkuH,MAAM5gF,IAAM5sC,EAAE5B,UAAU,IAAMkW,IAAIzF,IACxC7O,EAGJu/B,SAAS2F,KAAKZ,IAAItwB,QAASuwB,IAAIvwB,QAAS,EAAGswB,IAAI9zC,SACtD6L,aAEDpB,KAAOrB,MAAMrG,yBAChBkL,GAAGqhF,OAAS,oBACZrhF,GAAG+iF,WAAW,CAACl9C,IAAI/2C,GAAIg3C,IAAIh3C,GAAIigI,QAE/BlpF,IAAI26C,SAASxgF,IACb8lC,IAAI06C,SAASxgF,IAEbA,GAAG8oD,mBAAqB,eAChBqlE,MAAQtoF,IAAIijB,mBAAmB9oD,IAC/BouH,MAAQtoF,IAAIgjB,mBAAmB9oD,WAEb,IAAjBmuH,MAAM3hI,QAAmC,IAAjB4hI,MAAM5hI,OACxB,GAGJ,CAAC2hI,MAAM,GAAIC,MAAM,KAGrBpuH,IAgEXjQ,IAAIi/H,gBAAkB,SAAUj9H,MAAO4L,QAASC,gBACxCoC,GAAI6lC,IAAKC,IACTmpF,mBAAoBC,oBACpBC,kBAAmBC,sBAEnBzxH,QAAQnR,OAAS,IACjByiI,mBAAsBtxH,QAAQ,GAAGnB,OAASrB,MAAMlH,mBAC5C0J,QAAQ,GAAGvB,eAAiBjB,MAAMtF,oBACtCq5H,oBAAuBvxH,QAAQ,GAAGnB,OAASrB,MAAMlH,mBAC7C0J,QAAQ,GAAGvB,eAAiBjB,MAAMtF,oBAEtCs5H,kBAAqBxxH,QAAQ,GAAGvB,eAAiBjB,MAAMvF,kBACvDw5H,mBAAsBzxH,QAAQ,GAAGvB,eAAiBjB,MAAMvF,mBAUrC,IAAnB+H,QAAQnR,UACDyiI,oBAAsBG,oBACpBD,mBAAqBD,2BAExB,IAAIvhI,MAAM,kEACJgQ,QAAQ,IAAM,kBAAoBA,QAAQ,IADtC,6EAKhByxH,oBACAvpF,IAAM9zC,MAAMG,OAAOyL,QAAQ,IAC3BmoC,IAAM/zC,MAAMG,OAAOyL,QAAQ,MAE3BkoC,IAAM9zC,MAAMG,OAAOyL,QAAQ,IAC3BmoC,IAAM/zC,MAAMG,OAAOyL,QAAQ,MAG/BqC,GAAKjO,MAAMwM,OAAO,QACd,CAAC,eACOmb,EAAImsB,IAAIu8C,cACRpwF,EAAI8zC,IAAIvwB,QAAQvqB,MAAM,EAAG,SAEtB,CAAC+E,IAAIsO,KAAKyoB,SAASM,IAAI,CAACp1B,EAAG0nB,EAAE,GAAIA,EAAE,KAClC3pB,IAAIsO,KAAKyoB,SAASM,IAAI,CAAC1N,EAAE,GAAI1nB,EAAG0nB,EAAE,KAClC3pB,IAAIsO,KAAKyoB,SAASM,IAAI,CAAC1N,EAAE,GAAIA,EAAE,GAAI1nB,OAC3C4L,aAELyjF,OAAS,YACZrhF,GAAG+iF,WAAW,CAACl9C,IAAI/2C,GAAIg3C,IAAIh3C,KAE3B+2C,IAAI26C,SAASxgF,IACb8lC,IAAI06C,SAASxgF,IAENA,IAGXjQ,IAAIsB,gBAAgB,QAAStB,IAAI2+H,aACjC3+H,IAAIsB,gBAAgB,SAAUtB,IAAI4+H,cAClC5+H,IAAIsB,gBAAgB,eAAgBtB,IAAI6+H,yBACxC7+H,IAAIsB,gBAAgB,oBAAqBtB,IAAI++H,8BAC7C/+H,IAAIsB,gBAAgB,YAAatB,IAAIi/H,iBAE9B,CACHhB,MAAOj+H,IAAIi+H,MACXU,YAAa3+H,IAAI2+H,YACjBC,aAAc5+H,IAAI4+H,aAClBU,mBAAoBt/H,IAAI6+H,wBACxBU,wBAAyBv/H,IAAI++H,6BAC7BE,gBAAiBj/H,IAAIi/H,oBA6D7BjlI,OAAO,YAAY,CACf,MAAO,YAAa,gBAAiB,gBAAiB,kBAAmB,iBAAkB,cAC3F,eAAgB,aAAc,eAC/B,SAAUgG,IAAK8lB,IAAKirB,SAAUha,SAAU0Y,WAAYrkC,MAAO2a,OAAQ4qE,gBAAiBz7E,KAAM+oH,cAiBzFj+H,IAAIw/H,KAAO,SAAUx9H,MAAO2xC,GAAIC,GAAI/lC,iBAC3BuE,YAAYpQ,MAAO6L,WAAYzC,MAAM9G,iBAAkB8G,MAAMvF,wBAO7DysC,OAAS1wC,KAAKI,MAAMG,OAAOwxC,SAM3BnB,OAAS5wC,KAAKI,MAAMG,OAAOyxC,SAQ3Bk8B,MAAQ,QAORuoB,aAAe,UAQfuE,cAAgB,UAGhB79F,GAAK6C,KAAKI,MAAMw/F,MAAM5/F,KAAM,UAC5BI,MAAMmvE,SAASkS,SAASzhF,WACxBI,MAAMy/F,eAAe7/F,WAErB0vF,OAAS,OAGV1vF,KAAK0wC,OAAO7jC,cACPgiF,SAAS7uF,KAAK0wC,eACZ1wC,KAAK0wC,OAAO7jC,cAEd6jC,OAAOm+C,SAAS7uF,MAErBA,KAAK4wC,OAAO/jC,cACPgiF,SAAS7uF,KAAK4wC,eACZ5wC,KAAK4wC,OAAO/jC,cAEd+jC,OAAOi+C,SAAS7uF,WAGpB6vF,SAASn0F,KAAKsE,KAAK0wC,OAAQ1wC,KAAK4wC,aAEhCitF,qBAMAvpC,mBAEAvE,UAAY3xF,IAAIuR,SAAS3P,KAAK+vF,UAAW,CAC1Cr/C,OAAQ,SACRE,OAAQ,SACR2C,SAAU,WACVuqF,QAAS,UACTC,cAAe,UACfC,SAAU,WACVhkF,EAAG,IACHn/C,OAAQ,OAIhBuD,IAAIw/H,KAAK1kI,UAAY,IAAI61F,gBAEzB3wF,IAAIC,OAAOD,IAAIw/H,KAAK1kI,UAA4C,CAO5D87E,SAAU,SAAUlnE,EAAGiT,OAEP1gB,EAER49H,KACAxtF,IAAKE,IAAKxlC,EAAG0wC,IAAKvhD,EAClBilC,KAAM10B,KAJN+E,EAAI,GACJ5F,EAAI,CAAC,EAAG8D,EAAGiT,GAIXwoE,GAAKj2E,KAAKrG,SAASjN,KAAK+S,QAAQlB,oBAEhCyB,KAAK/I,SAAS+I,KAAKrG,SAASjN,KAAK+S,QAAQwgE,aACzC1oE,KAAO7K,KAAKI,MAAM4/F,aAClBzgE,KAAOjsB,KAAKrG,SAASjN,KAAK+S,QAAQwgE,UAAU1oE,QAG5C00B,KAAOv/B,KAAKI,MAAMqM,QAAQ8mE,UAAUyB,SAExCz1C,MAAa,GAALgqD,GAER35E,EAAE,GAAK5P,KAAK4jB,QAAQ,GAChB5jB,KAAK4jB,QAAQ,GAAK5jB,KAAKI,MAAM0L,OAAOyY,UAAU,GAAKvkB,KAAKI,MAAM2kB,MAC9D/kB,KAAK4jB,QAAQ,GAAK5jB,KAAKI,MAAM0L,OAAOyY,UAAU,GAAKvkB,KAAKI,MAAM4kB,MAClEpV,EAAE,GAAK5P,KAAK4jB,QAAQ,GAAK5jB,KAAKI,MAAM2kB,MACpCnV,EAAE,GAAK5P,KAAK4jB,QAAQ,IAAO5jB,KAAKI,MAAM4kB,MAEtC3kB,EAAI8uC,SAASqO,cAAcxzC,EAAG4F,KAC1BlB,MAAMrO,IAAMA,EAAIk/B,WAIhBjsB,KAAKrG,SAASjN,KAAK+S,QAAQ6/B,iBACvBt/B,KAAKrG,SAASjN,KAAK+S,QAAQ8/B,iBAKnCpC,IAAMzwC,KAAK0wC,OAAO7iC,OAClB8iC,IAAM3wC,KAAK4wC,OAAO/iC,OAGlBowH,KAAO,CAAC,EAAGruH,EAAE,GAAIA,EAAE,IAEnBquH,KAAO/5G,IAAI1D,aAAay9G,KAAMj0H,IAE9Bi0H,KAAO/5G,IAAI1D,aAAay9G,KAAMruH,IAGzB,IAAMquH,KAAK,GAChBA,KAAK,IAAMA,KAAK,GAChBA,KAAK,GAAK,EAEVA,KAAQ,IAAI95G,OAAO3a,MAAMzH,iBAAkBk8H,KAAK5kI,MAAM,GAAI2G,KAAKI,OAAQ4N,UACvE7C,EAAIslC,IAAItrB,SAAS3b,MAAM1H,eAAgB6uC,KACvCF,IAAMA,IAAIziC,UAAU3U,MAAM,GAC1Bs3C,IAAMA,IAAI3iC,UAAU3U,MAAM,GAGtB8R,EAAI+Y,IAAIzF,IACRo9B,IAAM,GAcF1wC,IAAMoa,OAAOC,oBACbra,EAAI,EAAI+Y,IAAIzF,IAGR/R,KAAKwC,IAAIyhC,IAAI,IAAMzsB,IAAIzF,KACvBtT,GAAKgkC,SAAShqB,SAAS,CAAC,EAAG,EAAG,GAAIwrB,KAClCA,IAAM,CAAC,EAAGF,IAAI,GAAKE,IAAI,GAAKxlC,EAAGslC,IAAI,GAAKE,IAAI,GAAKxlC,KAGjDA,GAAKgkC,SAAShqB,SAAS,CAAC,EAAG,EAAG,GAAIsrB,KAClCA,IAAM,CAAC,EAAGE,IAAI,GAAKF,IAAI,GAAKtlC,EAAGwlC,IAAI,GAAKF,IAAI,GAAKtlC,KAIzDA,EAAIwlC,IADJr2C,EAAI,GACSm2C,IAAIn2C,GAEboS,KAAKwC,IAAI/D,GAAK+Y,IAAIzF,MAElBtT,EAAIwlC,IADJr2C,EAAI,GACSm2C,IAAIn2C,IAErBuhD,KAAOoiF,KAAK3jI,GAAKm2C,IAAIn2C,IAAM6Q,MAG1BmI,KAAKrG,SAASjN,KAAK+S,QAAQ6/B,gBAAkBiJ,IAAM,OAI9CvoC,KAAKrG,SAASjN,KAAK+S,QAAQ8/B,eAAiBgJ,IAAM,MAKhErhB,OAAQ,eACA0jG,aAECl+H,KAAKivF,aAINjvF,KAAKm+H,cACD7qH,KAAKnJ,WAAWnK,KAAKk+H,QACrBA,MAAQl+H,KAAKk+H,UACAA,MAAMrjI,QAA2B,IAAjBqjI,MAAMrjI,cAC1B61C,OAASwtF,MAAM,QACfttF,OAASstF,MAAM,KAGpB5qH,KAAKnJ,WAAWnK,KAAKo+H,SACrBF,MAAQl+H,KAAKo+H,QACT9qH,KAAK9I,QAAQ0zH,YACRxtF,OAASwtF,MACPA,OAASA,MAAMrjI,QAA2B,IAAjBqjI,MAAMrjI,aACjC61C,OAAOohD,oBAAoBtoF,MAAM1H,eAAgBo8H,QAI1D5qH,KAAKnJ,WAAWnK,KAAKq+H,SACrBH,MAAQl+H,KAAKq+H,QACT/qH,KAAK9I,QAAQ0zH,YACRttF,OAASstF,MACPA,OAASA,MAAMrjI,QAA2B,IAAjBqjI,MAAMrjI,aACjC+1C,OAAOkhD,oBAAoBtoF,MAAM1H,eAAgBo8H,eAMjEI,gCACAT,gBAEDvqH,KAAKrG,SAASjN,KAAK+S,QAAQigE,aACtBigB,mBAAkB,GAGpBjzF,MAtCIA,MA6Cfs+H,yBAA0B,eAClBnzH,EAAGozH,KAAM/rG,GAAIC,GAAI+rG,MAAOC,MAAO3wH,EAAGiT,SAEjC/gB,KAAK0+H,gBAKVvzH,EAAInL,KAAK0wC,OAAO5P,KAAK9gC,KAAK4wC,QAE1B2tF,KAAOv+H,KAAK2+H,cAGZnsG,GAAKxyB,KAAK4+H,qBAAqB,GAAGz5G,SAAS3b,MAAM1H,eAAgB9B,KAAK0wC,OAAO7iC,QAC7E4kB,GAAKzyB,KAAK4+H,qBAAqB,GAAGz5G,SAAS3b,MAAM1H,eAAgB9B,KAAK4wC,OAAO/iC,SAGzE2kB,GAAKtO,IAAIzF,KAAOgU,GAAKvO,IAAIzF,KAAOtT,IAAMozH,QACtCC,MAAQx+H,KAAK0wC,OAAOw+C,aACPlvF,KAAK0wC,OAAO7lC,OAASrB,MAAMhH,qBAC3B8Q,KAAKrG,SAASjN,KAAK0wC,OAAO39B,QAAQ4/D,OAC/C8rD,MAAQz+H,KAAK4wC,OAAOs+C,aACPlvF,KAAK4wC,OAAO/lC,OAASrB,MAAMhH,qBAC3B8Q,KAAKrG,SAASjN,KAAK4wC,OAAO79B,QAAQ4/D,OAM3CxnE,EAAI+Y,IAAIzF,IACH+T,GAAKC,IAAMgsG,OACPjsG,IAAMC,IAAMgsG,QAAUD,YACtB5tF,OAAOkhD,oBAAoBtoF,MAAM1H,eAAgB,CAClD9B,KAAK0wC,OAAOtS,KAAOp+B,KAAK4wC,OAAOxS,IAAMp+B,KAAK0wC,OAAOtS,KAAOmgG,KAAOpzH,EAC/DnL,KAAK0wC,OAAOrS,KAAOr+B,KAAK4wC,OAAOvS,IAAMr+B,KAAK0wC,OAAOrS,KAAOkgG,KAAOpzH,SAE9DylC,OAAOouC,eACJxsD,IAAMC,IAAM+rG,OACfhsG,GAAKC,IAAM+rG,QAAUC,cACrB/tF,OAAOohD,oBAAoBtoF,MAAM1H,eAAgB,CAClD9B,KAAK4wC,OAAOxS,KAAOp+B,KAAK0wC,OAAOtS,IAAMp+B,KAAK4wC,OAAOxS,KAAOmgG,KAAOpzH,EAC/DnL,KAAK4wC,OAAOvS,KAAOr+B,KAAK0wC,OAAOrS,IAAMr+B,KAAK4wC,OAAOvS,KAAOkgG,KAAOpzH,SAE9DulC,OAAOsuC,eAKhBlxE,EAAIpB,KAAKywB,SAAW,GACpBpc,EAAIrU,KAAKywB,SAAW,GACpBhyB,EAAIuB,KAAKmU,KAAK/S,EAAIA,EAAIiT,EAAIA,GAEtB09G,YACK7tF,OAAOkhD,oBAAoBtoF,MAAM1H,eAAgB,CAClD9B,KAAK0wC,OAAOtS,IAAMtwB,EAAIywH,KAAOpzH,EAC7BnL,KAAK0wC,OAAOrS,IAAMtd,EAAIw9G,KAAOpzH,SAE5BylC,OAAOouC,cACLw/C,aACF9tF,OAAOohD,oBAAoBtoF,MAAM1H,eAAgB,CAClD9B,KAAK4wC,OAAOxS,IAAMtwB,EAAIywH,KAAOpzH,EAC7BnL,KAAK4wC,OAAOvS,IAAMtd,EAAIw9G,KAAOpzH,SAE5BulC,OAAOsuC,oBAIf4/C,qBAAqB,GAAGp6G,eAAehb,MAAM1H,eAAgB9B,KAAK0wC,OAAO7iC,OAAOG,gBAChF4wH,qBAAqB,GAAGp6G,eAAehb,MAAM1H,eAAgB9B,KAAK4wC,OAAO/iC,OAAOG,YAElFhO,MAlEIA,MAyEf69H,cAAe,eACP7zH,EAAIka,IAAI1D,aAAaxgB,KAAK0wC,OAAO7iC,OAAOG,UAAWhO,KAAK4wC,OAAO/iC,OAAOG,gBAErE4V,QAAQ,GAAK5Z,EAAE,QACf4Z,QAAQ,GAAK5Z,EAAE,QACf4Z,QAAQ,GAAK5Z,EAAE,QACf4Z,QAAQ,GAAK,OAEbjqB,aAOTu5F,eAAgB,kBAGPlzF,KAAKivF,aAINjvF,KAAKwhF,YAAYvvE,eAEZ6T,QAAWpX,MAAM1O,KAAK0wC,OAAO7iC,OAAOG,UAAU,GAAKhO,KAAK0wC,OAAO7iC,OAAOG,UAAU,GAC7EhO,KAAK4wC,OAAO/iC,OAAOG,UAAU,GAAKhO,KAAK4wC,OAAO/iC,OAAOG,UAAU,KAC9DkW,IAAI3D,aAAavgB,KAAK4jB,QAAS5jB,KAAK4jB,QAAS,IAAMM,IAAIzF,IAAMyF,IAAIzF,IAGrEze,KAAK8lB,aACDw/D,kBAAiB,IAI1BtlF,KAAKwhF,YAAYvvE,cACZ7R,MAAMmvE,SAASmS,WAAW1hF,MAI/BA,KAAKovF,UAAYpvF,KAAKwhF,YAAYvvE,SAAWjS,KAAKkQ,OAClDlQ,KAAKkQ,MAAMsxE,YAAYvvE,SAAWjS,KAAK8lB,cAElC5V,MAAMsqB,cACNp6B,MAAMmvE,SAASgW,WAAWvlF,KAAKkQ,aAInCijF,0BAQAlE,aAAc,EACZjvF,MArCIA,MAgDfm3D,mBAAoB,SAAUp6D,OACtBqqB,GAAKpnB,KAAK0wC,OAAOkmB,SAAS9oD,EAC1B+wH,GAAK7+H,KAAK0wC,OAAOkmB,SAAS71C,EAC1Bk+B,GAAKj/C,KAAK4wC,OAAOgmB,SAAS9oD,EAC1BoxC,GAAKl/C,KAAK4wC,OAAOgmB,SAAS71C,EAC1B+9G,GAAK/hI,EAAE65D,SAAS9oD,EAChB60C,GAAK5lD,EAAE65D,SAAS71C,QAmBb,CAAC,CAAC,IAAK89G,GAAI,MAAOC,GAAI,MAAOD,GAAI,MAAO5/E,GAAI,MAAO0D,GAAI,MAAO1D,GAAI,MAAO73B,GAAI,MAAOu7B,GAAI,MAAOv7B,GAAI,MAAO83B,GAAI,MAAO4/E,GAAI,MAAO5/E,GAAI,KAAK9jD,KAAK,MAOzJ0iI,QAAS,kBACDpxH,KAAKwC,IAAIlP,KAAK4jB,QAAQ,KAAOM,IAAIzF,KACzBze,KAAK4jB,QAAQ,GAAK5jB,KAAK4jB,QAAQ,GAGpCpC,EAAAA,GAOX+xB,SAAU,kBACF7mC,KAAKwC,IAAIlP,KAAK4jB,QAAQ,KAAOM,IAAIzF,KACzBze,KAAK4jB,QAAQ,GAAK5jB,KAAK4jB,QAAQ,GAGpCpC,EAAAA,GAOXw8G,SAAU,kBACCtxH,KAAKypB,OAAOn2B,KAAK4jB,QAAQ,GAAI5jB,KAAK4jB,QAAQ,KAcrDm7G,YAAa,SAAUrsF,cAAeC,0BAC7B5/B,QAAQ6/B,cAAgBF,mBACxB3/B,QAAQ8/B,aAAeF,kBAEvBvyC,MAAMmvE,SAASmS,WAAW1hF,MACxBA,MAIXi1F,cAAe,kBACJ,IAAI9wE,OAAO3a,MAAM1H,eAAgB,CAAC,IAAO9B,KAAK4wC,OAAOxS,IAAMp+B,KAAK0wC,OAAOtS,KAAM,IAAOp+B,KAAK4wC,OAAOvS,IAAMr+B,KAAK0wC,OAAOrS,MAAOr+B,KAAKI,QAOzI4+H,uBAAwB,SAAUC,WAC1B3rH,KAAKzU,OAAOmB,KAAKkQ,cACZA,MAAM2sF,eAAiB,IAAI14E,OAAO3a,MAAMzH,iBAAkB,CAACk9H,UAAU,IAAKA,UAAU,IAAKj/H,KAAKI,SAK3G80F,eAAgB,eACRpnF,EAAGiT,EACHomE,GAAK,EACL1mE,GAAK,IAAI0D,OAAO3a,MAAM1H,eAAgB9B,KAAK0wC,OAAO7iC,OAAOG,UAAWhO,KAAKI,OACzEsgB,GAAK,IAAIyD,OAAO3a,MAAM1H,eAAgB9B,KAAK4wC,OAAO/iC,OAAOG,UAAWhO,KAAKI,OACzEo3C,MAAQlkC,KAAKrG,SAASjN,KAAK+S,QAAQ6/B,eACnC6E,MAAQnkC,KAAKrG,SAASjN,KAAK+S,QAAQ8/B,kBAEnC2E,OAASC,QACTtI,SAASiD,aAAapyC,KAAMygB,GAAIC,GAAI,GAGxCD,GAAKA,GAAG8D,UACR7D,GAAKA,GAAG6D,WAEHjR,KAAKzU,OAAOmB,KAAKkQ,cACX,IAAIiU,OAAO3a,MAAMzH,iBAAkB,CAAC4M,IAAKA,KAAM3O,KAAKI,cAGvDkT,KAAKrG,SAASjN,KAAKkQ,MAAM6C,QAAQ8E,eACpC,UACA,WACA,OACG4I,GAAG,IAAMC,GAAG,IACZ5S,EAAI2S,GAAG,GACPM,EAAIN,GAAG,KAEP3S,EAAI4S,GAAG,GACPK,EAAIL,GAAG,cAGV,SACA,UACA,MACGD,GAAG,GAAKC,GAAG,IACX5S,EAAI2S,GAAG,GACPM,EAAIN,GAAG,KAEP3S,EAAI4S,GAAG,GACPK,EAAIL,GAAG,kBAIX5S,EAAI,IAAO2S,GAAG,GAAKC,GAAG,IACtBK,EAAI,IAAON,GAAG,GAAKC,GAAG,WAItB82B,OAASC,SACLnkC,KAAKzU,OAAOmB,KAAKkQ,SACjBi3E,GAAK7zE,KAAKrG,SAASjN,KAAKkQ,MAAM6C,QAAQzB,WAGtC5E,KAAKwC,IAAIpB,GAAKoW,IAAIzF,IAClB3Q,EAAIq5E,GACGnnF,KAAKI,MAAM0yC,YAAc5uB,IAAIzF,IAAM3Q,GAClCA,EAAI9N,KAAKI,MAAM0yC,YAAcq0C,GAAKjjE,IAAIzF,MAC9C3Q,EAAI9N,KAAKI,MAAM0yC,YAAcq0C,IAG7BjjE,IAAIzF,IAAM0oE,GAAKpmE,GAAKA,GAAKmD,IAAIzF,IAC7BsC,EAAIomE,GACGnnF,KAAKI,MAAM2yC,aAAe7uB,IAAIzF,IAAMsC,GACnCA,EAAI/gB,KAAKI,MAAM2yC,aAAeo0C,GAAKjjE,IAAIzF,MAC/CsC,EAAI/gB,KAAKI,MAAM2yC,aAAeo0C,KAI/B,IAAIhjE,OAAO3a,MAAMzH,iBAAkB,CAAC+L,EAAGiT,GAAI/gB,KAAKI,QAI3D6yF,kBAAmB,eACAzjF,EAAGnP,EAAG6+H,GAAjBt5G,KAAO,UAEXA,KAAKzoB,GAAK6C,KAAK7C,GAAK,IAAM6C,KAAKuvF,UAC/B3pE,KAAKnb,aAAejB,MAAMvF,uBACrBsrF,YACL3pE,KAAK8qB,OAAS1wC,KAAK0wC,OACnB9qB,KAAKgrB,OAAS5wC,KAAK4wC,OAEnBhrB,KAAKhC,QAAU5jB,KAAK4jB,QAEpBgC,KAAKxlB,MAAQJ,KAAKI,MAElBwlB,KAAK7S,QAAUO,KAAK3D,SAAS3P,KAAK+S,QAAS/S,KAAK+S,QAAQ+pH,iBAAiB,GACzEl3G,KAAK7S,QAAQ9C,MAAQjQ,KAAKI,MAAMqM,QAAQwD,MAAM+iE,MAC9C1/D,KAAKxC,gBAAgB8U,MACrBA,KAAK47D,YAAc,CACfvvE,QAASqB,KAAKrG,SAAS2Y,KAAK7S,QAAQd,UAGxC5R,EAAIL,KAAKuzC,WACT/jC,EAAIxP,KAAK89H,UACTl4G,KAAK2tB,SAAW,kBACLlzC,GAEXulB,KAAKk4G,QAAU,kBACJtuH,GAGX0vH,GAAKl/H,KAAKI,MAAMmvE,SAAS8P,uBACpBj/E,MAAMmvE,SAAS8P,mBAAoB,OACnCj/E,MAAMmvE,SAASkS,SAAS77D,WACxBxlB,MAAMmvE,SAAS8P,kBAAoB6/C,QACnC5vC,OAAO1pE,KAAKzoB,IAAMyoB,KAAK+6D,SAErB3gF,MASXmwF,aAAc,SAAUoB,eAChBj3F,EACAqW,KAAO2C,KAAKlJ,QAAQmnF,WAAaA,UAAY,CAACA,WAC9CnlF,IAAMuE,KAAK9V,WAEVP,EAAI,EAAGA,EAAI8R,IAAK9R,SACZo2C,OAAOm2C,gBAAgBnrF,KAAKiV,KAAKrW,SACjCs2C,OAAOi2C,gBAAgBnrF,KAAKiV,KAAKrW,WAGnC0F,MAIXozE,WAAY,SAAUv3B,SACdp7B,GAAIC,GAAIuxE,GAAO/jB,MACfpgE,EAAGiT,EAAG61E,GAAIC,UAEVvjF,KAAKrG,SAASjN,KAAK+S,QAAQ4kF,YACvB33F,KAAKgM,QAAQnR,OAAS,QACjB61C,OAAOwmD,kBAAiB,GAAM,QAC9BtmD,OAAOsmD,kBAAiB,GAAM,IAC5B5jF,KAAKzU,OAAOg9C,OACnB+6C,GAAKtjF,KAAKrG,SAASjN,KAAK+S,QAAQ+jF,WAChCD,GAAKvjF,KAAKrG,SAASjN,KAAK+S,QAAQgkF,WAIhCjpF,GAFA2S,GAAK,IAAI0D,OAAO3a,MAAMzH,iBAAkB,CAAC85C,IAAIs+D,MAAOt+D,IAAIu+D,OAAQp6G,KAAKI,QAE9D4N,UAAU,GACjB+S,EAAIN,GAAGzS,UAAU,GAEb4oF,IAAM,GAAK52F,KAAKI,MAAM6tE,aAAejuE,KAAKI,MAAM6tE,YAAYngE,EAAE2oF,eAE9DG,IADA1oB,MAAQluE,KAAKI,MAAM6tE,YAAYngE,EAAE2oF,cACtBO,YAAc1jF,KAAKrG,SAASihE,MAAMn7D,QAAQkkF,YAAc,IAEnEJ,IAAM,GAAK72F,KAAKI,MAAM6tE,aAAejuE,KAAKI,MAAM6tE,YAAYltD,EAAE01E,eAE9DI,IADA3oB,MAAQluE,KAAKI,MAAM6tE,YAAYltD,EAAE01E,cACtBO,YAAc1jF,KAAKrG,SAASihE,MAAMn7D,QAAQkkF,YAAc,IAInEL,GAAK,GAAKC,GAAK,IAOfn2E,GAAKyuB,SAASqE,mBAAmB,CAAC3lC,OAAQ4S,IAAKzgB,KAAMA,KAAKI,OAE1D6xF,GAAKpkD,WAAWa,SAAS,CAAC,EAAGhiC,KAAKyU,MAAMrT,EAAI8oF,IAAMA,GAAIlqF,KAAKyU,MAAMJ,EAAI81E,IAAMA,IAAKn2E,GAAG1S,WAC/EhO,KAAKI,MAAMwM,OAAO,YAAaqlF,GAAG54F,MAAM,GAAI,CAACwR,KAAM,cACrD6mF,UAAU,CAAC1xF,KAAK0wC,OAAQ1wC,KAAK4wC,iBAIlCF,OAAOwmD,kBAAiB,GAAO,QAC/BtmD,OAAOsmD,kBAAiB,GAAO,IAGjCl3F,MAIX+6E,aAAc,eACNokD,QAAU7rH,KAAKrG,SAASjN,KAAK+S,QAAQspF,qBAErCr8F,KAAKgM,QAAQnR,OAAS,SACjB61C,OAAOorD,mBAAmBqjC,cAC1BvuF,OAAOkrD,mBAAmBqjC,UAG5Bn/H,MAkBXo+B,EAAG,SAAUllB,OACLpL,EACApN,EAAIV,KAAK4jB,QAAQ,UAErB9V,EAAKpB,KAAKwC,IAAIlP,KAAK0wC,OAAO7iC,OAAOG,UAAU,IAAMkW,IAAIzF,IAC7Cze,KAAK0wC,OAAO7iC,OAAOG,UAAU,GAC7BhO,KAAK4wC,OAAO/iC,OAAOG,UAAU,GAErCkL,EAAgB,GAAXA,EAAI,KAED,EAAIxM,KAAKwC,IAAIgK,IAAMpL,EAAIoL,EAAIxY,GASvC29B,EAAG,SAAUnlB,OACL6H,EACA1T,EAAIrN,KAAK4jB,QAAQ,UAErB7C,EAAKrU,KAAKwC,IAAIlP,KAAK0wC,OAAO7iC,OAAOG,UAAU,IAAMkW,IAAIzF,IAC7Cze,KAAK0wC,OAAO7iC,OAAOG,UAAU,GAC7BhO,KAAK4wC,OAAO/iC,OAAOG,UAAU,GAErCkL,EAAgB,GAAXA,EAAI,KAED,EAAIxM,KAAKwC,IAAIgK,IAAM6H,EAAI7H,EAAI7L,GAUvCmvC,EAAG,SAAUtjC,OACL0O,EAAKlb,KAAKwC,IAAIlP,KAAK0wC,OAAO7iC,OAAOG,UAAU,IAAMkW,IAAIzF,IACjDze,KAAK0wC,OAAO7iC,OAAOG,UAAU,GAC7BhO,KAAK4wC,OAAO/iC,OAAOG,UAAU,UAErCkL,EAAgB,GAAXA,EAAI,KAED,EAAIxM,KAAKwC,IAAIgK,IAAM0O,GAO/BoyB,EAAG,kBACQh6C,KAAK0wC,OAAO5P,KAAK9gC,KAAK4wC,SAOjCuG,KAAM,kBACK,GAOXD,KAAM,kBACK,GAIXq+C,OAAQ,eACA9kD,IAAMzwC,KAAK0wC,OAAO7iC,OAAOG,UACzB2iC,IAAM3wC,KAAK4wC,OAAO/iC,OAAOG,gBAEtB,CAACtB,KAAKC,IAAI8jC,IAAI,GAAIE,IAAI,IAAKjkC,KAAKiS,IAAI8xB,IAAI,GAAIE,IAAI,IAAKjkC,KAAKiS,IAAI8xB,IAAI,GAAIE,IAAI,IAAKjkC,KAAKC,IAAI8jC,IAAI,GAAIE,IAAI,MAI/G4wC,OAAQ,gBACCiP,iBACLzB,gBAAgB71F,UAAUqoF,OAAO7nF,KAAKsG,SAyH9C5B,IAAIghI,WAAa,SAAUh/H,MAAO4L,QAASC,gBACnC2lC,GAAIvjC,GAAI0jC,GAAIC,GAAI13C,EAAG+R,KAInB6iF,YAHAt/E,EAAI,GACJyvH,aAAc,EACdlB,aAAc,KAOK,IAAnBnyH,QAAQnR,OAAc,IAElByY,KAAKlJ,QAAQ4B,QAAQ,KAAOA,QAAQ,GAAGnR,OAAS,EAChDwR,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,OAAQ,UAC9DslC,GAAK3xC,MAAMwM,OAAO,QAASZ,QAAQ,GAAIK,WACpC,GAAIiH,KAAKvJ,SAASiC,QAAQ,KAAOsH,KAAK9I,QAAQwB,QAAQ,IACzD+lC,GAAM3xC,MAAMG,OAAOyL,QAAQ,SACxB,GAAIsH,KAAKnJ,WAAW6B,QAAQ,KAAOsH,KAAK9I,QAAQwB,QAAQ,MAC3D+lC,GAAK/lC,QAAQ,KACbmyH,aAAc,OACX,GAAI7qH,KAAKnJ,WAAW6B,QAAQ,KAAOA,QAAQ,KAAKnR,QAAUmR,QAAQ,KAAKnR,QAAU,EACpFwR,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,OAAQ,UAC9DslC,GAAKsqF,MAAMU,YAAY38H,MAAO4L,QAAQ,KAAMK,MAC5C8xH,aAAc,MACX,CAAA,IAAI7qH,KAAK/I,SAASyB,QAAQ,MAAOsH,KAAK1I,wBAAwBoB,QAAQ,UAKnE,IAAIhQ,MAAM,0DACJgQ,QAAQ,IAAM,kBAAoBA,QAAQ,IADtC,wEAJhBqzH,aAAc,EACdhzH,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,OAAQ,UAC9DslC,GAAK3xC,MAAMwM,OAAO,QAAS,CAACZ,QAAQ,GAAG0kC,OAAQ1kC,QAAQ,IAAKK,SAQ5DgzH,YACAhzH,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,OAAQ,UAC9DulC,GAAK5xC,MAAMwM,OAAO,QAAS,CAACZ,QAAQ,GAAG4kC,OAAQ5kC,QAAQ,IAAKK,WACzD,GAAIiH,KAAKlJ,QAAQ4B,QAAQ,KAAOA,QAAQ,GAAGnR,OAAS,EACvDwR,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,OAAQ,UAC9DulC,GAAK5xC,MAAMwM,OAAO,QAASZ,QAAQ,GAAIK,WACpC,GAAIiH,KAAKvJ,SAASiC,QAAQ,KAAOsH,KAAK9I,QAAQwB,QAAQ,IACzDgmC,GAAM5xC,MAAMG,OAAOyL,QAAQ,SACxB,GAAIsH,KAAKnJ,WAAW6B,QAAQ,KAAQsH,KAAK9I,QAAQwB,QAAQ,MAC5DgmC,GAAKhmC,QAAQ,KACbmyH,aAAc,MACX,CAAA,KAAI7qH,KAAKnJ,WAAW6B,QAAQ,KAAOA,QAAQ,KAAKnR,QAAUmR,QAAQ,KAAKnR,QAAU,SAK9E,IAAImB,MAAM,0DACJgQ,QAAQ,IAAM,kBAAoBA,QAAQ,IADtC,wEAJhBK,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,OAAQ,UAC9DulC,GAAKqqF,MAAMU,YAAY38H,MAAO4L,QAAQ,KAAMK,MAC5C8xH,aAAc,EAOlB9xH,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,QAEtD4B,GAAK,IAAIjQ,IAAIw/H,KAAKx9H,MAAO2xC,GAAIC,GAAI3lC,MAE7B8xH,aACA9vH,GAAG8vH,aAAc,EACjB9vH,GAAG+vH,MAAQpyH,QAAQ,GACnBqC,GAAGgwH,MAAQryH,QAAQ,IACXqzH,cACRhxH,GAAG6gF,aAAc,GAIrB7gF,GAAG+iF,WAAW,CAACr/C,GAAG50C,GAAI60C,GAAG70C,UAKtB,GAAuB,IAAnB6O,QAAQnR,OAAc,KAE7Bq0F,aAAc,EACT50F,EAAI,EAAGA,EAAI,EAAGA,OACXgZ,KAAKrJ,SAAS+B,QAAQ1R,IAGtBsV,EAAEtV,GAAKgZ,KAAK/H,eAAeS,QAAQ1R,QAChC,CAAA,IAAIgZ,KAAKnJ,WAAW6B,QAAQ1R,UAIzB,IAAI0B,MAAM,0DACJgQ,QAAQ,IAAM,kBAAoBA,QAAQ,IAAM,kBAAoBA,QAAQ,IADxE,wEAHhB4D,EAAEtV,GAAK0R,QAAQ1R,GACf40F,aAAc,EAStB7iF,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,OAAQ,UAE1DslC,GADAm9C,YACK9uF,MAAMwM,OAAO,QAAS,CACvBgD,EAAE,KAAOA,EAAE,KAAOA,EAAE,KAAOA,EAAE,KAC7BA,EAAE,KAAOA,EAAE,KAAOA,EAAE,KAAOA,EAAE,MAC5BA,EAAE,KAAOA,EAAE,KAAOA,EAAE,KAAOA,EAAE,MAC/BvD,MAEEjM,MAAMwM,OAAO,QAAS,CACvB,iBACiD,IAArCgD,EAAE,KAAOA,EAAE,KAAOA,EAAE,KAAOA,EAAE,OAEzC,iBACiD,IAArCA,EAAE,KAAOA,EAAE,KAAOA,EAAE,KAAOA,EAAE,OAEzC,iBACkD,KAArCA,EAAE,KAAOA,EAAE,KAAOA,EAAE,KAAOA,EAAE,QACtCvD,MAIZA,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,OAAQ,UAE1DulC,GADAk9C,YACK9uF,MAAMwM,OAAO,QAAS,CACvBgD,EAAE,KAAOA,EAAE,KAAOA,EAAE,KAAOA,EAAE,MAC5BA,EAAE,KAAOA,EAAE,KAAOA,EAAE,MACpBA,EAAE,KAAOA,EAAE,KAAOA,EAAE,MACtBvD,MAEEjM,MAAMwM,OAAO,QAAS,CACvB,kBACWgD,EAAE,KAAOA,EAAE,KAAOA,EAAE,KAAOA,EAAE,MAExC,kBACYA,EAAE,KAAOA,EAAE,KAAOA,EAAE,MAEhC,kBACYA,EAAE,KAAOA,EAAE,KAAOA,EAAE,OAC5BvD,MAKZ0lC,GAAGszC,gBAAgB7qD,SACnBwX,GAAGqzC,gBAAgB7qD,SACnBnuB,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,SACtD4B,GAAK,IAAIjQ,IAAIw/H,KAAKx9H,MAAO2xC,GAAIC,GAAI3lC,OAE9B6iF,YAAcA,YACjB7gF,GAAG+iF,WAAW,CAACr/C,GAAIC,UAGhB,GAAuB,IAAnBhmC,QAAQnR,QAAgByY,KAAKnJ,WAAW6B,QAAQ,KAA+B,IAAxBA,QAAQ,KAAKnR,QACvEyY,KAAK9I,QAAQwB,QAAQ,KAAK,KAC1BsH,KAAK9I,QAAQwB,QAAQ,KAAK,IAC9B4lC,GAAK5lC,QAAQ,KACbK,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,SACtD4B,GAAK,IAAIjQ,IAAIw/H,KAAKx9H,MAAOwxC,GAAG,GAAIA,GAAG,GAAIvlC,OACpC8xH,aAAc,EACjB9vH,GAAG6vH,MAAQlyH,QAAQ,GACnBqC,GAAG+iF,WAAWx/C,QAEX,CAAA,KAAuB,IAAnB5lC,QAAQnR,QAAgByY,KAAKnJ,WAAW6B,QAAQ,KAA+B,IAAxBA,QAAQ,KAAKnR,QACvEyY,KAAKrJ,SAAS+B,QAAQ,KAAK,KAC3BsH,KAAKrJ,SAAS+B,QAAQ,KAAK,KAC3BsH,KAAKrJ,SAAS+B,QAAQ,KAAK,WAmCzB,IAAIhQ,MAAM,0DACJgQ,QAAQ,IAAM,kBAAoBA,QAAQ,IADtC,wEAlChB4lC,GAAK5lC,QAAQ,GAEbK,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,OAAQ,UAC9DslC,GAAK3xC,MAAMwM,OAAO,QAAS,CACvB,eACQgD,EAAIgiC,WAED,CAC2B,IAA7BhiC,EAAE,GAAKA,EAAE,GAAKA,EAAE,GAAKA,EAAE,IACM,IAA7BA,EAAE,GAAKA,EAAE,GAAKA,EAAE,GAAKA,EAAE,IACO,KAA7BA,EAAE,GAAKA,EAAE,GAAKA,EAAE,GAAKA,EAAE,OAE7BvD,MAERA,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,OAAQ,UAC9DulC,GAAK5xC,MAAMwM,OAAO,QAAS,CACvB,eACQgD,EAAIgiC,WAED,CACHhiC,EAAE,GAAKA,EAAE,GAAKA,EAAE,GAAKA,EAAE,IACtBA,EAAE,GAAKA,EAAE,GAAKA,EAAE,IAChBA,EAAE,GAAKA,EAAE,GAAKA,EAAE,MAErBvD,MAERA,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,SACtD4B,GAAK,IAAIjQ,IAAIw/H,KAAKx9H,MAAO2xC,GAAIC,GAAI3lC,OAE9B8xH,aAAc,EACjB9vH,GAAG6vH,MAAQlyH,QAAQ,GACnBqC,GAAG+iF,WAAW,CAACr/C,GAAIC,YAQhB3jC,IAGXjQ,IAAIsB,gBAAgB,OAAQtB,IAAIghI,YA2DhChhI,IAAIkhI,cAAgB,SAAUl/H,MAAO4L,QAASC,gBACtCoC,GAAIhC,QAERJ,WAAWymC,eAAgB,EAC3BzmC,WAAW0mC,cAAe,EAC1BtmC,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,WAEtD4B,GAAKjO,MAAMwM,OAAO,OAAQZ,QAAQ3S,MAAM,EAAG,GAAIgT,MAExB,IAAnBL,QAAQnR,OAAc,IACtBwT,GAAGqwH,gBAAiB,EAEhBprH,KAAKrJ,SAAS+B,QAAQ,IACtBqC,GAAGswH,YAAc,kBACN3yH,QAAQ,QAEhB,CAAA,IAAIsH,KAAKnJ,WAAW6B,QAAQ,UAGzB,IAAIhQ,MAAM,kEACJgQ,QAAQ,IADJ,uDAFhBqC,GAAGswH,YAAc3yH,QAAQ,GAO7BqC,GAAGgoF,WAAa,kBACLr2F,KAAKgM,QAAQ9Q,OAAO8E,KAAK2+H,gBAGpCtwH,GAAGuwH,qBAAuB,GAC1BvwH,GAAGuwH,qBAAqB,GAAK,IAAIz6G,OAAO3a,MAAM1H,eAAgBuM,GAAGqiC,OAAO7iC,OAAOG,UAAU3U,MAAM,EAAG,GAAI+G,OACtGiO,GAAGuwH,qBAAqB,GAAK,IAAIz6G,OAAO3a,MAAM1H,eAAgBuM,GAAGuiC,OAAO/iC,OAAOG,UAAU3U,MAAM,EAAG,GAAI+G,cAG1GiO,GAAGqhF,OAAS,UAELrhF,IAGXjQ,IAAIsB,gBAAgB,UAAWtB,IAAIkhI,eA+BnClhI,IAAImhI,YAAc,SAAUn/H,MAAO4L,QAASC,gBACpCoC,GAAIhC,YAERJ,WAAWymC,eAAgB,EAC3BzmC,WAAW0mC,cAAe,EAC1BtmC,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,UACtD4B,GAAKjO,MAAMwM,OAAO,OAAQZ,QAASK,OAEhCxB,KAAOrB,MAAMnG,mBAChBgL,GAAGqhF,OAAS,QAELrhF,IAGXjQ,IAAIsB,gBAAgB,QAAStB,IAAImhI,aAyBjCnhI,IAAIohI,WAAa,SAAUp/H,MAAO4L,QAASC,gBACnCI,KAAMozH,WAAYpxH,GAAIyI,IAAK4uB,SAG1BpyB,KAAKlJ,QAAQ4B,QAAQ,MAAOsH,KAAK9I,QAAQwB,QAAQ,MAASsH,KAAKlJ,QAAQ4B,QAAQ,MAAOsH,KAAK9I,QAAQwB,QAAQ,UAyCtG,IAAIhQ,MAAM,0DACJgQ,QAAQ,IAAM,kBAAoBA,QAAQ,IADtC,mEA/BX8K,OAPLzK,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,SACtD4B,GAAKjO,MAAMwM,OAAO,OAAQZ,QAASK,OAChCxB,KAAOrB,MAAMtH,iBAChBmM,GAAG6gF,aAAc,EACjB7gF,GAAGqiC,OAAOw+C,aAAc,EACxB7gF,GAAGuiC,OAAOs+C,aAAc,EAEZ7gF,GAAGmoD,UACPnoD,GAAGmoD,UAAUr9D,eAAe2d,OAC5BzI,GAAGmoD,UAAU1/C,KAAKjM,KAAOrB,MAAMrH,8BAKvCs9H,WAAansH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,OAAQ,SAEhEi5B,KADApyB,KAAKzU,OAAO4gI,WAAWC,eAChBD,WAAWC,cACXpsH,KAAKlJ,QAAQq1H,WAAWvxD,OACxBuxD,WAAWvxD,MAEX,EASX7/D,GAAGooF,aAAer2F,MAAMwM,OAAO,QAAS,CAACyB,GAAIq3B,MAAO+5F,YACpDpxH,GAAGooF,aAAa9G,MAAO,EACvBthF,GAAGqhF,OAAS,OACZrhF,GAAGuhF,KAAO,CACN1hB,MAAO7/D,GAAGooF,cAEdpoF,GAAGwhF,SAASn0F,KAAK2S,GAAGooF,cAQjBpoF,IAGXjQ,IAAIsB,gBAAgB,OAAQtB,IAAIohI,YA0BhCphI,IAAIuhI,cAAgB,SAAUv/H,MAAO4L,QAASC,gBACtClP,EAAG6S,EAAGrV,EAAG8T,GAAI2tE,WAGM,IAAnBhwE,QAAQnR,OACRkC,EAAIiP,QAAQ,GACZ4D,EAAI7S,EAAEq8F,gBAEH,CAAA,GAAuB,IAAnBptF,QAAQnR,aAcT,IAAImB,MAAM,6DACJgQ,QAAQ,IAAM,kBAAoBA,QAAQ,IADtC,2EAZZsH,KAAK9I,QAAQwB,QAAQ,IACrBjP,EAAIiP,QAAQ,GACZ4D,EAAI5D,QAAQ,OACT,CAAA,IAAIsH,KAAK9I,QAAQwB,QAAQ,UAItB,IAAIhQ,MAAM,6DACJgQ,QAAQ,IAAM,kBAAoBA,QAAQ,IADtC,wEAHhB4D,EAAI5D,QAAQ,GACZjP,EAAIiP,QAAQ,OAYhB4D,EAAEnF,eAAiBjB,MAAMvF,mBACzB+3E,QAAU57E,MAAMwM,OAAO,OAAQ,CAACgD,EAAE8gC,OAAQ9gC,EAAEghC,QAAS3kC,aAC7C4pE,OAAS94E,EACV6S,EAAEnF,eAAiBjB,MAAMrF,oBAAsByL,EAAE/E,OAASrB,MAAMlH,kBAC5B,SAAvCgR,KAAKrG,SAAS2C,EAAEmD,QAAQwpC,YACxBy/B,QAAU57E,MAAMwM,OAAO,OAAQ,CAC3B,eACQwV,EAAIxS,EAAEwuB,EACNxhC,EAAIgT,EAAEyuB,SACFthC,EAAEqhC,IAAMjJ,SAAS+H,EAAEtgC,EAAXu4B,CAAcp4B,EAAE8a,UAAY9a,EAAEshC,IAAMlJ,SAAS+H,EAAE9a,EAAX+S,CAAcp4B,EAAE8a,WAExE,kBACWsd,SAAS+H,EAAEttB,EAAEyuB,EAAblJ,CAAgBp4B,EAAE8a,WAE7B,kBACYsd,SAAS+H,EAAEttB,EAAEwuB,EAAbjJ,CAAgBp4B,EAAE8a,YAE/B5L,YAEHlP,EAAE8xF,SAAS7S,SAEXA,QAAQnG,OAAS94E,IAYjBi/E,QAAU57E,MAAMwM,OAAO,OAAQ,CAC3B,eAEQmlC,GAAIC,GAAI94B,EAAGmH,EAAGmhB,EAAG6N,EAAGnS,EAAG4B,GAAIiC,GAAI51B,EAD/B7Q,EAAIoS,KAAKmS,MAAM9hB,EAAE8a,aAGE,IAAnBjI,EAAEumC,aACE77C,IAAMsV,EAAE2nC,aAAe,GACvBj9C,QAED,CAAA,GAAuB,IAAnBsV,EAAEumC,oBAUF,EAPP77C,EAAwD,EAApDoS,KAAKmS,MAAM9hB,EAAE8a,UAAYjI,EAAE2nC,aAAe,GAAK,GACnDr+B,GAAKnc,EAAE8a,UAAYjI,EAAE2nC,aAAe,GAAKj9C,GAAK,EAC1CA,GAAKsV,EAAE2nC,aAAe,IACtBj9C,EAAIsV,EAAE2nC,aAAe,EACrBr+B,EAAI,UAMR5e,EAAI,EACG,GAKY,IAAnBsV,EAAEumC,cACFpE,GAAKniC,EAAErD,OAAOjS,GAAG0T,UACjBgkC,GAAKpiC,EAAErD,OAAOjS,EAAI,GAAG0T,YAErBqS,EAAIzQ,EAAErD,OAAOjS,GAAG0T,UAChBwzB,EAAI5xB,EAAErD,OAAOjS,EAAI,GAAG0T,UACpBqhC,EAAIz/B,EAAErD,OAAOjS,EAAI,GAAG0T,UACpBkvB,EAAIttB,EAAErD,OAAOjS,EAAI,GAAG0T,UACpB8wB,IAAM,EAAI5lB,IAAM,EAAIA,IAAMsoB,EAAE,GAAKnhB,EAAE,IAAM,GAAK,EAAInH,GAAKA,GAAKm2B,EAAE,GAAK7N,EAAE,IAAMtoB,EAAIA,GAAKgkB,EAAE,GAAImS,EAAE,IAC5FtO,IAAM,EAAI7nB,IAAM,EAAIA,IAAMsoB,EAAE,GAAKnhB,EAAE,IAAM,GAAK,EAAInH,GAAKA,GAAKm2B,EAAE,GAAK7N,EAAE,IAAMtoB,EAAIA,GAAKgkB,EAAE,GAAImS,EAAE,IAE5FvQ,IADA3zB,EAAIuB,KAAKmU,KAAKie,GAAKA,GAAKiC,GAAKA,IAE7BA,IAAM51B,EAEN6mC,GAAK,CAAC,GADND,GAAKh1C,EAAE8Q,OAAOG,WACF,GAAK8wB,GAAIiT,GAAG,GAAKhR,KAE5BgR,GAAG,GAAKC,GAAG,GAAKD,GAAG,GAAKC,GAAG,KAEpC,eAEQD,GAAIC,GAAI94B,EAAGmH,EAAGmhB,EAAG6N,EAAGnS,EAAG4B,GAAIiC,GAAI51B,EAD/B7Q,EAAIoS,KAAKmS,MAAM9hB,EAAE8a,aAGE,IAAnBjI,EAAEumC,aACE77C,IAAMsV,EAAE2nC,aAAe,GACvBj9C,QAED,CAAA,GAAuB,IAAnBsV,EAAEumC,oBAUF,EAPP77C,EAAwD,EAApDoS,KAAKmS,MAAM9hB,EAAE8a,UAAYjI,EAAE2nC,aAAe,GAAK,GACnDr+B,GAAKnc,EAAE8a,UAAYjI,EAAE2nC,aAAe,GAAKj9C,GAAK,EAC1CA,GAAKsV,EAAE2nC,aAAe,IACtBj9C,EAAIsV,EAAE2nC,aAAe,EACrBr+B,EAAI,UAMR5e,EAAI,EACG,GAKY,IAAnBsV,EAAEumC,cACFpE,GAAKniC,EAAErD,OAAOjS,GAAG0T,UACjBgkC,GAAKpiC,EAAErD,OAAOjS,EAAI,GAAG0T,YAErBqS,EAAIzQ,EAAErD,OAAOjS,GAAG0T,UAChBwzB,EAAI5xB,EAAErD,OAAOjS,EAAI,GAAG0T,UACpBqhC,EAAIz/B,EAAErD,OAAOjS,EAAI,GAAG0T,UACpBkvB,EAAIttB,EAAErD,OAAOjS,EAAI,GAAG0T,UACpB8wB,IAAM,EAAI5lB,IAAM,EAAIA,IAAMsoB,EAAE,GAAKnhB,EAAE,IAAM,GAAK,EAAInH,GAAKA,GAAKm2B,EAAE,GAAK7N,EAAE,IAAMtoB,EAAIA,GAAKgkB,EAAE,GAAImS,EAAE,IAC5FtO,IAAM,EAAI7nB,IAAM,EAAIA,IAAMsoB,EAAE,GAAKnhB,EAAE,IAAM,GAAK,EAAInH,GAAKA,GAAKm2B,EAAE,GAAK7N,EAAE,IAAMtoB,EAAIA,GAAKgkB,EAAE,GAAImS,EAAE,IAE5FvQ,IADA3zB,EAAIuB,KAAKmU,KAAKie,GAAKA,GAAKiC,GAAKA,IAE7BA,IAAM51B,EAEN6mC,GAAK,CAAC,GADND,GAAKh1C,EAAE8Q,OAAOG,WACF,GAAK8wB,GAAIiT,GAAG,GAAKhR,KAE1BiR,GAAG,GAAKD,GAAG,KAEtB,eAEQA,GAAIC,GAAI94B,EAAGmH,EAAGmhB,EAAG6N,EAAGnS,EAAG4B,GAAIiC,GAAI51B,EAD/B7Q,EAAIoS,KAAKmS,MAAM9hB,EAAE8a,aAGE,IAAnBjI,EAAEumC,aACE77C,IAAMsV,EAAE2nC,aAAe,GACvBj9C,QAED,CAAA,GAAuB,IAAnBsV,EAAEumC,oBAUF,EAPP77C,EAAwD,EAApDoS,KAAKmS,MAAM9hB,EAAE8a,UAAYjI,EAAE2nC,aAAe,GAAK,GACnDr+B,GAAKnc,EAAE8a,UAAYjI,EAAE2nC,aAAe,GAAKj9C,GAAK,EAC1CA,GAAKsV,EAAE2nC,aAAe,IACtBj9C,EAAIsV,EAAE2nC,aAAe,EACrBr+B,EAAI,UAMR5e,EAAI,EACG,GAKY,IAAnBsV,EAAEumC,cACFpE,GAAKniC,EAAErD,OAAOjS,GAAG0T,UACjBgkC,GAAKpiC,EAAErD,OAAOjS,EAAI,GAAG0T,YAErBqS,EAAIzQ,EAAErD,OAAOjS,GAAG0T,UAChBwzB,EAAI5xB,EAAErD,OAAOjS,EAAI,GAAG0T,UACpBqhC,EAAIz/B,EAAErD,OAAOjS,EAAI,GAAG0T,UACpBkvB,EAAIttB,EAAErD,OAAOjS,EAAI,GAAG0T,UACpB8wB,IAAM,EAAI5lB,IAAM,EAAIA,IAAMsoB,EAAE,GAAKnhB,EAAE,IAAM,GAAK,EAAInH,GAAKA,GAAKm2B,EAAE,GAAK7N,EAAE,IAAMtoB,EAAIA,GAAKgkB,EAAE,GAAImS,EAAE,IAC5FtO,IAAM,EAAI7nB,IAAM,EAAIA,IAAMsoB,EAAE,GAAKnhB,EAAE,IAAM,GAAK,EAAInH,GAAKA,GAAKm2B,EAAE,GAAK7N,EAAE,IAAMtoB,EAAIA,GAAKgkB,EAAE,GAAImS,EAAE,IAE5FvQ,IADA3zB,EAAIuB,KAAKmU,KAAKie,GAAKA,GAAKiC,GAAKA,IAE7BA,IAAM51B,EAEN6mC,GAAK,CAAC,GADND,GAAKh1C,EAAE8Q,OAAOG,WACF,GAAK8wB,GAAIiT,GAAG,GAAKhR,KAE1BgR,GAAG,GAAKC,GAAG,MAClB/lC,YAERlP,EAAE8xF,SAAS7S,SAEXA,QAAQnG,OAAS94E,GAEd6S,EAAE/E,OAASrB,MAAMpG,oBACxB44E,QAAU57E,MAAMwM,OAAO,OAAQ,CAC3B,eACQtS,EAAIoS,KAAKmS,MAAM9hB,EAAE8a,cAGhBtd,EAAI,EAAGA,EAAIqV,EAAElG,QAAQ7O,OAAQN,QAC9B8T,GAAKuB,EAAElG,QAAQnP,IAERsQ,OAASrB,MAAMjH,kBAAmB,IACjCjI,EAAI+T,GAAGkpC,mBAIXj9C,GAAK+T,GAAGkpC,oBAIZj9C,IAAM+T,GAAGkpC,aAAe,GACxBj9C,IAGAA,EAAI,EACG,EAGJ+T,GAAGgwB,EAAE/jC,GAAK+T,GAAG+vB,EAAE9jC,EAAI,GAAK+T,GAAG+vB,EAAE9jC,GAAK+T,GAAGgwB,EAAE/jC,EAAI,IAEtD,eACQA,EAAIoS,KAAKmS,MAAM9hB,EAAE8a,cAGhBtd,EAAI,EAAGA,EAAIqV,EAAElG,QAAQ7O,OAAQN,QAC9B8T,GAAKuB,EAAElG,QAAQnP,IAERsQ,OAASrB,MAAMjH,kBAAmB,IACjCjI,EAAI+T,GAAGkpC,mBAIXj9C,GAAK+T,GAAGkpC,oBAIZj9C,IAAM+T,GAAGkpC,aAAe,GACxBj9C,IAEAA,EAAI,EACG,EAGJ+T,GAAGgwB,EAAE/jC,EAAI,GAAK+T,GAAGgwB,EAAE/jC,IAE9B,eACQA,EAAIoS,KAAKmS,MAAM9hB,EAAE8a,cAGhBtd,EAAI,EAAGA,EAAIqV,EAAElG,QAAQ7O,OAAQN,QAC9B8T,GAAKuB,EAAElG,QAAQnP,IACRsQ,OAASrB,MAAMjH,kBAAmB,IACjCjI,EAAI+T,GAAGkpC,mBAGXj9C,GAAK+T,GAAGkpC,oBAGZj9C,IAAM+T,GAAGkpC,aAAe,GACxBj9C,IAGAA,EAAI,EACG,EAGJ+T,GAAG+vB,EAAE9jC,GAAK+T,GAAG+vB,EAAE9jC,EAAI,KAC1B2R,YACRlP,EAAE8xF,SAAS7S,SAGXA,QAAQnG,OAAS94E,GACV6S,EAAEnF,eAAiBjB,MAAMtF,qBAAuB0L,EAAE/E,OAASrB,MAAMlH,oBAGxE05E,QAAU57E,MAAMwM,OAAO,OAAQ,CAC3B,kBACWsX,IAAI3E,WAAW3P,EAAE6gF,cAAe1zF,EAAE8Q,OAAOG,WAAW,IAE/D,kBACWkW,IAAI3E,WAAW3P,EAAE6gF,cAAe1zF,EAAE8Q,OAAOG,WAAW,IAE/D,kBACWkW,IAAI3E,WAAW3P,EAAE6gF,cAAe1zF,EAAE8Q,OAAOG,WAAW,KAC3D/B,YAERlP,EAAE8xF,SAAS7S,SAEXA,QAAQnG,OAAS94E,IAGhBuW,KAAKzU,OAAOm9E,eACP,IAAIhgF,MAAM,oEAGpBggF,QAAQ0T,OAAS,UACjB1T,QAAQnxE,KAAOrB,MAAMhG,oBACrBw4E,QAAQoV,WAAWplF,SAEZgwE,SAuCX59E,IAAIwhI,kBAAoB,SAAUx/H,MAAO4L,QAASC,gBAC1CoC,GAAI6lC,IAAKC,OAEU,IAAnBnoC,QAAQnR,QACJmR,QAAQ,GAAGvB,eAAiBjB,MAAMtF,qBAClC8H,QAAQ,GAAGvB,eAAiBjB,MAAMtF,0BAEhC,IAAIlI,MAAM,oEACJgQ,QAAQ,IAAM,kBAAoBA,QAAQ,IADtC,oDAKpBkoC,IAAM9zC,MAAMG,OAAOyL,QAAQ,IAC3BmoC,IAAM/zC,MAAMG,OAAOyL,QAAQ,KAE3BqC,GAAKjO,MAAMwM,OAAO,OAAQ,CAAC,eACnBS,EAAI6mC,IAAItwB,QACRljB,EAAIyzC,IAAIvwB,eAELM,IAAI3E,WAAW2E,IAAIpE,UAAU,CAACzS,EAAEhU,MAAM,EAAG,GAAIqH,EAAErH,MAAM,EAAG,KAAM,CAACqH,EAAE,IAAK2M,EAAE,OAC/EpB,aAEDyjF,OAAS,cACZrhF,GAAG+iF,WAAW,CAACl9C,IAAI/2C,GAAIg3C,IAAIh3C,KAE3B+2C,IAAI26C,SAASxgF,IACb8lC,IAAI06C,SAASxgF,IAENA,IAwDXjQ,IAAIyhI,gBAAkB,SAAUz/H,MAAO4L,QAASC,gBACxCoC,GAAI6lC,IAAKC,IACTmpF,mBAAoBC,oBACpBuC,mBAAoBC,uBAEpB/zH,QAAQnR,OAAS,IACjByiI,mBAAsBtxH,QAAQ,GAAGnB,OAASrB,MAAMlH,mBAC5C0J,QAAQ,GAAGvB,eAAiBjB,MAAMtF,oBACtCq5H,oBAAuBvxH,QAAQ,GAAGnB,OAASrB,MAAMlH,mBAC7C0J,QAAQ,GAAGvB,eAAiBjB,MAAMtF,oBAEtC47H,mBAAsBxsH,KAAK9I,QAAQwB,QAAQ,IAC3C+zH,oBAAuBzsH,KAAK9I,QAAQwB,QAAQ,KAGzB,IAAnBA,QAAQnR,UACDyiI,oBAAsByC,qBACpBD,oBAAsBvC,2BAEzB,IAAIvhI,MAAM,kEACJgQ,QAAQ,IAAM,kBAAoBA,QAAQ,IADtC,+EAKhB+zH,qBACA7rF,IAAM9zC,MAAMG,OAAOyL,QAAQ,IAC3BmoC,IAAM/zC,MAAMG,OAAOyL,QAAQ,MAE3BkoC,IAAM9zC,MAAMG,OAAOyL,QAAQ,IAC3BmoC,IAAM/zC,MAAMG,OAAOyL,QAAQ,MAI/BqC,GAAKjO,MAAMwM,OAAO,UAAW,CAACsnC,IAAKC,KAAMloC,aAEtCyjF,OAAS,YACLrhF,IAOXjQ,IAAIsB,gBAAgB,UAAWtB,IAAIuhI,eACnCvhI,IAAIsB,gBAAgB,QAAStB,IAAIuhI,eACjCvhI,IAAIsB,gBAAgB,cAAetB,IAAIwhI,mBACvCxhI,IAAIsB,gBAAgB,YAAatB,IAAIyhI,iBAE9B,CACHjC,KAAMx/H,IAAIw/H,KACVwB,WAAYhhI,IAAIghI,WAChBO,cAAevhI,IAAIuhI,cACnBK,YAAa5hI,IAAIuhI,cACjBL,cAAelhI,IAAIkhI,cACnBE,WAAYphI,IAAIohI,WAChBD,YAAanhI,IAAImhI,YACjBK,kBAAmBxhI,IAAIwhI,kBACvBC,gBAAiBzhI,IAAIyhI,oBAkD7BznI,OAAO,aAAa,CAChB,MAAO,iBAAkB,YAAa,gBAAiB,eACxD,SAAUgG,IAAKoL,MAAO0a,IAAKirB,SAAU77B,aAgBpClV,IAAI6hI,MAAQ,SAAU7/H,MAAOjD,GAAIvD,KAAM8P,QAASuC,gBACxCi0H,OAAQC,SAAU7lI,EAAGd,aAEpB4G,MAAQA,WACRsJ,QAAU,GACfw2H,OAASlgI,KAAKI,MAAM80G,gBACf90G,MAAM80G,YAAc,EAEb,KAAP/3G,IAAemW,KAAKzU,OAAO1B,SAGvBA,GAAKA,QAFLA,GAAK6C,KAAKI,MAAMjD,GAAK,QAAU+iI,YAInC9/H,MAAM0J,OAAO9J,KAAK7C,IAAM6C,UAExB6K,KAAOrB,MAAM7G,uBACb8H,aAAejB,MAAMxF,mBAEZ,KAATpK,MAAiB0Z,KAAKzU,OAAOjF,WAGzBA,KAAOA,UAFPA,KAAO,SAAWoG,KAAKI,MAAMywF,aAAa7wF,aAI5CA,KAAK6K,UAWPgD,OAAS,QACTslE,mBAAqBlnE,WAAW6kF,wBAEhCsvC,eAAiB,gBACjBC,YAAc,UACdC,eAAiB,QACjBC,kBAAoB,QACpBC,YAAc,QACdC,gBAAkB,QAElBz0H,QAAU,GAGXm0H,SADA7sH,KAAKlJ,QAAQV,SACFA,QAEAW,MAAMnR,UAAUG,MAAMK,KAAK+B,UAAW,GAGhDnB,EAAI,EAAGA,EAAI6lI,SAAStlI,OAAQP,IAC7Bd,IAAMwG,KAAKI,MAAMG,OAAO4/H,SAAS7lI,KAE3BgZ,KAAKrG,SAASzT,IAAIuZ,QAAQ4/D,QAAWr/D,KAAKzU,OAAOrF,IAAIqU,cAClD6yH,SAASlnI,UAIjBu2F,UAAY,CACb4wC,QAAS,UACTz1G,IAAK,WACLw1G,SAAU,WACVE,UAAW,YACXC,SAAU,WACVt/C,OAAQ,cACRu/C,YAAa,cACb57C,aAAc,eACdkL,YAAa,iBAIrBhyF,IAAIC,OAAOD,IAAI6hI,MAAM/mI,UAA6C,CAK9DynI,QAAS,eACDtyH,GAAItR,EAAGzC,MACN+T,MAAMrO,KAAK0J,QACR1J,KAAK0J,QAAQvQ,eAAekV,MAC5BtR,EAAIiD,KAAK0J,QAAQ2E,IAAIiiC,MACjBh9B,KAAKlJ,QAAQrN,EAAE+M,UACfxP,EAAIgZ,KAAKlX,QAAQW,EAAE+M,OAAQ9J,KAAK7C,MACvB,UACEJ,EAAE+M,OAAOxP,gBAM3BoP,QAAU,GACR1J,MAUXkxF,WAAY,SAAUllF,aACd1R,EAAG8R,IAAK+kF,QAQZ/kF,KALI+kF,IADA79E,KAAKlJ,QAAQ4B,SACPA,QAEAvQ,WAGAZ,OACLP,EAAI,EAAGA,EAAI8R,MAAO9R,EACfgZ,KAAK7J,KAAKzJ,KAAKI,MAAO+wF,IAAI72F,SACrB0R,QAAQtQ,KAAKy1F,IAAI72F,IACfgZ,KAAKzU,OAAOsyF,IAAI72F,GAAG6C,UACrB6O,QAAQtQ,KAAKy1F,IAAI72F,GAAG6C,SAI5B6O,QAAUsH,KAAK7F,YAAYzN,KAAKgM,UAWzColF,WAAY,SAASplF,qBACZA,QAAU,QACVklF,WAAWllF,SACThM,MAOXq2F,WAAY,kBACD/iF,KAAKlJ,QAAQpK,KAAKgM,SAAWhM,KAAKgM,QAAU,IASvD+0H,mBAAoB,SAAS1yH,QACrB7U,IACO,KAAP6U,IAAaiF,KAAKzU,OAAOmB,KAAK0J,QAAQ2E,OACtC7U,IAAMwG,KAAK0J,QAAQ2E,IAAIiiC,WAClBziC,OAAOrU,IAAI2D,IAAM,CAAC6Q,UAAWxU,IAAIqU,OAAOG,UAAU3U,MAAM,MAUrEmhC,OAAQ,eACA+1C,KAAMliE,GAAI2yH,aAAcC,KAAM5gI,EAAG0zC,GAAIC,GAAIxI,MAAOtyB,EAAGwf,OAAQl/B,IAAM,SAEhEwG,KAAKivF,mBACCjvF,QAIS,aADpBuwE,KAAOvwE,KAAKkhI,0BACHtsE,mBACAmsE,mBAAmBxwD,KAAKpzE,IACtB6C,QAGXxG,IAAMwG,KAAK0J,QAAQ6mE,KAAKpzE,IAAImzC,MAGR,gBAAhBigC,KAAK3b,OACL17C,EAAI,CACA1f,IAAIqU,OAAOG,UAAU,GAAKhO,KAAK6N,OAAO0iE,KAAKpzE,IAAI6Q,UAAU,GACzDxU,IAAIqU,OAAOG,UAAU,GAAKhO,KAAK6N,OAAO0iE,KAAKpzE,IAAI6Q,UAAU,SAG1D,GAAoB,aAAhBuiE,KAAK3b,QAAyC,YAAhB2b,KAAK3b,OAAsB,IAE5DosE,aADgB,aAAhBzwD,KAAK3b,OACU,iBAEA,cAGfthD,KAAK9I,QAAQxK,KAAKghI,eAClBtoG,OAAS14B,KAAKghI,cAAcnzH,OAAOG,UAAU3U,MAAM,QAChD,GAA2B,aAAvB2G,KAAKghI,cACZtoG,OAAS14B,KAAKmhI,+BACX,GAAI7tH,KAAKlJ,QAAQpK,KAAKghI,eACzBtoG,OAAS14B,KAAKghI,kBACX,CAAA,IAAI1tH,KAAKnJ,WAAWnK,KAAKghI,sBAGrBhhI,KAFP04B,OAAS14B,KAAKghI,mBAKE,aAAhBzwD,KAAK3b,OACLppB,MAAQ2D,SAASI,IAAIvvC,KAAK6N,OAAO0iE,KAAKpzE,IAAI6Q,UAAU3U,MAAM,GAAIq/B,OAAQ14B,KAAK0J,QAAQ6mE,KAAKpzE,IAAImzC,QAC5Fp3B,EAAIlZ,KAAKI,MAAMwM,OAAO,YAAa,CAAC4+B,MAAO9S,OAAO,GAAIA,OAAO,IAAK,CAAC7tB,KAAM,YACvE2vB,aACC,CAAA,GAAoB,YAAhB+1C,KAAK3b,cAgBL50D,QAfPK,EAAI8uC,SAAShqB,SAASnlB,KAAK6N,OAAO0iE,KAAKpzE,IAAI6Q,UAAU3U,MAAM,GAAIq/B,QAC3DhsB,KAAKwC,IAAI7O,GAAK6jB,IAAIzF,WACXze,KAEXK,EAAI8uC,SAAShqB,SAAS3rB,IAAIqU,OAAOG,UAAU3U,MAAM,GAAIq/B,QAAUr4B,EAC/D0zC,GAAM/zC,KAAKygI,gBAAgBlwD,KAAKpzE,IAAIf,QAAQ,MAAQ,EAAKiE,EAAI,EAC7D2zC,GAAMh0C,KAAKygI,gBAAgBlwD,KAAKpzE,IAAIf,QAAQ,MAAQ,EAAKiE,EAAI,GAG7D6Y,EAAIlZ,KAAKI,MAAMwM,OAAO,YACd,CAAC,EAAG,EAAG,EACN8rB,OAAO,IAAM,EAAKqb,IAAKA,GAAI,EAC3Brb,OAAO,IAAM,EAAKsb,IAAK,EAAGA,IAAK,CAACnpC,KAAM,aAC7C2vB,cAYLnsB,WANA+yH,6BAA6B7wD,KAAMr3D,QAEnC+1E,aAAc,EAIRjvF,KAAK0J,WACR1J,KAAK0J,QAAQvQ,eAAekV,QACvB4yH,QAAQjhI,KAAK0J,QAAQ2E,IAAIohF,YACtBzvF,KAAK0J,QAAQ2E,IAAIohF,YAAYt2F,eAAe8nI,aACvCv3H,QAAQ2E,IAAIohF,YAAYR,YAAcjvF,KAAK0J,QAAQ2E,IAAIohF,YAAYtc,oBAAsBnzE,KAAKI,MAAM41G,qBASpH3nG,WAJAjO,MAAMwkH,eAAer0C,MAIfvwE,KAAK0J,QACR1J,KAAK0J,QAAQvQ,eAAekV,UACvB0yH,mBAAmB1yH,WAIzBrO,MAQXkhI,uBAAwB,eAChB7yH,GAAI7U,IAGJ6nI,UAFAzsE,OAAS,UACT0sE,QAAU,OAMTjzH,MAAMrO,KAAK0J,QACR1J,KAAK0J,QAAQvQ,eAAekV,MAC5B7U,IAAMwG,KAAK0J,QAAQ2E,IAAIiiC,OAEfziC,OAAOsX,SAAS3b,MAAM1H,eAAgB9B,KAAK6N,OAAOQ,KAAO6V,IAAIzF,KACjE6iH,QAAQ5lI,KAAKlC,IAAI2D,WAMN,IAAnBmkI,QAAQzmI,OACD,QACO+5D,UACJ,WACK0sE,UAInBD,UAAYC,QAAQ,GACpB9nI,IAAMwG,KAAK0J,QAAQ23H,WAAW/wF,MAE1BgxF,QAAQzmI,OAAS,EACjB+5D,OAAS,cAELthD,KAAK3F,UAAU3N,KAAKsgI,eAAgB9mI,MAAQ8Z,KAAKzU,OAAOmB,KAAKogI,gBAC7DxrE,OAAS,WACFthD,KAAK3F,UAAU3N,KAAKwgI,YAAahnI,MAAQ8Z,KAAKzU,OAAOmB,KAAKqgI,aACjEzrE,OAAS,UACFthD,KAAK3F,UAAU3N,KAAKugI,kBAAmB/mI,OAC9Co7D,OAAS,eAIV,QACOA,UACJysE,kBACKC,WASnBH,wBAAyB,eACjBzoG,OAAQtsB,IAAKiC,OAIZA,MAFLqqB,OAAS,CAAC,EAAG,GACbtsB,IAAM,EACKpM,KAAK6N,OACR7N,KAAK6N,OAAO1U,eAAekV,MAC3BqqB,OAAO,IAAM14B,KAAK6N,OAAOQ,IAAIL,UAAU,GACvC0qB,OAAO,IAAM14B,KAAK6N,OAAOQ,IAAIL,UAAU,KACrC5B,YAGNA,IAAM,IACNssB,OAAO,IAAMtsB,IACbssB,OAAO,IAAMtsB,KAGVssB,QAOX0oG,6BAA8B,SAAU7wD,KAAMr3D,OACtC7K,GAAI7U,QAEH6U,MAAMrO,KAAK0J,QACR1J,KAAK0J,QAAQvQ,eAAekV,MACxBiF,KAAKzU,OAAOmB,KAAKI,MAAMsJ,QAAQ2E,MAC/B7U,IAAMwG,KAAK0J,QAAQ2E,IAAIiiC,OAOfnzC,KAAOozE,KAAKpzE,GACI,gBAAhBozE,KAAK3b,OACAthD,KAAK3F,UAAU4iE,KAAK+wD,QAAS9nI,IAAI2D,KAClC3D,IAAIqU,OAAO2W,eAAehb,MAAM1H,eAC5B,CAAC9B,KAAK6N,OAAOQ,IAAIL,UAAU,GAAKkL,EAAE,GACjClZ,KAAK6N,OAAOQ,IAAIL,UAAU,GAAKkL,EAAE,KAEnB,aAAhBq3D,KAAK3b,QAAyC,YAAhB2b,KAAK3b,QAC1C17C,EAAEw4E,UAAU,CAACl4F,MAGG,aAAhB+2E,KAAK3b,QAAyC,YAAhB2b,KAAK3b,QACnCp7D,IAAIqU,OAAO2W,eAAehb,MAAM1H,eAC5BoiB,IAAI3E,WAAWrG,EAAE8F,OAAQhf,KAAK6N,OAAOrU,IAAI2D,IAAI6Q,mBAIlDhO,KAAK0J,QAAQ2E,MAWpCqyH,SAAU,SAAUpiI,oBACXoL,QAAQpL,OAAOnB,IAAM,CAACmzC,MAAOtwC,KAAKI,MAAMG,OAAOjC,cAC/CyiI,mBAAmBziI,OAAOnB,SAE1BojI,kBAAkB7kI,KAAK4C,QAE5BA,OAAOwL,OAAOpO,KAAKsE,KAAK7C,IACxBmB,OAAOwL,OAASwJ,KAAK7F,YAAYnP,OAAOwL,QAEjC9J,MAQX4gI,UAAW,SAAUl3H,aACb3M,MAECA,EAAI,EAAGA,EAAI2M,QAAQ7O,OAAQkC,SACvB2jI,SAASh3H,QAAQ3M,WAGnBiD,MAQX6gI,SAAU,SAAUh7E,WACZx3C,OAECA,MAAMw3C,MAAMn8C,QACTm8C,MAAMn8C,QAAQvQ,eAAekV,UACxBqyH,SAAS76E,MAAMn8C,QAAQ2E,IAAIiiC,cAIjCtwC,MAQX8gI,YAAa,SAAUxwF,qBACZtwC,KAAK0J,QAAQ4mC,MAAMnzC,IAEnB6C,MAUXuhI,kBAAmB,SAAUjjI,oBACpB8hI,eAAiB9hI,OAEf0B,MASXwhI,kBAAmB,SAAU93H,gBAClB1J,KAAKyhI,iBAAiB,WAAY/3H,UAS7Cg4H,iBAAkB,SAAUpxF,cACjBtwC,KAAK2hI,gBAAgB,WAAYrxF,QAQ5CsxF,oBAAqB,SAAUtxF,cACpBtwC,KAAK6hI,mBAAmB,WAAYvxF,QAU/CwxF,qBAAsB,SAAUp4H,gBACrB1J,KAAKyhI,iBAAiB,cAAe/3H,UAShDq4H,oBAAqB,SAAUzxF,cACpBtwC,KAAK2hI,gBAAgB,cAAerxF,QAQ/C0xF,uBAAwB,SAAU1xF,cACvBtwC,KAAK6hI,mBAAmB,cAAevxF,QASlD2xF,eAAgB,SAAU3jI,oBACjB+hI,YAAc/hI,OAEZ0B,MAWXkiI,eAAgB,SAAUx4H,QAAS+kD,eAC3B0zE,KAAM7nI,EAAG8R,QAObA,KALI+1H,KADA7uH,KAAKlJ,QAAQV,SACNA,QAEAjO,WAGAZ,OACNP,EAAI,EAAGA,EAAI8R,MAAO9R,OACdmmI,gBAAgBzgI,KAAKI,MAAMG,OAAO4hI,KAAK7nI,IAAI6C,IAAMsxD,WAAa,YAGhEzuD,KAAKyhI,iBAAiB,QAAS/3H,UAS1C04H,cAAe,SAAU9xF,MAAOme,uBACvBkzE,gBAAgB,QAASrxF,YACzBmwF,gBAAgBzgI,KAAKI,MAAMG,OAAO+vC,OAAOnzC,IAAMsxD,WAAa,KAE1DzuD,MAQXqiI,iBAAkB,SAAU/xF,cACjBtwC,KAAK6hI,mBAAmB,QAASvxF,QAO5CmxF,iBAAkB,SAAU7sE,OAAQlrD,aAC5By4H,KAAM7nI,EAAG8R,QAObA,KALI+1H,KADA7uH,KAAKlJ,QAAQV,SACNA,QAEAjO,WAGAZ,YACN+5D,OAAS,UAAY,GACrBt6D,EAAI,EAAGA,EAAI8R,MAAO9R,OACdqnI,gBAAgB/sE,OAAQutE,KAAK7nI,WAG/B0F,MAOX2hI,gBAAiB,SAAU/sE,OAAQtkB,mBAC1BskB,OAAS,UAAUl5D,KAAKsE,KAAKI,MAAMG,OAAO+vC,QAExCtwC,MAOX6hI,mBAAoB,SAAUjtE,OAAQtkB,WAC9B9J,IAAMxmC,KAAK40D,OAAS,UAAUx4D,QAAQ4D,KAAKI,MAAMG,OAAO+vC,eACxD9J,KAAO,QACFouB,OAAS,UAAUz5D,OAAOqrC,IAAK,GAGjCxmC,MAOXowF,YAAa,WACThyF,IAAIkC,WAAW,oBAAqB,6BAC/B4kF,aAAavpF,MAAMqE,KAAMvE,YAGlCypF,aAAc,eACN72E,OAECA,MAAMrO,KAAK0J,QACR1J,KAAK0J,QAAQvQ,eAAekV,UACvB3E,QAAQ2E,IAAIiiC,MAAM40C,aAAavpF,MAAMqE,KAAK0J,QAAQ2E,IAAIiiC,MAAO70C,kBAInEuE,QA+Of5B,IAAIkkI,YAAc,SAAUliI,MAAO4L,QAASC,gBACpCI,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,SACtD2V,EAAI,IAAIhkB,IAAI6hI,MAAM7/H,MAAOiM,KAAKlP,GAAIkP,KAAKzS,KAAMoS,QAASK,aAE1D+V,EAAEstE,OAAS,QACXttE,EAAEgvE,WAAWplF,SAENoW,GAGXhkB,IAAIsB,gBAAgB,QAAStB,IAAIkkI,aAE1B,CACHrC,MAAO7hI,IAAI6hI,MACXqC,YAAalkI,IAAIkkI,gBAuDzBlqI,OAAO,gBAAgB,CACnB,MAAO,iBAAkB,cAAe,YAAa,gBAAiB,gBAAiB,eACxF,SAAUgG,IAAKoL,MAAO2a,OAAQD,IAAKiR,SAAUga,SAAU77B,aAoEtDlV,IAAImkI,cAAgB,SAAUniI,MAAO4L,QAASC,gBACtCu2H,UAAWnpF,MAAOt5B,EAAGsvB,EAAGozF,UAAWnoI,EACnCooI,YAEA9kG,EAAI,GACJ+kG,UAAYrvH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,QAAS,QACpEm2H,YAActvH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,QAAS,UACtEo2H,WAAavvH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,aAG3DnS,EAAI,EAAGA,EAAI,EAAGA,OAEX0R,QAAQ1R,GAAGO,OAAS,EACpB+iC,EAAEtjC,GAAK8F,MAAMwM,OAAO,QAASZ,QAAQ1R,GAAIqoI,gBAEtC,GAAIrvH,KAAK9I,QAAQwB,QAAQ1R,IAC5BsjC,EAAEtjC,GAAK8F,MAAMG,OAAOyL,QAAQ1R,SAEzB,GAAIgZ,KAAKnJ,WAAW6B,QAAQ1R,KAAOgZ,KAAK9I,QAAQwB,QAAQ1R,MAC3DsjC,EAAEtjC,GAAK0R,QAAQ1R,SAEZ,CAAA,IAAIgZ,KAAKvJ,SAASiC,QAAQ1R,UAGvB,IAAI0B,MAAM,6DACJgQ,QAAQ,IAAM,kBAAoBA,QAAQ,IADtC,iFAFhB4xB,EAAEtjC,GAAK8F,MAAMG,OAAOyL,QAAQ1R,OAShCgZ,KAAKrJ,SAAS+B,QAAQ,IACtBy2H,UAAYnvH,KAAK/H,eAAeS,QAAQ,GAAI5L,YACzC,GAAIkT,KAAKnJ,WAAW6B,QAAQ,KAAOsH,KAAKrJ,SAAS+B,QAAQ,MAC5Dy2H,UAAYz2H,QAAQ,OACjB,IAECsH,KAAK9I,QAAQwB,QAAQ,IACrBqjC,EAAIjvC,MAAMG,OAAOyL,QAAQ,SAEtB,GAAIA,QAAQ,GAAGnR,OAAS,EAC3Bw0C,EAAIjvC,MAAMwM,OAAO,QAASZ,QAAQ,GAAI22H,gBAEnC,GAAIrvH,KAAKnJ,WAAW6B,QAAQ,KAAOsH,KAAK9I,QAAQwB,QAAQ,MAC3DqjC,EAAIrjC,QAAQ,SAET,CAAA,IAAIsH,KAAKvJ,SAASiC,QAAQ,UAGvB,IAAIhQ,MAAM,6DACJgQ,QAAQ,IAAM,kBAAoBA,QAAQ,IAAM,kBAAoBA,QAAQ,IADxE,iFAFhBqjC,EAAIjvC,MAAMG,OAAOyL,QAAQ,IAO7By2H,UAAY,kBACDpzF,EAAEvO,KAAKlD,EAAE,IAAMyR,EAAEvO,KAAKlD,EAAE,SAKlCtqB,KAAKzU,OAAOmN,QAAQ,MACrBA,QAAQ,GAAK,EAAIU,KAAKiV,IAIrBrO,KAAKzU,OAAOmN,QAAQ,MACrBA,QAAQ,GAAK,GAGjB+T,EAAI3f,MAAMwM,OAAO,QAAS,CACtB,iBACmC,IAAvBgxB,EAAE,GAAGQ,IAAMR,EAAE,GAAGQ,MAE5B,iBACmC,IAAvBR,EAAE,GAAGS,IAAMT,EAAE,GAAGS,OAE7BukG,cAEHvpF,MAAQj5C,MAAMwM,OAAO,QAAS,CAC1B,SAAUkB,UACC,GAEX,SAAUA,UACC,GAEX9B,QAAQ,GACRA,QAAQ,IAAK62H,aAEXJ,UAAYA,UAGlBC,YAAcrpF,MAAM27B,SAGpBwtD,UAAY,SAAUz5F,IAAK8U,mBACnBruC,EAAGs+C,GAAIte,GAAIC,GAAIC,GAAIC,GAAImzF,KAAMC,KAAMnmI,EAElCihD,gBAEDiQ,IADAt+C,EAAIizH,aACKjzH,EACTggC,GAAK5R,EAAE,GAAGQ,IACVqR,GAAK7R,EAAE,GAAGS,IAGVykG,KAAOtzF,IAFPE,GAAK9R,EAAE,GAAGQ,KAGV2kG,KAAOtzF,IAFPE,GAAK/R,EAAE,GAAGS,KAGVzhC,GAAKkxD,GAAKte,GAAKA,GAAKC,GAAKA,GAAKC,GAAKA,GAAKC,GAAKA,KAAO,EAAIngC,GAExD6pC,MAAMo3C,cAAgB,CAClB,CAAC7zF,EAAIA,EAAI8yC,GAAKA,GAAKC,GAAKA,GAAI/yC,EAAIkmI,KAAOtzH,EAAIkgC,GAAS9yC,EAAImmI,KAAOvzH,EAAImgC,IACnE,CAAC/yC,EAAIkmI,KAAOtzH,EAAIkgC,GAAaozF,KAAOA,KAAQh1E,GAAK,EAAGg1E,KAAOC,KAAOj1E,IAClE,CAAClxD,EAAImmI,KAAOvzH,EAAImgC,GAAYmzF,KAAOC,KAAOj1E,GAAWi1E,KAAOA,KAAQj1E,GAAK,MAMrFzU,MAAMjb,EAAI,SAAU2K,IAAK8U,mBACjBruC,EAAIizH,YACJ7yH,EAAIguB,EAAE,GAAGkD,KAAKlD,EAAE,IAChBl9B,EAAI,IAAOkP,EAAIA,EAAIJ,EAAIA,IAAMI,EAAIlD,KAAK8hB,IAAIua,KAAOv5B,GACjD0jB,KAAOxmB,KAAKypB,MAAMyH,EAAE,GAAGS,IAAMT,EAAE,GAAGS,IAAKT,EAAE,GAAGQ,IAAMR,EAAE,GAAGQ,YAEtDyf,eACD2kF,UAAUz5F,EAAK8U,eAGZjgB,EAAE,GAAGQ,IAAM1xB,KAAK8hB,IAAI0E,KAAO6V,KAAOroC,GAI7C24C,MAAMhb,EAAI,SAAU0K,IAAK8U,mBACjBruC,EAAIizH,YACJ7yH,EAAIguB,EAAE,GAAGkD,KAAKlD,EAAE,IAChBl9B,EAAI,IAAOkP,EAAIA,EAAIJ,EAAIA,IAAMI,EAAIlD,KAAK8hB,IAAIua,KAAOv5B,GACjD0jB,KAAOxmB,KAAKypB,MAAMyH,EAAE,GAAGS,IAAMT,EAAE,GAAGS,IAAKT,EAAE,GAAGQ,IAAMR,EAAE,GAAGQ,YAEpDR,EAAE,GAAGS,IAAM3xB,KAAKwiB,IAAIgE,KAAO6V,KAAOroC,GAG7C24C,MAAM2pF,SAAW3pF,MAAM3gB,OAAS3Y,EAChCs5B,MAAMxuC,KAAOrB,MAAMlH,kBACnB+2C,MAAMu2C,KAAO,CACLl3D,OAAQ2gB,MAAM3gB,QAEtB2gB,MAAMw2C,SAASn0F,KAAK29C,MAAM3gB,OAAQkF,EAAE,GAAIA,EAAE,IACtCtqB,KAAK9I,QAAQ6kC,IACbgK,MAAMw2C,SAASn0F,KAAK2zC,GAWxBgK,MAAM27B,SAAY,SAAUlnE,EAAGiT,OACvBkiH,GAAI38B,GAAI92F,EAAGzS,SAEXuW,KAAKrG,SAASjN,KAAK+S,QAAQ6pH,iBAC3BqG,GAAKrlG,EAAE,GAAG/vB,OACVy4F,GAAK1oE,EAAE,GAAG/vB,OACV2B,EAAIxP,KAAKyiI,aACT1lI,EAAI,IAAIonB,OAAO3a,MAAMzH,iBAAkB,CAAC+L,EAAGiT,GAAI/gB,KAAKI,QAC3C+kB,SAAS3b,MAAM1H,eAAgBmhI,IAAMlmI,EAAEooB,SAAS3b,MAAM1H,eAAgBwkG,KAE/D92F,GAGbkzH,YAAY/mI,MAAMqE,KAAMvE,YAGnCskB,EAAE8uE,SAASx1C,OACN/+C,EAAI,EAAGA,EAAI,EAAGA,IACXgZ,KAAK9I,QAAQozB,EAAEtjC,KACfsjC,EAAEtjC,GAAGu0F,SAASx1C,cAGlB/lC,KAAK9I,QAAQ6kC,IACbA,EAAEw/C,SAASx1C,OAEfA,MAAM+3C,WAAWplF,SAEVqtC,OAoCXj7C,IAAI8kI,gBAAkB,SAAU9iI,MAAO4L,QAASC,gBACxCu2H,UAAWnpF,MAAOt5B,EAAGsvB,EAAGozF,UAAWnoI,EAEnCsjC,EAAI,GACJ+kG,UAAYrvH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,QAAS,QACpEm2H,YAActvH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,QAAS,UACtEo2H,WAAavvH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,aAG3DnS,EAAI,EAAGA,EAAI,EAAGA,OAEX0R,QAAQ1R,GAAGO,OAAS,EACpB+iC,EAAEtjC,GAAK8F,MAAMwM,OAAO,QAASZ,QAAQ1R,GAAIqoI,gBAEtC,GAAIrvH,KAAK9I,QAAQwB,QAAQ1R,IAC5BsjC,EAAEtjC,GAAK8F,MAAMG,OAAOyL,QAAQ1R,SAEzB,GAAIgZ,KAAKnJ,WAAW6B,QAAQ1R,KAAOgZ,KAAK9I,QAAQwB,QAAQ1R,MAC3DsjC,EAAEtjC,GAAK0R,QAAQ1R,SAEZ,CAAA,IAAIgZ,KAAKvJ,SAASiC,QAAQ1R,UAGvB,IAAI0B,MAAM,+DACJgQ,QAAQ,IAAM,kBAAoBA,QAAQ,IADtC,iFAFhB4xB,EAAEtjC,GAAK8F,MAAMG,OAAOyL,QAAQ1R,OAShCgZ,KAAKrJ,SAAS+B,QAAQ,IACtBy2H,UAAYnvH,KAAK/H,eAAeS,QAAQ,GAAI5L,YACzC,GAAIkT,KAAKnJ,WAAW6B,QAAQ,KAAOsH,KAAKrJ,SAAS+B,QAAQ,MAC5Dy2H,UAAYz2H,QAAQ,OACjB,IAECsH,KAAK9I,QAAQwB,QAAQ,IACrBqjC,EAAIjvC,MAAMG,OAAOyL,QAAQ,SAEtB,GAAIA,QAAQ,GAAGnR,OAAS,EAC3Bw0C,EAAIjvC,MAAMwM,OAAO,QAASZ,QAAQ,GAAI22H,gBAEnC,GAAIrvH,KAAKnJ,WAAW6B,QAAQ,KAAOsH,KAAK9I,QAAQwB,QAAQ,MAC3DqjC,EAAIrjC,QAAQ,SAET,CAAA,IAAIsH,KAAKvJ,SAASiC,QAAQ,UAGvB,IAAIhQ,MAAM,+DACJgQ,QAAQ,IAAM,kBAAoBA,QAAQ,IAAM,kBAAoBA,QAAQ,IADxE,iFAFhBqjC,EAAIjvC,MAAMG,OAAOyL,QAAQ,IAO7By2H,UAAY,kBACDpzF,EAAEvO,KAAKlD,EAAE,IAAMyR,EAAEvO,KAAKlD,EAAE,SAKlCtqB,KAAKzU,OAAOmN,QAAQ,MACrBA,QAAQ,GAAK,OAASU,KAAKiV,IAI1BrO,KAAKzU,OAAOmN,QAAQ,MACrBA,QAAQ,IAAM,OAASU,KAAKiV,IAGhC5B,EAAI3f,MAAMwM,OAAO,QAAS,CACtB,iBACmC,IAAvBgxB,EAAE,GAAGQ,IAAMR,EAAE,GAAGQ,MAE5B,iBACmC,IAAvBR,EAAE,GAAGS,IAAMT,EAAE,GAAGS,OAE7BukG,cAEHvpF,MAAQj5C,MAAMwM,OAAO,QAAS,CAC1B,SAAUkB,UACC,GAEX,SAAUA,UACC,GACR9B,QAAQ,GAAIA,QAAQ,IAAK62H,aAE1BJ,UAAYA,UAIlBD,UAAY,SAAUz5F,IAAK8U,mBACnBruC,EAAGs+C,GAAIte,GAAIC,GAAIC,GAAIC,GAAImzF,KAAMC,KAAMnmI,EAElCihD,gBAEDiQ,IADAt+C,EAAIizH,aACKjzH,EACTggC,GAAK5R,EAAE,GAAGQ,IACVqR,GAAK7R,EAAE,GAAGS,IAGVykG,KAAOtzF,IAFPE,GAAK9R,EAAE,GAAGQ,KAGV2kG,KAAOtzF,IAFPE,GAAK/R,EAAE,GAAGS,KAGVzhC,GAAKkxD,GAAKte,GAAKA,GAAKC,GAAKA,GAAKC,GAAKA,GAAKC,GAAKA,KAAO,EAAIngC,GAExD6pC,MAAMo3C,cAAgB,CAClB,CAAC7zF,EAAIA,EAAI8yC,GAAKA,GAAKC,GAAKA,GAAI/yC,EAAIkmI,KAAOtzH,EAAIkgC,GAAS9yC,EAAImmI,KAAOvzH,EAAImgC,IACnE,CAAC/yC,EAAIkmI,KAAOtzH,EAAIkgC,GAAaozF,KAAOA,KAAQh1E,GAAK,EAAGg1E,KAAOC,KAAOj1E,IAClE,CAAClxD,EAAImmI,KAAOvzH,EAAImgC,GAAYmzF,KAAOC,KAAOj1E,GAAWi1E,KAAOA,KAAQj1E,GAAK,MAMrFzU,MAAMjb,EAAI,SAAU2K,IAAK8U,mBACjBruC,EAAIizH,YACJ7yH,EAAIguB,EAAE,GAAGkD,KAAKlD,EAAE,IAChBl9B,EAAI,IAAOkP,EAAIA,EAAIJ,EAAIA,IAAMI,EAAIlD,KAAK8hB,IAAIua,KAAOv5B,GACjD0jB,KAAOxmB,KAAKypB,MAAMyH,EAAE,GAAGS,IAAMT,EAAE,GAAGS,IAAKT,EAAE,GAAGQ,IAAMR,EAAE,GAAGQ,YAEtDyf,eACD2kF,UAAUz5F,EAAK8U,eAGZjgB,EAAE,GAAGQ,IAAM1xB,KAAK8hB,IAAI0E,KAAO6V,KAAOroC,GAI7C24C,MAAMhb,EAAI,SAAU0K,IAAK8U,mBACjBruC,EAAIizH,YACJ7yH,EAAIguB,EAAE,GAAGkD,KAAKlD,EAAE,IAChBl9B,EAAI,IAAOkP,EAAIA,EAAIJ,EAAIA,IAAMI,EAAIlD,KAAK8hB,IAAIua,KAAOv5B,GACjD0jB,KAAOxmB,KAAKypB,MAAMyH,EAAE,GAAGS,IAAMT,EAAE,GAAGS,IAAKT,EAAE,GAAGQ,IAAMR,EAAE,GAAGQ,YAEpDR,EAAE,GAAGS,IAAM3xB,KAAKwiB,IAAIgE,KAAO6V,KAAOroC,GAG7C24C,MAAM2pF,SAAW3pF,MAAM3gB,OAAS3Y,EAChCs5B,MAAMu2C,KAAO,CACTl3D,OAAQ2gB,MAAM3gB,QAElB2gB,MAAMw2C,SAASn0F,KAAK29C,MAAM3gB,OAAQkF,EAAE,GAAIA,EAAE,IACtCtqB,KAAK9I,QAAQ6kC,IACbgK,MAAMw2C,SAASn0F,KAAK2zC,GAExBgK,MAAMxuC,KAAOrB,MAAMlH,kBAEnByd,EAAE8uE,SAASx1C,OACN/+C,EAAI,EAAGA,EAAI,EAAGA,IACXgZ,KAAK9I,QAAQozB,EAAEtjC,KACfsjC,EAAEtjC,GAAGu0F,SAASx1C,cAGlB/lC,KAAK9I,QAAQ6kC,IACbA,EAAEw/C,SAASx1C,OAEfA,MAAM+3C,WAAWplF,SAEVqtC,OAgDXj7C,IAAI+kI,eAAiB,SAAU/iI,MAAO4L,QAASC,gBACvCu2H,UAAWnpF,MAAOt5B,EAQlBqjH,UANAC,GAAKr3H,QAAQ,GAEb8G,EAAI9G,QAAQ,GACZ22H,UAAYrvH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,QAAS,QACpEm2H,YAActvH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,QAAS,UACtEo2H,WAAavvH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,YAI5DT,QAAQ,GAAGnR,OAAS,EACpBwoI,GAAKjjI,MAAMwM,OAAO,QAASZ,QAAQ,GAAI22H,gBAEpC,GAAIrvH,KAAK9I,QAAQwB,QAAQ,IAC5Bq3H,GAAKjjI,MAAMG,OAAOyL,QAAQ,SAEvB,GAAIsH,KAAKnJ,WAAW6B,QAAQ,KAAOsH,KAAK9I,QAAQwB,QAAQ,MAC3Dq3H,GAAKr3H,QAAQ,SAEV,CAAA,IAAIsH,KAAKvJ,SAASiC,QAAQ,UAGvB,IAAIhQ,MAAM,8DACJgQ,QAAQ,IAAM,kBAAoBA,QAAQ,IADtC,2CAFhBq3H,GAAKjjI,MAAMG,OAAOyL,QAAQ,WAQ1BsH,KAAKlJ,QAAQ0I,IAAmB,IAAbA,EAAEjY,SACrBuoI,UAAY9vH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,QAAS,QACpEqG,EAAI1S,MAAMwM,OAAO,OAAQkG,EAAGswH,YAI3B9vH,KAAKzU,OAAOmN,QAAQ,MACrBA,QAAQ,GAAK,EAAIU,KAAKiV,IAIrBrO,KAAKzU,OAAOmN,QAAQ,MACrBA,QAAQ,GAAK,GAGjB+T,EAAI3f,MAAMwM,OAAO,QAAS,CACtB,kBAMWuiC,SAASqE,mBAAmB6vF,GAAIvwH,EAAG1S,OAAO4N,YAEtD40H,cAGHvpF,MAAQj5C,MAAMwM,OAAO,QAAS,CAC1B,SAAUkB,UACC,GAEX,SAAUA,UACC,GACR9B,QAAQ,GAAIA,QAAQ,IAAK62H,aAE1BG,SAAW3pF,MAAM3gB,OAAS3Y,EAChCs5B,MAAMu2C,KAAO,CACTl3D,OAAQ2gB,MAAM3gB,QAElB2gB,MAAMw2C,SAASn0F,KAAK29C,MAAM3gB,QAG1B8pG,UAAY,SAAUtpH,EAAG2kC,mBACjBxwC,EAAG3M,EAAGkP,EAAGs5D,GAAIpP,GAAIC,GAEhBlc,gBACDxwC,EAAIyF,EAAE8Q,QAAQ,GACdljB,EAAIoS,EAAE8Q,QAAQ,GACdhU,EAAIkD,EAAE8Q,QAAQ,GACdslD,GAAK77D,EAAIA,EAAI3M,EAAIA,EACjBo5D,GAAKupE,GAAGjlG,IACR27B,GAAKspE,GAAGhlG,IAERgb,MAAMo3C,cAAgB,CAClB,CAAE7gF,EAAIA,EAAIs5D,IAAMpP,GAAKA,GAAKC,GAAKA,IAAMnqD,EAAIvC,EAAI67D,GAAKpP,GAAIlqD,EAAIlP,EAAIwoE,GAAKnP,IACnE,CAACnqD,EAAIvC,EAAI67D,GAAKpP,IAAsBp5D,EAAIA,EAAY2M,EAAI3M,GACxD,CAACkP,EAAIlP,EAAIwoE,GAAKnP,GAAqB1sD,EAAI3M,GAAc2M,EAAIA,MAMrEgsC,MAAMjb,EAAI,SAAU2K,IAAK8U,mBACjBxwC,EACA6lB,KAAOpgB,EAAEkrH,WACT7yH,EAAIgkC,SAASqO,cAAc6lF,GAAGx1H,OAAOG,UAAW8E,EAAE8Q,SAClDvD,EAAIvN,EAAE49B,OAAO7iC,OAAOG,UACpBwzB,EAAI1uB,EAAE89B,OAAO/iC,OAAOG,UACpB+R,EAAIsjH,GAAGx1H,OAAOG,iBAGL,IAATqS,EAAE,GACFA,EAAI,CAAC,EAAGmhB,EAAE,GAAK1uB,EAAE8Q,QAAQ,GAAI4d,EAAE,GAAK1uB,EAAE8Q,QAAQ,IAC9B,IAAT4d,EAAE,KACTA,EAAI,CAAC,EAAGnhB,EAAE,GAAKvN,EAAE8Q,QAAQ,GAAIvD,EAAE,GAAKvN,EAAE8Q,QAAQ,KAGlDvW,IADQm0B,EAAE,GAAKnhB,EAAE,KAAON,EAAE,GAAKM,EAAE,KAAOmhB,EAAE,GAAKnhB,EAAE,KAAON,EAAE,GAAKM,EAAE,KAAO,EAAK,GAAK,GACxElV,GAAK,EAAIuB,KAAKwiB,IAAI6Z,MAEvB8U,eACD2kF,UAAUz5F,EAAK8U,eAGZwlF,GAAGjlG,IAAM1xB,KAAK8hB,IAAIua,IAAM7V,MAAQ7lB,GAI3CgsC,MAAMhb,EAAI,SAAU0K,IAAK8U,mBACjBxwC,EACA6lB,KAAOpgB,EAAEkrH,WACT7yH,EAAIgkC,SAASqO,cAAc6lF,GAAGx1H,OAAOG,UAAW8E,EAAE8Q,SAClDvD,EAAIvN,EAAE49B,OAAO7iC,OAAOG,UACpBwzB,EAAI1uB,EAAE89B,OAAO/iC,OAAOG,UACpB+R,EAAIsjH,GAAGx1H,OAAOG,iBAGL,IAATqS,EAAE,GACFA,EAAI,CAAC,EAAGmhB,EAAE,GAAK1uB,EAAE8Q,QAAQ,GAAI4d,EAAE,GAAK1uB,EAAE8Q,QAAQ,IAC9B,IAAT4d,EAAE,KACTA,EAAI,CAAC,EAAGnhB,EAAE,GAAKvN,EAAE8Q,QAAQ,GAAIvD,EAAE,GAAKvN,EAAE8Q,QAAQ,KAGlDvW,IADQm0B,EAAE,GAAKnhB,EAAE,KAAON,EAAE,GAAKM,EAAE,KAAOmhB,EAAE,GAAKnhB,EAAE,KAAON,EAAE,GAAKM,EAAE,KAAO,EAAK,GAAK,GACxElV,GAAK,EAAIuB,KAAKwiB,IAAI6Z,MAErBs6F,GAAGhlG,IAAM3xB,KAAKwiB,IAAI6Z,IAAM7V,MAAQ7lB,GAG3CgsC,MAAMxuC,KAAOrB,MAAMlH,kBACnByd,EAAE8uE,SAASx1C,OAEP/lC,KAAK9I,QAAQ64H,MACbA,GAAGx0C,SAASx1C,OACZA,MAAMw2C,SAASn0F,KAAK2nI,KAGxBvwH,EAAE+7E,SAASx1C,OACXA,MAAM+3C,WAAWplF,SAEVqtC,OA0DXj7C,IAAIklI,YAAc,SAAUljI,MAAO4L,QAASC,gBACpCu2H,UAAWnpF,MAAOkqF,SAAUC,SAAUC,IACtCC,MAAOr2H,EAAG3M,EAAGkP,EAAG6Q,GAAIC,GACpBpmB,EAAGqpI,YAAaC,cAChBC,eAAiB,CACb,CAAC,EAAG,EAAG,GACP,CAAC,EAAG,EAAG,GACP,CAAC,EAAG,EAAG,IAEX9jH,EAAI,CACA,CAAC,EAAG,EAAG,GACP,CAAC,EAAG,EAAG,GACP,CAAC,EAAG,EAAG,IAEXxT,OAAS,GACTxP,EAAI,GACJ+mI,WAAaxwH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,QAAS,SACrEm2H,YAActvH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,QAAS,UACtEo2H,WAAavvH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,YAEzC,IAAnBT,QAAQnR,OACR+oI,eAAgB,MACb,CAAA,GAAuB,IAAnB53H,QAAQnR,aAGT,IAAImB,MAAM,6CAA+CgQ,QAAQnR,OAAS,gBAFhF+oI,eAAgB,KAKhBA,kBACKtpI,EAAI,EAAGA,EAAI,EAAGA,OAEX0R,QAAQ1R,GAAGO,OAAS,EACpB0R,OAAOjS,GAAK8F,MAAMwM,OAAO,QAASZ,QAAQ1R,GAAIwpI,iBAE3C,GAAIxwH,KAAK9I,QAAQwB,QAAQ1R,IAC5BiS,OAAOjS,GAAK8F,MAAMG,OAAOyL,QAAQ1R,SAE9B,GAAIgZ,KAAKnJ,WAAW6B,QAAQ1R,KAAOgZ,KAAK9I,QAAQwB,QAAQ1R,MAC3DiS,OAAOjS,GAAK0R,QAAQ1R,SAEjB,CAAA,IAAIgZ,KAAKvJ,SAASiC,QAAQ1R,UAGvB,IAAI0B,MAAM,mEAAqEgQ,QAAQ1R,IAA7E,yFAFhBiS,OAAOjS,GAAK8F,MAAMG,OAAOyL,QAAQ1R,SAgBzCqpI,YAAc,CACV,CAAC,EAAG,EAAG,GACP,CAAC,EAAG,EAAG,GACP,CAAC,EAAG,EAAG,KAEC,GAAG,GAAMrwH,KAAKnJ,WAAW6B,QAAQ,IAAO,kBAAqBA,QAAQ,MAAU,kBAAqBA,QAAQ,IACxH23H,YAAY,GAAG,GAAMrwH,KAAKnJ,WAAW6B,QAAQ,IAAO,kBAAqBA,QAAQ,MAAU,kBAAqBA,QAAQ,IACxH23H,YAAY,GAAG,GAAMrwH,KAAKnJ,WAAW6B,QAAQ,IAAO,kBAAqBA,QAAQ,MAAU,kBAAqBA,QAAQ,IACxH23H,YAAY,GAAG,GAAMrwH,KAAKnJ,WAAW6B,QAAQ,IAAO,kBAAqBA,QAAQ,MAAU,kBAAqBA,QAAQ,IACxH23H,YAAY,GAAG,GAAMrwH,KAAKnJ,WAAW6B,QAAQ,IAAO,kBAAqBA,QAAQ,MAAU,kBAAqBA,QAAQ,IACxH23H,YAAY,GAAG,GAAMrwH,KAAKnJ,WAAW6B,QAAQ,IAAO,kBAAqBA,QAAQ,MAAU,kBAAqBA,QAAQ,OAI5Hy3H,IAAM,SAAUpjH,OACR/lB,EAAGC,MACFD,EAAI,EAAGA,EAAI,EAAGA,QACVC,EAAID,EAAGC,EAAI,EAAGA,IACf8lB,EAAE/lB,GAAGC,IAAM8lB,EAAE9lB,GAAGD,OAGnBA,EAAI,EAAGA,EAAI,EAAGA,QACVC,EAAI,EAAGA,EAAID,EAAGC,IACf8lB,EAAE/lB,GAAGC,GAAK8lB,EAAE9lB,GAAGD,UAGhB+lB,GAIXmjH,SAAW,SAAUx5H,EAAG8oB,OAChBx4B,EAAGC,EAAGkgB,IAAM,CACZ,CAAC,EAAG,EAAG,GACP,CAAC,EAAG,EAAG,GACP,CAAC,EAAG,EAAG,QAGNngB,EAAI,EAAGA,EAAI,EAAGA,QACVC,EAAI,EAAGA,EAAI,EAAGA,IACfkgB,IAAIngB,GAAGC,GAAKyP,EAAE1P,GAAKw4B,EAAEv4B,UAItBkpI,IAAIhpH,MAIf8oH,SAAW,SAAUljH,EAAGmhB,EAAGzkC,OACnBzC,EAAGC,EAAGwpI,IAAKC,IAAKC,GAChBxpH,IAAM,CACF,CAAC,EAAG,EAAG,GACP,CAAC,EAAG,EAAG,GACP,CAAC,EAAG,EAAG,QAGfwpH,GAAK//G,IAAI3E,WAAWiiB,EAAGzkC,GACvBgnI,IAAM7/G,IAAI3D,aAAaxjB,EAAGknI,IAC1BA,GAAK//G,IAAI3E,WAAWc,EAAGtjB,GACvBinI,IAAM9/G,IAAI3D,aAAaxjB,EAAGknI,IAErB3pI,EAAI,EAAGA,EAAI,EAAGA,QACVC,EAAI,EAAGA,EAAI,EAAGA,IACfkgB,IAAIngB,GAAGC,GAAKwpI,IAAM1jH,EAAE/lB,GAAGC,GAAKypI,IAAMxiG,EAAElnC,GAAGC,UAGxCkgB,KAKX4+B,MAAQj5C,MAAMwM,OAAO,QAAS,CAC1B,SAAUkB,UACC,GAEX,SAAUA,UACC,GACR,EAAG,EAAIpB,KAAKiV,IAAKkhH,YAGxBL,UAAY,SAAUz5F,IAAK8U,mBACnBvjD,EAAGC,EAAG6R,IAAKpC,MAEV6zC,cAAe,IACZ+lF,cAAe,KAEVtpI,EAAI,EAAGA,EAAI,EAAGA,IACfyC,EAAEzC,GAAKiS,OAAOjS,GAAGuT,OAAOG,UAI5ByS,GAAK+iH,SAASt/G,IAAI1D,aAAazjB,EAAE,GAAIA,EAAE,IAAKmnB,IAAI1D,aAAazjB,EAAE,GAAIA,EAAE,KACrE2jB,GAAK8iH,SAASt/G,IAAI1D,aAAazjB,EAAE,GAAIA,EAAE,IAAKmnB,IAAI1D,aAAazjB,EAAE,GAAIA,EAAE,KACrEgjB,EAAIwjH,SAAS9iH,GAAIC,GAAI3jB,EAAE,aAElBzC,EAAI,EAAGA,EAAI,EAAGA,QACVC,EAAID,EAAGC,EAAI,EAAGA,IACfwlB,EAAEzlB,GAAGC,GAAKopI,YAAYrpI,GAAGC,KACrBA,EAAID,IACJylB,EAAExlB,GAAGD,GAAKylB,EAAEzlB,GAAGC,QAO/B8+C,MAAMo3C,cAAgB1wE,GAGtB2jH,MAAQvuG,SAASO,OAAO3V,IAGd,GAAG,GAAG,GAAK,IACjB2jH,MAAM,GAAG,GAAG,KAAQ,EACpBA,MAAM,GAAG,GAAG,KAAQ,EACpBA,MAAM,GAAG,GAAG,KAAQ,GAInBppI,EAAI,EAAGA,EAAI,EAAGA,IAAK,KACpB8R,IAAM,EACD7R,EAAI,EAAGA,EAAI,EAAGA,IACf6R,KAAOs3H,MAAM,GAAGnpI,GAAGD,GAAKopI,MAAM,GAAGnpI,GAAGD,GAExC8R,IAAMM,KAAKmU,KAAKzU,KAKpBy3H,eAAiBH,MAAM,GACvB9zH,EAAIlD,KAAKmU,KAAKnU,KAAKwC,IAAIw0H,MAAM,GAAG,GAAG,KACnCr2H,EAAIX,KAAKmU,KAAKnU,KAAKwC,IAAIw0H,MAAM,GAAG,GAAG,KACnChjI,EAAIgM,KAAKmU,KAAKnU,KAAKwC,IAAIw0H,MAAM,GAAG,GAAG,YAKnCA,MAAM,GAAG,GAAG,IAAM,GAAOA,MAAM,GAAG,GAAG,IAAM,EAC3C15H,EAAIka,IAAI3E,WAAWskH,eAAgB,CAAC,EAAIj0H,EAAGlD,KAAK8hB,IAAIua,KAAO17B,EAAGX,KAAKwiB,IAAI6Z,KAAOroC,IACvEgjI,MAAM,GAAG,GAAG,IAAM,GAAOA,MAAM,GAAG,GAAG,GAAK,EACjD15H,EAAIka,IAAI3E,WAAWskH,eAAgB,CAACn3H,KAAK8hB,IAAIua,KAAOn5B,EAAG,EAAIvC,EAAGX,KAAKwiB,IAAI6Z,KAAOroC,IACvEgjI,MAAM,GAAG,GAAG,GAAK,IACxB15H,EAAIka,IAAI3E,WAAWskH,eAAgB,CAACn3H,KAAKwiB,IAAI6Z,KAAOn5B,EAAGlD,KAAK8hB,IAAIua,KAAO17B,EAAG,EAAI3M,KAG9E4S,KAAKzU,OAAOmL,IAEZA,EAAE,IAAMA,EAAE,GACVA,EAAE,IAAMA,EAAE,GACVA,EAAE,GAAK,GAEPA,EAAI,CAAC,EAAG2E,IAAKA,KAGV3E,GAIXqvC,MAAMjb,EAAI,SAAU2K,IAAK8U,sBACd2kF,UAAUz5F,IAAK8U,eAAe,IAIzCxE,MAAMhb,EAAI,SAAU0K,IAAK8U,sBACd2kF,UAAUz5F,IAAK8U,eAAe,IAIzCxE,MAAM2pF,SAAW5iI,MAAMwM,OAAO,QAAS,CACnC,eACQmB,EAAIsrC,MAAMo3C,oBAEP,CACH1iF,EAAE,GAAG,GAAKA,EAAE,GAAG,GAAKA,EAAE,GAAG,GAAKA,EAAE,GAAG,GACnCA,EAAE,GAAG,GAAKA,EAAE,GAAG,GAAKA,EAAE,GAAG,GAAKA,EAAE,GAAG,GACnCA,EAAE,GAAG,GAAKA,EAAE,GAAG,GAAKA,EAAE,GAAG,GAAKA,EAAE,GAAG,MAG5C60H,aAEHvpF,MAAMxuC,KAAOrB,MAAMlH,kBACnB+2C,MAAM3gB,OAAS2gB,MAAM2pF,SACrB3pF,MAAMu2C,KAAO,CACTl3D,OAAQ2gB,MAAM3gB,QAElB2gB,MAAMw2C,SAASn0F,KAAK29C,MAAM3gB,QAC1B2gB,MAAMw2C,SAAWx2C,MAAMw2C,SAAS30F,OAAOqR,QAEnCq3H,cAAe,KACVtpI,EAAI,EAAGA,EAAI,EAAGA,IACXgZ,KAAK9I,QAAQ+B,OAAOjS,KACpBiS,OAAOjS,GAAGu0F,SAASx1C,OAG3BA,MAAM+3C,WAAWplF,gBAErBqtC,MAAMw1C,SAASx1C,MAAM3gB,QAEd2gB,OAGXj7C,IAAIsB,gBAAgB,UAAWtB,IAAImkI,eACnCnkI,IAAIsB,gBAAgB,YAAatB,IAAI8kI,iBACrC9kI,IAAIsB,gBAAgB,WAAYtB,IAAI+kI,gBACpC/kI,IAAIsB,gBAAgB,QAAStB,IAAIklI,aAE1B,CACHf,cAAenkI,IAAImkI,cACnBW,gBAAiB9kI,IAAI8kI,gBACrBC,eAAgB/kI,IAAI+kI,eACpBG,YAAallI,IAAIklI,gBA2DzBlrI,OAAO,cAAc,CACjB,MAAO,eAAgB,cAAe,iBAAkB,gBAAiB,iBAAkB,eAC5F,SAAUgG,IAAK2wF,gBAAiB5qE,OAAQ3a,MAAO06H,MAAO92C,cAAe95E,aA2BpElV,IAAI+lI,OAAS,SAAU/jI,MAAOgkB,OAAQggH,KAAMC,KAAMp4H,iBAEzCuE,YAAYpQ,MAAO6L,WAAYzC,MAAMnH,mBAAoBmH,MAAMtF,0BAgB/DkgB,OAASA,YAGT4+G,SAAWhjI,KAAKI,MAAMG,OAAO6jI,WAM7B1rG,OAAS14B,KAAKI,MAAMG,OAAO6jI,WAM3BxzF,OAAS,UAQTgoB,OAAS,OAQTvoB,KAAO,UAQPmL,OAAS,UAETjvC,OAAS,GAEC,cAAX6X,aACKwsB,OAASxwC,MAAMG,OAAO8jI,WACtBzrE,OAAS54D,KAAK07C,UACD,gBAAXt3B,aACFkgH,QAAUD,UAEVlpB,aAAe7nG,KAAK/H,eAAe84H,KAAMrkI,KAAKI,MAAO,MAAM,QAE3D+6G,gBACa,cAAX/2F,aAEFisB,KAAOjwC,MAAMG,OAAO8jI,WACpBzrE,OAAS54D,KAAKqwC,KAAKK,OAAO7iC,OAAOsX,SAAS3b,MAAM1H,eAAgB9B,KAAKqwC,KAAKO,OAAO/iC,SACpE,gBAAXuW,cAEFo3B,OAASp7C,MAAMG,OAAO8jI,WACtBzrE,OAAS54D,KAAKw7C,OAAOE,eAIzBv+C,GAAK6C,KAAKI,MAAMw/F,MAAM5/F,KAAM,UAC5BI,MAAMmvE,SAASgV,YAAYvkF,WAC3BI,MAAMy/F,eAAe7/F,WAErBo1F,sBACA1F,OAAS,cACT4E,cAEDhhF,KAAKzU,OAAOmB,KAAK04B,OAAO7rB,eACnBgiF,SAAS7uF,KAAK04B,eACZ14B,KAAK04B,OAAO7rB,cAEd6rB,OAAOm2D,SAAS7uF,MAGV,gBAAXokB,YACK07E,cAAcukC,MACD,cAAXjgH,YACFisB,KAAKw+C,SAAS7uF,MACD,gBAAXokB,YACFo3B,OAAOqzC,SAAS7uF,MACH,cAAXokB,SACH9Q,KAAKzU,OAAOmB,KAAK4wC,OAAO/jC,eACnBgiF,SAAS7uF,KAAK4wC,eACZ5wC,KAAK4wC,OAAO/jC,cAEd+jC,OAAOi+C,SAAS7uF,YAIxB+vF,UAAYz8E,KAAK3D,SAAS3P,KAAK+vF,UAAW,CAC3CwE,UAAW,YACXgwC,UAAW,YACXl7B,KAAM,OACN5tE,KAAM,OACNm9B,OAAQ,SACRlgC,OAAQ,SACR2X,KAAM,OACNO,OAAQ,YAIhBxyC,IAAI+lI,OAAOjrI,UAAY,IAAI61F,gBAE3B3wF,IAAIC,OAAOD,IAAI+lI,OAAOjrI,UAA8C,CAShE87E,SAAU,SAAUlnE,EAAGiT,OACfwe,KAAM10B,KAINi0B,GAAIiC,GAAI2E,KAHR4D,GAAKtpC,KAAK04B,OAAO7qB,OAAOG,UACxBjR,EAAI,IAAIonB,OAAO3a,MAAMzH,iBAAkB,CAAC+L,EAAGiT,GAAI/gB,KAAKI,OACpDoP,EAAIxP,KAAK07C,gBAITpoC,KAAK/I,SAAS+I,KAAKrG,SAASjN,KAAK+S,QAAQwgE,aACzC1oE,KAAO7K,KAAKI,MAAM4/F,aAClBzgE,KAAOjsB,KAAKrG,SAASjN,KAAK+S,QAAQwgE,UAAU1oE,QAG5C00B,KAAOv/B,KAAKI,MAAMqM,QAAQ8mE,UAAUyB,SAExCl2C,GAAKwK,GAAG,GAAKvsC,EAAEiR,UAAU,GACzB+yB,GAAKuI,GAAG,GAAKvsC,EAAEiR,UAAU,GACzB03B,KAAOh5B,KAAKmU,KAAKie,GAAKA,GAAKiC,GAAKA,IAEhCxB,MAAkD,GAA1CjsB,KAAKrG,SAASjN,KAAK+S,QAAQlB,aACnC0tB,MAAQ7yB,KAAKmU,KAAK7gB,KAAKI,MAAM2kB,MAAQ/kB,KAAKI,MAAM4kB,OAE5C1R,KAAKrG,SAASjN,KAAK+S,QAAQ6pH,gBACnBl3F,KAAOl2B,EAAI+vB,KAGf7yB,KAAKwC,IAAIw2B,KAAOl2B,GAAK+vB,MASjC43B,mBAAoB,SAAUp6D,OAiCtBs0C,GAAKrxC,KAAK04B,OAAOk+B,SAAS9oD,EAC1B+R,GAAK7f,KAAK04B,OAAOk+B,SAAS71C,EAC1ByjH,GAAKznI,EAAE65D,SAAS9oD,EAChB22H,GAAK1nI,EAAE65D,SAAS71C,EAChB2jH,IAAM1kI,KAAK2kI,8BAGH,KAARD,IACO,GAGJ,CAAC,KAAOF,GAAK,MAAQnzF,GAAK,YAAcozF,GAAK,MAAQ5kH,GAAK,WAAa6kH,IAAM,MASxFC,sBAAuB,eASftzF,GAAIxxB,GAAIkyB,GAAIC,GACZ0yF,IAAM,SAEU,cAAhB1kI,KAAKokB,QACLitB,GAAKrxC,KAAK04B,OAAOk+B,SAAS9oD,EAC1B+R,GAAK7f,KAAK04B,OAAOk+B,SAAS71C,EAI1B2jH,IAAM,MAHN3yF,GAAK/xC,KAAK4wC,OAAOgmB,SAAS9oD,GAGR,MAAQujC,GAAK,aAF/BW,GAAKhyC,KAAK4wC,OAAOgmB,SAAS71C,GAEwB,MAAQlB,GAAK,QACxC,gBAAhB7f,KAAKokB,OACR9Q,KAAKrJ,SAASjK,KAAK44D,UACnB8rE,KAAO1kI,KAAK44D,OAAS54D,KAAK44D,QAAQ1uD,YAEf,cAAhBlK,KAAKokB,QACZ2tB,GAAK/xC,KAAKqwC,KAAKK,OAAOkmB,SAAS9oD,EAC/BkkC,GAAKhyC,KAAKqwC,KAAKK,OAAOkmB,SAAS71C,EAK/B2jH,IAAM,KAAO3yF,GAAK,MAHb/xC,KAAKqwC,KAAKO,OAAOgmB,SAAS9oD,EAGA,YAAckkC,GAAK,MAF7ChyC,KAAKqwC,KAAKO,OAAOgmB,SAAS71C,EAEgC,QACxC,gBAAhB/gB,KAAKokB,SACZsgH,IAAM1kI,KAAKw7C,OAAOE,UAGfgpF,KAMXlqG,OAAQ,eACA1sB,EAAGiT,EAAG6G,EAAGpY,EAAGI,EAAGtV,KAEf0F,KAAKivF,gBACD37E,KAAKrG,SAASjN,KAAK+S,QAAQigE,aACtBigB,mBAAkB,GAGP,cAAhBjzF,KAAKokB,YACAw0C,OAAS54D,KAAKqwC,KAAKK,OAAO7iC,OAAOsX,SAAS3b,MAAM1H,eAAgB9B,KAAKqwC,KAAKO,OAAO/iC,QAC/D,gBAAhB7N,KAAKokB,YACPw0C,OAAS54D,KAAKw7C,OAAOE,SACH,gBAAhB17C,KAAKokB,cACPw0C,OAAS54D,KAAKm7G,qBAGlB0iB,qBACA+G,sBAKLh9G,EAAI5nB,KAAK04B,OAAO7qB,OAAOG,UAAU,GACjCF,EAAI9N,KAAK04B,OAAO7qB,OAAOG,UAAU,GAAK4Z,EACtC7G,EAAI/gB,KAAK04B,OAAO7qB,OAAOG,UAAU,GAAK4Z,EACtCA,GAAKA,EACLpY,EAAIxP,KAAK07C,SACT9rC,EAAI,mBAEC2nC,aAAe,QACfpW,MAAQ,CAACrzB,EAAI0B,EAAG1B,EAAI0B,EAAG1B,EAAI0B,EAAII,EAAG9B,EAAGA,EAAI0B,EAAII,EAAG9B,EAAI0B,EAAG1B,EAAI0B,EAAG1B,EAAI0B,EAAG1B,EAAI0B,EAAII,EAAG9B,EAAGA,EAAI0B,EAAII,EAAG9B,EAAI0B,EAAG1B,EAAI0B,QACzG4xB,MAAQ,CAACrgB,EAAGA,EAAIvR,EAAII,EAAGmR,EAAIvR,EAAGuR,EAAIvR,EAAGuR,EAAIvR,EAAGuR,EAAIvR,EAAII,EAAGmR,EAAGA,EAAIvR,EAAII,EAAGmR,EAAIvR,EAAGuR,EAAIvR,EAAGuR,EAAIvR,EAAGuR,EAAIvR,EAAII,EAAGmR,QACrGo1B,aAAe,EACf77C,EAAI,EAAGA,EAAI0F,KAAKu3C,aAAcj9C,SAC1BiS,OAAOjS,GAAK,IAAI6pB,OAAO3a,MAAM1H,eAAgB,CAAC9B,KAAKmhC,MAAM7mC,GAAI0F,KAAKohC,MAAM9mC,IAAK0F,KAAKI,cAIxFJ,MAOX4kI,oBAAqB,eACb72H,EAAI/N,KAAK04B,OACTwgG,GAAKnrH,EAAEqwB,IACP+6F,GAAKprH,EAAEswB,IACP7uB,EAAIxP,KAAK07C,cAER+0C,cAAgB,CACjB,CAACyoC,GAAKA,GAAKC,GAAKA,GAAK3pH,EAAIA,GAAI0pH,IAAKC,IAClC,EAAED,GAAI,EAAG,GACT,EAAEC,GAAI,EAAG,KAQjB0E,cAAe,gBACNj6G,QAAQ,GAAK,QACbA,QAAQ,GAAK5jB,KAAK07C,cAClB93B,QAAQ,IAAM5jB,KAAK04B,OAAO7qB,OAAOG,UAAU,QAC3C4V,QAAQ,IAAM5jB,KAAK04B,OAAO7qB,OAAOG,UAAU,GAC3C8V,SAAS9jB,KAAK4jB,QAAQ,WAClBA,QAAQ,GAAKtQ,KAAKzU,OAAOmB,KAAK4wC,UAC/B5wC,KAAK4jB,QAAQ,GAAK5jB,KAAK4wC,OAAO/iC,OAAOG,UAAU,GAC/ChO,KAAK4jB,QAAQ,GAAK5jB,KAAK4wC,OAAO/iC,OAAOG,UAAU,IAC/C,QAEHrU,aAOTu5F,eAAgB,kBAGPlzF,KAAKivF,aAINjvF,KAAKwhF,YAAYvvE,eAEZ6T,QAAWpX,MAAM1O,KAAK04B,OAAO7qB,OAAOG,UAAU,GAAKhO,KAAK04B,OAAO7qB,OAAOG,UAAU,GAAKhO,KAAK07C,WAAc17C,KAAK04B,OAAO5S,OAGpH9lB,KAAK8lB,aACDw/D,kBAAiB,IAK1BtlF,KAAKwhF,YAAYvvE,cACZ7R,MAAMmvE,SAASiV,cAAcxkF,MAIlCA,KAAKovF,UAAYpvF,KAAKwhF,YAAYvvE,SAAWjS,KAAKkQ,OAClDlQ,KAAKkQ,MAAMsxE,YAAYvvE,SAAWjS,KAAK8lB,cAElC5V,MAAMsqB,cACNp6B,MAAMmvE,SAASgW,WAAWvlF,KAAKkQ,aAInCijF,0BAUAlE,aAAc,EACZjvF,MAtCIA,MA+Cf8/F,cAAe,SAAU8B,YACjBtuF,KAAKvJ,SAAS63F,aACdxU,cAAcsB,iBAAiB1uF,KAAM4hG,WAAY5hG,KAAKI,QAS9Dm0F,UAAW,SAAU/kF,eACZ2rG,aAAe7nG,KAAK/H,eAAeiE,EAAGxP,KAAKI,MAAO,MAAM,QACxDA,MAAMo6B,SAEJx6B,MAQX07C,OAAQ,SAAU5/C,cACVwX,KAAKzU,OAAO/C,aACPy4F,UAAUz4F,OACRkE,KAAK07C,UAGI,cAAhB17C,KAAKokB,OACD9Q,KAAK5F,UAAU1N,KAAK4wC,OAAO/iC,OAAOG,UAAW,CAAC,EAAG,EAAG,KAChDsF,KAAK5F,UAAU1N,KAAK04B,OAAO7qB,OAAOG,UAAW,CAAC,EAAG,EAAG,IAEjDW,IAGJ3O,KAAK04B,OAAOoI,KAAK9gC,KAAK4wC,QAGb,cAAhB5wC,KAAKokB,QAA0C,gBAAhBpkB,KAAKokB,OAC7BpkB,KAAK44D,OAGI,gBAAhB54D,KAAKokB,OACEpkB,KAAKm7G,eAGTxsG,KAOX41H,UAAW,kBACPnmI,IAAIkC,WAAW,qBAAsB,mBAC9BN,KAAK07C,UAIhBu5C,cAAe,kBACJj1F,KAAK04B,OAAO7qB,QAIvBqnF,eAAgB,eACRpnF,EAAGiT,EACHvR,EAAIxP,KAAK07C,SACT9rC,EAAI5P,KAAK04B,OAAO7qB,OAAOG,UACvBwY,MAAQ,yBAEJlT,KAAKrG,SAASjN,KAAK+S,QAAQ7C,MAAM2H,eACpC,MACD/J,EAAI8B,EAAE,GAAKJ,EACXuR,EAAInR,EAAE,aAEL,OACD9B,EAAI8B,EAAE,GAAK4W,MAAQhX,EACnBuR,EAAInR,EAAE,GAAK4W,MAAQhX,YAElB,KACD1B,EAAI8B,EAAE,GAAKJ,EACXuR,EAAInR,EAAE,aAEL,MACD9B,EAAI8B,EAAE,GAAK4W,MAAQhX,EACnBuR,EAAInR,EAAE,GAAK4W,MAAQhX,YAElB,MACD1B,EAAI8B,EAAE,GAAK4W,MAAQhX,EACnBuR,EAAInR,EAAE,GAAK4W,MAAQhX,YAElB,MACD1B,EAAI8B,EAAE,GACNmR,EAAInR,EAAE,GAAKJ,YAEV,MACD1B,EAAI8B,EAAE,GACNmR,EAAInR,EAAE,GAAKJ,gBAIX1B,EAAI8B,EAAE,GAAK4W,MAAQhX,EACnBuR,EAAInR,EAAE,GAAK4W,MAAQhX,SAIhB,IAAI2U,OAAO3a,MAAM1H,eAAgB,CAACgM,EAAGiT,GAAI/gB,KAAKI,QAIzD6yF,kBAAmB,eACXisC,GACA1vH,EAAIxP,KAAK07C,SACT91B,KAAO,CACHzoB,GAAI6C,KAAK7C,GAAK,IAAM6C,KAAKuvF,UACzB9kF,aAAcjB,MAAMtF,oBACpBw0B,OAAQ,CACJ7qB,OAAQ7N,KAAK04B,OAAO7qB,QAExB6tC,OAAQ,kBACGlsC,GAEX+0H,UAAW,kBACA/0H,GAEXpP,MAAOJ,KAAKI,MACZ2S,QAASO,KAAK3D,SAAS3P,KAAK+S,QAAS/S,KAAK+S,QAAQ+pH,iBAAiB,WAG3El3G,KAAK7S,QAAQ9C,MAAQjQ,KAAKI,MAAMqM,QAAQwD,MAAM+iE,WAEzCuc,YACLj8E,KAAKxC,gBAAgB8U,MACrBA,KAAK47D,YAAc,CACfvvE,QAASqB,KAAKrG,SAAS2Y,KAAK7S,QAAQd,UAGxCitH,GAAKl/H,KAAKI,MAAMmvE,SAAS8P,uBACpBj/E,MAAMmvE,SAAS8P,mBAAoB,OACnCj/E,MAAMmvE,SAASgV,YAAY3+D,WAC3BxlB,MAAMmvE,SAAS8P,kBAAoB6/C,QACnC5vC,OAAO1pE,KAAKzoB,IAAMyoB,KAAK+6D,SAErB3gF,MAQXmwF,aAAc,SAAUoB,eAChBj3F,EACAqW,KAAO2C,KAAKlJ,QAAQmnF,WAAaA,UAAY,CAACA,WAC9CnlF,IAAMuE,KAAK9V,WAEVP,EAAI,EAAGA,EAAI8R,IAAK9R,SACZo+B,OAAOmuD,gBAAgBnrF,KAAKiV,KAAKrW,IAElB,cAAhB0F,KAAKokB,aACAwsB,OAAOi2C,gBAAgBnrF,KAAKiV,KAAKrW,WAIvC0F,MAIXozE,WAAY,eACJ+rD,QAAU7rH,KAAKrG,SAASjN,KAAK+S,QAAQ4kF,wBAEpCj/D,OAAOw+D,iBAAiBioC,SAAS,GAClB,cAAhBn/H,KAAKokB,aACAwsB,OAAOsmD,iBAAiBioC,SAAS,GAGnCn/H,MAIX+6E,aAAc,eACNokD,QAAU7rH,KAAKrG,SAASjN,KAAK+S,QAAQspF,0BAEpC3jE,OAAOojE,mBAAmBqjC,SACX,cAAhBn/H,KAAKokB,aACAwsB,OAAOkrD,mBAAmBqjC,SAG5Bn/H,MAQXo+B,EAAG,SAAUllB,UACFlZ,KAAK07C,SAAWhvC,KAAK8hB,IAAQ,EAAJtV,EAAQxM,KAAKiV,IAAM3hB,KAAK04B,OAAO7qB,OAAOG,UAAU,IAQpFqwB,EAAG,SAAUnlB,UACFlZ,KAAK07C,SAAWhvC,KAAKwiB,IAAQ,EAAJhW,EAAQxM,KAAKiV,IAAM3hB,KAAK04B,OAAO7qB,OAAOG,UAAU,IAQpFwuC,EAAG,SAAUtjC,UACF,GAOXi+B,KAAM,kBACK,GAOXD,KAAM,kBACK,GAOXmyD,KAAM,eACE75F,EAAIxP,KAAK07C,gBAENlsC,EAAIA,EAAI9C,KAAKiV,IAOxB4zE,OAAQ,eACA1wE,GAAK7kB,KAAK04B,OAAO7qB,OAAOG,UACxBwB,EAAIxP,KAAK07C,eAEN,CAAC72B,GAAG,GAAKrV,EAAGqV,GAAG,GAAKrV,EAAGqV,GAAG,GAAKrV,EAAGqV,GAAG,GAAKrV,IAQrD6mF,WAAY,kBACoB,IAAxBr2F,KAAKgM,QAAQnR,OACNmF,KAAKgM,QAAQ9Q,OAAO8E,KAAK44D,QAE7B54D,KAAKgM,WA+FpB5N,IAAIymI,aAAe,SAAUzkI,MAAO4L,QAASC,gBACrCoC,GAAItR,EAAGzC,EAAG+R,KAAM7S,IAEhBsrI,YAAc,CAAC,SAAU,aAE7B/nI,EAAI,GACJvD,IAAM4G,MAAMG,OAAOyL,QAAQ,IACvBsH,KAAK/I,SAAS/Q,MAAQA,IAAIiR,eAAiBjB,MAAMtF,qBACjDoP,KAAK1I,wBAAwBoB,QAAQ,WAErCK,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,WAMlD4B,GAAK61H,MAAM3B,cAAcniI,MAAO,CAAC5G,IAAIk/B,OAAQl/B,IAAIk/B,OAAQ,kBAAoB,EAAIl/B,IAAIkiD,WAAcrvC,OAEpG8jF,aAAankF,QAAQ,IACjBqC,OAIN/T,EAAI,EAAGA,EAAI0R,QAAQnR,OAAQP,OACxBgZ,KAAK5I,YAAYtK,MAAO4L,QAAQ1R,SAER,KADxByC,EAAIA,EAAE7B,OAAOoY,KAAKvH,cAAc3L,MAAO,CAAC4L,QAAQ1R,IAAK2R,WAAY,SAAU,CAAC64H,YAAYxqI,OAClFyC,EAAElC,OAAS,SACP,IAAImB,MAAM,mFAGpBe,EAAErB,KAAKsQ,QAAQ1R,OAIvB+R,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,UAErC,IAAb1P,EAAElC,QAAgByY,KAAK9I,QAAQzN,EAAE,KAAOuW,KAAK9I,QAAQzN,EAAE,IAEvDsR,GAAK,IAAIjQ,IAAI+lI,OAAO/jI,MAAO,YAAarD,EAAE,GAAIA,EAAE,GAAIsP,WACjD,IAAKiH,KAAKrJ,SAASlN,EAAE,KAAOuW,KAAKnJ,WAAWpN,EAAE,KAAOuW,KAAKvJ,SAAShN,EAAE,MAChEuW,KAAK9I,QAAQzN,EAAE,IAEvBsR,GAAK,IAAIjQ,IAAI+lI,OAAO/jI,MAAO,cAAerD,EAAE,GAAIA,EAAE,GAAIsP,WACnD,IAAKiH,KAAKrJ,SAASlN,EAAE,KAAOuW,KAAKnJ,WAAWpN,EAAE,KAAOuW,KAAKvJ,SAAShN,EAAE,MACpEuW,KAAK9I,QAAQzN,EAAE,IAEnBsR,GAAK,IAAIjQ,IAAI+lI,OAAO/jI,MAAO,cAAerD,EAAE,GAAIA,EAAE,GAAIsP,WACnD,GAAKtP,EAAE,GAAG0N,eAAiBjB,MAAMtF,qBAAwBoP,KAAK9I,QAAQzN,EAAE,IAE3EsR,GAAK,IAAIjQ,IAAI+lI,OAAO/jI,MAAO,cAAerD,EAAE,GAAIA,EAAE,GAAIsP,WACnD,GAAKtP,EAAE,GAAG0N,eAAiBjB,MAAMtF,qBAAwBoP,KAAK9I,QAAQzN,EAAE,IAE3EsR,GAAK,IAAIjQ,IAAI+lI,OAAO/jI,MAAO,cAAerD,EAAE,GAAIA,EAAE,GAAIsP,WACnD,GAAKtP,EAAE,GAAG0N,eAAiBjB,MAAMvF,mBAAsBqP,KAAK9I,QAAQzN,EAAE,IAEzEsR,GAAK,IAAIjQ,IAAI+lI,OAAO/jI,MAAO,YAAarD,EAAE,GAAIA,EAAE,GAAIsP,WACjD,GAAKtP,EAAE,GAAG0N,eAAiBjB,MAAMvF,mBAAsBqP,KAAK9I,QAAQzN,EAAE,IAEzEsR,GAAK,IAAIjQ,IAAI+lI,OAAO/jI,MAAO,YAAarD,EAAE,GAAIA,EAAE,GAAIsP,UACjD,CAAA,KAAuB,IAAnBL,QAAQnR,QAAgByY,KAAK9I,QAAQzN,EAAE,KAAOuW,KAAK9I,QAAQzN,EAAE,KAAOuW,KAAK9I,QAAQzN,EAAE,WAUpF,IAAIf,MAAM,4DACJgQ,QAAQ,IAAM,kBAAoBA,QAAQ,IADtC,gJAPZ5N,IAAIqB,SAAS0sE,mBAGP,IAAInwE,MAAM,mHAFhBqS,GAAKjQ,IAAIqB,SAAS0sE,aAAa/rE,MAAOrD,EAAGsP,UAWjDgC,GAAG6gF,aAxEe,EAyElB7gF,GAAG+iF,WAAWr0F,GACdsR,GAAGqhF,OAAS,SACPp1F,EAAI,EAAGA,EAAIyC,EAAElC,OAAQP,IAClBgZ,KAAK9I,QAAQzN,EAAEzC,KACf+T,GAAGwhF,SAASn0F,KAAKqB,EAAEzC,WAGpB+T,IAGXjQ,IAAIsB,gBAAgB,SAAUtB,IAAIymI,cAE3B,CACHV,OAAQ/lI,IAAI+lI,OACZU,aAAczmI,IAAIymI,iBAmD1BzsI,OAAO,eAAe,CAClB,MAAO,iBAAkB,cAAe,kBAAmB,gBAAiB,aAAc,iBAC3F,SAAUgG,IAAKoL,MAAO2a,OAAQ0pB,WAAYsB,SAAU77B,KAAMy7E,wBAiBzD3wF,IAAI2mI,QAAU,SAAU3kI,MAAO08C,SAAU7wC,iBAChCuE,YAAYpQ,MAAO6L,WAAYzC,MAAMzG,oBAAqByG,MAAMpF,uBAEjE9J,EAAGwY,EAAG1G,IAAK7R,EAAGwC,EACdqmI,UAAY9vH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,UAAW,oBAErEskE,UAAY9kE,WAAW+4H,eACvB5B,UAAYA,eAMZtmF,SAAW,GACXxiD,EAAI,EAAGA,EAAIwiD,SAASjiD,OAAQP,SACxBwiD,SAASxiD,GAAK0F,KAAKI,MAAMG,OAAOu8C,SAASxiD,OAI9C0F,KAAK88C,SAASjiD,OAAS,GAAKmF,KAAK88C,SAAS98C,KAAK88C,SAASjiD,OAAS,GAAGsC,KAAO6C,KAAK88C,SAAS,GAAG3/C,SACvF2/C,SAASphD,KAAKsE,KAAK88C,SAAS,SAOhC3D,QAAU,GAEXn5C,KAAK+wE,cACL3kE,IAAMpM,KAAK88C,SAASjiD,OAAS,EACxBN,EAAI,EAAGA,EAAI6R,IAAK7R,IAEjBD,GAAKC,EAAI,GAAK6R,IACdg3H,UAAUjmI,GAAKimI,UAAU6B,KAAO7B,UAAU6B,IAAI3qI,GAC9C8oI,UAAUxpI,KAAOwpI,UAAU8B,OAAS9B,UAAU8B,MAAM5qI,GACpD8oI,UAAUzxH,YAAe2B,KAAKlJ,QAAQg5H,UAAU3rD,SAAW2rD,UAAU3rD,OAAOn9E,EAAI8oI,UAAU3rD,OAAO58E,SACrEuoI,UAAUzxH,YACtCyxH,UAAUnxH,QAAUqB,KAAKzU,OAAOoN,WAAWktC,QAAQlnC,SAAWhG,WAAWktC,QAAQlnC,QAAUhG,WAAWgG,SAExE,IAA1BmxH,UAAUzxH,cACVyxH,UAAUzxH,YAAc,SAG5BmB,EAAI1S,MAAMwM,OAAO,UAAW,CAAC5M,KAAK88C,SAASxiD,GAAI0F,KAAK88C,SAASxiD,EAAI,IAAK8oI,YACpEzzC,MAAO,OACJx2C,QAAQ7+C,GAAKwY,EAClBA,EAAEkoF,cAAgBh7F,cAIrB6vF,SAASn0F,KAAKsE,KAAK88C,SAAU98C,KAAKm5C,cAIlCh8C,GAAK6C,KAAKI,MAAMw/F,MAAM5/F,KAAM,MAM5B1F,EAAI,EAAGA,EAAI0F,KAAK88C,SAASjiD,OAAS,EAAGP,IACtCyC,EAAIiD,KAAKI,MAAMG,OAAOP,KAAK88C,SAASxiD,IAChCgZ,KAAKzU,OAAO9B,EAAE8P,eACTgiF,SAAS9xF,UACPA,EAAE8P,SAET9P,EAAE8xF,SAAS7uF,WAIdI,MAAMmvE,SAASkV,YAAYzkF,WAC3BI,MAAMy/F,eAAe7/F,WAErBo1F,sBACA1F,OAAS,eAGT4E,mBAEAvE,UAAY3xF,IAAIuR,SAAS3P,KAAK+vF,UAAW,CAC1C52C,QAAS,UACT2D,SAAU,WACVz8B,EAAG,OACHgpF,KAAM,OACN87B,UAAW,YACXnrF,EAAG,YACHorF,OAAQ,YACR/xF,YAAa,cACbkiD,OAAQ,SACRqrC,UAAW,YACXyE,aAAc,eACdC,aAAc,kBAItBlnI,IAAI2mI,QAAQ7rI,UAAY,IAAI61F,gBAE5B3wF,IAAIC,OAAOD,IAAI2mI,QAAQ7rI,UAA+C,CAuClE2jI,OAAQ,SAAS0I,KAAMC,KAAMpgH,gBACrB9qB,EAAGC,EAAG6R,IACN0B,EAAGiT,EAAGm4B,KACNlvC,EAAIhK,KAAK88C,SACT2oF,MAAO,MAEPrgH,aAAe5b,MAAM1H,gBAErBgM,GADAorC,KAAO,IAAI/0B,OAAO3a,MAAM1H,eAAgB,CAACyjI,KAAMC,MAAOxlI,KAAKI,QAClDmkB,UAAU,GACnBxD,EAAIm4B,KAAK30B,UAAU,KAEnBzW,EAAIy3H,KACJxkH,EAAIykH,MAIHlrI,EAAI,EAAGC,GADZ6R,IAAMpM,KAAK88C,SAASjiD,QACE,EAAGP,EAAI8R,IAAM,EAAG7R,EAAID,IAChC0P,EAAE1P,GAAGuT,OAAO0W,UAAU,GAAKxD,GAAQ/W,EAAEzP,GAAGsT,OAAO0W,UAAU,GAAKxD,GAC/DjT,GAAK9D,EAAEzP,GAAGsT,OAAO0W,UAAU,GAAKva,EAAE1P,GAAGuT,OAAO0W,UAAU,KACtDxD,EAAI/W,EAAE1P,GAAGuT,OAAO0W,UAAU,KAAOva,EAAEzP,GAAGsT,OAAO0W,UAAU,GAAKva,EAAE1P,GAAGuT,OAAO0W,UAAU,IAAMva,EAAE1P,GAAGuT,OAAO0W,UAAU,KAE/GkhH,MAAQA,aAITA,MASXzwD,SAAU,SAAUlnE,EAAGiT,OACfzmB,EAAG8R,OAEHkH,KAAKrG,SAASjN,KAAK+S,QAAQ6pH,iBAEvB58H,KAAK68H,OAAO/uH,EAAGiT,UACR,MAQf3U,IAAMpM,KAAKm5C,QAAQt+C,OACdP,EAAI,EAAGA,EAAI8R,IAAK9R,OACb0F,KAAKm5C,QAAQ7+C,GAAG06E,SAASlnE,EAAGiT,UACrB,SAIR,GAMXmyE,eAAgB,eACR54F,EAAG8R,QAGFpM,KAAKivF,mBACCjvF,QAGPA,KAAKwhF,YAAYvvE,QAAS,KAG1B7F,IAAMpM,KAAK88C,SAASjiD,YACfirB,QAAS,EACTxrB,EAAI,EAAGA,EAAI8R,MAAO9R,MACd0F,KAAK88C,SAASxiD,GAAGwrB,OAAQ,MACrBA,QAAS,QAMjB9lB,KAAK8lB,aACDw/D,kBAAiB,UAI1BtlF,KAAKwhF,YAAYvvE,cACZ7R,MAAMmvE,SAASmV,cAAc1kF,MAIlCA,KAAKovF,UAAYpvF,KAAKwhF,YAAYvvE,SAAWjS,KAAKkQ,OAClDlQ,KAAKkQ,MAAMsxE,YAAYvvE,SAAWjS,KAAK8lB,cAElC5V,MAAMsqB,cACNp6B,MAAMmvE,SAASgW,WAAWvlF,KAAKkQ,aAInCijF,0BAUAlE,aAAc,EACZjvF,MAMXi1F,cAAe,eACP5nF,EAAG3M,EAAGoN,EAAGiT,EAAGzmB,KAEa,IAAzB0F,KAAK88C,SAASjiD,cACP,IAAIspB,OAAO3a,MAAM1H,eAAgB,CAAC,EAAG,EAAG,GAAI9B,KAAKI,WAK5D0N,EAFAT,EAAIrN,KAAK88C,SAAS,GAAG1e,IAGrBrd,EAFArgB,EAAIV,KAAK88C,SAAS,GAAGze,IAGhB/jC,EAAI,EAAGA,EAAI0F,KAAK88C,SAASjiD,OAAQP,IAC9B0F,KAAK88C,SAASxiD,GAAG8jC,IAAM/wB,IACvBA,EAAIrN,KAAK88C,SAASxiD,GAAG8jC,KAGrBp+B,KAAK88C,SAASxiD,GAAG8jC,IAAMtwB,IACvBA,EAAI9N,KAAK88C,SAASxiD,GAAG8jC,KAGrBp+B,KAAK88C,SAASxiD,GAAG+jC,IAAM39B,IACvBA,EAAIV,KAAK88C,SAASxiD,GAAG+jC,KAGrBr+B,KAAK88C,SAASxiD,GAAG+jC,IAAMtd,IACvBA,EAAI/gB,KAAK88C,SAASxiD,GAAG+jC,YAItB,IAAIla,OAAO3a,MAAM1H,eAAgB,CAAW,IAATuL,EAAIS,GAAoB,IAATpN,EAAIqgB,IAAW/gB,KAAKI,QAGjF80F,eAAgB92F,IAAI6B,SAAS7B,IAAI2mI,QAAQ7rI,UAAW,iBAGpD+5F,kBAAmB,eACAisC,GAAXt5G,KAAO,UAEXA,KAAKzoB,GAAK6C,KAAK7C,GAAK,IAAM6C,KAAKuvF,eAC1BA,YACL3pE,KAAKk3B,SAAW98C,KAAK88C,SACrBl3B,KAAK7S,QAAUO,KAAK3D,SAAS3P,KAAK+S,QAAS/S,KAAK+S,QAAQ+pH,iBAAiB,GACzEl3G,KAAK7S,QAAQ9C,MAAQjQ,KAAKI,MAAMqM,QAAQwD,MAAM+iE,MAC9CptD,KAAKxlB,MAAQJ,KAAKI,MAClBkT,KAAKxC,gBAAgB8U,MAErBA,KAAK47D,YAAc,CACfvvE,QAASqB,KAAKrG,SAAS2Y,KAAK7S,QAAQd,UAGxCitH,GAAKl/H,KAAKI,MAAMmvE,SAAS8P,uBACpBj/E,MAAMmvE,SAAS8P,mBAAoB,OACnCj/E,MAAMmvE,SAASkV,YAAY7+D,WAC3BxlB,MAAMmvE,SAAS8P,kBAAoB6/C,QACnC5vC,OAAO1pE,KAAKzoB,IAAMyoB,KAAK+6D,SAErB3gF,MAQXqzF,YAAa,SAAUqyC,gBACfprI,KAEJ8D,IAAIkC,WAAW,wBAAyB,qCAEnCkhF,YAAYvvE,SAAU,OACtB7R,MAAMmvE,SAAS14D,QAAQ7W,MAAM,IAE7B0lI,eACIprI,EAAI,EAAGA,EAAI0F,KAAKm5C,QAAQt+C,OAAQP,SAC5B6+C,QAAQ7+C,GAAG+4F,cAIpBrzF,KAAKovF,UAAY97E,KAAKzU,OAAOmB,KAAKkQ,cAC7BA,MAAMsjF,gBAAiB,EACxBxzF,KAAKkQ,MAAMsxE,YAAYvvE,cAClB/B,MAAMmjF,gBAUvBC,YAAa,SAAUoyC,gBACfprI,KAEJ8D,IAAIkC,WAAW,wBAAyB,qCAEnCkhF,YAAYvvE,SAAU,OACtB7R,MAAMmvE,SAAS14D,QAAQ7W,MAAM,IAE7B0lI,eACIprI,EAAI,EAAGA,EAAI0F,KAAKm5C,QAAQt+C,OAAQP,SAC5B6+C,QAAQ7+C,GAAGg5F,cAAcJ,wBAIlC5/E,KAAKzU,OAAOmB,KAAKkQ,QAAUlQ,KAAKovF,UAAYpvF,KAAKkQ,MAAMsjF,sBAClDtjF,MAAMsjF,gBAAiB,EACvBxzF,KAAKkQ,MAAMsxE,YAAYvvE,cACnB/B,MAAMojF,cAAcJ,kBAG1BlzF,MAOXqpG,KAAM,kBACK38F,KAAKwC,IAAIigC,SAAS+C,cAAclyC,KAAK88C,UAAU,KAuB1DqoF,UAAW,eACH7qI,EACA8R,IAAMpM,KAAK88C,SAASjiD,OACpB8P,IAAM,MAELrQ,EAAI,EAAGA,EAAI8R,MAAO9R,EACnBqQ,KAAO3K,KAAK88C,SAASxiD,GAAGwmC,KAAK9gC,KAAK88C,SAASxiD,EAAI,WAG5CqQ,KAeX0oC,YAAa,eACe/4C,EAAG0P,EAAvBs7G,IAAM,CAAC,EAAG,EAAG,EAAG,GAChBtkG,GAAKhhB,KAAK88C,SAASjiD,OAAS,KAErB,IAAPmmB,UACOskG,QAEXA,IAAI,GAAKtlH,KAAK88C,SAAS,GAAG1e,IAC1BknF,IAAI,GAAKA,IAAI,GACbA,IAAI,GAAKtlH,KAAK88C,SAAS,GAAGze,IAC1BinF,IAAI,GAAKA,IAAI,GAERhrH,EAAI,EAAGA,EAAI0mB,KAAM1mB,GAClB0P,EAAIhK,KAAK88C,SAASxiD,GAAG8jC,KACbknF,IAAI,GACRA,IAAI,GAAKt7G,EACFA,EAAIs7G,IAAI,KACfA,IAAI,GAAKt7G,IAGbA,EAAIhK,KAAK88C,SAASxiD,GAAG+jC,KACbinF,IAAI,GACRA,IAAI,GAAKt7G,EACFA,EAAIs7G,IAAI,KACfA,IAAI,GAAKt7G,UAIVs7G,KAIX/vB,OAAQ,kBACGv1F,KAAKqzC,eAShBkuC,OAAQ,eACAjnF,MAECA,EAAI,EAAGA,EAAI0F,KAAKm5C,QAAQt+C,OAAQP,SAC5B8F,MAAMs2F,aAAa12F,KAAKm5C,QAAQ7+C,IAGzCy0F,gBAAgB71F,UAAUqoF,OAAO7nF,KAAKsG,OAQ1C2lI,UAAW,SAAU5oI,OACbzC,MAECgZ,KAAK9I,QAAQzN,UACN,MAGPzC,EAAI,EAAGA,EAAI0F,KAAK88C,SAASjiD,OAAQP,OAC9B0F,KAAK88C,SAASxiD,GAAG6C,KAAOJ,EAAEI,UACnB7C,SAIP,GAmCZsmI,UAAW,SAAU7jI,OACbvB,KAAO6O,MAAMnR,UAAUG,MAAMK,KAAK+B,kBAE/BuE,KAAKqlI,aAAa1pI,MAAMqE,KAAM,CAACA,KAAK88C,SAASjiD,OAAS,GAAGK,OAAOM,QAqC3E6pI,aAAc,SAAU7+F,IAAKzpC,OACrBzC,EAAG0mB,MAEkB,IAArBvlB,UAAUZ,cACHmF,QAIPwmC,KAAO,GAAKA,IAAMxmC,KAAK88C,SAASjiD,OAAS,SAClCmF,SAGXghB,GAAKvlB,UAAUZ,OAAS,EACnBP,EAAI,EAAGA,EAAI0mB,GAAK,EAAG1mB,SACfwiD,SAAS3hD,OAAOqrC,IAAMlsC,EAAG,EAC1BgZ,KAAKvH,cAAc/L,KAAKI,MAAO,CAAC3E,UAAUnB,IAAK,GAAI,UAAW,CAAC,aAAa,QAGvE,IAATksC,WACKsW,SAAS98C,KAAK88C,SAASjiD,OAAS,GAAKmF,KAAK88C,SAAS,IAExD98C,KAAK+wE,cACDvqC,IAAM,OACD2S,QAAQn5C,KAAKm5C,QAAQt+C,OAAS,GAAG+1C,OAAS5wC,KAAK88C,SAAS98C,KAAK88C,SAASjiD,OAAS,QAE/Es+C,QAAQ3S,KAAKoK,OAAS5wC,KAAK88C,SAAStW,IAAM,GAE9ClsC,EAAIksC,IAAM,EAAGlsC,EAAIksC,IAAM,EAAIxlB,GAAI1mB,SAC3B6+C,QAAQh+C,OAAOb,EAAG,EACnB0F,KAAKI,MAAMwM,OAAO,UAAW,CAAC5M,KAAK88C,SAASxiD,GAAI0F,KAAK88C,SAASxiD,EAAI,IAAK0F,KAAKojI,wBAInFhjI,MAAMo6B,SAEJx6B,MAQXslI,aAAc,SAAUvoI,OAChBzC,EAAGC,EAAGisC,IAAKo/F,UAAY,GAAIC,SAAW,GACtCC,KAAO,GAAIC,UAAY,YAWtBjpF,SAAW98C,KAAK88C,SAASzjD,MAAM,EAAG2G,KAAK88C,SAASjiD,OAAS,GAGzDP,EAAI,EAAGA,EAAImB,UAAUZ,OAAQP,IAC9BksC,IAAM/qC,UAAUnB,GACZgZ,KAAK9I,QAAQg8B,OACbA,IAAMxmC,KAAK2lI,UAAUn/F,MAGrBlzB,KAAKrJ,SAASu8B,MAAQA,KAAO,GAAKA,IAAMxmC,KAAK88C,SAASjiD,SAAuC,IAA7ByY,KAAKlX,QAAQ0pI,KAAMt/F,MACnFs/F,KAAKpqI,KAAK8qC,SAKblsC,EAAI,EAAGA,EAAIwrI,KAAKjrI,OAAQP,SACpBwiD,SAASgpF,KAAKxrI,IAAI4iB,YAAYld,UAIvC8lI,KAAOA,KAAK/mG,OACZ6mG,UAAY5lI,KAAK88C,SAASzjD,QAC1BwsI,SAAW7lI,KAAKm5C,QAAQ9/C,QAGpB2G,KAAK+wE,WACLg1D,UAAUrqI,KAAK,CAACoqI,KAAKA,KAAKjrI,OAAS,KAKlCP,EAAIwrI,KAAKjrI,OAAS,EAAGP,GAAK,EAAGA,IAC9BsrI,UAAUE,KAAKxrI,KAAO,EAElB0F,KAAK+wE,WAAc+0D,KAAKxrI,GAAK,EAAIwrI,KAAKxrI,EAAI,KAC1CyrI,UAAUA,UAAUlrI,OAAS,GAAG,GAAKirI,KAAKxrI,GAC1CyrI,UAAUrqI,KAAK,CAACoqI,KAAKxrI,EAAI,UAK7B0F,KAAK+wE,YACLg1D,UAAUA,UAAUlrI,OAAS,GAAG,GAAKirI,KAAK,SAIzChpF,SAAW,GACXxiD,EAAI,EAAGA,EAAIsrI,UAAU/qI,OAAQP,IAC1BgZ,KAAK9I,QAAQo7H,UAAUtrI,UAClBwiD,SAASphD,KAAKkqI,UAAUtrI,OAGjC0F,KAAK88C,SAAS98C,KAAK88C,SAASjiD,OAAS,GAAGsC,KAAO6C,KAAK88C,SAAS,GAAG3/C,SAC3D2/C,SAASphD,KAAKsE,KAAK88C,SAAS,IAIjC98C,KAAK+wE,UAAW,KACXz2E,EAAI,EAAGA,EAAIyrI,UAAUlrI,OAAQP,IAAK,KAC9BC,EAAIwrI,UAAUzrI,GAAG,GAAK,EAAGC,EAAIwrI,UAAUzrI,GAAG,GAAK,EAAGC,IAE/CA,EAAI,GAEJA,EAAI,OACC6F,MAAMs2F,aAAa12F,KAAKm5C,QAAQ0sF,SAAShrI,OAAS,IACvDgrI,SAASA,SAAShrI,OAAS,IAAM,GAC1BN,EAAIsrI,SAAShrI,OAAS,IAC7BN,EAAIsrI,SAAShrI,OAAS,QAGrBuF,MAAMs2F,aAAa12F,KAAKm5C,QAAQ5+C,IACrCsrI,SAAStrI,IAAM,EAMK,IAApBwrI,UAAUzrI,GAAG,IAAYyrI,UAAUzrI,GAAG,KAAOsrI,UAAU/qI,OAAS,IAChEgrI,SAASE,UAAUzrI,GAAG,GAAK,GAAK0F,KAAKI,MAAMwM,OAAO,UAAW,CAACg5H,UAAUl5H,KAAKiS,IAAIonH,UAAUzrI,GAAG,GAAK,EAAG,IAAKsrI,UAAUl5H,KAAKC,IAAIo5H,UAAUzrI,GAAG,GAAK,EAAG0F,KAAK88C,SAASjiD,OAAS,KAAMmF,KAAKojI,qBAIxLjqF,QAAU,GACV7+C,EAAI,EAAGA,EAAIurI,SAAShrI,OAAQP,KACR,IAAjBurI,SAASvrI,SACJ6+C,QAAQz9C,KAAKmqI,SAASvrI,IAK/ByrI,UAAU,GAAG,KAAO/lI,KAAK88C,SAASjiD,OAAS,GAA4C,IAAvCkrI,UAAUA,UAAUlrI,OAAS,GAAG,SAC3Es+C,QAAQz9C,KAAKsE,KAAKI,MAAMwM,OAAO,UAAW,CAAC5M,KAAK88C,SAAS,GAAI98C,KAAK88C,SAAS98C,KAAK88C,SAASjiD,OAAS,IAAKmF,KAAKojI,wBAIpHhjI,MAAMo6B,SAEJx6B,MAIXq2F,WAAY,uBACHjF,WAAWpxF,KAAK88C,UACd98C,KAAKgM,SAGhBsqF,cAAe,eACoDh8F,EAA3D+R,KAAO0iF,gBAAgB71F,UAAUo9F,cAAc58F,KAAKsG,SAEpDA,KAAK+wE,cACL1kE,KAAK2lG,MAAQ3lG,KAAK2lG,OAAS,GAC3B3lG,KAAK2lG,MAAMizB,IAAM,GACjB54H,KAAK2lG,MAAMv6B,OAAS,GAEfn9E,EAAI,EAAGA,EAAI0F,KAAKm5C,QAAQt+C,OAAQP,IACjC+R,KAAK2lG,MAAMizB,IAAIvpI,KAAKsE,KAAKm5C,QAAQ7+C,GAAG6C,IACpCkP,KAAK2lG,MAAMv6B,OAAO/7E,KAAKsE,KAAKm5C,QAAQ7+C,GAAGyY,QAAQpB,oBAIhDtF,MAGX+mE,WAAY,eACJ94E,EAAGg7F,UAGHA,QADAhiF,KAAKrG,SAASjN,KAAK+S,QAAQ4kF,YAM1Br9F,EAAI,EAAGA,EAAI0F,KAAK88C,SAASjiD,OAAQP,SAC7BwiD,SAASxiD,GAAG48F,iBAAiB5B,OAAO,IAYjDxD,oBAAqB,SAAU1tE,OAAQvW,OAAQkkF,eACvCE,GAAO33F,EAAG8R,IACVwD,EAAI,IAAIuU,OAAOC,OAAQvW,OAAQ7N,KAAKI,OACpC4xF,KAAO,IAAI7tE,OAAOC,OAAQ2tE,UAAW/xF,KAAKI,WAE9CgM,IAAMpM,KAAK88C,SAASjiD,OAAS,EACxBP,EAAI,EAAGA,EAAI8R,IAAK9R,QACZ0F,KAAK88C,SAASxiD,GAAGk3F,mBACXxxF,YAIfiyF,GAAKpkD,WAAWa,SAAS9+B,EAAE5B,UAAWgkF,KAAKhkF,WACvChO,KAAKI,MAAMwM,OAAO,YAAaqlF,GAAG54F,MAAM,GAAI,CAACwR,KAAM,cACrD6mF,UAAU1xF,KAAK88C,SAASzjD,MAAM,GAAI,IAE7B2G,MAiBXgmI,kBAAmB,SAASr5D,aAOpBs5D,MAGAC,UAAW5rI,EAAGC,EAAGusB,EAAGiM,EAAG2qD,MARvBvf,KAAO//D,IAAIsO,KAAKyiC,SAASuC,aAAa1xC,KAAK88C,UAC3CohB,QAAU9/D,IAAIsO,KAAKyiC,SAASuC,aAAai7B,QAAQ7vB,UAEjDqpF,QAAUhoE,KAAKtjE,OAAS,EACxBurI,WAAaloE,QAAQrjE,OAAS,EAG9BwrI,WAAa,GAKbC,SAAW,SAAS7lH,GAAIC,GAAI6lH,WACf7lH,GAAG,GAAKD,GAAG,KAAO8lH,GAAG,GAAK9lH,GAAG,KAAOC,GAAG,GAAKD,GAAG,KAAO8lH,GAAG,GAAK9lH,GAAG,KAAQ,OAGrFnmB,EAAI,EAAGA,EAAI8rI,WAAY9rI,IACxB+rI,WAAW3qI,KAAKwiE,QAAQ5jE,QAGvBA,EAAI,EAAGA,EAAI6rI,QAAS7rI,QACrB4rI,UAAYG,WAAWhtI,MAAM,GAE7BgtI,WAAa,GAEbv/G,EAAIo/G,WAHJD,MAAQC,UAAUrrI,QAGI,GAEjBN,EAAI,EAAGA,EAAI0rI,MAAO1rI,IACnBw4B,EAAImzG,UAAU3rI,GACV+rI,SAASnoE,KAAK7jE,GAAI6jE,KAAK7jE,EAAI,GAAIy4B,IAC1BuzG,SAASnoE,KAAK7jE,GAAI6jE,KAAK7jE,EAAI,GAAIwsB,MAChC42D,MAAQt/E,IAAIsO,KAAKyiC,SAAS4F,mBAAmBjuB,EAAGiM,EAAGorC,KAAK7jE,GAAI6jE,KAAK7jE,EAAI,KAC/D,GAAG,IAAMojF,MAAM,GAAG,GACxBA,MAAM,GAAG,IAAMA,MAAM,GAAG,GACxBA,MAAM,GAAG,GAAK,EACd2oD,WAAW3qI,KAAKgiF,MAAM,KAE1B2oD,WAAW3qI,KAAKq3B,IACTuzG,SAASnoE,KAAK7jE,GAAI6jE,KAAK7jE,EAAI,GAAIwsB,MACtC42D,MAAQt/E,IAAIsO,KAAKyiC,SAAS4F,mBAAmBjuB,EAAGiM,EAAGorC,KAAK7jE,GAAI6jE,KAAK7jE,EAAI,KAC/D,GAAG,IAAMojF,MAAM,GAAG,GACxBA,MAAM,GAAG,IAAMA,MAAM,GAAG,GACxBA,MAAM,GAAG,GAAK,EACd2oD,WAAW3qI,KAAKgiF,MAAM,KAE1B52D,EAAIiM,SAILszG,YA2GXtsC,UAAW,SAASptB,gBACT3sE,KAAKgmI,kBAAkBr5D,YAyGtCvuE,IAAIooI,cAAgB,SAAUpmI,MAAO4L,QAASC,gBACtCoC,GAAI/T,EAAG0mB,GAAIxnB,IAEX6S,KAAMo6H,YADNl6H,OAAS,GAETm6H,cAAe,KAEZpzH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,WAE1C,QADZjT,IAAM4G,MAAMG,OAAOyL,QAAQ,OAGvBxS,IAAMwS,QAAQ,IAEdsH,KAAK/I,SAAS/Q,MAAQA,IAAIqR,OAASrB,MAAMzG,qBACzCuQ,KAAK1I,wBAAwBoB,QAAQ,QAErC06H,cAAe,EACf1lH,GAAKxnB,IAAIsjD,SAASjiD,OAAS,EAC3B4rI,YAAcnzH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,UAAW,YACnEnS,EAAI,EAAGA,EAAI0mB,GAAI1mB,IACZmsI,YAAYpyC,YACZoyC,YAAY7sI,KAAiC,KAAzBJ,IAAIsjD,SAASxiD,GAAGV,KAAe,GAAMJ,IAAIsjD,SAASxiD,GAAGV,KAAO,KAEpF2S,OAAO7Q,KAAK0E,MAAMwM,OAAO,QAAS,CAACpT,IAAIsjD,SAASxiD,GAAI0R,QAAQ,IAAKy6H,uBAItD,KADfl6H,OAAS+G,KAAKvH,cAAc3L,MAAO4L,QAASC,WAAY,UAAW,CAAC,oBAE1D,IAAIjQ,MAAM,kOAIxBqQ,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,YACtD4B,GAAK,IAAIjQ,IAAI2mI,QAAQ3kI,MAAOmM,OAAQF,OACjC6iF,aAAc,EAGbw3C,iBACAr4H,GAAGg3E,gBAAgB7qD,SAAS8qD,mBAAmB4N,iBAC/ClyE,GAAKxnB,IAAIsjD,SAASjiD,OAAS,EACtBP,EAAI,EAAGA,EAAI0mB,GAAI1mB,IAChBiS,OAAOjS,GAAG+qF,gBAAgB7qD,SAAS8qD,mBAAmB4N,wBAIvD7kF,IAkEXjQ,IAAIuoI,qBAAuB,SAAUvmI,MAAO4L,QAASC,gBAC7CoC,GAAI/T,EAAGuC,EACCu7D,IAAKhsD,IAAKw6H,YAAav6H,KAA/BtP,EAAI,MAGRF,EAAImP,SADJI,IAAMJ,QAAQnR,QACI,GAEdyY,KAAKrJ,SAASpN,KAA0B,IAAnBmP,QAAQnR,QAAgBgC,EAAI,SAC3C,IAAIb,MAAM,mFAGhBsX,KAAKrJ,SAAS7J,MAAMG,OAAO1D,KAC3BuP,MACAw6H,aAAc,IAEd/pI,EAAIuP,IACJw6H,aAAc,IAIR,KADV7pI,EAAIuW,KAAKvH,cAAc3L,MAAO4L,QAAQ3S,MAAM,EAAG+S,KAAMH,WAAY,iBAAkB,CAAC,oBAE1E,IAAIjQ,MAAM,2JAGpBqQ,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,iBAAkB,YACnEnS,EAAI,EAAGA,EAAIuC,EAAGvC,IACf89D,IAAMh4D,MAAMwM,OAAO,YAAa,CAACF,KAAKiV,IAAM,GAAK9kB,EAAI,GAAKA,GAAIE,EAAEzC,EAAI,IAAK,CAACuQ,KAAM,WAC5E+7H,aACA7pI,EAAEzC,GAAG61F,aAAapzF,EAAEzC,EAAI,GAAI89D,KAC5Br7D,EAAEzC,GAAG0kF,eAED1rE,KAAKlJ,QAAQiC,KAAK44H,MAAQ54H,KAAK44H,IAAIpqI,QAAUgC,EAAI,IACjDwP,KAAKlP,GAAKkP,KAAK44H,IAAI3qI,EAAI,IAE3ByC,EAAEzC,GAAK8F,MAAMwM,OAAO,QAAS,CAAC7P,EAAEzC,EAAI,GAAI89D,KAAM/rD,MAC9CtP,EAAEzC,GAAGuQ,KAAOrB,MAAM3G,gBAIlB9F,EAAEzC,GAAG40F,aAAc,EACnBnyF,EAAEzC,GAAGyY,QAAQ4/D,OAAQ,UAI7BtmE,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,mBACtD4B,GAAKjO,MAAMwM,OAAO,UAAW7P,EAAGsP,OAC7BqjF,OAAS,iBAELrhF,IA8DXjQ,IAAIyoI,qBAAuB,SAAUzmI,MAAO4L,QAASC,gBAC7CI,KAAMgC,UAEVhC,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,mBACtD4B,GAAKjO,MAAMwM,OAAO,UAAWZ,QAASK,OACnCqjF,OAAS,iBAGZrhF,GAAGyuC,SAASrW,MACZrmC,MAAMs2F,aAAaroF,GAAG8qC,QAAQ9qC,GAAG8qC,QAAQt+C,OAAS,IAClDwT,GAAG8qC,QAAQ1S,MAEJp4B,IAGXjQ,IAAIsB,gBAAgB,UAAWtB,IAAIooI,eACnCpoI,IAAIsB,gBAAgB,iBAAkBtB,IAAIuoI,sBAC1CvoI,IAAIsB,gBAAgB,iBAAkBtB,IAAIyoI,sBAEnC,CACH9B,QAAS3mI,IAAI2mI,QACbyB,cAAepoI,IAAIooI,cACnBG,qBAAsBvoI,IAAIuoI,yBA0DlCvuI,OAAO,aAAa,CAChB,MAAO,iBAAkB,cAAe,eAAgB,YAAa,gBACrE,YAAa,gBAAiB,iBAAkB,aAAc,aAC/D,SAAUgG,IAAKoL,MAAO2a,OAAQ4qE,gBAAiB7qE,IAAKiR,SAAUmqB,KAAMnQ,SAAUi+C,cAAe95E,KAAMwzH,YAelG1oI,IAAI2oI,MAAQ,SAAU3mI,MAAO4L,QAASC,iBAC7BuE,YAAYpQ,MAAO6L,WAAYzC,MAAMjH,kBAAmBiH,MAAMrF,yBAE9DoI,OAAS,QAMTgrC,aAAejkC,KAAKrG,SAASjN,KAAK+S,QAAQi0H,uBAE1C7wF,aAAe,OAQfhV,MAAQ,UAQRC,MAAQ,UASR8sC,MAAQ,QAOR+4D,IAAM,KAEP3zH,KAAKzU,OAAOmN,QAAQ,SACfszB,QAAUtzB,QAAQ,QAElBszB,QAAU,SAId2jB,MAAQj3C,QAAQ,QAEhBk7H,MAAQl7H,QAAQ,QAGhB00F,aAAa1gG,KAAKs/B,QAASt/B,KAAKijD,MAAOjjD,KAAKknI,MAAOl7H,QAAQ,GAAIA,QAAQ,SAEvE81E,mBAEA3kF,GAAK6C,KAAKI,MAAMw/F,MAAM5/F,KAAM,UAC5BI,MAAMmvE,SAASsS,UAAU7hF,WAEzBI,MAAMy/F,eAAe7/F,WAErBo1F,sBACA1F,OAAS,aACT4E,cAEDhhF,KAAKvJ,SAAS/J,KAAKijD,aACd68C,cAAc9/F,KAAKijD,OAExB3vC,KAAKvJ,SAAS/J,KAAKknI,aACdpnC,cAAc9/F,KAAKknI,YAGvBn3C,UAAYz8E,KAAK3D,SAAS3P,KAAK+vF,UAAW,CAC3C2Q,aAAc,eACdymC,QAAS,eACT1tC,KAAM,SACNC,OAAQ,YAIhBt7F,IAAI2oI,MAAM7tI,UAAY,IAAI61F,gBAE1B3wF,IAAIC,OAAOD,IAAI2oI,MAAM7tI,UAA6C,CAO9Di+C,KAAM,iBAG4C,UAA1C7jC,KAAKrG,SAASjN,KAAK+S,QAAQwpC,WACpB,EAGE,IAAIp4B,OAAO3a,MAAMzH,iBAAkB,CAA2B,IAAzB/B,KAAKI,MAAM0yC,YAAmB,GAAI9yC,KAAKI,OAAO,GAC9E4N,UAAU,IAQhCkpC,KAAM,iBAG4C,UAA1C5jC,KAAKrG,SAASjN,KAAK+S,QAAQwpC,WACpB,EAAI7vC,KAAKiV,GAEN,IAAIwC,OAAO3a,MAAMzH,iBAAkB,CAA0B,IAAzB/B,KAAKI,MAAM0yC,YAAmB,GAAI9yC,KAAKI,OAAO,GAE7E4N,UAAU,IAYjCowB,EAAG,SAAUllB,UACFvK,KAYX0vB,EAAG,SAAUnlB,UACFvK,KAQX6tC,EAAG,SAAUtjC,UACF,GAUX87D,SAAU,SAAUlnE,EAAGiT,EAAG3G,WAClBlB,EAAGkuH,WAAYh7H,IAAKsuF,OAAQ9qF,EAC5BtV,EAAG+sI,GAAIC,GAEP/6H,OAAQ06H,IAGR1nG,KAAM10B,KAEN08H,IAAKC,IACLC,MACAhoF,GARAhgC,IAAM,GAENinC,MAAQpzC,KAAKrG,SAASjN,KAAK+S,QAAQ20H,iBACnCv8H,GAAKnL,KAAKk3C,OAASl3C,KAAKm3C,QAAUuP,MAElChhB,KAAOlkB,EAAAA,KAOPlO,KAAK/I,SAAS+I,KAAKrG,SAASjN,KAAK+S,QAAQwgE,aACzC1oE,KAAO7K,KAAKI,MAAM4/F,aAClBzgE,KAAOjsB,KAAKrG,SAASjN,KAAK+S,QAAQwgE,UAAU1oE,QAG5C00B,KAAOv/B,KAAKI,MAAMqM,QAAQ8mE,UAAUyB,SAGxClnE,GADAs5H,WAAa,IAAIjjH,OAAO3a,MAAMzH,iBAAkB,CAAC+L,EAAGiT,GAAI/gB,KAAKI,OAAO,IACrD4N,UAAU,GACzB+S,EAAIqmH,WAAWp5H,UAAU,GAIzBuxB,MAAkD,GAA1CjsB,KAAKrG,SAASjN,KAAK+S,QAAQlB,aACnC0tB,MAAQA,KACRgoG,IAAMvnI,KAAKI,MAAM2kB,MAAQ/kB,KAAKI,MAAM2kB,MACpCyiH,IAAMxnI,KAAKI,MAAM4kB,MAAQhlB,KAAKI,MAAM4kB,MAEpCy6B,GAAKz/C,KAAKm3C,OACLn3C,KAAKk3C,OACN5jC,KAAKzU,OAAOmB,KAAKmjD,gBACjB1D,GAAKz/C,KAAKmjD,aAAa,GAEvBh4C,GADKnL,KAAKmjD,aAAa,GACb1D,IAAMiH,OAIN,eADd+gF,MAAQn0H,KAAKrG,SAASjN,KAAK+S,QAAQwpC,aACI,UAAVkrF,UACrBznI,KAAK6mF,gBAAgBhsF,OAAS,SAKzBygG,wBACLZ,OAASx2E,IAAIjE,QAAQjgB,KAAKu7F,cAE1BztF,GADA8B,EAAIsU,IAAI3E,WAAWm7E,OAAQ,CAAC,EAAG5sF,EAAGiT,KAC5B,GACNA,EAAInR,EAAE,IAILtV,EAAI,EAAG4e,EAAIumC,GAAInlD,EAAIosD,MAAOpsD,IAAK,KAIhCorC,MAAQ53B,GAHRu5H,GAAKrnI,KAAKo+B,EAAEllB,EA7CA,SAgDOpL,EAAIu5H,IAAME,KAAOxmH,GAFpCumH,GAAKtnI,KAAKq+B,EAAEnlB,EA9CA,SAgDmC6H,EAAIumH,IAAME,MAE7CjoG,YACD,EAGXrmB,GAAK/N,OAEN,GAAc,SAAVs8H,OACG,kBAAVA,MAA2B,OAEtBn0H,KAAKzU,OAAOub,QAAUA,MAAQ,KAC/BA,MAAQ,GAGR9G,KAAKzU,OAAOmB,KAAKinI,MACjB3zH,KAAKrG,SAASjN,KAAK+S,QAAQ40H,SACL,IAAtB3nI,KAAKm2C,aAIL/pC,KADAG,QADA06H,IAAMjnI,KAAKinI,IAAIvyG,MAAM,IAAIvQ,OAAO3a,MAAM1H,eAAgB,CAACgM,EAAGiT,GAAI/gB,KAAKI,SACtDmM,QACA1R,QAEb0R,OAASvM,KAAKuM,OACdH,IAAMpM,KAAKu3C,aAAe,GAGzBj9C,EAAI8f,MAAO9f,EAAI8R,IAAK9R,OACK,IAAtB0F,KAAKm2C,aACL12B,IAAI/jB,KAAKyzC,SAASyM,6BAA6B,CAAC,EAAG9tC,EAAGiT,GAAI/gB,KAAM1F,IAE5D2sI,KACI16H,OAAOjS,GAAGgwB,OACV7K,IAAM0vB,SAASwM,uBACX,CAAC,EAAG7tC,EAAGiT,GACPxU,OAAOjS,GAAGgwB,KAAKtc,UACfzB,OAAOjS,GAAG0T,YAOdzB,OAAOjS,GAAGiwB,MAAQhe,OAAOjS,EAAI,KAAOiS,OAAOjS,GAAGiwB,OAC9C9K,IAAM0vB,SAASwM,uBACX,CAAC,EAAG7tC,EAAGiT,GACPxU,OAAOjS,GAAG0T,UACVzB,OAAOjS,GAAGiwB,KAAKvc,aAIvByR,IAAM0vB,SAASwM,uBACX,CAAC,EAAG7tC,EAAGiT,GACPxU,OAAOjS,GAAG0T,UACVzB,OAAOjS,EAAI,GAAG0T,WAKtByR,IAAI,IAAM,GAAKA,IAAI,IAAM,IACxB3R,EAAI2R,IAAI,GAAG,KAAO3R,EAAI2R,IAAI,GAAG,IAAM8nH,KACnCxmH,EAAItB,IAAI,GAAG,KAAOsB,EAAItB,IAAI,GAAG,IAAM+nH,KAAOjoG,YACpC,SAGR,SAEHmG,KAAOnG,MAMnBqoG,eAAgB,eACRttI,EAAG8R,OAEPA,IAAMpM,KAAKu3C,aAEPv3C,KAAKuM,OAAO1R,OAASmF,KAAKu3C,iBACrBj9C,EAAI0F,KAAKuM,OAAO1R,OAAQP,EAAI8R,IAAK9R,SAC7BiS,OAAOjS,GAAK,IAAI6pB,OAAO3a,MAAM1H,eAAgB,CAAC,EAAG,GAAI9B,KAAKI,OAAO,IAUlFo6B,OAAQ,kBACAx6B,KAAKivF,cACD37E,KAAKrG,SAASjN,KAAK+S,QAAQigE,aACtBigB,mBAAkB,QAEtBnR,eAGF9hF,MAOXkzF,eAAgB,kBAGPlzF,KAAKivF,aAINjvF,KAAKwhF,YAAYvvE,eAGZ6T,OAASw5B,KAAKC,UAAUv/C,KAAKuM,QAG7BvM,KAAK8lB,aACDw/D,kBAAiB,IAI1BtlF,KAAKwhF,YAAYvvE,cACZ7R,MAAMmvE,SAASuS,YAAY9hF,MAIhCA,KAAKovF,UAAYpvF,KAAKwhF,YAAYvvE,SAAWjS,KAAKkQ,OAClDlQ,KAAKkQ,MAAMsxE,YAAYvvE,SAAWjS,KAAK8lB,cAElC5V,MAAMsqB,cACNp6B,MAAMmvE,SAASgW,WAAWvlF,KAAKkQ,aAInCijF,0BAUAlE,aAAc,EACZjvF,MAtCIA,MA4Rf6nI,gBAAiB,aASjB/lD,YAAa,eACL11E,IAAKqzC,GAAIt/B,GAAIrS,EAAGiT,EAAGzmB,EACnBqH,QAAU3B,KAAK+S,QAAQ+0H,YAEvBjqF,eAAgB,UAEfy9C,6BACAusC,kBACLpoF,GAAKz/C,KAAKm3C,OACVh3B,GAAKngB,KAAKk3C,OAIN5jC,KAAKzU,OAAOmB,KAAKmhC,gBACZoW,aAAev3C,KAAKmhC,MAAMtmC,OAC/BuR,IAAMpM,KAAKu3C,kBAGNqwF,iBAEAttI,EAAI,EAAGA,EAAI8R,IAAK9R,IACjBwT,EAAIxT,EAGAgZ,KAAKzU,OAAOmB,KAAKohC,QACjBrgB,EAAIzmB,OAECiS,OAAOjS,GAAGkqB,eAAehb,MAAM1H,eAAgB,CAAC9B,KAAKmhC,MAAM7mC,GAAI0F,KAAKohC,MAAM9mC,KAAK,KAGpFymB,EAAI/gB,KAAKo+B,EAAEtwB,QAENvB,OAAOjS,GAAGkqB,eAAehb,MAAM1H,eAAgB,CAAC9B,KAAKmhC,MAAM7mC,GAAI0F,KAAKq+B,EAAEtd,EAAG88B,iBAAiB,SAE9FtxC,OAAOjS,GAAGqlD,GAAKrlD,EAGpBujD,eAAgB,UAIhBvqC,KAAKrG,SAASjN,KAAK+S,QAAQg1H,gBAGX,IAAZpmI,SAAiB2R,KAAKrG,SAASjN,KAAK+S,QAAQi1H,mBAC5C1oF,KAAKW,yBAAyBjgD,KAAMy/C,GAAIt/B,IACrB,IAAZxe,QACP29C,KAAKoD,yBAAyB1iD,KAAMy/C,GAAIt/B,IACrB,IAAZxe,QACP29C,KAAK+F,yBAAyBrlD,KAAMy/C,GAAIt/B,IACrB,IAAZxe,QACP29C,KAAK6K,yBAAyBnqD,KAAMy/C,GAAIt/B,IAExCm/B,KAAKoD,yBAAyB1iD,KAAMy/C,GAAIt/B,KAIxCngB,KAAKI,MAAMwgD,gBAAkB5gD,KAAKI,MAAMq0G,wBACnCl9D,aAAejkC,KAAKrG,SAASjN,KAAK+S,QAAQi0H,uBAE1CzvF,aAAejkC,KAAKrG,SAASjN,KAAK+S,QAAQ20H,sBAI9CE,iBACLtoF,KAAKE,2BAA2Bx/C,KAAMy/C,GAAIt/B,GAAIngB,KAAKu3C,eAEvDnrC,IAAMpM,KAAKu3C,aAEPjkC,KAAKrG,SAASjN,KAAK+S,QAAQ40H,SAC3B3nI,KAAKI,MAAMwgD,gBAAkB5gD,KAAKI,MAAMq0G,4BACnCwyB,IAAM,IAAIH,IAAI9mI,KAAKI,MAAMkzC,kBACzBh5C,EAAI,EAAGA,EAAI0F,KAAKuM,OAAO1R,OAAQP,SAC3B2sI,IAAI5yG,OAAOr0B,KAAKuM,OAAOjS,IAExBA,EAAI,SACCiS,OAAOjS,GAAGgwB,KAAOtqB,KAAKuM,OAAOjS,EAAI,IAGtCA,EAAI8R,IAAM,SACLG,OAAOjS,GAAGiwB,KAAOvqB,KAAKuM,OAAOjS,EAAI,QAUR,SAA1CgZ,KAAKrG,SAASjN,KAAK+S,QAAQwpC,YAC3BjpC,KAAKrG,SAASjN,KAAK+S,QAAQk1H,qBAEtB17H,OAAS4oB,SAAS8P,oBAAoBjlC,KAAKuM,OAAQ,SACnDgrC,aAAev3C,KAAKuM,OAAO1R,QAKpCuR,IAAMpM,KAAKu3C,aACNj9C,EAAI,EAAGA,EAAI8R,IAAK9R,SACZmiD,gBAAgBz8C,KAAKuM,OAAOjS,WAG9B0F,MAGXs7F,sBAAuB,eACfpiF,EAAG5e,EACH8R,IAAMpM,KAAK6mF,gBAAgBhsF,gBAE1B0gG,aAAe,CAAC,CAAC,EAAG,EAAG,GAAI,CAAC,EAAG,EAAG,GAAI,CAAC,EAAG,EAAG,IAE7CjhG,EAAI,EAAGA,EAAI8R,IAAK9R,KACjB4e,EAAIlZ,KAAK6mF,gBAAgBvsF,IACvBkgC,cACG+gE,aAAer3E,IAAIxE,WAAWxG,EAAE8F,OAAQhf,KAAKu7F,qBAG/Cv7F,MASXy8C,gBAAiB,SAAU1/C,OACnB6S,SACM5P,KAAK6mF,gBAAgBhsF,OAErB,IACN+U,EAAIsU,IAAI3E,WAAWvf,KAAKu7F,aAAcx+F,EAAEiR,WACxCjR,EAAEynB,eAAehb,MAAM1H,eAAgB8N,GAAG,GAAO,IAG9C7S,GAQXozF,aAAc,SAAUoB,eAChBj3F,EACAqW,KAAO2C,KAAKlJ,QAAQmnF,WAAaA,UAAY,CAACA,WAC9CnlF,IAAMuE,KAAK9V,WAEVP,EAAI,EAAGA,EAAI8R,IAAK9R,SACZusF,gBAAgBnrF,KAAKiV,KAAKrW,WAG5B0F,MAUXkoI,+BAAgC,SAAUznG,WAClC5B,KAAO,OAAS4B,MAChBf,KAAO1/B,YAEJ,SAAUkZ,EAAGslB,qBACZlkC,EAAGC,EAAGonC,GAAIlE,GACVlwB,IAAMmyB,KAAKb,MACXzyB,IAAMmB,IAAI1S,OAEV+B,EAAI,MAEJ8R,MAAMwK,UACCvK,OAGPuK,EAAI,SACA5F,KAAKnJ,WAAWoD,IAAI,IACbA,IAAI,KAGRA,IAAI,MAGW,IAAtBmyB,KAAKyW,aAAoB,IAGrBj9B,IAFI9M,IAAM,GAAK,SAGXkH,KAAKnJ,WAAWoD,IAAIA,IAAI1S,OAAS,IAC1B0S,IAAIA,IAAI1S,OAAS,KAGrB0S,IAAIA,IAAI1S,OAAS,OAG5BP,EAAoB,EAAhBoS,KAAKmS,MAAM3F,GAEfukB,GAAK,GADLkE,GAAKzoB,EAAI,GAGJ3e,EAAI,EAAGA,EAAI,EAAGA,IACX+Y,KAAKnJ,WAAWoD,IAAIjT,EAAIC,IACxBqC,EAAErC,GAAKgT,IAAIjT,EAAIC,KAEfqC,EAAErC,GAAKgT,IAAIjT,EAAIC,UAIhBkjC,GAAKA,IAAMA,GAAK7gC,EAAE,GAAK,EAAI+kC,GAAK/kC,EAAE,KAAO,EAAI6gC,GAAK7gC,EAAE,GAAK+kC,GAAK/kC,EAAE,IAAM+kC,GAAKA,OAIlFrnC,EADA4e,EAAI9M,IAAM,EACNA,IAAM,EAEN+N,SAASzN,KAAKmS,MAAM3F,GAAI,OAGtBA,SACF5F,KAAKnJ,WAAWoD,IAAIjT,IACbiT,IAAIjT,KAERiT,IAAIjT,OAGVC,EAAI,EAAGA,EAAI,EAAGA,IACX+Y,KAAKnJ,WAAWoD,IAAIjT,EAAIC,IACxBqC,EAAErC,GAAKgT,IAAIjT,EAAIC,KAEfqC,EAAErC,GAAKgT,IAAIjT,EAAIC,UAGhBqC,EAAE,IAAMA,EAAE,GAAKA,EAAE,KAAOsc,EAAI5e,KAU3ComG,aAAc,SAAUphE,QAAS2jB,MAAOikF,MAAOznF,GAAIt/B,QAC3CskB,GAAImrF,GAGJt8G,KAAKlJ,QAAQ64C,aAER9hB,MAAQ8hB,WAER1L,aAAev3C,KAAKmhC,MAAMtmC,YAC1BujC,EAAIp+B,KAAKkoI,+BAA+BvsI,MAAMqE,KAAM,CAAC,WACrD+S,QAAQwpC,UAAY,YACpB2yC,aAAc,SAGd9wD,EAAI9qB,KAAK/H,eAAe03C,MAAOjjD,KAAKI,MAAOk/B,SAC5ChsB,KAAKvJ,SAASk5C,YACTlwC,QAAQwpC,UAAY,iBAClBjpC,KAAKnJ,WAAW84C,QAAU3vC,KAAKrJ,SAASg5C,eAC1ClwC,QAAQwpC,UAAY,kBAGxB2yC,aAAc,GAGnB57E,KAAKlJ,QAAQ88H,aACR9lG,MAAQ8lG,WACR7oG,EAAIr+B,KAAKkoI,+BAA+BvsI,MAAMqE,KAAM,CAAC,YAErDq+B,EAAI/qB,KAAK/H,eAAe27H,MAAOlnI,KAAKI,MAAOk/B,SAOhDhsB,KAAKnJ,WAAW84C,QAAU3vC,KAAKlJ,QAAQ88H,SAEvCziG,GAAKnxB,KAAK/H,eAAe27H,MAAM,GAAIlnI,KAAKI,MAAO,IAC/CwvH,GAAKt8G,KAAK/H,eAAe27H,MAAM,GAAIlnI,KAAKI,MAAO,SAE1Cg+B,EAAI,SAAU2K,YACRka,MAAMla,KAAOr8B,KAAK8hB,IAAIua,KAAOtE,WAGnCpG,EAAI,SAAU0K,YACRka,MAAMla,KAAOr8B,KAAKwiB,IAAI6Z,KAAO6mF,WAGnC78G,QAAQwpC,UAAY,SAIzBjpC,KAAKzU,OAAO4gD,WACPtI,KAAO7jC,KAAK/H,eAAek0C,GAAIz/C,KAAKI,MAAO,KAEhDkT,KAAKzU,OAAOshB,WACP+2B,KAAO5jC,KAAK/H,eAAe4U,GAAIngB,KAAKI,MAAO,MASxD0/F,cAAe,SAAU8B,gBACjBumC,KAAMC,IAEN5uI,IADA6uI,cAAe,MAKdF,QADL3uI,IAAM,OAAW,QAAY,MAErBA,IAAIL,eAAegvI,OAASnoI,KAAK7G,eAAegvI,OAASnoI,KAAKmoI,MAAMr8H,WAE/Ds8H,OADLC,cAAe,EACHroI,KAAKmoI,MAAMr8H,OAAOzO,KACtB2C,KAAKmoI,MAAMr8H,OAAOzO,KAAKlE,eAAeivI,WACjCD,MAAMr8H,OAAOzO,KAAK+qI,KAAKv5C,SAAS7uF,MAMhDqoI,cACDj7C,cAAcsB,iBAAiB1uF,KAAM4hG,WAAY5hG,KAAKI,QAK9D80F,eAAgB,eACRtlF,EAAG9B,EAAGiT,EACNyuB,GAAK,IAAOxvC,KAAKI,MAAM0yC,YACvBrD,GAAK,IAAOzvC,KAAKI,MAAM2yC,aACvBrD,GAAK,IAAO1vC,KAAKI,MAAM0yC,YACvBnD,GAAK,IAAO3vC,KAAKI,MAAM2yC,oBAEnBz/B,KAAKrG,SAASjN,KAAK+S,QAAQ7C,MAAM2H,eAChC,OACD/J,EAAI0hC,GACJzuB,EAAI0uB,aAEH,OACD3hC,EAAI0hC,GACJzuB,EAAI4uB,aAEH,KACD7hC,EAAI4hC,GACJ3uB,EAAI,GAAM4uB,aAET,MACD7hC,EAAI4hC,GACJ3uB,EAAI4uB,aAEH,MACD7hC,EAAI4hC,GACJ3uB,EAAI0uB,aAEH,MACD3hC,EAAI,GAAM4hC,GACV3uB,EAAI0uB,aAEH,MACD3hC,EAAI,GAAM4hC,GACV3uB,EAAI4uB,iBAIJ7hC,EAAI0hC,GACJzuB,EAAI,GAAM4uB,UAGlB//B,EAAI,IAAIuU,OAAO3a,MAAMzH,iBAAkB,CAAC+L,EAAGiT,GAAI/gB,KAAKI,OAAO,GACpD+uC,SAAS4M,qBAAqBnsC,EAAE5B,UAAU,GAAI4B,EAAE5B,UAAU,GAAI,EAAGhO,KAAMA,KAAKI,OAAO,IAI9F6yF,kBAAmB,eACXisC,GACAt5G,KAAO,CACHzoB,GAAI6C,KAAK7C,GAAK,IAAM6C,KAAKuvF,UACzB9kF,aAAcjB,MAAMrF,mBAEpBoI,OAAQvM,KAAKuM,OAAOlT,MAAM,GAC1B88C,aAAcn2C,KAAKm2C,aACnBoB,aAAcv3C,KAAKu3C,aACnBn3C,MAAOJ,KAAKI,MACZ2S,QAASO,KAAK3D,SAAS3P,KAAK+S,QAAS/S,KAAK+S,QAAQ+pH,iBAAiB,WAG3El3G,KAAK7S,QAAQ9C,MAAQjQ,KAAKI,MAAMqM,QAAQwD,MAAM+iE,MAC9CptD,KAAK7S,QAAQwpC,UAAYv8C,KAAK+S,QAAQwpC,eACjCgzC,YAELj8E,KAAKxC,gBAAgB8U,MACrBA,KAAK47D,YAAc,CACfvvE,QAASqB,KAAKrG,SAAS2Y,KAAK7S,QAAQd,UAExCitH,GAAKl/H,KAAKI,MAAMmvE,SAAS8P,uBACpBj/E,MAAMmvE,SAAS8P,mBAAoB,OACnCj/E,MAAMmvE,SAASsS,UAAUj8D,WACzBxlB,MAAMmvE,SAAS8P,kBAAoB6/C,QACnC5vC,OAAO1pE,KAAKzoB,IAAMyoB,KAAK+6D,SAErB3gF,MAIXu1F,OAAQ,eAEwBj7F,EACxBmnC,OAAQvJ,GAFRif,KAAO31B,EAAAA,EAAU01B,MAAQ11B,EAAAA,EAAU4jG,KAAO5jG,EAAAA,EAAU6jG,MAAQ7jG,EAAAA,EAC5D1O,EAAI9S,KAAKuM,OAAO1R,UAGM,IAAtBmF,KAAKm2C,aAAoB,KAEpB77C,EAAI,EAAGA,EAAIwY,EAAGxY,SACViS,OAAOjS,GAAG8jC,EAAI9qB,KAAKxG,MAAK,kBAAqB9M,KAAKgO,UAAU,KAAOhO,KAAKuM,OAAOjS,SAC/EiS,OAAOjS,GAAG+jC,EAAI/qB,KAAKxG,MAAK,kBAAqB9M,KAAKgO,UAAU,KAAOhO,KAAKuM,OAAOjS,WAGxF49B,IADAuJ,OAAStM,SAASsM,OAAOzhC,KAAKuM,SAClB,KACZ4qC,KAAOhiB,SAAS2O,QAAO,SAAU5qB,UAAYuoB,OAAO,GAAGvoB,KAAO,CAAC,EAAGgf,KAClEgf,KAAO/hB,SAAS2O,QAAO,SAAU5qB,UAAauoB,OAAO,GAAGvoB,KAAO,CAAC,EAAGgf,KACnEktF,KAAOjwF,SAAS2O,QAAO,SAAU5qB,UAAYuoB,OAAO,GAAGvoB,KAAO,CAAC,EAAGgf,KAClEmtF,KAAOlwF,SAAS2O,QAAO,SAAU5qB,UAAauoB,OAAO,GAAGvoB,KAAO,CAAC,EAAGgf,KAEnEif,KAAO1V,OAAO,GAAG0V,MACjBD,KAAOzV,OAAO,GAAGyV,MACjBkuE,KAAO3jF,OAAO,GAAG2jF,MAEV,CAACjuE,KADRkuE,KAAO5jF,OAAO,GAAG4jF,MACGnuE,KAAMkuE,UAIzB9qH,EAAI,EAAGA,EAAIwY,EAAGxY,IACX68C,KAAOn3C,KAAKuM,OAAOjS,GAAG0T,UAAU,KAChCmpC,KAAOn3C,KAAKuM,OAAOjS,GAAG0T,UAAU,IAGhCkpC,KAAOl3C,KAAKuM,OAAOjS,GAAG0T,UAAU,KAChCkpC,KAAOl3C,KAAKuM,OAAOjS,GAAG0T,UAAU,IAGhCo3G,KAAOplH,KAAKuM,OAAOjS,GAAG0T,UAAU,KAChCo3G,KAAOplH,KAAKuM,OAAOjS,GAAG0T,UAAU,IAGhCq3G,KAAOrlH,KAAKuM,OAAOjS,GAAG0T,UAAU,KAChCq3G,KAAOrlH,KAAKuM,OAAOjS,GAAG0T,UAAU,UAIjC,CAACmpC,KAAMkuE,KAAMnuE,KAAMkuE,OAI9B/uB,WAAY,eACJt5F,EAAI,CAACiD,KAAKijD,MAAOjjD,KAAKknI,MAAOlnI,KAAKm3C,OAAQn3C,KAAKk3C,eAEvB,IAAxBl3C,KAAKgM,QAAQnR,SACbkC,EAAIiD,KAAKgM,SAGNjP,GASX28F,OAAQ,SAAU+E,WAEE1hG,EAAZw2B,MAAQ,UACRvzB,KAAKuM,OAAO1R,OAAS,IAAMyY,KAAKrG,SAASjN,KAAK+S,QAAQ4/D,SACtD51E,EAAIiD,KAAKuM,OAAO,GAEZgnB,MADiB,IAAjBkrE,MAAM5jG,OACE,CAAC4jG,MAAM,GAAK1hG,EAAEiR,UAAU,GAChCywF,MAAM,GAAK1hG,EAAEiR,UAAU,GACvBywF,MAAM,GAAK1hG,EAAEiR,UAAU,IAEf,CAACywF,MAAM,GAAK1hG,EAAEiR,UAAU,GAChCywF,MAAM,GAAK1hG,EAAEiR,UAAU,SAEtByjF,YAAYjoF,MAAM1H,eAAgByxB,QAEpCvzB,MAcXo7F,wBAAyB,eACjBR,cAAe0tC,iBACfh1H,KAAKzU,OAAOmB,KAAKq7F,yBACjBitC,UAAYtoI,KAAKq7F,uBACH5wF,eAAiBjB,MAAMrF,qBAGjCy2F,eAAgB,GAGjB,CAACA,cAAe0tC,cAqK/BlqI,IAAImqI,YAAc,SAAUnoI,MAAO4L,QAASC,gBACpCzS,IAAK+8C,GACLlqC,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,gBAE1DjT,IAAM4G,MAAMG,OAAOyL,QAAQ,IAAI,GAC3BsH,KAAK/I,SAAS/Q,OACbA,IAAIqR,OAASrB,MAAMjH,mBAChB/I,IAAIqR,OAASrB,MAAMtG,mBACnB1J,IAAIqR,OAASrB,MAAMxH,iBACnBxI,IAAIqR,OAASrB,MAAMlH,mBACnB9I,IAAIqR,OAASrB,MAAMxG,qBACvBsQ,KAAK1I,wBAAwBoB,QAAQ,KAEjCxS,IAAIqR,OAASrB,MAAMxG,mBACnBqJ,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,UAC/CjT,IAAIqR,OAASrB,MAAMxH,gBAC1BqK,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,OAC/CjT,IAAIqR,OAASrB,MAAMtG,mBACrBoQ,KAAKzU,OAAOoN,WAAW4mE,aACxB5mE,WAAW4mE,WAAY,GAE3BxmE,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,UAEtDJ,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,SAE1DJ,KAAOiH,KAAK9G,eAAeH,KAAMjM,MAAMqM,QAAS,UAEhD8pC,GAAK,IAAIn4C,IAAI2oI,MAAM3mI,MAAO,CAAC,IAAK,GAAI,IAAKiM,OACtCw7H,gBAAkB,eACbvtI,EAAG0mB,GAAKxnB,IAAI+9C,sBACXpB,aAAe38C,IAAI28C,kBACnBhV,MAAQ,QACRC,MAAQ,GACR9mC,EAAI,EAAGA,EAAI0mB,GAAI1mB,SACX6mC,MAAMzlC,KAAKlC,IAAI+S,OAAOjS,GAAG0T,UAAU,SACnCozB,MAAM1lC,KAAKlC,IAAI+S,OAAOjS,GAAG0T,UAAU,WAErChO,MAEXu2C,GAAG45C,aAAankF,QAAQ,IACxBxS,IAAIq1F,SAASt4C,IACbA,GAAG66C,WAAW,CAAC53F,MACf+8C,GAAG8kD,sBAAwB7hG,IAEpB+8C,KAEXlqC,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,SAC/C,IAAIrO,IAAI2oI,MAAM3mI,MAAO,CAAC,KAAKlF,OAAO8Q,SAAUK,QAGvDjO,IAAIsB,gBAAgB,QAAStB,IAAImqI,aA4CjCnqI,IAAIoqI,oBAAsB,SAAUpoI,MAAO4L,QAASC,gBAC5CI,KACA8kF,IAAM,CAAC,IAAK,KAAKj2F,OAAO8Q,gBAE5BK,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,UACjD8vC,UAAY,gBACV,IAAIn+C,IAAI2oI,MAAM3mI,MAAO+wF,IAAK9kF,OAGrCjO,IAAIsB,gBAAgB,gBAAiBtB,IAAIoqI,qBACzCpqI,IAAIsB,gBAAgB,OAAQtB,IAAIoqI,qBAkDhCpqI,IAAIqqI,aAAe,SAAUroI,MAAO4L,QAASC,gBACrCoC,GAAIggF,MAAO7wF,WAEf6wF,MAAQ,eACAnxD,EAAGpvB,EAAI,GAAIiT,EAAI,SAEZ,CAAC,SAAU7H,EAAG2E,eACbvjB,EAAGC,EAAGqV,MAELiO,UAAW,IACZ/P,EAAI,GACJiT,EAAI,GAGmB,IAAnB/U,QAAQnR,QAAgByY,KAAKlJ,QAAQ4B,QAAQ,KAAOsH,KAAKlJ,QAAQ4B,QAAQ,KAAOA,QAAQ,GAAGnR,SAAWmR,QAAQ,GAAGnR,WAC5GP,EAAI,EAAGA,EAAI0R,QAAQ,GAAGnR,OAAQP,IAC3BgZ,KAAKnJ,WAAW6B,QAAQ,GAAG1R,IAC3BwT,EAAEpS,KAAKsQ,QAAQ,GAAG1R,MAElBwT,EAAEpS,KAAKsQ,QAAQ,GAAG1R,IAGlBgZ,KAAKnJ,WAAW6B,QAAQ,GAAG1R,IAC3BymB,EAAErlB,KAAKsQ,QAAQ,GAAG1R,MAElBymB,EAAErlB,KAAKsQ,QAAQ,GAAG1R,aAIrBA,EAAI,EAAGA,EAAI0R,QAAQnR,OAAQP,OACxBgZ,KAAK9I,QAAQwB,QAAQ1R,IACrBwT,EAAEpS,KAAKsQ,QAAQ1R,GAAG8jC,KAClBrd,EAAErlB,KAAKsQ,QAAQ1R,GAAG+jC,UAEf,GAAI/qB,KAAKlJ,QAAQ4B,QAAQ1R,KAA6B,IAAtB0R,QAAQ1R,GAAGO,WACzCN,EAAI,EAAGA,EAAIyR,QAAQnR,OAAQN,IACxB+Y,KAAKnJ,WAAW6B,QAAQzR,GAAG,IAC3BuT,EAAEpS,KAAKsQ,QAAQzR,GAAG,MAElBuT,EAAEpS,KAAKsQ,QAAQzR,GAAG,IAGlB+Y,KAAKnJ,WAAW6B,QAAQzR,GAAG,IAC3BwmB,EAAErlB,KAAKsQ,QAAQzR,GAAG,MAElBwmB,EAAErlB,KAAKsQ,QAAQzR,GAAG,SAGnB+Y,KAAKnJ,WAAW6B,QAAQ1R,KAA+B,IAAxB0R,QAAQ1R,KAAKO,SACnD+U,EAAI5D,QAAQ1R,KACZwT,EAAEpS,KAAKkU,EAAE,IACTmR,EAAErlB,KAAKkU,EAAE,KAOrBstB,EAAI/H,SAASuJ,UAAU5wB,EAAGiT,UAGvBoU,SAAS6J,WAAW9lB,EAAGpL,EAAGiT,EAAGmc,IAGxC,kBACWpvB,EAAE,IAGb,kBACWA,EAAEA,EAAEjT,OAAS,OAK5BoR,WAAaqH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,UACjD8vC,UAAY,gBACvB/+C,IAAM6wF,SACNhgF,GAAK,IAAIjQ,IAAI2oI,MAAM3mI,MAAO,CAAC,IAAK,IAAK5C,IAAI,GAAIA,IAAI,GAAIA,IAAI,IAAKyO,aAC3DmlF,WAAWplF,SACdqC,GAAGqhF,OAAS,SAELrhF,IAOXjQ,IAAIsB,gBAAgB,SAAUtB,IAAIqqI,cA2DlCrqI,IAAIsqI,qBAAuB,SAAUtoI,MAAO4L,QAASC,gBAC7CoC,GAAIs6H,aACJp8H,OAAQg0B,IAAK11B,KACb9N,EAAGgrB,EAAGztB,EAAG0mB,GACT4nH,UACA13B,OAAS,gFAER59F,KAAKzU,OAAOmN,QAAQ,MAAQsH,KAAKlJ,QAAQ4B,QAAQ,UAC5C,IAAIhQ,MAAM,wGAA0Gk1G,YAEzH59F,KAAKzU,OAAOmN,QAAQ,MAASsH,KAAKrJ,SAAS+B,QAAQ,MAAQsH,KAAKnJ,WAAW6B,QAAQ,UAC9E,IAAIhQ,MAAM,mGAAqGk1G,YAEpH59F,KAAKzU,OAAOmN,QAAQ,MAAQsH,KAAKvJ,SAASiC,QAAQ,UAC7C,IAAIhQ,MAAM,oGAAsGk1G,WAG1HjlG,WAAaqH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,UAC5DR,WAAaqH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,mBACjD8vC,UAAY,YAEvBx/C,EAAIiP,QAAQ,GACZ+b,EAAI,IAGC9b,WAAW48H,sBACC,IAAb9rI,EAAElC,QAAgByY,KAAKlJ,QAAQrN,EAAE,KAAOuW,KAAKlJ,QAAQrN,EAAE,KACvDA,EAAE,GAAGlC,SAAWkC,EAAE,GAAGlC,WAChBP,EAAI,EAAGA,EAAIyC,EAAE,GAAGlC,OAAQP,IACzBytB,EAAEztB,GAAK,GACHgZ,KAAKnJ,WAAWpN,EAAE,GAAGzC,IACrBytB,EAAEztB,GAAGoB,KAAKqB,EAAE,GAAGzC,MAEfytB,EAAEztB,GAAGoB,KAAKqB,EAAE,GAAGzC,IAGfgZ,KAAKnJ,WAAWpN,EAAE,GAAGzC,IACrBytB,EAAEztB,GAAGoB,KAAKqB,EAAE,GAAGzC,MAEfytB,EAAEztB,GAAGoB,KAAKqB,EAAE,GAAGzC,aAKlBA,EAAI,EAAGA,EAAIyC,EAAElC,OAAQP,IAClBgZ,KAAKvJ,SAAShN,EAAEzC,IAChBytB,EAAErsB,KAAK0E,MAAMG,OAAOxD,EAAEzC,KACfgZ,KAAK9I,QAAQzN,EAAEzC,IACtBytB,EAAErsB,KAAKqB,EAAEzC,IAEFgZ,KAAKlJ,QAAQrN,EAAEzC,KAAuB,IAAhByC,EAAEzC,GAAGO,QAClCktB,EAAEztB,GAAK,GACHgZ,KAAKnJ,WAAWpN,EAAEzC,GAAG,IACrBytB,EAAEztB,GAAGoB,KAAKqB,EAAEzC,GAAG,MAEfytB,EAAEztB,GAAGoB,KAAKqB,EAAEzC,GAAG,IAGfgZ,KAAKnJ,WAAWpN,EAAEzC,GAAG,IACrBytB,EAAEztB,GAAGoB,KAAKqB,EAAEzC,GAAG,MAEfytB,EAAEztB,GAAGoB,KAAKqB,EAAEzC,GAAG,KAEZgZ,KAAKnJ,WAAWpN,EAAEzC,KAAyB,IAAlByC,EAAEzC,KAAKO,QACvCktB,EAAErsB,KAAKsQ,QAAQ1R,UAKK,IAA5B2R,WAAW68H,aACXv8H,OAAS+G,KAAKvH,cAAc3L,MAAO2nB,EAAG9b,WAAY,iBAAkB,CAAC,oBAErEM,OAAS,GAKTo8H,aAAe,SAAUI,UACd,CACH3qG,EAAG,kBAAqBrW,EAAEghH,IAAI,IAC9B1qG,EAAG,kBAAqBtW,EAAEghH,IAAI,IAC9BjoG,KAAM,SAAU/jC,OACR+hC,GAAK9+B,KAAKo+B,IAAMrhC,EAAEqhC,IAClB2C,GAAK/gC,KAAKq+B,IAAMthC,EAAEshC,WACf3xB,KAAKmU,KAAKie,GAAKA,GAAKiC,GAAKA,OAKvCzmC,EAAI,EAAGA,EAAIytB,EAAEltB,OAAQP,IAClBgZ,KAAK9I,QAAQud,EAAEztB,IACfiS,OAAO7Q,KAAKqsB,EAAEztB,IAEdiS,OAAO7Q,KAAKitI,aAAaruI,QAKrCimC,IAAMv0B,QAAQ,GACdnB,KAAOmB,QAAQ,GAEf48H,UAAY,CAAC,KAAK1tI,OAAOi6B,SAASkL,eAAe9zB,OAAQg0B,IAAK11B,OAE9DwD,GAAK,IAAIjQ,IAAI2oI,MAAM3mI,MAAOwoI,UAAW38H,YACrC+U,GAAKzU,OAAO1R,OACZwT,GAAG+iF,WAAW7kF,QACTjS,EAAI,EAAGA,EAAI0mB,GAAI1mB,IAChByC,EAAIwP,OAAOjS,GACPgZ,KAAK9I,QAAQzN,KACTuW,KAAKzU,OAAO9B,EAAE8P,UACdwB,GAAGwgF,SAAS9xF,UACLA,EAAE8P,SAET9P,EAAE8xF,SAASxgF,YAIvBA,GAAGqhF,OAAS,iBAELrhF,IAOXjQ,IAAIsB,gBAAgB,iBAAkBtB,IAAIsqI,sBAgG1CtqI,IAAI4qI,qBAAuB,SAAU5oI,MAAO4L,QAASC,gBAC7CoC,GAAIs6H,aACJp8H,OAAQiiD,SACRzxD,EAAGgrB,EAAGztB,EAAG0mB,GACTkwF,OAAS,8DAER59F,KAAKzU,OAAOmN,QAAQ,MAAQsH,KAAKlJ,QAAQ4B,QAAQ,UAC5C,IAAIhQ,MAAM,wGAA0Gk1G,YAEzH59F,KAAKzU,OAAOmN,QAAQ,MAAQsH,KAAK/I,SAASyB,QAAQ,UAC7C,IAAIhQ,MAAM,2FAA6Fk1G,WAGjHjlG,WAAaqH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,UAC5DR,WAAaqH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,mBACjD8vC,UAAY,YAEvBx/C,EAAIiP,QAAQ,GACZ+b,EAAI,IAGC9b,WAAW48H,sBACC,IAAb9rI,EAAElC,QAAgByY,KAAKlJ,QAAQrN,EAAE,KAAOuW,KAAKlJ,QAAQrN,EAAE,KACvDA,EAAE,GAAGlC,SAAWkC,EAAE,GAAGlC,WAChBP,EAAI,EAAGA,EAAIyC,EAAE,GAAGlC,OAAQP,IACzBytB,EAAEztB,GAAK,GACHgZ,KAAKnJ,WAAWpN,EAAE,GAAGzC,IACrBytB,EAAEztB,GAAGoB,KAAKqB,EAAE,GAAGzC,MAEfytB,EAAEztB,GAAGoB,KAAKqB,EAAE,GAAGzC,IAGfgZ,KAAKnJ,WAAWpN,EAAE,GAAGzC,IACrBytB,EAAEztB,GAAGoB,KAAKqB,EAAE,GAAGzC,MAEfytB,EAAEztB,GAAGoB,KAAKqB,EAAE,GAAGzC,aAKlBA,EAAI,EAAGA,EAAIyC,EAAElC,OAAQP,IAClBgZ,KAAKvJ,SAAShN,EAAEzC,IAChBytB,EAAErsB,KAAK0E,MAAMG,OAAOxD,EAAEzC,KACfgZ,KAAK9I,QAAQzN,EAAEzC,IACtBytB,EAAErsB,KAAKqB,EAAEzC,IAEFgZ,KAAKlJ,QAAQrN,EAAEzC,KAAuB,IAAhByC,EAAEzC,GAAGO,QAClCktB,EAAEztB,GAAK,GACHgZ,KAAKnJ,WAAWpN,EAAEzC,GAAG,IACrBytB,EAAEztB,GAAGoB,KAAKqB,EAAEzC,GAAG,MAEfytB,EAAEztB,GAAGoB,KAAKqB,EAAEzC,GAAG,IAGfgZ,KAAKnJ,WAAWpN,EAAEzC,GAAG,IACrBytB,EAAEztB,GAAGoB,KAAKqB,EAAEzC,GAAG,MAEfytB,EAAEztB,GAAGoB,KAAKqB,EAAEzC,GAAG,KAEZgZ,KAAKnJ,WAAWpN,EAAEzC,KAAyB,IAAlByC,EAAEzC,KAAKO,QACvCktB,EAAErsB,KAAKsQ,QAAQ1R,UAKK,IAA5B2R,WAAW68H,aACXv8H,OAAS+G,KAAKvH,cAAc3L,MAAO2nB,EAAG9b,WAAY,iBAAkB,CAAC,oBAErEM,OAAS,GAKTo8H,aAAe,SAAUI,UACd,CACH3qG,EAAG,kBAAqBrW,EAAEghH,IAAI,IAC9B1qG,EAAG,kBAAqBtW,EAAEghH,IAAI,MAIjCzuI,EAAI,EAAGA,EAAIytB,EAAEltB,OAAQP,IAClBgZ,KAAK9I,QAAQud,EAAEztB,IACfiS,OAAO7Q,KAAKqsB,EAAEztB,IAEdiS,OAAO7Q,KAAKitI,kBAKxBn6E,SAAWxiD,QAAQ,IAEnBqC,GAAK,IAAIjQ,IAAI2oI,MAAM3mI,MAAO,CAAC,IAAK,GAAI,GAAI,EAAGrD,EAAElC,OAAS,GAAIoR,aACvD47H,gBAAkB,eACbpoH,IAAKnlB,EACL8R,IAAMG,OAAO1R,OACbkC,EAAI,OAEHzC,EAAI,EAAGA,EAAI8R,IAAK9R,IACjByC,EAAErB,KAAK,CAAC6Q,OAAOjS,GAAG8jC,IAAK7xB,OAAOjS,GAAG+jC,MAGrC5e,IAAMrhB,IAAIsO,KAAK29C,SAAShR,MAAMt8C,EAAGyxD,eAC5BrtB,MAAQ1hB,IAAI,QACZ2hB,MAAQ3hB,IAAI,IAErBpR,GAAG8nC,aAAe,EAElBn1B,GAAKzU,OAAO1R,OACZwT,GAAG+iF,WAAW7kF,QACTjS,EAAI,EAAGA,EAAI0mB,GAAI1mB,IACZgZ,KAAK9I,QAAQ+B,OAAOjS,KACpBiS,OAAOjS,GAAGu0F,SAASxgF,WAG3BA,GAAGqhF,OAAS,iBAELrhF,IAGXjQ,IAAIsB,gBAAgB,iBAAkBtB,IAAI4qI,sBA4E1C5qI,IAAI6qI,iBAAmB,SAAU7oI,MAAO4L,QAASC,gBACzCpP,EAAGgO,KAAMjO,EAAGu0F,IAAKvhF,EAAGvD,SAExBA,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,eACjD8vC,UAAY,OAEjB3/C,EAAIoP,QAAQ,GACZnP,EAAIyW,KAAK/H,eAAeS,QAAQ,GAAI5L,MAAO,KAEtCkT,KAAKzU,OAAOhC,SACP,IAAIb,MAAM,uLAIpB6O,KAAOyI,KAAK/H,eAAeS,QAAQ,GAAI5L,MAAO,IAAI,IAC7CkT,KAAKzU,OAAOgM,YACP,IAAI7O,MAAM,8LAIpBm1F,IAAM,CAAC,CAAC,GAAI,CAAC,IAAIj2F,OAAO8Q,QAAQ3S,MAAM,KAEtCuW,EAAIxP,MAAMwM,OAAO,QAASukF,IAAK9kF,OAE7BuU,IAAM,EAQRhR,EAAEyD,MAAQ,kBACCrT,KAAK4gB,KAMhBhR,EAAEi4H,gBAAkB,eACZ1gH,EAAIgO,SAASkN,QAAQzlC,EAAGC,IAAKgO,OAAQ7K,KAAKm3C,OAAQn3C,KAAKk3C,aACtD/V,MAAQha,EAAE,QACVia,MAAQja,EAAE,QAGVvG,IAAMuG,EAAE,IAGVvX,GAGXxR,IAAIsB,gBAAgB,aAActB,IAAI6qI,kBAiCtC7qI,IAAI8qI,iBAAmB,SAAU9oI,MAAO4L,QAASC,gBACzC2D,EAAGimE,OAAQszD,WAAY98H,QAEJ,IAAnBL,QAAQnR,aACF,IAAImB,MAAM,oGAIpB65E,OAASz1E,MAAMG,OAAOyL,QAAQ,IAC9Bm9H,WAAa/oI,MAAMG,OAAOyL,QAAQ,IAE9B6pE,OAAOhrE,OAASrB,MAAMhH,qBAAuB8Q,KAAK9I,QAAQ2+H,kBACpD,IAAIntI,MAAM,iEACJgQ,QAAQ,IAAM,kBAAoBA,QAAQ,IADtC,qDAKpBK,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,eACjD8vC,UAAY,QACjB3sC,EAAIxP,MAAMwM,OAAO,QAAS,CAAC,CAAC,GAAI,CAAC,IAAKP,OAKnCw7H,gBAAkB,eACbvtI,EAAG0wC,KAAM9xB,EAAG7K,GAAI0tF,IAAKjuF,EAAGiT,EAAGysB,KAAM47F,UACjCpoH,GAAK3U,KAAKg9H,aACVC,QAAUzzD,OAAOh+D,SACjB0xH,SAAW1zD,OAAOujB,YAClB35C,GAAK8pF,SAASpyF,WAIlBnM,MAHSu+F,SAASryF,OAGLuI,IAAMz+B,QACdmgB,MAAQ,QACRC,MAAQ,GAMTmoG,SAAS9+H,eAAiBjB,MAAMrF,oBAChC6c,KAIC1mB,EAAI,EAAGA,EAAI0mB,GAAI1mB,IAAK,KAUhB+T,MATL6K,EAAIumC,GAAKnlD,EAAI0wC,KACbl9B,EAAIy7H,SAASnrG,EAAEllB,GAAKqwH,SAAS/sF,EAAEtjC,GAC/B6H,EAAIwoH,SAASlrG,EAAEnlB,GAAKqwH,SAAS/sF,EAAEtjC,GAG/B28D,OAAOic,oBAAoBtoF,MAAM1H,eAAgB,CAACgM,EAAGiT,IACrDysB,MAAO,EAGIxtC,KAAKI,MAAMsJ,WACd1J,KAAKI,MAAMsJ,QAAQvQ,eAAekV,OAClC0tF,IAAM/7F,KAAKI,MAAMsJ,QAAQ2E,OAEbwnE,SACRroC,MAAO,GAGPA,MAAQuuD,IAAI5oB,qBAEZi2D,UAAYrtC,IAAIhpF,QAAQigE,MACxB+oB,IAAIhpF,QAAQigE,OAAQ,EACpB+oB,IAAI9M,aAAc,EAClB8M,IAAIvhE,QAAO,GAGXuhE,IAAIhpF,QAAQigE,MAAQo2D,UAChBrtC,MAAQotC,wBAQnBhoG,MAAM7mC,GAAK6uI,WAAW/qG,SACtBgD,MAAM9mC,GAAK6uI,WAAW9qG,QAQ1BhwB,MAJLwnE,OAAOh+D,SAAWyxH,QAClB97F,MAAO,EAGIxtC,KAAKI,MAAMsJ,WACd1J,KAAKI,MAAMsJ,QAAQvQ,eAAekV,OAClC0tF,IAAM/7F,KAAKI,MAAMsJ,QAAQ2E,OACbwnE,SACRroC,MAAO,GAGPA,MAAQuuD,IAAI5oB,qBACZi2D,UAAYrtC,IAAIhpF,QAAQigE,MACxB+oB,IAAIhpF,QAAQigE,OAAQ,EACpB+oB,IAAI9M,aAAc,EAClB8M,IAAIvhE,QAAO,GACXuhE,IAAIhpF,QAAQigE,MAAQo2D,UAEhBrtC,MAAQotC,oBAQrBv5H,GAGXxR,IAAIsB,gBAAgB,aAActB,IAAI8qI,kBAwBtC9qI,IAAIorI,mBAAqB,SAAUppI,MAAO4L,QAASC,gBAC3C2D,EAAGvD,QACgB,IAAnBL,QAAQnR,aACF,IAAImB,MAAM,kHAIpBqQ,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,iBACtDmD,EAAIxP,MAAMwM,OAAO,QAASZ,QAASK,OAIhCw7H,gBAAkB,eACbvtI,EAAGC,EAAI,EACP6R,IAAMpM,KAAKijD,MAAMpoD,eAEhBsmC,MAAQ,QACRC,MAAQ,GAED,IAARh1B,aAIC+0B,MAAM5mC,GAAKyF,KAAKijD,MAAM,QACtB7hB,MAAM7mC,GAAKyF,KAAKknI,MAAM,KACzB3sI,EAEGD,EAAI,EAAGA,EAAI8R,MAAO9R,OACd6mC,MAAM5mC,GAAKyF,KAAKijD,MAAM3oD,QACtB8mC,MAAM7mC,GAAKyF,KAAKohC,MAAM7mC,EAAI,KAC7BA,OACG4mC,MAAM5mC,GAAKyF,KAAKijD,MAAM3oD,QACtB8mC,MAAM7mC,GAAKyF,KAAKknI,MAAM5sI,KACzBC,GAIHqV,GAGXxR,IAAIsB,gBAAgB,eAAgBtB,IAAIorI,oBA+BxCprI,IAAIqrI,iBAAmB,SAAUrpI,MAAO4L,QAASC,gBACzC2D,EACAypC,MAAOva,GAAIiC,GACX10B,QAEmB,IAAnBL,QAAQnR,QAAgBmR,QAAQ,GAAG09H,QAAUlgI,MAAMrF,yBAC7C,IAAInI,MAAM,qGAIpBqQ,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,SAEtD4sC,MAAQrtC,QAAQ,GAChB8yB,GAAK3J,SAAS+H,EAAEmc,MAAMjb,GACtB2C,GAAK5L,SAAS+H,EAAEmc,MAAMhb,IAEtBzuB,EAAIxP,MAAMwM,OAAO,QAAS,CACtB,SAAUsM,UAAYmgC,MAAMjb,EAAEllB,IAC9B,SAAUA,UAAY6nB,GAAG7nB,GAAK4lB,GAAG5lB,IACjCmgC,MAAMlC,OAAQkC,MAAMnC,QACrB7qC,OAED+kF,WAAW/3C,OAENzpC,GAGXxR,IAAIsB,gBAAgB,aAActB,IAAIqrI,kBAoCtCrrI,IAAIurI,wBAA0B,SAAUvpI,MAAO4L,QAASC,gBAChD2D,KAEmB,IAAnB5D,QAAQnR,aACF,IAAImB,MAAM,uHAIpB4T,EAAIxP,MAAMwM,OAAO,QAAS,CAAC,GAAI,IAAKX,aAIjC47H,gBAAkB,eACbx6H,EAAIjP,IAAIsO,KAAKisC,KAAK1qB,aAAajiB,QAAQ,GAAIA,QAAQ,GAAIhM,KAAKI,YAC3D+gC,MAAQ9zB,EAAE,QACV+zB,MAAQ/zB,EAAE,IAEZuC,GAqCXxR,IAAIwrI,iBAAmB,SAAUxpI,MAAO4L,QAASC,gBACzC2D,KAEmB,IAAnB5D,QAAQnR,aACF,IAAImB,MAAM,gHAIpB4T,EAAIxP,MAAMwM,OAAO,QAAS,CAAC,GAAI,IAAKX,aAIjC47H,gBAAkB,eACbx6H,EAAIjP,IAAIsO,KAAKisC,KAAKzqB,MAAMliB,QAAQ,GAAIA,QAAQ,GAAIhM,KAAKI,YACpD+gC,MAAQ9zB,EAAE,QACV+zB,MAAQ/zB,EAAE,IAEZuC,GAqCXxR,IAAIyrI,sBAAwB,SAAUzpI,MAAO4L,QAASC,gBAC9C2D,KAEmB,IAAnB5D,QAAQnR,aACF,IAAImB,MAAM,qHAIpB4T,EAAIxP,MAAMwM,OAAO,QAAS,CAAC,GAAI,IAAKX,aAIjC47H,gBAAkB,eACbx6H,EAAIjP,IAAIsO,KAAKisC,KAAKxqB,WAAWniB,QAAQ,GAAIA,QAAQ,GAAIhM,KAAKI,YACzD+gC,MAAQ9zB,EAAE,QACV+zB,MAAQ/zB,EAAE,IAEZuC,GAGXxR,IAAIsB,gBAAgB,kBAAmBtB,IAAIyrI,uBAC3CzrI,IAAIsB,gBAAgB,oBAAqBtB,IAAIurI,yBAC7CvrI,IAAIsB,gBAAgB,aAActB,IAAIwrI,kBAoGtCxrI,IAAI0rI,cAAgB,SAAU1pI,MAAO4L,QAASC,gBACtCq5G,IAAKhrH,EAAG8R,IACRC,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,cAEnC,IAAnBT,QAAQnR,aACF,IAAImB,MAAM,6JAGhBgQ,QAAQ,GAAGnR,OAAS,QACd,IAAImB,MAAM,6GAGpBspH,IAAMllH,MAAMwM,OAAO,QAAS,CAAC,GAAG,IAAKP,MAErCD,IAAMJ,QAAQ,GAAGnR,OACjByqH,IAAI1+F,EAAI,GACHtsB,EAAI,EAAGA,EAAI8R,IAAK9R,IACjBgrH,IAAI1+F,EAAEtsB,GAAKgZ,KAAK/H,eAAeS,QAAQ,GAAG1R,GAAI8F,MAAO,MAAM,UAE/DklH,IAAIx3G,EAAIwF,KAAK/H,eAAeS,QAAQ,GAAI5L,MAAO,MAAM,GACrDklH,IAAIxyF,EAAIxf,KAAK/H,eAAeS,QAAQ,GAAI5L,MAAO,MAAM,GAErDklH,IAAIuiB,gBAAkB,eACd5oF,GAAIC,GAAIvJ,GAAIC,GAAI4E,GAAIuvF,GAAIpnF,GAAIq0B,IAAKlpE,EAErC60C,GAAMrvC,KAAKrG,SAASjN,KAAK+S,QAAQi3H,YACjChzD,IAAM1jE,KAAKrG,SAASjN,KAAK+S,QAAQikE,KAEjCrhC,IADA7nC,EAAI9N,KAAK8N,KACW,GAAX9N,KAAK8yB,IACd8iB,GAAK9nC,EAAe,GAAX9N,KAAK8yB,IAAY6vB,GAC1BnI,GAAK1sC,EAAe,GAAX9N,KAAK8yB,IAEdmsB,GAAK,CAACnxC,EAAG8nC,GADTm0F,GAAKj8H,EAAe,GAAX9N,KAAK8yB,IAAY6vB,GACT70C,EAAGA,EAAG6nC,GAAIA,GAAI6E,GAAIA,GAAI1sC,EAAGa,IAAKgnC,GAAI6E,GAAI7rC,IAAKb,EAAGA,EAAG8nC,GAAIm0F,GAAIj8H,GAC1EoxC,GAAK,CAACl/C,KAAK4mB,EAAE,KACL5mB,KAAK4mB,EAAE,KACP5mB,KAAK4mB,EAAE,KACP5mB,KAAK4mB,EAAE,KACP5mB,KAAK4mB,EAAE,KACP5mB,KAAK4mB,EAAE,KACP5mB,KAAK4mB,EAAE,KACP5mB,KAAK4mB,EAAE,KACP5mB,KAAK4mB,EAAE,KACP5mB,KAAK4mB,EAAE,KACPjY,IACA3O,KAAK4mB,EAAE,KACP5mB,KAAK4mB,EAAE,KACPjY,IACA3O,KAAK4mB,EAAE,KACP5mB,KAAK4mB,EAAE,KACP5mB,KAAK4mB,EAAE,KACP5mB,KAAK4mB,EAAE,KACP5mB,KAAK4mB,EAAE,MACH,aAARowD,UACK71C,MAAQ8d,QACR7d,MAAQ8d,UAER/d,MAAQ+d,QACR9d,MAAQ6d,KAGdqmE,KAGXlnH,IAAIsB,gBAAgB,UAAWtB,IAAI0rI,eAE5B,CACH/C,MAAO3oI,IAAI2oI,MACX2B,qBAAsBtqI,IAAIsqI,qBAC1BH,YAAanqI,IAAImqI,YACjBsB,sBAAuBzrI,IAAIyrI,sBAC3BF,wBAAyBvrI,IAAIurI,wBAC7BC,iBAAkBxrI,IAAIwrI,iBACtBH,iBAAkBrrI,IAAIqrI,iBACtBjB,oBAAqBpqI,IAAIoqI,oBACzBQ,qBAAsB5qI,IAAI4qI,qBAC1BiB,WAAY7rI,IAAIoqI,oBAChBC,aAAcrqI,IAAIqqI,aAClBQ,iBAAkB7qI,IAAI6qI,iBACtBO,mBAAoBprI,IAAIorI,mBACxBN,iBAAkB9qI,IAAI8qI,qBA0D9B9wI,OAAO,cAAc,CACjB,MAAO,gBAAiB,YAAa,cAAe,cAAe,aAAc,mBAClF,SAAUgG,IAAK+wC,SAAUjrB,IAAKC,OAAQggH,OAAQ7wH,KAAM9J,cAwDnDpL,IAAI8rI,UAAY,SAAU9pI,MAAO4L,QAASC,gBAClCoC,GAAIhC,KAAME,WAGC,KADfA,OAAS+G,KAAKvH,cAAc3L,MAAO4L,QAASC,WAAY,MAAO,CAAC,SAAU,cAAe,iBACjEM,OAAO1R,OAAS,QAC9B,IAAImB,MAAM,yDACJgQ,QAAQ,IAAM,kBAAoBA,QAAQ,IAAM,kBAChDA,QAAQ,IAFJ,gFAMpBK,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,QACtD4B,GAAKjO,MAAMwM,OAAO,QAAS,CAAC,CAAC,GAAI,CAAC,IAAKP,OAEpCqjF,OAAS,MACZrhF,GAAG+iF,WAAW7kF,QAMd8B,GAAGxD,KAAOrB,MAAMxH,gBAQhBqM,GAAGqqB,OAASnsB,OAAO,GAQnB8B,GAAG+mC,YAAc7oC,OAAO,GACxB8B,GAAGuiC,OAASviC,GAAG+mC,YAQf/mC,GAAGgnC,WAAa9oC,OAAO,GACvB8B,GAAG+iC,OAAS/iC,GAAGgnC,WAIX/hC,KAAKzU,OAAOwP,GAAGqqB,OAAO7rB,UACtBwB,GAAGwgF,SAASxgF,GAAGqqB,eACRrqB,GAAGqqB,OAAO7rB,SAEjBwB,GAAGqqB,OAAOm2D,SAASxgF,IAEnBiF,KAAKzU,OAAOwP,GAAG+mC,YAAYvoC,UAC3BwB,GAAGwgF,SAASxgF,GAAG+mC,oBACR/mC,GAAG+mC,YAAYvoC,SAEtBwB,GAAG+mC,YAAYy5C,SAASxgF,IAExBiF,KAAKzU,OAAOwP,GAAGgnC,WAAWxoC,UAC1BwB,GAAGwgF,SAASxgF,GAAGgnC,mBACRhnC,GAAGgnC,WAAWxoC,SAErBwB,GAAGgnC,WAAWw5C,SAASxgF,IAI3BA,GAAGioE,aAAejqE,KAAK89H,aAGvB97H,GAAGw5H,gBAAkB,eACbz5H,GAAI26B,IAAUqhG,IAAK35F,IAAKE,IACxByK,IAAM,EACN/6B,EAAIrgB,KAAKo1C,YACT5T,EAAIxhC,KAAK04B,OACT2W,EAAIrvC,KAAKq1C,WACTC,KAAOhiC,KAAKrG,SAASjN,KAAK+S,QAAQwiC,WAEtCxM,IAAMoG,SAASI,IAAIlvB,EAAGmhB,EAAG6N,IACX,UAATiG,MAAoBvM,IAAMr8B,KAAKiV,IAClB,UAAT2zB,MAAoBvM,IAAMr8B,KAAKiV,MACpCy5B,KAAO,GAKPp7C,KAAKs2E,eACL8zD,IAAM79H,OAAO,GAAGsB,OAAOG,UACvByiC,IAAMlkC,OAAO,GAAGsB,OAAOG,UACvB2iC,IAAMpkC,OAAO,GAAGsB,OAAOG,WAChBo8H,IAAI,GAAKz5F,IAAI,KAAOy5F,IAAI,GAAK35F,IAAI,KAAO25F,IAAI,GAAKz5F,IAAI,KAAOy5F,IAAI,GAAK35F,IAAI,IAEtE,QACD2E,YAAc7oC,OAAO,QACrB8oC,WAAa9oC,OAAO,UAEpB6oC,YAAc7oC,OAAO,QACrB8oC,WAAa9oC,OAAO,KAIjC8T,EAAIA,EAAExS,OAAOG,UACbwzB,EAAIA,EAAE3zB,OAAOG,UACbqhC,EAAIA,EAAExhC,OAAOG,UAEbI,GAAK+gC,SAAS+L,UAAU76B,EAAGmhB,EAAG6N,GAAG,EAAO+L,UAEnCja,MAAQ/yB,GAAG,QACXgzB,MAAQhzB,GAAG,QAEX+nC,aAAe,OAEf0nF,qBACA+G,uBAUTv2H,GAAGqtC,OAAS,kBACD17C,KAAKo1C,YAAYtU,KAAK9gC,KAAK04B,SAUtCrqB,GAAGk2H,UAAY,kBACXnmI,IAAIkC,WAAW,kBAAmB,gBAC3BN,KAAK07C,UAUhBrtC,GAAGgF,MAAQ,kBACArT,KAAK07C,SAAWvM,SAASI,IAAIvvC,KAAKo1C,YAAap1C,KAAK04B,OAAQ14B,KAAKq1C,aAI5EhnC,GAAG2mE,SAAW,SAAUlnE,EAAGiT,OACnB2kB,KAAM0hG,WACNpyF,IACA0lD,OAAQ9qF,EACR2vB,KAAM10B,KACN2E,EAAIxP,KAAK07C,gBAETpoC,KAAKrG,SAASjN,KAAK+S,QAAQ6pH,gBACpB58H,KAAKqqI,eAAev8H,EAAGiT,IAG9BzN,KAAK/I,SAAS+I,KAAKrG,SAASjN,KAAK+S,QAAQwgE,aACzC1oE,KAAO7K,KAAKI,MAAM4/F,aAClBzgE,KAAOjsB,KAAKrG,SAASjN,KAAK+S,QAAQwgE,UAAU1oE,QAG5C00B,KAAOv/B,KAAKI,MAAMqM,QAAQ8mE,UAAUyB,SAExCz1C,MAAQ7yB,KAAKC,IAAI3M,KAAKI,MAAM2kB,MAAO/kB,KAAKI,MAAM4kB,OAC9CoiH,WAAa,IAAIjjH,OAAO3a,MAAMzH,iBAAkB,CAAC+L,EAAGiT,GAAI/gB,KAAKI,OAEzDJ,KAAK6mF,gBAAgBhsF,OAAS,SAGzBygG,wBACLZ,OAASx2E,IAAIjE,QAAQjgB,KAAKu7F,cAC1B3rF,EAAIsU,IAAI3E,WAAWm7E,OAAQ0sC,WAAWp5H,WACtCo5H,WAAa,IAAIjjH,OAAO3a,MAAM1H,eAAgB8N,EAAG5P,KAAKI,QAG1DslC,KAAO1lC,KAAK04B,OAAO7qB,OAAOsX,SAAS3b,MAAM1H,eAAgBslI,aACzDpyF,IAAOtoC,KAAKwC,IAAIw2B,KAAOl2B,GAAK+vB,QAOxByV,IAAM7F,SAAS8F,YAAYj1C,KAAMonI,aAE9BpyF,MAYX3mC,GAAGg8H,eAAiB,SAAUv8H,EAAGiT,OACzBqmH,WAAa,IAAIjjH,OAAO3a,MAAMzH,iBAAkB,CAAC+L,EAAGiT,GAAI/gB,KAAKI,OAC7DoP,EAAIxP,KAAK07C,SAET1G,IADOh1C,KAAK04B,OAAO7qB,OAAOsX,SAAS3b,MAAM1H,eAAgBslI,YAC3C53H,SAEdwlC,MACAA,IAAM7F,SAAS8F,YAAYj1C,KAAMonI,aAE9BpyF,KAIX3mC,GAAG4mF,cAAgB,kBACRj1F,KAAK04B,OAAO7qB,QAIvBQ,GAAG6mF,eAAiB,eACZrnF,OAAQ2R,IAAK8qH,KAAMC,KAAMn+H,IACzBgjC,MAAQD,SAASI,IAAIvvC,KAAKo1C,YAAap1C,KAAK04B,OAAQ14B,KAAKq1C,YACzDvW,GAAK,GAAK9+B,KAAKI,MAAM2kB,MACrBgc,GAAK,GAAK/gC,KAAKI,MAAM4kB,MACrB2rB,IAAM3wC,KAAK4wC,OAAO/iC,OAAOG,UACzBw8H,IAAMxqI,KAAK04B,OAAO7qB,OAAOG,UACzBy8H,UAAY95F,IAAI,GAAK65F,IAAI,GACzBE,UAAY/5F,IAAI,GAAK65F,IAAI,GACzBl1F,KAAOhiC,KAAKrG,SAASjN,KAAK+S,QAAQwiC,WAClCo1F,KAAO3qI,KAAKkQ,MAAQlQ,KAAKkQ,MAAM6C,QAAU/S,KAAK+S,QAAQ7C,aAO5C,UAATolC,MAAoBlG,MAAQ1iC,KAAKiV,IACpB,UAAT2zB,MAAoBlG,MAAQ1iC,KAAKiV,MACtCytB,QAAU,EAAI1iC,KAAKiV,GAAKytB,QAQ5Bk7F,MALAz8H,OAAS,IAAIsW,OAAO3a,MAAM1H,eAAgB,CACtC0oI,IAAI,GAAK99H,KAAK8hB,IAAY,GAAR4gB,OAAeq7F,UAAY/9H,KAAKwiB,IAAY,GAARkgB,OAAes7F,UACrEF,IAAI,GAAK99H,KAAKwiB,IAAY,GAARkgB,OAAeq7F,UAAY/9H,KAAK8hB,IAAY,GAAR4gB,OAAes7F,WACtE1qI,KAAKI,QAEM4N,UAAU,GAAKw8H,IAAI,GACjCD,KAAO18H,OAAOG,UAAU,GAAKw8H,IAAI,GAGjCF,KAAOA,OADPl+H,IAAMM,KAAKmU,KAAKypH,KAAOA,KAAOC,KAAOA,OAChBzrG,IAAM1yB,IAC3Bm+H,KAAOA,MAAQn+H,IAAM20B,IAAM30B,IAC3BoT,IAAM,CAACgrH,IAAI,GAAKF,KAAME,IAAI,GAAKD,MAE/BI,KAAK9yH,SAAWs3B,SAASsE,kBAAkBtE,SAASI,IAAI,CAAC,EAAE,GAAG,CAAC,EAAE,GAAG/vB,MAE7D,IAAI2E,OAAO3a,MAAM1H,eAAgB0d,IAAKxf,KAAKI,QAItDiO,GAAGu2H,oBAAsBT,OAAOA,OAAOjrI,UAAU0rI,oBAGjDv2H,GAAGwvH,cAAgBsG,OAAOA,OAAOjrI,UAAU2kI,cAE3CxvH,GAAG0hF,UAAY3xF,IAAIuR,SAAStB,GAAG0hF,UAAW,CACtCw0C,UAAW,YACX3rE,OAAQ,SACRlgC,OAAQ,SACR0c,YAAa,cACbC,WAAY,aACZhiC,MAAO,UAGXhF,GAAGg3E,gBAAgB7qD,SACZnsB,IAGXjQ,IAAIsB,gBAAgB,MAAOtB,IAAI8rI,WA6B/B9rI,IAAIwsI,iBAAmB,SAAUxqI,MAAO4L,QAASC,gBACzCoC,GAAIi7B,GAAIj9B,KAAME,WAIH,KADfA,OAAS+G,KAAKvH,cAAc3L,MAAO4L,QAASC,WAAY,WACd,IAAlBM,OAAO1R,aACrB,IAAImB,MAAM,gEACJgQ,QAAQ,IAAM,kBAAoBA,QAAQ,IADtC,mDAKpBK,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,aAAc,WACpE68B,GAAKlpC,MAAMwM,OAAO,WAAYL,OAAQF,OACnCsjF,MAAO,EAEVtjF,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,eACtD4B,GAAKjO,MAAMwM,OAAO,MAAO,CAAC08B,GAAI/8B,OAAO,GAAIA,OAAO,IAAKF,OAClDqjF,OAAS,aACZrhF,GAAG+iF,WAAW,CAAC7kF,OAAO,GAAGpP,GAAIoP,OAAO,GAAGpP,KACvCkR,GAAGuhF,KAAO,CACNozC,SAAU15F,IAEdj7B,GAAGwhF,SAASn0F,KAAK4tC,IAQjBj7B,GAAG20H,SAAW30H,GAAGqqB,OAAS4Q,GAEnBj7B,IAGXjQ,IAAIsB,gBAAgB,aAActB,IAAIwsI,kBAgCtCxsI,IAAIysI,sBAAwB,SAAUzqI,MAAO4L,QAASC,gBAC9CoC,GAAIi7B,GAAIj9B,KAAME,WAIH,KADfA,OAAS+G,KAAKvH,cAAc3L,MAAO4L,QAASC,WAAY,WACd,IAAlBM,OAAO1R,aACrB,IAAImB,MAAM,gEACJgQ,QAAQ,IAAM,kBAAoBA,QAAQ,IAAM,kBAAoBA,QAAQ,IADxE,yDAKpBK,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,kBAAmB,WACzE68B,GAAKlpC,MAAMwM,OAAO,eAAgBL,OAAQF,OACvCsjF,MAAO,GAEVtjF,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,oBACjD09H,cAAe,GACpB97H,GAAKjO,MAAMwM,OAAO,MAAO,CAAC08B,GAAI/8B,OAAO,GAAIA,OAAO,GAAIA,OAAO,IAAKF,OAE7DqjF,OAAS,kBACZrhF,GAAG+iF,WAAW,CAAC7kF,OAAO,GAAGpP,GAAIoP,OAAO,GAAGpP,GAAIoP,OAAO,GAAGpP,KACrDkR,GAAGuhF,KAAO,CACNl3D,OAAQ4Q,IAEZj7B,GAAGwhF,SAASn0F,KAAK4tC,IAQjBj7B,GAAGqqB,OAAS4Q,GAELj7B,IAGXjQ,IAAIsB,gBAAgB,kBAAmBtB,IAAIysI,uBAkC3CzsI,IAAI0sI,eAAiB,SAAU1qI,MAAO4L,QAASC,mBAC3CA,WAAWspC,UAAY,QAChBn3C,IAAI8rI,UAAU9pI,MAAO4L,QAASC,aAGzC7N,IAAIsB,gBAAgB,WAAYtB,IAAI0sI,gBAiCpC1sI,IAAI2sI,eAAiB,SAAU3qI,MAAO4L,QAASC,mBAC3CA,WAAWspC,UAAY,QAChBn3C,IAAI8rI,UAAU9pI,MAAO4L,QAASC,aAGzC7N,IAAIsB,gBAAgB,WAAYtB,IAAI2sI,gBAE7B,CACHb,UAAW9rI,IAAI8rI,UACfU,iBAAkBxsI,IAAIwsI,iBACtBC,sBAAuBzsI,IAAIysI,sBAC3BC,eAAgB1sI,IAAI0sI,eACpBC,eAAgB3sI,IAAI2sI,mBAqD5B3yI,OAAO,iBAAiB,CACpB,MAAO,gBAAiB,YAAa,kBAAmB,cAAe,iBAAkB,eAC1F,SAAUgG,IAAK+wC,SAAUjrB,IAAK2pB,WAAY1pB,OAAQ3a,MAAO8J,aAgGxDlV,IAAI4sI,aAAe,SAAU5qI,MAAO4L,QAASC,gBACrCoC,GAAIhC,KAAM/R,EAEV+F,EAAG2J,EAEHuC,OAHA1B,KAAO,aAMPmB,QAAQ,GAAGvB,eAAiBjB,MAAMvF,mBAC9B+H,QAAQ,GAAGvB,eAAiBjB,MAAMvF,oBACjCqP,KAAKlJ,QAAQ4B,QAAQ,KAAOsH,KAAKrJ,SAAS+B,QAAQ,OAClDsH,KAAKlJ,QAAQ4B,QAAQ,KAAOsH,KAAKrJ,SAAS+B,QAAQ,OAClDsH,KAAKrJ,SAAS+B,QAAQ,KAAOsH,KAAKnJ,WAAW6B,QAAQ,KAAOsH,KAAKvJ,SAASiC,QAAQ,KAEvFnB,KAAO,aACJ,KAEY,KADf0B,OAAS+G,KAAKvH,cAAc3L,MAAO4L,QAASC,WAAY,SAZ3C,CAAC,SAAU,cAAe,sBAc7B,IAAIjQ,MAAM,4DACJgQ,QAAQ,IAAM,kBAAoBA,QAAQ,IAAM,kBAChDA,QAAQ,IAAM,MAE9BnB,KAAO,aAIXwB,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,WACtD4B,GAAKjO,MAAMwM,OAAO,QAAS,CAAC,CAAC,GAAI,CAAC,IAAKP,OACpCxB,KAAOrB,MAAMxG,mBAChBqL,GAAGqhF,OAAS,SAUXrhF,GAAG48H,WAAa,eACTzwF,GAAK,GAAMnsC,GAAGjO,MAAM2kB,MACpBglH,GAAKvoH,EAAAA,EACL0pH,GAAK,GAAM78H,GAAGjO,MAAM2kB,aAEpBzR,KAAK9I,QAAQ6D,GAAGqqB,UAEhBqxG,GAAiC,MAA5B17H,GAAGqqB,OAAOoI,KAAKzyB,GAAGuiC,SAGpBlkC,KAAKiS,IAAI67B,GAAI9tC,KAAKC,IAAIo9H,GAAImB,MAGxB,WAATrgI,KAICwD,GAAGqtC,OAAS,eACLlsC,EAAI8D,KAAKrG,SAASjB,QAAQ,UACpB,SAANwD,EACOxP,KAAKirI,aAETz7H,GAGXnB,GAAGwoE,MAAQz2E,MAAMG,OAAOyL,QAAQ,IAChCqC,GAAGyoE,MAAQ12E,MAAMG,OAAOyL,QAAQ,IAEhCqC,GAAGwoE,MAAMgY,SAASxgF,IAClBA,GAAGyoE,MAAM+X,SAASxgF,IAClBA,GAAG+iF,WAAWplF,SAEdqC,GAAGqiC,OAAS,CAAC39B,QAAS,IACtB1E,GAAGuiC,OAAS,CAAC79B,QAAS,IACtB1E,GAAG+iC,OAAS,CAACr+B,QAAS,IAGtB1S,EAAI8uC,SAASqG,aAAannC,GAAGwoE,MAAMjzD,QAASvV,GAAGyoE,MAAMlzD,QAAS,EAAGxjB,OAE7DkT,KAAKlJ,QAAQ4B,QAAQ,KAEK,IAAtBA,QAAQ,GAAGnR,SACXmR,QAAQ,GAAK,CAAC,GAAG9Q,OAAO8Q,QAAQ,KAOpChC,EAAImlC,SAASqE,mBAAmB,CAAC3lC,OAAQ,CAACG,UAAWhC,QAAQ,KAAMqC,GAAGwoE,MAAOz2E,OAC7E4J,EAAI6jC,WAAWa,SAAS1kC,EAAEgE,UAAW3N,EAAE2N,WACvCK,GAAG88H,WAAcjnH,IAAI3D,aAAavW,EAAG,CAAC,EAAGqE,GAAGwoE,MAAMjzD,QAAQ,IAAKvV,GAAGwoE,MAAMjzD,QAAQ,IAAK,IAAM,EAAK,GAAM,GAEtGvV,GAAG88H,WAAcn/H,QAAQ,IAAM,EAAK,GAAK,EAGzCsH,KAAKlJ,QAAQ4B,QAAQ,KAEK,IAAtBA,QAAQ,GAAGnR,SACXmR,QAAQ,GAAK,CAAC,GAAG9Q,OAAO8Q,QAAQ,KAOpChC,EAAImlC,SAASqE,mBAAmB,CAAC3lC,OAAQ,CAACG,UAAWhC,QAAQ,KAAMqC,GAAGyoE,MAAO12E,OAC7E4J,EAAI6jC,WAAWa,SAAS1kC,EAAEgE,UAAW3N,EAAE2N,WACvCK,GAAG+8H,WAAclnH,IAAI3D,aAAavW,EAAG,CAAC,EAAGqE,GAAGyoE,MAAMlzD,QAAQ,IAAKvV,GAAGyoE,MAAMlzD,QAAQ,IAAK,IAAM,EAAK,GAAM,GAEtGvV,GAAG+8H,WAAcp/H,QAAQ,IAAM,EAAK,GAAK,EAG7CqC,GAAGw5H,gBAAkB,eACbr4H,EAAGmmC,GAAIC,GACPv1B,EAEAgvB,EACAjhC,GAFAozB,EAAI,CAAC,EAAG,EAAG,MAIfmU,GAAK31C,KAAK62E,MACVjhC,GAAK51C,KAAK82E,MAGVt1C,EAAItd,IAAI1D,aAAam1B,GAAG/xB,QAASgyB,GAAGhyB,SAEhClX,KAAKwC,IAAIsyB,EAAE,IAAMtd,IAAIzF,IAAMyF,IAAIzF,MAC/B+iB,EAAE,IAAMA,EAAE,GACVA,EAAE,IAAMA,EAAE,GACVA,EAAE,IAAMA,EAAE,IAGdhyB,EAAIxP,KAAKmrI,WAAanrI,KAAK07C,SAC3Br7B,EAAIwtB,WAAW3iB,IAAIsW,EAAG,CAAC,EAAGhyB,EAAImmC,GAAG/xB,QAAQ,IAAKpU,EAAImmC,GAAG/xB,QAAQ,KAG7DpU,EAAIxP,KAAKorI,WAAaprI,KAAK07C,SAC3BrM,EAAIxB,WAAW3iB,IAAIsW,EAAG,CAAC,EAAGhyB,EAAIomC,GAAGhyB,QAAQ,IAAKpU,EAAIomC,GAAGhyB,QAAQ,UAExDgtB,OAAO/iC,OAAS,IAAIsW,OAAO3a,MAAM1H,eAAgBue,EAAGhS,GAAGjO,YACvDswC,OAAO7iC,OAAS,IAAIsW,OAAO3a,MAAM1H,eAAgB0/B,EAAGnzB,GAAGjO,YACvDgxC,OAAOvjC,OAAS,IAAIsW,OAAO3a,MAAM1H,eAAgButC,EAAGhhC,GAAGjO,OAExDsM,KAAKwC,IAAImR,EAAE,IAAM6D,IAAIzF,KAAO/R,KAAKwC,IAAIsyB,EAAE,IAAMtd,IAAIzF,KAAO/R,KAAKwC,IAAImgC,EAAE,IAAMnrB,IAAIzF,gBACxE0iB,MAAQ,CAACxyB,eACTyyB,MAAQ,CAACzyB,MAIlBP,GAAK+gC,SAAS+L,UAAU76B,EAAGmhB,EAAG6N,GAAG,EAAM,QAElClO,MAAQ/yB,GAAG,QACXgzB,MAAQhzB,GAAG,QAEX+nC,aAAe,GAGxB9nC,GAAG0hF,UAAY3xF,IAAIuR,SAAStB,GAAG0hF,UAAW,CACtCn3B,OAAQ,SACR2rE,UAAW,SACXhwC,UAAW,mBAOZ,GAAa,YAAT1pF,KAAoB,KAQ3BwD,GAAGqiC,OAASnkC,OAAO,GAQnB8B,GAAGuiC,OAASrkC,OAAO,GAQnB8B,GAAG+iC,OAAS7kC,OAAO,GAGdjS,EAAI,EAAGA,EAAI,EAAGA,IACXgZ,KAAKzU,OAAO0N,OAAOjS,GAAGuS,UACtBwB,GAAGwgF,SAAStiF,OAAOjS,WACZiS,OAAOjS,GAAGuS,SAEjBN,OAAOjS,GAAGu0F,SAASxgF,IAK3BA,GAAGioE,aAAerqE,WAAWk+H,aAC7B97H,GAAG+iF,WAAW7kF,QAQV+G,KAAKzU,OAAO0N,OAAO,MACnB8B,GAAGg9H,OAAS9+H,OAAO,GACnB8B,GAAGg9H,OAAOx8C,SAASxgF,KAGvBA,GAAG0hF,UAAY3xF,IAAIuR,SAAStB,GAAG0hF,UAAW,CACtC56C,IAAK,MACLzc,OAAQ,SACR0c,YAAa,cACbC,WAAY,aACZujB,OAAQ,SACR2rE,UAAW,SACXhwC,UAAW,cAOflmF,GAAGw5H,gBAAkB,eACbz5H,GAASg8H,IAAK35F,IAAKE,IAInB5H,IAHA1oB,EAAIrgB,KAAK4wC,OACTpP,EAAIxhC,KAAK0wC,OACTrB,EAAIrvC,KAAKoxC,OACJgK,IAAM,EACXkwF,KAAOh4H,KAAKrG,SAASjN,KAAK+S,QAAQwiC,eAEjCl1B,EAAEyF,SAAW0b,EAAE1b,SAAWupB,EAAEvpB,mBACxBqb,MAAQ,CAACxyB,eACTyyB,MAAQ,CAACzyB,MAIlBo6B,IAAMoG,SAASI,IAAIlvB,EAAGmhB,EAAG6N,IACX,UAATi8F,MAAoBviG,IAAMr8B,KAAKiV,IAClB,UAAT2pH,MAAoBviG,IAAMr8B,KAAKiV,MACpCy5B,KAAO,GAKPp7C,KAAKs2E,cAAgBhjE,KAAKzU,OAAOmB,KAAKqrI,UACtCjB,IAAMpqI,KAAK4wC,OAAO/iC,OAAOG,UACzByiC,IAAMzwC,KAAKqrI,OAAOx9H,OAAOG,UACzB2iC,IAAM3wC,KAAKoxC,OAAOvjC,OAAOG,WAClBo8H,IAAI,GAAKz5F,IAAI,KAAOy5F,IAAI,GAAK35F,IAAI,KAAO25F,IAAI,GAAKz5F,IAAI,KAAOy5F,IAAI,GAAK35F,IAAI,KAErE,IACPpB,EAAIrvC,KAAK4wC,OACTvwB,EAAIrgB,KAAKoxC,SAIjB/wB,EAAIA,EAAExS,OAAOG,UACbwzB,EAAIA,EAAE3zB,OAAOG,UACbqhC,EAAIA,EAAExhC,OAAOG,UAEbI,GAAK+gC,SAAS+L,UAAU76B,EAAGmhB,EAAG6N,GAAG,EAAM+L,UAElCja,MAAQ/yB,GAAG,QACXgzB,MAAQhzB,GAAG,QACX+nC,aAAe,GAUxB9nC,GAAGqtC,OAAS,kBACD17C,KAAK4wC,OAAO9P,KAAK9gC,KAAK0wC,UAGjCrkC,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,SAAU,QAC3DomE,WAAY,EACjBxmE,KAAKzS,MAAQ,OACbyU,GAAG8mC,IAAM/0C,MAAMwM,OAAO,MAAO,CAACyB,GAAGqiC,OAAQriC,GAAGuiC,OAAQviC,GAAG+iC,QAAS/kC,MAChEgC,GAAGwgF,SAASxgF,GAAG8mC,YAGnB9mC,GAAGqqB,OAASrqB,GAAGqiC,OACfriC,GAAG+mC,YAAc/mC,GAAGuiC,OACpBviC,GAAGgnC,WAAahnC,GAAG+iC,OAGnB/iC,GAAGk9H,cAAgB,SAAUz9H,EAAGiT,OACxBquB,MAAO5D,MAAOtY,KACdqM,KAAM10B,KAINmqC,IAHAoyF,WAAa,IAAIjjH,OAAO3a,MAAMzH,iBAAkB,CAAC+L,EAAGiT,GAAI/gB,KAAKI,OAC7DoP,EAAIxP,KAAK07C,SACThW,KAAO1lC,KAAK04B,OAAO7qB,OAAOsX,SAAS3b,MAAM1H,eAAgBslI,YAEzDkE,KAAOh4H,KAAKrG,SAASjN,KAAK+S,QAAQwiC,kBAElCjiC,KAAK/I,SAAS+I,KAAKrG,SAASjN,KAAK+S,QAAQwgE,aACzC1oE,KAAO7K,KAAKI,MAAM4/F,aAClBzgE,KAAOjsB,KAAKrG,SAASjN,KAAK+S,QAAQwgE,UAAU1oE,QAG5C00B,KAAOv/B,KAAKI,MAAMqM,QAAQ8mE,UAAUyB,SAExCz1C,MAAQ7yB,KAAKC,IAAI3M,KAAKI,MAAM2kB,MAAO/kB,KAAKI,MAAM4kB,QAC9CgwB,IAAOtoC,KAAKwC,IAAIw2B,KAAOl2B,GAAK+vB,QAExB6P,MAAQD,SAASI,IAAIvvC,KAAK4wC,OAAQ5wC,KAAK04B,OAAQ0uG,WAAWp5H,UAAU3U,MAAM,IAC1EmyC,MAAQ,EACRtY,KAAOic,SAASI,IAAIvvC,KAAK4wC,OAAQ5wC,KAAK04B,OAAQ14B,KAAKoxC,SAErC,UAATk6F,MAAoBp4G,KAAOxmB,KAAKiV,IACnB,UAAT2pH,MAAoBp4G,KAAOxmB,KAAKiV,MACrC6pB,MAAQtY,KACRA,KAAO,EAAIxmB,KAAKiV,KAGhBytB,MAAQ5D,OAAS4D,MAAQlc,QACzB8hB,KAAM,IAIPA,KAYX3mC,GAAGg8H,eAAiB,SAAUv8H,EAAGiT,OACzBquB,MAIA5D,MACAtY,KAJAk0G,WAAa,IAAIjjH,OAAO3a,MAAMzH,iBAAkB,CAAC+L,EAAGiT,GAAI/gB,KAAKI,OAC7DoP,EAAIxP,KAAK07C,SAIT1G,IAHOh1C,KAAK0wC,OAAO7iC,OAAOsX,SAAS3b,MAAM1H,eAAgBslI,YAG3C53H,EACd87H,KAAOh4H,KAAKrG,SAASjN,KAAK+S,QAAQwiC,kBAElCP,MACA5F,MAAQD,SAASI,IAAIvvC,KAAKo1C,YAAap1C,KAAK04B,OAAQ0uG,WAAWp5H,UAAU3U,MAAM,IAC/EmyC,MAAQ,EACRtY,KAAOic,SAASI,IAAIvvC,KAAKo1C,YAAap1C,KAAK04B,OAAQ14B,KAAKq1C,aAE1C,UAATi2F,MAAoBp4G,KAAOxmB,KAAKiV,IACnB,UAAT2pH,MAAoBp4G,KAAOxmB,KAAKiV,MACrC6pB,MAAQtY,KACRA,KAAO,EAAIxmB,KAAKiV,KAGhBytB,MAAQ5D,OAAS4D,MAAQlc,QACzB8hB,KAAM,IAGPA,KAGX3mC,GAAG2mE,SAAW,SAAUlnE,EAAGiT,UACnBzN,KAAKrG,SAASjN,KAAK+S,QAAQ4kE,oBACvBrkE,KAAKrG,SAASjN,KAAK+S,QAAQ6pH,gBACxB58H,KAAKqqI,eAAev8H,EAAGiT,GAG3B/gB,KAAKurI,cAAcz9H,EAAGiT,IAIjC1S,GAAG4mF,cAAgB,kBACRj1F,KAAK0wC,OAAO7iC,QAOvBQ,GAAG6mF,eAAiB,eACZrnF,OAAQ2R,IAAK8qH,KAAMC,KAAMn+H,IACzBgjC,MAAQD,SAASI,IAAIvvC,KAAK4wC,OAAQ5wC,KAAK0wC,OAAQ1wC,KAAKoxC,QACpDtS,GAAK,GAAK9+B,KAAKI,MAAM2kB,MACrBgc,GAAK,GAAK/gC,KAAKI,MAAM4kB,MACrB2rB,IAAM3wC,KAAK4wC,OAAO/iC,OAAOG,UACzBw8H,IAAMxqI,KAAK0wC,OAAO7iC,OAAOG,UACzBy8H,UAAY95F,IAAI,GAAK65F,IAAI,GACzBE,UAAY/5F,IAAI,GAAK65F,IAAI,GACzBc,KAAOh4H,KAAKrG,SAASjN,KAAK+S,QAAQwiC,WAClCo1F,KAAO3qI,KAAKkQ,MAAQlQ,KAAKkQ,MAAM6C,QAAU/S,KAAK+S,QAAQ7C,aAO5C,UAATo7H,MAAoBl8F,MAAQ1iC,KAAKiV,IACpB,UAAT2pH,MAAoBl8F,MAAQ1iC,KAAKiV,MACtCytB,QAAU,EAAI1iC,KAAKiV,GAAKytB,QAQ5Bk7F,MALAz8H,OAAS,IAAIsW,OAAO3a,MAAM1H,eAAgB,CACtC0oI,IAAI,GAAK99H,KAAK8hB,IAAY,GAAR4gB,OAAeq7F,UAAY/9H,KAAKwiB,IAAY,GAARkgB,OAAes7F,UACrEF,IAAI,GAAK99H,KAAKwiB,IAAY,GAARkgB,OAAeq7F,UAAY/9H,KAAK8hB,IAAY,GAAR4gB,OAAes7F,WACtE1qI,KAAKI,QAEM4N,UAAU,GAAKw8H,IAAI,GACjCD,KAAO18H,OAAOG,UAAU,GAAKw8H,IAAI,GAGjCF,KAAOA,OADPl+H,IAAMM,KAAKmU,KAAKypH,KAAOA,KAAOC,KAAOA,OAChBzrG,IAAM1yB,IAC3Bm+H,KAAOA,MAAQn+H,IAAM20B,IAAM30B,IAC3BoT,IAAM,CAACgrH,IAAI,GAAKF,KAAME,IAAI,GAAKD,MAE/BI,KAAK9yH,SAAWs3B,SAASsE,kBAAkBtE,SAASI,IAAI,CAAC,EAAE,GAAG,CAAC,EAAE,GAAG/vB,MAE7D,IAAI2E,OAAO3a,MAAM1H,eAAgB0d,IAAKxf,KAAKI,QAQtDiO,GAAGkmF,UAAY,SAAU5pF,KAIpB0D,GAAGqtC,OAAS,eACLlsC,EAAI8D,KAAKrG,SAAStC,WACZ,SAAN6E,EACOxP,KAAKirI,aAETz7H,IAQfnB,GAAGk2H,UAAY,kBACXnmI,IAAIkC,WAAW,qBAAsB,mBAC9BN,KAAK07C,UAUH,YAAT7wC,OACAwD,GAAGyjF,oBAAsB,SAAU1tE,OAAQvW,OAAQkkF,eAC3CE,GACAriF,EAAI,IAAIuU,OAAOC,OAAQvW,OAAQ7N,KAAKI,OACpC4xF,KAAO,IAAI7tE,OAAOC,OAAQ2tE,UAAW/xF,KAAKI,cAEzCiO,GAAGqiC,OAAO8gD,aAAgBnjF,GAAGuiC,OAAO4gD,aAAgBnjF,GAAG+iC,OAAOogD,aAInES,GAAKpkD,WAAWa,SAAS9+B,EAAE5B,UAAWgkF,KAAKhkF,WACvChO,KAAKI,MAAMwM,OAAO,YAAaqlF,GAAG54F,MAAM,GAAI,CAACwR,KAAM,cACrD6mF,UAAU,CAACrjF,GAAGqiC,OAAQriC,GAAGuiC,OAAQviC,GAAG+iC,SAE/BpxC,MAPIA,OAWnBqO,GAAGg3E,gBAAgB7qD,SAEZnsB,IAGXjQ,IAAIsB,gBAAgB,SAAUtB,IAAI4sI,cAiClC5sI,IAAIotI,yBAA2B,SAAUprI,MAAO4L,QAASC,gBACjDoC,GAAIi7B,GAAIj9B,KAAME,WAGH,KADfA,OAAS+G,KAAKvH,cAAc3L,MAAO4L,QAASC,WAAY,gBAE9C,IAAIjQ,MAAM,yEACJgQ,QAAQ,IAAM,kBAAoBA,QAAQ,IAAM,kBAAoBA,QAAQ,IAAM,aAGlGs9B,GAAKlpC,MAAMwM,OAAO,eAAgBL,OAAOlT,MAAM,EAAG,GAAIgT,OACnDsjF,MAAO,EAEVtjF,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,uBACtD4B,GAAKjO,MAAMwM,OAAO,SAAU,CAAC08B,GAAI/8B,OAAO,GAAIA,OAAO,GAAIA,OAAO,IAAKF,OAEhEqjF,OAAS,qBACZrhF,GAAG+iF,WAAW7kF,QAQd8B,GAAGqqB,OAAS4Q,GACZj7B,GAAGuhF,KAAO,CACNl3D,OAAQ4Q,IAGLj7B,IAGXjQ,IAAIsB,gBAAgB,qBAAsBtB,IAAIotI,0BAiC9CptI,IAAIqtI,kBAAoB,SAAUrrI,MAAO4L,QAASC,mBAC9CA,WAAWspC,UAAY,QAChBn3C,IAAI4sI,aAAa5qI,MAAO4L,QAASC,aAG5C7N,IAAIsB,gBAAgB,cAAetB,IAAIqtI,mBAiCvCrtI,IAAIstI,kBAAoB,SAAUtrI,MAAO4L,QAASC,mBAC9CA,WAAWspC,UAAY,QAChBn3C,IAAI4sI,aAAa5qI,MAAO4L,QAASC,aAG5C7N,IAAIsB,gBAAgB,cAAetB,IAAIstI,mBAoIvCttI,IAAIutI,YAAc,SAAUvrI,MAAO4L,QAASC,gBACpCoC,GAAIuqD,OAAQvsD,KAAMu/H,QAClBtxI,EAAGiS,OACH1B,KAAO,aAGPmB,QAAQ,GAAGvB,eAAiBjB,MAAMvF,mBAC9B+H,QAAQ,GAAGvB,eAAiBjB,MAAMvF,oBACjCqP,KAAKlJ,QAAQ4B,QAAQ,KAAOsH,KAAKrJ,SAAS+B,QAAQ,OAClDsH,KAAKlJ,QAAQ4B,QAAQ,KAAOsH,KAAKrJ,SAAS+B,QAAQ,KAEvDnB,KAAO,aACJ,KAEY,KADf0B,OAAS+G,KAAKvH,cAAc3L,MAAO4L,QAASC,WAAY,gBAE9C,IAAIjQ,MAAM,2DACJgQ,QAAQ,IAAM,kBAAoBA,QAAQ,IAAM,kBAAoBA,QAAQ,IAAM,MAElGnB,KAAO,aAGXwB,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,SAGjD6G,KAAKzU,OAAOwN,KAAKzS,OAAuB,KAAdyS,KAAKzS,OAChCyS,KAAKzS,KAAOwG,MAAMywF,aAAa,CAAChmF,KAAMrB,MAAMtG,qBAI5C01D,OADAtlD,KAAKzU,OAAOwN,KAAKusD,QACRvsD,KAAKusD,OAEL,EAGA,WAAT/tD,MACAmB,QAAQtQ,KAAKk9D,SACbvqD,GAAKjO,MAAMwM,OAAO,SAAUZ,QAASK,OAClCw/H,sBAAwBx9H,GAAGw5H,gBAG9Bx5H,GAAGy9H,SAAW,SAAUnhI,OACxB0D,GAAG4rF,KAAO,SAAUtvF,UAGpB0D,GAAKjO,MAAMwM,OAAO,SAAU,CAACL,OAAO,GAAIA,OAAO,GAAIA,OAAO,IAAKF,OAC5D8oC,IAAIpiC,QAAQ+/D,MAAO,EAUtBzkE,GAAGiiC,MAAQjiC,GAAGuiC,OAASviC,GAAG+mC,YAAc7oC,OAAO,GAQ/C8B,GAAG6nE,YAAc7nE,GAAG+iC,OAAS/iC,GAAGgnC,WAAa9oC,OAAO,GAKpD8B,GAAGqtC,OAAS,eAEJlsC,EAAI8D,KAAKrG,SAAS2rD,cACZ,SAANppD,EACOnB,GAAG48H,aAEPz7H,GAGXnB,GAAGw9H,sBAAwB,eAMnBz9H,GACA26B,IANA1oB,EAAIrgB,KAAK4wC,OACTpP,EAAIxhC,KAAK0wC,OACTrB,EAAIrvC,KAAKoxC,OACT5hC,EAAIxP,KAAK07C,SACTvwC,EAAIq2B,EAAEV,KAAKzgB,GAGX+6B,IAAM,EACNkwF,KAAOh4H,KAAKrG,SAASjN,KAAK+S,QAAQwiC,WAEtCxM,IAAMoG,SAASI,IAAIlvB,EAAGmhB,EAAG6N,IACX,UAATi8F,MAAoBviG,IAAMr8B,KAAKiV,IAClB,UAAT2pH,MAAoBviG,IAAMr8B,KAAKiV,MACpCy5B,KAAO,GAGX/6B,EAAIA,EAAExS,OAAOG,UACbwzB,EAAIA,EAAE3zB,OAAOG,UACbqhC,EAAIA,EAAExhC,OAAOG,UAEbqS,EAAI,CAAC,EAAGmhB,EAAE,IAAMnhB,EAAE,GAAKmhB,EAAE,IAAMhyB,EAAIrE,EAAGq2B,EAAE,IAAMnhB,EAAE,GAAKmhB,EAAE,IAAMhyB,EAAIrE,GACjEkkC,EAAI,CAAC,EAAG7N,EAAE,IAAM6N,EAAE,GAAK7N,EAAE,IAAMhyB,EAAIrE,EAAGq2B,EAAE,IAAM6N,EAAE,GAAK7N,EAAE,IAAMhyB,EAAIrE,GAEjEiD,GAAK+gC,SAAS+L,UAAU76B,EAAGmhB,EAAG6N,GAAG,EAAM+L,UAElCja,MAAQ/yB,GAAG,QACXgzB,MAAQhzB,GAAG,QACX+nC,aAAe,GA2GxB9nC,GAAGy9H,SAAW,SAAUnhI,SAChB8yB,GAAIC,GAAIquG,KACRhvI,EAAIiD,KAAKq1C,WACTttB,EAAI/nB,KAAKo1C,mBAETr4C,EAAEy0F,cACF/zD,GAAKz9B,KAAKI,MAAMwM,OAAO,YAAa,CAACjC,IAAK3K,KAAK04B,QAAS,CAAC7tB,KAAM,WAC/D9N,EAAEozF,aAAapoE,EAAG0V,IAGlBA,GAAGjD,SACHz9B,EAAE28F,OAAOx1E,IAAI3E,WAAWke,GAAGze,OAAQ+I,EAAEla,OAAOG,YAMxC+9H,KAJAz4H,KAAKnJ,WAAWQ,KAIT,kBAA8B,EAAV+B,KAAKiV,GAAShX,OAKjC,kBAA8B,EAAV+B,KAAKiV,GAAShX,KAE9C+yB,GAAK19B,KAAKI,MAAMwM,OAAO,YAAa,CAACm/H,KAAM/rI,KAAK04B,QAAS,CAAC7tB,KAAM,WAChE9N,EAAE8Q,OAAOqQ,GAAG,UAAU,WAClBwf,GAAGlD,SACHzS,EAAE2xE,OAAOx1E,IAAI3E,WAAWme,GAAG1e,OAAQjiB,EAAE8Q,OAAOG,eAGhDjR,EAAEq0F,WAAWrpE,IAEV/nB,MAYXqO,GAAG4rF,KAAO,eACFl9F,EAAIiD,KAAKq1C,kBAETt4C,EAAE8pF,gBAAgBhsF,OAAS,IAC3BkC,EAAE8pF,gBAAgBpgD,MAClB1pC,EAAEmyF,aAAc,EAChBnyF,EAAEiP,QAAU,GAEZjP,EAAE8Q,OAAOsQ,IAAI,WAGVne,MAGXqO,GAAG+iF,WAAW7kF,SAKd+G,KAAKzU,OAAOwP,GAAG0E,QAAQ6iE,OACvBvnE,GAAG6B,MAAM0jF,QAAQtgF,KAAKrG,SAASoB,GAAG0E,QAAQ6iE,OAG9CvnE,GAAGqhF,OAAS,QACZrhF,GAAGxD,KAAOrB,MAAMtG,kBAChBmL,GAAGuhF,KAAO,GAEVvhF,GAAG29H,sBAAwB,eACnB3rH,EAAGmhB,EAAG6N,EAEN7c,GAAIC,GACJzoB,EAAG2rC,GAAIC,GAFPpmC,EAAIxP,KAAK07C,SAKA,WAAT7wC,WAEKghI,wBAGTxrH,EAAIrgB,KAAK4wC,OACTpP,EAAIxhC,KAAK0wC,OACTrB,EAAIrvC,KAAKoxC,OAET/wB,EAAIA,EAAExS,OAAOG,UACbwzB,EAAIA,EAAE3zB,OAAOG,UACbqhC,EAAIA,EAAExhC,OAAOG,UAEbwkB,GAAK2c,SAAShqB,SAAS9E,EAAGmhB,EAAG,GAC7B/O,GAAK0c,SAAShqB,SAASkqB,EAAG7N,EAAG,GAG7BnhB,EAAI,CAAC,EAAGmhB,EAAE,IAAMnhB,EAAE,GAAKmhB,EAAE,IAAMhyB,EAAIgjB,GAAIgP,EAAE,IAAMnhB,EAAE,GAAKmhB,EAAE,IAAMhyB,EAAIgjB,IAClE6c,EAAI,CAAC,EAAG7N,EAAE,IAAM6N,EAAE,GAAK7N,EAAE,IAAMhyB,EAAIijB,GAAI+O,EAAE,IAAM6N,EAAE,GAAK7N,EAAE,IAAMhyB,EAAIijB,IAElEzoB,EAAIka,IAAI1D,aAAa6uB,EAAG7N,GACxBmU,GAAK,EAAEt1B,EAAE,GAAKrW,EAAE,GAAKqW,EAAE,GAAKrW,EAAE,GAAIqW,EAAE,GAAKrW,EAAE,GAAIqW,EAAE,GAAKrW,EAAE,IACxDA,EAAIka,IAAI1D,aAAaH,EAAGmhB,GACxBoU,GAAK,EAAEvG,EAAE,GAAKrlC,EAAE,GAAKqlC,EAAE,GAAKrlC,EAAE,GAAIqlC,EAAE,GAAKrlC,EAAE,GAAIqlC,EAAE,GAAKrlC,EAAE,KAExDA,EAAIka,IAAI1D,aAAam1B,GAAIC,KACvB,IAAM5rC,EAAE,GACVA,EAAE,IAAMA,EAAE,QAELm3B,MAAQ,CAACK,EAAE,GAAInhB,EAAE,GAAIrW,EAAE,GAAIqlC,EAAE,GAAI7N,EAAE,SACnCJ,MAAQ,CAACI,EAAE,GAAInhB,EAAE,GAAIrW,EAAE,GAAIqlC,EAAE,GAAI7N,EAAE,SAEnC2U,aAAe,GAGxB9nC,GAAG49H,oBAAsB,gBAChB9qG,MAAQ,CAACxyB,UACTyyB,MAAQ,CAACzyB,UACTwnC,aAAe,GAGxB9nC,GAAGw5H,gBAAkB,eACbh9H,KAAOyI,KAAKrG,SAASjN,KAAK+S,QAAQlI,MAClCw0B,IAAM8P,SAASG,UAAUtvC,KAAK4wC,OAAQ5wC,KAAK0wC,OAAQ1wC,KAAKoxC,QACxDk6F,KAAOh4H,KAAKrG,SAASjN,KAAK+S,QAAQwiC,YAExB,UAAT+1F,MAAoBjsG,IAAM,KACb,UAATisG,MAAoBjsG,IAAM,OAC/BA,IAAM,IAAQA,KAGd3yB,KAAKwC,IAAImwB,IAAM,IAAQ/rB,KAAKrG,SAASjN,KAAK+S,QAAQm5H,kBAAoBhoH,IAAIzF,MAC1E5T,KAAOyI,KAAKrG,SAASjN,KAAK+S,QAAQo5H,YAGzB,SAATthI,UACKohI,sBACW,WAATphI,UACFmhI,wBACW,WAATnhI,UACFghI,wBACW,cAAThhI,YACFghI,wBACA7rI,KAAK6/B,IAAI9sB,QAAQd,cACb4tB,IAAIqlD,aAAa,CAACjzE,SAAS,OAInCjS,KAAK+S,QAAQd,SAAqB,cAATpH,MAAwB7K,KAAK6/B,IAAI9sB,QAAQd,eAC9D4tB,IAAIqlD,aAAa,CAACjzE,SAAS,KAYxC25H,QAAUt4H,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,QAAS,OAClE4B,GAAGwxB,IAAMz/B,MAAMwM,OAAO,QAAS,CAAC,eACxByT,EAAGmhB,EAAGhyB,EAAGrE,EAAG+C,GAAI2nB,GAAID,GAAInb,IACxB6wH,YAEAh4H,KAAKzU,OAAOwP,GAAGwxB,OAASxxB,GAAGwxB,IAAI9sB,QAAQd,QAChC,CAAC,EAAG,IAGfoO,EAAIhS,GAAGuiC,OAAO/iC,OAAOG,UACrBwzB,EAAInzB,GAAGqiC,OAAO7iC,OAAOG,UACrBwB,EAAInB,GAAGqtC,SACPvwC,EAAIgkC,SAAShqB,SAAS9E,EAAGmhB,EAAG,GAC5BtzB,GAAKihC,SAASI,IAAIlhC,GAAGuiC,OAAQviC,GAAGqiC,OAAQriC,GAAG+iC,SAG7B,WADdk6F,KAAOh4H,KAAKrG,SAASoB,GAAG0E,QAAQwiC,aACPrnC,GAAKxB,KAAKiV,IACjB,UAAT2pH,MAAoBp9H,GAAKxB,KAAKiV,MACnCzT,KAAO,EAAIxB,KAAKiV,GAAKzT,KAEzBA,IAAM,GAEN2nB,GAAKnpB,KAAK8hB,IAAItgB,IACd0nB,GAAKlpB,KAAKwiB,IAAIhhB,IAEdmS,EAAI,CAAC,EAAGmhB,EAAE,IAAMnhB,EAAE,GAAKmhB,EAAE,IAAMhyB,EAAIrE,EAAGq2B,EAAE,IAAMnhB,EAAE,GAAKmhB,EAAE,IAAMhyB,EAAIrE,GAEjEsP,IAAM,CACF,CAAC,EAAG,EAAG,GACP,CAAC+mB,EAAE,GAAK,GAAMA,EAAE,GAAK3L,GAAK,GAAM2L,EAAE,GAAK5L,GAAS,GAALC,GAAgB,IAALD,IACtD,CAAC4L,EAAE,GAAK,GAAMA,EAAE,GAAK5L,GAAK,GAAM4L,EAAE,GAAK3L,GAAS,GAALD,GAAgB,GAALC,KAEnD3R,IAAI3E,WAAW9E,IAAK4F,MAC3BurH,SAEJv9H,GAAGwxB,IAAI8vD,MAAO,EACdthF,GAAGuhF,KAAK/vD,IAAMxxB,GAAGwxB,IAEJ,WAATh1B,SACKvQ,EAAI,EAAGA,EAAI,EAAGA,IACf8F,MAAMG,OAAOyL,QAAQ1R,IAAIu0F,SAASxgF,GAAGwxB,cAGpCvlC,EAAI,EAAGA,EAAI,EAAGA,IACf8F,MAAMG,OAAOgM,OAAOjS,IAAIu0F,SAASxgF,GAAGwxB,YAK5CxxB,GAAG6mF,eAAiB,eACZ11E,IACAa,EAAGmhB,EAAGhyB,EAAGrE,EAAG+C,GAAI2nB,GAAID,GAAInb,IADnBqkB,GAAK,GAEVwsG,KAAOh4H,KAAKrG,SAASoB,GAAG0E,QAAQwiC,WAChCo1F,KAAO3qI,KAAKkQ,MAAQlQ,KAAKkQ,MAAM6C,QAAU/S,KAAK+S,QAAQ7C,aAOtDoD,KAAKzU,OAAOmB,KAAKkQ,MAAM6C,QAAQs7D,YAC/BvvC,GAAKxrB,KAAKrG,SAASjN,KAAKkQ,MAAM6C,QAAQs7D,WAE1CvvC,IAAM9+B,KAAKI,MAAM2kB,MAEjB1E,EAAIhS,GAAGuiC,OAAO/iC,OAAOG,UACrBwzB,EAAInzB,GAAGqiC,OAAO7iC,OAAOG,UACrBwB,EAAInB,GAAGqtC,SACPvwC,EAAIgkC,SAAShqB,SAAS9E,EAAGmhB,EAAG,GAC5BtzB,GAAKihC,SAASI,IAAIlhC,GAAGuiC,OAAQviC,GAAGqiC,OAAQriC,GAAG+iC,SAC7B,UAATk6F,MAAoBp9H,GAAKxB,KAAKiV,IACjB,UAAT2pH,MAAoBp9H,GAAKxB,KAAKiV,MACnCzT,KAAO,EAAIxB,KAAKiV,GAAKzT,KAEzBA,IAAM,GACN2nB,GAAKnpB,KAAK8hB,IAAItgB,IACd0nB,GAAKlpB,KAAKwiB,IAAIhhB,IAEdmS,EAAI,CAAC,EAAGmhB,EAAE,IAAMnhB,EAAE,GAAKmhB,EAAE,IAAMhyB,EAAIrE,EAAGq2B,EAAE,IAAMnhB,EAAE,GAAKmhB,EAAE,IAAMhyB,EAAIrE,GAEjEsP,IAAM,CACF,CAAC,EAAG,EAAG,GACP,CAAC+mB,EAAE,GAAK,GAAMA,EAAE,GAAK3L,GAAK,GAAM2L,EAAE,GAAK5L,GAAS,GAALC,GAAgB,IAALD,IACtD,CAAC4L,EAAE,GAAK,GAAMA,EAAE,GAAK5L,GAAK,GAAM4L,EAAE,GAAK3L,GAAS,GAALD,GAAgB,GAALC,MAE1DrW,IAAM0E,IAAI3E,WAAW9E,IAAK4F,IACtB,IAAMb,IAAI,GACdA,IAAI,IAAMA,IAAI,GACdA,IAAI,IAAMA,IAAI,GAEdrU,EAAIgkC,SAAShqB,SAAS3F,IAAKgiB,EAAG,GAC9BhiB,IAAM,CAACA,IAAI,GAAIgiB,EAAE,IAAMhiB,IAAI,GAAKgiB,EAAE,KAAOhyB,EAAIsvB,IAAM3zB,EAAIq2B,EAAE,IAAMhiB,IAAI,GAAKgiB,EAAE,KAAOhyB,EAAIsvB,IAAM3zB,GAE3Fw/H,KAAK9yH,SAAWs3B,SAASsE,kBAAkBtE,SAASI,IAAI,CAAC,EAAE,GAAI,CAAC,EAAE,GAAI/vB,MAE/D,IAAI2E,OAAO3a,MAAM1H,eAAgB0d,IAAKxf,KAAKI,QAUtDiO,GAAGgF,MAAQ,kBACA87B,SAASI,IAAIvvC,KAAK4wC,OAAQ5wC,KAAK0wC,OAAQ1wC,KAAKoxC,SAGvD/iC,GAAG0hF,UAAYz8E,KAAK3D,SAAStB,GAAG0hF,UAAW,CACvC18E,MAAO,QACPy4H,SAAU,WACV7xC,KAAM,SAGH5rF,IAGXjQ,IAAIsB,gBAAgB,QAAStB,IAAIutI,aAmCjCvtI,IAAIguI,qBAAuB,SAAUhsI,MAAO4L,QAASC,gBAC7CoC,UAEJpC,WAAWspC,UAAY,SACvBlnC,GAAKjQ,IAAIutI,YAAYvrI,MAAO4L,QAASC,aAGlCoH,MAAQ,eACHrJ,EAAImlC,SAASI,IAAIvvC,KAAK4wC,OAAQ5wC,KAAK0wC,OAAQ1wC,KAAKoxC,eAC5CpnC,EAAI0C,KAAKiV,GAAM3X,EAAI,EAAM0C,KAAKiV,GAAK3X,GAExCqE,IAGXjQ,IAAIsB,gBAAgB,iBAAkBtB,IAAIguI,sBAmC1ChuI,IAAIiuI,kBAAoB,SAAUjsI,MAAO4L,QAASC,gBAC1CoC,UAEJpC,WAAWspC,UAAY,SACvBlnC,GAAKjQ,IAAIutI,YAAYvrI,MAAO4L,QAASC,aAGlCoH,MAAQ,eACHrJ,EAAImlC,SAASI,IAAIvvC,KAAK4wC,OAAQ5wC,KAAK0wC,OAAQ1wC,KAAKoxC,eAC5CpnC,GAAK0C,KAAKiV,GAAM3X,EAAI,EAAM0C,KAAKiV,GAAK3X,GAEzCqE,IAGXjQ,IAAIsB,gBAAgB,cAAetB,IAAIiuI,mBAEhC,CACHrB,aAAc5sI,IAAI4sI,aAClBQ,yBAA0BptI,IAAIotI,yBAC9BC,kBAAmBrtI,IAAIqtI,kBACvBC,kBAAmBttI,IAAIstI,kBACvBC,YAAavtI,IAAIutI,YACjBU,kBAAmBjuI,IAAIiuI,kBACvBD,qBAAsBhuI,IAAIguI,yBAkDlCh0I,OAAO,sBAAsB,CACzB,MAAO,iBAAkB,YAAa,eACvC,SAAUgG,IAAKoL,MAAO0a,IAAK5Q,aA6D1BlV,IAAIkuI,eAAiB,SAAUlsI,MAAOyK,KAAM0hI,aACnC9hI,aAAejB,MAAMnF,wBACrBwG,KAAOrB,MAAM3F,gCACbmb,OAAS,CACV,CAAC,EAAG,EAAG,GACP,CAAC,EAAG,EAAG,GACP,CAAC,EAAG,EAAG,SAEN5e,MAAQA,WACRuxF,iBAAkB,OAClB66C,UAAUpsI,MAAOyK,KAAM0hI,aAEvBx8C,UAAY,CACbp0F,MAAO,QACP+1F,UAAW,YACXqE,OAAQ,SACRjpF,KAAM,SACN8kF,KAAM,SAIdxzF,IAAIkuI,eAAepzI,UAAY,GAE/BkF,IAAIC,OAAOD,IAAIkuI,eAAepzI,UAAsD,CAKhFshC,OAAQ,kBACGx6B,MAgCXwsI,UAAW,SAAUpsI,MAAOyK,KAAM0hI,YAC1BjyI,WAECq3F,iBAAkB,EAElBr3F,EAAI,EAAGA,EAAIiyI,OAAO1xI,OAAQP,OACF,iBAAdiyI,OAAOjyI,GAAiB,MAC1Bq3F,iBAAkB,WAKlB,cAAT9mF,KAAsB,IACA,IAAlB0hI,OAAO1xI,aACD,IAAImB,MAAM,+DAEfywI,UAAYn5H,KAAKjI,mBAAmBjL,MAAOmsI,OAAQ,QACnD/xG,OAAS,gBACLxb,OAAO,GAAG,GAAKhf,KAAKysI,UAAU,QAC9BztH,OAAO,GAAG,GAAKhf,KAAKysI,UAAU,SAEpC,GAAa,UAAT5hI,KAAkB,IACH,IAAlB0hI,OAAO1xI,aACD,IAAImB,MAAM,2DAEfywI,UAAYn5H,KAAKjI,mBAAmBjL,MAAOmsI,OAAQ,QACnD/xG,OAAS,gBACLxb,OAAO,GAAG,GAAKhf,KAAKysI,UAAU,QAC9BztH,OAAO,GAAG,GAAKhf,KAAKysI,UAAU,SAGpC,GAAa,YAAT5hI,KAEH0hI,OAAO1xI,OAAS,IAChB0xI,OAAO,GAAKnsI,MAAMG,OAAOgsI,OAAO,KAId,IAAlBA,OAAO1xI,SACP0xI,OAAO,GAAKnsI,MAAMG,OAAOgsI,OAAO,KAId,IAAlBA,OAAO1xI,cACF4xI,UAAYn5H,KAAKjI,mBAAmBjL,MAAOmsI,OAAQ,SAGvD/xG,OAAS,eACN1sB,EAAGiT,EAAG6G,EAAG8kH,KAAMC,KAAMxhI,EACrBnB,EAAGjN,EAGe,IAAlBwvI,OAAO1xI,OACPmP,EAAIuiI,OAAO,GAAG3oH,QAEW,IAAlB2oH,OAAO1xI,OACdmP,EAAIka,IAAI1D,aAAa+rH,OAAO,GAAG1+H,OAAOG,UAAWu+H,OAAO,GAAG1+H,OAAOG,WAEzC,IAAlBu+H,OAAO1xI,SACdmP,EAAIka,IAAI1D,aACJ,CAAC,EAAGxgB,KAAKysI,UAAU,GAAIzsI,KAAKysI,UAAU,IACtC,CAAC,EAAGzsI,KAAKysI,UAAU,GAAIzsI,KAAKysI,UAAU,MAK9C3+H,EAAI9D,EAAE,GACN+W,EAAI/W,EAAE,GAGNmB,GADApO,EAAI,GADJ6qB,EAAI5d,EAAE,IACI8D,GAAI8Z,EAAI7G,EAAGjT,EAAIA,EAAIiT,EAAIA,IAC3B,GAGN2rH,KAAO3vI,EAAE,GAAKA,EAAE,GAChB4vI,KAAO5vI,EAAE,GAAKA,EAAE,GAGhB+Q,GAAK9D,EAAE,GACP+W,EAAK/W,EAAE,QAEFgV,OAAO,GAAG,IAAMlR,EAAIA,EAAIiT,EAAIA,GAAK5V,OACjC6T,OAAO,GAAG,GAAK,EAAIlR,EAAIiT,EAAI5V,OAC3B6T,OAAO,GAAG,GAAKhf,KAAKgf,OAAO,GAAG,QAC9BA,OAAO,GAAG,IAAMhf,KAAKgf,OAAO,GAAG,QAC/BA,OAAO,GAAG,GAAK0tH,MAAQ,EAAI1sI,KAAKgf,OAAO,GAAG,IAAM2tH,KAAO3sI,KAAKgf,OAAO,GAAG,QACtEA,OAAO,GAAG,GAAK2tH,MAAQ,EAAI3sI,KAAKgf,OAAO,GAAG,IAAM0tH,KAAO1sI,KAAKgf,OAAO,GAAG,SAE5E,GAAa,WAATnU,KAEe,IAAlB0hI,OAAO1xI,YACF4xI,UAAYn5H,KAAKjI,mBAAmBjL,MAAOmsI,OAAQ,GAEjDA,OAAO1xI,OAAS,GAAK0xI,OAAO1xI,QAAU,SACxC4xI,UAAYn5H,KAAKjI,mBAAmBjL,MAAOmsI,OAAQ,GAElC,IAAlBA,OAAO1xI,QAAiByY,KAAKlJ,QAAQmiI,OAAO,MAC5CA,OAAO,GAAKnsI,MAAMG,OAAOgsI,OAAO,WAInC/xG,OAAS,eACN1sB,EAAGiT,EACHmS,KAAOlzB,KAAKysI,UAAU,GACtB52G,GAAKnpB,KAAK8hB,IAAI0E,MACd0C,GAAKlpB,KAAKwiB,IAAIgE,WAEblU,OAAO,GAAG,GAAM6W,QAChB7W,OAAO,GAAG,IAAM4W,QAChB5W,OAAO,GAAG,GAAM4W,QAChB5W,OAAO,GAAG,GAAM6W,GAGjB02G,OAAO1xI,OAAS,IACM,IAAlB0xI,OAAO1xI,QACPiT,EAAI9N,KAAKysI,UAAU,GACnB1rH,EAAI/gB,KAAKysI,UAAU,IAEfn5H,KAAKlJ,QAAQmiI,OAAO,KACpBz+H,EAAIy+H,OAAO,GAAG,GACdxrH,EAAIwrH,OAAO,GAAG,KAEdz+H,EAAIy+H,OAAO,GAAGnuG,IACdrd,EAAIwrH,OAAO,GAAGluG,UAGjBrf,OAAO,GAAG,GAAKlR,GAAK,EAAI+nB,IAAM9U,EAAI6U,QAClC5W,OAAO,GAAG,GAAK+B,GAAK,EAAI8U,IAAM/nB,EAAI8nB,UAG5C,GAAa,UAAT/qB,KAAkB,IACH,IAAlB0hI,OAAO1xI,aACD,IAAImB,MAAM,2DAGfywI,UAAYn5H,KAAKjI,mBAAmBjL,MAAOmsI,OAAQ,QACnD/xG,OAAS,gBACLxb,OAAO,GAAG,GAAKhf,KAAKysI,UAAU,QAC9BztH,OAAO,GAAG,GAAKhf,KAAKysI,UAAU,SAEpC,GAAa,YAAT5hI,KAAoB,IACL,IAAlB0hI,OAAO1xI,aACD,IAAImB,MAAM,6DAGfywI,UAAYn5H,KAAKjI,mBAAmBjL,MAAOmsI,OAAQ,QAEnD/xG,OAAS,gBACLxb,OAAO,GAAG,GAAKhf,KAAKysI,UAAU,QAC9BztH,OAAO,GAAG,GAAKhf,KAAKysI,UAAU,QAC9BztH,OAAO,GAAG,GAAKhf,KAAKysI,UAAU,QAC9BztH,OAAO,GAAG,GAAKhf,KAAKysI,UAAU,QAC9BztH,OAAO,GAAG,GAAKhf,KAAKysI,UAAU,QAC9BztH,OAAO,GAAG,GAAKhf,KAAKysI,UAAU,QAC9BztH,OAAO,GAAG,GAAKhf,KAAKysI,UAAU,QAC9BztH,OAAO,GAAG,GAAKhf,KAAKysI,UAAU,QAC9BztH,OAAO,GAAG,GAAKhf,KAAKysI,UAAU,MAa/C9wI,MAAO,SAAUoB,EAAGmY,kBACXslB,SAEDlnB,KAAKzU,OAAOqW,MACLgP,IAAI3E,WAAWvf,KAAKgf,OAAQjiB,EAAEm8F,cAAclrF,WAEhDkW,IAAI3E,WAAWvf,KAAKgf,OAAQjiB,EAAE8Q,OAAOG,YAShD0jF,UAAW,SAAU30F,OACb6S,EAAGxD,IAAK9R,MAEPgZ,KAAKlJ,QAAQrN,KACdA,EAAI,CAACA,IAGTqP,IAAMrP,EAAElC,OAEHP,EAAI,EAAGA,EAAI8R,IAAK9R,SACZkgC,SACL5qB,EAAIsU,IAAI3E,WAAWvf,KAAKgf,OAAQjiB,EAAEzC,GAAGuT,OAAOG,WAC5CjR,EAAEzC,GAAGuT,OAAO2W,eAAehb,MAAM1H,eAAgB8N,IAWzDmmF,OAAQ,SAAUh5F,OACVzC,EAAG8R,OACHkH,KAAKlJ,QAAQrN,OACbqP,IAAMrP,EAAElC,OAEHP,EAAI,EAAGA,EAAI8R,IAAK9R,IACjByC,EAAEzC,GAAGusF,gBAAgBnrF,KAAKsE,WAG9BjD,EAAE8pF,gBAAgBnrF,KAAKsE,OAS/BowF,YAAa,SAAU3kF,MACnBrN,IAAIkC,WAAW,+BAAgC,kCAOnD4kF,aAAc,SAAUz5E,QAYxBmmF,KAAM,SAAU14E,OACE5e,EAAG8R,IAAKwgI,KAAMphI,EAAGnL,EAAG9F,EAA9BklB,IAAM,OAEVrT,IAAM8M,EAAE8F,OAAOnkB,OACf+xI,KAAO5sI,KAAKgf,OAAO,GAAGnkB,OAEjBP,EAAI,EAAGA,EAAI8R,IAAK9R,IACjBmlB,IAAInlB,GAAK,YAGRkgC,SACLthB,EAAEshB,SAEGlgC,EAAI,EAAGA,EAAI8R,IAAK9R,QACZC,EAAI,EAAGA,EAAIqyI,KAAMryI,IAAK,KACvB8F,EAAI,EACCmL,EAAI,EAAGA,EAAIY,IAAKZ,IACjBnL,GAAK6Y,EAAE8F,OAAO1kB,GAAGkR,GAAKxL,KAAKgf,OAAOxT,GAAGjR,GAEzCklB,IAAInlB,GAAGC,GAAK8F,cAIfm6B,OAAS,eACNpuB,IAAMpM,KAAKgf,OAAOnkB,OAClB+xI,KAAO5sI,KAAKgf,OAAO,GAAGnkB,WAErBP,EAAI,EAAGA,EAAI8R,IAAK9R,QACZC,EAAI,EAAGA,EAAIqyI,KAAMryI,SACbykB,OAAO1kB,GAAGC,GAAKklB,IAAInlB,GAAGC,IAIhCyF,MAKXq2F,WAAY,eACJt5F,EAAI,CAAC,GAAG7B,OAAOS,MAAM,GAAIqE,KAAKgf,gBAEN,IAAxBhf,KAAKgM,QAAQnR,SACbkC,EAAIiD,KAAKgM,SAGNjP,KAmRfqB,IAAIyuI,gBAAkB,SAAUzsI,MAAO4L,QAASC,mBACrC,IAAI7N,IAAIkuI,eAAelsI,MAAO6L,WAAWpB,KAAMmB,UAG1D5N,IAAIsB,gBAAgB,YAAatB,IAAIyuI,iBAE9B,CACHP,eAAgBluI,IAAIkuI,eACpBO,gBAAiBzuI,IAAIyuI,oBAkF7Bz0I,OAAO,sBAAsB,CACzB,MAAO,YAAa,gBAAiB,gBAAiB,cACtD,aAAc,iBAAkB,aAAc,YAAa,cAAe,sBAC1E,mBAAoB,aAAc,iBACnC,SAAUgG,IAAK8lB,IAAKirB,SAAUha,SAAUhR,OACvC7Q,KAAM9J,MAAO6yH,MAAOuB,KAAMuG,OAAQ2I,UAClC/4B,YAAagzB,MAAOhC,gBAgCpB3mI,IAAI2uI,2BAA6B,SAAU3sI,MAAO4L,QAASC,gBACnD6G,EAAG/V,EAAGmc,EAAG7M,QAEbL,QAAQ,GAAK5L,MAAMG,OAAOyL,QAAQ,IAClCA,QAAQ,GAAK5L,MAAMG,OAAOyL,QAAQ,IAE9BsH,KAAK5I,YAAYtK,MAAO4L,QAAQ,KAAOA,QAAQ,GAAGvB,eAAiBjB,MAAMvF,kBACzElH,EAAIuW,KAAKvH,cAAc3L,MAAO,CAAC4L,QAAQ,IAAKC,WAAY,SAAS,GACjE6G,EAAI9G,QAAQ,OACT,CAAA,IAAIsH,KAAK5I,YAAYtK,MAAO4L,QAAQ,KAAOA,QAAQ,GAAGvB,eAAiBjB,MAAMvF,wBAI1E,IAAIjI,MAAM,yEACJgQ,QAAQ,IAAM,kBAAoBA,QAAQ,IADtC,2CAHhBjP,EAAIuW,KAAKvH,cAAc3L,MAAO,CAAC4L,QAAQ,IAAKC,WAAY,SAAS,GACjE6G,EAAI9G,QAAQ,UAOhBK,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,wBAEtDyM,EAAI9Y,MAAMwM,OAAO,QAAS,CACtB,kBACWuiC,SAASqE,mBAAmBz2C,EAAG+V,EAAG1S,SAE9CiM,MAECiH,KAAKzU,OAAO9B,EAAE8P,UACdqM,EAAE21E,SAAS9xF,UACJA,EAAE8P,SAET9P,EAAE8xF,SAAS31E,GAEfpG,EAAE+7E,SAAS31E,GAEXA,EAAEw2E,OAAS,uBACXx2E,EAAEk4E,WAAW,CAACr0F,EAAEI,GAAI+b,EAAE/b,KAEtB+b,EAAEshB,SAQDthB,EAAEi+C,mBAAqB,eAoChBlpD,GAAK6E,EAAE49B,OAAOkmB,SAAS9oD,EACvBI,GAAK4E,EAAE49B,OAAOkmB,SAAS71C,EACvB0Z,GAAK3nB,EAAE89B,OAAOgmB,SAAS9oD,EACvB8sB,GAAK9nB,EAAE89B,OAAOgmB,SAAS71C,EAEvBgxB,GAAKh1C,EAAE65D,SAAS9oD,EAChBkkC,GAAKj1C,EAAE65D,SAAS71C,EAChB0c,GAAKvkB,EAAE09C,SAAS9oD,EAChB4vB,GAAKxkB,EAAE09C,SAAS71C,QAQb,CANK,IAAM7S,GAAK,MAAQuvB,GAAK,MAAQvvB,GAAK,MAAQusB,GAAK,MAAQiD,GAAK,MAAQjD,GAAK,MAChFxsB,GAAK,MAAQyvB,GAAK,MAAQzvB,GAAK,MAAQ2sB,GAAK,MAAQ6C,GAAK,MAAQ7C,GAAK,IAClE,IAAMoX,GAAK,MAAQ9jC,GAAK,MAAQ8jC,GAAK,MAAQpX,GAAK,MAAQ8C,GAAK,MAAQxvB,GAAK,MAChFwvB,GAAK,MAAQ9C,GAAK,MAAQmX,GAAK,MAAQ9jC,GAAK,MAAQ8jC,GAAK,MAAQtX,GAAK,MAAQgD,GAAK,MACnFxvB,GAAK,MAAQwvB,GAAK,MAAQhD,GAAK,MAKpCvhB,GAmCX9a,IAAI4uI,oBAAsB,SAAU5sI,MAAO4L,QAASC,gBAC5ClP,EAAG+V,EAAGm6H,GAAI5gI,QAEdL,QAAQ,GAAK5L,MAAMG,OAAOyL,QAAQ,IAClCA,QAAQ,GAAK5L,MAAMG,OAAOyL,QAAQ,IAE9BsH,KAAK5I,YAAYtK,MAAO4L,QAAQ,KAAOA,QAAQ,GAAGvB,eAAiBjB,MAAMvF,kBACzE6O,EAAI9G,QAAQ,GACZjP,EAAIuW,KAAKvH,cAAc3L,MAAO,CAAC4L,QAAQ,IAAKC,WAAY,SAAS,OAC9D,CAAA,IAAIqH,KAAK5I,YAAYtK,MAAO4L,QAAQ,KAAOA,QAAQ,GAAGvB,eAAiBjB,MAAMvF,wBAI1E,IAAIjI,MAAM,mEACJgQ,QAAQ,IAAM,kBAAoBA,QAAQ,IADtC,2CAHhB8G,EAAI9G,QAAQ,GACZjP,EAAIuW,KAAKvH,cAAc3L,MAAO,CAAC4L,QAAQ,IAAKC,WAAY,SAAS,UAOrEI,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,kBACtDwgI,GAAKrP,KAAKwB,WAAWh/H,MAAO,CACxB,kBACW0S,EAAE8Q,QAAQ,GAAK7mB,EAAEqhC,IAAMtrB,EAAE8Q,QAAQ,GAAK7mB,EAAEshC,KAEnD,kBACYvrB,EAAE8Q,QAAQ,GAAK7mB,EAAEy/C,KAE7B,kBACW1pC,EAAE8Q,QAAQ,GAAK7mB,EAAEy/C,MAE7BnwC,OAEAqjF,OAAS,gBACZu9C,GAAG77C,WAAW,CAACt+E,EAAE3V,GAAIJ,EAAEI,KAEnBmW,KAAKzU,OAAO9B,EAAE8P,UACdogI,GAAGp+C,SAAS9xF,UACLA,EAAE8P,SAET9P,EAAE8xF,SAASo+C,IAEfn6H,EAAE+7E,SAASo+C,IAEJA,IAgCX7uI,IAAI8uI,yBAA2B,SAAU9sI,MAAO4L,QAASC,gBACjD6G,EAAG/V,EAAGmc,KAEVlN,QAAQ,GAAK5L,MAAMG,OAAOyL,QAAQ,IAClCA,QAAQ,GAAK5L,MAAMG,OAAOyL,QAAQ,IAC9BsH,KAAK5I,YAAYtK,MAAO4L,QAAQ,KAAOA,QAAQ,GAAGvB,eAAiBjB,MAAMvF,kBACzElH,EAAIuW,KAAKvH,cAAc3L,MAAO,CAAC4L,QAAQ,IAAKC,WAAY,SAAS,GACjE6G,EAAI9G,QAAQ,OACT,CAAA,IAAIsH,KAAK5I,YAAYtK,MAAO4L,QAAQ,KAAOA,QAAQ,GAAGvB,eAAiBjB,MAAMvF,wBAI1E,IAAIjI,MAAM,yEACJgQ,QAAQ,IAAM,kBAAoBA,QAAQ,IADtC,2CAHhBjP,EAAIuW,KAAKvH,cAAc3L,MAAO,CAAC4L,QAAQ,IAAKC,WAAY,SAAS,GACjE6G,EAAI9G,QAAQ,UAOhBkN,EAAI9Y,MAAMwM,OAAO,QAAS,CACtB,kBACWuiC,SAAS6B,cAAcl+B,EAAG/V,EAAGqD,OAAO,KAEhD6L,YAECqH,KAAKzU,OAAO9B,EAAE8P,UACdqM,EAAE21E,SAAS9xF,UACJA,EAAE8P,SAET9P,EAAE8xF,SAAS31E,GAEfpG,EAAE+7E,SAAS31E,GAEXA,EAAEw2E,OAAS,qBACXx2E,EAAEk4E,WAAW,CAACr0F,EAAEI,GAAI2V,EAAE3V,KAEtB+b,EAAEshB,SAQDthB,EAAEi+C,mBAAqB,eAmChBlpD,GAAK6E,EAAE49B,OAAOkmB,SAAS9oD,EACvBI,GAAK4E,EAAE49B,OAAOkmB,SAAS71C,EACvB0Z,GAAK3nB,EAAE89B,OAAOgmB,SAAS9oD,EACvB8sB,GAAK9nB,EAAE89B,OAAOgmB,SAAS71C,EACvBgxB,GAAKh1C,EAAE65D,SAAS9oD,EAChBkkC,GAAKj1C,EAAE65D,SAAS71C,EAChB0c,GAAKvkB,EAAE09C,SAAS9oD,EAChB4vB,GAAKxkB,EAAE09C,SAAS71C,QAQb,CANK,IAAM7S,GAAK,MAAQuvB,GAAK,MAAQvvB,GAAK,MAAQusB,GAAK,MAAQiD,GAAK,MAAQjD,GAAK,MAChFxsB,GAAK,MAAQyvB,GAAK,MAAQzvB,GAAK,MAAQ2sB,GAAK,MAAQ6C,GAAK,MAAQ7C,GAAK,IAClE,IAAMoX,GAAK,MAAQ9jC,GAAK,MAAQ8jC,GAAK,MAAQpX,GAAK,MAAQ8C,GAAK,MAAQxvB,GAAK,MAChFwvB,GAAK,MAAQ9C,GAAK,MAAQmX,GAAK,MAAQ9jC,GAAK,MAAQ8jC,GAAK,MAAQtX,GAAK,MAAQgD,GAAK,MACnFxvB,GAAK,MAAQwvB,GAAK,MAAQhD,GAAK,MAKpCvhB,GAoCX9a,IAAI+uI,2BAA6B,SAAU/sI,MAAO4L,QAASC,gBACnDlP,EAAG+V,EAAGm6H,GAAI/zH,EAAG7M,QAEjBL,QAAQ,GAAK5L,MAAMG,OAAOyL,QAAQ,IAClCA,QAAQ,GAAK5L,MAAMG,OAAOyL,QAAQ,IAC9BsH,KAAK5I,YAAYtK,MAAO4L,QAAQ,KAAOA,QAAQ,GAAGvB,eAAiBjB,MAAMvF,kBACzE6O,EAAI9G,QAAQ,GACZjP,EAAIuW,KAAKvH,cAAc3L,MAAO,CAAC4L,QAAQ,IAAKC,WAAY,SAAS,OAC9D,CAAA,IAAIqH,KAAK5I,YAAYtK,MAAO4L,QAAQ,KAAOA,QAAQ,GAAGvB,eAAiBjB,MAAMvF,wBAI1E,IAAIjI,MAAM,mEACJgQ,QAAQ,IAAM,kBAAoBA,QAAQ,IADtC,2CAHhB8G,EAAI9G,QAAQ,GACZjP,EAAIuW,KAAKvH,cAAc3L,MAAO,CAAC4L,QAAQ,IAAKC,WAAY,SAAS,UAMrEI,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,uBAAwB,UAC9EyM,EAAI9a,IAAI8uI,yBAAyB9sI,MAAO,CAAC0S,EAAG/V,GAAIsP,OAC9CsjF,MAAO,EAEJr8E,KAAKzU,OAAOoN,WAAWgE,SACxBhE,WAAWgE,MAAQ7P,MAAMqM,QAAQwD,MAAMogC,MAG3ChkC,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,yBACtDwgI,GAAKrP,KAAKwB,WAAWh/H,MAAO,CACxB,kBACY+uC,SAAS6B,cAAcl+B,EAAG/V,EAAGqD,OAAO,GAAK,CAAC8Y,EAAGnc,GAAK,CAACA,EAAGmc,KAEnE7M,OAQAikC,MAAQp3B,EAEP5F,KAAKzU,OAAO9B,EAAE8P,UACdogI,GAAGp+C,SAAS9xF,UACLA,EAAE8P,SAET9P,EAAE8xF,SAASo+C,IAEfn6H,EAAE+7E,SAASo+C,IAEXA,GAAGv9C,OAAS,uBACZu9C,GAAG77C,WAAW,CAACr0F,EAAEI,GAAI2V,EAAE3V,KACvB8vI,GAAGr9C,KAAO,CACNt/C,MAAOp3B,GAEX+zH,GAAGp9C,SAASn0F,KAAKwd,GAEV+zH,IAkCX7uI,IAAIgvI,eAAiB,SAAUhtI,MAAO4L,QAASC,gBACvCoB,EAAG3M,EAAGwY,EAAG5e,EACT+R,SAEC/R,EAAI,EAAGA,EAAI0R,QAAQnR,SAAUP,EAC9B0R,QAAQ1R,GAAK8F,MAAMG,OAAOyL,QAAQ1R,OAEf,IAAnB0R,QAAQnR,QAAgByY,KAAK5I,YAAYtK,MAAO4L,QAAQ,KAAOsH,KAAK5I,YAAYtK,MAAO4L,QAAQ,IAC/FA,QAAUsH,KAAKvH,cAAc3L,MAAO4L,QAASC,WAAY,SACzDoB,EAAIrB,QAAQ,GACZtL,EAAIsL,QAAQ,OACT,CAAA,GAAuB,IAAnBA,QAAQnR,QAAgBmR,QAAQ,GAAGvB,eAAiBjB,MAAMvF,wBAI3D,IAAIjI,MAAM,kFAHhBqR,EAAIrB,QAAQ,GAAG0kC,OACfhwC,EAAIsL,QAAQ,GAAG4kC,cAMnBvkC,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,YACtDyM,EAAI9Y,MAAMwM,OAAO,QAAS,CACtB,eACQkB,EAAIT,EAAEQ,OAAOG,UAAU,GAAKtN,EAAEmN,OAAOG,UAAU,UAC/CU,MAAMZ,IAAMpB,KAAKwC,IAAI7B,EAAEQ,OAAOG,UAAU,IAAMkW,IAAIzF,KAAO/R,KAAKwC,IAAIxO,EAAEmN,OAAOG,UAAU,IAAMkW,IAAIzF,IACxF9P,IAGA,GAAJb,GAEX,eACQiT,EAAI1T,EAAEQ,OAAOG,UAAU,GAAKtN,EAAEmN,OAAOG,UAAU,UAC/CU,MAAMqS,IAAMrU,KAAKwC,IAAI7B,EAAEQ,OAAOG,UAAU,IAAMkW,IAAIzF,KAAO/R,KAAKwC,IAAIxO,EAAEmN,OAAOG,UAAU,IAAMkW,IAAIzF,IACxF9P,IAGA,GAAJoS,IACP1U,MACJiH,KAAKzU,OAAOwO,EAAER,UACdqM,EAAE21E,SAASxhF,UACJA,EAAER,SAETQ,EAAEwhF,SAAS31E,GAEX5F,KAAKzU,OAAO6B,EAAEmM,UACdqM,EAAE21E,SAASnuF,UACJA,EAAEmM,SAETnM,EAAEmuF,SAAS31E,GAGfA,EAAEw2E,OAAS,WACXx2E,EAAEk4E,WAAW,CAAC/jF,EAAElQ,GAAIuD,EAAEvD,KAEtB+b,EAAEmsE,gBAAgB7qD,SAQjBthB,EAAEi+C,mBAAqB,eA2BhBlpD,GAAKZ,EAAEupD,SAAS9oD,EAChBI,GAAKb,EAAEupD,SAAS71C,EAChB0Z,GAAK/5B,EAAEk2D,SAAS9oD,EAChB8sB,GAAKl6B,EAAEk2D,SAAS71C,EAChB0c,GAAKvkB,EAAE09C,SAAS9oD,EAChB4vB,GAAKxkB,EAAE09C,SAAS71C,QAOb,CALK,IAAM7S,GAAK,MAAQuvB,GAAK,MAAQvvB,GAAK,MAAQusB,GAAK,MAAQiD,GAAK,MAAQjD,GAAK,MAChFxsB,GAAK,MAAQyvB,GAAK,MAAQzvB,GAAK,MAAQ2sB,GAAK,MAAQ6C,GAAK,MAAQ7C,GAAK,IAClE,IAAM3sB,GAAK,YAAcA,GAAK,MAAQwvB,GAAK,MAAQvvB,GAAK,UAAYA,GAAK,MAC7EwvB,GAAK,MAAQjD,GAAK,UAAYA,GAAK,MAAQgD,GAAK,MAAQ7C,GAAK,UAAYA,GAAK,MAAQ8C,GAAK,MAKhGxkB,GAgCX9a,IAAIivI,oBAAsB,SAAUjtI,MAAO4L,QAASC,gBAC5CoB,EAAG3M,EAAGkP,EAAG7S,EAAGzC,MAEXA,EAAI,EAAGA,EAAI0R,QAAQnR,SAAUP,EAC9B0R,QAAQ1R,GAAK8F,MAAMG,OAAOyL,QAAQ1R,OAEf,IAAnB0R,QAAQnR,QACJyY,KAAK5I,YAAYtK,MAAO4L,QAAQ,KAChCsH,KAAK5I,YAAYtK,MAAO4L,QAAQ,KAChCsH,KAAK5I,YAAYtK,MAAO4L,QAAQ,IACpCA,QAAUsH,KAAKvH,cAAc3L,MAAO4L,QAASC,WAAY,SACzDoB,EAAIrB,QAAQ,GACZtL,EAAIsL,QAAQ,GACZ4D,EAAI5D,QAAQ,QACT,GAAIsH,KAAK5I,YAAYtK,MAAO4L,QAAQ,KACnCA,QAAQ,GAAGvB,eAAiBjB,MAAMvF,kBACtC2L,EAAI0D,KAAKvH,cAAc3L,MAAO,CAAC4L,QAAQ,IAAKC,WAAY,SAAS,GACjEoB,EAAIrB,QAAQ,GAAG0kC,OACfhwC,EAAIsL,QAAQ,GAAG4kC,WACZ,CAAA,IAAIt9B,KAAK5I,YAAYtK,MAAO4L,QAAQ,KACnCA,QAAQ,GAAGvB,eAAiBjB,MAAMvF,wBAKhC,IAAIjI,MAAM,oEACJgQ,QAAQ,IAAM,eAAiBA,QAAQ,IAAM,kBAAoBA,QAAQ,IADrE,gEAJhB4D,EAAI0D,KAAKvH,cAAc3L,MAAO,CAAC4L,QAAQ,IAAKC,WAAY,SAAS,GACjEoB,EAAIrB,QAAQ,GAAG0kC,OACfhwC,EAAIsL,QAAQ,GAAG4kC,cAOnB7zC,EAAIqD,MAAMwM,OAAO,QAAS,CACtB,kBACWgD,EAAE/B,OAAOG,UAAU,GAAKtN,EAAEmN,OAAOG,UAAU,GAAKX,EAAEQ,OAAOG,UAAU,IAE9E,kBACW4B,EAAE/B,OAAOG,UAAU,GAAKtN,EAAEmN,OAAOG,UAAU,GAAKX,EAAEQ,OAAOG,UAAU,KAE/E/B,YAGCqH,KAAKzU,OAAOwO,EAAER,UACd9P,EAAE8xF,SAASxhF,UACJA,EAAER,SAETQ,EAAEwhF,SAAS9xF,GAEXuW,KAAKzU,OAAO6B,EAAEmM,UACd9P,EAAE8xF,SAASnuF,UACJA,EAAEmM,SAETnM,EAAEmuF,SAAS9xF,GAEXuW,KAAKzU,OAAO+Q,EAAE/C,UACd9P,EAAE8xF,SAASj/E,UACJA,EAAE/C,SAET+C,EAAEi/E,SAAS9xF,GAGfA,EAAE2yF,OAAS,gBACX3yF,EAAEq0F,WAAW,CAAC/jF,EAAElQ,GAAIuD,EAAEvD,GAAIyS,EAAEzS,KAI5BJ,EAAEsoF,gBAAgB7qD,SAElBz9B,EAAEo6D,mBAAqB,eAmCflpD,GAAKZ,EAAEupD,SAAS9oD,EAChBI,GAAKb,EAAEupD,SAAS71C,EAChB0Z,GAAK/5B,EAAEk2D,SAAS9oD,EAChB8sB,GAAKl6B,EAAEk2D,SAAS71C,EAChBN,GAAK7Q,EAAEgnD,SAAS9oD,EAChB4S,GAAK9Q,EAAEgnD,SAAS71C,EAChB0c,GAAK1gC,EAAE65D,SAAS9oD,EAChB4vB,GAAK3gC,EAAE65D,SAAS71C,QASb,CAPM,IAAM6Z,GAAK,MAAQ6C,GAAK,MAAQ7C,GAAK,MAAQna,GAAK,MAAQvS,GAAK,MAAQuvB,GAAK,MACjFvvB,GAAK,MAAQuS,GAAK,MAAQid,GAAK,MAAQjD,GAAK,MAAQiD,GAAK,MAAQzvB,GAAK,MAAQyS,GAAK,MACnF+Z,GAAK,MAAQ/Z,GAAK,MAAQzS,GAAK,IAC1B,IAAMyvB,GAAK,MAAQzvB,GAAK,MAAQyvB,GAAK,MAAQjd,GAAK,MAAQma,GAAK,MAAQ3sB,GAAK,MACjF2sB,GAAK,MAAQna,GAAK,MAAQgd,GAAK,MAAQvvB,GAAK,MAAQuvB,GAAK,MAAQ/c,GAAK,MAAQ+Z,GAAK,MACnFvsB,GAAK,MAAQusB,GAAK,MAAQ/Z,GAAK,MAKpC3jB,GAiEXqB,IAAIkvI,eAAiB,SAAUltI,MAAO4L,QAASC,gBACvClP,EAAGwwI,GAAIC,GAAIh3F,GAAIl8C,EAAG+R,KAAMohI,GAAK,MAE5BnzI,EAAI,EAAGA,EAAI0R,QAAQnR,SAAUP,EAC9B0R,QAAQ1R,GAAK8F,MAAMG,OAAOyL,QAAQ1R,WAEtCyC,EAAI,KACmB,IAAnBiP,QAAQnR,QAGRkC,GADAiP,QAAUsH,KAAKvH,cAAc3L,MAAO4L,QAASC,WAAY,UAC7C,GACZwhI,GAAK,GACEn6H,KAAK5I,YAAYtK,MAAO4L,QAAQ,KAEvCjP,EAAIuW,KAAKvH,cAAc3L,MAAO,CAAC4L,QAAQ,IAAKC,WAAY,SAAS,GAEjEuqC,GAAK,kBACMxqC,QAAQ,GAAG4X,UAEftQ,KAAK5I,YAAYtK,MAAO4L,QAAQ,MAEvCjP,EAAIuW,KAAKvH,cAAc3L,MAAO,CAAC4L,QAAQ,IAAKC,WAAY,SAAS,GAEjEuqC,GAAK,kBACMxqC,QAAQ,GAAG4X,UAIrBtQ,KAAKzU,OAAOoN,WAAWgE,SACxBhE,WAAWgE,MAAQ7P,MAAMqM,QAAQwD,MAAMogC,MAG3ChkC,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,WAAY,UAI9D8gI,GAHO,IAAPE,GAGKrtI,MAAMwM,OAAO,QAAS,CACvB,kBACWsX,IAAI1D,aAAa,CAAC,EAAG,EAAG,GAAIg2B,QAExCnqC,MAIEjM,MAAMwM,OAAO,gBAAiBZ,QAASK,OAE7C6iF,aAAc,EAEjB7iF,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,aAEtD+gI,GAAKptI,MAAMwM,OAAO,OAAQ,CAAC7P,EAAGwwI,IAAKlhI,OAEhCqjF,OAAS,WACZ89C,GAAG59C,KAAO,CACNt/C,MAAOi9F,IAGXC,GAAG39C,SAASn0F,KAAK6xI,IACjBC,GAAGp8C,WAAW,CAACplF,QAAQ,GAAG7O,GAAI6O,QAAQ,GAAG7O,KAClB,IAAnB6O,QAAQnR,QACR2yI,GAAGt8C,WAAWllF,QAAQ,GAAG7O,IAa7BqwI,GAAGl9F,MAAQi9F,GAEJC,IAkCXpvI,IAAIsvI,oBAAsB,SAAUttI,MAAO4L,QAASC,gBAC5ClP,aAIAkP,WAAWmqE,YAAa,EACxBnqE,WAAWoqE,WAAY,GACvBt5E,EAAIqB,IAAIkvI,eAAeltI,MAAO4L,QAASC,YAAYi5E,aAAa,CAACxyC,eAAe,EAAOC,cAAc,KACnG+8C,OAAS,gBAIJ3yF,EACT,MAAOE,SACC,IAAIjB,MAAM,mEACJgQ,QAAQ,IAAM,kBAAoBA,QAAQ,IADtC,kEAoCxB5N,IAAIuvI,aAAe,SAAUvtI,MAAO4L,QAASC,gBACrClP,EAAG6S,EAAGkD,EAAGxY,EAAG8nB,EAAGxlB,EAAGyP,KAAMkhI,GAAIK,UAE3BtzI,EAAI,EAAGA,EAAI0R,QAAQnR,SAAUP,EAC9B0R,QAAQ1R,GAAK8F,MAAMG,OAAOyL,QAAQ1R,OAGf,IAAnB0R,QAAQnR,OACRkC,EAAIiP,QAAQ,GACZ4D,EAAI7S,EAAEq8F,gBAEH,CAAA,GAAuB,IAAnBptF,QAAQnR,aAaT,IAAImB,MAAM,4DACJgQ,QAAQ,IAAM,kBAAoBA,QAAQ,IADtC,wEAZZsH,KAAK5I,YAAYtK,MAAO4L,QAAQ,IAChCjP,EAAIuW,KAAKvH,cAAc3L,MAAO,CAAC4L,QAAQ,IAAKC,WAAY,SAAS,GACjE2D,EAAI5D,QAAQ,OACT,CAAA,IAAIsH,KAAK5I,YAAYtK,MAAO4L,QAAQ,UAIjC,IAAIhQ,MAAM,4DACJgQ,QAAQ,IAAM,kBAAoBA,QAAQ,IADtC,qEAHhB4D,EAAI5D,QAAQ,GACZjP,EAAIuW,KAAKvH,cAAc3L,MAAO,CAAC4L,QAAQ,IAAKC,WAAY,SAAS,OAYzEI,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,UAClDmD,EAAEnF,eAAiBjB,MAAMvF,kBAEzB2pI,MAAQt6H,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,SAAU,SACjE8gI,GAAKntI,MAAMwM,OAAO,QAAS,CACvB,eACQ7P,EAAImnB,IAAI1D,aAAa,CAAC,EAAG,EAAG,GAAI5Q,EAAEgU,eAC/B,CAAC7mB,EAAE,IAAKA,EAAE,GAAIA,EAAE,MAE5B6wI,OACHL,GAAGr+C,aAAc,GAEjBp8E,EAAI1S,MAAMwM,OAAO,OAAQ,CAAC7P,EAAGwwI,IAAKlhI,OAShCikC,MAAQi9F,GACVz6H,EAAE88E,KAAO,CACLt/C,MAAOi9F,IAEXz6H,EAAE+8E,SAASn0F,KAAK6xI,SACb,GAAI39H,EAAEnF,eAAiBjB,MAAMtF,oBAChC4O,EAAI1S,MAAMwM,OAAO,OAAQ,CAACgD,EAAEozH,SAAUjmI,GAAIsP,WACvC,GAAIuD,EAAEnF,eAAiBjB,MAAMrF,mBACW,SAAvCmP,KAAKrG,SAAS2C,EAAEmD,QAAQwpC,YACxBn6B,EAAIxS,EAAEwuB,EACNxhC,EAAIgT,EAAEyuB,EACNvrB,EAAI1S,MAAMwM,OAAO,OAAQ,CACrB,kBACY7P,EAAEqhC,IAAMjJ,SAAS+H,EAAE9a,EAAX+S,CAAcp4B,EAAE8a,UAAY9a,EAAEshC,IAAMlJ,SAAS+H,EAAEtgC,EAAXu4B,CAAcp4B,EAAE8a,WAExE,kBACWsd,SAAS+H,EAAE9a,EAAX+S,CAAcp4B,EAAE8a,WAE3B,kBACWsd,SAAS+H,EAAEtgC,EAAXu4B,CAAcp4B,EAAE8a,YAE5BxL,OAEHyG,EAAI1S,MAAMwM,OAAO,OAAQ,CACrB,eAGQmlC,GAAIC,GAAI94B,EAAGmH,EAAGmhB,EAAG6N,EAAGnS,EAAG4B,GAAIiC,GAAI51B,EAF/B7Q,EAAIoS,KAAKmS,MAAM9hB,EAAE8a,UACjB4tB,KAAO1oC,EAAE8a,SAAWvd,KAGD,IAAnBsV,EAAEi+H,aACEvzI,IAAMsV,EAAE2nC,aAAe,IACvBj9C,GAAK,EACLmrC,KAAO,OAER,CAAA,GAAuB,IAAnB71B,EAAEumC,oBAUF,EAPP77C,EAAwD,EAApDoS,KAAKmS,MAAM9hB,EAAE8a,UAAYjI,EAAE2nC,aAAe,GAAK,GACnDr+B,GAAKnc,EAAE8a,UAAYjI,EAAE2nC,aAAe,GAAKj9C,GAAK,EAC1CA,GAAKsV,EAAE2nC,aAAe,IACtBj9C,EAAIsV,EAAE2nC,aAAe,EACrBr+B,EAAI,UAMR5e,EAAI,EACG,EAGY,IAAnBsV,EAAEumC,cACMvmC,EAAEyuB,EAAE/jC,GAAKmrC,MAAQ71B,EAAEyuB,EAAE/jC,EAAI,GAAKsV,EAAEyuB,EAAE/jC,MAAQsV,EAAEyuB,EAAE/jC,GAAKsV,EAAEyuB,EAAE/jC,EAAI,KAAOsV,EAAEwuB,EAAE9jC,GAAKmrC,MAAQ71B,EAAEwuB,EAAE9jC,EAAI,GAAKsV,EAAEwuB,EAAE9jC,MAAQsV,EAAEwuB,EAAE9jC,EAAI,GAAKsV,EAAEwuB,EAAE9jC,KAErI+lB,EAAIzQ,EAAErD,OAAOjS,GAAG0T,UAChBwzB,EAAI5xB,EAAErD,OAAOjS,EAAI,GAAG0T,UACpBqhC,EAAIz/B,EAAErD,OAAOjS,EAAI,GAAG0T,UACpBkvB,EAAIttB,EAAErD,OAAOjS,EAAI,GAAG0T,UACpB8wB,IAAM,EAAI5lB,IAAM,EAAIA,IAAMsoB,EAAE,GAAKnhB,EAAE,IAAM,GAAK,EAAInH,GAAKA,GAAKm2B,EAAE,GAAK7N,EAAE,IAAMtoB,EAAIA,GAAKgkB,EAAE,GAAImS,EAAE,IAC5FtO,IAAM,EAAI7nB,IAAM,EAAIA,IAAMsoB,EAAE,GAAKnhB,EAAE,IAAM,GAAK,EAAInH,GAAKA,GAAKm2B,EAAE,GAAK7N,EAAE,IAAMtoB,EAAIA,GAAKgkB,EAAE,GAAImS,EAAE,IAE5FvQ,IADA3zB,EAAIuB,KAAKmU,KAAKie,GAAKA,GAAKiC,GAAKA,IAE7BA,IAAM51B,EAEN6mC,GAAK,CAAC,GADND,GAAKh1C,EAAE8Q,OAAOG,WACF,GAAK+yB,GAAIgR,GAAG,GAAKjT,IACtBiT,GAAG,GAAKC,GAAG,GAAKD,GAAG,GAAKC,GAAG,KAG1C,eAEQD,GAAQ74B,EAAGmH,EAAGmhB,EAAG6N,EAAGnS,EAAG4B,GAAIiC,GAAI51B,EAD/B7Q,EAAIoS,KAAKmS,MAAM9hB,EAAE8a,aAGE,IAAnBjI,EAAEi+H,aACEvzI,IAAMsV,EAAE2nC,aAAe,IACvBj9C,GAAK,OAEN,CAAA,GAAuB,IAAnBsV,EAAEumC,oBAUF,EAPP77C,EAAwD,EAApDoS,KAAKmS,MAAM9hB,EAAE8a,UAAYjI,EAAE2nC,aAAe,GAAK,GACnDr+B,GAAKnc,EAAE8a,UAAYjI,EAAE2nC,aAAe,GAAKj9C,GAAK,EAC1CA,GAAKsV,EAAE2nC,aAAe,IACtBj9C,EAAIsV,EAAE2nC,aAAe,EACrBr+B,EAAI,UAMR5e,EAAI,EACG,EAEY,IAAnBsV,EAAEumC,aACKvmC,EAAEwuB,EAAE9jC,EAAI,GAAKsV,EAAEwuB,EAAE9jC,IAExB+lB,EAAIzQ,EAAErD,OAAOjS,GAAG0T,UAChBwzB,EAAI5xB,EAAErD,OAAOjS,EAAI,GAAG0T,UACpBqhC,EAAIz/B,EAAErD,OAAOjS,EAAI,GAAG0T,UACpBkvB,EAAIttB,EAAErD,OAAOjS,EAAI,GAAG0T,UACpB8wB,IAAM,EAAI5lB,IAAM,EAAIA,IAAMsoB,EAAE,GAAKnhB,EAAE,IAAM,GAAK,EAAInH,GAAKA,GAAKm2B,EAAE,GAAK7N,EAAE,IAAMtoB,EAAIA,GAAKgkB,EAAE,GAAImS,EAAE,IAC5FtO,IAAM,EAAI7nB,IAAM,EAAIA,IAAMsoB,EAAE,GAAKnhB,EAAE,IAAM,GAAK,EAAInH,GAAKA,GAAKm2B,EAAE,GAAK7N,EAAE,IAAMtoB,EAAIA,GAAKgkB,EAAE,GAAImS,EAAE,IAE5FvQ,IADA3zB,EAAIuB,KAAKmU,KAAKie,GAAKA,GAAKiC,GAAKA,IAE7BA,IAAM51B,EAED,CAAC,GADN4mC,GAAKh1C,EAAE8Q,OAAOG,WACF,GAAK+yB,GAAIgR,GAAG,GAAKjT,IACnB,GAAKiT,GAAG,KAI1B,eAEQA,GAAIC,GAAI94B,EAAGmH,EAAGmhB,EAAG6N,EAAGnS,EAAG4B,GAAIiC,GAAI51B,EAD/B7Q,EAAIoS,KAAKmS,MAAM9hB,EAAE8a,aAGE,IAAnBjI,EAAEi+H,aACEvzI,IAAMsV,EAAE2nC,aAAe,IACvBj9C,GAAK,OAEN,CAAA,GAAuB,IAAnBsV,EAAEumC,oBAUF,EAPP77C,EAAwD,EAApDoS,KAAKmS,MAAM9hB,EAAE8a,UAAYjI,EAAE2nC,aAAe,GAAK,GACnDr+B,GAAKnc,EAAE8a,UAAYjI,EAAE2nC,aAAe,GAAKj9C,GAAK,EAC1CA,GAAKsV,EAAE2nC,aAAe,IACtBj9C,EAAIsV,EAAE2nC,aAAe,EACrBr+B,EAAI,UAMR5e,EAAI,EACG,EAGY,IAAnBsV,EAAEumC,aACKvmC,EAAEyuB,EAAE/jC,EAAI,GAAKsV,EAAEyuB,EAAE/jC,IAExB+lB,EAAIzQ,EAAErD,OAAOjS,GAAG0T,UAChBwzB,EAAI5xB,EAAErD,OAAOjS,EAAI,GAAG0T,UACpBqhC,EAAIz/B,EAAErD,OAAOjS,EAAI,GAAG0T,UACpBkvB,EAAIttB,EAAErD,OAAOjS,EAAI,GAAG0T,UACpB8wB,IAAM,EAAI5lB,IAAM,EAAIA,IAAMsoB,EAAE,GAAKnhB,EAAE,IAAM,GAAK,EAAInH,GAAKA,GAAKm2B,EAAE,GAAK7N,EAAE,IAAMtoB,EAAIA,GAAKgkB,EAAE,GAAImS,EAAE,IAC5FtO,IAAM,EAAI7nB,IAAM,EAAIA,IAAMsoB,EAAE,GAAKnhB,EAAE,IAAM,GAAK,EAAInH,GAAKA,GAAKm2B,EAAE,GAAK7N,EAAE,IAAMtoB,EAAIA,GAAKgkB,EAAE,GAAImS,EAAE,IAE5FvQ,IADA3zB,EAAIuB,KAAKmU,KAAKie,GAAKA,GAAKiC,GAAKA,IAE7BA,IAAM51B,EAEN6mC,GAAK,CAAC,GADND,GAAKh1C,EAAE8Q,OAAOG,WACF,GAAK+yB,GAAIgR,GAAG,GAAKjT,IACtBiT,GAAG,GAAKC,GAAG,MAG3B3lC,UAEJ,CAAA,GAAIuD,EAAE/E,OAASrB,MAAMpG,yBAqFlB,IAAIpH,MAAM,4DACJgQ,QAAQ,IAAM,kBAAoBA,QAAQ,IADtC,qEApFhB8G,EAAI1S,MAAMwM,OAAO,OAAQ,CACrB,eACQyB,GAAI9T,EACJD,EAAIoS,KAAKmS,MAAM9hB,EAAE8a,UACjB4tB,KAAO1oC,EAAE8a,SAAWvd,MAGnBC,EAAI,EAAGA,EAAIqV,EAAElG,QAAQ7O,OAAQN,QAC9B8T,GAAKuB,EAAElG,QAAQnP,IAERsQ,OAASrB,MAAMjH,kBAAmB,IACjCjI,EAAI+T,GAAGkpC,mBAIXj9C,GAAK+T,GAAGkpC,oBAIZj9C,IAAM+T,GAAGkpC,aAAe,IACxBj9C,GAAK,EACLmrC,KAAO,GAGPnrC,EAAI,EACG,GAGH+T,GAAGgwB,EAAE/jC,GAAKmrC,MAAQp3B,GAAGgwB,EAAE/jC,EAAI,GAAK+T,GAAGgwB,EAAE/jC,MAAQ+T,GAAGgwB,EAAE/jC,GAAK+T,GAAGgwB,EAAE/jC,EAAI,KAAO+T,GAAG+vB,EAAE9jC,GAAKmrC,MAAQp3B,GAAG+vB,EAAE9jC,EAAI,GAAK+T,GAAG+vB,EAAE9jC,MAAQ+T,GAAG+vB,EAAE9jC,EAAI,GAAK+T,GAAG+vB,EAAE9jC,KAEnJ,eACQ+T,GAAI9T,EACJD,EAAIoS,KAAKmS,MAAM9hB,EAAE8a,cAGhBtd,EAAI,EAAGA,EAAIqV,EAAElG,QAAQ7O,OAAQN,QAC9B8T,GAAKuB,EAAElG,QAAQnP,IACRsQ,OAASrB,MAAMjH,kBAAmB,IACjCjI,EAAI+T,GAAGkpC,mBAIXj9C,GAAK+T,GAAGkpC,oBAIZj9C,IAAM+T,GAAGkpC,aAAe,IACxBj9C,GAAM,GAGNA,EAAI,EACG,EAGJ+T,GAAG+vB,EAAE9jC,EAAI,GAAK+T,GAAG+vB,EAAE9jC,IAE9B,eACQ+T,GAAI9T,EACJD,EAAIoS,KAAKmS,MAAM9hB,EAAE8a,cAGhBtd,EAAI,EAAGA,EAAIqV,EAAElG,QAAQ7O,OAAQN,QAC9B8T,GAAKuB,EAAElG,QAAQnP,IACRsQ,OAASrB,MAAMjH,kBAAmB,IACjCjI,EAAI+T,GAAGkpC,mBAIXj9C,GAAK+T,GAAGkpC,oBAIZj9C,IAAM+T,GAAGkpC,aAAe,IACxBj9C,GAAK,GAGLA,EAAI,EACG,EAGJ+T,GAAGgwB,EAAE/jC,EAAI,GAAK+T,GAAGgwB,EAAE/jC,KAE/B+R,aAOPyG,EAAE48E,OAAS,SACX58E,EAAEs+E,WAAWplF,SAETsH,KAAKzU,OAAO9B,EAAE8P,UACdiG,EAAE+7E,SAAS9xF,UACJA,EAAE8P,SAET9P,EAAE8xF,SAAS/7E,GAEflD,EAAEi/E,SAAS/7E,GAEJA,GA+BX1U,IAAI0vI,eAAiB,SAAU1tI,MAAO4L,QAASC,gBACvClP,EAAG+V,EAAGxY,EAAG+R,QAEbL,QAAUsH,KAAKvH,cAAc3L,MAAO4L,QAASC,WAAY,SACrDqH,KAAK9I,QAAQwB,QAAQ,KAAOsH,KAAK9I,QAAQwB,QAAQ,KAAOsH,KAAK9I,QAAQwB,QAAQ,IAAK,MAElFK,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,WAAY,UAC7D2mE,YAAa,GAElBr2E,EAAIqD,MAAMwM,OAAO,QAAS,CACtB,kBACWuiC,SAASW,cAAc9jC,QAAQ,GAAIA,QAAQ,GAAIA,QAAQ,GAAI5L,SAEvEiM,OACDsjF,MAAO,EAEJr1F,EAAI,EAAGA,EAAI,EAAGA,IAEXgZ,KAAKzU,OAAOmN,QAAQ1R,GAAGuS,UACvB9P,EAAE8xF,SAAS7iF,QAAQ1R,WACZ0R,QAAQ1R,GAAGuS,SAElBb,QAAQ1R,GAAGu0F,SAAS9xF,UAIvBuW,KAAKzU,OAAOoN,WAAWgE,SACxBhE,WAAWgE,MAAQ7P,MAAMqM,QAAQwD,MAAMogC,MAG3ChkC,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,aACtDqG,EAAI8qH,KAAKwB,WAAWh/H,MAAO,CAAC4L,QAAQ,GAAIjP,GAAIsP,OAQ1CikC,MAAQvzC,EAEV+V,EAAE48E,OAAS,WACX58E,EAAEs+E,WAAWplF,SACb8G,EAAE88E,KAAO,CACLt/C,MAAOvzC,GAEX+V,EAAE+8E,SAASn0F,KAAKqB,GAET+V,QAGL,IAAI9W,MAAM,oEACJgQ,QAAQ,IAAM,kBAAoBA,QAAQ,IADtC,mDAuCpB5N,IAAI2vI,iCAAmC,SAAU3tI,MAAO4L,QAASC,gBAIzDu4H,GAAIC,GAAIp4H,KAAM7O,IACdm4C,GAAKv1C,MAAMG,OAAOyL,QAAQ,IAC1B4pC,GAAKx1C,MAAMG,OAAOyL,QAAQ,OAE1B2pC,GAAGlrC,eAAiBjB,MAAMvF,mBAAqB2xC,GAAGnrC,eAAiBjB,MAAMvF,wBACnE,IAAIjI,MAAM,kFACJgQ,QAAQ,IAAM,kBAAoBA,QAAQ,IADtC,iDAKfsH,KAAKzU,OAAOoN,WAAWgE,SACxBhE,WAAWgE,MAAQ7P,MAAMqM,QAAQwD,MAAMogC,MAG3ChkC,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,gBAAiB,SACvE+3H,GAAKpkI,MAAMwM,OAAO,OAAQ,CACtB,eACQ4lB,GAAK9lB,KAAKmU,KAAK80B,GAAG/xB,QAAQ,GAAK+xB,GAAG/xB,QAAQ,GAAK+xB,GAAG/xB,QAAQ,GAAK+xB,GAAG/xB,QAAQ,IAC1E6O,GAAK/lB,KAAKmU,KAAK+0B,GAAGhyB,QAAQ,GAAKgyB,GAAGhyB,QAAQ,GAAKgyB,GAAGhyB,QAAQ,GAAKgyB,GAAGhyB,QAAQ,WAEvE+xB,GAAG/xB,QAAQ,GAAK4O,GAAKojB,GAAGhyB,QAAQ,GAAK6O,IAEhD,eACQD,GAAK9lB,KAAKmU,KAAK80B,GAAG/xB,QAAQ,GAAK+xB,GAAG/xB,QAAQ,GAAK+xB,GAAG/xB,QAAQ,GAAK+xB,GAAG/xB,QAAQ,IAC1E6O,GAAK/lB,KAAKmU,KAAK+0B,GAAGhyB,QAAQ,GAAKgyB,GAAGhyB,QAAQ,GAAKgyB,GAAGhyB,QAAQ,GAAKgyB,GAAGhyB,QAAQ,WAEvE+xB,GAAG/xB,QAAQ,GAAK4O,GAAKojB,GAAGhyB,QAAQ,GAAK6O,IAEhD,eACQD,GAAK9lB,KAAKmU,KAAK80B,GAAG/xB,QAAQ,GAAK+xB,GAAG/xB,QAAQ,GAAK+xB,GAAG/xB,QAAQ,GAAK+xB,GAAG/xB,QAAQ,IAC1E6O,GAAK/lB,KAAKmU,KAAK+0B,GAAGhyB,QAAQ,GAAKgyB,GAAGhyB,QAAQ,GAAKgyB,GAAGhyB,QAAQ,GAAKgyB,GAAGhyB,QAAQ,WAEvE+xB,GAAG/xB,QAAQ,GAAK4O,GAAKojB,GAAGhyB,QAAQ,GAAK6O,KAEjDpmB,MAEEiH,KAAKzU,OAAOoN,WAAWgE,SACxBhE,WAAWgE,MAAQ7P,MAAMqM,QAAQwD,MAAMogC,MAE3ChkC,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,gBAAiB,SACvEg4H,GAAKrkI,MAAMwM,OAAO,OAAQ,CACtB,eACQ4lB,GAAK9lB,KAAKmU,KAAK80B,GAAG/xB,QAAQ,GAAK+xB,GAAG/xB,QAAQ,GAAK+xB,GAAG/xB,QAAQ,GAAK+xB,GAAG/xB,QAAQ,IAC1E6O,GAAK/lB,KAAKmU,KAAK+0B,GAAGhyB,QAAQ,GAAKgyB,GAAGhyB,QAAQ,GAAKgyB,GAAGhyB,QAAQ,GAAKgyB,GAAGhyB,QAAQ,WAEvE+xB,GAAG/xB,QAAQ,GAAK4O,GAAKojB,GAAGhyB,QAAQ,GAAK6O,IAEhD,eACQD,GAAK9lB,KAAKmU,KAAK80B,GAAG/xB,QAAQ,GAAK+xB,GAAG/xB,QAAQ,GAAK+xB,GAAG/xB,QAAQ,GAAK+xB,GAAG/xB,QAAQ,IAC1E6O,GAAK/lB,KAAKmU,KAAK+0B,GAAGhyB,QAAQ,GAAKgyB,GAAGhyB,QAAQ,GAAKgyB,GAAGhyB,QAAQ,GAAKgyB,GAAGhyB,QAAQ,WAEvE+xB,GAAG/xB,QAAQ,GAAK4O,GAAKojB,GAAGhyB,QAAQ,GAAK6O,IAEhD,eACQD,GAAK9lB,KAAKmU,KAAK80B,GAAG/xB,QAAQ,GAAK+xB,GAAG/xB,QAAQ,GAAK+xB,GAAG/xB,QAAQ,GAAK+xB,GAAG/xB,QAAQ,IAC1E6O,GAAK/lB,KAAKmU,KAAK+0B,GAAGhyB,QAAQ,GAAKgyB,GAAGhyB,QAAQ,GAAKgyB,GAAGhyB,QAAQ,GAAKgyB,GAAGhyB,QAAQ,WAEvE+xB,GAAG/xB,QAAQ,GAAK4O,GAAKojB,GAAGhyB,QAAQ,GAAK6O,KAEjDpmB,MAiBH7O,IAAM,IAAIu2G,YAAY,CAACl9B,MAAO2tD,GAAI1tD,MAAO2tD,KAEzCD,GAAG70C,MAAO,EACV80C,GAAG90C,MAAO,EAEVnyF,IAAIkyF,OAAS,gBACblyF,IAAI4zF,WAAW,CAACz7C,GAAGx4C,GAAIy4C,GAAGz4C,KAC1BK,IAAIoyF,KAAO,CACP/Y,MAAO2tD,GACP1tD,MAAO2tD,IAIJjnI,KA8GXY,IAAI4vI,mBAAqB,SAAU5tI,MAAO4L,QAASC,gBAC3ClP,EAAGzC,EAAG+S,EAAG3M,EAAGkP,KAEhB5D,QAAUsH,KAAKvH,cAAc3L,MAAO4L,QAASC,WAAY,SACrDqH,KAAK9I,QAAQwB,QAAQ,KAAOsH,KAAK9I,QAAQwB,QAAQ,KAAOsH,KAAK9I,QAAQwB,QAAQ,IAAK,KAElFqB,EAAIrB,QAAQ,GACZtL,EAAIsL,QAAQ,GACZ4D,EAAI5D,QAAQ,GAEZjP,EAAIs/H,MAAMU,YAAY38H,MAAO,CACzB,kBACW+uC,SAASgC,aAAa9jC,EAAG3M,EAAGkP,EAAGxP,SAE3C6L,YAEE3R,EAAI,EAAGA,EAAI,EAAGA,IACXgZ,KAAKzU,OAAOmN,QAAQ1R,GAAGuS,UACvB9P,EAAE8xF,SAAS7iF,QAAQ1R,WACZ0R,QAAQ1R,GAAGuS,SAElBb,QAAQ1R,GAAGu0F,SAAS9xF,UAI5BA,EAAE2yF,OAAS,eACX3yF,EAAEq0F,WAAWplF,SAEbjP,EAAEo6D,mBAAqB,eAWflpD,GAAKZ,EAAEupD,SAAS9oD,EAChBI,GAAKb,EAAEupD,SAAS71C,EAChB0Z,GAAK/5B,EAAEk2D,SAAS9oD,EAChB8sB,GAAKl6B,EAAEk2D,SAAS71C,EAChBN,GAAK7Q,EAAEgnD,SAAS9oD,EAChB4S,GAAK9Q,EAAEgnD,SAAS71C,EAChB0c,GAAK1gC,EAAE65D,SAAS9oD,EAChB4vB,GAAK3gC,EAAE65D,SAAS71C,QAKb,CAHK,CAAC,KAAM0c,GAAI,MAAOxvB,GAAI,UAAWyvB,GAAI,MAAOxvB,GAAI,UAAWuvB,GAAI,MAAOhD,GAAI,UAAWiD,GAAI,MAAO9C,GAAI,QAAQx/B,KAAK,IACjH,CAAC,KAAMqiC,GAAI,MAAOxvB,GAAI,UAAWyvB,GAAI,MAAOxvB,GAAI,UAAWuvB,GAAI,MAAOhd,GAAI,UAAWid,GAAI,MAAOhd,GAAI,QAAQtlB,KAAK,MAK1H2B,QAGL,IAAIf,MAAM,2EACJgQ,QAAQ,IAAM,eAAiBA,QAAQ,IAAM,kBAAoBA,QAAQ,IADrE,mDA8BpB5N,IAAI6vI,eAAiB,SAAU7tI,MAAO4L,QAASC,gBACvClP,EAAGsjB,EAAGmhB,EAAG6N,EAAG/0C,QAEhB0R,QAAUsH,KAAKvH,cAAc3L,MAAO4L,QAASC,WAAY,UAC7CpR,QAAU,GAAKyY,KAAK9I,QAAQwB,QAAQ,KAAOsH,KAAK9I,QAAQwB,QAAQ,KAAOsH,KAAK9I,QAAQwB,QAAQ,WA4B9F,IAAIhQ,MAAM,8DACJgQ,QAAQ,IAAM,eAAiBA,QAAQ,IAAM,kBAAoBA,QAAQ,IADrE,sDA3BhBqU,EAAIrU,QAAQ,GACZw1B,EAAIx1B,QAAQ,GACZqjC,EAAIrjC,QAAQ,GAEZjP,EAAIqD,MAAMwM,OAAO,QAAS,CAAC,eACnBS,EAAG3M,EAAGkP,SAEVvC,EAAIX,KAAKmU,MAAM2gB,EAAEpD,IAAMiR,EAAEjR,MAAQoD,EAAEpD,IAAMiR,EAAEjR,MAAQoD,EAAEnD,IAAMgR,EAAEhR,MAAQmD,EAAEnD,IAAMgR,EAAEhR,MAC/E39B,EAAIgM,KAAKmU,MAAMR,EAAE+d,IAAMiR,EAAEjR,MAAQ/d,EAAE+d,IAAMiR,EAAEjR,MAAQ/d,EAAEge,IAAMgR,EAAEhR,MAAQhe,EAAEge,IAAMgR,EAAEhR,MAC/EzuB,EAAIlD,KAAKmU,MAAM2gB,EAAEpD,IAAM/d,EAAE+d,MAAQoD,EAAEpD,IAAM/d,EAAE+d,MAAQoD,EAAEnD,IAAMhe,EAAEge,MAAQmD,EAAEnD,IAAMhe,EAAEge,MAExE,IAAIla,OAAO3a,MAAM1H,eAAgB,EAAEuL,EAAIgT,EAAE+d,IAAM19B,EAAI8gC,EAAEpD,IAAMxuB,EAAIy/B,EAAEjR,MAAQ/wB,EAAI3M,EAAIkP,IAAKvC,EAAIgT,EAAEge,IAAM39B,EAAI8gC,EAAEnD,IAAMzuB,EAAIy/B,EAAEhR,MAAQhxB,EAAI3M,EAAIkP,IAAKxP,SAChJ6L,YAEC3R,EAAI,EAAGA,EAAI,EAAGA,IACXgZ,KAAKzU,OAAOmN,QAAQ1R,GAAGuS,UACvB9P,EAAE8xF,SAAS7iF,QAAQ1R,WACZ0R,QAAQ1R,GAAGuS,SAElBb,QAAQ1R,GAAGu0F,SAAS9xF,UAI5BA,EAAE2yF,OAAS,WACX3yF,EAAEq0F,WAAWplF,SAQVjP,GA2BXqB,IAAI8vI,mBAAqB,SAAU9tI,MAAO4L,QAASC,gBAC3ClP,EAAG6S,EAAGvD,KAAM/R,MAGA,KADhB0R,QAAUsH,KAAKvH,cAAc3L,MAAO4L,QAASC,WAAY,gBAE/C,IAAIjQ,MAAM,kEACJgQ,QAAQ,IAAM,eAAiBA,QAAQ,IAAM,kBAAoBA,QAAQ,IADrE,0DAMhBK,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,eAAgB,WACtE1P,EAAIqB,IAAI4vI,mBAAmB5tI,MAAO4L,QAASK,OAEzCsjF,MAAO,EAEJr8E,KAAKzU,OAAOoN,WAAWgE,SACxBhE,WAAWgE,MAAQ7P,MAAMqM,QAAQwD,MAAMurC,QAE3CnvC,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,iBACtDmD,EAAIu0H,OAAOU,aAAazkI,MAAO,CAACrD,EAAGiP,QAAQ,IAAKK,OAE9CqjF,OAAS,eACX9/E,EAAEwhF,WAAWplF,SACb4D,EAAEggF,KAAO,CACLl3D,OAAQ37B,GAEZ6S,EAAEigF,SAASn0F,KAAKkU,GACXtV,EAAI,EAAGA,EAAI,EAAGA,IACXgZ,KAAKzU,OAAOmN,QAAQ1R,GAAGuS,UACvB+C,EAAEi/E,SAAS7iF,QAAQ1R,WACZ0R,QAAQ1R,GAAGuS,SAElBb,QAAQ1R,GAAGu0F,SAASj/E,GAI9B,MAAO3S,SACC,IAAIjB,MAAM,kEACJgQ,QAAQ,IAAM,eAAiBA,QAAQ,IAAM,kBAAoBA,QAAQ,IADrE,yDAOb4D,GA4BXxR,IAAI+vI,eAAiB,SAAU/tI,MAAO4L,QAASC,gBACvC3R,EAAGyC,EAAG6S,EAAGvD,SAGG,KADhBL,QAAUsH,KAAKvH,cAAc3L,MAAO4L,QAASC,WAAY,gBAE/C,IAAIjQ,MAAM,kEACJgQ,QAAQ,IAAM,eAAiBA,QAAQ,IAAM,kBAAoBA,QAAQ,IADrE,0DAKhBK,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,WAAY,WAClE1P,EAAIqB,IAAI6vI,eAAe7tI,MAAO4L,QAASK,OAErCsjF,MAAO,EAEJr8E,KAAKzU,OAAOoN,WAAWgE,SACxBhE,WAAWgE,MAAQ7P,MAAMqM,QAAQwD,MAAMurC,QAE3CnvC,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,aACtDmD,EAAIu0H,OAAOU,aAAazkI,MAAO,CAACrD,EAAG,eAC3BsQ,EAAIX,KAAKmU,MAAM7U,QAAQ,GAAGoyB,IAAMpyB,QAAQ,GAAGoyB,MAAQpyB,QAAQ,GAAGoyB,IAAMpyB,QAAQ,GAAGoyB,MAAQpyB,QAAQ,GAAGqyB,IAAMryB,QAAQ,GAAGqyB,MAAQryB,QAAQ,GAAGqyB,IAAMryB,QAAQ,GAAGqyB,MACvJ39B,EAAIgM,KAAKmU,MAAM7U,QAAQ,GAAGoyB,IAAMpyB,QAAQ,GAAGoyB,MAAQpyB,QAAQ,GAAGoyB,IAAMpyB,QAAQ,GAAGoyB,MAAQpyB,QAAQ,GAAGqyB,IAAMryB,QAAQ,GAAGqyB,MAAQryB,QAAQ,GAAGqyB,IAAMryB,QAAQ,GAAGqyB,MACvJzuB,EAAIlD,KAAKmU,MAAM7U,QAAQ,GAAGoyB,IAAMpyB,QAAQ,GAAGoyB,MAAQpyB,QAAQ,GAAGoyB,IAAMpyB,QAAQ,GAAGoyB,MAAQpyB,QAAQ,GAAGqyB,IAAMryB,QAAQ,GAAGqyB,MAAQryB,QAAQ,GAAGqyB,IAAMryB,QAAQ,GAAGqyB,MACvJh+B,GAAKgN,EAAI3M,EAAIkP,GAAK,SAEflD,KAAKmU,MAAOxgB,EAAIgN,IAAMhN,EAAIK,IAAML,EAAIuP,GAAMvP,KACjDgM,OAEFqjF,OAAS,WACX9/E,EAAEwhF,WAAWplF,SACR1R,EAAI,EAAGA,EAAI,EAAGA,IACXgZ,KAAKzU,OAAOmN,QAAQ1R,GAAGuS,UACvB+C,EAAEi/E,SAAS7iF,QAAQ1R,WACZ0R,QAAQ1R,GAAGuS,SAElBb,QAAQ1R,GAAGu0F,SAASj/E,GAU5BA,EAAE8oB,OAAS37B,EAEX6S,EAAEggF,KAAO,CACLl3D,OAAQ9oB,EAAE8oB,QAEd9oB,EAAEigF,SAASn0F,KAAKqB,GAElB,MAAOE,SACC,IAAIjB,MAAM,kEACJgQ,QAAQ,IAAM,eAAiBA,QAAQ,IAAM,kBAAoBA,QAAQ,IADrE,yDAOb4D,GAsGXxR,IAAIgwI,iBAAmB,SAAUhuI,MAAO4L,QAASC,gBACzC6G,EAAGu7H,IAAK7+H,EAAG8+H,IAAKp1H,EAAG5e,EACnB+R,KAAMkiI,MACNr9B,OAAS,kFAER52G,EAAI,EAAGA,EAAI0R,QAAQnR,SAAUP,EAC9B0R,QAAQ1R,GAAK8F,MAAMG,OAAOyL,QAAQ1R,OAGtC+R,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,cAElD6G,KAAK9I,QAAQwB,QAAQ,IACrBqiI,IAAM/6H,KAAKvH,cAAc3L,MAAO,CAAC4L,QAAQ,IAAKuiI,OAAO,OAClD,CAAA,GAAIviI,QAAQ,GAAGvB,eAAiBjB,MAAMrF,oBACjC6H,QAAQ,GAAGvB,eAAiBjB,MAAMvF,mBAClC+H,QAAQ,GAAGnB,OAASrB,MAAMzG,qBAC1BiJ,QAAQ,GAAGvB,eAAiBjB,MAAMtF,0BAGpC,IAAIlI,MAAM,wEACJgQ,QAAQ,IAAM,kBAAoBA,QAAQ,IAAM,KAAOklG,QAHnEm9B,IAAMriI,QAAQ,MAMdA,QAAQ,GAAGvB,eAAiBjB,MAAMvF,wBAG5B,IAAIjI,MAAM,uEACJgQ,QAAQ,IAAM,kBAAoBA,QAAQ,IAAM,KAAOklG,WAHnEp+F,EAAI9G,QAAQ,GAMhBkN,EAAI4zH,UAAUD,gBAAgBzsI,MAAO,CAAC0S,GAAI,CAACjI,KAAM,YAC7CyI,KAAK9I,QAAQ6jI,KACb7+H,EAAI6sH,MAAMU,YAAY38H,MAAO,CAACiuI,IAAKn1H,GAAI7M,WAEpC,GAAIgiI,IAAI5jI,eAAiBjB,MAAMrF,mBAClCqL,EAAIu3H,MAAMwB,YAAYnoI,MAAO,CAACiuI,IAAKn1H,GAAI7M,WACpC,GAAIgiI,IAAI5jI,eAAiBjB,MAAMvF,kBAClCuL,EAAIouH,KAAKwB,WAAWh/H,MAAO,CAACiuI,IAAKn1H,GAAI7M,WAClC,GAAIgiI,IAAIxjI,OAASrB,MAAMzG,oBAC1ByM,EAAIu1H,QAAQyB,cAAcpmI,MAAO,CAACiuI,IAAKn1H,GAAI7M,UACxC,CAAA,GAAIgiI,IAAI5jI,eAAiBjB,MAAMtF,0BAY5B,IAAIlI,MAAM,uEACJgQ,QAAQ,IAAM,kBAAoBA,QAAQ,IAAM,KAAOklG,QAZnC,cAA5B7kG,KAAKxB,KAAKnM,eAEV6vI,MAAQj7H,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,aAAc,WACrE6hI,IAAMjS,MAAMU,YAAY38H,MAAO,CAACiuI,IAAI31G,OAAQxf,GAAIq1H,QAC5ClpD,gBAAgB7qD,SAAS8qD,iBAAiBhyE,KAAKrG,SAASqhI,IAAIv7H,QAAQd,UAAUihF,iBAClF1jF,EAAI20H,OAAOU,aAAazkI,MAAO,CAACkuI,IAAK,kBAAmBD,IAAI3yF,WAAcrvC,OAG1EmD,EAAI20H,OAAOU,aAAazkI,MAAO,CAACiuI,IAAKn1H,GAAI7M,aAM7CiH,KAAKzU,OAAOwvI,IAAIxhI,WAChB2C,EAAEq/E,SAASw/C,YACJA,IAAIxhI,SAIfiG,EAAE+7E,SAASr/E,GAEXA,EAAEkgF,OAAS,aACXlgF,EAAE0hF,WAAWp+E,GACbtD,EAAE61E,gBAAgB7qD,SAEdlnB,KAAK9I,QAAQgF,KACbA,EAAE2nD,mBAAqB,eAWflpD,GAAK6E,EAAE49B,OAAOkmB,SAAS9oD,EACvBI,GAAK4E,EAAE49B,OAAOkmB,SAAS71C,EACvB0Z,GAAK3nB,EAAE89B,OAAOgmB,SAAS9oD,EACvB8sB,GAAK9nB,EAAE89B,OAAOgmB,SAAS71C,EACvBgxB,GAAKs8F,IAAIz3E,SAAS9oD,EAClBkkC,GAAKq8F,IAAIz3E,SAAS71C,EAClBy5B,GAAKhrC,EAAEonD,SAAS9oD,EAChBi8H,GAAKv6H,EAAEonD,SAAS71C,QAKb,CAHK,CAAC,KAAMgpH,GAAI,MAAO/3F,GAAI,QAAS9jC,GAAI,MAAO0sB,GAAI,QAAS3sB,GAAI,MAAOwsB,GAAI,QAAS+f,GAAI,MAAOzI,GAAI,MAAM32C,KAAK,IACzG,CAAC,KAAMo/C,GAAI,MAAOvsC,GAAI,UAAW87H,GAAI,MAAO77H,GAAI,UAAW6jC,GAAI,MAAO9jC,GAAI,UAAW+jC,GAAI,MAAO9jC,GAAI,QAAQ9S,KAAK,OAM9HoU,GAkFXpR,IAAIowI,oBAAsB,SAAUpuI,MAAO4L,QAASC,gBAC5CoiI,IAAK/zI,EAAGyT,EAAGyB,EAAG8+H,IAAKp1H,EACnB7M,KAAMkiI,MACNr9B,OAAS,mFAER52G,EAAI,EAAGA,EAAI0R,QAAQnR,SAAUP,EAC9B0R,QAAQ1R,GAAK8F,MAAMG,OAAOyL,QAAQ1R,OAGtC+R,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,iBAClD6G,KAAK9I,QAAQwB,QAAQ,IAErBqiI,IAAM/6H,KAAKvH,cAAc3L,MAAO,CAAC4L,QAAQ,IAAKK,MAAM,OACjD,CAAA,GAAIL,QAAQ,GAAGvB,eAAiBjB,MAAMrF,oBACjC6H,QAAQ,GAAGvB,eAAiBjB,MAAMvF,mBAClC+H,QAAQ,GAAGnB,OAASrB,MAAMzG,qBAC1BiJ,QAAQ,GAAGvB,eAAiBjB,MAAMtF,0BAGpC,IAAIlI,MAAM,oEACJgQ,QAAQ,IAAM,kBAAoBA,QAAQ,IAAM,KAAOklG,QAHnEm9B,IAAMriI,QAAQ,OAMdsH,KAAK9I,QAAQwB,QAAQ,UAKf,IAAIhQ,MAAM,oEACJgQ,QAAQ,IAAM,kBAAoBA,QAAQ,IAAM,KAAOklG,WALnEq9B,MAAQj7H,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,gBAAiB,SAExEsB,EAAIuF,KAAKvH,cAAc3L,MAAO,CAAC4L,QAAQ,IAAKuiI,OAAO,GAMvDr1H,EAAI4zH,UAAUD,gBAAgBzsI,MAAO,CAACsM,KAAKiV,GAAI5T,GAAI,CAAClD,KAAM,WACtDyI,KAAK9I,QAAQ6jI,KACb7+H,EAAI6sH,MAAMU,YAAY38H,MAAO,CAACiuI,IAAKn1H,GAAI7M,WAGpC,GAAIgiI,IAAI5jI,eAAiBjB,MAAMrF,mBAClCqL,EAAIu3H,MAAMwB,YAAYnoI,MAAO,CAACiuI,IAAKn1H,GAAI7M,WACpC,GAAIgiI,IAAI5jI,eAAiBjB,MAAMvF,kBAClCuL,EAAIouH,KAAKwB,WAAWh/H,MAAO,CAACiuI,IAAKn1H,GAAI7M,WACjC,GAAIgiI,IAAIxjI,OAASrB,MAAMzG,oBAC3ByM,EAAIu1H,QAAQyB,cAAcpmI,MAAO,CAACiuI,IAAKn1H,GAAI7M,UACxC,CAAA,GAAIgiI,IAAI5jI,eAAiBjB,MAAMtF,0BAY5B,IAAIlI,MAAM,oEACJgQ,QAAQ,IAAM,kBAAoBA,QAAQ,IAAM,KAAOklG,QAZnC,cAA5B7kG,KAAKxB,KAAKnM,eAEV6vI,MAAQj7H,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,gBAAiB,WACxE6hI,IAAMjS,MAAMU,YAAY38H,MAAO,CAACiuI,IAAI31G,OAAQxf,GAAIq1H,QAC5ClpD,gBAAgB7qD,SAAS8qD,iBAAiBhyE,KAAKrG,SAASqhI,IAAIv7H,QAAQd,UAAUihF,iBAClF1jF,EAAI20H,OAAOU,aAAazkI,MAAO,CAACkuI,IAAK,kBAAmBD,IAAI3yF,WAAcrvC,OAG1EmD,EAAI20H,OAAOU,aAAazkI,MAAO,CAACiuI,IAAKn1H,GAAI7M,aAO7CiH,KAAKzU,OAAOwvI,IAAIxhI,WAChB2C,EAAEq/E,SAASw/C,YACJA,IAAIxhI,SAIfkB,EAAE8gF,SAASr/E,GAEXA,EAAEkgF,OAAS,gBACXlgF,EAAE0hF,WAAWnjF,GACbyB,EAAE61E,gBAAgB7qD,SAEXhrB,GA4BXpR,IAAIqwI,kBAAoB,SAAUruI,MAAO4L,QAASC,gBAC1CoC,GAAKjQ,IAAIowI,oBAAoBpuI,MAAO4L,QAASC,mBACjDoC,GAAGqhF,OAAS,cACLrhF,IA0BXjQ,IAAIswI,eAAiB,SAAUtuI,MAAO4L,QAASC,gBACvCqiB,SAAU+qB,MAAOhtC,KACjB+N,MAAOmoB,IAAKosG,OAAQC,OAAQC,KAAMC,KAClCC,YAAaC,WAAYC,YAAaC,WAC5BnyI,EAAVmc,EAAI,QAEJ5F,KAAKlJ,QAAQ4B,QAAQ,KAAOA,QAAQ,GAAGvB,eAAiBjB,MAAMrF,mBAC9DmqB,SAAWtiB,QAAQ,GACnBqtC,MAAQrtC,QAAQ,OACb,CAAA,IAAIsH,KAAKlJ,QAAQ4B,QAAQ,KAAOA,QAAQ,GAAGvB,eAAiBjB,MAAMrF,yBAI/D,IAAInI,MAAM,8DACJgQ,QAAQ,IAAM,kBAAoBA,QAAQ,IADtC,wEAHhBsiB,SAAWtiB,QAAQ,GACnBqtC,MAAQrtC,QAAQ,UAOpBK,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,aACjDomE,WAAY,EACjB91E,EAAIqD,MAAMwM,OAAO,QAAS,CAAC,CAAC,GAAI,CAAC,IAAKP,MAGtC+N,MAAQkU,SAAS,GACjBiU,IAAMjU,SAAS,GAEXhb,KAAKnJ,WAAWiQ,QAEhBw0H,OAAS,kBAAqBv1F,MAAMhb,EAAEswG,WACtCv0H,OAFAu0H,OAASv0H,WAITu0H,OAASv0H,MACTw0H,OAASv1F,MAAMhb,EAAEjkB,QAGjB9G,KAAKnJ,WAAWo4B,MAEhBusG,KAAO,kBAAqBz1F,MAAMhb,EAAEwwG,SACpCtsG,KAFAssG,KAAOtsG,SAIPssG,KAAOtsG,IACPusG,KAAOz1F,MAAMhb,EAAEkE,MAGnBl2B,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,WAAY,aAClEsiI,YAAc3uI,MAAMwM,OAAO,SAAU,CAAC+hI,OAAQC,OAAQv1F,OAAQhtC,MAC1DiH,KAAKnJ,WAAWwkI,SAChBI,YAAY17C,cAGhBhnF,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,WAAY,YAClEuiI,WAAa5uI,MAAMwM,OAAO,QAAS,CAC/B,iBAC0C,MAAlC0G,KAAKrG,SAASlQ,EAAEgW,QAAQi7D,MACjB,EAGJ+gE,YAAY3wG,KAEvB,iBAC0C,MAAlC9qB,KAAKrG,SAASlQ,EAAEgW,QAAQi7D,MACjB+gE,YAAY1wG,IAGhB,IAEZhyB,MAEHA,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,WAAY,cAClEwiI,YAAc7uI,MAAMwM,OAAO,SAAU,CAACiiI,KAAMC,KAAMz1F,OAAQhtC,MACtDiH,KAAKnJ,WAAW0kI,OAChBI,YAAY57C,cAGhBhnF,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,WAAY,aAClEyiI,WAAa9uI,MAAMwM,OAAO,QAAS,CAC/B,iBAC0C,MAAlC0G,KAAKrG,SAASlQ,EAAEgW,QAAQi7D,MACjB,EAEJihE,YAAY7wG,KAEvB,iBAC0C,MAAlC9qB,KAAKrG,SAASlQ,EAAEgW,QAAQi7D,MACjBihE,YAAY5wG,IAGhB,IAEZhyB,OAGoB,KADvBA,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,aAC7C4nF,WAAqC,MAAdhoF,KAAK2hE,OACjC3hE,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,WAAY,SAClEJ,KAAOiH,KAAK9G,eAAeH,KAAMjM,MAAMqM,QAAS,UAEhDyM,EAAI9Y,MAAMwM,OAAO,OAAQ,CACrB,eACQuR,IAAM,IAAIgG,OAAO3a,MAAMzH,iBAAkB,CACrCuR,KAAKrG,SAASjN,KAAK+S,QAAQ8S,OAAO,IAAM7lB,KAAKI,MAAM0L,OAAOyY,UAAU,GACpE,GACDvkB,KAAKI,OAAO,GACfu5C,GAAK35C,KAAKI,MAAMkzC,iBAChBxU,GAAuB,IAAjB6a,GAAG,GAAKA,GAAG,IACjB7rC,EAAImhI,YAAY7wG,WAEhBtwB,EAAI6rC,GAAG,GACP7rC,EAAI6rC,GAAG,GAAK7a,GACLhxB,EAAI6rC,GAAG,KACd7rC,EAAI6rC,GAAG,GAAK7a,IAGThxB,EAAIqQ,IAAInQ,UAAU,IAE7B,eACQmQ,IAAM,IAAIgG,OAAO3a,MAAMzH,iBAAkB,CACrC,EACAuR,KAAKrG,SAASjN,KAAK+S,QAAQ8S,OAAO,IAAM7lB,KAAKI,MAAM0L,OAAOyY,UAAU,IACrEvkB,KAAKI,OAAO,GACfu5C,GAAK35C,KAAKI,MAAMkzC,iBAChBvS,GAAuB,IAAjB4Y,GAAG,GAAKA,GAAG,IACjB54B,EAAIkuH,YAAY5wG,WAEhBtd,EAAI44B,GAAG,GACP54B,EAAI44B,GAAG,GAAK5Y,GACLhgB,EAAI44B,GAAG,KACd54B,EAAI44B,GAAG,GAAK5Y,IAGThgB,EAAI5C,IAAInQ,UAAU,IAE7B,eACQmhI,IAAMh6G,SAASiB,YAAY,CAAC44G,WAAW5wG,IAAK8wG,WAAW9wG,KAAMib,MAAMhb,SAChE,WAAa/qB,KAAK/E,QAAQ4gI,IAAK,KAE3C9iI,OAEDsjF,MAAO,EAETo/C,YAAYlgD,SAAS31E,GACrB+1H,YAAYpgD,SAAS31E,IAIzB61H,YAAYp/C,MAAO,EACnBq/C,WAAWr/C,MAAO,EAElBs/C,YAAYt/C,MAAO,EACnBu/C,WAAWv/C,MAAO,EAElB5yF,EAAE2yF,OAAS,WACX3yF,EAAEq0F,WAAW,CAAC/3C,MAAMl8C,GAAImxB,WACxBvxB,EAAE6yF,KAAO,CACLnjB,UAAWsiE,YACXr1D,SAAUs1D,WACVtiE,WAAYuiE,YACZt1D,UAAWu1D,YAEfnyI,EAAE8yF,SAASn0F,KAAKqzI,YAAaC,WAAYC,YAAaC,YAElD7iI,KAAKwmE,YACL91E,EAAE6yF,KAAK1/E,MAAQgJ,EACfnc,EAAE8yF,SAASn0F,KAAKwd,IAUpBnc,EAAEsW,MAAQ,kBACC8hB,SAAS2H,EAAE,CAACkyG,WAAW5wG,IAAK8wG,WAAW9wG,KAAMib,MAAMhb,IAO9DthC,EAAE8qI,gBAAkB,eACZ/5H,EAAGiT,EACHzmB,EAAGkX,KAAM6/D,MACT+9D,KAAMC,IACNC,KAAMC,OAE+B,MAArCj8H,KAAKrG,SAASjN,KAAK+S,QAAQi7D,MAAe,KACtC+gE,YAAY1wG,IAAM4wG,YAAY5wG,KAC9B+wG,KAAOL,YAAY3wG,IACnBkxG,KAAOP,YAAY1wG,IACnBgxG,IAAMJ,YAAY7wG,IAClBmxG,IAAMN,YAAY5wG,MAElB+wG,KAAOH,YAAY7wG,IACnBkxG,KAAOL,YAAY5wG,IACnBgxG,IAAMN,YAAY3wG,IAClBmxG,IAAMR,YAAY1wG,KAEtB7sB,KAAO9E,KAAKC,IAAIyiI,KAAMC,KACtBh+D,MAAQ3kE,KAAKiS,IAAIywH,KAAMC,KAEvBvhI,EAAI,CAAC,EAAGshI,MACRruH,EAAI,CAACuuH,KAAMA,MAENh1I,EAAI,EAAGA,EAAI++C,MAAM9B,aAAcj9C,IAC5Bg1I,MAAQj2F,MAAM9sC,OAAOjS,GAAG0T,UAAU,IAC9BwD,MAAQ6nC,MAAM9sC,OAAOjS,GAAG0T,UAAU,IAClCqrC,MAAM9sC,OAAOjS,GAAG0T,UAAU,IAAMuhI,KAChCl2F,MAAM9sC,OAAOjS,GAAG0T,UAAU,IAAMqjE,QACpCvjE,EAAEpS,KAAK29C,MAAM9sC,OAAOjS,GAAG0T,UAAU,IACjC+S,EAAErlB,KAAK29C,MAAM9sC,OAAOjS,GAAG0T,UAAU,KAGzCF,EAAEpS,KAAK2zI,KACPtuH,EAAErlB,KAAK6zI,KACPzhI,EAAEpS,KAAK,GACPqlB,EAAErlB,KAAK6zI,KAGPzhI,EAAEpS,KAAK,GACPqlB,EAAErlB,KAAK4zI,UACJ,KACCN,WAAW5wG,IAAM8wG,WAAW9wG,KAC5B5sB,KAAOw9H,WAAW5wG,IAClBizC,MAAQ69D,WAAW9wG,MAEnB5sB,KAAO09H,WAAW9wG,IAClBizC,MAAQ29D,WAAW5wG,KAGvBtwB,EAAI,CAAC0D,KAAMA,MACXuP,EAAI,CAAC,EAAGs4B,MAAMhb,EAAE7sB,OAEXlX,EAAI,EAAGA,EAAI++C,MAAM9B,aAAcj9C,IAC3BkX,MAAQ6nC,MAAM9sC,OAAOjS,GAAG0T,UAAU,IAAQqrC,MAAM9sC,OAAOjS,GAAG0T,UAAU,IAAMqjE,QAC3EvjE,EAAEpS,KAAK29C,MAAM9sC,OAAOjS,GAAG0T,UAAU,IACjC+S,EAAErlB,KAAK29C,MAAM9sC,OAAOjS,GAAG0T,UAAU,KAGzCF,EAAEpS,KAAK21E,OACPtwD,EAAErlB,KAAK29C,MAAMhb,EAAEgzC,QACfvjE,EAAEpS,KAAK21E,OACPtwD,EAAErlB,KAAK,GAGPoS,EAAEpS,KAAK8V,MACPuP,EAAErlB,KAAK,QAGNylC,MAAQrzB,OACRszB,MAAQrgB,GAGjBguH,YAAYlgD,SAAS9xF,GACrBkyI,YAAYpgD,SAAS9xF,GACrBiyI,WAAWngD,SAAS9xF,GACpBmyI,WAAWrgD,SAAS9xF,GASpBA,EAAE28E,SAAWs1D,WASbjyI,EAAE48E,UAAYu1D,WASdnyI,EAAE0vE,UAAYsiE,YASdhyI,EAAE2vE,WAAauiE,YAEflyI,EAAEgzF,UAAY3xF,IAAIuR,SAAS5S,EAAEgzF,UAAW,CACpCtjB,UAAW,YACXiN,SAAU,WACVhN,WAAY,aACZiN,UAAW,YACXtmE,MAAO,UAOXtW,EAAEmT,MAAQgJ,EAEHnc,GA0BXqB,IAAIoxI,WAAa,SAAUpvI,MAAO4L,QAASC,gBACnC2D,EAAGvD,YAEPA,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,SACtDmD,EAAIxP,MAAMwM,OAAO,QAAS,CAAC,CAAC,MAAO,CAAC,OAAQP,OAE1CqjF,OAAS,OACX9/E,EAAE/E,KAAOrB,MAAMjG,iBAKdqM,EAAEi4H,gBAAkB,eACbztH,MAAOmoB,IAAKjoC,EAAGm1I,QAASC,YACxB52D,MAAQxlE,KAAKrG,SAASjN,KAAK+S,QAAQ48H,OACnC52D,MAAQzlE,KAAKrG,SAASjN,KAAK+S,QAAQ68H,WAGnCH,QADAn8H,KAAKlJ,QAAQpK,KAAK+S,QAAQ88H,SAChB,IAAI1rH,OAAO7Q,KAAKrG,SAASjN,KAAK+S,QAAQ+8H,SAAWtmI,MAAM1H,eAC7C9B,KAAK+S,QAAQ88H,QAASzvI,OAEhC,IAAI+jB,OAAO3a,MAAMzH,iBAAkB,CAAC,EAAG,GAAI3B,OAIrDsvI,YADAp8H,KAAKlJ,QAAQpK,KAAK+S,QAAQg9H,aACZ,IAAI5rH,OAAO7Q,KAAKrG,SAASjN,KAAK+S,QAAQi9H,SAAWxmI,MAAM1H,eACjD9B,KAAK+S,QAAQg9H,YAAa3vI,OAEhC,IAAI+jB,OAAO3a,MAAMzH,iBAAkB,CAAC3B,MAAM0yC,YAAa1yC,MAAM2yC,cAAe3yC,OA0B9FA,MAAMqM,QAAQqpE,KAAK+C,SAAU,EAyB7BjpE,EAAEuxB,MAAQ,GACVvxB,EAAEwxB,MAAQ,GAIVhnB,MAAQ1N,KAAKmS,MAAM4wH,QAAQzhI,UAAU,GAAK+qE,OAASA,MACnDx2C,IAAM71B,KAAKsgB,KAAK0iH,YAAY1hI,UAAU,GAAK+qE,OAASA,MAEhD02D,QAAQzhI,UAAU,GAAK0hI,YAAY1hI,UAAU,KAC7CoM,MAAQ1N,KAAKsgB,KAAK0iH,YAAY1hI,UAAU,GAAK+qE,OAASA,MACtDx2C,IAAM71B,KAAKmS,MAAM4wH,QAAQzhI,UAAU,GAAK+qE,OAASA,OAIhDz+E,EAAI8f,MAAO9f,EAAIioC,IAAMw2C,MAAOz+E,GAAKy+E,MAClCnpE,EAAEuxB,MAAMzlC,KAAK+zI,QAAQzhI,UAAU,GAAI0hI,YAAY1hI,UAAU,GAAIW,KAC7DiB,EAAEwxB,MAAM1lC,KAAKpB,EAAGA,EAAGqU,SAIvByL,MAAQ1N,KAAKsgB,KAAKyiH,QAAQzhI,UAAU,GAAK8qE,OAASA,MAClDv2C,IAAM71B,KAAKmS,MAAM6wH,YAAY1hI,UAAU,GAAK8qE,OAASA,MAEjD22D,QAAQzhI,UAAU,GAAK0hI,YAAY1hI,UAAU,KACzDoM,MAAQ1N,KAAKmS,MAAM6wH,YAAY1hI,UAAU,GAAK8qE,OAASA,MACvDv2C,IAAM71B,KAAKsgB,KAAKyiH,QAAQzhI,UAAU,GAAK8qE,OAASA,OAInCx+E,EAAI8f,MAAO9f,EAAIioC,IAAMu2C,MAAOx+E,GAAKw+E,MAClClpE,EAAEuxB,MAAMzlC,KAAKpB,EAAGA,EAAGqU,KACnBiB,EAAEwxB,MAAM1lC,KAAK+zI,QAAQzhI,UAAU,GAAI0hI,YAAY1hI,UAAU,GAAIW,MAOrEiB,EAAEolE,SAAW,kBACF,GAGX50E,MAAMs0G,MAAMh5G,KAAKkU,GAEVA,GA+EXxR,IAAI6xI,iBAAmB,SAAU7vI,MAAO4L,QAASC,gBACzCrP,EAAGyQ,EAAGhB,QAEVA,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,cAClDT,QAAQ,GAAGvB,eAAiBjB,MAAMvF,mBAClCoJ,EAAIjN,MAAMwM,OAAO,QAAS,CAAC,GAAI,IAAKP,OAClC2oE,SAAW,kBACF,GAEX3nE,EAAEw6H,gBAAkB,eACZn0F,GAAI7jC,GAGJkO,EACA47B,GAAKv5C,MAAMkzC,iBACXmI,OAASpvC,KAAK4T,SAAW,EAAI,EAE7B6S,EADY,IACIpmB,KAAKiS,IAAIg7B,GAAG,GAAKA,GAAG,GAAIA,GAAG,GAAKA,GAAG,IAGnDu2F,GAAK,CACDriI,OAAQ,CACJG,UAAW,CAAC,GAAI2rC,GAAG,GAAKA,GAAG,IAAM,EAAGttC,KAAK4T,QAAU05B,GAAG,GAAKA,GAAG,MAItEw2F,OAASnkI,QAAQ,GAAG4X,QAAQvqB,MAAM,GAClC+2I,OAASD,OAcbpyH,EAzBgB,IAyBArR,KAAKiS,IAAIwwB,SAAS6B,cAAchlC,QAAQ,GAAIkkI,GAAI9vI,OAAO,GAAG+kB,SAAS3b,MAAM1H,eAAgBouI,GAAGriI,QAASilB,GACrH/U,GAAK09B,OAGLy0F,GAAK,CACDriI,OAAQ,CACJG,UAAW,CAAC,GAAI2rC,GAAG,GAAKA,GAAG,IAAM,GAAIA,GAAG,GAAKA,GAAG,IAAM,KAY9DjG,GAAK,CAAC,GAJFw8F,GADAxjI,KAAKwC,IAAIgV,IAAI3D,aAAa2vH,GAAGriI,OAAOG,UAAWhC,QAAQ,GAAG4X,QAAS,KAAOM,IAAIzF,IACzE0wB,SAAS6B,cAAchlC,QAAQ,GAAIkkI,GAAI9vI,OAAO,GAAG4N,UAEjDkiI,GAAGriI,OAAOG,WAEP,GAAKmiI,OAAO,GAAKr9G,EAAGo9G,GAAG,GAAKC,OAAO,GAAKr9G,GACpDjjB,GAAK,CAAC,EAAGqgI,GAAG,GAAKE,OAAO,GAAKt9G,EAAGo9G,GAAG,GAAKE,OAAO,GAAKt9G,QAK/CqO,MAAQ,CAACuS,GAAG,GAAIA,GAAG,GAAKy8F,OAAO,GAAKpyH,EAAGlO,GAAG,GAAKugI,OAAO,GAAKryH,EAAGlO,GAAG,GAAI6jC,GAAG,SACxEtS,MAAQ,CAACsS,GAAG,GAAIA,GAAG,GAAKy8F,OAAO,GAAKpyH,EAAGlO,GAAG,GAAKugI,OAAO,GAAKryH,EAAGlO,GAAG,GAAI6jC,GAAG,UAE9E,GAAI1nC,QAAQ,GAAGvB,eAAiBjB,MAAMrF,oBACR,kBAAjC6H,QAAQ,GAAG+G,QAAQwpC,WAEnBlvC,EAAIjN,MAAMwM,OAAO,QAAS,CAAC,GAAI,IAAKP,OAClCw7H,gBAAkB,eAGZj2G,MAAO8O,MAAOzJ,KACd7qB,IAAK9R,EAGL+1I,SAAUC,SACVC,OACAC,MARA98G,KAAO1zB,KAAKI,MAAMkzC,iBAClB/mC,OAAS,GAGTkzC,GAAKzzC,QAAQ,GAAGmrC,OAChBh3B,GAAKnU,QAAQ,GAAGkrC,OAIhBu5F,QAAgC,IAArB/8G,KAAK,GAAKA,KAAK,OAI9B9B,MAHcte,KAAKrG,SAASjN,KAAK+S,QAAQkN,SAGrB,EAAI,OAEnBkhB,MAAQ,QACRC,MAAQ,GAED,KADZh1B,IAAMJ,QAAQ,GAAGO,OAAO1R,YAKxB64B,KAAK,IAAM+8G,QACX/8G,KAAK,IAAM+8G,QAEXx5G,MAAQ,EACDA,KAAO7qB,IAAM,GAAG,KAGd9R,EAAI28B,KAAO,EAAGyJ,MAAQt0B,IAAK9R,EAAI8R,IAAK9R,OACjC0R,QAAQ,GAAGO,OAAOjS,GAAGwrB,SAAU,CAC/B4a,MAAQpmC,WAKZomC,OAASt0B,cAKR9R,EAAIomC,MAAOzJ,KAAO7qB,IAAM,EAAG9R,EAAI8R,IAAM,EAAG9R,QACpC0R,QAAQ,GAAGO,OAAOjS,EAAI,GAAGwrB,SAAU,CACpCmR,KAAO38B,YAKfi2I,OAASvkI,QAAQ,GAAGO,OAAOm0B,OAAO1yB,UAAU,GAC5CwiI,MAAQxkI,QAAQ,GAAGO,OAAO0qB,MAAMjpB,UAAU,GAG1CqiI,SAAY38G,KAAK,GAAK+rB,GAAMA,GAAK/rB,KAAK,GACtC48G,SAAY58G,KAAK,GAAKvT,GAAMA,GAAKuT,KAAK,GAGtC28G,SAAsB,IAAV3vG,MAAoB2vG,SAAW3jI,KAAKiS,IAAI0xH,SAAUE,QAC9DD,SAAYr5G,OAAS7qB,IAAM,EAAKkkI,SAAW5jI,KAAKC,IAAI2jI,SAAUE,OAI9DF,SAAYr5G,OAAS7qB,IAAM,EAAI+T,GAAIqwH,OAInCjkI,OAAS,IAEF7Q,KAAK,CAAC,EAPb20I,SAAsB,IAAV3vG,MAAmB+e,GAAI8wF,OAOT78G,KAAK9B,SAC/BrlB,OAAO7Q,KAAK,CAAC,EAAG20I,SAAUrkI,QAAQ,GAAGO,OAAOm0B,OAAO1yB,UAAU,KACxD1T,EAAIomC,MAAOpmC,GAAK28B,KAAM38B,IACvBiS,OAAO7Q,KAAKsQ,QAAQ,GAAGO,OAAOjS,GAAG0T,eAErCzB,OAAO7Q,KAAK,CAAC,EAAG40I,SAAUtkI,QAAQ,GAAGO,OAAO0qB,MAAMjpB,UAAU,KAC5DzB,OAAO7Q,KAAK,CAAC,EAAG40I,SAAU58G,KAAK9B,SAC/BrlB,OAAO7Q,KAAK6Q,OAAO,IAEdjS,EAAI,EAAGA,EAAIiS,OAAO1R,OAAQP,SACtB6mC,MAAMzlC,KAAK6Q,OAAOjS,GAAG,SACrB8mC,MAAM1lC,KAAK6Q,OAAOjS,GAAG,IAI1B28B,KAAO7qB,IAAM,SACR+0B,MAAMzlC,KAAKiT,UACXyyB,MAAM1lC,KAAKiT,QAO5BtB,EAAE2nE,SAAW,kBACF,WAIXp4E,EAAI0W,KAAK/H,eAAeS,QAAQ,KAC3BsH,KAAKzU,OAAOjC,SACP,IAAIZ,MAAM,yGAKxBqR,EAAE6jF,WAAWllF,QAAQ,IACdqB,GAIXjP,IAAIsB,gBAAgB,gBAAiBtB,IAAIsvI,qBACzCtvI,IAAIsB,gBAAgB,WAAYtB,IAAI0vI,gBACpC1vI,IAAIsB,gBAAgB,gBAAiBtB,IAAI2vI,kCACzC3vI,IAAIsB,gBAAgB,UAAWtB,IAAIsyI,eACnCtyI,IAAIsB,gBAAgB,eAAgBtB,IAAI8vI,oBACxC9vI,IAAIsB,gBAAgB,uBAAwBtB,IAAI4vI,oBAChD5vI,IAAIsB,gBAAgB,eAAgBtB,IAAI4vI,oBACxC5vI,IAAIsB,gBAAgB,WAAYtB,IAAI6vI,gBACpC7vI,IAAIsB,gBAAgB,WAAYtB,IAAI+vI,gBACpC/vI,IAAIsB,gBAAgB,WAAYtB,IAAIswI,gBACpCtwI,IAAIsB,gBAAgB,WAAYtB,IAAIgvI,gBACpChvI,IAAIsB,gBAAgB,gBAAiBtB,IAAIowI,qBACzCpwI,IAAIsB,gBAAgB,cAAetB,IAAIqwI,mBACvCrwI,IAAIsB,gBAAgB,SAAUtB,IAAIuvI,cAClCvvI,IAAIsB,gBAAgB,uBAAwBtB,IAAI2uI,4BAChD3uI,IAAIsB,gBAAgB,WAAYtB,IAAIkvI,gBACpClvI,IAAIsB,gBAAgB,gBAAiBtB,IAAIivI,qBACzCjvI,IAAIsB,gBAAgB,gBAAiBtB,IAAI4uI,qBACzC5uI,IAAIsB,gBAAgB,qBAAsBtB,IAAI8uI,0BAC9C9uI,IAAIsB,gBAAgB,uBAAwBtB,IAAI+uI,4BAChD/uI,IAAIsB,gBAAgB,aAActB,IAAIgwI,kBACtChwI,IAAIsB,gBAAgB,OAAQtB,IAAIoxI,YAChCpxI,IAAIsB,gBAAgB,aAActB,IAAI6xI,kBAE/B,CACHvC,oBAAqBtvI,IAAIsvI,oBACzBI,eAAgB1vI,IAAI0vI,eACpB6C,gCAAiCvyI,IAAI2vI,iCACrCG,mBAAoB9vI,IAAI8vI,mBACxBF,mBAAoB5vI,IAAI4vI,mBACxBC,eAAgB7vI,IAAI6vI,eACpBE,eAAgB/vI,IAAI+vI,eACpBO,eAAgBtwI,IAAIswI,eACpBtB,eAAgBhvI,IAAIgvI,eACpBoB,oBAAqBpwI,IAAIowI,oBACzBC,kBAAmBrwI,IAAIqwI,kBACvBd,aAAcvvI,IAAIuvI,aAClBZ,2BAA4B3uI,IAAI2uI,2BAChCO,eAAgBlvI,IAAIkvI,eACpBD,oBAAqBjvI,IAAIivI,oBACzBL,oBAAqB5uI,IAAI4uI,oBACzBE,yBAA0B9uI,IAAI8uI,yBAC9B0D,0BAA2BxyI,IAAI+uI,2BAC/BiB,iBAAkBhwI,IAAIgwI,iBACtBoB,WAAYpxI,IAAIoxI,WAChBS,iBAAkB7xI,IAAI6xI,qBA4D9B73I,OAAO,gBAAgB,CACnB,MAAO,gBAAiB,eACzB,SAAUgG,IAAK+3D,SAAU7iD,aAuCxBlV,IAAIyyI,YAAc,SAAUzwI,MAAO4L,QAASC,gBACpC2D,EAAG7S,MAEHuW,KAAKlJ,QAAQ4B,UAA+B,IAAnBA,QAAQnR,SAAgByY,KAAK9I,QAAQwB,QAAQ,UAGhE,IAAIhQ,MAAM,6GAFhBe,EAAIiP,QAAQ,IAMhB4D,EAAIxP,MAAMwM,OAAO,QAAS,CAAC,CAAC,MAAO,CAAC,OAAQX,aAC1C6kI,gBAAiB,EAEnBlhI,EAAE8/E,OAAS,QACX9/E,EAAEwhF,WAAW,CAACr0F,EAAEI,KAMhByS,EAAEi4H,gBAAkB,eACZkJ,IAAKttG,GAAI5E,KAETjvB,EAAExP,MAAM+0G,KAAO,IAInB47B,IAAM56E,SAASY,oBAAoB32D,MAAOrD,GAAG,GAAM3B,KAAK,QAC5CwU,EAAEmhI,MAIdnhI,EAAEmhI,IAAMA,KAERttG,GAAK,SAAU31B,EAAGiT,EAAGuC,GAAIpK,GAqBG,IAAU83H,UApBlCphI,EAAEuxB,MAAQrzB,EACV8B,EAAEwxB,MAAQrgB,EAQVnR,EAAE0T,GAAKA,GAQP1T,EAAEqhI,MAAQ/3H,EAGVtJ,EAAEunD,oBAAgC65E,UAahC1tH,GAZS,SAAUgtB,WACTh2C,EACAwT,EAAI,IAAMwiC,MAAMsmB,SAAS9oD,EAAI,IAC7BiT,EAAI,IAAMuvB,MAAMsmB,SAAS71C,EAAI,IAC7BtB,IAAM,OAELnlB,EAAI,EAAGA,EAAI02I,UAAUn2I,OAAQP,IAC9BmlB,IAAInlB,GAAK02I,UAAU12I,GAAGU,QAAQ,QAAS,KAAKA,QAAQ,KAAM8S,GAAG9S,QAAQ,KAAM+lB,UAGxEtB,SAInBof,KAAOs3B,SAASiB,6BAA6Bh3D,MAAOrD,EAAG0mC,KAE/CytG,MAAOryG,KAAKsyG,MAAOtyG,KAAKuyG,WAAYvyG,KAAKwyG,YAE9CzhI,GAGXxR,IAAIsB,gBAAgB,QAAStB,IAAIyyI,aAE1B,CACHA,YAAazyI,IAAIyyI,gBAoDzBz4I,OAAO,aAAa,CAChB,MAAO,iBAAkB,cAAe,eAAgB,YAAa,aAAc,uBACpF,SAAUgG,IAAKoL,MAAO2a,OAAQ4qE,gBAAiB7qE,IAAK5Q,KAAM2lF,sBAsBzD76F,IAAIgzH,MAAQ,SAAUhxH,MAAOyN,OAAQ5B,WAAYigF,IAAKzyD,WAC7CjpB,YAAYpQ,MAAO6L,WAAYzC,MAAM/G,kBAAmB+G,MAAMnF,yBAC9D1E,QAAUK,KAAKI,MAAMG,OAAO0L,WAAW8nE,aACvC0rB,kBAAkB5xF,aAElByjI,EAAIh+H,KAAK/H,eAAekuB,KAAK,GAAIz5B,KAAKI,MAAO,SAC7C2pE,EAAIz2D,KAAK/H,eAAekuB,KAAK,GAAIz5B,KAAKI,MAAO,SAE7CmxI,QAAU,CAACvxI,KAAKsxI,IAAKtxI,KAAK+pE,UAM1BtwC,KAAO,CAAC/sB,KAAKwC,IAAIlP,KAAKuxI,QAAQ,GAAKnxI,MAAM2kB,OAAQrY,KAAKwC,IAAIlP,KAAKuxI,QAAQ,GAAKnxI,MAAM4kB,aAMlFknE,IAAMA,SAENwD,OAAS,aAIT8hD,KAAO,CACRxxI,KAAK6N,OAAOG,UAAU3U,MAAM,GAC5B,CAAC2G,KAAK6N,OAAOG,UAAU,GAAIhO,KAAKsxI,IAAK,GACrC,CAACtxI,KAAK6N,OAAOG,UAAU,GAAI,EAAGhO,KAAK+pE,WAIlC5sE,GAAK6C,KAAKI,MAAMw/F,MAAM5/F,KAAM,WAE5BI,MAAMmvE,SAASuY,UAAU9nF,WACzBI,MAAMy/F,eAAe7/F,WAErB+vF,UAAY3xF,IAAIuR,SAAS3P,KAAK+vF,UAAW,CAC1C0hD,kBAAmB,eACnBC,MAAO,kBAIftzI,IAAIgzH,MAAMl4H,UAAY,IAAI61F,gBAC1Bz7E,KAAKnD,qBAAqB/R,IAAIgzH,MAAOn4B,cAAe,qBAEpD76F,IAAIC,OAAOD,IAAIgzH,MAAMl4H,UAA6C,CAQ9D87E,SAAU,SAAUlnE,EAAGiT,OACf+d,GAAIiC,GAAIvxB,EAAG3E,KAAM00B,KACjB3vB,EAAG5F,EAAGjN,EAAG8iC,IACTzzB,IAAMpM,KAAK6mF,gBAAgBhsF,cAEvByY,KAAK/I,SAAS+I,KAAKrG,SAASjN,KAAK+S,QAAQwgE,aACzC1oE,KAAO7K,KAAKI,MAAM4/F,aAClBzgE,KAAOjsB,KAAKrG,SAASjN,KAAK+S,QAAQwgE,UAAU1oE,QAG5C00B,KAAOv/B,KAAKI,MAAMqM,QAAQ8mE,UAAUyB,SAIhC,IAAR5oE,KACA0yB,GAAKhxB,EAAI9N,KAAK6N,OAAO0W,UAAU,GAC/Bwc,GAAK/gC,KAAK6N,OAAO0W,UAAU,GAAKxD,EAGzB+d,MAFPtvB,EAAI+vB,OAEeT,GAAK9+B,KAAKy5B,KAAK,IAAMjqB,GACpCuxB,KAAOvxB,GAAKuxB,GAAK/gC,KAAKy5B,KAAK,IAAMjqB,IAOzCxF,EAAI,EADJ4F,GAFAA,EAAI,IAAIuU,OAAO3a,MAAMzH,iBAAkB,CAAC+L,EAAGiT,GAAI/gB,KAAKI,QAE9C4N,WACC,GAAKhO,KAAKwxI,KAAK,GAAG,GACrB5hI,EAAE,GAAK5P,KAAKwxI,KAAK,GAAG,GACpB5hI,EAAE,GAAK5P,KAAKwxI,KAAK,GAAG,IAKpB,IADJz0I,GAHA8iC,IAAM3b,IAAI3D,cAGFvW,EAAGhK,KAAKwxI,KAAK,MACPz0I,GAAK8iC,IAAI7/B,KAAKwxI,KAAK,GAAIxxI,KAAKwxI,KAAK,KAGvC,IAFJz0I,EAAI8iC,IAAI71B,EAAGhK,KAAKwxI,KAAK,MAEPz0I,GAAK8iC,IAAI7/B,KAAKwxI,KAAK,GAAIxxI,KAAKwxI,KAAK,MAavDh3G,OAAQ,SAAU28D,mBACTn3F,KAAKivF,kBAILqL,aAAanD,iBACblD,kBACA09C,aAEE3xI,MAPIA,MAcfkzF,eAAgB,kBACLlzF,KAAKy7F,sBAAsB,gBAQtCxH,WAAY,uBACHs9C,QAAU,CAACvxI,KAAKsxI,IAAKtxI,KAAK+pE,UAC1BtwC,KAAO,CAAC/sB,KAAKwC,IAAIlP,KAAKuxI,QAAQ,GAAKvxI,KAAKI,MAAM2kB,OAAQrY,KAAKwC,IAAIlP,KAAKuxI,QAAQ,GAAKvxI,KAAKI,MAAM4kB,QAE1FhlB,MAUX2xI,WAAY,eACJr3I,EAAGC,EAAG6R,IAAMpM,KAAK6mF,gBAAgBhsF,OAAQmP,EAAI,MAErC,IAARoC,SACKolI,KAAO,CAAC,CAACxxI,KAAKw8C,IAAKx8C,KAAKo+B,IAAKp+B,KAAKq+B,KACnC,CAACr+B,KAAKw8C,IAAKx8C,KAAKsxI,IAAK,GACrB,CAACtxI,KAAKw8C,IAAK,EAAGx8C,KAAK+pE,UACpB,KAEH//D,EAAE,GAAK,CAAChK,KAAKw8C,IAAKx8C,KAAKo+B,IAAKp+B,KAAKq+B,KACjCr0B,EAAE,GAAK,CAAChK,KAAKw8C,IAAKx8C,KAAKo+B,IAAMp+B,KAAKsxI,IAAKtxI,KAAKq+B,KAC5Cr0B,EAAE,GAAK,CAAChK,KAAKw8C,IAAKx8C,KAAKo+B,IAAKp+B,KAAKq+B,IAAMr+B,KAAK+pE,KAGvCzvE,EAAI,EAAGA,EAAI8R,IAAK9R,QACZC,EAAI,EAAGA,EAAI,EAAGA,IACfyP,EAAEzP,GAAK2pB,IAAI3E,WAAWvf,KAAK6mF,gBAAgBvsF,GAAG0kB,OAAQhV,EAAEzP,QAI3DA,EAAI,EAAGA,EAAI,EAAGA,IACfyP,EAAEzP,GAAG,IAAMyP,EAAEzP,GAAG,GAChByP,EAAEzP,GAAG,IAAMyP,EAAEzP,GAAG,GAChByP,EAAEzP,GAAG,IAAMyP,EAAEzP,GAAG,OAIfA,EAAI,EAAGA,EAAI,EAAGA,IACfyP,EAAEzP,GAAG,IAAMyP,EAAE,GAAG,GAChBA,EAAEzP,GAAG,IAAMyP,EAAE,GAAG,GAChBA,EAAEzP,GAAG,IAAMyP,EAAE,GAAG,QAEfwnI,KAAOxnI,SAGThK,MAGXmwF,aAAc,SAAUoB,eAChBj3F,KAEAgZ,KAAKlJ,QAAQmnF,eACRj3F,EAAI,EAAGA,EAAIi3F,UAAU12F,OAAQP,SACzBusF,gBAAgBnrF,KAAK61F,UAAUj3F,cAGnCusF,gBAAgBnrF,KAAK61F,kBAGvBvxF,MAIXq2F,WAAY,eACJt5F,EAAI,CAACiD,KAAKksF,IAAK,CAAClsF,KAAKw8C,IAAKx8C,KAAKo+B,IAAKp+B,KAAKq+B,KAAMr+B,KAAKuxI,gBAE5B,IAAxBvxI,KAAKgM,QAAQnR,SACbkC,EAAIiD,KAAKgM,SAGNjP,GA6DX60I,QAAS,SAASt6H,MAAOC,oBAChB+5H,EAAIh+H,KAAK/H,eAAe+L,MAAOtX,KAAKI,MAAO,SAC3C2pE,EAAIz2D,KAAK/H,eAAegM,OAAQvX,KAAKI,MAAO,IAI1CJ,MAOXsxI,EAAG,aAMHvnE,EAAG,eAiCP3rE,IAAIyzI,YAAc,SAAUzxI,MAAO4L,QAASC,gBACpCI,KAAMszD,GACNusB,IAAMlgF,QAAQ,GACd6B,OAAS7B,QAAQ,GACjBytB,KAAOztB,QAAQ,MAEnBK,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,WACtDkzD,GAAKs5B,cAAcrsF,OAAOxO,IAAIgzH,MAAOhxH,MAAOyN,OAAQxB,KAAM6/E,IAAKzyD,aAErD,IAAIz9B,MAAM,2DACAgQ,QAAQ,IAAM,kBAAoBA,QAAQ,IAD1C,8EAKA,IAAhBK,KAAKmtE,QACL7Z,GAAG60B,YAAYnoF,KAAKmtE,QAGjB7Z,IAGXvhE,IAAIsB,gBAAgB,QAAStB,IAAIyzI,aAE1B,CACHzgB,MAAOhzH,IAAIgzH,MACXygB,YAAazzI,IAAIyzI,gBA4DzBz5I,OAAO,iBAAiB,CACpB,MAAO,YAAa,iBAAkB,cAAe,aAAc,eACpE,SAAUgG,IAAK8lB,IAAK1a,MAAO2a,OAAQ7Q,KAAM+oH,cAwHxCj+H,IAAI0zI,aAAe,SAAU1xI,MAAO4L,QAASC,gBACrC8lI,KAAMvwB,KAAMwwB,KAAM53H,MAAO63H,KAAMC,MAC/BngG,GAAIC,GAAI2D,GAAWw8F,GAAIxD,OAAQC,OAAQ38F,GAAI2D,GAAI18B,EAC/Ck5H,SAAU17D,UAAW4E,UAAWiO,GAAIlpF,EAAGgM,YAG3CqqE,WADArqE,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,WACrC4lI,UACjBD,SAAW/lI,KAAKgoF,UAChB/Y,UAAYjvE,KAAK4uF,UAGjB5uF,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,SAAU,UAChEslC,GAAK3xC,MAAMwM,OAAO,QAASZ,QAAQ,GAAKK,MAGxCA,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,SAAU,UAChEulC,GAAK5xC,MAAMwM,OAAO,QAASZ,QAAQ,GAAKK,MAIxCA,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,SAAU,aAChEkpC,GAAKv1C,MAAMwM,OAAO,UAAW,CAACmlC,GAAIC,IAAK3lC,OAGpCwxH,gBAEHkU,KAAOhgG,GAAGlkC,OAAOG,UAAU3U,MAAM,GACjCmoH,KAAOxvE,GAAGnkC,OAAOG,UAAU3U,MAAM,GACjC24I,KAAOhmI,QAAQ,GAAG,GAClBoO,MAAQpO,QAAQ,GAAG,GACnBimI,KAAOjmI,QAAQ,GAAG,GAClBkmI,MAAQD,KAAOD,KAGf3xI,GAAa,KADbkpF,GAAKj2E,KAAKrG,SAASquE,YACDlhE,MAAQ1N,KAAKyU,MAAM/G,MAAQmvE,IAAMA,GACnDolD,OAASoD,KAAK,IAAMvwB,KAAK,GAAKuwB,KAAK,KAAO1xI,EAAI2xI,OAASC,KAAOD,MAC9DpD,OAASmD,KAAK,IAAMvwB,KAAK,GAAKuwB,KAAK,KAAO1xI,EAAI2xI,OAASC,KAAOD,OAG9D3lI,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,WAGjDomE,WAAY,GAEjB5gC,GAAK7xC,MAAMwM,OAAO,SAAU,CAAC+hI,OAAQC,OAAQj5F,IAAKtpC,OAC/C64E,aAAa,CAAC+V,UAAW3f,YAG5BjvE,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,SAAU,YAChEmpC,GAAKx1C,MAAMwM,OAAO,UAAW,CAACmlC,GAAIE,IAAM5lC,MASxC4lC,GAAG5+B,MAAQ,eACH6+H,MAAQlyI,KAAKk7F,MAAQl7F,KAAKm7F,MAC1BR,MAAQrnF,KAAKrG,SAASjN,KAAK+S,QAAQkoF,kBAErB,IAAXN,MACK36F,KAAK6X,SAAWq6H,MAAQlyI,KAAKm7F,MAC7BzuF,KAAKyU,OAAOnhB,KAAK6X,SAAWq6H,MAAQlyI,KAAKm7F,OAASR,OAASA,OAG3E1oD,GAAG89C,UAAYz8E,KAAK3D,SAASsiC,GAAG89C,UAAW,CACvC18E,MAAO,QACPi/H,SAAU,WACVL,KAAM,QACND,KAAM,QACNO,OAAQ,SACRC,OAAQ,WASZvgG,GAAGipD,MAAQ+2C,KAQXhgG,GAAGkpD,MAAQ62C,KASX//F,GAAGsgG,OAAS,SAAS5nI,iBACZuwF,MAAQvwF,IACN3K,MAWXiyC,GAAGqgG,SAAW,SAAS3nI,SACfunI,MAAQlyI,KAAKk7F,MAAQl7F,KAAKm7F,aAE1BzuF,KAAKwC,IAAIgjI,OAAShuH,IAAIzF,SACjB5G,UAAYlN,IAAM3K,KAAKm7F,OAAS+2C,WAEhCr6H,SAAW,OAEfA,SAAWnL,KAAKiS,IAAI,EAAKjS,KAAKC,IAAI,EAAK3M,KAAK6X,WAC1C7X,MAUXiyC,GAAGugG,OAAS,SAAS7nI,iBACZwwF,MAAQxwF,IACN3K,MAGPoyI,WACA/lI,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,SAAU,SAChEyM,EAAI9Y,MAAMwM,OAAO,OAAQ,CACrB,iBAC+B,KAAnBolC,GAAG5T,IAAM2T,GAAG3T,KAAc4T,GAAG5T,KAEzC,iBAC+B,KAAnB4T,GAAG3T,IAAM0T,GAAG1T,KAAc2T,GAAG3T,KAEzC,eACQxhC,EACAsO,EAAImI,KAAKrG,SAASglC,GAAGl/B,QAAQ/D,QAC7ByjI,GAAKn/H,KAAKrG,SAASglC,GAAGl/B,QAAQ2/H,aAC9BzuB,GAAK3wG,KAAKrG,SAASglC,GAAGl/B,QAAQ4/H,WAC9BnF,GAAKl6H,KAAKrG,SAASglC,GAAGl/B,QAAQ6/H,kBAExB,IAANznI,GAAmD,IAAxCmI,KAAKrG,SAASglC,GAAGl/B,QAAQwgE,aAEpCpoE,EAAImI,KAAKrG,SAASglC,GAAGl/B,QAAQwgE,YAI7B12E,EADO,OAAP41I,GACIA,GACGxgG,GAAGr4C,MAAoB,KAAZq4C,GAAGr4C,KACjBq4C,GAAGr4C,KAAO,MAEV,GAGRiD,GAAKyW,KAAK/E,QAAQ0jC,GAAG5+B,QAASlI,GAEnB,OAAP84G,KACApnH,GAAKonH,IAEE,OAAPupB,KACA3wI,GAAK2wI,IAGF3wI,IAEZwP,MAQH4lC,GAAG/hC,MAAQgJ,EAGX+4B,GAAGl/B,QAAQshF,WAAY,EACvBpiD,GAAGm9C,UAAW,GASlBn9C,GAAGvB,OAASqB,GAQZE,GAAGrB,OAASoB,GAQZC,GAAGypC,SAAW/lC,GAQd1D,GAAG0pC,SAAW/lC,GAEV8gC,YAGArqE,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,SAAU,SAC3D6G,KAAKzU,OAAOwN,KAAKwmI,qBAClBxmI,KAAKqnE,kBAAoB,SAAS8iB,KAAMs8C,KAAMh3I,WAEtCi3I,MAAQ9gG,GAAGvB,OAAO5P,KAAKmR,GAAGrB,QAC1BohG,KAAO//F,GAAGkpD,MAAO82C,KAAOhgG,GAAGipD,MAC3BvwF,IAAM3K,KAAKgzI,oBAAoBF,KAAMt8C,OAASy7C,KAAOD,MAAQe,MAASf,YAElEe,MAAQ7uH,IAAIzF,KAAO/R,KAAKwC,IAAIvE,KAAOuZ,IAAIzF,IAC3B,IAEAze,KAAKizI,gBAAgBtoI,OAKxC,EACTwnI,GAAK/xI,MAAMwM,OAAO,QAAS,CACvBqlC,GAAGypC,SACHzpC,GAAGvB,OAAO5P,KAAKiR,IAHV,EAKL,SAAUykD,UACFu8C,MAAQ9gG,GAAGvB,OAAO5P,KAAKmR,GAAGrB,QAC1BzlC,EAAI8mC,GAAGvB,OAAO7iC,OAAOsX,SAAS3b,MAAM1H,eAAgB00F,aAEpDu8C,MAAQ7uH,IAAIzF,IACL,EAGJtT,EAAI4nI,MAAQb,MAAQF,OAEhC3lI,MAQH4lC,GAAGi8B,MAAQikE,IAIflgG,GAAGsvC,OAAS,WACJ6wD,UACAhyI,MAAMs2F,aAAax9E,GAGvB9Y,MAAMs2F,aAAa9gD,IACnBx1C,MAAMs2F,aAAa/gD,IACnBv1C,MAAMs2F,aAAa1kD,IACnB5xC,MAAMs2F,aAAa3kD,IAGnBsqF,MAAMA,MAAMnjI,UAAUqoF,OAAO7nF,KAAKu4C,KAGtCF,GAAG49C,MAAO,EACV39C,GAAG29C,MAAO,EACVh6C,GAAGg6C,MAAO,EACV/5C,GAAG+5C,MAAO,EACNyiD,WACAl5H,EAAEy2E,MAAO,GAIb19C,GAAGy9C,OAAS,SACZz9C,GAAGjmC,QAAUA,QACbimC,GAAG29C,KAAO,CACNl/C,OAAQqB,GACRnB,OAAQoB,GACRkhG,SAAUv9F,GACVw9F,SAAUv9F,IAEd3D,GAAG49C,SAASn0F,KAAKq2C,GAAIC,GAAI2D,GAAIC,IAEzB8gC,YACAy7D,GAAGxiD,MAAO,EACV19C,GAAG29C,KAAK1hB,MAAQikE,GAChBlgG,GAAG49C,SAASn0F,KAAKy2I,KAGrBlgG,GAAGokD,WAAa,iBACL,CACHr2F,KAAK0wC,OAAO7iC,OAAOG,UAAU3U,MAAM,GACnC2G,KAAK4wC,OAAO/iC,OAAOG,UAAU3U,MAAM,GACnC,CAAC2G,KAAKm7F,MAAOn7F,KAAK6X,UAAY7X,KAAKk7F,MAAQl7F,KAAKm7F,OAASn7F,KAAKm7F,MAAOn7F,KAAKk7F,SAIlFjpD,GAAGypC,SAASx9D,GAAG,MAAM,SAASzK,SACtBooC,IAAKjsC,EAEL0D,KAAKrG,SAASglC,GAAGl/B,QAAQqgI,YAAc9/H,KAAKrG,SAASglC,GAAGl/B,QAAQ4/D,SAChE92B,IAAMlG,GAAGv1C,MAAM24G,iBAAiBtlG,IAAK,GACrC7D,EAAI,IAAIuU,OAAO3a,MAAMzH,iBAAkB85C,IAAK77C,KAAKI,OACjD6xC,GAAGynD,OAAO,CAAC9pF,EAAE5B,UAAU,GAAI4B,EAAE5B,UAAU,SAqC/CikC,GAAGozC,gBAAgB7qD,SACdp6B,MAAM08F,oBACP7qD,GAAGqzC,mBAAmB4N,iBACtBjhD,GAAGypC,SAAS4J,mBAAmB4N,iBAC/BjhD,GAAG0pC,SAAS2J,mBAAmB4N,iBAC3Bxc,WACAzkC,GAAGi8B,MAAMoX,mBAAmB4N,kBAI7BjhD,IAGX7zC,IAAIsB,gBAAgB,SAAUtB,IAAI0zI,cAE3B,CACHA,aAAc1zI,IAAI0zI,iBAuD1B15I,OAAO,kBAAkB,CACrB,MAAO,aAAc,iBACtB,SAAUgG,IAAKkV,KAAMy7E,wBAgCpB3wF,IAAIi1I,kBAAoB,SAAUjzI,MAAO4L,QAASC,gBAC1C8lI,KAAMvwB,KACNn1G,KAAMqqE,UAAW07D,SAAUpjI,OAC3BwnC,GAAIzE,GAAIC,GAAIn1C,EAAGs1I,UAEnBJ,KAAO/lI,QAAQ,GACfw1G,KAAOx1G,QAAQ,GAGfK,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,cAAe,UACrEslC,GAAK3xC,MAAMwM,OAAO,QAASmlI,KAAO1lI,MAGlCA,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,cAAe,UACrEulC,GAAK5xC,MAAMwM,OAAO,QAAS40G,KAAOn1G,MAElC0lC,GAAGmzC,aAAa,CAAClK,oBAAqB,CAAChpC,MACvCA,GAAGkzC,aAAa,CAAClK,oBAAqB,CAACjpC,MAGvC1lC,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,eACtDiqE,UAAYrqE,KAAKgmI,UACjBD,SAAW/lI,KAAKgoF,UAGD,KAFfrlF,OAAS3C,KAAK2C,SAEyB,IAAnB3C,KAAKknE,YAErBvkE,OAAS3C,KAAKknE,WAId6+D,WACA/lI,KAAKgoF,WAAY,GAErB79C,GAAKp2C,MAAMwM,OAAO,UAAW,CAACmlC,GAAIC,IAAK3lC,MAGnC+lI,WAEIv1I,EADAoP,WAAWrS,MAA4B,KAApBqS,WAAWrS,KAC1BqS,WAAWrS,KAAO,MAElB,GAER48C,GAAGtmC,MAAM0jF,SAAQ,kBACN/2F,EAAIyW,KAAK/E,QAAQwjC,GAAGjR,KAAKkR,IAAKhjC,YAIzC0nE,YACArqE,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,cAAe,SAErE0lI,GAAK/xI,MAAMwM,OAAO,QAAS,CAAC4pC,GAAI,IAAMnqC,MACtCmqC,GAAGq5C,SAASn0F,KAAKy2I,KAKrB37F,GAAG+qC,OAAS,WACJ7K,WACAlgC,GAAG+5C,YAAY4hD,IAGnB/xI,MAAMs2F,aAAa1kD,IACnB5xC,MAAMs2F,aAAa3kD,IAEnBg9C,gBAAgB71F,UAAUqoF,OAAO7nF,KAAKsG,OAU1Cw2C,GAAGnjC,MAAQ,kBACA0+B,GAAGjR,KAAKkR,KAGnBD,GAAG49C,MAAO,EACV39C,GAAG29C,MAAO,EAEVn5C,GAAGk5C,OAAS,cACZl5C,GAAG6/C,WAAa,iBACL,CAAC,CAACtkD,GAAG3T,IAAK2T,GAAG1T,KAAM,CAAC2T,GAAG5T,IAAK4T,GAAG3T,OAG1CmY,GAAGo5C,KAAO,CACNl/C,OAAQqB,GACRnB,OAAQoB,IAGR0kC,YACAy7D,GAAGxiD,MAAO,GAGdn5C,GAAGu5C,UAAY3xF,IAAIuR,SAAS6mC,GAAGu5C,UAAW,CACtC18E,MAAO,UAGXmjC,GAAG6uC,gBAAgB7qD,SACdp6B,MAAM08F,oBACPtmD,GAAG8uC,mBAAmB4N,iBAEtB18C,GAAG9F,OAAO40C,mBAAmB4N,iBAC7B18C,GAAG5F,OAAO00C,mBAAmB4N,kBAG1B18C,IAGXp4C,IAAIsB,gBAAgB,cAAetB,IAAIi1I,mBAEhC,CACHA,kBAAmBj1I,IAAIi1I,sBAiD/Bj7I,OAAO,oBAAoB,CAAC,MAAO,eAAe,SAAUgG,IAAKkV,aAI7DlV,IAAIk1I,WAAa,uBACRz0G,KAAO,QACP00G,cAAgB,QAChBC,WAAa,GAEXxzI,MAGX5B,IAAIC,OAAOD,IAAIk1I,WAAWp6I,UAAkD,CACxEu6I,cAAe,SAAUnsF,MAAOosF,aAAcC,eACtCr5I,EAAGC,EAAGq5I,QAENtgI,KAAKlJ,QAAQspI,qBACRH,cAAgBG,aACrBA,cAAe,GAGfpgI,KAAKlJ,QAAQupI,kBACRH,WAAaG,UAClBA,WAAY,QAGX90G,KAAO,GAER60G,oBACKH,cAAgB,IAGrBI,iBACKH,WAAa,IAGlBlgI,KAAKzU,OAAOyoD,OAAQ,UAEfzoB,KAAO,GAEPvkC,EAAI,EAAGA,EAAIgtD,MAAMzsD,OAAQP,aACrBukC,KAAKvkC,GAAK,GAEVC,EAAI,EAAGA,EAAI+sD,MAAMhtD,GAAGO,OAAQN,IAC7Bq5I,KAAOtsF,MAAMhtD,GAAGC,GACZod,WAAWi8H,MAAM1pI,aAAe0pI,UAC3B/0G,KAAKvkC,GAAGC,GAAKod,WAAWi8H,WAExB/0G,KAAKvkC,GAAGC,GADG,MAATq5I,KACWA,KAEAjlI,OAK1B+kI,oBACKH,cAAgBvzI,KAAK6+B,KAAK,GAAGxlC,MAAM,QACnCwlC,KAAO7+B,KAAK6+B,KAAKxlC,MAAM,IAG5Bs6I,mBACKH,WAAa,GACbl5I,EAAI,EAAGA,EAAI0F,KAAK6+B,KAAKhkC,OAAQP,SACzBk5I,WAAW93I,KAAKsE,KAAK6+B,KAAKvkC,GAAG,SAC7BukC,KAAKvkC,GAAK0F,KAAK6+B,KAAKvkC,GAAGjB,MAAM,UAKvC2G,MAGX6zI,cAAe,SAAUvsF,MAAOosF,aAAcC,eACtCtmG,IAAK/yC,EAAGC,EAAG6wE,IAAKwoE,QAEhBtgI,KAAKlJ,QAAQspI,qBACRH,cAAgBG,aACrBA,cAAe,GAGfpgI,KAAKlJ,QAAQupI,kBACRH,WAAaG,UAClBA,WAAY,QAGX90G,KAAO,GAER60G,oBACKH,cAAgB,IAGrBI,iBACKH,WAAa,IAItBlsF,MAAQpmD,SAASC,eAAemmD,OAE5Bh0C,KAAKzU,OAAOyoD,OAAQ,KAEpBja,IAAMia,MAAM7wC,qBAAqB,WAC5BooB,KAAO,GAEPvkC,EAAI,EAAGA,EAAI+yC,IAAIxyC,OAAQP,QACxB8wE,IAAM/9B,IAAI/yC,GAAGmc,qBAAqB,WAC7BooB,KAAKvkC,GAAK,GAEVC,EAAI,EAAGA,EAAI6wE,IAAIvwE,OAAQN,IACxBq5I,KAAOxoE,IAAI7wE,GAAG6G,UAEVuW,WAAWi8H,MAAM1pI,aAAe0pI,UAC3B/0G,KAAKvkC,GAAGC,GAAKod,WAAWi8H,WAExB/0G,KAAKvkC,GAAGC,GADG,MAATq5I,KACWA,KAEAjlI,OAK1B+kI,oBACKH,cAAgBvzI,KAAK6+B,KAAK,GAAGxlC,MAAM,QACnCwlC,KAAO7+B,KAAK6+B,KAAKxlC,MAAM,IAG5Bs6I,mBACKH,WAAa,GACbl5I,EAAI,EAAGA,EAAI0F,KAAK6+B,KAAKhkC,OAAQP,SACzBk5I,WAAW93I,KAAKsE,KAAK6+B,KAAKvkC,GAAG,SAC7BukC,KAAKvkC,GAAK0F,KAAK6+B,KAAKvkC,GAAGjB,MAAM,UAKvC2G,MAGX8zI,UAAW,SAAUl6I,KAAMiiD,IAAKhd,YACtB,IAAI7iC,MAAM,oBAGpB+3I,OAAQ,SAAUn6I,KAAMiiD,IAAKhd,YACnB,IAAI7iC,MAAM,oBAGpBg4I,UAAW,SAAU5oE,SACb9wE,EACAyQ,OAAS,MAGTuI,KAAKvJ,SAASqhE,SACT9wE,EAAI,EAAGA,EAAI0F,KAAKuzI,cAAc14I,OAAQP,OACnC8wE,MAAQprE,KAAKuzI,cAAcj5I,GAAI,CAC/B8wE,IAAM9wE,YAObA,EAAI,EAAGA,EAAI0F,KAAK6+B,KAAKhkC,OAAQP,IAC1B0F,KAAK6+B,KAAKvkC,GAAGO,OAASuwE,MACtBrgE,OAAOzQ,GAAKqd,WAAW3X,KAAK6+B,KAAKvkC,GAAG8wE,cAIrCrgE,QAGXkpI,OAAQ,SAAU5mG,SACVtiC,OAAQzQ,KAGRgZ,KAAKvJ,SAASsjC,SACT/yC,EAAI,EAAGA,EAAI0F,KAAKwzI,WAAW34I,OAAQP,OAChC+yC,MAAQrtC,KAAKwzI,WAAWl5I,GAAI,CAC5B+yC,IAAM/yC,YAOlByQ,OAAS,GAIJzQ,EAAI,EAAGA,EAAI0F,KAAK6+B,KAAKwO,KAAKxyC,OAAQP,IACnCyQ,OAAOzQ,GAAK0F,KAAK6+B,KAAKwO,KAAK/yC,UAGxByQ,UAIR3M,IAAIk1I,cA+Dfl7I,OAAO,aAAa,CAChB,MAAO,gBAAiB,kBAAmB,iBAAkB,cAAe,eAAgB,oBAC5F,cAAe,aAAc,YAAa,aAAc,aAAc,YAAa,eAAgB,iBACnG,sBAAuB,YAAa,gBACrC,SAAUgG,IAAK+2B,SAAU0Y,WAAYrkC,MAAO2a,OAAQ4qE,gBAAiBukD,WAAYhmE,MAAOh6D,KAAMwhB,IAAKiyG,MAAO1K,MAAO78B,KAC5GulC,QAASmP,OAAQpH,UAAWlP,KAAMuG,eAgBtC/lI,IAAI+1I,MAAQ,SAAU/zI,MAAO4L,QAASC,gBAG9B6B,EAAGiT,EAAGzmB,EAAGsV,EAAGwH,MAAOhL,YAFlBoE,YAAYpQ,MAAO6L,aAInBqH,KAAKlJ,QAAQ4B,UAA+B,IAAnBA,QAAQnR,aAC5B,IAAImB,MAAM,uDAMfyD,SAAW,GAEZ6T,KAAKrJ,SAAS+B,QAAQ,QAItB+U,EAAI/U,QACJ8B,EAAI,GACCxT,EAAI,EAAGA,EAAIymB,EAAElmB,OAAQP,IACtBwT,EAAExT,GAAKA,EAAI,OAEZ,GAAuB,IAAnB0R,QAAQnR,QAAgByY,KAAKlJ,QAAQ4B,QAAQ,QAIpD+U,EAAI/U,QAAQ,GACZ8B,EAAI,GAEJ1B,IAAMkH,KAAKrG,SAAS8T,GAAGlmB,OAClBP,EAAI,EAAGA,EAAI8R,IAAK9R,IACjBwT,EAAExT,GAAKA,EAAI,OAEW,IAAnB0R,QAAQnR,SAEfuR,IAAMM,KAAKC,IAAIX,QAAQ,GAAGnR,OAAQmR,QAAQ,GAAGnR,QAC7CiT,EAAI9B,QAAQ,GAAG3S,MAAM,EAAG+S,KACxB2U,EAAI/U,QAAQ,GAAG3S,MAAM,EAAG+S,SAGxBkH,KAAKlJ,QAAQ2W,IAAmB,IAAbA,EAAElmB,aACf,IAAImB,MAAM,mDAKpBob,MAAQnL,WAAWmoI,WAAWp5I,QAAQ,KAAM,IAAIN,MAAM,KACjDJ,EAAI,EAAGA,EAAI8c,MAAMvc,OAAQP,IAAK,QACvB8c,MAAM9c,QACT,MACDsV,EAAI5P,KAAKq0I,QAAQj0I,MAAO0N,EAAGiT,EAAG9U,sBAE7B,OACD2D,EAAI5P,KAAKyhF,SAASrhF,MAAO0N,EAAGiT,EAAG9U,sBAE9B,MACD2D,EAAI5P,KAAKs0I,QAAQl0I,MAAO0N,EAAGiT,EAAG9U,sBAE7B,SACD2D,EAAI5P,KAAKu0I,WAAWn0I,MAAO0N,EAAGiT,EAAG9U,sBAEhC,MACD2D,EAAI5P,KAAKw0I,QAAQp0I,MAAO2gB,EAAG9U,sBAE1B,QACD2D,EAAI5P,KAAKy0I,WAAWr0I,MAAO0N,EAAGiT,EAAG9U,sBAEhC,QACD2D,EAAI5P,KAAK00I,UAAUt0I,MAAO4L,QAASC,iBAGlCxM,SAAS/D,KAAKkU,eAElBzS,GAAK6C,KAAKI,MAAMw/F,MAAM5/F,KAAM,SAE1BA,KAAKP,UAGhBrB,IAAI+1I,MAAMj7I,UAAY,IAAI61F,gBAE1B3wF,IAAIC,OAAOD,IAAI+1I,MAAMj7I,UAA6C,CAU9DuoF,SAAU,SAAUrhF,MAAO0N,EAAGiT,EAAG9U,mBAE7BA,WAAWkF,UAAY,OACvBlF,WAAWyyE,mBAAqB,OAEzBt+E,MAAMwM,OAAO,QAAS,CAACkB,EAAGiT,GAAI9U,aAazCsoI,WAAY,SAAUn0I,MAAO0N,EAAGiT,EAAG9U,mBAE/BA,WAAW+/D,UAAY,OACvB//D,WAAWyyE,mBAAqB,OAEzBt+E,MAAMwM,OAAO,SAAU,CAACkB,EAAGiT,GAAI9U,aAc1CqoI,QAAS,SAAUl0I,MAAO0N,EAAGiT,EAAG9U,gBACxBozB,IAAMpzB,WAAWi1B,cAErB7B,IAAM3yB,KAAKiS,IAAIxE,SAASklB,IAAK,IAAK,IAAM,EAGxCpzB,WAAWkF,UAAY,OACvBlF,WAAWyyE,mBAAqB,OAEzBt+E,MAAMwM,OAAO,gBAAiB,CAACuoB,SAAS8L,qBAAqB5B,IAAKvxB,EAAGiT,IAAK9U,aAmBrFooI,QAAS,SAAUj0I,MAAO0N,EAAGiT,EAAG9U,gBACxB3R,EAAas7E,KAAM9iD,EAAG6hH,IAAKC,IAAKC,IAAKtnH,GAAIkqD,OAGzCprE,KAAMyoI,QAFNC,KAAO,GACPh4I,EAAI,GAEJi4I,UAAY,SAAU16I,EAAGsC,UACd,kBACIkR,EAAExT,KAAOsC,EAAIk2B,IAG5BmiH,YAAc,CACVtiE,OAAO,EACPE,WAAW,EACX5gE,SAAS,EACTrY,KAAM,QAGdyS,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,WAG1CJ,KAAKiL,MACbwb,EAAIzmB,KAAKiL,UACN,IACCxJ,EAAEjT,QAAU,EACZi4B,EAAI,WAGJA,EAAIhlB,EAAE,GAAKA,EAAE,GACRxT,EAAI,EAAGA,EAAIwT,EAAEjT,OAAS,EAAGP,IAC1Bw4B,EAAKhlB,EAAExT,EAAI,GAAKwT,EAAExT,GAAKw4B,EAAKhlB,EAAExT,EAAI,GAAKwT,EAAExT,GAAKw4B,EAGtDA,GAAK,OAGTgiH,QAAUxhI,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,QAAS,SAE7DnS,EAAI,EAAGA,EAAIwT,EAAEjT,OAAQP,IAClBgZ,KAAKnJ,WAAW2D,EAAExT,KAClBq6I,IAAMK,UAAU16I,GAAI,IACpBs6I,IAAMI,UAAU16I,EAAG,GACnBu6I,IAAMG,UAAU16I,EAAG,MAEnBq6I,IAAM7mI,EAAExT,GAAS,GAAJw4B,EACb8hH,IAAM9mI,EAAExT,GACRu6I,IAAM/mI,EAAExT,GAAS,GAAJw4B,GAGbvF,GADAja,KAAKnJ,WAAW4W,EAAEzmB,IACbymB,EAAEzmB,KAEFymB,EAAEzmB,GAEXizB,GAAKxM,EAAEzmB,GAEU,eAAb+R,KAAK2qE,KACLj6E,EAAE,GAAKqD,MAAMwM,OAAO,QAAS,CAAC,EAAG+nI,KAAMM,aACvCl4I,EAAE,GAAKqD,MAAMwM,OAAO,QAAS,CAAC2gB,GAAIonH,KAAMM,aACxCl4I,EAAE,GAAKqD,MAAMwM,OAAO,QAAS,CAAC2gB,GAAIsnH,KAAMI,aACxCl4I,EAAE,GAAKqD,MAAMwM,OAAO,QAAS,CAAC,EAAGioI,KAAMI,aAEnC3hI,KAAKzU,OAAOwN,KAAKioE,SAAWhhE,KAAKzU,OAAOwN,KAAKioE,OAAOh6E,MACpDw6I,QAAQ1mE,QAAU,UAClBwH,KAAOx1E,MAAMwM,OAAO,OAAQ,CACxB2gB,GACAqnH,IACAvoI,KAAKioE,OAAOh6E,IAAKw6I,UAChB/hI,QAAQkvF,QAAW,SAAS25B,YAAc,kBACnCA,IAAIx9F,KAAO,EAAK,OAAS,SADb,CAElBw3C,SAIV74E,EAAE,GAAKqD,MAAMwM,OAAO,QAAS,CAAC+nI,IAAK,GAAIM,aACvCl4I,EAAE,GAAKqD,MAAMwM,OAAO,QAAS,CAAC+nI,IAAKpnH,IAAK0nH,aACxCl4I,EAAE,GAAKqD,MAAMwM,OAAO,QAAS,CAACioI,IAAKtnH,IAAK0nH,aACxCl4I,EAAE,GAAKqD,MAAMwM,OAAO,QAAS,CAACioI,IAAK,GAAII,aAEnC3hI,KAAKzU,OAAOwN,KAAKioE,SAAWhhE,KAAKzU,OAAOwN,KAAKioE,OAAOh6E,MACpDw6I,QAAQ3mE,QAAU,UAElByH,KAAOx1E,MAAMwM,OAAO,OAAQ,CACxBgoI,IACArnH,GACAlhB,KAAKioE,OAAOh6E,IAAKw6I,UAEhB/hI,QAAQmvF,QAAW,SAAS05B,YACtB,kBACSA,IAAIv9F,KAAO,EAAK,SAAW,OAFvB,CAIjBu3C,QAKXtiE,KAAKlJ,QAAQiC,KAAKorE,UAClBA,OAASprE,KAAKorE,OACdprE,KAAK8E,UAAYsmE,OAAOn9E,EAAIm9E,OAAO58E,SAGvCk6I,KAAKz6I,GAAK8F,MAAMwM,OAAO,UAAW7P,EAAGsP,MACjCiH,KAAKzU,OAAOwN,KAAKioE,SAAWhhE,KAAKzU,OAAOwN,KAAKioE,OAAOh6E,MACpDy6I,KAAKz6I,GAAGs7E,KAAOA,aAIhBm/D,MAiBXN,WAAY,SAAUr0I,MAAO0N,EAAGiT,EAAG9U,gBAC3B3R,EACAiS,OAAS,GACT2oI,aAAejpI,WAAWkpI,iBAE9BlpI,WAAW0mE,OAAQ,EACnB1mE,WAAWrS,KAAO,GAEbU,EAAI,EAAGA,EAAIwT,EAAEjT,OAAQP,IACtB2R,WAAWmpI,cAAcF,cAAeA,aAAa56I,EAAI46I,aAAar6I,QACtE0R,OAAOjS,GAAK8F,MAAMwM,OAAO,QAAS,CAACkB,EAAExT,GAAIymB,EAAEzmB,IAAK2R,mBAG7CM,QAoBXioI,QAAS,SAAUp0I,MAAO2gB,EAAG9U,gBACrB3R,EAAGo+B,OACH37B,EAAI,GACJ8vE,OAAS,GAETwoE,YADIxnG,WAAWjtB,IAAIG,GACN9U,WAAWwrE,QACxB69D,oBAAsBrpI,WAAWyrE,gBACjC69D,WAAatpI,WAAWqoE,OACxB9kE,EAAIvD,WAAW2sD,QAAU,EACzBA,OAASppD,EACTgmI,KAAOvpI,WAAWysB,QAAU,CAAC,EAAG,GAChCyqF,GAAKqyB,KAAK,GACVpyB,GAAKoyB,KAAK,GAEVC,gBAAkB,SAAUl7I,EAAG2F,IAAKijH,WACzB,eACC9iH,EAAG/F,EAAGi1C,IACNr2B,EAAI,MAEH5e,EAAI,EAAGA,GAAKC,EAAGD,IAChB4e,GAAKvB,WAAWrE,KAAKrG,SAAS8T,EAAEzmB,SAGpC+F,EAAI6Y,EACC5e,EAAIC,EAAI,EAAGD,EAAIymB,EAAElmB,OAAQP,IAC1B+F,GAAKsX,WAAWrE,KAAKrG,SAAS8T,EAAEzmB,YAEpCi1C,IAAa,IAANlvC,EAAY,EAAIqM,KAAKiV,GAAKzI,EAAI7Y,EAAK,EAEnCu4D,SAAWlsD,KAAKxM,KAAKqvC,KAAO4zE,KAI3CuyB,qBAAuB,SAAU94I,EAAGyD,OAC5By+B,IAAM9+B,KAAK0wC,OAAO7iC,OAAOG,UAAU,GAAKhO,KAAK4wC,OAAO/iC,OAAOG,UAAU,GACrE+yB,IAAM/gC,KAAK0wC,OAAO7iC,OAAOG,UAAU,GAAKhO,KAAK4wC,OAAO/iC,OAAOG,UAAU,GAErEsF,KAAKzU,OAAOmB,KAAKkQ,cACZA,MAAMywE,SAASvpE,MAAMi3D,SAAYhuE,EAAIiT,KAAKrG,SAASjN,KAAKkQ,MAAM6C,QAAQzB,UAAa,UACnFpB,MAAM8uE,mBAGVpuC,OAAO/iC,OAAS,IAAIsW,OAAO3a,MAAM1H,eAAgB,CAClD9B,KAAK0wC,OAAO7iC,OAAOG,UAAU,GAAK8wB,GAAKliC,EACvCoD,KAAK0wC,OAAO7iC,OAAOG,UAAU,GAAK+yB,GAAKnkC,GACxCoD,KAAKI,YACH4+E,cAGT22D,aAAe,WACN31I,KAAK4/E,mBACDA,aAAc,OACdx/E,MAAMogF,mBAAmBxgF,KAAK7C,IAAM6C,UACpCI,MAAMmvE,SAAS2D,UAAUlzE,MAE9B01I,qBAAqBh8I,KAAKsG,KAAM,IAAK,KAI7C41I,eAAiB,WACT51I,KAAK4/E,mBACAA,aAAc,OACdx/E,MAAMmvE,SAASia,YAAYxpF,MAEhC01I,qBAAqBh8I,KAAKsG,KAAM,SAAY,KAIpDi1I,YAAc,CACVtiE,OAAO,EACPE,WAAW,EACX5gE,SAAS,EACTrY,KAAM,QAGT0Z,KAAKlJ,QAAQmrI,gBACdA,WAAa,GACRj7I,EAAI,EAAGA,EAAIymB,EAAElmB,OAAQP,IACtBi7I,WAAWj7I,GAAK,OAInBgZ,KAAKnJ,WAAWqF,KACjBopD,OAAS,kBACEppD,IAIfvD,WAAW0rE,kBAAoB1rE,WAAW0rE,oBAAqB,EAC/D1rE,WAAW2mC,eAAgB,EAC3B3mC,WAAW4mC,cAAe,EAE1Bna,OAASt4B,MAAMwM,OAAO,QAAS,CAACu2G,GAAIC,IAAK6xB,aACzCl4I,EAAE,GAAKqD,MAAMwM,OAAO,QAAS,CACzB,kBACWgsD,SAAWuqD,IAEtB,kBACWC,KAEZ6xB,aAEE36I,EAAI,EAAGA,EAAIymB,EAAElmB,OAAQP,IACtByC,EAAEzC,EAAI,GAAK8F,MAAMwM,OAAO,QAAS,CAAC6oI,gBAAgBn7I,EAAG,MAAO6oH,IAAKsyB,gBAAgBn7I,EAAG,MAAO8oH,KAAM6xB,aAEjGhpI,WAAWrS,KAAO27I,WAAWj7I,GAC7B2R,WAAWooF,UAAgC,KAApBpoF,WAAWrS,KAClCqS,WAAWkF,UAAYkkI,YAAcA,WAAW/6I,EAAI+6I,WAAWx6I,QAC/DoR,WAAW4pI,WAAaR,YAAcA,WAAW/6I,EAAI+6I,WAAWx6I,QAChEoR,WAAWyyE,mBAAqB42D,qBAAuBA,oBAAoBh7I,EAAIg7I,oBAAoBz6I,QAEnGgyE,OAAOvyE,GAAK8F,MAAMwM,OAAO,SAAU,CAAC8rB,OAAQ37B,EAAEzC,GAAIyC,EAAEzC,EAAI,IAAK2R,YAEzDA,WAAW0rE,oBAEX9K,OAAOvyE,GAAG06E,SAAWnI,OAAOvyE,GAAG+vI,gBAE/Bp+H,WAAW2rE,kBACX/K,OAAOvyE,GAAG44E,UAAYyiE,aAEtB9oE,OAAOvyE,GAAGkvF,YAAcosD,sBAMzB,CAACE,QAASjpE,OAAQtgE,OAAQxP,EAAGimI,SAAUtqG,SAiClDg8G,UAAW,SAAUt0I,MAAO4L,QAASC,gBAC7B3R,EAAGC,EAAGw7I,WAAYC,YAAaC,MAAOC,KACtC1vB,GAAI2vB,MAAOC,IAAKC,IAAKC,QAASC,QAC9BC,QAASC,QAASC,OAAQC,KAC1BpB,WAAYF,WAAiCz8E,OAAQg+E,OACrDpB,KAAMryB,GAAIC,GAAI1qF,OAAQ4pE,YAAa/yD,IAAKxyC,EAAGszC,KAAMn3B,EACjD29H,OAAQC,OAAQC,SAA2BC,QAASC,MAAOC,MAC3DC,IAAKC,YAAaC,SAAUC,SAAiBC,GAAIhuD,GAAI1qD,KACrDzyB,IAAMJ,QAAQnR,OAEd28I,WAAa,eACLr3G,GAAIC,GAAI+B,GAAI3Z,GACZy2G,UAAY3rH,KAAKrG,SAASjN,KAAK+S,QAAQ7C,MAAM2V,QAAQxsB,MAAM,UAE/D8mC,GAAKngC,KAAK0wC,OAAOtS,IACjBgC,GAAKpgC,KAAK4wC,OAAOxS,IACjB+D,GAAKniC,KAAK0wC,OAAOrS,IACjB7V,GAAKxoB,KAAK4wC,OAAOvS,IACb+B,GAAKD,KACL8+F,UAAU,IAAMA,UAAU,IAG1Bz2G,GAAK2Z,KACL88F,UAAU,IAAMA,UAAU,SAGzBD,uBAAuBC,WAErB,IAAI96G,OAAO3a,MAAM1H,eAAgB,CAAC9B,KAAK4wC,OAAOxS,IAAKp+B,KAAK4wC,OAAOvS,KAAMr+B,KAAKI,QAGrFq3I,cAAgB,SAAUroG,MAAO90C,OACzB4e,EAAGw+H,OAAQC,YAEfz+H,EAAI9Y,MAAMwM,OAAO,YAAa,GAAG8pI,OAAOp8I,GAAKk8I,QAAQl8I,IAAK,GAAI,CAACuQ,KAAM,cACrE6sI,OAASt3I,MAAMwM,OAAO,YAAa,CAACgsD,QAAW+9E,KAAKr8I,GAAKm8I,QAAQn8I,IAAOo8I,OAAOp8I,GAAKk8I,QAAQl8I,KAAM,GAAI,CAACuQ,KAAM,UAC7GqO,EAAE04E,KAAK8lD,QACPC,KAAOv3I,MAAMwM,OAAO,YAAa,CAACwiC,OAAQ,CAACvkC,KAAM,WACjDqO,EAAE04E,KAAK+lD,MAEAz+H,MAGX9M,KAAO,QACD,IAAIpQ,MAAM,oCAGpB+5I,WAAa9pI,WAAW2rI,YACnBtkI,KAAKzU,OAAOk3I,kBACP,IAAI/5I,MAAM,uDAEpBg6I,YAAcD,WAAWl7I,SACN,QACT,IAAImB,MAAM,oEAGf1B,EAAI,EAAGA,EAAI8R,IAAK9R,OACb07I,cAAgBhqI,QAAQ1R,GAAGO,aACrB,IAAImB,MAAM,oEAAsEgQ,QAAQ1R,GAAGO,OAAS,OAASm7I,YAAc,SAIzIC,MAAQ,GACRC,KAAO,GAEF37I,EAAI,EAAGA,EAAIy7I,YAAaz7I,IACzB07I,MAAM17I,GAAKyR,QAAQ,GAAGzR,GACtB27I,KAAK37I,GAAK07I,MAAM17I,OAGfD,EAAI,EAAGA,EAAI8R,IAAK9R,QACZC,EAAI,EAAGA,EAAIy7I,YAAaz7I,IACrByR,QAAQ1R,GAAGC,GAAK07I,MAAM17I,KACtB07I,MAAM17I,GAAKyR,QAAQ1R,GAAGC,IAGtByR,QAAQ1R,GAAGC,GAAK27I,KAAK37I,KACrB27I,KAAK37I,GAAKyR,QAAQ1R,GAAGC,QAKjCisH,GAAK,GACL2vB,MAAQ,GAEH77I,EAAI,EAAGA,EAAI8R,IAAK9R,IACjBksH,GAAGlsH,GAAK,GACR67I,MAAM77I,GAAK,OAGf87I,IAAM,GACNC,IAAM,GAGNC,QAAUrqI,WAAW4rI,iBAAmB,EAExCtB,QAAUtqI,WAAW6rI,eAAiB,EAEjCx9I,EAAI,EAAGA,EAAI07I,YAAa17I,IACzB87I,IAAI97I,IAAM27I,MAAM37I,GAAK47I,KAAK57I,IAAMg8I,QAChCD,IAAI/7I,IAAM27I,MAAM37I,GAAK47I,KAAK57I,IAAMi8I,WAIpCC,QAAUvqI,WAAW8rI,iBAAmB3B,IACxCK,QAAUxqI,WAAW+rI,eAAiB3B,IAEtCK,OAASzqI,WAAWgsI,YAAc/B,KAE9B5iI,KAAKzU,OAAOoN,WAAWmO,WAClB9f,EAAI,EAAGA,EAAI07I,YAAa17I,IACzBo8I,OAAOp8I,GAAK2R,WAAWmO,SAK/Bu8H,KAAO1qI,WAAWisI,UAAYjC,MAC1B3iI,KAAKzU,OAAOoN,WAAWs2B,SAClBjoC,EAAI,EAAGA,EAAI07I,YAAa17I,IACzBq8I,KAAKr8I,GAAK2R,WAAWs2B,OAIzBi0G,QAAQ37I,SAAWm7I,kBACb,IAAIh6I,MAAM,qFAGhBy6I,QAAQ57I,SAAWm7I,kBACb,IAAIh6I,MAAM,mFAGhB06I,OAAO77I,SAAWm7I,kBACZ,IAAIh6I,MAAM,+EAGhB26I,KAAK97I,SAAWm7I,kBACV,IAAIh6I,MAAM,8EAIpBu5I,WAAatpI,WAAWksI,YAAc3xB,GACtC6uB,WAAappI,WAAWwrE,OACFxrE,WAAWyrE,gBACjC9e,OAAS3sD,WAAW2sD,QAAU,GAC9B2wB,GAAKt9E,WAAW4F,aAAe,EAE1ByB,KAAKzU,OAAOoN,WAAW0rE,qBACxB1rE,WAAW0rE,mBAAoB,GAGnCi/D,OAAS,CACLh9I,KAAMqS,WAAWrS,KACjBuD,GAAI8O,WAAW9O,GACf0U,YAAa03E,GACb6uD,gBAAiBnsI,WAAWmsI,iBAAmB7uD,GAC/C53E,YAAa1F,WAAW0F,aAAe,QACvCihC,eAAe,EACfC,cAAc,EACd1hC,UAAWlF,WAAW+/D,WAAa,UACnC56D,YAAanF,WAAWylE,aAAe,GACvCgN,mBAAoBzyE,WAAWigE,oBAAsB,UACrDyS,qBAAsB1yE,WAAWslE,sBAAwB,QACzDK,SAAU3lE,WAAW2lE,UAAY,QAIrCuxC,IADAqyB,KAAOvpI,WAAWysB,QAAU,CAAC,EAAG,IACtB,GACV0qF,GAAKoyB,KAAK,GACV98G,OAASt4B,MAAMwM,OAAO,QAAS,CAACu2G,GAAIC,IAAK,CAACxpH,KAAM,GAAI+4E,OAAO,EAAM0hB,WAAW,EAAOpiF,SAAS,IAC9EvF,KAAKiV,GAAK,EAAIjV,KAAKiV,GAAKq0H,YAEtCzmG,IADA+yD,YAAcr2F,WAAWosI,YAAc,EAEvCt7I,EAAI,GACJszC,KAAO,GAEF/1C,EAAI,EAAGA,EAAI07I,YAAa17I,QACzBi1C,KAAO,EAAI7iC,KAAKiV,GAAKq0H,YACrBa,OAASj+E,OAASlsD,KAAK8hB,IAAI+gB,KAAO4zE,GAClC2zB,OAASl+E,OAASlsD,KAAKwiB,IAAIqgB,KAAO6zE,GAElCrmH,EAAEzC,GAAK8F,MAAMwM,OAAO,QAAS,CAACiqI,OAAQC,QAAS,CAACl9I,KAAM,GAAI+4E,OAAO,EAAM0hB,WAAW,EAAOpiF,SAAS,IAClGo+B,KAAK/1C,GAAK8F,MAAMwM,OAAO,OAAQ,CAAC8rB,OAAQ37B,EAAEzC,IAAK,CAC3CV,KAAMm8I,WAAWz7I,GACjByxE,YAAa6qE,OAAOjlI,YACpB8gE,YAAamkE,OAAO/kI,YACpB2/D,cAAe,EACf9+B,eAAe,EACfC,cAAc,EACdkgC,WAAW,EACXtB,qBAAsBqlE,OAAOj4D,uBAEjCtuC,KAAK/1C,GAAG46F,eAAiBsiD,WACzBt+H,EAAIu+H,cAAcloG,IAAKj1C,GAElBC,EAAI,EAAGA,EAAIyR,QAAQnR,OAAQN,IAC5BskC,KAAO7yB,QAAQzR,GAAGD,GAClB67I,MAAM57I,GAAGD,GAAK8F,MAAMwM,OAAO,QAAS,CAACiyB,KAAM,GAAI,CAACjlC,KAAM,GAAI+4E,OAAO,EAAM0hB,WAAW,EAAOpiF,SAAS,IAClGkkI,MAAM57I,GAAGD,GAAG61F,aAAagmD,MAAM57I,GAAGD,GAAI4e,OAI9C69H,SAAW,GACNz8I,EAAI,EAAGA,EAAI8R,IAAK9R,QACjBs8I,OAAOf,WAAaR,YAAcA,WAAW/6I,EAAI+6I,WAAWx6I,QAC5D+7I,OAAOjlI,YAAc0jI,YAAcA,WAAW/6I,EAAI+6I,WAAWx6I,QAC7D+7I,OAAOzlI,UAAYkkI,YAAcA,WAAW/6I,EAAI+6I,WAAWx6I,QAC3Dk8I,SAASz8I,GAAK8F,MAAMwM,OAAO,UAAWupI,MAAM77I,GAAI,CAC5Cy2E,WAAW,EACX8B,WAAW,EACX7G,UAAW4qE,OAAOzlI,UAClBugE,YAAaklE,OAAOxlI,YACpB86D,mBAAoB0qE,OAAOl4D,qBAG1BnkF,EAAI,EAAGA,EAAIy7I,YAAaz7I,IACzBw8I,SAASz8I,GAAG6+C,QAAQ5+C,GAAG2qF,aAAa,eAAiBmwD,WAAW/6I,EAAI+6I,WAAWx6I,SAC/Ek8I,SAASz8I,GAAG6+C,QAAQ5+C,GAAG2qF,aAAa,eAAiB0xD,OAAOwB,wBAIlDnsI,WAAWqsI,gBAAkB,YAE1C,QACDrB,MAAQhrI,WAAWssI,kBAAoB,EACvCrB,MAAQjrI,WAAWusI,iBAAmB,OAEjC1+D,OAAS15E,MAAMwM,OAAO,SAAU,CAACu2G,GAAKvqD,OAASq+E,MAAO7zB,GAAKxqD,OAASs+E,OAAQ,CAC7E5iE,OAAQihE,WACR99D,OAAQ49D,uBAGX,qBAGDj3I,IAAIsD,MAAM,8BAGds1I,QAAU,GACN/qI,WAAWwsI,YAAa,KACxBtB,IAAM,GACD78I,EAAI,EAAGA,EAAI,EAAGA,IACf68I,IAAI78I,GAAK,GAAKA,KAElB68I,IAAI,GAAK,KAETE,UADAD,YAAcnrI,WAAWysI,kBAAoBvB,KACtBt8I,QAER,QACL,IAAImB,MAAM,kEAGpBs7I,SAAW,GAEXp+H,EAAIu+H,cADIn1C,YAAc51F,KAAKiV,GAAKq0H,YACP,GAEzBY,OAAOzlI,UAAY,OACnBylI,OAAOl4D,mBAAqB,OAC5Bk4D,OAAOjlI,YAAc1F,WAAW0F,aAAe,QAC/CilI,OAAO/kI,YAAc5F,WAAW0sI,mBAAqB,GACrD/B,OAAO3mI,MAAQ,EAGfsnI,IAAMZ,KAAK,GAAKD,OAAO,KAAOW,SAAW,GAEpC/8I,EAAI,EAAGA,EAAI+8I,SAAU/8I,IACtBg9I,SAASh9I,GAAK8F,MAAMwM,OAAO,QAAS,CAAC8pI,OAAO,GAAKp8I,EAAIi9I,GAAI,GAAI,CACzD39I,KAAMw9I,YAAY98I,GAClBm/B,KAAM,EACNk5C,OAAO,EACPE,WAAW,EACX5gE,SAAS,IAEbqlI,SAASh9I,GAAG61F,aAAamnD,SAASh9I,GAAI4e,GACtC89H,QAAQ18I,GAAK8F,MAAMwM,OAAO,SAAU,CAAC8rB,OAAQ4+G,SAASh9I,IAAKs8I,oBAI9Dj2D,SAAWo2D,SAAS,GAAGp2D,SACrB,CACHq2D,QAASA,QACThlC,MAAO3hE,KACP9jC,OAAQ4pI,MACRnT,SAAUtqG,OACVq+G,SAAUA,WAQlB7jD,eAAgB,kBACLlzF,MAIXw6B,OAAQ,kBACAx6B,KAAKivF,kBACA44C,kBAGF7nI,MAaX6nI,gBAAiB,kBAAqB7nI,QAmPzC5B,IAAIw6I,YAAc,SAAUx4I,MAAO4L,QAASC,gBACpC4yB,KAAMwO,IAAK/yC,EAAGC,EAAG6wE,IAEjBt4C,EAAGhlB,EAAG+qI,SAAUxsI,KAChB6K,cAAetd,KAAMmyE,YAAaC,UAClC8sE,aAAcC,WAAY3sI,IAH1B4sI,OAAS,GAIT1xF,MAAQxyB,IAAI7gB,UAAY7T,MAAMc,SAASC,eAAe6K,QAAQ,IAAM,QAEjD,IAAnBA,QAAQnR,QAAkByY,KAAKvJ,SAASiC,QAAQ,IAAM,IACnDsH,KAAKzU,OAAOyoD,OAAQ,IAEpBj7C,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,SAGtDoyB,MADAyoB,OAAS,IAAIgsF,YAAcO,cAAc7nI,QAAQ,GAAIK,KAAK4sI,YAAa5sI,KAAK4sI,cAC/Dp6G,KACbusC,IAAM9jB,MAAMisF,cACZlmG,IAAMia,MAAMksF,WAEZt8H,cAAgB7K,KAAKiL,MACrB1d,KAAOyS,KAAKzS,KACZmyE,YAAc1/D,KAAKsF,YACnBq6D,UAAY3/D,KAAK8E,UACjB2nI,aAAezsI,KAAKsyE,qBACpBo6D,WAAa1sI,KAAKqyE,mBAElBt+E,MAAMy9C,gBAENzxC,IAAMyyB,KAAKhkC,OACXg+I,SAAW,GACPxsI,KAAKihC,MAAQh6B,KAAKlJ,QAAQiC,KAAKihC,WAC1BhzC,EAAI,EAAGA,EAAI8R,IAAK9R,QACZC,EAAI,EAAGA,EAAI8R,KAAKihC,KAAKzyC,OAAQN,OACzB8R,KAAKihC,KAAK/yC,KAAOD,GAAO+R,KAAK4sI,aAAe5sI,KAAKihC,KAAK/yC,KAAO8yC,IAAI/yC,GAAK,CACvEu+I,SAASn9I,KAAKmjC,KAAKvkC,gBAM/Bu+I,SAAWh6G,SAGfzyB,IAAMysI,SAASh+I,OAEVP,EAAI,EAAGA,EAAI8R,IAAK9R,IAAK,IAEtBwT,EAAI,GACAzB,KAAK+nI,aAAkD,IAApC/nI,KAAK+nI,WAAWh4I,QAAQ,OAAe,KAEtD02B,EADA5b,eAGI,GAGRpJ,EAAEpS,KAAK,EAAIo3B,EAAI,GAAKx4B,EAAI,IAAOw4B,EAAI1mB,KAE9B7R,EAAI,EAAGA,EAAIs+I,SAASv+I,GAAGO,OAAQN,IAChCuT,EAAEpS,KAAKoS,EAAEvT,EAAI,GAAK,GAGtB8R,KAAKiL,MAAQwb,EAAI1mB,IAGjBxS,MAAQA,KAAKiB,SAAWuR,IACxBC,KAAKzS,KAAOA,KAAKU,GACV+R,KAAK4sI,cACZ5sI,KAAKzS,KAAOwxE,IAAI9wE,IAGhByxE,aAAeA,YAAYlxE,SAAWuR,IACtCC,KAAKsF,YAAco6D,YAAYzxE,GAE/B+R,KAAKsF,YAAc27D,MAAMxD,SAAUxvE,EAAI,GAAK8R,IAAO,IAAK,GAAK,IAG7D4/D,WAAaA,UAAUnxE,SAAWuR,IAClCC,KAAK8E,UAAY66D,UAAU1xE,GAE3B+R,KAAK8E,UAAYm8D,MAAMxD,SAAUxvE,EAAI,GAAK8R,IAAO,IAAK,GAAK,GAG3D0sI,cAAgBA,aAAaj+I,SAAWuR,IACxCC,KAAKsyE,qBAAuBm6D,aAAax+I,GAEzC+R,KAAKsyE,qBAAuBrR,MAAMxD,SAAUxvE,EAAI,GAAK8R,IAAO,IAAK,GAAK,GAGtE2sI,YAAcA,WAAWl+I,SAAWuR,IACpCC,KAAKqyE,mBAAqBq6D,WAAWz+I,GAErC+R,KAAKqyE,mBAAqBpR,MAAMxD,SAAUxvE,EAAI,GAAK8R,IAAO,IAAK,GAAK,IAGpEC,KAAK+nI,aAAkD,IAApC/nI,KAAK+nI,WAAWh4I,QAAQ,OAC3C48I,OAAOt9I,KAAK,IAAI0C,IAAI+1I,MAAM/zI,MAAO,CAAC0N,EAAG+qI,SAASv+I,IAAK+R,OAEnD2sI,OAAOt9I,KAAK,IAAI0C,IAAI+1I,MAAM/zI,MAAO,CAACy4I,SAASv+I,IAAK+R,OAIxDjM,MAAMo3G,yBAGHwhC,cAGX3sI,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,SAC/C,IAAIrO,IAAI+1I,MAAM/zI,MAAO4L,QAASK,OAGzCjO,IAAIsB,gBAAgB,QAAStB,IAAIw6I,aAkBjCx6I,IAAI86I,OAAS,SAAU94I,MAAOyN,OAAQ5B,gBAC9BI,aAGCmE,cAELnE,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,eAEjDrM,MAAQA,WACRyN,OAAS,IAAIsW,OAAO3a,MAAM1H,eAAgB+L,OAAQ7N,KAAKI,YACvDw2I,OAAS,QACTuC,YAAc9sI,KAAK8rI,YAAc9rI,KAAKioE,YACtC8kE,YAAc/sI,KAAKgtI,YAAchtI,KAAKorE,YACtCu6B,MAAQ,QACR4kC,OAAO/kI,YAAcxF,KAAKwF,aAAe,OACzC+kI,OAAOhkG,eAAgB,OACvBgkG,OAAO/jG,cAAe,OACtB+jG,OAAOviD,WAAY,OACnBuiD,OAAOjkE,OAAQ,OACfv7D,MAAQ/K,KAAKitI,aAAejtI,KAAK+K,MAEnB,aAAfpX,KAAKoX,YAGC,IAAIpb,MAAM,mCAAqCgE,KAAKoX,YAFrDmiI,mBAAmBn5I,MAAOiM,OAMvCjO,IAAI86I,OAAOhgJ,UAAY,IAAI61F,gBAS3B3wF,IAAI86I,OAAOhgJ,UAAUqgJ,mBAAqB,SAAUn5I,MAAO6L,gBACnD3R,EACAk/I,YAAcvtI,WAAWwtI,YAAc,EACvCC,MAAQztI,WAAW0tI,WAAa,IAAM35I,KAAKI,MAAM4kB,MAEjDkwE,eAAiB,uBACR8pC,uBAAuBh/H,KAAK+S,QAAQ7C,MAAM2V,QACxC,IAAI1B,OAAO3a,MAAM1H,eAAgB,CAAC9B,KAAK4wC,OAAOxS,IAAKp+B,KAAK4wC,OAAOvS,KAAMr+B,KAAKI,YAGpF9F,EAAI,EAAGA,EAAI0F,KAAKm5I,YAAYt+I,OAAQP,SAChCs8I,OAAOh9I,KAAOoG,KAAKm5I,YAAY7+I,QAC/Bs8I,OAAOjlI,YAAc3R,KAAKo5I,YAAY9+I,EAAI0F,KAAKo5I,YAAYv+I,aAC3D+7I,OAAOj4D,qBAAuB3+E,KAAKo5I,YAAY9+I,EAAI0F,KAAKo5I,YAAYv+I,aACpE+7I,OAAO1mI,MAAQ,CAChB2V,OAAQ,CAAC,GAAI,GACbkmD,YAAa/rE,KAAKo5I,YAAY9+I,EAAI0F,KAAKo5I,YAAYv+I,QACnD43E,YAAazyE,KAAK42I,OAAO/kI,kBAGxBmgG,MAAM13G,GAAK8F,MAAMwM,OAAO,OAAQ,CACjC,CAAC5M,KAAK6N,OAAOG,UAAU,GAAIhO,KAAK6N,OAAOG,UAAU,GAAK1T,EAAIo/I,MAC1D,CAAC15I,KAAK6N,OAAOG,UAAU,GAAKwrI,YAAax5I,KAAK6N,OAAOG,UAAU,GAAK1T,EAAIo/I,OACxE15I,KAAK42I,aAEJ5kC,MAAM13G,GAAG46F,eAAiBA,oBAC1B8c,MAAM13G,GAAG+qF,gBAAgB7qD,SAAS8qD,iBAAiBhyE,KAAKrG,SAASjN,KAAKgyG,MAAM13G,GAAGyY,QAAQd,UAAUihF,kBAsD9G90F,IAAIw7I,aAAe,SAAUx5I,MAAO4L,QAASC,gBAErC4tI,WAAa,CAAC,EAAG,OAEjBvmI,KAAKzU,OAAOmN,UAA+B,IAAnBA,QAAQnR,aAG1B,IAAImB,MAAM,mEAFZ69I,WAAa7tI,QAKd,IAAI5N,IAAI86I,OAAO94I,MAAOy5I,WAAY5tI,aAG7C7N,IAAIsB,gBAAgB,SAAUtB,IAAIw7I,cAE3B,CACHzF,MAAO/1I,IAAI+1I,MACX+E,OAAQ96I,IAAI86I,OACZN,YAAax6I,IAAIw6I,YACjBgB,aAAcx7I,IAAIw7I,iBAyD1BxhJ,OAAO,cAAc,CACjB,MAAO,iBAAkB,eAAgB,eAC1C,SAAUgG,IAAKoL,MAAOulF,gBAAiBz7E,aA2EtClV,IAAI07I,OAAS,SAAU15I,MAAO4L,QAASC,gBAC/B6B,EAAGiT,EAAGi2D,gBAELxmE,YAAYpQ,MAAO6L,WAAYzC,MAAMpG,mBAAoBoG,MAAMnF,yBAE/D01I,gBAAiB,OACjB35I,MAAQA,WACR2S,QAAQmlE,UAAY,YAOpB8hE,YAAc1mI,KAAK9G,eAAexM,KAAK+S,QAAS3S,MAAMqM,QAAS,iBAC7DzM,KAAKg6I,YAAY78I,GAExB2Q,EAAI,EACJiT,EAAI,EACJi2D,IAAM,GAEiB,IAAnBhrE,QAAQnR,SAEe,IAAnBmR,QAAQnR,QAERiT,EAAI9B,QAAQ,GACZ+U,EAAI/U,QAAQ,GACZgrE,IAAMhrE,QAAQ,IACY,IAAnBA,QAAQnR,OAEXyY,KAAKlJ,QAAQ4B,QAAQ,KACrB8B,EAAI9B,QAAQ,GAAG,GACf+U,EAAI/U,QAAQ,GAAG,GACfgrE,IAAMhrE,QAAQ,KAGd8B,EAAI9B,QAAQ,GACZ+U,EAAI/U,QAAQ,KAIhB8B,EAAI9B,QAAQ,GAAG,GACf+U,EAAI/U,QAAQ,GAAG,UAIlB+S,KAAKjR,EAAGiT,EAAGi2D,UAEX+Y,UAAYz8E,KAAK3D,SAAS3P,KAAK+vF,UAAW,CAC3CkqD,QAAS,UACTC,GAAI,UACJC,KAAM,OACNC,GAAI,OACJ/oE,MAAO,QACPnrC,GAAI,QACJ10B,KAAM,OACN0R,GAAI,OACJm3H,MAAO,QACPC,GAAI,QACJC,QAAS,UACTtN,GAAI,UACJuN,YAAa,cACbC,GAAI,cACJC,MAAO,QACPC,OAAQ,SACRC,KAAM,OACNC,WAAY,aACZC,GAAI,aACJC,WAAY,aACZvgI,GAAI,aACJwgI,QAAS,aACTC,SAAU,cACVC,WAAY,aACZx/I,KAAM,aACNy/I,UAAW,YACX10G,IAAK,YACL20G,OAAQ,SACRv/F,IAAK,MACL69C,OAAQ,SACRt7D,EAAG,IACHC,EAAG,MAGAr+B,MAGX5B,IAAI07I,OAAO5gJ,UAAY,IAAI61F,gBAE3B3wF,IAAIC,OAAOD,IAAI07I,OAAO5gJ,UAA8C,CAKhE6lB,KAAM,SAAUjR,EAAGiT,EAAGi2D,SACdqkE,gBAAkB,CACd1oE,OAAO,EACP/4E,KAAM,GACNqY,SAAS,EACT4gE,WAAW,QAGdyoE,SAAW,GAAK5uI,KAAKmU,KAAK7gB,KAAKI,MAAM2kB,MAAQ/kB,KAAKI,MAAM2kB,MAAQ/kB,KAAKI,MAAM4kB,MAAQhlB,KAAKI,MAAM4kB,YAE9F62B,IAAM,CAAC/tC,EAAGiT,QACVw6H,WAAY,OACZvkE,IAAM,QACNx1E,MAAQ,QACRkI,QAAU,QACV2vC,MAAQr5C,KAAKI,MAAMwM,OAAO,QAAS,CAAC,CAAC5M,KAAK67C,IAAI,IAAK,CAAC77C,KAAK67C,IAAI,KAAM77C,KAAKg6I,kBACxEtwI,QAAQhO,KAAKsE,KAAKq5C,YAElB4D,OAASj9C,KAAKI,MAAMwM,OAAO,QAAS5M,KAAK67C,IAAKw/F,sBAC9C3xI,QAAQhO,KAAKsE,KAAKi9C,aAElBu+F,QAAUx7I,KAAKI,MAAMwM,OAAO,QAAS,CAAC5M,KAAK67C,IAAI,GAAI77C,KAAK67C,IAAI,GAAK77C,KAAKs7I,UAAWD,sBACjF3xI,QAAQhO,KAAKsE,KAAKw7I,cAElBzoI,QAAQi6D,MAAMqJ,WAAY,OAC1BtjE,QAAQi6D,MAAMt6B,eAAgB,OAC9B3/B,QAAQi6D,MAAMr6B,cAAe,OAC7Bq6B,MAAQhtE,KAAKI,MAAMwM,OAAO,OAAQ,CAAC5M,KAAKi9C,OAAQj9C,KAAKw7I,SAAUx7I,KAAK+S,QAAQi6D,YAC5EtjE,QAAQhO,KAAKsE,KAAKgtE,YAElB4iB,KAAO,CACR5iB,MAAOhtE,KAAKgtE,YAEX6iB,SAASn0F,KAAKsE,KAAKgtE,YAEnBqE,MAAM,GAAK2F,UACX52E,MAAMo6B,UAQfy/G,QAAS,SAAU7tI,QACH,IAARA,WACOpM,SAGPkZ,EACA4lB,GAAK1yB,IAAMM,KAAK8hB,IAAIxuB,KAAKg3E,IAAMtqE,KAAKiV,GAAK,KACzCof,GAAK30B,IAAMM,KAAKwiB,IAAIlvB,KAAKg3E,IAAMtqE,KAAKiV,GAAK,YAExC3hB,KAAK+5I,kBACN7gI,EAAIlZ,KAAKI,MAAMwM,OAAO,YAAa,CAACkyB,GAAIiC,IAAK,CAACl2B,KAAM,eAElD6mF,UAAU1xF,KAAKi9C,QACjB/jC,EAAEw4E,UAAU1xF,KAAKw7I,UAGjBx7I,KAAKu7I,WAEDv7I,KAAKq5C,MAAMlY,MAAMtmC,QAAU,YACtBw+C,MAAQr5C,KAAKI,MAAMwM,OAAO,QAAS,CAAC,CAAC5M,KAAK67C,IAAI,IAAK,CAAC77C,KAAK67C,IAAI,KAAM77C,KAAKg6I,kBACxEtwI,QAAQhO,KAAKsE,KAAKq5C,aAI1BwC,IAAI,IAAM/c,QACV+c,IAAI,IAAM9a,GAEX/gC,KAAKu7I,iBACAliG,MAAMlY,MAAMzlC,KAAKsE,KAAK67C,IAAI,SAC1BxC,MAAMjY,MAAM1lC,KAAKsE,KAAK67C,IAAI,UAG9Bz7C,MAAMo6B,SACJx6B,MAQXm6I,KAAM,SAAU/tI,YACLpM,KAAKi6I,SAAS7tI,MAQzBilE,MAAO,SAAUjiC,aACR4nC,KAAO5nC,WACP4nC,KAAO,IAEPh3E,KAAK+5I,iBACE/5I,KAAKI,MAAMwM,OAAO,YAAa,EAAEwiC,MAAQ1iC,KAAKiV,GAAK,IAAK3hB,KAAKi9C,QAAS,CAACpyC,KAAM,WACnF6mF,UAAU1xF,KAAKw7I,qBAGhBp7I,MAAMo6B,SACJx6B,MAQXwR,KAAM,SAAU49B,cACLpvC,KAAKqxE,OAAOjiC,QAOvBirG,MAAO,uBACEkB,WAAY,EACVv7I,MAOXu6I,QAAS,uBACAgB,WAAY,OACZliG,MAAQr5C,KAAKI,MAAMwM,OAAO,QAAS,CAAC,CAAC5M,KAAK67C,IAAI,IAAK,CAAC77C,KAAK67C,IAAI,KAAM77C,KAAKg6I,kBACxEtwI,QAAQhO,KAAKsE,KAAKq5C,OAEhBr5C,MAOX06I,MAAO,eACCpgJ,EAAG+T,OAEF/T,EAAI,EAAGA,EAAI0F,KAAK0J,QAAQ7O,OAAQP,KACjC+T,GAAKrO,KAAK0J,QAAQpP,IACXuQ,OAASrB,MAAMjH,yBACbnC,MAAMs2F,aAAaroF,SACnB3E,QAAQvO,OAAOb,EAAG,gBAI1B++C,MAAQr5C,KAAKI,MAAMwM,OAAO,QAAS,CAAC,CAAC5M,KAAK67C,IAAI,IAAK,CAAC77C,KAAK67C,IAAI,KAAM77C,KAAKg6I,kBACxEtwI,QAAQhO,KAAKsE,KAAKq5C,YAClBj5C,MAAMo6B,SAEJx6B,MAOXw6I,YAAa,eACLlgJ,EAAG+T,GACHjC,IAAMpM,KAAK0J,QAAQ7O,WAElBP,EAAI,EAAGA,EAAI8R,IAAK9R,IACjB+T,GAAKrO,KAAK0J,QAAQpP,QACb8F,MAAMs2F,aAAaroF,gBAGvB0Q,KAAK,EAAG,EAAG,IACT/e,MASX26I,OAAQ,SAAU7sI,EAAGiT,UAGbzN,KAAKlJ,QAAQ0D,QACR+tC,IAAM/tC,OAEN+tC,IAAM,CAAC/tC,EAAGiT,GAGd/gB,KAAK+5I,sBACD98F,OAAO60C,oBAAoBtoF,MAAM1H,eAAgB,CAACgM,EAAGiT,SACrDy6H,QAAQ1pD,oBAAoBtoF,MAAM1H,eAAgB,CAACgM,EAAGiT,EAAI/gB,KAAKs7I,WAChEt7I,KAAKI,MAAMwM,OAAO,YAAa,GAAG5M,KAAKg3E,IAAM,IAAMtqE,KAAKiV,GAAK,IAAK3hB,KAAKi9C,QAAS,CAACpyC,KAAM,WACzF6mF,UAAU1xF,KAAKw7I,eAGhBniG,MAAQr5C,KAAKI,MAAMwM,OAAO,QAAS,CAAC,CAAC5M,KAAK67C,IAAI,IAAK,CAAC77C,KAAK67C,IAAI,KAAM77C,KAAKg6I,kBACxEtwI,QAAQhO,KAAKsE,KAAKq5C,YAClBj5C,MAAMo6B,SAEJx6B,MASXy7I,WAAY,SAAUhiH,kBAEb4f,MAAQr5C,KAAKI,MAAMwM,OAAO,QAAS,CAAC,CAAC5M,KAAK67C,IAAI,IAAK,CAAC77C,KAAK67C,IAAI,KAAM77C,KAAK07I,SAAS,cAAejiH,YAChG/vB,QAAQhO,KAAKsE,KAAKq5C,OAChBr5C,MASX27I,YAAa,SAAU3yE,mBACd3vB,MAAQr5C,KAAKI,MAAMwM,OAAO,QAAS,CAAC,CAAC5M,KAAK67C,IAAI,IAAK,CAAC77C,KAAK67C,IAAI,KAAM77C,KAAK07I,SAAS,cAAe1yE,aAChGt/D,QAAQhO,KAAKsE,KAAKq5C,OAEhBr5C,MASX47I,qBAAsB,SAAU5yE,mBAEvB3vB,MAAQr5C,KAAKI,MAAMwM,OAAO,QAAS,CAAC,CAAC5M,KAAK67C,IAAI,IAAK,CAAC77C,KAAK67C,IAAI,KAAM77C,KAAK07I,SAAS,uBAAwB1yE,aACzGt/D,QAAQhO,KAAKsE,KAAKq5C,OAChBr5C,MASXklF,aAAc,SAAUj5E,gBAChB3R,EAAG+T,GAAIb,IACPpB,IAAMpM,KAAK0J,QAAQ7O,WAElBP,EAAI,EAAGA,EAAI8R,IAAK9R,KACjB+T,GAAKrO,KAAK0J,QAAQpP,IACXuQ,OAASrB,MAAMjH,mBAClB8L,GAAG62E,aAAaj5E,mBAKxBuB,IAAMxN,KAAK+S,QAAQ5V,QACd4V,QAAUO,KAAK3D,SAAS3P,KAAKq5C,MAAMtmC,cACnCA,QAAQ5V,GAAKqQ,SACbwsI,YAAc1mI,KAAK3D,SAAS3P,KAAK+S,gBAC/B/S,KAAKg6I,YAAY78I,GAEjB6C,MAUX07I,SAAU,SAAUnrI,IAAK5F,iBAChBqvI,YAAYzpI,IAAI7R,eAAiBiM,IAC/B3K,KAAKg6I,aAOhBe,WAAY,uBACHhB,gBAAiB,OACjB/sE,MAAMkY,aAAa,CAACjzE,SAAS,SAC7Bc,QAAQi6D,MAAM/6D,SAAU,OACxB0oI,OAAO36I,KAAK67C,IAAI,GAAI77C,KAAK67C,IAAI,SAC7Bz7C,MAAMo6B,SAEJx6B,MAOX66I,WAAY,uBACHd,gBAAiB,OACjB/sE,MAAMkY,aAAa,CAACjzE,SAAS,SAC7Bc,QAAQi6D,MAAM/6D,SAAU,OACxB7R,MAAMo6B,SAEJx6B,MAOX46I,KAAM,uBACG/+F,IAAM,CAAC,EAAG,QACV8+F,OAAO36I,KAAK67C,IAAI,GAAI77C,KAAK67C,IAAI,IAE3B77C,MAOXk7I,WAAY,uBACH15I,MAAM9F,KAAK,CAACsE,KAAK67C,IAAI,GAAI77C,KAAK67C,IAAI,GAAI77C,KAAKg3E,MAEzCh3E,MAQXm7I,UAAW,eACH5zG,OAASvnC,KAAKwB,MAAMilC,kBACnBoV,IAAI,GAAKtU,OAAO,QAChBsU,IAAI,GAAKtU,OAAO,QAChByvC,IAAMzvC,OAAO,QACbozG,OAAO36I,KAAK67C,IAAI,GAAI77C,KAAK67C,IAAI,IAE3B77C,MAUXo7I,OAAQ,SAAUvuD,YACVr9C,GAAIC,GAAIC,GAAIC,GAAIzc,YAEhB5f,KAAKlJ,QAAQyiF,SACbr9C,GAAKxvC,KAAK67C,IAAI,GACdpM,GAAKzvC,KAAK67C,IAAI,GACdnM,GAAKm9C,OAAO,GACZl9C,GAAKk9C,OAAO,GAGZ35D,KAAOxmB,KAAKypB,MAAMwZ,GAAKF,GAAIC,GAAKF,SAC3B6hC,MAAMrxE,KAAKg3E,IAAc,IAAP9jD,KAAaxmB,KAAKiV,KAClCrO,KAAKrJ,SAAS4iF,cAChBxb,MAAMrxE,KAAKg3E,IAAM6V,QAEnB7sF,MASX05F,OAAQ,SAAU7M,YACV/tD,GAAIiC,GAAI7nB,SAER5F,KAAKlJ,QAAQyiF,UACb/tD,GAAK+tD,OAAO,GAAK7sF,KAAK67C,IAAI,GAC1B9a,GAAK8rD,OAAO,GAAK7sF,KAAK67C,IAAI,GAErB77C,KAAK+5I,kBACN7gI,EAAIlZ,KAAKI,MAAMwM,OAAO,YAAa,CAACkyB,GAAIiC,IAAK,CAACl2B,KAAM,eAClD6mF,UAAU1xF,KAAKi9C,QACjB/jC,EAAEw4E,UAAU1xF,KAAKw7I,UAGjBx7I,KAAKu7I,WAEDv7I,KAAKq5C,MAAMlY,MAAMtmC,QAAU,YACtBw+C,MAAQr5C,KAAKI,MAAMwM,OAAO,QAAS,CAAC,CAAC5M,KAAK67C,IAAI,IAAK,CAAC77C,KAAK67C,IAAI,KAAM77C,KAAKg6I,kBACxEtwI,QAAQhO,KAAKsE,KAAKq5C,aAI1BwC,IAAI,GAAKgxC,OAAO,QAChBhxC,IAAI,GAAKgxC,OAAO,GAEjB7sF,KAAKu7I,iBACAliG,MAAMlY,MAAMzlC,KAAKsE,KAAK67C,IAAI,SAC1BxC,MAAMjY,MAAM1lC,KAAKsE,KAAK67C,IAAI,UAE9Bz7C,MAAMo6B,UAGRx6B,MAMXk6I,GAAI,SAAU9tI,YAAcpM,KAAKi6I,QAAQ7tI,MAIzCguI,GAAI,SAAUhuI,YAAcpM,KAAKm6I,KAAK/tI,MAItC8W,GAAI,SAAUksB,cAAgBpvC,KAAKwR,KAAK49B,QAIxClJ,GAAI,SAAUkJ,cAAgBpvC,KAAKqxE,MAAMjiC,QAIzCkrG,GAAI,kBAAqBt6I,KAAKq6I,SAI9BpN,GAAI,kBAAqBjtI,KAAKu6I,WAI9BO,GAAI,kBAAqB96I,KAAK66I,cAI9BrgI,GAAI,kBAAqBxa,KAAK+6I,cAI9BN,GAAI,kBAAqBz6I,KAAKw6I,eAI9B9+I,KAAM,kBAAqBsE,KAAKk7I,cAIhCz0G,IAAK,kBAAqBzmC,KAAKm7I,aAS/BU,OAAQ,SAAU3iI,EAAG2c,QACbv7B,EAAGC,EAAG8T,GAAIozC,GACVr1C,IAAMpM,KAAK0J,QAAQ7O,WAElBP,EAAI,EAAGC,EAAI,EAAGD,EAAI8R,IAAK9R,QACxB+T,GAAKrO,KAAK0J,QAAQpP,IAEXmQ,eAAiBjB,MAAMrF,mBAAoB,IAC1C5J,GAAK2e,GAAKA,EAAI3e,EAAI8T,GAAGkpC,oBACrBkK,GAAMvoC,EAAI3e,EACH8T,GAAGwnB,IAAI4rB,IAElBlnD,GAAK8T,GAAGkpC,oBAITv3C,KAAK61B,OAShBuI,EAAG,SAAUllB,UACJ5F,KAAKzU,OAAOqa,GAIVlZ,KAAK67I,OAAO3iI,EAAG,KAHXlZ,KAAK67C,IAAI,IAYxBxd,EAAG,SAAUnlB,UACJ5F,KAAKzU,OAAOqa,GAGVlZ,KAAK67I,OAAO3iI,EAAG,KAFXlZ,KAAK67C,IAAI,IAQxBW,EAAG,SAAUtjC,UACF,GAMXi+B,KAAM,kBACK,GAOXD,KAAM,eACE58C,EACA8R,IAAMpM,KAAK0J,QAAQ7O,OACnBwuC,GAAK,MAEJ/uC,EAAI,EAAGA,EAAI8R,IAAK9R,IACZ0F,KAAK0J,QAAQpP,GACXmQ,eAAiBjB,MAAMrF,qBAC1BklC,IAAMrpC,KAAK0J,QAAQpP,GAAGi9C,qBAGvBlO,IASX2rC,SAAU,SAAUlnE,EAAGiT,OACfzmB,EAAG+T,OAGF/T,EAAI,EAAGA,EAAI0F,KAAK0J,QAAQ7O,OAAQP,QACjC+T,GAAKrO,KAAK0J,QAAQpP,IAEXuQ,OAASrB,MAAMjH,mBACd8L,GAAG2mE,SAASlnE,EAAGiT,UAER,SAKZ,KAkBf3iB,IAAI09I,aAAe,SAAU17I,MAAO4L,QAASC,gBACrCI,YACJL,QAAUA,SAAW,GAErBK,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,UAC/C,IAAIrO,IAAI07I,OAAO15I,MAAO4L,QAASK,OAG1CjO,IAAIsB,gBAAgB,SAAUtB,IAAI09I,cAE3B,CACHhC,OAAQ17I,IAAI07I,OACZgC,aAAc19I,IAAI09I,iBA0D1B1jJ,OAAO,aAAa,CAChB,MAAO,YAAa,gBAAiB,gBAAiB,iBAAkB,eAAgB,cAAe,aAAc,cACtH,SAAUgG,IAAK8lB,IAAKirB,SAAUha,SAAU3rB,MAAOulF,gBAAiB5qE,OAAQ7Q,KAAMksF,aAe7EphG,IAAI29I,MAAQ,SAAU1rG,KAAM69B,MAAOjiE,oBAC1BuE,YAAY6/B,KAAKjwC,MAAO6L,WAAYzC,MAAMpH,kBAAmBoH,MAAMnF,yBAMnEgsC,KAAOA,UAMPjwC,MAAQJ,KAAKqwC,KAAKjwC,WAMlBq0F,cAAgB,UAMhBunD,WAAa,UAMbC,aAAc,OAEdC,WAAa,GAEd5oI,KAAKnJ,WAAW+jE,kBACXumB,cAAgBvmB,MACf,IAAIlyE,MAAM,+CAGhBsX,KAAKlJ,QAAQ8jE,YACR8tE,WAAa9tE,QAEdxhE,KAAKwC,IAAIg/D,OAAShqD,IAAIzF,KAAOyvD,MAAQ,KACrCA,MAAQjiE,WAAWkwI,sBAOlB1nD,cAAgBz0F,KAAK00F,kBAAkBxmB,YAEvC+tE,aAAc,QAOlBhoE,iBAAmBhoE,WAAWmwI,sBAM9BluE,MAAQ,QAMR8oB,WAAa,OAQb1iB,OAAS,QAMT+nE,UAAY,QAMZC,aAAe,OAEfn/I,GAAK6C,KAAKqwC,KAAKigD,SAAStwF,WACxB0vF,OAAS,aACTG,SAASn0F,KAAKsE,KAAKs0E,aACnBl0E,MAAMw/F,MAAM5/F,KAAM,OAG3B5B,IAAI29I,MAAM7iJ,UAAY,IAAI61F,gBAE1B3wF,IAAIC,OAAOD,IAAI29I,MAAM7iJ,UAA6C,CAW9Dw7F,kBAAmB,SAAUxmB,cAClB,eACC36C,MAAO7yB,EAAGglC,YAEVpyB,KAAKrG,SAASjN,KAAK+S,QAAQwpI,eAE3B72G,MADAhlC,EAAIV,KAAKw8I,uBAAuBx8I,KAAKy8I,qBAAsB,kBAClD9qH,MAAQjxB,EAAEg8I,QAGP,GADZnpH,MAAQ7mB,KAAKsV,IAAI,GAAItV,KAAKmS,MAAMnS,KAAKpL,IAAI,GAAMokC,MAAQh5B,KAAKiwI,UAExDppH,OAAS,IAENA,OAIJ26C,QAWf8G,SAAU,SAAUlnE,EAAGiT,OACfzmB,EAAG4e,EAEH1J,EAAG3E,KADHuB,IAAOpM,KAAKkuE,OAASluE,KAAKkuE,MAAMrzE,QAAW,KAG3CyY,KAAK/I,SAAS+I,KAAKrG,SAASjN,KAAK+S,QAAQwgE,aACzC1oE,KAAO7K,KAAKI,MAAM4/F,aAClBxwF,EAAI8D,KAAKrG,SAASjN,KAAK+S,QAAQwgE,UAAU1oE,QAGzC2E,EAAIxP,KAAKI,MAAMqM,QAAQ8mE,UAAUyB,SAErCxlE,GAA+C,GAA1C8D,KAAKrG,SAASjN,KAAK+S,QAAQlB,cAC3ByB,KAAKrG,SAASjN,KAAKqwC,KAAKt9B,QAAQsgE,WACjCrzE,KAAKqwC,KAAK5lC,eAAiBjB,MAAMrF,0BAC1B,KAIkB,IAAzBnE,KAAKqwC,KAAKzsB,QAAQ,IAAqC,IAAzB5jB,KAAKqwC,KAAKzsB,QAAQ,IAAY5jB,KAAKqwC,KAAKxlC,OAASrB,MAAMtH,wBAC9E,MAGN5H,EAAI,EAAGA,EAAI8R,IAAK9R,QACjB4e,EAAIlZ,KAAKkuE,MAAM5zE,IAGT,MAE8B,IAAzB0F,KAAKqwC,KAAKzsB,QAAQ,IAAYlX,KAAKwC,IAAIgK,EAAE,GAAG,GAAKlZ,KAAKqwC,KAAKK,OAAO7iC,OAAO0W,UAAU,IAAML,IAAIzF,KAClE,IAAzBze,KAAKqwC,KAAKzsB,QAAQ,IAAYlX,KAAKwC,IAAIgK,EAAE,GAAG,GAAKlZ,KAAKqwC,KAAKK,OAAO7iC,OAAO0W,UAAU,IAAML,IAAIzF,OAE9F/R,KAAKwC,IAAIgK,EAAE,GAAG,GAAKA,EAAE,GAAG,KAAO,GAAKxM,KAAKwC,IAAIgK,EAAE,GAAG,GAAKA,EAAE,GAAG,KAAO,MACtC,IAAzBlZ,KAAKqwC,KAAKzsB,QAAQ,OAEdlX,KAAKwC,IAAI6R,EAA0B,IAArB7H,EAAE,GAAG,GAAKA,EAAE,GAAG,KAAa,EAAI1J,GAAK0J,EAAE,GAAG,GAAK1J,EAAI1B,GAAKA,EAAIoL,EAAE,GAAG,GAAK1J,SAC7E,OAER,GAA6B,IAAzBxP,KAAKqwC,KAAKzsB,QAAQ,IACrBlX,KAAKwC,IAAIpB,EAA0B,IAArBoL,EAAE,GAAG,GAAKA,EAAE,GAAG,KAAa,EAAI1J,GAAK0J,EAAE,GAAG,GAAK1J,EAAIuR,GAAKA,EAAI7H,EAAE,GAAG,GAAK1J,SAC7E,SAQxB,GAUXsiF,oBAAqB,SAAU1tE,OAAQvW,OAAQkkF,eACvCjzD,GAAIiC,GACJnxB,EAAI,IAAIuU,OAAOC,OAAQvW,OAAQ7N,KAAKI,OACpC4xF,KAAO,IAAI7tE,OAAOC,OAAQ2tE,UAAW/xF,KAAKI,OAC1Cu5C,GAAK35C,KAAKI,MAAMkzC,wBAEhBtzC,KAAKqwC,KAAKxlC,OAASrB,MAAMtH,kBACxBoR,KAAKrG,SAASjN,KAAKqwC,KAAKt9B,QAAQsgE,WAKjC3mE,KAAKwC,IAAIlP,KAAKqwC,KAAKzsB,QAAQ,IAAMM,IAAIzF,KACrC/R,KAAKwC,IAAIU,EAAE5B,UAAU,GAAKgkF,KAAKhkF,UAAU,IAAMkW,IAAIzF,KAGnDqgB,GAAKkzD,KAAKhkF,UAAU,GAAK4B,EAAE5B,UAAU,GACrC2rC,GAAG,IAAM7a,GACT6a,GAAG,IAAM7a,QACJ1+B,MAAMi3G,eAAe19D,GAAI35C,KAAKI,MAAMw0G,gBAAiB,WAEnDloG,KAAKwC,IAAIlP,KAAKqwC,KAAKzsB,QAAQ,IAAMM,IAAIzF,KACrC/R,KAAKwC,IAAIU,EAAE5B,UAAU,GAAKgkF,KAAKhkF,UAAU,IAAMkW,IAAIzF,MAG1DsiB,GAAKixD,KAAKhkF,UAAU,GAAK4B,EAAE5B,UAAU,GACrC2rC,GAAG,IAAM5Y,GACT4Y,GAAG,IAAM5Y,QACJ3gC,MAAMi3G,eAAe19D,GAAI35C,KAAKI,MAAMw0G,gBAAiB,WAGvD50G,MAtBIA,MA6Bf48I,0BAA2B,eACnBC,WAAYtnD,OACZunD,MAAOnjG,QAEP35C,KAAKqwC,KAAK5lC,eAAiBjB,MAAMvF,yBAE5B84I,wBAGDrwI,KAAKwC,IAAIlP,KAAK8+B,IAAM5a,IAAIzF,KACxB/R,KAAKwC,IAAIlP,KAAK+gC,IAAM7c,IAAIzF,aAMhCo+H,WAAa78I,KAAKy8I,qBAKdlnD,OADAv1F,KAAKqwC,KAAK5lC,eAAiBjB,MAAMvF,kBACxBjE,KAAKw8I,uBAAuBK,YAE5B,CACLH,MAAO18I,KAAKqwC,KAAK8G,OACjBxlB,MAAO3xB,KAAKqwC,KAAK6G,QAIgB,UAArC5jC,KAAKrG,SAASjN,KAAK+S,QAAQlI,QAC3B8uC,GAAK35C,KAAKI,MAAMkzC,iBAChBwpG,MAAQpwI,KAAKiS,IAAIjS,KAAKmU,KAAK84B,GAAG,GAAKA,GAAG,GAAKA,GAAG,GAAKA,GAAG,IAClDjtC,KAAKmU,KAAK84B,GAAG,GAAKA,GAAG,GAAKA,GAAG,GAAKA,GAAG,KACzC47C,OAAO5jE,MAAQmrH,YAId5uE,MAAQ,QACRguE,WAAa,GAEdl8I,KAAKi8I,iBACAe,yBAAyBH,WAAYtnD,aAErC0nD,mBAAmBJ,WAAYtnD,QAGjCv1F,MAQX+8I,sBAAuB,SAAUlhG,SACzB1wC,EAAGs0C,GAAIt/B,GAAI/T,IACX8wI,QAAoD,GAA1C5pI,KAAKrG,SAASjN,KAAK+S,QAAQ+rE,aACrCq+D,QAAoD,GAA1C7pI,KAAKrG,SAASjN,KAAK+S,QAAQ8rE,aAGrCvrE,KAAKzU,OAAOg9C,MACZ4D,GAAKz/C,KAAKqwC,KAAK8G,OACfh3B,GAAKngB,KAAKqwC,KAAK6G,QACf9qC,IAAMpM,KAAKqwC,KAAK9jC,OAAO1R,QACb,QACDuiJ,MAAQ,OACRC,MAAQ,GACNn5H,IAAIxF,OAAOm9B,IAAK4D,IAAMv7B,IAAIzF,UAC5B2+H,MAAQp9I,KAAKqwC,KAAK9jC,OAAO,GAAGyB,UAAU,GAAKhO,KAAKqwC,KAAK9jC,OAAO,GAAGyB,UAAU,QACzEqvI,MAAQr9I,KAAKqwC,KAAK9jC,OAAO,GAAGyB,UAAU,GAAKhO,KAAKqwC,KAAK9jC,OAAO,GAAGyB,UAAU,IACvEkW,IAAIxF,OAAOm9B,IAAK17B,IAAM+D,IAAIzF,UAC5B2+H,MAAQp9I,KAAKqwC,KAAK9jC,OAAOH,IAAM,GAAG4B,UAAU,GAAKhO,KAAKqwC,KAAK9jC,OAAOH,IAAM,GAAG4B,UAAU,QACrFqvI,MAAQr9I,KAAKqwC,KAAK9jC,OAAOH,IAAM,GAAG4B,UAAU,GAAKhO,KAAKqwC,KAAK9jC,OAAOH,IAAM,GAAG4B,UAAU,UAErFovI,OAASjoH,SAAS+H,EAAEl9B,KAAKqwC,KAAKhS,EAArBlJ,CAAwB0mB,UACjCwhG,MAAQloH,SAAS+H,EAAEl9B,KAAKqwC,KAAKjS,EAArBjJ,CAAwB0mB,aAIpCuhG,MAAQp9I,KAAKqwC,KAAKzsB,QAAQ,QAC1By5H,MAAQr9I,KAAKqwC,KAAKzsB,QAAQ,SAE9B05H,MAAQt9I,KAAKo9I,WACbG,MAAQv9I,KAAKq9I,WAGbv+G,GAAK9+B,KAAKo9I,WACVr8G,GAAK/gC,KAAKq9I,MAGflyI,EAAIuB,KAAKmU,KACL7gB,KAAKo9I,MAAQp9I,KAAKo9I,MAAQp9I,KAAKI,MAAM2kB,MAAQ/kB,KAAKI,MAAM2kB,MACpD/kB,KAAKq9I,MAAQr9I,KAAKq9I,MAAQr9I,KAAKI,MAAM4kB,MAAQhlB,KAAKI,MAAM4kB,YAE3Do4H,OAASF,QAAU/xI,EAAInL,KAAKI,MAAM2kB,WAClCs4H,OAASH,QAAU/xI,EAAInL,KAAKI,MAAM4kB,WAClCs4H,OAASH,QAAUhyI,EAAInL,KAAKI,MAAM2kB,WAClCw4H,OAASJ,QAAUhyI,EAAInL,KAAKI,MAAM4kB,WAGlCw4H,SAAWlqI,KAAKrG,SAASjN,KAAK+S,QAAQ8rE,aAAe,EAAK,WAAa,cACvE4+D,SAAWnqI,KAAKrG,SAASjN,KAAK+S,QAAQ+rE,aAAe,EAAK,WAAa,UAchF29D,mBAAoB,eACZjxB,IAAKC,IAAKiyB,IAAKhyB,IAAKC,IAAKgyB,IAAQl+F,GAAIt/B,GACrCu8E,KAAOppF,KAAKrG,SAASjN,KAAK+S,QAAQghE,eAElC/zE,KAAKqwC,KAAK5lC,eAAiBjB,MAAMvF,kBAC7BjE,KAAKqwC,KAAKxlC,OAASrB,MAAMtH,iBAClBitC,SAASqE,mBAAmB,CAC/B3lC,OAAQ,CACJG,UAAW,CAAC,EAAG,EAAG,KAEvBhO,KAAKqwC,KAAMrwC,KAAKI,QAEvBs9I,IAAM19I,KAAKqwC,KAAKK,OAAO7iC,OAAOG,UAAU,GACxCw9G,IAAMxrH,KAAKqwC,KAAKK,OAAO7iC,OAAOG,UAAU,GACxCy9G,IAAMzrH,KAAKqwC,KAAKK,OAAO7iC,OAAOG,UAAU,GACxC2vI,IAAM39I,KAAKqwC,KAAKO,OAAO/iC,OAAOG,UAAU,GACxC09G,IAAM1rH,KAAKqwC,KAAKO,OAAO/iC,OAAOG,UAAU,GACxC29G,IAAM3rH,KAAKqwC,KAAKO,OAAO/iC,OAAOG,UAAU,GAE3B,UAAT0uF,KACO18F,KAAKqwC,KAAKO,OAAO/iC,OAEf,WAAT6uF,KACO,IAAIv4E,OAAO3a,MAAM1H,eAAgB,CACtB,IAAb47I,IAAMC,KACO,IAAbnyB,IAAME,KACO,IAAbD,IAAME,MACR3rH,KAAKI,OAERkT,KAAKrJ,SAASyyF,MACP,IAAIv4E,OAAO3a,MAAM1H,eAAgB,CACpC47I,KAAOC,IAAMD,KAAOhhD,KACpB8uB,KAAOE,IAAMF,KAAO9uB,KACpB+uB,KAAOE,IAAMF,KAAO/uB,MACrB18F,KAAKI,OAELJ,KAAKqwC,KAAKK,OAAO7iC,SAE5B4xC,GAAKz/C,KAAKqwC,KAAK8G,OACfh3B,GAAKngB,KAAKqwC,KAAK6G,OACF,UAATwlD,KACIv8E,GACY,WAATu8E,KACS,IAAXj9C,GAAKt/B,IACH7M,KAAKrJ,SAASyyF,MACjBj9C,IAAM,EAAIi9C,MAAQv8E,GAAKu8E,KAGvBj9C,KAmBZ+8F,uBAAwB,SAAUK,WAAYhyI,UACtC+yI,WAAYC,WACZC,GAAIC,GACJrtG,OAAQE,OAAQotG,gBAAiBC,gBAEjCC,YAAaC,YACb3mG,MAAQlkC,KAAKrG,SAASjN,KAAKqwC,KAAKt9B,QAAQ6/B,eACxC6E,MAAQnkC,KAAKrG,SAASjN,KAAKqwC,KAAKt9B,QAAQ8/B,cACxCurG,KAAO9qI,KAAKrG,SAASjN,KAAK+S,QAAQsrI,0BAGlCr+I,KAAKqwC,KAAK5lC,eAAiBjB,MAAMrF,mBAC1B,CACHu4I,MAAO18I,KAAKqwC,KAAK8G,OACjBxlB,MAAO3xB,KAAKqwC,KAAK6G,SAIzBxG,OAAS,IAAIvsB,OAAO3a,MAAM1H,eAAgB9B,KAAKqwC,KAAKK,OAAO7iC,OAAOG,UAAWhO,KAAKI,OAClFwwC,OAAS,IAAIzsB,OAAO3a,MAAM1H,eAAgB9B,KAAKqwC,KAAKO,OAAO/iC,OAAOG,UAAWhO,KAAKI,OAElF49I,gBAAmBtxI,KAAKwC,IAAIwhC,OAAO1iC,UAAU,KAAOkW,IAAIzF,KACpDiyB,OAAOnsB,UAAU,IAAM,GAAOmsB,OAAOnsB,UAAU,IAAMvkB,KAAKI,MAAM0yC,aAChEpC,OAAOnsB,UAAU,IAAM,GAAOmsB,OAAOnsB,UAAU,IAAMvkB,KAAKI,MAAM2yC,aACpEkrG,gBAAmBvxI,KAAKwC,IAAI0hC,OAAO5iC,UAAU,KAAOkW,IAAIzF,KACpDmyB,OAAOrsB,UAAU,IAAM,GAAOqsB,OAAOrsB,UAAU,IAAMvkB,KAAKI,MAAM0yC,aAChElC,OAAOrsB,UAAU,IAAM,GAAOqsB,OAAOrsB,UAAU,IAAMvkB,KAAKI,MAAM2yC,aAGhEz/B,KAAKzU,OAAOgM,OAAkB,iBAATA,KAGrBskC,SAASiD,aAAapyC,KAAKqwC,KAAMK,OAAQE,OAAQt9B,KAAKrG,SAASjN,KAAKqwC,KAAKt9B,QAAQs/B,SAIjFlD,SAASgE,yBAAyBnzC,KAAKqwC,KAAMK,OAAQE,QAIzDktG,GAAKxqI,KAAKrG,SAASjN,KAAKqwC,KAAKt9B,QAAQ1B,YACrC0sI,GAAKzqI,KAAKrG,SAASjN,KAAKqwC,KAAKt9B,QAAQxB,YACjCusI,IAAMC,WACD39I,MAAMmvE,SAASgU,qBAAqBvjF,KAAKqwC,KAAMK,OAAQE,OACpDt9B,KAAKrG,SAASjN,KAAKqwC,KAAKt9B,QAAQlB,cAEpCisI,IACAptG,OAAOlsB,eAAehb,MAAMzH,iBAAkB,CAC1C2uC,OAAOnsB,UAAU,GACjBmsB,OAAOnsB,UAAU,KAGrBw5H,IACAntG,OAAOpsB,eAAehb,MAAMzH,iBAAkB,CAC1C6uC,OAAOrsB,UAAU,GACjBqsB,OAAOrsB,UAAU,OAmB7B25H,YAAcl+I,KAAKgzI,oBAAoB6J,WAAYnsG,UACnDytG,YAAcn+I,KAAKgzI,oBAAoB6J,WAAYjsG,UAM/CgtG,WAAaM,YACR1mG,QAASwmG,iBAAoBI,OAC9BR,YAAc15H,IAAIzF,KAEtBo/H,WAAaM,YACR1mG,QAASwmG,iBAAoBG,OAC9BP,YAAc35H,IAAIzF,MAEf0/H,YAAcD,aACrBN,WAAaO,YACR1mG,QAASwmG,iBAAoBG,OAC9BR,YAAc15H,IAAIzF,KAEtBo/H,WAAaK,YACR1mG,QAASwmG,iBAAoBI,OAC9BP,YAAc35H,IAAIzF,OAGtBm/H,WAAa,EACbC,WAAa,GAGV,CACHnB,MAAOkB,WACPjsH,MAAOksH,cAcf7K,oBAAqB,SAAUF,KAAMxiG,WAC7ByB,GAAIC,GACJssG,QAASC,SACTp5H,gBAEJ4sB,GAAK/xC,KAAKqwC,KAAKK,OAAO7iC,OACtBmkC,GAAKhyC,KAAKqwC,KAAKO,OAAO/iC,OACtBsX,SAAW2tH,KAAK3tH,SAAS3b,MAAM1H,eAAgBwuC,OAG/CguG,QAAU,CAACtsG,GAAGhkC,UAAU,GAAK+jC,GAAG/jC,UAAU,GACtCgkC,GAAGhkC,UAAU,GAAK+jC,GAAG/jC,UAAU,GAC/BgkC,GAAGhkC,UAAU,GAAK+jC,GAAG/jC,UAAU,IACnCuwI,SAAW,CAACjuG,MAAMtiC,UAAU,GAAK8kI,KAAK9kI,UAAU,GAC5CsiC,MAAMtiC,UAAU,GAAK8kI,KAAK9kI,UAAU,GACpCsiC,MAAMtiC,UAAU,GAAK8kI,KAAK9kI,UAAU,IACpCkW,IAAI3D,aAAa+9H,QAASC,SAAU,GAAK,IACzCp5H,WAAa,GAGVA,UAWX63H,yBAA0B,SAAUH,WAAYtnD,YACxCipD,aAEAC,OADAC,KAAOx6H,IAAIzF,IAGXu4E,WAAch3F,KAAKi8I,YAAcj8I,KAAKy0F,cAAc,GAAKz0F,KAAKg3F,WAC9D2nD,MAAQrrI,KAAKrG,SAASjN,KAAK+S,QAAQwpI,aACnCqC,MAAQtrI,KAAKrG,SAASjN,KAAK+S,QAAQkkF,eAEnCj3F,KAAKqwC,KAAK5lC,eAAiBjB,MAAMvF,oBAEjCw6I,OAASz+I,KAAK6+I,kBAIlB7nD,YAAc1jF,KAAKrG,SAASjN,KAAK+S,QAAQ0I,OACrCkjI,OAAS3+I,KAAKi0E,iBAAmB/vD,IAAIzF,KACrCu4E,WAAah3F,KAAK8+I,mBAAmB9nD,WAAY6lD,WAAY4B,QAC7DznD,YAAe4nD,MAAQ,GACfD,QACR3nD,YAAe4nD,MAAQ,QAEtB5nD,WAAaA,aAEdA,WAAa9yE,IAAIzF,UAKrB+/H,aAAe,EACVlrI,KAAKrG,SAASjN,KAAK+S,QAAQgsI,YAC5BP,aAAexnD,YAEZwnD,cAAgBjpD,OAAO5jE,MAAQ+sH,OAE9BF,cAAgBjpD,OAAOmnD,MAAQgC,WAC1BM,oBAAoBnC,WAAY2B,aAAcxnD,WAAYynD,QAEnED,cAAgBxnD,aAGXzB,OAAO5jE,MAAQ6sH,aAA6B,IAAbxnD,mBAMxCwnD,cAAgBxnD,WACTwnD,cAAgBjpD,OAAOmnD,MAAQgC,OAE9BF,cAAgBjpD,OAAO5jE,MAAQ+sH,WAC1BM,oBAAoBnC,WAAY2B,aAAcxnD,WAAYynD,WAEnED,cAAgBxnD,YAGIzB,OAAOmnD,MAAsB,IAAb1lD,kBAgB5C8nD,mBAAoB,SAAU9nD,WAAY6lD,WAAY4B,YAC9CQ,GAAIC,GACJC,QACA/jG,IAAM,EACNgkG,SAAW9rI,KAAKrG,SAASjN,KAAK+S,QAAQkkF,eAEtCj3F,KAAKqwC,KAAK5lC,eAAiBjB,MAAMrF,0BAC1B6yF,cAEFh3F,KAAKw8I,uBAAuBK,WAAY,iBACjDoC,GAAKpC,WAAW7uI,UAAU,GAAKywI,OAAO3wI,EAAIkpF,WAC1CkoD,GAAKrC,WAAW7uI,UAAU,GAAKywI,OAAO19H,EAAIi2E,WAC1CmoD,QAAUtC,WAAW13H,SAAS3b,MAAMzH,iBAAkB,IAAIoiB,OAAO3a,MAAM1H,eAAgB,CAACm9I,GAAIC,IAAKl/I,KAAKI,QAEnF,IAAf42F,kBACO,OAGJmoD,SAAWC,SAAW,GAAKp/I,KAAKi0E,kBAE/B+iB,YADQ,IAAR57C,IACc,EAEA,EAElBA,MAAQ,EAER6jG,GAAKpC,WAAW7uI,UAAU,GAAKywI,OAAO3wI,EAAIkpF,WAC1CkoD,GAAKrC,WAAW7uI,UAAU,GAAKywI,OAAO19H,EAAIi2E,WAC1CmoD,QAAUtC,WAAW13H,SAAS3b,MAAMzH,iBAAkB,IAAIoiB,OAAO3a,MAAM1H,eAAgB,CAACm9I,GAAIC,IAAKl/I,KAAKI,eAEnG42F,YAaXgoD,oBAAqB,SAAUnC,WAAY2B,aAAcxnD,WAAYynD,YAC7D3wI,EAAGiT,EAAGs+H,WAAYlN,GAClBmN,SAAW,KAGXt/I,KAAKqwC,KAAK5lC,eAAiBjB,MAAMvF,mBACjC6J,EAAI+uI,WAAW7uI,UAAU,GAAKwwI,aAAeC,OAAO3wI,EACpDiT,EAAI87H,WAAW7uI,UAAU,GAAKwwI,aAAeC,OAAO19H,IAEpDjT,EAAI9N,KAAKqwC,KAAKjS,EAAEy+G,WAAa2B,cAC7Bz9H,EAAI/gB,KAAKqwC,KAAKhS,EAAEw+G,WAAa2B,eAEjCa,WAAa,IAAIl7H,OAAO3a,MAAM1H,eAAgB,CAACgM,EAAGiT,GAAI/gB,KAAKI,OACvDJ,KAAKqwC,KAAK5lC,eAAiBjB,MAAMrF,qBACjCm7I,SAAWzC,WAAa2B,kBACnBzB,sBAAsBuC,WAO/BD,WAAWz9I,MAAQ8K,KAAKyU,MAAMq9H,aAAexnD,aAAe1jF,KAAKrG,SAASjN,KAAK+S,QAAQkkF,YAAc,IAAO,EAK1F,KADlBk7C,GAAKnyI,KAAKu/I,eAAeF,WAAYA,WAAWz9I,QACzC/G,cACEqzE,MAAMxyE,KAAKy2I,IACZkN,WAAWz9I,OAAS0R,KAAKrG,SAASjN,KAAK+S,QAAQysI,iBAE1CtD,WAAWxgJ,KACZsE,KAAKy/I,kBACDz/I,KAAK0zE,kBAAkB2rE,WAAYxC,WAAYyC,UAC/CD,WACAr/I,KAAKkuE,MAAMrzE,cAKdqhJ,WAAWxgJ,KAAK,QAYjCuhJ,mBAAoB,SAAUJ,WAAYtnD,YAClC8pD,WAAYK,UAAWplJ,EAAG63I,GAC1BrkI,EAAGiT,EACa4+H,UAEhBlB,OAFAC,KAAOx6H,IAAIzF,IACXmhI,kBAAoBtsI,KAAKlJ,QAAQpK,KAAK+S,QAAQuhE,QAE9CurE,MAAQvsI,KAAKrG,SAASjN,KAAK+S,QAAQysI,gBAGnCx/I,KAAKqwC,KAAK5lC,eAAiBjB,MAAMvF,oBACjCw6I,OAASz+I,KAAK6+I,kBAEbvkJ,EAAI,EAAGA,EAAI0F,KAAKg8I,WAAWnhJ,OAAQP,IAChC0F,KAAKqwC,KAAK5lC,eAAiBjB,MAAMvF,mBACjC07I,UAAY3/I,KAAKg8I,WAAW1hJ,GAC5BwT,EAAI+uI,WAAW7uI,UAAU,GAAK2xI,UAAYlB,OAAO3wI,EACjDiT,EAAI87H,WAAW7uI,UAAU,GAAK2xI,UAAYlB,OAAO19H,IAEjD4+H,UAAY9C,WAAa78I,KAAKg8I,WAAW1hJ,GACzCwT,EAAI9N,KAAKqwC,KAAKjS,EAAEuhH,WAChB5+H,EAAI/gB,KAAKqwC,KAAKhS,EAAEshH,YAEpBN,WAAa,IAAIl7H,OAAO3a,MAAM1H,eAAgB,CAACgM,EAAGiT,GAAI/gB,KAAKI,OAEvDJ,KAAKqwC,KAAK5lC,eAAiBjB,MAAMrF,yBAC5B44I,sBAAsB4C,WAMb,KADlBxN,GAAKnyI,KAAKu/I,eAAeF,YAAY,IAC9BxkJ,QAAgB8kJ,WAAapqD,OAAOmnD,MAAQgC,MAC/CiB,WAAapqD,OAAO5jE,MAAQ+sH,YACvBxwE,MAAMxyE,KAAKy2I,IAEZ0N,QACKD,mBAAqBtsI,KAAKzU,OAAOmB,KAAK+S,QAAQuhE,OAAOh6E,MAC1DolJ,UAAYE,kBACItsI,KAAKrG,SAASjN,KAAK+S,QAAQuhE,OAAOh6E,IAAMqlJ,eACnDzD,WAAWxgJ,KACZsE,KAAKy/I,kBACDz/I,KAAK0zE,kBAAkB2rE,WAAYxC,WAAY6C,WAC/CL,WACA/kJ,UAIH4hJ,WAAWxgJ,KAAK,QAYrCmjJ,eAAgB,eAGRiB,gBAAiBC,gBACjB3sG,SAAWpzC,KAAKqwC,KAAKK,OAAO5P,KAAK9gC,KAAKqwC,KAAKO,eAE3C5wC,KAAKqwC,KAAKxlC,OAASrB,MAAMtH,kBAIzB49I,gBAAkB9/I,KAAKqwC,KAAKK,OAAO7iC,OAAOG,UAC1C+xI,gBAAkB//I,KAAKqwC,KAAKO,OAAO/iC,OAAOG,WAGtC8xI,gBAAgB,GAAKC,gBAAgB,IAChCrzI,KAAKwC,IAAI4wI,gBAAgB,GAAKC,gBAAgB,IAAM77H,IAAIzF,KACzDqhI,gBAAgB,GAAKC,gBAAgB,MACzCD,gBAAkB9/I,KAAKqwC,KAAKO,OAAO/iC,OAAOG,UAC1C+xI,gBAAkB//I,KAAKqwC,KAAKK,OAAO7iC,OAAOG,aAI9C8xI,gBAAkB9/I,KAAKqwC,KAAKK,OAAO7iC,OAAOG,UAC1C+xI,gBAAkB//I,KAAKqwC,KAAKO,OAAO/iC,OAAOG,WAEvC,CACHF,GAAIiyI,gBAAgB,GAAKD,gBAAgB,IAAM1sG,SAC/CryB,GAAIg/H,gBAAgB,GAAKD,gBAAgB,IAAM1sG,WAWvD4sG,gBAAiB,SAASlyI,EAAGiT,EAAGhT,OACxBozC,GAAKnhD,KAAKI,MAAM0yC,YAChBsO,GAAKphD,KAAKI,MAAM2yC,yBAEVn1C,IAANmQ,IACAA,EAAI,GAEAD,EAAE,IAAMC,GAAKD,EAAE,IAAMqzC,GAAKpzC,GAAKgT,EAAE,IAAMhT,GAAKgT,EAAE,IAAMqgC,GAAKrzC,GACxDD,EAAE,IAAMC,GAAKD,EAAE,IAAMqzC,GAAKpzC,GAAKgT,EAAE,IAAMhT,GAAKgT,EAAE,IAAMqgC,GAAKrzC,GAWtEwxI,eAAgB,SAAU1xI,OAAQjM,WAC1BgO,EAAGqwI,YAAahyH,aAChBiyH,IAAKC,IAAKC,IAAKC,IAAK70G,MACpBp0B,MAGA9c,EAAGkV,EAAUmqC,GAAI2mG,KAAM/sH,MAFvBzlB,EAAI,EAAE,KAAU,KAChBiT,EAAI,EAAE,KAAU,QAGpBnR,EAAI/B,OAAO0W,UACP3iB,OACAs+I,IAAMlgJ,KAAKo9I,MACX+C,IAAMngJ,KAAKq9I,MACXjmI,MAAQpX,KAAKy9I,WAEbyC,IAAMlgJ,KAAKs9I,MACX6C,IAAMngJ,KAAKu9I,MACXnmI,MAAQpX,KAAKw9I,UAEjByC,YAAc,EAAEE,IAAMvwI,EAAE,GAAKswI,IAAMtwI,EAAE,GAAIuwI,IAAKD,KAK1Ct+I,OAA8C,UAArC0R,KAAKrG,SAASjN,KAAK+S,QAAQlI,UAEpC8uC,GAAK35C,KAAKI,MAAMkzC,iBAEhB/f,OADA+sH,KAAO,EAAM5zI,KAAKiV,IACH,IAIf/R,EAAI/B,OAAOG,WACXwB,EAAI9C,KAAKmU,KAAKjR,EAAE,GAAKA,EAAE,GAAKA,EAAE,GAAKA,EAAE,KAC7BlD,KAAKiS,IAAIjS,KAAKmU,KAAK84B,GAAG,GAAKA,GAAG,GAAKA,GAAG,GAAKA,GAAG,IACtCjtC,KAAKmU,KAAK84B,GAAG,GAAKA,GAAG,GAAKA,GAAG,GAAKA,GAAG,KAEtC,KAEX7rC,EAAI,GACJiT,EAAI,GACCzmB,EAAI,EAAGA,GAAKgmJ,KAAMhmJ,GAAKi5B,MACxBzlB,EAAEpS,KAAKsE,KAAKI,MAAM0L,OAAOyY,UAAU,GAAK/U,EAAI9C,KAAK8hB,IAAIl0B,GAAK0F,KAAKI,MAAM2kB,OACrEhE,EAAErlB,KAAKsE,KAAKI,MAAM0L,OAAOyY,UAAU,GAAK/U,EAAI9C,KAAKwiB,IAAI50B,GAAK0F,KAAKI,MAAM4kB,aAElE,CAAClX,EAAGiT,EAAGnf,gBAKJ,aAAVwV,OACA6W,aAAekhB,SAAS6D,cAAcitG,YAAajgJ,KAAKI,OACxD0N,EAAE,GAAKmgB,aAAa,GAAG1J,UAAU,GACjCzW,EAAE,GAAKmgB,aAAa,GAAG1J,UAAU,GACjCxD,EAAE,GAAKkN,aAAa,GAAG1J,UAAU,GACjCxD,EAAE,GAAKkN,aAAa,GAAG1J,UAAU,KAG7BinB,MADqC,MAArCl4B,KAAKrG,SAASjN,KAAK+S,QAAQ0hE,MACnB/nE,KAAKiV,GAAG,EAC4B,MAArCrO,KAAKrG,SAASjN,KAAK+S,QAAQ0hE,OACrB/nE,KAAKiV,GAAG,EAEb,EAEZy+H,IAAM1zI,KAAK8hB,IAAIgd,OAAS00G,IAAMxzI,KAAKwiB,IAAIsc,OAAS20G,IAChDE,IAAM3zI,KAAKwiB,IAAIsc,OAAS00G,IAAMxzI,KAAK8hB,IAAIgd,OAAS20G,IAEhDryI,EAAE,GAAK8B,EAAE,GAAKwwI,IAAM9sI,KAAKrG,SAASjN,KAAK+S,QAAQwtI,YAAY,IAC3Dx/H,EAAE,GAAKnR,EAAE,GAAKywI,IAAM/sI,KAAKrG,SAASjN,KAAK+S,QAAQwtI,YAAY,IAC3DzyI,EAAE,GAAK8B,EAAE,GACTmR,EAAE,GAAKnR,EAAE,GAET47B,OAASA,MACT40G,IAAM1zI,KAAK8hB,IAAIgd,OAAS00G,IAAMxzI,KAAKwiB,IAAIsc,OAAS20G,IAChDE,IAAM3zI,KAAKwiB,IAAIsc,OAAS00G,IAAMxzI,KAAK8hB,IAAIgd,OAAS20G,IAEhDryI,EAAE,GAAK8B,EAAE,GAAKwwI,IAAM9sI,KAAKrG,SAASjN,KAAK+S,QAAQwtI,YAAY,IAC3Dx/H,EAAE,GAAKnR,EAAE,GAAKywI,IAAM/sI,KAAKrG,SAASjN,KAAK+S,QAAQwtI,YAAY,KAI3DvgJ,KAAKggJ,gBAAgBlyI,EAAGiT,SACjB,CAACjT,EAAGiT,EAAGnf,aAIf,IAUXqxI,gBAAiB,SAASn3I,WAClB4jJ,UACA1wI,OACAsmC,KAAOhiC,KAAKrG,SAASjN,KAAK+S,QAAQytI,oBAGlCltI,KAAKrJ,SAASnO,UACd4jJ,WAAahzI,KAAKyU,MAAc,KAARrlB,OAAiB,MAAOoO,YAClCrP,OAASyY,KAAKrG,SAASjN,KAAK+S,QAAQ0tI,kBACd,IAA5Bf,UAAUtjJ,QAAQ,QAEtB4S,OAASsE,KAAKrG,SAASjN,KAAK+S,QAAQ/D,QACU,IAA1CsE,KAAKrG,SAASjN,KAAK+S,QAAQwgE,YAA+B,IAAXvkE,SAE/CA,OAASsE,KAAKrG,SAASjN,KAAK+S,QAAQwgE,YAIxCmsE,UAAY5jJ,MAAM4kJ,cAAc1xI,QAAQ9E,YAGxCoJ,KAAKrG,SAASjN,KAAK+S,QAAQ4tI,iCAC3BjB,UAAY1/I,KAAK4gJ,gCAAgClB,YAGjDA,UAAUtjJ,QAAQ,MAAQ,IAAiC,IAA5BsjJ,UAAUtjJ,QAAQ,OAIjDsjJ,WAFAA,UAAYA,UAAU1kJ,QAAQ,MAAO,KAEfA,QAAQ,MAAO,MAGzC0kJ,UAAY5jJ,MAAMoO,WAGlBorC,KAAKz6C,OAAS,IACI,MAAd6kJ,UACAA,UAAYpqG,KACS,OAAdoqG,UACPA,UAAY,IAAMpqG,KACG,MAAdoqG,YACPA,WAAwBpqG,OAI5BhiC,KAAKrG,SAASjN,KAAK+S,QAAQ8tI,mBAC3BnB,UAAYA,UAAU1kJ,QAAQ,KAAM,MAEjC0kJ,WAUXkB,gCAAiC,SAASlB,kBAGN,IAA5BA,UAAUtjJ,QAAQ,KACXsjJ,WAII/nI,WAAW+nI,UAAUrjJ,UAAU,EAAGqjJ,UAAUtjJ,QAAQ,OACnDsjJ,UAAUrjJ,UAAUqjJ,UAAUtjJ,QAAQ,OAI1BpB,QAAQ,WAAW,SAASisF,MAAM2G,QACtDlrE,KAAO,aAGXA,MAASkrE,GACJ5yF,QAAQ,KAAM,KACdA,QAAQ,MAAO,IACfA,QAAQ,KAAK,KACbA,QAAQ,KAAK,KACbA,QAAQ,KAAK,KACbA,QAAQ,KAAK,KACbA,QAAQ,KAAK,KACbA,QAAQ,KAAK,KACbA,QAAQ,KAAK,KACbA,QAAQ,KAAK,KACbA,QAAQ,KAAK,KACbA,QAAQ,KAAK,SAiB1B04E,kBAAmB,SAAU8iB,KAAMs8C,KAAMh3I,WACtBqpB,aAGV7R,KAAKzU,OAAO/C,OAAQ,IACrBqpB,SAAWnlB,KAAKgzI,oBAAoBF,KAAMt8C,MACtC9pF,KAAKwC,IAAIiW,UAAYjB,IAAIzF,UAClB,IAEX3iB,MAAQqpB,SAAW7R,KAAKrG,SAASjN,KAAK+S,QAAQ0I,cAEtCzb,KAAKizI,gBAAgBn3I,QAarC2jJ,kBAAmB,SAAUC,UAAWlpD,KAAMsqD,gBACrCC,GAAIC,GAAIjzI,EAAGo5E,UAKfA,GAAK7zE,KAAKrG,SAASjN,KAAK+S,QAAQ7C,MAAMoB,UACtCyvI,GAAK,CAACvqD,KAAKjyE,UAAU,GAAIiyE,KAAKjyE,UAAU,IACxCy8H,GAAK,CAACxqD,KAAKjyE,UAAU,GAAIiyE,KAAKjyE,UAAU,IACxCxW,OAAYnQ,IAAPupF,GAAoB,GAAKA,GAC9Bp5E,GAAK,GACA/N,KAAKggJ,gBAAgBe,GAAIC,GAAIjzI,IAIlCgzI,GAAKztI,KAAKrG,SAASjN,KAAK+S,QAAQ7C,MAAM2V,OAAO,IAC7Cm7H,GAAK1tI,KAAKrG,SAASjN,KAAK+S,QAAQ7C,MAAM2V,OAAO,IAEtC,CACH/X,EAAG0oF,KAAKxoF,UAAU,GAAK+yI,GAAM/gJ,KAAKI,MAAM2kB,MACxChE,EAAGy1E,KAAKxoF,UAAU,GAAKgzI,GAAMhhJ,KAAKI,MAAM4kB,MACxC9L,EAAGwmI,UACHplJ,EAAGwmJ,aAVI,MAkBhBtmH,OAAQ,kBACAx6B,KAAKivF,aAG0B,IAA3BjvF,KAAKI,MAAM0yC,aAAiD,IAA5B9yC,KAAKI,MAAM2yC,mBACtC6pG,4BAaN58I,MAOXkzF,eAAgB,kBACPlzF,KAAKivF,aAINjvF,KAAKwhF,YAAYvvE,cACZ7R,MAAMmvE,SAAS+U,YAAYtkF,WAE/BihJ,4BAEA9tD,0BAMAlE,aAAc,EACZjvF,MAfIA,MAwBfihJ,qBAAsB,eACd3mJ,EAAGC,EACH2mJ,QAASC,UACT90I,KACA6D,MAAOg6F,GACPj4F,YAGJivI,QAAUlhJ,KAAKk8I,WAAWrhJ,OAI1BsmJ,UAAYnhJ,KAAKs0E,OAAOz5E,OAEnBP,EAAI,EAAGC,EAAI,EAAGD,EAAI4mJ,QAAS5mJ,IACD,OAAvB0F,KAAKk8I,WAAW5hJ,KAKpB4vG,GAAKlqG,KAAKk8I,WAAW5hJ,GACjBC,EAAI4mJ,YAEJjxI,MAAQlQ,KAAKs0E,OAAO/5E,IACdq5F,QAAQsW,GAAGhxF,GACjBhJ,MAAMoxF,UAAU4I,GAAGp8F,EAAGo8F,GAAGnpF,GACzBxmB,WAGK+hJ,cAAgB,EAErBjwI,KAAO,CACHonE,SAAS,EACTxjE,MAAOjQ,KAAKI,MAAMqM,QAAQwD,MAAMogC,KAChCkhC,qBAAsBvxE,KAAKI,MAAMqM,QAAQmpE,KAAK7J,YAC9C2G,qBAAsB1yE,KAAKI,MAAMqM,QAAQmpE,KAAKnD,YAC9ChB,uBAAwBzxE,KAAKI,MAAMqM,QAAQmpE,KAAKpE,cAChDsB,KAAM9yE,KAAK+S,QAAQ+/D,OAEvBzmE,KAAOiH,KAAK3D,SAAStD,KAAMrM,KAAK+S,QAAQ7C,QACnC/S,GAAK6C,KAAK7C,GAAK+sG,GAAG5vG,EAAI,QAAU0F,KAAKs8I,aAE1CpsI,MAAQsvF,KAAKkD,WAAW1iG,KAAKI,MAAO,CAAC8pG,GAAGp8F,EAAGo8F,GAAGnpF,EAAGmpF,GAAGhxF,GAAI7M,WACnDwiF,SAAS3+E,OACdA,MAAMkhF,WAAWpxF,MACjBkQ,MAAMg/E,aAAc,EACpBh/E,MAAMy/E,MAAO,OACRrb,OAAO54E,KAAKwU,QAML,aADhB+B,QAAUqB,KAAKrG,SAASjN,KAAK+S,QAAQ7C,MAAM+B,YAEvCA,QAAUjS,KAAKwhF,YAAYvvE,SAG/B/B,MAAMm1E,gBACDC,iBAAiBrzE,SACjBihF,iBAELhjF,MAAM+yG,UAAY3vG,KAAKrG,SAASjN,KAAK+S,QAAQ7C,MAAM2V,OAAO,IAC1D3V,MAAMgzG,UAAY5vG,KAAKrG,SAASjN,KAAK+S,QAAQ7C,MAAM2V,OAAO,SAKzDtrB,EADL2mJ,QAAU3mJ,EACQA,EAAI4mJ,UAAW5mJ,SACxB6F,MAAMmvE,SAAS14D,QAAQ7W,KAAKs0E,OAAO/5E,IAAI,QAKvC+5E,OAAO/5E,GAAGwY,QAAQd,QAAUjS,KAAKs0E,OAAO/5E,GAAGinF,YAAYvvE,SAAU,SAGnEjS,MAGXqzF,YAAa,eACL/4F,MAEJ8D,IAAIkC,WAAW,wBAAyB,qCAEnCkhF,YAAYvvE,SAAU,OACtB7R,MAAMmvE,SAAS14D,QAAQ7W,MAAM,GAC7B1F,EAAI,EAAGA,EAAI0F,KAAKs0E,OAAOz5E,OAAQP,IAC5BgZ,KAAKzU,OAAOmB,KAAKs0E,OAAOh6E,UACnBg6E,OAAOh6E,GAAG+4F,qBAIhBrzF,MAGXszF,YAAa,eACLh5F,MAEJ8D,IAAIkC,WAAW,wBAAyB,qCAEnCkhF,YAAYvvE,SAAU,OACtB7R,MAAMmvE,SAAS14D,QAAQ7W,MAAM,GAE7B1F,EAAI,EAAGA,EAAI0F,KAAKs0E,OAAOz5E,OAAQP,IAC5BgZ,KAAKzU,OAAOmB,KAAKs0E,OAAOh6E,UACnBg6E,OAAOh6E,GAAGg5F,qBAIhBtzF,QA4Cf5B,IAAIgjJ,YAAc,SAAUhhJ,MAAO4L,QAASC,gBACpCoC,GAAIq3B,KACJr5B,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,YAGtDi5B,KADA15B,QAAQnR,OAAS,EACVwR,KAAKqzH,cAEL1zH,QAAQ,GAGfA,QAAQ,GAAGvB,eAAiBjB,MAAMvF,mBAClC+H,QAAQ,GAAGvB,eAAiBjB,MAAMrF,yBAG5B,IAAInI,MAAM,2DAA6DgQ,QAAQ,IAAM,aAF3FqC,GAAK,IAAIjQ,IAAI29I,MAAM/vI,QAAQ,GAAI05B,KAAMr5B,MAMrCiH,KAAKnJ,WAAWkC,KAAKg1I,sBACrBhzI,GAAGqlE,kBAAoBrnE,KAAKg1I,oBAE5B/tI,KAAKnJ,WAAWkC,KAAKwmI,qBACrBxkI,GAAGqlE,kBAAoBrnE,KAAKwmI,mBAGhCxkI,GAAG+iF,WAAWplF,QAAQ,IACtBqC,GAAG6gF,aAAc,EACjB7gF,GAAG2wE,WAAWhzE,QAAQ,GAAGw1E,YAAYvvE,SAE9B5D,IA+EXjQ,IAAIkjJ,gBAAkB,SAAUlhJ,MAAO4L,QAASC,gBACxC8C,IAAKzU,EAAG2nB,KAAM3K,MAAmBjJ,GACjCwtC,IAAM,GACNxvC,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,YAErDT,QAAQ,GAAGvB,eAAiBjB,MAAMvF,mBACnC+H,QAAQ,GAAGvB,eAAiBjB,MAAMrF,oBAA6C,iBAAf6H,QAAQ,SAClE,IAAIhQ,MAAM,gEAAkEgQ,QAAQ,IAAM,kBAAoBA,QAAQ,IAAM,kBAAoBA,QAAQ,IAAM,UAMxKiW,KAAqB,OAHrBlT,IAAM/C,QAAQ,IAEM,IADpBsL,MAAQjL,KAAKqzH,gBAIRplI,EAAI,EAAGA,EAAIyU,IAAKzU,IACjBuhD,IAAIvhD,GAAK2nB,KAAO3nB,EAAIgd,aAGxBjJ,GAAKjO,MAAMwM,OAAO,QAAS,CAACZ,QAAQ,GAAI6vC,KAAMxvC,OAC3CqjF,OAAS,QAELrhF,IAGXjQ,IAAIsB,gBAAgB,QAAStB,IAAIgjJ,aACjChjJ,IAAIsB,gBAAgB,OAAQtB,IAAIkjJ,iBAChCljJ,IAAIsB,gBAAgB,QAAStB,IAAIkjJ,iBAE1B,CACHvF,MAAO39I,IAAI29I,MACXqF,YAAahjJ,IAAIgjJ,YACjBG,eAAgBnjJ,IAAIkjJ,gBACpBA,gBAAiBljJ,IAAIkjJ,oBAmD7BlpJ,OAAO,YAAY,CACf,MAAO,iBAAkB,YAAa,YAAa,gBAAiB,kBAAmB,aAAc,cACtG,SAAUgG,IAAKoL,MAAOg2F,KAAMt7E,IAAKirB,SAAUtB,WAAYv6B,KAAMwhB,YAY5D12B,IAAIymG,GAAK,SAAU1pF,KAAM2pF,WAAY+C,aAC5B1sF,KAAOA,UACP2pF,WAAaA,gBACb+C,OAASA,QAGlBzpG,IAAIC,OAAOD,IAAIymG,GAAG3rG,UAA0C,CACxDsoJ,YAAa,SAAUC,QAAStmI,UACxB7gB,EAAG8R,IAAK5O,OAGO,cAAf2d,KAAKrf,OAAyBqf,KAAK4pF,SAAS,GAAGjpG,QAAU2lJ,eAClDtmI,KAAK4pF,SAAS,GAClB,GAAI5pF,KAAK4pF,aACZ34F,IAAM+O,KAAK4pF,SAASlqG,OACfP,EAAI,EAAGA,EAAI8R,MAAO9R,KAEP,QADZkD,IAAMwC,KAAKwhJ,YAAYC,QAAStmI,KAAK4pF,SAASzqG,YAEnCkD,WAIZ,MAOXkkJ,QAAS,SAAUvmI,UACX7gB,EAAG8R,QAEW,WAAb+O,KAAKtQ,MACQ,UAAdsQ,KAAKrf,OAAmC,UAAdqf,KAAKrf,OACjB,UAAdqf,KAAKrf,OAAmC,UAAdqf,KAAKrf,OACjB,UAAdqf,KAAKrf,OAAmC,cAAdqf,KAAKrf,OACjB,UAAdqf,KAAKrf,QACQ,YAAbqf,KAAKtQ,MAAmC,cAAbsQ,KAAKtQ,OAEhCsQ,KAAK6pF,QAAS,GAEd7pF,KAAK4pF,aACL34F,IAAM+O,KAAK4pF,SAASlqG,OACfP,EAAI,EAAGA,EAAI8R,MAAO9R,OACdonJ,QAAQvmI,KAAK4pF,SAASzqG,KAKvCqnJ,iBAAkB,SAAUxmI,KAAMmkB,aAG1Bk7F,QAFAt6H,IAAMib,KAAK4pF,SAAS,GAAGjpG,MACvB+3F,IAAM14E,KAAK4pF,SAAS,UAIhB7kG,SACC,MAEDs6H,QAAUx6H,KAAK8kG,WAAW,UAAW,SACjCjR,IAAI,GACJ7zF,KAAK8kG,WAAW,UAAW,aACvB9kG,KAAK8kG,WAAW,WAAY,QAC5B,CAAC9kG,KAAK8kG,WAAW,UAAW,SACxBxxF,KAAK3D,SAASkkF,IAAI,IAClBvgF,KAAK3D,SAASkkF,IAAI,kBAM7B,OACD2mC,QAAUx6H,KAAK8kG,WAAW,UAAW,SACjC9kG,KAAK8kG,WAAW,aAAc,GAC9B9kG,KAAK8kG,WAAW,UAAW,SACvB9kG,KAAK8kG,WAAW,aAAc,GAC9B9kG,KAAK8kG,WAAW3pF,KAAKtQ,KAAMsQ,KAAKrf,MAC5BwX,KAAK3D,SAASwL,KAAK4pF,SAAS,IAC5BzxF,KAAK3D,SAASwL,KAAK4pF,SAAS,iBAMvC,MACDy1B,QAAUx6H,KAAK8kG,WAAW,UAAW,aACjC9kG,KAAK8kG,WAAW,WAAY,OAC5BxxF,KAAK3D,SAASkkF,gBAIjB,MACD2mC,QAAUx6H,KAAK8kG,WAAW,UAAW,SACjC9kG,KAAK8kG,WAAW,UAAW,aACvB9kG,KAAK8kG,WAAW,WAAY,OAC5BxxF,KAAK3D,SAASkkF,iBAKrB,MACD2mC,QAAUx6H,KAAK8kG,WAAW,UAAW,SACjC9kG,KAAK8kG,WAAW,aAAc,GAC9B9kG,KAAK8kG,WAAW,UAAW,SACvB9kG,KAAK8kG,WAAW,UAAW,aACvB9kG,KAAK8kG,WAAW,WAAY,OAC5BxxF,KAAK3D,SAASkkF,MAElB7zF,KAAK8kG,WAAW,aAAc,eAKrC,MACD01B,QAAUx6H,KAAK8kG,WAAW,UAAW,SACjC9kG,KAAK8kG,WAAW,UAAW,SACvB9kG,KAAK8kG,WAAW,aAAc,GAC9B9kG,KAAK8kG,WAAW,UAAW,SACvB9kG,KAAK8kG,WAAW,UAAW,aACvB9kG,KAAK8kG,WAAW,WAAY,OAC5BxxF,KAAK3D,SAASkkF,MAElB7zF,KAAK8kG,WAAW,aAAc,gBAMzC,MACD01B,QAAUx6H,KAAK8kG,WAAW3pF,KAAKtQ,KAAMsQ,KAAKrf,MACtCwX,KAAK3D,SAASwL,KAAK4pF,SAAS,IAC5BzxF,KAAK3D,SAASwL,KAAK4pF,SAAS,eAI/B,MAEDy1B,QAAUx6H,KAAK8kG,WAAW,UAAW,SACjC9kG,KAAK8kG,WAAW,UAAW,aACvBxxF,KAAK3D,SAASwL,KAAK4pF,SAAS,IAC5BzxF,KAAK3D,SAASwL,KAAK4pF,SAAS,KAEhC/kG,KAAK8kG,WAAW,UAAW,SACvB9kG,KAAK8kG,WAAW,UAAW,SACvB9kG,KAAK4hJ,WAAWzmI,KAAK4pF,SAAS,GAAG,GAAIzlE,SACrCt/B,KAAK8kG,WAAW,UAAW,SACvBxxF,KAAK3D,SAASwL,KAAK4pF,SAAS,GAAG,IAC/BzxF,KAAK3D,SAASwL,KAAK4pF,SAAS,GAAG,MAGvC/kG,KAAK8kG,WAAW,UAAW,SACvB9kG,KAAK4hJ,WAAWzmI,KAAK4pF,SAAS,GAAG,GAAIzlE,SACrCt/B,KAAK8kG,WAAW,UAAW,aACvB9kG,KAAK8kG,WAAW,WAAY,OAC5B,CAACxxF,KAAK3D,SAASwL,KAAK4pF,SAAS,GAAG,mBAO/C,UACA,KACDy1B,QAAUx6H,KAAK8kG,WAAW,UAAW,SACjC9kG,KAAK8kG,WAAW,aAAc,GAE9BxxF,KAAK3D,SAASkkF,IAAI,eAIrB,WACA,SACA,KACD2mC,QAAUx6H,KAAK8kG,WAAW,UAAW,SACjC9kG,KAAK8kG,WAAW,UAAW,SACvB9kG,KAAK8kG,WAAW,aAAc,GAE9BxxF,KAAK3D,SAASkkF,IAAI,KAEtB7zF,KAAK8kG,WAAW,aAAc,+BAIjC,YACA,KACD01B,QAAUx6H,KAAK8kG,WAAW,UAAW,SACjC9kG,KAAK8kG,WAAW,UAAW,SACvB9kG,KAAK8kG,WAAW,aAAc,GAE9BxxF,KAAK3D,SAASkkF,IAAI,KAEtB7zF,KAAK8kG,WAAW,aAAc,+BAIjC,OACD01B,QAAUx6H,KAAK8kG,WAAW,UAAW,SACjC9kG,KAAK8kG,WAAW,aAAc,GAC9B9kG,KAAK8kG,WAAW,UAAW,aACvB9kG,KAAK8kG,WAAW,WAAY,QAC5B,CACI9kG,KAAK8kG,WAAW,UAAW,SACvB9kG,KAAK8kG,WAAW,aAAc,GAC9B9kG,KAAK8kG,WAAW,UAAW,SACvBxxF,KAAK3D,SAASkkF,IAAI,IAClBvgF,KAAK3D,SAASkkF,IAAI,mBAQrC,OACD2mC,QAAUx6H,KAAK8kG,WAAW,UAAW,SACjC9kG,KAAK8kG,WAAW,UAAW,SACvB9kG,KAAK8kG,WAAW,aAAc,GAC9B9kG,KAAK8kG,WAAW,UAAW,aACvB9kG,KAAK8kG,WAAW,WAAY,QAC5B,CACI9kG,KAAK8kG,WAAW,UAAW,SACvB9kG,KAAK8kG,WAAW,aAAc,GAC9B9kG,KAAK8kG,WAAW,UAAW,SACvBxxF,KAAK3D,SAASkkF,IAAI,IAClBvgF,KAAK3D,SAASkkF,IAAI,oBAWzC,OACD2mC,QAAUx6H,KAAK8kG,WAAW,UAAW,SACjC9kG,KAAK8kG,WAAW,aAAc,GAC9B9kG,KAAK8kG,WAAW,UAAW,SACvB9kG,KAAK8kG,WAAW,aAAc,GAC9B9kG,KAAK8kG,WAAW,UAAW,SACvBxxF,KAAK3D,SAASkkF,IAAI,IAClBvgF,KAAK3D,SAASkkF,IAAI,iBAM7B,OACD2mC,QAAUx6H,KAAK8kG,WAAW,UAAW,SACjC9kG,KAAK8kG,WAAW,UAAW,SACvB9kG,KAAK8kG,WAAW,aAAc,GAC9B9kG,KAAK8kG,WAAW,UAAW,SACvB9kG,KAAK8kG,WAAW,aAAc,GAC9B9kG,KAAK8kG,WAAW,UAAW,SACvBxxF,KAAK3D,SAASkkF,IAAI,IAClBvgF,KAAK3D,SAASkkF,IAAI,kBAOjC,OACD2mC,QAAUx6H,KAAK8kG,WAAW,UAAW,aACjC9kG,KAAK8kG,WAAW,WAAY,QAC5B,CAACxxF,KAAK3D,SAASkkF,IAAI,gBAItB,OACD2mC,QAAUx6H,KAAK8kG,WAAW,UAAW,aACjC9kG,KAAK8kG,WAAW,WAAY,QAC5B,CAACxxF,KAAK3D,SAASkkF,IAAI,gBAItB,OACD2mC,QAAUx6H,KAAK8kG,WAAW,UAAW,SACjC9kG,KAAK8kG,WAAW,aAAc,GAC9B9kG,KAAK8kG,WAAW,UAAW,SACvB9kG,KAAK8kG,WAAW,UAAW,aACvB9kG,KAAK8kG,WAAW,WAAY,QAC5B,CAACxxF,KAAK3D,SAASkkF,IAAI,MAEvB7zF,KAAK8kG,WAAW,aAAc,eAKrC,QACD01B,QAAUx6H,KAAK8kG,WAAW,UAAW,SACjC9kG,KAAK8kG,WAAW,aAAc,GAC9B9kG,KAAK8kG,WAAW,UAAW,aACvB9kG,KAAK8kG,WAAW,WAAY,QAC5B,CACI9kG,KAAK8kG,WAAW,UAAW,SACvB9kG,KAAK8kG,WAAW,UAAW,SACvBxxF,KAAK3D,SAASkkF,IAAI,IAClBvgF,KAAK3D,SAASkkF,IAAI,KAEtB7zF,KAAK8kG,WAAW,aAAc,iBAO7C,QACD01B,QAAUx6H,KAAK8kG,WAAW,UAAW,SACjC9kG,KAAK8kG,WAAW,aAAc,GAC9B9kG,KAAK8kG,WAAW,UAAW,aACvB9kG,KAAK8kG,WAAW,WAAY,QAC5B,CACI9kG,KAAK8kG,WAAW,UAAW,SACvB9kG,KAAK8kG,WAAW,UAAW,SACvBxxF,KAAK3D,SAASkkF,IAAI,IAClBvgF,KAAK3D,SAASkkF,IAAI,KAEtB7zF,KAAK8kG,WAAW,aAAc,iBAO7C,QACD01B,QAAUx6H,KAAK8kG,WAAW,UAAW,SACjC9kG,KAAK8kG,WAAW,aAAc,GAC9B9kG,KAAK8kG,WAAW,UAAW,SACvB9kG,KAAK8kG,WAAW,aAAc,GAC9B9kG,KAAK8kG,WAAW,UAAW,SACvBxxF,KAAK3D,SAASkkF,IAAI,IAClBvgF,KAAK3D,SAASkkF,IAAI,2BAO9B2mC,QAAUx6H,KAAK8kG,WAAW,aAAc,GACxC7jG,QAAQK,IAAI,kBAAoBpB,IAAM,yBAChC,IAAIlE,MAAM,SAAWgE,KAAKqwC,KAAO,cAKxCmqF,SAGXonB,WAAY,SAAUzmI,KAAMmkB,aACpBk7F,eAEIr/G,KAAKtQ,UACJ,iBACOsQ,KAAKrf,WAaJ,aAGG0+H,QAD0B,OAA1Br/G,KAAK4pF,SAAS,GAAGjpG,MACPkE,KAAK2hJ,iBAAiBxmI,KAAMmkB,SAEN,IAA5BnkB,KAAK4pF,SAAS,GAAGlqG,OACPmF,KAAK8kG,WAAW,aAAc,GAE9B9kG,KAAK8kG,WAAW,UAAW,SACjC9kG,KAAK2hJ,iBAAiBxmI,KAAMmkB,SAE5Bt/B,KAAK4hJ,WAAWzmI,KAAK4pF,SAAS,GAAG,GAAIzlE,oBAMhD,SAEDk7F,QAAUx6H,KAAK8kG,WAAW,UAAW,SACjC9kG,KAAK8kG,WAAW,UAAW,SACvB9kG,KAAK8kG,WAAW,UAAW,SACvB9kG,KAAK4hJ,WAAWzmI,KAAK4pF,SAAS,GAAIzlE,SAClChsB,KAAK3D,SAASwL,KAAK4pF,SAAS,KAEhC/kG,KAAK8kG,WAAW,UAAW,SACvBxxF,KAAK3D,SAASwL,KAAK4pF,SAAS,IAC5B/kG,KAAK4hJ,WAAWzmI,KAAK4pF,SAAS,GAAIzlE,WAG1Ct/B,KAAK8kG,WAAW,UAAW,SACvBxxF,KAAK3D,SAASwL,KAAK4pF,SAAS,IAC5BzxF,KAAK3D,SAASwL,KAAK4pF,SAAS,gBAKnC,SAEDy1B,QAAUx6H,KAAK8kG,WAAW,UAAW,SACjC9kG,KAAK8kG,WAAW,UAAW,SACvBxxF,KAAK3D,SAASwL,KAAK4pF,SAAS,IAC5B/kG,KAAK4hJ,WAAWzmI,KAAK4pF,SAAS,GAAIzlE,UACtCt/B,KAAK8kG,WAAW,UAAW,SACvB9kG,KAAK4hJ,WAAWzmI,KAAK4pF,SAAS,GAAIzlE,SAClChsB,KAAK3D,SAASwL,KAAK4pF,SAAS,gBAInC,SACDy1B,QAAUx6H,KAAK8kG,WAAW,UAAW,SACjC9kG,KAAK4hJ,WAAWzmI,KAAK4pF,SAAS,GAAIzlE,oBAIrC,aACA,SACDk7F,QAAUx6H,KAAK8kG,WAAW,UAAW3pF,KAAKrf,MACtCkE,KAAK4hJ,WAAWzmI,KAAK4pF,SAAS,GAAIzlE,SAClCt/B,KAAK4hJ,WAAWzmI,KAAK4pF,SAAS,GAAIzlE,oBAIrC,SAEDk7F,QAAUx6H,KAAK8kG,WAAW,UAAW,SACjCxxF,KAAK3D,SAASwL,MACdnb,KAAK8kG,WAAW,UAAW,SACvB9kG,KAAK8kG,WAAW,UAAW,SACvB9kG,KAAK4hJ,WAAWzmI,KAAK4pF,SAAS,GAAIzlE,SAClCt/B,KAAK8kG,WAAW,UAAW,SACvBxxF,KAAK3D,SAASwL,KAAK4pF,SAAS,IAC5BzxF,KAAK3D,SAASwL,KAAK4pF,SAAS,MAGpC/kG,KAAK8kG,WAAW,UAAW,SACvB9kG,KAAK4hJ,WAAWzmI,KAAK4pF,SAAS,GAAIzlE,SAClCt/B,KAAK8kG,WAAW,UAAW,aACvB9kG,KAAK8kG,WAAW,WAAY,OAC5B,CAACxxF,KAAK3D,SAASwL,KAAK4pF,SAAS,mBASpD,WAGGy1B,QADAr/G,KAAKrf,QAAUwjC,QACLt/B,KAAK8kG,WAAW,aAAc,GAE9B9kG,KAAK8kG,WAAW,aAAc,aAI3C,aACD01B,QAAUx6H,KAAK8kG,WAAW,aAAc,UAWzC01B,SAUX1yB,kBAAmB,SAAU3sF,KAAMwnF,OAAQ+E,SACnCt7F,IAAK9R,EAAGC,EAAGsnJ,QAASC,SAAej0B,MAAO2M,QAC1CunB,QAASziH,QAAS0iH,OAAQjoH,SAExB,GACD5e,YADC,WAKDk1B,KAAOl1B,KAAKk1B,UACZ+6B,IAAMjwD,KAAKiwD,IAIhBh/D,IAAM+O,KAAK4pF,SAASlqG,OACfP,EAAI,EAAGA,EAAI8R,MAAO9R,KACf6gB,KAAK4pF,SAASzqG,IAAM6gB,KAAK4pF,SAASzqG,GAAGuQ,KACrCsQ,KAAK4pF,SAASzqG,GAAK0F,KAAK8nG,kBAAkB3sF,KAAK4pF,SAASzqG,GAAI6gB,KAAMusF,UAC/D,GAAIp0F,KAAKlJ,QAAQ+Q,KAAK4pF,SAASzqG,QAC7BC,EAAI,EAAGA,EAAI4gB,KAAK4pF,SAASzqG,GAAGO,SAAUN,EACnC4gB,KAAK4pF,SAASzqG,GAAGC,IAAM4gB,KAAK4pF,SAASzqG,GAAGC,GAAGsQ,OAC3CsQ,KAAK4pF,SAASzqG,GAAGC,GAAKyF,KAAK8nG,kBAAkB3sF,KAAK4pF,SAASzqG,GAAGC,GAAI4gB,KAAMusF,SAO/E,YADDvsF,KAAKtQ,QAGI,eADDsQ,KAAKrf,SAEDqf,KAAK4pF,SAAS,IAAiC,MAA3B5pF,KAAK4pF,SAAS,GAAGjpG,MAAe,IACpB,YAA5Bqf,KAAK4pF,SAAS,GAAG,GAAGl6F,MAOpBk3I,QAAU5mI,KAAK4pF,SAAS,GAAG,GAAGjpG,MAE9BkmJ,QADAH,QAAU7hJ,KAAKwhJ,YAAYO,QAASr6C,MACnB3C,SAAS,GAItBzlE,QADAnkB,KAAK4pF,SAAS,GAAGlqG,QAAU,EACjBsgB,KAAK4pF,SAAS,GAAG,GAAGjpG,MAEpB+lJ,QAAQ98C,SAAS,GAAG,GAElC+8C,SAAWD,QAAQ98C,SAAS,KAM5B+8C,SAAW3mI,KAAK4pF,SAAS,GAAG,GAC5Bi9C,OAAS,CAAC,KAIN1iH,QADAnkB,KAAK4pF,SAAS,GAAGlqG,QAAU,EACjBsgB,KAAK4pF,SAAS,GAAG,GAAGjpG,MAEpB,KAYlB0+H,QAAUsnB,UANN/nH,MADA5e,KAAK4pF,SAAS,GAAGlqG,QAAU,EACnBsgB,KAAK4pF,SAAS,GAAG,GAAGjpG,MAEpB,IAMC,OACFi+B,OAAS,GACZygG,QAAUx6H,KAAK4hJ,WAAWpnB,QAASl7F,SACnCk7F,QAAUx6H,KAAK+nG,mBAAmByyB,SAClCzgG,QAQJ8zF,MAHe,WAAflrB,OAAO93F,MAAqC,aAAhB83F,OAAO7mG,MAG3BkE,KAAK8kG,WAAW,UAAW,SAC/Bk9C,OACAxnB,SAGIA,aAGPknB,QAAQ7zB,OACb1yG,KAAKtQ,KAAOgjH,MAAMhjH,KAClBsQ,KAAKrf,MAAQ+xH,MAAM/xH,MACnBqf,KAAK4pF,SAAS,GAAK8oB,MAAM9oB,SAAS,GAClC5pF,KAAK4pF,SAAS,GAAK8oB,MAAM9oB,SAAS,UAY/C5pF,MAGX4sF,mBAAoB,SAAU5sF,UACtB7gB,EAAG8R,IAAK61I,GAAIlkG,GAAIzwC,QAGhBgG,KAAKlJ,QAAQ+Q,UACb/O,IAAM+O,KAAKtgB,OACNP,EAAI,EAAGA,EAAI8R,MAAO9R,EACnB6gB,KAAK7gB,GAAK0F,KAAK+nG,mBAAmB5sF,KAAK7gB,OAG9B,WAAb6gB,KAAKtQ,OAAsBsQ,KAAK4pF,gBACzB5pF,SAGX/O,IAAM+O,KAAK4pF,SAASlqG,OACfP,EAAI,EAAGA,EAAI8R,MAAO9R,EAAG,MACjB4nJ,oBAAqB,KAEtB/mI,KAAK4pF,SAASzqG,GAAK0F,KAAK+nG,mBAAmB5sF,KAAK4pF,SAASzqG,UACpD0F,KAAKkiJ,2BAIV/mI,KAAKrf,WAGJ,YACDmmJ,GAAK9mI,KAAK4pF,SAAS,GAEJ,aADfhnD,GAAK5iC,KAAK4pF,SAAS,IACZl6F,SACEvQ,EAAI,EAAGA,EAAI2nJ,GAAGpnJ,SAAUP,KAErB2nJ,GAAG3nJ,IAAMyjD,GAAGjiD,MAAO,CACnBiiD,GAAGinD,QAAS,kBASvB,YACDi9C,GAAK9mI,KAAK4pF,SAAS,GACnBhnD,GAAK5iC,KAAK4pF,SAAS,GACJ,cAAXk9C,GAAGp3I,MAAqC,IAAbo3I,GAAGnmJ,aACvBiiD,MAEI,cAAXA,GAAGlzC,MAAqC,IAAbkzC,GAAGjiD,aACvBmmJ,MAII,cAAXA,GAAGp3I,MAAmC,cAAXkzC,GAAGlzC,YAC9Bo3I,GAAGnmJ,OAASiiD,GAAGjiD,MACRmmJ,aAUV,YACDA,GAAK9mI,KAAK4pF,SAAS,GACnBhnD,GAAK5iC,KAAK4pF,SAAS,GACJ,cAAXk9C,GAAGp3I,MAAoC,GAAZo3I,GAAGnmJ,aACvBiiD,MAEI,cAAXA,GAAGlzC,MAAoC,GAAZkzC,GAAGjiD,aACvBmmJ,MAEI,cAAXA,GAAGp3I,MAAqC,IAAbo3I,GAAGnmJ,aACvBmmJ,MAEI,cAAXlkG,GAAGlzC,MAAqC,IAAbkzC,GAAGjiD,aACvBiiD,MAEI,cAAXA,GAAGlzC,MAAqC,IAAbkzC,GAAGjiD,aACvBiiD,MAII,WAAXkkG,GAAGp3I,MAAiC,UAAZo3I,GAAGnmJ,OAChB,WAAXiiD,GAAGlzC,MAAiC,UAAZkzC,GAAGjiD,aAC3Bqf,KAAK4pF,SAAW,CAACk9C,GAAGl9C,SAAS,GAAIhnD,GAAGgnD,SAAS,SACxCm9C,oBAAqB,EACnB/mI,QAGK,UAAZ8mI,GAAGnmJ,OAAiC,UAAZiiD,GAAGjiD,aAC3Bqf,KAAKtQ,KAAO,UACZsQ,KAAKrf,MAAQ,SACbqf,KAAK4pF,SAAW,CAAC/kG,KAAK8kG,WAAW,UAAW,SAAUm9C,GAAGl9C,SAAS,GAAIhnD,UACjEmkG,oBAAqB,EACnB/mI,QAGK,UAAZ8mI,GAAGnmJ,OAAiC,UAAZiiD,GAAGjiD,aAC3Bqf,KAAKtQ,KAAO,UACZsQ,KAAKrf,MAAQ,SACbqf,KAAK4pF,SAAW,CAAC/kG,KAAK8kG,WAAW,UAAW,SAAUm9C,GAAIlkG,GAAGgnD,SAAS,UACjEm9C,oBAAqB,EACnB/mI,QAGK,UAAZ8mI,GAAGnmJ,OACoB,cAAvBmmJ,GAAGl9C,SAAS,GAAGl6F,MAAgD,GAAxBo3I,GAAGl9C,SAAS,GAAGjpG,aACtDqf,KAAKtQ,KAAO,UACZsQ,KAAKrf,MAAQ,SACbqf,KAAK4pF,SAAW,CAAChnD,GAAIkkG,GAAGl9C,SAAS,SAC5Bm9C,oBAAqB,EACnB/mI,QAGK,UAAZ4iC,GAAGjiD,OACoB,cAAvBiiD,GAAGgnD,SAAS,GAAGl6F,MAAgD,GAAxBkzC,GAAGgnD,SAAS,GAAGjpG,aACtDqf,KAAKtQ,KAAO,UACZsQ,KAAKrf,MAAQ,SACbqf,KAAK4pF,SAAW,CAACk9C,GAAIlkG,GAAGgnD,SAAS,SAC5Bm9C,oBAAqB,EACnB/mI,QAKI,cAAX8mI,GAAGp3I,MAAmC,cAAXkzC,GAAGlzC,YAC9BsQ,KAAK4pF,SAAW,CAAChnD,GAAIkkG,SAChBC,oBAAqB,EACnB/mI,QAGI,cAAX8mI,GAAGp3I,MAAmC,WAAXkzC,GAAGlzC,MAClB,UAAZkzC,GAAGjiD,OAA4C,cAAvBiiD,GAAGgnD,SAAS,GAAGl6F,YACvCsQ,KAAK4pF,SAAW,CAAChnD,GAAIkkG,SAChBC,oBAAqB,EACnB/mI,QAKI,WAAX8mI,GAAGp3I,MAAiC,cAAZo3I,GAAGnmJ,QACf,YAAXiiD,GAAGlzC,MAAkC,WAAXkzC,GAAGlzC,MAAiC,cAAZkzC,GAAGjiD,cACtDqf,KAAK4pF,SAAW,CAAChnD,GAAIkkG,SAChBC,oBAAqB,EACnB/mI,QAII,WAAX8mI,GAAGp3I,MAAgC,WAAXkzC,GAAGlzC,MACf,UAAZkzC,GAAGjiD,OAA4C,YAAvBiiD,GAAGgnD,SAAS,GAAGl6F,YACvCsQ,KAAK4pF,SAAW,CAAChnD,GAAIkkG,SAChBC,oBAAqB,EACnB/mI,QAII,cAAX8mI,GAAGp3I,MAAmC,WAAXkzC,GAAGlzC,OACjB,UAAZkzC,GAAGjiD,OAAiC,UAAZiiD,GAAGjiD,QACL,cAAvBiiD,GAAGgnD,SAAS,GAAGl6F,YACfyC,KAAOywC,GAAGgnD,SAAS,GACnBhnD,GAAGgnD,SAAS,GAAKk9C,GACjB9mI,KAAK4pF,SAAW,CAACz3F,KAAMywC,SAClBmkG,oBAAqB,EACnB/mI,QAII,cAAX4iC,GAAGlzC,MAAmC,WAAXo3I,GAAGp3I,MAClB,UAAZo3I,GAAGnmJ,OACoB,cAAvBmmJ,GAAGl9C,SAAS,GAAGl6F,YACfsQ,KAAK4pF,SAAW,CACZk9C,GAAGl9C,SAAS,GACZ/kG,KAAK8kG,WAAW,UAAW,SAAUm9C,GAAGl9C,SAAS,GAAIhnD,UAEpDmkG,oBAAqB,EACnB/mI,QAII,cAAX8mI,GAAGp3I,MAAmC,cAAXkzC,GAAGlzC,YAC9Bo3I,GAAGnmJ,OAASiiD,GAAGjiD,MACRmmJ,MAKI,cAAXA,GAAGp3I,MAAmC,WAAXkzC,GAAGlzC,OACjB,UAAZkzC,GAAGjiD,OAAiC,UAAZiiD,GAAGjiD,QACL,cAAvBiiD,GAAGgnD,SAAS,GAAGl6F,YACfkzC,GAAGgnD,SAAS,GAAGjpG,OAASmmJ,GAAGnmJ,MACpBiiD,MAIXkkG,GAAG/vD,KAAOlyF,KAAK6nG,OAAOr6B,QAAQy0E,IAC9BlkG,GAAGm0C,KAAOlyF,KAAK6nG,OAAOr6B,QAAQzvB,IAC1BkkG,GAAG/vD,OAASn0C,GAAGm0C,YACf/2E,KAAKrf,MAAQ,SACbqf,KAAK4pF,SAAS,GAAK/kG,KAAK8kG,WAAW,aAAc,GAC1C3pF,QAGI,cAAX8mI,GAAGp3I,MAAmC,WAAXkzC,GAAGlzC,OACjB,UAAZkzC,GAAGjiD,OAAiC,UAAZiiD,GAAGjiD,QACL,cAAvBiiD,GAAGgnD,SAAS,GAAGl6F,YACfkzC,GAAGgnD,SAAS,GAAGjpG,OAASmmJ,GAAGnmJ,MACpBiiD,MAII,WAAXA,GAAGlzC,MAAiC,UAAZkzC,GAAGjiD,QACtBmmJ,GAAG/vD,OACJ+vD,GAAG/vD,KAAOlyF,KAAK6nG,OAAOr6B,QAAQy0E,KAE7BlkG,GAAGgnD,SAAS,GAAG7S,OAChBn0C,GAAGgnD,SAAS,GAAG7S,KAAOlyF,KAAK6nG,OAAOr6B,QAAQzvB,GAAGgnD,SAAS,KAEtDk9C,GAAG/vD,OAASn0C,GAAGgnD,SAAS,GAAG7S,aAC3Bn0C,GAAGgnD,SAAS,GAAK/kG,KAAK8kG,WAAW,UAAW,SACxC/mD,GAAGgnD,SAAS,GACZ/kG,KAAK8kG,WAAW,aAAc,SAE7Bo9C,oBAAqB,EACnBnkG,MAKA,WAAXkkG,GAAGp3I,MAAiC,UAAZo3I,GAAGnmJ,OAChB,WAAXiiD,GAAGlzC,MAAiC,UAAZkzC,GAAGjiD,QAC3BmmJ,GAAGl9C,SAAS,GAAG7S,KAAOlyF,KAAK6nG,OAAOr6B,QAAQy0E,GAAGl9C,SAAS,IACtDhnD,GAAGgnD,SAAS,GAAG7S,KAAOlyF,KAAK6nG,OAAOr6B,QAAQzvB,GAAGgnD,SAAS,IAClDk9C,GAAGl9C,SAAS,GAAG7S,OAASn0C,GAAGgnD,SAAS,GAAG7S,aACvC+vD,GAAGl9C,SAAS,GAAK/kG,KAAK8kG,WAAW,UAAW,SACxCm9C,GAAGl9C,SAAS,GACZhnD,GAAGgnD,SAAS,SAEXm9C,oBAAqB,EACnBD,aASd,YACDA,GAAK9mI,KAAK4pF,SAAS,GACnBhnD,GAAK5iC,KAAK4pF,SAAS,GACJ,cAAXk9C,GAAGp3I,MAAqC,IAAbo3I,GAAGnmJ,aAC9Bqf,KAAKrf,MAAQ,SACbqf,KAAK4pF,SAAS,GAAKhnD,GACZ5iC,QAEI,cAAX4iC,GAAGlzC,MAAqC,IAAbkzC,GAAGjiD,aACvBmmJ,MAEI,cAAXA,GAAGp3I,MAAmC,cAAXkzC,GAAGlzC,MAC9Bo3I,GAAGnmJ,OAASiiD,GAAGjiD,aACRkE,KAAK8kG,WAAW,aAAc,MAE1B,YAAXm9C,GAAGp3I,MAAiC,YAAXkzC,GAAGlzC,MAC5Bo3I,GAAGnmJ,OAASiiD,GAAGjiD,aACRkE,KAAK8kG,WAAW,aAAc,MAI1B,cAAXm9C,GAAGp3I,MAAmC,cAAXkzC,GAAGlzC,YAC9Bo3I,GAAGnmJ,OAASiiD,GAAGjiD,MACRmmJ,MAII,WAAXA,GAAGp3I,MAAiC,UAAZo3I,GAAGnmJ,OAChB,WAAXiiD,GAAGlzC,MAAiC,UAAZkzC,GAAGjiD,QAE3BmmJ,GAAGl9C,SAAS,GAAG7S,KAAOlyF,KAAK6nG,OAAOr6B,QAAQy0E,GAAGl9C,SAAS,IACtDhnD,GAAGgnD,SAAS,GAAG7S,KAAOlyF,KAAK6nG,OAAOr6B,QAAQzvB,GAAGgnD,SAAS,IAClDk9C,GAAGl9C,SAAS,GAAG7S,OAASn0C,GAAGgnD,SAAS,GAAG7S,aAEvC/2E,KAAKrf,MAAQ,SACbqf,KAAK4pF,SAAW,CACZ/kG,KAAK8kG,WAAW,UAAW,SACvBm9C,GAAGl9C,SAAS,GACZhnD,GAAGgnD,SAAS,IAChBk9C,GAAGl9C,SAAS,SAEXm9C,oBAAqB,EACnB/mI,QAIA,WAAX8mI,GAAGp3I,MAAiC,UAAZo3I,GAAGnmJ,QAE3BmmJ,GAAGl9C,SAAS,GAAG7S,KAAOlyF,KAAK6nG,OAAOr6B,QAAQy0E,GAAGl9C,SAAS,IACtDhnD,GAAGm0C,KAAOlyF,KAAK6nG,OAAOr6B,QAAQzvB,IAC1BkkG,GAAGl9C,SAAS,GAAG7S,OAASn0C,GAAGm0C,aAE3B/2E,KAAKrf,MAAQ,SACbqf,KAAK4pF,SAAW,CACZ/kG,KAAK8kG,WAAW,UAAW,SACvBm9C,GAAGl9C,SAAS,GACZ/kG,KAAK8kG,WAAW,aAAc,IAClC/mD,SAECmkG,oBAAqB,EACnB/mI,QAIA,WAAX4iC,GAAGlzC,MAAiC,UAAZkzC,GAAGjiD,QAE3BiiD,GAAGgnD,SAAS,GAAG7S,KAAOlyF,KAAK6nG,OAAOr6B,QAAQzvB,GAAGgnD,SAAS,IACtDk9C,GAAG/vD,KAAOlyF,KAAK6nG,OAAOr6B,QAAQy0E,IAC1BlkG,GAAGgnD,SAAS,GAAG7S,OAAS+vD,GAAG/vD,aAE3B/2E,KAAKrf,MAAQ,SACbqf,KAAK4pF,SAAW,CACZ/kG,KAAK8kG,WAAW,UAAW,SACvB9kG,KAAK8kG,WAAW,aAAc,GAC9B/mD,GAAGgnD,SAAS,IAChBk9C,SAECC,oBAAqB,EACnB/mI,eAQd,YAEc,eADf8mI,GAAK9mI,KAAK4pF,SAAS,IACZl6F,MAAqC,IAAbo3I,GAAGnmJ,aACvBmmJ,MAEI,WAAXA,GAAGp3I,MAAiC,UAAZo3I,GAAGnmJ,aACpBmmJ,GAAGl9C,SAAS,aAQtB,YACDk9C,GAAK9mI,KAAK4pF,SAAS,GACnBhnD,GAAK5iC,KAAK4pF,SAAS,GACJ,cAAXk9C,GAAGp3I,MAAmC,cAAXkzC,GAAGlzC,MAC9Bo3I,GAAGnmJ,OAASiiD,GAAGjiD,OAAsB,IAAbmmJ,GAAGnmJ,aAC3BmmJ,GAAGnmJ,MAAQ,EACJmmJ,MAEI,cAAXA,GAAGp3I,MAAqC,IAAbo3I,GAAGnmJ,OACnB,cAAXiiD,GAAGlzC,MAAqC,IAAbkzC,GAAGjiD,aAC9BmmJ,GAAGnmJ,MAAQ,EACJmmJ,MAII,cAAXA,GAAGp3I,MAAqC,IAAbo3I,GAAGnmJ,QAClB,WAAXiiD,GAAGlzC,MAAgC,YAAXkzC,GAAGlzC,aAC5BsQ,KAAKtQ,KAAO,aACZsQ,KAAKrf,MAAQ,EACNqf,QAGI,YAAX8mI,GAAGp3I,MAAiC,YAAXkzC,GAAGlzC,MAC5Bo3I,GAAGnmJ,OAASiiD,GAAGjiD,aACRkE,KAAK8kG,WAAW,aAAc,MAE1B,cAAXm9C,GAAGp3I,MAAqC,IAAbo3I,GAAGnmJ,OACnB,cAAXiiD,GAAGlzC,MAAqC,IAAbkzC,GAAGjiD,aAC1BmmJ,GAAGnmJ,MAAQ,EACXmmJ,GAAGnmJ,MAAQ0lB,EAAAA,EAEXygI,GAAGnmJ,OAAS0lB,EAAAA,EAETygI,MAII,WAAXA,GAAGp3I,MAAiC,UAAZo3I,GAAGnmJ,OAChB,WAAXiiD,GAAGlzC,MAAiC,UAAZkzC,GAAGjiD,aAC3Bqf,KAAK4pF,SAAW,CAACk9C,GAAGl9C,SAAS,GAAIhnD,GAAGgnD,SAAS,SACxCm9C,oBAAqB,EACnB/mI,QAGK,UAAZ8mI,GAAGnmJ,OAAiC,UAAZiiD,GAAGjiD,aAC3Bqf,KAAKtQ,KAAO,UACZsQ,KAAKrf,MAAQ,SACbqf,KAAK4pF,SAAW,CAAC/kG,KAAK8kG,WAAW,UAAW,SAAUm9C,GAAGl9C,SAAS,GAAIhnD,UACjEmkG,oBAAqB,EACnB/mI,QAGK,UAAZ8mI,GAAGnmJ,OAAiC,UAAZiiD,GAAGjiD,aAC3Bqf,KAAKtQ,KAAO,UACZsQ,KAAKrf,MAAQ,SACbqf,KAAK4pF,SAAW,CAAC/kG,KAAK8kG,WAAW,UAAW,SAAUm9C,GAAIlkG,GAAGgnD,SAAS,UACjEm9C,oBAAqB,EACnB/mI,QAII,WAAX8mI,GAAGp3I,MAAiC,UAAZo3I,GAAGnmJ,QACtBiiD,GAAGm0C,OACJn0C,GAAGm0C,KAAOlyF,KAAK6nG,OAAOr6B,QAAQzvB,KAE7BkkG,GAAGl9C,SAAS,GAAG7S,OAChB+vD,GAAGl9C,SAAS,GAAG7S,KAAOlyF,KAAK6nG,OAAOr6B,QAAQy0E,GAAGl9C,SAAS,KAEtDhnD,GAAGm0C,OAAS+vD,GAAGl9C,SAAS,GAAG7S,aAC3B+vD,GAAGl9C,SAAS,GAAK/kG,KAAK8kG,WAAW,UAAW,SACxCm9C,GAAGl9C,SAAS,GACZ/kG,KAAK8kG,WAAW,aAAc,SAE7Bo9C,oBAAqB,EACnBD,MAKA,cAAXlkG,GAAGlzC,MAAmC,WAAXo3I,GAAGp3I,MAClB,UAAZo3I,GAAGnmJ,OACoB,cAAvBmmJ,GAAGl9C,SAAS,GAAGl6F,YACfsQ,KAAKrf,MAAQ,SACbqf,KAAK4pF,SAAW,CACZk9C,GAAGl9C,SAAS,GACZ/kG,KAAK8kG,WAAW,UAAW,SAAUm9C,GAAGl9C,SAAS,GAAIhnD,UAEpDmkG,oBAAqB,EACnB/mI,QAII,WAAX8mI,GAAGp3I,MAAiC,UAAZo3I,GAAGnmJ,OAChB,WAAXiiD,GAAGlzC,MAAiC,UAAZkzC,GAAGjiD,QAC3BmmJ,GAAGl9C,SAAS,GAAG7S,KAAOlyF,KAAK6nG,OAAOr6B,QAAQy0E,GAAGl9C,SAAS,IACtDhnD,GAAGgnD,SAAS,GAAG7S,KAAOlyF,KAAK6nG,OAAOr6B,QAAQzvB,GAAGgnD,SAAS,IAClDk9C,GAAGl9C,SAAS,GAAG7S,OAASn0C,GAAGgnD,SAAS,GAAG7S,aACvC+vD,GAAGl9C,SAAS,GAAK/kG,KAAK8kG,WAAW,UAAW,SACxCm9C,GAAGl9C,SAAS,GACZhnD,GAAGgnD,SAAS,SAEXm9C,oBAAqB,EACnBD,aAWd,YACDA,GAAK9mI,KAAK4pF,SAAS,GAEJ,eADfhnD,GAAK5iC,KAAK4pF,SAAS,IACZl6F,MAAqC,IAAbkzC,GAAGjiD,aAC9BiiD,GAAGjiD,MAAQ,EACJiiD,MAEI,cAAXA,GAAGlzC,MAAoC,GAAZkzC,GAAGjiD,aACvBmmJ,MAEI,cAAXA,GAAGp3I,MAAoC,GAAZo3I,GAAGnmJ,aACvBmmJ,MAEI,cAAXA,GAAGp3I,MAAqC,IAAbo3I,GAAGnmJ,OACnB,cAAXiiD,GAAGlzC,MAAqC,IAAbkzC,GAAGjiD,aACvBmmJ,MAII,WAAXA,GAAGp3I,MAAiC,UAAZo3I,GAAGnmJ,aAC3Bqf,KAAK4pF,SAAW,CACZk9C,GAAGl9C,SAAS,GACZ/kG,KAAK8kG,WAAW,UAAW,SACvBm9C,GAAGl9C,SAAS,GACZhnD,KAED5iC,YAKXA,KAAKrf,WAIJ,YACDmmJ,GAAK9mI,KAAK4pF,SAAS,GACnBhnD,GAAK5iC,KAAK4pF,SAAS,GACJ,cAAXk9C,GAAGp3I,MAAmC,cAAXkzC,GAAGlzC,MAC9Bo3I,GAAGnmJ,OAASiiD,GAAGjiD,aACfmmJ,GAAGnmJ,OAASiiD,GAAGjiD,MACRmmJ,MAGI,YAAXA,GAAGp3I,MAAiC,YAAXkzC,GAAGlzC,MAC5Bo3I,GAAGnmJ,OAASiiD,GAAGjiD,aACfqf,KAAK4pF,SAAS,GAAK/kG,KAAK8kG,WAAW,aAAc,GACjD3pF,KAAKrf,MAAQ,SACNqf,QAGI,WAAX8mI,GAAGp3I,MAAiC,UAAZo3I,GAAGnmJ,aAC3Bqf,KAAKrf,MAAQ,SACbqf,KAAK4pF,SAAS,GAAKhnD,GACnB5iC,KAAK4pF,SAAS,GAAKk9C,GAAGl9C,SAAS,QAC1Bm9C,oBAAqB,EACnB/mI,QAGI,WAAX4iC,GAAGlzC,MAAiC,UAAZkzC,GAAGjiD,aAC3Bqf,KAAKrf,MAAQ,SACbqf,KAAK4pF,SAAS,GAAKhnD,GAAGgnD,SAAS,QAC1Bm9C,oBAAqB,EACnB/mI,QAII,WAAX8mI,GAAGp3I,MAAiC,UAAZo3I,GAAGnmJ,OAChB,WAAXiiD,GAAGlzC,MAAiC,UAAZkzC,GAAGjiD,QAE3BmmJ,GAAGl9C,SAAS,GAAG7S,KAAOlyF,KAAK6nG,OAAOr6B,QAAQy0E,GAAGl9C,SAAS,IACtDhnD,GAAGgnD,SAAS,GAAG7S,KAAOlyF,KAAK6nG,OAAOr6B,QAAQzvB,GAAGgnD,SAAS,IAClDk9C,GAAGl9C,SAAS,GAAG7S,OAASn0C,GAAGgnD,SAAS,GAAG7S,aAEvC/2E,KAAKrf,MAAQ,SACbqf,KAAK4pF,SAAW,CACZ/kG,KAAK8kG,WAAW,UAAW,SACvBm9C,GAAGl9C,SAAS,GACZhnD,GAAGgnD,SAAS,IAChBk9C,GAAGl9C,SAAS,SAEXm9C,oBAAqB,EACnB/mI,QAIA,WAAX8mI,GAAGp3I,MAAiC,UAAZo3I,GAAGnmJ,QAE3BmmJ,GAAGl9C,SAAS,GAAG7S,KAAOlyF,KAAK6nG,OAAOr6B,QAAQy0E,GAAGl9C,SAAS,IACtDhnD,GAAGm0C,KAAOlyF,KAAK6nG,OAAOr6B,QAAQzvB,IAC1BkkG,GAAGl9C,SAAS,GAAG7S,OAASn0C,GAAGm0C,aAE3B/2E,KAAKrf,MAAQ,SACbqf,KAAK4pF,SAAW,CACZ/kG,KAAK8kG,WAAW,UAAW,SACvBm9C,GAAGl9C,SAAS,GACZ/kG,KAAK8kG,WAAW,aAAc,IAClC/mD,SAECmkG,oBAAqB,EACnB/mI,QAIA,WAAX4iC,GAAGlzC,MAAiC,UAAZkzC,GAAGjiD,QAE3BiiD,GAAGgnD,SAAS,GAAG7S,KAAOlyF,KAAK6nG,OAAOr6B,QAAQzvB,GAAGgnD,SAAS,IACtDk9C,GAAG/vD,KAAOlyF,KAAK6nG,OAAOr6B,QAAQy0E,IAC1BlkG,GAAGgnD,SAAS,GAAG7S,OAAS+vD,GAAG/vD,aAE3B/2E,KAAKrf,MAAQ,SACbqf,KAAK4pF,SAAW,CACZ/kG,KAAK8kG,WAAW,UAAW,SACvB9kG,KAAK8kG,WAAW,aAAc,GAC9B/mD,GAAGgnD,SAAS,IAChBk9C,SAECC,oBAAqB,EACnB/mI,eAOd,YACD8mI,GAAK9mI,KAAK4pF,SAAS,GAEJ,YADfhnD,GAAK5iC,KAAK4pF,SAAS,IACZl6F,MAAiC,UAAZkzC,GAAGjiD,aAC3Bqf,KAAKrf,MAAQ,SACbqf,KAAK4pF,SAAS,GAAKhnD,GAAGgnD,SAAS,QAC1Bm9C,oBAAqB,EACnB/mI,eAIV,oBACMnb,KAAKmiJ,mBAAmBhnI,aAGhCA,MAGXgnI,mBAAoB,SAAUhnI,UACtBjb,IAAMib,KAAK4pF,SAAS,GAAGjpG,MACvB+3F,IAAM14E,KAAK4pF,SAAS,MAGN,GAAdlR,IAAIh5F,cACGsgB,YAGHjb,SAMC,UACA,SACkB,cAAf2zF,IAAI,GAAGhpF,MAAyC,IAAjBgpF,IAAI,GAAG/3F,aACtCqf,KAAKtQ,KAAO,aACZsQ,KAAKrf,MAAQ,EACNqf,QAEQ,YAAf04E,IAAI,GAAGhpF,MAAsC,MAAhBgpF,IAAI,GAAG/3F,aACpCqf,KAAKtQ,KAAO,aACZsQ,KAAKrf,MAAQ,EACNqf,QAEQ,WAAf04E,IAAI,GAAGhpF,MAAqC,UAAhBgpF,IAAI,GAAG/3F,OACR,cAA3B+3F,IAAI,GAAGkR,SAAS,GAAGl6F,MAAwBgpF,IAAI,GAAGkR,SAAS,GAAGjpG,MAAQ,GAAM,GACjD,YAA3B+3F,IAAI,GAAGkR,SAAS,GAAGl6F,MAAkD,MAA5BgpF,IAAI,GAAGkR,SAAS,GAAGjpG,aAC5Dqf,KAAKtQ,KAAO,aACZsQ,KAAKrf,MAAQ,EACNqf,eAQV,SACkB,cAAf04E,IAAI,GAAGhpF,MAAyC,IAAjBgpF,IAAI,GAAG/3F,aACtCqf,KAAKtQ,KAAO,aACZsQ,KAAKrf,MAAQ,EACNqf,QAEQ,YAAf04E,IAAI,GAAGhpF,MAAsC,MAAhBgpF,IAAI,GAAG/3F,aACpCqf,KAAKtQ,KAAO,UACZsQ,KAAKrf,MAAQ,SACbqf,KAAK4pF,SAAW,CAAC/kG,KAAK8kG,WAAW,aAAc,IACxC3pF,eAgBV,SACkB,cAAf04E,IAAI,GAAGhpF,MAAyC,IAAjBgpF,IAAI,GAAG/3F,aACtCqf,KAAKtQ,KAAO,aACZsQ,KAAKrf,MAAQ,EACNqf,eAKV,SACkB,cAAf04E,IAAI,GAAGhpF,MAAyC,IAAjBgpF,IAAI,GAAG/3F,aACtCqf,KAAKtQ,KAAO,aACZsQ,KAAKrf,MAAQ,EACNqf,YAMZA,QAKR/c,IAAIymG,MA+CfzsG,OAAO,aAAa,CAAC,MAAO,eAAe,SAAUgG,IAAKkV,aAQtDlV,IAAIgkJ,KAAO,CAQPC,WAAY,SAAUjiJ,MAAOkiJ,QAAS/4E,YAC9BtsE,EAAG6V,EAAGxY,MAeL2C,KAbAqW,KAAKlJ,QAAQk4I,WACdA,QAAU,CAACA,UAGVhvI,KAAKlJ,QAAQm/D,UACdA,OAAS,CAACA,SAGdz2D,EAAIpG,KAAKC,IAAI21I,QAAQznJ,OAAQ0uE,OAAO1uE,QAEpCynJ,QAAQznJ,OAASiY,EACjBy2D,OAAO1uE,OAASiY,EAEN1S,MAAMsJ,WACRtJ,MAAMsJ,QAAQvQ,eAAe8D,OACxB3C,EAAI,EAAGA,EAAIwY,EAAGxY,IACf8F,MAAMsJ,QAAQzM,GAAGqlJ,QAAQhoJ,IAAMivE,OAAOjvE,IAWtDioJ,cAAe,SAAUniJ,MAAOkiJ,aACxBrlJ,EAAG6V,EAAGxY,MAUL2C,KARAqW,KAAKlJ,QAAQk4I,WACdA,QAAU,CAACA,UAGfxvI,EAAIwvI,QAAQznJ,OAEZynJ,QAAQznJ,OAASiY,EAEP1S,MAAMsJ,WACRtJ,MAAMsJ,QAAQvQ,eAAe8D,OACxB3C,EAAI,EAAGA,EAAIwY,EAAGxY,WACR8F,MAAMsJ,QAAQzM,GAAGqlJ,QAAQhoJ,KAWhD8X,IAAK,SAAU/R,SACM,iBAANA,GAAqC,aAAnBA,EAAEmpE,OAAO,EAAG,KACrCnpE,EAAI,IAAMA,EAAI,KAGXA,GAUXmiJ,eAAgB,SAAUC,SAAUpiJ,OAC5BtD,EAAGywI,GAAIlzI,EACP4Q,IAAM,GACN0a,KAAOtS,KAAK3D,SAAS8yI,UACrBC,SAAW,OAEVpoJ,EAAI,EAAGA,EAAImB,UAAUZ,OAAQP,IAC9BooJ,SAAShnJ,KAAKD,UAAUnB,QAG5B4Q,IAAMoI,KAAK3D,SAASzE,IAAK9M,IAAI0tE,QAAQrsE,UAAU,GAC1CnF,EAAIooJ,SAAS7nJ,OAAQP,EAAI,EAAGA,IAC7B4Q,IAAMoI,KAAK3D,SAASzE,IAAKw3I,SAASpoJ,EAAI,IAAI,OAGzCyC,KAAKmO,IACFA,IAAI/R,eAAe4D,KACnBywI,GAAKzwI,EAAE2B,cAEe,WAAlB4L,QAAOY,IAAInO,KAAmBmO,IAAInO,KAAO6oB,KAAK4nH,YAEvC5nH,KAAK4nH,YAKjB5nH,MASX+8H,kBAAmB,SAAUviJ,MAAO5G,SAC5B6T,EAAGhN,MAIFA,KAFLgN,EAAIrN,KAAKwiJ,eAAehpJ,IAAI88F,gBAAiBl4F,IAAI0tE,QAAQtyE,IAAIk2F,SAEnDl2F,IAAIo2F,KACNp2F,IAAIo2F,KAAKz2F,eAAekH,KACxBgN,EAAEhN,GAAKL,KAAKwiJ,eAAehpJ,IAAIo2F,KAAKvvF,GAAGi2F,gBACXl4F,IAAI0tE,QAAQtyE,IAAIk2F,QAAQrvF,GACxBjC,IAAI0tE,QAAQtyE,IAAIo2F,KAAKvvF,GAAGqvF,SACpDriF,EAAEhN,GAAGlD,GAAK3D,IAAIo2F,KAAKvvF,GAAGlD,GACtBkQ,EAAEhN,GAAGzG,KAAOJ,IAAIo2F,KAAKvvF,GAAGzG,aAIhCyT,EAAElQ,GAAK3D,IAAI2D,GACXkQ,EAAEzT,KAAOJ,IAAII,KAENyT,GAGXgqG,eAAgB,SAASurC,QAASxiJ,MAAOyiJ,qBACrCD,QAAQlnJ,KAAK,CACTlC,IAAKqpJ,aACLz+H,OAAQ,iBACRmoH,OAAQ,CAACnsI,MAAMkzC,iBAAkBlzC,MAAMw0G,mBAGpCguC,SASXjzD,KAAM,SAAUvvF,WACRnD,EAAGzD,IAAKmG,QAASU,EACjBunH,MAAQ,GAERk7B,YAAc,GACd12I,IAAMhM,MAAMu4D,YAAY99D,gBAEvBwnJ,WAAWjiJ,MAAO,UAAU,GAE5BnD,EAAI,EAAGA,EAAImP,IAAKnP,OAEjB0C,QAAU,KADVnG,IAAM4G,MAAMu4D,YAAY17D,IAGf8lJ,QAAUvpJ,IAAIm2F,KAAM,KACzBhwF,QAAQkL,KAAOrR,IAAI48F,UACnBz2F,QAAQqM,QAAUxS,IAAI68F,aAAah9F,QAGd,UAAjBsG,QAAQkL,MAA2C,IAAvBlL,QAAQqM,QAAQ,KAC5CrM,QAAQqM,QAAUrM,QAAQqM,QAAQ3S,MAAM,IAGvCgH,EAAI,EAAGA,EAAIV,QAAQqM,QAAQnR,OAAQwF,IAChCiT,KAAKvJ,SAASpK,QAAQqM,QAAQ3L,KACA,MAA1BV,QAAQqM,QAAQ3L,GAAG,IACO,MAA1BV,QAAQqM,QAAQ3L,GAAG,GAEvBV,QAAQqM,QAAQ3L,GAAK,IAAMV,QAAQqM,QAAQ3L,GAAK,IACzCiT,KAAKlJ,QAASzK,QAAQqM,QAAQ3L,MACrCV,QAAQqM,QAAQ3L,GAAK,IAAMV,QAAQqM,QAAQ3L,GAAG6J,WAAa,KAInEvK,QAAQsM,WAAajM,KAAK2iJ,kBAAkBviJ,MAAO5G,KAC9B,WAAjBmG,QAAQkL,MAAqBrR,IAAIm7F,WACjCizB,MAAMlsH,KAAK,CACPlC,IAAKA,IAAI2D,GACT1D,KAAM,YACNkR,KAAK,IAIbm4I,YAAYpnJ,KAAKiE,qBAIpB4iJ,cAAcniJ,MAAO,UAEnB,CACHX,SAAUqjJ,YACVl7B,MAAOA,MACPg7B,QAhDU,KA2DlBI,gBAAiB,SAAU31I,EAAG41I,eACtB3oJ,EACA+F,EAAI,OAEH/F,EAAI,EAAGA,EAAI+S,EAAExS,OAAQP,IACtB+F,EAAE3E,KAAKunJ,UAAUvpJ,KAAKsG,KAAMqN,EAAE/S,YAG3B+F,EAAEjF,KAAK,OAQlB8nJ,OAAQ,SAAU1pJ,SACVc,EAAGqW,KAAMlX,oBAEED,UACV,YACGA,IAAK,IACLmX,KAAO,GAEH2C,KAAKlJ,QAAQ5Q,KAAM,KACdc,EAAI,EAAGA,EAAId,IAAIqB,OAAQP,IACxBqW,KAAKjV,KAAKsE,KAAKkjJ,OAAO1pJ,IAAIc,WAGvB,IAAMqW,KAAKvV,KAAK,KAAO,QAG7B3B,QAAQD,IACLA,IAAIL,eAAeM,OACnBkX,KAAKjV,KAAKjC,KAAO,KAAOuG,KAAKkjJ,OAAO1pJ,IAAIC,cAIzC,KAAOkX,KAAKvV,KAAK,MAAQ,YAE7B,WACN,eACM,IAAO5B,IAAIwB,QAAQ,MAAM,QAAQA,QAAQ,UAAW,QAAU,QACpE,aACA,iBACMxB,IAAI0Q,eACV,aACM,SASfi5I,SAAU,SAAU/iJ,WACZ9F,EAAGmF,SAAUtC,GACbwyF,KAAO3vF,KAAK2vF,KAAKvvF,OACjBgjJ,OAAS,OAEbzzD,KAAKizD,QAAU5iJ,KAAKq3G,eAAe1nB,KAAKizD,QAASxiJ,MAAO,UAExDX,SAAWkwF,KAAKlwF,SAEXnF,EAAI,EAAGA,EAAImF,SAAS5E,OAAQP,IACzBmF,SAASnF,GAAG2R,WAAWrS,KAAKiB,OAAS,GACrCuoJ,OAAO1nJ,KAAK,MAAQ+D,SAASnF,GAAG2R,WAAWrS,MAE/CwpJ,OAAO1nJ,KAAK,IAAMpB,EAAI,MAAQmF,SAASnF,GAAGuQ,KAAO,IAAMpL,SAASnF,GAAG0R,QAAQ5Q,KAAK,MAAQ,KAAO4E,KAAKkjJ,OAAOzjJ,SAASnF,GAAG2R,YAAYjR,QAAQ,KAAM,OAAS,KAEjI,SAArByE,SAASnF,GAAGuQ,OAEZ1N,GAAKsC,SAASnF,GAAG2R,WAAW9O,GACW,OAAnCiD,MAAMsJ,QAAQvM,IAAIs5F,cAClB2sD,OAAO1nJ,KAAK,IAAMpB,EAAI,uBAG9B8oJ,OAAO1nJ,KAAK,QAGXpB,EAAI,EAAGA,EAAIq1F,KAAKizD,QAAQ/nJ,OAAQP,IACjC8oJ,OAAO1nJ,KAAKi0F,KAAKizD,QAAQtoJ,GAAGd,IAAM,IAAMm2F,KAAKizD,QAAQtoJ,GAAG8pB,OAAS,IAAMpkB,KAAKgjJ,gBAAgBrzD,KAAKizD,QAAQtoJ,GAAGiyI,OAAQvsI,KAAKkjJ,QAAU,MACnIE,OAAO1nJ,KAAK,QAGXpB,EAAI,EAAGA,EAAIq1F,KAAKi4B,MAAM/sH,OAAQP,IAC/B8oJ,OAAO1nJ,KAAKi0F,KAAKi4B,MAAMttH,GAAGd,IAAM,IAAMm2F,KAAKi4B,MAAMttH,GAAGb,KAAO,MAAQuG,KAAKkjJ,OAAOvzD,KAAKi4B,MAAMttH,GAAGqQ,KAAO,KACpGy4I,OAAO1nJ,KAAK,WAGT0nJ,OAAOhoJ,KAAK,OAQvBioJ,aAAc,SAAUjjJ,WAChB9F,EAAGmF,SAAUtC,GACbwyF,KAAO3vF,KAAK2vF,KAAKvvF,OACjBgjJ,OAAS,OAEbzzD,KAAKizD,QAAU5iJ,KAAKq3G,eAAe1nB,KAAKizD,QAASxiJ,MAAO,SAExDX,SAAWkwF,KAAKlwF,SAEXnF,EAAI,EAAGA,EAAImF,SAAS5E,OAAQP,IAC7B8oJ,OAAO1nJ,KAAK,iBAAmB+D,SAASnF,GAAGuQ,KAAO,OAASpL,SAASnF,GAAG0R,QAAQ5Q,KAAK,MAAQ,MAAQkY,KAAK7C,OAAOhR,SAASnF,GAAG2R,YAAc,MAEjH,SAArBxM,SAASnF,GAAGuQ,OAEZ1N,GAAKsC,SAASnF,GAAG2R,WAAW9O,GACW,OAAnCiD,MAAMsJ,QAAQvM,IAAIs5F,cAClB2sD,OAAO1nJ,KAAK,kBAAoByB,GAAK,iCAAmCA,GAAK,0BAKpF7C,EAAI,EAAGA,EAAIq1F,KAAKizD,QAAQ/nJ,OAAQP,IACjC8oJ,OAAO1nJ,KAAKi0F,KAAKizD,QAAQtoJ,GAAGd,IAAM,IAAMm2F,KAAKizD,QAAQtoJ,GAAG8pB,OAAS,IAAMpkB,KAAKgjJ,gBAAgBrzD,KAAKizD,QAAQtoJ,GAAGiyI,OAAQj5H,KAAK7C,QAAU,MACnI2yI,OAAO1nJ,KAAK,QAGXpB,EAAI,EAAGA,EAAIq1F,KAAKi4B,MAAM/sH,OAAQP,IAC/B8oJ,OAAO1nJ,KAAKi0F,KAAKi4B,MAAMttH,GAAGd,IAAM,IAAMm2F,KAAKi4B,MAAMttH,GAAGb,KAAO,MAAQ6Z,KAAK7C,OAAOk/E,KAAKi4B,MAAMttH,GAAGqQ,KAAO,KACpGy4I,OAAO1nJ,KAAK,WAGT0nJ,OAAOhoJ,KAAK,QAIpBgD,IAAIgkJ,QA0CfhqJ,OAAO,eAAe,CAClB,MAAO,aAAc,eACtB,SAAUgG,IAAKkV,KAAM+oH,cAuFpBj+H,IAAIklJ,WAAa,SAASljJ,MAAO4L,QAASC,gBAClC8lC,GAAIC,GAAIpiC,EAAGvD,KAAMk3I,gBAGE,IAAnBv3I,QAAQnR,aAmCR0oJ,aAAev3I,QAAQrR,KAAI,SAASgoG,cAAiB,YAAcA,QAAU,OACvE,IAAI3mG,MAAM,iDACZunJ,aAAanoJ,KAAK,MADN,iEAlCZkY,KAAKlJ,QAAQ4B,QAAQ,KAAOA,QAAQ,GAAGnR,OAAS,EAChDwR,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,OAAQ,UAC9DslC,GAAK3xC,MAAMwM,OAAO,QAASZ,QAAQ,GAAIK,WACpC,GAAIiH,KAAKvJ,SAASiC,QAAQ,KAAOsH,KAAK9I,QAAQwB,QAAQ,IACzD+lC,GAAM3xC,MAAMG,OAAOyL,QAAQ,SACxB,GAAIsH,KAAKnJ,WAAW6B,QAAQ,KAAOsH,KAAK9I,QAAQwB,QAAQ,MAC3D+lC,GAAK/lC,QAAQ,SACV,CAAA,KAAIsH,KAAKnJ,WAAW6B,QAAQ,KAAOA,QAAQ,KAAKnR,QAAUmR,QAAQ,KAAKnR,QAAU,SAI9E,IAAImB,MAAM,0DACJgQ,QAAQ,IAAM,kBAAoBA,QAAQ,IADtC,+DAHhBK,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,OAAQ,UAC9DslC,GAAKsqF,MAAMU,YAAY38H,MAAO4L,QAAQ,KAAMK,SAQ5CiH,KAAKlJ,QAAQ4B,QAAQ,KAAOA,QAAQ,GAAGnR,OAAS,EAChDwR,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,OAAQ,UAC9DulC,GAAK5xC,MAAMwM,OAAO,QAASZ,QAAQ,GAAIK,WACpC,GAAIiH,KAAKvJ,SAASiC,QAAQ,KAAOsH,KAAK9I,QAAQwB,QAAQ,IACzDgmC,GAAM5xC,MAAMG,OAAOyL,QAAQ,SACxB,GAAIsH,KAAKnJ,WAAW6B,QAAQ,KAAQsH,KAAK9I,QAAQwB,QAAQ,MAC5DgmC,GAAKhmC,QAAQ,SACV,CAAA,KAAIsH,KAAKnJ,WAAW6B,QAAQ,KAAOA,QAAQ,KAAKnR,QAAUmR,QAAQ,KAAKnR,QAAU,SAI9E,IAAImB,MAAM,0DACJgQ,QAAQ,IAAM,kBAAoBA,QAAQ,IADtC,+DAHhBK,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,OAAQ,UAC9DulC,GAAKqqF,MAAMU,YAAY38H,MAAO4L,QAAQ,KAAMK,aAcpDA,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,QACtD6G,KAAK7D,MAAMpD,KAAMiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,OAAQ,WACxEmD,EAAIxP,MAAMwM,OAAO,QAAS,CAAC,CAAC,GAAI,CAAC,IAAKP,OAKnCw7H,gBAAkB,eAGb4S,GAAI+I,GAAI1kH,GAAIiC,GACZjzB,EAAGiT,EAAGnkB,EAGNolD,GAAI5S,MAAO93B,MANXjX,EAAI,EACJojJ,MAAQ1xG,GAAGjR,KAAKkR,IAGhB0xG,SAAW3xG,GACX4xG,SAAW3xG,OAGfgQ,GAAK1uC,KAAKrG,SAAS2C,EAAEmD,QAAQ+oE,WAC7B1sC,OAAS97B,KAAKrG,SAAS2C,EAAEmD,QAAQq8B,OACjC93B,MAAQhE,KAAKrG,SAAS2C,EAAEmD,QAAQuE,OAC5BhE,KAAKrG,SAAS2C,EAAEmD,QAAQgrD,WACxB2lF,SAAW1xG,GACX2xG,SAAW5xG,GACX3C,OAASA,OAEbqrG,GAAK/tI,KAAK8hB,IAAI4gB,OACdo0G,GAAK92I,KAAKwiB,IAAIkgB,OACdtQ,IAAM6kH,SAASvlH,IAAMslH,SAAStlH,KAAOqlH,MACrC1iH,IAAM4iH,SAAStlH,IAAMqlH,SAASrlH,KAAOolH,MAGrChJ,IAAMnjI,MAAQ5K,KAAKwC,IAAIs0I,IACvBA,IAAMlsI,MAAQ5K,KAAKwC,IAAIs0I,SAElBriH,MAAQ,QACRC,MAAQ,GAEN/gC,EAAIojJ,OACP31I,EAAI41I,SAAStlH,IAAMU,GAAKz+B,EACxB0gB,EAAI2iI,SAASrlH,IAAM0C,GAAK1gC,EAIxBmjJ,IADA5mJ,EAAI8P,KAAKC,IAAI8tI,GAAIgJ,MAAQpjJ,GAAKqM,KAAKwC,IAAIurI,IAEvCA,IAAM79I,OAEDukC,MAAMzlC,KAAKoS,QACXszB,MAAM1lC,KAAKqlB,QAEXogB,MAAMzlC,KAAKoS,EAAIgxB,GAAK27G,GAAK15G,GAAKyiH,SAC9BpiH,MAAM1lC,KAAKqlB,EAAI+d,GAAK0kH,GAAKziH,GAAK05G,SAE9Bt5G,MAAMzlC,KAAKiT,UACXyyB,MAAM1lC,KAAKiT,KAChBtO,GAAK2hD,IAINpyC,GAGXxR,IAAIsB,gBAAgB,OAAQtB,IAAIklJ,YAEzB,CACHA,WAAYllJ,IAAIklJ,eAgDxBlrJ,OAAO,wBAAwB,CAC3B,MAAO,aAAc,iBAAkB,iBACxC,SAAUgG,IAAKkV,KAAM9J,MAAOu7H,aAIvBjyD,yBACyB,WACjBiyD,QAAQA,QAAQ7rI,UAAUqoF,OAAO7nF,KAAKsG,WAEjCI,MAAMs2F,aAAa12F,KAAKi8E,eACxB77E,MAAMs2F,aAAa12F,KAAK61E,aAExBz1E,MAAMs2F,aAAa12F,KAAK07E,eACxBt7E,MAAMs2F,aAAa12F,KAAK+7E,gBAExB37E,MAAMs2F,aAAa12F,KAAKkQ,OAEzBlQ,KAAK4jJ,wBACAxjJ,MAAMs2F,aAAa12F,KAAKg8E,UAbzClJ,WAgBW,kBACI9yE,KAAKg8E,QAAQzoC,mBA0DhCn1C,IAAIylJ,oBAAsB,SAAUzjJ,MAAO4L,QAASC,gBAC5CoC,GAAI2tE,QAAS8nE,OAAQjuE,OAAQoG,SAAUP,SAAUK,UAAW7rE,MAAO7D,KACnE03I,kBAAmB,KAEA,IAAnB/3I,QAAQnR,QAAgBmR,QAAQ,GAAGnB,OAASrB,MAAMhG,oBAClDw4E,QAAUhwE,QAAQ,GAClB83I,OAAS9nE,QAAQnG,YACd,GAAuB,IAAnB7pE,QAAQnR,QAAgBmR,QAAQ,GAAGnB,OAASrB,MAAMhH,mBACzDshJ,OAAS93I,QAAQ,GACjBK,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAU,gBAAiB,WACxEuvE,QAAU57E,MAAMwM,OAAO,UAAW,CAACk3I,QAASz3I,MAC5C03I,kBAAmB,MAChB,CAAA,GAAuB,IAAnB/3I,QAAQnR,QACXmR,QAAQ,GAAGvB,eAAiBjB,MAAMvF,oBAAqBqP,KAAK9I,QAAQwB,QAAQ,UAI1E,IAAIhQ,MAAM,oEAAsEgQ,QAAQ,IAAM,MAHpGgwE,QAAUhwE,QAAQ,GAClB83I,OAAS93I,QAAQ,UAKrBK,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,gBAAiB,aACvEsvE,UAAY37E,MAAMwM,OAAO,QAAS,CAAC,iBACxB,CAACk3I,OAAO1lH,IAAM,EAAI0lH,OAAOzlH,OAChChyB,MAEJA,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,gBAAiB,YACvEivE,SAAWt7E,MAAMwM,OAAO,OAAQ,CAACk3I,OAAQ/nE,WAAY1vE,MAErDA,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,gBAAiB,UACvEopE,OAASz1E,MAAMwM,OAAO,SAAU,CAACk3I,OAAO1lH,IAAM,EAAG0lH,OAAOzlH,IAAKq9C,UAAWrvE,MAExEA,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,gBAAiB,YACvEwvE,SAAW77E,MAAMwM,OAAO,QAAS,CAAC,iBACvB,CAACipE,OAAOz3C,IAAKy3C,OAAOx3C,KAAOw3C,OAAOz3C,IAAM0lH,OAAO1lH,KAAO49C,QAAQzoC,cACrElnC,OAEJA,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,kBACjD0sC,QAAU7lC,KAAK9G,eAAeH,KAAK8sC,QAAS/4C,MAAMqM,QAAS,gBAAiB,YACjF4B,GAAKjO,MAAMwM,OAAO,UAAW,CAACk3I,OAAQjuE,OAAQoG,UAAW5vE,OAStDgH,MAAQy/D,WACXzkE,GAAG2tE,QAAUA,QACb3tE,GAAGu1I,kBAAoBG,iBAIvB11I,GAAG8qC,QAAQ,GAAGg8C,UAAS,GAAO,GAE9B9oF,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,gBAAiB,UACvEyD,MAAQ9P,MAAMwM,OAAO,OAAQ,CACzB,kBAAqBipE,OAAOz3C,IAAM,IAClC,iBAAmD,IAA7By3C,OAAOx3C,IAAM49C,SAAS59C,MAC5C,iBAAqB,KACtBhyB,OAEGs0F,UAAS,kBACJrtF,KAAK/E,QAAQF,GAAGgF,QAASC,KAAKrG,SAASiD,MAAM6C,QAAQ/D,YAEhEkB,MAAM8uE,aAEN3wE,GAAGwnE,OAASA,OACZxnE,GAAG0tE,UAAYA,UACf1tE,GAAGqtE,SAAWA,SACdrtE,GAAG4tE,SAAWA,SACd5tE,GAAG6B,MAAQA,MAEX7B,GAAGuhF,KAAO,CACN/Z,OAAQA,OACRmuE,UAAWjoE,UACXm3D,SAAUx3D,SACVuoE,SAAUhoE,SACV/rE,MAAOA,OAEX7B,GAAGwhF,SAASn0F,KAAKm6E,OAAQkG,UAAWL,SAAUO,SAAU/rE,OAExD7B,GAAG0hF,UAAY3xF,IAAIuR,SAAStB,GAAG0hF,UAAW,CACtC/T,QAAS,UACTnG,OAAQ,SACRkG,UAAW,YACXL,SAAU,WACVO,SAAU,WACV/rE,MAAO,QACPmD,MAAO,QACP4iB,EAAG,UAGP5nB,GAAGkzE,OAASzO,yBAELzkE,IAGXjQ,IAAIsB,gBAAgB,gBAAiBtB,IAAIylJ,qBAElC,CACHA,oBAAqBzlJ,IAAIylJ,wBAiDjCzrJ,OAAO,mBAAmB,CACtB,MAAO,YAAa,eACrB,SAAUgG,IAAK02B,IAAKxhB,UAIfw/D,gCACgC,gBACnBoxE,OAASlkJ,KAAK60F,iBAAiB/c,aAC/B13E,MAAMo6B,iBAoHvBp8B,IAAI+lJ,eAAiB,SAAU/jJ,MAAO4L,QAASC,gBACvCiN,EAAGi4E,IACH9kF,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,mBAQ1D0kF,IAAM,CAACnlF,QAAQ,GAAIA,QAAQ,GACvB,wFAMJkN,EAAI9Y,MAAMwM,OAAO,OAAQukF,IAAK9kF,OAC5BxB,KAAOyI,KAAK5P,qBAEdwV,EAAE27E,iBAAmB37E,EAAEynE,SAASmiB,WAAW,GAAGA,WAAW,GACzD5pF,EAAE4sE,cAAgB5sE,EAAEynE,SAASmiB,WAAW,GAAGA,WAAW,GAEtD5pF,EAAE07E,YAAc17E,EAAE27E,iBAClB37E,EAAE07E,YAAYzd,WAAa9qE,KAAK8qE,SAEhCj+D,EAAE4sE,cAAc1kF,UAAY4K,QAAQ,GACpCkN,EAAE27E,iBAAiB13F,GAAK+b,EAAEynE,SAASxjF,GAAK,YACxC+b,EAAE4sE,cAAc3oF,GAAK+b,EAAEynE,SAASxjF,GAAK,SACrC+b,EAAE4sE,cAAcZ,aAAa,MAAOhsE,EAAE27E,iBAAiB13F,IAGvD+b,EAAEnI,WAAWO,SAAW,MACxBlR,MAAMmvE,SAASmW,gBAAgBxsE,GAAG,GAElCA,EAAE27E,iBAAiB/c,QAAUzrE,KAAKyrE,QAElC5+D,EAAEgrI,OAAS73I,KAAKyrE,QAShB5+D,EAAE7F,MAAQ,kBACCrT,KAAKkkJ,QAGhBhrI,EAAEshB,OAAS,kBACHx6B,KAAKivF,cACL7wF,IAAIohG,KAAKtmG,UAAUshC,OAAO9gC,KAAKsG,WAC1BkkJ,OAASlkJ,KAAK60F,iBAAiB/c,SAEjC93E,MAGX80B,IAAIhd,SAASoB,EAAE27E,iBAAkB,SAAU/hB,gCAAiC55D,GAErEA,GAGX9a,IAAIsB,gBAAgB,WAAYtB,IAAI+lJ,gBAE7B,CACHA,eAAgB/lJ,IAAI+lJ,mBAiD5B/rJ,OAAO,gBAAgB,CACnB,MAAO,YAAa,eACrB,SAAUgG,IAAK02B,IAAKxhB,UAIfw/D,4BAC4B,SAAUr/D,UACzBywI,OAASlkJ,KAAKokJ,cAActoJ,WAC5BsE,MAAMo6B,iBA2EvBp8B,IAAIimJ,YAAc,SAAUjkJ,MAAO4L,QAASC,gBACpCiN,EAAGi4E,IACH9kF,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,gBAE1D0kF,IAAM,CAACnlF,QAAQ,GAAIA,QAAQ,GACvB,6GAEIK,KAAKutE,UAFT,kCAQJ1gE,EAAI9Y,MAAMwM,OAAO,OAAQukF,IAAK9kF,OAC5BxB,KAAOyI,KAAK3P,kBAEduV,EAAE4sE,cAAgB5sE,EAAEynE,SAASmiB,WAAW,GAAGA,WAAW,GACtD5pF,EAAEkrI,cAAgBlrI,EAAEynE,SAASmiB,WAAW,GAAGA,WAAW,GACtD5pF,EAAE4sE,cAAc1kF,UAAY4K,QAAQ,GACpCkN,EAAEkrI,cAActoJ,MAAQkQ,QAAQ,GAChCkN,EAAE07E,YAAc17E,EAAEkrI,cAClBlrI,EAAE07E,YAAYzd,WAAa9qE,KAAK8qE,SAChCj+D,EAAE4sE,cAAc3oF,GAAK+b,EAAEynE,SAASxjF,GAAK,SACrC+b,EAAEkrI,cAAcjnJ,GAAK+b,EAAEynE,SAASxjF,GAAK,SAErC+b,EAAEgrI,OAASl4I,QAAQ,GACnBkN,EAAEshB,OAAS,kBACHx6B,KAAKivF,cACL7wF,IAAIohG,KAAKtmG,UAAUshC,OAAO9gC,KAAKsG,WAC1BkkJ,OAASlkJ,KAAKokJ,cAActoJ,OAE9BkE,MAUXkZ,EAAE7F,MAAQ,kBACCrT,KAAKkkJ,QA2ChBhrI,EAAEkR,IAAM,SAAUzf,iBACTu5I,OAASv5I,SACTy5I,cAActoJ,MAAQ6O,IACpB3K,MAGX80B,IAAIhd,SAASoB,EAAEkrI,cAAe,QAAStxE,4BAA6B55D,GACpE4b,IAAIhd,SAASoB,EAAEkrI,cAAe,aAAa,SAAS3wI,KAAWH,KAAKzU,OAAO4U,IAAIo2E,kBAAoBp2E,IAAIo2E,oBAAwB3wE,GAC/H4b,IAAIhd,SAASoB,EAAEkrI,cAAe,cAAc,SAAS3wI,KAAWH,KAAKzU,OAAO4U,IAAIo2E,kBAAoBp2E,IAAIo2E,oBAAwB3wE,GAChI4b,IAAIhd,SAASoB,EAAEkrI,cAAe,eAAe,SAAS3wI,KAAWH,KAAKzU,OAAO4U,IAAIo2E,kBAAoBp2E,IAAIo2E,oBAAwB3wE,GAGjIA,EAAEnI,WAAWO,SAAW,MACxBlR,MAAMmvE,SAASmW,gBAAgBxsE,GAAG,GAE3BA,GAGX9a,IAAIsB,gBAAgB,QAAStB,IAAIimJ,aAE1B,CACHA,YAAajmJ,IAAIimJ,gBAiDzBjsJ,OAAO,iBAAiB,CACpB,MAAO,YAAa,eACrB,SAAUgG,IAAK02B,IAAKxhB,UAIfw/D,6BAC6B,WACjB9yE,KAAKskJ,eACAA,gBAEJlkJ,MAAMo6B,iBA6IvBp8B,IAAI2rF,aAAe,SAAU3pF,MAAO4L,QAASC,gBACrCiN,EAAGi4E,IACH9kF,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,iBAQ1D0kF,IAAM,CAACnlF,QAAQ,GAAIA,QAAQ,GAAI,wDAE/BkN,EAAI9Y,MAAMwM,OAAO,OAAQukF,IAAK9kF,OAC5BxB,KAAOyI,KAAK1P,mBAEdsV,EAAE2sE,eAAiB3sE,EAAEynE,SAASmiB,WAAW,GACzC5pF,EAAE2sE,eAAe1oF,GAAK+b,EAAEynE,SAASxjF,GAAK,UACtC+b,EAAE2sE,eAAezkF,UAAY4K,QAAQ,GAErCkN,EAAE07E,YAAc17E,EAAE2sE,eAClB3sE,EAAE07E,YAAYzd,WAAa9qE,KAAK8qE,SAGhCj+D,EAAEnI,WAAWO,SAAW,MACxBlR,MAAMmvE,SAASmW,gBAAgBxsE,GAAG,GAE9BlN,QAAQ,KACJsH,KAAKvJ,SAASiC,QAAQ,KACtBkN,EAAEqrI,IAAM,IAAInmJ,IAAIolG,WAChBtqF,EAAEqrI,IAAIv7C,IAAI5oG,OACV8Y,EAAEorI,SAAW,WACTprI,EAAEqrI,IAAInnI,MAAMpR,QAAQ,MAGxBkN,EAAEorI,SAAWt4I,QAAQ,IAI7B8oB,IAAIhd,SAASoB,EAAE2sE,eAAgB,QAAS/S,6BAA8B55D,GACtE4b,IAAIhd,SAASoB,EAAE2sE,eAAgB,aAAa,SAAUpyE,KAAWH,KAAKzU,OAAO4U,IAAIo2E,kBAAoBp2E,IAAIo2E,oBAAwB3wE,GACjI4b,IAAIhd,SAASoB,EAAE2sE,eAAgB,cAAc,SAAUpyE,KAAWH,KAAKzU,OAAO4U,IAAIo2E,kBAAoBp2E,IAAIo2E,oBAAwB3wE,GAClI4b,IAAIhd,SAASoB,EAAE2sE,eAAgB,eAAe,SAAUpyE,KAAWH,KAAKzU,OAAO4U,IAAIo2E,kBAAoBp2E,IAAIo2E,oBAAwB3wE,GAE5HA,GAGX9a,IAAIsB,gBAAgB,SAAUtB,IAAI2rF,cAE3B,CACHA,aAAc3rF,IAAI2rF,iBAoDzB3xF,OAAO,qBAAqB,CACzB,MAAO,iBAAkB,cAAe,eAAgB,YAAa,aAAc,uBACpF,SAAUgG,IAAKoL,MAAO2a,OAAQ4qE,gBAAiB7qE,IAAK5Q,KAAM2lF,sBAkBxD76F,IAAIomJ,cAAgB,SAAUpkJ,MAAOyN,OAAQ5B,WAAYu5E,QAAS/rD,WAC1DjpB,YAAYpQ,MAAO6L,WAAYzC,MAAM1F,0BAA2B0F,MAAMnF,yBACtE1E,QAAUK,KAAKI,MAAMG,OAAO0L,WAAW8nE,aACvC0rB,kBAAkB5xF,aAElB4gH,cAAe,OAMfh1F,KAAO,CAAC,EAAG,GACZnmB,KAAKzU,OAAO46B,OAASA,KAAK5+B,OAAS,SAC9B4zH,cAAe,OAEf6iB,EAAIh+H,KAAK/H,eAAekuB,KAAK,GAAIz5B,KAAKI,MAAO,SAC7C2pE,EAAIz2D,KAAK/H,eAAekuB,KAAK,GAAIz5B,KAAKI,MAAO,SAC7CmxI,QAAU,CAACvxI,KAAKsxI,IAAKtxI,KAAK+pE,WAS9Byb,QAAUA,aAEVkK,OAAS,qBAWTvyF,GAAK6C,KAAKI,MAAMw/F,MAAM5/F,KAAM,WAE5BI,MAAMmvE,SAASgZ,kBAAkBvoF,WACjCI,MAAMy/F,eAAe7/F,WAErB+vF,UAAY3xF,IAAIuR,SAAS3P,KAAK+vF,UAAW,CAC1C0hD,kBAAmB,eACnBC,MAAO,kBAIftzI,IAAIomJ,cAActrJ,UAAY,IAAI61F,gBAClCz7E,KAAKnD,qBAAqB/R,IAAIomJ,cAAevrD,cAAe,qBAE5D76F,IAAIC,OAAOD,IAAIomJ,cAActrJ,UAAqD,CAQ9E87E,SAAU,SAAUlnE,EAAGiT,OACf+d,GAAIiC,GAAIvxB,EAAG3E,KAAM00B,KACjB3vB,EAAG5F,EAAGjN,EAAG8iC,IACTzzB,IAAMpM,KAAK6mF,gBAAgBhsF,cAEvByY,KAAK/I,SAAS+I,KAAKrG,SAASjN,KAAK+S,QAAQwgE,aACzC1oE,KAAO7K,KAAKI,MAAM4/F,aAClBzgE,KAAOjsB,KAAKrG,SAASjN,KAAK+S,QAAQwgE,UAAU1oE,QAG5C00B,KAAOv/B,KAAKI,MAAMqM,QAAQ8mE,UAAUyB,SAIhC,IAAR5oE,KACA0yB,GAAKhxB,EAAI9N,KAAK6N,OAAO0W,UAAU,GAC/Bwc,GAAK/gC,KAAK6N,OAAO0W,UAAU,GAAKxD,EAGzB+d,MAFPtvB,EAAI+vB,OAEeT,GAAK9+B,KAAKy5B,KAAK,IAAMjqB,GACjCuxB,KAAOvxB,GAAKuxB,GAAK/gC,KAAKy5B,KAAK,IAAMjqB,IAO5CxF,EAAI,EADJ4F,GAFAA,EAAI,IAAIuU,OAAO3a,MAAMzH,iBAAkB,CAAC+L,EAAGiT,GAAI/gB,KAAKI,QAE9C4N,WACC,GAAKhO,KAAKwxI,KAAK,GAAG,GACrB5hI,EAAE,GAAK5P,KAAKwxI,KAAK,GAAG,GACpB5hI,EAAE,GAAK5P,KAAKwxI,KAAK,GAAG,IAKpB,IADJz0I,GAHA8iC,IAAM3b,IAAI3D,cAGFvW,EAAGhK,KAAKwxI,KAAK,MACPz0I,GAAK8iC,IAAI7/B,KAAKwxI,KAAK,GAAIxxI,KAAKwxI,KAAK,KAGvC,IAFJz0I,EAAI8iC,IAAI71B,EAAGhK,KAAKwxI,KAAK,MAEPz0I,GAAK8iC,IAAI7/B,KAAKwxI,KAAK,GAAIxxI,KAAKwxI,KAAK,MAavDh3G,OAAQ,SAAU28D,mBACTn3F,KAAKivF,kBAGLqL,aAAanD,iBACblD,aAEEj0F,MALIA,MAYfkzF,eAAgB,kBACLlzF,KAAKy7F,sBAAsB,wBAQtCxH,WAAY,eACJt6C,GAAK,CAAC,EAAG,UAET35C,KAAKyuH,mBACA8iB,QAAU,CAACvxI,KAAKsxI,IAAKtxI,KAAK+pE,UAC1BtwC,KAAO,CAAC/sB,KAAKwC,IAAIlP,KAAKuxI,QAAQ,GAAKvxI,KAAKI,MAAM2kB,OACtCrY,KAAKwC,IAAIlP,KAAKuxI,QAAQ,GAAKvxI,KAAKI,MAAM4kB,SAE/ChlB,KAAK2gF,SAASqxC,kBACdr4E,GAAK35C,KAAK2gF,SAASmiB,WAAW,GAAG1nF,6BAC5Bqe,KAAO,CAACkgB,GAAGriC,MAAOqiC,GAAGpiC,SAI3BvX,MAUX2xI,WAAY,eACJr3I,EAAGC,EAAG6R,IAAMpM,KAAK6mF,gBAAgBhsF,OAAQmP,EAAI,MAErC,IAARoC,SACKolI,KAAO,CAAC,CAACxxI,KAAKw8C,IAAKx8C,KAAKo+B,IAAKp+B,KAAKq+B,KACnC,CAACr+B,KAAKw8C,IAAKx8C,KAAKsxI,IAAK,GACrB,CAACtxI,KAAKw8C,IAAK,EAAGx8C,KAAK+pE,UACpB,KAEH//D,EAAE,GAAK,CAAChK,KAAKw8C,IAAKx8C,KAAKo+B,IAAKp+B,KAAKq+B,KACjCr0B,EAAE,GAAK,CAAChK,KAAKw8C,IAAKx8C,KAAKo+B,IAAMp+B,KAAKsxI,IAAKtxI,KAAKq+B,KAC5Cr0B,EAAE,GAAK,CAAChK,KAAKw8C,IAAKx8C,KAAKo+B,IAAKp+B,KAAKq+B,IAAMr+B,KAAK+pE,KAGvCzvE,EAAI,EAAGA,EAAI8R,IAAK9R,QACZC,EAAI,EAAGA,EAAI,EAAGA,IACfyP,EAAEzP,GAAK2pB,IAAI3E,WAAWvf,KAAK6mF,gBAAgBvsF,GAAG0kB,OAAQhV,EAAEzP,QAI3DA,EAAI,EAAGA,EAAI,EAAGA,IACfyP,EAAEzP,GAAG,IAAMyP,EAAEzP,GAAG,GAChByP,EAAEzP,GAAG,IAAMyP,EAAEzP,GAAG,GAChByP,EAAEzP,GAAG,IAAMyP,EAAEzP,GAAG,OAIfA,EAAI,EAAGA,EAAI,EAAGA,IACfyP,EAAEzP,GAAG,IAAMyP,EAAE,GAAG,GAChBA,EAAEzP,GAAG,IAAMyP,EAAE,GAAG,GAChBA,EAAEzP,GAAG,IAAMyP,EAAE,GAAG,QAEfwnI,KAAOxnI,SAGThK,MAGXmwF,aAAc,SAAUoB,eAChBj3F,KAEAgZ,KAAKlJ,QAAQmnF,eACRj3F,EAAI,EAAGA,EAAIi3F,UAAU12F,OAAQP,SACzBusF,gBAAgBnrF,KAAK61F,UAAUj3F,cAGnCusF,gBAAgBnrF,KAAK61F,kBAGvBvxF,MAIXq2F,WAAY,eACJt5F,EAAI,CAACiD,KAAKksF,IAAK,CAAClsF,KAAKw8C,IAAKx8C,KAAKo+B,IAAKp+B,KAAKq+B,KAAMr+B,KAAKuxI,gBAE5B,IAAxBvxI,KAAKgM,QAAQnR,SACbkC,EAAIiD,KAAKgM,SAGNjP,GAcX60I,QAAS,SAASt6H,MAAOC,oBAChB+5H,EAAIh+H,KAAK/H,eAAe+L,MAAOtX,KAAKI,MAAO,SAC3C2pE,EAAIz2D,KAAK/H,eAAegM,OAAQvX,KAAKI,MAAO,SAC5CquH,cAAe,EAEbzuH,MAOXsxI,EAAG,aAMHvnE,EAAG,eA0HP3rE,IAAIqmJ,oBAAsB,SAAUrkJ,MAAO4L,QAASC,gBAC5CI,KAAMq4I,GACNl/D,QAAUx5E,QAAQ,GAClB6B,OAAS7B,QAAQ,GACjBytB,KAAO,MAEPztB,QAAQnR,QAAU,IAClB4+B,KAAOztB,QAAQ,IAGnBK,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,mBACtDi4I,GAAKzrD,cAAcrsF,OAAOxO,IAAIomJ,cAAepkJ,MAAOyN,OAAQxB,KAAMm5E,QAAS/rD,aAEjE,IAAIz9B,MAAM,mEACAgQ,QAAQ,IAAM,kBAAoBA,QAAQ,IAD1C,0GAKb04I,IAGXtmJ,IAAIsB,gBAAgB,gBAAiBtB,IAAIqmJ,qBACzCrmJ,IAAIsB,gBAAgB,KAAMtB,IAAIqmJ,qBAEvB,CACHD,cAAepmJ,IAAIomJ,cACnBG,oBAAqBvmJ,IAAIqmJ,wBAMjCrsJ,OAAO,YAAY,CACf,MAAO,YACR,SAAUgG,IAAK0tE,gBAId1tE,IAAIC,OAAOytE,QAAS,CAEhB2N,QAAS,CACL1N,YAAa,SAGjB64E,OAAQ,CAaJC,aAAc,SAUdC,MAAO,CAAE7yI,SAAS,EAAM2+B,OAAQ,CAACh3C,KAAM,MAQvCmrJ,MAAO,CAAE9yI,SAAS,EAAM2+B,OAAQ,CAACh3C,KAAM,MAQvCorJ,MAAO,CAAE/yI,SAAS,EAAM2+B,OAAQ,CAACh3C,KAAM,MAQvCqrJ,WAAY,CAAEhzI,SAAS,EAAMhC,MAAO,EAAGi1I,OAAQ,CAAEj1I,MAAO,IAMxDk1I,WAAY,CAAElzI,SAAS,EAAMhC,MAAO,EAAGi1I,OAAQ,CAAEj1I,MAAO,IAMxDm1I,WAAY,CAAEnzI,SAAS,EAAMhC,MAAO,EAAGi1I,OAAQ,CAAEj1I,MAAO,IAOxDo1I,YAAa,CAAEpzI,SAAS,EAAOhC,MAAO,EAAGi1I,OAAQ,CAAEj1I,MAAO,IAM1Dq1I,YAAa,CAAErzI,SAAS,EAAOhC,MAAO,EAAGi1I,OAAQ,CAAEj1I,MAAO,IAM1Ds1I,YAAa,CAAEtzI,SAAS,EAAOhC,MAAO,EAAGi1I,OAAQ,CAAEj1I,MAAO,IAQ1Du1I,gBAAiB,CAACvzI,QAAS,UAAW85D,YAAa,UAAW0G,YAAa,GAM3EgzE,gBAAiB,CAACxzI,QAAS,UAAW85D,YAAa,UAAW0G,YAAa,GAM3EizE,iBAAkB,CAACzzI,QAAS,UAAW85D,YAAa,UAAW0G,YAAa,GAM5EkzE,iBAAkB,CAAC1zI,QAAS,UAAW85D,YAAa,UAAW0G,YAAa,GAO5EmzE,gBAAiB,CAAC3zI,QAAS,UAAW85D,YAAa,UAAW0G,YAAa,GAM3EozE,gBAAiB,CAAC5zI,QAAS,UAAW85D,YAAa,UAAW0G,YAAa,GAM3EqzE,iBAAkB,CAAC7zI,QAAS,UAAW85D,YAAa,UAAW0G,YAAa,GAM5EszE,iBAAkB,CAAC9zI,QAAS,UAAW85D,YAAa,UAAW0G,YAAa,GAO5EuzE,gBAAiB,CAAC/zI,QAAS,UAAW85D,YAAa,UAAW0G,YAAa,GAM3EwzE,gBAAiB,CAACh0I,QAAS,UAAW85D,YAAa,UAAW0G,YAAa,GAM3EyzE,iBAAkB,CAACj0I,QAAS,UAAW85D,YAAa,UAAW0G,YAAa,GAM5E0zE,iBAAkB,CAACl0I,QAAS,UAAW85D,YAAa,UAAW0G,YAAa,IAKhF2zE,OAAQ,CACJlzE,WAAW,EACXvhE,YAAa,QACb8gE,YAAa,EACb3gE,SAAU,KAEV4+B,OAAQ,CAAEz+B,SAAS,EAAOrY,KAAM,IAChCg3C,OAAQ,CAAE3+B,SAAS,EAAOrY,KAAM,GAAIsW,MAAO,CAAE+B,SAAS,KAG1DizI,OAAQ,CACJzyE,YAAa,EACb1G,YAAa,UACbyF,cAAe,GACf0B,WAAW,EACXlH,UAAW,UACX0F,YAAa,GACb5/D,SAAU,KAEVG,QAAS,WAGbo0I,OAAQ,CACJ5zE,YAAa,EACb1G,YAAa,QACb4G,OAAO,EACP7gE,SAAU,KAEV8/D,SAAU,SACVC,oBAAqB,UAErBnhC,OAAQ,CAACz+B,SAAS,EAAOrY,KAAM,IAC/Bg3C,OAAQ,CAAC3+B,SAAS,EAAOrY,KAAM,KAGnC0sJ,QAAS,CACL7zE,YAAa,EACb1G,YAAa,QACbyF,cAAe,EACf0B,WAAW,EACXphE,SAAU,KAEV8/D,SAAU,SACVC,oBAAqB,UACrBI,cAAevlE,KAAKiV,GACpBqqD,UAAW,UACX0F,YAAa,IAGjB60E,QAAS,CACL9zE,YAAa,EACbb,SAAU,SACVC,oBAAqB,UACrB7F,UAAW,SACXuF,qBAAsB,WAG1Bi1E,UAAW,CAKPtzE,WAAW,EACXphE,UAAW,EACX2gE,YAAa,EAObg0E,OAAQ,GAOPC,OAAQ,IAKbC,OAAQ,CACJxzE,oBAAoB,KAKrB/0E,IAAI0tE,WAkCf1zE,OAAO,YAAY,CAAC,QACjB,SAAUgG,YAGTA,IAAIwoJ,OAAS,GAENxoJ,IAAIwoJ,UAiCfxuJ,OAAO,YAAY,CAAC,MAAO,UAAW,iBAAkB,aAAc,YAAa,eAAgB,cAChG,SAAUgG,IAAK0tE,QAAStiE,MAAO8J,KAAM4Q,IAAK6qE,gBAAiB63D,eAG1DA,OAAOC,OAAS,SAAUzmJ,MAAO4L,QAASC,gBAClC66I,OAAQj5I,OAAQ4rB,UACfjpB,YAAYpQ,MAAO6L,WAAYzC,MAAMzF,mBAAoByF,MAAMrF,oBAEpE2iJ,OAAS96I,QAAQ,GACjB6B,OAAS7B,QAAQ,GACjBytB,KAAOztB,QAAQ,QAKV+6I,GAAK,QAOLA,GAAGr9I,QAAU,QAMbq9I,GAAGpuF,YAAc,QAMjBouF,GAAG94E,YAAc,UAMjB84E,GAAG/nI,OAAS,CACb,CAAC,EAAG,EAAG,EAAG,GACV,CAAC,EAAG,EAAG,EAAG,GACV,CAAC,EAAG,EAAG,EAAG,SAIT+nI,GAAGD,OAASA,YACZC,GAAGl5I,OAASA,YACZk5I,GAAGttH,KAAOA,UAMVstH,GAAGv3I,GAAK,OAERw3I,eAAiB,UAEjB7pJ,GAAK6C,KAAKI,MAAMw/F,MAAM5/F,KAAM,UAC5BI,MAAMy/F,eAAe7/F,WACrB0vF,OAAS,cACTK,UAAYz8E,KAAK3D,SAAS3P,KAAK+vF,UAAW,KAGnD62D,OAAOC,OAAO3tJ,UAAY,IAAI61F,gBAE9B3wF,IAAIC,OAAOuoJ,OAAOC,OAAO3tJ,UAAiD,CACtE0T,OAAQ,SAAUy6G,YAAar7G,QAASC,gBAGhCoC,GAFAnS,OAAS,UAITmrH,YAAYjrH,QAAQ,MAAQ,KACrB,EACPF,OAAOR,KAAKsE,OAEhBqO,GAAKrO,KAAKI,MAAMwM,OAAOy6G,YAAanrH,OAAOhB,OAAO8Q,SAAUC,iBAEnDif,IAAI7c,IAENA,IAGX6c,IAAK,SAAU7c,SACN04I,GAAGr9I,QAAQ2E,GAAGlR,IAAMkR,QACpB04I,GAAGpuF,YAAYj9D,KAAK2S,KAS7BmsB,OAAQ,eAEAv9B,EAAGuS,EAAGnC,EAAGzQ,EAAG6d,IADZssI,GAAK/mJ,KAAK+mJ,UAGTzzI,KAAKzU,OAAOkoJ,GAAGE,WACf3zI,KAAKzU,OAAOkoJ,GAAGG,WACflnJ,KAAKivF,aAIVhyF,EAAI8pJ,GAAGE,SAAS5zI,QAChB7D,EAAIu3I,GAAGv3I,EACPnC,EAAI05I,GAAGG,SAAS7zI,QAChBzW,EAAI4S,EAAI9C,KAAKwiB,IAAIjyB,GACjBwd,IAAM,CAAC,CAAC,EAAG,EAAG,GAAK,CAAC,EAAG,EAAG,GAAI,CAAC,EAAG,EAAG,IAErCssI,GAAG/nI,OAAS,CACR,CAAC,EAAG,EAAG,EAAG,GACV,CAAC,EAAG,EAAG,EAAG,GACV,CAAC,EAAG,EAAG,EAAG,IAGd+nI,GAAG/nI,OAAO,GAAG,GAAKxP,EAAI9C,KAAK8hB,IAAInhB,GAC/B05I,GAAG/nI,OAAO,GAAG,IAAMxP,EAAI9C,KAAKwiB,IAAI7hB,GAChC05I,GAAG/nI,OAAO,GAAG,GAAKpiB,EAAI8P,KAAKwiB,IAAI7hB,GAC/B05I,GAAG/nI,OAAO,GAAG,GAAKpiB,EAAI8P,KAAK8hB,IAAInhB,GAC/B05I,GAAG/nI,OAAO,GAAG,GAAKtS,KAAK8hB,IAAIvxB,GAGvBwd,IAAI,GAAG,GAAKssI,GAAGttH,KAAK,IAAMstH,GAAGD,OAAO,GAAG,GAAKC,GAAGD,OAAO,GAAG,IACzDrsI,IAAI,GAAG,GAAKssI,GAAGttH,KAAK,IAAMstH,GAAGD,OAAO,GAAG,GAAKC,GAAGD,OAAO,GAAG,IACzDrsI,IAAI,GAAG,GAAKssI,GAAGl5I,OAAO,GAAK4M,IAAI,GAAG,GAAKssI,GAAGD,OAAO,GAAG,GACpDrsI,IAAI,GAAG,GAAKssI,GAAGl5I,OAAO,GAAK4M,IAAI,GAAG,GAAKssI,GAAGD,OAAO,GAAG,GAEpDC,GAAG/nI,OAASkF,IAAIxE,WAAWjF,IAAKssI,GAAG/nI,QAGhChf,MA9BIA,MAiCfkzF,eAAgB,uBACPjE,aAAc,EACZjvF,MAaXmnJ,cAAe,SAAUr5I,EAAGiT,EAAG6G,OACvBpI,WAEAA,IADqB,IAArB/jB,UAAUZ,OACJ,CAAC,EAAGiT,EAAGiT,EAAG6G,GAGC,IAAb9Z,EAAEjT,OACI,CAAC,GAAGK,OAAO4S,GAEXA,EAGPoW,IAAI3E,WAAWvf,KAAK+mJ,GAAG/nI,OAAQQ,MAY1C4nI,mBAAoB,SAAU92G,MAAOwO,OAAQC,UACrCtkC,IAAKmzB,IAAKziC,EAAG6V,GACbnkB,EAAIiiD,OAAOzlD,MAAM,GACjBgmD,IAAM,CAAC,EAAG,EAAG,EAAG,GAEpBN,KAAOA,MAAQ,CAAC,EAAG,EAAG,EAAG,GACzB/9B,GAAKkD,IAAIvD,KAAK9jB,EAAG,GACjBsO,EAAI+Y,IAAI3D,aAAaw+B,KAAK1lD,MAAM,GAAIwD,EAAG,GAAKmkB,IAE5CvG,IAAMza,KAAK+mJ,GAAG/nI,OAAO3lB,MAAM,EAAG,IAC1BqC,KAAK,CAAC,GAAGR,OAAO2B,IAGpB+wC,IAAM0C,MAAMziC,OAAOG,UAAU9S,OAAO,CAACiQ,QAGf,IAAdsP,IAAI,GAAG,KACPA,IAAI,GAAG,GAAKA,IAAI,GAAG,GAAe,KAAVyJ,IAAIzF,KAEhC4gC,IAAMn7B,IAAIiR,SAASC,MAAM3a,IAAKmzB,KAChC,MAAOx5B,KACLirC,IAAM,CAAC,EAAG1wC,IAAKA,IAAKA,YAGjB0wC,KAGXgoG,gBAAiB,SAAUC,SACnBC,KAAOvnJ,KAAK+mJ,GAAGD,cACfQ,IAAI,GAAKC,KAAK,GAAG,KAAMD,IAAI,GAAKC,KAAK,GAAG,IACxCD,IAAI,GAAKC,KAAK,GAAG,KAAMD,IAAI,GAAKC,KAAK,GAAG,IACxCD,IAAI,GAAKC,KAAK,GAAG,KAAMD,IAAI,GAAKC,KAAK,GAAG,IACxCD,IAAI,GAAKC,KAAK,GAAG,KAAMD,IAAI,GAAKC,KAAK,GAAG,IACxCD,IAAI,GAAKC,KAAK,GAAG,KAAMD,IAAI,GAAKC,KAAK,GAAG,IACxCD,IAAI,GAAKC,KAAK,GAAG,KAAMD,IAAI,GAAKC,KAAK,GAAG,IAErCD,KAGXE,qBAAsB,SAAUzqJ,EAAGoO,EAAGqE,OAC9Bi4I,KAAMntJ,EAAGigD,GAAIC,OAEjBitG,KAAOj4I,EACFlV,EAAI,EAAGA,EAAI,EAAGA,IACF,IAAT6Q,EAAE7Q,KACFigD,IAAMv6C,KAAK+mJ,GAAGD,OAAOxsJ,GAAG,GAAKyC,EAAEzC,IAAM6Q,EAAE7Q,GACvCkgD,IAAMx6C,KAAK+mJ,GAAGD,OAAOxsJ,GAAG,GAAKyC,EAAEzC,IAAM6Q,EAAE7Q,GAEnCmtJ,KADAj4I,EAAI,EACG9C,KAAKiS,IAAI8oI,KAAM/6I,KAAKC,IAAI4tC,GAAIC,KAE5B9tC,KAAKC,IAAI86I,KAAM/6I,KAAKiS,IAAI47B,GAAIC,aAIxCitG,MAGXC,SAAU,SAAU3/H,UACTA,EAAE,GAAK/nB,KAAK+mJ,GAAGD,OAAO,GAAG,GAAK5iI,IAAIzF,KAAOsJ,EAAE,GAAK/nB,KAAK+mJ,GAAGD,OAAO,GAAG,GAAK5iI,IAAIzF,KAC9EsJ,EAAE,GAAK/nB,KAAK+mJ,GAAGD,OAAO,GAAG,GAAK5iI,IAAIzF,KAAOsJ,EAAE,GAAK/nB,KAAK+mJ,GAAGD,OAAO,GAAG,GAAK5iI,IAAIzF,KAC3EsJ,EAAE,GAAK/nB,KAAK+mJ,GAAGD,OAAO,GAAG,GAAK5iI,IAAIzF,KAAOsJ,EAAE,GAAK/nB,KAAK+mJ,GAAGD,OAAO,GAAG,GAAK5iI,IAAIzF,KAWnFkpI,uBAAwB,SAASC,OAAQC,OAAQ18I,OAEzCpO,EAAGi6E,IAAKxnE,EAAGuY,EADXvqB,IAAM,CAAC,GAAI,WAGf2N,EAAIA,GAAK08I,OAAOd,GAAG57I,EAEnBpO,EAAImnB,IAAIirB,SAAS2O,YAAY8pG,OAAOb,GAAGjoG,OAAQ8oG,OAAOb,GAAG57I,EAAG08I,OAAOd,GAAGjoG,OAAQ3zC,EACrE+Y,IAAI1D,aAAaonI,OAAOb,GAAGjoG,OAAQ+oG,OAAOd,GAAGjoG,QAAS,GAC/Dk4B,IAAM9yD,IAAIirB,SAASmP,eAAespG,OAAOb,GAAGloC,KAAM+oC,OAAOb,GAAGjoC,KAAM+oC,OAAOd,GAAGloC,KAAMgpC,OAAOd,GAAGjoC,MAC5FtvG,EAAIxP,KAAKwnJ,qBAAqBzqJ,EAAGi6E,IAAKx1D,EAAAA,GACtCuG,EAAI7D,IAAIpD,KAAKtR,EAAGwnE,IAAKj6E,GACjBiD,KAAK0nJ,SAAS3/H,KACdvqB,IAAI,GAAKuqB,GAEbvY,EAAIxP,KAAKwnJ,qBAAqBzqJ,EAAGi6E,KAAMx1D,EAAAA,GACvCuG,EAAI7D,IAAIpD,KAAKtR,EAAGwnE,IAAKj6E,GACjBiD,KAAK0nJ,SAAS3/H,KACdvqB,IAAI,GAAKuqB,GAENvqB,KAGXsqJ,QAAS,SAAU1pH,EAAGC,EAAGme,EAAGurG,WAAYC,gBAChCC,IAAKC,IAAK/gI,EAAGnd,EAAGm+I,IAChBC,QAASC,QACTtrJ,EAAI,CAAC,EAAG,EAAG,GACXurJ,QAAUP,WAAW,GACrBQ,QAAUP,WAAW,GAErB7mH,MAAQ,GACRC,MAAQ,OAEZgnH,SAAW90I,KAAKrG,SAAS86I,WAAW,IAAMz0I,KAAKrG,SAAS86I,WAAW,KAAQO,QAC3ED,SAAW/0I,KAAKrG,SAAS+6I,WAAW,IAAM10I,KAAKrG,SAAS+6I,WAAW,KAAQO,QAEtEN,IAAM,EAAGA,KAAOK,QAASL,MAAO,KACjC9gI,EAAI4gI,WAAW,GAAKK,QAAUH,IACzBC,IAAM,EAAGA,KAAOK,QAASL,MAC1Bl+I,EAAIg+I,WAAW,GAAKK,QAAUH,IAC9BnrJ,EAAE,GAAKqhC,EAAEjX,EAAGnd,GACZjN,EAAE,GAAKshC,EAAElX,EAAGnd,GACZjN,EAAE,GAAKy/C,EAAEr1B,EAAGnd,GACZm+I,IAAMnoJ,KAAKmnJ,cAAcpqJ,GACzBokC,MAAMzlC,KAAKysJ,IAAI,IACf/mH,MAAM1lC,KAAKysJ,IAAI,IAEnBhnH,MAAMzlC,KAAKiT,KACXyyB,MAAM1lC,KAAKiT,SAGVu5I,IAAM,EAAGA,KAAOK,QAASL,MAAO,KACjCl+I,EAAIg+I,WAAW,GAAKK,QAAUH,IACzBD,IAAM,EAAGA,KAAOK,QAASL,MAC1B9gI,EAAI4gI,WAAW,GAAKK,QAAUH,IAC9BlrJ,EAAE,GAAKqhC,EAAEjX,EAAGnd,GACZjN,EAAE,GAAKshC,EAAElX,EAAGnd,GACZjN,EAAE,GAAKy/C,EAAEr1B,EAAGnd,GACZm+I,IAAMnoJ,KAAKmnJ,cAAcpqJ,GACzBokC,MAAMzlC,KAAKysJ,IAAI,IACf/mH,MAAM1lC,KAAKysJ,IAAI,IAEnBhnH,MAAMzlC,KAAKiT,KACXyyB,MAAM1lC,KAAKiT,WAGR,CAACwyB,MAAOC,QAGnBonH,eAAgB,eACRnoJ,EAAIL,KAAK+mJ,GAAGG,SAAS/rD,MAErB+2C,MADIlyI,KAAK+mJ,GAAGG,SAAShsD,MACT76F,EACZooJ,OAASzoJ,KAAK+mJ,GAAGG,SAAS7zI,QAAU,QAEnC0zI,GAAGG,SAASrvI,UAAa4wI,OAASpoJ,GAAK6xI,MACxClyI,KAAK+mJ,GAAGG,SAASrvI,SAAW,SACvBkvI,GAAGG,SAASrvI,SAAW,QAE3BzX,MAAMo6B,cAENwsH,eAAiBlpJ,WAAW,gBAAmB0qJ,kBAAoB17I,KAAK9M,MAAO,MAGxF0oJ,YAAa,WACTC,aAAa3oJ,KAAKgnJ,qBACbA,eAAiB,QAiF9BJ,OAAOgC,aAAe,SAAUxoJ,MAAO4L,QAASC,gBACxC48I,KAAax8I,KACbyB,EAAGiT,EAAG+R,EAAG/U,EACTlQ,OAAS7B,QAAQ,GACjBytB,KAAOztB,QAAQ,UAEnBK,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,WACtDo8I,KAAO,IAAIjC,OAAOC,OAAOzmJ,MAAO4L,QAASK,OACpC4hE,YAAc46E,KAAKj8I,OAAO,SAAUZ,QAASC,YAElD6B,EAAID,OAAO,GACXkT,EAAIlT,OAAO,GACXilB,EAAI2G,KAAK,GACT1b,EAAI0b,KAAK,GAgCTovH,KAAK9B,GAAGG,SAAW9mJ,MAAMwM,OAAO,SAAU,CAAC,CAACkB,EAAI,EAAGiT,EAAI,GAAI,CAACjT,EAAIglB,EAAI,EAAG/R,EAAI,GAAI,CAAC,EAAG,EAAK,EAAIrU,KAAKiV,KAAM,CACnGvK,MAAO,EAAGxd,KAAM,KAChB82C,OAAQ,CAAEkiC,QAAQ,GAClBhiC,OAAQ,CAAEgiC,QAAQ,KAMtBi2E,KAAK9B,GAAGE,SAAW7mJ,MAAMwM,OAAO,SAAU,CAAC,CAACkB,EAAI,EAAGiT,GAAI,CAACjT,EAAI,EAAGiT,EAAIhD,GAAI,CAAC,EAAG,GAAMrR,KAAKiV,GAAK,IAAK,CAC5FvK,MAAO,EAAGxd,KAAM,KAChB82C,OAAQ,CAAEkiC,QAAQ,GAClBhiC,OAAQ,CAAEgiC,QAAQ,KAGtBi2E,KAAKzoJ,MAAMqjH,iBAAmB,SAAU31G,EAAGiT,EAAG1S,QACtClD,EAEAmI,KAAKzU,OAAOwP,GAAG04I,IAEL,UADV57I,EAAImI,KAAKrG,SAASoB,GAAG0E,QAAQywG,gBAEzBqlC,KAAKzoJ,MAAMsjH,uBAAuB,IAC9BpwG,KAAKrE,WAAWZ,GAAG04I,GAAG3oH,KAAO,MAC7B9qB,KAAKrE,WAAWZ,GAAG04I,GAAG1oH,KAAO,MAC7B/qB,KAAKrE,WAAWZ,GAAG04I,GAAGvqG,KAAO,IAAKnuC,IAEtCw6I,KAAKzoJ,MAAMsjH,uBAAuB,IAC9BpwG,KAAK/E,QAAQF,GAAG04I,GAAG3oH,IAAKjzB,GAAK,MAC7BmI,KAAK/E,QAAQF,GAAG04I,GAAG1oH,IAAKlzB,GAAK,MAC7BmI,KAAK/E,QAAQF,GAAG04I,GAAGvqG,IAAKrxC,GAAK,IAAKkD,IAG1Cw6I,KAAKzoJ,MAAMsjH,uBAAuB,IAAM51G,EAAI,KAAOiT,EAAI,IAAK1S,KAI7Dw6I,MAEXzqJ,IAAIsB,gBAAgB,SAAUknJ,OAAOgC,cAE9BhC,OAAOC,UAsClBzuJ,OAAO,WAAW,CAAC,MAAO,aAAc,YAAa,gBAAiB,cACnE,SAAUgG,IAAKkV,KAAM4Q,IAAKirB,SAAUy3G,QAGnCA,OAAOkC,WAAa,SAAU1oJ,MAAO4L,QAASC,gBAEtC3R,EAAGC,EAAGiR,EAAGkoC,GAAI7jC,GACbxD,KACAwvC,IAGAm7B,IAIAxpC,KAAMC,GACNs7G,KAAMC,KAAMC,OAAQC,OACpBC,GAAIC,UACJC,WAbAR,KAAO78I,QAAQ,GAIfs9I,WAAa,CAAC,IAAK,IAAK,KAGxBC,MAAQ,CAAC,OAAQ,SACjBC,KAAO,CAAC,EAAG,EAAG,GACdC,MAAQ,CAAC,EAAG,EAAG,GAKfC,KAAO,MAEPp2I,KAAKzU,OAAOgqJ,KAAK9B,QACZzsJ,EAAI,EAAGA,EAAIgvJ,WAAWzuJ,OAAQP,IAC/BkvJ,KAAKlvJ,GAAKuuJ,KAAK9B,GAAGD,OAAOxsJ,GAAG,GAC5BmvJ,MAAMnvJ,GAAKuuJ,KAAK9B,GAAGD,OAAOxsJ,GAAG,YAG5BA,EAAI,EAAGA,EAAIgvJ,WAAWzuJ,OAAQP,IAC/BkvJ,KAAKlvJ,GAAK0R,QAAQ,GAAG1R,GACrBmvJ,MAAMnvJ,GAAK0R,QAAQ,GAAG,OAM9B6vC,KADAxvC,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,WAC3Ck9I,aACNrvJ,EAAI,EAAGA,EAAIgvJ,WAAWzuJ,OAAQP,IAG/B6uJ,IADAnyE,IAAMsyE,WAAWhvJ,IA5BJ,OA+BD,WAARuhD,KACArO,KAAO,CAAC,EAAG,EAAG,IACdC,GAAK,CAAC,EAAG,EAAG,IACTnzC,GAAKmvJ,MAAMnvJ,GACdovJ,KAAKP,IAAMN,KAAKj8I,OAAO,SAAU,CAAC4gC,KAAMC,IAAKphC,KAAK88I,GAAGzqJ,kBAErDyqJ,IAAM,SACN37G,KAAOg8G,KAAKnwJ,QACZo0C,GAAKg8G,MAAMpwJ,QACD,IAANiB,GACAkzC,KAAK,GAAKi8G,MAAM,GAChBh8G,GAAG,GAAK+7G,KAAK,KAEbh8G,KAAKlzC,GAAKmvJ,MAAMnvJ,GAChBmzC,GAAG,GAAK+7G,KAAK,IAEjB/7G,GAAGnzC,GAAKmvJ,MAAMnvJ,GACd+R,KAAK88I,GAAGzqJ,eAAe23E,WAAY,EACnCqzE,KAAKP,IAAMN,KAAKj8I,OAAO,SAAU,CAAC4gC,KAAMC,IAAKphC,KAAK88I,GAAGzqJ,gBAGrD2qJ,WAAa,CACTp3I,SAAS,EACTmiE,WAAY,EACZ7F,YAAa,CAAC,EAAG,GACjBqF,YAAY,GAEN,IAANt5E,IACA+uJ,WAAW96E,YAAc,CAAC,EAAG,IAEjCm7E,KAAKP,GAAK,SAAWN,KAAKj8I,OAAO,QAAS,CAAC88I,KAAKP,IAAK,GAAIE,iBAKjEK,KAAKE,EAAIxpJ,MAAMwM,OAAO,eAAgB,CAC9B88I,KAAKJ,WAAW,GAnEP,QAoETI,KAAKJ,WAAW,GApEP,SAqEV,CACC1vJ,KAAM,GAAIqY,SAAS,EAAO4gE,WAAW,IAIxCv4E,EAAI,EAAGA,EAAIgvJ,WAAWzuJ,OAAQP,QAE/Bo5C,IAAMp5C,EAAI,GAAK,EACfuV,IAAMvV,EAAI,GAAK,EAEf08E,IAAMsyE,WAAWhvJ,GACZC,EAAI,EAAGA,EAAIgvJ,MAAM1uJ,OAAQN,KAG1BizC,KAAO,CAAC,EAAG,EAAG,IACTlzC,GAAY,IAANC,EAAWivJ,KAAKlvJ,GAAKmvJ,MAAMnvJ,GAEtC0uJ,KAAO,CAAC,EAAG,EAAG,IADdD,KAAO,CAAC,EAAG,EAAG,IAETr1G,IAAM,EACXs1G,KAAKn5I,IAAM,EACXo5I,OAAS,CAACO,KAAK91G,IAAK+1G,MAAM/1G,KAC1Bw1G,OAAS,CAACM,KAAK35I,IAAK45I,MAAM55I,KAC1Bs5I,GAAKnyE,IAAM,QAAUuyE,MAAMhvJ,GAE3B8R,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,SAAU08I,IAChEO,KAAKP,IACDN,KAAKj8I,OAAO,UAAW,CAAC4gC,KAAMu7G,KAAMC,KAAMC,OAAQC,QAAS78I,MAC/Dq9I,KAAKP,IAAIpC,GAAGr3D,OAAS,kBAKxBp1F,EAAI,EAAGA,EAAIgvJ,WAAWzuJ,OAAQP,QAE/B08E,IAAMsyE,WAAWhvJ,GACZC,EAAI,EAAGA,EAAIgvJ,MAAM1uJ,OAAQN,QACrBiR,EAAI,EAAGA,GAAK,EAAGA,IAGhB29I,GAAKnyE,IAAM,QAAUuyE,MAAMhvJ,GADpB+uJ,WADP51G,IAAMp5C,EAAIkR,GAAK,GAEsBlM,cAAgB,OACrD8pJ,UAAYpyE,IAAM,QAAUuyE,MAAMhvJ,IAElCizC,KAAO,CAAC,EAAG,EAAG,IAETlzC,IADLmzC,GAAK,CAAC,EAAG,EAAG,IACCnzC,GAAY,IAANC,EAAWivJ,KAAKlvJ,GAAKmvJ,MAAMnvJ,GAE9CkzC,KAAKkG,IAAM81G,KAAK91G,IAChBjG,GAAGiG,IAAM+1G,MAAM/1G,IAEfrnC,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,SAAU08I,IAChEO,KAAKP,IAAMN,KAAKj8I,OAAO,SAAU,CAAC4gC,KAAMC,IAAKphC,MAC7Cq9I,KAAKN,WAAWv6D,SAAS66D,KAAKP,KAC9BO,KAAKN,WAAWv5D,SAASn0F,KAAKguJ,KAAKP,YAKxCO,MAEXtrJ,IAAIsB,gBAAgB,SAAUknJ,OAAOkC,YAErClC,OAAOpnB,WAAa,SAAUp/H,MAAO4L,QAASC,gBAEtCI,KAGAw9I,SAAUC,OAKCC,GAAIh7C,GAAIi7C,GATnBnB,KAAO78I,QAAQ,GAEfoO,MAAQpO,QAAQ,GAChBu2B,IAAMv2B,QAAQ,UAIlBK,KAAOiH,KAAK9G,eAAeP,WAAWykC,OAAQtwC,MAAMqM,QAAS,SAAU,UACvEo9I,SAAWzpJ,MAAMwM,OAAO,QAAS,EAClBm9I,GAER3vI,MAAM,GAFM20F,GAEF30F,MAAM,GAFA4vI,GAEI5vI,MAAM,GADlB,kBAAqByuI,KAAK1B,cAAc4C,GAAIh7C,GAAIi7C,IAAI,KAE9D,SAAUD,GAAIh7C,GAAIi7C,WACR,kBAAqBnB,KAAK1B,cAAc4C,GAAIh7C,GAAIi7C,IAAI,IAD9D,CAEE5vI,MAAM,GAAIA,MAAM,GAAIA,MAAM,KAC9B/N,MAEHA,KAAOiH,KAAK9G,eAAeP,WAAW2kC,OAAQxwC,MAAMqM,QAAS,SAAU,UACvEq9I,OAAS1pJ,MAAMwM,OAAO,QAAS,CAC1B,SAAUm9I,GAAIh7C,GAAIi7C,WACR,kBAAqBnB,KAAK1B,cAAc4C,GAAIh7C,GAAIi7C,IAAI,IAD9D,CAEEznH,IAAI,GAAIA,IAAI,GAAIA,IAAI,IACtB,SAAUwnH,GAAIh7C,GAAIi7C,WACR,kBAAqBnB,KAAK1B,cAAc4C,GAAIh7C,GAAIi7C,IAAI,IAD9D,CAEEznH,IAAI,GAAIA,IAAI,GAAIA,IAAI,KACxBl2B,MAEHA,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,UACjDrM,MAAMwM,OAAO,QAAS,CAACi9I,SAAUC,QAASz9I,OAInDjO,IAAIsB,gBAAgB,SAAUknJ,OAAOpnB,YAErConB,OAAOqD,WAAa,SAAU7pJ,MAAO4L,QAASK,UAOtCgC,GANAw6I,KAAO78I,QAAQ,GACfskC,MAAQtkC,QAAQ,GAChB+8I,KAAO/8I,QAAQ,GACfi9I,OAASj9I,QAAQ,GACjBg9I,KAAOh9I,QAAQ,GACfk9I,OAASl9I,QAAQ,UAGrBqC,GAAKjO,MAAMwM,OAAO,QAAS,CAAC,GAAI,IAAKP,OAClCw7H,gBAAkB,eAKblyF,GAAIC,GAAIn2B,IAAKnlB,EAJb6kD,GAAK8pG,OAAO,GACZiB,GAAKjB,OAAO,GACZ7pG,GAAK8pG,OAAO,GACZ7pJ,GAAK6pJ,OAAO,GAEZjqG,GAAK,CAAC,EAAG,EAAG,GACZC,GAAK,CAAC,EAAG,EAAG,GAEZn3B,EAAI,CAAC,EAAG,EAAG,YAEVoZ,MAAQ,QACRC,MAAQ,GAER9mC,EAAI,EAAGA,EAAI,EAAGA,IACfytB,EAAEztB,GAAKgZ,KAAKrG,SAASqjC,MAAMh2C,IAC3B2kD,GAAG3kD,GAAKgZ,KAAKrG,SAAS87I,KAAKzuJ,IAC3B4kD,GAAG5kD,GAAKgZ,KAAKrG,SAAS+7I,KAAK1uJ,QAE/Bq7C,GAAKv3C,IAAIsO,KAAKiU,KAAKs+B,GAAI,GACvBrJ,GAAKx3C,IAAIsO,KAAKiU,KAAKu+B,GAAI,GAClB5kD,EAAI,EAAGA,EAAI,EAAGA,IACf2kD,GAAG3kD,IAAMq7C,GACTuJ,GAAG5kD,IAAMs7C,GAYbn2B,IAAMopI,KAAKf,SACP,SAAS3gI,EAAGnd,UAAY+d,EAAE,GAAKZ,EAAI83B,GAAG,GAAKj1C,EAAIk1C,GAAG,MAClD,SAAS/3B,EAAGnd,UAAY+d,EAAE,GAAKZ,EAAI83B,GAAG,GAAKj1C,EAAIk1C,GAAG,MAClD,SAAS/3B,EAAGnd,UAAY+d,EAAE,GAAKZ,EAAI83B,GAAG,GAAKj1C,EAAIk1C,GAAG,KAClD,CAACxyC,KAAKsgB,KAAKmyB,IAAKzyC,KAAKmS,MAAMqrI,KAAMx9I,KAAKsgB,KAAKk9H,IAAMx9I,KAAKmS,MAAMsgC,KA/BrD,GAgCP,CAACzyC,KAAKsgB,KAAKoyB,IAAK1yC,KAAKmS,MAAMxf,KAAMqN,KAAKsgB,KAAK3tB,IAAMqN,KAAKmS,MAAMugC,KAhCrD,SAiCNje,MAAQ1hB,IAAI,QACZ2hB,MAAQ3hB,IAAI,IAEdpR,IAEXjQ,IAAIsB,gBAAgB,SAAUknJ,OAAOqD,eAiCzC7xJ,OAAO,aAAa,CAAC,MAAO,aAAc,cACvC,SAAUgG,IAAKkV,KAAMszI,QAGpBA,OAAOre,YAAc,SAAUnoI,MAAO4L,QAASK,UAEvC06I,GAAI14I,GADJw6I,KAAO78I,QAAQ,UAGnB+6I,GAAK,CACDr3D,OAAQ,UACRtxD,EAAGpyB,QAAQ,GACXqyB,EAAGryB,QAAQ,GACXwwC,EAAGxwC,QAAQ,KAEZ4xB,EAAI,CAACmpH,GAAG3oH,EAAG2oH,GAAG1oH,EAAG0oH,GAAGvqG,IAEvBnuC,GAAKjO,MAAMwM,OAAO,QAAS,CAAC,GAAI,IAAKP,OAClC06I,GAAKA,GAEJzzI,KAAKnJ,WAAWkE,GAAG04I,GAAG3oH,IAGtB/vB,GAAG04I,GAAGniH,MAAQ54B,QAAQ,GACtBqC,GAAGw5H,gBAAkB,eAKbsgB,IAAKjvI,EAAG5e,EAJRosD,MAAQpzC,KAAKrG,SAASjN,KAAK+S,QAAQi0H,kBACnC3mI,EAAIiT,KAAKrG,SAASjN,KAAK+mJ,GAAGniH,MAAM,IAChC3nC,EAAIqW,KAAKrG,SAASjN,KAAK+mJ,GAAGniH,MAAM,IAChCrR,OAASt2B,EAAIoD,IAAMqmD,MAAQ,GAE3B3pD,EAAI,CAAC,EAAG,EAAG,YAEVokC,MAAQ,QACRC,MAAQ,GAERloB,EAAI7Y,EAAG6Y,GAAKjc,EAAGic,GAAKqa,MAAO,KACvBj5B,EAAI,EAAGA,EAAI,EAAGA,IACfyC,EAAEzC,GAAK0F,KAAK+mJ,GAAGnpH,EAAEtjC,GAAG4e,GAExBivI,IAAMU,KAAK1B,cAAcpqJ,QACpBokC,MAAMzlC,KAAKysJ,IAAI,SACf/mH,MAAM1lC,KAAKysJ,IAAI,OAGrB70I,KAAKlJ,QAAQiE,GAAG04I,GAAG3oH,KAG1B/vB,GAAGw5H,gBAAkB,eACbvtI,EAEA6tJ,IADAnnI,GAAKhhB,KAAK+mJ,GAAG3oH,EAAEvjC,gBAGdsmC,MAAQ,QACRC,MAAQ,GAER9mC,EAAI,EAAGA,EAAI0mB,GAAI1mB,IAChB6tJ,IAAMU,KAAK1B,cAAc,CAACnnJ,KAAK+mJ,GAAG3oH,EAAE9jC,GAAI0F,KAAK+mJ,GAAG1oH,EAAE/jC,GAAI0F,KAAK+mJ,GAAGvqG,EAAEliD,UAC3D6mC,MAAMzlC,KAAKysJ,IAAI,SACf/mH,MAAM1lC,KAAKysJ,IAAI,MAKzB95I,IAEXjQ,IAAIsB,gBAAgB,UAAWknJ,OAAOre,gBAqC1CnwI,OAAO,gBAAgB,CAAC,MAAO,aAAc,YAAa,gBAAiB,cACxE,SAAUgG,IAAKkV,KAAM4Q,IAAKirB,SAAUy3G,QA4BnCA,OAAOxnB,WAAa,SAAUh/H,MAAO4L,QAASC,gBAEtCI,KAAM06I,GAAIz2G,MAAOI,OAAQE,OACzBviC,GAFAw6I,KAAO78I,QAAQ,UAKnB+6I,GAAK,CACDr3D,OAAQ,SACR9qD,MAAO54B,QAAQ,IAAM,EAAEwV,EAAAA,EAAUA,EAAAA,IAKjC8uB,MADAh9B,KAAK9I,QAAQwB,QAAQ,IACbA,QAAQ,GAER68I,KAAKj8I,OAAO,UAAWZ,QAAQ,GAAI,CAAEiG,SAAS,EAAOrY,KAAM,GAAIi5E,WAAW,IAEtFk0E,GAAGz2G,MAAQA,MAGPh9B,KAAK9I,QAAQwB,QAAQ,KAAOsH,KAAKzU,OAAOmN,QAAQ,GAAG+6I,KAGnDr2G,OAASJ,MACTM,OAAS5kC,QAAQ,GACjB+6I,GAAGt4F,UAAY,iBACJ,CACH7d,OAAOm2G,GAAG3oH,IAAMkS,MAAMy2G,GAAG3oH,IACzBwS,OAAOm2G,GAAG1oH,IAAMiS,MAAMy2G,GAAG1oH,IACzBuS,OAAOm2G,GAAGvqG,IAAMlM,MAAMy2G,GAAGvqG,MAGjCuqG,GAAGniH,MAAQ,CAAC,EAAG,KAMXtxB,KAAKnJ,WAAW6B,QAAQ,IACxB+6I,GAAGt4F,UAAYziD,QAAQ,GACM,IAAtBA,QAAQ,GAAGnR,OAClBksJ,GAAGt4F,UAAY,CAAC,GAAGvzD,OAAO8Q,QAAQ,IACL,IAAtBA,QAAQ,GAAGnR,SAClBksJ,GAAGt4F,UAAYziD,QAAQ,IAM3B+6I,GAAGoD,eAAiB,SAAU36I,OAGtBlV,EAFAyC,EAAI,GACJoO,EAAI,MAGRpO,EAAErB,KAAK40C,MAAMy2G,GAAG3oH,KAChBrhC,EAAErB,KAAK40C,MAAMy2G,GAAG1oH,KAChBthC,EAAErB,KAAK40C,MAAMy2G,GAAGvqG,KAEZlpC,KAAKnJ,WAAW48I,GAAGt4F,WACnBtjD,EAAI47I,GAAGt4F,qBAEFn0D,EAAI,EAAGA,EAAI,EAAGA,IACf6Q,EAAEzP,KAAK4X,KAAKrG,SAAS85I,GAAGt4F,UAAUn0D,YAGtCoS,KAAKwC,IAAIM,KAAOgS,EAAAA,IAChBhS,EAAIq5I,KAAKrB,qBAAqBzqJ,EAAGoO,EAAGqE,IAEjC,CACHzS,EAAE,GAAKoO,EAAE,GAAKqE,EACdzS,EAAE,GAAKoO,EAAE,GAAKqE,EACdzS,EAAE,GAAKoO,EAAE,GAAKqE,IAKtBnD,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,SAAU,UAChEikC,OAASm4G,KAAKj8I,OAAO,UAAW,CAC5B,kBACWm6I,GAAGoD,eAAe72I,KAAKrG,SAAS85I,GAAGniH,MAAM,OAErDv4B,MACHA,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,SAAU,UAChEmkC,OAASi4G,KAAKj8I,OAAO,UAAW,CAC5B,kBACWm6I,GAAGoD,eAAe72I,KAAKrG,SAAS85I,GAAGniH,MAAM,OAErDv4B,OAGPA,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,WACtD4B,GAAKw6I,KAAKj8I,OAAO,UAAW,CAAC8jC,OAAQE,QAASvkC,OAC3CqkC,OAASA,OACZriC,GAAGuiC,OAASA,OACZF,OAAOm+C,SAASxgF,IAChBuiC,OAAOi+C,SAASxgF,IAChBA,GAAG04I,GAAKA,GAED14I,IAEXjQ,IAAIsB,gBAAgB,SAAUknJ,OAAOxnB,YAErCwnB,OAAOwD,YAAc,SAAUhqJ,MAAO4L,QAASC,gBAEvCI,KAAM06I,GACNz2G,MAGAjiC,GAAIynE,KALJ+yE,KAAO78I,QAAQ,GAGf+8I,KAAO/8I,QAAQ,GACfg9I,KAAOh9I,QAAQ,UAYnB+6I,GAAK,CACDr3D,OAAQ,UACRmvB,KAAM,GACNC,KAAM,GACNmqC,OAAQj9I,QAAQ,GAChBk9I,OAAQl9I,QAAQ,GAChB+8I,KAAMA,KACNC,KAAMA,MAIN14G,MADAh9B,KAAK9I,QAAQwB,QAAQ,IACbA,QAAQ,GAER68I,KAAKj8I,OAAO,UAAWZ,QAAQ,GAAI,CAAEiG,SAAS,EAAOrY,KAAM,GAAIi5E,WAAW,IAEtFk0E,GAAGz2G,MAAQA,MAEXy2G,GAAGsD,aAAe,eACV/vJ,MACCA,EAAI,EAAGA,EAAI,EAAGA,IACfysJ,GAAGloC,KAAKvkH,GAAKgZ,KAAKrG,SAAS85I,GAAGgC,KAAKzuJ,IACnCysJ,GAAGjoC,KAAKxkH,GAAKgZ,KAAKrG,SAAS85I,GAAGiC,KAAK1uJ,IAEvCysJ,GAAGjoG,OAAS56B,IAAI1D,aAAaumI,GAAGloC,KAAMkoC,GAAGjoC,MACzCioC,GAAG57I,EAAI+Y,IAAI3D,aAAawmI,GAAGz2G,MAAMy2G,GAAGl5I,OAAOxU,MAAM,GAAI0tJ,GAAGjoG,OAAQ,IAEpEioG,GAAGsD,eAEHh+I,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,YACtD4B,GAAKjO,MAAMwM,OAAO,QAAS,CAAC,GAAI,IAAKP,OAClC06I,GAAKA,GAER14I,GAAGw5H,gBAAkB,eACb1oF,GAAI+qG,GAAI9qG,GAAI//C,GACZ8oJ,IAAKxyG,GAAIC,GAMMzqC,EAAG7Q,EAAGC,EAAG8S,EAAG3M,EAAUm7C,IAAKyuG,QAL1CC,OAAS,CAAC,aAAc,aAAc,cACtCh+I,OAAS,GACT0yC,GAAK,CAAC,EAAG,EAAG,GACZC,GAAK,CAAC,EAAG,EAAG,GACZn3B,EAAI,CAAC,EAAG,EAAG,GACXhrB,EAAI,CAAC,EAAG,EAAG,WAEVokC,MAAQ,QACRC,MAAQ,QAER2lH,GAAGsD,eAGe,gBAAnBrqJ,KAAK+mJ,GAAGr3D,SAA4Bm5D,KAAK56E,aACvC84E,GAAGkC,QAAWlC,GAAGmC,OAqFhB,KAEH/pG,GAAK7rC,KAAKrG,SAASjN,KAAK+mJ,GAAGkC,OAAO,IAClCiB,GAAK52I,KAAKrG,SAASjN,KAAK+mJ,GAAGkC,OAAO,IAClC7pG,GAAK9rC,KAAKrG,SAASjN,KAAK+mJ,GAAGmC,OAAO,IAClC7pJ,GAAKiU,KAAKrG,SAASjN,KAAK+mJ,GAAGmC,OAAO,IAElCnhI,EAAI/nB,KAAK+mJ,GAAGz2G,MAAMy2G,GAAGl5I,OAAOxU,MAAM,GAElC4lD,GAAKj/C,KAAK+mJ,GAAGloC,KAAKxlH,QAClB6lD,GAAKl/C,KAAK+mJ,GAAGjoC,KAAKzlH,QAClBs8C,GAAKzxB,IAAIvD,KAAKs+B,GAAI,GAClBrJ,GAAK1xB,IAAIvD,KAAKu+B,GAAI,GACb5kD,EAAI,EAAGA,EAAI,EAAGA,IACf2kD,GAAG3kD,IAAMq7C,GACTuJ,GAAG5kD,IAAMs7C,OAGRr7C,EAAI,EAAGA,EAAI,EAAGA,IAAK,QACZA,QACC,EAAG8S,EAAI8xC,GAAIz+C,EAAI0+C,cACf,EAAG/xC,EAAI68I,GAAIxpJ,EAAI0+C,cACf,EAAG/xC,EAAI68I,GAAIxpJ,EAAIrB,cACf,EAAGgO,EAAI8xC,GAAIz+C,EAAIrB,OAEnB/E,EAAI,EAAGA,EAAI,EAAGA,IACfyC,EAAEzC,GAAKytB,EAAEztB,GAAK+S,EAAI4xC,GAAG3kD,GAAKoG,EAAIw+C,GAAG5kD,GAErC6tJ,IAAMU,KAAK1B,cAAcpqJ,QACpBokC,MAAMzlC,KAAKysJ,IAAI,SACf/mH,MAAM1lC,KAAKysJ,IAAI,SAGnBhnH,MAAMzlC,KAAKsE,KAAKmhC,MAAM,SACtBC,MAAM1lC,KAAKsE,KAAKohC,MAAM,QAtHzB,KAOG7mC,EAAI,EAAGA,EAAIgwJ,OAAO1vJ,OAAQN,IAAK,IAGZ,KAFpBwC,EAAI8rJ,KAAKlB,uBAAuB3nJ,KAAM6oJ,KAAK56E,YAAYs8E,OAAOhwJ,MAExD,GAAGM,QAAgC,IAAhBkC,EAAE,GAAGlC,OAAc,KAGnCP,EAAI,EAAGA,EAAIiS,OAAO1R,UACds0C,SAAShqB,SAASpoB,EAAE,GAAIwP,OAAOjS,GAAG,GAAI,GAAK4pB,IAAIzF,KAAO0wB,SAAShqB,SAASpoB,EAAE,GAAIwP,OAAOjS,GAAG,GAAI,GAAK4pB,IAAIzF,KACrG0wB,SAAShqB,SAASpoB,EAAE,GAAIwP,OAAOjS,GAAG,GAAI,GAAK4pB,IAAIzF,KAAO0wB,SAAShqB,SAASpoB,EAAE,GAAIwP,OAAOjS,GAAG,GAAI,GAAK4pB,IAAIzF,KAF/EnkB,KAM3BA,IAAMiS,OAAO1R,QACb0R,OAAO7Q,KAAKqB,EAAE1D,aAKtB0D,EAAI,CAAC,EAAG,EAAG,IACTxC,GAAKsuJ,KAAK9B,GAAGD,OAAOvsJ,GAAG,GAGzB4Q,EAAI+Y,IAAI3D,aAAaxjB,EAAG8rJ,KAAK56E,YAAYs8E,OAAOhwJ,IAAIwsJ,GAAGjoG,OAAQ,GAG3C,KAFpB/hD,EAAI8rJ,KAAKlB,uBAAuB3nJ,KAAM6oJ,KAAK56E,YAAYs8E,OAAOhwJ,IAAK4Q,IAE7D,GAAGtQ,QAAgC,IAAhBkC,EAAE,GAAGlC,OAAc,KAEnCP,EAAI,EAAGA,EAAIiS,OAAO1R,UACds0C,SAAShqB,SAASpoB,EAAE,GAAIwP,OAAOjS,GAAG,GAAI,GAAK4pB,IAAIzF,KAAO0wB,SAAShqB,SAASpoB,EAAE,GAAIwP,OAAOjS,GAAG,GAAI,GAAK4pB,IAAIzF,KACrG0wB,SAAShqB,SAASpoB,EAAE,GAAIwP,OAAOjS,GAAG,GAAI,GAAK4pB,IAAIzF,KAAO0wB,SAAShqB,SAASpoB,EAAE,GAAIwP,OAAOjS,GAAG,GAAI,GAAK4pB,IAAIzF,KAF/EnkB,KAM3BA,IAAMiS,OAAO1R,QACb0R,OAAO7Q,KAAKqB,EAAE1D,UAQlB,EACRwiD,IADQ,EAERvhD,EAAI,IACD,KAEkB,KADjByC,EAAIwP,OAAOsvC,KAAKvhD,IACVO,SACFstJ,IAAMU,KAAK1B,cAAcpqJ,QACpBokC,MAAMzlC,KAAKysJ,IAAI,SACf/mH,MAAM1lC,KAAKysJ,IAAI,KAExB7tJ,GAAKA,EAAI,GAAK,EACdyC,EAAIwP,OAAOsvC,KAAKvhD,GAEhBgwJ,QAAUzuG,IACLthD,EAAI,EAAGA,EAAIgS,OAAO1R,OAAQN,IAAK,IAC5BA,IAAMshD,KAAO1M,SAAShqB,SAASpoB,EAAGwP,OAAOhS,GAAG,IAAM2pB,IAAIzF,IAAK,CAC3Do9B,IAAMthD,EACND,EAAI,WAGJC,IAAMshD,KAAO1M,SAAShqB,SAASpoB,EAAGwP,OAAOhS,GAAG,IAAM2pB,IAAIzF,IAAK,CAC3Do9B,IAAMthD,EACND,EAAI,YAIRuhD,MAAQyuG,QAAS,CACjBrpJ,QAAQK,IAAI,2CAA4Cu6C,kBA3BxD,IA8BCA,KACTssG,IAAMU,KAAK1B,cAAc56I,OA/BjB,GA+B+B,SAClC40B,MAAMzlC,KAAKysJ,IAAI,SACf/mH,MAAM1lC,KAAKysJ,IAAI,MAwC5B97I,KAAOiH,KAAK9G,eAAeP,WAAWi5I,OAAQ9kJ,MAAMqM,QAAS,UAEzDs6I,GAAGkC,QAAUlC,GAAGmC,SAChBpzE,KAAO+yE,KAAKj8I,OAAO,SAAU,CAAC0jC,MAAMy2G,GAAGl5I,OAAOxU,MAAM,GAAI0vJ,KAAMhC,GAAGkC,OAAQD,KAAMjC,GAAGmC,QAAS78I,MAC3FgC,GAAGynE,KAAOA,KACVznE,GAAGwhF,SAASn0F,KAAKo6E,OAWdznE,IAEXjQ,IAAIsB,gBAAgB,UAAWknJ,OAAOwD,gBAiC1ChyJ,OAAO,aAAa,CAAC,MAAO,iBAAkB,YAAa,gBAAiB,aAAc,cACvF,SAAUgG,IAAKoL,MAAO0a,IAAKirB,SAAU77B,KAAMszI,QA4BzCA,OAAO7pB,YAAc,SAAU38H,MAAO4L,QAASC,gBAExCI,KAAMm+I,SAAUzD,GAChBzsJ,EAAG6tJ,IACH95I,GAHAw6I,KAAO78I,QAAQ,MAKnBK,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,WAEtDs6I,GAAK,CACDr3D,OAAQ,UACR7hF,OAAQ,CAAC,EAAG,EAAG,EAAG,GAClBuwB,EAAG,kBAAqBp+B,KAAK6N,OAAO,IACpCwwB,EAAG,kBAAqBr+B,KAAK6N,OAAO,IACpC2uC,EAAG,kBAAqBx8C,KAAK6N,OAAO,KAKpC7B,QAAQnR,OAAS,GAAKyY,KAAKzU,OAAOmN,QAAQA,QAAQnR,OAAS,GAAGksJ,IAC9DA,GAAGlsD,MAAQ7uF,QAAQy6B,MAEnBsgH,GAAGlsD,MAAQ,KAGQ,IAAnB7uF,QAAQnR,OACRksJ,GAAGnpH,EAAI5xB,QAAQ,GACf+6I,GAAGl5I,OAAS,CAAC,GAAG3S,OAAOoY,KAAKrG,SAAS85I,GAAGnpH,SACrC,GAAuB,IAAnB5xB,QAAQnR,WACfksJ,GAAGnpH,EAAI5xB,QAAQ3S,MAAM,GAChBiB,EAAI,EAAGA,EAAI,EAAGA,IACfysJ,GAAGl5I,OAAOvT,EAAI,GAAKgZ,KAAKrG,SAAS85I,GAAGnpH,EAAEtjC,WAU9CysJ,GAAGzsD,aAAe,eACV76E,IAAKnlB,KACLgZ,KAAKnJ,WAAWnK,KAAK49B,GACrBne,IAAMnM,KAAKrG,SAASjN,KAAK49B,QACpB/vB,OAAS,CAAC,EAAG4R,IAAI,GAAIA,IAAI,GAAIA,IAAI,kBAEjC5R,OAAO,GAAK,EACZvT,EAAI,EAAGA,EAAI,EAAGA,IACXgZ,KAAKnJ,WAAWnK,KAAK49B,EAAEtjC,WAClBuT,OAAOvT,EAAI,GAAKgZ,KAAKrG,SAASjN,KAAK49B,EAAEtjC,YAI/C0F,MAEX+mJ,GAAGzsD,eAEH6tD,IAAMU,KAAK1B,cAAcJ,GAAGl5I,SAC5BQ,GAAKjO,MAAMwM,OAAO,QAASu7I,IAAK97I,OAC7B06I,GAAKA,GACR14I,GAAG04I,GAAGoB,IAAM95I,GAAGR,OAAOG,UAAU3U,QAChCmxJ,SAAWn8I,GAAGmsB,OAEVnsB,GAAG04I,GAAGlsD,QACNxsF,GAAGo8I,SAAW,SAAU5tJ,EAAGkR,EAAGD,EAAG65B,SACzB+iH,QAAUr8I,GAAG04I,GAAGlsD,MAAMksD,GACtBO,IAAM,CAAC,EAAGoD,QAAQtsH,EAAEtwB,EAAE,GAAIA,EAAE,IAAK48I,QAAQrsH,EAAEvwB,EAAE,GAAIA,EAAE,IAAK48I,QAAQluG,EAAE1uC,EAAE,GAAIA,EAAE,KAC1Eq6I,IAAMU,KAAK1B,cAAcG,YAE7B3/G,IAAI,GAAKt5B,GAAG+vB,IAAM+pH,IAAI,GACtBxgH,IAAI,GAAKt5B,GAAGgwB,IAAM8pH,IAAI,GAEfxgH,IAAI,GAAKA,IAAI,GAAKA,IAAI,GAAKA,IAAI,IAG1Ct5B,GAAGs8I,sBAAwB,eAUhBrD,IAAKa,IAPRr6I,EAAI,CAAC,EAAG,GAMR48I,QAAU1qJ,KAAK+mJ,GAAGlsD,MAAMksD,GAGxBzzI,KAAKzU,OAAOmB,KAAK+mJ,GAAGxa,UACpBz+H,EAAI9N,KAAK+mJ,GAAGxa,OAAOlzI,SAEnB6qB,IAAIwiB,IAAIO,YAAYjnC,KAAKyqJ,SAdrB,EACA,EAaqC38I,EAVhC,EACA,KACA,EACA,KASbw5I,IAAM,CAAC,EAAGoD,QAAQtsH,EAAEtwB,EAAE,GAAIA,EAAE,IAAK48I,QAAQrsH,EAAEvwB,EAAE,GAAIA,EAAE,IAAK48I,QAAQluG,EAAE1uC,EAAE,GAAIA,EAAE,KAC1Eq6I,IAAMU,KAAK1B,cAAcG,UACpBP,GAAGxa,OAASz+H,OACZi5I,GAAGl5I,OAASy5I,SACZz5I,OAAO2W,eAAehb,MAAM1H,eAAgBqmJ,UAC5CpB,GAAGoB,IAAMA,MAItB95I,GAAGmsB,OAAS,SAAU+1C,UACd+2E,IAAKvoG,YACJ/+C,KAAKivF,aAONjvF,KAAKwxF,aACqD,IAA1DriD,SAAShqB,SAASnlB,KAAK+mJ,GAAGoB,IAAKnoJ,KAAK6N,OAAOG,WAEvChO,KAAK+mJ,GAAGlsD,WACH8vD,yBAGL5rG,KAAO,CAAC,EAAG,EAAG,EAAG/+C,KAAK+mJ,GAAGl5I,OAAO,IAEjB,KADfy5I,IAAMuB,KAAKzB,mBAAmB/4I,GAAI,CAAC,EAAG,EAAG,EAAG,GAAI0wC,OACxC,UACCgoG,GAAGl5I,OAASg7I,KAAKxB,gBAAgBC,aAIzCP,GAAGzsD,eAERjsF,GAAGR,OAAO2W,eAAehb,MAAM1H,eAC3B+mJ,KAAK1B,cAAc,CAAC,EAAGnnJ,KAAK+mJ,GAAG3oH,IAAKp+B,KAAK+mJ,GAAG1oH,IAAKr+B,KAAK+mJ,GAAGvqG,aAG5DuqG,GAAGoB,IAAM95I,GAAGR,OAAOG,UAAU3U,QAElCmxJ,SAAS7uJ,MAAMqE,KAAM,CAACuwE,OACfvwE,MA7BIA,MAgCRqO,IAEXjQ,IAAIsB,gBAAgB,UAAWknJ,OAAO7pB,gBAiC1C3kI,OAAO,eAAe,CAAC,MAAO,aAAc,cACzC,SAAUgG,IAAKkV,KAAMszI,QAgEpBA,OAAOgE,wBAA0B,SAAUxqJ,MAAO4L,QAASC,gBAEnDI,KAMA06I,GAAI14I,GAPJw6I,KAAO78I,QAAQ,UASnB+6I,GAAK,CACDr3D,OAAQ,YACRtxD,EATIpyB,QAAQ,GAUZqyB,EATIryB,QAAQ,GAUZwwC,EATIxwC,QAAQ,GAUZ6+I,QATU7+I,QAAQ,GAUlB8+I,QATU9+I,QAAQ,IAWtBK,KAAOiH,KAAK9G,eAAeP,WAAY7L,MAAMqM,QAAS,cACtD4B,GAAKjO,MAAMwM,OAAO,QAAS,CAAC,GAAI,IAAKP,OAClCw7H,gBAAkB,eACbygB,QAAUh1I,KAAKrG,SAASjN,KAAK+S,QAAQg4I,QACrCxC,QAAUj1I,KAAKrG,SAASjN,KAAK+S,QAAQi4I,QACrCC,IAAM33I,KAAKrG,SAASjN,KAAK+mJ,GAAG8D,SAC5BK,IAAM53I,KAAKrG,SAASjN,KAAK+mJ,GAAG+D,SAC5BrrI,IAAMopI,KAAKf,QAAQ9nJ,KAAK+mJ,GAAG3oH,EAAGp+B,KAAK+mJ,GAAG1oH,EAAGr+B,KAAK+mJ,GAAGvqG,EAC7CyuG,IAAI/vJ,OAAO,CAACotJ,UACZ4C,IAAIhwJ,OAAO,CAACqtJ,gBACfpnH,MAAQ1hB,IAAI,QACZ2hB,MAAQ3hB,IAAI,IAErBpR,GAAG04I,GAAKA,GAED14I,IAEXjQ,IAAIsB,gBAAgB,sBAAuBknJ,OAAOgE,yBA6ElDhE,OAAOpe,oBAAsB,SAAUpoI,MAAO4L,QAASC,gBAC/C48I,KAAO78I,QAAQ,GAGfwwC,EAAIxwC,QAAQ,GACZ6+I,QAAU7+I,QAAQ,GAClB8+I,QAAU9+I,QAAQ,UAEf68I,KAAKj8I,OAAO,sBAAuB,CANlC,SAASua,EAAGnd,UAAYmd,GACxB,SAASA,EAAGnd,UAAYA,GAKiBwyC,EAAGquG,QAASC,SAAU7+I,aAE3E7N,IAAIsB,gBAAgB,kBAAmBknJ,OAAOpe,wBAKlDpwI,OAAO,wBAAwB,CAC3B,MACA,YACA,iBACA,aACA,YACA,cACA,eACA,YACA,iBACA,UACA,mBACA,WACA,gBACA,WACA,YACA,gBACA,kBACA,gBACA,gBACA,YACA,YACA,eACA,oBACA,cACA,iBACA,aACA,UACA,WACA,eACA,cACA,qBACA,aACA,YACA,aACA,cACA,gBACA,eACA,aACA,cACA,iBACA,mBACA,sBACA,gBACA,YACA,aACA,iBACA,kBACA,aACA,sBACA,cACA,cACA,aACA,YACA,eACA,aACA,iBACA,gBACA,oBACA,oBACA,YACA,aACA,eACA,eACA,kBACA,cACA,eACA,wBACA,mBACA,gBACA,iBACA,qBACA,YACA,WACA,aACA,gBACA,aACA,eACA,YACA,cACD,SAAUgG,IAAK02B,YAIVA,IAAI7gB,UACJjT,OAAO5C,IAAMA,IAQN02B,IAAIlgB,UAA8B,gCAAX1X,2BAAAA,SAC9BA,OAAOF,QAAUoB,IACV02B,IAAI7f,gBACXC,KAAK9W,IAAMA,KAGRA,OAGH9F,QAAQ,yBAx4gFT"} \ No newline at end of file diff --git a/amd/src/input.js b/amd/src/input.js index a9879d3f0..7852eb6c4 100644 --- a/amd/src/input.js +++ b/amd/src/input.js @@ -30,7 +30,7 @@ * - StackMatrixInput * objects of these types need to implement the two methods addEventHandlers and getValue(). * - * @package qtype_stack + * @module qtype_stack/input * @copyright 2018 The Open University * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ diff --git a/amd/src/jsxgraph.js b/amd/src/jsxgraph.js index a015e0a6f..8cc227b91 100644 --- a/amd/src/jsxgraph.js +++ b/amd/src/jsxgraph.js @@ -4,12 +4,13 @@ define(["qtype_stack/jsxgraphcore-lazy"], function(JXG) { return { find_input_id: function(divid, name) { var tmp = document.getElementById(divid); - while ((tmp = tmp.parentElement) && !(tmp.classList.contains("formulation") && tmp.parentElement.classList.contains("content"))) {} + while ((tmp = tmp.parentElement) && !(tmp.classList.contains("formulation") && + tmp.parentElement.classList.contains("content"))) {} tmp = tmp.querySelector('input[id$="_' + name + '"]'); // We use this function to also tie into the change tracking of Moodle. // We do it here so that all possible code written by authors will also be tracked. // The author just needst to generate a change event they do not need to know how the VLE works. - tmp.addEventListener('change', function(e) { + tmp.addEventListener('change', function() { M.core_formchangechecker.set_form_changed(); }); return tmp.id; @@ -59,7 +60,7 @@ define(["qtype_stack/jsxgraphcore-lazy"], function(JXG) { var lastValue = JSON.stringify([point.X(), point.Y()]); // Then from input to graph. 'input' for live stuff and 'change' for other. - theInput.addEventListener('input', function(e) { + theInput.addEventListener('input', function() { if (theInput.value != lastValue) { // Only when something changed. try { @@ -75,7 +76,7 @@ define(["qtype_stack/jsxgraphcore-lazy"], function(JXG) { lastValue = theInput.value; } }); - theInput.addEventListener('change', function(e) { + theInput.addEventListener('change', function() { if (theInput.value != lastValue) { // Only when something changed. try { @@ -165,7 +166,7 @@ define(["qtype_stack/jsxgraphcore-lazy"], function(JXG) { var lastValue = JSON.stringify([[point1.X(), point1.Y()],[point2.X(), point2.Y()]]); // Then from input to graph. 'input' for live stuff and 'change' for other. - theInput.addEventListener('input', function(e) { + theInput.addEventListener('input', function() { if (theInput.value != lastValue) { // Only when something changed. try { @@ -186,7 +187,7 @@ define(["qtype_stack/jsxgraphcore-lazy"], function(JXG) { lastValue = theInput.value; } }); - theInput.addEventListener('change', function(e) { + theInput.addEventListener('change', function() { if (theInput.value != lastValue) { // Only when something changed. try { @@ -284,7 +285,7 @@ define(["qtype_stack/jsxgraphcore-lazy"], function(JXG) { var lastValue = JSON.stringify([[point1.X(), point1.Y()],[point2.X() - point1.X(), point2.Y() - point1.Y()]]); // Then from input to graph. 'input' for live stuff and 'change' for other. - theInput.addEventListener('input', function(e) { + theInput.addEventListener('input', function() { if (theInput.value != lastValue) { // Only when something changed. try { @@ -306,7 +307,7 @@ define(["qtype_stack/jsxgraphcore-lazy"], function(JXG) { lastValue = theInput.value; } }); - theInput.addEventListener('change', function(e) { + theInput.addEventListener('change', function() { if (theInput.value != lastValue) { // Only when something changed. try { @@ -366,7 +367,8 @@ define(["qtype_stack/jsxgraphcore-lazy"], function(JXG) { if (initial1X !== point1.X() || initial1Y !== point1.Y()) { var tmp = JSON.stringify([[point1.X(), point1.Y()], [Math.atan2(point2.Y() - point1.Y(), point2.X() - point1.X()), - Math.sqrt((point2.X() - point1.X())*(point2.X() - point1.X()) + (point2.Y() - point1.Y())*(point2.Y() - point1.Y()))]]); + Math.sqrt((point2.X() - point1.X())*(point2.X() - point1.X()) + + (point2.Y() - point1.Y())*(point2.Y() - point1.Y()))]]); initial1X = false; // ignore these after initial change. initial1Y = false; if (theInput.value != tmp) { @@ -393,7 +395,8 @@ define(["qtype_stack/jsxgraphcore-lazy"], function(JXG) { if (initial2X !== point2.X() || initial2Y !== point2.Y()) { var tmp = JSON.stringify([[point1.X(), point1.Y()], [Math.atan2(point2.Y() - point1.Y(), point2.X() - point1.X()), - Math.sqrt((point2.X() - point1.X())*(point2.X() - point1.X()) + (point2.Y() - point1.Y())*(point2.Y() - point1.Y()))]]); + Math.sqrt((point2.X() - point1.X())*(point2.X() - point1.X()) + + (point2.Y() - point1.Y())*(point2.Y() - point1.Y()))]]); initial2X = false; // ignore these after initial change. initial2Y = false; if (theInput.value != tmp) { @@ -414,10 +417,11 @@ define(["qtype_stack/jsxgraphcore-lazy"], function(JXG) { var lastValue = JSON.stringify([[point1.X(), point1.Y()], [Math.atan2(point2.Y() - point1.Y(), point2.X() - point1.X()), - Math.sqrt((point2.X() - point1.X())*(point2.X() - point1.X()) + (point2.Y() - point1.Y())*(point2.Y() - point1.Y()))]]); + Math.sqrt((point2.X() - point1.X())*(point2.X() - point1.X()) + + (point2.Y() - point1.Y())*(point2.Y() - point1.Y()))]]); // Then from input to graph. 'input' for live stuff and 'change' for other. - theInput.addEventListener('input', function(e) { + theInput.addEventListener('input', function() { if (theInput.value != lastValue) { // Only when something changed. try { @@ -445,7 +449,7 @@ define(["qtype_stack/jsxgraphcore-lazy"], function(JXG) { lastValue = theInput.value; } }); - theInput.addEventListener('change', function(e) { + theInput.addEventListener('change', function() { if (theInput.value != lastValue) { // Only when something changed. try { @@ -517,7 +521,7 @@ define(["qtype_stack/jsxgraphcore-lazy"], function(JXG) { var lastValue = JSON.stringify(slider.Value()); // Then from input to graph. 'input' for live stuff and 'change' for other. - theInput.addEventListener('input', function(e) { + theInput.addEventListener('input', function() { if (theInput.value !== lastValue) { // Only when something changed. try { @@ -533,7 +537,7 @@ define(["qtype_stack/jsxgraphcore-lazy"], function(JXG) { lastValue = theInput.value; } }); - theInput.addEventListener('change', function(e) { + theInput.addEventListener('change', function() { if (theInput.value !== lastValue) { // Only when something changed. try { diff --git a/amd/src/jsxgraphcore-lazy.js b/amd/src/jsxgraphcore-lazy.js index 7676756d0..cc5fc1152 100644 --- a/amd/src/jsxgraphcore-lazy.js +++ b/amd/src/jsxgraphcore-lazy.js @@ -1,14 +1,13 @@ -define(function () { /* - JSXGraph 1.2.1 + JSXGraph 1.4.4 - Copyright 2008-2021 + Copyright 2008-2022 Matthias Ehmann, Michael Gerhaeuser, Carsten Miller, Bianca Valentin, - Alfred Wassermann, Andreas Walter, + Alfred Wassermann, Peter Wilfahrt This file is part of JSXGraph. @@ -33,32 +32,14 @@ define(function () { and <https://opensource.org/licenses/MIT/>. */ -/** - * almond 0.2.5 Copyright (c) 2011-2012, The Dojo Foundation All Rights Reserved. - * Available via the MIT or new BSD license. - * see: https://github.com/jrburke/almond for details - */ +define(function () { /** - * UTF-8 Decoder by Bjoern Hoehrmann - * - * Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de> - * - * 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. + * @license almond 0.3.3 Copyright jQuery Foundation and other contributors. + * Released under MIT license, http://github.com/requirejs/almond/LICENSE */ +//Going sloppy to avoid 'use strict' string cost, but strict practices should +//be followed. /*global setTimeout: false */ var requirejs, require, define; @@ -491,13 +472,13 @@ var requirejs, require, define; define("../node_modules/almond/almond", function(){}); /* - Copyright 2008-2021 + Copyright 2008-2022 Matthias Ehmann, Michael Gerhaeuser, Carsten Miller, Bianca Valentin, - Alfred Wassermann, Andreas Walter, + Alfred Wassermann, Peter Wilfahrt This file is part of JSXGraph and JSXCompressor. @@ -545,6 +526,7 @@ define('jxg',[], function () { /** * JXG is the top object of JSXGraph and defines the namespace + * @exports jxg as JXG */ var jxg = {}; @@ -591,9 +573,16 @@ define('jxg',[], function () { * Set a constant <tt>name</tt> in <tt>object</tt> to <tt>value</tt>. The value can't be changed after declaration. * @param {Object} object * @param {String} name - * @param value + * @param {Number|String|Boolean} value + * @param {Boolean} ignoreRedefine This should be left at its default: false. */ - jxg.defineConstant = function (object, name, value) { + jxg.defineConstant = function (object, name, value, ignoreRedefine) { + ignoreRedefine = ignoreRedefine || false; + + if (ignoreRedefine && jxg.exists(object[name])) { + return; + } + Object.defineProperty(object, name, { value: value, writable: false, @@ -615,9 +604,9 @@ define('jxg',[], function () { onlyOwn = onlyOwn || false; toUpper = toUpper || false; - // the purpose of this for...in loop is indeed to use hasOwnProperty only if the caller explicitly wishes so. + // The purpose of this for...in loop is indeed to use hasOwnProperty only if the caller explicitly wishes so. for (e in constants) { - if (!onlyOwn || (onlyOwn && extension.hasOwnProperty(e))) { + if (!onlyOwn || (onlyOwn && constants.hasOwnProperty(e))) { if (toUpper) { e2 = e.toUpperCase(); } else { @@ -645,7 +634,7 @@ define('jxg',[], function () { /** * Associative array that keeps track of all constructable elements registered - * via {@link JXG.JSXGraph.registerElement}. + * via {@link JXG.registerElement}. * @type Object */ elements: {}, @@ -837,13 +826,13 @@ define('jxg',[], function () { }); /* - Copyright 2008-2021 + Copyright 2008-2022 Matthias Ehmann, Michael Gerhaeuser, Carsten Miller, Bianca Valentin, - Alfred Wassermann, Andreas Walter, + Alfred Wassermann, Peter Wilfahrt This file is part of JSXGraph. @@ -879,9 +868,9 @@ define('base/constants',['jxg'], function (JXG) { 'use strict'; var major = 1, - minor = 2, - patch = 1, - add = '', //'dev_a', // 'dev', + minor = 4, + patch = 4, + add = '', //'dev' version = major + '.' + minor + '.' + patch + (add ? '-' + add : ''), constants; @@ -890,7 +879,7 @@ define('base/constants',['jxg'], function (JXG) { * Constant: the currently used JSXGraph version. * * @name JXG.version - * @type {String} + * @type String */ version: version, @@ -899,21 +888,21 @@ define('base/constants',['jxg'], function (JXG) { * showCopyright is not set to false on board creation). * * @name JXG.licenseText - * @type {String} + * @type String */ licenseText: 'JSXGraph v' + version + ' Copyright (C) see https://jsxgraph.org', /** * Constant: user coordinates relative to the coordinates system defined by the bounding box. * @name JXG.COORDS_BY_USER - * @type {Number} + * @type Number */ COORDS_BY_USER: 0x0001, /** * Constant: screen coordinates in pixel relative to the upper left corner of the div element. * @name JXG.COORDS_BY_SCREEN - * @type {Number} + * @type Number */ COORDS_BY_SCREEN: 0x0002, @@ -948,6 +937,8 @@ define('base/constants',['jxg'], function (JXG) { OBJECT_TYPE_INPUT: 28, OBJECT_TYPE_BUTTON: 29, OBJECT_TYPE_TRANSFORMATION: 30, + OBJECT_TYPE_FOREIGNOBJECT: 31, + OBJECT_TYPE_VIEW3D: 32, // IMPORTANT: // ---------- @@ -968,8 +959,19 @@ define('base/constants',['jxg'], function (JXG) { GENTYPE_ABC: 1, // unused GENTYPE_AXIS: 2, GENTYPE_MID: 3, - /** @deprecated, now use {@link JXG.GENTYPE_REFLECTION_ON_LINE} */ GENTYPE_REFLECTION: 4, - /** @deprecated, now use {@link JXG.GENTYPE_REFLECTION_ON_POINT} */ GENTYPE_MIRRORELEMENT: 5, + + /** + * @ignore + * @deprecated, now use {@link JXG.GENTYPE_REFLECTION_ON_LINE} + * + */ + GENTYPE_REFLECTION: 4, + /** + * @ignore + * @deprecated, now use {@link JXG.GENTYPE_REFLECTION_ON_POINT} + */ + GENTYPE_MIRRORELEMENT: 5, + GENTYPE_REFLECTION_ON_LINE: 4, GENTYPE_REFLECTION_ON_POINT: 5, GENTYPE_TANGENT: 6, @@ -982,7 +984,11 @@ define('base/constants',['jxg'], function (JXG) { GENTYPE_GLIDER: 13, GENTYPE_INTERSECTION: 14, GENTYPE_CIRCLE: 15, - /** @deprecated NOT USED ANY MORE SINCE SKETCHOMETRY 2.0 (only for old constructions needed) */ GENTYPE_CIRCLE2POINTS: 16, + /** + * @ignore @deprecated NOT USED ANY MORE SINCE SKETCHOMETRY 2.0 (only for old constructions needed) + */ + GENTYPE_CIRCLE2POINTS: 16, + GENTYPE_LINE: 17, GENTYPE_TRIANGLE: 18, GENTYPE_QUADRILATERAL: 19, @@ -1014,7 +1020,12 @@ define('base/constants',['jxg'], function (JXG) { GENTYPE_ABLATION: 45, GENTYPE_MIGRATE: 46, GENTYPE_VECTORCOPY: 47, - GENTYPE_POLYGONCOPY: 48, + GENTYPE_POLYGONCOPY: 48, /** + * Constants + * @name Constants + * @namespace + */ + // GENTYPE_TRANSFORM: 48, // unused // 49 ... 50 // unused ... @@ -1064,13 +1075,13 @@ define('base/constants',['jxg'], function (JXG) { }); /* - Copyright 2008-2021 + Copyright 2008-2022 Matthias Ehmann, Michael Gerhaeuser, Carsten Miller, Bianca Valentin, - Alfred Wassermann, Andreas Walter, + Alfred Wassermann, Peter Wilfahrt This file is part of JSXGraph. @@ -1261,18 +1272,29 @@ define('utils/type',[ * @param {Boolean} [checkEmptyString=false] If set to true, it is also checked whether v is not equal to ''. * @returns {Boolean} True, if v is neither undefined nor null. */ - exists: (function (undef) { - return function (v, checkEmptyString) { - var result = !(v === undef || v === null); + exists: function (v, checkEmptyString) { + /* eslint-disable eqeqeq */ + var result = !(v == undefined || v === null); + /* eslint-enable eqeqeq */ + checkEmptyString = checkEmptyString || false; - checkEmptyString = checkEmptyString || false; - - if (checkEmptyString) { - return result && v !== ''; - } - return result; - }; - }()), + if (checkEmptyString) { + return result && v !== ''; + } + return result; + }, + // exists: (function (undef) { + // return function (v, checkEmptyString) { + // var result = !(v === undef || v === null); + + // checkEmptyString = checkEmptyString || false; + + // if (checkEmptyString) { + // return result && v !== ''; + // } + // return result; + // }; + // }()), /** * Checks if v is an empty object or empty. @@ -1386,7 +1408,8 @@ define('utils/type',[ }, /** - * Test if the parents array contains existing points. If instead parents contains coordinate arrays or function returning coordinate arrays + * Test if the parents array contains existing points. If instead parents contains coordinate arrays or + * function returning coordinate arrays * free points with these coordinates are created. * * @param {JXG.Board} board Board object @@ -1429,10 +1452,12 @@ define('utils/type',[ } if (this.isArray(parents[i]) && parents[i].length > 1) { points.push(board.create('point', parents[i], attr)); + points[points.length - 1]._is_new = true; } else if (this.isFunction(parents[i])) { val = parents[i](); if (this.isArray(val) && (val.length > 1)) { points.push(board.create('point', [parents[i]], attr)); + points[points.length - 1]._is_new = true; } } else { points.push(board.select(parents[i])); @@ -1765,12 +1790,12 @@ define('utils/type',[ * is returned by JavaScript's toFixed() * * @memberOf JXG - * @param {Number} num Number tp be rounded - * @param {Number} precision Decimal digits - * @return {String} Rounded number is returned as string + * @param {Number} num Number tp be rounded + * @param {Number} digits Decimal digits + * @return {String} Rounded number is returned as string */ - toFixed: function (num, precision) { - return this._round10(num, -precision).toFixed(precision); + toFixed: function (num, digits) { + return this._round10(num, -digits).toFixed(digits); }, /** @@ -2028,7 +2053,7 @@ define('utils/type',[ } // options from attributes - o = attributes; + o = (typeof attributes === 'object') ? attributes : {}; isAvail = true; for (i = 3; i < len; i++) { if (this.exists(o[arguments[i]])) { @@ -2042,6 +2067,11 @@ define('utils/type',[ this.extend(a, o, null, true); } + if (arguments[2] === 'board') { + // For board attributes we are done now. + return a; + } + // Special treatment of labels o = options; isAvail = true; @@ -2167,6 +2197,7 @@ define('utils/type',[ strokecolor: '', strokeopacity: '', strokewidth: '', + tabindex: -100000, transitionduration: 0, top: -100000, visible: null @@ -2211,7 +2242,7 @@ define('utils/type',[ * @returns {String} */ unescapeHTML: function (str) { - // this regex is NOT insecure. We are replacing everything found with '' + // This regex is NOT insecure. We are replacing everything found with '' /*jslint regexp:true*/ return str.replace(/<\/?[^>]+>/gi, '').replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'); }, @@ -2328,7 +2359,7 @@ define('utils/type',[ return html_sanitize(str, function () { return undefined; }, function (id) { return id; }); } - if (str) { + if (str && typeof str === 'string') { str = str.replace(/</g, '<').replace(/>/g, '>'); } @@ -2353,13 +2384,13 @@ define('utils/type',[ }); /* - Copyright 2008-2021 + Copyright 2008-2022 Matthias Ehmann, Michael Gerhaeuser, Carsten Miller, Bianca Valentin, - Alfred Wassermann, Andreas Walter, + Alfred Wassermann, Peter Wilfahrt This file is part of JSXGraph. @@ -2405,8 +2436,9 @@ define('utils/env',['jxg', 'utils/type'], function (JXG, Type) { JXG.extendConstants(JXG, /** @lends JXG */{ /** * Determines the property that stores the relevant information in the event object. - * @type {String} + * @type String * @default 'touches' + * @private */ touchProperty: 'touches', }); @@ -2427,7 +2459,7 @@ define('utils/env',['jxg', 'utils/type'], function (JXG, Type) { * @returns {Boolean} */ isPointerEvent: function (evt) { - return JXG.exists(evt['pointerId']); + return JXG.exists(evt.pointerId); }, /** @@ -2485,12 +2517,16 @@ define('utils/env',['jxg', 'utils/type'], function (JXG, Type) { * @default false */ supportsES6: function () { + var testMap; + /* jshint ignore:start */ try { + // This would kill the old uglifyjs: testMap = (a = 0) => a; new Function('(a = 0) => a'); return true; } catch (err) { return false; } + /* jshint ignore:end */ }, /** @@ -2602,7 +2638,7 @@ define('utils/env',['jxg', 'utils/type'], function (JXG, Type) { * @returns {Boolean} */ isWebkitApple: function () { - return this.isApple() && (navigator.userAgent.search(/Mobile\/[0-9A-Za-z\.]*Safari/) > -1); + return this.isApple() && (navigator.userAgent.search(/Mobile\/[0-9A-Za-z.]*Safari/) > -1); }, /** @@ -3142,33 +3178,74 @@ define('utils/env',['jxg', 'utils/type'], function (JXG, Type) { window.setTimeout(timerFun, 1); }, + /** + * Calculate the scale factor and vertical shift for the JSXGraph div + * in full screen mode. + * + * @param {Object} obj Reference to a DOM node. + * @returns Object {scale: number, vshift: number} + * @see JXG.Board#fullscreenListener + * @private + */ + _getScaleFactors: function (node) { + var width = node.getBoundingClientRect().width, + height = node.getBoundingClientRect().height, + + // Determine the maximum scale factor. + r_w = window.screen.width / width, + r_h = window.screen.height / height, + + // Determine the vertical shift to place the div in the center of the screen + vshift = (window.screen.height - height) * 0.5, + + // Scaling factor: if not supplied, it's taken as large as possible + scale = Math.min(r_w, r_h); + + // Adapt vshift and scale for landscape on tablets + if (window.matchMedia && window.matchMedia('(orientation:landscape)').matches && + window.screen.width < window.screen.height) { + // Landscape on iOS: it returns 'landscape', but still width < height. + r_w = window.screen.height / width; + r_h = window.screen.width / height; + scale = Math.min(r_w, r_h); + vshift = (window.screen.width - height) * 0.5; + } + scale *= 0.85; + + return { scale: scale, vshift: vshift, width: width }; + }, + /** * Scale and vertically shift a DOM element (usually a JSXGraph div) * inside of a parent DOM * element which is set to fullscreen. * This is realized with a CSS transformation. - * + * * * @param {String} wrap_id id of the parent DOM element which is in fullscreen mode - * @param {String} inner_id id of the DOM element which is scaled and shifted- + * @param {String} inner_id id of the DOM element which is scaled and shifted * @param {Number} scale Scaling factor * @param {Number} vshift Vertical shift (in pixel) * * @private - * @see JXG#toFullscreen + * @see JXG.Board#toFullscreen + * @see JXG.Board#fullscreenListener + * */ scaleJSXGraphDiv: function (wrap_id, inner_id, scale, vshift) { var len = document.styleSheets.length, style, - pseudo_keys = [':-webkit-full-screen', ':-moz-full-screen', ':fullscreen', ':-ms-fullscreen'], + pseudo_keys = [':fullscreen', ':-webkit-full-screen', ':-moz-full-screen', ':-ms-fullscreen'], len_pseudo = pseudo_keys.length, i, + // CSS rules to center the inner div horizontally and vertically. rule_inner = '{margin:0 auto;transform:matrix(' + scale + ',0,0,' + scale + ',0,' + vshift + ');}', + // A previously installed CSS rule to center the JSXGraph div has to // be searched and removed again. - regex = new RegExp('.*' + wrap_id + ':.*full.*screen.*' + inner_id + '.*auto;.*transform:.*matrix'); + regex = new RegExp('.*#' + wrap_id + ':.*full.*screen.*#' + inner_id + '.*auto;.*transform:.*matrix'); if (len === 0) { - // In case there is not a single CSS rule defined. + // In case there is not a single CSS rule defined at all. style = document.createElement('style'); // WebKit hack :( style.appendChild(document.createTextNode('')); @@ -3185,92 +3262,19 @@ define('utils/env',['jxg', 'utils/type'], function (JXG, Type) { document.styleSheets[len - 1].deleteRule(0); } - // Install a CSS rule to center the JSXGraph div at the first position - // of the list. + // Install a CSS rule to center the JSXGraph div at the first position of the list. for (i = 0; i < len_pseudo; i++) { try { - document.styleSheets[len - 1].insertRule(wrap_id + pseudo_keys[i] + ' ' + inner_id + rule_inner, 0); + document.styleSheets[len - 1].insertRule('#' + wrap_id + pseudo_keys[i] + ' #' + inner_id + rule_inner, 0); break; } catch (err) { - console.log('JXG.scaleJSXGraphDiv: Could not add CSS rule "' + pseudo_keys[i] + '".'); - console.log('One possible reason could be that the id of the JSXGraph container does not start with a letter.'); + // console.log('JXG.scaleJSXGraphDiv: Could not add CSS rule "' + pseudo_keys[i] + '".'); + // console.log('One possible reason could be that the id of the JSXGraph container does not start with a letter.'); } } - }, - - /** - * Set the DOM element with id='wrap_id' containing the the JSXGraph div - * element into fullscreen mode. - * By default, the JSXGraph element is scaled as large as possible while - * retaining its proportions. - * - * @param {String} wrap_id id of DOM element containing the JSXGraph - * div element. - * - * @param {String} jsxgraph_id ID of the JSXGraph div element. - * @parame {Number} scale scale factor for the JSXGraph div. If null, - * the scaling factor is chosen as large as possible. - * - * @example - * - * <div id="outer" class="JXG_wrap_private"> - * <div id='jxgbox' class='jxgbox' style='width:300px; height:300px;'></div> - * </div> - * <button onClick="JXG.toFullscreen('outer', 'jxgbox')">Fullscreen</button> - * <script> - * var board = JXG.JSXGraph.initBoard('jxgbox', {axis:true, boundingbox:[-8, 8, 8,-8]}); - * var p = board.create('point', [0, 1]); - * </script> - * - * </pre><div id="JXGf9b973ea4_outer" class="JXG_wrap_private"><div id="JXGd9b973ea4-fd43-11e8-ab14-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div></div> - * <button onClick="JXG.toFullscreen('JXGf9b973ea4_outer', 'JXGd9b973ea4-fd43-11e8-ab14-901b0e1b8723')">Fullscreen</button> - * <script type="text/javascript"> - * (function() { - * var board = JXG.JSXGraph.initBoard('JXGd9b973ea4-fd43-11e8-ab14-901b0e1b8723', - * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); - * var p = board.create('point', [0, 1]); - * })(); - * </script><pre> - * - */ - toFullscreen: function (wrap_id, jsxgraph_id, scale) { - var elem = document.getElementById(wrap_id), - elem_inner = document.getElementById(jsxgraph_id), - - // height seems to be independent from zoom level on all browsers - height = parseInt(elem_inner.style.height, 10), - - // Determine the maximum scale factor. - r_w = window.screen.width / parseInt(elem_inner.style.width, 10), - r_h = window.screen.height / parseInt(elem_inner.style.height, 10), - - // Determine the vertical shift to place the div in the center of the screen - vshift = (window.screen.height - height) * 0.5; - - // Scaling factor: if not supplied, it's taken as large as possible - scale = scale || Math.min(r_w, r_h); - - // Adapt vshift and scale for landscape on tablets - if (window.matchMedia && window.matchMedia('(orientation:landscape)').matches && - window.screen.width < window.screen.height) { - // Landscape on iOS: it returns 'landscape', but still width<height. - r_w = window.screen.height / parseInt(elem_inner.style.width, 10); - r_h = window.screen.width / parseInt(elem_inner.style.height, 10); - scale = Math.min(r_w, r_h); - vshift = (window.screen.width - height) * 0.5; - } - scale *= 0.85; - - // Do the shifting and scaling via CSS pseudo rules - this.scaleJSXGraphDiv('#' + wrap_id, '#' + jsxgraph_id, scale, vshift); - - // Trigger the fullscreen mode - elem.requestFullscreen = elem.requestFullscreen || - elem.webkitRequestFullscreen || - elem.mozRequestFullScreen || - elem.msRequestFullscreen; - if (elem.requestFullscreen) { - elem.requestFullscreen(); + if (i === len_pseudo) { + console.log('JXG.scaleJSXGraphDiv: Could not add any CSS rule.'); + console.log('One possible reason could be that the id of the JSXGraph container does not start with a letter.'); } } }); @@ -3279,7 +3283,7 @@ define('utils/env',['jxg', 'utils/type'], function (JXG, Type) { }); /* - Copyright 2008-2021 + Copyright 2008-2022 Matthias Ehmann, Michael Gerhaeuser, Carsten Miller, @@ -3383,7 +3387,7 @@ define('utils/xml',['jxg', 'utils/type'], function (JXG, Type) { return JXG.XML; }); /* - Copyright 2008-2021 + Copyright 2008-2022 Matthias Ehmann, Michael Gerhaeuser, Carsten Miller, @@ -3555,7 +3559,7 @@ define('utils/event',['jxg', 'utils/type'], function (JXG, Type) { }); /* - Copyright 2008-2021 + Copyright 2008-2022 Matthias Ehmann, Michael Gerhaeuser, Carsten Miller, @@ -3665,7 +3669,7 @@ define('math/math',['jxg', 'utils/type'], function (JXG, Type) { /** * The JavaScript implementation of the % operator returns the symmetric modulo. - * They are both identical if a >= 0 and m >= 0 but the results differ if a or m < 0. + * mod and "%" are both identical if a >= 0 and m >= 0 but the results differ if a or m < 0. * @param {Number} a * @param {Number} m * @returns {Number} Mathematical modulo <tt>a mod m</tt> @@ -4022,6 +4026,15 @@ define('math/math',['jxg', 'utils/type'], function (JXG, Type) { return Math.sqrt(sum); }, + axpy: function (a, x, y) { + var i, le = x.length, + p = []; + for (i = 0; i < le; i++) { + p[i] = a * x[i] + y[i]; + } + return p; + }, + /** * Compute the factorial of a positive integer. If a non-integer value * is given, the fraction will be ignored. @@ -4076,6 +4089,7 @@ define('math/math',['jxg', 'utils/type'], function (JXG, Type) { /** * Calculates the cosine hyperbolicus of x. + * @function * @param {Number} x The number the cosine hyperbolicus will be calculated of. * @returns {Number} Cosine hyperbolicus of the given value. */ @@ -4085,6 +4099,7 @@ define('math/math',['jxg', 'utils/type'], function (JXG, Type) { /** * Sine hyperbolicus of x. + * @function * @param {Number} x The number the sine hyperbolicus will be calculated of. * @returns {Number} Sine hyperbolicus of the given value. */ @@ -4092,8 +4107,31 @@ define('math/math',['jxg', 'utils/type'], function (JXG, Type) { return (Math.exp(x) - Math.exp(-x)) * 0.5; }, + /** + * Hyperbolic arc-cosine of a number. + * + * @param {Number} x + * @returns {Number} + */ + acosh: Math.acosh || function(x) { + return Math.log(x + Math.sqrt(x * x - 1)); + }, + + /** + * Hyperbolic arcsine of a number + * @param {Number} x + * @returns {Number} + */ + asinh: Math.asinh || function(x) { + if (x === -Infinity) { + return x; + } + return Math.log(x + Math.sqrt(x * x + 1)); + }, + /** * Computes the cotangent of x. + * @function * @param {Number} x The number the cotangent will be calculated of. * @returns {Number} Cotangent of the given value. */ @@ -4116,7 +4154,7 @@ define('math/math',['jxg', 'utils/type'], function (JXG, Type) { * For n even, for negative valuees of x NaN is returned * @param {Number} x radicand. Must be non-negative, if n even. * @param {Number} n index of the root. must be strictly positive integer. - * @return {Number} returns real root or NaN + * @returns {Number} returns real root or NaN * * @example * nthroot(16, 4): 2 @@ -4151,8 +4189,9 @@ define('math/math',['jxg', 'utils/type'], function (JXG, Type) { * Computes cube root of real number * Polyfill for Math.cbrt(). * + * @function * @param {Number} x Radicand - * @return {Number} Cube root of x. + * @returns {Number} Cube root of x. */ cbrt: Math.cbrt || function(x) { return this.nthroot(x, 3); @@ -4244,6 +4283,8 @@ define('math/math',['jxg', 'utils/type'], function (JXG, Type) { /** * The sign() function returns the sign of a number, indicating whether the number is positive, negative or zero. + * + * @function * @param {Number} x A Number * @returns {[type]} This function has 5 kinds of return values, * 1, -1, 0, -0, NaN, which represent "positive number", "negative number", "positive zero", "negative zero" @@ -4300,7 +4341,7 @@ define('math/math',['jxg', 'utils/type'], function (JXG, Type) { * @param {Number} b Second number * @returns {Number} gcd(a, b) if a and b are numbers, NaN else. */ - gcd: function (a,b) { + gcd: function (a, b) { a = Math.abs(a); b = Math.abs(b); @@ -4328,7 +4369,7 @@ define('math/math',['jxg', 'utils/type'], function (JXG, Type) { * @param {Number} b Second number * @returns {Number} lcm(a, b) if a and b are numbers, NaN else. */ - lcm: function (a,b) { + lcm: function (a, b) { var ret; if (!(Type.isNumber(a) && Type.isNumber(b))) { @@ -4343,6 +4384,177 @@ define('math/math',['jxg', 'utils/type'], function (JXG, Type) { return 0; }, + /** + * Error function, see {@link https://en.wikipedia.org/wiki/Error_function}. + * + * @see JXG.Math.PropFunc.erf + * @param {Number} x + * @returns {Number} + */ + erf: function(x) { + return this.ProbFuncs.erf(x); + }, + + /** + * Complementary error function, i.e. 1 - erf(x). + * + * @see JXG.Math.erf + * @see JXG.Math.PropFunc.erfc + * @param {Number} x + * @returns {Number} + */ + erfc: function(x) { + return this.ProbFuncs.erfc(x); + }, + + /** + * Inverse of error function + * + * @see JXG.Math.erf + * @see JXG.Math.PropFunc.erfi + * @param {Number} x + * @returns {Number} + */ + erfi: function(x) { + return this.ProbFuncs.erfi(x); + }, + + /** + * Normal distribution function + * + * @see JXG.Math.PropFunc.ndtr + * @param {Number} x + * @returns {Number} + */ + ndtr: function(x) { + return this.ProbFuncs.ndtr(x); + }, + + /** + * Inverse of normal distribution function + * + * @see JXG.Math.ndtr + * @see JXG.Math.PropFunc.ndtri + * @param {Number} x + * @returns {Number} + */ + ndtri: function(x) { + return this.ProbFuncs.ndtri(x); + }, + + /* ******************** Comparisons and logical operators ************** */ + + /** + * Logical test: a < b? + * + * @param {Number} a + * @param {Number} b + * @returns {Boolean} + */ + lt: function(a, b) { + return a < b; + }, + + /** + * Logical test: a <= b? + * + * @param {Number} a + * @param {Number} b + * @returns {Boolean} + */ + leq: function(a, b) { + return a <= b; + }, + + /** + * Logical test: a > b? + * + * @param {Number} a + * @param {Number} b + * @returns {Boolean} + */ + gt: function(a, b) { + return a > b; + }, + + /** + * Logical test: a >= b? + * + * @param {Number} a + * @param {Number} b + * @returns {Boolean} + */ + geq: function(a, b) { + return a >= b; + }, + + /** + * Logical test: a === b? + * + * @param {Number} a + * @param {Number} b + * @returns {Boolean} + */ + eq: function(a, b) { + return a === b; + }, + + /** + * Logical test: a !== b? + * + * @param {Number} a + * @param {Number} b + * @returns {Boolean} + */ + neq: function(a, b) { + return a !== b; + }, + + /** + * Logical operator: a && b? + * + * @param {Boolean} a + * @param {Boolean} b + * @returns {Boolean} + */ + and: function(a, b) { + return a && b; + }, + + /** + * Logical operator: !a? + * + * @param {Boolean} a + * @returns {Boolean} + */ + not: function(a) { + return !a; + }, + + /** + * Logical operator: a || b? + * + * @param {Boolean} a + * @param {Boolean} b + * @returns {Boolean} + */ + or: function(a, b) { + return a || b; + }, + + /** + * Logical operator: either a or b? + * + * @param {Boolean} a + * @param {Boolean} b + * @returns {Boolean} + */ + xor: function(a, b) { + return (a || b) && !(a && b); + }, + + /* *************************** Normalize *************************** */ + /** * Normalize the standard form [c, b0, b1, a, k, r, q0, q1]. * @private @@ -4410,6 +4622,35 @@ define('math/math',['jxg', 'utils/type'], function (JXG, Type) { } return v; + }, + + /** + * Theorem of Vieta: Given a set of simple zeroes x_0, ..., x_n + * of a polynomial f, compute the coefficients s_k, (k=0,...,n-1) + * of the polynomial of the form. See {@link https://de.wikipedia.org/wiki/Elementarsymmetrisches_Polynom}. + * <p> + * f(x) = (x-x_0)*...*(x-x_n) = + * x^n + sum_{k=1}^{n} (-1)^(k) s_{k-1} x^(n-k) + * </p> + * @param {Array} x Simple zeroes of the polynomial. + * @returns {Array} Coefficients of the polynomial. + * + */ + Vieta: function(x) { + var n = x.length, + s = [], + m, k, y; + + s = x.slice(); + for (m = 1; m < n; ++m) { + y = s[m]; + s[m] *= s[m - 1]; + for (k = m - 1; k >= 1; --k) { + s[k] += s[k - 1] * y; + } + s[0] += y; + } + return s; } }; @@ -4417,7 +4658,7 @@ define('math/math',['jxg', 'utils/type'], function (JXG, Type) { }); /* - Copyright 2008-2021 + Copyright 2008-2022 Matthias Ehmann, Michael Gerhaeuser, Carsten Miller, @@ -4508,7 +4749,7 @@ define('base/coords',[ /** * If true, this coordinates object will emit update events every time * the coordinates are set. - * @type {boolean} + * @type boolean * @default true */ this.emitter = !Type.exists(emitter) || emitter; @@ -4652,11 +4893,11 @@ define('base/coords',[ }, /** - * Copy array, either srcCoords or usrCoords + * Copy array, either scrCoords or usrCoords * Uses slice() in case of standard arrays and set() in case of * typed arrays. * @private - * @param {String} obj Either 'srcCoords' or 'usrCoords' + * @param {String} obj Either 'scrCoords' or 'usrCoords' * @param {Number} offset Offset, defaults to 0 if not given * @returns {Array} Returns copy of the coords array either as standard array or as * typed array. @@ -4696,7 +4937,7 @@ define('base/coords',[ }); /* - Copyright 2008-2021 + Copyright 2008-2022 Matthias Ehmann, Michael Gerhaeuser, Carsten Miller, @@ -4828,7 +5069,691 @@ define('utils/expect',[ }); /* - Copyright 2008-2021 + Copyright 2008-2022 + Matthias Ehmann, + Carsten Miller, + Andreas Walter, + Alfred Wassermann + + This file is part of JSXGraph. + + JSXGraph is free software dual licensed under the GNU LGPL or MIT License. + + You can redistribute it and/or modify it under the terms of the + + * GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version + OR + * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT + + JSXGraph is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License and + the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> + and <http://opensource.org/licenses/MIT/>. + */ + + +/*global JXG: true, define: true*/ +/*jslint nomen: true, plusplus: true*/ +/*eslint no-loss-of-precision: off */ + +/* depends: + jxg + math/math + utils/type + */ + +define('math/probfuncs',['math/math', 'utils/type'], function (Mat, Type) { + + "use strict"; + + /** + * Probability functions, e.g. error function, + * see: https://en.wikipedia.org/wiki/Error_function + * Ported from + * by https://github.com/jeremybarnes/cephes/blob/master/cprob/ndtr.c, + * + * Cephes Math Library Release 2.9: November, 2000 + * Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier + * + * @name JXG.Math.ProbFuncs + * @exports Mat.ProbFuncs as JXG.Math.ProbFuncs + * @namespace + */ + Mat.ProbFuncs = { + MAXNUM: 1.701411834604692317316873e38, // 2**127 + SQRTH: 7.07106781186547524401E-1, // sqrt(2)/2 + SQRT2: 1.41421356237309504880, // sqrt(2) + MAXLOG: 7.08396418532264106224E2, // log 2**1022 + + P: [ + 2.46196981473530512524E-10, + 5.64189564831068821977E-1, + 7.46321056442269912687E0, + 4.86371970985681366614E1, + 1.96520832956077098242E2, + 5.26445194995477358631E2, + 9.34528527171957607540E2, + 1.02755188689515710272E3, + 5.57535335369399327526E2 + ], + + Q: [ + 1.32281951154744992508E1, + 8.67072140885989742329E1, + 3.54937778887819891062E2, + 9.75708501743205489753E2, + 1.82390916687909736289E3, + 2.24633760818710981792E3, + 1.65666309194161350182E3, + 5.57535340817727675546E2 + ], + + R: [ + 5.64189583547755073984E-1, + 1.27536670759978104416E0, + 5.01905042251180477414E0, + 6.16021097993053585195E0, + 7.40974269950448939160E0, + 2.97886665372100240670E0 + ], + + S: [ + 2.26052863220117276590E0, + 9.39603524938001434673E0, + 1.20489539808096656605E1, + 1.70814450747565897222E1, + 9.60896809063285878198E0, + 3.36907645100081516050E0 + ], + + T: [ + 9.60497373987051638749E0, + 9.00260197203842689217E1, + 2.23200534594684319226E3, + 7.00332514112805075473E3, + 5.55923013010394962768E4 + ], + + U: [ + 3.35617141647503099647E1, + 5.21357949780152679795E2, + 4.59432382970980127987E3, + 2.26290000613890934246E4, + 4.92673942608635921086E4 + ], + + // UTHRESH: 37.519379347, + M: 128.0, + MINV: 0.0078125, + + /** + * + * Exponential of squared argument + * + * SYNOPSIS: + * + * double x, y, expx2(); + * int sign; + * + * y = expx2( x, sign ); + * + * + * + * DESCRIPTION: + * + * Computes y = exp(x*x) while suppressing error amplification + * that would ordinarily arise from the inexactness of the + * exponential argument x*x. + * + * If sign < 0, the result is inverted; i.e., y = exp(-x*x) . + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -26.6, 26.6 10^7 3.9e-16 8.9e-17 + * + * @private + * @param {Number} x + * @param {Number} sign (int) + * @returns {Number} + */ + expx2: function(x, sign) { + // double x; + // int sign; + var u, u1, m, f; + + x = Math.abs(x); + if (sign < 0) { + x = -x; + } + + // Represent x as an exact multiple of M plus a residual. + // M is a power of 2 chosen so that exp(m * m) does not overflow + // or underflow and so that |x - m| is small. + m = this.MINV * Math.floor(this.M * x + 0.5); + f = x - m; + + // x^2 = m^2 + 2mf + f^2 + u = m * m; + u1 = 2 * m * f + f * f; + + if (sign < 0) { + u = -u; + u1 = -u1; + } + + if ( u + u1 > this.MAXLOG) { + return Infinity; + } + + // u is exact, u1 is small. + u = Math.exp(u) * Math.exp(u1); + return u; + }, + + /** + * + * Evaluate polynomial + * + * SYNOPSIS: + * + * int N; + * double x, y, coef[N+1], polevl[]; + * + * y = polevl( x, coef, N ); + * + * DESCRIPTION: + * + * Evaluates polynomial of degree N: + * + * 2 N + * y = C + C x + C x +...+ C x + * 0 1 2 N + * + * Coefficients are stored in reverse order: + * + * coef[0] = C , ..., coef[N] = C . + * N 0 + * + * The function p1evl() assumes that coef[N] = 1.0 and is + * omitted from the array. Its calling arguments are + * otherwise the same as polevl(). + * + * + * SPEED: + * + * In the interest of speed, there are no checks for out + * of bounds arithmetic. This routine is used by most of + * the functions in the library. Depending on available + * equipment features, the user may wish to rewrite the + * program in microcode or assembly language. + * + * @private + * @param {Number} x + * @param {Number} coef + * @param {Number} N + * @returns {Number} + */ + polevl: function(x, coef, N) { + var ans, i; + + if (Type.exists(coef.reduce)) { + return coef.reduce(function(acc, c) { + return acc * x + c; + }, 0); + } + // Polyfill + for (i = 0, ans = 0; i <= N; i++) { + ans = ans * x + coef[i]; + } + return ans; + + }, + + /** + * Evaluate polynomial when coefficient of x is 1.0. + * Otherwise same as polevl. + * + * @private + * @param {Number} x + * @param {Number} coef + * @param {Number} N + * @returns {Number} + */ + p1evl: function(x, coef, N) { + var ans, i; + + if (Type.exists(coef.reduce)) { + return coef.reduce(function(acc, c) { + return acc * x + c; + }, 1); + } + // Polyfill + for (i = 0, ans = 1; i < N; i++) { + ans = ans * x + coef[i]; + } + return ans; + }, + + /** + * + * Normal distribution function + * + * SYNOPSIS: + * + * y = ndtr( x ); + * + * DESCRIPTION: + * + * Returns the area under the Gaussian probability density + * function, integrated from minus infinity to x: + * + * x + * - + * 1 | | 2 + * ndtr(x) = --------- | exp( - t /2 ) dt + * sqrt(2pi) | | + * - + * -inf. + * + * = ( 1 + erf(z) ) / 2 + * = erfc(z) / 2 + * + * where z = x/sqrt(2). Computation is via the functions + * erf and erfc with care to avoid error amplification in computing exp(-x^2). + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -13,0 30000 1.3e-15 2.2e-16 + * + * + * ERROR MESSAGES: + * + * message condition value returned + * erfc underflow x > 37.519379347 0.0 + * + * @param {Number} a + * @returns {Number} + */ + ndtr: function(a) { + // a: double, return double + var x, y, z; + + x = a * this.SQRTH; + z = Math.abs(x); + + if (z < 1.0) { + y = 0.5 + 0.5 * this.erf(x); + } else { + y = 0.5 * this.erfce(z); + /* Multiply by exp(-x^2 / 2) */ + z = this.expx2(a, -1); + y = y * Math.sqrt(z); + if (x > 0) { + y = 1.0 - y; + } + } + return y; + }, + + /** + * @private + * @param {Number} a + * @returns {Number} + */ + _underflow: function(a) { + console.log('erfc', 'UNDERFLOW'); + if (a < 0) { + return 2.0; + } + return 0.0; + }, + + /** + * + * Complementary error function + * + * SYNOPSIS: + * + * double x, y, erfc(); + * + * y = erfc( x ); + * + * + * + * DESCRIPTION: + * + * + * 1 - erf(x) = + * + * inf. + * - + * 2 | | 2 + * erfc(x) = -------- | exp( - t ) dt + * sqrt(pi) | | + * - + * x + * + * + * For small x, erfc(x) = 1 - erf(x); otherwise rational + * approximations are computed. + * + * A special function expx2.c is used to suppress error amplification + * in computing exp(-x^2). + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE 0,26.6417 30000 1.3e-15 2.2e-16 + * + * + * ERROR MESSAGES: + * + * message condition value returned + * erfc underflow x > 9.231948545 (DEC) 0.0 + * + * @param {Number} a + * @returns {Number} + */ + erfc: function(a) { + var p, q, x, y, z; + + if (a < 0.0) { + x = -a; + } else { + x = a; + } + if (x < 1.0) { + return 1.0 - this.erf(a); + } + + z = -a * a; + if (z < -this.MAXLOG) { + return this._underflow(a); + } + + z = this.expx2(a, -1); // Compute z = exp(z). + + if (x < 8.0) { + p = this.polevl(x, this.P, 8); + q = this.p1evl(x, this.Q, 8); + } else { + p = this.polevl(x, this.R, 5); + q = this.p1evl(x, this.S, 6); + } + + y = (z * p) / q; + + if (a < 0) { + y = 2.0 - y; + } + + if (y === 0.0) { + return this._underflow(a); + } + + return y; + }, + + /** + * Exponentially scaled erfc function + * exp(x^2) erfc(x) + * valid for x > 1. + * Use with ndtr and expx2. + * + * @private + * @param {Number} x + * @returns {Number} + */ + erfce: function(x) { + var p, q; + + if (x < 8.0) { + p = this.polevl(x, this.P, 8); + q = this.p1evl(x, this.Q, 8); + } else { + p = this.polevl( x, this.R, 5 ); + q = this.p1evl( x, this.S, 6 ); + } + return p / q; + }, + + /** + * Error function + * + * SYNOPSIS: + * + * double x, y, erf(); + * + * y = erf( x ); + * + * + * + * DESCRIPTION: + * + * The integral is + * + * x + * - + * 2 | | 2 + * erf(x) = -------- | exp( - t ) dt. + * sqrt(pi) | | + * - + * 0 + * + * For 0 <= |x| < 1, erf(x) = x * P4(x**2)/Q5(x**2); otherwise + * erf(x) = 1 - erfc(x). + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC 0,1 14000 4.7e-17 1.5e-17 + * IEEE 0,1 30000 3.7e-16 1.0e-16 + * + * @param {Number} x + * @returns {Number} + */ + erf: function(x) { + var y, z; + + if (Math.abs(x) > 1.0) { + return 1.0 - this.erfc(x); + } + z = x * x; + y = x * this.polevl(z, this.T, 4) / this.p1evl(z, this.U, 5); + return y; + }, + + s2pi: 2.50662827463100050242E0, // sqrt(2pi) + + // approximation for 0 <= |y - 0.5| <= 3/8 */ + P0: [ + -5.99633501014107895267E1, + 9.80010754185999661536E1, + -5.66762857469070293439E1, + 1.39312609387279679503E1, + -1.23916583867381258016E0 + ], + + Q0: [ + 1.95448858338141759834E0, + 4.67627912898881538453E0, + 8.63602421390890590575E1, + -2.25462687854119370527E2, + 2.00260212380060660359E2, + -8.20372256168333339912E1, + 1.59056225126211695515E1, + -1.18331621121330003142E0, + ], + + // Approximation for interval z = sqrt(-2 log y ) between 2 and 8 + // i.e., y between exp(-2) = .135 and exp(-32) = 1.27e-14. + P1: [ + 4.05544892305962419923E0, + 3.15251094599893866154E1, + 5.71628192246421288162E1, + 4.40805073893200834700E1, + 1.46849561928858024014E1, + 2.18663306850790267539E0, + -1.40256079171354495875E-1, + -3.50424626827848203418E-2, + -8.57456785154685413611E-4 + ], + + Q1: [ + 1.57799883256466749731E1, + 4.53907635128879210584E1, + 4.13172038254672030440E1, + 1.50425385692907503408E1, + 2.50464946208309415979E0, + -1.42182922854787788574E-1, + -3.80806407691578277194E-2, + -9.33259480895457427372E-4 + ], + + // Approximation for interval z = sqrt(-2 log y ) between 8 and 64 + // i.e., y between exp(-32) = 1.27e-14 and exp(-2048) = 3.67e-890. + P2: [ + 3.23774891776946035970E0, + 6.91522889068984211695E0, + 3.93881025292474443415E0, + 1.33303460815807542389E0, + 2.01485389549179081538E-1, + 1.23716634817820021358E-2, + 3.01581553508235416007E-4, + 2.65806974686737550832E-6, + 6.23974539184983293730E-9 + ], + + Q2: [ + 6.02427039364742014255E0, + 3.67983563856160859403E0, + 1.37702099489081330271E0, + 2.16236993594496635890E-1, + 1.34204006088543189037E-2, + 3.28014464682127739104E-4, + 2.89247864745380683936E-6, + 6.79019408009981274425E-9 + ], + + /** + * + * Inverse of Normal distribution function + * + * SYNOPSIS: + * + * double x, y, ndtri(); + * + * x = ndtri( y ); + * + * DESCRIPTION: + * + * Returns the argument, x, for which the area under the + * Gaussian probability density function (integrated from + * minus infinity to x) is equal to y. + * + * + * For small arguments 0 < y < exp(-2), the program computes + * z = sqrt( -2.0 * log(y) ); then the approximation is + * x = z - log(z)/z - (1/z) P(1/z) / Q(1/z). + * There are two rational functions P/Q, one for 0 < y < exp(-32) + * and the other for y up to exp(-2). For larger arguments, + * w = y - 0.5, and x/sqrt(2pi) = w + w**3 R(w**2)/S(w**2)). + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC 0.125, 1 5500 9.5e-17 2.1e-17 + * DEC 6e-39, 0.135 3500 5.7e-17 1.3e-17 + * IEEE 0.125, 1 20000 7.2e-16 1.3e-16 + * IEEE 3e-308, 0.135 50000 4.6e-16 9.8e-17 + * + * + * ERROR MESSAGES: + * + * message condition value returned + * ndtri domain x <= 0 -MAXNUM + * ndtri domain x >= 1 MAXNUM + * + * @param {Number} y0 + * @returns {Number} + */ + ndtri: function(y0) { + var x, y, z, y2, x0, x1, code; + + if (y0 <= 0.0) { + //console.log("ndtri", "DOMAIN "); + return -Infinity; // -this.MAXNUM; + } + if (y0 >= 1.0) { + // console.log("ndtri", "DOMAIN"); + return Infinity; // this.MAXNUM; + } + + code = 1; + y = y0; + if (y > (1.0 - 0.13533528323661269189)) { // 0.135... = exp(-2) + y = 1.0 - y; + code = 0; + } + + if (y > 0.13533528323661269189) { + y = y - 0.5; + y2 = y * y; + x = y + y * (y2 * this.polevl(y2, this.P0, 4) / this.p1evl(y2, this.Q0, 8)); + x = x * this.s2pi; + return x; + } + + x = Math.sqrt( -2.0 * Math.log(y) ); + x0 = x - Math.log(x) / x; + + z = 1.0 / x; + if (x < 8.0) { // y > exp(-32) = 1.2664165549e-14 + x1 = z * this.polevl(z, this.P1, 8 ) / this.p1evl(z, this.Q1, 8); + } else { + x1 = z * this.polevl(z, this.P2, 8) / this.p1evl(z, this.Q2, 8); + } + x = x0 - x1; + if (code !== 0) { + x = -x; + } + return x; + }, + + /** + * Inverse of error function erf. + * + * @param {Number} x + * @returns {Number} + */ + erfi: function(x) { + return this.ndtri((x + 1) * 0.5) * this.SQRTH; + } + }; + + return Mat.ProbFuncs; +}); + +/* + Copyright 2008-2022 Matthias Ehmann, Michael Gerhaeuser, Carsten Miller, @@ -5000,10 +5925,13 @@ define('math/ia',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, Type) { var doubleBits = new JXG.Math.DoubleBits(), /** - * Object for interval arithmetic + * Interval for interval arithmetics. Consists of the properties + * <ul> + * <li>lo + * <li>hi + * </ul> * @name JXG.Math.Interval - * @exports MatInterval as JXG.Math.Interval - * @namespace + * @type Object */ MatInterval = function (lo, hi) { if (lo !== undefined && hi !== undefined) { @@ -5101,9 +6029,8 @@ define('math/ia',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, Type) { }); /** - * Object for interval arithmetic - * @name JXG.Math.Interval - * @exports Mat.Interval as JXG.Math.Interval + * Object for interval arithmetics. + * @name JXG.Math.IntervalArithmetic * @namespace */ JXG.Math.IntervalArithmetic = { @@ -5123,6 +6050,14 @@ define('math/ia',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, Type) { /* * Arithmetics */ + + /** + * Addition + * + * @param {JXG.Math.Interval|Number} x + * @param {JXG.Math.Interval|Number} y + * @returns JXG.Math.Interval + */ add: function(x, y) { if (Type.isNumber(x)) { x = this.Interval(x); @@ -5133,7 +6068,14 @@ define('math/ia',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, Type) { return new MatInterval(this.addLo(x.lo, y.lo), this.addHi(x.hi, y.hi)); }, - sub: function(x, y) { + /** + * Subtraction + * + * @param {JXG.Math.Interval|Number} x + * @param {JXG.Math.Interval|Number} y + * @returns JXG.Math.Interval + */ + sub: function(x, y) { if (Type.isNumber(x)) { x = this.Interval(x); } @@ -5143,7 +6085,14 @@ define('math/ia',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, Type) { return new MatInterval(this.subLo(x.lo, y.hi), this.subHi(x.hi, y.lo)); }, - mul: function(x, y) { + /** + * Multiplication + * + * @param {JXG.Math.Interval|Number} x + * @param {JXG.Math.Interval|Number} y + * @returns JXG.Math.Interval + */ + mul: function(x, y) { var xl, xh, yl, yh, out; if (Type.isNumber(x)) { @@ -5240,7 +6189,14 @@ define('math/ia',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, Type) { return out; }, - div: function(x, y) { + /** + * Division + * + * @param {JXG.Math.Interval|Number} x + * @param {JXG.Math.Interval|Number} y + * @returns JXG.Math.Interval + */ + div: function(x, y) { if (Type.isNumber(x)) { x = this.Interval(x); } @@ -5266,11 +6222,23 @@ define('math/ia',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, Type) { return this.divNonZero(x, y); }, - positive: function(x) { + /** + * Return +x (i.e. identity) + * + * @param {JXG.Math.Interval} x + * @returns JXG.Math.Interval + */ + positive: function(x) { return new MatInterval(x.lo, x.hi); }, - negative: function(x) { + /** + * Return -x + * + * @param {JXG.Math.Interval} x + * @returns JXG.Math.Interval + */ + negative: function(x) { if (Type.isNumber(x)) { return new MatInterval(-x); } @@ -5280,33 +6248,67 @@ define('math/ia',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, Type) { /* * Utils */ + + /** + * Test if interval is empty set. + * @param {JXG.Math.Interval} i + * @returns Boolean + */ isEmpty: function(i) { return i.lo > i.hi; }, + /** + * Test if interval is (-Infinity, Infinity). + * @param {JXG.Math.Interval} i + * @returns Boolean + */ isWhole: function(i){ return i.lo === -Infinity && i.hi === Infinity; }, - zeroIn: function(i) { + /** + * Test if interval contains 0. + * @param {JXG.Math.Interval} i + * @returns Boolean + */ + zeroIn: function(i) { return this.hasValue(i, 0); }, - hasValue: function(i, value) { + /** + * Test if interval contains a specific value. + * @param {JXG.Math.Interval} i + * @param {Number} value + * @returns Boolean + */ + hasValue: function(i, value) { if (this.isEmpty(i)) { return false; } return i.lo <= value && value <= i.hi; }, - hasInterval: function(x, y) { + /** + * Test if interval x contains interval y. + * @param {JXG.Math.Interval} x + * @param {JXG.Math.Interval} y + * @returns Boolean + */ + hasInterval: function(x, y) { if (this.isEmpty(x)) { return true; } return !this.isEmpty(y) && y.lo <= x.lo && x.hi <= y.hi; }, - intervalsOverlap: function(x, y) { + /** + * Test if intervals x and y have non-zero intersection. + * @param {JXG.Math.Interval} x + * @param {JXG.Math.Interval} y + * @returns Boolean + */ + intervalsOverlap: function(x, y) { if (this.isEmpty(x) || this.isEmpty(y)) { return false; } @@ -5316,6 +6318,12 @@ define('math/ia',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, Type) { /* * Division */ + /** + * @private + * @param {JXG.Math.Interval} x + * @param {JXG.Math.Interval} y + * @returns JXG.Math.Interval + */ divNonZero: function(x, y) { var xl = x.lo, xh = x.hi, @@ -5351,7 +6359,13 @@ define('math/ia',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, Type) { return out; }, - divPositive: function(x, v) { + /** + * @private + * @param {JXG.Math.Interval} x + * @param {JXG.Math.Interval} y + * @returns JXG.Math.Interval + */ + divPositive: function(x, v) { if (x.lo === 0 && x.hi === 0) { return x; } @@ -5369,7 +6383,13 @@ define('math/ia',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, Type) { return new MatInterval(this.divLo(x.lo, v), Number.POSITIVE_INFINITY); }, - divNegative: function(x, v) { + /** + * @private + * @param {JXG.Math.Interval} x + * @param {JXG.Math.Interval} y + * @returns JXG.Math.Interval + */ + divNegative: function(x, v) { if (x.lo === 0 && x.hi === 0) { return x; } @@ -5387,7 +6407,12 @@ define('math/ia',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, Type) { return new MatInterval(Number.NEGATIVE_INFINITY, this.divHi(x.lo, v)); }, - divZero: function(x) { + /** + * @private + * @param {JXG.Math.Interval} x + * @returns JXG.Math.Interval + */ + divZero: function(x) { if (x.lo === 0 && x.hi === 0) { return x; } @@ -5397,6 +6422,12 @@ define('math/ia',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, Type) { /* * Algebra */ + /** + * x mod y: x - n * y + * @param {JXG.Math.Interval|Number} x + * @param {JXG.Math.Interval|Number} y + * @returns JXG.Math.Interval + */ fmod: function(x, y) { var yb, n; if (Type.isNumber(x)) { @@ -5419,6 +6450,11 @@ define('math/ia',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, Type) { return this.sub(x, this.mul(y, new MatInterval(n))); }, + /** + * 1 / x + * @param {JXG.Math.Interval|Number} x + * @returns JXG.Math.Interval + */ multiplicativeInverse: function(x) { if (Type.isNumber(x)) { x = this.Interval(x); @@ -5446,6 +6482,12 @@ define('math/ia',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, Type) { return new MatInterval(this.divLo(1, x.hi), this.divHi(1, x.lo)); }, + /** + * x<sup>power</sup> + * @param {JXG.Math.Interval|Number} x + * @param {JXG.Math.Interval|Number} power + * @returns JXG.Math.Interval + */ pow: function(x, power) { var yl, yh; @@ -5507,13 +6549,24 @@ define('math/ia',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, Type) { return this.EMPTY.clone(); }, - sqrt: function(x) { + /** + * sqrt(x) + * @param {JXG.Math.Interval|Number} x + * @returns JXG.Math.Interval + */ + sqrt: function(x) { if (Type.isNumber(x)) { x = this.Interval(x); } return this.nthRoot(x, 2); }, + /** + * x<sup>1/n</sup> + * @param {JXG.Math.Interval|Number} x + * @param {Number} n + * @returns JXG.Math.Interval + */ nthRoot: function(x, n) { var power,yl, yh, yp, yn; @@ -5565,6 +6618,11 @@ define('math/ia',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, Type) { /* * Misc */ + /** + * + * @param {JXG.Math.Interval|Number} x + * @returns JXG.Math.Interval + */ exp: function(x) { if (Type.isNumber(x)) { x = this.Interval(x); @@ -5575,6 +6633,11 @@ define('math/ia',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, Type) { return new MatInterval(this.expLo(x.lo), this.expHi(x.hi)); }, + /** + * Natural log + * @param {JXG.Math.Interval|Number} x + * @returns JXG.Math.Interval + */ log: function(x) { var l; if (Type.isNumber(x)) { @@ -5587,12 +6650,22 @@ define('math/ia',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, Type) { return new MatInterval(l, this.logHi(x.hi)); }, + /** + * Natural log, alias for {@link JXG.Math.IntervalArithmetic#log}. + * @param {JXG.Math.Interval|Number} x + * @returns JXG.Math.Interval + */ ln: function(x) { return this.log(x); }, // export const LOG_EXP_10 = this.log(new MatInterval(10, 10)) // export const LOG_EXP_2 = log(new MatInterval(2, 2)) + /** + * Logarithm to base 10. + * @param {JXG.Math.Interval|Number} x + * @returns JXG.Math.Interval + */ log10: function(x) { if (this.isEmpty(x)) { return this.EMPTY.clone(); @@ -5600,6 +6673,11 @@ define('math/ia',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, Type) { return this.div(this.log(x), this.log(new MatInterval(10, 10))); }, + /** + * Logarithm to base 2. + * @param {JXG.Math.Interval|Number} x + * @returns JXG.Math.Interval + */ log2: function(x) { if (this.isEmpty(x)) { return this.EMPTY.clone(); @@ -5607,6 +6685,12 @@ define('math/ia',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, Type) { return this.div(this.log(x), this.log(new MatInterval(2, 2))); }, + /** + * Hull of intervals x and y + * @param {JXG.Math.Interval} x + * @param {JXG.Math.Interval} y + * @returns JXG.Math.Interval + */ hull: function(x, y) { var badX = this.isEmpty(x), badY = this.isEmpty(y); @@ -5622,6 +6706,12 @@ define('math/ia',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, Type) { return new MatInterval(Math.min(x.lo, y.lo), Math.max(x.hi, y.hi)); }, + /** + * Intersection of intervals x and y + * @param {JXG.Math.Interval} x + * @param {JXG.Math.Interval} y + * @returns JXG.Math.Interval + */ intersection: function(x, y) { var lo, hi; if (this.isEmpty(x) || this.isEmpty(y)) { @@ -5635,6 +6725,12 @@ define('math/ia',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, Type) { return this.EMPTY.clone(); }, + /** + * Union of overlapping intervals x and y + * @param {JXG.Math.Interval} x + * @param {JXG.Math.Interval} y + * @returns JXG.Math.Interval + */ union: function(x, y) { if (!this.intervalsOverlap(x, y)) { throw new Error('Interval#unions do not overlap'); @@ -5642,6 +6738,12 @@ define('math/ia',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, Type) { return new MatInterval(Math.min(x.lo, y.lo), Math.max(x.hi, y.hi)); }, + /** + * Difference of overlapping intervals x and y + * @param {JXG.Math.Interval} x + * @param {JXG.Math.Interval} y + * @returns JXG.Math.Interval + */ difference: function(x, y) { if (this.isEmpty(x) || this.isWhole(y)) { return this.EMPTY.clone(); @@ -5673,6 +6775,10 @@ define('math/ia',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, Type) { return x.clone(); }, + /** + * @param {JXG.Math.Interval} x + * @returns JXG.Math.Interval + */ width: function(x) { if (this.isEmpty(x)) { return 0; @@ -5680,6 +6786,10 @@ define('math/ia',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, Type) { return this.subHi(x.hi, x.lo); }, + /** + * @param {JXG.Math.Interval} x + * @returns JXG.Math.Interval + */ abs: function(x) { if (Type.isNumber(x)) { x = this.Interval(x); @@ -5696,6 +6806,11 @@ define('math/ia',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, Type) { return new MatInterval(0, Math.max(-x.lo, x.hi)); }, + /** + * @param {JXG.Math.Interval} x + * @param {JXG.Math.Interval} y + * @returns JXG.Math.Interval + */ max: function(x, y) { var badX = this.isEmpty(x), badY = this.isEmpty(y); @@ -5711,6 +6826,11 @@ define('math/ia',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, Type) { return new MatInterval(Math.max(x.lo, y.lo), Math.max(x.hi, y.hi)); }, + /** + * @param {JXG.Math.Interval} x + * @param {JXG.Math.Interval} y + * @returns JXG.Math.Interval + */ min: function(x, y) { var badX = this.isEmpty(x), badY = this.isEmpty(y); @@ -5748,6 +6868,10 @@ define('math/ia',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, Type) { return interval; }, + /** + * @param {JXG.Math.Interval} x + * @returns JXG.Math.Interval + */ cos: function(x) { var cache, pi2, t, cosv, lo, hi, rlo, rhi; @@ -5792,6 +6916,10 @@ define('math/ia',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, Type) { return new MatInterval(-1, 1); }, + /** + * @param {JXG.Math.Interval} x + * @returns JXG.Math.Interval + */ sin: function(x) { if (this.isEmpty(x) || this.onlyInfinity(x)) { return this.EMPTY.clone(); @@ -5799,6 +6927,10 @@ define('math/ia',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, Type) { return this.cos(this.sub(x, this.PI_HALF)); }, + /** + * @param {JXG.Math.Interval} x + * @returns JXG.Math.Interval + */ tan: function(x) { var cache, t, pi; if (this.isEmpty(x) || this.onlyInfinity(x)) { @@ -5820,6 +6952,10 @@ define('math/ia',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, Type) { return new MatInterval(this.tanLo(t.lo), this.tanHi(t.hi)); }, + /** + * @param {JXG.Math.Interval} x + * @returns JXG.Math.Interval + */ asin: function(x) { var lo, hi; if (this.isEmpty(x) || x.hi < -1 || x.lo > 1) { @@ -5830,6 +6966,10 @@ define('math/ia',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, Type) { return new MatInterval(lo, hi); }, + /** + * @param {JXG.Math.Interval} x + * @returns JXG.Math.Interval + */ acos: function(x) { var lo, hi; if (this.isEmpty(x) || x.hi < -1 || x.lo > 1) { @@ -5840,6 +6980,10 @@ define('math/ia',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, Type) { return new MatInterval(lo, hi); }, + /** + * @param {JXG.Math.Interval} x + * @returns JXG.Math.Interval + */ atan: function(x) { if (this.isEmpty(x)) { return this.EMPTY.clone(); @@ -5847,6 +6991,10 @@ define('math/ia',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, Type) { return new MatInterval(this.atanLo(x.lo), this.atanHi(x.hi)); }, + /** + * @param {JXG.Math.Interval} x + * @returns JXG.Math.Interval + */ sinh: function(x) { if (this.isEmpty(x)) { return this.EMPTY.clone(); @@ -5854,6 +7002,10 @@ define('math/ia',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, Type) { return new MatInterval(this.sinhLo(x.lo), this.sinhHi(x.hi)); }, + /** + * @param {JXG.Math.Interval} x + * @returns JXG.Math.Interval + */ cosh: function(x) { if (this.isEmpty(x)) { return this.EMPTY.clone(); @@ -5867,6 +7019,10 @@ define('math/ia',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, Type) { return new MatInterval(1, this.coshHi(-x.lo > x.hi ? x.lo : x.hi)); }, + /** + * @param {JXG.Math.Interval} x + * @returns JXG.Math.Interval + */ tanh: function(x) { if (this.isEmpty(x)) { return this.EMPTY.clone(); @@ -5878,6 +7034,11 @@ define('math/ia',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, Type) { * Relational */ + /** + * @param {JXG.Math.Interval} x + * @param {JXG.Math.Interval} y + * @returns Boolean + */ equal: function(x, y) { if (this.isEmpty(x)) { return this.isEmpty(y); @@ -5892,6 +7053,11 @@ define('math/ia',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, Type) { // assertEps(x[1], y[1]) // }, + /** + * @param {JXG.Math.Interval} x + * @param {JXG.Math.Interval} y + * @returns Boolean + */ notEqual: function(x, y) { if (this.isEmpty(x)) { return !this.isEmpty(y); @@ -5899,6 +7065,11 @@ define('math/ia',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, Type) { return this.isEmpty(y) || x.hi < y.lo || x.lo > y.hi; }, + /** + * @param {JXG.Math.Interval} x + * @param {JXG.Math.Interval} y + * @returns Boolean + */ lt: function(x, y) { if (Type.isNumber(x)) { x = this.Interval(x); @@ -5912,6 +7083,11 @@ define('math/ia',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, Type) { return x.hi < y.lo; }, + /** + * @param {JXG.Math.Interval} x + * @param {JXG.Math.Interval} y + * @returns Boolean + */ gt: function(x, y) { if (Type.isNumber(x)) { x = this.Interval(x); @@ -5925,6 +7101,11 @@ define('math/ia',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, Type) { return x.lo > y.hi; }, + /** + * @param {JXG.Math.Interval} x + * @param {JXG.Math.Interval} y + * @returns Boolean + */ leq: function(x, y) { if (Type.isNumber(x)) { x = this.Interval(x); @@ -5938,6 +7119,11 @@ define('math/ia',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, Type) { return x.hi <= y.lo; }, + /** + * @param {JXG.Math.Interval} x + * @param {JXG.Math.Interval} y + * @returns Boolean + */ geq: function(x, y) { if (Type.isNumber(x)) { x = this.Interval(x); @@ -6068,11 +7254,19 @@ define('math/ia',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, Type) { return y; }, + /** + * @ignore + * @private + */ disable: function() { this.next = this.prev = this.identity; }, - enable: function() { + /** + * @ignore + * @private + */ + enable: function() { this.prev = function(v) { return this._prev(v); }; @@ -6140,7 +7334,7 @@ define('math/ia',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, Type) { /* - Copyright 2008-2021 + Copyright 2008-2022 Matthias Ehmann, Michael Gerhaeuser, Carsten Miller, @@ -6562,7 +7756,7 @@ define('math/extrapolate',['math/math'], function (Mat) { }); /* - Copyright 2008-2021 + Copyright 2008-2022 Matthias Ehmann, Michael Gerhaeuser, Carsten Miller, @@ -6573,20 +7767,20 @@ define('math/extrapolate',['math/math'], function (Mat) { This file is part of JSXGraph. JSXGraph is free software dual licensed under the GNU LGPL or MIT License. - + You can redistribute it and/or modify it under the terms of the - + * GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version OR * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT - + JSXGraph is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License and the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> and <http://opensource.org/licenses/MIT/>. @@ -6605,58 +7799,64 @@ define('math/qdt',['math/math', 'utils/type'], function (Mat, Type) { "use strict"; - var + /** + * Instantiate a new quad tree. + * + * @name JXG.Math.Quadtree + * @exports Mat.Quadtree as JXG.Math.Quadtree + * @param {Array} bbox Bounding box of the new quad (sub)tree. + * @constructor + */ + Mat.Quadtree = function (bbox) { /** - * Instantiate a new quad tree. - * @param {Array} bbox Bounding box of the new quad (sub)tree. - * @constructor + * The maximum number of points stored in a quad tree node + * before it is subdivided. + * @type Number + * @default 10 */ - Quadtree = function (bbox) { - /** - * The maximum number of points stored in a quad tree node - * before it is subdivided. - * @type {Number} - * @default 10 - */ - this.capacity = 10; + this.capacity = 10; - /** - * Point storage. - * @type {Array} - */ - this.points = []; - - this.xlb = bbox[0]; - this.xub = bbox[2]; - this.ylb = bbox[3]; - this.yub = bbox[1]; + /** + * Point storage. + * @name JXG.Math.Quadtree#points + * @type Array + */ + this.points = []; + this.xlb = bbox[0]; + this.xub = bbox[2]; + this.ylb = bbox[3]; + this.yub = bbox[1]; - /** - * In a subdivided quad tree this represents the top left subtree. - * @type {JXG.Quadtree} - */ - this.northWest = null; + /** + * In a subdivided quad tree this represents the top left subtree. + * @name JXG.Math.Quadtree#northWest + * @type JXG.Math.Quadtree + */ + this.northWest = null; - /** - * In a subdivided quad tree this represents the top right subtree. - * @type {JXG.Quadtree} - */ - this.northEast = null; + /** + * In a subdivided quad tree this represents the top right subtree. + * @name JXG.Math.Quadtree#northEast + * @type JXG.Math.Quadtree + */ + this.northEast = null; - /** - * In a subdivided quad tree this represents the bottom right subtree. - * @type {JXG.Quadtree} - */ - this.southEast = null; + /** + * In a subdivided quad tree this represents the bottom right subtree. + * @name JXG.Math.Quadtree#southEast + * @type JXG.Math.Quadtree + */ + this.southEast = null; - /** - * In a subdivided quad tree this represents the bottom left subtree. - * @type {JXG.Quadtree} - */ - this.southWest = null; - }; + /** + * In a subdivided quad tree this represents the bottom left subtree. + * @name JXG.Math.Quadtree#southWest + * @type JXG.Math.Quadtree + */ + this.southWest = null; + }; - Type.extend(Quadtree.prototype, /** @lends JXG.Quadtree.prototype */ { + Type.extend(Mat.Quadtree.prototype, /** @lends JXG.Math.Quadtree.prototype */ { /** * Checks if the given coordinates are inside the quad tree. * @param {Number} x @@ -6712,10 +7912,10 @@ define('math/qdt',['math/math', 'utils/type'], function (Mat, Type) { mx = this.xlb + (this.xub - this.xlb) / 2, my = this.ylb + (this.yub - this.ylb) / 2; - this.northWest = new Quadtree([this.xlb, this.yub, mx, my]); - this.northEast = new Quadtree([mx, this.yub, this.xub, my]); - this.southEast = new Quadtree([this.xlb, my, mx, this.ylb]); - this.southWest = new Quadtree([mx, my, this.xub, this.ylb]); + this.northWest = new Mat.Quadtree([this.xlb, this.yub, mx, my]); + this.northEast = new Mat.Quadtree([mx, this.yub, this.xub, my]); + this.southEast = new Mat.Quadtree([this.xlb, my, mx, this.ylb]); + this.southWest = new Mat.Quadtree([mx, my, this.xub, this.ylb]); for (i = 0; i < l; i += 1) { this.northWest.insert(this.points[i]); @@ -6727,6 +7927,7 @@ define('math/qdt',['math/math', 'utils/type'], function (Mat, Type) { /** * Internal _query method that lacks adjustment of the parameter. + * @name JXG.Math.Quadtree#_query * @param {Number} x * @param {Number} y * @returns {Boolean|JXG.Quadtree} The quad tree if the point is found, false @@ -6768,6 +7969,7 @@ define('math/qdt',['math/math', 'utils/type'], function (Mat, Type) { /** * Retrieve the smallest quad tree that contains the given point. + * @name JXG.Math.Quadtree#_query * @param {JXG.Coords|Number} xp * @param {Number} y * @returns {Boolean|JXG.Quadtree} The quad tree if the point is found, false @@ -6790,13 +7992,11 @@ define('math/qdt',['math/math', 'utils/type'], function (Mat, Type) { } }); - Mat.Quadtree = Quadtree; - - return Quadtree; + return Mat.Quadtree; }); /* - Copyright 2008-2021 + Copyright 2008-2022 Matthias Ehmann, Michael Gerhaeuser, Carsten Miller, @@ -6828,6 +8028,7 @@ define('math/qdt',['math/math', 'utils/type'], function (Mat, Type) { /*global JXG: true, define: true*/ /*jslint nomen: true, plusplus: true*/ +/*eslint no-loss-of-precision: off */ /* depends: utils/type @@ -6839,7 +8040,7 @@ define('math/qdt',['math/math', 'utils/type'], function (Mat, Type) { * algorithms for solving linear equations etc. */ -define('math/numerics',['jxg', 'utils/type', 'math/math'], function (JXG, Type, Mat) { +define('math/numerics',['jxg', 'utils/type', 'utils/env', 'math/math'], function (JXG, Type, Env, Mat) { "use strict"; @@ -8564,6 +9765,8 @@ define('math/numerics',['jxg', 'utils/type', 'math/math'], function (JXG, Type, * Returns the Lagrange polynomials, see * Jean-Paul Berrut, Lloyd N. Trefethen: Barycentric Lagrange Interpolation, * SIAM Review, Vol 46, No 3, (2004) 501-517. + * <p> + * It possesses the method getTerm() which returns the string containing the function term of the polynomial. * @param {Array} p Array of JXG.Points * @returns {function} A function of one parameter which returns the value of the polynomial, whose graph runs through the given points. * @memberof JXG.Math.Numerics @@ -8594,9 +9797,38 @@ define('math/numerics',['jxg', 'utils/type', 'math/math'], function (JXG, Type, * * </script><pre> * + * @example + * var points = []; + * points[0] = board.create('point', [-1,2], {size:4}); + * points[1] = board.create('point', [0, 0], {size:4}); + * points[2] = board.create('point', [2, 1], {size:4}); + * + * var f = JXG.Math.Numerics.lagrangePolynomial(points); + * var graph = board.create('functiongraph', [f,-10, 10], {strokeWidth:3}); + * var txt = board.create('text', [-3, -4, () => f.getTerm(2, 't', ' * ')], {fontSize: 16}); + * + * </pre><div id="JXG73fdaf12-e257-4374-b488-ae063e4eecbb" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG73fdaf12-e257-4374-b488-ae063e4eecbb', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * var points = []; + * points[0] = board.create('point', [-1,2], {size:4}); + * points[1] = board.create('point', [0, 0], {size:4}); + * points[2] = board.create('point', [2, 1], {size:4}); + * + * var f = JXG.Math.Numerics.lagrangePolynomial(points); + * var graph = board.create('functiongraph', [f,-10, 10], {strokeWidth:3}); + * var txt = board.create('text', [-3, -4, () => f.getTerm(2, 't', ' * ')], {fontSize: 16}); + * + * })(); + * + * </script><pre> + * */ lagrangePolynomial: function (p) { var w = [], + that = this, /** @ignore */ fct = function (x, suspendedUpdate) { var i, // j, @@ -8640,12 +9872,159 @@ define('math/numerics',['jxg', 'utils/type', 'math/math'], function (JXG, Type, return num / denom; }; - fct.getTerm = function () { - return ''; + /** + * Get the term of the Lagrange polynomial as string. + * Calls {@link JXG.Math.Numerics#lagrangePolynomialTerm}. + * + * @name JXG.Math.Numerics#lagrangePolynomial.getTerm + * @param {Number} digits Number of digits of the coefficients + * @param {String} param Variable name + * @param {String} dot Dot symbol + * @returns {String} containing the term of Lagrange polynomial as string. + * @see JXG.Math.Numerics#lagrangePolynomialTerm + * @example + * var points = []; + * points[0] = board.create('point', [-1,2], {size:4}); + * points[1] = board.create('point', [0, 0], {size:4}); + * points[2] = board.create('point', [2, 1], {size:4}); + * + * var f = JXG.Math.Numerics.lagrangePolynomial(points); + * var graph = board.create('functiongraph', [f,-10, 10], {strokeWidth:3}); + * var txt = board.create('text', [-3, -4, () => f.getTerm(2, 't', ' * ')], {fontSize: 16}); + * + * </pre><div id="JXG73fdaf12-e257-4374-b488-ae063e4eeccf" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG73fdaf12-e257-4374-b488-ae063e4eeccf', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * var points = []; + * points[0] = board.create('point', [-1,2], {size:4}); + * points[1] = board.create('point', [0, 0], {size:4}); + * points[2] = board.create('point', [2, 1], {size:4}); + * + * var f = JXG.Math.Numerics.lagrangePolynomial(points); + * var graph = board.create('functiongraph', [f,-10, 10], {strokeWidth:3}); + * var txt = board.create('text', [-3, -4, () => f.getTerm(2, 't', ' * ')], {fontSize: 16}); + * + * })(); + * + * </script><pre> + * + */ + fct.getTerm = function(digits, param, dot) { + return that.lagrangePolynomialTerm(p, digits, param, dot)(); }; return fct; }, + // fct.getTerm = that.lagrangePolynomialTerm(p, 2, 'x'); + + /** + * Determine the Lagrange polynomial through an array of points and + * return the term of the polynomial as string. + * + * @param {Array} points Array of JXG.Points + * @param {Number} digits Number of decimal digits of the coefficients + * @param {String} param Name of the parameter. Default: 'x'. + * @param {String} dot Multiplication symbol. Default: ' * '. + * @returns {String} containing the Lagrange polynomial through + * the supplied points. + * @memberof JXG.Math.Numerics + * + * @example + * var points = []; + * points[0] = board.create('point', [-1,2], {size:4}); + * points[1] = board.create('point', [0, 0], {size:4}); + * points[2] = board.create('point', [2, 1], {size:4}); + * + * var f = JXG.Math.Numerics.lagrangePolynomial(points); + * var graph = board.create('functiongraph', [f,-10, 10], {strokeWidth:3}); + * + * var f_txt = JXG.Math.Numerics.lagrangePolynomialTerm(points, 2, 't', ' * '); + * var txt = board.create('text', [-3, -4, f_txt], {fontSize: 16}); + * + * </pre><div id="JXGd45e9e96-7526-486d-aa43-e1178d5f2baa" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXGd45e9e96-7526-486d-aa43-e1178d5f2baa', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * var points = []; + * points[0] = board.create('point', [-1,2], {size:4}); + * points[1] = board.create('point', [0, 0], {size:4}); + * points[2] = board.create('point', [2, 1], {size:4}); + * + * var f = JXG.Math.Numerics.lagrangePolynomial(points); + * var graph = board.create('functiongraph', [f,-10, 10], {strokeWidth:3}); + * + * var f_txt = JXG.Math.Numerics.lagrangePolynomialTerm(points, 2, 't', ' * '); + * var txt = board.create('text', [-3, -4, f_txt], {fontSize: 16}); + * + * })(); + * + * </script><pre> + * + */ + lagrangePolynomialTerm: function(points, digits, param, dot) { + return function() { + var len = points.length, + zeroes = [], + coeffs = [], + coeffs_sum = [], + isLeading = true, + n, t, + i, j, c, p; + + param = param || 'x'; + if (dot === undefined) { + dot = ' * '; + } + + n = len - 1; // (Max) degree of the polynomial + for (j = 0; j < len; j++) { + coeffs_sum[j] = 0; + } + + for (i = 0; i < len; i++) { + c = points[i].Y(); + p = points[i].X(); + zeroes = []; + for (j = 0; j < len; j++) { + if (j !== i) { + c /= p - points[j].X(); + zeroes.push(points[j].X()); + } + } + coeffs = [1].concat(Mat.Vieta(zeroes)); + for (j = 0; j < coeffs.length; j++) { + coeffs_sum[j] += (j%2===1?(-1):1) * coeffs[j] * c; + } + } + + t = ''; + for (j = 0; j < coeffs_sum.length; j++) { + c = coeffs_sum[j]; + if (Math.abs(c) < Mat.eps) { + continue; + } + if (JXG.exists(digits)) { + c = Env._round10(c, -digits); + } + if (isLeading) { + t += (c > 0) ? (c) : ('-' + (-c)); + isLeading = false; + } else { + t += (c > 0) ? (' + ' + c) : (' - ' + (-c)); + } + + if (n - j > 1) { + t += dot + param + '^' + (n - j); + } else if (n - j === 1) { + t += dot + param; + } + } + return t; // board.jc.manipulate('f = map(x) -> ' + t + ';'); + }; + }, /** * Determine the coefficients of a cardinal spline polynom, See @@ -10372,7 +11751,1298 @@ define('math/numerics',['jxg', 'utils/type', 'math/math'], function (JXG, Type, }); /* - Copyright 2008-2021 + Copyright 2008-2022 + Matthias Ehmann, + Carsten Miller, + Reinhard Oldenburg, + Alfred Wassermann + + This file is part of JSXGraph. + + JSXGraph is free software dual licensed under the GNU LGPL or MIT License. + + You can redistribute it and/or modify it under the terms of the + + * GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version + OR + * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT + + JSXGraph is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License and + the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> + and <http://opensource.org/licenses/MIT/>. + + This is a port of jcobyla + + - to JavaScript by Reihard Oldenburg and + - to JSXGraph By Alfred Wassermann +*/ +/* + * jcobyla + * + * The MIT License + * + * Copyright (c) 2012 Anders Gustafsson, Cureos AB. + * + * 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. + * + * Remarks: + * + * The original Fortran 77 version of this code was by Michael Powell (M.J.D.Powell @ damtp.cam.ac.uk) + * The Fortran 90 version was by Alan Miller (Alan.Miller @ vic.cmis.csiro.au). Latest revision - 30 October 1998 + */ + +/** + * Constrained Optimization BY Linear Approximation in Java. + * + * COBYLA2 is an implementation of Powell's nonlinear derivative free constrained optimization that uses + * a linear approximation approach. The algorithm is a sequential trust region algorithm that employs linear + * approximations to the objective and constraint functions, where the approximations are formed by linear + * interpolation at n + 1 points in the space of the variables and tries to maintain a regular shaped simplex + * over iterations. + * + * It solves nonsmooth NLP with a moderate number of variables (about 100). Inequality constraints only. + * + * The initial point X is taken as one vertex of the initial simplex with zero being another, so, X should + * not be entered as the zero vector. + * + * @author Anders Gustafsson, Cureos AB. Translation to Javascript by Reinhard Oldenburg, Goethe-University + */ + +/*global JXG: true, define: true*/ +/*jslint nomen: true, plusplus: true, continue: true*/ + +/* depends: + jxg + math/math + utils/type + */ + +define('math/nlp',['jxg'], function (JXG) { + + "use strict"; + + /** + * The JXG.Math.Nlp namespace holds numerical algorithms for non-linear optimization. + * @name JXG.Math.Nlp + * @namespace + * + */ + JXG.Math.Nlp = { + + arr: function(n) { + var a = new Array(n), + i; + for (i = 0; i <n ; i++) { + a[i] = 0.0; + } + return a; + }, + + arr2: function(n, m) { + var i = 0, + a = new Array(n); + + while (i < n) { + a[i] = this.arr(m); + i++; + } + return a; + }, + + arraycopy: function(x, a, iox, b, n) { + var i = 0; + while (i < n) { + iox[i + b] = x[i + a]; + i++; + } + }, + + // status Variables + Normal: 0, + MaxIterationsReached: 1, + DivergingRoundingErrors: 2, + + /** + * Minimizes the objective function F with respect to a set of inequality constraints CON, + * and returns the optimal variable array. F and CON may be non-linear, and should preferably be smooth. + * Calls {@link JXG.Math.Nlp#cobylb}. + * + * @param calcfc Interface implementation for calculating objective function and constraints. + * @param n Number of variables. + * @param m Number of constraints. + * @param x On input initial values of the variables (zero-based array). On output + * optimal values of the variables obtained in the COBYLA minimization. + * @param rhobeg Initial size of the simplex. + * @param rhoend Final value of the simplex. + * @param iprint Print level, 0 <= iprint <= 3, where 0 provides no output and + * 3 provides full output to the console. + * @param maxfun Maximum number of function evaluations before terminating. + * @returns {Number} Exit status of the COBYLA2 optimization. + */ + FindMinimum: function(calcfc, n, m, x, rhobeg, rhoend, iprint, maxfun) { + // CobylaExitStatus FindMinimum(final Calcfc calcfc, int n, int m, double[] x, double rhobeg, double rhoend, int iprint, int maxfun) + // This subroutine minimizes an objective function F(X) subject to M + // inequality constraints on X, where X is a vector of variables that has + // N components. The algorithm employs linear approximations to the + // objective and constraint functions, the approximations being formed by + // linear interpolation at N+1 points in the space of the variables. + // We regard these interpolation points as vertices of a simplex. The + // parameter RHO controls the size of the simplex and it is reduced + // automatically from RHOBEG to RHOEND. For each RHO the subroutine tries + // to achieve a good vector of variables for the current size, and then + // RHO is reduced until the value RHOEND is reached. Therefore RHOBEG and + // RHOEND should be set to reasonable initial changes to and the required + // accuracy in the variables respectively, but this accuracy should be + // viewed as a subject for experimentation because it is not guaranteed. + // The subroutine has an advantage over many of its competitors, however, + // which is that it treats each constraint individually when calculating + // a change to the variables, instead of lumping the constraints together + // into a single penalty function. The name of the subroutine is derived + // from the phrase Constrained Optimization BY Linear Approximations. + + // The user must set the values of N, M, RHOBEG and RHOEND, and must + // provide an initial vector of variables in X. Further, the value of + // IPRINT should be set to 0, 1, 2 or 3, which controls the amount of + // printing during the calculation. Specifically, there is no output if + // IPRINT=0 and there is output only at the end of the calculation if + // IPRINT=1. Otherwise each new value of RHO and SIGMA is printed. + // Further, the vector of variables and some function information are + // given either when RHO is reduced or when each new value of F(X) is + // computed in the cases IPRINT=2 or IPRINT=3 respectively. Here SIGMA + // is a penalty parameter, it being assumed that a change to X is an + // improvement if it reduces the merit function + // F(X)+SIGMA*MAX(0.0, - C1(X), - C2(X),..., - CM(X)), + // where C1,C2,...,CM denote the constraint functions that should become + // nonnegative eventually, at least to the precision of RHOEND. In the + // printed output the displayed term that is multiplied by SIGMA is + // called MAXCV, which stands for 'MAXimum Constraint Violation'. The + // argument ITERS is an integer variable that must be set by the user to a + // limit on the number of calls of CALCFC, the purpose of this routine being + // given below. The value of ITERS will be altered to the number of calls + // of CALCFC that are made. + // In order to define the objective and constraint functions, we require + // a subroutine that has the name and arguments + // SUBROUTINE CALCFC (N,M,X,F,CON) + // DIMENSION X(:),CON(:) . + // The values of N and M are fixed and have been defined already, while + // X is now the current vector of variables. The subroutine should return + // the objective and constraint functions at X in F and CON(1),CON(2), + // ...,CON(M). Note that we are trying to adjust X so that F(X) is as + // small as possible subject to the constraint functions being nonnegative. + + // Local variables + var mpp = m + 2, + status, + // Internal base-1 X array + iox = this.arr(n + 1), + that = this, + fcalcfc; + + iox[0] = 0.0; + this.arraycopy(x, 0, iox, 1, n); + + // Internal representation of the objective and constraints calculation method, + // accounting for that X and CON arrays in the cobylb method are base-1 arrays. + fcalcfc = function(n, m, thisx, con) { // int n, int m, double[] x, double[] con + var ix = that.arr(n), + ocon, f; + + that.arraycopy(thisx, 1, ix, 0, n); + ocon = that.arr(m); + f = calcfc(n, m, ix, ocon); + that.arraycopy(ocon, 0, con, 1, m); + return f; + }; + + status = this.cobylb(fcalcfc, n, m, mpp, iox, rhobeg, rhoend, iprint, maxfun); + this.arraycopy(iox, 1, x, 0, n); + + return status; + }, + + // private static CobylaExitStatus cobylb(Calcfc calcfc, int n, int m, int mpp, double[] x, + // double rhobeg, double rhoend, int iprint, int maxfun) + /** + * JavaScript implementation of the non-linear optimization method COBYLA. + * @param {Function} calcfc + * @param {Number} n + * @param {Number} m + * @param {Number} mpp + * @param {Number} x + * @param {Number} rhobeg + * @param {Number} rhoend + * @param {Number} iprint + * @param {Number} maxfun + * @returns {Number} Exit status of the COBYLA2 optimization + */ + cobylb: function (calcfc, n, m, mpp, x, rhobeg, rhoend, iprint, maxfun) { + // calcf ist funktion die aufgerufen wird wie calcfc(n, m, ix, ocon) + // N.B. Arguments CON, SIM, SIMI, DATMAT, A, VSIG, VETA, SIGBAR, DX, W & IACT + // have been removed. + + // Set the initial values of some parameters. The last column of SIM holds + // the optimal vertex of the current simplex, and the preceding N columns + // hold the displacements from the optimal vertex to the other vertices. + // Further, SIMI holds the inverse of the matrix that is contained in the + // first N columns of SIM. + + // Local variables + var status = -1, + + alpha = 0.25, + beta = 2.1, + gamma = 0.5, + delta = 1.1, + + f = 0.0, + resmax = 0.0, + total, + + np = n + 1, + mp = m + 1, + rho = rhobeg, + parmu = 0.0, + + iflag = false, + ifull = false, + parsig = 0.0, + prerec = 0.0, + prerem = 0.0, + + con = this.arr(1 + mpp), + sim = this.arr2(1 + n, 1 + np), + simi = this.arr2(1 + n, 1 + n), + datmat = this.arr2(1 + mpp, 1 + np), + a = this.arr2(1 + n, 1 + mp), + vsig = this.arr(1 + n), + veta = this.arr(1 + n), + sigbar = this.arr(1 + n), + dx = this.arr(1 + n), + w = this.arr(1 + n), + i, j, k, l, + temp, tempa, nfvals, + jdrop, ibrnch, + skipVertexIdent, + phimin, nbest, + error, + pareta, wsig, weta, + cvmaxp, cvmaxm, dxsign, + resnew, barmu, phi, + vmold, vmnew, trured, ratio, edgmax, cmin, cmax, denom; + + if (iprint >= 2) { + console.log("The initial value of RHO is " + rho + " and PARMU is set to zero."); + } + + nfvals = 0; + temp = 1.0 / rho; + + for (i = 1; i <= n; ++i) { + sim[i][np] = x[i]; + sim[i][i] = rho; + simi[i][i] = temp; + } + + jdrop = np; + ibrnch = false; + + // Make the next call of the user-supplied subroutine CALCFC. These + // instructions are also used for calling CALCFC during the iterations of + // the algorithm. + //alert("Iteration "+nfvals+" x="+x); + L_40: + do { + if (nfvals >= maxfun && nfvals > 0) { + status = this.MaxIterationsReached; + break L_40; + } + + ++nfvals; + f = calcfc(n, m, x, con); + resmax = 0.0; + for (k = 1; k <= m; ++k) { + resmax = Math.max(resmax, -con[k]); + } + //alert( " f="+f+" resmax="+resmax); + + if (nfvals === iprint - 1 || iprint === 3) { + this.PrintIterationResult(nfvals, f, resmax, x, n, iprint); + } + + con[mp] = f; + con[mpp] = resmax; + + // Set the recently calculated function values in a column of DATMAT. This + // array has a column for each vertex of the current simplex, the entries of + // each column being the values of the constraint functions (if any) + // followed by the objective function and the greatest constraint violation + // at the vertex. + skipVertexIdent = true; + if (!ibrnch) { + skipVertexIdent = false; + + for (i = 1; i <= mpp; ++i) { + datmat[i][jdrop] = con[i]; + } + + if (nfvals <= np) { + // Exchange the new vertex of the initial simplex with the optimal vertex if + // necessary. Then, if the initial simplex is not complete, pick its next + // vertex and calculate the function values there. + + if (jdrop <= n) { + if (datmat[mp][np] <= f) { + x[jdrop] = sim[jdrop][np]; + } else { + sim[jdrop][np] = x[jdrop]; + for (k = 1; k <= mpp; ++k) { + datmat[k][jdrop] = datmat[k][np]; + datmat[k][np] = con[k]; + } + for (k = 1; k <= jdrop; ++k) { + sim[jdrop][k] = -rho; + temp = 0.0; + for (i = k; i <= jdrop; ++i) { + temp -= simi[i][k]; + } + simi[jdrop][k] = temp; + } + } + } + if (nfvals <= n) { + jdrop = nfvals; + x[jdrop] += rho; + continue L_40; + } + } + ibrnch = true; + } + + L_140: + do { + L_550: + do { + if (!skipVertexIdent) { + // Identify the optimal vertex of the current simplex. + phimin = datmat[mp][np] + parmu * datmat[mpp][np]; + nbest = np; + + for (j = 1; j <= n; ++j) { + temp = datmat[mp][j] + parmu * datmat[mpp][j]; + if (temp < phimin) { + nbest = j; + phimin = temp; + } else if (temp === phimin && parmu === 0.0 && datmat[mpp][j] < datmat[mpp][nbest]) { + nbest = j; + } + } + + // Switch the best vertex into pole position if it is not there already, + // and also update SIM, SIMI and DATMAT. + if (nbest <= n) { + for (i = 1; i <= mpp; ++i) { + temp = datmat[i][np]; + datmat[i][np] = datmat[i][nbest]; + datmat[i][nbest] = temp; + } + for (i = 1; i <= n; ++i) { + temp = sim[i][nbest]; + sim[i][nbest] = 0.0; + sim[i][np] += temp; + + tempa = 0.0; + for (k = 1; k <= n; ++k) + { + sim[i][k] -= temp; + tempa -= simi[k][i]; + } + simi[nbest][i] = tempa; + } + } + + // Make an error return if SIGI is a poor approximation to the inverse of + // the leading N by N submatrix of SIG. + error = 0.0; + for (i = 1; i <= n; ++i) { + for (j = 1; j <= n; ++j) { + temp = this.DOT_PRODUCT( + this.PART(this.ROW(simi, i), 1, n), + this.PART(this.COL(sim, j), 1, n) + ) - (i === j ? 1.0 : 0.0); + error = Math.max(error, Math.abs(temp)); + } + } + if (error > 0.1) { + status = this.DivergingRoundingErrors; + break L_40; + } + + // Calculate the coefficients of the linear approximations to the objective + // and constraint functions, placing minus the objective function gradient + // after the constraint gradients in the array A. The vector W is used for + // working space. + for (k = 1; k <= mp; ++k) { + con[k] = -datmat[k][np]; + for (j = 1; j <= n; ++j) { + w[j] = datmat[k][j] + con[k]; + } + + for (i = 1; i <= n; ++i) { + a[i][k] = (k === mp ? -1.0 : 1.0) * this.DOT_PRODUCT( + this.PART(w, 1, n), this.PART(this.COL(simi, i), 1, n)); + } + } + + // Calculate the values of sigma and eta, and set IFLAG = 0 if the current + // simplex is not acceptable. + iflag = true; + parsig = alpha * rho; + pareta = beta * rho; + + for (j = 1; j <= n; ++j) { + wsig = 0.0; + for (k = 1; k <= n; ++k) { + wsig += simi[j][k] * simi[j][k]; + } + weta = 0.0; + for (k = 1; k <= n; ++k) { + weta += sim[k][j] * sim[k][j]; + } + vsig[j] = 1.0 / Math.sqrt(wsig); + veta[j] = Math.sqrt(weta); + if (vsig[j] < parsig || veta[j] > pareta) { iflag = false; } + } + + // If a new vertex is needed to improve acceptability, then decide which + // vertex to drop from the simplex. + if (!ibrnch && !iflag) { + jdrop = 0; + temp = pareta; + for (j = 1; j <= n; ++j) { + if (veta[j] > temp) { + jdrop = j; + temp = veta[j]; + } + } + if (jdrop === 0) { + for (j = 1; j <= n; ++j) { + if (vsig[j] < temp) { + jdrop = j; + temp = vsig[j]; + } + } + } + + // Calculate the step to the new vertex and its sign. + temp = gamma * rho * vsig[jdrop]; + for (k = 1; k <= n; ++k) { + dx[k] = temp * simi[jdrop][k]; + } + cvmaxp = 0.0; + cvmaxm = 0.0; + total = 0.0; + for (k = 1; k <= mp; ++k) { + total = this.DOT_PRODUCT( + this.PART(this.COL(a, k), 1, n), + this.PART(dx, 1, n) + ); + if (k < mp) { + temp = datmat[k][np]; + cvmaxp = Math.max(cvmaxp, -total - temp); + cvmaxm = Math.max(cvmaxm, total - temp); + } + } + dxsign = parmu * (cvmaxp - cvmaxm) > 2.0 * total ? -1.0 : 1.0; + + // Update the elements of SIM and SIMI, and set the next X. + temp = 0.0; + for (i = 1; i <= n; ++i) { + dx[i] = dxsign * dx[i]; + sim[i][jdrop] = dx[i]; + temp += simi[jdrop][i] * dx[i]; + } + for (k = 1; k <= n; ++k) { + simi[jdrop][k] /= temp; + } + + for (j = 1; j <= n; ++j) { + if (j !== jdrop) { + temp = this.DOT_PRODUCT( + this.PART(this.ROW(simi, j), 1, n), + this.PART(dx, 1, n) + ); + for (k = 1; k <= n; ++k) { + simi[j][k] -= temp * simi[jdrop][k]; + } + } + x[j] = sim[j][np] + dx[j]; + } + continue L_40; + } + + // Calculate DX = x(*)-x(0). + // Branch if the length of DX is less than 0.5*RHO. + ifull = this.trstlp(n, m, a, con, rho, dx); + if (!ifull) { + temp = 0.0; + for (k = 1; k <= n; ++k) { + temp += dx[k] * dx[k]; + } + if (temp < 0.25 * rho * rho) { + ibrnch = true; + break L_550; + } + } + + // Predict the change to F and the new maximum constraint violation if the + // variables are altered from x(0) to x(0) + DX. + total = 0.0; + resnew = 0.0; + con[mp] = 0.0; + for (k = 1; k <= mp; ++k) { + total = con[k] - this.DOT_PRODUCT(this.PART(this.COL(a, k), 1, n), this.PART(dx, 1, n)); + if (k < mp) { resnew = Math.max(resnew, total); } + } + + // Increase PARMU if necessary and branch back if this change alters the + // optimal vertex. Otherwise PREREM and PREREC will be set to the predicted + // reductions in the merit function and the maximum constraint violation + // respectively. + prerec = datmat[mpp][np] - resnew; + barmu = prerec > 0.0 ? total / prerec : 0.0; + if (parmu < 1.5 * barmu) { + parmu = 2.0 * barmu; + if (iprint >= 2) { console.log("Increase in PARMU to " + parmu); } + phi = datmat[mp][np] + parmu * datmat[mpp][np]; + for (j = 1; j <= n; ++j) { + temp = datmat[mp][j] + parmu * datmat[mpp][j]; + if (temp < phi || (temp === phi && parmu === 0.0 && datmat[mpp][j] < datmat[mpp][np])) { + continue L_140; + } + } + } + prerem = parmu * prerec - total; + + // Calculate the constraint and objective functions at x(*). + // Then find the actual reduction in the merit function. + for (k = 1; k <= n; ++k) { + x[k] = sim[k][np] + dx[k]; + } + ibrnch = true; + continue L_40; + } + + skipVertexIdent = false; + vmold = datmat[mp][np] + parmu * datmat[mpp][np]; + vmnew = f + parmu * resmax; + trured = vmold - vmnew; + if (parmu === 0.0 && f === datmat[mp][np]) { + prerem = prerec; + trured = datmat[mpp][np] - resmax; + } + + // Begin the operations that decide whether x(*) should replace one of the + // vertices of the current simplex, the change being mandatory if TRURED is + // positive. Firstly, JDROP is set to the index of the vertex that is to be + // replaced. + ratio = trured <= 0.0 ? 1.0 : 0.0; + jdrop = 0; + for (j = 1; j <= n; ++j) { + temp = Math.abs(this.DOT_PRODUCT(this.PART(this.ROW(simi, j), 1, n), this.PART(dx, 1, n))); + if (temp > ratio) { + jdrop = j; + ratio = temp; + } + sigbar[j] = temp * vsig[j]; + } + + // Calculate the value of ell. + + edgmax = delta * rho; + l = 0; + for (j = 1; j <= n; ++j) { + if (sigbar[j] >= parsig || sigbar[j] >= vsig[j]) { + temp = veta[j]; + if (trured > 0.0) { + temp = 0.0; + for (k = 1; k <= n; ++k) { + temp += Math.pow(dx[k] - sim[k][j], 2.0); + } + temp = Math.sqrt(temp); + } + if (temp > edgmax) { + l = j; + edgmax = temp; + } + } + } + if (l > 0) { jdrop = l; } + + if (jdrop !== 0) { + // Revise the simplex by updating the elements of SIM, SIMI and DATMAT. + temp = 0.0; + for (i = 1; i <= n; ++i) { + sim[i][jdrop] = dx[i]; + temp += simi[jdrop][i] * dx[i]; + } + for (k = 1; k <= n; ++k) { simi[jdrop][k] /= temp; } + for (j = 1; j <= n; ++j) { + if (j !== jdrop) { + temp = this.DOT_PRODUCT(this.PART(this.ROW(simi, j), 1, n), this.PART(dx, 1, n)); + for (k = 1; k <= n; ++k) { + simi[j][k] -= temp * simi[jdrop][k]; + } + } + } + for (k = 1; k <= mpp; ++k) { + datmat[k][jdrop] = con[k]; + } + + // Branch back for further iterations with the current RHO. + if (trured > 0.0 && trured >= 0.1 * prerem) { + continue L_140; + } + } + } while (false); + + if (!iflag) { + ibrnch = false; + continue L_140; + } + + if (rho <= rhoend) { + status = this.Normal; + break L_40; + } + + // Otherwise reduce RHO if it is not at its least value and reset PARMU. + cmin = 0.0; + cmax = 0.0; + rho *= 0.5; + if (rho <= 1.5 * rhoend) { rho = rhoend; } + if (parmu > 0.0) { + denom = 0.0; + for (k = 1; k <= mp; ++k) { + cmin = datmat[k][np]; + cmax = cmin; + for (i = 1; i <= n; ++i) { + cmin = Math.min(cmin, datmat[k][i]); + cmax = Math.max(cmax, datmat[k][i]); + } + if (k <= m && cmin < 0.5 * cmax) { + temp = Math.max(cmax, 0.0) - cmin; + denom = denom <= 0.0 ? temp : Math.min(denom, temp); + } + } + if (denom === 0.0) { + parmu = 0.0; + } else if (cmax - cmin < parmu * denom) { + parmu = (cmax - cmin) / denom; + } + } + if (iprint >= 2) { + console.log("Reduction in RHO to "+rho+" and PARMU = "+parmu); + } + if (iprint === 2) { + this.PrintIterationResult(nfvals, datmat[mp][np], datmat[mpp][np], this.COL(sim, np), n, iprint); + } + } while (true); + } while (true); + + switch (status) { + case this.Normal: + if (iprint >= 1) { console.log("%nNormal return from subroutine COBYLA%n"); } + if (ifull) { + if (iprint >= 1) { this.PrintIterationResult(nfvals, f, resmax, x, n, iprint); } + return status; + } + break; + case this.MaxIterationsReached: + if (iprint >= 1) { + console.log("%nReturn from subroutine COBYLA because the MAXFUN limit has been reached.%n"); + } + break; + case this.DivergingRoundingErrors: + if (iprint >= 1) { + console.log("%nReturn from subroutine COBYLA because rounding errors are becoming damaging.%n"); + } + break; + } + + for (k = 1; k <= n; ++k) { x[k] = sim[k][np]; } + f = datmat[mp][np]; + resmax = datmat[mpp][np]; + if (iprint >= 1) { this.PrintIterationResult(nfvals, f, resmax, x, n, iprint); } + + return status; + }, + + trstlp: function(n, m, a, b, rho, dx) { //(int n, int m, double[][] a, double[] b, double rho, double[] dx) + // N.B. Arguments Z, ZDOTA, VMULTC, SDIRN, DXNEW, VMULTD & IACT have been removed. + + // This subroutine calculates an N-component vector DX by applying the + // following two stages. In the first stage, DX is set to the shortest + // vector that minimizes the greatest violation of the constraints + // A(1,K)*DX(1)+A(2,K)*DX(2)+...+A(N,K)*DX(N) .GE. B(K), K = 2,3,...,M, + // subject to the Euclidean length of DX being at most RHO. If its length is + // strictly less than RHO, then we use the resultant freedom in DX to + // minimize the objective function + // -A(1,M+1)*DX(1) - A(2,M+1)*DX(2) - ... - A(N,M+1)*DX(N) + // subject to no increase in any greatest constraint violation. This + // notation allows the gradient of the objective function to be regarded as + // the gradient of a constraint. Therefore the two stages are distinguished + // by MCON .EQ. M and MCON .GT. M respectively. It is possible that a + // degeneracy may prevent DX from attaining the target length RHO. Then the + // value IFULL = 0 would be set, but usually IFULL = 1 on return. + // + // In general NACT is the number of constraints in the active set and + // IACT(1),...,IACT(NACT) are their indices, while the remainder of IACT + // contains a permutation of the remaining constraint indices. Further, Z + // is an orthogonal matrix whose first NACT columns can be regarded as the + // result of Gram-Schmidt applied to the active constraint gradients. For + // J = 1,2,...,NACT, the number ZDOTA(J) is the scalar product of the J-th + // column of Z with the gradient of the J-th active constraint. DX is the + // current vector of variables and here the residuals of the active + // constraints should be zero. Further, the active constraints have + // nonnegative Lagrange multipliers that are held at the beginning of + // VMULTC. The remainder of this vector holds the residuals of the inactive + // constraints at DX, the ordering of the components of VMULTC being in + // agreement with the permutation of the indices of the constraints that is + // in IACT. All these residuals are nonnegative, which is achieved by the + // shift RESMAX that makes the least residual zero. + + // Initialize Z and some other variables. The value of RESMAX will be + // appropriate to DX = 0, while ICON will be the index of a most violated + // constraint if RESMAX is positive. Usually during the first stage the + // vector SDIRN gives a search direction that reduces all the active + // constraint violations by one simultaneously. + + // Local variables + + var temp = 0, + nactx = 0, + resold = 0.0, + + z = this.arr2(1 + n, 1 + n), + zdota = this.arr(2 + m), + vmultc = this.arr(2 + m), + sdirn = this.arr(1 + n), + dxnew = this.arr(1 + n), + vmultd = this.arr(2 + m), + iact = this.arr(2 + m), + + mcon = m, + nact = 0, + icon, resmax, + i, k, + first, + optold, icount, step, stpful, optnew, + ratio, isave, vsave, + total, + kp, kk, sp, alpha, beta, + tot, spabs, acca, accb, + zdotv, zdvabs, kw, + dd, ss, sd, + zdotw, zdwabs, + kl, sumabs, tempa; + + for (i = 1; i <= n; ++i) { + z[i][i] = 1.0; + dx[i] = 0.0; + } + + icon = 0; + resmax = 0.0; + if (m >= 1) { + for (k = 1; k <= m; ++k) { + if (b[k] > resmax) { + resmax = b[k]; + icon = k; + } + } + for (k = 1; k <= m; ++k) { + iact[k] = k; + vmultc[k] = resmax - b[k]; + } + } + + // End the current stage of the calculation if 3 consecutive iterations + // have either failed to reduce the best calculated value of the objective + // function or to increase the number of active constraints since the best + // value was calculated. This strategy prevents cycling, but there is a + // remote possibility that it will cause premature termination. + + first = true; + do { + L_60: + do { + if (!first || (first && resmax === 0.0)) { + mcon = m + 1; + icon = mcon; + iact[mcon] = mcon; + vmultc[mcon] = 0.0; + } + first = false; + + optold = 0.0; + icount = 0; + step = 0; + stpful = 0; + + L_70: + do { + optnew = (mcon === m) ? resmax : -this.DOT_PRODUCT( + this.PART(dx, 1, n), this.PART(this.COL(a, mcon), 1, n) + ); + + if (icount === 0 || optnew < optold) { + optold = optnew; + nactx = nact; + icount = 3; + } else if (nact > nactx) { + nactx = nact; + icount = 3; + } else { + --icount; + } + if (icount === 0) { break L_60; } + + // If ICON exceeds NACT, then we add the constraint with index IACT(ICON) to + // the active set. Apply Givens rotations so that the last N-NACT-1 columns + // of Z are orthogonal to the gradient of the new constraint, a scalar + // product being set to zero if its nonzero value could be due to computer + // rounding errors. The array DXNEW is used for working space. + ratio = 0; + if (icon <= nact) { + if (icon < nact) { + // Delete the constraint that has the index IACT(ICON) from the active set. + + isave = iact[icon]; + vsave = vmultc[icon]; + k = icon; + do { + kp = k + 1; + kk = iact[kp]; + sp = this.DOT_PRODUCT( + this.PART(this.COL(z, k), 1, n), + this.PART(this.COL(a, kk), 1, n) + ); + temp = Math.sqrt(sp * sp + zdota[kp] * zdota[kp]); + alpha = zdota[kp] / temp; + beta = sp / temp; + zdota[kp] = alpha * zdota[k]; + zdota[k] = temp; + for (i = 1; i <= n; ++i) { + temp = alpha * z[i][kp] + beta * z[i][k]; + z[i][kp] = alpha * z[i][k] - beta * z[i][kp]; + z[i][k] = temp; + } + iact[k] = kk; + vmultc[k] = vmultc[kp]; + k = kp; + } while (k < nact); + + iact[k] = isave; + vmultc[k] = vsave; + } + --nact; + + // If stage one is in progress, then set SDIRN to the direction of the next + // change to the current vector of variables. + if (mcon > m) { + // Pick the next search direction of stage two. + temp = 1.0 / zdota[nact]; + for (k = 1; k <= n; ++k) { sdirn[k] = temp * z[k][nact]; } + } else { + temp = this.DOT_PRODUCT( + this.PART(sdirn, 1, n), this.PART(this.COL(z, nact + 1), 1, n) + ); + for (k = 1; k <= n; ++k) { sdirn[k] -= temp * z[k][nact + 1]; } + } + } else { + kk = iact[icon]; + for (k = 1; k <= n; ++k) { dxnew[k] = a[k][kk]; } + tot = 0.0; + + // { + k = n; + while (k > nact) { + sp = 0.0; + spabs = 0.0; + for (i = 1; i <= n; ++i) { + temp = z[i][k] * dxnew[i]; + sp += temp; + spabs += Math.abs(temp); + } + acca = spabs + 0.1 * Math.abs(sp); + accb = spabs + 0.2 * Math.abs(sp); + if (spabs >= acca || acca >= accb) { sp = 0.0; } + if (tot === 0.0) { + tot = sp; + } else { + kp = k + 1; + temp = Math.sqrt(sp * sp + tot * tot); + alpha = sp / temp; + beta = tot / temp; + tot = temp; + for (i = 1; i <= n; ++i) { + temp = alpha * z[i][k] + beta * z[i][kp]; + z[i][kp] = alpha * z[i][kp] - beta * z[i][k]; + z[i][k] = temp; + } + } + --k; + } + // } + + if (tot === 0.0) { + // The next instruction is reached if a deletion has to be made from the + // active set in order to make room for the new active constraint, because + // the new constraint gradient is a linear combination of the gradients of + // the old active constraints. Set the elements of VMULTD to the multipliers + // of the linear combination. Further, set IOUT to the index of the + // constraint to be deleted, but branch if no suitable index can be found. + + ratio = -1.0; + //{ + k = nact; + do { + zdotv = 0.0; + zdvabs = 0.0; + + for (i = 1; i <= n; ++i) { + temp = z[i][k] * dxnew[i]; + zdotv += temp; + zdvabs += Math.abs(temp); + } + acca = zdvabs + 0.1 * Math.abs(zdotv); + accb = zdvabs + 0.2 * Math.abs(zdotv); + if (zdvabs < acca && acca < accb) { + temp = zdotv / zdota[k]; + if (temp > 0.0 && iact[k] <= m) { + tempa = vmultc[k] / temp; + if (ratio < 0.0 || tempa < ratio) { ratio = tempa; } + } + + if (k >= 2) { + kw = iact[k]; + for (i = 1; i <= n; ++i) { dxnew[i] -= temp * a[i][kw]; } + } + vmultd[k] = temp; + } else { + vmultd[k] = 0.0; + } + } while (--k > 0); + //} + if (ratio < 0.0) { break L_60; } + + // Revise the Lagrange multipliers and reorder the active constraints so + // that the one to be replaced is at the end of the list. Also calculate the + // new value of ZDOTA(NACT) and branch if it is not acceptable. + + for (k = 1; k <= nact; ++k) { + vmultc[k] = Math.max(0.0, vmultc[k] - ratio * vmultd[k]); + } + if (icon < nact) { + isave = iact[icon]; + vsave = vmultc[icon]; + k = icon; + do { + kp = k + 1; + kw = iact[kp]; + sp = this.DOT_PRODUCT( + this.PART(this.COL(z, k), 1, n), + this.PART(this.COL(a, kw), 1, n) + ); + temp = Math.sqrt(sp * sp + zdota[kp] * zdota[kp]); + alpha = zdota[kp] / temp; + beta = sp / temp; + zdota[kp] = alpha * zdota[k]; + zdota[k] = temp; + for (i = 1; i <= n; ++i) { + temp = alpha * z[i][kp] + beta * z[i][k]; + z[i][kp] = alpha * z[i][k] - beta * z[i][kp]; + z[i][k] = temp; + } + iact[k] = kw; + vmultc[k] = vmultc[kp]; + k = kp; + } while (k < nact); + iact[k] = isave; + vmultc[k] = vsave; + } + temp = this.DOT_PRODUCT( + this.PART(this.COL(z, nact), 1, n), + this.PART(this.COL(a, kk), 1, n) + ); + if (temp === 0.0) { break L_60; } + zdota[nact] = temp; + vmultc[icon] = 0.0; + vmultc[nact] = ratio; + } else { + // Add the new constraint if this can be done without a deletion from the + // active set. + + ++nact; + zdota[nact] = tot; + vmultc[icon] = vmultc[nact]; + vmultc[nact] = 0.0; + } + + // Update IACT and ensure that the objective function continues to be + // treated as the last active constraint when MCON>M. + + iact[icon] = iact[nact]; + iact[nact] = kk; + if (mcon > m && kk !== mcon) { + k = nact - 1; + sp = this.DOT_PRODUCT( + this.PART(this.COL(z, k), 1, n), + this.PART(this.COL(a, kk), 1, n) + ); + temp = Math.sqrt(sp * sp + zdota[nact] * zdota[nact]); + alpha = zdota[nact] / temp; + beta = sp / temp; + zdota[nact] = alpha * zdota[k]; + zdota[k] = temp; + for (i = 1; i <= n; ++i) { + temp = alpha * z[i][nact] + beta * z[i][k]; + z[i][nact] = alpha * z[i][k] - beta * z[i][nact]; + z[i][k] = temp; + } + iact[nact] = iact[k]; + iact[k] = kk; + temp = vmultc[k]; + vmultc[k] = vmultc[nact]; + vmultc[nact] = temp; + } + + // If stage one is in progress, then set SDIRN to the direction of the next + // change to the current vector of variables. + if (mcon > m) { + // Pick the next search direction of stage two. + temp = 1.0 / zdota[nact]; + for (k = 1; k <= n; ++k) { sdirn[k] = temp * z[k][nact]; } + } else { + kk = iact[nact]; + temp = (this.DOT_PRODUCT( + this.PART(sdirn, 1, n), + this.PART(this.COL(a, kk), 1, n) + ) - 1.0) / zdota[nact]; + for (k = 1; k <= n; ++k) { sdirn[k] -= temp * z[k][nact]; } + } + } + + // Calculate the step to the boundary of the trust region or take the step + // that reduces RESMAX to zero. The two statements below that include the + // factor 1.0E-6 prevent some harmless underflows that occurred in a test + // calculation. Further, we skip the step if it could be zero within a + // reasonable tolerance for computer rounding errors. + dd = rho * rho; + sd = 0.0; + ss = 0.0; + for (i = 1; i <= n; ++i) { + if (Math.abs(dx[i]) >= 1.0E-6 * rho) { dd -= dx[i] * dx[i]; } + sd += dx[i] * sdirn[i]; + ss += sdirn[i] * sdirn[i]; + } + if (dd <= 0.0) { break L_60; } + temp = Math.sqrt(ss * dd); + if (Math.abs(sd) >= 1.0E-6 * temp) { temp = Math.sqrt(ss * dd + sd * sd); } + stpful = dd / (temp + sd); + step = stpful; + if (mcon === m) { + acca = step + 0.1 * resmax; + accb = step + 0.2 * resmax; + if (step >= acca || acca >= accb) { break L_70; } + step = Math.min(step, resmax); + } + + // Set DXNEW to the new variables if STEP is the steplength, and reduce + // RESMAX to the corresponding maximum residual if stage one is being done. + // Because DXNEW will be changed during the calculation of some Lagrange + // multipliers, it will be restored to the following value later. + for (k = 1; k <= n; ++k) { dxnew[k] = dx[k] + step * sdirn[k]; } + if (mcon === m) { + resold = resmax; + resmax = 0.0; + for (k = 1; k <= nact; ++k) { + kk = iact[k]; + temp = b[kk] - this.DOT_PRODUCT( + this.PART(this.COL(a, kk), 1, n), this.PART(dxnew, 1, n) + ); + resmax = Math.max(resmax, temp); + } + } + + // Set VMULTD to the VMULTC vector that would occur if DX became DXNEW. A + // device is included to force VMULTD(K) = 0.0 if deviations from this value + // can be attributed to computer rounding errors. First calculate the new + // Lagrange multipliers. + //{ + k = nact; + do { + zdotw = 0.0; + zdwabs = 0.0; + for (i = 1; i <= n; ++i) { + temp = z[i][k] * dxnew[i]; + zdotw += temp; + zdwabs += Math.abs(temp); + } + acca = zdwabs + 0.1 * Math.abs(zdotw); + accb = zdwabs + 0.2 * Math.abs(zdotw); + if (zdwabs >= acca || acca >= accb) { zdotw = 0.0; } + vmultd[k] = zdotw / zdota[k]; + if (k >= 2) { + kk = iact[k]; + for (i = 1; i <= n; ++i) { dxnew[i] -= vmultd[k] * a[i][kk]; } + } + } while (k-- >= 2); + if (mcon > m) { vmultd[nact] = Math.max(0.0, vmultd[nact]); } + //} + + // Complete VMULTC by finding the new constraint residuals. + + for (k = 1; k <= n; ++k) { dxnew[k] = dx[k] + step * sdirn[k]; } + if (mcon > nact) { + kl = nact + 1; + for (k = kl; k <= mcon; ++k) { + kk = iact[k]; + total = resmax - b[kk]; + sumabs = resmax + Math.abs(b[kk]); + for (i = 1; i <= n; ++i) { + temp = a[i][kk] * dxnew[i]; + total += temp; + sumabs += Math.abs(temp); + } + acca = sumabs + 0.1 * Math.abs(total); + accb = sumabs + 0.2 * Math.abs(total); + if (sumabs >= acca || acca >= accb) { total = 0.0; } + vmultd[k] = total; + } + } + + // Calculate the fraction of the step from DX to DXNEW that will be taken. + + ratio = 1.0; + icon = 0; + for (k = 1; k <= mcon; ++k) { + if (vmultd[k] < 0.0) { + temp = vmultc[k] / (vmultc[k] - vmultd[k]); + if (temp < ratio) { + ratio = temp; + icon = k; + } + } + } + + // Update DX, VMULTC and RESMAX. + + temp = 1.0 - ratio; + for (k = 1; k <= n; ++k) { dx[k] = temp * dx[k] + ratio * dxnew[k]; } + for (k = 1; k <= mcon; ++k) { + vmultc[k] = Math.max(0.0, temp * vmultc[k] + ratio * vmultd[k]); + } + if (mcon === m) { resmax = resold + ratio * (resmax - resold); } + + // If the full step is not acceptable then begin another iteration. + // Otherwise switch to stage two or end the calculation. + } while (icon > 0); + + if (step === stpful) { + return true; + } + + } while (true); + + // We employ any freedom that may be available to reduce the objective + // function before returning a DX whose length is less than RHO. + + } while (mcon === m); + + return false; + }, + + PrintIterationResult: function(nfvals, f, resmax, x, n, iprint) { + if (iprint > 1) { console.log("NFVALS = "+nfvals+" F = "+f+" MAXCV = "+resmax); } + if (iprint > 1) { console.log("X = " + this.PART(x, 1, n)); } + }, + + ROW: function(src, rowidx) { + return src[rowidx].slice(); + // var col, + // cols = src[0].length, + // dest = this.arr(cols); + + // for (col = 0; col < cols; ++col) { + // dest[col] = src[rowidx][col]; + // } + // return dest; + }, + + COL: function(src, colidx) { + var row, + rows = src.length, + dest = this.arr(rows); + for (row = 0; row < rows; ++row) { + dest[row] = src[row][colidx]; + } + return dest; + }, + + PART: function(src, from, to) { + return src.slice(from, to + 1); + // var srcidx, + // dest = this.arr(to - from + 1), + // destidx = 0; + // for (srcidx = from; srcidx <= to; ++srcidx, ++destidx) { + // dest[destidx] = src[srcidx]; + // } + // return dest; + }, + + FORMAT: function(x) { + return x.join(','); + // var i, fmt = ""; + // for (i = 0; i < x.length; ++i) { + // fmt += ", " + x[i]; + // } + // return fmt; + }, + + DOT_PRODUCT: function(lhs, rhs) { + var i, sum = 0.0, + len = lhs.length; + for (i = 0; i < len; ++i) { + sum += lhs[i] * rhs[i]; + } + return sum; + } + + }; + + return JXG.Math.Nlp; +}); + +/* + Copyright 2008-2022 Matthias Ehmann, Michael Gerhaeuser, Carsten Miller, @@ -10503,6 +13173,57 @@ define('math/statistics',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, return 0.0; }, + /** + * The P-th percentile ( 0 < P ≤ 100 ) of a list of N ordered values (sorted from least to greatest) + * is the smallest value in the list such that no more than P percent of the data is strictly less + * than the value and at least P percent of the data is less than or equal to that value. See {@link https://en.wikipedia.org/wiki/Percentile}. + * + * Here, the <i>linear interpolation between closest ranks</i> method is used. + * @param {Array} arr The set of values, need not be ordered. + * @param {Number|Array} percentile One or several percentiles + * @returns {Number|Array} Depending if a number or an array is the input for percentile, a number or an array containing the percentils + * is returned. + */ + percentile: function(arr, percentile) { + var tmp, len, i, p, res = [], per; + + if (arr.length > 0) { + if (ArrayBuffer.isView(arr)) { + tmp = new Float64Array(arr); + tmp.sort(); + } else { + tmp = arr.slice(0); + tmp.sort(function (a, b) { + return a - b; + }); + } + len = tmp.length; + + if (Type.isArray(percentile)) { + p = percentile; + } else { + p = [percentile]; + } + + for (i = 0; i < p.length; i++) { + per = len * p[i] * 0.01; + if (parseInt(per, 10) === per) { + res.push( (tmp[per - 1] + tmp[per]) * 0.5 ); + } else { + res.push( tmp[parseInt(per, 10)] ); + } + } + + if (Type.isArray(percentile)) { + return res; + } else { + return res[0]; + } + } + + return 0.0; + }, + /** * Bias-corrected sample variance. A variance is a measure of how far a * set of numbers are spread out from each other. @@ -10607,7 +13328,7 @@ define('math/statistics',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, } else { len = arr.length; res = []; - + for (i = 0; i < len; i++) { res[i] = Math.abs(arr[i]); } @@ -10839,9 +13560,50 @@ define('math/statistics',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, /** * The Theil-Sen estimator can be used to determine a more robust linear regression of a set of sample * points than least squares regression in {@link JXG.Math.Numerics.regressionPolynomial}. + * + * If the function should be applied to an array a of points, a the coords array can be generated with + * JavaScript array.map: + * + * <pre> + * JXG.Math.Statistics.TheilSenRegression(a.map(el => el.coords)); + * </pre> + * * @param {Array} coords Array of {@link JXG.Coords}. - * @returns {Array} The stdform of the regression line. + * @returns {Array} A stdform array of the regression line. * @memberof JXG.Math.Statistics + * + * @example + * var board = JXG.JSXGraph.initBoard('jxgbox', { boundingbox: [-6,6,6,-6], axis : true }); + * var a=[]; + * a[0]=board.create('point', [0,0]); + * a[1]=board.create('point', [3,0]); + * a[2]=board.create('point', [0,3]); + * + * board.create('line', [ + * () => JXG.Math.Statistics.TheilSenRegression(a.map(el => el.coords)) + * ], + * {strokeWidth:1, strokeColor:'black'}); + * + * </pre><div id="JXG0a28be85-91c5-44d3-aae6-114e81217cf0" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG0a28be85-91c5-44d3-aae6-114e81217cf0', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * var board = JXG.JSXGraph.initBoard('jxgbox', { boundingbox: [-6,6,6,-6], axis : true }); + * var a=[]; + * a[0]=board.create('point', [0,0]); + * a[1]=board.create('point', [3,0]); + * a[2]=board.create('point', [0,3]); + * + * board.create('line', [ + * () => JXG.Math.Statistics.TheilSenRegression(a.map(el => el.coords)) + * ], + * {strokeWidth:1, strokeColor:'black'}); + * + * })(); + * + * </script><pre> + * */ TheilSenRegression: function (coords) { var i, j, @@ -10900,13 +13662,13 @@ define('math/statistics',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, }); /* - Copyright 2008-2021 + Copyright 2008-2022 Matthias Ehmann, Michael Gerhaeuser, Carsten Miller, Bianca Valentin, - Alfred Wassermann, Andreas Walter, + Alfred Wassermann, Peter Wilfahrt This file is part of JSXGraph. @@ -11396,6 +14158,38 @@ define('math/geometry',[ return d; }, + /** + * Affine ratio of three collinear points a, b, c: (c - a) / (b - a). + * If r > 1 or r < 0 then c is outside of the segment ab. + * + * @param {Array|JXG.Coords} a + * @param {Array|JXG.Coords} b + * @param {Array|JXG.Coords} c + * @returns {Number} affine ratio (c - a) / (b - a) + */ + affineRatio: function(a, b, c) { + var r = 0.0, dx; + + if (Type.exists(a.usrCoords)) { + a = a.usrCoords; + } + if (Type.exists(b.usrCoords)) { + b = b.usrCoords; + } + if (Type.exists(c.usrCoords)) { + c = c.usrCoords; + } + + dx = b[1] - a[1]; + + if (Math.abs(dx) > Mat.eps) { + r = (c[1] - a[1]) / dx; + } else { + r = (c[2] - a[2]) / (b[2] - a[2]); + } + return r; + }, + /** * Sort vertices counter clockwise starting with the first point. * @@ -11924,30 +14718,76 @@ define('math/geometry',[ * <li>i==0: use the positive square root,</li> * <li>i==1: use the negative square root.</li></ul> * See further {@link JXG.Point#createIntersectionPoint}. - * @param {Boolean} alwaysintersect. Flag that determines if segements and arc can have an outer intersection point + * @param {Boolean} alwaysintersect. Flag that determines if segments and arc can have an outer intersection point * on their defining line or circle. * @returns {Function} Function returning a {@link JXG.Coords} object that determines * the intersection point. */ intersectionFunction: function (board, el1, el2, i, j, alwaysintersect) { - var func, that = this; - - if (el1.elementClass === Const.OBJECT_CLASS_CURVE && - el2.elementClass === Const.OBJECT_CLASS_CURVE) { + var func, that = this, + el1_isArcType = false, + el2_isArcType = false; + + el1_isArcType = (el1.elementClass === Const.OBJECT_CLASS_CURVE && + (el1.type === Const.OBJECT_TYPE_ARC || el1.type === Const.OBJECT_TYPE_SECTOR) + ) ? true : false; + el2_isArcType = (el2.elementClass === Const.OBJECT_CLASS_CURVE && + (el2.type === Const.OBJECT_TYPE_ARC || el2.type === Const.OBJECT_TYPE_SECTOR) + ) ? true : false; + + if ((el1.elementClass === Const.OBJECT_CLASS_CURVE || el2.elementClass === Const.OBJECT_CLASS_CURVE) && + (el1.elementClass === Const.OBJECT_CLASS_CURVE || el1.elementClass === Const.OBJECT_CLASS_CIRCLE) && + (el2.elementClass === Const.OBJECT_CLASS_CURVE || el2.elementClass === Const.OBJECT_CLASS_CIRCLE) /*&& + !(el1_isArcType && el2_isArcType)*/ ) { // curve - curve + // with the exception that both elements are arc types /** @ignore */ func = function () { return that.meetCurveCurve(el1, el2, i, j, el1.board); }; - } else if ((el1.elementClass === Const.OBJECT_CLASS_CURVE && el2.elementClass === Const.OBJECT_CLASS_LINE) || - (el2.elementClass === Const.OBJECT_CLASS_CURVE && el1.elementClass === Const.OBJECT_CLASS_LINE)) { - // curve - line (this includes intersections between conic sections and lines + } else if (( + el1.elementClass === Const.OBJECT_CLASS_CURVE && + !el1_isArcType && + el2.elementClass === Const.OBJECT_CLASS_LINE + ) || + ( + el2.elementClass === Const.OBJECT_CLASS_CURVE && + !el2_isArcType && + el1.elementClass === Const.OBJECT_CLASS_LINE + ) + ) { + // curve - line (this includes intersections between conic sections and lines) + // with the exception that the curve is of arc type /** @ignore */ func = function () { return that.meetCurveLine(el1, el2, i, el1.board, alwaysintersect); }; + } else if (el1.type === Const.OBJECT_TYPE_POLYGON || el2.type === Const.OBJECT_TYPE_POLYGON) { + // polygon - other + // Uses the Greiner-Hormann clipping algorithm + // Not implemented: polygon - point + + if (el1.elementClass === Const.OBJECT_CLASS_LINE) { + // line - path + /** @ignore */ + func = function () { + return that.meetPolygonLine(el2, el1, i, el1.board, alwaysintersect); + }; + } else if (el2.elementClass === Const.OBJECT_CLASS_LINE) { + // path - line + func = function () { + return that.meetPolygonLine(el1, el2, i, el1.board, alwaysintersect); + }; + } else { + // path - path + /** @ignore */ + func = function () { + return that.meetPathPath(el1, el2, i, el1.board); + }; + } + } else if (el1.elementClass === Const.OBJECT_CLASS_LINE && el2.elementClass === Const.OBJECT_CLASS_LINE) { // line - line, lines may also be segments. /** @ignore */ @@ -11960,7 +14800,7 @@ define('math/geometry',[ /** * If one of the lines is a segment or ray and - * the the intersection point should disappear if outside + * the intersection point should disappear if outside * of the segment or ray we call * meetSegmentSegment */ @@ -11969,8 +14809,7 @@ define('math/geometry',[ el1.point1.coords.usrCoords, el1.point2.coords.usrCoords, el2.point1.coords.usrCoords, - el2.point2.coords.usrCoords, - el1.board + el2.point2.coords.usrCoords ); if ((!first1 && res[1] < 0) || (!last1 && res[1] > 1) || @@ -11987,16 +14826,80 @@ define('math/geometry',[ return that.meet(el1.stdform, el2.stdform, i, el1.board); }; } else { - // All other combinations of circles and lines + // All other combinations of circles and lines, + // Arc types are treated as circles. /** @ignore */ func = function () { - return that.meet(el1.stdform, el2.stdform, i, el1.board); + var res = that.meet(el1.stdform, el2.stdform, i, el1.board), + has = true, + first, last, r, dx; + + if (alwaysintersect) { + return res; + } + if (el1.elementClass === Const.OBJECT_CLASS_LINE) { + first = Type.evaluate(el1.visProp.straightfirst); + last = Type.evaluate(el1.visProp.straightlast); + if (!first || !last) { + r = that.affineRatio(el1.point1.coords, el1.point2.coords, res); + if ( (!last && r > 1 + Mat.eps) || (!first && r < 0 - Mat.eps) ) { + return (new Coords(JXG.COORDS_BY_USER, [0, NaN, NaN], el1.board)); + } + } + } + if (el2.elementClass === Const.OBJECT_CLASS_LINE) { + first = Type.evaluate(el2.visProp.straightfirst); + last = Type.evaluate(el2.visProp.straightlast); + if (!first || !last) { + r = that.affineRatio(el2.point1.coords, el2.point2.coords, res); + if ( (!last && r > 1 + Mat.eps) || (!first && r < 0 - Mat.eps) ) { + return (new Coords(JXG.COORDS_BY_USER, [0, NaN, NaN], el1.board)); + } + } + } + if (el1_isArcType) { + has = that.coordsOnArc(el1, res); + if (has && el2_isArcType) { + has = that.coordsOnArc(el2, res); + } + if (!has) { + return (new Coords(JXG.COORDS_BY_USER, [0, NaN, NaN], el1.board)); + } + } + return res; }; } return func; }, + /** + * Returns true if the coordinates are on the arc element, + * false otherwise. Usually, coords is an intersection + * on the circle line. Now it is decided if coords are on the + * circle restricted to the arc line. + * @param {Arc} arc arc or sector element + * @param {JXG.Coords} coords Coords object of an intersection + * @returns {Boolean} + * @private + */ + coordsOnArc: function(arc, coords) { + var angle = this.rad(arc.radiuspoint, arc.center, coords.usrCoords.slice(1)), + alpha = 0.0, + beta = this.rad(arc.radiuspoint, arc.center, arc.anglepoint), + ev_s = Type.evaluate(arc.visProp.selection); + + if ((ev_s === 'minor' && beta > Math.PI) || + (ev_s === 'major' && beta < Math.PI)) { + alpha = beta; + beta = 2 * Math.PI; + } + if (angle < alpha || angle > beta) { + return false; + } + return true; + }, + /** * Computes the intersection of a pair of lines, circles or both. * It uses the internal data array stdform of these elements. @@ -12153,7 +15056,6 @@ define('math/geometry',[ return new Coords(Const.COORDS_BY_USER, [NaN, NaN], board); } - c = circ[0]; b = circ.slice(1, 3); a = circ[3]; @@ -12245,7 +15147,7 @@ define('math/geometry',[ if (Type.exists(method) && method === 'newton') { co = Numerics.generalizedNewton(c1, c2, nr, t2ini); } else { - if (c1.bezierDegree === 3 && c2.bezierDegree === 3) { + if (c1.bezierDegree === 3 || c2.bezierDegree === 3) { co = this.meetBezierCurveRedBlueSegments(c1, c2, nr); } else { co = this.meetCurveRedBlueSegments(c1, c2, nr); @@ -12286,11 +15188,7 @@ define('math/geometry',[ li = el1; } - // if (Type.evaluate(cu.visProp.curvetype) === 'plot') { - v = this.meetCurveLineDiscrete(cu, li, nr, board, !alwaysIntersect); - // } else { - // v = this.meetCurveLineContinuous(cu, li, nr, board); - // } + v = this.meetCurveLineDiscrete(cu, li, nr, board, !alwaysIntersect); return v; }, @@ -12305,6 +15203,8 @@ define('math/geometry',[ * @param {JXG.Line} li Line * @param {Number} nr Will return the nr-th intersection point. * @param {JXG.Board} board + * @param {Boolean} testSegment Test if intersection has to be inside of the segment or somewhere on the + * line defined by the segment * @returns {JXG.Coords} Coords object containing the intersection. */ meetCurveLineContinuous: function (cu, li, nr, board, testSegment) { @@ -12369,81 +15269,6 @@ define('math/geometry',[ return (new Coords(Const.COORDS_BY_USER, [z, cu.X(t), cu.Y(t)], board)); }, - /** - * Intersection of line and curve, continuous case. - * Segments are treated as lines. Finding the nr-the intersection point - * works for nr=0,1 only. - * - * @private - * @deprecated - * @param {JXG.Curve} cu Curve - * @param {JXG.Line} li Line - * @param {Number} nr Will return the nr-th intersection point. - * @param {JXG.Board} board - * - * BUG: does not respect cu.minX() and cu.maxX() - */ - meetCurveLineContinuousOld: function (cu, li, nr, board) { - var t, t2, i, func, z, - tnew, steps, delta, tstart, tend, cux, cuy, - eps = Mat.eps * 10; - - JXG.deprecated('Geometry.meetCurveLineContinuousOld()', 'Geometry.meetCurveLineContinuous()'); - func = function (t) { - var v = li.stdform[0] + li.stdform[1] * cu.X(t) + li.stdform[2] * cu.Y(t); - return v * v; - }; - - // Find some intersection point - if (this.meetCurveLineContinuous.t1memo) { - tstart = this.meetCurveLineContinuous.t1memo; - t = Numerics.root(func, tstart); - } else { - tstart = cu.minX(); - tend = cu.maxX(); - t = Numerics.root(func, [tstart, tend]); - } - - this.meetCurveLineContinuous.t1memo = t; - cux = cu.X(t); - cuy = cu.Y(t); - - // Find second intersection point - if (nr === 1) { - if (this.meetCurveLineContinuous.t2memo) { - tstart = this.meetCurveLineContinuous.t2memo; - } - t2 = Numerics.root(func, tstart); - - if (!(Math.abs(t2 - t) > 0.1 && Math.abs(cux - cu.X(t2)) > 0.1 && Math.abs(cuy - cu.Y(t2)) > 0.1)) { - steps = 20; - delta = (cu.maxX() - cu.minX()) / steps; - tnew = cu.minX(); - - for (i = 0; i < steps; i++) { - t2 = Numerics.root(func, [tnew, tnew + delta]); - - if (Math.abs(func(t2)) <= eps && Math.abs(t2 - t) > 0.1 && Math.abs(cux - cu.X(t2)) > 0.1 && Math.abs(cuy - cu.Y(t2)) > 0.1) { - break; - } - - tnew += delta; - } - } - t = t2; - this.meetCurveLineContinuous.t2memo = t; - } - - // Is the point on the line? - if (Math.abs(func(t)) > eps) { - z = NaN; - } else { - z = 1.0; - } - - return (new Coords(Const.COORDS_BY_USER, [z, cu.X(t), cu.Y(t)], board)); - }, - /** * Intersection of line and curve, discrete case. * Segments are treated as lines. @@ -12479,7 +15304,7 @@ define('math/geometry',[ } p2 = cu.points[0].usrCoords; - for (i = 1; i < len; i++) { + for (i = 1; i < len; i += cu.bezierDegree) { p1 = p2.slice(0); p2 = cu.points[i].usrCoords; d = this.distance(p1, p2); @@ -12496,8 +15321,6 @@ define('math/geometry',[ lip1.slice(1), lip2.slice(1) ], testSegment); - - i += 2; } else { res = [this.meetSegmentSegment(p1, p2, lip1, lip2)]; } @@ -12509,7 +15332,7 @@ define('math/geometry',[ /** * If the intersection point is not part of the segment, * this intersection point is set to non-existent. - * This prevents jumping of the intersection points. + * This prevents jumping behavior of the intersection points. * But it may be discussed if it is the desired behavior. */ if (testSegment && @@ -12588,36 +15411,131 @@ define('math/geometry',[ }, /** - * Intersection of two segments. - * @param {Array} p1 First point of segment 1 using homogeneous coordinates [z,x,y] - * @param {Array} p2 Second point of segment 1 using homogeneous coordinates [z,x,y] - * @param {Array} q1 First point of segment 2 using homogeneous coordinates [z,x,y] - * @param {Array} q2 Second point of segment 2 using homogeneous coordinates [z,x,y] + * (Virtual) Intersection of two segments. + * @param {Array} p1 First point of segment 1 using normalized homogeneous coordinates [1,x,y] + * @param {Array} p2 Second point or direction of segment 1 using normalized homogeneous coordinates [1,x,y] or point at infinity [0,x,y], respectively + * @param {Array} q1 First point of segment 2 using normalized homogeneous coordinates [1,x,y] + * @param {Array} q2 Second point or direction of segment 2 using normalized homogeneous coordinates [1,x,y] or point at infinity [0,x,y], respectively * @returns {Array} [Intersection point, t, u] The first entry contains the homogeneous coordinates - * of the intersection point. The second and third entry gives the position of the intersection between the - * two defining points. For example, the second entry t is defined by: intersection point = t*p1 + (1-t)*p2. + * of the intersection point. The second and third entry give the position of the intersection with respect + * to the definiting parameters. For example, the second entry t is defined by: intersection point = p1 + t * deltaP, where + * deltaP = (p2 - p1) when both parameters are coordinates, and deltaP = p2 if p2 is a point at infinity. * If the two segments are collinear, [[0,0,0], Infinity, Infinity] is returned. **/ meetSegmentSegment: function (p1, p2, q1, q2) { - var t, u, diff, + var t, u, i, d, li1 = Mat.crossProduct(p1, p2), li2 = Mat.crossProduct(q1, q2), - c = Mat.crossProduct(li1, li2), - denom = c[0]; + c = Mat.crossProduct(li1, li2); - if (Math.abs(denom) < Mat.eps) { + if (Math.abs(c[0]) < Mat.eps) { return [c, Infinity, Infinity]; } - diff = [q1[1] - p1[1], q1[2] - p1[2]]; + // Normalize the intersection coordinates + c[1] /= c[0]; + c[2] /= c[0]; + c[0] /= c[0]; + + // Now compute in principle: + // t = dist(c - p1) / dist(p2 - p1) and + // u = dist(c - q1) / dist(q2 - q1) + // However: the points q1, q2, p1, p2 might be ideal points - or in general - the + // coordinates might be not normalized. + // Note that the z-coordinates of p2 and q2 are used to determine whether it should be interpreted + // as a segment coordinate or a direction. + i = (Math.abs(p2[1] - p2[0] * p1[1]) < Mat.eps) ? 2 : 1; + d = p1[i] / p1[0]; + t = (c[i] - d) / ( (p2[0] !== 0) ? (p2[i] / p2[0] - d) : p2[i] ); - // Because of speed issues, evalute the determinants directly - t = (diff[0] * (q2[2] - q1[2]) - diff[1] * (q2[1] - q1[1])) / denom; - u = (diff[0] * (p2[2] - p1[2]) - diff[1] * (p2[1] - p1[1])) / denom; + i = (Math.abs(q2[1] - q2[0] * q1[1]) < Mat.eps) ? 2 : 1; + d = q1[i] / q1[0]; + u = (c[i] - d) / ( (q2[0] !== 0) ? (q2[i] / q2[0] - d) : q2[i] ); return [c, t, u]; }, + /** + * Find the n-th intersection point of two pathes, usually given by polygons. Uses parts of the + * Greiner-Hormann algorithm in JXG.Math.Clip. + * + * @param {JXG.Circle|JXG.Curve|JXG.Polygon} path1 + * @param {JXG.Circle|JXG.Curve|JXG.Polygon} path2 + * @param {Number} n + * @param {JXG.Board} board + * + * @returns {JXG.Coords} Intersection point. In case no intersection point is detected, + * the ideal point [0,0,0] is returned. + * + */ + meetPathPath: function(path1, path2, nr, board) { + var S, C, len, intersections; + + S = JXG.Math.Clip._getPath(path1, board); + len = S.length; + if (len > 0 && this.distance(S[0].coords.usrCoords, S[len - 1].coords.usrCoords, 3) < Mat.eps) { + S.pop(); + } + + C = JXG.Math.Clip._getPath(path2, board); + len = C.length; + if (len > 0 && this.distance(C[0].coords.usrCoords, C[len - 1].coords.usrCoords, 3) < Mat.eps * Mat.eps) { + C.pop(); + } + + // Handle cases where at least one of the paths is empty + if (nr < 0 || JXG.Math.Clip.isEmptyCase(S, C, 'intersection')) { + return (new Coords(Const.COORDS_BY_USER, [0, 0, 0], board)); + } + + JXG.Math.Clip.makeDoublyLinkedList(S); + JXG.Math.Clip.makeDoublyLinkedList(C); + + intersections = JXG.Math.Clip.findIntersections(S, C, board)[0]; + if (nr < intersections.length) { + return intersections[nr].coords; + } + return (new Coords(Const.COORDS_BY_USER, [0, 0, 0], board)); + }, + + /** + * Find the n-th intersection point between a polygon and a line. + * @param {JXG.Polygon} path + * @param {JXG.Line} line + * @param {Number} nr + * @param {JXG.Board} board + * @param {Boolean} alwaysIntersect If false just the segment between the two defining points of the line are tested for intersection. + * + * @returns {JXG.Coords} Intersection point. In case no intersection point is detected, + * the ideal point [0,0,0] is returned. + */ + meetPolygonLine: function(path, line, nr, board, alwaysIntersect) { + var i, res, border, + crds = [0,0,0], + len = path.borders.length, + intersections = []; + + for (i = 0; i < len; i++) { + border = path.borders[i]; + res = this.meetSegmentSegment( + border.point1.coords.usrCoords, + border.point2.coords.usrCoords, + line.point1.coords.usrCoords, + line.point2.coords.usrCoords); + + if ( + (!alwaysIntersect || (res[2] >= 0 && res[2] < 1)) && + res[1] >= 0 && res[1] < 1) { + intersections.push(res[0]); + } + } + + if (nr >= 0 && nr < intersections.length) { + crds = intersections[nr]; + } + return (new Coords(Const.COORDS_BY_USER, crds, board)); + }, + /****************************************/ /**** BEZIER CURVE ALGORITHMS ****/ /****************************************/ @@ -12853,40 +15771,71 @@ define('math/geometry',[ * @returns {Array} The homogeneous coordinates of the nr-th intersection point. */ meetBezierCurveRedBlueSegments: function (red, blue, nr) { - var p, i, j, + var p, i, j, k, po, redArr, blueArr, - bbr, bbb, - lenBlue = blue.numberPoints, //points.length, - lenRed = red.numberPoints, // points.length, + bbr, bbb, intersections, + startRed = 0, + startBlue = 0, + lenBlue = blue.numberPoints, + lenRed = red.numberPoints, L = []; - if (lenBlue < 4 || lenRed < 4) { + if (lenBlue < blue.bezierDegree + 1 || lenRed < red.bezierDegree + 1) { return [0, NaN, NaN]; } + lenBlue -= blue.bezierDegree; + lenRed -= red.bezierDegree; - for (i = 0; i < lenRed - 3; i += 3) { + // For sectors, we ignore the "legs" + if (red.type === Const.OBJECT_TYPE_SECTOR) { + startRed = 3; + lenRed -= 3; + } + if (blue.type === Const.OBJECT_TYPE_SECTOR) { + startBlue = 3; + lenBlue -= 3; + } + + for (i = startRed; i < lenRed; i += red.bezierDegree) { p = red.points; redArr = [ - [p[i].usrCoords[1], p[i].usrCoords[2]], - [p[i + 1].usrCoords[1], p[i + 1].usrCoords[2]], - [p[i + 2].usrCoords[1], p[i + 2].usrCoords[2]], - [p[i + 3].usrCoords[1], p[i + 3].usrCoords[2]] + p[i].usrCoords.slice(1), + p[i + 1].usrCoords.slice(1) ]; + if (red.bezierDegree === 3) { + redArr[2] = p[i + 2].usrCoords.slice(1); + redArr[3] = p[i + 3].usrCoords.slice(1); + } bbr = this._bezierBbox(redArr); - for (j = 0; j < lenBlue - 3; j += 3) { + for (j = startBlue; j < lenBlue; j += blue.bezierDegree) { p = blue.points; blueArr = [ - [p[j].usrCoords[1], p[j].usrCoords[2]], - [p[j + 1].usrCoords[1], p[j + 1].usrCoords[2]], - [p[j + 2].usrCoords[1], p[j + 2].usrCoords[2]], - [p[j + 3].usrCoords[1], p[j + 3].usrCoords[2]] + p[j].usrCoords.slice(1), + p[j + 1].usrCoords.slice(1) ]; + if (blue.bezierDegree === 3) { + blueArr[2] = p[j + 2].usrCoords.slice(1); + blueArr[3] = p[j + 3].usrCoords.slice(1); + } bbb = this._bezierBbox(blueArr); if (this._bezierOverlap(bbr, bbb)) { - L = L.concat(this.meetBeziersegmentBeziersegment(redArr, blueArr)); + intersections = this.meetBeziersegmentBeziersegment(redArr, blueArr); + if (intersections.length === 0) { + continue; + } + for (k = 0; k < intersections.length; k++) { + po = intersections[k]; + if (po[1] < -Mat.eps || + po[1] > 1 + Mat.eps || + po[2] < -Mat.eps || + po[2] > 1 + Mat.eps) { + continue; + } + L.push(po); + } if (L.length > nr) { return L[nr][0]; } @@ -12928,7 +15877,7 @@ define('math/geometry',[ /** * Generate the defining points of a 3rd degree bezier curve that approximates - * a circle sector defined by three arrays A, B,C, each of length three. + * a circle sector defined by three coordinate points A, B, C, each defined by an array of length three. * The coordinate arrays are given in homogeneous coordinates. * @param {Array} A First point * @param {Array} B Second point (intersection point) @@ -13158,7 +16107,8 @@ define('math/geometry',[ * @param {JXG.Curve} curve Curve on that the point is projected. * @param {JXG.Board} [board=point.board] Reference to a board. * @see #projectCoordsToCurve - * @returns {JXG.Coords} The coordinates of the projection of the given point on the given graph. + * @returns {Array} [JXG.Coords, position] The coordinates of the projection of the given + * point on the given graph and the relative position on the curve (real number). */ projectPointToCurve: function (point, curve, board) { if (!Type.exists(board)) { @@ -13170,9 +16120,9 @@ define('math/geometry',[ t = point.position || 0.0, result = this.projectCoordsToCurve(x, y, t, curve, board); - point.position = result[1]; + // point.position = result[1]; - return result[0]; + return result; }, /** @@ -13185,14 +16135,14 @@ define('math/geometry',[ * @param {JXG.Curve} curve Curve on that the point is projected. * @param {JXG.Board} [board=curve.board] Reference to a board. * @see #projectPointToCurve - * @returns {JXG.Coords} Array containing the coordinates of the projection of the given point on the given graph and + * @returns {JXG.Coords} Array containing the coordinates of the projection of the given point on the given curve and * the position on the curve. */ projectCoordsToCurve: function (x, y, t, curve, board) { var newCoords, newCoordsObj, i, j, mindist, dist, lbda, v, coords, d, p1, p2, res, - minfunc, tnew, fnew, fold, delta, steps, + minfunc, t_new, f_new, f_old, delta, steps, minX, maxX, infty = Number.POSITIVE_INFINITY; @@ -13261,34 +16211,35 @@ define('math/geometry',[ minfunc = function (t) { var dx, dy; if (t < curve.minX() || t > curve.maxX()) { - return NaN; + return Infinity; } dx = x - curve.X(t); dy = y - curve.Y(t); return dx * dx + dy * dy; }; - fold = minfunc(t); + f_old = minfunc(t); steps = 50; - delta = (curve.maxX() - curve.minX()) / steps; - tnew = curve.minX(); + minX = curve.minX(); + maxX = curve.maxX(); + + delta = (maxX - minX) / steps; + t_new = minX; for (i = 0; i < steps; i++) { - fnew = minfunc(tnew); + f_new = minfunc(t_new); - if (fnew < fold || isNaN(fold)) { - t = tnew; - fold = fnew; + if (f_new < f_old || f_old === Infinity) { + t = t_new; + f_old = f_new; } - tnew += delta; + t_new += delta; } //t = Numerics.root(Numerics.D(minfunc), t); - t = Numerics.fminbr(minfunc, [t - delta, t + delta]); + t = Numerics.fminbr(minfunc, [Math.max(t - delta, minX), Math.min(t + delta, maxX)]); - minX = curve.minX(); - maxX = curve.maxX(); // Distinction between closed and open curves is not necessary. // If closed, the cyclic projection shift will work anyhow // if (Math.abs(curve.X(minX) - curve.X(maxX)) < Mat.eps && @@ -13323,19 +16274,28 @@ define('math/geometry',[ len = pol.vertices.length, d_best = Infinity, d, - projection, + projection, proj, bestprojection; - for (i = 0; i < len; i++) { + for (i = 0; i < len - 1; i++) { projection = JXG.Math.Geometry.projectCoordsToSegment( p, pol.vertices[i].coords.usrCoords, - pol.vertices[(i + 1) % len].coords.usrCoords + pol.vertices[i + 1].coords.usrCoords ); - d = JXG.Math.Geometry.distance(projection[0], p, 3); - if (0 <= projection[1] && projection[1] <= 1 && d < d_best) { - bestprojection = projection[0].slice(0); + if (0 <= projection[1] && projection[1] <= 1) { + d = JXG.Math.Geometry.distance(projection[0], p, 3); + proj = projection[0]; + } else if (projection[1] < 0) { + d = JXG.Math.Geometry.distance(pol.vertices[i].coords.usrCoords, p, 3); + proj = pol.vertices[i].coords.usrCoords; + } else { + d = JXG.Math.Geometry.distance(pol.vertices[i + 1].coords.usrCoords, p, 3); + proj = pol.vertices[i + 1].coords.usrCoords; + } + if (d < d_best) { + bestprojection = proj.slice(0); d_best = d; } } @@ -13348,10 +16308,12 @@ define('math/geometry',[ * @param {JXG.Point} point Point to project. * @param {JXG.Turtle} turtle on that the point is projected. * @param {JXG.Board} [board=point.board] Reference to a board. - * @returns {JXG.Coords} The coordinates of the projection of the given point on the given turtle. + * @returns {Array} [JXG.Coords, position] Array containing the coordinates of the projection of the given point on the turtle and + * the position on the turtle. */ projectPointToTurtle: function (point, turtle, board) { var newCoords, t, x, y, i, dist, el, minEl, + res, newPos, np = 0, npmin = 0, mindist = Number.POSITIVE_INFINITY, @@ -13366,13 +16328,15 @@ define('math/geometry',[ el = turtle.objects[i]; if (el.elementClass === Const.OBJECT_CLASS_CURVE) { - newCoords = this.projectPointToCurve(point, el); + res = this.projectPointToCurve(point, el); + newCoords = res[0]; + newPos = res[1]; dist = this.distance(newCoords.usrCoords, point.coords.usrCoords); if (dist < mindist) { x = newCoords.usrCoords[1]; y = newCoords.usrCoords[2]; - t = point.position; + t = newPos; mindist = dist; minEl = el; npmin = np; @@ -13382,9 +16346,9 @@ define('math/geometry',[ } newCoords = new Coords(Const.COORDS_BY_USER, [x, y], board); - point.position = t + npmin; - - return minEl.updateTransform(newCoords); + // point.position = t + npmin; + // return minEl.updateTransform(newCoords); + return [minEl.updateTransform(newCoords), t + npmin]; }, /** @@ -13512,14 +16476,93 @@ define('math/geometry',[ }; return [makeFct('X', 'cos'), makeFct('Y', 'sin'), 0, pi2]; - } + }, + + + meet3Planes: function (n1, d1, n2, d2, n3, d3) { + var p = [0, 0, 0], + n31, n12, n23, denom, + i; + + n31 = Mat.crossProduct(n3, n1); + n12 = Mat.crossProduct(n1, n2); + n23 = Mat.crossProduct(n2, n3); + denom = Mat.innerProduct(n1, n23, 3); + for (i = 0; i < 3; i++) { + p[i] = (d1 * n23[i] + d2 * n31[i] + d3 * n12[i]) / denom; + } + return p; + }, + + + meetPlanePlane: function (v11, v12, v21, v22) { + var i, no1, no2, + v = [0, 0, 0], + w = [0, 0, 0]; + + for (i = 0; i < 3; i++) { + v[i] = Type.evaluate(v11[i]); + w[i] = Type.evaluate(v12[i]); + } + no1 = Mat.crossProduct(v, w); + + for (i = 0; i < 3; i++) { + v[i] = Type.evaluate(v21[i]); + w[i] = Type.evaluate(v22[i]); + } + no2 = Mat.crossProduct(v, w); + + return Mat.crossProduct(no1, no2); + }, + + project3DTo3DPlane: function (point, normal, foot) { + // TODO: homogeneous 3D coordinates + var sol = [0, 0, 0], + le, d1, d2, lbda; + + foot = foot || [0, 0, 0]; + + le = Mat.norm(normal); + d1 = Mat.innerProduct(point, normal, 3); + d2 = Mat.innerProduct(foot, normal, 3); + // (point - lbda * normal / le) * normal / le == foot * normal / le + // => (point * normal - foot * normal) == lbda * le + lbda = (d1 - d2) / le; + sol = Mat.axpy(-lbda, normal, point); + + return sol; + }, + + getPlaneBounds: function (v1, v2, q, s, e) { + var s1, s2, e1, e2, mat, rhs, sol; + + if (v1[2] + v2[0] !== 0) { + mat = [ + [v1[0], v2[0]], + [v1[1], v2[1]] + ]; + rhs = [s - q[0], s - q[1]]; + + sol = Numerics.Gauss(mat, rhs); + s1 = sol[0]; + s2 = sol[1]; + + rhs = [e - q[0], e - q[1]]; + sol = Numerics.Gauss(mat, rhs); + e1 = sol[0]; + e2 = sol[1]; + return [s1, e1, s2, e2]; + } + return null; + }, + }); return Mat.Geometry; }); /* - Copyright 2008-2021 + Copyright 2008-2022 Matthias Ehmann, Michael Gerhaeuser, Carsten Miller, @@ -13842,6 +16885,32 @@ define('math/plot',['jxg', 'base/constants', 'base/coords', 'math/math', 'math/e } }, + /** + * Check if there is a single NaN function value at t0. + * @param {*} curve + * @param {*} t0 + * @returns {Boolean} true if there is a second NaN point close by, false otherwise + */ + neighborhood_isNaN_v2: function(curve, t0) { + var is_undef, + pnt = new Coords(Const.COORDS_BY_USER, [0, 0], curve.board, false), + t, p; + + t = t0 + Mat.eps; + pnt.setCoordinates(Const.COORDS_BY_USER, [curve.X(t, true), curve.Y(t, true)], false); + p = pnt.usrCoords; + is_undef = isNaN(p[1] + p[2]); + if (!is_undef) { + t = t0 - Mat.eps; + pnt.setCoordinates(Const.COORDS_BY_USER, [curve.X(t, true), curve.Y(t, true)], false); + p = pnt.usrCoords; + is_undef = isNaN(p[1] + p[2]); + if (!is_undef) { + return false; + } + } + return true; + }, /** * Investigate a function term at the bounds of intervals where @@ -13870,79 +16939,92 @@ define('math/plot',['jxg', 'base/constants', 'base/coords', 'math/math', 'math/e // asymptote; if (depth <= 1) { - pnt = new Coords(Const.COORDS_BY_USER, [0, 0], curve.board, false); - j = 0; - // Bisect a, b and c until the point t_real is inside of the definition interval - // and as close as possible at the boundary. - // t_real2 is the second closest point. - do { - // There are four cases: - // a | c | b - // --------------- - // inf | R | R - // R | R | inf - // inf | inf | R - // R | inf | inf - // - if (isNaN(a[1] + a[2]) && !isNaN(c[1] + c[2])) { - t_nan = ta; - t_real = tc; - t_real2 = tb; - } else if (isNaN(b[1] + b[2]) && !isNaN(c[1] + c[2])) { - t_nan = tb; - t_real = tc; - t_real2 = ta; - } else if (isNaN(c[1] + c[2]) && !isNaN(b[1] + b[2])) { - t_nan = tc; - t_real = tb; - t_real2 = tb + (tb - tc); - } else if (isNaN(c[1] + c[2]) && !isNaN(a[1] + a[2])) { - t_nan = tc; - t_real = ta; - t_real2 = ta - (tc - ta); - } else { - return false; - } - t = 0.5 * (t_nan + t_real); - pnt.setCoordinates(Const.COORDS_BY_USER, [curve.X(t, true), curve.Y(t, true)], false); - p = pnt.usrCoords; - - is_undef = isNaN(p[1] + p[2]); - if (is_undef) { - t_nan = t; - } else { - t_real2 = t_real; - t_real = t; - } - ++j; - } while (is_undef && j < max_it); - - // If bisection was successful, take this point. - // Usefule only for general curves, for function graph - // the code below overwrite p_good from here. - if (j < max_it) { - p_good = p.slice(); - c = p.slice(); - t_real = t; - } - - // OK, bisection has been done now. - // t_real contains the closest inner point to the border of the interval we could find. - // t_real2 is the second nearest point to this boundary. - // Now we approximate the derivative by computing the slope of the line through these two points - // and test if it is "infinite", i.e larger than 400 in absolute values. - // - vx = curve.X(t_real, true) ; - vx2 = curve.X(t_real2, true) ; - dx = (vx - vx2) / (t_real - t_real2); - vy = curve.Y(t_real, true) ; - vy2 = curve.Y(t_real2, true) ; - dy = (vy - vy2) / (t_real - t_real2); - - if (p_good !== null) { - this._insertPoint_v2(curve, new Coords(Const.COORDS_BY_USER, p_good, curve.board, false)); - return true; - } + pnt = new Coords(Const.COORDS_BY_USER, [0, 0], curve.board, false); + // Test if there is a single undefined point. + // If yes, we ignore it. + if (isNaN(a[1] + a[2]) && !isNaN(c[1] + c[2]) && !this.neighborhood_isNaN_v2(curve, ta)) { + return false; + } + if (isNaN(b[1] + b[2]) && !isNaN(c[1] + c[2]) && !this.neighborhood_isNaN_v2(curve, tb)) { + return false; + } + if (isNaN(c[1] + c[2]) && (!isNaN(a[1] + a[2]) || !isNaN(b[1] + b[2])) && + !this.neighborhood_isNaN_v2(curve, tc)) { + return false; + } + + j = 0; + // Bisect a, b and c until the point t_real is inside of the definition interval + // and as close as possible at the boundary. + // t_real2 is the second closest point. + do { + // There are four cases: + // a | c | b + // --------------- + // inf | R | R + // R | R | inf + // inf | inf | R + // R | inf | inf + // + if (isNaN(a[1] + a[2]) && !isNaN(c[1] + c[2])) { + t_nan = ta; + t_real = tc; + t_real2 = tb; + } else if (isNaN(b[1] + b[2]) && !isNaN(c[1] + c[2])) { + t_nan = tb; + t_real = tc; + t_real2 = ta; + } else if (isNaN(c[1] + c[2]) && !isNaN(b[1] + b[2])) { + t_nan = tc; + t_real = tb; + t_real2 = tb + (tb - tc); + } else if (isNaN(c[1] + c[2]) && !isNaN(a[1] + a[2])) { + t_nan = tc; + t_real = ta; + t_real2 = ta - (tc - ta); + } else { + return false; + } + t = 0.5 * (t_nan + t_real); + pnt.setCoordinates(Const.COORDS_BY_USER, [curve.X(t, true), curve.Y(t, true)], false); + p = pnt.usrCoords; + + is_undef = isNaN(p[1] + p[2]); + if (is_undef) { + t_nan = t; + } else { + t_real2 = t_real; + t_real = t; + } + ++j; + } while (is_undef && j < max_it); + + // If bisection was successful, take this point. + // Useful only for general curves, for function graph + // the code below overwrite p_good from here. + if (j < max_it) { + p_good = p.slice(); + c = p.slice(); + t_real = t; + } + + // OK, bisection has been done now. + // t_real contains the closest inner point to the border of the interval we could find. + // t_real2 is the second nearest point to this boundary. + // Now we approximate the derivative by computing the slope of the line through these two points + // and test if it is "infinite", i.e larger than 400 in absolute values. + // + vx = curve.X(t_real, true) ; + vx2 = curve.X(t_real2, true) ; + dx = (vx - vx2) / (t_real - t_real2); + vy = curve.Y(t_real, true) ; + vy2 = curve.Y(t_real2, true) ; + dy = (vy - vy2) / (t_real - t_real2); + + if (p_good !== null) { + this._insertPoint_v2(curve, new Coords(Const.COORDS_BY_USER, p_good, curve.board, false)); + return true; + } } return false; }, @@ -14016,7 +17098,11 @@ define('math/plot',['jxg', 'base/constants', 'base/coords', 'math/math', 'math/e //if (this._borderCase(a, b, c, ta, tb, tc, depth)) {} } else { this._plotRecursive_v2(curve, a, ta, c, tc, depth, delta); - this._insertPoint_v2(curve, pnt, tc); + + if (!isNaN(pnt.scrCoords[1] + pnt.scrCoords[2])) { + this._insertPoint_v2(curve, pnt, tc); + } + this._plotRecursive_v2(curve, c, tc, b, tb, depth, delta); } @@ -14024,7 +17110,7 @@ define('math/plot',['jxg', 'base/constants', 'base/coords', 'math/math', 'math/e }, /** - * Updates the data points of a parametric curve. This version is used if {@link JXG.Curve#doadvancedplot} is <tt>true</tt>. + * Updates the data points of a parametric curve. This version is used if {@link JXG.Curve#plotVersion} is <tt>3</tt>. * * @param {JXG.Curve} curve JSXGraph curve element * @param {Number} mi Left bound of curve @@ -14348,7 +17434,10 @@ define('math/plot',['jxg', 'base/constants', 'base/coords', 'math/math', 'math/e fnX1, fnX2, fnY1, fnY2, bbox = curve.board.getBoundingBox(); - if (!this._isOutsidePoint(a, curve.board)) { + // The code below is too unstable. + // E.g. [function(t) { return Math.pow(t, 2) * (t + 5) * Math.pow(t - 5, 2); }, -8, 8] + // Therefore, we return here. + if (true || !this._isOutsidePoint(a, curve.board)) { return [a, ta]; } @@ -14490,7 +17579,7 @@ define('math/plot',['jxg', 'base/constants', 'base/coords', 'math/math', 'math/e }, /** - * + * * @param {JXG.Curve} curve JSXGraph curve element * @param {Number} ta * @param {Number} tb @@ -14700,13 +17789,14 @@ define('math/plot',['jxg', 'base/constants', 'base/coords', 'math/math', 'math/e }, /** - * Updates the data points of a parametric curve. This version is used if {@link JXG.Curve#doadvancedplot} is <tt>true</tt>. + * Updates the data points of a parametric curve. This version is used if {@link JXG.Curve#plotVersion} is <tt>3</tt>. + * This is an experimental plot version, <b>not recommended</b> to be used. * @param {JXG.Curve} curve JSXGraph curve element * @param {Number} mi Left bound of curve * @param {Number} ma Right bound of curve * @returns {JXG.Curve} Reference to the curve object. */ - updateParametricCurve: function (curve, mi, ma) { + updateParametricCurve_v3: function (curve, mi, ma) { var ta, tb, a, b, suspendUpdate = false, pa = new Coords(Const.COORDS_BY_USER, [0, 0], curve.board, false), @@ -14797,6 +17887,7 @@ define('math/plot',['jxg', 'base/constants', 'base/coords', 'math/math', 'math/e sgn, sgnChange, isGroup = false, abs_vec, + last = -Infinity, very_small = false, smooth = false, group = 0, @@ -14816,13 +17907,17 @@ define('math/plot',['jxg', 'base/constants', 'base/coords', 'math/math', 'math/e //console.log("Median", med); for (i = 0; i < le; i++) { + // Start a group if not yet done and + // add position to group if (abs_vec[i] > med /*&& abs_vec[i] > 0.01*/) { positions.push({i: i, v: vec[i], group: group}); + last = i; if (!isGroup) { isGroup = true; } } else { - if (isGroup) { + if (isGroup && i > last + 4) { + // End the group if (positions.length > 0) { groups.push(positions.slice(0)); } @@ -15254,6 +18349,7 @@ console.log("Polynomial of degree", level); _insertPoint_v4: function (curve, crds, t, doLog) { var p, prev = null, + x, y, near = 0.8; if (curve.points.length > 0) { @@ -15263,13 +18359,16 @@ console.log("Polynomial of degree", level); // Add regular point p = new Coords(Const.COORDS_BY_USER, crds, curve.board); - if (prev !== null && - Math.abs(p.scrCoords[1] - prev[1]) < near && - Math.abs(p.scrCoords[2] - prev[2]) < near) { + if (prev !== null) { + x = p.scrCoords[1] - prev[1]; + y = p.scrCoords[2] - prev[2]; + if (x * x + y * y < near * near) { + // Math.abs(p.scrCoords[1] - prev[1]) < near && + // Math.abs(p.scrCoords[2] - prev[2]) < near) { return; } + } -//console.log("insert", t) p._t = t; curve.points.push(p); }, @@ -15325,6 +18424,9 @@ console.log("Polynomial of degree", level); } components2 = this.findComponents(curve, t1, t2, size); + if (components2.length === 0) { + return; + } if (group.type === 'borderleft') { t1 = components2[0].left_t; t2 = components2[0].t_values[0]; @@ -15369,7 +18471,7 @@ console.log("Polynomial of degree", level); }, - _recurse_v4: function(curve, comp, group, x_table, y_table) { + _seconditeration_v4: function(curve, comp, group, x_table, y_table) { var i, t1, t2, ret, components2, comp2, idx, groups2, g, x_table2, y_table2, start, le; @@ -15412,17 +18514,50 @@ console.log("Polynomial of degree", level); return this; }, + _recurse_v4: function(curve, t1, t2, x1, y1, x2, y2, level) { + var tol = 2, + t = (t1 + t2) * 0.5, + x = curve.X(t, true), + y = curve.Y(t, true), + dx, dy; + + //console.log("Level", level) + if (level === 0) { + this._insertPoint_v4(curve, [1, NaN, NaN], t); + return; + } + // console.log("R", t1, t2) + dx = (x - x1) * curve.board.unitX; + dy = (y - y1) * curve.board.unitY; + // console.log("D1", Math.sqrt(dx * dx + dy * dy)) + if (Math.sqrt(dx * dx + dy * dy) > tol) { + this._recurse_v4(curve, t1, t, x1, y1, x, y, level - 1); + } else { + this._insertPoint_v4(curve, [1, x, y], t); + } + dx = (x - x2) * curve.board.unitX; + dy = (y - y2) * curve.board.unitY; + // console.log("D2", Math.sqrt(dx * dx + dy * dy), x-x2, y-y2) + if (Math.sqrt(dx * dx + dy * dy) > tol) { + this._recurse_v4(curve, t, t2, x, y, x2, y2, level - 1); + } else { + this._insertPoint_v4(curve, [1, x, y], t); + } + }, + handleSingularity: function(curve, comp, group, x_table, y_table) { var idx = group.idx, t, t1, t2, y_int, - x, lo, hi, + i1, i2, + x, y, lo, hi, d_lft, d_rgt, d_thresh = 100, di1 = 5, - di2 = 3; + di2 = 3, + d1, d2; t = group.t; - // console.log("HandleSingularity at t =", t); + console.log("HandleSingularity at t =", t); // console.log(comp.t_values[idx - 1], comp.y_values[idx - 1], comp.t_values[idx + 1], comp.y_values[idx + 1]); // console.log(group); @@ -15446,19 +18581,19 @@ console.log("Polynomial of degree", level); x = curve.X(t, true); - // console.log(">>>", t1, t2, lo, hi, x); - d_lft = (y_table[0][idx - di2] - y_table[0][idx - di1]) / (comp.t_values[idx - di2] - comp.t_values[idx - di1]); d_rgt = (y_table[0][idx + di2] - y_table[0][idx + di1]) / (comp.t_values[idx + di2] - comp.t_values[idx + di1]); - // console.log(":::", d_lft, d_rgt); + console.log(":::", d_lft, d_rgt); + + //this._insertPoint_v4(curve, [1, NaN, NaN], 0); if (d_lft < -d_thresh) { // Left branch very steep downwards -> add the minimum this._insertPoint_v4(curve, [1, x, lo], t, true); if (d_rgt <= d_thresh) { // Right branch not very steep upwards -> interrupt the curve - // I.e. exclude the case -infty / -infty + // I.e. it looks like -infty / (finite or infty) and not like -infty / -infty this._insertPoint_v4(curve, [1, NaN, NaN], t); } } else if (d_lft > d_thresh) { @@ -15466,24 +18601,64 @@ console.log("Polynomial of degree", level); this._insertPoint_v4(curve, [1, x, hi], t); if (d_rgt >= -d_thresh) { // Right branch not very steep downwards -> interrupt the curve - // I.e. exclude the case infty / infty + // I.e. it looks like infty / (finite or -infty) and not like infty / infty this._insertPoint_v4(curve, [1, NaN, NaN], t); } } else { - if (Math.abs(y_table[0][idx - 1] - y_table[0][idx + 1]) * curve.board.unitY >= 2) { - // Finite jump - // console.log("JUMP") + if (lo === -Infinity) { + this._insertPoint_v4(curve, [1, x, lo], t, true); this._insertPoint_v4(curve, [1, NaN, NaN], t); - } else { - if (lo === -Infinity) { - this._insertPoint_v4(curve, [1, x, lo], t, true); - this._insertPoint_v4(curve, [1, NaN, NaN], t); - } - if (hi === Infinity) { - this._insertPoint_v4(curve, [1, NaN, NaN], t); - this._insertPoint_v4(curve, [1, x, hi], t, true); - } } + if (hi === Infinity) { + this._insertPoint_v4(curve, [1, NaN, NaN], t); + this._insertPoint_v4(curve, [1, x, hi], t, true); + } + + if (group.t < comp.t_values[idx]) { + i1 = idx - 1; + i2 = idx; + } else { + i1 = idx; + i2 = idx + 1; + } + t1 = comp.t_values[i1]; + t2 = comp.t_values[i2]; + this._recurse_v4(curve, t1, t2, + x_table[0][i1], + y_table[0][i1], + x_table[0][i2], + y_table[0][i2], + 10 + ); + + // x = (x_table[0][idx] - x_table[0][idx - 1]) * curve.board.unitX; + // y = (y_table[0][idx] - y_table[0][idx - 1]) * curve.board.unitY; + // d1 = Math.sqrt(x * x + y * y); + // x = (x_table[0][idx + 1] - x_table[0][idx]) * curve.board.unitX; + // y = (y_table[0][idx + 1] - y_table[0][idx]) * curve.board.unitY; + // d2 = Math.sqrt(x * x + y * y); + + // console.log("end", t1, t2, t); + // if (true || (d1 > 2 || d2 > 2)) { + +// console.log(d1, d2, y_table[0][idx]) +// // Finite jump +// this._insertPoint_v4(curve, [1, NaN, NaN], t); +// } else { +// if (lo !== -Infinity && hi !== Infinity) { +// // Critical point which can be ignored +// this._insertPoint_v4(curve, [1, x_table[0][idx], y_table[0][idx]], comp.t_values[idx]); +// } else { +// if (lo === -Infinity) { +// this._insertPoint_v4(curve, [1, x, lo], t, true); +// this._insertPoint_v4(curve, [1, NaN, NaN], t); +// } +// if (hi === Infinity) { +// this._insertPoint_v4(curve, [1, NaN, NaN], t); +// this._insertPoint_v4(curve, [1, x, hi], t, true); +// } +// } + // } } if (d_rgt < -d_thresh) { // Right branch very steep downwards -> add the maximum @@ -15498,7 +18673,7 @@ console.log("Polynomial of degree", level); /** * Number of equidistant points where the function is evaluated */ - steps: 1021, + steps: 1021, //2053, // 1021, /** * If the absolute maximum of the set of differences is larger than @@ -15536,7 +18711,6 @@ console.log("Polynomial of degree", level); // if (degree_y >= 0) { // console.log("y polynomial of degree", degree_y); // } - if (groups.length === 0 || groups[0].type !== 'borderleft') { groups.unshift({ idx: 0, @@ -15614,7 +18788,7 @@ console.log("Polynomial of degree", level); if (groups[g].type === 'borderleft' || groups[g].type === 'borderright') { this.handleBorder(curve, comp, groups[g], x_table, y_table); } else { - this._recurse_v4(curve, comp, groups[g], x_table, y_table); + this._seconditeration_v4(curve, comp, groups[g], x_table, y_table); } start = groups[g].idx + 1 + 1; @@ -15630,6 +18804,13 @@ console.log("Polynomial of degree", level); }, + /** + * Updates the data points of a parametric curve, plotVersion 4. This version is used if {@link JXG.Curve#plotVersion} is <tt>4</tt>. + * @param {JXG.Curve} curve JSXGraph curve element + * @param {Number} mi Left bound of curve + * @param {Number} ma Right bound of curve + * @returns {JXG.Curve} Reference to the curve object. + */ updateParametricCurve_v4: function (curve, mi, ma) { var ta, tb, w2, bbox; @@ -15653,6 +18834,25 @@ console.log("Polynomial of degree", level); curve.numberPoints = curve.points.length; //console.log(curve.numberPoints); + }, + + //---------------------------------------------------------------------- + // Plot algorithm alias + //---------------------------------------------------------------------- + + /** + * Updates the data points of a parametric curve, alias for {@link JXG.Curve#updateParametricCurve_v2}. + * This is needed for backwards compatibility, if this method has been + * used directly in an application. + * @param {JXG.Curve} curve JSXGraph curve element + * @param {Number} mi Left bound of curve + * @param {Number} ma Right bound of curve + * @returns {JXG.Curve} Reference to the curve object. + * + * @see JXG.Curve#updateParametricCurve_v2 + */ + updateParametricCurve: function (curve, mi, ma) { + return this.updateParametricCurve_v2(curve, mi, ma); } }; @@ -15661,7 +18861,7 @@ console.log("Polynomial of degree", level); }); /* - Copyright 2008-2021 + Copyright 2008-2022 Matthias Ehmann, Michael Gerhaeuser, Carsten Miller, @@ -16334,7 +19534,7 @@ define('math/metapost',['utils/type', 'math/math'], function (Type, Mat) { }); /* - Copyright 2008-2021 + Copyright 2008-2022 Matthias Ehmann, Michael Gerhaeuser, Carsten Miller, @@ -17437,7 +20637,7 @@ define('utils/encoding',['jxg'], function (JXG) { }); /* - Copyright 2008-2021 + Copyright 2008-2022 Matthias Ehmann, Michael Gerhaeuser, Carsten Miller, @@ -17572,7 +20772,7 @@ define('utils/base64',['jxg', 'utils/encoding'], function (JXG, Encoding) { // deactivate regexp linting. Our regex is secure, because we replace everything with '' /*jslint regexp:true*/ - encInput = input.replace(/[^A-Za-z0-9\+\/=]/g, ''); + encInput = input.replace(/[^A-Za-z0-9+/=]/g, ''); /*jslint regexp:false*/ len = encInput.length; @@ -17648,7 +20848,7 @@ define('utils/base64',['jxg', 'utils/encoding'], function (JXG, Encoding) { }); /* - Copyright 2008-2021 + Copyright 2008-2022 Matthias Ehmann, Michael Gerhaeuser, Carsten Miller, @@ -17827,7 +21027,7 @@ define('server/server',[ // bind cbp callback method to JXG.Server to get access to JXG.Server fields from within cpb this.cb = JXG.bind(this.cbp, this); - // we're using our own XMLHttpRequest object in here because of a/sync and POST + // We are using our own XMLHttpRequest object in here because of a/sync and POST if (window.XMLHttpRequest) { AJAX = new XMLHttpRequest(); AJAX.overrideMimeType('text/plain; charset=iso-8859-1'); @@ -17890,7 +21090,7 @@ define('server/server',[ return JXG.Server; }); /* - Copyright 2008-2021 + Copyright 2008-2022 Matthias Ehmann, Michael Gerhaeuser, Carsten Miller, @@ -18272,11 +21472,12 @@ define('math/symbolic',[ }); /* - Copyright 2008-2021 + Copyright 2008-2022 Matthias Ehmann, Michael Gerhaeuser, Carsten Miller, Alfred Wassermann +console.log("P:", P.coords.usrCoords, P.data.type) This file is part of JSXGraph. @@ -18335,28 +21536,67 @@ define('math/clip',[ * @exports Mat.Clip as JXG.Math.Clip * @namespace */ + // Mat.Clip = function () { + // }; + + // JXG.extend(Mat.Clip.prototype, /** @lends JXG.Curve.prototype */ { + Mat.Clip = { + _isSeparator: function(node) { + return isNaN(node.coords.usrCoords[1]) && isNaN(node.coords.usrCoords[2]); + }, + /** * Add pointers to an array S such that it is a circular doubly-linked list. * * @private * @param {Array} S Array - * @return {Array} return the array S + * @return {Array} return containing the starter indices of each component. */ makeDoublyLinkedList: function(S) { var i, + first = null, + components = [], le = S.length; if (le > 0) { for (i = 0; i < le; i++) { - S[i]._next = S[(i + 1) % le]; - S[i]._prev = S[(le + i - 1) % le]; + // S[i]._next = S[(i + 1) % le]; + // S[i]._prev = S[(le + i - 1) % le]; + + // If S[i] is component separator we proceed with the next node. + if (this._isSeparator(S[i])) { + S[i]._next = S[(i + 1) % le]; + S[i]._prev = S[(le + i - 1) % le]; + continue; + } + + // Now we know that S[i] is a path component + if (first === null) { + // Start the component if it is not yet started. + first = i; + components.push(first); + } + if (this._isSeparator(S[(i + 1) % le]) || i === le - 1) { + // If the next node is a component separator or if the node is the last node, + // then we close the loop + + S[i]._next = S[first]; + S[first]._prev = S[i]; + S[i]._end = true; + first = null; + } else { + // Here, we are not at the end of component + S[i]._next = S[(i + 1) % le]; + S[first]._prev = S[i]; + } + if (!this._isSeparator(S[(le + i - 1) % le])) { + S[i]._prev = S[(le + i - 1) % le]; + } } - S[le - 1]._end = true; } - - return S; + return components; }, /** @@ -18386,7 +21626,8 @@ define('math/clip',[ * Volume 20, Issue 3, November 2001, Pages 131-144. * * @param {Array} usrCoords Homogenous coordinates of the point - * @param {Array} path Array of JXG.Coords determining a path, i.e. the vertices of the polygon. + * @param {Array} path Array of points determining a path, i.e. the vertices of the polygon. The array elements + * do not have to be full points, but have to have a subobject "coords". * @return {Number} Winding number of the point. The point is * regarded outside if the winding number is zero, * inside otherwise. @@ -18492,8 +21733,6 @@ define('math/clip',[ pathname: pathname, done: false, type: type, - revtype: type, - link: null, idx: 0 }; @@ -18539,10 +21778,11 @@ define('math/clip',[ P_crossings[i].sort(function(a, b) { return (a.data.alpha > b.data.alpha) ? 1 : -1; }); if (P_crossings[i].length > 0) { - // console.log("Crossings", P_crossings[i]) + // console.log("Crossings", P_crossings[i]) last = P_crossings[i].length - 1; P = P_crossings[i][0]; -//console.log("SORT", P.coords.usrCoords) + + //console.log("SORT", P.coords.usrCoords) Q = P.data.path[P.pos]; next_node = Q._next; // Store the next "normal" node @@ -18551,7 +21791,7 @@ define('math/clip',[ } if (P.data.alpha === 0.0 && P.data.type === 'T') { -// console.log("SKIP", P.coords.usrCoords, P.data.type, P.neighbour.data.type); + // console.log("SKIP", P.coords.usrCoords, P.data.type, P.neighbour.data.type); Q.intersection = true; Q.data = P.data; Q.neighbour = P.neighbour; @@ -18578,7 +21818,7 @@ define('math/clip',[ if (i === P_le - 1) { P._end = true; - //console.log("END", P._end, P.coords.usrCoords, P._prev.coords.usrCoords, P._next.coords.usrCoords); + //console.log("END", P._end, P.coords.usrCoords, P._prev.coords.usrCoords, P._next.coords.usrCoords); } P_intersect = P_intersect.concat(P_crossings[i]); @@ -18611,9 +21851,20 @@ define('math/clip',[ }, _print_array: function(arr) { - var i; + var i, end; for (i = 0; i < arr.length; i++) { - console.log(i, arr[i].coords.usrCoords, arr[i].data.type); + //console.log(i, arr[i].coords.usrCoords, arr[i].data.type); + try { + end = ""; + if (arr[i]._end) { + end = " end"; + } + console.log(i, arr[i].coords.usrCoords, arr[i].data.type, "\t", + "prev", arr[i]._prev.coords.usrCoords, + "next", arr[i]._next.coords.usrCoords + end); + } catch (e) { + console.log(i, arr[i].coords.usrCoords); + } } }, @@ -18641,7 +21892,7 @@ define('math/clip',[ _noOverlap: function(p1, p2, q1, q2) { var k, - eps = Mat.eps * Mat.eps, + eps = Math.sqrt(Mat.eps), minp, maxp, minq, maxq, no_overlap = false; @@ -18650,7 +21901,7 @@ define('math/clip',[ maxp = Math.max(p1[k], p2[k]); minq = Math.min(q1[k], q2[k]); maxq = Math.max(q1[k], q2[k]); - if (maxp < minq - eps|| minp > maxq + eps) { + if (maxp < minq - eps || minp > maxq + eps) { no_overlap = true; break; } @@ -18677,13 +21928,17 @@ define('math/clip',[ S_le = S.length, C_le = C.length, Si, Si1, Cj, Cj1, + d1, d2, alpha, type, IS, IC, S_intersect = [], C_intersect = [], S_crossings = [], - C_crossings = []; + C_crossings = [], + hasMultCompsS = false, + hasMultCompsC = false, + DEBUG = false; for (j = 0; j < C_le; j++) { C_crossings.push([]); @@ -18692,11 +21947,41 @@ define('math/clip',[ // Run through the subject path. for (i = 0; i < S_le; i++) { S_crossings.push([]); + + // Test if S[i] or its successor is a path separator. + // If yes, we know that the path consists of multiple components. + // We immediately jump to the next segment. + if (this._isSeparator(S[i]) || this._isSeparator(S[(i + 1) % S_le])) { + hasMultCompsS = true; + continue; + } + + // If the path consists of multiple components then there is + // no path-closing segment between the last node and the first + // node. In this case we can leave the loop now. + if (hasMultCompsS && i === S_le - 1) { + break; + } + Si = S[i].coords.usrCoords; Si1 = S[(i + 1) % S_le].coords.usrCoords; - // Run through the clip path. for (j = 0; j < C_le; j++) { + // Test if C[j] or its successor is a path separator. + // If yes, we know that the path consists of multiple components. + // We immediately jump to the next segment. + if (this._isSeparator(C[j]) || this._isSeparator(C[(j + 1) % C_le])) { + hasMultCompsC = true; + continue; + } + + // If the path consists of multiple components then there is + // no path-closing segment between the last node and the first + // node. In this case we can leave the loop now. + if (hasMultCompsC && j === C_le - 1) { + break; + } + // Test if bounding boxes of the two curve segments overlap // If not, the expensive intersection test can be skipped. Cj = C[j].coords.usrCoords; @@ -18708,29 +21993,29 @@ define('math/clip',[ // Intersection test res = Geometry.meetSegmentSegment(Si, Si1, Cj, Cj1); -//console.log(i, j, ":", res[0][1] / res[0][0], res[0][2] / res[0][0], res[1], res[2]); + + d1 = Geometry.distance(Si, Si1, 3); + d2 = Geometry.distance(Cj, Cj1, 3); // Found an intersection point - // isCollinear = false; - if ((res[1] > -eps && res[1] < 1 - eps && // "regular" intersection - res[2] > -eps && res[2] < 1 - eps) || - (res[1] === Infinity && - res[2] === Infinity && Mat.norm(res[0], 3) < eps) // collinear + if ( // "Regular" intersection + (res[1] * d1 > -eps && res[1] < 1 - eps / d1 && res[2] * d2 > -eps && res[2] < 1 - eps / d2) || + // Collinear segments + (res[1] === Infinity && res[2] === Infinity && Mat.norm(res[0], 3) < eps) ) { crds = new Coords(Const.COORDS_BY_USER, res[0], board); type = 'X'; -// console.log("IS", i, j, crds.usrCoords, res[1], res[2]); - // Degenerate cases - if (Math.abs(res[1]) < eps || Math.abs(res[2]) < eps) { + // Handle degenerated cases + if (Math.abs(res[1]) * d1 < eps || Math.abs(res[2]) * d2 < eps) { // Crossing / bouncing at vertex or // end of delayed crossing / bouncing type = 'T'; - if (Math.abs(res[1]) < eps) { + if (Math.abs(res[1]) * d1 < eps) { res[1] = 0; } - if (Math.abs(res[2]) < eps) { + if (Math.abs(res[2]) * d2 < eps) { res[2] = 0; } if (res[1] === 0) { @@ -18738,16 +22023,24 @@ define('math/clip',[ } else { crds = new Coords(Const.COORDS_BY_USER, Cj, board); } + + if (DEBUG) { + console.log("Degenerate case I", res[1], res[2], crds.usrCoords, "type", type); + } } else if (res[1] === Infinity && res[2] === Infinity && - Mat.norm(res[0], 3) < eps) { + Mat.norm(res[0], 3) < eps) { // console.log(C_intersect); + - // In this case there might be two intersection points to be added // Collinear segments + // Here, there might be two intersection points to be added + alpha = this._inbetween(Si, Cj, Cj1); -// console.log("alpha Si", alpha, Si); -// console.log(j, Cj) -// console.log((j + 1) % C_le, Cj1) + if (DEBUG) { + // console.log("alpha Si", alpha, Si); + // console.log(j, Cj) + // console.log((j + 1) % C_le, Cj1) + } if (alpha >= 0 && alpha < 1) { type = 'T'; crds = new Coords(Const.COORDS_BY_USER, Si, board); @@ -18757,28 +22050,38 @@ define('math/clip',[ IC = new this.Vertex(crds, j, res[2], C, 'C', type); IS.neighbour = IC; IC.neighbour = IS; - S_crossings[i].push(IS); C_crossings[j].push(IC); + if (DEBUG) { + console.log("Degenerate case II", res[1], res[2], crds.usrCoords, "type T"); + } } alpha = this._inbetween(Cj, Si, Si1); -// console.log("alpha Cj", alpha, Si); - if (Geometry.distance(Si, Cj, 3) > Mat.eps && + if (DEBUG) { + // console.log("alpha Cj", alpha, Si, Geometry.distance(Si, Cj, 3)); + } + if (Geometry.distance(Si, Cj, 3) > eps && alpha >= 0 && alpha < 1) { - type = 'T'; - crds = new Coords(Const.COORDS_BY_USER, Cj, board); - res[1] = alpha; - res[2] = 0; - IS = new this.Vertex(crds, i, res[1], S, 'S', type); - IC = new this.Vertex(crds, j, res[2], C, 'C', type); - IS.neighbour = IC; - IC.neighbour = IS; - - S_crossings[i].push(IS); - C_crossings[j].push(IC); + + type = 'T'; + crds = new Coords(Const.COORDS_BY_USER, Cj, board); + res[1] = alpha; + res[2] = 0; + IS = new this.Vertex(crds, i, res[1], S, 'S', type); + IC = new this.Vertex(crds, j, res[2], C, 'C', type); + IS.neighbour = IC; + IC.neighbour = IS; + S_crossings[i].push(IS); + C_crossings[j].push(IC); + if (DEBUG) { + console.log("Degenerate case III", res[1], res[2], crds.usrCoords, "type T"); + } } continue; } + if (DEBUG) { + console.log("IS", i, j, crds.usrCoords, type); + } IS = new this.Vertex(crds, i, res[1], S, 'S', type); IC = new this.Vertex(crds, j, res[2], C, 'C', type); @@ -18793,165 +22096,303 @@ define('math/clip',[ // For both paths, sort their intersection points S_intersect = this.sortIntersections(S_crossings); -// console.log('>>>>>>') -// this._print_array(S_intersect); -//console.log(S_intersect) -// console.log('----------') + + if (DEBUG) { + console.log('>>>>>> Intersections '); + console.log("S_intersect"); + this._print_array(S_intersect); + console.log('----------'); + } for (i = 0; i < S_intersect.length; i++) { S_intersect[i].data.idx = i; S_intersect[i].neighbour.data.idx = i; } C_intersect = this.sortIntersections(C_crossings); -// this._print_array(C_intersect); -// console.log(C_intersect) -// console.log('<<<<<< Phase 1 done') + if (DEBUG) { + console.log("C_intersect"); + this._print_array(C_intersect); + console.log('<<<<<< Phase 1 done'); + } return [S_intersect, C_intersect]; }, + /** + * It is testedd if the point q lies to the left or right + * of the poylgonal chain [p1, p2, p3]. + * @param {Array} q User coords array + * @param {Array} p1 User coords array + * @param {Array} p2 User coords array + * @param {Array} p3 User coords array + * @returns string 'left' or 'right' + * @private + */ _getPosition: function(q, p1, p2, p3) { var s1 = this.det(q, p1, p2), s2 = this.det(q, p2, p3), s3 = this.det(p1, p2, p3); - if (s3 >= 0) { // Left turn or straight - if (s1 > 0 && s2 > 0) { + // Left turn + if (s3 >= 0) { + if (s1 >= 0 && s2 >= 0) { return 'left'; } return 'right'; } // Right turn - if (s1 < 0 && s2 < 0) { - return 'right'; + if (s1 >= 0 || s2 >= 0) { + return 'left'; } - return 'left'; + return 'right'; }, + /** + * Determine the delayed status of degenerated intersection points. + * It is of the form + * ['on|left|right', 'on|left|right'] + * <p> + * If all four determinants are zero, we add random noise to the point. + * + * @param {JXG.Math.Clip.Vertex} P Start of path + * @private + * @see JXG.Math.Clip#markEntryExit + * @see JXG.Math.Clip#_handleIntersectionChains + */ _classifyDegenerateIntersections: function(P) { var Pp, Pm, Qp, Qm, Q, side, - cnt; + cnt, tmp, + oppositeDir, + s1, s2, s3, s4, + DEBUG = false; + if (DEBUG) { + console.log("\n-------------- _classifyDegenerateIntersections()", (Type.exists(P.data))?P.data.pathname:' '); + } cnt = 0; + P._tours = 0; while (true) { - if (P.intersection && P.data.type === 'T') { -//console.log("P:", P.coords.usrCoords, P.data.type) + if (DEBUG) { + console.log("Inspect P:", P.coords.usrCoords, (P.data) ? P.data.type : " "); + } + if (P.intersection && (P.data.type === 'T')) { // Handle the degenerate cases // Decide if they are (delayed) bouncing or crossing intersections Pp = P._next.coords.usrCoords; // P+ Pm = P._prev.coords.usrCoords; // P- + // If the intersection point is degenerated and + // equal to the start and end of one component, + // then there will be two adjacent points with + // the same coordinate. + // In that case, we proceed to the next node. + if (Geometry.distance(P.coords.usrCoords, Pp, 3) < Mat.eps) { + Pp = P._next._next.coords.usrCoords; + } + if (Geometry.distance(P.coords.usrCoords, Pm, 3) < Mat.eps) { + Pm = P._prev._prev.coords.usrCoords; + } + Q = P.neighbour; - Qm = P.neighbour._prev.coords.usrCoords; // Q- - Qp = P.neighbour._next.coords.usrCoords; // Q+ - -// console.log("Chain 1:", Pm, P.coords.usrCoords, Pp) -// console.log("Chain 2:", Qm, P.neighbour.coords.usrCoords, Qp) -// console.log(P._next.neighbour, Q._prev) -// console.log(P._next.intersection, P._next.neighbour === Q._prev) - if (P._next.intersection && P._next.neighbour === Q._next) { - if (P._prev.intersection && P._prev.neighbour === Q._prev) { - P.delayedStatus = ['on', 'on']; - } else { - side = this._getPosition(Qm, Pm, P.coords.usrCoords, Pp); - if (side === 'right') { - P.delayedStatus = ['left', 'on']; - } else { - P.delayedStatus = ['right', 'on']; - } + Qm = Q._prev.coords.usrCoords; // Q- + Qp = Q._next.coords.usrCoords; // Q+ + if (Geometry.distance(Q.coords.usrCoords, Qp, 3) < Mat.eps) { + Qp = Q._next._next.coords.usrCoords; + } + if (Geometry.distance(Q.coords.usrCoords, Qm, 3) < Mat.eps) { + Qm = Q._prev._prev.coords.usrCoords; + } + + if (DEBUG) { + console.log("P chain:", Pm, P.coords.usrCoords, Pp); + console.log("Q chain:", Qm, P.neighbour.coords.usrCoords, Qp); + console.log("Pm", this._getPosition(Pm, Qm, Q.coords.usrCoords, Qp)); + console.log("Pp", this._getPosition(Pp, Qm, Q.coords.usrCoords, Qp)); + } + + s1 = this.det(P.coords.usrCoords, Pm, Qm); + s2 = this.det(P.coords.usrCoords, Pp, Qp); + s3 = this.det(P.coords.usrCoords, Pm, Qp); + s4 = this.det(P.coords.usrCoords, Pp, Qm); + + if (s1 === 0 && s2 === 0 && s3 === 0 && s4 === 0) { + P.coords.usrCoords[1] *= 1 + Math.random() * Mat.eps; + P.coords.usrCoords[2] *= 1 + Math.random() * Mat.eps; + Q.coords.usrCoords[1] = P.coords.usrCoords[1]; + Q.coords.usrCoords[2] = P.coords.usrCoords[2]; + s1 = this.det(P.coords.usrCoords, Pm, Qm); + s2 = this.det(P.coords.usrCoords, Pp, Qp); + s3 = this.det(P.coords.usrCoords, Pm, Qp); + s4 = this.det(P.coords.usrCoords, Pp, Qm); + if (DEBUG) { + console.log("Random shift", P.coords.usrCoords); + console.log(s1, s2, s3, s4, s2 === 0); + console.log(this._getPosition(Pm, Qm, Q.coords.usrCoords, Qp), + this._getPosition(Pp, Qm, Q.coords.usrCoords, Qp)); } - } else if (P._next.intersection && P._next.neighbour === Q._prev) { - if (P._prev.intersection && P._prev.neighbour === Q._next) { - P.delayedStatus = ['on', 'on']; - } else { - side = this._getPosition(Qp, Pm, P.coords.usrCoords, Pp); - if (side === 'right') { - P.delayedStatus = ['left', 'on']; - } else { - P.delayedStatus = ['right', 'on']; - } + } + oppositeDir = false; + if (s1 === 0) { + // Q-, Q=P, P- on straight line + if (Geometry.affineRatio(P.coords.usrCoords, Pm, Qm) < 0) { + oppositeDir = true; + } + } else if (s2 === 0) { + if (Geometry.affineRatio(P.coords.usrCoords, Pp, Qp) < 0) { + oppositeDir = true; + } + } else if (s3 === 0) { + if (Geometry.affineRatio(P.coords.usrCoords, Pm, Qp) > 0) { + oppositeDir = true; } + } else if (s4 === 0) { + if (Geometry.affineRatio(P.coords.usrCoords, Pp, Qm) > 0) { + oppositeDir = true; + } + } + if (oppositeDir) { + // Swap Qm and Qp + // Then Qm Q Qp has the same direction as Pm P Pp + tmp = Qm; Qm = Qp; Qp = tmp; + tmp = s1; s1 = s3; s3 = tmp; + tmp = s2; s2 = s4; s4 = tmp; } - if (P._prev.intersection && P._prev.neighbour === Q._prev) { - if (!(P._next.intersection && P._next.neighbour === Q._next)) { - side = this._getPosition(Qp, Pm, P.coords.usrCoords, Pp); - if (side === 'right') { - P.delayedStatus = ['on', 'left']; - } else { - P.delayedStatus = ['on', 'right']; - } - } - } else if (P._prev.intersection && P._prev.neighbour === Q._next) { - if (!(P._next.intersection && P._next.neighbour === Q._prev)) { - side = this._getPosition(Qm, Pm, P.coords.usrCoords, Pp); - if (side === 'right') { - P.delayedStatus = ['on', 'left']; + if (DEBUG) { + console.log(s1, s2, s3, s4, oppositeDir); + } + + if (!Type.exists(P.delayedStatus)) { + P.delayedStatus = []; + } + + if (s1 === 0 && s2 === 0) { + // Line [P-,P] equals [Q-,Q] and line [P,P+] equals [Q,Q+] + // Interior of delayed crossing / bouncing + P.delayedStatus = ['on', 'on']; + + } else if (s1 === 0) { + // P- on line [Q-,Q], P+ not on line [Q,Q+] + // Begin / end of delayed crossing / bouncing + side = this._getPosition(Pp, Qm, Q.coords.usrCoords, Qp); + P.delayedStatus = ['on', side]; + + } else if (s2 === 0) { + // P+ on line [Q,Q+], P- not on line [Q-,Q] + // Begin / end of delayed crossing / bouncing + side = this._getPosition(Pm, Qm, Q.coords.usrCoords, Qp); + P.delayedStatus = [side, 'on']; + + } else { + // Neither P+ on line [Q,Q+], nor P- on line [Q-,Q] + // No delayed crossing / bouncing + if (P.delayedStatus.length === 0) { + if (this._getPosition(Pm, Qm, Q.coords.usrCoords, Qp) !== this._getPosition(Pp, Qm, Q.coords.usrCoords, Qp)) { + P.data.type = 'X'; } else { - P.delayedStatus = ['on', 'right']; + P.data.type = 'B'; } } } - if ((!P._next.intersection || (P._next.neighbour !== Q._prev && P._next.neighbour !== Q._next)) && - (!P._prev.intersection || (P._prev.neighbour !== Q._prev && P._prev.neighbour !== Q._next))) { - // Neither P- nor P+ are intersections - - side = this._getPosition(Qm, Pm, P.coords.usrCoords, Pp); - if (side !== this._getPosition(Qp, Pm, P.coords.usrCoords, Pp)) { - P.data.type = 'X'; - P.data.revtype = 'X'; - } else{ - P.data.type = 'B'; - P.data.revtype = 'B'; - } -// console.log("OTHER4", P.coords.usrCoords, P.data.type); + if (DEBUG) { + console.log(">>>> P:", P.coords.usrCoords, "delayedStatus:", P.delayedStatus.toString(), (P.data) ? P.data.type : " ", "\n---"); } -//console.log("P result", P.coords.usrCoords, P.data.type, P.delayedStatus) - cnt++; } - if (P._end || cnt > 1000) { + + if (Type.exists(P._tours)) { + P._tours++; + } + + if (P._tours > 3 || P._end || cnt > 1000) { + // Jump out if either + // - we reached the end + // - there are more than 1000 intersection points + // - P._tours > 3: We went already 4 times through this path. + if (cnt > 1000) { + console.log("Clipping: _classifyDegenerateIntersections exit"); + } + if (Type.exists(P._tours)) { + delete P._tours; + } break; } + if (P.intersection) { + cnt++; + } P = P._next; } + if (DEBUG) { + console.log("------------------------"); + } }, + /** + * At this point the degenerated intersections have been classified. + * Now we decide if the intersection chains of the given path + * ultimatively cross the other path or bounce. + * + * @param {JXG.Math.Clip.Vertex} P Start of path + * + * @see JXG.Math.Clip#markEntryExit + * @see JXG.Math.Clip#_classifyDegenerateIntersections + * @private + */ _handleIntersectionChains: function(P) { var cnt = 0, start_status = 'Null', P_start, intersection_chain = false, - wait_for_exit = false; + wait_for_exit = false, + DEBUG = false; + if (DEBUG) { + console.log("\n-------------- _handleIntersectionChains()", + (Type.exists(P.data))?P.data.pathname:' '); + } while (true) { if (P.intersection === true) { - //console.log("Chain point", P.coords.usrCoords, P.data.type); + if (DEBUG) { + if (P.data.type === 'T') { + console.log("Degenerate point", P.coords.usrCoords, P.data.type, (P.data.type === 'T')?P.delayedStatus:' '); + } else { + console.log("Intersection point", P.coords.usrCoords, P.data.type); + } + } if (P.data.type === 'T') { if (P.delayedStatus[0] !== 'on' && P.delayedStatus[1] === 'on') { + // First point of intersection chain intersection_chain = true; P_start = P; start_status = P.delayedStatus[0]; - } else if (P.delayedStatus[0] === 'on' && P.delayedStatus[1] === 'on') { + + } else if (intersection_chain && + P.delayedStatus[0] === 'on' && P.delayedStatus[1] === 'on') { + // Interior of intersection chain P.data.type = 'B'; - P.data.revtype = 'B'; - } else if (P.delayedStatus[0] === 'on' && P.delayedStatus[1] !== 'on' && - intersection_chain) { + if (DEBUG) { + console.log("Interior", P.coords.usrCoords); + } + } else if (intersection_chain && + P.delayedStatus[0] === 'on' && P.delayedStatus[1] !== 'on') { + // Last point of intersection chain intersection_chain = false; if (start_status === P.delayedStatus[1]) { - P.data.type = 'B'; - P.data.revtype = 'B'; - P_start.data.type = 'B'; - P_start.data.revtype = 'B'; + // Intersection chain is delayed bouncing + P_start.data.type = 'DB'; + P.data.type = 'DB'; + if (DEBUG) { + console.log("Chain: delayed bouncing", P_start.coords.usrCoords, '...', P.coords.usrCoords); + } } else { - P.data.type = 'X'; - P.data.revtype = 'B'; - P_start.data.type = 'B'; - P_start.data.revtype = 'X'; + // Intersection chain is delayed crossing + P_start.data.type = 'DX'; + P.data.type = 'DX'; + if (DEBUG) { + console.log("Chain: delayed crossing", P_start.coords.usrCoords, '...', P.coords.usrCoords); + } } - P_start.data.link = P; - P.data.link = P_start; } } cnt++; @@ -18963,7 +22404,7 @@ define('math/clip',[ break; } if (cnt > 1000) { - console.log("Intersection chain: SAFETY EXIT!!!!"); + console.log("Warning: _handleIntersectionChains: intersection chain reached maximum numbers of iterations"); break; } P = P._next; @@ -19046,78 +22487,205 @@ define('math/clip',[ } }, + _getStatus: function(P, path) { + var status; + while (P.intersection) { + if (P._end) { + break; + } + P = P._next; + } + if (this.windingNumber(P.coords.usrCoords, path) % 2 === 0) { + // Outside + status = 'entry'; + } else { + // Inside + status = 'exit'; + } + + return [P, status]; + }, + /** * Mark the intersection vertices of path1 as entry points or as exit points * in respect to path2. - * + * <p> * This is the simple algorithm as in * Greiner, Günther; Kai Hormann (1998). "Efficient clipping of arbitrary polygons". * ACM Transactions on Graphics. 17 (2): 71–83 + * <p> + * The algorithm handles also "delayed crossings" from + * Erich, L. Foster, and Kai Hormann, Kai, and Romeo Traaian Popa (2019), + * "Clipping simple polygons with degenerate intersections", Computers & Graphics:X, 2. + * and - as an additional improvement - + * handles self intersections of delayed crossings (A.W. 2021). * * @private * @param {Array} path1 First path * @param {Array} path2 Second path */ - markEntryExit: function(path1, path2) { - var status, P, P_start, cnt; + markEntryExit: function(path1, path2, starters) { + var status, P, cnt, res, + i, len, start, + chain_start = null, + intersection_chain = 0, + DEBUG = false; - this._classifyDegenerateIntersections(path1[0]); - this._handleIntersectionChains(path1[0]); + len = starters.length; + for (i = 0; i < len; i++) { + start = starters[i]; + if (DEBUG) { + console.log("\n;;;;;;;;;; Labelling phase", + (Type.exists(path1[start].data))?path1[start].data.pathname:' ', + path1[start].coords.usrCoords); + } + this._classifyDegenerateIntersections(path1[start]); + this._handleIntersectionChains(path1[start]); + if (DEBUG) { + console.log("\n---- back to markEntryExit"); + } + + // Decide if the first point of the component is inside or outside + // of the other path. + res = this._getStatus(path1[start], path2); + P = res[0]; + status = res[1]; + if (DEBUG) { + console.log("Start node:", P.coords.usrCoords, status); + } + + P._starter = true; + + // Greiner-Hormann entry/exit algorithm + // with additional handling of delayed crossing / bouncing + cnt = 0; + chain_start = null; + intersection_chain = 0; + + while (true) { + if (P.intersection === true) { + if (P.data.type === 'X' && intersection_chain === 1) { + // While we are in an intersection chain, i.e. a delayed crossing, + // we stumble on a crossing intersection. + // Probably, the other path is self intersecting. + // We end the intersection chain here and + // mark this event by setting intersection_chain = 2. + chain_start.entry_exit = status; + if (status === 'exit') { + chain_start.data.type = 'X'; + } + intersection_chain = 2; + } - // Decide if the first point of the path is inside or outside - // of the other path. - P = path1[0]; - while (P.intersection) { - if (P._end) { - break; - } - P = P._next; - } - if (this.windingNumber(P.coords.usrCoords, path2) === 0) { - // Outside - status = 'entry'; - } else { - // Inside - status = 'exit'; - } + if (P.data.type === 'X' || P.data.type === 'DB') { + P.entry_exit = status; + status = (status === 'entry') ? 'exit' : 'entry'; + if (DEBUG) { + console.log("mark:", P.coords.usrCoords, P.data.type, P.entry_exit); + } + } - P_start = P; - // Greiner-Hormann entry/exit algorithm - cnt = 0; - while (true) { - if (P.intersection === true && P.data.type === 'X') { - P.entry_exit = status; - status = (status === 'entry') ? 'exit' : 'entry'; - if (P.data.link !== null && !P.data.link.entry_exit) { - P.data.link.entry_exit = P.entry_exit; + if (P.data.type === 'DX') { + if (intersection_chain === 0) { + // Start of intersection chain. + // No active intersection chain yet, + // i.e. we did not pass a the first node of a delayed crossing. + chain_start = P; + intersection_chain = 1; + if (DEBUG) { + console.log("Start intersection chain:", P.coords.usrCoords, P.data.type, status); + } + + } else if (intersection_chain === 1) { + // Active intersection chain (intersection_chain===1)! + // End of delayed crossing chain reached + P.entry_exit = status; + chain_start.entry_exit = status; + if (status === 'exit') { + chain_start.data.type = 'X'; + } else { + P.data.type = 'X'; + } + status = (status === 'entry') ? 'exit' : 'entry'; + + if (DEBUG) { + console.log("mark':", chain_start.coords.usrCoords, chain_start.data.type, chain_start.entry_exit); + console.log("mark:", P.coords.usrCoords, P.data.type, P.entry_exit); + } + chain_start = null; + intersection_chain = 0; + + } else if (intersection_chain === 2) { + // The delayed crossing had been interrupted by a crossing intersection. + // Now we treat the end of the delayed crossing as regular crossing. + P.entry_exit = status; + P.data.type = 'X'; + status = (status === 'entry') ? 'exit' : 'entry'; + chain_start = null; + intersection_chain = 0; + } + } } - } - if (P.intersection === true && P.data.type !== 'X') { - if (!P.entry_exit && P.data.link !== null) { - P.entry_exit = P.data.link.entry_exit; + + P = P._next; + if (Type.exists(P._starter) || cnt > 10000) { + break; } + + cnt++; } - P = P._next; - if (P === P_start || cnt > 1000) { - break; - } - cnt++; } + }, - P_start = P; - cnt = 0; - while (true) { - P = P._next; - if (P === P_start || cnt > 1000) { - break; - } - cnt++; + /** + * + * @private + * @param {Array} P + * @param {Boolean} isBackward + * @returns {Boolean} True, if the node is an intersection and is of type 'X' + */ + _stayOnPath: function(P, status) { + var stay = true; + + if (P.intersection && P.data.type !== 'B') { + stay = (status === P.entry_exit); } + return stay; }, - _isCrossing: function(P, isBackward) { - isBackward = isBackward || false; - return P.intersection && ((isBackward ? P.data.revtype : P.data.type) === 'X'); + /** + * Add a point to the clipping path and returns if the algorithms + * arrived at an intersection point which has already been visited. + * In this case, true is returned. + * + * @param {Array} path Resulting path + * @param {JXG.Math.Clip.Vertex} vertex Point to be added + * @param {Boolean} DEBUG debug output to console.log + * @returns {Boolean} true: point has been visited before, false otherwise + * @private + */ + _addVertex: function(path, vertex, DEBUG) { + if (!isNaN(vertex.coords.usrCoords[1]) && !isNaN(vertex.coords.usrCoords[2])) { + path.push(vertex); + } + if (vertex.intersection && vertex.data.done) { + if (DEBUG) { + console.log("Add last intersection point", vertex.coords.usrCoords, + "on", vertex.data.pathname, vertex.entry_exit, + vertex.data.type); + } + return true; + } + if (vertex.intersection) { + vertex.data.done = true; + + if (DEBUG) { + console.log("Add intersection point", vertex.coords.usrCoords, + "on", vertex.data.pathname, vertex.entry_exit, + vertex.data.type); + } + } + return false; }, /** @@ -19137,84 +22705,137 @@ define('math/clip',[ tracing: function(S, S_intersect, clip_type) { var P, current, start, cnt = 0, - reverse, + status, maxCnt = 10000, S_idx = 0, - path = []; + path = [], + done = false, + DEBUG = false; -// console.log("------ Start Phase 3"); + if (DEBUG) { + console.log("\n------ Start Phase 3"); + } - reverse = (clip_type === 'difference' || clip_type === 'union') ? true : false; + // reverse = (clip_type === 'difference' || clip_type === 'union') ? true : false; while (S_idx < S_intersect.length && cnt < maxCnt) { + // Take the first intersection node of the subject path + // which is not yet included as start point. current = S_intersect[S_idx]; - if (current.data.done || !this._isCrossing(current, reverse)) { + if (current.data.done || current.data.type !== 'X' /*|| !this._isCrossing(current, reverse)*/) { S_idx++; continue; } -// console.log("Start", current.data.pathname, current.coords.usrCoords, current.data.type, current.data.revtype, current.entry_exit, S_idx); + if (DEBUG) { + console.log("\nStart", current.data.pathname, current.coords.usrCoords, current.data.type, current.entry_exit, S_idx); + } if (path.length > 0) { // Add a new path path.push([NaN, NaN]); } + // Start now the tracing with that node of the subject path start = current.data.idx; P = S; - do { - // Add the "current" intersection vertex - path.push(current); -// console.log("Add intersection", current.coords.usrCoords); - current.data.done = true; -// console.log("AT", current.data.pathname, current.entry_exit, current.coords.usrCoords, current.data.type, current.data.revtype); + done = this._addVertex(path, current, DEBUG); + status = current.entry_exit; + do { + if (done) { + break; + } + // + // Decide if we follow the current path forward or backward. + // for example, in case the clipping is of type "intersection" + // and the current intersection node is of type entry, we go forward. + // if ((clip_type === 'intersection' && current.entry_exit === 'entry') || (clip_type === 'union' && current.entry_exit === 'exit') || (clip_type === 'difference' && (P === S) === (current.entry_exit === 'exit')) ) { - current = current._next; - do { - cnt++; - - path.push(current); -// console.log("Add fw", current.coords.usrCoords); + if (DEBUG) { + console.log("Go forward on", current.data.pathname, current.entry_exit); + } - if (!this._isCrossing(current, reverse)) { // In case there are two adjacent intersects - current = current._next; + // + // Take the next nodes and add them to the path + // as long as they are not intersection nodes of type 'X'. + // + do { + current = current._next; + done = this._addVertex(path, current, DEBUG); + if (done) { + break; } - } while (!this._isCrossing(current, reverse) && cnt < maxCnt); + } while (this._stayOnPath(current, status)); + cnt++; } else { - current = current._prev; + if (DEBUG) { + console.log("Go backward on", current.data.pathname); + } + // + // Here, we go backward: + // Take the previous nodes and add them to the path + // as long as they are not intersection nodes of type 'X'. + // do { - cnt++; - - path.push(current); -// console.log("Add bw", current.coords.usrCoords); - - if (!this._isCrossing(current, true)) { // In case there are two adjacent intersects - current = current._prev; -//console.log("goto", current.coords.usrCoords) + current = current._prev; + done = this._addVertex(path, current, DEBUG); + if (done) { + break; } - } while (!this._isCrossing(current, true) && cnt < maxCnt); + } while (this._stayOnPath(current, status)); + cnt++; + } + + if (done) { + break; } - current.data.done = true; if (!current.neighbour) { - console.log("BREAK!!!!!!!!!!!!!!!!!", cnt); + console.log("Tracing: emergency break - no neighbour!!!!!!!!!!!!!!!!!", cnt); return [[0], [0]]; } - -// console.log("Switch", current.coords.usrCoords, current.data.pathname, "to", current.neighbour.data.pathname); + // + // We stopped the forward or backward loop, because we've + // arrived at a crossing intersection node, i.e. we have to + // switch to the other path now. + if (DEBUG) { + console.log("Switch from", current.coords.usrCoords, current.data.pathname, "to", + current.neighbour.coords.usrCoords, "on", current.neighbour.data.pathname); + } current = current.neighbour; if (current.data.done) { - path.push(current); break; } + current.data.done = true; + status = current.entry_exit; + + // if (current.data.done) { + // // We arrived at an intersection node which is already + // // added to the clipping path. + // // We add it again to close the clipping path and jump out of the + // // loop. + // path.push(current); + // if (DEBUG) { + // console.log("Push last", current.coords.usrCoords); + // } + // break; + // } P = current.data.path; - } while (!(current.data.pathname === 'S' && current.data.idx === start) && cnt < maxCnt); + // Polygon closed: + // if (DEBUG) { + // console.log("End of loop:", "start=", start, "idx=", current.data.idx); + // } + // } while (!(current.data.pathname === 'S' && current.data.idx === start) && cnt < maxCnt); + } while (current.data.idx !== start && cnt < maxCnt); + + if (cnt >= maxCnt) { + console.log("Tracing: stopping an infinite loop!", cnt); + } S_idx++; } - return this._getCoordsArrays(path, false); }, @@ -19224,50 +22845,17 @@ define('math/clip',[ * @param {Array} S First path, array of JXG.Coords * @param {Array} C Second path, array of JXG.Coords * @param {String} clip_type Type of Boolean operation: 'intersection', 'union', 'differrence'. - * @param {Array} pathX Array of x-coordinates of the resulting path - * @param {Array} pathY Array of y-coordinates of the resulting path * @return {Boolean} true, if one of the input paths is empty, false otherwise. */ - isEmptyCase: function(S, C, clip_type, pathX, pathY) { - // var i; - + isEmptyCase: function(S, C, clip_type) { if (clip_type === 'intersection' && (S.length === 0 || C.length === 0)) { - return true; //[pathX, pathY]; + return true; } - if (clip_type === 'union' && (S.length === 0 || C.length === 0)) { - // if (S.length === 0) { - // for (i = 0; i < C.length; ++i) { - // pathX.push(C[i].coords.usrCoords[1]); - // pathY.push(C[i].coords.usrCoords[2]); - // } - // if (C.length > 0) { - // pathX.push(C[0].coords.usrCoords[1]); - // pathY.push(C[0].coords.usrCoords[2]); - // } - // } else { - // for (i = 0; i < S.length; ++i) { - // pathX.push(S[i].coords.usrCoords[1]); - // pathY.push(S[i].coords.usrCoords[2]); - // } - // if (S.length > 0) { - // pathX.push(S[0].coords.usrCoords[1]); - // pathY.push(S[0].coords.usrCoords[2]); - // } - // } - return true; //[pathX, pathY]; + if (clip_type === 'union' && (S.length === 0 && C.length === 0)) { + return true; } - if (clip_type === 'difference' && (S.length === 0 || C.length === 0)) { - // if (C.length === 0) { - // for (i = 0; i < S.length; ++i) { - // pathX.push(S[i].coords.usrCoords[1]); - // pathY.push(S[i].coords.usrCoords[2]); - // } - // if (S.length > 0) { - // pathX.push(S[0].coords.usrCoords[1]); - // pathY.push(S[0].coords.usrCoords[2]); - // } - // } - return true; //[pathX, pathY]; + if (clip_type === 'difference' && S.length === 0) { + return true; } return false; @@ -19297,11 +22885,6 @@ define('math/clip',[ } } - // le = pathX.length; - // for (i = 0; i < le; i++) { - // console.log(pathX[i], pathY[i]); - // } - return [pathX, pathY]; }, @@ -19342,22 +22925,11 @@ define('math/clip',[ return this._getCoordsArrays(path, true); } - // From now on, both paths have non-zero length - // - // Handle union - if (clip_type === 'union') { - path = path.concat(S); - path.push(S[0]); - path.push([NaN, NaN]); - path = path.concat(C); - path.push(C[0]); - return this._getCoordsArrays(path, false); - } - + // From now on, both paths have non-zero length. // The two paths have no crossing intersections, - // but there might be bounicng intersections. + // but there might be bouncing intersections. - // First, we find - if possible - on each path a point which is not an intersection point. + // First, we find -- if possible -- on each path a point which is not an intersection point. if (S.length > 0) { P = S[0]; while (P.intersection) { @@ -19379,12 +22951,15 @@ define('math/clip',[ // Test if one curve is contained by the other if (this.windingNumber(P.coords.usrCoords, C) === 0) { - // S is outside of C. + // P is outside of C: + // Either S is disjoint from C or C is inside of S if (this.windingNumber(Q.coords.usrCoords, S) !== 0) { // C is inside of S, i.e. C subset of S - if (clip_type === 'difference') { - + if (clip_type === 'union') { + path = path.concat(S); + path.push(S[0]); + } else if (clip_type === 'difference') { path = path.concat(S); path.push(S[0]); if (Geometry.signedPolygon(S) * Geometry.signedPolygon(C) > 0) { @@ -19393,13 +22968,21 @@ define('math/clip',[ } path.push([NaN, NaN]); } - path = path.concat(C); - path.push(C[0]); - doClose = false; + if (clip_type === 'difference' || clip_type === 'intersection') { + path = path.concat(C); + path.push(C[0]); + doClose = false; + } } else { // The curves are disjoint if (clip_type === 'difference') { path = path.concat(S); doClose = true; + } else if (clip_type === 'union') { + path = path.concat(S); + path.push(S[0]); + path.push([NaN, NaN]); + path = path.concat(C); + path.push(C[0]); } } } else { @@ -19407,13 +22990,23 @@ define('math/clip',[ if (clip_type === 'intersection') { path = path.concat(S); doClose = true; + } else if (clip_type === 'union') { + path = path.concat(C); + path.push(C[0]); } + // 'difference': path is empty } return this._getCoordsArrays(path, doClose); }, + /** + * Count intersection points of type 'X'. + * @param {JXG.Mat.Clip.Vertex} intersections + * @returns Number + * @private + */ _countCrossingIntersections: function(intersections) { var i, le = intersections.length, @@ -19427,6 +23020,86 @@ define('math/clip',[ return sum; }, + /** + * Create path from all sorts of input elements and convert it + * to a suitable input path for greinerHormann(). + * + * @private + * @param {Object} obj Maybe curve, arc, sector, circle, polygon, array of points, array of JXG.Coords, + * array of coordinate pairs. + * @param {JXG.Board} board JSXGraph board object. It is needed to convert between + * user coordinates and screen coordinates. + * @returns {Array} Array of JXG.Coords elements containing a path. + * @see JXG.Math.Clip#greinerHormann + */ + _getPath: function(obj, board) { + var i, len, r, rad, angle, alpha, + steps, + S = []; + + // Collect all points into path array S + if (obj.elementClass === Const.OBJECT_CLASS_CURVE && + (obj.type === Const.OBJECT_TYPE_ARC || obj.type === Const.OBJECT_TYPE_SECTOR)) { + angle = Geometry.rad(obj.radiuspoint, obj.center, obj.anglepoint); + steps = Math.floor(angle * 180 / Math.PI); + r = obj.Radius(); + rad = angle / steps; + alpha = Math.atan2(obj.radiuspoint.coords.usrCoords[2] - obj.center.coords.usrCoords[2], + obj.radiuspoint.coords.usrCoords[1] - obj.center.coords.usrCoords[1]); + + if (obj.type === Const.OBJECT_TYPE_SECTOR) { + this._addToList(S, obj.center.coords, 0); + } + for (i = 0; i <= steps; i++) { + this._addToList(S, new Coords(Const.COORDS_BY_USER, [ + obj.center.coords.usrCoords[0], + obj.center.coords.usrCoords[1] + Math.cos(i * rad + alpha) * r, + obj.center.coords.usrCoords[2] + Math.sin(i * rad + alpha) * r + ], board), i + 1); + } + if (obj.type === Const.OBJECT_TYPE_SECTOR) { + this._addToList(S, obj.center.coords, steps + 2); + } + + } else if (obj.elementClass === Const.OBJECT_CLASS_CURVE && Type.exists(obj.points)) { + len = obj.numberPoints; + for (i = 0; i < len; i++) { + this._addToList(S, obj.points[i], i); + } + } else if (obj.type === Const.OBJECT_TYPE_POLYGON) { + for (i = 0; i < obj.vertices.length; i++) { + this._addToList(S, obj.vertices[i].coords, i); + } + } else if (obj.elementClass === Const.OBJECT_CLASS_CIRCLE) { + steps = 359; + r = obj.Radius(); + rad = 2 * Math.PI / steps; + for (i = 0; i <= steps; i++) { + this._addToList(S, new Coords(Const.COORDS_BY_USER, [ + obj.center.coords.usrCoords[0], + obj.center.coords.usrCoords[1] + Math.cos(i * rad) * r, + obj.center.coords.usrCoords[2] + Math.sin(i * rad) * r + ], board), i); + } + } else if (Type.isArray(obj)) { + len = obj.length; + for (i = 0; i < len; i++) { + if (Type.exists(obj[i].coords)) { + // Point type + this._addToList(S, obj[i].coords, i); + } else if (Type.isArray(obj[i])) { + // Coordinate pair + this._addToList(S, new Coords(Const.COORDS_BY_USER, obj[i], board), i); + } else if (Type.exists(obj[i].usrCoords)) { + // JXG.Coordinates + this._addToList(S, obj[i], i); + } + } + } + + return S; + }, + /** * Determine the intersection, union or difference of two closed paths. * <p> @@ -19450,7 +23123,11 @@ define('math/clip',[ * </ul> * * @param {JXG.Circle|JXG.Curve|JXG.Polygon} subject First closed path, usually called 'subject'. + * Maybe curve, arc, sector, circle, polygon, array of points, array of JXG.Coords, + * array of coordinate pairs. * @param {JXG.Circle|JXG.Curve|JXG.Polygon} clip Second closed path, usually called 'clip'. + * Maybe curve, arc, sector, circle, polygon, array of points, array of JXG.Coords, + * array of coordinate pairs. * @param {String} clip_type Determines the type of boolean operation on the two paths. * Possible values are 'intersection', 'union', or 'difference'. * @param {JXG.Board} board JSXGraph board object. It is needed to convert between @@ -19627,12 +23304,12 @@ define('math/clip',[ * [bbox[2], bbox[1]], // ur * [bbox[0], bbox[1]]] // ul * triangle = [[-1,1], [1,1], [0,-1], [-1,1]]; - * + * * var a = JXG.Math.Clip.greinerHormann(canvas, triangle, 'difference', this.board); * this.dataX = a[0]; * this.dataY = a[1]; * }; - * + * * </pre><div id="JXGe94da07a-2a01-4498-ad62-f71a327f8e25" class="jxgbox" style="width: 300px; height: 300px;"></div> * <script type="text/javascript"> * (function() { @@ -19649,169 +23326,85 @@ define('math/clip',[ * [bbox[2], bbox[1]], // ur * [bbox[0], bbox[1]]] // ul * triangle = [[-1,1], [1,1], [0,-1], [-1,1]]; - * + * * var a = JXG.Math.Clip.greinerHormann(canvas, triangle, 'difference', this.board); * this.dataX = a[0]; * this.dataY = a[1]; * }; - * + * * })(); - * + * * </script><pre> - * + * */ greinerHormann: function(subject, clip, clip_type, board) { //}, // subject_first_point_type, clip_first_point_type) { - var i, r, rad, len, - steps = 359, - S = [], + var len, S = [], C = [], S_intersect = [], // C_intersect = [], + S_starters, + C_starters, res = [], - pathX = [], - pathY = []; + DEBUG = false; - // Collect all points into subject array S - if (subject.elementClass === Const.OBJECT_CLASS_CURVE && Type.exists(subject.points)) { - len = subject.points.length; - for (i = 0; i < len; i++) { - this._addToList(S, subject.points[i], i); - } - } else if (subject.type === Const.OBJECT_TYPE_POLYGON) { - for (i = 0; i < subject.vertices.length; i++) { - this._addToList(S, subject.vertices[i].coords, i); - } - } else if (subject.elementClass === Const.OBJECT_CLASS_CIRCLE) { - r = subject.Radius(); - rad = 2 * Math.PI / steps; - for (i = 0; i <= steps; i++) { - this._addToList(S, new Coords(Const.COORDS_BY_USER, [ - subject.center.coords.usrCoords[0], - subject.center.coords.usrCoords[1] + Math.cos(i * rad) * r, - subject.center.coords.usrCoords[2] + Math.sin(i * rad) * r - ], board), i); - } - } else if (Type.isArray(subject)) { - len = subject.length; - for (i = 0; i < len; i++) { - if (Type.exists(subject[i].coords)) { - // Point type - this._addToList(S, subject[i].coords, i); - } else if (Type.isArray(subject[i])) { - // Coordinate pair - this._addToList(S, new Coords(Const.COORDS_BY_USER, subject[i], board), i); - } else if (Type.exists(subject[i].usrCoords)) { - // JXG.Coordinates - this._addToList(S, subject[i], i); - } - } + if (DEBUG) { + console.log("\n------------ GREINER-HORMANN --------------"); } + // Collect all subject points into subject array S + S = this._getPath(subject, board); len = S.length; if (len > 0 && Geometry.distance(S[0].coords.usrCoords, S[len - 1].coords.usrCoords, 3) < Mat.eps) { S.pop(); } // Collect all points into clip array C - if (clip.elementClass === Const.OBJECT_CLASS_CURVE && Type.exists(clip.points)) { - len = clip.points.length; - for (i = 0; i < len; i++) { - this._addToList(C, clip.points[i], i); - } - } else if (clip.type === Const.OBJECT_TYPE_POLYGON) { - for (i = 0; i < clip.vertices.length; i++) { - this._addToList(C, clip.vertices[i].coords, i); - } - } else if (clip.elementClass === Const.OBJECT_CLASS_CIRCLE) { - r = clip.Radius(); - rad = 2 * Math.PI / steps; - for (i = 0; i <= steps; i++) { - this._addToList(C, new Coords(Const.COORDS_BY_USER, [ - clip.center.coords.usrCoords[0], - clip.center.coords.usrCoords[1] + Math.cos(i * rad) * r, - clip.center.coords.usrCoords[2] + Math.sin(i * rad) * r - ], board), i); - } - } else if (Type.isArray(clip)) { - len = clip.length; - for (i = 0; i < len; i++) { - if (Type.exists(clip[i].coords)) { - // Point type - this._addToList(C, clip[i].coords, i); - } else if (Type.isArray(clip[i])) { - // Coordinate pair - this._addToList(C, new Coords(Const.COORDS_BY_USER, clip[i], board), i); - } else if (Type.exists(clip[i].usrCoords)) { - // JXG.Coordinates - this._addToList(C, clip[i], i); - } - } - } - + C = this._getPath(clip, board); len = C.length; if (len > 0 && Geometry.distance(C[0].coords.usrCoords, C[len - 1].coords.usrCoords, 3) < Mat.eps * Mat.eps) { C.pop(); } // Handle cases where at least one of the paths is empty - if (this.isEmptyCase(S, C, clip_type, pathX, pathY)) { - return [pathX, pathY]; + if (this.isEmptyCase(S, C, clip_type)) { + return [[], []]; } // Add pointers for doubly linked lists - this.makeDoublyLinkedList(S); - this.makeDoublyLinkedList(C); + S_starters = this.makeDoublyLinkedList(S); + C_starters = this.makeDoublyLinkedList(C); + + if (DEBUG) { + this._print_array(S); + console.log("Components:", S_starters); + this._print_array(C); + console.log("Components:", C_starters); + } res = this.findIntersections(S, C, board); S_intersect = res[0]; - // C_intersect = res[1]; - - // For non-closed paths - // if (true && typeof subject_first_point_type === 'string') { - // S[0].neighbour = C[C.length - 1]; - // S[0].first_point_type = subject_first_point_type; - // S[S.length - 1].neighbour = C[0]; - // S[S.length - 1].first_point_type = subject_first_point_type; - // } - // if (true && typeof clip_first_point_type === 'string') { - // C[0].neighbour = S[S.length - 1]; - // C[0].first_point_type = clip_first_point_type; - // C[C.length - 1].neighbour = S[0]; - // C[C.length - 1].first_point_type = clip_first_point_type; - // } this._handleFullyDegenerateCase(S, C, board); // Phase 2: mark intersection points as entry or exit points - this.markEntryExit(S, C); + this.markEntryExit(S, C, S_starters); + // if (S[0].coords.distance(Const.COORDS_BY_USER, C[0].coords) === 0) { // // Randomly disturb the first point of the second path // // if both paths start at the same point. // C[0].usrCoords[1] *= 1 + Math.random() * 0.0001 - 0.00005; // C[0].usrCoords[2] *= 1 + Math.random() * 0.0001 - 0.00005; // } - this.markEntryExit(C, S); + this.markEntryExit(C, S, C_starters); // Handle cases without intersections if (this._countCrossingIntersections(S_intersect) === 0) { return this.handleEmptyIntersection(S, C, clip_type); } - // if (false) { - // for (i = 0; i < S_intersect.length; i++) { - // console.log('S', S_intersect[i].cnt, S_intersect[i].entry_exit, S_intersect[i].usrCoords, - // S_intersect[i].pos, S_intersect[i].alpha); - // } - // console.log(); - // for (i = 0; i < C_intersect.length; i++) { - // console.log('C', C_intersect[i].cnt, C_intersect[i].entry_exit, C_intersect[i].usrCoords, - // C_intersect[i].pos, C_intersect[i].alpha); - // } - // } // Phase 3: tracing return this.tracing(S, S_intersect, clip_type); - }, /** @@ -20026,7 +23619,7 @@ define('math/clip',[ difference: function(path1, path2, board) { return this.greinerHormann(path1, path2, 'difference', board); } - }; + }; //); JXG.extend(Mat.Clip, /** @lends JXG.Math.Clip */ { }); @@ -20035,7 +23628,7 @@ define('math/clip',[ }); /* - Copyright 2008-2021 + Copyright 2008-2022 Matthias Ehmann, Michael Gerhaeuser, Carsten Miller, @@ -20347,325 +23940,325 @@ define('math/poly',['jxg', 'math/math', 'utils/type'], function (JXG, Mat, Type) return Mat.Poly; }); -/* - Copyright 2008-2021 - Matthias Ehmann, - Michael Gerhaeuser, - Carsten Miller, - Bianca Valentin, - Alfred Wassermann, - Peter Wilfahrt - - This file is part of JSXGraph. - - JSXGraph is free software dual licensed under the GNU LGPL or MIT License. - - You can redistribute it and/or modify it under the terms of the - - * GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version - OR - * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT - - JSXGraph is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License and - the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> - and <http://opensource.org/licenses/MIT/>. - */ - - -/*global JXG: true, define: true*/ -/*jslint nomen: true, plusplus: true*/ - -/* depends: - jxg - */ - -/** - * @fileoverview A class for complex arithmetics JXG.Complex is defined in this - * file. Also a namespace JXG.C is included to provide instance-independent - * arithmetic functions. - */ - -define('math/complex',['jxg', 'utils/type'], function (JXG, Type) { - - "use strict"; - - /** - * Creates a new complex number. - * @class This class is for calculating with complex numbers. - * @constructor - * @param {Number} [x=0] Real part. - * @param {Number} [y=0] Imaginary part. - */ - JXG.Complex = function (x, y) { - /** - * This property is only to signalize that this object is of type JXG.Complex. Only - * used internally to distinguish between normal JavaScript numbers and JXG.Complex numbers. - * @type Boolean - * @default true - * @private - */ - this.isComplex = true; - - /* is the first argument a complex number? if it is, - * extract real and imaginary part. */ - if (x && x.isComplex) { - y = x.imaginary; - x = x.real; - } - - /** - * Real part of the complex number. - * @type Number - * @default 0 - */ - this.real = x || 0; - - /** - * Imaginary part of the complex number. - * @type Number - * @default 0 - */ - this.imaginary = y || 0; - - /** - * Absolute value in the polar form of the complex number. Currently unused. - * @type Number - */ - this.absval = 0; - - /** - * Angle value in the polar form of the complex number. Currently unused. - * @type Number - */ - this.angle = 0; - }; - - JXG.extend(JXG.Complex.prototype, /** @lends JXG.Complex.prototype */ { - /** - * Converts a complex number into a string. - * @returns {String} Formatted string containing the complex number in human readable form (algebraic form). - */ - toString: function () { - return this.real + ' + ' + this.imaginary + 'i'; - }, - - /** - * Add another complex number to this complex number. - * @param {JXG.Complex,Number} c A JavaScript number or a JXG.Complex object to be added to the current object. - * @returns {JXG.Complex} Reference to this complex number - */ - add: function (c) { - if (Type.isNumber(c)) { - this.real += c; - } else { - this.real += c.real; - this.imaginary += c.imaginary; - } - - return this; - }, - - /** - * Subtract another complex number from this complex number. - * @param {JXG.Complex,Number} c A JavaScript number or a JXG.Complex object to subtract from the current object. - * @returns {JXG.Complex} Reference to this complex number - */ - sub: function (c) { - if (Type.isNumber(c)) { - this.real -= c; - } else { - this.real -= c.real; - this.imaginary -= c.imaginary; - } - - return this; - }, - - /** - * Multiply another complex number to this complex number. - * @param {JXG.Complex,Number} c A JavaScript number or a JXG.Complex object to - * multiply with the current object. - * @returns {JXG.Complex} Reference to this complex number - */ - mult: function (c) { - var re, im; - - if (Type.isNumber(c)) { - this.real *= c; - this.imaginary *= c; - } else { - re = this.real; - im = this.imaginary; - - // (a+ib)(x+iy) = ax-by + i(xb+ay) - this.real = re * c.real - im * c.imaginary; - this.imaginary = re * c.imaginary + im * c.real; - } - - return this; - }, - - /** - * Divide this complex number by the given complex number. - * @param {JXG.Complex,Number} c A JavaScript number or a JXG.Complex object to - * divide the current object by. - * @returns {JXG.Complex} Reference to this complex number - */ - div: function (c) { - var denom, im, re; - - if (Type.isNumber(c)) { - if (Math.abs(c) < Math.eps) { - this.real = Infinity; - this.imaginary = Infinity; - - return this; - } - - this.real /= c; - this.imaginary /= c; - } else { - // (a+ib)(x+iy) = ax-by + i(xb+ay) - if ((Math.abs(c.real) < Math.eps) && (Math.abs(c.imaginary) < Math.eps)) { - this.real = Infinity; - this.imaginary = Infinity; - - return this; - } - - denom = c.real * c.real + c.imaginary * c.imaginary; - - re = this.real; - im = this.imaginary; - this.real = (re * c.real + im * c.imaginary) / denom; - this.imaginary = (im * c.real - re * c.imaginary) / denom; - } - - return this; - }, - - /** - * Conjugate a complex number in place. - * @returns {JXG.Complex} Reference to this complex number - */ - conj: function () { - this.imaginary *= -1; - - return this; - } - }); - - /** - * @description - * JXG.C is the complex number (name)space. It provides functions to calculate with - * complex numbers (defined in {@link JXG.Complex}). With this namespace you don't have to modify - * your existing complex numbers, e.g. to add two complex numbers: - * <pre class="code"> var z1 = new JXG.Complex(1, 0); - * var z2 = new JXG.Complex(0, 1); - * z = JXG.C.add(z1, z1);</pre> - * z1 and z2 here remain unmodified. With the object oriented approach above this - * section the code would look like: - * <pre class="code"> var z1 = new JXG.Complex(1, 0); - * var z2 = new JXG.Complex(0, 1); - * var z = new JXG.Complex(z1); - * z.add(z2);</pre> - * @namespace Namespace for the complex number arithmetic functions. - */ - JXG.C = {}; - - /** - * Add two (complex) numbers z1 and z2 and return the result as a (complex) number. - * @param {JXG.Complex,Number} z1 Summand - * @param {JXG.Complex,Number} z2 Summand - * @returns {JXG.Complex} A complex number equal to the sum of the given parameters. - */ - JXG.C.add = function (z1, z2) { - var z = new JXG.Complex(z1); - z.add(z2); - return z; - }; - - /** - * Subtract two (complex) numbers z1 and z2 and return the result as a (complex) number. - * @param {JXG.Complex,Number} z1 Minuend - * @param {JXG.Complex,Number} z2 Subtrahend - * @returns {JXG.Complex} A complex number equal to the difference of the given parameters. - */ - JXG.C.sub = function (z1, z2) { - var z = new JXG.Complex(z1); - z.sub(z2); - return z; - }; - - /** - * Multiply two (complex) numbers z1 and z2 and return the result as a (complex) number. - * @param {JXG.Complex,Number} z1 Factor - * @param {JXG.Complex,Number} z2 Factor - * @returns {JXG.Complex} A complex number equal to the product of the given parameters. - */ - JXG.C.mult = function (z1, z2) { - var z = new JXG.Complex(z1); - z.mult(z2); - return z; - }; - - /** - * Divide two (complex) numbers z1 and z2 and return the result as a (complex) number. - * @param {JXG.Complex,Number} z1 Dividend - * @param {JXG.Complex,Number} z2 Divisor - * @returns {JXG.Complex} A complex number equal to the quotient of the given parameters. - */ - JXG.C.div = function (z1, z2) { - var z = new JXG.Complex(z1); - z.div(z2); - return z; - }; - - /** - * Conjugate a complex number and return the result. - * @param {JXG.Complex,Number} z1 Complex number - * @returns {JXG.Complex} A complex number equal to the conjugate of the given parameter. - */ - JXG.C.conj = function (z1) { - var z = new JXG.Complex(z1); - z.conj(); - return z; - }; - - /** - * Absolute value of a complex number. - * @param {JXG.Complex,Number} z1 Complex number - * @returns {Number} real number equal to the absolute value of the given parameter. - */ - JXG.C.abs = function (z1) { - var z = new JXG.Complex(z1); - - z.conj(); - z.mult(z1); - - return Math.sqrt(z.real); - }; - - JXG.Complex.C = JXG.C; - - return JXG.Complex; -}); +/* + Copyright 2008-2022 + Matthias Ehmann, + Michael Gerhaeuser, + Carsten Miller, + Bianca Valentin, + Alfred Wassermann, + Peter Wilfahrt + + This file is part of JSXGraph. + + JSXGraph is free software dual licensed under the GNU LGPL or MIT License. + + You can redistribute it and/or modify it under the terms of the + + * GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version + OR + * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT + + JSXGraph is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License and + the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> + and <http://opensource.org/licenses/MIT/>. + */ + + +/*global JXG: true, define: true*/ +/*jslint nomen: true, plusplus: true*/ + +/* depends: + jxg + */ + +/** + * @fileoverview A class for complex arithmetics JXG.Complex is defined in this + * file. Also a namespace JXG.C is included to provide instance-independent + * arithmetic functions. + */ + +define('math/complex',['jxg', 'utils/type'], function (JXG, Type) { + + "use strict"; + + /** + * Creates a new complex number. + * @class This class is for calculating with complex numbers. + * @constructor + * @param {Number} [x=0] Real part. + * @param {Number} [y=0] Imaginary part. + */ + JXG.Complex = function (x, y) { + /** + * This property is only to signalize that this object is of type JXG.Complex. Only + * used internally to distinguish between normal JavaScript numbers and JXG.Complex numbers. + * @type Boolean + * @default true + * @private + */ + this.isComplex = true; + + /* is the first argument a complex number? if it is, + * extract real and imaginary part. */ + if (x && x.isComplex) { + y = x.imaginary; + x = x.real; + } + + /** + * Real part of the complex number. + * @type Number + * @default 0 + */ + this.real = x || 0; + + /** + * Imaginary part of the complex number. + * @type Number + * @default 0 + */ + this.imaginary = y || 0; + + /** + * Absolute value in the polar form of the complex number. Currently unused. + * @type Number + */ + this.absval = 0; + + /** + * Angle value in the polar form of the complex number. Currently unused. + * @type Number + */ + this.angle = 0; + }; + + JXG.extend(JXG.Complex.prototype, /** @lends JXG.Complex.prototype */ { + /** + * Converts a complex number into a string. + * @returns {String} Formatted string containing the complex number in human readable form (algebraic form). + */ + toString: function () { + return this.real + ' + ' + this.imaginary + 'i'; + }, + + /** + * Add another complex number to this complex number. + * @param {JXG.Complex,Number} c A JavaScript number or a JXG.Complex object to be added to the current object. + * @returns {JXG.Complex} Reference to this complex number + */ + add: function (c) { + if (Type.isNumber(c)) { + this.real += c; + } else { + this.real += c.real; + this.imaginary += c.imaginary; + } + + return this; + }, + + /** + * Subtract another complex number from this complex number. + * @param {JXG.Complex,Number} c A JavaScript number or a JXG.Complex object to subtract from the current object. + * @returns {JXG.Complex} Reference to this complex number + */ + sub: function (c) { + if (Type.isNumber(c)) { + this.real -= c; + } else { + this.real -= c.real; + this.imaginary -= c.imaginary; + } + + return this; + }, + + /** + * Multiply another complex number to this complex number. + * @param {JXG.Complex,Number} c A JavaScript number or a JXG.Complex object to + * multiply with the current object. + * @returns {JXG.Complex} Reference to this complex number + */ + mult: function (c) { + var re, im; + + if (Type.isNumber(c)) { + this.real *= c; + this.imaginary *= c; + } else { + re = this.real; + im = this.imaginary; + + // (a+ib)(x+iy) = ax-by + i(xb+ay) + this.real = re * c.real - im * c.imaginary; + this.imaginary = re * c.imaginary + im * c.real; + } + + return this; + }, + + /** + * Divide this complex number by the given complex number. + * @param {JXG.Complex,Number} c A JavaScript number or a JXG.Complex object to + * divide the current object by. + * @returns {JXG.Complex} Reference to this complex number + */ + div: function (c) { + var denom, im, re; + + if (Type.isNumber(c)) { + if (Math.abs(c) < Math.eps) { + this.real = Infinity; + this.imaginary = Infinity; + + return this; + } + + this.real /= c; + this.imaginary /= c; + } else { + // (a+ib)(x+iy) = ax-by + i(xb+ay) + if ((Math.abs(c.real) < Math.eps) && (Math.abs(c.imaginary) < Math.eps)) { + this.real = Infinity; + this.imaginary = Infinity; + + return this; + } + + denom = c.real * c.real + c.imaginary * c.imaginary; + + re = this.real; + im = this.imaginary; + this.real = (re * c.real + im * c.imaginary) / denom; + this.imaginary = (im * c.real - re * c.imaginary) / denom; + } + + return this; + }, + + /** + * Conjugate a complex number in place. + * @returns {JXG.Complex} Reference to this complex number + */ + conj: function () { + this.imaginary *= -1; + + return this; + } + }); + + /** + * @description + * JXG.C is the complex number (name)space. It provides functions to calculate with + * complex numbers (defined in {@link JXG.Complex}). With this namespace you don't have to modify + * your existing complex numbers, e.g. to add two complex numbers: + * <pre class="code"> var z1 = new JXG.Complex(1, 0); + * var z2 = new JXG.Complex(0, 1); + * z = JXG.C.add(z1, z1);</pre> + * z1 and z2 here remain unmodified. With the object oriented approach above this + * section the code would look like: + * <pre class="code"> var z1 = new JXG.Complex(1, 0); + * var z2 = new JXG.Complex(0, 1); + * var z = new JXG.Complex(z1); + * z.add(z2);</pre> + * @namespace Namespace for the complex number arithmetic functions. + */ + JXG.C = {}; + + /** + * Add two (complex) numbers z1 and z2 and return the result as a (complex) number. + * @param {JXG.Complex,Number} z1 Summand + * @param {JXG.Complex,Number} z2 Summand + * @returns {JXG.Complex} A complex number equal to the sum of the given parameters. + */ + JXG.C.add = function (z1, z2) { + var z = new JXG.Complex(z1); + z.add(z2); + return z; + }; + + /** + * Subtract two (complex) numbers z1 and z2 and return the result as a (complex) number. + * @param {JXG.Complex,Number} z1 Minuend + * @param {JXG.Complex,Number} z2 Subtrahend + * @returns {JXG.Complex} A complex number equal to the difference of the given parameters. + */ + JXG.C.sub = function (z1, z2) { + var z = new JXG.Complex(z1); + z.sub(z2); + return z; + }; + + /** + * Multiply two (complex) numbers z1 and z2 and return the result as a (complex) number. + * @param {JXG.Complex,Number} z1 Factor + * @param {JXG.Complex,Number} z2 Factor + * @returns {JXG.Complex} A complex number equal to the product of the given parameters. + */ + JXG.C.mult = function (z1, z2) { + var z = new JXG.Complex(z1); + z.mult(z2); + return z; + }; + + /** + * Divide two (complex) numbers z1 and z2 and return the result as a (complex) number. + * @param {JXG.Complex,Number} z1 Dividend + * @param {JXG.Complex,Number} z2 Divisor + * @returns {JXG.Complex} A complex number equal to the quotient of the given parameters. + */ + JXG.C.div = function (z1, z2) { + var z = new JXG.Complex(z1); + z.div(z2); + return z; + }; + + /** + * Conjugate a complex number and return the result. + * @param {JXG.Complex,Number} z1 Complex number + * @returns {JXG.Complex} A complex number equal to the conjugate of the given parameter. + */ + JXG.C.conj = function (z1) { + var z = new JXG.Complex(z1); + z.conj(); + return z; + }; + + /** + * Absolute value of a complex number. + * @param {JXG.Complex,Number} z1 Complex number + * @returns {Number} real number equal to the absolute value of the given parameter. + */ + JXG.C.abs = function (z1) { + var z = new JXG.Complex(z1); + + z.conj(); + z.mult(z1); + + return Math.sqrt(z.real); + }; + + JXG.Complex.C = JXG.C; + + return JXG.Complex; +}); /* - Copyright 2008-2021 + Copyright 2008-2022 Matthias Ehmann, Michael Gerhaeuser, Carsten Miller, Bianca Valentin, - Alfred Wassermann, Andreas Walter, + Alfred Wassermann, Peter Wilfahrt This file is part of JSXGraph. @@ -20705,7 +24298,8 @@ define('math/complex',['jxg', 'utils/type'], function (JXG, Type) { * Stoyan Stefanov <sstoo@gmail.com> (see http://www.phpied.com/rgb-color-parser-in-javascript/) */ -define('utils/color',['jxg', 'utils/type', 'math/math'], function (JXG, Type, Mat) { +define('utils/color',['jxg', 'utils/type', 'math/math'], + function (JXG, Type, Mat) { "use strict"; @@ -20858,9 +24452,10 @@ define('utils/color',['jxg', 'utils/type', 'math/math'], function (JXG, Type, Ma yellow: 'ffff00', yellowgreen: '9acd32' }, + // array of color definition objects colorDefs = [{ - re: /^\s*rgba\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*([\d\.]{1,3})\s*\)\s*$/, + re: /^\s*rgba\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*([\d.]{1,3})\s*\)\s*$/, example: ['rgba(123, 234, 45, 0.5)', 'rgba(255,234,245,1.0)'], process: function (bits) { return [ @@ -21532,11 +25127,153 @@ define('utils/color',['jxg', 'utils/type', 'math/math'], function (JXG, Type, Ma return lightColor; }; + /** + * Use the color scheme of JSXGraph up to version 1.3.2. + * This method has to be called before JXG.JSXGraph.initBoard(); + * + * @see JXG.palette + * @see JXG.paletteWong + * + * @example + * + * JXG.setClassicColors(); + * var board = JXG.JSXGraph.initBoard('jxgbox', {boundingbox: [-5, 5, 5,-5]}); + * + */ + JXG.setClassicColors = function() { + JXG.Options.elements.strokeColor = 'blue'; + JXG.Options.elements.fillColor = 'red'; + JXG.Options.hatch.strokeColor = 'blue'; + JXG.Options.angle.fillColor = '#ff7f00'; + JXG.Options.angle.highlightFillColor = '#ff7f00'; + JXG.Options.angle.strokeColor = '#ff7f00'; + JXG.Options.angle.label.strokeColor = 'blue'; + JXG.Options.arc.strokeColor = 'blue'; + JXG.Options.circle.center.fillColor = 'red'; + JXG.Options.circle.center.strokeColor = 'blue'; + JXG.Options.circumcircle.strokeColor = 'blue'; + JXG.Options.circumcircle.center.fillColor = 'red'; + JXG.Options.circumcircle.center.strokeColor = 'blue'; + JXG.Options.circumcirclearc.strokeColor = 'blue'; + JXG.Options.circumcirclesector.strokeColor = 'blue'; + JXG.Options.circumcirclesector.fillColor = 'green'; + JXG.Options.circumcirclesector.highlightFillColor = 'green'; + JXG.Options.conic.strokeColor = 'blue'; + JXG.Options.curve.strokeColor = 'blue'; + JXG.Options.incircle.strokeColor = 'blue'; + JXG.Options.incircle.center.fillColor = 'red'; + JXG.Options.incircle.center.strokeColor = 'blue'; + JXG.Options.inequality.fillColor = 'red'; + JXG.Options.integral.fillColor = 'red'; + JXG.Options.integral.curveLeft.color = 'red'; + JXG.Options.integral.curveRight.color = 'red'; + JXG.Options.line.strokeColor = 'blue'; + JXG.Options.point.fillColor = 'red'; + JXG.Options.point.strokeColor = 'red'; + JXG.Options.polygon.fillColor = 'green'; + JXG.Options.polygon.highlightFillColor = 'green'; + JXG.Options.polygon.vertices.strokeColor = 'red'; + JXG.Options.polygon.vertices.fillColor = 'red'; + JXG.Options.regularpolygon.fillColor = 'green'; + JXG.Options.regularpolygon.highlightFillColor = 'green'; + JXG.Options.regularpolygon.vertices.strokeColor = 'red'; + JXG.Options.regularpolygon.vertices.fillColor = 'red'; + JXG.Options.riemannsum.fillColor = 'yellow'; + JXG.Options.sector.fillColor = 'green'; + JXG.Options.sector.highlightFillColor = 'green'; + JXG.Options.semicircle.center.fillColor = 'red'; + JXG.Options.semicircle.center.strokeColor = 'blue'; + JXG.Options.slopetriangle.fillColor = 'red'; + JXG.Options.slopetriangle.highlightFillColor = 'red'; + JXG.Options.turtle.arrow.strokeColor = 'blue'; + }; + + JXG.extend(JXG, /** @lends JXG */ { + /** + * Bang Wong color palette, + * optimized for various type + * of color blindness. + * It contains values for + * <ul> + * <li> 'black' + * <li> 'orange' + * <li> 'skyblue' + * <li> 'bluishgreen' + * <li> 'yellow' + * <li> 'darkblue' + * <li> 'vermillion' + * <li> 'reddishpurple' + * </ul> + * + * As substitutes for standard colors, it contains the following aliases: + * + * <ul> + * <li> black (= #000000) + * <li> blue (= darkblue) + * <li> green (= bluishgreen) + * <li> purple (= reddishpurple) + * <li> red (= vermillion) + * <li> white (= #ffffff) + * </ul> + * + * See <a href="https://www.nature.com/articles/nmeth.1618">Bang Wong: "Points of view: Color blindness"</a> + * and + * <a href="https://davidmathlogic.com/colorblind/">https://davidmathlogic.com/colorblind/</a>. + * + * @name JXG.paletteWong + * @type Object + * @see JXG.palette + * @example + * var p = board.create('line', [[-1, 1], [2, -3]], {strokeColor: JXG.paletteWong.yellow}); + */ + paletteWong: { + black: '#000000', + orange: '#E69F00', + skyblue: '#56B4E9', + bluishgreen: '#009E73', + yellow: '#F0E442', + darkblue: '#0072B2', + vermillion: '#D55E00', + reddishpurple: '#CC79A7', + + blue: '#0072B2', + red: '#D55E00', // vermillion + green: '#009E73', // bluishgreen + purple: '#CC79A7', // reddishpurple + white: '#ffffff' + } + }); + + /** + * Default color palette. + * Contains at least color values for + * <ul> + * <li> black + * <li> blue + * <li> green + * <li> purple + * <li> red + * <li> white + * <li> yellow + * </ul> + * + * @name JXG.palette + * @type Object + * @default JXG.paletteWong + * @see JXG.paletteWong + * + * @example + * + * var p = board.create('line', [[-1, 1], [2, -3]], {strokeColor: JXG.palette.yellow}); + * + */ + JXG.palette = JXG.paletteWong; + return JXG; }); /* - Copyright 2008-2021 + Copyright 2008-2022 Matthias Ehmann, Michael Gerhaeuser, Carsten Miller, @@ -21750,7 +25487,7 @@ define('options',[ * axis:true in {@link JXG.JSXGraph#initBoard}. * * @name JXG.Board#defaultAxes - * @type {Object} + * @type Object * @default {x: {name:'x'}, y: {name: 'y'}} * */ @@ -21828,7 +25565,7 @@ define('options',[ * Attributes to control the screenshot function. * The following attributes can be set: * <ul> - * <li>scale: scaling factor (default=0) + * <li>scale: scaling factor (default=1.0) * <li>type: format of the screenshot image. Default: png * <li>symbol: Unicode symbol which is shown in the navigation bar. Default: '\u2318' * <li>css: CSS rules to format the div element containing the screen shot image @@ -21836,7 +25573,7 @@ define('options',[ * </ul> * * @name JXG.Board#screenshot - * @type {Object} + * @type Object */ screenshot: { scale: 1.0, @@ -21861,7 +25598,9 @@ define('options',[ * controls if the icon is shown. * The following attribute(s) can be set: * <ul> - * <li>symbol: Unicode symbol which is shown in the navigation bar. Default: '\u25a1' + * <li>symbol (String): Unicode symbol which is shown in the navigation bar. Default: '\u25a1' + * <li>id (String): Id of the HTML element which is brought to full screen or null if the JSXgraph div is taken. + * It may be an outer div element, e.g. if the old aspect ratio trick is used. Default: null, i.e. use the JSXGraph div. * </ul> * * @example @@ -21892,10 +25631,11 @@ define('options',[ * * @name JXG.Board#fullscreen * @see JXG.Board#showFullscreen - * @type {Object} + * @type Object */ fullscreen: { - symbol: '\u26f6' //'\u25a1' + symbol: '\u25a1', // '\u26f6' (not supported by MacOS), // '\u25a1' + id: null }, /** @@ -22027,7 +25767,10 @@ define('options',[ /** * Change redraw strategy in SVG rendering engine. - * + * <p> + * This optimization seems to be <b>obsolete</b> in newer browsers (from 2021 on, at least) + * and even slow down the constructions. Therefore, the default is set to 'none' since v1.2.4. + * <p> * If set to 'svg', before every redrawing of the JSXGraph construction * the SVG sub-tree of the DOM tree is taken out of the DOM. * @@ -22038,11 +25781,12 @@ define('options',[ * Using 'svg' or 'all' speeds up the update process considerably. The risk * is that if there is an exception, only a white div or window is left. * + * * @name JXG.Board#minimizeReflow * @type String - * @default 'svg' + * @default 'none' */ - minimizeReflow: 'svg', + minimizeReflow: 'none', /** * A number that will be added to the absolute position of the board used in mouse coordinate @@ -22076,13 +25820,13 @@ define('options',[ * factorY: 1.25, // vertical zoom factor (multiplied to {@link JXG.Board#zoomY}) * wheel: true, // allow zooming by mouse wheel or * // by pinch-to-toom gesture on touch devices - * needShift: true, // mouse wheel zooming needs pressing of the shift key - * min: 0.001 // minimal values of {@link JXG.Board#zoomX} and {@link JXG.Board#zoomY}, limits zoomOut - * max: 1000.0 // maximal values of {@link JXG.Board#zoomX} and {@link JXG.Board#zoomY}, limits zoomIn + * needShift: true, // mouse wheel zooming needs pressing of the shift key + * min: 0.001, // minimal values of {@link JXG.Board#zoomX} and {@link JXG.Board#zoomY}, limits zoomOut + * max: 1000.0, // maximal values of {@link JXG.Board#zoomX} and {@link JXG.Board#zoomY}, limits zoomIn * - * pinchHorizontal: true // Allow pinch-to-zoom to zoom only horizontal axis - * pinchVertical: true // Allow pinch-to-zoom to zoom only vertical axis - * pinchSensitivity: 7 // Sensitivity (in degrees) for recognizing horizontal or vertical pinch-to-zoom gestures. + * pinchHorizontal: true, // Allow pinch-to-zoom to zoom only horizontal axis + * pinchVertical: true, // Allow pinch-to-zoom to zoom only vertical axis + * pinchSensitivity: 7 // Sensitivity (in degrees) for recognizing horizontal or vertical pinch-to-zoom gestures. * } * </pre> * @@ -22144,6 +25888,154 @@ define('options',[ enabled: true }, + /** + * Control using the keyboard to change the construction. + * <ul> + * <li> enabled: true / false + * <li> dx: horizontal shift amount per key press + * <li> dy: vertical shift amount per key press + * <li> panShift: zoom if shift key is pressed + * <li> panCtrl: zoom if ctrl key is pressed + * </ul> + * + * @example + * var board = JXG.JSXGraph.initBoard("jxgbox", {boundingbox: [-5,5,5,-5], + * axis: true, + * showCopyright:true, + * showNavigation:true, + * keyboard: { + * enabled: true, + * dy: 30, + * panShift: true, + * panCtrl: false + * } + * }); + * + * </pre><div id="JXGb1d3aab6-ced2-4fe9-8fa5-b0accc8c7266" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXGb1d3aab6-ced2-4fe9-8fa5-b0accc8c7266', + * {boundingbox: [-5,5,5,-5], + * axis: true, + * showCopyright:true, + * showNavigation:true, + * keyboard: { + * enabled: true, + * dy: 30, + * panShift: true, + * panCtrl: false + * } + * }); + * + * })(); + * + * </script><pre> + * + * + * @see JXG.Board#keyDownListener + * @see JXG.Board#keyFocusInListener + * @see JXG.Board#keyFocusOutListener + * + * @name JXG.Board#keyboard + * @type Object + * @default {enabled: true, dx: 10, dy:10, panShift: true, panCtrl: false} + */ + keyboard: { + enabled: true, + dx: 10, + dy: 10, + panShift: true, + panCtrl: false + }, + + /** + * Control if JSXGraph reacts to resizing of the JSXGraph container element + * by the user / browser. + * The attribute "throttle" determines the minimal time in msec between to + * resize calls. + * + * @see JXG.Board#startResizeObserver + * @see JXG.Board#resizeListener + * + * @name JXG.Board#resize + * @type Object + * @default {enabled: true, throttle: 10} + * + * @example + * var board = JXG.JSXGraph.initBoard('jxgbox', { + * boundingbox: [-5,5,5,-5], + * keepAspectRatio: true, + * axis: true, + * resize: {enabled: true, throttle: 200} + * }); + * + * </pre><div id="JXGb55d4608-5d71-4bc3-b332-18c15fbda8c3" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXGb55d4608-5d71-4bc3-b332-18c15fbda8c3', { + * boundingbox: [-5,5,5,-5], + * keepAspectRatio: true, + * axis: true, + * resize: {enabled: true, throttle: 200} + * }); + * + * })(); + * + * </script><pre> + * + * + */ + resize: { + enabled: true, + throttle: 10 + }, + + /** + * Element which listens to move events of the pointing device. + * This allows to drag elements of a JSXGraph construction outside of the board. + * Especially, on mobile devices this enhances the user experience. + * However, it is recommended to allow dragging outside of the JSXGraph board only + * in certain constructions where users may not "loose" points outside of the board. + * Then points may become unreachable. + * <p> + * A situation where dragging outside of the board is uncritical is for example if + * only sliders are used to interact with the construction. + * <p> + * Possible values for this attributes are: + * <ul> + * <li> an element specified by document.getElementById('some id'); + * <li> null: to use the JSXgraph container div element + * <li> document + * </ul> + * + * @name JXG.Board#moveTarget + * @type HTML node or document + * @default null + * + * @example + * var board = JXG.JSXGraph.initBoard('jxgbox', { + * boundingbox: [-5,5,5,-5], + * axis: true, + * moveTarget: document + * }); + * + * </pre><div id="JXG973457e5-c63f-4516-8570-743f2cc560e1" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG973457e5-c63f-4516-8570-743f2cc560e1', + * {boundingbox: [-5,5,5,-5], + * axis: true, + * moveTarget: document + * }); + * + * })(); + * + * </script><pre> + * + * + */ + moveTarget: null, + /** * Control the possibilities for a selection rectangle. * Starting a selection event triggers the "startselecting" event. @@ -22165,6 +26057,10 @@ define('options',[ * visible: false // Initial visibility. Should be set to false always * } * </pre> + * <p> + * Board events triggered by selection manipulation: + * 'startselecting', 'stopselecting', 'mousestartselecting', 'mousestopselecting', + * 'pointerstartselecting', 'pointerstopselecting', 'touchstartselecting', 'touchstopselecting'. * * @example * board.on('stopselecting', function(){ @@ -22178,14 +26074,10 @@ define('options',[ * }); * * @name JXG.Board#selection - * @see JXG.Board#startselecting - * @see JXG.Board#stopselecting - * @see JXG.Board#mousestartselecting - * @see JXG.Board#pointerstartselecting - * @see JXG.Board#touchstartselecting - * @see JXG.Board#mousestopselecting - * @see JXG.Board#pointerstopselecting - * @see JXG.Board#touchstopselecting + * + * @see JXG.Board#startSelectionMode + * @see JXG.Board#stopSelectionMode + * * @type Object * @default */ @@ -22238,7 +26130,7 @@ define('options',[ * </pre> * These settings are overruled by the CSS class 'JXG_navigation'. * @deprecated - * @type {Object} + * @type Object * @name JXG.Options#navbar * */ @@ -22277,7 +26169,7 @@ define('options',[ * @see JXG.GeometryElement#highlightStrokeOpacity * @default {@link JXG.Options.elements.color#strokeColor} */ - strokeColor: '#0000ff', + strokeColor: Color.palette.blue, /** * The stroke color of the given geometry element when the user moves the mouse over it. @@ -22289,7 +26181,7 @@ define('options',[ * @see JXG.GeometryElement#highlightStrokeOpacity * @default {@link JXG.Options.elements.color#highlightStrokeColor} */ - highlightStrokeColor: '#C3D9FF', + highlightStrokeColor: '#c3d9ff', /** * The fill color of this geometry element. @@ -22300,7 +26192,7 @@ define('options',[ * @see JXG.GeometryElement#highlightFillOpacity * @default {@link JXG.Options.elements.color#fillColor} */ - fillColor: 'red', + fillColor: Color.palette.red, /** * The fill color of the given geometry element when the mouse is pointed over it. @@ -22832,7 +26724,7 @@ define('options',[ * This attributes takes either the value 'inherit' or an object of the form: * <pre> * precision: { - * touch: 15, + * touch: 30, * mouse: 4, * pen: 4 * } @@ -22868,7 +26760,24 @@ define('options',[ * @private * By default, an element is not a label. Do not change this. */ - isLabel: false + isLabel: false, + + /** + * Controls if an element can get the focus with the tab key. + * See <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex">descriptiona at MDN</a>. + * The additional value null completely disables focus of an element. + * The value will be ignored if keyboard control of the board is not enabled or + * the element is fixed or not visible. + * + * @name JXG.GeometryElement#tabindex + * @type Number + * @default 0 + * @see JXG.Board#keyboard + * @see JXG.GeometryElement#fixed + * @see JXG.GeometryElement#visible + */ + tabindex: 0 + // close the meta tag /**#@-*/ }, @@ -22913,7 +26822,7 @@ define('options',[ * Attributes for the ticks labels * * @name Ticks#label - * @type {Object} + * @type Object * @default {} * */ @@ -22949,7 +26858,7 @@ define('options',[ * (function() { * var board = JXG.JSXGraph.initBoard('JXGc1e46cd1-e025-4002-80aa-b450869fdaa2', { * boundingbox: [-500000, 500000, 500000, -500000], - * showcopyright: false, shownavigation: false + * showcopyright: false, shownavigation: false, * axis: true, * defaultAxes: { * x: { @@ -22966,9 +26875,9 @@ define('options',[ * } * }, * }); - * + * * })(); - * + * * </script><pre> * * @name Ticks#beautifulScientificTickLabels @@ -23135,14 +27044,28 @@ define('options',[ /** * If a label exceeds {@link Ticks#maxLabelLength} this determines the precision used to shorten the tick label. + * Replaced by the digits attribute. * * @type Number * @name Ticks#precision * @see Ticks#maxLabelLength + * @see Ticks#digits + * @deprecated * @default 3 */ precision: 3, + /** + * If a label exceeds {@link Ticks#maxLabelLength} this determines the number of digits used to shorten the tick label. + * + * @type Number + * @name Ticks#digits + * @see Ticks#maxLabelLength + * @deprecated + * @default 3 + */ + digits: 3, + /** * The default distance between two ticks. Please be aware that this value does not have * to be used if {@link Ticks#insertTicks} is set to true. @@ -23158,7 +27081,7 @@ define('options',[ * Tick face for ticks of finite length. By default (face: '|') this is a straight line. * Possible other values are '<' and '>'. These faces are used in * {@link JXG.Hatch} for hatch marking parallel lines. - * @type {String} + * @type String * @name{Ticks#face} * @see hatch * @default '|' @@ -23187,7 +27110,7 @@ define('options',[ strokeOpacity: 1, strokeWidth: 1, - strokeColor: 'black', + strokeColor: '#000000', highlightStrokeColor: '#888888', fillColor: 'none', highlightFillColor: 'none', @@ -23227,7 +27150,7 @@ define('options',[ anchor: 'middle', face: '|', strokeWidth: 2, - strokeColor: 'blue', + strokeColor: Color.palette.blue, ticksDistance: 0.2 }, @@ -23249,12 +27172,12 @@ define('options',[ * } * </pre> * - * @type {Object} + * @type Object * @name JXG.Options#precision * @see JXG.GeometryElement#precision */ precision: { - touch: 15, + touch: 30, touchMax: 100, mouse: 4, pen: 4, @@ -23289,7 +27212,7 @@ define('options',[ * trace: 0 * } * </pre> - * @type {Object} + * @type Object * @name JXG.Options#layer */ layer: { @@ -23333,13 +27256,16 @@ define('options',[ /** * Radius of the sector, displaying the angle. + * The radius can be given as number (in user coordinates) + * or as string 'auto'. In the latter case, the angle + * is set to an value between 20 and 50 px. * - * @type Number + * @type {Number|String} * @name Angle#radius - * @default 0.5 + * @default 'auto' * @visprop */ - radius: 0.5, + radius: 'auto', /** * Display type of the angle field. Possible values are @@ -23377,9 +27303,13 @@ define('options',[ */ orthoSensitivity: 1.0, - fillColor: '#FF7F00', - highlightFillColor: '#FF7F00', - strokeColor: '#FF7F00', + fillColor: Color.palette.orange, + highlightFillColor: Color.palette.orange, + strokeColor: Color.palette.orange, + // fillColor: '#ff7f00', + // highlightFillColor: '#ff7f00', + // strokeColor: '#ff7f00', + fillOpacity: 0.3, highlightFillOpacity: 0.3, @@ -23404,7 +27334,7 @@ define('options',[ dot: { visible: false, strokeColor: 'none', - fillColor: 'black', + fillColor: '#000000', size: 2, face: 'o', withLabel: false, @@ -23414,7 +27344,7 @@ define('options',[ label: { position: 'top', offset: [0, 0], - strokeColor: '#0000FF' + strokeColor: Color.palette.blue }, /** @@ -23466,8 +27396,8 @@ define('options',[ lastArrow: false, fillColor: 'none', highlightFillColor: 'none', - strokeColor: '#0000ff', - highlightStrokeColor: '#C3D9FF', + strokeColor: Color.palette.blue, + highlightStrokeColor: '#c3d9ff', useDirection: false, /** @@ -23500,7 +27430,7 @@ define('options',[ /**#@-*/ }, - /* special arc options */ + /* special arrow options */ arrow: { /**#@+ * @visprop @@ -23607,6 +27537,8 @@ define('options',[ visible: false }, + tabindex: -1, + /** * Attributes for the axis label. * @@ -23657,7 +27589,7 @@ define('options',[ * @name Bisectorlines#line1 */ line1: { // - strokeColor: 'black' + strokeColor: '#000000' }, /** @@ -23667,12 +27599,48 @@ define('options',[ * @name Bisectorlines#line2 */ line2: { // - strokeColor: 'black' + strokeColor: '#000000' } /**#@-*/ }, + /* special options for boxplot curves */ + boxplot: { + /**#@+ + * @visprop + */ + + /** + * Direction of the box plot: 'vertical' or 'horizontal' + * + * @type String + * @name Boxplot#dir + * @default: 'vertical' + */ + dir: 'vertical', + + /** + * Relative width of the maximum and minimum quantile + * + * @type Number + * @name Boxplot#smallWidth + * @default: 0.5 + */ + smallWidth: 0.5, + + strokeWidth: 2, + strokeColor: Color.palette.blue, + fillColor: Color.palette.blue, + fillOpacity: 0.2, + highlightStrokeWidth: 2, + highlightStrokeColor: Color.palette.blue, + highlightFillColor: Color.palette.blue, + highlightFillOpacity: 0.1 + + /**#@-*/ + }, + /* special button options */ button: { /**#@+ @@ -23724,7 +27692,7 @@ define('options',[ * * @name isArrayOfCoordinates * @memberOf Cardinalspline.prototype - * @type {Boolean} + * @type Boolean * @default false */ isArrayOfCoordinates: false, @@ -23759,7 +27727,7 @@ define('options',[ */ chartStyle: 'line', - colors: ['#B02B2C', '#3F4C6B', '#C79810', '#D15600', '#FFFF88', '#C3D9FF', '#4096EE', '#008C00'], + colors: ['#B02B2C', '#3F4C6B', '#C79810', '#D15600', '#FFFF88', '#c3d9ff', '#4096EE', '#008C00'], highlightcolors: null, fillcolor: null, highlightonsector: false, @@ -23824,8 +27792,8 @@ define('options',[ fillColor: 'none', highlightFillColor: 'none', - strokeColor: '#0000ff', - highlightStrokeColor: '#C3D9FF', + strokeColor: Color.palette.blue, + highlightStrokeColor: '#c3d9ff', /** * Attributes for center point. @@ -23837,6 +27805,25 @@ define('options',[ visible: false, withLabel: false, fixed: false, + + fillColor: Color.palette.red, + strokeColor: Color.palette.red, + highlightFillColor: '#c3d9ff', + highlightStrokeColor: '#c3d9ff', + + name: '' + }, + + /** + * Attributes for center point. + * + * @type Point + * @name Circle#center + */ + point2: { + visible: false, + withLabel: false, + fixed: false, name: '' }, @@ -23860,8 +27847,8 @@ define('options',[ fillColor: 'none', highlightFillColor: 'none', - strokeColor: '#0000ff', - highlightStrokeColor: '#C3D9FF', + strokeColor: Color.palette.blue, + highlightStrokeColor: '#c3d9ff', /** * Attributes for center point. @@ -23873,6 +27860,10 @@ define('options',[ visible: false, fixed: false, withLabel: false, + fillColor: Color.palette.red, + strokeColor: Color.palette.red, + highlightFillColor: '#c3d9ff', + highlightStrokeColor: '#c3d9ff', name: '' } /**#@-*/ @@ -23885,8 +27876,8 @@ define('options',[ fillColor: 'none', highlightFillColor: 'none', - strokeColor: '#0000ff', - highlightStrokeColor: '#C3D9FF', + strokeColor: Color.palette.blue, + highlightStrokeColor: '#c3d9ff', /** * Attributes for center point. @@ -23910,12 +27901,12 @@ define('options',[ */ useDirection: true, - fillColor: '#00FF00', - highlightFillColor: '#00FF00', + fillColor: Color.palette.yellow, + highlightFillColor: Color.palette.yellow, fillOpacity: 0.3, highlightFillOpacity: 0.3, - strokeColor: '#0000ff', - highlightStrokeColor: '#C3D9FF', + strokeColor: Color.palette.blue, + highlightStrokeColor: '#c3d9ff', /** * Attributes for center point. @@ -23940,8 +27931,8 @@ define('options',[ fillColor: 'none', highlightFillColor: 'none', - strokeColor: '#0000ff', - highlightStrokeColor: '#C3D9FF', + strokeColor: Color.palette.blue, + highlightStrokeColor: '#c3d9ff', /** * Attributes for foci points. @@ -23981,7 +27972,7 @@ define('options',[ }, /** - * Attributes for parabola line incase the line is given by two + * Attributes for parabola line in case the line is given by two * points or coordinate pairs. * * @type Line @@ -23997,7 +27988,7 @@ define('options',[ /* special curve options */ curve: { strokeWidth: 1, - strokeColor: '#0000ff', + strokeColor: Color.palette.blue, fillColor: 'none', fixed: true, @@ -24138,7 +28129,42 @@ define('options',[ */ label: { position: 'lft' - } + }, + + /** + * Configure arrow head at the start position for curve. + * Recommended arrow head type is 7. + * + * @name Curve#firstArrow + * @type Boolean / Object + * @default false + * @see Line#firstArrow for options + */ + firstArrow: false, + + /** + * Configure arrow head at the end position for curve. + * Recommended arrow head type is 7. + * + * @name Curve#lastArrow + * @see Line#lastArrow for options + * @type Boolean / Object + * @default false + */ + lastArrow: false + + /**#@-*/ + }, + + /* special foreignObject options */ + foreignobject: { + + /**#@+ + * @visprop + */ + attractors: [], + fixed: true, + visible: true /**#@-*/ }, @@ -24163,8 +28189,8 @@ define('options',[ hasGrid: false, gridX: 1, gridY: 1, - //strokeColor: '#C0C0C0', - strokeColor: '#C0C0C0', + //strokeColor: '#c0c0c0', + strokeColor: '#c0c0c0', strokeOpacity: 0.5, strokeWidth: 1, dash: 0, // dashed grids slow down the iPad considerably @@ -24207,7 +28233,7 @@ define('options',[ frozen: true, isLabel: false, - strokeColor: 'black', + strokeColor: '#000000', display: 'html', anchorX: 'left', anchorY: 'middle', @@ -24266,7 +28292,8 @@ define('options',[ /** * Defines together with {@link Image#snapSizeY} the grid the image snaps on to. - * The image will only snap on integer multiples to snapSizeX in x and snapSizeY in y direction. + * The image will only snap on user coordinates which are + * integer multiples to snapSizeX in x and snapSizeY in y direction. * If this value is equal to or less than <tt>0</tt>, it will use the grid displayed by the major ticks * of the default ticks of the default x axes of the board. * @@ -24318,8 +28345,8 @@ define('options',[ fillColor: 'none', highlightFillColor: 'none', - strokeColor: '#0000ff', - highlightStrokeColor: '#C3D9FF', + strokeColor: Color.palette.blue, + highlightStrokeColor: '#c3d9ff', /** * Attributes of circle center. @@ -24331,6 +28358,10 @@ define('options',[ visible: false, fixed: false, withLabel: false, + fillColor: Color.palette.red, + strokeColor: Color.palette.red, + highlightFillColor: '#c3d9ff', + highlightStrokeColor: '#c3d9ff', name: '' } /**#@-*/ @@ -24341,7 +28372,7 @@ define('options',[ * @visprop */ - fillColor: 'red', + fillColor: Color.palette.red, fillOpacity: 0.2, strokeColor: 'none', @@ -24393,9 +28424,9 @@ define('options',[ fixed: true, strokeWidth: 0, strokeOpacity: 0, - fillColor: 'red', - fillOpacity: 0.4, - highlightFillColor: 'red', + fillColor: Color.palette.red, + fillOpacity: 0.3, + highlightFillColor: Color.palette.red, highlightFillOpacity: 0.2, /** @@ -24408,7 +28439,7 @@ define('options',[ curveLeft: { // Start point visible: true, withLabel: false, - color: 'red', + color: Color.palette.red, fillOpacity: 0.8, layer: 9 }, @@ -24437,7 +28468,7 @@ define('options',[ curveRight: { // End point visible: true, withLabel: false, - color: 'red', + color: Color.palette.red, fillOpacity: 0.8, layer: 9 }, @@ -24529,10 +28560,10 @@ define('options',[ */ visible: 'inherit', - strokeColor: 'black', + strokeColor: '#000000', strokeOpacity: 1, highlightStrokeOpacity: 0.666666, - highlightStrokeColor: 'black', + highlightStrokeColor: '#000000', fixed: true, @@ -24580,7 +28611,7 @@ define('options',[ * * @name Label#autoPosition * @see Label#offset - * @type {Boolean} + * @type Boolean * @default false * * @example @@ -24642,9 +28673,9 @@ define('options',[ * (Circular) array of label colors. * @name: Legend#colors * @type Array - * @default "['#B02B2C', '#3F4C6B', '#C79810', '#D15600', '#FFFF88', '#C3D9FF', '#4096EE', '#008C00']" + * @default "['#B02B2C', '#3F4C6B', '#C79810', '#D15600', '#FFFF88', '#c3d9ff', '#4096EE', '#008C00']" */ - colors: ['#B02B2C', '#3F4C6B', '#C79810', '#D15600', '#FFFF88', '#C3D9FF', '#4096EE', '#008C00'], + colors: ['#B02B2C', '#3F4C6B', '#C79810', '#D15600', '#FFFF88', '#c3d9ff', '#4096EE', '#008C00'], /** * Height (in px) of one legend entry @@ -24667,18 +28698,20 @@ define('options',[ */ /** - * Line has an arrow head at the position of its first point or the corresponding + * Configure the arrow head at the position of its first point or the corresponding * intersection with the canvas border * * In case firstArrow is an object it has the sub-attributes: * <pre> * { - * type: 1, // possible values are 1, 2, ..., 6 - * size: 3, // size of the arrow head. + * type: 1, // possible values are 1, 2, ..., 7. Default value is 1. + * size: 6, // size of the arrow head. Default value is 6. * // This value is multiplied with the strokeWidth of the line - * highlightSize: 3, // size of the arrow head in case the element is highlighted + * // Exception: for type=7 size is ignored + * highlightSize: 6, // size of the arrow head in case the element is highlighted. Default value * } * </pre> + * type=7 is the default for curves if firstArrow: true * * @name Line#firstArrow * @see Line#lastArrow @@ -24689,18 +28722,20 @@ define('options',[ firstArrow: false, /** - * Line has an arrow head at the position of its second point or the corresponding + * Configute the arrow head at the position of its second point or the corresponding * intersection with the canvas border. * - * In case firstArrow is an object it has the sub-attributes: + * In case lastArrow is an object it has the sub-attributes: * <pre> * { - * type: 1, // possible values are 1, 2, ..., 6 - * size: 3, // size of the arrow head. - * // This value is multiplied with the strokeWidth of the line - * highlightSize: 3, // size of the arrow head in case the element is highlighted + * type: 1, // possible values are 1, 2, ..., 7. Default value is 1. + * size: 6, // size of the arrow head. Default value is 6. + * // This value is multiplied with the strokeWidth of the line. + * // Exception: for type=7 size is ignored + * highlightSize: 6, // size of the arrow head in case the element is highlighted. Default value is 6. * } * </pre> + * type=7 is the default for curves if lastArrow: true * * @example * var p1 = board.create('point', [-5, 2], {size:1}); @@ -24780,8 +28815,8 @@ define('options',[ fillColor: 'none', // Important for VML on IE highlightFillColor: 'none', // Important for VML on IE - strokeColor: '#0000ff', - highlightStrokeColor: '#888888', + strokeColor: Color.palette.blue, + highlightStrokeColor: '#c3d9ff', withTicks: false, /** @@ -24916,7 +28951,7 @@ define('options',[ * Not available for VML renderer. * [lineCap description] * @name Line#lineCap - * @type {String} + * @type String * @default 'butt' */ lineCap: 'butt' @@ -24968,7 +29003,7 @@ define('options',[ * * @name isArrayOfCoordinates * @memberOf Metapostspline.prototype - * @type {Boolean} + * @type Boolean * @default false */ isArrayOfCoordinates: false, @@ -25209,11 +29244,22 @@ define('options',[ */ sizeUnit: 'screen', - fillColor: '#ff0000', - highlightFillColor: '#EEEEEE', strokeWidth: 2, - strokeColor: '#ff0000', - highlightStrokeColor: '#C3D9FF', + + fillColor: Color.palette.red, + strokeColor: Color.palette.red, + highlightFillColor:'#c3d9ff', + highlightStrokeColor: '#c3d9ff', + // strokeOpacity: 1.0, + // fillOpacity: 1.0, + // highlightFillOpacity: 0.5, + // highlightStrokeOpacity: 0.5, + + // fillColor: '#ff0000', + // highlightFillColor: '#eeeeee', + // strokeWidth: 2, + // strokeColor: '#ff0000', + // highlightStrokeColor: '#c3d9ff', /** * If true, the point size changes on zoom events. @@ -25269,7 +29315,7 @@ define('options',[ /** * Unit for attractorDistance and snatchDistance, used for magnetized points and for snapToPoints. - * Possible values are 'screen' and 'user. + * Possible values are 'screen' and 'user'. * * @name Point#attractorUnit * @@ -25309,8 +29355,12 @@ define('options',[ snatchDistance: 0.0, /** - * If set to true, the point will snap to a grid defined by - * {@link Point#snapSizeX} and {@link Point#snapSizeY}. + * If set to true, the point will snap to a grid of integer multiples of + * {@link Point#snapSizeX} and {@link Point#snapSizeY} (in user coordinates). + * <p> + * The coordinates of the grid points are either integer multiples of snapSizeX and snapSizeY + * (given in user coordinates, not pixels) or are the intersection points + * of the major ticks of the boards default axes in case that snapSizeX, snapSizeY are negative. * * @name Point#snapToGrid * @@ -25321,8 +29371,44 @@ define('options',[ */ snapToGrid: false, + /** + * If set to true, the point will only snap to (possibly invisibly) grid points + * when within {@link Point#attractorDistance} of such a grid point. + * <p> + * The coordinates of the grid points are either integer multiples of snapSizeX and snapSizeY + * (given in user coordinates, not pixels) or are the intersection points + * of the major ticks of the boards default axes in case that snapSizeX, snapSizeY are negative. + * + * @name Point#attractToGrid + * + * @see Point#attractorDistance + * @see Point#attractorUnit + * @see Point#snapToGrid + * @see Point#snapSizeX + * @see Point#snapSizeY + * @type Boolean + * @default false + * + * @example + * board.create('point', [3, 3], { attractToGrid: true, attractorDistance: 10, attractorunit: 'screen' }); + * + * </pre><div id="JXG397ab787-cd40-449c-a7e7-a3f7bab1d4f6" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG397ab787-cd40-449c-a7e7-a3f7bab1d4f6', + * {boundingbox: [-1, 4, 7,-4], axis: true, showcopyright: false, shownavigation: false}); + * board.create('point', [3, 3], { attractToGrid: true, attractorDistance: 10, attractorunit: 'screen' }); + * + * })(); + * + * </script><pre> + * + */ + attractToGrid: false, + /** * Defines together with {@link Point#snapSizeY} the grid the point snaps on to. + * It is given in user coordinates, not in pixels. * The point will only snap on integer multiples to snapSizeX in x and snapSizeY in y direction. * If this value is equal to or less than <tt>0</tt>, it will use the grid displayed by the major ticks * of the default ticks of the default x axes of the board. @@ -25339,6 +29425,7 @@ define('options',[ /** * Defines together with {@link Point#snapSizeX} the grid the point snaps on to. + * It is given in user coordinates, not in pixels. * The point will only snap on integer multiples to snapSizeX in x and snapSizeY in y direction. * If this value is equal to or less than <tt>0</tt>, it will use the grid displayed by the major ticks * of the default ticks of the default y axes of the board. @@ -25393,10 +29480,12 @@ define('options',[ */ hasInnerPoints: false, - fillColor: '#00FF00', - highlightFillColor: '#00FF00', + fillColor: Color.palette.yellow, + highlightFillColor: Color.palette.yellow, + // fillColor: '#00ff00', + // highlightFillColor: '#00ff00', fillOpacity: 0.3, - highlightFillOpacity: 0.3, + highlightFillOpacity: 0.2, /** * Is the polygon bordered by lines? @@ -25435,8 +29524,8 @@ define('options',[ layer: 9, withLabel: false, name: '', - strokeColor: '#ff0000', - fillColor: '#ff0000', + strokeColor: Color.palette.red, + fillColor: Color.palette.red, fixed: false, visible: 'inherit' }, @@ -25537,10 +29626,10 @@ define('options',[ * @default false */ hasInnerPoints: false, - fillColor: '#00FF00', - highlightFillColor: '#00FF00', + fillColor: Color.palette.yellow, + highlightFillColor: Color.palette.yellow, fillOpacity: 0.3, - highlightFillOpacity: 0.3, + highlightFillOpacity: 0.2, /** * Is the polygon bordered by lines? @@ -25577,8 +29666,8 @@ define('options',[ vertices: { layer: 9, withLabel: true, - strokeColor: '#ff0000', - fillColor: '#ff0000', + strokeColor: Color.palette.red, + fillColor: Color.palette.red, fixed: false }, @@ -25603,7 +29692,7 @@ define('options',[ withLabel: false, fillOpacity: 0.3, - fillColor: '#ffff00' + fillColor: Color.palette.yellow /**#@-*/ }, @@ -25614,8 +29703,11 @@ define('options',[ * @visprop */ - fillColor: '#00FF00', - highlightFillColor: '#00FF00', + fillColor: Color.palette.yellow, + highlightFillColor: Color.palette.yellow, + // fillColor: '#00ff00', + // highlightFillColor: '#00ff00', + fillOpacity: 0.3, highlightFillOpacity: 0.3, highlightOnSector: false, @@ -25717,6 +29809,10 @@ define('options',[ visible: false, withLabel: false, fixed: false, + fillColor: Color.palette.red, + strokeColor: Color.palette.red, + highlightFillColor:'#eeeeee', + highlightStrokeColor: Color.palette.red, name: '' } @@ -25741,13 +29837,27 @@ define('options',[ /** * The precision of the slider value displayed in the optional text. + * Replaced by the attribute "digits". + * * @memberOf Slider.prototype * @name precision * @type Number + * @deprecated + * @see Slider#digits * @default 2 */ precision: 2, + /** + * The number of digits of the slider value displayed in the optional text. + * + * @memberOf Slider.prototype + * @name digits + * @type Number + * @default 2 + */ + digits: 2, + firstArrow: false, lastArrow: false, @@ -25772,7 +29882,7 @@ define('options',[ /** * If not null, this replaces the part "name = " in the slider label. * Possible types: string, number or function. - * @type {String} + * @type String * @name suffixLabel * @memberOf Slider.prototype * @default null @@ -25784,7 +29894,7 @@ define('options',[ /** * If not null, this is appended to the value in the slider label. * Possible types: string, number or function. - * @type {String} + * @type String * @name unitLabel * @memberOf Slider.prototype * @default null @@ -25796,7 +29906,7 @@ define('options',[ /** * If not null, this is appended to the value and to unitLabel in the slider label. * Possible types: string, number or function. - * @type {String} + * @type String * @name postLabel * @memberOf Slider.prototype * @default null @@ -25865,6 +29975,7 @@ define('options',[ visible: 'inherit', fixed: true, scalable: false, + tabindex: null, name: '', strokeWidth: 1, strokeColor: '#000000', @@ -25883,7 +29994,7 @@ define('options',[ // Label drawing drawLabels: false, - precision: 2, + digits: 2, includeBoundaries: 1, drawZero: true, label: { @@ -25914,6 +30025,7 @@ define('options',[ strokeWidth: 3, visible: 'inherit', fixed: true, + tabindex: null, name: '', strokeColor: '#000000', highlightStrokeColor: '#888888' @@ -26029,9 +30141,9 @@ define('options',[ * @visprop */ - fillColor: 'red', + fillColor: Color.palette.red, fillOpacity: 0.4, - highlightFillColor: 'red', + highlightFillColor: Color.palette.red, highlightFillOpacity: 0.3, borders: { @@ -26095,9 +30207,9 @@ define('options',[ * Attributes for the top point. * * @type Point - * @name Slopetriangle#topPoint + * @name Slopetriangle#toppoint */ - topPoint: { + toppoint: { visible: false, withLabel: false, name: '' @@ -26154,13 +30266,26 @@ define('options',[ /** * The precision of the tape measure value displayed in the optional text. + * Replaced by the attribute digits + * * @memberOf Tapemeasure.prototype * @name precision * @type Number + * @deprecated + * @see Tapemeasure#digits * @default 2 */ precision: 2, + /** + * The precision of the tape measure value displayed in the optional text. + * @memberOf Tapemeasure.prototype + * @name precision + * @type Number + * @default 2 + */ + digits: 2, + /** * Attributes for first helper point defining the tape measure position. * @@ -26249,9 +30374,37 @@ define('options',[ * @memberOf Text.prototype * @default 12 * @type Number + * @see Text#fontUnit */ fontSize: 12, + /** + * CSS unit for the font size of a text element. Usually, this will be the default value 'px' but + * for responsive application, also 'vw', 'vh', vmax', 'vmin' or 'rem' might be useful. + * + * @name fontUnit + * @memberOf Text.prototype + * @default 'px' + * @type String + * @see Text#fontSize + * + * @example + * var txt = board.create('text', [2, 2, "hello"], {fontSize: 8, fontUnit: 'vmin'}); + * + * </pre><div id="JXG2da7e972-ac62-416b-a94b-32559c9ec9f9" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG2da7e972-ac62-416b-a94b-32559c9ec9f9', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * var txt = board.create('text', [2, 2, "hello"], {fontSize: 8, fontUnit: 'vmin'}); + * + * })(); + * + * </script><pre> + * + */ + fontUnit: 'px', + /** * Used to round texts given by a number. * @@ -26296,8 +30449,8 @@ define('options',[ */ isLabel: false, - strokeColor: 'black', - highlightStrokeColor: 'black', + strokeColor: '#000000', + highlightStrokeColor: '#000000', highlightStrokeOpacity: 0.666666, /** @@ -26469,8 +30622,6 @@ define('options',[ * { * fontSize: 24, useMathJax: true * }); - * ze: 24, useMathJax: true - * }); * * </pre> * <script> @@ -26525,9 +30676,6 @@ define('options',[ * { * fontSize: 24, useMathJax: true * }); - * ze: 24, useMathJax: true - * }); - * * })(); * * </script><pre> @@ -26535,7 +30683,7 @@ define('options',[ * * @example * // Load MathJax: - * // <script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js"></script> + * // <script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js"<</script> * * // function and its derivative * var f1 = function(x) { return x * x * x; }, @@ -26642,9 +30790,101 @@ define('options',[ * * </script><pre> * + * @example + * var board = JXG.JSXGraph.initBoard('jxgbox', {boundingbox: [-1, 10, 11, -2], axis: true}); + * board.options.text.useMathjax = true; + * + * a = board.create('slider',[[-0.7,1.5],[5,1.5],[0,0.5,1]], { + * suffixlabel:'\\(t_1=\\)', + * unitLabel: ' \\(\\text{ ms}\\)', + * snapWidth:0.01}), + * + * func = board.create('functiongraph',[function(x){return (a.Value()*x*x)}], {strokeColor: "red"}); + * text1 = board.create('text', [5, 1, function(){ + * return '\\(a(t)= { 1 \\over ' + a.Value().toFixed(3) + '}\\)'; + * }], {fontSize: 15, fixed:true, strokeColor:'red', anchorY: 'top', parse: false}); + * + * </pre><div id="JXGf8bd01db-fb6a-4a5c-9e7f-8823f7aa5ac6" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXGf8bd01db-fb6a-4a5c-9e7f-8823f7aa5ac6', + * {boundingbox: [-1, 10, 11, -2], axis: true, showcopyright: false, shownavigation: false}); + * board.options.text.useMathjax = true; + * + * a = board.create('slider',[[-0.7,1.5],[5,1.5],[0,0.5,1]], { + * suffixlabel:'\\(t_1=\\)', + * unitLabel: ' \\(\\text{ ms}\\)', + * snapWidth:0.01}), + * + * func = board.create('functiongraph',[function(x){return (a.Value()*x*x)}], {strokeColor: "red"}); + * text1 = board.create('text', [5, 1, function(){ + * return '\\(a(t)= { 1 \\over ' + a.Value().toFixed(3) + '}\\)'; + * }], {fontSize: 15, fixed:true, strokeColor:'red', anchorY: 'top', parse: false}); + * + * })(); + * + * </script><pre> + * */ useMathJax: false, + /** + * + * If true, KaTeX will be used to render the input string. + * For this feature, katex.min.js and katex.min.css have to be included. + * <p> + * The example below does not work, because there is a conflict with + * the MathJax library which is used below. + * </p> + * + * @name useKatex + * @memberOf Text.prototype + * @default false + * @type Boolean + * + * + * @example + * JXG.Options.text.useKatex = true; + * + * const board = JXG.JSXGraph.initBoard('jxgbox', { + * boundingbox: [-2, 5, 8, -5], axis:true + * }); + * + * var a = board.create('slider',[[-0.7,1.5],[5,1.5],[0,0.5,1]], { + * suffixlabel:'t_1=', + * unitLabel: ' \\text{ ms}', + * snapWidth:0.01}); + * + * func = board.create('functiongraph',[function(x){return (a.Value()*x*x)}], {strokeColor: "red"}); + * text1 = board.create('text', [5, 1, function(){ + * return 'a(t)= { 1 \\over ' + a.Value().toFixed(3) + '}'; + * }], {fontSize: 15, fixed:true, strokeColor:'red', anchorY: 'top'}); + * + * </pre> + * <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.13.10/dist/katex.min.css" integrity="sha384-0cCFrwW/0bAk1Z/6IMgIyNU3kfTcNirlObr4WjrUU7+hZeD6ravdYJ3kPWSeC31M" crossorigin="anonymous"> + * <script src="https://cdn.jsdelivr.net/npm/katex@0.13.10/dist/katex.min.js" integrity="sha384-dtFDxK2tSkECx/6302Z4VN2ZRqt6Gis+b1IwCjJPrn0kMYFQT9rbtyQWg5NFWAF7" crossorigin="anonymous"></script> + * <div id="JXG497f065c-cfc1-44c3-ba21-5fa581668869" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG497f065c-cfc1-44c3-ba21-5fa581668869', + * {boundingbox: [-2, 5, 8, -5], axis: true, showcopyright: false, shownavigation: false}); + * board.options.useKatex = true; + * var a = board.create('slider',[[-0.7,1.5],[5,1.5],[0,0.5,1]], { + * suffixlabel:'t_1=', + * unitLabel: ' \\text{ ms}', + * snapWidth:0.01}); + * + * func = board.create('functiongraph',[function(x){return (a.Value()*x*x)}], {strokeColor: "red"}); + * text1 = board.create('text', [5, 1, function(){ + * return 'a(t)= { 1 \\over ' + a.Value().toFixed(3) + '}'; + * }], {fontSize: 15, fixed:true, strokeColor:'red', anchorY: 'top'}); + * + * })(); + * + * </script><pre> + */ + useKatex: false, + /** * Determines the rendering method of the text. Possible values * include <tt>'html'</tt> and <tt>'internal</tt>. @@ -26820,7 +31060,7 @@ define('options',[ arrow: { strokeWidth: 2, withLabel: false, - strokeColor: '#ff0000', + strokeColor: Color.palette.red, lastArrow: true } /**#@-*/ @@ -26832,7 +31072,7 @@ define('options',[ * It is used in {@link JXG.GeometryElement#setAttribute} and in * the constructor {@link JXG.GeometryElement}. * Attention: In Options.js abbreviations are not allowed. - * @type {Object} + * @type Object * @name JXG.Options#shortcuts * */ @@ -27130,7 +31370,7 @@ define('options',[ }); /* - Copyright 2008-2021 + Copyright 2008-2022 Matthias Ehmann, Michael Gerhaeuser, Carsten Miller, @@ -27168,7 +31408,8 @@ define('options',[ plusplus: Only allowed in for-loops newcap: AsciiMathMl exposes non-constructor functions beginning with upper case letters */ -/*jslint nomen: true, plusplus: true, newcap:true*/ +/*jslint nomen: true, plusplus: true, newcap: true, unparam: true*/ +/*eslint no-unused-vars: "off"*/ /* depends: jxg @@ -27360,6 +31601,10 @@ define('renderer/abstract',[ if (!not.gradient) { this.setShadow(el); } + + if (!not.tabindex) { + this.setTabindex(el); + } } else { this.setDraft(el); } @@ -27520,10 +31765,103 @@ define('renderer/abstract',[ this.updateLine(el); }, + /** + * Updates visual appearance of the renderer element assigned to the given {@link JXG.Line}. + * @param {JXG.Line} el Reference to the {@link JXG.Line} object that has to be updated. + * @see Line + * @see JXG.Line + * @see JXG.AbstractRenderer#drawLine + */ + updateLine: function (el) { + this._updateVisual(el); + this.updatePathWithArrowHeads(el); // Calls the renderer primitive + this.setLineCap(el); + }, + + /* ************************** + * Curves + * **************************/ + + /** + * Draws a {@link JXG.Curve} on the {@link JXG.Board}. + * @param {JXG.Curve} el Reference to a graph object, that has to be plotted. + * @see Curve + * @see JXG.Curve + * @see JXG.AbstractRenderer#updateCurve + */ + drawCurve: function (el) { + el.rendNode = this.appendChildPrim(this.createPrim('path', el.id), Type.evaluate(el.visProp.layer)); + this.appendNodesToElement(el, 'path'); + this.updateCurve(el); + }, + + /** + * Updates visual appearance of the renderer element assigned to the given {@link JXG.Curve}. + * @param {JXG.Curve} el Reference to a {@link JXG.Curve} object, that has to be updated. + * @see Curve + * @see JXG.Curve + * @see JXG.AbstractRenderer#drawCurve + */ + updateCurve: function (el) { + this._updateVisual(el); + this.updatePathWithArrowHeads(el); // Calls the renderer primitive + this.setLineCap(el); + }, + + /* ************************** + * Arrow heads and related stuff + * **************************/ + + /** + * Handles arrow heads of a line or curve element and calls the renderer primitive. + * + * @param {JXG.GeometryElement} el Reference to a line or curve object that has to be drawn. + * @param {Boolean} doHighlight + * + * @private + * @see Line + * @see JXG.Line + * @see Curve + * @see JXG.Curve + * @see JXG.AbstractRenderer#updateLine + * @see JXG.AbstractRenderer#updateCurve + * @see JXG.AbstractRenderer#makeArrows + * @see JXG.AbstractRenderer#getArrowHeadData + */ + updatePathWithArrowHeads: function(el, doHighlight) { + var ev = el.visProp, + hl = doHighlight ? 'highlight' : '', + w, + arrowData; + + if (doHighlight && ev.highlightstrokewidth) { + w = Math.max(Type.evaluate(ev.highlightstrokewidth), Type.evaluate(ev.strokewidth)); + } else { + w = Type.evaluate(ev.strokewidth); + } + + // Get information if there are arrow heads and how large they are. + arrowData = this.getArrowHeadData(el, w, hl); + + // Create the SVG nodes if neccessary + this.makeArrows(el, arrowData); + + // Draw the paths with arrow heads + if (el.elementClass === Const.OBJECT_CLASS_LINE) { + this.updateLineWithEndings(el, arrowData); + } else if (el.elementClass === Const.OBJECT_CLASS_CURVE) { + this.updatePath(el); + } + + this.setArrowSize(el, arrowData); + }, + /** * This method determines some data about the line endings of this element. * If there are arrow heads, the offset is determined so that no parts of the line stroke - * overlap over the arrow head. + * lap over the arrow head. + * <p> + * The returned object also contains the types of the arrow heads. * * @param {JXG.GeometryElement} el JSXGraph line or curve element * @param {Number} strokewidth strokewidth of the element @@ -27553,9 +31891,21 @@ define('renderer/abstract',[ if (Type.exists(ev_fa.type)) { typeFirst = Type.evaluate(ev_fa.type); + } else { + if (el.elementClass === Const.OBJECT_CLASS_LINE) { + typeFirst = 1; + } else { + typeFirst = 7; + } } if (Type.exists(ev_la.type)) { typeLast = Type.evaluate(ev_la.type); + } else { + if (el.elementClass === Const.OBJECT_CLASS_LINE) { + typeLast = 1; + } else { + typeLast = 7; + } } if (ev_fa) { @@ -27566,6 +31916,7 @@ define('renderer/abstract',[ if (hl !== '' && Type.exists(ev_fa[hl + 'size'])) { size = Type.evaluate(ev_fa[hl + 'size']); } + off = strokewidth * size; if (typeFirst === 2) { off *= 0.5; @@ -27576,6 +31927,10 @@ define('renderer/abstract',[ } else if (typeFirst === 4 || typeFirst === 5 || typeFirst === 6) { off = strokewidth * size / 1.5; minlen += strokewidth * size; + } else if (typeFirst === 7) { + off = 0; + size = 10; + minlen += strokewidth; } else { minlen += strokewidth * size; } @@ -27601,6 +31956,10 @@ define('renderer/abstract',[ } else if (typeLast === 4 || typeLast === 5 || typeLast === 6) { off = strokewidth * size / 1.5; minlen += strokewidth * size; + } else if (typeLast === 7) { + off = 0; + size = 10; + minlen += strokewidth; } else { minlen += strokewidth * size; } @@ -27608,10 +31967,14 @@ define('renderer/abstract',[ sizeLast = size; } } + el.visPropCalc.typeFirst = typeFirst; + el.visPropCalc.typeLast = typeLast; return { evFirst: ev_fa, evLast: ev_la, + typeFirst: typeFirst, + typeLast: typeLast, offFirst: offFirst, offLast: offLast, sizeFirst: sizeFirst, @@ -27624,7 +31987,67 @@ define('renderer/abstract',[ }, /** - * Shorten the line length such that the arrow head touches + * Corrects the line length if there are arrow heads, such that + * the arrow ends exactly at the intended position. + * Calls the renderer method to draw the line. + * + * @param {JXG.Line} el Reference to a line object, that has to be drawn + * @param {Object} arrowData Data concerning possible arrow heads + * + * @returns {JXG.AbstractRenderer} Reference to the renderer + * + * @private + * @see Line + * @see JXG.Line + * @see JXG.AbstractRenderer#updateLine + * @see JXG.AbstractRenderer#getPositionArrowHead + * + */ + updateLineWithEndings: function(el, arrowData) { + var c1, c2, + // useTotalLength = true, + margin = null; + + c1 = new Coords(Const.COORDS_BY_USER, el.point1.coords.usrCoords, el.board); + c2 = new Coords(Const.COORDS_BY_USER, el.point2.coords.usrCoords, el.board); + margin = Type.evaluate(el.visProp.margin); + Geometry.calcStraight(el, c1, c2, margin); + + this.handleTouchpoints(el, c1, c2, arrowData); + this.getPositionArrowHead(el, c1, c2, arrowData); + + this.updateLinePrim(el.rendNode, + c1.scrCoords[1], c1.scrCoords[2], + c2.scrCoords[1], c2.scrCoords[2], el.board); + + return this; + }, + + /** + * + * Calls the renderer method to draw a curve. + * + * @param {JXG.GeometryElement} el Reference to a line object, that has to be drawn. + * @returns {JXG.AbstractRenderer} Reference to the renderer + * + * @private + * @see Curve + * @see JXG.Curve + * @see JXG.AbstractRenderer#updateCurve + * + */ + updatePath: function(el) { + if (Type.evaluate(el.visProp.handdrawing)) { + this.updatePathPrim(el.rendNode, this.updatePathStringBezierPrim(el), el.board); + } else { + this.updatePathPrim(el.rendNode, this.updatePathStringPrim(el), el.board); + } + + return this; + }, + + /** + * Shorten the length of a line element such that the arrow head touches * the start or end point and such that the arrow head ends exactly * at the start / end position of the line. * @@ -27638,13 +32061,13 @@ define('renderer/abstract',[ * Additionally, if one of these values is zero, the arrow is not displayed. This is the case, if the * line length is very short. */ - getPositionArrowHead: function(el, c1, c2, a) { + getPositionArrowHead: function(el, c1, c2, a) { var d, d1x, d1y, d2x, d2y; /* Handle arrow heads. - The default arrow head is an isosceles triangle with base length 10 units and height 10 units. + The default arrow head (type==1) is an isosceles triangle with base length 10 units and height 10 units. These 10 units are scaled to strokeWidth * arrowSize pixels pixels. */ if (a.evFirst || a.evLast) { @@ -27687,7 +32110,7 @@ define('renderer/abstract',[ * @param {Object} a */ handleTouchpoints: function(el, c1, c2, a) { - var s1, s2, s, d, + var s1, s2, d, d1x, d1y, d2x, d2y; if (a.evFirst || a.evLast) { @@ -27695,7 +32118,6 @@ define('renderer/abstract',[ s1 = Type.evaluate(el.point1.visProp.size) + Type.evaluate(el.point1.visProp.strokewidth); s2 = Type.evaluate(el.point2.visProp.size) + Type.evaluate(el.point2.visProp.strokewidth); - s = s1 + s2; // Handle touchlastpoint /touchfirstpoint if (a.evFirst && Type.evaluate(el.visProp.touchfirstpoint)) { @@ -27719,84 +32141,6 @@ define('renderer/abstract',[ return this; }, - /** - * Corrects the line length if there are arrow heads, such that - * the arrow ends exactly at the intended position. - * Calls the renderer method to draw the line. - * - * @param {JXG.Line} el Reference to a line object, that has to be drawn - * @param {Object} arrowData Data concerning possible arrow heads - * - * @returns {JXG.AbstractRenderer} Reference to the renderer - * - * @private - * @see Line - * @see JXG.Line - * @see JXG.AbstractRenderer#updateLine - * @see JXG.AbstractRenderer#getPositionArrowHead - * @see JXG.AbstractRenderer#getArrowHeadData - * - */ - updateLineEndings: function(el, arrowData) { - var c1, c2, - // useTotalLength = true, - margin = null; - - c1 = new Coords(Const.COORDS_BY_USER, el.point1.coords.usrCoords, el.board); - c2 = new Coords(Const.COORDS_BY_USER, el.point2.coords.usrCoords, el.board); - margin = Type.evaluate(el.visProp.margin); - Geometry.calcStraight(el, c1, c2, margin); - - this.handleTouchpoints(el, c1, c2, arrowData); - - // Shorten path without el.rendNode.getTotalLength - // if (!Type.exists(el.rendNode.getTotalLength)) { - this.getPositionArrowHead(el, c1, c2, arrowData); - // useTotalLength = false; - // } - - this.updateLinePrim(el.rendNode, - c1.scrCoords[1], c1.scrCoords[2], - c2.scrCoords[1], c2.scrCoords[2], el.board); - - // Shorten path with el.rendNode.getTotalLength - // This does not work sufficiently good in webkit. - // See also _createArrowHead for arrow head position - // if (useTotalLength) { - // this.shortenPath(el.rendNode, arrowData.offFirst, arrowData.offLast); - // } - - return this; - }, - - /** - * - * Calls the renderer method to draw the curve and - * corrects the curve length if there are arrow heads, such that - * the arrow ends exactly at the intended position. - * - * @param {JXG.GeometryElement} el Reference to a line object, that has to be drawn. - * @param {Object} arrowData Data concerning possible arrow heads - * @returns {JXG.AbstractRenderer} Reference to the renderer - * - * @private - * @see Curve - * @see JXG.Curve - * @see JXG.AbstractRenderer#updateCurve - * @see JXG.AbstractRenderer#getArrowHeadData - */ - updatePathEndings: function(el, arrowData) { - if (Type.evaluate(el.visProp.handdrawing)) { - this.updatePathPrim(el.rendNode, this.updatePathStringBezierPrim(el), el.board); - } else { - this.updatePathPrim(el.rendNode, this.updatePathStringPrim(el), el.board); - } - - this.shortenPath(el.rendNode, arrowData.offFirst, arrowData.offLast); - - return this; - }, - /** * Set the arrow head size. * @@ -27822,60 +32166,6 @@ define('renderer/abstract',[ return this; }, - /** - * Handle arrow heads of a line or curve element and call the renderer primitive. - * - * @param {JXG.GeometryElement} el Reference to a line or curve object that has to be drawn. - * @param {Boolean} doHighlight - * - * @private - * @see Line - * @see JXG.Line - * @see Curve - * @see JXG.Curve - * @see JXG.AbstractRenderer#makeArrows - * @see JXG.AbstractRenderer#getArrowHeadData - */ - updatePathWithArrowHeads: function(el, doHighlight) { - var ev = el.visProp, - hl = doHighlight ? 'highlight' : '', - w, - arrowData; - - if (doHighlight && ev.highlightstrokewidth) { - w = Math.max(Type.evaluate(ev.highlightstrokewidth), Type.evaluate(ev.strokewidth)); - } else { - w = Type.evaluate(ev.strokewidth); - } - - // Get information if there are arrow heads and how large they are. - arrowData = this.getArrowHeadData(el, w, hl); - - // Create the SVG nodes if neccessary - this.makeArrows(el); - - // Draw the paths with arrow heads - if (el.elementClass === Const.OBJECT_CLASS_LINE) { - this.updateLineEndings(el, arrowData); - } else if (el.elementClass === Const.OBJECT_CLASS_CURVE) { - this.updatePathEndings(el, arrowData); - } - this.setArrowSize(el, arrowData); - }, - - /** - * Updates visual appearance of the renderer element assigned to the given {@link JXG.Line}. - * @param {JXG.Line} el Reference to the {@link JXG.Line} object that has to be updated. - * @see Line - * @see JXG.Line - * @see JXG.AbstractRenderer#drawLine - */ - updateLine: function (el) { - this._updateVisual(el); - this.updatePathWithArrowHeads(el); - this.setLineCap(el); - }, - /** * Update the line endings (linecap) of a straight line from its attribute * 'linecap'. @@ -27889,6 +32179,10 @@ define('renderer/abstract',[ */ setLineCap: function(el) { /* stub */ }, + /* ************************** + * Ticks related stuff + * **************************/ + /** * Creates a rendering node for ticks added to a line. * @param {JXG.Line} el A arbitrary line. @@ -27915,39 +32209,6 @@ define('renderer/abstract',[ */ updateTicks: function (element) { /* stub */ }, - /* ************************** - * Curves - * **************************/ - - /** - * Draws a {@link JXG.Curve} on the {@link JXG.Board}. - * @param {JXG.Curve} el Reference to a graph object, that has to be plotted. - * @see Curve - * @see JXG.Curve - * @see JXG.AbstractRenderer#updateCurve - */ - drawCurve: function (el) { - el.rendNode = this.appendChildPrim(this.createPrim('path', el.id), Type.evaluate(el.visProp.layer)); - this.appendNodesToElement(el, 'path'); - if (el.numberPoints > 1) { - this.makeArrows(el); - } - this._updateVisual(el, {shadow: true}, true); - this.updateCurve(el); - }, - - /** - * Updates visual appearance of the renderer element assigned to the given {@link JXG.Curve}. - * @param {JXG.Curve} el Reference to a {@link JXG.Curve} object, that has to be updated. - * @see Curve - * @see JXG.Curve - * @see JXG.AbstractRenderer#drawCurve - */ - updateCurve: function (el) { - this.updatePathWithArrowHeads(el); - this._updateVisual(el); - }, - /* ************************** * Circle related stuff * **************************/ @@ -27989,7 +32250,6 @@ define('renderer/abstract',[ } }, - /* ************************** * Polygon related stuff * **************************/ @@ -28122,8 +32382,10 @@ define('renderer/abstract',[ * @see JXG.AbstractRenderer#updateTextStyle */ updateText: function (el) { - var content = el.plaintext, v, c, + var content = el.plaintext, + v, c, parentNode, + scale, vshift, id, wrap_id, ax, ay; if (el.visPropCalc.visible) { @@ -28140,11 +32402,14 @@ define('renderer/abstract',[ ax = el.getAnchorX(); if (ax === 'right') { - v = Math.floor(el.board.canvasWidth - c); + // v = Math.floor(el.board.canvasWidth - c); + v = el.board.canvasWidth - c; } else if (ax === 'middle') { - v = Math.floor(c - 0.5 * el.size[0]); + // v = Math.floor(c - 0.5 * el.size[0]); + v = c - 0.5 * el.size[0]; } else { // 'left' - v = Math.floor(c); + // v = Math.floor(c); + v = c; } // This may be useful for foreignObj. @@ -28169,11 +32434,14 @@ define('renderer/abstract',[ ay = el.getAnchorY(); if (ay === 'bottom') { - v = Math.floor(el.board.canvasHeight - c); + // v = Math.floor(el.board.canvasHeight - c); + v = el.board.canvasHeight - c; } else if (ay === 'middle') { - v = Math.floor(c - 0.5 * el.size[1]); + // v = Math.floor(c - 0.5 * el.size[1]); + v = c - 0.5 * el.size[1]; } else { // top - v = Math.floor(c); + // v = Math.floor(c); + v = c; } // This may be useful for foreignObj. @@ -28196,10 +32464,18 @@ define('renderer/abstract',[ // Set the content if (el.htmlStr !== content) { try { - el.rendNode.innerHTML = content; + if (el.type === Type.OBJECT_TYPE_BUTTON) { + el.rendNodeButton.innerHTML = content; + } else if (el.type === Type.OBJECT_TYPE_CHECKBOX || + el.type === Type.OBJECT_TYPE_INPUT) { + el.rendNodeLabel.innerHTML = content; + } else { + el.rendNode.innerHTML = content; + } } catch (e) { - // Setting innerHTML sometimes fails in IE8. A workaround is to - // take the node off the DOM, assign innerHTML, then append back. + // Setting innerHTML sometimes fails in IE8. + // A workaround is to take the node off the DOM, assign innerHTML, + // then append back. // Works for text elements as they are absolutely positioned. parentNode = el.rendNode.parentNode; el.rendNode.parentNode.removeChild(el.rendNode); @@ -28209,7 +32485,7 @@ define('renderer/abstract',[ el.htmlStr = content; if (Type.evaluate(el.visProp.usemathjax)) { - // typesetting directly might not work because mathjax was not loaded completely + // Typesetting directly might not work because mathjax was not loaded completely // see http://www.mathjax.org/docs/1.1/typeset.html try { if (MathJax.typeset) { @@ -28219,10 +32495,31 @@ define('renderer/abstract',[ // Version 2 MathJax.Hub.Queue(['Typeset', MathJax.Hub, el.rendNode]); } + + // Restore the transformation necessary for fullscreen mode + // MathJax removes it when handling dynamic content + id = el.board.container; + wrap_id = 'fullscreenwrap_' + id; + if (document.getElementById(wrap_id)) { + scale = el.board.containerObj._cssFullscreenStore.scale; + vshift = el.board.containerObj._cssFullscreenStore.vshift; + Env.scaleJSXGraphDiv('#' + wrap_id, '#' + id, scale, vshift); + } + } catch (e) { JXG.debug('MathJax (not yet) loaded'); } - } else if (Type.evaluate(el.visProp.useasciimathml)) { + } else if (Type.evaluate(el.visProp.usekatex)) { + try { + /* eslint-disable no-undef */ + katex.render(content, el.rendNode, { + throwOnError: false + }); + /* eslint-enable no-undef */ + } catch (e) { + JXG.debug('KaTeX (not yet) loaded'); + } + } else if (Type.evaluate(el.visProp.useasciimathml)) { // This is not a constructor. // See http://www1.chapman.edu/~jipsen/mathml/asciimath.html for more information // about AsciiMathML and the project's source code. @@ -28288,6 +32585,7 @@ define('renderer/abstract',[ display = Env.isBrowser ? ev.display : 'internal', nodeList = ['rendNode', 'rendNodeTag', 'rendNodeLabel'], lenN = nodeList.length, + fontUnit = Type.evaluate(ev.fontunit), cssList, prop, style, cssString, styleList = ['cssdefaultstyle', 'cssstyle'], lenS = styleList.length; @@ -28340,7 +32638,7 @@ define('renderer/abstract',[ try { for (node = 0; node < lenN; node++) { if (Type.exists(el[nodeList[node]])) { - el[nodeList[node]].style.fontSize = fs + 'px'; + el[nodeList[node]].style.fontSize = fs + fontUnit; } } } catch (e) { @@ -28503,6 +32801,9 @@ define('renderer/abstract',[ el.rendNode.className = Type.evaluate(doHighlight ? el.visProp.highlightcssclass : el.visProp.cssclass); }, + drawForeignObject: function (el) { /* stub */ }, + + updateForeignObject: function(el) { /* stub */ }, /* ************************** * Render primitive objects @@ -28546,9 +32847,10 @@ define('renderer/abstract',[ * Can be used to create the nodes to display arrows. This is an abstract method which has to be implemented * in any descendant renderer. * @param {JXG.GeometryElement} element The element the arrows are to be attached to. + * @param {Object} arrowData Data concerning possible arrow heads * */ - makeArrows: function (element) { /* stub */ }, + makeArrows: function (element, arrowData) { /* stub */ }, /** * Updates width of an arrow DOM node. Used in @@ -28651,6 +32953,20 @@ define('renderer/abstract',[ */ setPropertyPrim: function (node, key, val) { /* stub */ }, + setTabindex: function(element) { + var val; + if (element.board.attr.keyboard.enabled && Type.exists(element.rendNode)) { + val = Type.evaluate(element.visProp.tabindex); + if (!element.visPropCalc.visible || Type.evaluate(element.visProp.fixed)) { + val = null; + } + if (val !== element.visPropOld.tabindex) { + element.rendNode.setAttribute('tabindex', val); + element.visPropOld.tabindex = val; + } + } + }, + /** * Shows or hides an element on the canvas; Only a stub, requires implementation in the derived renderer. * @param {JXG.GeometryElement} element Reference to the object that has to appear. @@ -28808,8 +33124,7 @@ define('renderer/abstract',[ * @see JXG.AbstractRenderer#updateTextStyle */ highlight: function (el) { - var i, ev = el.visProp, - sw, obj; + var i, ev = el.visProp, sw; this.setObjectTransition(el); if (!ev.draft) { @@ -28856,8 +33171,7 @@ define('renderer/abstract',[ * @see JXG.AbstractRenderer#updateTextStyle */ noHighlight: function (el) { - var i, ev = el.visProp, - obj, sw; + var i, ev = el.visProp, sw; this.setObjectTransition(el); if (!Type.evaluate(el.visProp.draft)) { @@ -28952,6 +33266,7 @@ define('renderer/abstract',[ if (button.classList !== undefined) { // classList not available in IE 9 button.classList.add('JXG_navigation_button'); } + // button.setAttribute('tabindex', 0); // Highlighting is now done with CSS // Env.addEvent(button, 'mouseover', function () { @@ -28997,7 +33312,7 @@ define('renderer/abstract',[ if (board.attr.showfullscreen) { createButton(board.attr.fullscreen.symbol, function () { - board.toFullscreen(); + board.toFullscreen(board.attr.fullscreen.id); }); } @@ -29134,19 +33449,6 @@ define('renderer/abstract',[ */ screenshot: function (board) {}, - /** - * Shorten SVG path at the beginning and at the end to avoid visible overlap of - * the line and its arrow heads. This method uses the SVG method getTotalLength. - * - * @param {Node} node Reference to a SVG node representing a line or curve. - * @param {Number} offFirst Shorten path at the beginning by this number of pixels - * @param {Number} offLast Shorten path at the end by this number of pixels - * - * @see JXG.AbstractRenderer#updatePathEndings - * @see JXG.AbstractRenderer#updateLineEndings - */ - shortenPath: function(node, offFirst, offLast) {}, - /** * Move element into new layer. This is trivial for canvas, but needs more effort in SVG. * Does not work dynamically, i.e. if level is a function. @@ -29163,7 +33465,7 @@ define('renderer/abstract',[ }); /* - Copyright 2008-2021 + Copyright 2008-2022 Matthias Ehmann, Michael Gerhaeuser, Carsten Miller, @@ -29278,7 +33580,7 @@ define('reader/file',[ } else { // This is for all browsers except ancient IEs. text = req.responseText; - console.log(text); + // console.log(text); } this.parseString(text, board, format, callback); } @@ -29385,6 +33687,8 @@ define('reader/file',[ if (Type.exists(Reader)) { read = new Reader(board, str); read.read(); + } else if (format === 'jessiecode') { + } else { throw new Error('JSXGraph: There is no reader available for \'' + format + '\'.'); } @@ -29449,7 +33753,7 @@ End Function\n\ }); /* - Copyright 2008-2021 + Copyright 2008-2022 Matthias Ehmann, Michael Gerhaeuser, Carsten Miller, @@ -29555,12 +33859,12 @@ define('parser/geonext',[ // Search for F or p.M before (...)^ pre = left.substring(0, pos + 1); p = pos; - while (p >= 0 && pre.substr(p, 1).match(/([\w\.]+)/)) { + while (p >= 0 && pre.substr(p, 1).match(/([\w.]+)/)) { leftop = RegExp.$1 + leftop; p -= 1; } leftop += left.substring(pos + 1, left.length); - leftop = leftop.replace(/([\(\)\+\*\%\^\-\/\]\[])/g, '\\$1'); + leftop = leftop.replace(/([()+*%^\-/\][])/g, '\\$1'); } else { throw new Error("JSXGraph: Missing '(' in expression"); } @@ -29572,7 +33876,7 @@ define('parser/geonext',[ // To the right of the ^ operator there also may be a function or method call // or a term in parenthesis. Alos, ere we search for the closing // parenthesis. - if (right.match(/^([\w\.]*\()/)) { + if (right.match(/^([\w.]*\()/)) { count = 1; pos = RegExp.$1.length; @@ -29589,7 +33893,7 @@ define('parser/geonext',[ if (count === 0) { rightop = right.substring(0, pos); - rightop = rightop.replace(/([\(\)\+\*\%\^\-\/\[\]])/g, '\\$1'); + rightop = rightop.replace(/([()+*%^\-/[\]])/g, '\\$1'); } else { throw new Error("JSXGraph: Missing ')' in expression"); } @@ -29830,7 +34134,7 @@ define('parser/geonext',[ expr = /(Dist)\(([\w_]+),([\w_]+)\)/g; term = term.replace(expr, 'dist($(\'$2\'), $(\'$3\'))'); - expr = /(Deg)\(([\w_]+),([ \w\[\w_]+),([\w_]+)\)/g; + expr = /(Deg)\(([\w_]+),([ \w[\w_]+),([\w_]+)\)/g; term = term.replace(expr, 'deg($(\'$2\'),$(\'$3\'),$(\'$4\'))'); // Search for Rad('gi23','gi24','gi25') @@ -29962,7 +34266,7 @@ define('parser/geonext',[ }); /* - Copyright 2008-2021 + Copyright 2008-2022 Matthias Ehmann, Michael Gerhaeuser, Carsten Miller, @@ -29994,7 +34298,7 @@ define('parser/geonext',[ /*global JXG: true, define: true*/ -/*jslint nomen: true, plusplus: true*/ +/*jslint nomen: true, plusplus: true, unparam: true*/ /* depends: jxg @@ -30009,8 +34313,8 @@ define('parser/geonext',[ */ define('base/element',[ - 'jxg', 'base/constants', 'base/coords', 'math/math', 'math/statistics', 'options', 'parser/geonext', 'utils/event', 'utils/color', 'utils/type' -], function (JXG, Const, Coords, Mat, Statistics, Options, GeonextParser, EventEmitter, Color, Type) { + 'jxg', 'base/constants', 'base/coords', 'math/math', 'math/statistics', 'options', 'utils/event', 'utils/color', 'utils/type' +], function (JXG, Const, Coords, Mat, Statistics, Options, EventEmitter, Color, Type) { "use strict"; @@ -30187,14 +34491,14 @@ define('base/element',[ /** * Inherits contains the subelements, which may have an attribute - * (in partuclar the attribute "visible") having value 'inherit'. + * (in particular the attribute "visible") having value 'inherit'. * @type Object */ this.inherits = []; /** * The position of this element inside the {@link JXG.Board#objectsList}. - * @type {Number} + * @type Number * @default -1 * @private */ @@ -30863,45 +35167,42 @@ define('base/element',[ }, /** - * Hide the element. It will still exist but not visible on the board. + * Hide the element. It will still exist but not be visible on the board. + * Alias for "element.setAttribute({visible: false});" * @return {JXG.GeometryElement} Reference to the element - * @deprecated - * @private */ - hideElement: function () { - JXG.deprecated('Element.hideElement()', 'Element.setDisplayRendNode()'); - - // TODO: Does override value of this.visProp.visible - this.visPropCalc.visible = this.visProp.visible = false; - this.board.renderer.display(this, false); + hide: function () { + this.setAttribute({visible: false}); + return this; + }, - if (Type.exists(this.label) && this.hasLabel) { - this.label.hiddenByParent = true; - if (this.label.visPropCalc.visible) { - this.label.hideElement(); - } - } + /** + * Hide the element. It will still exist but not be visible on the board. + * Alias for {@link JXG.GeometryElement#hide} + * @returns {JXG.GeometryElement} Reference to the element + */ + hideElement: function() { + this.hide(); return this; }, /** * Make the element visible. + * Alias for "element.setAttribute({visible: true});" * @return {JXG.GeometryElement} Reference to the element - * @deprecated - * @private */ - showElement: function () { - JXG.deprecated('Element.showElement()', 'Element.setDisplayRendNode()'); - - this.visPropCalc.visible = this.visProp.visible = true; - this.board.renderer.display(this, true); + show: function () { + this.setAttribute({visible: true}); + return this; + }, - if (Type.exists(this.label) && this.hasLabel && this.label.hiddenByParent) { - this.label.hiddenByParent = false; - if (!this.label.visPropCalc.visible) { - this.label.showElement().updateRenderer(); - } - } + /** + * Make the element visible. + * Alias for {@link JXG.GeometryElement#show} + * @returns {JXG.GeometryElement} Reference to the element + */ + showElement: function() { + this.show(); return this; }, @@ -31018,26 +35319,35 @@ define('base/element',[ }, /** - * Resolves property shortcuts like <tt>color</tt> and expands them, e.g. <tt>strokeColor</tt> and <tt>fillColor</tt>. - * Writes the expanded properties back to the given <tt>properties</tt>. - * @param {Object} properties - * @returns {Object} The given parameter with shortcuts expanded. + * Resolves attribute shortcuts like <tt>color</tt> and expands them, e.g. <tt>strokeColor</tt> and <tt>fillColor</tt>. + * Writes the expanded attributes back to the given <tt>attributes</tt>. + * @param {Object} attributes object + * @returns {Object} The given attributes object with shortcuts expanded. + * @private */ - resolveShortcuts: function (properties) { - var key, i; + resolveShortcuts: function (attributes) { + var key, i, + j, + subattr = ['traceattributes', 'traceAttributes']; for (key in Options.shortcuts) { if (Options.shortcuts.hasOwnProperty(key)) { - if (Type.exists(properties[key])) { - for (i = 0; i < Options.shortcuts[key].length; i++) { - if (!Type.exists(properties[Options.shortcuts[key][i]])) { - properties[Options.shortcuts[key][i]] = properties[key]; + + if (Type.exists(attributes[key])) { + for (i = 0; i < Options.shortcuts[key].length; i++) { + if (!Type.exists(attributes[Options.shortcuts[key][i]])) { + attributes[Options.shortcuts[key][i]] = attributes[key]; + } + } + } + for (j = 0; j < subattr.length; j++) { + if (Type.isObject(attributes[subattr[j]])) { + attributes[subattr[j]] = this.resolveShortcuts(attributes[subattr[j]]); + } } } - } - } } - return properties; + return attributes; }, /** @@ -31323,6 +35633,12 @@ define('base/element',[ this.board.renderer.setLayer(this, Type.evaluate(value)); this._set(key, value); break; + case 'tabindex': + if (Type.exists(this.rendNode)) { + this.rendNode.setAttribute('tabindex', value); + this._set(key, value); + } + break; default: if (Type.exists(this.visProp[key]) && (!JXG.Validator[key] || @@ -31525,7 +35841,7 @@ define('base/element',[ // initiated by the user, e.g. through custom DOM events. We can't just pick one because this would break user // defined highlighting in many ways: // * if overriding the highlight() methods the user had to handle the highlightedObjects stuff, otherwise he'd break - // everything (e.g. the pie chart example http://jsxgraph.uni-bayreuth.de/wiki/index.php/Pie_chart (not exactly + // everything (e.g. the pie chart example https://jsxgraph.org/wiki/index.php/Pie_chart (not exactly // user defined but for this type of chart the highlight method was overridden and not adjusted to the changes in here) // where it just kept highlighting until the radius of the pie was far beyond infinity... // * user defined highlighting would get pointless, everytime the user highlights something using .highlight(), it would get @@ -31585,6 +35901,8 @@ define('base/element',[ * Dimensions of the smallest rectangle enclosing the element. * @returns {Array} The coordinates of the enclosing rectangle in a format * like the bounding box in {@link JXG.Board#setBoundingBox}. + * + * @returns {Array} similar to {@link JXG.Board#setBoundingBox}. */ bounds: function () { return [0, 0, 0, 0]; @@ -31885,10 +36203,9 @@ define('base/element',[ */ removeAllTicks: function () { var t; - if (Type.exists(this.ticks)) { - for (t = this.ticks.length; t > 0; t--) { - this.removeTicks(this.ticks[t - 1]); + for (t = this.ticks.length - 1; t >= 0; t--) { + this.removeTicks(this.ticks[t]); } this.ticks = []; this.board.update(); @@ -31907,29 +36224,56 @@ define('base/element',[ } if (Type.exists(this.ticks)) { - for (t = this.ticks.length; t > 0; t--) { - if (this.ticks[t - 1] === tick) { - this.board.removeObject(this.ticks[t - 1]); - - if (this.ticks[t - 1].ticks) { - for (j = 0; j < this.ticks[t - 1].ticks.length; j++) { - if (Type.exists(this.ticks[t - 1].labels[j])) { - this.board.removeObject(this.ticks[t - 1].labels[j]); + for (t = this.ticks.length - 1; t >= 0; t--) { + if (this.ticks[t] === tick) { + this.board.removeObject(this.ticks[t]); + + if (this.ticks[t].ticks) { + for (j = 0; j < this.ticks[t].ticks.length; j++) { + if (Type.exists(this.ticks[t].labels[j])) { + this.board.removeObject(this.ticks[t].labels[j]); } } } - delete this.ticks[t - 1]; + delete this.ticks[t]; break; } } } }, + /** + * Determine values of snapSizeX and snapSizeY. If the attributes + * snapSizex and snapSizeY are greater than zero, these values are taken. + * Otherwise, determine the distance between major ticks of the + * default axes. + * @returns {Array} containing the snap sizes for x and y direction. + * @private + */ + getSnapSizes: function() { + var sX, sY, ticks; + + sX = Type.evaluate(this.visProp.snapsizex); + sY = Type.evaluate(this.visProp.snapsizey); + + if (sX <= 0 && this.board.defaultAxes && this.board.defaultAxes.x.defaultTicks) { + ticks = this.board.defaultAxes.x.defaultTicks; + sX = ticks.ticksDelta * (Type.evaluate(ticks.visProp.minorticks) + 1); + } + + if (sY <= 0 && this.board.defaultAxes && this.board.defaultAxes.y.defaultTicks) { + ticks = this.board.defaultAxes.y.defaultTicks; + sY = ticks.ticksDelta * (Type.evaluate(ticks.visProp.minorticks) + 1); + } + + return [sX, sY]; + }, + /** * Move an element to its nearest grid point. * The function uses the coords object of the element as - * its actual position. If there is no coords object, nothing is done. + * its actual position. If there is no coords object or if the object is fixed, nothing is done. * @param {Boolean} force force snapping independent from what the snaptogrid attribute says * @param {Boolean} fromParent True if the drag comes from a child element. This is the case if a line * through two points is dragged. In this case we do not try to force the points to stay inside of @@ -31937,55 +36281,56 @@ define('base/element',[ * @returns {JXG.GeometryElement} Reference to this element */ handleSnapToGrid: function (force, fromParent) { - var x, y, ticks, - //i, len, g, el, p, - boardBB, + var x, y, rx, ry, rcoords, + boardBB, res, sX, sY, needsSnapToGrid = false, - sX = Type.evaluate(this.visProp.snapsizex), - sY = Type.evaluate(this.visProp.snapsizey); + attractToGrid = Type.evaluate(this.visProp.attracttogrid), + ev_au = Type.evaluate(this.visProp.attractorunit), + ev_ad = Type.evaluate(this.visProp.attractordistance); - if (!Type.exists(this.coords)) { + if (!Type.exists(this.coords) || Type.evaluate(this.visProp.fixed)) { return this; } - needsSnapToGrid = Type.evaluate(this.visProp.snaptogrid) || force === true; + needsSnapToGrid = Type.evaluate(this.visProp.snaptogrid) || attractToGrid || force === true; if (needsSnapToGrid) { x = this.coords.usrCoords[1]; y = this.coords.usrCoords[2]; + res = this.getSnapSizes(); + sX = res[0]; + sY = res[1]; - if (sX <= 0 && this.board.defaultAxes && this.board.defaultAxes.x.defaultTicks) { - ticks = this.board.defaultAxes.x.defaultTicks; - sX = ticks.ticksDelta * (Type.evaluate(ticks.visProp.minorticks) + 1); - } - - if (sY <= 0 && this.board.defaultAxes && this.board.defaultAxes.y.defaultTicks) { - ticks = this.board.defaultAxes.y.defaultTicks; - sY = ticks.ticksDelta * (Type.evaluate(ticks.visProp.minorticks) + 1); - } - - // if no valid snap sizes are available, don't change the coords. + // If no valid snap sizes are available, don't change the coords. if (sX > 0 && sY > 0) { boardBB = this.board.getBoundingBox(); - x = Math.round(x / sX) * sX; - y = Math.round(y / sY) * sY; - - // checking whether x and y are still within boundingBox, - // if not, adjust them to remain within the board - if (!fromParent) { - if (x < boardBB[0]) { - x += sX; - } else if (x > boardBB[2]) { - x -= sX; - } + rx = Math.round(x / sX) * sX; + ry = Math.round(y / sY) * sY; + rcoords = new JXG.Coords(Const.COORDS_BY_USER, [rx, ry], this.board); + if (!attractToGrid || + rcoords.distance( + ev_au === 'screen' ? Const.COORDS_BY_SCREEN : Const.COORDS_BY_USER, this.coords + ) < ev_ad) { + x = rx; + y = ry; + // Checking whether x and y are still within boundingBox. + // If not, adjust them to remain within the board. + // Otherwise a point may become invisible. + if (!fromParent) { + if (x < boardBB[0]) { + x += sX; + } else if (x > boardBB[2]) { + x -= sX; + } - if (y < boardBB[3]) { - y += sY; - } else if (y > boardBB[1]) { - y -= sY; + if (y < boardBB[3]) { + y += sY; + } else if (y > boardBB[1]) { + y -= sY; + } } + this.coords.setCoordinates(Const.COORDS_BY_USER, [x, y]); } - this.coords.setCoordinates(Const.COORDS_BY_USER, [x, y]); } } return this; @@ -32231,13 +36576,11 @@ define('base/element',[ }); /* - Copyright 2008-2021 + Copyright 2008-2022 Matthias Ehmann, Michael Gerhaeuser, Carsten Miller, - Bianca Valentin, - Alfred Wassermann, - Peter Wilfahrt + Alfred Wassermann This file is part of JSXGraph. @@ -32262,1582 +36605,1334 @@ define('base/element',[ */ -/*global JXG: true, define: true*/ +/*global JXG: true, define: true, console: true, window: true*/ /*jslint nomen: true, plusplus: true*/ -/*depends: +/* depends: jxg - base/constants + options math/math + math/geometry + math/numerics + base/coords + base/constants + base/element + parser/geonext utils/type + elements: + transform */ /** - * @fileoverview This file contains code for transformations of geometrical objects. + * @fileoverview The geometry object CoordsElement is defined in this file. + * This object provides the coordinate handling of points, images and texts. */ -define('base/transformation',[ - 'jxg', 'base/constants', 'math/math', 'utils/type' -], function (JXG, Const, Mat, Type) { +define('base/coordselement',[ + 'jxg', 'math/math', 'math/geometry', 'math/numerics', 'math/statistics', 'base/coords', 'base/constants', 'utils/type', +], function (JXG, Mat, Geometry, Numerics, Statistics, Coords, Const, Type) { "use strict"; /** - * A transformation consists of a 3x3 matrix, i.e. it is a projective transformation. - * @class Creates a new transformation object. Do not use this constructor to create a transformation. Use {@link JXG.Board#create} with - * type {@link Transformation} instead. - * @constructor - * @param {JXG.Board} board The board the new circle is drawn on. - * @param {String} type Can be - * <ul><li> 'translate' - * <li> 'scale' - * <li> 'reflect' - * <li> 'rotate' - * <li> 'shear' - * <li> 'generic' - * </ul> - * @param {Object} params The parameters depend on the transformation type - * - * <p> - * Translation matrix: - * <pre> - * ( 1 0 0) ( z ) - * ( a 1 0) * ( x ) - * ( b 0 1) ( y ) - * </pre> - * - * <p> - * Scale matrix: - * <pre> - * ( 1 0 0) ( z ) - * ( 0 a 0) * ( x ) - * ( 0 0 b) ( y ) - * </pre> - * - * <p> - * A rotation matrix with angle a (in Radians) - * <pre> - * ( 1 0 0 ) ( z ) - * ( 0 cos(a) -sin(a)) * ( x ) - * ( 0 sin(a) cos(a) ) ( y ) - * </pre> - * - * <p> - * Shear matrix: - * <pre> - * ( 1 0 0) ( z ) - * ( 0 1 a) * ( x ) - * ( 0 b 1) ( y ) - * </pre> - * - * <p>Generic transformation: - * <pre> - * ( a b c ) ( z ) - * ( d e f ) * ( x ) - * ( g h i ) ( y ) - * </pre> + * An element containing coords is the basic geometric element. Based on points lines and circles can be constructed which can be intersected + * which in turn are points again which can be used to construct new lines, circles, polygons, etc. This class holds methods for + * all kind of coordinate elements like points, texts and images. + * @class Creates a new coords element object. Do not use this constructor to create an element. * + * @private + * @augments JXG.GeometryElement + * @param {Array} coordinates An array with the affine user coordinates of the point. + * {@link JXG.Options#elements}, and - optionally - a name and an id. */ - JXG.Transformation = function (board, type, params) { - this.elementClass = Const.OBJECT_CLASS_OTHER; - this.type = Const.OBJECT_TYPE_TRANSFORMATION; - this.matrix = [ - [1, 0, 0], - [0, 1, 0], - [0, 0, 1] - ]; - this.board = board; - this.isNumericMatrix = false; - this.setMatrix(board, type, params); + JXG.CoordsElement = function (coordinates, isLabel) { + var i; - this.methodMap = { - apply: 'apply', - applyOnce: 'applyOnce', - bindTo: 'bindTo', - bind: 'bind', - melt: 'melt' - }; - }; + if (!Type.exists(coordinates)) { + coordinates = [1, 0, 0]; + } - JXG.Transformation.prototype = {}; + for (i = 0; i < coordinates.length; ++i) { + coordinates[i] = parseFloat(coordinates[i]); + } - JXG.extend(JXG.Transformation.prototype, /** @lends JXG.Transformation.prototype */ { /** - * Updates the numerical data for the transformation, i.e. the entry of the subobject matrix. - * @returns {JXG.Transform} returns pointer to itself + * Coordinates of the element. + * @type JXG.Coords + * @private */ - update: function () { - return this; - }, + this.coords = new Coords(Const.COORDS_BY_USER, coordinates, this.board); + this.initialCoords = new Coords(Const.COORDS_BY_USER, coordinates, this.board); /** - * Set the transformation matrix for different types of standard transforms. - * @param {JXG.Board} board - * @param {String} type Transformation type, possible values are - * 'translate', 'scale', 'reflect', 'rotate', - * 'shear', 'generic'. - * @param {Array} params Parameters for the various transformation types. - * - * <p>These are - * @param {Array} x,y Shift vector (number or function) in case of 'translate'. - * @param {Array} scale_x,scale_y Scale vector (number or function) in case of 'scale'. - * @param {Array} line|point_pair|"four coordinates" In case of 'reflect' the parameters could - * be a line, a pair of points or four number (or functions) p_x, p_y, q_x, q_y, - * determining a line through points (p_x, p_y) and (q_x, q_y). - * @param {Array} angle,x,y|angle,[x,y] In case of 'rotate' the parameters are an angle or angle function, - * returning the angle in Radians and - optionally - a coordinate pair or a point defining the - * returning the angle in Radians and - optionally - a coordinate pair defining the - * rotation center. If the rotation center is not given, the transformation rotates around (0,0). - * @param {Array} shear_x,shear_y Shear vector (number or function) in case of 'shear'. - * @param {Array} a,b,c,d,e,f,g,h,i Nine matrix entries (numbers or functions) for a generic - * projective transformation in case of 'generic'. - * - * <p>A transformation with a generic matrix looks like: - * <pre> - * ( a b c ) ( z ) - * ( d e f ) * ( x ) - * ( g h i ) ( y ) - * </pre> + * Relative position on a slide element (line, circle, curve) if element is a glider on this element. + * @type Number + * @private + */ + this.position = null; + + /** + * True if there the method this.updateConstraint() has been set. It is + * probably different from the prototype function() {return this;}. + * Used in updateCoords fo glider elements. * + * @see JXG.CoordsElement#updateCoords + * @type Boolean + * @private */ - setMatrix: function (board, type, params) { - var i; + this.isConstrained = false; - this.isNumericMatrix = true; + /** + * Determines whether the element slides on a polygon if point is a glider. + * @type Boolean + * @default false + * @private + */ + this.onPolygon = false; - for (i = 0; i < params.length; i++) { - if (typeof params[i] !== 'number') { - this.isNumericMatrix = false; - break; - } - } + /** + * When used as a glider this member stores the object, where to glide on. + * To set the object to glide on use the method + * {@link JXG.Point#makeGlider} and DO NOT set this property directly + * as it will break the dependency tree. + * @type JXG.GeometryElement + */ + this.slideObject = null; - if (type === 'translate') { - if (params.length !== 2) { - throw new Error("JSXGraph: translate transformation needs 2 parameters."); - } - this.evalParam = Type.createEvalFunction(board, params, 2); - this.update = function () { - this.matrix[1][0] = this.evalParam(0); - this.matrix[2][0] = this.evalParam(1); - }; - } else if (type === 'scale') { - if (params.length !== 2) { - throw new Error("JSXGraph: scale transformation needs 2 parameters."); - } - this.evalParam = Type.createEvalFunction(board, params, 2); - this.update = function () { - this.matrix[1][1] = this.evalParam(0); // x - this.matrix[2][2] = this.evalParam(1); // y - }; - // Input: line or two points - } else if (type === 'reflect') { - // line or two points - if (params.length < 4) { - params[0] = board.select(params[0]); - } + /** + * List of elements the element is bound to, i.e. the element glides on. + * Only the last entry is active. + * Use {@link JXG.Point#popSlideObject} to remove the currently active slideObject. + */ + this.slideObjects = []; - // two points - if (params.length === 2) { - params[1] = board.select(params[1]); - } + /** + * A {@link JXG.CoordsElement#updateGlider} call is usually followed + * by a general {@link JXG.Board#update} which calls + * {@link JXG.CoordsElement#updateGliderFromParent}. + * To prevent double updates, {@link JXG.CoordsElement#needsUpdateFromParent} + * is set to false in updateGlider() and reset to true in the following call to + * {@link JXG.CoordsElement#updateGliderFromParent} + * @type Boolean + */ + this.needsUpdateFromParent = true; - // 4 coordinates [px,py,qx,qy] - if (params.length === 4) { - this.evalParam = Type.createEvalFunction(board, params, 4); - } + /** + * Stores the groups of this element in an array of Group. + * @type Array + * @see JXG.Group + * @private + */ + this.groups = []; - this.update = function () { - var x, y, z, xoff, yoff, d, - v, p; - // Determine homogeneous coordinates of reflections axis - // line - if (params.length === 1) { - v = params[0].stdform; - // two points - } else if (params.length === 2) { - v = Mat.crossProduct(params[1].coords.usrCoords, params[0].coords.usrCoords); - // two points coordinates [px,py,qx,qy] - } else if (params.length === 4) { - v = Mat.crossProduct( - [1, this.evalParam(2), this.evalParam(3)], - [1, this.evalParam(0), this.evalParam(1)] - ); - } + /* + * Do we need this? + */ + this.Xjc = null; + this.Yjc = null; - // Project origin to the line. This gives a finite point p - x = v[1]; - y = v[2]; - z = v[0]; - p = [-z * x, -z * y, x * x + y * y]; - d = p[2]; + // documented in GeometryElement + this.methodMap = Type.deepCopy(this.methodMap, { + move: 'moveTo', + moveTo: 'moveTo', + moveAlong: 'moveAlong', + visit: 'visit', + glide: 'makeGlider', + makeGlider: 'makeGlider', + intersect: 'makeIntersection', + makeIntersection: 'makeIntersection', + X: 'X', + Y: 'Y', + free: 'free', + setPosition: 'setGliderPosition', + setGliderPosition: 'setGliderPosition', + addConstraint: 'addConstraint', + dist: 'Dist', + onPolygon: 'onPolygon' + }); - // Normalize p - xoff = p[0] / p[2]; - yoff = p[1] / p[2]; + /* + * this.element may have been set by the object constructor. + */ + if (Type.exists(this.element)) { + this.addAnchor(coordinates, isLabel); + } + this.isDraggable = true; - // x, y is the direction of the line - x = -v[2]; - y = v[1]; + }; - this.matrix[1][1] = (x * x - y * y) / d; - this.matrix[1][2] = 2 * x * y / d; - this.matrix[2][1] = this.matrix[1][2]; - this.matrix[2][2] = -this.matrix[1][1]; - this.matrix[1][0] = xoff * (1 - this.matrix[1][1]) - yoff * this.matrix[1][2]; - this.matrix[2][0] = yoff * (1 - this.matrix[2][2]) - xoff * this.matrix[2][1]; - }; - } else if (type === 'rotate') { - // angle, x, y - if (params.length === 3) { - this.evalParam = Type.createEvalFunction(board, params, 3); - // angle, p or angle - } else if (params.length > 0 && params.length <= 2) { - this.evalParam = Type.createEvalFunction(board, params, 1); + JXG.extend(JXG.CoordsElement.prototype, /** @lends JXG.CoordsElement.prototype */ { + /** + * Dummy function for unconstrained points or gliders. + * @private + */ + updateConstraint: function () { + return this; + }, - if (params.length === 2 && !Type.isArray(params[1])) { - params[1] = board.select(params[1]); - } - } + /** + * Updates the coordinates of the element. + * @private + */ + updateCoords: function (fromParent) { + if (!this.needsUpdate) { + return this; + } - this.update = function () { - var x, y, - beta = this.evalParam(0), - co = Math.cos(beta), - si = Math.sin(beta); + if (!Type.exists(fromParent)) { + fromParent = false; + } - this.matrix[1][1] = co; - this.matrix[1][2] = -si; - this.matrix[2][1] = si; - this.matrix[2][2] = co; + if (!Type.evaluate(this.visProp.frozen)) { + this.updateConstraint(); + } - // rotate around [x,y] otherwise rotate around [0,0] - if (params.length > 1) { - if (params.length === 3) { - x = this.evalParam(1); - y = this.evalParam(2); - } else { - if (Type.isArray(params[1])) { - x = params[1][0]; - y = params[1][1]; - } else { - x = params[1].X(); - y = params[1].Y(); - } - } - this.matrix[1][0] = x * (1 - co) + y * si; - this.matrix[2][0] = y * (1 - co) - x * si; - } - }; - } else if (type === 'shear') { - if (params.length !== 2) { - throw new Error("JSXGraph: shear transformation needs 2 parameters."); + /* + * We need to calculate the new coordinates no matter of the elements visibility because + * a child could be visible and depend on the coordinates of the element/point (e.g. perpendicular). + * + * Check if the element is a glider and calculate new coords in dependency of this.slideObject. + * This function is called with fromParent==true in case it is a glider element for example if + * the defining elements of the line or circle have been changed. + */ + if (this.type === Const.OBJECT_TYPE_GLIDER) { + if (this.isConstrained) { + fromParent = false; } - this.evalParam = Type.createEvalFunction(board, params, 2); - this.update = function () { - this.matrix[1][2] = this.evalParam(0); - this.matrix[2][1] = this.evalParam(1); - }; - } else if (type === 'generic') { - if (params.length !== 9) { - throw new Error("JSXGraph: generic transformation needs 9 parameters."); + if (fromParent) { + this.updateGliderFromParent(); + } else { + this.updateGlider(); } - - this.evalParam = Type.createEvalFunction(board, params, 9); - - this.update = function () { - this.matrix[0][0] = this.evalParam(0); - this.matrix[0][1] = this.evalParam(1); - this.matrix[0][2] = this.evalParam(2); - this.matrix[1][0] = this.evalParam(3); - this.matrix[1][1] = this.evalParam(4); - this.matrix[1][2] = this.evalParam(5); - this.matrix[2][0] = this.evalParam(6); - this.matrix[2][1] = this.evalParam(7); - this.matrix[2][2] = this.evalParam(8); - }; } - }, - /** - * Transform a GeometryElement: - * First, the transformation matrix is updated, then do the matrix-vector-multiplication. - * @param {JXG.GeometryElement} p element which is transformed - * @param {String} 'self' Apply the transformation to the initialCoords instead of the coords if this is set. - * @returns {Array} - */ - apply: function (p, self) { - this.update(); + this.updateTransform(fromParent); - if (Type.exists(self)) { - return Mat.matVecMult(this.matrix, p.initialCoords.usrCoords); - } - return Mat.matVecMult(this.matrix, p.coords.usrCoords); + return this; }, /** - * Applies a transformation once to a GeometryElement or an array of elements. - * If it is a free point, then it can be dragged around later - * and will overwrite the transformed coordinates. - * @param {JXG.Point,Array} p + * Update of glider in case of dragging the glider or setting the postion of the glider. + * The relative position of the glider has to be updated. + * + * In case of a glider on a line: + * If the second point is an ideal point, then -1 < this.position < 1, + * this.position==+/-1 equals point2, this.position==0 equals point1 + * + * If the first point is an ideal point, then 0 < this.position < 2 + * this.position==0 or 2 equals point1, this.position==1 equals point2 + * + * @private */ - applyOnce: function (p) { - var c, len, i; + updateGlider: function () { + var i, p1c, p2c, d, v, poly, cc, pos, sgn, + alpha, beta, + delta = 2.0 * Math.PI, + angle, + cp, c, invMat, newCoords, newPos, + doRound = false, + ev_sw, + slide = this.slideObject, + res, cu, + slides = [], + isTransformed; - if (!Type.isArray(p)) { - p = [p]; - } + this.needsUpdateFromParent = false; + if (slide.elementClass === Const.OBJECT_CLASS_CIRCLE) { + if (Type.evaluate(this.visProp.isgeonext)) { + delta = 1.0; + } + newCoords = Geometry.projectPointToCircle(this, slide, this.board); + newPos = Geometry.rad([slide.center.X() + 1.0, slide.center.Y()], slide.center, this) / delta; + } else if (slide.elementClass === Const.OBJECT_CLASS_LINE) { + /* + * onPolygon==true: the point is a slider on a segment and this segment is one of the + * "borders" of a polygon. + * This is a GEONExT feature. + */ + if (this.onPolygon) { + p1c = slide.point1.coords.usrCoords; + p2c = slide.point2.coords.usrCoords; + i = 1; + d = p2c[i] - p1c[i]; - len = p.length; + if (Math.abs(d) < Mat.eps) { + i = 2; + d = p2c[i] - p1c[i]; + } - for (i = 0; i < len; i++) { - this.update(); - c = Mat.matVecMult(this.matrix, p[i].coords.usrCoords); - p[i].coords.setCoordinates(Const.COORDS_BY_USER, c); - } - }, + cc = Geometry.projectPointToLine(this, slide, this.board); + pos = (cc.usrCoords[i] - p1c[i]) / d; + poly = slide.parentPolygon; - /** - * Binds a transformation to a GeometryElement or an array of elements. In every update of the - * GeometryElement(s), the transformation is executed. That means, in order to immediately - * apply the transformation, a call of board.update() has to follow. - * @param {Array,JXG.Object} p JXG.Object or array of JXG.Object to - * which the transformation is bound to. - */ - bindTo: function (p) { - var i, len; - if (Type.isArray(p)) { - len = p.length; + if (pos < 0) { + for (i = 0; i < poly.borders.length; i++) { + if (slide === poly.borders[i]) { + slide = poly.borders[(i - 1 + poly.borders.length) % poly.borders.length]; + break; + } + } + } else if (pos > 1.0) { + for (i = 0; i < poly.borders.length; i++) { + if (slide === poly.borders[i]) { + slide = poly.borders[(i + 1 + poly.borders.length) % poly.borders.length]; + break; + } + } + } - for (i = 0; i < len; i++) { - p[i].transformations.push(this); + // If the slide object has changed, save the change to the glider. + if (slide.id !== this.slideObject.id) { + this.slideObject = slide; + } } - } else { - p.transformations.push(this); - } - }, - /** - * Unused - * @deprecated Use setAttribute - * @param term - */ - setProperty: function (term) { - JXG.deprecated('Transformation.setProperty()', 'Transformation.setAttribute()'); - }, + p1c = slide.point1.coords; + p2c = slide.point2.coords; - /** - * Empty method. Unused. - * @param {Object} term Key-value pairs of the attributes. - */ - setAttribute: function (term) { }, + // Distance between the two defining points + d = p1c.distance(Const.COORDS_BY_USER, p2c); - /** - * Combine two transformations to one transformation. This only works if - * both of transformation matrices consist solely of numbers, and do not - * contain functions. - * - * Multiplies the transformation with a transformation t from the left. - * i.e. (this) = (t) join (this) - * @param {JXG.Transform} t Transformation which is the left multiplicand - * @returns {JXG.Transform} the transformation object. - */ - melt: function (t) { - var res = [], i, len, len0, k, s, j; + // The defining points are identical + if (d < Mat.eps) { + //this.coords.setCoordinates(Const.COORDS_BY_USER, p1c); + newCoords = p1c; + doRound = true; + newPos = 0.0; + } else { + newCoords = Geometry.projectPointToLine(this, slide, this.board); + p1c = p1c.usrCoords.slice(0); + p2c = p2c.usrCoords.slice(0); - len = t.matrix.length; - len0 = this.matrix[0].length; + // The second point is an ideal point + if (Math.abs(p2c[0]) < Mat.eps) { + i = 1; + d = p2c[i]; - for (i = 0; i < len; i++) { - res[i] = []; - } + if (Math.abs(d) < Mat.eps) { + i = 2; + d = p2c[i]; + } - this.update(); - t.update(); + d = (newCoords.usrCoords[i] - p1c[i]) / d; + sgn = (d >= 0) ? 1 : -1; + d = Math.abs(d); + newPos = sgn * d / (d + 1); - for (i = 0; i < len; i++) { - for (j = 0; j < len0; j++) { - s = 0; - for (k = 0; k < len; k++) { - s += t.matrix[i][k] * this.matrix[k][j]; + // The first point is an ideal point + } else if (Math.abs(p1c[0]) < Mat.eps) { + i = 1; + d = p1c[i]; + + if (Math.abs(d) < Mat.eps) { + i = 2; + d = p1c[i]; + } + + d = (newCoords.usrCoords[i] - p2c[i]) / d; + + // 1.0 - d/(1-d); + if (d < 0.0) { + newPos = (1 - 2.0 * d) / (1.0 - d); + } else { + newPos = 1 / (d + 1); + } + } else { + i = 1; + d = p2c[i] - p1c[i]; + + if (Math.abs(d) < Mat.eps) { + i = 2; + d = p2c[i] - p1c[i]; + } + newPos = (newCoords.usrCoords[i] - p1c[i]) / d; } - res[i][j] = s; } - } - this.update = function () { - var len = this.matrix.length, - len0 = this.matrix[0].length; + // Snap the glider point of the slider into its appropiate position + // First, recalculate the new value of this.position + // Second, call update(fromParent==true) to make the positioning snappier. + ev_sw = Type.evaluate(this.visProp.snapwidth); + if (Type.evaluate(ev_sw) > 0.0 && + Math.abs(this._smax - this._smin) >= Mat.eps) { + newPos = Math.max(Math.min(newPos, 1), 0); - for (i = 0; i < len; i++) { - for (j = 0; j < len0; j++) { - this.matrix[i][j] = res[i][j]; + v = newPos * (this._smax - this._smin) + this._smin; + v = Math.round(v / ev_sw) * ev_sw; + newPos = (v - this._smin) / (this._smax - this._smin); + this.update(true); + } + + p1c = slide.point1.coords; + if (!Type.evaluate(slide.visProp.straightfirst) && + Math.abs(p1c.usrCoords[0]) > Mat.eps && newPos < 0) { + newCoords = p1c; + doRound = true; + newPos = 0; + } + + p2c = slide.point2.coords; + if (!Type.evaluate(slide.visProp.straightlast) && + Math.abs(p2c.usrCoords[0]) > Mat.eps && newPos > 1) { + newCoords = p2c; + doRound = true; + newPos = 1; + } + } else if (slide.type === Const.OBJECT_TYPE_TURTLE) { + // In case, the point is a constrained glider. + this.updateConstraint(); + res = Geometry.projectPointToTurtle(this, slide, this.board); + newCoords = res[0]; + newPos = res[1]; // save position for the overwriting below + } else if (slide.elementClass === Const.OBJECT_CLASS_CURVE) { + if ((slide.type === Const.OBJECT_TYPE_ARC || + slide.type === Const.OBJECT_TYPE_SECTOR)) { + newCoords = Geometry.projectPointToCircle(this, slide, this.board); + + angle = Geometry.rad(slide.radiuspoint, slide.center, this); + alpha = 0.0; + beta = Geometry.rad(slide.radiuspoint, slide.center, slide.anglepoint); + newPos = angle; + + ev_sw = Type.evaluate(slide.visProp.selection); + if ((ev_sw === 'minor' && beta > Math.PI) || + (ev_sw === 'major' && beta < Math.PI)) { + alpha = beta; + beta = 2 * Math.PI; + } + + // Correct the position if we are outside of the sector/arc + if (angle < alpha || angle > beta) { + newPos = beta; + + if ((angle < alpha && angle > alpha * 0.5) || (angle > beta && angle > beta * 0.5 + Math.PI)) { + newPos = alpha; + } + + this.needsUpdateFromParent = true; + this.updateGliderFromParent(); + } + + delta = beta - alpha; + if (this.visProp.isgeonext) { + delta = 1.0; + } + if (Math.abs(delta) > Mat.eps) { + newPos /= delta; + } + } else { + // In case, the point is a constrained glider. + this.updateConstraint(); + + // Handle the case if the curve comes from a transformation of a continous curve. + if (slide.transformations.length > 0) { + isTransformed = false; + res = slide.getTransformationSource(); + if (res[0]) { + isTransformed = res[0]; + slides.push(slide); + slides.push(res[1]); + } + // Recurse + while (res[0] && Type.exists(res[1]._transformationSource)) { + res = res[1].getTransformationSource(); + slides.push(res[1]); + } + + cu = this.coords.usrCoords; + if (isTransformed) { + for (i = 0; i < slides.length; i++) { + slides[i].updateTransformMatrix(); + invMat = Mat.inverse(slides[i].transformMat); + cu = Mat.matVecMult(invMat, cu); + } + cp = (new Coords(Const.COORDS_BY_USER, cu, this.board)).usrCoords; + c = Geometry.projectCoordsToCurve(cp[1], cp[2], + this.position || 0, + slides[slides.length - 1], + this.board); + // projectPointCurve() already would apply the transformation. + // Since we are projecting on the original curve, we have to do + // the transformations "by hand". + cu = c[0].usrCoords; + for (i = slides.length - 2; i >= 0; i--) { + cu = Mat.matVecMult(slides[i].transformMat, cu); + } + c[0] = new Coords(Const.COORDS_BY_USER, cu, this.board); + } else { + slide.updateTransformMatrix(); + invMat = Mat.inverse(slide.transformMat); + cu = Mat.matVecMult(invMat, cu); + cp = (new Coords(Const.COORDS_BY_USER, cu, this.board)).usrCoords; + c = Geometry.projectCoordsToCurve(cp[1], cp[2], this.position || 0, slide, this.board); + } + + newCoords = c[0]; + newPos = c[1]; + } else { + res = Geometry.projectPointToCurve(this, slide, this.board); + newCoords = res[0]; + newPos = res[1]; // save position for the overwriting below } } - }; - return this; + } else if (Type.isPoint(slide)) { + //this.coords.setCoordinates(Const.COORDS_BY_USER, Geometry.projectPointToPoint(this, slide, this.board).usrCoords, false); + newCoords = Geometry.projectPointToPoint(this, slide, this.board); + newPos = this.position; // save position for the overwriting below + } + + this.coords.setCoordinates(Const.COORDS_BY_USER, newCoords.usrCoords, doRound); + this.position = newPos; }, - // documented in element.js - // Not yet, since transformations are not listed in board.objects. - getParents: function () { - var p = [[].concat.apply([], this.matrix)]; + /** + * Update of a glider in case a parent element has been updated. That means the + * relative position of the glider stays the same. + * @private + */ + updateGliderFromParent: function () { + var p1c, p2c, r, lbda, c, + slide = this.slideObject, + slides = [], + res, i, + isTransformed, + baseangle, alpha, angle, beta, + delta = 2.0 * Math.PI; - if (this.parents.length !== 0) { - p = this.parents; + if (!this.needsUpdateFromParent) { + this.needsUpdateFromParent = true; + return; } - return p; - } + if (slide.elementClass === Const.OBJECT_CLASS_CIRCLE) { + r = slide.Radius(); + if (Type.evaluate(this.visProp.isgeonext)) { + delta = 1.0; + } + c = [ + slide.center.X() + r * Math.cos(this.position * delta), + slide.center.Y() + r * Math.sin(this.position * delta) + ]; + } else if (slide.elementClass === Const.OBJECT_CLASS_LINE) { + p1c = slide.point1.coords.usrCoords; + p2c = slide.point2.coords.usrCoords; - }); + // If one of the defining points of the line does not exist, + // the glider should disappear + if ((p1c[0] === 0 && p1c[1] === 0 && p1c[2] === 0) || + (p2c[0] === 0 && p2c[1] === 0 && p2c[2] === 0)) { + c = [0, 0, 0]; + // The second point is an ideal point + } else if (Math.abs(p2c[0]) < Mat.eps) { + lbda = Math.min(Math.abs(this.position), 1 - Mat.eps); + lbda /= (1.0 - lbda); - /** - * @class This element is used to provide projective transformations. - * @pseudo - * @description A transformation consists of a 3x3 matrix, i.e. it is a projective transformation. - * @name Transformation - * @augments JXG.Transformation - * @constructor - * @type JXG.Transformation - * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {numbers,functions} parameters The parameters depend on the transformation type, supplied as attribute 'type'. - * Possible transformation types are - * <ul><li> 'translate' - * <li> 'scale' - * <li> 'reflect' - * <li> 'rotate' - * <li> 'shear' - * <li> 'generic' - * </ul> - * The transformation matrix then looks like: - * <p> - * Translation matrix: - * <pre> - * ( 1 0 0) ( z ) - * ( a 1 0) * ( x ) - * ( b 0 1) ( y ) - * </pre> - * - * <p> - * Scale matrix: - * <pre> - * ( 1 0 0) ( z ) - * ( 0 a 0) * ( x ) - * ( 0 0 b) ( y ) - * </pre> - * - * <p> - * A rotation matrix with angle a (in Radians) - * <pre> - * ( 1 0 0 ) ( z ) - * ( 0 cos(a) -sin(a)) * ( x ) - * ( 0 sin(a) cos(a) ) ( y ) - * </pre> - * - * <p> - * Shear matrix: - * <pre> - * ( 1 0 0) ( z ) - * ( 0 1 a) * ( x ) - * ( 0 b 1) ( y ) - * </pre> - * - * <p>Generic transformation: - * <pre> - * ( a b c ) ( z ) - * ( d e f ) * ( x ) - * ( g h i ) ( y ) - * </pre> - * - * @see JXG.Transformation#setMatrix - * - * @example - * // The point B is determined by taking twice the vector A from the origin - * - * var p0 = board.create('point', [0, 3], {name: 'A'}), - * t = board.create('transform', [function(){ return p0.X(); }, "Y(A)"], {type: 'translate'}), - * p1 = board.create('point', [p0, t], {color: 'blue'}); - * - * </pre><div class="jxgbox" id="JXG14167b0c-2ad3-11e5-8dd9-901b0e1b8723" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function() { - * var board = JXG.JSXGraph.initBoard('JXG14167b0c-2ad3-11e5-8dd9-901b0e1b8723', - * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); - * var p0 = board.create('point', [0, 3], {name: 'A'}), - * t = board.create('transform', [function(){ return p0.X(); }, "Y(A)"], {type:'translate'}), - * p1 = board.create('point', [p0, t], {color: 'blue'}); - * - * })(); - * - * </script><pre> - * - * @example - * // The point B is the result of scaling the point A with factor 2 in horizontal direction - * // and with factor 0.5 in vertical direction. - * - * var p1 = board.create('point', [1, 1]), - * t = board.create('transform', [2, 0.5], {type: 'scale'}), - * p2 = board.create('point', [p1, t], {color: 'blue'}); - * - * </pre><div class="jxgbox" id="JXGa6827a72-2ad3-11e5-8dd9-901b0e1b8723" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function() { - * var board = JXG.JSXGraph.initBoard('JXGa6827a72-2ad3-11e5-8dd9-901b0e1b8723', - * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); - * var p1 = board.create('point', [1, 1]), - * t = board.create('transform', [2, 0.5], {type: 'scale'}), - * p2 = board.create('point', [p1, t], {color: 'blue'}); - * - * })(); - * - * </script><pre> - * - * @example - * // The point B is rotated around C which gives point D. The angle is determined - * // by the vertical height of point A. - * - * var p0 = board.create('point', [0, 3], {name: 'A'}), - * p1 = board.create('point', [1, 1]), - * p2 = board.create('point', [2, 1], {name:'C', fixed: true}), - * - * // angle, rotation center: - * t = board.create('transform', ['Y(A)', p2], {type: 'rotate'}), - * p3 = board.create('point', [p1, t], {color: 'blue'}); - * - * </pre><div class="jxgbox" id="JXG747cf11e-2ad4-11e5-8dd9-901b0e1b8723" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function() { - * var board = JXG.JSXGraph.initBoard('JXG747cf11e-2ad4-11e5-8dd9-901b0e1b8723', - * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); - * var p0 = board.create('point', [0, 3], {name: 'A'}), - * p1 = board.create('point', [1, 1]), - * p2 = board.create('point', [2, 1], {name:'C', fixed: true}), - * - * // angle, rotation center: - * t = board.create('transform', ['Y(A)', p2], {type: 'rotate'}), - * p3 = board.create('point', [p1, t], {color: 'blue'}); - * - * })(); - * - * </script><pre> - * - * @example - * // A concatenation of several transformations. - * var p1 = board.create('point', [1, 1]), - * t1 = board.create('transform', [-2, -1], {type: 'translate'}), - * t2 = board.create('transform', [Math.PI/4], {type: 'rotate'}), - * t3 = board.create('transform', [2, 1], {type: 'translate'}), - * p2 = board.create('point', [p1, [t1, t2, t3]], {color: 'blue'}); - * - * </pre><div class="jxgbox" id="JXGf516d3de-2ad5-11e5-8dd9-901b0e1b8723" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function() { - * var board = JXG.JSXGraph.initBoard('JXGf516d3de-2ad5-11e5-8dd9-901b0e1b8723', - * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); - * var p1 = board.create('point', [1, 1]), - * t1 = board.create('transform', [-2, -1], {type:'translate'}), - * t2 = board.create('transform', [Math.PI/4], {type:'rotate'}), - * t3 = board.create('transform', [2, 1], {type:'translate'}), - * p2 = board.create('point', [p1, [t1, t2, t3]], {color: 'blue'}); - * - * })(); - * - * </script><pre> - * - * @example - * // Reflection of point A - * var p1 = board.create('point', [1, 1]), - * p2 = board.create('point', [1, 3]), - * p3 = board.create('point', [-2, 0]), - * l = board.create('line', [p2, p3]), - * t = board.create('transform', [l], {type: 'reflect'}), // Possible are l, l.id, l.name - * p4 = board.create('point', [p1, t], {color: 'blue'}); - * - * </pre><div class="jxgbox" id="JXG6f374a04-2ad6-11e5-8dd9-901b0e1b8723" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function() { - * var board = JXG.JSXGraph.initBoard('JXG6f374a04-2ad6-11e5-8dd9-901b0e1b8723', - * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); - * var p1 = board.create('point', [1, 1]), - * p2 = board.create('point', [1, 3]), - * p3 = board.create('point', [-2, 0]), - * l = board.create('line', [p2, p3]), - * t = board.create('transform', [l], {type:'reflect'}), // Possible are l, l.id, l.name - * p4 = board.create('point', [p1, t], {color: 'blue'}); - * - * })(); - * - * </script><pre> - * - * @example - * // One time application of a transform to points A, B - * var p1 = board.create('point', [1, 1]), - * p2 = board.create('point', [1, 1]), - * t = board.create('transform', [3, 2], {type: 'shear'}); - * t.applyOnce([p1, p2]); - * - * </pre><div class="jxgbox" id="JXGb6cee1c4-2ad6-11e5-8dd9-901b0e1b8723" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function() { - * var board = JXG.JSXGraph.initBoard('JXGb6cee1c4-2ad6-11e5-8dd9-901b0e1b8723', - * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); - * var p1 = board.create('point', [1, 1]), - * p2 = board.create('point', [-1, -2]), - * t = board.create('transform', [3, 2], {type: 'shear'}); - * t.applyOnce([p1, p2]); - * - * })(); - * - * </script><pre> - * - * @example - * // Construct a square of side length 2 with the - * // help of transformations - * var sq = [], - * right = board.create('transform', [2, 0], {type: 'translate'}), - * up = board.create('transform', [0, 2], {type: 'translate'}), - * pol, rot, p0; - * - * // The first point is free - * sq[0] = board.create('point', [0, 0], {name: 'Drag me'}), - * - * // Construct the other free points by transformations - * sq[1] = board.create('point', [sq[0], right]), - * sq[2] = board.create('point', [sq[0], [right, up]]), - * sq[3] = board.create('point', [sq[0], up]), - * - * // Polygon through these four points - * pol = board.create('polygon', sq, { - * fillColor:'blue', - * gradient:'radial', - * gradientsecondcolor:'white', - * gradientSecondOpacity:'0' - * }), - * - * p0 = board.create('point', [0, 3], {name: 'angle'}), - * // Rotate the square around point sq[0] by dragging A - * rot = board.create('transform', ['Y(angle)', sq[0]], {type: 'rotate'}); - * - * // Apply the rotation to all but the first point of the square - * rot.bindTo(sq.slice(1)); - * - * </pre><div class="jxgbox" id="JXGc7f9097e-2ad7-11e5-8dd9-901b0e1b8723" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function() { - * var board = JXG.JSXGraph.initBoard('JXGc7f9097e-2ad7-11e5-8dd9-901b0e1b8723', - * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); - * // Construct a square of side length 2 with the - * // help of transformations - * var sq = [], - * right = board.create('transform', [2, 0], {type: 'translate'}), - * up = board.create('transform', [0, 2], {type: 'translate'}), - * pol, rot, p0; - * - * // The first point is free - * sq[0] = board.create('point', [0, 0], {name: 'Drag me'}), - * - * // Construct the other free points by transformations - * sq[1] = board.create('point', [sq[0], right]), - * sq[2] = board.create('point', [sq[0], [right, up]]), - * sq[3] = board.create('point', [sq[0], up]), - * - * // Polygon through these four points - * pol = board.create('polygon', sq, { - * fillColor:'blue', - * gradient:'radial', - * gradientsecondcolor:'white', - * gradientSecondOpacity:'0' - * }), - * - * p0 = board.create('point', [0, 3], {name: 'angle'}), - * // Rotate the square around point sq[0] by dragging A - * rot = board.create('transform', ['Y(angle)', sq[0]], {type: 'rotate'}); - * - * // Apply the rotation to all but the first point of the square - * rot.bindTo(sq.slice(1)); - * - * })(); - * - * </script><pre> - * - */ - JXG.createTransform = function (board, parents, attributes) { - return new JXG.Transformation(board, attributes.type, parents); - }; + if (this.position < 0) { + lbda = -lbda; + } - JXG.registerElement('transform', JXG.createTransform); + c = [ + p1c[0] + lbda * p2c[0], + p1c[1] + lbda * p2c[1], + p1c[2] + lbda * p2c[2] + ]; + // The first point is an ideal point + } else if (Math.abs(p1c[0]) < Mat.eps) { + lbda = Math.max(this.position, Mat.eps); + lbda = Math.min(lbda, 2 - Mat.eps); - return { - Transformation: JXG.Transformation, - createTransform: JXG.createTransform - }; -}); + if (lbda > 1) { + lbda = (lbda - 1) / (lbda - 2); + } else { + lbda = (1 - lbda) / lbda; + } -/* - Copyright 2008-2021 - Matthias Ehmann, - Michael Gerhaeuser, - Carsten Miller, - Alfred Wassermann + c = [ + p2c[0] + lbda * p1c[0], + p2c[1] + lbda * p1c[1], + p2c[2] + lbda * p1c[2] + ]; + } else { + lbda = this.position; + c = [ + p1c[0] + lbda * (p2c[0] - p1c[0]), + p1c[1] + lbda * (p2c[1] - p1c[1]), + p1c[2] + lbda * (p2c[2] - p1c[2]) + ]; + } + } else if (slide.type === Const.OBJECT_TYPE_TURTLE) { + this.coords.setCoordinates(Const.COORDS_BY_USER, [slide.Z(this.position), slide.X(this.position), slide.Y(this.position)]); + // In case, the point is a constrained glider. + this.updateConstraint(); + c = Geometry.projectPointToTurtle(this, slide, this.board)[0].usrCoords; + } else if (slide.elementClass === Const.OBJECT_CLASS_CURVE) { + // Handle the case if the curve comes from a transformation of a continuous curve. + isTransformed = false; + res = slide.getTransformationSource(); + if (res[0]) { + isTransformed = res[0]; + slides.push(slide); + slides.push(res[1]); + } + // Recurse + while (res[0] && Type.exists(res[1]._transformationSource)) { + res = res[1].getTransformationSource(); + slides.push(res[1]); + } + if (isTransformed) { + this.coords.setCoordinates(Const.COORDS_BY_USER, [ + slides[slides.length - 1].Z(this.position), + slides[slides.length - 1].X(this.position), + slides[slides.length - 1].Y(this.position)]); + } else { + this.coords.setCoordinates(Const.COORDS_BY_USER, [ + slide.Z(this.position), + slide.X(this.position), + slide.Y(this.position)]); + } - This file is part of JSXGraph. + if (slide.type === Const.OBJECT_TYPE_ARC || slide.type === Const.OBJECT_TYPE_SECTOR) { + baseangle = Geometry.rad([slide.center.X() + 1, slide.center.Y()], slide.center, slide.radiuspoint); - JSXGraph is free software dual licensed under the GNU LGPL or MIT License. + alpha = 0.0; + beta = Geometry.rad(slide.radiuspoint, slide.center, slide.anglepoint); - You can redistribute it and/or modify it under the terms of the + if ((slide.visProp.selection === 'minor' && beta > Math.PI) || + (slide.visProp.selection === 'major' && beta < Math.PI)) { + alpha = beta; + beta = 2 * Math.PI; + } - * GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version - OR - * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT + delta = beta - alpha; + if (Type.evaluate(this.visProp.isgeonext)) { + delta = 1.0; + } + angle = this.position * delta; - JSXGraph is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. + // Correct the position if we are outside of the sector/arc + if (angle < alpha || angle > beta) { + angle = beta; - You should have received a copy of the GNU Lesser General Public License and - the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> - and <http://opensource.org/licenses/MIT/>. - */ + if ((angle < alpha && angle > alpha * 0.5) || + (angle > beta && angle > beta * 0.5 + Math.PI)) { + angle = alpha; + } + this.position = angle; + if (Math.abs(delta) > Mat.eps) { + this.position /= delta; + } + } -/*global JXG: true, define: true, console: true, window: true*/ -/*jslint nomen: true, plusplus: true*/ + r = slide.Radius(); + c = [ + slide.center.X() + r * Math.cos(this.position * delta + baseangle), + slide.center.Y() + r * Math.sin(this.position * delta + baseangle) + ]; + } else { + // In case, the point is a constrained glider. + this.updateConstraint(); -/* depends: - jxg - options - math/math - math/geometry - math/numerics - base/coords - base/constants - base/element - parser/geonext - utils/type - elements: - transform - */ + if (isTransformed) { + c = Geometry.projectPointToCurve(this, slides[slides.length - 1], this.board)[0].usrCoords; + // projectPointCurve() already would do the transformation. + // But since we are projecting on the original curve, we have to do + // the transformation "by hand". + for (i = slides.length - 2; i >= 0; i--) { + c = (new Coords(Const.COORDS_BY_USER, + Mat.matVecMult(slides[i].transformMat, c), this.board)).usrCoords; + } -/** - * @fileoverview The geometry object CoordsElement is defined in this file. - * This object provides the coordinate handling of points, images and texts. - */ + } else { + c = Geometry.projectPointToCurve(this, slide, this.board)[0].usrCoords; + } + } -define('base/coordselement',[ - 'jxg', 'options', 'math/math', 'math/geometry', 'math/numerics', 'math/statistics', 'base/coords', 'base/constants', 'base/element', - 'parser/geonext', 'utils/type', 'base/transformation' -], function (JXG, Options, Mat, Geometry, Numerics, Statistics, Coords, Const, GeometryElement, GeonextParser, Type, Transform) { + } else if (Type.isPoint(slide)) { + c = Geometry.projectPointToPoint(this, slide, this.board).usrCoords; + } - "use strict"; + this.coords.setCoordinates(Const.COORDS_BY_USER, c, false); + }, - /** - * An element containing coords is the basic geometric element. Based on points lines and circles can be constructed which can be intersected - * which in turn are points again which can be used to construct new lines, circles, polygons, etc. This class holds methods for - * all kind of coordinate elements like points, texts and images. - * @class Creates a new coords element object. Do not use this constructor to create an element. - * - * @private - * @augments JXG.GeometryElement - * @param {Array} coordinates An array with the affine user coordinates of the point. - * {@link JXG.Options#elements}, and - optionally - a name and an id. - */ - JXG.CoordsElement = function (coordinates, isLabel) { - var i; + updateRendererGeneric: function (rendererMethod) { + //var wasReal; - if (!Type.exists(coordinates)) { - coordinates = [1, 0, 0]; - } + if (!this.needsUpdate) { + return this; + } - for (i = 0; i < coordinates.length; ++i) { - coordinates[i] = parseFloat(coordinates[i]); - } + if (this.visPropCalc.visible) { + //wasReal = this.isReal; + this.isReal = (!isNaN(this.coords.usrCoords[1] + this.coords.usrCoords[2])); + //Homogeneous coords: ideal point + this.isReal = (Math.abs(this.coords.usrCoords[0]) > Mat.eps) ? this.isReal : false; - /** - * Coordinates of the element. - * @type JXG.Coords - * @private - */ - this.coords = new Coords(Const.COORDS_BY_USER, coordinates, this.board); - this.initialCoords = new Coords(Const.COORDS_BY_USER, coordinates, this.board); + if (// wasReal && + !this.isReal) { + this.updateVisibility(false); + } + } - /** - * Relative position on a slide element (line, circle, curve) if element is a glider on this element. - * @type Number - * @private - */ - this.position = null; + // Call the renderer only if element is visible. + // Update the position + if (this.visPropCalc.visible) { + this.board.renderer[rendererMethod](this); + } + + // Update the label if visible. + if (this.hasLabel && this.visPropCalc.visible && this.label && + this.label.visPropCalc.visible && this.isReal) { + this.label.update(); + this.board.renderer.updateText(this.label); + } + + // Update rendNode display + this.setDisplayRendNode(); + // if (this.visPropCalc.visible !== this.visPropOld.visible) { + // this.board.renderer.display(this, this.visPropCalc.visible); + // this.visPropOld.visible = this.visPropCalc.visible; + // + // if (this.hasLabel) { + // this.board.renderer.display(this.label, this.label.visPropCalc.visible); + // } + // } + + this.needsUpdate = false; + return this; + }, /** - * Determines whether the element slides on a polygon if point is a glider. - * @type Boolean - * @default false - * @private + * Getter method for x, this is used by for CAS-points to access point coordinates. + * @returns {Number} User coordinate of point in x direction. */ - this.onPolygon = false; + X: function () { + return this.coords.usrCoords[1]; + }, /** - * When used as a glider this member stores the object, where to glide on. - * To set the object to glide on use the method - * {@link JXG.Point#makeGlider} and DO NOT set this property directly - * as it will break the dependency tree. - * @type JXG.GeometryElement + * Getter method for y, this is used by CAS-points to access point coordinates. + * @returns {Number} User coordinate of point in y direction. */ - this.slideObject = null; + Y: function () { + return this.coords.usrCoords[2]; + }, /** - * List of elements the element is bound to, i.e. the element glides on. - * Only the last entry is active. - * Use {@link JXG.Point#popSlideObject} to remove the currently active slideObject. + * Getter method for z, this is used by CAS-points to access point coordinates. + * @returns {Number} User coordinate of point in z direction. */ - this.slideObjects = []; + Z: function () { + return this.coords.usrCoords[0]; + }, /** - * A {@link JXG.CoordsElement#updateGlider} call is usually followed - * by a general {@link JXG.Board#update} which calls - * {@link JXG.CoordsElement#updateGliderFromParent}. - * To prevent double updates, {@link JXG.CoordsElement#needsUpdateFromParent} - * is set to false in updateGlider() and reset to true in the following call to - * {@link JXG.CoordsElement#updateGliderFromParent} - * @type {Boolean} + * New evaluation of the function term. + * This is required for CAS-points: Their XTerm() method is + * overwritten in {@link JXG.CoordsElement#addConstraint}. + * + * @returns {Number} User coordinate of point in x direction. + * @private */ - this.needsUpdateFromParent = true; + XEval: function () { + return this.coords.usrCoords[1]; + }, /** - * Dummy function for unconstrained points or gliders. + * New evaluation of the function term. + * This is required for CAS-points: Their YTerm() method is overwritten + * in {@link JXG.CoordsElement#addConstraint}. + * + * @returns {Number} User coordinate of point in y direction. * @private */ - this.updateConstraint = function () { - return this; - }; + YEval: function () { + return this.coords.usrCoords[2]; + }, /** - * Stores the groups of this element in an array of Group. - * @type Array - * @see JXG.Group + * New evaluation of the function term. + * This is required for CAS-points: Their ZTerm() method is overwritten in + * {@link JXG.CoordsElement#addConstraint}. + * + * @returns {Number} User coordinate of point in z direction. * @private */ - this.groups = []; + ZEval: function () { + return this.coords.usrCoords[0]; + }, - /* - * Do we need this? + /** + * Getter method for the distance to a second point, this is required for CAS-elements. + * Here, function inlining seems to be worthwile (for plotting). + * @param {JXG.Point} point2 The point to which the distance shall be calculated. + * @returns {Number} Distance in user coordinate to the given point */ - this.Xjc = null; - this.Yjc = null; - - // documented in GeometryElement - this.methodMap = Type.deepCopy(this.methodMap, { - move: 'moveTo', - moveTo: 'moveTo', - moveAlong: 'moveAlong', - visit: 'visit', - glide: 'makeGlider', - makeGlider: 'makeGlider', - intersect: 'makeIntersection', - makeIntersection: 'makeIntersection', - X: 'X', - Y: 'Y', - free: 'free', - setPosition: 'setGliderPosition', - setGliderPosition: 'setGliderPosition', - addConstraint: 'addConstraint', - dist: 'Dist', - onPolygon: 'onPolygon' - }); - - /* - * this.element may have been set by the object constructor. - */ - if (Type.exists(this.element)) { - this.addAnchor(coordinates, isLabel); - } - this.isDraggable = true; - - }; + Dist: function (point2) { + if (this.isReal && point2.isReal) { + return this.coords.distance(Const.COORDS_BY_USER, point2.coords); + } + return NaN; + }, - JXG.extend(JXG.CoordsElement.prototype, /** @lends JXG.CoordsElement.prototype */ { /** - * Updates the coordinates of the element. - * @private + * Alias for {@link JXG.Element#handleSnapToGrid} + * @param {Boolean} force force snapping independent from what the snaptogrid attribute says + * @returns {JXG.CoordsElement} Reference to this element */ - updateCoords: function (fromParent) { - if (!this.needsUpdate) { - return this; - } - - if (!Type.exists(fromParent)) { - fromParent = false; - } - - /* - * We need to calculate the new coordinates no matter of the elements visibility because - * a child could be visible and depend on the coordinates of the element/point (e.g. perpendicular). - * - * Check if the element is a glider and calculate new coords in dependency of this.slideObject. - * This function is called with fromParent==true in case it is a glider element for example if - * the defining elements of the line or circle have been changed. - */ - if (this.type === Const.OBJECT_TYPE_GLIDER) { - if (fromParent) { - this.updateGliderFromParent(); - } else { - this.updateGlider(); - } - } - - if (!Type.evaluate(this.visProp.frozen)) { - this.updateConstraint(); - } - this.updateTransform(); - - return this; + snapToGrid: function (force) { + return this.handleSnapToGrid(force); }, /** - * Update of glider in case of dragging the glider or setting the postion of the glider. - * The relative position of the glider has to be updated. - * - * In case of a glider on a line: - * If the second point is an ideal point, then -1 < this.position < 1, - * this.position==+/-1 equals point2, this.position==0 equals point1 - * - * If the first point is an ideal point, then 0 < this.position < 2 - * this.position==0 or 2 equals point1, this.position==1 equals point2 - * - * @private + * Let a point snap to the nearest point in distance of + * {@link JXG.Point#attractorDistance}. + * The function uses the coords object of the point as + * its actual position. + * @param {Boolean} force force snapping independent from what the snaptogrid attribute says + * @returns {JXG.Point} Reference to this element */ - updateGlider: function () { - var i, p1c, p2c, d, v, poly, cc, pos, sgn, - alpha, beta, - delta = 2.0 * Math.PI, - angle, - cp, c, invMat, newCoords, newPos, - doRound = false, - ev_sw, - slide = this.slideObject, - res, cu, - slides = [], - isTransformed; + handleSnapToPoints: function (force) { + var i, pEl, pCoords, + d = 0, + len, + dMax = Infinity, + c = null, + ev_au, ev_ad, + ev_is2p = Type.evaluate(this.visProp.ignoredsnaptopoints), + len2, j, ignore = false; - this.needsUpdateFromParent = false; - if (slide.elementClass === Const.OBJECT_CLASS_CIRCLE) { - if (Type.evaluate(this.visProp.isgeonext)) { - delta = 1.0; - } - //this.coords.setCoordinates(Const.COORDS_BY_USER, - // Geometry.projectPointToCircle(this, slide, this.board).usrCoords, false); - newCoords = Geometry.projectPointToCircle(this, slide, this.board); - newPos = Geometry.rad([slide.center.X() + 1.0, slide.center.Y()], slide.center, this) / delta; - } else if (slide.elementClass === Const.OBJECT_CLASS_LINE) { - /* - * onPolygon==true: the point is a slider on a segment and this segment is one of the - * "borders" of a polygon. - * This is a GEONExT feature. - */ - if (this.onPolygon) { - p1c = slide.point1.coords.usrCoords; - p2c = slide.point2.coords.usrCoords; - i = 1; - d = p2c[i] - p1c[i]; + len = this.board.objectsList.length; - if (Math.abs(d) < Mat.eps) { - i = 2; - d = p2c[i] - p1c[i]; - } + if (ev_is2p) { + len2 = ev_is2p.length; + } - cc = Geometry.projectPointToLine(this, slide, this.board); - pos = (cc.usrCoords[i] - p1c[i]) / d; - poly = slide.parentPolygon; + if (Type.evaluate(this.visProp.snaptopoints) || force) { + ev_au = Type.evaluate(this.visProp.attractorunit); + ev_ad = Type.evaluate(this.visProp.attractordistance); - if (pos < 0) { - for (i = 0; i < poly.borders.length; i++) { - if (slide === poly.borders[i]) { - slide = poly.borders[(i - 1 + poly.borders.length) % poly.borders.length]; + for (i = 0; i < len; i++) { + pEl = this.board.objectsList[i]; + + if (ev_is2p) { + ignore = false; + for (j = 0; j < len2; j++) { + if (pEl === this.board.select(ev_is2p[j])) { + ignore = true; break; } } - } else if (pos > 1.0) { - for (i = 0; i < poly.borders.length; i++) { - if (slide === poly.borders[i]) { - slide = poly.borders[(i + 1 + poly.borders.length) % poly.borders.length]; - break; - } + if (ignore) { + continue; } } - // If the slide object has changed, save the change to the glider. - if (slide.id !== this.slideObject.id) { - this.slideObject = slide; + if (Type.isPoint(pEl) && pEl !== this && pEl.visPropCalc.visible) { + pCoords = Geometry.projectPointToPoint(this, pEl, this.board); + if (ev_au === 'screen') { + d = pCoords.distance(Const.COORDS_BY_SCREEN, this.coords); + } else { + d = pCoords.distance(Const.COORDS_BY_USER, this.coords); + } + + if (d < ev_ad && d < dMax) { + dMax = d; + c = pCoords; + } } } - p1c = slide.point1.coords; - p2c = slide.point2.coords; - - // Distance between the two defining points - d = p1c.distance(Const.COORDS_BY_USER, p2c); - - // The defining points are identical - if (d < Mat.eps) { - //this.coords.setCoordinates(Const.COORDS_BY_USER, p1c); - newCoords = p1c; - doRound = true; - newPos = 0.0; - } else { - //this.coords.setCoordinates(Const.COORDS_BY_USER, Geometry.projectPointToLine(this, slide, this.board).usrCoords, false); - newCoords = Geometry.projectPointToLine(this, slide, this.board); - p1c = p1c.usrCoords.slice(0); - p2c = p2c.usrCoords.slice(0); - - // The second point is an ideal point - if (Math.abs(p2c[0]) < Mat.eps) { - i = 1; - d = p2c[i]; + if (c !== null) { + this.coords.setCoordinates(Const.COORDS_BY_USER, c.usrCoords); + } + } - if (Math.abs(d) < Mat.eps) { - i = 2; - d = p2c[i]; - } + return this; + }, - d = (newCoords.usrCoords[i] - p1c[i]) / d; - sgn = (d >= 0) ? 1 : -1; - d = Math.abs(d); - newPos = sgn * d / (d + 1); + /** + * Alias for {@link JXG.CoordsElement#handleSnapToPoints}. + * + * @param {Boolean} force force snapping independent from what the snaptogrid attribute says + * @returns {JXG.Point} Reference to this element + */ + snapToPoints: function (force) { + return this.handleSnapToPoints(force); + }, - // The first point is an ideal point - } else if (Math.abs(p1c[0]) < Mat.eps) { - i = 1; - d = p1c[i]; + /** + * A point can change its type from free point to glider + * and vice versa. If it is given an array of attractor elements + * (attribute attractors) and the attribute attractorDistance + * then the point will be made a glider if it less than attractorDistance + * apart from one of its attractor elements. + * If attractorDistance is equal to zero, the point stays in its + * current form. + * @returns {JXG.Point} Reference to this element + */ + handleAttractors: function () { + var i, el, projCoords, + d = 0.0, + projection, + ev_au = Type.evaluate(this.visProp.attractorunit), + ev_ad = Type.evaluate(this.visProp.attractordistance), + ev_sd = Type.evaluate(this.visProp.snatchdistance), + ev_a = Type.evaluate(this.visProp.attractors), + len = ev_a.length; - if (Math.abs(d) < Mat.eps) { - i = 2; - d = p1c[i]; - } + if (ev_ad === 0.0) { + return; + } - d = (newCoords.usrCoords[i] - p2c[i]) / d; + for (i = 0; i < len; i++) { + el = this.board.select(ev_a[i]); - // 1.0 - d/(1-d); - if (d < 0.0) { - newPos = (1 - 2.0 * d) / (1.0 - d); + if (Type.exists(el) && el !== this) { + if (Type.isPoint(el)) { + projCoords = Geometry.projectPointToPoint(this, el, this.board); + } else if (el.elementClass === Const.OBJECT_CLASS_LINE) { + projection = Geometry.projectCoordsToSegment( + this.coords.usrCoords, + el.point1.coords.usrCoords, + el.point2.coords.usrCoords); + if (!Type.evaluate(el.visProp.straightfirst) && projection[1] < 0.0) { + projCoords = el.point1.coords; + } else if (!Type.evaluate(el.visProp.straightlast) && projection[1] > 1.0) { + projCoords = el.point2.coords; } else { - newPos = 1 / (d + 1); + projCoords = new Coords(Const.COORDS_BY_USER, projection[0], this.board); } + } else if (el.elementClass === Const.OBJECT_CLASS_CIRCLE) { + projCoords = Geometry.projectPointToCircle(this, el, this.board); + } else if (el.elementClass === Const.OBJECT_CLASS_CURVE) { + projCoords = Geometry.projectPointToCurve(this, el, this.board)[0]; + } else if (el.type === Const.OBJECT_TYPE_TURTLE) { + projCoords = Geometry.projectPointToTurtle(this, el, this.board)[0]; + } else if (el.type === Const.OBJECT_TYPE_POLYGON) { + projCoords = new Coords(Const.COORDS_BY_USER, + Geometry.projectCoordsToPolygon(this.coords.usrCoords, el), + this.board); + } + + if (ev_au === 'screen') { + d = projCoords.distance(Const.COORDS_BY_SCREEN, this.coords); } else { - i = 1; - d = p2c[i] - p1c[i]; + d = projCoords.distance(Const.COORDS_BY_USER, this.coords); + } - if (Math.abs(d) < Mat.eps) { - i = 2; - d = p2c[i] - p1c[i]; + if (d < ev_ad) { + if (!(this.type === Const.OBJECT_TYPE_GLIDER && + (el === this.slideObject || this.slideObject && this.onPolygon && this.slideObject.parentPolygon === el) + ) + ) { + this.makeGlider(el); } - newPos = (newCoords.usrCoords[i] - p1c[i]) / d; + break; // bind the point to the first attractor in its list. + } + if (d >= ev_sd && + (el === this.slideObject || this.slideObject && this.onPolygon && this.slideObject.parentPolygon === el) + ) { + this.popSlideObject(); } } + } - // Snap the glider point of the slider into its appropiate position - // First, recalculate the new value of this.position - // Second, call update(fromParent==true) to make the positioning snappier. - ev_sw = Type.evaluate(this.visProp.snapwidth); - if (Type.evaluate(ev_sw) > 0.0 && - Math.abs(this._smax - this._smin) >= Mat.eps) { - newPos = Math.max(Math.min(newPos, 1), 0); + return this; + }, - v = newPos * (this._smax - this._smin) + this._smin; - v = Math.round(v / ev_sw) * ev_sw; - newPos = (v - this._smin) / (this._smax - this._smin); - this.update(true); - } + /** + * Sets coordinates and calls the point's update() method. + * @param {Number} method The type of coordinates used here. + * Possible values are {@link JXG.COORDS_BY_USER} and {@link JXG.COORDS_BY_SCREEN}. + * @param {Array} coords coordinates <tt>([z], x, y)</tt> in screen/user units + * @returns {JXG.Point} this element + */ + setPositionDirectly: function (method, coords) { + var i, c, dc, + oldCoords = this.coords, + newCoords; - p1c = slide.point1.coords; - if (!Type.evaluate(slide.visProp.straightfirst) && - Math.abs(p1c.usrCoords[0]) > Mat.eps && newPos < 0) { - newCoords = p1c; - doRound = true; - newPos = 0; + if (this.relativeCoords) { + c = new Coords(method, coords, this.board); + if (Type.evaluate(this.visProp.islabel)) { + dc = Statistics.subtract(c.scrCoords, oldCoords.scrCoords); + this.relativeCoords.scrCoords[1] += dc[1]; + this.relativeCoords.scrCoords[2] += dc[2]; + } else { + dc = Statistics.subtract(c.usrCoords, oldCoords.usrCoords); + this.relativeCoords.usrCoords[1] += dc[1]; + this.relativeCoords.usrCoords[2] += dc[2]; } - p2c = slide.point2.coords; - if (!Type.evaluate(slide.visProp.straightlast) && - Math.abs(p2c.usrCoords[0]) > Mat.eps && newPos > 1) { - newCoords = p2c; - doRound = true; - newPos = 1; - } - } else if (slide.type === Const.OBJECT_TYPE_TURTLE) { - // In case, the point is a constrained glider. - // side-effect: this.position is overwritten - this.updateConstraint(); - //this.coords.setCoordinates(Const.COORDS_BY_USER, Geometry.projectPointToTurtle(this, slide, this.board).usrCoords, false); - newCoords = Geometry.projectPointToTurtle(this, slide, this.board); - newPos = this.position; // save position for the overwriting below - } else if (slide.elementClass === Const.OBJECT_CLASS_CURVE) { - if ((slide.type === Const.OBJECT_TYPE_ARC || - slide.type === Const.OBJECT_TYPE_SECTOR)) { - newCoords = Geometry.projectPointToCircle(this, slide, this.board); + return this; + } - angle = Geometry.rad(slide.radiuspoint, slide.center, this); - alpha = 0.0; - beta = Geometry.rad(slide.radiuspoint, slide.center, slide.anglepoint); - newPos = angle; + this.coords.setCoordinates(method, coords); + this.handleSnapToGrid(); + this.handleSnapToPoints(); + this.handleAttractors(); - ev_sw = Type.evaluate(slide.visProp.selection); - if ((ev_sw === 'minor' && beta > Math.PI) || - (ev_sw === 'major' && beta < Math.PI)) { - alpha = beta; - beta = 2 * Math.PI; + // Update the initial coordinates. This is needed for free points + // that have a transformation bound to it. + for (i = this.transformations.length - 1; i >= 0; i--) { + if (method === Const.COORDS_BY_SCREEN) { + newCoords = (new Coords(method, coords, this.board)).usrCoords; + } else { + if (coords.length === 2) { + coords = [1].concat(coords); } + newCoords = coords; + } + this.initialCoords.setCoordinates(Const.COORDS_BY_USER, Mat.matVecMult(Mat.inverse(this.transformations[i].matrix), newCoords)); + } + this.prepareUpdate().update(); - // Correct the position if we are outside of the sector/arc - if (angle < alpha || angle > beta) { - newPos = beta; - - if ((angle < alpha && angle > alpha * 0.5) || (angle > beta && angle > beta * 0.5 + Math.PI)) { - newPos = alpha; - } - - this.needsUpdateFromParent = true; - this.updateGliderFromParent(); - } + // If the user suspends the board updates we need to recalculate the relative position of + // the point on the slide object. This is done in updateGlider() which is NOT called during the + // update process triggered by unsuspendUpdate. + if (this.board.isSuspendedUpdate && this.type === Const.OBJECT_TYPE_GLIDER) { + this.updateGlider(); + } - delta = beta - alpha; - if (this.visProp.isgeonext) { - delta = 1.0; - } - if (Math.abs(delta) > Mat.eps) { - newPos /= delta; - } - } else { - // In case, the point is a constrained glider. - this.updateConstraint(); + return this; + }, - // Handle the case if the curve comes from a transformation of a continous curve. - if (slide.transformations.length > 0) { - isTransformed = false; - res = slide.getTransformationSource(); - if (res[0]) { - isTransformed = res[0]; - slides.push(slide); - slides.push(res[1]); - } - // Recurse - while (res[0] && Type.exists(res[1]._transformationSource)) { - res = res[1].getTransformationSource(); - slides.push(res[1]); - } + /** + * Translates the point by <tt>tv = (x, y)</tt>. + * @param {Number} method The type of coordinates used here. + * Possible values are {@link JXG.COORDS_BY_USER} and {@link JXG.COORDS_BY_SCREEN}. + * @param {Array} tv (x, y) + * @returns {JXG.Point} + */ + setPositionByTransform: function (method, tv) { + var t; - cu = this.coords.usrCoords; - if (isTransformed) { - for (i = 0; i < slides.length; i++) { - slides[i].updateTransformMatrix(); - invMat = Mat.inverse(slides[i].transformMat); - cu = Mat.matVecMult(invMat, cu); - } - cp = (new Coords(Const.COORDS_BY_USER, cu, this.board)).usrCoords; - c = Geometry.projectCoordsToCurve(cp[1], cp[2], - this.position || 0, - slides[slides.length - 1], - this.board); - // projectPointCurve() already would apply the transformation. - // Since we are projecting on the original curve, we have to do - // the transformations "by hand". - cu = c[0].usrCoords; - for (i = slides.length - 2; i >= 0; i--) { - cu = Mat.matVecMult(slides[i].transformMat, cu); - } - c[0] = new Coords(Const.COORDS_BY_USER, cu, this.board); - } else { - slide.updateTransformMatrix(); - invMat = Mat.inverse(slide.transformMat); - cu = Mat.matVecMult(invMat, cu); - cp = (new Coords(Const.COORDS_BY_USER, cu, this.board)).usrCoords; - c = Geometry.projectCoordsToCurve(cp[1], cp[2], this.position || 0, slide, this.board); - } + tv = new Coords(method, tv, this.board); + t = this.board.create('transform', tv.usrCoords.slice(1), {type: 'translate'}); - newCoords = c[0]; - newPos = c[1]; - } else { - // side-effect: this.position is overwritten - // this.coords.setCoordinates(Const.COORDS_BY_USER, Geometry.projectPointToCurve(this, slide, this.board).usrCoords, false); - newCoords = Geometry.projectPointToCurve(this, slide, this.board); - newPos = this.position; // save position for the overwriting below - } - } - } else if (Type.isPoint(slide)) { - //this.coords.setCoordinates(Const.COORDS_BY_USER, Geometry.projectPointToPoint(this, slide, this.board).usrCoords, false); - newCoords = Geometry.projectPointToPoint(this, slide, this.board); - newPos = this.position; // save position for the overwriting below + if (this.transformations.length > 0 && + this.transformations[this.transformations.length - 1].isNumericMatrix) { + this.transformations[this.transformations.length - 1].melt(t); + } else { + this.addTransform(this, t); } - this.coords.setCoordinates(Const.COORDS_BY_USER, newCoords.usrCoords, doRound); - this.position = newPos; + this.prepareUpdate().update(); + + return this; }, /** - * Update of a glider in case a parent element has been updated. That means the - * relative position of the glider stays the same. - * @private + * Sets coordinates and calls the point's update() method. + * @param {Number} method The type of coordinates used here. + * Possible values are {@link JXG.COORDS_BY_USER} and {@link JXG.COORDS_BY_SCREEN}. + * @param {Array} coords coordinates in screen/user units + * @returns {JXG.Point} */ - updateGliderFromParent: function () { - var p1c, p2c, r, lbda, c, - slide = this.slideObject, - slides = [], - res, i, - isTransformed, - baseangle, alpha, angle, beta, - delta = 2.0 * Math.PI; + setPosition: function (method, coords) { + return this.setPositionDirectly(method, coords); + }, - if (!this.needsUpdateFromParent) { - this.needsUpdateFromParent = true; - return; + /** + * Sets the position of a glider relative to the defining elements + * of the {@link JXG.Point#slideObject}. + * @param {Number} x + * @returns {JXG.Point} Reference to the point element. + */ + setGliderPosition: function (x) { + if (this.type === Const.OBJECT_TYPE_GLIDER) { + this.position = x; + this.board.update(); } - if (slide.elementClass === Const.OBJECT_CLASS_CIRCLE) { - r = slide.Radius(); - if (Type.evaluate(this.visProp.isgeonext)) { - delta = 1.0; - } - c = [ - slide.center.X() + r * Math.cos(this.position * delta), - slide.center.Y() + r * Math.sin(this.position * delta) - ]; - } else if (slide.elementClass === Const.OBJECT_CLASS_LINE) { - p1c = slide.point1.coords.usrCoords; - p2c = slide.point2.coords.usrCoords; + return this; + }, - // If one of the defining points of the line does not exist, - // the glider should disappear - if ((p1c[0] === 0 && p1c[1] === 0 && p1c[2] === 0) || - (p2c[0] === 0 && p2c[1] === 0 && p2c[2] === 0)) { - c = [0, 0, 0]; - // The second point is an ideal point - } else if (Math.abs(p2c[0]) < Mat.eps) { - lbda = Math.min(Math.abs(this.position), 1 - Mat.eps); - lbda /= (1.0 - lbda); + /** + * Convert the point to glider and update the construction. + * To move the point visual onto the glider, a call of board update is necessary. + * @param {String|Object} slide The object the point will be bound to. + */ + makeGlider: function (slide) { + var slideobj = this.board.select(slide), + onPolygon = false, + min, + i, + dist; - if (this.position < 0) { - lbda = -lbda; + if (slideobj.type === Const.OBJECT_TYPE_POLYGON){ + // Search for the closest edge of the polygon. + min = Number.MAX_VALUE; + for (i = 0; i < slideobj.borders.length; i++){ + dist = JXG.Math.Geometry.distPointLine(this.coords.usrCoords, slideobj.borders[i].stdform); + if (dist < min){ + min = dist; + slide = slideobj.borders[i]; } + } + slideobj = this.board.select(slide); + onPolygon = true; + } - c = [ - p1c[0] + lbda * p2c[0], - p1c[1] + lbda * p2c[1], - p1c[2] + lbda * p2c[2] - ]; - // The first point is an ideal point - } else if (Math.abs(p1c[0]) < Mat.eps) { - lbda = Math.max(this.position, Mat.eps); - lbda = Math.min(lbda, 2 - Mat.eps); - - if (lbda > 1) { - lbda = (lbda - 1) / (lbda - 2); - } else { - lbda = (1 - lbda) / lbda; - } + /* Gliders on Ticks are forbidden */ + if (!Type.exists(slideobj)) { + throw new Error("JSXGraph: slide object undefined."); + } else if (slideobj.type === Const.OBJECT_TYPE_TICKS) { + throw new Error("JSXGraph: gliders on ticks are not possible."); + } - c = [ - p2c[0] + lbda * p1c[0], - p2c[1] + lbda * p1c[1], - p2c[2] + lbda * p1c[2] - ]; - } else { - lbda = this.position; - c = [ - p1c[0] + lbda * (p2c[0] - p1c[0]), - p1c[1] + lbda * (p2c[1] - p1c[1]), - p1c[2] + lbda * (p2c[2] - p1c[2]) - ]; - } - } else if (slide.type === Const.OBJECT_TYPE_TURTLE) { - this.coords.setCoordinates(Const.COORDS_BY_USER, [slide.Z(this.position), slide.X(this.position), slide.Y(this.position)]); - // In case, the point is a constrained glider. - // side-effect: this.position is overwritten: - this.updateConstraint(); - c = Geometry.projectPointToTurtle(this, slide, this.board).usrCoords; - } else if (slide.elementClass === Const.OBJECT_CLASS_CURVE) { - // Handle the case if the curve comes from a transformation of a continous curve. - isTransformed = false; - res = slide.getTransformationSource(); - if (res[0]) { - isTransformed = res[0]; - slides.push(slide); - slides.push(res[1]); - } - // Recurse - while (res[0] && Type.exists(res[1]._transformationSource)) { - res = res[1].getTransformationSource(); - slides.push(res[1]); - } - if (isTransformed) { - this.coords.setCoordinates(Const.COORDS_BY_USER, [ - slides[slides.length - 1].Z(this.position), - slides[slides.length - 1].X(this.position), - slides[slides.length - 1].Y(this.position)]); - } else { - this.coords.setCoordinates(Const.COORDS_BY_USER, [ - slide.Z(this.position), - slide.X(this.position), - slide.Y(this.position)]); - } + this.slideObject = this.board.select(slide); + this.slideObjects.push(this.slideObject); + this.addParents(slide); - if (slide.type === Const.OBJECT_TYPE_ARC || slide.type === Const.OBJECT_TYPE_SECTOR) { - baseangle = Geometry.rad([slide.center.X() + 1, slide.center.Y()], slide.center, slide.radiuspoint); + this.type = Const.OBJECT_TYPE_GLIDER; + this.elType = 'glider'; + this.visProp.snapwidth = -1; // By default, deactivate snapWidth + this.slideObject.addChild(this); + this.isDraggable = true; + this.onPolygon = onPolygon; - alpha = 0.0; - beta = Geometry.rad(slide.radiuspoint, slide.center, slide.anglepoint); + this.generatePolynomial = function () { + return this.slideObject.generatePolynomial(this); + }; - if ((slide.visProp.selection === 'minor' && beta > Math.PI) || - (slide.visProp.selection === 'major' && beta < Math.PI)) { - alpha = beta; - beta = 2 * Math.PI; - } + // Determine the initial value of this.position + this.updateGlider(); + this.needsUpdateFromParent = true; + this.updateGliderFromParent(); - delta = beta - alpha; - if (Type.evaluate(this.visProp.isgeonext)) { - delta = 1.0; - } - angle = this.position * delta; + return this; + }, - // Correct the position if we are outside of the sector/arc - if (angle < alpha || angle > beta) { - angle = beta; + /** + * Remove the last slideObject. If there are more than one elements the point is bound to, + * the second last element is the new active slideObject. + */ + popSlideObject: function () { + if (this.slideObjects.length > 0) { + this.slideObjects.pop(); - if ((angle < alpha && angle > alpha * 0.5) || - (angle > beta && angle > beta * 0.5 + Math.PI)) { - angle = alpha; - } + // It may not be sufficient to remove the point from + // the list of childElement. For complex dependencies + // one may have to go to the list of ancestor and descendants. A.W. + // Yes indeed, see #51 on github bugtracker + // delete this.slideObject.childElements[this.id]; + this.slideObject.removeChild(this); - this.position = angle; - if (Math.abs(delta) > Mat.eps) { - this.position /= delta; - } + if (this.slideObjects.length === 0) { + this.type = this._org_type; + if (this.type === Const.OBJECT_TYPE_POINT) { + this.elType = 'point'; + } else if (this.elementClass === Const.OBJECT_CLASS_TEXT) { + this.elType = 'text'; + } else if (this.type === Const.OBJECT_TYPE_IMAGE) { + this.elType = 'image'; + } else if (this.type === Const.OBJECT_TYPE_FOREIGNOBJECT) { + this.elType = 'foreignobject'; } - r = slide.Radius(); - c = [ - slide.center.X() + r * Math.cos(this.position * delta + baseangle), - slide.center.Y() + r * Math.sin(this.position * delta + baseangle) - ]; + this.slideObject = null; } else { - // In case, the point is a constrained glider. - // side-effect: this.position is overwritten - this.updateConstraint(); - - if (isTransformed) { - c = Geometry.projectPointToCurve(this, slides[slides.length - 1], this.board).usrCoords; - // projectPointCurve() already would do the transformation. - // But since we are projecting on the original curve, we have to do - // the transformation "by hand". - for (i = slides.length - 2; i >= 0; i--) { - c = (new Coords(Const.COORDS_BY_USER, - Mat.matVecMult(slides[i].transformMat, c), this.board)).usrCoords; - } - - } else { - c = Geometry.projectPointToCurve(this, slide, this.board).usrCoords; - } + this.slideObject = this.slideObjects[this.slideObjects.length - 1]; } - - } else if (Type.isPoint(slide)) { - c = Geometry.projectPointToPoint(this, slide, this.board).usrCoords; } - - this.coords.setCoordinates(Const.COORDS_BY_USER, c, false); }, - updateRendererGeneric: function (rendererMethod) { - //var wasReal; - - if (!this.needsUpdate) { - return this; - } + /** + * Converts a calculated element into a free element, + * i.e. it will delete all ancestors and transformations and, + * if the element is currently a glider, will remove the slideObject reference. + */ + free: function () { + var ancestorId, ancestor; + // child; - if (this.visPropCalc.visible) { - //wasReal = this.isReal; - this.isReal = (!isNaN(this.coords.usrCoords[1] + this.coords.usrCoords[2])); - //Homogeneous coords: ideal point - this.isReal = (Math.abs(this.coords.usrCoords[0]) > Mat.eps) ? this.isReal : false; + if (this.type !== Const.OBJECT_TYPE_GLIDER) { + // remove all transformations + this.transformations.length = 0; - if (// wasReal && - !this.isReal) { - this.updateVisibility(false); - } - } + delete this.updateConstraint; + this.isConstrained = false; + // this.updateConstraint = function () { + // return this; + // }; - // Call the renderer only if element is visible. - // Update the position - if (this.visPropCalc.visible) { - this.board.renderer[rendererMethod](this); - } + if (!this.isDraggable) { + this.isDraggable = true; - // Update the label if visible. - if (this.hasLabel && this.visPropCalc.visible && this.label && - this.label.visPropCalc.visible && this.isReal) { - this.label.update(); - this.board.renderer.updateText(this.label); - } + if (this.elementClass === Const.OBJECT_CLASS_POINT) { + this.type = Const.OBJECT_TYPE_POINT; + this.elType = 'point'; + } - // Update rendNode display - this.setDisplayRendNode(); - // if (this.visPropCalc.visible !== this.visPropOld.visible) { - // this.board.renderer.display(this, this.visPropCalc.visible); - // this.visPropOld.visible = this.visPropCalc.visible; - // - // if (this.hasLabel) { - // this.board.renderer.display(this.label, this.label.visPropCalc.visible); - // } - // } + this.XEval = function () { + return this.coords.usrCoords[1]; + }; - this.needsUpdate = false; - return this; - }, + this.YEval = function () { + return this.coords.usrCoords[2]; + }; - /** - * Getter method for x, this is used by for CAS-points to access point coordinates. - * @returns {Number} User coordinate of point in x direction. - */ - X: function () { - return this.coords.usrCoords[1]; - }, + this.ZEval = function () { + return this.coords.usrCoords[0]; + }; - /** - * Getter method for y, this is used by CAS-points to access point coordinates. - * @returns {Number} User coordinate of point in y direction. - */ - Y: function () { - return this.coords.usrCoords[2]; - }, + this.Xjc = null; + this.Yjc = null; + } else { + return; + } + } - /** - * Getter method for z, this is used by CAS-points to access point coordinates. - * @returns {Number} User coordinate of point in z direction. - */ - Z: function () { - return this.coords.usrCoords[0]; - }, + // a free point does not depend on anything. And instead of running through tons of descendants and ancestor + // structures, where we eventually are going to visit a lot of objects twice or thrice with hard to read and + // comprehend code, just run once through all objects and delete all references to this point and its label. + for (ancestorId in this.board.objects) { + if (this.board.objects.hasOwnProperty(ancestorId)) { + ancestor = this.board.objects[ancestorId]; - /** - * New evaluation of the function term. - * This is required for CAS-points: Their XTerm() method is - * overwritten in {@link JXG.CoordsElement#addConstraint}. - * - * @returns {Number} User coordinate of point in x direction. - * @private - */ - XEval: function () { - return this.coords.usrCoords[1]; - }, + if (ancestor.descendants) { + delete ancestor.descendants[this.id]; + delete ancestor.childElements[this.id]; - /** - * New evaluation of the function term. - * This is required for CAS-points: Their YTerm() method is overwritten - * in {@link JXG.CoordsElement#addConstraint}. - * - * @returns {Number} User coordinate of point in y direction. - * @private - */ - YEval: function () { - return this.coords.usrCoords[2]; - }, + if (this.hasLabel) { + delete ancestor.descendants[this.label.id]; + delete ancestor.childElements[this.label.id]; + } + } + } + } - /** - * New evaluation of the function term. - * This is required for CAS-points: Their ZTerm() method is overwritten in - * {@link JXG.CoordsElement#addConstraint}. - * - * @returns {Number} User coordinate of point in z direction. - * @private - */ - ZEval: function () { - return this.coords.usrCoords[0]; - }, + // A free point does not depend on anything. Remove all ancestors. + this.ancestors = {}; // only remove the reference - /** - * Getter method for the distance to a second point, this is required for CAS-elements. - * Here, function inlining seems to be worthwile (for plotting). - * @param {JXG.Point} point2 The point to which the distance shall be calculated. - * @returns {Number} Distance in user coordinate to the given point - */ - Dist: function (point2) { - if (this.isReal && point2.isReal) { - return this.coords.distance(Const.COORDS_BY_USER, point2.coords); + // Completely remove all slideObjects of the element + this.slideObject = null; + this.slideObjects = []; + if (this.elementClass === Const.OBJECT_CLASS_POINT) { + this.type = Const.OBJECT_TYPE_POINT; + this.elType = 'point'; + } else if (this.elementClass === Const.OBJECT_CLASS_TEXT) { + this.type = this._org_type; + this.elType = 'text'; + } else if (this.elementClass === Const.OBJECT_CLASS_OTHER) { + this.type = this._org_type; + this.elType = 'image'; } - return NaN; }, /** - * Alias for {@link JXG.Element#handleSnapToGrid} - * @param {Boolean} force force snapping independent from what the snaptogrid attribute says - * @returns {JXG.Point} Reference to this element + * Convert the point to CAS point and call update(). + * @param {Array} terms [[zterm], xterm, yterm] defining terms for the z, x and y coordinate. + * The z-coordinate is optional and it is used for homogeneous coordinates. + * The coordinates may be either <ul> + * <li>a JavaScript function,</li> + * <li>a string containing GEONExT syntax. This string will be converted into a JavaScript + * function here,</li> + * <li>a Number</li> + * <li>a pointer to a slider object. This will be converted into a call of the Value()-method + * of this slider.</li> + * </ul> + * @see JXG.GeonextParser#geonext2JS */ - snapToGrid: function (force) { - return this.handleSnapToGrid(force); - }, + addConstraint: function (terms) { + var i, v, + newfuncs = [], + what = ['X', 'Y'], - /** - * Let a point snap to the nearest point in distance of - * {@link JXG.Point#attractorDistance}. - * The function uses the coords object of the point as - * its actual position. - * @param {Boolean} force force snapping independent from what the snaptogrid attribute says - * @returns {JXG.Point} Reference to this element - */ - handleSnapToPoints: function (force) { - var i, pEl, pCoords, - d = 0, - len, - dMax = Infinity, - c = null, - ev_au, ev_ad, - ev_is2p = Type.evaluate(this.visProp.ignoredsnaptopoints), - len2, j, ignore = false; + makeConstFunction = function (z) { + return function () { + return z; + }; + }, - len = this.board.objectsList.length; + makeSliderFunction = function (a) { + return function () { + return a.Value(); + }; + }; - if (ev_is2p) { - len2 = ev_is2p.length; + if (this.elementClass === Const.OBJECT_CLASS_POINT) { + this.type = Const.OBJECT_TYPE_CAS; } - if (Type.evaluate(this.visProp.snaptopoints) || force) { - ev_au = Type.evaluate(this.visProp.attractorunit); - ev_ad = Type.evaluate(this.visProp.attractordistance); + this.isDraggable = false; - for (i = 0; i < len; i++) { - pEl = this.board.objectsList[i]; + for (i = 0; i < terms.length; i++) { + v = terms[i]; - if (ev_is2p) { - ignore = false; - for (j = 0; j < len2; j++) { - if (pEl === this.board.select(ev_is2p[j])) { - ignore = true; - break; - } - } - if (ignore) { - continue; - } + if (Type.isString(v)) { + // Convert GEONExT syntax into JavaScript syntax + //t = JXG.GeonextParser.geonext2JS(v, this.board); + //newfuncs[i] = new Function('','return ' + t + ';'); + //v = GeonextParser.replaceNameById(v, this.board); + newfuncs[i] = this.board.jc.snippet(v, true, null, true); + + if (terms.length === 2) { + this[what[i] + 'jc'] = terms[i]; } + } else if (Type.isFunction(v)) { + newfuncs[i] = v; + } else if (Type.isNumber(v)) { + newfuncs[i] = makeConstFunction(v); + // Slider + } else if (Type.isObject(v) && Type.isFunction(v.Value)) { + newfuncs[i] = makeSliderFunction(v); + } - if (Type.isPoint(pEl) && pEl !== this && pEl.visPropCalc.visible) { - pCoords = Geometry.projectPointToPoint(this, pEl, this.board); - if (ev_au === 'screen') { - d = pCoords.distance(Const.COORDS_BY_SCREEN, this.coords); - } else { - d = pCoords.distance(Const.COORDS_BY_USER, this.coords); - } + newfuncs[i].origin = v; + } - if (d < ev_ad && d < dMax) { - dMax = d; - c = pCoords; - } + // Intersection function + if (terms.length === 1) { + this.updateConstraint = function () { + var c = newfuncs[0](); + + // Array + if (Type.isArray(c)) { + this.coords.setCoordinates(Const.COORDS_BY_USER, c); + // Coords object + } else { + this.coords = c; } - } + return this; + }; + // Euclidean coordinates + } else if (terms.length === 2) { + this.XEval = newfuncs[0]; + this.YEval = newfuncs[1]; - if (c !== null) { - this.coords.setCoordinates(Const.COORDS_BY_USER, c.usrCoords); + this.setParents([newfuncs[0].origin, newfuncs[1].origin]); + + this.updateConstraint = function () { + this.coords.setCoordinates(Const.COORDS_BY_USER, [this.XEval(), this.YEval()]); + return this; + }; + // Homogeneous coordinates + } else { + this.ZEval = newfuncs[0]; + this.XEval = newfuncs[1]; + this.YEval = newfuncs[2]; + + this.setParents([newfuncs[0].origin, newfuncs[1].origin, newfuncs[2].origin]); + + this.updateConstraint = function () { + this.coords.setCoordinates(Const.COORDS_BY_USER, [this.ZEval(), this.XEval(), this.YEval()]); + return this; + }; + } + this.isConstrained = true; + + /** + * We have to do an update. Otherwise, elements relying on this point will receive NaN. + */ + this.prepareUpdate().update(); + if (!this.board.isSuspendedUpdate) { + this.updateVisibility().updateRenderer(); + if (this.hasLabel) { + this.label.fullUpdate(); } } @@ -33845,484 +37940,14 @@ define('base/coordselement',[ }, /** - * Alias for {@link JXG.CoordsElement#handleSnapToPoints}. - * - * @param {Boolean} force force snapping independent from what the snaptogrid attribute says - * @returns {JXG.Point} Reference to this element - */ - snapToPoints: function (force) { - return this.handleSnapToPoints(force); - }, - - /** - * A point can change its type from free point to glider - * and vice versa. If it is given an array of attractor elements - * (attribute attractors) and the attribute attractorDistance - * then the point will be made a glider if it less than attractorDistance - * apart from one of its attractor elements. - * If attractorDistance is equal to zero, the point stays in its - * current form. - * @returns {JXG.Point} Reference to this element - */ - handleAttractors: function () { - var i, el, projCoords, - d = 0.0, - projection, - ev_au = Type.evaluate(this.visProp.attractorunit), - ev_ad = Type.evaluate(this.visProp.attractordistance), - ev_sd = Type.evaluate(this.visProp.snatchdistance), - ev_a = Type.evaluate(this.visProp.attractors), - len = ev_a.length; - - if (ev_ad === 0.0) { - return; - } - - for (i = 0; i < len; i++) { - el = this.board.select(ev_a[i]); - - if (Type.exists(el) && el !== this) { - if (Type.isPoint(el)) { - projCoords = Geometry.projectPointToPoint(this, el, this.board); - } else if (el.elementClass === Const.OBJECT_CLASS_LINE) { - projection = Geometry.projectCoordsToSegment( - this.coords.usrCoords, - el.point1.coords.usrCoords, - el.point2.coords.usrCoords); - if (!Type.evaluate(el.visProp.straightfirst) && projection[1] < 0.0) { - projCoords = el.point1.coords; - } else if (!Type.evaluate(el.visProp.straightlast) && projection[1] > 1.0) { - projCoords = el.point2.coords; - } else { - projCoords = new Coords(Const.COORDS_BY_USER, projection[0], this.board); - } - } else if (el.elementClass === Const.OBJECT_CLASS_CIRCLE) { - projCoords = Geometry.projectPointToCircle(this, el, this.board); - } else if (el.elementClass === Const.OBJECT_CLASS_CURVE) { - projCoords = Geometry.projectPointToCurve(this, el, this.board); - } else if (el.type === Const.OBJECT_TYPE_TURTLE) { - projCoords = Geometry.projectPointToTurtle(this, el, this.board); - } - - if (ev_au === 'screen') { - d = projCoords.distance(Const.COORDS_BY_SCREEN, this.coords); - } else { - d = projCoords.distance(Const.COORDS_BY_USER, this.coords); - } - - if (d < ev_ad) { - if (!(this.type === Const.OBJECT_TYPE_GLIDER && this.slideObject === el)) { - this.makeGlider(el); - } - break; // bind the point to the first attractor in its list. - } - if (el === this.slideObject && d >= ev_sd) { - this.popSlideObject(); - } - } - } - - return this; - }, - - /** - * Sets coordinates and calls the point's update() method. - * @param {Number} method The type of coordinates used here. - * Possible values are {@link JXG.COORDS_BY_USER} and {@link JXG.COORDS_BY_SCREEN}. - * @param {Array} coords coordinates <tt>([z], x, y)</tt> in screen/user units - * @returns {JXG.Point} this element - */ - setPositionDirectly: function (method, coords) { - var i, c, dc, - oldCoords = this.coords, - newCoords; - - if (this.relativeCoords) { - c = new Coords(method, coords, this.board); - if (Type.evaluate(this.visProp.islabel)) { - dc = Statistics.subtract(c.scrCoords, oldCoords.scrCoords); - this.relativeCoords.scrCoords[1] += dc[1]; - this.relativeCoords.scrCoords[2] += dc[2]; - } else { - dc = Statistics.subtract(c.usrCoords, oldCoords.usrCoords); - this.relativeCoords.usrCoords[1] += dc[1]; - this.relativeCoords.usrCoords[2] += dc[2]; - } - - return this; - } - - this.coords.setCoordinates(method, coords); - this.handleSnapToGrid(); - this.handleSnapToPoints(); - this.handleAttractors(); - - // Update the initial coordinates. This is needed for free points - // that have a transformation bound to it. - for (i = this.transformations.length - 1; i >= 0; i--) { - if (method === Const.COORDS_BY_SCREEN) { - newCoords = (new Coords(method, coords, this.board)).usrCoords; - } else { - if (coords.length === 2) { - coords = [1].concat(coords); - } - newCoords = coords; - } - this.initialCoords.setCoordinates(Const.COORDS_BY_USER, Mat.matVecMult(Mat.inverse(this.transformations[i].matrix), newCoords)); - } - this.prepareUpdate().update(); - - // If the user suspends the board updates we need to recalculate the relative position of - // the point on the slide object. This is done in updateGlider() which is NOT called during the - // update process triggered by unsuspendUpdate. - if (this.board.isSuspendedUpdate && this.type === Const.OBJECT_TYPE_GLIDER) { - this.updateGlider(); - } - - return this; - }, - - /** - * Translates the point by <tt>tv = (x, y)</tt>. - * @param {Number} method The type of coordinates used here. - * Possible values are {@link JXG.COORDS_BY_USER} and {@link JXG.COORDS_BY_SCREEN}. - * @param {Array} tv (x, y) - * @returns {JXG.Point} - */ - setPositionByTransform: function (method, tv) { - var t; - - tv = new Coords(method, tv, this.board); - t = this.board.create('transform', tv.usrCoords.slice(1), {type: 'translate'}); - - if (this.transformations.length > 0 && - this.transformations[this.transformations.length - 1].isNumericMatrix) { - this.transformations[this.transformations.length - 1].melt(t); - } else { - this.addTransform(this, t); - } - - this.prepareUpdate().update(); - - return this; - }, - - /** - * Sets coordinates and calls the point's update() method. - * @param {Number} method The type of coordinates used here. - * Possible values are {@link JXG.COORDS_BY_USER} and {@link JXG.COORDS_BY_SCREEN}. - * @param {Array} coords coordinates in screen/user units - * @returns {JXG.Point} - */ - setPosition: function (method, coords) { - return this.setPositionDirectly(method, coords); - }, - - /** - * Sets the position of a glider relative to the defining elements - * of the {@link JXG.Point#slideObject}. - * @param {Number} x - * @returns {JXG.Point} Reference to the point element. - */ - setGliderPosition: function (x) { - if (this.type === Const.OBJECT_TYPE_GLIDER) { - this.position = x; - this.board.update(); - } - - return this; - }, - - /** - * Convert the point to glider and update the construction. - * To move the point visual onto the glider, a call of board update is necessary. - * @param {String|Object} slide The object the point will be bound to. - */ - makeGlider: function (slide) { - var slideobj = this.board.select(slide), - onPolygon = false, - min, - i, - dist; - - if (slideobj.type === Const.OBJECT_TYPE_POLYGON){ - // Search for the closest side of the polygon. - min = Number.MAX_VALUE; - for (i = 0; i < slideobj.borders.length; i++){ - dist = JXG.Math.Geometry.distPointLine(this.coords.usrCoords, slideobj.borders[i].stdform); - if (dist < min){ - min = dist; - slide = slideobj.borders[i]; - } - } - slideobj = this.board.select(slide); - onPolygon = true; - } - - /* Gliders on Ticks are forbidden */ - if (!Type.exists(slideobj)) { - throw new Error("JSXGraph: slide object undefined."); - } else if (slideobj.type === Const.OBJECT_TYPE_TICKS) { - throw new Error("JSXGraph: gliders on ticks are not possible."); - } - - this.slideObject = this.board.select(slide); - this.slideObjects.push(this.slideObject); - this.addParents(slide); - - this.type = Const.OBJECT_TYPE_GLIDER; - this.elType = 'glider'; - this.visProp.snapwidth = -1; // By default, deactivate snapWidth - this.slideObject.addChild(this); - this.isDraggable = true; - this.onPolygon = onPolygon; - - this.generatePolynomial = function () { - return this.slideObject.generatePolynomial(this); - }; - - // Determine the initial value of this.position - this.updateGlider(); - this.needsUpdateFromParent = true; - this.updateGliderFromParent(); - - return this; - }, - - /** - * Remove the last slideObject. If there are more than one elements the point is bound to, - * the second last element is the new active slideObject. - */ - popSlideObject: function () { - if (this.slideObjects.length > 0) { - this.slideObjects.pop(); - - // It may not be sufficient to remove the point from - // the list of childElement. For complex dependencies - // one may have to go to the list of ancestor and descendants. A.W. - // yes indeed, see #51 on github bugtracker - //delete this.slideObject.childElements[this.id]; - this.slideObject.removeChild(this); - - if (this.slideObjects.length === 0) { - this.type = this._org_type; - if (this.type === Const.OBJECT_TYPE_POINT) { - this.elType = 'point'; - } else if (this.elementClass === Const.OBJECT_CLASS_TEXT) { - this.elType = 'text'; - } else if (this.type === Const.OBJECT_TYPE_IMAGE) { - this.elType = 'image'; - } - - this.slideObject = null; - } else { - this.slideObject = this.slideObjects[this.slideObjects.length - 1]; - } - } - }, - - /** - * Converts a calculated element into a free element, - * i.e. it will delete all ancestors and transformations and, - * if the element is currently a glider, will remove the slideObject reference. - */ - free: function () { - var ancestorId, ancestor; - // child; - - if (this.type !== Const.OBJECT_TYPE_GLIDER) { - // remove all transformations - this.transformations.length = 0; - - this.updateConstraint = function () { - return this; - }; - - if (!this.isDraggable) { - this.isDraggable = true; - - if (this.elementClass === Const.OBJECT_CLASS_POINT) { - this.type = Const.OBJECT_TYPE_POINT; - this.elType = 'point'; - } - - this.XEval = function () { - return this.coords.usrCoords[1]; - }; - - this.YEval = function () { - return this.coords.usrCoords[2]; - }; - - this.ZEval = function () { - return this.coords.usrCoords[0]; - }; - - this.Xjc = null; - this.Yjc = null; - } else { - return; - } - } - - // a free point does not depend on anything. And instead of running through tons of descendants and ancestor - // structures, where we eventually are going to visit a lot of objects twice or thrice with hard to read and - // comprehend code, just run once through all objects and delete all references to this point and its label. - for (ancestorId in this.board.objects) { - if (this.board.objects.hasOwnProperty(ancestorId)) { - ancestor = this.board.objects[ancestorId]; - - if (ancestor.descendants) { - delete ancestor.descendants[this.id]; - delete ancestor.childElements[this.id]; - - if (this.hasLabel) { - delete ancestor.descendants[this.label.id]; - delete ancestor.childElements[this.label.id]; - } - } - } - } - - // A free point does not depend on anything. Remove all ancestors. - this.ancestors = {}; // only remove the reference - - // Completely remove all slideObjects of the element - this.slideObject = null; - this.slideObjects = []; - if (this.elementClass === Const.OBJECT_CLASS_POINT) { - this.type = Const.OBJECT_TYPE_POINT; - this.elType = 'point'; - } else if (this.elementClass === Const.OBJECT_CLASS_TEXT) { - this.type = this._org_type; - this.elType = 'text'; - } else if (this.elementClass === Const.OBJECT_CLASS_OTHER) { - this.type = this._org_type; - this.elType = 'image'; - } - }, - - /** - * Convert the point to CAS point and call update(). - * @param {Array} terms [[zterm], xterm, yterm] defining terms for the z, x and y coordinate. - * The z-coordinate is optional and it is used for homogeneous coordinates. - * The coordinates may be either <ul> - * <li>a JavaScript function,</li> - * <li>a string containing GEONExT syntax. This string will be converted into a JavaScript - * function here,</li> - * <li>a Number</li> - * <li>a pointer to a slider object. This will be converted into a call of the Value()-method - * of this slider.</li> - * </ul> - * @see JXG.GeonextParser#geonext2JS - */ - addConstraint: function (terms) { - var i, v, - newfuncs = [], - what = ['X', 'Y'], - - makeConstFunction = function (z) { - return function () { - return z; - }; - }, - - makeSliderFunction = function (a) { - return function () { - return a.Value(); - }; - }; - - if (this.elementClass === Const.OBJECT_CLASS_POINT) { - this.type = Const.OBJECT_TYPE_CAS; - } - - this.isDraggable = false; - - for (i = 0; i < terms.length; i++) { - v = terms[i]; - - if (Type.isString(v)) { - // Convert GEONExT syntax into JavaScript syntax - //t = JXG.GeonextParser.geonext2JS(v, this.board); - //newfuncs[i] = new Function('','return ' + t + ';'); - //v = GeonextParser.replaceNameById(v, this.board); - newfuncs[i] = this.board.jc.snippet(v, true, null, true); - - if (terms.length === 2) { - this[what[i] + 'jc'] = terms[i]; - } - } else if (Type.isFunction(v)) { - newfuncs[i] = v; - } else if (Type.isNumber(v)) { - newfuncs[i] = makeConstFunction(v); - // Slider - } else if (Type.isObject(v) && Type.isFunction(v.Value)) { - newfuncs[i] = makeSliderFunction(v); - } - - newfuncs[i].origin = v; - } - - // Intersection function - if (terms.length === 1) { - this.updateConstraint = function () { - var c = newfuncs[0](); - - // Array - if (Type.isArray(c)) { - this.coords.setCoordinates(Const.COORDS_BY_USER, c); - // Coords object - } else { - this.coords = c; - } - }; - // Euclidean coordinates - } else if (terms.length === 2) { - this.XEval = newfuncs[0]; - this.YEval = newfuncs[1]; - - this.setParents([newfuncs[0].origin, newfuncs[1].origin]); - - this.updateConstraint = function () { - this.coords.setCoordinates(Const.COORDS_BY_USER, [this.XEval(), this.YEval()]); - }; - // Homogeneous coordinates - } else { - this.ZEval = newfuncs[0]; - this.XEval = newfuncs[1]; - this.YEval = newfuncs[2]; - - this.setParents([newfuncs[0].origin, newfuncs[1].origin, newfuncs[2].origin]); - - this.updateConstraint = function () { - this.coords.setCoordinates(Const.COORDS_BY_USER, [this.ZEval(), this.XEval(), this.YEval()]); - }; - } - - /** - * We have to do an update. Otherwise, elements relying on this point will receive NaN. - */ - this.prepareUpdate().update(); - if (!this.board.isSuspendedUpdate) { - this.updateVisibility().updateRenderer(); - if (this.hasLabel) { - this.label.fullUpdate(); - } - } - - return this; - }, - - /** - * In case there is an attribute "anchor", the element is bound to - * this anchor element. - * This is handled with this.relativeCoords. If the element is a label - * relativeCoords are given in scrCoords, otherwise in usrCoords. - * @param{Array} coordinates Offset from th anchor element. These are the values for this.relativeCoords. - * In case of a label, coordinates are screen coordinates. Otherwise, coordinates are user coordinates. - * @param{Boolean} isLabel Yes/no - * @private + * In case there is an attribute "anchor", the element is bound to + * this anchor element. + * This is handled with this.relativeCoords. If the element is a label + * relativeCoords are given in scrCoords, otherwise in usrCoords. + * @param{Array} coordinates Offset from th anchor element. These are the values for this.relativeCoords. + * In case of a label, coordinates are screen coordinates. Otherwise, coordinates are user coordinates. + * @param{Boolean} isLabel Yes/no + * @private */ addAnchor: function (coordinates, isLabel) { if (isLabel) { @@ -34374,6 +37999,7 @@ define('base/coordselement',[ this.updateConstraint = function () { this.coords.setCoordinates(Const.COORDS_BY_USER, [this.ZEval(), this.XEval(), this.YEval()]); }; + this.isConstrained = true; this.updateConstraint(); //this.coords = new Coords(Const.COORDS_BY_SCREEN, [0, 0], this.board); @@ -34382,9 +38008,10 @@ define('base/coordselement',[ /** * Applies the transformations of the element. * This method applies to text and images. Point transformations are handled differently. + * @param {Boolean} fromParent True if the drag comes from a child element. Unused. * @returns {JXG.CoordsElement} Reference to itself. */ - updateTransform: function () { + updateTransform: function (fromParent) { var i; if (this.transformations.length === 0) { @@ -34399,7 +38026,7 @@ define('base/coordselement',[ }, /** - * Add transformations to this point. + * Add transformations to this element. * @param {JXG.GeometryElement} el * @param {JXG.Transformation|Array} transform Either one {@link JXG.Transformation} * or an array of {@link JXG.Transformation}s. @@ -34605,7 +38232,8 @@ define('base/coordselement',[ /** * Starts an animated point movement towards the given coordinates <tt>where</tt>. * The animation is done after <tt>time</tt> milliseconds. - * If the second parameter is not given or is equal to 0, setPosition() is called, see #setPosition. + * If the second parameter is not given or is equal to 0, setPosition() is called, see #setPosition, + * i.e. the coordinates are changed without animation. * @param {Array} where Array containing the x and y coordinate of the target location. * @param {Number} [time] Number of milliseconds the animation should last. * @param {Object} [options] Optional settings for the animation @@ -34736,7 +38364,9 @@ define('base/coordselement',[ */ _anim: function (direction, stepCount) { var dX, dY, alpha, startPoint, newX, radius, - sp1c, sp2c, d; + sp1c, sp2c, + res, + d; this.intervalCount += 1; if (this.intervalCount > stepCount) { @@ -34769,13 +38399,15 @@ define('base/coordselement',[ } this.coords.setCoordinates(Const.COORDS_BY_SCREEN, [newX, 0]); - this.coords = Geometry.projectPointToCurve(this, this.slideObject, this.board); + res = Geometry.projectPointToCurve(this, this.slideObject, this.board); + this.coords = res[0]; + this.position = res[1]; } else if (this.slideObject.elementClass === Const.OBJECT_CLASS_CIRCLE) { alpha = 2 * Math.PI; if (direction < 0) { alpha *= this.intervalCount / stepCount; } else { - alpha *= (stepCount - this.intervalCount); + alpha *= (stepCount - this.intervalCount) / stepCount; } radius = this.slideObject.Radius(); @@ -34879,7 +38511,7 @@ define('base/coordselement',[ }); /* - Copyright 2008-2021 + Copyright 2008-2022 Matthias Ehmann, Michael Gerhaeuser, Carsten Miller, @@ -34909,7 +38541,6 @@ define('base/coordselement',[ and <http://opensource.org/licenses/MIT/>. */ - /*global JXG: true, define: true, window: true*/ /*jslint nomen: true, plusplus: true*/ @@ -34930,18 +38561,18 @@ define('base/coordselement',[ define('base/text',[ 'jxg', 'base/constants', 'base/element', 'parser/geonext', - 'utils/env', 'utils/type', 'math/math', 'math/geometry', 'base/coordselement' -], function (JXG, Const, GeometryElement, GeonextParser, Env, Type, Mat, Geometry, CoordsElement) { + 'utils/env', 'utils/type', 'math/math', 'base/coordselement' +], function (JXG, Const, GeometryElement, GeonextParser, Env, Type, Mat, CoordsElement) { "use strict"; var priv = { - HTMLSliderInputEventHandler: function () { - this._val = parseFloat(this.rendNodeRange.value); - this.rendNodeOut.value = this.rendNodeRange.value; - this.board.update(); - } - }; + HTMLSliderInputEventHandler: function () { + this._val = parseFloat(this.rendNodeRange.value); + this.rendNodeOut.value = this.rendNodeRange.value; + this.board.update(); + } + }; /** * Construct and handle texts. @@ -34979,18 +38610,20 @@ define('base/text',[ * Width and height of the the text element in pixel. * * @private - * @type {Array} + * @type Array */ this.size = [1.0, 1.0]; this.id = this.board.setId(this, 'T'); - // Set text before drawing - this._setUpdateText(content); - this.updateText(); - this.board.renderer.drawText(this); this.board.finalizeAdding(this); + // Set text before drawing + // this._createFctUpdateText(content); + // this.updateText(); + + this.setText(content); + if (Type.isString(this.content)) { this.notifyParents(this.content); } @@ -35013,7 +38646,7 @@ define('base/text',[ * at the left side or at the right side of the text. * Sensitivity is set in this.board.options.precision.hasPoint. * If dragarea is set to 'all' (default), tests if the the screen - * coordinates (x,y) are in within the text boundary. + * coordinates (x,y) are in within the text boundary. * @param {Number} x * @param {Number} y * @returns {Boolean} @@ -35057,12 +38690,12 @@ define('base/text',[ top = bot - this.size[1]; if (Type.evaluate(this.visProp.dragarea) === 'all') { - return x >= lft - r && x < rt + r && y >= top - r && y <= bot + r; + return x >= lft - r && x < rt + r && y >= top - r && y <= bot + r; } // e.g. 'small' return (y >= top - r && y <= bot + r) && - ((x >= lft - r && x <= lft + 2 * r) || - (x >= rt - 2 * r && x <= rt + r)); + ((x >= lft - r && x <= lft + 2 * r) || + (x >= rt - 2 * r && x <= rt + r)); }, /** @@ -35071,17 +38704,18 @@ define('base/text',[ * @param {String|Function|Number} text * @private */ - _setUpdateText: function (text) { + _createFctUpdateText: function (text) { var updateText, resolvedText, ev_p = Type.evaluate(this.visProp.parse), - ev_um = Type.evaluate(this.visProp.usemathjax); + ev_um = Type.evaluate(this.visProp.usemathjax), + ev_uk = Type.evaluate(this.visProp.usekatex); this.orgText = text; if (Type.isFunction(text)) { this.updateText = function () { resolvedText = text().toString(); - if (ev_p && !ev_um) { - this.plaintext = this.replaceSub(this.replaceSup(this.convertGeonext2CSS(resolvedText))); + if (ev_p && !ev_um && !ev_uk) { + this.plaintext = this.replaceSub(this.replaceSup(this.convertGeonextAndSketchometry2CSS(resolvedText))); } else { this.plaintext = resolvedText; } @@ -35097,7 +38731,7 @@ define('base/text',[ if (Type.evaluate(this.visProp.useasciimathml)) { // Convert via ASCIIMathML this.content = "'`" + text + "`'"; - } else if (ev_um) { + } else if (ev_um || ev_uk) { this.content = "'" + text + "'"; } else { // Converts GEONExT syntax into JavaScript string @@ -35121,7 +38755,7 @@ define('base/text',[ * @private */ _setText: function (text) { - this._setUpdateText(text); + this._createFctUpdateText(text); // First evaluation of the string. // We need this for display='internal' and Canvas @@ -35149,7 +38783,6 @@ define('base/text',[ var s; this.visProp.castext = text; - if (Type.isFunction(text)) { s = function () { return Type.sanitizeHTML(text()); @@ -35187,7 +38820,7 @@ define('base/text',[ * @return {[type]} [description] */ updateSize: function () { - var tmp, s, that, node, + var tmp, that, node, ev_d = Type.evaluate(this.visProp.display); if (!Env.isBrowser || this.board.renderer.type === 'no') { @@ -35216,9 +38849,7 @@ define('base/text',[ // that.needsUpdate = true; // that.updateRenderer(); // }, 0); - // console.log("HERE"); // } else { - // console.log("tHERE"); // this.size = s; // } } else { @@ -35227,13 +38858,14 @@ define('base/text',[ } else if (ev_d === 'internal') { if (this.board.renderer.type === 'svg') { that = this; - window.setTimeout(function(){ + window.setTimeout(function () { try { tmp = node.getBBox(); that.size = [tmp.width, tmp.height]; that.needsUpdate = true; that.updateRenderer(); - } catch (e) {} + } catch (e) { + } }, 0); } else if (this.board.renderer.type === 'canvas') { this.size = this.crudeSizeEstimate(); @@ -35257,7 +38889,7 @@ define('base/text',[ * @param {String} string * @returns {String} */ - utf8_decode : function (string) { + utf8_decode: function (string) { return string.replace(/&#x(\w+);/g, function (m, p1) { return String.fromCharCode(parseInt(p1, 16)); }); @@ -35455,8 +39087,8 @@ define('base/text',[ * @param{String} expr Math term * @returns {string} expanded String */ - expandShortMath: function(expr) { - var re = /([\)0-9\.])\s*([\(a-zA-Z_])/g; + expandShortMath: function (expr) { + var re = /([)0-9.])\s*([(a-zA-Z_])/g; return expr.replace(re, '$1*$2'); }, @@ -35470,7 +39102,7 @@ define('base/text',[ * @param{Boolean} [avoidGeonext2JS] Optional flag if geonext2JS should be called. For backwards compatibility * this has to be set explicitely to true. * @private - * @see JXG.GeonextParser.geonext2JS. + * @see JXG.GeonextParser.geonext2JS */ generateTerm: function (contentStr, expand, avoidGeonext2JS) { var res, term, i, j, @@ -35530,7 +39162,7 @@ define('base/text',[ } plaintext += ' + "' + this.replaceSub(this.replaceSup(contentStr)) + '"'; - plaintext = this.convertGeonext2CSS(plaintext); + plaintext = this.convertGeonextAndSketchometry2CSS(plaintext); // This should replace &pi; by π plaintext = plaintext.replace(/&/g, '&'); @@ -35541,25 +39173,76 @@ define('base/text',[ /** * Converts the GEONExT tags <overline> and <arrow> to - * HTML span tags with proper CSS formating. + * HTML span tags with proper CSS formatting. * @private - * @see JXG.Text.generateTerm @see JXG.Text._setText + * @see JXG.Text.generateTerm + * @see JXG.Text._setText */ convertGeonext2CSS: function (s) { if (Type.isString(s)) { - s = s.replace(/<overline>/g, '<span style=text-decoration:overline>'); - s = s.replace(/<overline>/g, '<span style=text-decoration:overline>'); - s = s.replace(/<\/overline>/g, '</span>'); - s = s.replace(/<\/overline>/g, '</span>'); - s = s.replace(/<arrow>/g, '<span style=text-decoration:overline>'); - s = s.replace(/<arrow>/g, '<span style=text-decoration:overline>'); - s = s.replace(/<\/arrow>/g, '</span>'); - s = s.replace(/<\/arrow>/g, '</span>'); + s = s.replace( + /(<|<)overline(>|>)/g, + '<span style=text-decoration:overline;>' + ); + s = s.replace( + /(<|<)\/overline(>|>)/g, + '</span>' + ); + s = s.replace( + /(<|<)arrow(>|>)/g, + '<span style=text-decoration:overline;>' + ); + s = s.replace( + /(<|<)\/arrow(>|>)/g, + '</span>' + ); + } + + return s; + }, + + /** + * Converts the sketchometry tag <sketchofont> to + * HTML span tags with proper CSS formatting. + * @private + * @see JXG.Text.generateTerm + * @see JXG.Text._setText + */ + convertSketchometry2CSS: function (s) { + if (Type.isString(s)) { + s = s.replace( + /(<|<)sketchofont(>|>)/g, + '<span style=font-family:sketchometry-light;font-weight:500;>' + ); + s = s.replace( + /(<|<)\/sketchofont(>|>)/g, + '</span>' + ); + s = s.replace( + /(<|<)sketchometry-light(>|>)/g, + '<span style=font-family:sketchometry-light;font-weight:500;>' + ); + s = s.replace( + /(<|<)\/sketchometry-light(>|>)/g, + '</span>' + ); } return s; }, + /** + * Alias for convertGeonext2CSS and convertSketchometry2CSS + * @private + * @see JXG.Text.convertGeonext2CSS + * @see JXG.Text.convertSketchometry2CSS + */ + convertGeonextAndSketchometry2CSS: function (s){ + s = this.convertGeonext2CSS(s); + s = this.convertSketchometry2CSS(s); + return s; + }, + /** * Finds dependencies in a given term and notifies the parents by adding the * dependent object to the found objects child elements. @@ -35575,7 +39258,7 @@ define('base/text',[ content = content.replace(/<\/value>/g, '</value>'); do { - search = /<value>([\w\s\*\/\^\-\+\(\)\[\],<>=!]+)<\/value>/; + search = /<value>([\w\s*/^\-+()[\],<>=!]+)<\/value>/; res = search.exec(content); if (res !== null) { @@ -35613,7 +39296,7 @@ define('base/text',[ return [c[1], c[2] + this.size[1] / this.board.unitY, c[1] + this.size[0] / this.board.unitX, c[2]]; }, - getAnchorX: function() { + getAnchorX: function () { var a = Type.evaluate(this.visProp.anchorx); if (a === 'auto') { switch (this.visProp.position) { @@ -35634,7 +39317,7 @@ define('base/text',[ return a; }, - getAnchorY: function() { + getAnchorY: function () { var a = Type.evaluate(this.visProp.anchory); if (a === 'auto') { switch (this.visProp.position) { @@ -35666,31 +39349,32 @@ define('base/text',[ * @param {Number} h width of the box in pixel * @return {Number} Number of overlapping elements */ - getNumberofConflicts: function(x, y, w, h) { + getNumberofConflicts: function (x, y, w, h) { var count = 0, - i, obj, le, + i, obj, le, savePointPrecision; // Set the precision of hasPoint to half the max if label isn't too long savePointPrecision = this.board.options.precision.hasPoint; - this.board.options.precision.hasPoint = Math.max(w, h) * 0.5; + // this.board.options.precision.hasPoint = Math.max(w, h) * 0.5; + this.board.options.precision.hasPoint = (w + h) * 0.25; // TODO: // Make it compatible with the objects' visProp.precision attribute - for (i = 0, le = this.board.objectsList.length; i < le; i++) { - obj = this.board.objectsList[i]; - if (obj.visPropCalc.visible && + for (i = 0, le = this.board.objectsList.length; i < le; i++) { + obj = this.board.objectsList[i]; + if (obj.visPropCalc.visible && obj.elType !== 'axis' && obj.elType !== 'ticks' && obj !== this.board.infobox && obj !== this && obj.hasPoint(x, y)) { - count++; - } - } + count++; + } + } this.board.options.precision.hasPoint = savePointPrecision; - return count; + return count; }, /** @@ -35700,25 +39384,33 @@ define('base/text',[ * * @returns {JXG.Text} Reference to the text object. */ - setAutoPosition: function() { + setAutoPosition: function () { var x, y, cx, cy, - anchorCoords, anchorX, anchorY, + anchorCoords, + // anchorX, anchorY, w = this.size[0], h = this.size[1], start_angle, angle, - min_conflicts = Infinity, - min_angle, + optimum = { + conflicts: Infinity, + angle: 0, + r: 0 + }, + max_r, delta_r, conflicts, offset, r, num_positions = 12, step = 2 * Math.PI / num_positions, j, dx, dy, co, si; - if (this === this.board.infobox || !Type.evaluate(this.visProp.islabel) || !this.element) { + if (this === this.board.infobox || + !this.visPropCalc.visible || + !Type.evaluate(this.visProp.islabel) || + !this.element) { return this; } - anchorX = Type.evaluate(this.visProp.anchorx); - anchorY = Type.evaluate(this.visProp.anchory); + // anchorX = Type.evaluate(this.visProp.anchorx); + // anchorY = Type.evaluate(this.visProp.anchory); offset = Type.evaluate(this.visProp.offset); anchorCoords = this.element.getLabelAnchor(); cx = anchorCoords.scrCoords[1]; @@ -35733,50 +39425,44 @@ define('base/text',[ if (conflicts === 0) { return this; } + // console.log(this.id, conflicts, w, h); + // r = Geometry.distance([0, 0], offset, 2); - r = Geometry.distance([0, 0], [dx, dy], 2); + r = 12; + max_r = 28; + delta_r = 0.2 * r; start_angle = Math.atan2(dy, dx); - min_angle = start_angle; - min_conflicts = conflicts; - - for (j = 1, angle = start_angle + step; j < num_positions; j++) { - co = Math.cos(angle); - si = Math.sin(angle); - - x = cx + r * co; - // if (co < -0.2) { - // x -= w * 0.5; - // } else if (co > 0.2) { - // x += w * 0.5; - // } - y = cy - r * si; - // if (si > -0.2 && si < 0.0) { - // y += h * 0.5; - // } else if (si >= 0.0 && si < 0.2) { - // y -= h * 0.5; - // } - // if (si < -0.2) { - // y += h * 0.5; - // } else if (si > 0.2) { - // y -= h * 0.5; - // } + optimum.conflicts = conflicts; + optimum.angle = start_angle; + optimum.r = r; - conflicts = this.getNumberofConflicts(x, y, w, h); - if (conflicts < min_conflicts) { - min_conflicts = conflicts; - min_angle = angle; - } - if (min_conflicts === 0) { - break; + while (optimum.conflicts > 0 && r < max_r) { + for (j = 1, angle = start_angle + step; j < num_positions && optimum.conflicts > 0; j++) { + co = Math.cos(angle); + si = Math.sin(angle); + + x = cx + r * co; + y = cy - r * si; + + conflicts = this.getNumberofConflicts(x, y, w, h); + if (conflicts < optimum.conflicts) { + optimum.conflicts = conflicts; + optimum.angle = angle; + optimum.r = r; + } + if (optimum.conflicts === 0) { + break; + } + angle += step; } - angle += step; + r += delta_r; } - - r = Geometry.distance([0, 0], offset, 2); - co = Math.cos(min_angle); - si = Math.sin(min_angle); + // console.log(this.id, "after", optimum) + r = optimum.r; + co = Math.cos(optimum.angle); + si = Math.sin(optimum.angle); this.visProp.offset = [r * co, r * si]; if (co < -0.2) { @@ -35786,13 +39472,6 @@ define('base/text',[ } else { this.visProp.anchorx = 'middle'; } - // if (si < -0.2) { - // this.visProp.anchory = 'top'; - // } else if (si > 0.2) { - // this.visProp.anchory = 'bottom'; - // } else { - // this.visProp.anchory = 'middle'; - // } return this; } @@ -35878,8 +39557,8 @@ define('base/text',[ if (!t) { throw new Error("JSXGraph: Can't create text with parent types '" + - (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + - "\nPossible parent types: [x,y], [z,x,y], [element,transformation]"); + (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + + "\nPossible parent types: [x,y], [z,x,y], [element,transformation]"); } if (attr.rotate !== 0 && attr.display === 'internal') { // This is the default value, i.e. no rotation @@ -35951,7 +39630,7 @@ define('base/text',[ t.rendNodeForm.id = t.rendNode.id + '_form'; t.rendNodeRange.id = t.rendNode.id + '_range'; t.rendNodeOut.id = t.rendNode.id + '_out'; - } catch (e) { + } catch (e) { JXG.debug(e); } @@ -36011,7 +39690,7 @@ define('base/text',[ define('utils/uuid',['jxg'], function (JXG) { - "use strict"; + 'use strict'; // constants var uuidCharsStr = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', @@ -36023,11 +39702,17 @@ define('utils/uuid',['jxg'], function (JXG) { */ JXG.Util = JXG.Util || {}; - JXG.Util.genUUID = function () { + JXG.Util.genUUID = function (prefix) { var r, i, uuid = [], rnd = 0; + prefix = prefix || ''; + + if (prefix !== '' && prefix.substr(prefix.length - 1) !== '-') { + prefix = prefix + '-'; + } + for (i = 0; i < 36; i++) { if (i === 8 || i === 13 || i === 18 || i === 23) { uuid[i] = '-'; @@ -36044,7 +39729,7 @@ define('utils/uuid',['jxg'], function (JXG) { } } - return uuid.join(''); + return prefix + uuid.join(''); }; return JXG.Util; @@ -36143,7 +39828,7 @@ define('parser/jessiecode',[ /** * The global scope. - * @type {Object} + * @type Object */ this.scope = { id: 0, @@ -36156,7 +39841,7 @@ define('parser/jessiecode',[ /** * Keeps track of all possible scopes every required. - * @type {Array} + * @type Array */ this.scopes = []; this.scopes.push(this.scope); @@ -36213,7 +39898,7 @@ define('parser/jessiecode',[ /** * Store $log messages in case there's no console. - * @type {Array} + * @type Array */ this.$log = []; @@ -36223,6 +39908,12 @@ define('parser/jessiecode',[ */ this.builtIn = this.defineBuiltIn(); + /** + * List of all possible operands in JessieCode (except of JSXGraph objects). + * @type Object + */ + this.operands = this.getPossibleOperands(); + /** * The board which currently is used to create and look up elements. * @type JXG.Board @@ -36366,7 +40057,10 @@ define('parser/jessiecode',[ if (Type.exists(attributes)) { attr = attributes; } else { - attr = {name: (that.lhs[that.scope] !== 0 ? that.lhs[that.scope] : '')}; + attr = {}; + } + if (attr.name === undefined && attr.id === undefined) { + attr.name = (that.lhs[that.scope.id] !== 0 ? that.lhs[that.scope.id] : ''); } return that.board.create(vname, parameters, attr); }; @@ -36468,32 +40162,44 @@ define('parser/jessiecode',[ }, /** - * Looks up the value of the given variable. + * Looks up the value of the given variable. We use a simple type inspection. + * * @param {String} vname Name of the variable * @param {Boolean} [local=false] Only look up the internal symbol table and don't look for * the <tt>vname</tt> in Math or the element list. + * @param {Boolean} [isFunctionName=false] Lookup function of tpye builtIn, Math.*, creator. + * + * @see JXG.JessieCode#resolveType */ - getvar: function (vname, local) { + getvar: function (vname, local, isFunctionName) { var s; local = Type.def(local, false); + // Local scope has always precedence s = this.isLocalVariable(vname); if (s !== null) { return s.locals[vname]; } - // check for an element with this name - if (this.isCreator(vname)) { - return this.creator(vname); - } - - if (this.isBuiltIn(vname)) { + // Handle the - so far only - few constants by hard coding them. + if (vname === '$board' || vname === 'EULER' || vname === 'PI') { return this.builtIn[vname]; } - if (this.isMathMethod(vname)) { - return Math[vname]; + if (!!isFunctionName) { + if (this.isBuiltIn(vname)) { + return this.builtIn[vname]; + } + + if (this.isMathMethod(vname)) { + return Math[vname]; + } + + // check for an element with this name + if (this.isCreator(vname)) { + return this.creator(vname); + } } if (!local) { @@ -36656,12 +40362,13 @@ define('parser/jessiecode',[ /** * Converts a node type <tt>node_op</tt> and value <tt>op_map</tt> or <tt>op_function</tt> into a executable - * function. + * function. Does a simple type inspection. * @param {Object} node * @returns {function} + * @see JXG.JessieCode#resolveType */ - defineFunction: function (node) { - var fun, i, + defineFunction: function (node) { + var fun, i, that = this, list = node.children[0], scope = this.pushScope(list); @@ -36689,6 +40396,11 @@ define('parser/jessiecode',[ fun = eval(str); /*jslint evil:false*/ + scope.argtypes = []; + for (i = 0; i < list.length; i++) { + scope.argtypes.push(that.resolveType(list[i], node)); + } + return fun; } catch (e) { $jc$._warn('error compiling function\n\n' + str + '\n\n' + e.toString()); @@ -36896,7 +40608,7 @@ define('parser/jessiecode',[ * @param {String} code JessieCode code to be parsed * @param {Boolean} [geonext=false] Geonext compatibility mode. * @param {Boolean} dontstore If false, the code string is stored in this.code. - * @return {Object} Parse JessieCode code and execute it.. + * @return {Object} Parse JessieCode code and execute it. */ parse: function (code, geonext, dontstore) { return this._genericParse(code, 'parse', geonext, dontstore); @@ -36958,20 +40670,26 @@ define('parser/jessiecode',[ var i, v; if (node.replaced) { - // these children exist, if node.replaced is set. + // These children exist, if node.replaced is set. v = this.board.objects[node.children[1][0].value]; if (Type.exists(v) && v.name !== "") { node.type = 'node_var'; node.value = v.name; - // maybe it's not necessary, but just to be sure that everything is cleaned up we better delete all + // Maybe it's not necessary, but just to be sure that everything is cleaned up we better delete all // children and the replaced flag node.children.length = 0; delete node.replaced; } } + if (Type.isArray(node)) { + for (i = 0; i < node.length; i++) { + node[i] = this.replaceIDs(node[i]); + } + } + if (node.children) { // assignments are first evaluated on the right hand side for (i = node.children.length; i > 0; i--) { @@ -36996,8 +40714,8 @@ define('parser/jessiecode',[ v = node.value; - // we are interested only in nodes of type node_var and node_op > op_lhs. - // currently, we are not checking if the id is a local variable. in this case, we're stuck anyway. + // We are interested only in nodes of type node_var and node_op > op_lhs. + // Currently, we are not checking if the id is a local variable. in this case, we're stuck anyway. if (node.type === 'node_op' && v === 'op_lhs' && node.children.length === 1) { this.isLHS = true; @@ -37009,8 +40727,14 @@ define('parser/jessiecode',[ } } + if (Type.isArray(node)) { + for (i = 0; i < node.length; i++) { + node[i] = this.replaceNames(node[i]); + } + } + if (node.children) { - // assignments are first evaluated on the right hand side + // Assignments are first evaluated on the right hand side for (i = node.children.length; i > 0; i--) { if (Type.exists(node.children[i - 1])) { node.children[i - 1] = this.replaceNames(node.children[i - 1]); @@ -37070,7 +40794,7 @@ define('parser/jessiecode',[ } } - // the $()-function-calls are special because their parameter is given as a string, not as a node_var. + // The $()-function-calls are special because their parameter is given as a string, not as a node_var. if (node.type === 'node_op' && node.value === 'op_execfun' && node.children.length > 1 && node.children[0].value === '$' && node.children[1].length > 0) { @@ -37127,6 +40851,80 @@ define('parser/jessiecode',[ return e[v]; }, + /** + * Type inspection: check if the string vname appears as function name in the + * AST node. Used in "op_execfun". This allows the JessieCode exmples below. + * + * @private + * @param {String} vname + * @param {Object} node + * @returns 'any' or 'function' + * @see JXG.JessieCode#execute + * @see JXG.JessieCode#getvar + * + * @example + * var p = board.create('point', [2, 0], {name: 'X'}); + * var txt = 'X(X)'; + * console.log(board.jc.parse(txt)); + * + * @example + * var p = board.create('point', [2, 0], {name: 'X'}); + * var txt = 'f = function(el, X) { return X(el); }; f(X, X);'; + * console.log(board.jc.parse(txt)); + * + * @example + * var p = board.create('point', [2, 0], {name: 'point'}); + * var txt = 'B = point(1,3); X(point);'; + * console.log(board.jc.parse(txt)); + * + * @example + * var p = board.create('point', [2, 0], {name: 'A'}); + * var q = board.create('point', [-2, 0], {name: 'X'}); + * var txt = 'getCoord=function(p, f){ return f(p); }; getCoord(A, X);'; + * console.log(board.jc.parse(txt)); + */ + resolveType: function(vname, node) { + var i, t, + type = 'any'; // Possible values: 'function', 'any' + + if (Type.isArray(node)) { + // node contains the parameters of a function call or function declaration + for (i = 0; i < node.length; i++) { + t = this.resolveType(vname, node[i]); + if (t !== 'any') { + type = t; + return type; + } + } + } + + if (node.type === 'node_op' && node.value === 'op_execfun' && + node.children[0].type === 'node_var' && node.children[0].value === vname) { + return 'function'; + } + + if (node.type === 'node_op') { + for (i = 0; i < node.children.length; i++) { + if (node.children[0].type === 'node_var' && node.children[0].value === vname && + (node.value === 'op_add' || node.value === 'op_sub' || node.value === 'op_mul' || + node.value === 'op_div' || node.value === 'op_mod' || node.value === 'op_exp' || + node.value === 'op_neg')) { + return 'any'; + } + } + + for (i = 0; i < node.children.length; i++) { + t = this.resolveType(vname, node.children[i]); + if (t !== 'any') { + type = t; + return type; + } + } + } + + return 'any'; + }, + /** * Resolves the lefthand side of an assignment operation * @param node @@ -37214,7 +41012,7 @@ define('parser/jessiecode',[ break; case 'op_assign': v = this.getLHS(node.children[0]); - this.lhs[this.scope.id] = v[1]; + this.lhs[this.scope.id] = v.what; if (v.o.type && v.o.elementClass && v.o.methodMap && v.what === 'label') { this._error('Left-hand side of assignment is read-only.'); @@ -37358,7 +41156,9 @@ define('parser/jessiecode',[ } // look up the variables name in the variable table + node.children[0]._isFunctionName = true; fun = this.execute(node.children[0]); + delete node.children[0]._isFunctionName; // determine the scope the function wants to run in if (fun && fun.sc) { @@ -37373,7 +41173,14 @@ define('parser/jessiecode',[ // interpret ALL the parameters for (i = 0; i < list.length; i++) { - parents[i] = this.execute(list[i]); + if (Type.exists(fun.scope) && Type.exists(fun.scope.argtypes) &&fun.scope.argtypes[i] === 'function') { + // Type inspection + list[i]._isFunctionName = true; + parents[i] = this.execute(list[i]); + delete list[i]._isFunctionName; + } else { + parents[i] = this.execute(list[i]); + } //parents[i] = Type.evalSlider(this.execute(list[i])); this.dpstack[this.pscope].push({ line: node.children[1][i].line, @@ -37433,7 +41240,7 @@ define('parser/jessiecode',[ v = this.getvar(node.children[0]); ret = this.del(v); break; - case 'op_equ': + case 'op_eq': // == is intentional /*jslint eqeq:true*/ ret = this.execute(node.children[0]) == this.execute(node.children[1]); @@ -37448,16 +41255,16 @@ define('parser/jessiecode',[ case 'op_approx': ret = Math.abs(this.execute(node.children[0]) - this.execute(node.children[1])) < Mat.eps; break; - case 'op_grt': + case 'op_gt': ret = this.execute(node.children[0]) > this.execute(node.children[1]); break; - case 'op_lot': + case 'op_lt': ret = this.execute(node.children[0]) < this.execute(node.children[1]); break; - case 'op_gre': + case 'op_geq': ret = this.execute(node.children[0]) >= this.execute(node.children[1]); break; - case 'op_loe': + case 'op_leq': ret = this.execute(node.children[0]) <= this.execute(node.children[1]); break; case 'op_or': @@ -37495,11 +41302,16 @@ define('parser/jessiecode',[ break; case 'node_var': - ret = this.getvar(node.value); + // node._isFunctionName is set in execute: at op_execfun. + ret = this.getvar(node.value, false, node._isFunctionName); break; case 'node_const': - ret = Number(node.value); + if(node.value === null) { + ret = null; + } else { + ret = Number(node.value); + } break; case 'node_const_bool': @@ -37643,7 +41455,7 @@ define('parser/jessiecode',[ this.popScope(); break; case 'op_execfunmath': - console.log('TODO'); + console.log('op_execfunmath: TODO'); ret = '-1'; break; case 'op_execfun': @@ -37664,6 +41476,13 @@ define('parser/jessiecode',[ list.push(this.compile(node.children[1][i], js)); } ret = this.compile(node.children[0], js) + '(' + list.join(', ') + (node.children[2] && js ? ', ' + e : '') + ')' + (node.children[2] && !js ? e : ''); + if (js) { + // Inserting a newline here allows simulataneously + // - procedural calls like Q.moveTo(...); and + // - function calls in expressions like log(x) + 1; + // Problem: procedural calls will not be ended by a semicolon. + ret += '\n'; + } // save us a function call when compiled to javascript if (js && node.children[0].value === '$') { @@ -37697,37 +41516,37 @@ define('parser/jessiecode',[ ret += this.compile(node.children[0], js) + ')'; break; - case 'op_equ': - ret = '(' + this.compile(node.children[0], js) + ' == ' + this.compile(node.children[1], js) + ')'; + case 'op_eq': + ret = '(' + this.compile(node.children[0], js) + ' === ' + this.compile(node.children[1], js) + ')'; break; case 'op_neq': - ret = '(' + this.compile(node.children[0], js) + ' != ' + this.compile(node.children[1], js) + ')'; + ret = '(' + this.compile(node.children[0], js) + ' !== ' + this.compile(node.children[1], js) + ')'; break; case 'op_approx': ret = '(' + this.compile(node.children[0], js) + ' ~= ' + this.compile(node.children[1], js) + ')'; break; - case 'op_grt': + case 'op_gt': if (js) { ret = '$jc$.gt(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ')'; } else { ret = '(' + this.compile(node.children[0], js) + ' > ' + this.compile(node.children[1], js) + ')'; } break; - case 'op_lot': + case 'op_lt': if (js) { ret = '$jc$.lt(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ')'; } else { ret = '(' + this.compile(node.children[0], js) + ' < ' + this.compile(node.children[1], js) + ')'; } break; - case 'op_gre': + case 'op_geq': if (js) { ret = '$jc$.geq(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ')'; } else { ret = '(' + this.compile(node.children[0], js) + ' >= ' + this.compile(node.children[1], js) + ')'; } break; - case 'op_loe': + case 'op_leq': if (js) { ret = '$jc$.leq(' + this.compile(node.children[0], js) + ', ' + this.compile(node.children[1], js) + ')'; } else { @@ -37817,12 +41636,33 @@ define('parser/jessiecode',[ } if (node.needsBrackets) { - ret = '{\n' + ret + '}\n'; + ret = '{\n' + ret + '\n}\n'; } return ret; }, + /** + * This is used as the global getName() function. + * @param {JXG.GeometryElement} obj + * @param {Boolean} useId + * @returns {String} + */ + getName: function (obj,useId) { + var name = ''; + + if (Type.exists(obj) && Type.exists(obj.getName)) { + name = obj.getName(); + if ((!Type.exists(name) || name === '') && !!useId) { + name = obj.id; + } + } else if (!!useId) { + name = obj.id; + } + + return name; + }, + /** * This is used as the global X() function. * @param {JXG.Point|JXG.Text} e @@ -37859,6 +41699,19 @@ define('parser/jessiecode',[ return e.L(); }, + /** + * This is used as the global area() function. + * @param {JXG.Circle|JXG.Polygon} obj + * @returns {Number} + */ + area: function (obj) { + if (!Type.exists(obj) || !Type.exists(obj.Area)) { + this._error('Error: Can\'t calculate area.'); + } + + return obj.Area(); + }, + /** * This is used as the global dist() function. * @param {JXG.Point} p1 @@ -37873,6 +41726,19 @@ define('parser/jessiecode',[ return p1.Dist(p2); }, + /** + * This is used as the global radius() function. + * @param {JXG.Circle|Sector} obj + * @returns {Number} + */ + radius: function (obj) { + if (!Type.exists(obj) || !Type.exists(obj.Radius)) { + this._error('Error: Can\'t calculate radius.'); + } + + return obj.Radius(); + }, + /** * + operator implementation * @param {Number|Array|JXG.Point} a @@ -38079,32 +41945,39 @@ define('parser/jessiecode',[ return Mat.pow(a, b); }, - lt: function(a, b) { + lt: function (a, b) { if (Interval.isInterval(a) || Interval.isInterval(b)) { return Interval.lt(a, b); } return a < b; }, - leq: function(a, b) { + leq: function (a, b) { if (Interval.isInterval(a) || Interval.isInterval(b)) { return Interval.leq(a, b); } return a <= b; }, - gt: function(a, b) { + gt: function (a, b) { if (Interval.isInterval(a) || Interval.isInterval(b)) { return Interval.gt(a, b); } return a > b; }, - geq: function(a, b) { + geq: function (a, b) { if (Interval.isInterval(a) || Interval.isInterval(b)) { return Intervalt.geq(a, b); } return a >= b; }, - DDD: function(f) { + randint: function (min, max, step) { + if (!Type.exists(step)) { + step = 1; + } + return Math.round(Math.random() * (max - min) / step) * step + min; + }, + + DDD: function (f) { console.log('Dummy derivative function. This should never appear!'); }, @@ -38212,42 +42085,58 @@ define('parser/jessiecode',[ builtIn = { PI: Math.PI, EULER: Math.E, + D: that.DDD, X: that.X, Y: that.Y, V: that.V, L: that.L, - dist: that.dist, - rad: Geometry.rad, + + acosh: Mat.acosh, + acot: Mat.acot, + asinh: Mat.asinh, + binomial: Mat.binomial, + cbrt: Mat.cbrt, + cosh: Mat.cosh, + cot: Mat.cot, deg: Geometry.trueAngle, + A: that.area, + area: that.area, + dist: that.dist, + R: that.radius, + radius: that.radius, + erf: Mat.erf, + erfc: Mat.erfc, + erfi: Mat.erfi, factorial: Mat.factorial, - trunc: Type.trunc, - log: Mat.log, + gcd: Mat.gcd, + lb: Mat.log2, + lcm: Mat.lcm, + ld: Mat.log2, + lg: Mat.log10, ln: Math.log, + log: Mat.log, log10: Mat.log10, - lg: Mat.log10, log2: Mat.log2, - lb: Mat.log2, - ld: Mat.log2, - cosh: Mat.cosh, - sinh: Mat.sinh, - cot: Mat.cot, - acot: Mat.acot, - + ndtr: Mat.ndtr, + ndtri: Mat.ndtri, nthroot: Mat.nthroot, - cbrt: Mat.cbrt, pow: Mat.pow, + rad: Geometry.rad, ratpow: Mat.ratpow, - gcd: Mat.gcd, - lcm: Mat.lcm, - binomial: Mat.binomial, + trunc: Type.trunc, + sinh: Mat.sinh, + + randint: that.randint, + IfThen: that.ifthen, 'import': that.importModule, 'use': that.use, 'remove': that.del, '$': that.getElementById, + getName: that.getName, + name: that.getName, '$board': that.board, - '$log': that.log, - D: that.DDD + '$log': that.log }; // special scopes for factorial, deg, and rad @@ -38263,35 +42152,52 @@ define('parser/jessiecode',[ builtIn.Y.src = '$jc$.Y'; builtIn.V.src = '$jc$.V'; builtIn.L.src = '$jc$.L'; - builtIn.dist.src = '$jc$.dist'; - builtIn.rad.src = 'JXG.Math.Geometry.rad'; + + builtIn.acosh.src = 'JXG.Math.acosh'; + builtIn.acot.src = 'JXG.Math.acot'; + builtIn.asinh.src = 'JXG.Math.asinh'; + builtIn.binomial.src = 'JXG.Math.binomial'; + builtIn.cbrt.src = 'JXG.Math.cbrt'; + builtIn.cot.src = 'JXG.Math.cot'; + builtIn.cosh.src = 'JXG.Math.cosh'; builtIn.deg.src = 'JXG.Math.Geometry.trueAngle'; + builtIn.erf.src = 'JXG.Math.erf'; + builtIn.erfc.src = 'JXG.Math.erfc'; + builtIn.erfi.src = 'JXG.Math.erfi'; + builtIn.A.src = '$jc$.area'; + builtIn.area.src = '$jc$.area'; + builtIn.dist.src = '$jc$.dist'; + builtIn.R.src = '$jc$.radius'; + builtIn.radius.src = '$jc$.radius'; builtIn.factorial.src = 'JXG.Math.factorial'; - builtIn.trunc.src = 'JXG.trunc'; - builtIn.log.src = 'JXG.Math.log'; + builtIn.gcd.src = 'JXG.Math.gcd'; + builtIn.lb.src = 'JXG.Math.log2'; + builtIn.lcm.src = 'JXG.Math.lcm'; + builtIn.ld.src = 'JXG.Math.log2'; + builtIn.lg.src = 'JXG.Math.log10'; builtIn.ln.src = 'Math.log'; + builtIn.log.src = 'JXG.Math.log'; builtIn.log10.src = 'JXG.Math.log10'; - builtIn.lg.src = 'JXG.Math.log10'; builtIn.log2.src = 'JXG.Math.log2'; - builtIn.lb.src = 'JXG.Math.log2'; - builtIn.ld.src = 'JXG.Math.log2'; - builtIn.cosh.src = 'JXG.Math.cosh'; - builtIn.sinh.src = 'JXG.Math.sinh'; - builtIn.cot.src = 'JXG.Math.cot'; - builtIn.acot.src = 'JXG.Math.acot'; + builtIn.ndtr.src = 'JXG.Math.ndtr'; + builtIn.ndtri.src = 'JXG.Math.ndtri'; builtIn.nthroot.src = 'JXG.Math.nthroot'; - builtIn.cbrt.src = 'JXG.Math.cbrt'; builtIn.pow.src = 'JXG.Math.pow'; + builtIn.rad.src = 'JXG.Math.Geometry.rad'; builtIn.ratpow.src = 'JXG.Math.ratpow'; - builtIn.gcd.src = 'JXG.Math.gcd'; - builtIn.lcm.src = 'JXG.Math.lcm'; - builtIn.binomial.src = 'JXG.Math.binomial'; + builtIn.trunc.src = 'JXG.trunc'; + builtIn.sinh.src = 'JXG.Math.sinh'; + + builtIn.randint.src = '$jc$.randint'; + builtIn['import'].src = '$jc$.importModule'; builtIn.use.src = '$jc$.use'; builtIn.remove.src = '$jc$.del'; builtIn.IfThen.src = '$jc$.ifthen'; // usually unused, see node_op > op_execfun builtIn.$.src = '(function (n) { return $jc$.board.select(n); })'; + builtIn.getName.src = '$jc$.getName'; + builtIn.name.src = '$jc$.getName'; if (builtIn.$board) { builtIn.$board.src = '$jc$.board'; } @@ -38300,6 +42206,103 @@ define('parser/jessiecode',[ return builtIn; }, + /** + * Returns information about the possible functions and constants. + * @returns {Object} + */ + getPossibleOperands: function () { + var FORBIDDEN = ['E'], + jessiecode = this.defineBuiltIn(), + math = Math, + jc, ma, merge, + i, j, p, len, e, + funcs, funcsJC, consts, operands, + sort, pack; + + sort = function (a, b) { + return a.toLowerCase().localeCompare(b.toLowerCase()); + }; + + pack = function (name, origin) { + var that = null; + + if (origin === 'jc') that = jessiecode[name]; + else if (origin === 'Math') that = math[name]; + else return; + + if (FORBIDDEN.includes(name)) { + return; + } else if (JXG.isFunction(that)) { + return { + name: name, + type: 'function', + numParams: that.length, + origin: origin, + }; + } else if (JXG.isNumber(that)) { + return { + name: name, + type: 'constant', + value: that, + origin: origin, + }; + } else if (that !== undefined) { + console.error('undefined type', that); + } + }; + + jc = Object.getOwnPropertyNames(jessiecode).sort(sort); + ma = Object.getOwnPropertyNames(math).sort(sort); + merge = []; + i = 0; + j = 0; + + while (i < jc.length || j < ma.length) { + if (jc[i] === ma[j]) { + p = pack(ma[j], 'Math'); + if (JXG.exists(p)) merge.push(p); + i++; + j++; + } else if (!JXG.exists(ma[j]) || jc[i].toLowerCase().localeCompare(ma[j].toLowerCase()) < 0) { + p = pack(jc[i], 'jc'); + if (JXG.exists(p)) merge.push(p); + i++; + } else { + p = pack(ma[j], 'Math'); + if (JXG.exists(p)) merge.push(p); + j++; + } + } + + funcs = []; + funcsJC = []; + consts = []; + operands = {}; + len = merge.length; + for (i = 0; i < len; i++) { + e = merge[i]; + switch (e.type) { + case 'function': + funcs.push(e.name); + if (e.origin === 'jc') + funcsJC.push(e.name); + break; + case 'constant': + consts.push(e.name); + break; + } + operands[e.name] = e; + } + + return { + all: operands, + list: merge, + functions: funcs, + functions_jessiecode: funcsJC, + constants: consts, + }; + }, + /** * Output a debugging message. Uses debug console, if available. Otherwise an HTML element with the * id "debug" and an innerHTML property is used. @@ -38420,12 +42423,12 @@ define('parser/jessiecode',[ } */ var parser = (function(){ -var o=function(k,v,o,l){for(o=o||{},l=k.length;l--;o[k[l]]=v);return o},$V0=[2,14],$V1=[1,13],$V2=[1,37],$V3=[1,14],$V4=[1,15],$V5=[1,21],$V6=[1,16],$V7=[1,17],$V8=[1,33],$V9=[1,18],$Va=[1,19],$Vb=[1,12],$Vc=[1,59],$Vd=[1,60],$Ve=[1,58],$Vf=[1,46],$Vg=[1,48],$Vh=[1,49],$Vi=[1,50],$Vj=[1,51],$Vk=[1,52],$Vl=[1,53],$Vm=[1,54],$Vn=[1,45],$Vo=[1,38],$Vp=[1,39],$Vq=[5,7,8,14,15,16,17,19,20,21,23,26,27,50,51,58,65,74,75,76,77,78,79,80,82,91,93],$Vr=[5,7,8,12,14,15,16,17,19,20,21,23,26,27,50,51,58,65,74,75,76,77,78,79,80,82,91,93],$Vs=[8,10,16,32,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,57,64,65,66,83,86],$Vt=[2,48],$Vu=[1,72],$Vv=[10,16,32,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,57,66,83,86],$Vw=[1,78],$Vx=[8,10,16,32,34,35,37,41,42,43,45,46,47,48,50,51,53,54,55,57,64,65,66,83,86],$Vy=[1,82],$Vz=[8,10,16,32,34,35,37,39,45,46,47,48,50,51,53,54,55,57,64,65,66,83,86],$VA=[1,83],$VB=[1,84],$VC=[1,85],$VD=[8,10,16,32,34,35,37,39,41,42,43,50,51,53,54,55,57,64,65,66,83,86],$VE=[1,89],$VF=[1,90],$VG=[1,91],$VH=[1,92],$VI=[1,97],$VJ=[8,10,16,32,34,35,37,39,41,42,43,45,46,47,48,53,54,55,57,64,65,66,83,86],$VK=[1,103],$VL=[1,104],$VM=[8,10,16,32,34,35,37,39,41,42,43,45,46,47,48,50,51,57,64,65,66,83,86],$VN=[1,105],$VO=[1,106],$VP=[1,107],$VQ=[1,126],$VR=[1,139],$VS=[83,86],$VT=[1,149],$VU=[10,66,86],$VV=[8,10,16,20,32,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,57,64,65,66,82,83,86],$VW=[1,166],$VX=[10,86]; +var o=function(k,v,o,l){for(o=o||{},l=k.length;l--;o[k[l]]=v);return o},$V0=[2,14],$V1=[1,13],$V2=[1,37],$V3=[1,14],$V4=[1,15],$V5=[1,21],$V6=[1,16],$V7=[1,17],$V8=[1,33],$V9=[1,18],$Va=[1,19],$Vb=[1,12],$Vc=[1,59],$Vd=[1,60],$Ve=[1,58],$Vf=[1,46],$Vg=[1,48],$Vh=[1,49],$Vi=[1,50],$Vj=[1,51],$Vk=[1,52],$Vl=[1,53],$Vm=[1,54],$Vn=[1,45],$Vo=[1,38],$Vp=[1,39],$Vq=[5,7,8,14,15,16,17,19,20,21,23,26,27,50,51,58,65,74,75,76,77,78,79,80,82,91,93],$Vr=[5,7,8,12,14,15,16,17,19,20,21,23,26,27,50,51,58,65,74,75,76,77,78,79,80,82,91,93],$Vs=[8,10,16,32,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,57,64,65,66,83,86],$Vt=[2,48],$Vu=[1,72],$Vv=[10,16,32,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,57,66,83,86],$Vw=[1,78],$Vx=[8,10,16,32,34,35,37,41,42,43,45,46,47,48,50,51,53,54,55,57,64,65,66,83,86],$Vy=[1,82],$Vz=[8,10,16,32,34,35,37,39,45,46,47,48,50,51,53,54,55,57,64,65,66,83,86],$VA=[1,83],$VB=[1,84],$VC=[1,85],$VD=[8,10,16,32,34,35,37,39,41,42,43,50,51,53,54,55,57,64,65,66,83,86],$VE=[1,89],$VF=[1,90],$VG=[1,91],$VH=[1,92],$VI=[1,97],$VJ=[8,10,16,32,34,35,37,39,41,42,43,45,46,47,48,53,54,55,57,64,65,66,83,86],$VK=[1,103],$VL=[1,104],$VM=[8,10,16,32,34,35,37,39,41,42,43,45,46,47,48,50,51,57,64,65,66,83,86],$VN=[1,105],$VO=[1,106],$VP=[1,107],$VQ=[1,126],$VR=[1,139],$VS=[83,86],$VT=[1,150],$VU=[10,66,86],$VV=[8,10,16,20,32,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,57,64,65,66,82,83,86],$VW=[1,167],$VX=[10,86]; var parser = {trace: function trace () { }, yy: {}, symbols_: {"error":2,"Program":3,"StatementList":4,"EOF":5,"IfStatement":6,"IF":7,"(":8,"Expression":9,")":10,"Statement":11,"ELSE":12,"LoopStatement":13,"WHILE":14,"FOR":15,";":16,"DO":17,"UnaryStatement":18,"USE":19,"IDENTIFIER":20,"DELETE":21,"ReturnStatement":22,"RETURN":23,"EmptyStatement":24,"StatementBlock":25,"{":26,"}":27,"ExpressionStatement":28,"AssignmentExpression":29,"ConditionalExpression":30,"LeftHandSideExpression":31,"=":32,"LogicalORExpression":33,"?":34,":":35,"LogicalANDExpression":36,"||":37,"EqualityExpression":38,"&&":39,"RelationalExpression":40,"==":41,"!=":42,"~=":43,"AdditiveExpression":44,"<":45,">":46,"<=":47,">=":48,"MultiplicativeExpression":49,"+":50,"-":51,"UnaryExpression":52,"*":53,"/":54,"%":55,"ExponentExpression":56,"^":57,"!":58,"MemberExpression":59,"CallExpression":60,"PrimaryExpression":61,"FunctionExpression":62,"MapExpression":63,".":64,"[":65,"]":66,"BasicLiteral":67,"ObjectLiteral":68,"ArrayLiteral":69,"NullLiteral":70,"BooleanLiteral":71,"StringLiteral":72,"NumberLiteral":73,"NULL":74,"TRUE":75,"FALSE":76,"STRING":77,"NUMBER":78,"NAN":79,"INFINITY":80,"ElementList":81,"<<":82,">>":83,"PropertyList":84,"Property":85,",":86,"PropertyName":87,"Arguments":88,"AttributeList":89,"Attribute":90,"FUNCTION":91,"ParameterDefinitionList":92,"MAP":93,"->":94,"$accept":0,"$end":1}, terminals_: {2:"error",5:"EOF",7:"IF",8:"(",10:")",12:"ELSE",14:"WHILE",15:"FOR",16:";",17:"DO",19:"USE",20:"IDENTIFIER",21:"DELETE",23:"RETURN",26:"{",27:"}",32:"=",34:"?",35:":",37:"||",39:"&&",41:"==",42:"!=",43:"~=",45:"<",46:">",47:"<=",48:">=",50:"+",51:"-",53:"*",54:"/",55:"%",57:"^",58:"!",64:".",65:"[",66:"]",74:"NULL",75:"TRUE",76:"FALSE",77:"STRING",78:"NUMBER",79:"NAN",80:"INFINITY",82:"<<",83:">>",86:",",91:"FUNCTION",93:"MAP",94:"->"}, -productions_: [0,[3,2],[6,5],[6,7],[13,5],[13,9],[13,7],[18,2],[18,2],[22,2],[22,3],[24,1],[25,3],[4,2],[4,0],[11,1],[11,1],[11,1],[11,1],[11,1],[11,1],[11,1],[28,2],[9,1],[29,1],[29,3],[30,1],[30,5],[33,1],[33,3],[36,1],[36,3],[38,1],[38,3],[38,3],[38,3],[40,1],[40,3],[40,3],[40,3],[40,3],[44,1],[44,3],[44,3],[49,1],[49,3],[49,3],[49,3],[56,1],[56,3],[52,1],[52,2],[52,2],[52,2],[31,1],[31,1],[59,1],[59,1],[59,1],[59,3],[59,4],[61,1],[61,1],[61,1],[61,1],[61,3],[67,1],[67,1],[67,1],[67,1],[70,1],[71,1],[71,1],[72,1],[73,1],[73,1],[73,1],[69,2],[69,3],[68,2],[68,3],[84,1],[84,3],[85,3],[87,1],[87,1],[87,1],[60,2],[60,3],[60,2],[60,4],[60,3],[88,2],[88,3],[89,1],[89,3],[90,1],[90,1],[81,1],[81,3],[62,4],[62,5],[63,6],[92,1],[92,3]], +productions_: [0,[3,2],[6,5],[6,7],[13,5],[13,9],[13,7],[18,2],[18,2],[22,2],[22,3],[24,1],[25,3],[4,2],[4,0],[11,1],[11,1],[11,1],[11,1],[11,1],[11,1],[11,1],[28,2],[9,1],[29,1],[29,3],[30,1],[30,5],[33,1],[33,3],[36,1],[36,3],[38,1],[38,3],[38,3],[38,3],[40,1],[40,3],[40,3],[40,3],[40,3],[44,1],[44,3],[44,3],[49,1],[49,3],[49,3],[49,3],[56,1],[56,3],[52,1],[52,2],[52,2],[52,2],[31,1],[31,1],[59,1],[59,1],[59,1],[59,3],[59,4],[61,1],[61,1],[61,1],[61,1],[61,3],[67,1],[67,1],[67,1],[67,1],[70,1],[71,1],[71,1],[72,1],[73,1],[73,1],[73,1],[69,2],[69,3],[68,2],[68,3],[84,1],[84,3],[85,3],[87,1],[87,1],[87,1],[60,2],[60,3],[60,2],[60,4],[60,3],[88,2],[88,3],[89,1],[89,3],[90,1],[90,1],[81,1],[81,3],[62,4],[62,5],[63,5],[63,6],[92,1],[92,3]], performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate /* action[1] */, $$ /* vstack */, _$ /* lstack */) { /* this == yyval */ @@ -38489,7 +42492,7 @@ case 31: this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_and', $$[$0-2], $$[$0]); this.$.isMath = false; break; case 33: - this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_equ', $$[$0-2], $$[$0]); this.$.isMath = false; + this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_eq', $$[$0-2], $$[$0]); this.$.isMath = false; break; case 34: this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_neq', $$[$0-2], $$[$0]); this.$.isMath = false; @@ -38498,16 +42501,16 @@ case 35: this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_approx', $$[$0-2], $$[$0]); this.$.isMath = false; break; case 37: - this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_lot', $$[$0-2], $$[$0]); this.$.isMath = false; + this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_lt', $$[$0-2], $$[$0]); this.$.isMath = false; break; case 38: - this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_grt', $$[$0-2], $$[$0]); this.$.isMath = false; + this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_gt', $$[$0-2], $$[$0]); this.$.isMath = false; break; case 39: - this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_loe', $$[$0-2], $$[$0]); this.$.isMath = false; + this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_leq', $$[$0-2], $$[$0]); this.$.isMath = false; break; case 40: - this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_gre', $$[$0-2], $$[$0]); this.$.isMath = false; + this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_geq', $$[$0-2], $$[$0]); this.$.isMath = false; break; case 42: this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_add', $$[$0-2], $$[$0]); this.$.isMath = true; @@ -38576,10 +42579,10 @@ case 78: this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_array', $$[$0-1]); break; case 79: - this.$ = AST.createNode(lc(_$[$0-1]), 'node_op', 'op_emptyobject', {}); + this.$ = AST.createNode(lc(_$[$0-1]), 'node_op', 'op_emptyobject', {}); this.$.needsBrackets = true; break; case 80: - this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_proplst_val', $$[$0-1]); + this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_proplst_val', $$[$0-1]); this.$.needsBrackets = true; break; case 82: this.$ = AST.createNode(lc(_$[$0-2]), 'node_op', 'op_proplst', $$[$0-2], $$[$0]); @@ -38596,10 +42599,10 @@ break; case 92: this.$ = []; break; -case 94: case 98: case 103: +case 94: case 98: case 104: this.$ = [$$[$0]]; break; -case 95: case 99: case 104: +case 95: case 99: case 105: this.$ = $$[$0-2].concat($$[$0]); break; case 96: @@ -38612,11 +42615,14 @@ case 101: this.$ = AST.createNode(lc(_$[$0-4]), 'node_op', 'op_function', $$[$0-2], $$[$0]); this.$.isMath = false; break; case 102: + this.$ = AST.createNode(lc(_$[$0-4]), 'node_op', 'op_map', [], $$[$0]); +break; +case 103: this.$ = AST.createNode(lc(_$[$0-5]), 'node_op', 'op_map', $$[$0-3], $$[$0]); break; } }, -table: [o([5,7,8,14,15,16,17,19,20,21,23,26,50,51,58,65,74,75,76,77,78,79,80,82,91,93],$V0,{3:1,4:2}),{1:[3]},{5:[1,3],6:6,7:$V1,8:$V2,9:20,11:4,13:7,14:$V3,15:$V4,16:$V5,17:$V6,18:8,19:$V7,20:$V8,21:$V9,22:9,23:$Va,24:11,25:5,26:$Vb,28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{1:[2,1]},o($Vq,[2,13]),o($Vr,[2,15]),o($Vr,[2,16]),o($Vr,[2,17]),o($Vr,[2,18]),o($Vr,[2,19]),o($Vr,[2,20]),o($Vr,[2,21]),o([7,8,14,15,16,17,19,20,21,23,26,27,50,51,58,65,74,75,76,77,78,79,80,82,91,93],$V0,{4:61}),{8:[1,62]},{8:[1,63]},{8:[1,64]},{6:6,7:$V1,8:$V2,9:20,11:65,13:7,14:$V3,15:$V4,16:$V5,17:$V6,18:8,19:$V7,20:$V8,21:$V9,22:9,23:$Va,24:11,25:5,26:$Vb,28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{20:[1,66]},{20:[1,67]},{8:$V2,9:69,16:[1,68],20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{16:[1,70]},o($Vr,[2,11]),o($Vs,[2,23]),o($Vs,[2,24]),o([8,10,16,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,64,65,66,83,86],$Vt,{32:[1,71],57:$Vu}),o([8,10,16,32,35,39,41,42,43,45,46,47,48,50,51,53,54,55,57,64,65,66,83,86],[2,26],{34:[1,73],37:[1,74]}),o($Vv,[2,54],{88:77,8:$Vw,64:[1,75],65:[1,76]}),o($Vv,[2,55],{88:79,8:$Vw,64:[1,81],65:[1,80]}),o($Vx,[2,28],{39:$Vy}),o($Vs,[2,56]),o($Vs,[2,57]),o($Vs,[2,58]),o($Vz,[2,30],{41:$VA,42:$VB,43:$VC}),o($Vs,[2,61]),o($Vs,[2,62]),o($Vs,[2,63]),o($Vs,[2,64]),{8:$V2,9:86,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:[1,87]},{8:[1,88]},o($VD,[2,32],{45:$VE,46:$VF,47:$VG,48:$VH}),o($Vs,[2,66]),o($Vs,[2,67]),o($Vs,[2,68]),o($Vs,[2,69]),{20:$VI,72:98,73:99,77:$Vj,78:$Vk,79:$Vl,80:$Vm,83:[1,93],84:94,85:95,87:96},{8:$V2,20:$V8,29:102,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,66:[1,100],67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,81:101,82:$Vn,91:$Vo,93:$Vp},o($VJ,[2,36],{50:$VK,51:$VL}),o($Vs,[2,70]),o($Vs,[2,71]),o($Vs,[2,72]),o($Vs,[2,73]),o($Vs,[2,74]),o($Vs,[2,75]),o($Vs,[2,76]),o($VM,[2,41],{53:$VN,54:$VO,55:$VP}),o($Vs,[2,44]),o($Vs,[2,50]),{8:$V2,20:$V8,31:109,50:$Vc,51:$Vd,52:108,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,50:$Vc,51:$Vd,52:110,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,50:$Vc,51:$Vd,52:111,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{6:6,7:$V1,8:$V2,9:20,11:4,13:7,14:$V3,15:$V4,16:$V5,17:$V6,18:8,19:$V7,20:$V8,21:$V9,22:9,23:$Va,24:11,25:5,26:$Vb,27:[1,112],28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,9:113,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,9:114,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,9:115,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{14:[1,116]},o($Vr,[2,7]),o($Vr,[2,8]),o($Vr,[2,9]),{16:[1,117]},o($Vr,[2,22]),{8:$V2,20:$V8,29:118,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,50:$Vc,51:$Vd,52:119,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,29:120,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,36:121,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{20:[1,122]},{8:$V2,9:123,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},o($Vs,[2,87],{89:124,90:125,68:127,20:$VQ,82:$Vn}),{8:$V2,10:[1,128],20:$V8,29:102,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,81:129,82:$Vn,91:$Vo,93:$Vp},o($Vs,[2,89]),{8:$V2,9:130,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{20:[1,131]},{8:$V2,20:$V8,31:109,38:132,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,40:133,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,40:134,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,40:135,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{10:[1,136]},{10:[1,137],20:$VR,92:138},{20:$VR,92:140},{8:$V2,20:$V8,31:109,44:141,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,44:142,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,44:143,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,44:144,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},o($Vs,[2,79]),{83:[1,145],86:[1,146]},o($VS,[2,81]),{35:[1,147]},{35:[2,84]},{35:[2,85]},{35:[2,86]},o($Vs,[2,77]),{66:[1,148],86:$VT},o($VU,[2,98]),{8:$V2,20:$V8,31:109,49:150,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,49:151,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,50:$Vc,51:$Vd,52:152,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,50:$Vc,51:$Vd,52:153,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,50:$Vc,51:$Vd,52:154,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},o($Vs,[2,51]),o([8,10,16,32,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,64,65,66,83,86],$Vt,{57:$Vu}),o($Vs,[2,52]),o($Vs,[2,53]),o([5,7,8,10,12,14,15,16,17,19,20,21,23,26,27,32,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,57,58,64,65,66,74,75,76,77,78,79,80,82,83,86,91,93],[2,12]),{10:[1,155]},{10:[1,156]},{16:[1,157]},{8:[1,158]},o($Vr,[2,10]),o($Vs,[2,25]),o($Vs,[2,49]),{35:[1,159]},o($Vx,[2,29],{39:$Vy}),o($Vs,[2,59]),{66:[1,160]},o([8,10,16,32,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,57,64,65,66,83],[2,88],{86:[1,161]}),o($Vs,[2,94]),o($Vs,[2,96]),o($Vs,[2,97]),o($VV,[2,92]),{10:[1,162],86:$VT},{66:[1,163]},o($Vs,[2,91]),o($Vz,[2,31],{41:$VA,42:$VB,43:$VC}),o($VD,[2,33],{45:$VE,46:$VF,47:$VG,48:$VH}),o($VD,[2,34],{45:$VE,46:$VF,47:$VG,48:$VH}),o($VD,[2,35],{45:$VE,46:$VF,47:$VG,48:$VH}),o($Vs,[2,65]),{25:164,26:$Vb},{10:[1,165],86:$VW},o($VX,[2,103]),{10:[1,167],86:$VW},o($VJ,[2,37],{50:$VK,51:$VL}),o($VJ,[2,38],{50:$VK,51:$VL}),o($VJ,[2,39],{50:$VK,51:$VL}),o($VJ,[2,40],{50:$VK,51:$VL}),o($Vs,[2,80]),{20:$VI,72:98,73:99,77:$Vj,78:$Vk,79:$Vl,80:$Vm,85:168,87:96},{8:$V2,20:$V8,29:169,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},o($Vs,[2,78]),{8:$V2,20:$V8,29:170,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},o($VM,[2,42],{53:$VN,54:$VO,55:$VP}),o($VM,[2,43],{53:$VN,54:$VO,55:$VP}),o($Vs,[2,45]),o($Vs,[2,46]),o($Vs,[2,47]),{6:6,7:$V1,8:$V2,9:20,11:171,13:7,14:$V3,15:$V4,16:$V5,17:$V6,18:8,19:$V7,20:$V8,21:$V9,22:9,23:$Va,24:11,25:5,26:$Vb,28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{6:6,7:$V1,8:$V2,9:20,11:172,13:7,14:$V3,15:$V4,16:$V5,17:$V6,18:8,19:$V7,20:$V8,21:$V9,22:9,23:$Va,24:11,25:5,26:$Vb,28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,9:173,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,9:174,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,29:175,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},o($Vs,[2,60]),{20:$VQ,68:127,82:$Vn,90:176},o($VV,[2,93]),o($Vs,[2,90]),o($Vs,[2,100]),{25:177,26:$Vb},{20:[1,178]},{94:[1,179]},o($VS,[2,82]),o($VS,[2,83]),o($VU,[2,99]),o($Vq,[2,2],{12:[1,180]}),o($Vr,[2,4]),{16:[1,181]},{10:[1,182]},o($Vs,[2,27]),o($Vs,[2,95]),o($Vs,[2,101]),o($VX,[2,104]),{8:$V2,9:183,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{6:6,7:$V1,8:$V2,9:20,11:184,13:7,14:$V3,15:$V4,16:$V5,17:$V6,18:8,19:$V7,20:$V8,21:$V9,22:9,23:$Va,24:11,25:5,26:$Vb,28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,9:185,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{16:[1,186]},o($Vs,[2,102]),o($Vr,[2,3]),{10:[1,187]},o($Vr,[2,6]),{6:6,7:$V1,8:$V2,9:20,11:188,13:7,14:$V3,15:$V4,16:$V5,17:$V6,18:8,19:$V7,20:$V8,21:$V9,22:9,23:$Va,24:11,25:5,26:$Vb,28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},o($Vr,[2,5])], +table: [o([5,7,8,14,15,16,17,19,20,21,23,26,50,51,58,65,74,75,76,77,78,79,80,82,91,93],$V0,{3:1,4:2}),{1:[3]},{5:[1,3],6:6,7:$V1,8:$V2,9:20,11:4,13:7,14:$V3,15:$V4,16:$V5,17:$V6,18:8,19:$V7,20:$V8,21:$V9,22:9,23:$Va,24:11,25:5,26:$Vb,28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{1:[2,1]},o($Vq,[2,13]),o($Vr,[2,15]),o($Vr,[2,16]),o($Vr,[2,17]),o($Vr,[2,18]),o($Vr,[2,19]),o($Vr,[2,20]),o($Vr,[2,21]),o([7,8,14,15,16,17,19,20,21,23,26,27,50,51,58,65,74,75,76,77,78,79,80,82,91,93],$V0,{4:61}),{8:[1,62]},{8:[1,63]},{8:[1,64]},{6:6,7:$V1,8:$V2,9:20,11:65,13:7,14:$V3,15:$V4,16:$V5,17:$V6,18:8,19:$V7,20:$V8,21:$V9,22:9,23:$Va,24:11,25:5,26:$Vb,28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{20:[1,66]},{20:[1,67]},{8:$V2,9:69,16:[1,68],20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{16:[1,70]},o($Vr,[2,11]),o($Vs,[2,23]),o($Vs,[2,24]),o([8,10,16,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,64,65,66,83,86],$Vt,{32:[1,71],57:$Vu}),o([8,10,16,32,35,39,41,42,43,45,46,47,48,50,51,53,54,55,57,64,65,66,83,86],[2,26],{34:[1,73],37:[1,74]}),o($Vv,[2,54],{88:77,8:$Vw,64:[1,75],65:[1,76]}),o($Vv,[2,55],{88:79,8:$Vw,64:[1,81],65:[1,80]}),o($Vx,[2,28],{39:$Vy}),o($Vs,[2,56]),o($Vs,[2,57]),o($Vs,[2,58]),o($Vz,[2,30],{41:$VA,42:$VB,43:$VC}),o($Vs,[2,61]),o($Vs,[2,62]),o($Vs,[2,63]),o($Vs,[2,64]),{8:$V2,9:86,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:[1,87]},{8:[1,88]},o($VD,[2,32],{45:$VE,46:$VF,47:$VG,48:$VH}),o($Vs,[2,66]),o($Vs,[2,67]),o($Vs,[2,68]),o($Vs,[2,69]),{20:$VI,72:98,73:99,77:$Vj,78:$Vk,79:$Vl,80:$Vm,83:[1,93],84:94,85:95,87:96},{8:$V2,20:$V8,29:102,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,66:[1,100],67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,81:101,82:$Vn,91:$Vo,93:$Vp},o($VJ,[2,36],{50:$VK,51:$VL}),o($Vs,[2,70]),o($Vs,[2,71]),o($Vs,[2,72]),o($Vs,[2,73]),o($Vs,[2,74]),o($Vs,[2,75]),o($Vs,[2,76]),o($VM,[2,41],{53:$VN,54:$VO,55:$VP}),o($Vs,[2,44]),o($Vs,[2,50]),{8:$V2,20:$V8,31:109,50:$Vc,51:$Vd,52:108,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,50:$Vc,51:$Vd,52:110,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,50:$Vc,51:$Vd,52:111,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{6:6,7:$V1,8:$V2,9:20,11:4,13:7,14:$V3,15:$V4,16:$V5,17:$V6,18:8,19:$V7,20:$V8,21:$V9,22:9,23:$Va,24:11,25:5,26:$Vb,27:[1,112],28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,9:113,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,9:114,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,9:115,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{14:[1,116]},o($Vr,[2,7]),o($Vr,[2,8]),o($Vr,[2,9]),{16:[1,117]},o($Vr,[2,22]),{8:$V2,20:$V8,29:118,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,50:$Vc,51:$Vd,52:119,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,29:120,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,36:121,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{20:[1,122]},{8:$V2,9:123,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},o($Vs,[2,87],{89:124,90:125,68:127,20:$VQ,82:$Vn}),{8:$V2,10:[1,128],20:$V8,29:102,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,81:129,82:$Vn,91:$Vo,93:$Vp},o($Vs,[2,89]),{8:$V2,9:130,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{20:[1,131]},{8:$V2,20:$V8,31:109,38:132,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,40:133,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,40:134,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,40:135,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{10:[1,136]},{10:[1,137],20:$VR,92:138},{10:[1,140],20:$VR,92:141},{8:$V2,20:$V8,31:109,44:142,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,44:143,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,44:144,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,44:145,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},o($Vs,[2,79]),{83:[1,146],86:[1,147]},o($VS,[2,81]),{35:[1,148]},{35:[2,84]},{35:[2,85]},{35:[2,86]},o($Vs,[2,77]),{66:[1,149],86:$VT},o($VU,[2,98]),{8:$V2,20:$V8,31:109,49:151,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,49:152,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,50:$Vc,51:$Vd,52:153,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,50:$Vc,51:$Vd,52:154,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,31:109,50:$Vc,51:$Vd,52:155,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},o($Vs,[2,51]),o([8,10,16,32,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,64,65,66,83,86],$Vt,{57:$Vu}),o($Vs,[2,52]),o($Vs,[2,53]),o([5,7,8,10,12,14,15,16,17,19,20,21,23,26,27,32,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,57,58,64,65,66,74,75,76,77,78,79,80,82,83,86,91,93],[2,12]),{10:[1,156]},{10:[1,157]},{16:[1,158]},{8:[1,159]},o($Vr,[2,10]),o($Vs,[2,25]),o($Vs,[2,49]),{35:[1,160]},o($Vx,[2,29],{39:$Vy}),o($Vs,[2,59]),{66:[1,161]},o([8,10,16,32,34,35,37,39,41,42,43,45,46,47,48,50,51,53,54,55,57,64,65,66,83],[2,88],{86:[1,162]}),o($Vs,[2,94]),o($Vs,[2,96]),o($Vs,[2,97]),o($VV,[2,92]),{10:[1,163],86:$VT},{66:[1,164]},o($Vs,[2,91]),o($Vz,[2,31],{41:$VA,42:$VB,43:$VC}),o($VD,[2,33],{45:$VE,46:$VF,47:$VG,48:$VH}),o($VD,[2,34],{45:$VE,46:$VF,47:$VG,48:$VH}),o($VD,[2,35],{45:$VE,46:$VF,47:$VG,48:$VH}),o($Vs,[2,65]),{25:165,26:$Vb},{10:[1,166],86:$VW},o($VX,[2,104]),{94:[1,168]},{10:[1,169],86:$VW},o($VJ,[2,37],{50:$VK,51:$VL}),o($VJ,[2,38],{50:$VK,51:$VL}),o($VJ,[2,39],{50:$VK,51:$VL}),o($VJ,[2,40],{50:$VK,51:$VL}),o($Vs,[2,80]),{20:$VI,72:98,73:99,77:$Vj,78:$Vk,79:$Vl,80:$Vm,85:170,87:96},{8:$V2,20:$V8,29:171,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},o($Vs,[2,78]),{8:$V2,20:$V8,29:172,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},o($VM,[2,42],{53:$VN,54:$VO,55:$VP}),o($VM,[2,43],{53:$VN,54:$VO,55:$VP}),o($Vs,[2,45]),o($Vs,[2,46]),o($Vs,[2,47]),{6:6,7:$V1,8:$V2,9:20,11:173,13:7,14:$V3,15:$V4,16:$V5,17:$V6,18:8,19:$V7,20:$V8,21:$V9,22:9,23:$Va,24:11,25:5,26:$Vb,28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{6:6,7:$V1,8:$V2,9:20,11:174,13:7,14:$V3,15:$V4,16:$V5,17:$V6,18:8,19:$V7,20:$V8,21:$V9,22:9,23:$Va,24:11,25:5,26:$Vb,28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,9:175,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,9:176,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,20:$V8,29:177,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},o($Vs,[2,60]),{20:$VQ,68:127,82:$Vn,90:178},o($VV,[2,93]),o($Vs,[2,90]),o($Vs,[2,100]),{25:179,26:$Vb},{20:[1,180]},{8:$V2,9:181,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{94:[1,182]},o($VS,[2,82]),o($VS,[2,83]),o($VU,[2,99]),o($Vq,[2,2],{12:[1,183]}),o($Vr,[2,4]),{16:[1,184]},{10:[1,185]},o($Vs,[2,27]),o($Vs,[2,95]),o($Vs,[2,101]),o($VX,[2,105]),o($Vs,[2,102]),{8:$V2,9:186,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{6:6,7:$V1,8:$V2,9:20,11:187,13:7,14:$V3,15:$V4,16:$V5,17:$V6,18:8,19:$V7,20:$V8,21:$V9,22:9,23:$Va,24:11,25:5,26:$Vb,28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{8:$V2,9:188,20:$V8,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},{16:[1,189]},o($Vs,[2,103]),o($Vr,[2,3]),{10:[1,190]},o($Vr,[2,6]),{6:6,7:$V1,8:$V2,9:20,11:191,13:7,14:$V3,15:$V4,16:$V5,17:$V6,18:8,19:$V7,20:$V8,21:$V9,22:9,23:$Va,24:11,25:5,26:$Vb,28:10,29:22,30:23,31:24,33:25,36:28,38:32,40:40,44:47,49:55,50:$Vc,51:$Vd,52:56,56:57,58:$Ve,59:26,60:27,61:29,62:30,63:31,65:$Vf,67:34,68:35,69:36,70:41,71:42,72:43,73:44,74:$Vg,75:$Vh,76:$Vi,77:$Vj,78:$Vk,79:$Vl,80:$Vm,82:$Vn,91:$Vo,93:$Vp},o($Vr,[2,5])], defaultActions: {3:[2,1],97:[2,84],98:[2,85],99:[2,86]}, parseError: function parseError (str, hash) { if (hash.recoverable) { @@ -39168,80 +43174,82 @@ case 20:return 80 break; case 21:return 94 break; -case 22:return 82 +case 22:return 94 +break; +case 23:return 82 break; -case 23:return 83 +case 24:return 83 break; -case 24:return 26 +case 25:return 26 break; -case 25:return 27 +case 26:return 27 break; -case 26:return 16 +case 27:return 16 break; -case 27:return '#' +case 28:return '#' break; -case 28:return 34 +case 29:return 34 break; -case 29:return 35 +case 30:return 35 break; -case 30:return 79 +case 31:return 79 break; -case 31:return 64 +case 32:return 64 break; -case 32:return 65 +case 33:return 65 break; -case 33:return 66 +case 34:return 66 break; -case 34:return 8 +case 35:return 8 break; -case 35:return 10 +case 36:return 10 break; -case 36:return 58 +case 37:return 58 break; -case 37:return 57 +case 38:return 57 break; -case 38:return 53 +case 39:return 53 break; -case 39:return 54 +case 40:return 54 break; -case 40:return 55 +case 41:return 55 break; -case 41:return 50 +case 42:return 50 break; -case 42:return 51 +case 43:return 51 break; -case 43:return 47 +case 44:return 47 break; -case 44:return 45 +case 45:return 45 break; -case 45:return 48 +case 46:return 48 break; -case 46:return 46 +case 47:return 46 break; -case 47:return 41 +case 48:return 41 break; -case 48:return 43 +case 49:return 43 break; -case 49:return 42 +case 50:return 42 break; -case 50:return 39 +case 51:return 39 break; -case 51:return 37 +case 52:return 37 break; -case 52:return 32 +case 53:return 32 break; -case 53:return 86 +case 54:return 86 break; -case 54:return 5 +case 55:return 5 break; -case 55:return 20 +case 56:return 20 break; -case 56:return 'INVALID' +case 57:return 'INVALID' break; } }, -rules: [/^(?:\s+)/,/^(?:[0-9]+\.[0-9]*|[0-9]*\.[0-9]+\b)/,/^(?:[0-9]+)/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:\/\/.*)/,/^(?:\/\*(.|\n|\r)*?\*\/)/,/^(?:if\b)/,/^(?:else\b)/,/^(?:while\b)/,/^(?:do\b)/,/^(?:for\b)/,/^(?:function\b)/,/^(?:map\b)/,/^(?:use\b)/,/^(?:return\b)/,/^(?:delete\b)/,/^(?:true\b)/,/^(?:false\b)/,/^(?:null\b)/,/^(?:Infinity\b)/,/^(?:->)/,/^(?:<<)/,/^(?:>>)/,/^(?:\{)/,/^(?:\})/,/^(?:;)/,/^(?:#)/,/^(?:\?)/,/^(?::)/,/^(?:NaN\b)/,/^(?:\.)/,/^(?:\[)/,/^(?:\])/,/^(?:\()/,/^(?:\))/,/^(?:!)/,/^(?:\^)/,/^(?:\*)/,/^(?:\/)/,/^(?:%)/,/^(?:\+)/,/^(?:-)/,/^(?:<=)/,/^(?:<)/,/^(?:>=)/,/^(?:>)/,/^(?:==)/,/^(?:~=)/,/^(?:!=)/,/^(?:&&)/,/^(?:\|\|)/,/^(?:=)/,/^(?:,)/,/^(?:$)/,/^(?:[A-Za-z_\$][A-Za-z0-9_]*)/,/^(?:.)/], -conditions: {"INITIAL":{"rules":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56],"inclusive":true}} +rules: [/^(?:\s+)/,/^(?:[0-9]+\.[0-9]*|[0-9]*\.[0-9]+\b)/,/^(?:[0-9]+)/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:\/\/.*)/,/^(?:\/\*(.|\n|\r)*?\*\/)/,/^(?:if\b)/,/^(?:else\b)/,/^(?:while\b)/,/^(?:do\b)/,/^(?:for\b)/,/^(?:function\b)/,/^(?:map\b)/,/^(?:use\b)/,/^(?:return\b)/,/^(?:delete\b)/,/^(?:true\b)/,/^(?:false\b)/,/^(?:null\b)/,/^(?:Infinity\b)/,/^(?:->)/,/^(?:=>)/,/^(?:<<)/,/^(?:>>)/,/^(?:\{)/,/^(?:\})/,/^(?:;)/,/^(?:#)/,/^(?:\?)/,/^(?::)/,/^(?:NaN\b)/,/^(?:\.)/,/^(?:\[)/,/^(?:\])/,/^(?:\()/,/^(?:\))/,/^(?:!)/,/^(?:\^)/,/^(?:\*)/,/^(?:\/)/,/^(?:%)/,/^(?:\+)/,/^(?:-)/,/^(?:<=)/,/^(?:<)/,/^(?:>=)/,/^(?:>)/,/^(?:==)/,/^(?:~=)/,/^(?:!=)/,/^(?:&&)/,/^(?:\|\|)/,/^(?:=)/,/^(?:,)/,/^(?:$)/,/^(?:[A-Za-z_\$][A-Za-z0-9_]*)/,/^(?:.)/], +conditions: {"INITIAL":{"rules":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57],"inclusive":true}} }); return lexer; })(); @@ -39277,11251 +43285,9498 @@ if (typeof module !== 'undefined' && require.main === module) { }); /* - Copyright 2008-2021 - Matthias Ehmann, - Michael Gerhaeuser, - Carsten Miller, - Bianca Valentin, - Alfred Wassermann, - Peter Wilfahrt + Copyright 2008-2022 + Matthias Ehmann, + Michael Gerhaeuser, + Carsten Miller, + Bianca Valentin, + Alfred Wassermann, + Peter Wilfahrt - This file is part of JSXGraph. + This file is part of JSXGraph. - JSXGraph is free software dual licensed under the GNU LGPL or MIT License. + JSXGraph is free software dual licensed under the GNU LGPL or MIT License. - You can redistribute it and/or modify it under the terms of the + You can redistribute it and/or modify it under the terms of the - * GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version - OR - * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT + * GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version + OR + * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT - JSXGraph is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. + JSXGraph is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. - You should have received a copy of the GNU Lesser General Public License and - the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> - and <http://opensource.org/licenses/MIT/>. + You should have received a copy of the GNU Lesser General Public License and + the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> + and <http://opensource.org/licenses/MIT/>. */ -/*global JXG: true, define: true, console: true, window: true*/ +/*global JXG: true, define: true*/ /*jslint nomen: true, plusplus: true*/ /* depends: jxg - options - math/math - math/geometry - math/numerics - base/coords - base/constants - base/element - parser/geonext utils/type - elements: - transform - */ - -/** - * @fileoverview The geometry object Point is defined in this file. Point stores all - * style and functional properties that are required to draw and move a point on - * a board. */ -define('base/point',[ - 'jxg', 'options', 'math/math', 'math/geometry', 'math/numerics', 'base/coords', 'base/constants', 'base/element', - 'parser/geonext', 'utils/type', 'base/transformation', 'base/coordselement' -], function (JXG, Options, Mat, Geometry, Numerics, Coords, Const, GeometryElement, GeonextParser, Type, Transform, CoordsElement) { +define('base/composition',['jxg', 'utils/type'], function (JXG, Type) { "use strict"; /** - * A point is the basic geometric element. Based on points lines and circles can be constructed which can be intersected - * which in turn are points again which can be used to construct new lines, circles, polygons, etc. This class holds methods for - * all kind of points like free points, gliders, and intersection points. - * @class Creates a new point object. Do not use this constructor to create a point. Use {@link JXG.Board#create} with - * type {@link Point}, {@link Glider}, or {@link Intersection} instead. - * @augments JXG.GeometryElement - * @augments JXG.CoordsElement - * @param {string|JXG.Board} board The board the new point is drawn on. - * @param {Array} coordinates An array with the user coordinates of the point. - * @param {Object} attributes An object containing visual properties like in {@link JXG.Options#point} and - * {@link JXG.Options#elements}, and optional a name and an id. - * @see JXG.Board#generateName + * A composition is a simple container that manages none or more {@link JXG.GeometryElement}s. + * @param {Object} elements A list of elements with a descriptive name for the element as the key and a reference + * to the element as the value of every list entry. The name is used to access the element later on. + * @example + * var p1 = board.create('point', [1, 2]), + * p2 = board.create('point', [2, 3]), + * c = new JXG.Composition({ + * start: p1, + * end: p2 + * }); + * + * // moves p1 to [3, 3] + * c.start.moveTo([3, 3]); + * @class JXG.Composition */ - JXG.Point = function (board, coordinates, attributes) { - this.constructor(board, attributes, Const.OBJECT_TYPE_POINT, Const.OBJECT_CLASS_POINT); - this.element = this.board.select(attributes.anchor); - this.coordsConstructor(coordinates); - - this.elType = 'point'; + JXG.Composition = function (elements) { + var e, + that = this, + genericMethods = [ + /** + * Invokes setAttribute for every stored element with a setAttribute method and hands over the given arguments. + * See {@link JXG.GeometryElement#setAttribute} for further description, valid parameters and return values. + * @name setAttribute + * @memberOf JXG.Composition.prototype + * @function + */ + 'setAttribute', - /* Register point at board. */ - this.id = this.board.setId(this, 'P'); - this.board.renderer.drawPoint(this); - this.board.finalizeAdding(this); + /** + * Invokes setParents for every stored element with a setParents method and hands over the given arguments. + * See {@link JXG.GeometryElement#setParents} for further description, valid parameters and return values. + * @name setParents + * @memberOf JXG.Composition.prototype + * @function + */ + 'setParents', - this.createLabel(); + /** + * Invokes prepareUpdate for every stored element with a prepareUpdate method and hands over the given arguments. + * See {@link JXG.GeometryElement#prepareUpdate} for further description, valid parameters and return values. + * @name prepareUpdate + * @memberOf JXG.Composition.prototype + * @function + */ + 'prepareUpdate', - }; + /** + * Invokes updateRenderer for every stored element with a updateRenderer method and hands over the given arguments. + * See {@link JXG.GeometryElement#updateRenderer} for further description, valid parameters and return values. + * @name updateRenderer + * @memberOf JXG.Composition.prototype + * @function + */ + 'updateRenderer', - /** - * Inherits here from {@link JXG.GeometryElement}. - */ - JXG.Point.prototype = new GeometryElement(); - Type.copyPrototypeMethods(JXG.Point, CoordsElement, 'coordsConstructor'); + /** + * Invokes update for every stored element with a update method and hands over the given arguments. + * See {@link JXG.GeometryElement#update} for further description, valid parameters and return values. + * @name update + * @memberOf JXG.Composition.prototype + * @function + */ + 'update', - JXG.extend(JXG.Point.prototype, /** @lends JXG.Point.prototype */ { - /** - * Checks whether (x,y) is near the point. - * @param {Number} x Coordinate in x direction, screen coordinates. - * @param {Number} y Coordinate in y direction, screen coordinates. - * @returns {Boolean} True if (x,y) is near the point, False otherwise. - * @private - */ - hasPoint: function (x, y) { - var coordsScr = this.coords.scrCoords, r, - prec, type, - unit = Type.evaluate(this.visProp.sizeunit); + /** + * Invokes fullUpdate for every stored element with a fullUpdate method and hands over the given arguments. + * See {@link JXG.GeometryElement#fullUpdate} for further description, valid parameters and return values. + * @name fullUpdate + * @memberOf JXG.Composition.prototype + * @function + */ + 'fullUpdate', - if (Type.isObject(Type.evaluate(this.visProp.precision))) { - type = this.board._inputDevice; - prec = Type.evaluate(this.visProp.precision[type]); - } else { - // 'inherit' - prec = this.board.options.precision.hasPoint; - } - r = parseFloat(Type.evaluate(this.visProp.size)); - if (unit === 'user') { - r *= Math.sqrt(this.board.unitX * this.board.unitY); - } + /** + * Invokes highlight for every stored element with a highlight method and hands over the given arguments. + * See {@link JXG.GeometryElement#highlight} for further description, valid parameters and return values. + * @name highlight + * @memberOf JXG.Composition.prototype + * @function + */ + 'highlight', - r += parseFloat(Type.evaluate(this.visProp.strokewidth)) * 0.5; - if (r < prec) { - r = prec; - } + /** + * Invokes noHighlight for every stored element with a noHighlight method and hands over the given arguments. + * See {@link JXG.GeometryElement#noHighlight} for further description, valid parameters and return values. + * @name noHighlight + * @memberOf JXG.Composition.prototype + * @function + */ + 'noHighlight' + ], + generateMethod = function (what) { + return function () { + var i; - return ((Math.abs(coordsScr[1] - x) < r + 2) && (Math.abs(coordsScr[2] - y) < r + 2)); - }, + for (i in that.elements) { + if (that.elements.hasOwnProperty(i)) { + if (Type.exists(that.elements[i][what])) { + that.elements[i][what].apply(that.elements[i], arguments); + } + } + } + return that; + }; + }; - /** - * Updates the position of the point. - */ - update: function (fromParent) { - if (!this.needsUpdate) { - return this; - } + for (e = 0; e < genericMethods.length; e++) { + this[genericMethods[e]] = generateMethod(genericMethods[e]); + } - this.updateCoords(fromParent); + this.elements = {}; + this.objects = this.elements; - if (Type.evaluate(this.visProp.trace)) { - this.cloneToBackground(true); - } + this.elementsByName = {}; + this.objectsList = []; - return this; - }, + // unused, required for select() + this.groups = {}; - /** - * Applies the transformations of the element to {@link JXG.Point#baseElement}. - * Point transformations are relative to a base element. - * @returns {JXG.CoordsElement} Reference to this object. - */ - updateTransform: function () { - var c, i; + this.methodMap = { + setAttribute: 'setAttribute', + setProperty: 'setAttribute', + setParents: 'setParents', + add: 'add', + remove: 'remove', + select: 'select' + }; - if (this.transformations.length === 0 || this.baseElement === null) { - return this; + for (e in elements) { + if (elements.hasOwnProperty(e)) { + this.add(e, elements[e]); } + } - // case of bindTo - if (this === this.baseElement) { - c = this.transformations[0].apply(this.baseElement, 'self'); - // case of board.create('point',[baseElement,transform]); - } else { - c = this.transformations[0].apply(this.baseElement); - } - - this.coords.setCoordinates(Const.COORDS_BY_USER, c); + this.dump = true; + this.subs = {}; + }; - for (i = 1; i < this.transformations.length; i++) { - this.coords.setCoordinates(Const.COORDS_BY_USER, this.transformations[i].apply(this)); - } - return this; - }, + JXG.extend(JXG.Composition.prototype, /** @lends JXG.Composition.prototype */ { /** - * Calls the renderer to update the drawing. - * @private + * Adds an element to the composition container. + * @param {String} what Descriptive name for the element, e.g. <em>startpoint</em> or <em>area</em>. This is used to + * access the element later on. There are some reserved names: <em>elements, add, remove, update, prepareUpdate, + * updateRenderer, highlight, noHighlight</em>, and all names that would form invalid object property names in + * JavaScript. + * @param {JXG.GeometryElement|JXG.Composition} element A reference to the element that is to be added. This can be + * another composition, too. + * @returns {Boolean} True, if the element was added successfully. Reasons why adding the element failed include + * using a reserved name and providing an invalid element. */ - updateRenderer: function () { - this.updateRendererGeneric('updatePoint'); - return this; - }, - - // documented in JXG.GeometryElement - bounds: function () { - return this.coords.usrCoords.slice(1).concat(this.coords.usrCoords.slice(1)); - }, + add: function (what, element) { + if (!Type.exists(this[what]) && Type.exists(element)) { + if (Type.exists(element.id)) { + this.elements[element.id] = element; + } else { + this.elements[what] = element; + } - /** - * Convert the point to intersection point and update the construction. - * To move the point visual onto the intersection, a call of board update is necessary. - * - * @param {String|Object} el1, el2, i, j The intersecting objects and the numbers. - **/ - makeIntersection: function (el1, el2, i, j) { - var func; + if (Type.exists(element.name)) { + this.elementsByName[element.name] = element; + } - el1 = this.board.select(el1); - el2 = this.board.select(el2); + element.on('attribute:name', this.nameListener, this); - func = Geometry.intersectionFunction(this.board, el1, el2, i, j, - Type.evaluate(this.visProp.alwaysintersect)); - this.addConstraint([func]); + this.objectsList.push(element); + this[what] = element; + this.methodMap[what] = element; - try { - el1.addChild(this); - el2.addChild(this); - } catch (e) { - throw new Error("JSXGraph: Can't create 'intersection' with parent types '" + - (typeof el1) + "' and '" + (typeof el2) + "'."); + return true; } - this.type = Const.OBJECT_TYPE_INTERSECTION; - this.elType = 'intersection'; - this.parents = [el1.id, el2.id, i, j]; + return false; + }, - this.generatePolynomial = function () { - var poly1 = el1.generatePolynomial(this), - poly2 = el2.generatePolynomial(this); + /** + * Remove an element from the composition container. + * @param {String} what The name used to access the element. + * @returns {Boolean} True, if the element has been removed successfully. + */ + remove: function (what) { + var found = false, + e; - if ((poly1.length === 0) || (poly2.length === 0)) { - return []; + for (e in this.elements) { + if (this.elements.hasOwnProperty(e)) { + if (this.elements[e].id === this[what].id) { + found = true; + break; + } } + } - return [poly1[0], poly2[0]]; - }; + if (found) { + delete this.elements[this[what].id]; + delete this[what]; + } - this.prepareUpdate().update(); + return found; }, - /** - * Set the style of a point. - * Used for GEONExT import and should not be used to set the point's face and size. - * @param {Number} i Integer to determine the style. - * @private - */ - setStyle: function (i) { - var facemap = [ - // 0-2 - 'cross', 'cross', 'cross', - // 3-6 - 'circle', 'circle', 'circle', 'circle', - // 7-9 - 'square', 'square', 'square', - // 10-12 - 'plus', 'plus', 'plus' - ], sizemap = [ - // 0-2 - 2, 3, 4, - // 3-6 - 1, 2, 3, 4, - // 7-9 - 2, 3, 4, - // 10-12 - 2, 3, 4 - ]; + nameListener: function (oval, nval, el) { + delete this.elementsByName[oval]; + this.elementsByName[nval] = el; + }, - this.visProp.face = facemap[i]; - this.visProp.size = sizemap[i]; + select: function (filter) { + // for now, hijack JXG.Board's select() method + if (Type.exists(JXG.Board)) { + return JXG.Board.prototype.select.call(this, filter); + } - this.board.renderer.changePointStyle(this); - return this; + return new JXG.Composition(); }, - /** - * @deprecated Use JXG#normalizePointFace instead - * @param s - * @returns {*} - */ - normalizeFace: function (s) { - JXG.deprecated('Point.normalizeFace()', 'JXG.normalizePointFace()'); - return Options.normalizePointFace(s); + getParents: function () { + return this.parents; }, - /** - * Set the face of a point element. - * @param {String} f String which determines the face of the point. See {@link JXG.GeometryElement#face} for a list of available faces. - * @see JXG.GeometryElement#face - * @deprecated Use setAttribute() - */ - face: function (f) { - JXG.deprecated('Point.face()', 'Point.setAttribute()'); - this.setAttribute({face: f}); + getType: function () { + return this.elType; }, - /** - * Set the size of a point element - * @param {Number} s Integer which determines the size of the point. - * @see JXG.GeometryElement#size - * @deprecated Use setAttribute() - */ - size: function (s) { - JXG.deprecated('Point.size()', 'Point.setAttribute()'); - this.setAttribute({size: s}); - }, + getAttributes: function () { + var attr = {}, + e; - // already documented in GeometryElement - cloneToBackground: function () { - var copy = {}; + for (e in this.subs) { + if (this.subs.hasOwnProperty(e)) { + attr[e] = this.subs[e].visProp; + } + } - copy.id = this.id + 'T' + this.numTraces; - this.numTraces += 1; + return this.attr; + } + }); - copy.coords = this.coords; - copy.visProp = Type.deepCopy(this.visProp, this.visProp.traceattributes, true); - copy.visProp.layer = this.board.options.layer.trace; - copy.elementClass = Const.OBJECT_CLASS_POINT; - copy.board = this.board; - Type.clearVisPropOld(copy); + return JXG.Composition; +}); - copy.visPropCalc = { - visible: Type.evaluate(copy.visProp.visible) - }; +/* + Copyright 2008-2022 + Matthias Ehmann, + Michael Gerhaeuser, + Carsten Miller, + Bianca Valentin, + Alfred Wassermann, + Peter Wilfahrt - this.board.renderer.drawPoint(copy); - this.traces[copy.id] = copy.rendNode; + This file is part of JSXGraph. - return this; - } + JSXGraph is free software dual licensed under the GNU LGPL or MIT License. - }); + You can redistribute it and/or modify it under the terms of the - /** - * @class This element is used to provide a constructor for a general point. A free point is created if the given parent elements are all numbers - * and the property fixed is not set or set to false. If one or more parent elements is not a number but a string containing a GEONE<sub>x</sub>T - * constraint or a function the point will be considered as constrained). That means that the user won't be able to change the point's - * position directly. - * @pseudo - * @description - * @name Point - * @augments JXG.Point - * @constructor - * @type JXG.Point - * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {Number,string,function_Number,string,function_Number,string,function} z_,x,y Parent elements can be two or three elements of type number, a string containing a GEONE<sub>x</sub>T - * constraint, or a function which takes no parameter and returns a number. Every parent element determines one coordinate. If a coordinate is - * given by a number, the number determines the initial position of a free point. If given by a string or a function that coordinate will be constrained - * that means the user won't be able to change the point's position directly by mouse because it will be calculated automatically depending on the string - * or the function's return value. If two parent elements are given the coordinates will be interpreted as 2D affine Euclidean coordinates, if three such - * parent elements are given they will be interpreted as homogeneous coordinates. - * @param {JXG.Point_JXG.Transformation_Array} Point,Transformation A point can also be created providing a transformation or an array of transformations. - * The resulting point is a clone of the base point transformed by the given Transformation. {@see JXG.Transformation}. - * - * @example - * // Create a free point using affine Euclidean coordinates - * var p1 = board.create('point', [3.5, 2.0]); - * </pre><div class="jxgbox" id="JXG672f1764-7dfa-4abc-a2c6-81fbbf83e44b" style="width: 200px; height: 200px;"></div> - * <script type="text/javascript"> - * var board = JXG.JSXGraph.initBoard('JXG672f1764-7dfa-4abc-a2c6-81fbbf83e44b', {boundingbox: [-1, 5, 5, -1], axis: true, showcopyright: false, shownavigation: false}); - * var p1 = board.create('point', [3.5, 2.0]); - * </script><pre> - * @example - * // Create a constrained point using anonymous function - * var p2 = board.create('point', [3.5, function () { return p1.X(); }]); - * </pre><div class="jxgbox" id="JXG4fd4410c-3383-4e80-b1bb-961f5eeef224" style="width: 200px; height: 200px;"></div> - * <script type="text/javascript"> - * var fpex1_board = JXG.JSXGraph.initBoard('JXG4fd4410c-3383-4e80-b1bb-961f5eeef224', {boundingbox: [-1, 5, 5, -1], axis: true, showcopyright: false, shownavigation: false}); - * var fpex1_p1 = fpex1_board.create('point', [3.5, 2.0]); - * var fpex1_p2 = fpex1_board.create('point', [3.5, function () { return fpex1_p1.X(); }]); - * </script><pre> - * @example - * // Create a point using transformations - * var trans = board.create('transform', [2, 0.5], {type:'scale'}); - * var p3 = board.create('point', [p2, trans]); - * </pre><div class="jxgbox" id="JXG630afdf3-0a64-46e0-8a44-f51bd197bb8d" style="width: 400px; height: 400px;"></div> - * <script type="text/javascript"> - * var fpex2_board = JXG.JSXGraph.initBoard('JXG630afdf3-0a64-46e0-8a44-f51bd197bb8d', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); - * var fpex2_trans = fpex2_board.create('transform', [2, 0.5], {type:'scale'}); - * var fpex2_p2 = fpex2_board.create('point', [3.5, 2.0]); - * var fpex2_p3 = fpex2_board.create('point', [fpex2_p2, fpex2_trans]); - * </script><pre> - */ - JXG.createPoint = function (board, parents, attributes) { - var el, attr; + * GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version + OR + * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT - attr = Type.copyAttributes(attributes, board.options, 'point'); - el = CoordsElement.create(JXG.Point, board, parents, attr); - if (!el) { - throw new Error("JSXGraph: Can't create point with parent types '" + - (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + - "\nPossible parent types: [x,y], [z,x,y], [element,transformation]"); - } + JSXGraph is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. - return el; - }; + You should have received a copy of the GNU Lesser General Public License and + the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> + and <http://opensource.org/licenses/MIT/>. + */ - /** - * @class This element is used to provide a constructor for a glider point. - * @pseudo - * @description A glider is a point which lives on another geometric element like a line, circle, curve, turtle. - * @name Glider - * @augments JXG.Point - * @constructor - * @type JXG.Point - * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {Number_Number_Number_JXG.GeometryElement} z_,x_,y_,GlideObject Parent elements can be two or three elements of type number and the object the glider lives on. - * The coordinates are completely optional. If not given the origin is used. If you provide two numbers for coordinates they will be interpreted as affine Euclidean - * coordinates, otherwise they will be interpreted as homogeneous coordinates. In any case the point will be projected on the glide object. - * @example - * // Create a glider with user defined coordinates. If the coordinates are not on - * // the circle (like in this case) the point will be projected onto the circle. - * var p1 = board.create('point', [2.0, 2.0]); - * var c1 = board.create('circle', [p1, 2.0]); - * var p2 = board.create('glider', [2.0, 1.5, c1]); - * </pre><div class="jxgbox" id="JXG4f65f32f-e50a-4b50-9b7c-f6ec41652930" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * var gpex1_board = JXG.JSXGraph.initBoard('JXG4f65f32f-e50a-4b50-9b7c-f6ec41652930', {boundingbox: [-1, 5, 5, -1], axis: true, showcopyright: false, shownavigation: false}); - * var gpex1_p1 = gpex1_board.create('point', [2.0, 2.0]); - * var gpex1_c1 = gpex1_board.create('circle', [gpex1_p1, 2.0]); - * var gpex1_p2 = gpex1_board.create('glider', [2.0, 1.5, gpex1_c1]); - * </script><pre> - * @example - * // Create a glider with default coordinates (1,0,0). Same premises as above. - * var p1 = board.create('point', [2.0, 2.0]); - * var c1 = board.create('circle', [p1, 2.0]); - * var p2 = board.create('glider', [c1]); - * </pre><div class="jxgbox" id="JXG4de7f181-631a-44b1-a12f-bc4d995609e8" style="width: 200px; height: 200px;"></div> - * <script type="text/javascript"> - * var gpex2_board = JXG.JSXGraph.initBoard('JXG4de7f181-631a-44b1-a12f-bc4d995609e8', {boundingbox: [-1, 5, 5, -1], axis: true, showcopyright: false, shownavigation: false}); - * var gpex2_p1 = gpex2_board.create('point', [2.0, 2.0]); - * var gpex2_c1 = gpex2_board.create('circle', [gpex2_p1, 2.0]); - * var gpex2_p2 = gpex2_board.create('glider', [gpex2_c1]); - * </script><pre> - *@example - * //animate example 2 - * var p1 = board.create('point', [2.0, 2.0]); - * var c1 = board.create('circle', [p1, 2.0]); - * var p2 = board.create('glider', [c1]); - * var button1 = board.create('button', [1, 7, 'start animation',function(){p2.startAnimation(1,4)}]); - * var button2 = board.create('button', [1, 5, 'stop animation',function(){p2.stopAnimation()}]); - * </pre><div class="jxgbox" id="JXG4de7f181-631a-44b1-a12f-bc4d133709e8" style="width: 200px; height: 200px;"></div> - * <script type="text/javascript"> - * var gpex3_board = JXG.JSXGraph.initBoard('JXG4de7f181-631a-44b1-a12f-bc4d133709e8', {boundingbox: [-1, 10, 10, -1], axis: true, showcopyright: false, shownavigation: false}); - * var gpex3_p1 = gpex2_board.create('point', [2.0, 2.0]); - * var gpex3_c1 = gpex2_board.create('circle', [gpex2_p1, 2.0]); - * var gpex3_p2 = gpex2_board.create('glider', [gpex2_c1]); - * board.create('button', [1, 7, 'start animation',function(){gpex3_p2.startAnimation(1,4)}]); - * board.create('button', [1, 5, 'stop animation',function(){gpex3_p2.stopAnimation()}]); - * </script><pre> - */ - JXG.createGlider = function (board, parents, attributes) { - var el, coords, - attr = Type.copyAttributes(attributes, board.options, 'glider'); - if (parents.length === 1) { - coords = [0, 0]; - } else { - coords = parents.slice(0, 2); - } - el = board.create('point', coords, attr); +/*global JXG: true, define: true, AMprocessNode: true, MathJax: true, window: true, document: true, init: true, translateASCIIMath: true, google: true*/ - // eltype is set in here - el.makeGlider(parents[parents.length - 1]); +/*jslint nomen: true, plusplus: true*/ - return el; - }; +/* depends: + jxg + base/constants + base/coords + options + math/numerics + math/math + math/geometry + math/complex + parser/jessiecode + parser/geonext + utils/color + utils/type + utils/event + utils/env + elements: + transform + point + line + text + grid + */ + +/** + * @fileoverview The JXG.Board class is defined in this file. JXG.Board controls all properties and methods + * used to manage a geonext board like managing geometric elements, managing mouse and touch events, etc. + */ + +define('base/board',[ + 'jxg', 'base/constants', 'base/coords', 'options', 'math/numerics', 'math/math', 'math/geometry', 'math/complex', + 'math/statistics', + 'parser/jessiecode', 'utils/color', 'utils/type', 'utils/event', 'utils/env', + 'base/composition' +], function (JXG, Const, Coords, Options, Numerics, Mat, Geometry, Complex, Statistics, JessieCode, Color, Type, + EventEmitter, Env, Composition) { + 'use strict'; /** - * @class This element is used to provide a constructor for an intersection point. - * @pseudo - * @description An intersection point is a point which lives on two Lines or Circles or one Line and one Circle at the same time, i.e. - * an intersection point of the two elements. - * @name Intersection - * @augments JXG.Point + * Constructs a new Board object. + * @class JXG.Board controls all properties and methods used to manage a geonext board like managing geometric + * elements, managing mouse and touch events, etc. You probably don't want to use this constructor directly. + * Please use {@link JXG.JSXGraph.initBoard} to initialize a board. * @constructor - * @type JXG.Point - * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {JXG.Line,JXG.Circle_JXG.Line,JXG.Circle_Number} el1,el2,i The result will be a intersection point on el1 and el2. i determines the - * intersection point if two points are available: <ul> - * <li>i==0: use the positive square root,</li> - * <li>i==1: use the negative square root.</li></ul> - * @example - * // Create an intersection point of circle and line - * var p1 = board.create('point', [2.0, 2.0]); - * var c1 = board.create('circle', [p1, 2.0]); - * - * var p2 = board.create('point', [2.0, 2.0]); - * var p3 = board.create('point', [2.0, 2.0]); - * var l1 = board.create('line', [p2, p3]); - * - * var i = board.create('intersection', [c1, l1, 0]); - * </pre><div class="jxgbox" id="JXGe5b0e190-5200-4bc3-b995-b6cc53dc5dc0" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * var ipex1_board = JXG.JSXGraph.initBoard('JXGe5b0e190-5200-4bc3-b995-b6cc53dc5dc0', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}); - * var ipex1_p1 = ipex1_board.create('point', [4.0, 4.0]); - * var ipex1_c1 = ipex1_board.create('circle', [ipex1_p1, 2.0]); - * var ipex1_p2 = ipex1_board.create('point', [1.0, 1.0]); - * var ipex1_p3 = ipex1_board.create('point', [5.0, 3.0]); - * var ipex1_l1 = ipex1_board.create('line', [ipex1_p2, ipex1_p3]); - * var ipex1_i = ipex1_board.create('intersection', [ipex1_c1, ipex1_l1, 0]); - * </script><pre> + * @param {String} container The id or reference of the HTML DOM element the board is drawn in. This is usually a HTML div. + * @param {JXG.AbstractRenderer} renderer The reference of a renderer. + * @param {String} id Unique identifier for the board, may be an empty string or null or even undefined. + * @param {JXG.Coords} origin The coordinates where the origin is placed, in user coordinates. + * @param {Number} zoomX Zoom factor in x-axis direction + * @param {Number} zoomY Zoom factor in y-axis direction + * @param {Number} unitX Units in x-axis direction + * @param {Number} unitY Units in y-axis direction + * @param {Number} canvasWidth The width of canvas + * @param {Number} canvasHeight The height of canvas + * @param {Object} attributes The attributes object given to {@link JXG.JSXGraph.initBoard} + * @borrows JXG.EventEmitter#on as this.on + * @borrows JXG.EventEmitter#off as this.off + * @borrows JXG.EventEmitter#triggerEventHandlers as this.triggerEventHandlers + * @borrows JXG.EventEmitter#eventHandlers as this.eventHandlers */ - JXG.createIntersectionPoint = function (board, parents, attributes) { - var el, el1, el2, func, i, j, - attr = Type.copyAttributes(attributes, board.options, 'intersection'); + JXG.Board = function (container, renderer, id, origin, zoomX, zoomY, unitX, unitY, canvasWidth, canvasHeight, attributes) { + /** + * Board is in no special mode, objects are highlighted on mouse over and objects may be + * clicked to start drag&drop. + * @type Number + * @constant + */ + this.BOARD_MODE_NONE = 0x0000; - // make sure we definitely have the indices - parents.push(0, 0); + /** + * Board is in drag mode, objects aren't highlighted on mouse over and the object referenced in + * {@link JXG.Board#mouse} is updated on mouse movement. + * @type Number + * @constant + * @see JXG.Board#drag_obj + */ + this.BOARD_MODE_DRAG = 0x0001; - el1 = board.select(parents[0]); - el2 = board.select(parents[1]); + /** + * In this mode a mouse move changes the origin's screen coordinates. + * @type Number + * @constant + */ + this.BOARD_MODE_MOVE_ORIGIN = 0x0002; - i = parents[2] || 0; - j = parents[3] || 0; + /** + * Update is made with high quality, e.g. graphs are evaluated at much more points. + * @type Number + * @constant + * @see JXG.Board#updateQuality + */ + this.BOARD_MODE_ZOOM = 0x0011; - el = board.create('point', [0, 0, 0], attr); + /** + * Update is made with low quality, e.g. graphs are evaluated at a lesser amount of points. + * @type Number + * @constant + * @see JXG.Board#updateQuality + */ + this.BOARD_QUALITY_LOW = 0x1; - // el.visProp.alwaysintersect is evaluated as late as in the returned function - func = Geometry.intersectionFunction(board, el1, el2, i, j, el.visProp.alwaysintersect); - el.addConstraint([func]); + /** + * Update is made with high quality, e.g. graphs are evaluated at much more points. + * @type Number + * @constant + * @see JXG.Board#updateQuality + */ + this.BOARD_QUALITY_HIGH = 0x2; - try { - el1.addChild(el); - el2.addChild(el); - } catch (e) { - throw new Error("JSXGraph: Can't create 'intersection' with parent types '" + - (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'."); + /** + * Pointer to the document element containing the board. + * @type Object + */ + // Former version: + // this.document = attributes.document || document; + if (Type.exists(attributes.document) && attributes.document !== false) { + this.document = attributes.document; + } else if (document !== undefined && Type.isObject(document)) { + this.document = document; } - el.type = Const.OBJECT_TYPE_INTERSECTION; - el.elType = 'intersection'; - el.setParents([el1.id, el2.id]); - /** - * Array of length 2 containing the numbers i and j. - * The intersection point is i-th intersection point. - * j is unused. - * @type Array - * @private + * The html-id of the html element containing the board. + * @type String */ - el.intersectionNumbers = [i, j]; - el.getParents = function() { - return this.parents.concat(this.intersectionNumbers); - }; - - el.generatePolynomial = function () { - var poly1 = el1.generatePolynomial(el), - poly2 = el2.generatePolynomial(el); - - if ((poly1.length === 0) || (poly2.length === 0)) { - return []; - } - - return [poly1[0], poly2[0]]; - }; - - return el; - }; + this.container = container; - /** - * @class This element is used to provide a constructor for the "other" intersection point. - * @pseudo - * @description An intersection point is a point which lives on two Lines or Circles or one Line and one Circle at the same time, i.e. - * an intersection point of the two elements. Additionally, one intersection point is provided. The function returns the other intersection point. - * @name OtherIntersection - * @augments JXG.Point - * @constructor - * @type JXG.Point - * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {JXG.Line,JXG.Circle_JXG.Line,JXG.Circle_JXG.Point} el1,el2,p The result will be a intersection point on el1 and el2. i determines the - * intersection point different from p: - * @example - * // Create an intersection point of circle and line - * var p1 = board.create('point', [2.0, 2.0]); - * var c1 = board.create('circle', [p1, 2.0]); - * - * var p2 = board.create('point', [2.0, 2.0]); - * var p3 = board.create('point', [2.0, 2.0]); - * var l1 = board.create('line', [p2, p3]); - * - * var i = board.create('intersection', [c1, l1, 0]); - * var j = board.create('otherintersection', [c1, l1, i]); - * </pre><div class="jxgbox" id="JXG45e25f12-a1de-4257-a466-27a2ae73614c" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * var ipex2_board = JXG.JSXGraph.initBoard('JXG45e25f12-a1de-4257-a466-27a2ae73614c', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}); - * var ipex2_p1 = ipex2_board.create('point', [4.0, 4.0]); - * var ipex2_c1 = ipex2_board.create('circle', [ipex2_p1, 2.0]); - * var ipex2_p2 = ipex2_board.create('point', [1.0, 1.0]); - * var ipex2_p3 = ipex2_board.create('point', [5.0, 3.0]); - * var ipex2_l1 = ipex2_board.create('line', [ipex2_p2, ipex2_p3]); - * var ipex2_i = ipex2_board.create('intersection', [ipex2_c1, ipex2_l1, 0], {name:'D'}); - * var ipex2_j = ipex2_board.create('otherintersection', [ipex2_c1, ipex2_l1, ipex2_i], {name:'E'}); - * </script><pre> - */ - JXG.createOtherIntersectionPoint = function (board, parents, attributes) { - var el, el1, el2, other; + /** + * Pointer to the html element containing the board. + * @type Object + */ + this.containerObj = (Env.isBrowser ? this.document.getElementById(this.container) : null); - if (parents.length !== 3 || - !Type.isPoint(parents[2]) || - (parents[0].elementClass !== Const.OBJECT_CLASS_LINE && parents[0].elementClass !== Const.OBJECT_CLASS_CIRCLE) || - (parents[1].elementClass !== Const.OBJECT_CLASS_LINE && parents[1].elementClass !== Const.OBJECT_CLASS_CIRCLE)) { - // Failure - throw new Error("JSXGraph: Can't create 'other intersection point' with parent types '" + - (typeof parents[0]) + "', '" + (typeof parents[1]) + "'and '" + (typeof parents[2]) + "'." + - "\nPossible parent types: [circle|line,circle|line,point]"); + if (Env.isBrowser && renderer.type !== 'no' && this.containerObj === null) { + throw new Error("\nJSXGraph: HTML container element '" + container + "' not found."); } - el1 = board.select(parents[0]); - el2 = board.select(parents[1]); - other = board.select(parents[2]); - - el = board.create('point', [function () { - var c = Geometry.meet(el1.stdform, el2.stdform, 0, el1.board); + /** + * A reference to this boards renderer. + * @type JXG.AbstractRenderer + * @name JXG.Board#renderer + * @private + * @ignore + */ + this.renderer = renderer; - if (Math.abs(other.X() - c.usrCoords[1]) > Mat.eps || - Math.abs(other.Y() - c.usrCoords[2]) > Mat.eps || - Math.abs(other.Z() - c.usrCoords[0]) > Mat.eps) { - return c; - } + /** + * Grids keeps track of all grids attached to this board. + * @type Array + * @private + */ + this.grids = []; - return Geometry.meet(el1.stdform, el2.stdform, 1, el1.board); - }], attributes); + /** + * Some standard options + * @type JXG.Options + */ + this.options = Type.deepCopy(Options); + this.attr = attributes; - el.type = Const.OBJECT_TYPE_INTERSECTION; - el.elType = 'otherintersection'; - el.setParents([el1.id, el2.id, other]); + /** + * Dimension of the board. + * @default 2 + * @type Number + */ + this.dimension = 2; - el1.addChild(el); - el2.addChild(el); + this.jc = new JessieCode(); + this.jc.use(this); - el.generatePolynomial = function () { - var poly1 = el1.generatePolynomial(el), - poly2 = el2.generatePolynomial(el); + /** + * Coordinates of the boards origin. This a object with the two properties + * usrCoords and scrCoords. usrCoords always equals [1, 0, 0] and scrCoords + * stores the boards origin in homogeneous screen coordinates. + * @type Object + * @private + */ + this.origin = {}; + this.origin.usrCoords = [1, 0, 0]; + this.origin.scrCoords = [1, origin[0], origin[1]]; - if ((poly1.length === 0) || (poly2.length === 0)) { - return []; - } + /** + * Zoom factor in X direction. It only stores the zoom factor to be able + * to get back to 100% in zoom100(). + * @name JXG.Board.zoomX + * @type Number + * @private + * @ignore + */ + this.zoomX = zoomX; - return [poly1[0], poly2[0]]; - }; + /** + * Zoom factor in Y direction. It only stores the zoom factor to be able + * to get back to 100% in zoom100(). + * @name JXG.Board.zoomY + * @type Number + * @private + * @ignore + */ + this.zoomY = zoomY; - return el; - }; + /** + * The number of pixels which represent one unit in user-coordinates in x direction. + * @type Number + * @private + */ + this.unitX = unitX * this.zoomX; - /** - * @class This element is used to provide a constructor for the pole point of a line with respect to a conic or a circle. - * @pseudo - * @description The pole point is the unique reciprocal relationship of a line with respect to a conic. - * The lines tangent to the intersections of a conic and a line intersect at the pole point of that line with respect to that conic. - * A line tangent to a conic has the pole point of that line with respect to that conic as the tangent point. - * See {@link http://en.wikipedia.org/wiki/Pole_and_polar} for more information on pole and polar. - * @name PolePoint - * @augments JXG.Point - * @constructor - * @type JXG.Point - * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {JXG.Conic,JXG.Circle_JXG.Point} el1,el2 or - * @param {JXG.Point_JXG.Conic,JXG.Circle} el1,el2 The result will be the pole point of the line with respect to the conic or the circle. - * @example - * // Create the pole point of a line with respect to a conic - * var p1 = board.create('point', [-1, 2]); - * var p2 = board.create('point', [ 1, 4]); - * var p3 = board.create('point', [-1,-2]); - * var p4 = board.create('point', [ 0, 0]); - * var p5 = board.create('point', [ 4,-2]); - * var c1 = board.create('conic',[p1,p2,p3,p4,p5]); - * var p6 = board.create('point', [-1, 4]); - * var p7 = board.create('point', [2, -2]); - * var l1 = board.create('line', [p6, p7]); - * var p8 = board.create('polepoint', [c1, l1]); - * </pre><div class="jxgbox" id="JXG7b7233a0-f363-47dd-9df5-8018d0d17a98" class="jxgbox" style="width:400px; height:400px;"></div> - * <script type='text/javascript'> - * var ppex1_board = JXG.JSXGraph.initBoard('JXG7b7233a0-f363-47dd-9df5-8018d0d17a98', {boundingbox: [-3, 5, 5, -3], axis: true, showcopyright: false, shownavigation: false}); - * var ppex1_p1 = ppex1_board.create('point', [-1, 2]); - * var ppex1_p2 = ppex1_board.create('point', [ 1, 4]); - * var ppex1_p3 = ppex1_board.create('point', [-1,-2]); - * var ppex1_p4 = ppex1_board.create('point', [ 0, 0]); - * var ppex1_p5 = ppex1_board.create('point', [ 4,-2]); - * var ppex1_c1 = ppex1_board.create('conic',[ppex1_p1,ppex1_p2,ppex1_p3,ppex1_p4,ppex1_p5]); - * var ppex1_p6 = ppex1_board.create('point', [-1, 4]); - * var ppex1_p7 = ppex1_board.create('point', [2, -2]); - * var ppex1_l1 = ppex1_board.create('line', [ppex1_p6, ppex1_p7]); - * var ppex1_p8 = ppex1_board.create('polepoint', [ppex1_c1, ppex1_l1]); - * </script><pre> - * @example - * // Create the pole point of a line with respect to a circle - * var p1 = board.create('point', [1, 1]); - * var p2 = board.create('point', [2, 3]); - * var c1 = board.create('circle',[p1,p2]); - * var p3 = board.create('point', [-1, 4]); - * var p4 = board.create('point', [4, -1]); - * var l1 = board.create('line', [p3, p4]); - * var p5 = board.create('polepoint', [c1, l1]); - * </pre><div class="jxgbox" id="JXG7b7233a0-f363-47dd-9df5-9018d0d17a98" class="jxgbox" style="width:400px; height:400px;"></div> - * <script type='text/javascript'> - * var ppex2_board = JXG.JSXGraph.initBoard('JXG7b7233a0-f363-47dd-9df5-9018d0d17a98', {boundingbox: [-3, 7, 7, -3], axis: true, showcopyright: false, shownavigation: false}); - * var ppex2_p1 = ppex2_board.create('point', [1, 1]); - * var ppex2_p2 = ppex2_board.create('point', [2, 3]); - * var ppex2_c1 = ppex2_board.create('circle',[ppex2_p1,ppex2_p2]); - * var ppex2_p3 = ppex2_board.create('point', [-1, 4]); - * var ppex2_p4 = ppex2_board.create('point', [4, -1]); - * var ppex2_l1 = ppex2_board.create('line', [ppex2_p3, ppex2_p4]); - * var ppex2_p5 = ppex2_board.create('polepoint', [ppex2_c1, ppex2_l1]); - * </script><pre> - */ - JXG.createPolePoint = function (board, parents, attributes) { - var el, el1, el2, - firstParentIsConic, secondParentIsConic, - firstParentIsLine, secondParentIsLine; + /** + * The number of pixels which represent one unit in user-coordinates in y direction. + * @type Number + * @private + */ + this.unitY = unitY * this.zoomY; - if (parents.length > 1) { - firstParentIsConic = (parents[0].type === Const.OBJECT_TYPE_CONIC || - parents[0].elementClass === Const.OBJECT_CLASS_CIRCLE); - secondParentIsConic = (parents[1].type === Const.OBJECT_TYPE_CONIC || - parents[1].elementClass === Const.OBJECT_CLASS_CIRCLE); + /** + * Keep aspect ratio if bounding box is set and the width/height ratio differs from the + * width/height ratio of the canvas. + * @type Boolean + * @private + */ + this.keepaspectratio = false; - firstParentIsLine = (parents[0].elementClass === Const.OBJECT_CLASS_LINE); - secondParentIsLine = (parents[1].elementClass === Const.OBJECT_CLASS_LINE); - } + /** + * Canvas width. + * @type Number + * @private + */ + this.canvasWidth = canvasWidth; -/* if (parents.length !== 2 || !(( - parents[0].type === Const.OBJECT_TYPE_CONIC || - parents[0].elementClass === Const.OBJECT_CLASS_CIRCLE) && - parents[1].elementClass === Const.OBJECT_CLASS_LINE || - parents[0].elementClass === Const.OBJECT_CLASS_LINE && ( - parents[1].type === Const.OBJECT_TYPE_CONIC || - parents[1].elementClass === Const.OBJECT_CLASS_CIRCLE))) {*/ - if (parents.length !== 2 || - !((firstParentIsConic && secondParentIsLine) || - (firstParentIsLine && secondParentIsConic))) { - // Failure - throw new Error("JSXGraph: Can't create 'pole point' with parent types '" + - (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + - "\nPossible parent type: [conic|circle,line], [line,conic|circle]"); - } + /** + * Canvas Height + * @type Number + * @private + */ + this.canvasHeight = canvasHeight; - if (secondParentIsLine) { - el1 = board.select(parents[0]); - el2 = board.select(parents[1]); + // If the given id is not valid, generate an unique id + if (Type.exists(id) && id !== '' && Env.isBrowser && !Type.exists(this.document.getElementById(id))) { + this.id = id; } else { - el1 = board.select(parents[1]); - el2 = board.select(parents[0]); + this.id = this.generateId(); } - el = board.create('point', - [function () { - var q = el1.quadraticform, - s = el2.stdform.slice(0, 3); - - return [JXG.Math.Numerics.det([s, q[1], q[2]]), - JXG.Math.Numerics.det([q[0], s, q[2]]), - JXG.Math.Numerics.det([q[0], q[1], s])]; - }], attributes); - - el.elType = 'polepoint'; - el.setParents([el1.id, el2.id]); - - el1.addChild(el); - el2.addChild(el); - - return el; - }; + EventEmitter.eventify(this); - JXG.registerElement('point', JXG.createPoint); - JXG.registerElement('glider', JXG.createGlider); - JXG.registerElement('intersection', JXG.createIntersectionPoint); - JXG.registerElement('otherintersection', JXG.createOtherIntersectionPoint); - JXG.registerElement('polepoint', JXG.createPolePoint); + this.hooks = []; - return { - Point: JXG.Point, - createPoint: JXG.createPoint, - createGlider: JXG.createGlider, - createIntersection: JXG.createIntersectionPoint, - createOtherIntersection: JXG.createOtherIntersectionPoint, - createPolePoint: JXG.createPolePoint - }; -}); + /** + * An array containing all other boards that are updated after this board has been updated. + * @type Array + * @see JXG.Board#addChild + * @see JXG.Board#removeChild + */ + this.dependentBoards = []; -/* - Copyright 2008-2021 - Matthias Ehmann, - Michael Gerhaeuser, - Carsten Miller, - Bianca Valentin, - Alfred Wassermann, - Peter Wilfahrt + /** + * During the update process this is set to false to prevent an endless loop. + * @default false + * @type Boolean + */ + this.inUpdate = false; - This file is part of JSXGraph. + /** + * An associative array containing all geometric objects belonging to the board. Key is the id of the object and value is a reference to the object. + * @type Object + */ + this.objects = {}; - JSXGraph is free software dual licensed under the GNU LGPL or MIT License. + /** + * An array containing all geometric objects on the board in the order of construction. + * @type Array + */ + this.objectsList = []; - You can redistribute it and/or modify it under the terms of the + /** + * An associative array containing all groups belonging to the board. Key is the id of the group and value is a reference to the object. + * @type Object + */ + this.groups = {}; - * GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version - OR - * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT + /** + * Stores all the objects that are currently running an animation. + * @type Object + */ + this.animationObjects = {}; - JSXGraph is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. + /** + * An associative array containing all highlighted elements belonging to the board. + * @type Object + */ + this.highlightedObjects = {}; - You should have received a copy of the GNU Lesser General Public License and - the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> - and <http://opensource.org/licenses/MIT/>. - */ + /** + * Number of objects ever created on this board. This includes every object, even invisible and deleted ones. + * @type Number + */ + this.numObjects = 0; + /** + * An associative array to store the objects of the board by name. the name of the object is the key and value is a reference to the object. + * @type Object + */ + this.elementsByName = {}; -/*global JXG: true, define: true*/ -/*jslint nomen: true, plusplus: true*/ + /** + * The board mode the board is currently in. Possible values are + * <ul> + * <li>JXG.Board.BOARD_MODE_NONE</li> + * <li>JXG.Board.BOARD_MODE_DRAG</li> + * <li>JXG.Board.BOARD_MODE_MOVE_ORIGIN</li> + * </ul> + * @type Number + */ + this.mode = this.BOARD_MODE_NONE; -/* depends: - jxg - math/math - math/geometry - math/numerics - math/statistics - base/constants - base/coords - base/element - utils/type - elements: - transform - point - ticks - */ + /** + * The update quality of the board. In most cases this is set to {@link JXG.Board#BOARD_QUALITY_HIGH}. + * If {@link JXG.Board#mode} equals {@link JXG.Board#BOARD_MODE_DRAG} this is set to + * {@link JXG.Board#BOARD_QUALITY_LOW} to speed up the update process by e.g. reducing the number of + * evaluation points when plotting functions. Possible values are + * <ul> + * <li>BOARD_QUALITY_LOW</li> + * <li>BOARD_QUALITY_HIGH</li> + * </ul> + * @type Number + * @see JXG.Board#mode + */ + this.updateQuality = this.BOARD_QUALITY_HIGH; -/** - * @fileoverview The geometry object Line is defined in this file. Line stores all - * style and functional properties that are required to draw and move a line on - * a board. - */ + /** + * If true updates are skipped. + * @type Boolean + */ + this.isSuspendedRedraw = false; -define('base/line',[ - 'jxg', 'math/math', 'math/geometry', 'math/numerics', 'math/statistics', 'base/constants', 'base/coords', - 'base/element', 'utils/type', 'base/point' -], function (JXG, Mat, Geometry, Numerics, Statistics, Const, Coords, GeometryElement, Type, Point) { + this.calculateSnapSizes(); - "use strict"; + /** + * The distance from the mouse to the dragged object in x direction when the user clicked the mouse button. + * @type Number + * @see JXG.Board#drag_dy + * @see JXG.Board#drag_obj + */ + this.drag_dx = 0; - /** - * The Line class is a basic class for all kind of line objects, e.g. line, arrow, and axis. It is usually defined by two points and can - * be intersected with some other geometry elements. - * @class Creates a new basic line object. Do not use this constructor to create a line. - * Use {@link JXG.Board#create} with - * type {@link Line}, {@link Arrow}, or {@link Axis} instead. - * @constructor - * @augments JXG.GeometryElement - * @param {String,JXG.Board} board The board the new line is drawn on. - * @param {Point} p1 Startpoint of the line. - * @param {Point} p2 Endpoint of the line. - * @param {Object} attributes Javascript object containing attributes like name, id and colors. - */ - JXG.Line = function (board, p1, p2, attributes) { - this.constructor(board, attributes, Const.OBJECT_TYPE_LINE, Const.OBJECT_CLASS_LINE); + /** + * The distance from the mouse to the dragged object in y direction when the user clicked the mouse button. + * @type Number + * @see JXG.Board#drag_dx + * @see JXG.Board#drag_obj + */ + this.drag_dy = 0; /** - * Startpoint of the line. You really should not set this field directly as it may break JSXGraph's - * update system so your construction won't be updated properly. - * @type JXG.Point + * The last position where a drag event has been fired. + * @type Array + * @see JXG.Board#moveObject */ - this.point1 = this.board.select(p1); + this.drag_position = [0, 0]; /** - * Endpoint of the line. Just like {@link JXG.Line.point1} you shouldn't write this field directly. - * @type JXG.Point + * References to the object that is dragged with the mouse on the board. + * @type JXG.GeometryElement + * @see JXG.Board#touches */ - this.point2 = this.board.select(p2); + this.mouse = {}; /** - * Array of ticks storing all the ticks on this line. Do not set this field directly and use - * {@link JXG.Line#addTicks} and {@link JXG.Line#removeTicks} to add and remove ticks to and from the line. + * Keeps track on touched elements, like {@link JXG.Board#mouse} does for mouse events. * @type Array - * @see JXG.Ticks + * @see JXG.Board#mouse */ - this.ticks = []; + this.touches = []; /** - * Reference of the ticks created automatically when constructing an axis. - * @type JXG.Ticks - * @see JXG.Ticks + * A string containing the XML text of the construction. + * This is set in {@link JXG.FileReader.parseString}. + * Only useful if a construction is read from a GEONExT-, Intergeo-, Geogebra-, or Cinderella-File. + * @type String */ - this.defaultTicks = null; + this.xmlString = ''; /** - * If the line is the border of a polygon, the polygon object is stored, otherwise null. - * @type JXG.Polygon - * @default null - * @private + * Cached result of getCoordsTopLeftCorner for touch/mouseMove-Events to save some DOM operations. + * @type Array */ - this.parentPolygon = null; + this.cPos = []; - /* Register line at board */ - this.id = this.board.setId(this, 'L'); - this.board.renderer.drawLine(this); - this.board.finalizeAdding(this); + /** + * Contains the last time (epoch, msec) since the last touchMove event which was not thrown away or since + * touchStart because Android's Webkit browser fires too much of them. + * @type Number + */ + this.touchMoveLast = 0; - this.elType = 'line'; + /** + * Contains the pointerId of the last touchMove event which was not thrown away or since + * touchStart because Android's Webkit browser fires too much of them. + * @type Number + */ + this.touchMoveLastId = Infinity; - /* Add arrow as child to defining points */ - this.point1.addChild(this); - this.point2.addChild(this); + /** + * Contains the last time (epoch, msec) since the last getCoordsTopLeftCorner call which was not thrown away. + * @type Number + */ + this.positionAccessLast = 0; - this.inherits.push(this.point1, this.point2); + /** + * Collects all elements that triggered a mouse down event. + * @type Array + */ + this.downObjects = []; - this.updateStdform(); // This is needed in the following situation: - // * the line is defined by three coordinates - // * and it will have a glider - // * and board.suspendUpdate() has been called. + if (this.attr.showcopyright) { + this.renderer.displayCopyright(Const.licenseText, parseInt(this.options.text.fontSize, 10)); + } - // create Label - this.createLabel(); + /** + * Full updates are needed after zoom and axis translates. This saves some time during an update. + * @default false + * @type Boolean + */ + this.needsFullUpdate = false; - this.methodMap = JXG.deepCopy(this.methodMap, { - point1: 'point1', - point2: 'point2', - getSlope: 'getSlope', - getRise: 'getRise', - getYIntersect: 'getRise', - getAngle: 'getAngle', - L: 'L', - length: 'L' - }); - }; + /** + * If reducedUpdate is set to true then only the dragged element and few (e.g. 2) following + * elements are updated during mouse move. On mouse up the whole construction is + * updated. This enables us to be fast even on very slow devices. + * @type Boolean + * @default false + */ + this.reducedUpdate = false; - JXG.Line.prototype = new GeometryElement(); + /** + * The current color blindness deficiency is stored in this property. If color blindness is not emulated + * at the moment, it's value is 'none'. + */ + this.currentCBDef = 'none'; - JXG.extend(JXG.Line.prototype, /** @lends JXG.Line.prototype */ { /** - * Checks whether (x,y) is near the line. - * @param {Number} x Coordinate in x direction, screen coordinates. - * @param {Number} y Coordinate in y direction, screen coordinates. - * @returns {Boolean} True if (x,y) is near the line, False otherwise. + * If GEONExT constructions are displayed, then this property should be set to true. + * At the moment there should be no difference. But this may change. + * This is set in {@link JXG.GeonextReader.readGeonext}. + * @type Boolean + * @default false + * @see JXG.GeonextReader.readGeonext */ - hasPoint: function (x, y) { - // Compute the stdform of the line in screen coordinates. - var c = [], s, - v = [1, x, y], - vnew, - p1c, p2c, d, pos, i, - prec, type, - sw = Type.evaluate(this.visProp.strokewidth); + this.geonextCompatibilityMode = false; - if (Type.isObject(Type.evaluate(this.visProp.precision))) { - type = this.board._inputDevice; - prec = Type.evaluate(this.visProp.precision[type]); - } else { - // 'inherit' - prec = this.board.options.precision.hasPoint; - } - prec += sw * 0.5; + if (this.options.text.useASCIIMathML && translateASCIIMath) { + init(); + } else { + this.options.text.useASCIIMathML = false; + } - c[0] = this.stdform[0] - - this.stdform[1] * this.board.origin.scrCoords[1] / this.board.unitX + - this.stdform[2] * this.board.origin.scrCoords[2] / this.board.unitY; - c[1] = this.stdform[1] / this.board.unitX; - c[2] = this.stdform[2] / (-this.board.unitY); + /** + * A flag which tells if the board registers mouse events. + * @type Boolean + * @default false + */ + this.hasMouseHandlers = false; - s = Geometry.distPointLine(v, c); - if (isNaN(s) || s > prec) { - return false; - } + /** + * A flag which tells if the board registers touch events. + * @type Boolean + * @default false + */ + this.hasTouchHandlers = false; - if (Type.evaluate(this.visProp.straightfirst) && - Type.evaluate(this.visProp.straightlast)) { - return true; - } + /** + * A flag which stores if the board registered pointer events. + * @type Boolean + * @default false + */ + this.hasPointerHandlers = false; - // If the line is a ray or segment we have to check if the projected point is between P1 and P2. - p1c = this.point1.coords; - p2c = this.point2.coords; + /** + * A flag which tells if the board the JXG.Board#mouseUpListener is currently registered. + * @type Boolean + * @default false + */ + this.hasMouseUp = false; - // Project the point orthogonally onto the line - vnew = [0, c[1], c[2]]; - // Orthogonal line to c through v - vnew = Mat.crossProduct(vnew, v); - // Intersect orthogonal line with line - vnew = Mat.crossProduct(vnew, c); + /** + * A flag which tells if the board the JXG.Board#touchEndListener is currently registered. + * @type Boolean + * @default false + */ + this.hasTouchEnd = false; - // Normalize the projected point - vnew[1] /= vnew[0]; - vnew[2] /= vnew[0]; - vnew[0] = 1; + /** + * A flag which tells us if the board has a pointerUp event registered at the moment. + * @type Boolean + * @default false + */ + this.hasPointerUp = false; - vnew = (new Coords(Const.COORDS_BY_SCREEN, vnew.slice(1), this.board)).usrCoords; - d = p1c.distance(Const.COORDS_BY_USER, p2c); - p1c = p1c.usrCoords.slice(0); - p2c = p2c.usrCoords.slice(0); + /** + * Offset for large coords elements like images + * @type Array + * @private + * @default [0, 0] + */ + this._drag_offset = [0, 0]; - // The defining points are identical - if (d < Mat.eps) { - pos = 0; - } else { - /* - * Handle the cases, where one of the defining points is an ideal point. - * d is set to something close to infinity, namely 1/eps. - * The ideal point is (temporarily) replaced by a finite point which has - * distance d from the other point. - * This is accomplished by extracting the x- and y-coordinates (x,y)=:v of the ideal point. - * v determines the direction of the line. v is normalized, i.e. set to length 1 by dividing through its length. - * Finally, the new point is the sum of the other point and v*d. - * - */ + /** + * Stores the input device used in the last down or move event. + * @type String + * @private + * @default 'mouse' + */ + this._inputDevice = 'mouse'; - // At least one point is an ideal point - if (d === Number.POSITIVE_INFINITY) { - d = 1 / Mat.eps; + /** + * Keeps a list of pointer devices which are currently touching the screen. + * @type Array + * @private + */ + this._board_touches = []; - // The second point is an ideal point - if (Math.abs(p2c[0]) < Mat.eps) { - d /= Geometry.distance([0, 0, 0], p2c); - p2c = [1, p1c[1] + p2c[1] * d, p1c[2] + p2c[2] * d]; - // The first point is an ideal point - } else { - d /= Geometry.distance([0, 0, 0], p1c); - p1c = [1, p2c[1] + p1c[1] * d, p2c[2] + p1c[2] * d]; - } - } - i = 1; - d = p2c[i] - p1c[i]; + /** + * A flag which tells us if the board is in the selecting mode + * @type Boolean + * @default false + */ + this.selectingMode = false; - if (Math.abs(d) < Mat.eps) { - i = 2; - d = p2c[i] - p1c[i]; - } - pos = (vnew[i] - p1c[i]) / d; - } + /** + * A flag which tells us if the user is selecting + * @type Boolean + * @default false + */ + this.isSelecting = false; - if (!Type.evaluate(this.visProp.straightfirst) && pos < 0) { - return false; - } + /** + * A flag which tells us if the user is scrolling the viewport + * @type Boolean + * @private + * @default false + * @see JXG.Board#scrollListener + */ + this._isScrolling = false; - return !(!Type.evaluate(this.visProp.straightlast) && pos > 1); + /** + * A flag which tells us if a resize is in process + * @type Boolean + * @private + * @default false + * @see JXG.Board#resizeListener + */ + this._isResizing = false; - }, + /** + * A bounding box for the selection + * @type Array + * @default [ [0,0], [0,0] ] + */ + this.selectingBox = [[0, 0], [0, 0]]; - // documented in base/element - update: function () { - var funps; + this.mathLib = Math; // Math or JXG.Math.IntervalArithmetic + this.mathLibJXG = JXG.Math; // JXG.Math or JXG.Math.IntervalArithmetic - if (!this.needsUpdate) { - return this; - } + if (this.attr.registerevents) { + this.addEventHandlers(); + } - if (this.constrained) { - if (Type.isFunction(this.funps)) { - funps = this.funps(); - if (funps && funps.length && funps.length === 2) { - this.point1 = funps[0]; - this.point2 = funps[1]; - } - } else { - if (Type.isFunction(this.funp1)) { - funps = this.funp1(); - if (Type.isPoint(funps)) { - this.point1 = funps; - } else if (funps && funps.length && funps.length === 2) { - this.point1.setPositionDirectly(Const.COORDS_BY_USER, funps); - } - } + this.methodMap = { + update: 'update', + fullUpdate: 'fullUpdate', + on: 'on', + off: 'off', + trigger: 'trigger', + setView: 'setBoundingBox', + setBoundingBox: 'setBoundingBox', + migratePoint: 'migratePoint', + colorblind: 'emulateColorblindness', + suspendUpdate: 'suspendUpdate', + unsuspendUpdate: 'unsuspendUpdate', + clearTraces: 'clearTraces', + left: 'clickLeftArrow', + right: 'clickRightArrow', + up: 'clickUpArrow', + down: 'clickDownArrow', + zoomIn: 'zoomIn', + zoomOut: 'zoomOut', + zoom100: 'zoom100', + zoomElements: 'zoomElements', + remove: 'removeObject', + removeObject: 'removeObject' + }; + }; - if (Type.isFunction(this.funp2)) { - funps = this.funp2(); - if (Type.isPoint(funps)) { - this.point2 = funps; - } else if (funps && funps.length && funps.length === 2) { - this.point2.setPositionDirectly(Const.COORDS_BY_USER, funps); - } - } - } - } + JXG.extend(JXG.Board.prototype, /** @lends JXG.Board.prototype */ { - this.updateSegmentFixedLength(); - this.updateStdform(); + /** + * Generates an unique name for the given object. The result depends on the objects type, if the + * object is a {@link JXG.Point}, capital characters are used, if it is of type {@link JXG.Line} + * only lower case characters are used. If object is of type {@link JXG.Polygon}, a bunch of lower + * case characters prefixed with P_ are used. If object is of type {@link JXG.Circle} the name is + * generated using lower case characters. prefixed with k_ is used. In any other case, lower case + * chars prefixed with s_ is used. + * @param {Object} object Reference of an JXG.GeometryElement that is to be named. + * @returns {String} Unique name for the object. + */ + generateName: function (object) { + var possibleNames, i, + maxNameLength = this.attr.maxnamelength, + pre = '', + post = '', + indices = [], + name = ''; - if (Type.evaluate(this.visProp.trace)) { - this.cloneToBackground(true); + if (object.type === Const.OBJECT_TYPE_TICKS) { + return ''; } - return this; - }, + if (Type.isPoint(object)) { + // points have capital letters + possibleNames = ['', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']; + } else if (object.type === Const.OBJECT_TYPE_ANGLE) { + possibleNames = ['', 'α', 'β', 'γ', 'δ', 'ε', 'ζ', 'η', 'θ', + 'ι', 'κ', 'λ', 'μ', 'ν', 'ξ', 'ο', 'π', 'ρ', + 'σ', 'τ', 'υ', 'φ', 'χ', 'ψ', 'ω']; + } else { + // all other elements get lowercase labels + possibleNames = ['', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']; + } - /** - * Update segments with fixed length and at least one movable point. - * @private - */ - updateSegmentFixedLength: function () { - var d, dnew, d1, d2, drag1, drag2, x, y; + if (!Type.isPoint(object) && + object.elementClass !== Const.OBJECT_CLASS_LINE && + object.type !== Const.OBJECT_TYPE_ANGLE) { + if (object.type === Const.OBJECT_TYPE_POLYGON) { + pre = 'P_{'; + } else if (object.elementClass === Const.OBJECT_CLASS_CIRCLE) { + pre = 'k_{'; + } else if (object.elementClass === Const.OBJECT_CLASS_TEXT) { + pre = 't_{'; + } else { + pre = 's_{'; + } + post = '}'; + } - if (!this.hasFixedLength) { - return this; + for (i = 0; i < maxNameLength; i++) { + indices[i] = 0; } - // Compute the actual length of the segment - d = this.point1.Dist(this.point2); - // Determine the length the segment ought to have - dnew = this.fixedLength(); - // Distances between the two points and their respective - // position before the update - d1 = this.fixedLengthOldCoords[0].distance(Const.COORDS_BY_USER, this.point1.coords); - d2 = this.fixedLengthOldCoords[1].distance(Const.COORDS_BY_USER, this.point2.coords); + while (indices[maxNameLength - 1] < possibleNames.length) { + for (indices[0] = 1; indices[0] < possibleNames.length; indices[0]++) { + name = pre; - // If the position of the points or the fixed length function has been changed we have to work. - if (d1 > Mat.eps || d2 > Mat.eps || d !== dnew) { - drag1 = this.point1.isDraggable && - (this.point1.type !== Const.OBJECT_TYPE_GLIDER) && - !Type.evaluate(this.point1.visProp.fixed); - drag2 = this.point2.isDraggable && - (this.point2.type !== Const.OBJECT_TYPE_GLIDER) && - !Type.evaluate(this.point2.visProp.fixed); + for (i = maxNameLength; i > 0; i--) { + name += possibleNames[indices[i - 1]]; + } - // First case: the two points are different - // Then we try to adapt the point that was not dragged - // If this point can not be moved (e.g. because it is a glider) - // we try move the other point - if (d > Mat.eps) { - if ((d1 > d2 && drag2) || - (d1 <= d2 && drag2 && !drag1)) { - this.point2.setPositionDirectly(Const.COORDS_BY_USER, [ - this.point1.X() + (this.point2.X() - this.point1.X()) * dnew / d, - this.point1.Y() + (this.point2.Y() - this.point1.Y()) * dnew / d - ]); - this.point2.fullUpdate(); - } else if ((d1 <= d2 && drag1) || - (d1 > d2 && drag1 && !drag2)) { - this.point1.setPositionDirectly(Const.COORDS_BY_USER, [ - this.point2.X() + (this.point1.X() - this.point2.X()) * dnew / d, - this.point2.Y() + (this.point1.Y() - this.point2.Y()) * dnew / d - ]); - this.point1.fullUpdate(); + if (!Type.exists(this.elementsByName[name + post])) { + return name + post; } - // Second case: the two points are identical. In this situation - // we choose a random direction. - } else { - x = Math.random() - 0.5; - y = Math.random() - 0.5; - d = Math.sqrt(x * x + y * y); - if (drag2) { - this.point2.setPositionDirectly(Const.COORDS_BY_USER, [ - this.point1.X() + x * dnew / d, - this.point1.Y() + y * dnew / d - ]); - this.point2.fullUpdate(); - } else if (drag1) { - this.point1.setPositionDirectly(Const.COORDS_BY_USER, [ - this.point2.X() + x * dnew / d, - this.point2.Y() + y * dnew / d - ]); - this.point1.fullUpdate(); + } + indices[0] = possibleNames.length; + + for (i = 1; i < maxNameLength; i++) { + if (indices[i - 1] === possibleNames.length) { + indices[i - 1] = 1; + indices[i] += 1; } } - // Finally, we save the position of the two points. - this.fixedLengthOldCoords[0].setCoordinates(Const.COORDS_BY_USER, this.point1.coords.usrCoords); - this.fixedLengthOldCoords[1].setCoordinates(Const.COORDS_BY_USER, this.point2.coords.usrCoords); } - return this; + + return ''; }, /** - * Updates the stdform derived from the parent point positions. - * @private + * Generates unique id for a board. The result is randomly generated and prefixed with 'jxgBoard'. + * @returns {String} Unique id for a board. */ - updateStdform: function () { - var v = Mat.crossProduct(this.point1.coords.usrCoords, this.point2.coords.usrCoords); + generateId: function () { + var r = 1; - this.stdform[0] = v[0]; - this.stdform[1] = v[1]; - this.stdform[2] = v[2]; - this.stdform[3] = 0; + // as long as we don't have a unique id generate a new one + while (Type.exists(JXG.boards['jxgBoard' + r])) { + r = Math.round(Math.random() * 65535); + } - this.normalize(); + return ('jxgBoard' + r); }, /** - * Uses the boards renderer to update the line. - * @private + * Composes an id for an element. If the ID is empty ('' or null) a new ID is generated, depending on the + * object type. As a side effect {@link JXG.Board#numObjects} + * is updated. + * @param {Object} obj Reference of an geometry object that needs an id. + * @param {Number} type Type of the object. + * @returns {String} Unique id for an element. */ - updateRenderer: function () { - //var wasReal; - - if (!this.needsUpdate) { - return this; - } + setId: function (obj, type) { + var randomNumber, + num = this.numObjects, + elId = obj.id; - if (this.visPropCalc.visible) { - // wasReal = this.isReal; - this.isReal = (!isNaN(this.point1.coords.usrCoords[1] + this.point1.coords.usrCoords[2] + - this.point2.coords.usrCoords[1] + this.point2.coords.usrCoords[2]) && - (Mat.innerProduct(this.stdform, this.stdform, 3) >= Mat.eps * Mat.eps)); + this.numObjects += 1; - if (//wasReal && - !this.isReal) { - this.updateVisibility(false); + // If no id is provided or id is empty string, a new one is chosen + if (elId === '' || !Type.exists(elId)) { + elId = this.id + type + num; + while (Type.exists(this.objects[elId])) { + randomNumber = Math.round(Math.random() * 65535); + elId = this.id + type + num + '-' + randomNumber; } } - if (this.visPropCalc.visible) { - this.board.renderer.updateLine(this); - } + obj.id = elId; + this.objects[elId] = obj; + obj._pos = this.objectsList.length; + this.objectsList[this.objectsList.length] = obj; - /* Update the label if visible. */ - if (this.hasLabel && this.visPropCalc.visible && this.label && - this.label.visPropCalc.visible && this.isReal) { - - this.label.update(); - this.board.renderer.updateText(this.label); - } - - // Update rendNode display - this.setDisplayRendNode(); - // if (this.visPropCalc.visible !== this.visPropOld.visible) { - // this.setDisplayRendNode(this.visPropCalc.visible); - // if (this.hasLabel) { - // this.board.renderer.display(this.label, this.label.visPropCalc.visible); - // } - // } - - this.needsUpdate = false; - return this; - }, - - /** - * Used to generate a polynomial for a point p that lies on this line, i.e. p is collinear to - * {@link JXG.Line#point1} and {@link JXG.Line#point2}. - * - * @param {JXG.Point} p The point for that the polynomial is generated. - * @returns {Array} An array containing the generated polynomial. - * @private - */ - generatePolynomial: function (p) { - var u1 = this.point1.symbolic.x, - u2 = this.point1.symbolic.y, - v1 = this.point2.symbolic.x, - v2 = this.point2.symbolic.y, - w1 = p.symbolic.x, - w2 = p.symbolic.y; - - /* - * The polynomial in this case is determined by three points being collinear: - * - * U (u1,u2) W (w1,w2) V (v1,v2) - * ----x--------------x------------------------x---------------- - * - * The collinearity condition is - * - * u2-w2 w2-v2 - * ------- = ------- (1) - * u1-w1 w1-v1 - * - * Multiplying (1) with denominators and simplifying is - * - * u2w1 - u2v1 + w2v1 - u1w2 + u1v2 - w1v2 = 0 - */ - - return [['(', u2, ')*(', w1, ')-(', u2, ')*(', v1, ')+(', w2, ')*(', v1, ')-(', u1, ')*(', w2, ')+(', u1, ')*(', v2, ')-(', w1, ')*(', v2, ')'].join('')]; + return elId; }, /** - * Calculates the y intersect of the line. - * @returns {Number} The y intersect. + * After construction of the object the visibility is set + * and the label is constructed if necessary. + * @param {Object} obj The object to add. */ - getRise: function () { - if (Math.abs(this.stdform[2]) >= Mat.eps) { - return -this.stdform[0] / this.stdform[2]; + finalizeAdding: function (obj) { + if (Type.evaluate(obj.visProp.visible) === false) { + this.renderer.display(obj, false); } - - return Infinity; }, - /** - * Calculates the slope of the line. - * @returns {Number} The slope of the line or Infinity if the line is parallel to the y-axis. - */ - getSlope: function () { - if (Math.abs(this.stdform[2]) >= Mat.eps) { - return -this.stdform[1] / this.stdform[2]; + finalizeLabel: function (obj) { + if (obj.hasLabel && + !Type.evaluate(obj.label.visProp.islabel) && + Type.evaluate(obj.label.visProp.visible) === false) { + this.renderer.display(obj.label, false); } - - return Infinity; }, - /** - * Determines the angle between the positive x axis and the line. - * @returns {Number} - */ - getAngle: function () { - return Math.atan2(-this.stdform[1], this.stdform[2]); - }, + /********************************************************** + * + * Event Handler helpers + * + **********************************************************/ /** - * Determines whether the line is drawn beyond {@link JXG.Line#point1} and - * {@link JXG.Line#point2} and updates the line. - * @param {Boolean} straightFirst True if the Line shall be drawn beyond - * {@link JXG.Line#point1}, false otherwise. - * @param {Boolean} straightLast True if the Line shall be drawn beyond - * {@link JXG.Line#point2}, false otherwise. - * @see #straightFirst - * @see #straightLast + * Returns false if the event has been triggered faster than the maximum frame rate. + * + * @param {Event} evt Event object given by the browser (unused) + * @returns {Boolean} If the event has been triggered faster than the maximum frame rate, false is returned. * @private + * @see JXG.Board#pointerMoveListener + * @see JXG.Board#touchMoveListener + * @see JXG.Board#mouseMoveListener */ - setStraight: function (straightFirst, straightLast) { - this.visProp.straightfirst = straightFirst; - this.visProp.straightlast = straightLast; - - this.board.renderer.updateLine(this); - return this; - }, + checkFrameRate: function(evt) { + var handleEvt = false, + time = new Date().getTime(); - // documented in geometry element - getTextAnchor: function () { - return new Coords(Const.COORDS_BY_USER, [0.5 * (this.point2.X() + this.point1.X()), 0.5 * (this.point2.Y() + this.point1.Y())], this.board); + if (Type.exists(evt.pointerId) && this.touchMoveLastId !== evt.pointerId) { + handleEvt = true; + this.touchMoveLastId = evt.pointerId; + } + if (!handleEvt && (time - this.touchMoveLast) * this.attr.maxframerate >= 1000) { + handleEvt = true; + } + if (handleEvt) { + this.touchMoveLast = time; + } + return handleEvt; }, /** - * Adjusts Label coords relative to Anchor. DESCRIPTION - * @private + * Calculates mouse coordinates relative to the boards container. + * @returns {Array} Array of coordinates relative the boards container top left corner. */ - setLabelRelativeCoords: function (relCoords) { - if (Type.exists(this.label)) { - this.label.relativeCoords = new Coords(Const.COORDS_BY_SCREEN, [relCoords[0], -relCoords[1]], this.board); - } - }, - - // documented in geometry element - getLabelAnchor: function () { - var x, y, - fs = 0, - c1 = new Coords(Const.COORDS_BY_USER, this.point1.coords.usrCoords, this.board), - c2 = new Coords(Const.COORDS_BY_USER, this.point2.coords.usrCoords, this.board), - ev_sf = Type.evaluate(this.visProp.straightfirst), - ev_sl = Type.evaluate(this.visProp.straightlast); + getCoordsTopLeftCorner: function () { + var cPos, doc, crect, + // In ownerDoc we need the "real" document object. + // The first version is used in the case of shadowDom, + // the second case in the "normal" case. + ownerDoc = this.document.ownerDocument || this.document, + docElement = ownerDoc.documentElement || this.document.body.parentNode, + docBody = ownerDoc.body, + container = this.containerObj, + // viewport, content, + zoom, o; - if (ev_sf || ev_sl) { - Geometry.calcStraight(this, c1, c2, 0); + /** + * During drags and origin moves the container element is usually not changed. + * Check the position of the upper left corner at most every 1000 msecs + */ + if (this.cPos.length > 0 && + (this.mode === this.BOARD_MODE_DRAG || this.mode === this.BOARD_MODE_MOVE_ORIGIN || + (new Date()).getTime() - this.positionAccessLast < 1000)) { + return this.cPos; } + this.positionAccessLast = (new Date()).getTime(); - c1 = c1.scrCoords; - c2 = c2.scrCoords; + // Check if getBoundingClientRect exists. If so, use this as this covers *everything* + // even CSS3D transformations etc. + // Supported by all browsers but IE 6, 7. - if (!Type.exists(this.label)) { - return new Coords(Const.COORDS_BY_SCREEN, [NaN, NaN], this.board); - } + if (container.getBoundingClientRect) { + crect = container.getBoundingClientRect(); - switch (Type.evaluate(this.label.visProp.position)) { - case 'lft': - case 'llft': - case 'ulft': - if (c1[1] <= c2[1]) { - x = c1[1]; - y = c1[2]; - } else { - x = c2[1]; - y = c2[2]; - } - break; - case 'rt': - case 'lrt': - case 'urt': - if (c1[1] > c2[1]) { - x = c1[1]; - y = c1[2]; - } else { - x = c2[1]; - y = c2[2]; - } - break; - default: - x = 0.5 * (c1[1] + c2[1]); - y = 0.5 * (c1[2] + c2[2]); - } - // Correct coordinates if the label seems to be outside of canvas. - if (ev_sf || ev_sl) { - if (Type.exists(this.label)) { // Does not exist during createLabel - fs = Type.evaluate(this.label.visProp.fontsize); + zoom = 1.0; + // Recursively search for zoom style entries. + // This is necessary for reveal.js on webkit. + // It fails if the user does zooming + o = container; + while (o && Type.exists(o.parentNode)) { + if (Type.exists(o.style) && Type.exists(o.style.zoom) && o.style.zoom !== '') { + zoom *= parseFloat(o.style.zoom); + } + o = o.parentNode; } + cPos = [crect.left * zoom, crect.top * zoom]; - if (Math.abs(x) < Mat.eps) { - x = fs; - } else if (this.board.canvasWidth + Mat.eps > x && - x > this.board.canvasWidth - fs - Mat.eps) { - x = this.board.canvasWidth - fs; - } + // add border width + cPos[0] += Env.getProp(container, 'border-left-width'); + cPos[1] += Env.getProp(container, 'border-top-width'); - if (Mat.eps + fs > y && y > -Mat.eps) { - y = fs; - } else if (this.board.canvasHeight + Mat.eps > y && - y > this.board.canvasHeight - fs - Mat.eps) { - y = this.board.canvasHeight - fs; + // vml seems to ignore paddings + if (this.renderer.type !== 'vml') { + // add padding + cPos[0] += Env.getProp(container, 'padding-left'); + cPos[1] += Env.getProp(container, 'padding-top'); } + + this.cPos = cPos.slice(); + return this.cPos; } - return new Coords(Const.COORDS_BY_SCREEN, [x, y], this.board); - }, + // + // OLD CODE + // IE 6-7 only: + // + cPos = Env.getOffset(container); + doc = this.document.documentElement.ownerDocument; - // documented in geometry element - cloneToBackground: function () { - var copy = {}, r, s, er; + if (!this.containerObj.currentStyle && doc.defaultView) { // Non IE + // this is for hacks like this one used in wordpress for the admin bar: + // html { margin-top: 28px } + // seems like it doesn't work in IE - copy.id = this.id + 'T' + this.numTraces; - copy.elementClass = Const.OBJECT_CLASS_LINE; - this.numTraces++; - copy.point1 = this.point1; - copy.point2 = this.point2; + cPos[0] += Env.getProp(docElement, 'margin-left'); + cPos[1] += Env.getProp(docElement, 'margin-top'); - copy.stdform = this.stdform; + cPos[0] += Env.getProp(docElement, 'border-left-width'); + cPos[1] += Env.getProp(docElement, 'border-top-width'); - copy.board = this.board; + cPos[0] += Env.getProp(docElement, 'padding-left'); + cPos[1] += Env.getProp(docElement, 'padding-top'); + } - copy.visProp = Type.deepCopy(this.visProp, this.visProp.traceattributes, true); - copy.visProp.layer = this.board.options.layer.trace; - Type.clearVisPropOld(copy); - copy.visPropCalc = { - visible: Type.evaluate(copy.visProp.visible) - }; + if (docBody) { + cPos[0] += Env.getProp(docBody, 'left'); + cPos[1] += Env.getProp(docBody, 'top'); + } - s = this.getSlope(); - r = this.getRise(); - copy.getSlope = function () { - return s; - }; - copy.getRise = function () { - return r; - }; + // Google Translate offers widgets for web authors. These widgets apparently tamper with the clientX + // and clientY coordinates of the mouse events. The minified sources seem to be the only publicly + // available version so we're doing it the hacky way: Add a fixed offset. + // see https://groups.google.com/d/msg/google-translate-general/H2zj0TNjjpY/jw6irtPlCw8J + if (typeof google === 'object' && google.translate) { + cPos[0] += 10; + cPos[1] += 25; + } - er = this.board.renderer.enhancedRendering; - this.board.renderer.enhancedRendering = true; - this.board.renderer.drawLine(copy); - this.board.renderer.enhancedRendering = er; - this.traces[copy.id] = copy.rendNode; + // add border width + cPos[0] += Env.getProp(container, 'border-left-width'); + cPos[1] += Env.getProp(container, 'border-top-width'); - return this; + // vml seems to ignore paddings + if (this.renderer.type !== 'vml') { + // add padding + cPos[0] += Env.getProp(container, 'padding-left'); + cPos[1] += Env.getProp(container, 'padding-top'); + } + + cPos[0] += this.attr.offsetx; + cPos[1] += this.attr.offsety; + + this.cPos = cPos.slice(); + return this.cPos; }, /** - * Add transformations to this line. - * @param {JXG.Transformation|Array} transform Either one {@link JXG.Transformation} or an array of - * {@link JXG.Transformation}s. - * @returns {JXG.Line} Reference to this line object. + * Get the position of the mouse in screen coordinates, relative to the upper left corner + * of the host tag. + * @param {Event} e Event object given by the browser. + * @param {Number} [i] Only use in case of touch events. This determines which finger to use and should not be set + * for mouseevents. + * @returns {Array} Contains the mouse coordinates in screen coordinates, ready for {@link JXG.Coords} */ - addTransform: function (transform) { - var i, - list = Type.isArray(transform) ? transform : [transform], - len = list.length; + getMousePosition: function (e, i) { + var cPos = this.getCoordsTopLeftCorner(), + absPos, + v; - for (i = 0; i < len; i++) { - this.point1.transformations.push(list[i]); - this.point2.transformations.push(list[i]); + // Position of cursor using clientX/Y + absPos = Env.getPosition(e, i, this.document); + + /** + * In case there has been no down event before. + */ + if (!Type.exists(this.cssTransMat)) { + this.updateCSSTransforms(); } + // Position relative to the top left corner + v = [1, absPos[0] - cPos[0], absPos[1] - cPos[1]]; + v = Mat.matVecMult(this.cssTransMat, v); + v[1] /= v[0]; + v[2] /= v[0]; + return [v[1], v[2]]; - return this; + // Method without CSS transformation + /* + return [absPos[0] - cPos[0], absPos[1] - cPos[1]]; + */ }, - // see GeometryElement.js - snapToGrid: function (pos) { - var c1, c2, dc, t, ticks, - x, y, sX, sY; + /** + * Initiate moving the origin. This is used in mouseDown and touchStart listeners. + * @param {Number} x Current mouse/touch coordinates + * @param {Number} y Current mouse/touch coordinates + */ + initMoveOrigin: function (x, y) { + this.drag_dx = x - this.origin.scrCoords[1]; + this.drag_dy = y - this.origin.scrCoords[2]; - if (Type.evaluate(this.visProp.snaptogrid)) { - if (this.parents.length < 3) { // Line through two points - this.point1.handleSnapToGrid(true, true); - this.point2.handleSnapToGrid(true, true); - } else if (Type.exists(pos)) { // Free line - sX = Type.evaluate(this.visProp.snapsizex); - sY = Type.evaluate(this.visProp.snapsizey); + this.mode = this.BOARD_MODE_MOVE_ORIGIN; + this.updateQuality = this.BOARD_QUALITY_LOW; + }, - c1 = new Coords(Const.COORDS_BY_SCREEN, [pos.Xprev, pos.Yprev], this.board); + /** + * Collects all elements below the current mouse pointer and fulfilling the following constraints: + * <ul><li>isDraggable</li><li>visible</li><li>not fixed</li><li>not frozen</li></ul> + * @param {Number} x Current mouse/touch coordinates + * @param {Number} y current mouse/touch coordinates + * @param {Object} evt An event object + * @param {String} type What type of event? 'touch', 'mouse' or 'pen'. + * @returns {Array} A list of geometric elements. + */ + initMoveObject: function (x, y, evt, type) { + var pEl, + el, + collect = [], + offset = [], + haspoint, + len = this.objectsList.length, + dragEl = {visProp: {layer: -10000}}; - x = c1.usrCoords[1]; - y = c1.usrCoords[2]; + //for (el in this.objects) { + for (el = 0; el < len; el++) { + pEl = this.objectsList[el]; + haspoint = pEl.hasPoint && pEl.hasPoint(x, y); - if (sX <= 0 && this.board.defaultAxes && this.board.defaultAxes.x.defaultTicks) { - ticks = this.board.defaultAxes.x.defaultTicks; - sX = ticks.ticksDelta * (Type.evaluate(ticks.visProp.minorticks) + 1); - } - if (sY <= 0 && this.board.defaultAxes && this.board.defaultAxes.y.defaultTicks) { - ticks = this.board.defaultAxes.y.defaultTicks; - sY = ticks.ticksDelta * (Type.evaluate(ticks.visProp.minorticks) + 1); - } + if (pEl.visPropCalc.visible && haspoint) { + pEl.triggerEventHandlers([type + 'down', 'down'], [evt]); + this.downObjects.push(pEl); + } - // if no valid snap sizes are available, don't change the coords. - if (sX > 0 && sY > 0) { - // projectCoordsToLine - /* - v = [0, this.stdform[1], this.stdform[2]]; - v = Mat.crossProduct(v, c1.usrCoords); - c2 = Geometry.meetLineLine(v, this.stdform, 0, this.board); - */ - c2 = Geometry.projectPointToLine({coords: c1}, this, this.board); + if (haspoint && + pEl.isDraggable && + pEl.visPropCalc.visible && + ((this.geonextCompatibilityMode && + (Type.isPoint(pEl) || + pEl.elementClass === Const.OBJECT_CLASS_TEXT) + ) || + !this.geonextCompatibilityMode + ) && + !Type.evaluate(pEl.visProp.fixed) + /*(!pEl.visProp.frozen) &&*/ + ) { - dc = Statistics.subtract([1, Math.round(x / sX) * sX, Math.round(y / sY) * sY], c2.usrCoords); - t = this.board.create('transform', dc.slice(1), {type: 'translate'}); - t.applyOnce([this.point1, this.point2]); + // Elements in the highest layer get priority. + if (pEl.visProp.layer > dragEl.visProp.layer || + (pEl.visProp.layer === dragEl.visProp.layer && + pEl.lastDragTime.getTime() >= dragEl.lastDragTime.getTime() + )) { + // If an element and its label have the focus + // simultaneously, the element is taken. + // This only works if we assume that every browser runs + // through this.objects in the right order, i.e. an element A + // added before element B turns up here before B does. + if (!this.attr.ignorelabels || + (!Type.exists(dragEl.label) || pEl !== dragEl.label)) { + dragEl = pEl; + collect.push(dragEl); + + // Save offset for large coords elements. + if (Type.exists(dragEl.coords)) { + offset.push(Statistics.subtract(dragEl.coords.scrCoords.slice(1), [x, y])); + } else { + offset.push([0, 0]); + } + + // we can't drop out of this loop because of the event handling system + //if (this.attr.takefirst) { + // return collect; + //} + } } } + } + + if (this.attr.drag.enabled && collect.length > 0) { + this.mode = this.BOARD_MODE_DRAG; + } + + // A one-element array is returned. + if (this.attr.takefirst) { + collect.length = 1; + this._drag_offset = offset[0]; } else { - this.point1.handleSnapToGrid(false, true); - this.point2.handleSnapToGrid(false, true); + collect = collect.slice(-1); + this._drag_offset = offset[offset.length - 1]; } - return this; - }, + if (!this._drag_offset) { + this._drag_offset = [0, 0]; + } - // see element.js - snapToPoints: function () { - var forceIt = Type.evaluate(this.visProp.snaptopoints); + // Move drag element to the top of the layer + if (this.renderer.type === 'svg' && + Type.exists(collect[0]) && + Type.evaluate(collect[0].visProp.dragtotopoflayer) && + collect.length === 1 && + Type.exists(collect[0].rendNode)) { - if (this.parents.length < 3) { // Line through two points - this.point1.handleSnapToPoints(forceIt); - this.point2.handleSnapToPoints(forceIt); + collect[0].rendNode.parentNode.appendChild(collect[0].rendNode); } - return this; + // Init rotation angle and scale factor for two finger movements + this.previousRotation = 0.0; + this.previousScale = 1.0; + + if (collect.length >= 1) { + collect[0].highlight(true); + this.triggerEventHandlers(['mousehit', 'hit'], [evt, collect[0]]); + } + + return collect; }, /** - * Treat the line as parametric curve in homogeneous coordinates, where the parameter t runs from 0 to 1. - * First we transform the interval [0,1] to [-1,1]. - * If the line has homogeneous coordinates [c, a, b] = stdform[] then the direction of the line is [b, -a]. - * Now, we take one finite point that defines the line, i.e. we take either point1 or point2 - * (in case the line is not the ideal line). - * Let the coordinates of that point be [z, x, y]. - * Then, the curve runs linearly from - * [0, b, -a] (t=-1) to [z, x, y] (t=0) - * and - * [z, x, y] (t=0) to [0, -b, a] (t=1) - * - * @param {Number} t Parameter running from 0 to 1. - * @returns {Number} X(t) x-coordinate of the line treated as parametric curve. - * */ - X: function (t) { - var x, - b = this.stdform[2]; - - x = (Math.abs(this.point1.coords.usrCoords[0]) > Mat.eps) ? - this.point1.coords.usrCoords[1] : - this.point2.coords.usrCoords[1]; - - t = (t - 0.5) * 2; + * Moves an object. + * @param {Number} x Coordinate + * @param {Number} y Coordinate + * @param {Object} o The touch object that is dragged: {JXG.Board#mouse} or {JXG.Board#touches}. + * @param {Object} evt The event object. + * @param {String} type Mouse or touch event? + */ + moveObject: function (x, y, o, evt, type) { + var newPos = new Coords(Const.COORDS_BY_SCREEN, this.getScrCoordsOfMouse(x, y), this), + drag, + dragScrCoords, newDragScrCoords; - return (1 - Math.abs(t)) * x - t * b; - }, + if (!(o && o.obj)) { + return; + } + drag = o.obj; - /** - * Treat the line as parametric curve in homogeneous coordinates. - * See {@link JXG.Line#X} for a detailed description. - * @param {Number} t Parameter running from 0 to 1. - * @returns {Number} Y(t) y-coordinate of the line treated as parametric curve. - */ - Y: function (t) { - var y, - a = this.stdform[1]; + // Save updates for very small movements of coordsElements, see below + if (drag.coords) { + dragScrCoords = drag.coords.scrCoords.slice(); + } - y = (Math.abs(this.point1.coords.usrCoords[0]) > Mat.eps) ? - this.point1.coords.usrCoords[2] : - this.point2.coords.usrCoords[2]; + /* + * Save the position. + */ + this.drag_position = [newPos.scrCoords[1], newPos.scrCoords[2]]; + this.drag_position = Statistics.add(this.drag_position, this._drag_offset); + // + // We have to distinguish between CoordsElements and other elements like lines. + // The latter need the difference between two move events. + if (Type.exists(drag.coords)) { + drag.setPositionDirectly(Const.COORDS_BY_SCREEN, this.drag_position); + } else { + this.displayInfobox(false); + // Hide infobox in case the user has touched an intersection point + // and drags the underlying line now. - t = (t - 0.5) * 2; + if (!isNaN(o.targets[0].Xprev + o.targets[0].Yprev)) { + drag.setPositionDirectly(Const.COORDS_BY_SCREEN, + [newPos.scrCoords[1], newPos.scrCoords[2]], + [o.targets[0].Xprev, o.targets[0].Yprev] + ); + } + // Remember the actual position for the next move event. Then we are able to + // compute the difference vector. + o.targets[0].Xprev = newPos.scrCoords[1]; + o.targets[0].Yprev = newPos.scrCoords[2]; + } + // This may be necessary for some gliders and labels + if (Type.exists(drag.coords)) { + drag.prepareUpdate().update(false).updateRenderer(); + this.updateInfobox(drag); + drag.prepareUpdate().update(true).updateRenderer(); + } - return (1 - Math.abs(t)) * y + t * a; - }, + if (drag.coords) { + newDragScrCoords = drag.coords.scrCoords; + } + // No updates for very small movements of coordsElements + if (!drag.coords || + dragScrCoords[1] !== newDragScrCoords[1] || + dragScrCoords[2] !== newDragScrCoords[2]) { - /** - * Treat the line as parametric curve in homogeneous coordinates. - * See {@link JXG.Line#X} for a detailed description. - * - * @param {Number} t Parameter running from 0 to 1. - * @returns {Number} Z(t) z-coordinate of the line treated as parametric curve. - */ - Z: function (t) { - var z = (Math.abs(this.point1.coords.usrCoords[0]) > Mat.eps) ? - this.point1.coords.usrCoords[0] : - this.point2.coords.usrCoords[0]; + drag.triggerEventHandlers([type + 'drag', 'drag'], [evt]); - t = (t - 0.5) * 2; + this.update(); + } + drag.highlight(true); + this.triggerEventHandlers(['mousehit', 'hit'], [evt, drag]); - return (1 - Math.abs(t)) * z; + drag.lastDragTime = new Date(); }, /** - * The distance between the two points defining the line. - * @returns {Number} + * Moves elements in multitouch mode. + * @param {Array} p1 x,y coordinates of first touch + * @param {Array} p2 x,y coordinates of second touch + * @param {Object} o The touch object that is dragged: {JXG.Board#touches}. + * @param {Object} evt The event object that lead to this movement. */ - L: function () { - return this.point1.Dist(this.point2); - }, + twoFingerMove: function (o, id, evt) { + var drag; - /** - * Treat the element as a parametric curve - * @private - */ - minX: function () { - return 0.0; + if (Type.exists(o) && Type.exists(o.obj)) { + drag = o.obj; + } else { + return; + } + + if (drag.elementClass === Const.OBJECT_CLASS_LINE || + drag.type === Const.OBJECT_TYPE_POLYGON) { + this.twoFingerTouchObject(o.targets, drag, id); + } else if (drag.elementClass === Const.OBJECT_CLASS_CIRCLE) { + this.twoFingerTouchCircle(o.targets, drag, id); + } + + if (evt) { + drag.triggerEventHandlers(['touchdrag', 'drag'], [evt]); + } }, /** - * Treat the element as parametric curve - * @private + * Moves, rotates and scales a line or polygon with two fingers. + * @param {Array} tar Array conatining touch event objects: {JXG.Board#touches.targets}. + * @param {object} drag The object that is dragged: + * @param {Number} id pointerId of the event. In case of old touch event this is emulated. */ - maxX: function () { - return 1.0; - }, - - // documented in geometry element - bounds: function () { - var p1c = this.point1.coords.usrCoords, - p2c = this.point2.coords.usrCoords; + twoFingerTouchObject: function (tar, drag, id) { + var np, op, nd, od, + d, alpha, + S, t1, t3, t4, t5, + ar, i, len, + fixEl, moveEl, fix; - return [Math.min(p1c[1], p2c[1]), Math.max(p1c[2], p2c[2]), Math.max(p1c[1], p2c[1]), Math.min(p1c[2], p2c[2])]; - }, + if (Type.exists(tar[0]) && Type.exists(tar[1]) && + !isNaN(tar[0].Xprev + tar[0].Yprev + tar[1].Xprev + tar[1].Yprev)) { - // documented in GeometryElement.js - remove: function () { - this.removeAllTicks(); - GeometryElement.prototype.remove.call(this); - }, + if (id === tar[0].num) { + fixEl = tar[1]; + moveEl = tar[0]; + } else { + fixEl = tar[0]; + moveEl = tar[1]; + } - // hideElement: function () { - // var i; - // - // GeometryElement.prototype.hideElement.call(this); - // - // for (i = 0; i < this.ticks.length; i++) { - // this.ticks[i].hideElement(); - // } - // }, - // - // showElement: function () { - // var i; - // GeometryElement.prototype.showElement.call(this); - // - // for (i = 0; i < this.ticks.length; i++) { - // this.ticks[i].showElement(); - // } - // } - }); + fix = (new Coords(Const.COORDS_BY_SCREEN, [fixEl.Xprev, fixEl.Yprev], this)).usrCoords; + // Previous finger position + op = (new Coords(Const.COORDS_BY_SCREEN, [moveEl.Xprev, moveEl.Yprev], this)).usrCoords; + // New finger position + np = (new Coords(Const.COORDS_BY_SCREEN, [moveEl.X, moveEl.Y], this)).usrCoords; - /** - * @class This element is used to provide a constructor for a general line. A general line is given by two points. By setting additional properties - * a line can be used as an arrow and/or axis. - * @pseudo - * @description - * @name Line - * @augments JXG.Line - * @constructor - * @type JXG.Line - * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {JXG.Point,array,function_JXG.Point,array,function} point1,point2 Parent elements can be two elements either of type {@link JXG.Point} or array of - * numbers describing the coordinates of a point. In the latter case the point will be constructed automatically as a fixed invisible point. - * It is possible to provide a function returning an array or a point, instead of providing an array or a point. - * @param {Number,function_Number,function_Number,function} c,a,b A line can also be created providing three numbers. The line is then described by - * the set of solutions of the equation <tt>a*x+b*y+c*z = 0</tt>. It is possible to provide three functions returning numbers, too. - * @param {function} f This function must return an array containing three numbers forming the line's homogeneous coordinates. - * <p> - * Additionally, a line can be created by providing a line and a transformation (or an array of transformations). - * Then, the result is a line which is the transformation of the supplied line. - * @example - * // Create a line using point and coordinates/ - * // The second point will be fixed and invisible. - * var p1 = board.create('point', [4.5, 2.0]); - * var l1 = board.create('line', [p1, [1.0, 1.0]]); - * </pre><div class="jxgbox" id="JXGc0ae3461-10c4-4d39-b9be-81d74759d122" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * var glex1_board = JXG.JSXGraph.initBoard('JXGc0ae3461-10c4-4d39-b9be-81d74759d122', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}); - * var glex1_p1 = glex1_board.create('point', [4.5, 2.0]); - * var glex1_l1 = glex1_board.create('line', [glex1_p1, [1.0, 1.0]]); - * </script><pre> - * @example - * // Create a line using three coordinates - * var l1 = board.create('line', [1.0, -2.0, 3.0]); - * </pre><div class="jxgbox" id="JXGcf45e462-f964-4ba4-be3a-c9db94e2593f" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * var glex2_board = JXG.JSXGraph.initBoard('JXGcf45e462-f964-4ba4-be3a-c9db94e2593f', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}); - * var glex2_l1 = glex2_board.create('line', [1.0, -2.0, 3.0]); - * </script><pre> - * @example - * // Create a line (l2) as reflection of another line (l1) - * // reflection line - * var li = board.create('line', [1,1,1], {strokeColor: '#aaaaaa'}); - * var reflect = board.create('transform', [li], {type: 'reflect'}); - * - * var l1 = board.create('line', [1,-5,1]); - * var l2 = board.create('line', [l1, reflect]); - * - * </pre><div id="JXGJXGa00d7dd6-d38c-11e7-93b3-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function() { - * var board = JXG.JSXGraph.initBoard('JXGJXGa00d7dd6-d38c-11e7-93b3-901b0e1b8723', - * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); - * // reflection line - * var li = board.create('line', [1,1,1], {strokeColor: '#aaaaaa'}); - * var reflect = board.create('transform', [li], {type: 'reflect'}); - * - * var l1 = board.create('line', [1,-5,1]); - * var l2 = board.create('line', [l1, reflect]); - * })(); - * - * </script><pre> - * - * @example - * var t = board.create('transform', [2, 1.5], {type: 'scale'}); - * var l1 = board.create('line', [1, -5, 1]); - * var l2 = board.create('line', [l1, t]); - * - * </pre><div id="d16d5b58-6338-11e8-9fb9-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function() { - * var board = JXG.JSXGraph.initBoard('d16d5b58-6338-11e8-9fb9-901b0e1b8723', - * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); - * var t = board.create('transform', [2, 1.5], {type: 'scale'}); - * var l1 = board.create('line', [1, -5, 1]); - * var l2 = board.create('line', [l1, t]); - * - * })(); - * - * </script><pre> - * - * @example - * //create line between two points - * var p1 = board.create('point', [0,0]); - * var p2 = board.create('point', [2,2]); - * var l1 = board.create('line', [p1,p2], {straightFirst:false, straightLast:false}); - * </pre><div id="d21d5b58-6338-11e8-9fb9-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function() { - * var board = JXG.JSXGraph.initBoard('d21d5b58-6338-11e8-9fb9-901b0e1b8723', - * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); - * var ex5p1 = board.create('point', [0,0]); - * var ex5p2 = board.create('point', [2,2]); - * var ex5l1 = board.create('line', [p1,p2], {straightFirst:false, straightLast:false}); - * })(); - * - * </script><pre> - */ - JXG.createLine = function (board, parents, attributes) { - var ps, el, p1, p2, i, attr, - c = [], - doTransform = false, - constrained = false, - isDraggable; + // Old and new directions + od = Mat.crossProduct(fix, op); + nd = Mat.crossProduct(fix, np); - /** - * The line is defined by two points or coordinates of two points. - * In the latter case, the points are created. - */ - if (parents.length === 2) { - // point 1 given by coordinates - if (Type.isArray(parents[0]) && parents[0].length > 1) { - attr = Type.copyAttributes(attributes, board.options, 'line', 'point1'); - p1 = board.create('point', parents[0], attr); - } else if (Type.isString(parents[0]) || Type.isPoint(parents[0])) { - p1 = board.select(parents[0]); - } else if (Type.isFunction(parents[0]) && Type.isPoint(parents[0]())) { - p1 = parents[0](); - constrained = true; - } else if (Type.isFunction(parents[0]) && parents[0]().length && parents[0]().length >= 2) { - attr = Type.copyAttributes(attributes, board.options, 'line', 'point1'); - p1 = Point.createPoint(board, parents[0](), attr); - constrained = true; - } else if (Type.isObject(parents[0]) && Type.isTransformationOrArray(parents[1])) { - doTransform = true; - attr = Type.copyAttributes(attributes, board.options, 'line', 'point1'); - p1 = board.create('point', [parents[0].point1, parents[1]], attr); - } else { - throw new Error("JSXGraph: Can't create line with parent types '" + - (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + - "\nPossible parent types: [point,point], [[x1,y1],[x2,y2]], [a,b,c]"); - } + // Intersection between the two directions + S = Mat.crossProduct(od, nd); - // point 2 given by coordinates - if (doTransform) { - attr = Type.copyAttributes(attributes, board.options, 'line', 'point2'); - p2 = board.create('point', [parents[0].point2, parents[1]], attr); - } else if (Type.isArray(parents[1]) && parents[1].length > 1) { - attr = Type.copyAttributes(attributes, board.options, 'line', 'point2'); - p2 = board.create('point', parents[1], attr); - } else if (Type.isString(parents[1]) || Type.isPoint(parents[1])) { - p2 = board.select(parents[1]); - } else if (Type.isFunction(parents[1]) && Type.isPoint(parents[1]()) ) { - p2 = parents[1](); - constrained = true; - } else if (Type.isFunction(parents[1]) && parents[1]().length && parents[1]().length >= 2) { - attr = Type.copyAttributes(attributes, board.options, 'line', 'point2'); - p2 = Point.createPoint(board, parents[1](), attr); - constrained = true; - } else { - throw new Error("JSXGraph: Can't create line with parent types '" + - (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + - "\nPossible parent types: [point,point], [[x1,y1],[x2,y2]], [a,b,c]"); - } + // If parallel translate, otherwise rotate + if (Math.abs(S[0]) < Mat.eps) { + return; + } - attr = Type.copyAttributes(attributes, board.options, 'line'); + alpha = Geometry.rad(op.slice(1), fix.slice(1), np.slice(1)); - el = new JXG.Line(board, p1, p2, attr); + t1 = this.create('transform', [alpha, [fix[1], fix[2]]], {type: 'rotate'}); + t1.update(); - if (constrained) { - el.constrained = true; - el.funp1 = parents[0]; - el.funp2 = parents[1]; - } else if (!doTransform) { - el.isDraggable = true; - } + if (Type.evaluate(drag.visProp.scalable)) { + // Scale + d = Geometry.distance(np, fix) / Geometry.distance(op, fix); - //if (!el.constrained) { - el.setParents([p1.id, p2.id]); - //} + t3 = this.create('transform', [-fix[1], -fix[2]], {type: 'translate'}); + t4 = this.create('transform', [d, d], {type: 'scale'}); + t5 = this.create('transform', [fix[1], fix[2]], {type: 'translate'}); + t1.melt(t3).melt(t4).melt(t5); + } - // Line is defined by three homogeneous coordinates. - // Also in this case points are created. - } else if (parents.length === 3) { - // free line - isDraggable = true; - for (i = 0; i < 3; i++) { - if (Type.isNumber(parents[i])) { - // createFunction will just wrap a function around our constant number - // that does nothing else but to return that number. - c[i] = Type.createFunction(parents[i]); - } else if (Type.isFunction(parents[i])) { - c[i] = parents[i]; - isDraggable = false; - } else { - throw new Error("JSXGraph: Can't create line with parent types '" + - (typeof parents[0]) + "' and '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." + - "\nPossible parent types: [point,point], [[x1,y1],[x2,y2]], [a,b,c]"); + if (drag.elementClass === Const.OBJECT_CLASS_LINE) { + ar = []; + if (drag.point1.draggable()) { + ar.push(drag.point1); + } + if (drag.point2.draggable()) { + ar.push(drag.point2); + } + t1.applyOnce(ar); + } else if (drag.type === Const.OBJECT_TYPE_POLYGON) { + ar = []; + len = drag.vertices.length - 1; + for (i = 0; i < len; ++i) { + if (drag.vertices[i].draggable()) { + ar.push(drag.vertices[i]); + } + } + t1.applyOnce(ar); } - } - // point 1 is the midpoint between (0,c,-b) and point 2. => point1 is finite. - attr = Type.copyAttributes(attributes, board.options, 'line', 'point1'); - if (isDraggable) { - p1 = board.create('point', [ - c[2]() * c[2]() + c[1]() * c[1](), - c[2]() - c[1]() * c[0]() + c[2](), - -c[1]() - c[2]() * c[0]() - c[1]() - ], attr); - } else { - p1 = board.create('point', [ - function () { - return (c[2]() * c[2]() + c[1]() * c[1]()) * 0.5; - }, - function () { - return (c[2]() - c[1]() * c[0]() + c[2]()) * 0.5; - }, - function () { - return (-c[1]() - c[2]() * c[0]() - c[1]()) * 0.5; - }], attr); + this.update(); + drag.highlight(true); } + }, - // point 2: (b^2+c^2,-ba+c,-ca-b) - attr = Type.copyAttributes(attributes, board.options, 'line', 'point2'); - if (isDraggable) { - p2 = board.create('point', [ - c[2]() * c[2]() + c[1]() * c[1](), - -c[1]() * c[0]() + c[2](), - -c[2]() * c[0]() - c[1]() - ], attr); - } else { - p2 = board.create('point', [ - function () { - return c[2]() * c[2]() + c[1]() * c[1](); - }, - function () { - return -c[1]() * c[0]() + c[2](); - }, - function () { - return -c[2]() * c[0]() - c[1](); - }], attr); + /* + * Moves, rotates and scales a circle with two fingers. + * @param {Array} tar Array conatining touch event objects: {JXG.Board#touches.targets}. + * @param {object} drag The object that is dragged: + * @param {Number} id pointerId of the event. In case of old touch event this is emulated. + */ + twoFingerTouchCircle: function (tar, drag, id) { + var fixEl, moveEl, np, op, fix, + d, alpha, t1, t2, t3, t4; + + if (drag.method === 'pointCircle' || drag.method === 'pointLine') { + return; } - // If the line will have a glider and board.suspendUpdate() has been called, we - // need to compute the initial position of the two points p1 and p2. - p1.prepareUpdate().update(); - p2.prepareUpdate().update(); - attr = Type.copyAttributes(attributes, board.options, 'line'); - el = new JXG.Line(board, p1, p2, attr); - // Not yet working, because the points are not draggable. - el.isDraggable = isDraggable; - el.setParents([p1, p2]); + if (Type.exists(tar[0]) && Type.exists(tar[1]) && + !isNaN(tar[0].Xprev + tar[0].Yprev + tar[1].Xprev + tar[1].Yprev)) { - // The parent array contains a function which returns two points. - } else if (parents.length === 1 && Type.isFunction(parents[0]) && parents[0]().length === 2 && - Type.isPoint(parents[0]()[0]) && - Type.isPoint(parents[0]()[1])) { - ps = parents[0](); - attr = Type.copyAttributes(attributes, board.options, 'line'); - el = new JXG.Line(board, ps[0], ps[1], attr); - el.constrained = true; - el.funps = parents[0]; - el.setParents(ps); + if (id === tar[0].num) { + fixEl = tar[1]; + moveEl = tar[0]; + } else { + fixEl = tar[0]; + moveEl = tar[1]; + } - } else if (parents.length === 1 && Type.isFunction(parents[0]) && parents[0]().length === 3 && - Type.isNumber(parents[0]()[0]) && - Type.isNumber(parents[0]()[1]) && - Type.isNumber(parents[0]()[2])) { - ps = parents[0]; + fix = (new Coords(Const.COORDS_BY_SCREEN, [fixEl.Xprev, fixEl.Yprev], this)).usrCoords; + // Previous finger position + op = (new Coords(Const.COORDS_BY_SCREEN, [moveEl.Xprev, moveEl.Yprev], this)).usrCoords; + // New finger position + np = (new Coords(Const.COORDS_BY_SCREEN, [moveEl.X, moveEl.Y], this)).usrCoords; - attr = Type.copyAttributes(attributes, board.options, 'line', 'point1'); - p1 = board.create('point', [ - function () { - var c = ps(); + alpha = Geometry.rad(op.slice(1), fix.slice(1), np.slice(1)); - return [ - (c[2] * c[2] + c[1] * c[1]) * 0.5, - (c[2] - c[1] * c[0] + c[2]) * 0.5, - (-c[1] - c[2] * c[0] - c[1]) * 0.5 - ]; - }], attr); + // Rotate and scale by the movement of the second finger + t1 = this.create('transform', [-fix[1], -fix[2]], {type: 'translate'}); + t2 = this.create('transform', [alpha], {type: 'rotate'}); + t1.melt(t2); + if (Type.evaluate(drag.visProp.scalable)) { + d = Geometry.distance(fix, np) / Geometry.distance(fix, op); + t3 = this.create('transform', [d, d], {type: 'scale'}); + t1.melt(t3); + } + t4 = this.create('transform', [fix[1], fix[2]], {type: 'translate'}); + t1.melt(t4); - attr = Type.copyAttributes(attributes, board.options, 'line', 'point2'); - p2 = board.create('point', [ - function () { - var c = ps(); + if (drag.center.draggable()) { + t1.applyOnce([drag.center]); + } - return [ - c[2] * c[2] + c[1] * c[1], - -c[1] * c[0] + c[2], - -c[2] * c[0] - c[1] - ]; - }], attr); + if (drag.method === 'twoPoints') { + if (drag.point2.draggable()) { + t1.applyOnce([drag.point2]); + } + } else if (drag.method === 'pointRadius') { + if (Type.isNumber(drag.updateRadius.origin)) { + drag.setRadius(drag.radius * d); + } + } - attr = Type.copyAttributes(attributes, board.options, 'line'); - el = new JXG.Line(board, p1, p2, attr); + this.update(drag.center); + drag.highlight(true); + } + }, - el.constrained = true; - el.funps = parents[0]; - el.setParents([p1, p2]); + highlightElements: function (x, y, evt, target) { + var el, pEl, pId, + overObjects = {}, + len = this.objectsList.length; - } else { - throw new Error("JSXGraph: Can't create line with parent types '" + - (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + - "\nPossible parent types: [point,point], [[x1,y1],[x2,y2]], [a,b,c]"); - } + // Elements below the mouse pointer which are not highlighted yet will be highlighted. + for (el = 0; el < len; el++) { + pEl = this.objectsList[el]; + pId = pEl.id; + if (Type.exists(pEl.hasPoint) && pEl.visPropCalc.visible && pEl.hasPoint(x, y)) { + // this is required in any case because otherwise the box won't be shown until the point is dragged + this.updateInfobox(pEl); - return el; - }; - - JXG.registerElement('line', JXG.createLine); - - /** - * @class This element is used to provide a constructor for a segment. - * It's strictly spoken just a wrapper for element {@link Line} with {@link Line#straightFirst} - * and {@link Line#straightLast} properties set to false. If there is a third variable then the - * segment has a fixed length (which may be a function, too). - * @pseudo - * @description - * @name Segment - * @augments JXG.Line - * @constructor - * @type JXG.Line - * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {JXG.Point,array_JXG.Point,array} point1,point2 Parent elements can be two elements either of type {@link JXG.Point} - * or array of numbers describing the - * coordinates of a point. In the latter case the point will be constructed automatically as a fixed invisible point. - * @param {number,function} length (optional) The points are adapted - if possible - such that their distance - * has this value. - * @see Line - * @example - * // Create a segment providing two points. - * var p1 = board.create('point', [4.5, 2.0]); - * var p2 = board.create('point', [1.0, 1.0]); - * var l1 = board.create('segment', [p1, p2]); - * </pre><div class="jxgbox" id="JXGd70e6aac-7c93-4525-a94c-a1820fa38e2f" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * var slex1_board = JXG.JSXGraph.initBoard('JXGd70e6aac-7c93-4525-a94c-a1820fa38e2f', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}); - * var slex1_p1 = slex1_board.create('point', [4.5, 2.0]); - * var slex1_p2 = slex1_board.create('point', [1.0, 1.0]); - * var slex1_l1 = slex1_board.create('segment', [slex1_p1, slex1_p2]); - * </script><pre> - * - * @example - * // Create a segment providing two points. - * var p1 = board.create('point', [4.0, 1.0]); - * var p2 = board.create('point', [1.0, 1.0]); - * var l1 = board.create('segment', [p1, p2]); - * var p3 = board.create('point', [4.0, 2.0]); - * var p4 = board.create('point', [1.0, 2.0]); - * var l2 = board.create('segment', [p3, p4, 3]); - * var p5 = board.create('point', [4.0, 3.0]); - * var p6 = board.create('point', [1.0, 4.0]); - * var l3 = board.create('segment', [p5, p6, function(){ return l1.L();} ]); - * </pre><div class="jxgbox" id="JXG617336ba-0705-4b2b-a236-c87c28ef25be" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * var slex2_board = JXG.JSXGraph.initBoard('JXG617336ba-0705-4b2b-a236-c87c28ef25be', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}); - * var slex2_p1 = slex2_board.create('point', [4.0, 1.0]); - * var slex2_p2 = slex2_board.create('point', [1.0, 1.0]); - * var slex2_l1 = slex2_board.create('segment', [slex2_p1, slex2_p2]); - * var slex2_p3 = slex2_board.create('point', [4.0, 2.0]); - * var slex2_p4 = slex2_board.create('point', [1.0, 2.0]); - * var slex2_l2 = slex2_board.create('segment', [slex2_p3, slex2_p4, 3]); - * var slex2_p5 = slex2_board.create('point', [4.0, 2.0]); - * var slex2_p6 = slex2_board.create('point', [1.0, 2.0]); - * var slex2_l3 = slex2_board.create('segment', [slex2_p5, slex2_p6, function(){ return slex2_l1.L();}]); - * </script><pre> - * - */ - JXG.createSegment = function (board, parents, attributes) { - var el, attr; + if (!Type.exists(this.highlightedObjects[pId])) { // highlight only if not highlighted + overObjects[pId] = pEl; + pEl.highlight(); + // triggers board event. + this.triggerEventHandlers(['mousehit', 'hit'], [evt, pEl, target]); + } - attributes.straightFirst = false; - attributes.straightLast = false; - attr = Type.copyAttributes(attributes, board.options, 'segment'); + if (pEl.mouseover) { + pEl.triggerEventHandlers(['mousemove', 'move'], [evt]); + } else { + pEl.triggerEventHandlers(['mouseover', 'over'], [evt]); + pEl.mouseover = true; + } + } + } - el = board.create('line', parents.slice(0, 2), attr); + for (el = 0; el < len; el++) { + pEl = this.objectsList[el]; + pId = pEl.id; + if (pEl.mouseover) { + if (!overObjects[pId]) { + pEl.triggerEventHandlers(['mouseout', 'out'], [evt]); + pEl.mouseover = false; + } + } + } + }, - if (parents.length === 3) { - el.hasFixedLength = true; + /** + * Helper function which returns a reasonable starting point for the object being dragged. + * Formerly known as initXYstart(). + * @private + * @param {JXG.GeometryElement} obj The object to be dragged + * @param {Array} targets Array of targets. It is changed by this function. + */ + saveStartPos: function (obj, targets) { + var xy = [], i, len; - if (Type.isNumber(parents[2])) { - el.fixedLength = function () { - return parents[2]; - }; - } else if (Type.isFunction(parents[2])) { - el.fixedLength = parents[2]; + if (obj.type === Const.OBJECT_TYPE_TICKS) { + xy.push([1, NaN, NaN]); + } else if (obj.elementClass === Const.OBJECT_CLASS_LINE) { + xy.push(obj.point1.coords.usrCoords); + xy.push(obj.point2.coords.usrCoords); + } else if (obj.elementClass === Const.OBJECT_CLASS_CIRCLE) { + xy.push(obj.center.coords.usrCoords); + if (obj.method === 'twoPoints') { + xy.push(obj.point2.coords.usrCoords); + } + } else if (obj.type === Const.OBJECT_TYPE_POLYGON) { + len = obj.vertices.length - 1; + for (i = 0; i < len; i++) { + xy.push(obj.vertices[i].coords.usrCoords); + } + } else if (obj.type === Const.OBJECT_TYPE_SECTOR) { + xy.push(obj.point1.coords.usrCoords); + xy.push(obj.point2.coords.usrCoords); + xy.push(obj.point3.coords.usrCoords); + } else if (Type.isPoint(obj) || obj.type === Const.OBJECT_TYPE_GLIDER) { + xy.push(obj.coords.usrCoords); + } else if (obj.elementClass === Const.OBJECT_CLASS_CURVE) { + // if (Type.exists(obj.parents)) { + // len = obj.parents.length; + // if (len > 0) { + // for (i = 0; i < len; i++) { + // xy.push(this.select(obj.parents[i]).coords.usrCoords); + // } + // } else + // } + if (obj.points.length > 0) { + xy.push(obj.points[0].usrCoords); + } } else { - throw new Error("JSXGraph: Can't create segment with third parent type '" + - (typeof parents[2]) + "'." + - "\nPossible third parent types: number or function"); + try { + xy.push(obj.coords.usrCoords); + } catch (e) { + JXG.debug('JSXGraph+ saveStartPos: obj.coords.usrCoords not available: ' + e); + } } - el.getParents = function() { - return this.parents.concat(this.fixedLength()); - }; - - el.fixedLengthOldCoords = []; - el.fixedLengthOldCoords[0] = new Coords(Const.COORDS_BY_USER, el.point1.coords.usrCoords.slice(1, 3), board); - el.fixedLengthOldCoords[1] = new Coords(Const.COORDS_BY_USER, el.point2.coords.usrCoords.slice(1, 3), board); - } - - el.elType = 'segment'; - - return el; - }; + len = xy.length; + for (i = 0; i < len; i++) { + targets.Zstart.push(xy[i][0]); + targets.Xstart.push(xy[i][1]); + targets.Ystart.push(xy[i][2]); + } + }, - JXG.registerElement('segment', JXG.createSegment); + mouseOriginMoveStart: function (evt) { + var r, pos; - /** - * @class This element is used to provide a constructor for arrow, which is just a wrapper for element - * {@link Line} with {@link Line#straightFirst} - * and {@link Line#straightLast} properties set to false and {@link Line#lastArrow} set to true. - * @pseudo - * @description - * @name Arrow - * @augments JXG.Line - * @constructor - * @type JXG.Line - * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {JXG.Point,array_JXG.Point,array} point1,point2 Parent elements can be two elements either of type {@link JXG.Point} or array of numbers describing the - * coordinates of a point. In the latter case the point will be constructed automatically as a fixed invisible point. - * @param {Number_Number_Number} a,b,c A line can also be created providing three numbers. The line is then described by the set of solutions - * of the equation <tt>a*x+b*y+c*z = 0</tt>. - * @see Line - * @example - * // Create an arrow providing two points. - * var p1 = board.create('point', [4.5, 2.0]); - * var p2 = board.create('point', [1.0, 1.0]); - * var l1 = board.create('arrow', [p1, p2]); - * </pre><div class="jxgbox" id="JXG1d26bd22-7d6d-4018-b164-4c8bc8d22ccf" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * var alex1_board = JXG.JSXGraph.initBoard('JXG1d26bd22-7d6d-4018-b164-4c8bc8d22ccf', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}); - * var alex1_p1 = alex1_board.create('point', [4.5, 2.0]); - * var alex1_p2 = alex1_board.create('point', [1.0, 1.0]); - * var alex1_l1 = alex1_board.create('arrow', [alex1_p1, alex1_p2]); - * </script><pre> - */ - JXG.createArrow = function (board, parents, attributes) { - var el, attr; + r = this._isRequiredKeyPressed(evt, 'pan'); + if (r) { + pos = this.getMousePosition(evt); + this.initMoveOrigin(pos[0], pos[1]); + } - attributes.straightFirst = false; - attributes.straightLast = false; - attr = Type.copyAttributes(attributes, board.options, 'arrow'); - el = board.create('line', parents, attr); - //el.setArrow(false, true); - el.type = Const.OBJECT_TYPE_VECTOR; - el.elType = 'arrow'; + return r; + }, - return el; - }; + mouseOriginMove: function (evt) { + var r = (this.mode === this.BOARD_MODE_MOVE_ORIGIN), + pos; - JXG.registerElement('arrow', JXG.createArrow); + if (r) { + pos = this.getMousePosition(evt); + this.moveOrigin(pos[0], pos[1], true); + } - /** - * @class This element is used to provide a constructor for an axis. It's strictly spoken just a wrapper for element {@link Line} with {@link Line#straightFirst} - * and {@link Line#straightLast} properties set to true. Additionally {@link Line#lastArrow} is set to true and default {@link Ticks} will be created. - * @pseudo - * @description - * @name Axis - * @augments JXG.Line - * @constructor - * @type JXG.Line - * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {JXG.Point,array_JXG.Point,array} point1,point2 Parent elements can be two elements either of type {@link JXG.Point} or array of numbers describing the - * coordinates of a point. In the latter case, the point will be constructed automatically as a fixed invisible point. - * @param {Number_Number_Number} a,b,c A line can also be created providing three numbers. The line is then described by the set of solutions - * of the equation <tt>a*x+b*y+c*z = 0</tt>. - * @example - * // Create an axis providing two coord pairs. - * var l1 = board.create('axis', [[0.0, 1.0], [1.0, 1.3]]); - * </pre><div class="jxgbox" id="JXG4f414733-624c-42e4-855c-11f5530383ae" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * var axex1_board = JXG.JSXGraph.initBoard('JXG4f414733-624c-42e4-855c-11f5530383ae', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}); - * var axex1_l1 = axex1_board.create('axis', [[0.0, 1.0], [1.0, 1.3]]); - * </script><pre> - */ - JXG.createAxis = function (board, parents, attributes) { - var attr, attr_ticks, el, els, dist; + return r; + }, - // Arrays or points, that is all we need. - if ((Type.isArray(parents[0]) || Type.isPoint(parents[0])) && (Type.isArray(parents[1]) || Type.isPoint(parents[1]))) { + /** + * Start moving the origin with one finger. + * @private + * @param {Object} evt Event from touchStartListener + * @return {Boolean} returns if the origin is moved. + */ + touchStartMoveOriginOneFinger: function (evt) { + var touches = evt[JXG.touchProperty], + conditions, pos; - // Create line - attr = Type.copyAttributes(attributes, board.options, 'axis'); - el = board.create('line', parents, attr); - el.type = Const.OBJECT_TYPE_AXIS; - el.isDraggable = false; - el.point1.isDraggable = false; - el.point2.isDraggable = false; + conditions = this.attr.pan.enabled && + !this.attr.pan.needtwofingers && + touches.length === 1; - for (els in el.ancestors) { - if (el.ancestors.hasOwnProperty(els)) { - el.ancestors[els].type = Const.OBJECT_TYPE_AXISPOINT; - } + if (conditions) { + pos = this.getMousePosition(evt, 0); + this.initMoveOrigin(pos[0], pos[1]); } - // Create ticks - attr_ticks = Type.copyAttributes(attributes, board.options, 'axis', 'ticks'); - if (Type.exists(attr_ticks.ticksdistance)) { - dist = attr_ticks.ticksdistance; - } else if (Type.isArray(attr_ticks.ticks)) { - dist = attr_ticks.ticks; - } else { - dist = 1.0; - } + return conditions; + }, - /** - * The ticks attached to the axis. - * @memberOf Axis.prototype - * @name defaultTicks - * @type JXG.Ticks - */ - el.defaultTicks = board.create('ticks', [el, dist], attr_ticks); - el.defaultTicks.dump = false; - el.elType = 'axis'; - el.subs = { - ticks: el.defaultTicks - }; - el.inherits.push(el.defaultTicks); + /** + * Move the origin with one finger + * @private + * @param {Object} evt Event from touchMoveListener + * @return {Boolean} returns if the origin is moved. + */ + touchOriginMove: function (evt) { + var r = (this.mode === this.BOARD_MODE_MOVE_ORIGIN), + pos; - } else { - throw new Error("JSXGraph: Can't create axis with parent types '" + - (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + - "\nPossible parent types: [point,point], [[x1,y1],[x2,y2]]"); - } + if (r) { + pos = this.getMousePosition(evt, 0); + this.moveOrigin(pos[0], pos[1], true); + } - return el; - }; + return r; + }, - JXG.registerElement('axis', JXG.createAxis); + /** + * Stop moving the origin with one finger + * @return {null} null + * @private + */ + originMoveEnd: function () { + this.updateQuality = this.BOARD_QUALITY_HIGH; + this.mode = this.BOARD_MODE_NONE; + }, - /** - * @class With the element tangent the slope of a line, circle, or curve in a certain point can be visualized. A tangent is always constructed - * by a glider on a line, circle, or curve and describes the tangent in the glider point on that line, circle, or curve. - * @pseudo - * @description - * @name Tangent - * @augments JXG.Line - * @constructor - * @type JXG.Line - * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {Glider} g A glider on a line, circle, or curve. - * @example - * // Create a tangent providing a glider on a function graph - * var c1 = board.create('curve', [function(t){return t},function(t){return t*t*t;}]); - * var g1 = board.create('glider', [0.6, 1.2, c1]); - * var t1 = board.create('tangent', [g1]); - * </pre><div class="jxgbox" id="JXG7b7233a0-f363-47dd-9df5-4018d0d17a98" style="width: 400px; height: 400px;"></div> - * <script type="text/javascript"> - * var tlex1_board = JXG.JSXGraph.initBoard('JXG7b7233a0-f363-47dd-9df5-4018d0d17a98', {boundingbox: [-6, 6, 6, -6], axis: true, showcopyright: false, shownavigation: false}); - * var tlex1_c1 = tlex1_board.create('curve', [function(t){return t},function(t){return t*t*t;}]); - * var tlex1_g1 = tlex1_board.create('glider', [0.6, 1.2, tlex1_c1]); - * var tlex1_t1 = tlex1_board.create('tangent', [tlex1_g1]); - * </script><pre> - */ - JXG.createTangent = function (board, parents, attributes) { - var p, c, g, f, j, el, tangent; + /********************************************************** + * + * Event Handler + * + **********************************************************/ - // One argument: glider on line, circle or curve - if (parents.length === 1) { - p = parents[0]; - c = p.slideObject; - // Two arguments: (point,F"|conic) or (line|curve|circle|conic,point). // Not yet: curve! - } else if (parents.length === 2) { - // In fact, for circles and conics it is the polar - if (Type.isPoint(parents[0])) { - p = parents[0]; - c = parents[1]; - } else if (Type.isPoint(parents[1])) { - c = parents[0]; - p = parents[1]; + /** + * Add all possible event handlers to the board object + */ + addEventHandlers: function () { + if (Env.supportsPointerEvents()) { + this.addPointerEventHandlers(); } else { - throw new Error("JSXGraph: Can't create tangent with parent types '" + - (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + - "\nPossible parent types: [glider], [point,line|curve|circle|conic]"); + this.addMouseEventHandlers(); + this.addTouchEventHandlers(); } - } else { - throw new Error("JSXGraph: Can't create tangent with parent types '" + - (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + - "\nPossible parent types: [glider], [point,line|curve|circle|conic]"); - } - if (c.elementClass === Const.OBJECT_CLASS_LINE) { - tangent = board.create('line', [c.point1, c.point2], attributes); - tangent.glider = p; - } else if (c.elementClass === Const.OBJECT_CLASS_CURVE && c.type !== Const.OBJECT_TYPE_CONIC) { - if (Type.evaluate(c.visProp.curvetype) !== 'plot') { - tangent = board.create('line', [ - function () { - var g = c.X, - f = c.Y; - return -p.X() * Numerics.D(f)(p.position) + p.Y() * Numerics.D(g)(p.position); - }, - function () { - return Numerics.D(c.Y)(p.position); - }, - function () { - return -Numerics.D(c.X)(p.position); + // This one produces errors on IE + //Env.addEvent(this.containerObj, 'contextmenu', function (e) { e.preventDefault(); return false;}, this); + // This one works on IE, Firefox and Chromium with default configurations. On some Safari + // or Opera versions the user must explicitly allow the deactivation of the context menu. + if (this.containerObj !== null) { + this.containerObj.oncontextmenu = function (e) { + if (Type.exists(e)) { + e.preventDefault(); } - ], attributes); + return false; + }; + } - p.addChild(tangent); - // this is required for the geogebra reader to display a slope - tangent.glider = p; - } else { // curveType 'plot' - // equation of the line segment: 0 = y*(x1-x2) + x*(y2-y1) + y1*x2-x1*y2 - tangent = board.create('line', [ - function () { - var i = Math.floor(p.position), - p1, p2; + this.addFullscreenEventHandlers(); + this.addKeyboardEventHandlers(); - if (i === c.numberPoints - 1) { - i--; - } + if (Env.isBrowser) { + try { + // resizeObserver: triggered if size of the JSXGraph div changes. + this.startResizeObserver(); + } catch (err) { + // resize event: triggered if size of window changes + Env.addEvent(window, 'resize', this.resizeListener, this); + // intersectionObserver: triggered if JSXGraph becomes visible. + this.startIntersectionObserver(); + } + // Scroll event: needs to be captured since on mobile devices + // sometimes a header bar is displayed / hidden, which triggers a + // resize event. + Env.addEvent(window, 'scroll', this.scrollListener, this); + } + }, - if (i < 0) { - return 1; - } + /** + * Remove all event handlers from the board object + */ + removeEventHandlers: function () { + this.removeMouseEventHandlers(); + this.removeTouchEventHandlers(); + this.removePointerEventHandlers(); - // The curve points are transformed (if there is a transformation) - // c.X(i) is not transformed. - p1 = c.points[i].usrCoords; - p2 = c.points[i + 1].usrCoords; - return p1[2] * p2[1] - p1[1] * p2[2]; - //return c.Y(i) * c.X(i + 1) - c.X(i) * c.Y(i + 1); - }, - function () { - var i = Math.floor(p.position), - p1, p2; + this.removeFullscreenEventHandlers(); + this.removeKeyboardEventHandlers(); + if (Env.isBrowser) { + if (Type.exists(this.resizeObserver)) { + this.stopResizeObserver(); + } else { + Env.removeEvent(window, 'resize', this.resizeListener, this); + this.stopIntersectionObserver(); + } + Env.removeEvent(window, 'scroll', this.scrollListener, this); + } + }, - if (i === c.numberPoints - 1) { - i--; - } + /** + * Registers the MSPointer* event handlers. + */ + addPointerEventHandlers: function () { + if (!this.hasPointerHandlers && Env.isBrowser) { + var moveTarget = this.attr.movetarget || this.containerObj; - if (i < 0) { - return 0; - } + if (window.navigator.msPointerEnabled) { // IE10- + Env.addEvent(this.containerObj, 'MSPointerDown', this.pointerDownListener, this); + Env.addEvent(moveTarget, 'MSPointerMove', this.pointerMoveListener, this); + } else { + Env.addEvent(this.containerObj, 'pointerdown', this.pointerDownListener, this); + Env.addEvent(moveTarget, 'pointermove', this.pointerMoveListener, this); + } + Env.addEvent(this.containerObj, 'mousewheel', this.mouseWheelListener, this); + Env.addEvent(this.containerObj, 'DOMMouseScroll', this.mouseWheelListener, this); - // The curve points are transformed (if there is a transformation) - // c.X(i) is not transformed. - p1 = c.points[i].usrCoords; - p2 = c.points[i + 1].usrCoords; - return p2[2] - p1[2]; - // return c.Y(i + 1) - c.Y(i); - }, - function () { - var i = Math.floor(p.position), - p1, p2; + if (this.containerObj !== null) { + // This is needed for capturing touch events. + // It is also in jsxgraph.css, but one never knows... + this.containerObj.style.touchAction = 'none'; + } - if (i === c.numberPoints - 1) { - i--; - } + this.hasPointerHandlers = true; + } + }, - if (i < 0) { - return 0.0; - } + /** + * Registers mouse move, down and wheel event handlers. + */ + addMouseEventHandlers: function () { + if (!this.hasMouseHandlers && Env.isBrowser) { + var moveTarget = this.attr.movetarget || this.containerObj; - // The curve points are transformed (if there is a transformation) - // c.X(i) is not transformed. - p1 = c.points[i].usrCoords; - p2 = c.points[i + 1].usrCoords; - return p1[1] - p2[1]; - // return c.X(i) - c.X(i + 1); - }], attributes); + Env.addEvent(this.containerObj, 'mousedown', this.mouseDownListener, this); + Env.addEvent(moveTarget, 'mousemove', this.mouseMoveListener, this); - p.addChild(tangent); - // this is required for the geogebra reader to display a slope - tangent.glider = p; - } - } else if (c.type === Const.OBJECT_TYPE_TURTLE) { - tangent = board.create('line', [ - function () { - var i = Math.floor(p.position); + Env.addEvent(this.containerObj, 'mousewheel', this.mouseWheelListener, this); + Env.addEvent(this.containerObj, 'DOMMouseScroll', this.mouseWheelListener, this); - // run through all curves of this turtle - for (j = 0; j < c.objects.length; j++) { - el = c.objects[j]; + this.hasMouseHandlers = true; + } + }, - if (el.type === Const.OBJECT_TYPE_CURVE) { - if (i < el.numberPoints) { - break; - } + /** + * Register touch start and move and gesture start and change event handlers. + * @param {Boolean} appleGestures If set to false the gesturestart and gesturechange event handlers + * will not be registered. + * + * Since iOS 13, touch events were abandoned in favour of pointer events + */ + addTouchEventHandlers: function (appleGestures) { + if (!this.hasTouchHandlers && Env.isBrowser) { + var moveTarget = this.attr.movetarget || this.containerObj; - i -= el.numberPoints; - } - } + Env.addEvent(this.containerObj, 'touchstart', this.touchStartListener, this); + Env.addEvent(moveTarget, 'touchmove', this.touchMoveListener, this); - if (i === el.numberPoints - 1) { - i--; - } + /* + if (!Type.exists(appleGestures) || appleGestures) { + // Gesture listener are called in touchStart and touchMove. + //Env.addEvent(this.containerObj, 'gesturestart', this.gestureStartListener, this); + //Env.addEvent(this.containerObj, 'gesturechange', this.gestureChangeListener, this); + } + */ - if (i < 0) { - return 1; - } + this.hasTouchHandlers = true; + } + }, - return el.Y(i) * el.X(i + 1) - el.X(i) * el.Y(i + 1); - }, - function () { - var i = Math.floor(p.position); + /** + * Add fullscreen events which update the CSS transformation matrix to correct + * the mouse/touch/pointer positions in case of CSS transformations. + */ + addFullscreenEventHandlers: function() { + var i, + // standard/Edge, firefox, chrome/safari, IE11 + events = ['fullscreenchange', 'mozfullscreenchange', 'webkitfullscreenchange', 'msfullscreenchange'], + le = events.length; - // run through all curves of this turtle - for (j = 0; j < c.objects.length; j++) { - el = c.objects[j]; + if (!this.hasFullsceenEventHandlers && Env.isBrowser) { + for (i = 0; i < le; i++) { + Env.addEvent(this.document, events[i], this.fullscreenListener, this); + } + this.hasFullsceenEventHandlers = true; + } + }, - if (el.type === Const.OBJECT_TYPE_CURVE) { - if (i < el.numberPoints) { - break; - } + addKeyboardEventHandlers: function() { + if (this.attr.keyboard.enabled && !this.hasKeyboardHandlers && Env.isBrowser) { + Env.addEvent(this.containerObj, 'keydown', this.keyDownListener, this); + Env.addEvent(this.containerObj, 'focusin', this.keyFocusInListener, this); + Env.addEvent(this.containerObj, 'focusout', this.keyFocusOutListener, this); + this.hasKeyboardHandlers = true; + } + }, - i -= el.numberPoints; - } - } + /** + * Remove all registered touch event handlers. + */ + removeKeyboardEventHandlers: function () { + if (this.hasKeyboardHandlers && Env.isBrowser) { + Env.removeEvent(this.containerObj, 'keydown', this.keyDownListener, this); + Env.removeEvent(this.containerObj, 'focusin', this.keyFocusInListener, this); + Env.removeEvent(this.containerObj, 'focusout', this.keyFocusOutListener, this); + this.hasKeyboardHandlers = false; + } + }, - if (i === el.numberPoints - 1) { - i--; - } - if (i < 0) { - return 0; - } + /** + * Remove all registered event handlers regarding fullscreen mode. + */ + removeFullscreenEventHandlers: function() { + var i, + // standard/Edge, firefox, chrome/safari, IE11 + events = ['fullscreenchange', 'mozfullscreenchange', 'webkitfullscreenchange', 'msfullscreenchange'], + le = events.length; - return el.Y(i + 1) - el.Y(i); - }, - function () { - var i = Math.floor(p.position); + if (this.hasFullsceenEventHandlers && Env.isBrowser) { + for (i = 0; i < le; i++) { + Env.removeEvent(this.document, events[i], this.fullscreenListener, this); + } + this.hasFullsceenEventHandlers = false; + } + }, - // run through all curves of this turtle - for (j = 0; j < c.objects.length; j++) { - el = c.objects[j]; - if (el.type === Const.OBJECT_TYPE_CURVE) { - if (i < el.numberPoints) { - break; - } - i -= el.numberPoints; - } - } - if (i === el.numberPoints - 1) { - i--; - } + /** + * Remove MSPointer* Event handlers. + */ + removePointerEventHandlers: function () { + if (this.hasPointerHandlers && Env.isBrowser) { + var moveTarget = this.attr.movetarget || this.containerObj; - if (i < 0) { - return 0; + if (window.navigator.msPointerEnabled) { // IE10- + Env.removeEvent(this.containerObj, 'MSPointerDown', this.pointerDownListener, this); + Env.removeEvent(moveTarget, 'MSPointerMove', this.pointerMoveListener, this); + } else { + Env.removeEvent(this.containerObj, 'pointerdown', this.pointerDownListener, this); + Env.removeEvent(moveTarget, 'pointermove', this.pointerMoveListener, this); + } + + Env.removeEvent(this.containerObj, 'mousewheel', this.mouseWheelListener, this); + Env.removeEvent(this.containerObj, 'DOMMouseScroll', this.mouseWheelListener, this); + + if (this.hasPointerUp) { + if (window.navigator.msPointerEnabled) { // IE10- + Env.removeEvent(this.document, 'MSPointerUp', this.pointerUpListener, this); + } else { + Env.removeEvent(this.document, 'pointerup', this.pointerUpListener, this); + Env.removeEvent(this.document, 'pointercancel', this.pointerUpListener, this); } + this.hasPointerUp = false; + } - return el.X(i) - el.X(i + 1); - }], attributes); - p.addChild(tangent); + this.hasPointerHandlers = false; + } + }, - // this is required for the geogebra reader to display a slope - tangent.glider = p; - } else if (c.elementClass === Const.OBJECT_CLASS_CIRCLE || c.type === Const.OBJECT_TYPE_CONIC) { - // If p is not on c, the tangent is the polar. - // This construction should work on conics, too. p has to lie on c. - tangent = board.create('line', [ - function () { - return Mat.matVecMult(c.quadraticform, p.coords.usrCoords)[0]; - }, - function () { - return Mat.matVecMult(c.quadraticform, p.coords.usrCoords)[1]; - }, - function () { - return Mat.matVecMult(c.quadraticform, p.coords.usrCoords)[2]; - }], attributes); + /** + * De-register mouse event handlers. + */ + removeMouseEventHandlers: function () { + if (this.hasMouseHandlers && Env.isBrowser) { + var moveTarget = this.attr.movetarget || this.containerObj; - p.addChild(tangent); - // this is required for the geogebra reader to display a slope - tangent.glider = p; - } + Env.removeEvent(this.containerObj, 'mousedown', this.mouseDownListener, this); + Env.removeEvent(moveTarget, 'mousemove', this.mouseMoveListener, this); - if (!Type.exists(tangent)) { - throw new Error('JSXGraph: Couldn\'t create tangent with the given parents.'); - } + if (this.hasMouseUp) { + Env.removeEvent(this.document, 'mouseup', this.mouseUpListener, this); + this.hasMouseUp = false; + } - tangent.elType = 'tangent'; - tangent.type = Const.OBJECT_TYPE_TANGENT; - tangent.setParents(parents); + Env.removeEvent(this.containerObj, 'mousewheel', this.mouseWheelListener, this); + Env.removeEvent(this.containerObj, 'DOMMouseScroll', this.mouseWheelListener, this); - return tangent; - }; + this.hasMouseHandlers = false; + } + }, - /** - * @class This element is used to provide a constructor for the radical axis with respect to two circles with distinct centers. - * The angular bisector of the polar lines of the circle centers with respect to the other circle is always the radical axis. - * The radical axis passes through the intersection points when the circles intersect. - * When a circle about the midpoint of circle centers, passing through the circle centers, intersects the circles, the polar lines pass through those intersection points. - * @pseudo - * @description - * @name RadicalAxis - * @augments JXG.Line - * @constructor - * @type JXG.Line - * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {JXG.Circle} circle Circle one of the two respective circles. - * @param {JXG.Circle} circle Circle the other of the two respective circles. - * @example - * // Create the radical axis line with respect to two circles - * var board = JXG.JSXGraph.initBoard('7b7233a0-f363-47dd-9df5-5018d0d17a98', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); - * var p1 = board.create('point', [2, 3]); - * var p2 = board.create('point', [1, 4]); - * var c1 = board.create('circle', [p1, p2]); - * var p3 = board.create('point', [6, 5]); - * var p4 = board.create('point', [8, 6]); - * var c2 = board.create('circle', [p3, p4]); - * var r1 = board.create('radicalaxis', [c1, c2]); - * </pre><div class="jxgbox" id="JXG7b7233a0-f363-47dd-9df5-5018d0d17a98" class="jxgbox" style="width:400px; height:400px;"></div> - * <script type='text/javascript'> - * var rlex1_board = JXG.JSXGraph.initBoard('JXG7b7233a0-f363-47dd-9df5-5018d0d17a98', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); - * var rlex1_p1 = rlex1_board.create('point', [2, 3]); - * var rlex1_p2 = rlex1_board.create('point', [1, 4]); - * var rlex1_c1 = rlex1_board.create('circle', [rlex1_p1, rlex1_p2]); - * var rlex1_p3 = rlex1_board.create('point', [6, 5]); - * var rlex1_p4 = rlex1_board.create('point', [8, 6]); - * var rlex1_c2 = rlex1_board.create('circle', [rlex1_p3, rlex1_p4]); - * var rlex1_r1 = rlex1_board.create('radicalaxis', [rlex1_c1, rlex1_c2]); - * </script><pre> - */ - JXG.createRadicalAxis = function (board, parents, attributes) { - var el, el1, el2; + /** + * Remove all registered touch event handlers. + */ + removeTouchEventHandlers: function () { + if (this.hasTouchHandlers && Env.isBrowser) { + var moveTarget = this.attr.movetarget || this.containerObj; - if (parents.length !== 2 || - parents[0].elementClass !== Const.OBJECT_CLASS_CIRCLE || - parents[1].elementClass !== Const.OBJECT_CLASS_CIRCLE) { - // Failure - throw new Error("JSXGraph: Can't create 'radical axis' with parent types '" + - (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + - "\nPossible parent type: [circle,circle]"); - } + Env.removeEvent(this.containerObj, 'touchstart', this.touchStartListener, this); + Env.removeEvent(moveTarget, 'touchmove', this.touchMoveListener, this); - el1 = board.select(parents[0]); - el2 = board.select(parents[1]); + if (this.hasTouchEnd) { + Env.removeEvent(this.document, 'touchend', this.touchEndListener, this); + this.hasTouchEnd = false; + } - el = board.create('line', [function () { - var a = el1.stdform, - b = el2.stdform; + this.hasTouchHandlers = false; + } + }, - return Mat.matVecMult(Mat.transpose([a.slice(0, 3), b.slice(0, 3)]), [b[3], -a[3]]); - }], attributes); + /** + * Handler for click on left arrow in the navigation bar + * @returns {JXG.Board} Reference to the board + */ + clickLeftArrow: function () { + this.moveOrigin(this.origin.scrCoords[1] + this.canvasWidth * 0.1, this.origin.scrCoords[2]); + return this; + }, - el.elType = 'radicalaxis'; - el.setParents([el1.id, el2.id]); + /** + * Handler for click on right arrow in the navigation bar + * @returns {JXG.Board} Reference to the board + */ + clickRightArrow: function () { + this.moveOrigin(this.origin.scrCoords[1] - this.canvasWidth * 0.1, this.origin.scrCoords[2]); + return this; + }, - el1.addChild(el); - el2.addChild(el); + /** + * Handler for click on up arrow in the navigation bar + * @returns {JXG.Board} Reference to the board + */ + clickUpArrow: function () { + this.moveOrigin(this.origin.scrCoords[1], this.origin.scrCoords[2] - this.canvasHeight * 0.1); + return this; + }, - return el; - }; + /** + * Handler for click on down arrow in the navigation bar + * @returns {JXG.Board} Reference to the board + */ + clickDownArrow: function () { + this.moveOrigin(this.origin.scrCoords[1], this.origin.scrCoords[2] + this.canvasHeight * 0.1); + return this; + }, - /** - * @class This element is used to provide a constructor for the polar line of a point with respect to a conic or a circle. - * @pseudo - * @description The polar line is the unique reciprocal relationship of a point with respect to a conic. - * The lines through the intersections of a conic and the polar line of a point with respect to that conic and through that point are tangent to the conic. - * A point on a conic has the polar line of that point with respect to that conic as the tangent line to that conic at that point. - * See {@link http://en.wikipedia.org/wiki/Pole_and_polar} for more information on pole and polar. - * @name PolarLine - * @augments JXG.Line - * @constructor - * @type JXG.Line - * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {JXG.Conic,JXG.Circle_JXG.Point} el1,el2 or - * @param {JXG.Point_JXG.Conic,JXG.Circle} el1,el2 The result will be the polar line of the point with respect to the conic or the circle. - * @example - * // Create the polar line of a point with respect to a conic - * var p1 = board.create('point', [-1, 2]); - * var p2 = board.create('point', [ 1, 4]); - * var p3 = board.create('point', [-1,-2]); - * var p4 = board.create('point', [ 0, 0]); - * var p5 = board.create('point', [ 4,-2]); - * var c1 = board.create('conic',[p1,p2,p3,p4,p5]); - * var p6 = board.create('point', [-1, 1]); - * var l1 = board.create('polarline', [c1, p6]); - * </pre><div class="jxgbox" id="JXG7b7233a0-f363-47dd-9df5-6018d0d17a98" class="jxgbox" style="width:400px; height:400px;"></div> - * <script type='text/javascript'> - * var plex1_board = JXG.JSXGraph.initBoard('JXG7b7233a0-f363-47dd-9df5-6018d0d17a98', {boundingbox: [-3, 5, 5, -3], axis: true, showcopyright: false, shownavigation: false}); - * var plex1_p1 = plex1_board.create('point', [-1, 2]); - * var plex1_p2 = plex1_board.create('point', [ 1, 4]); - * var plex1_p3 = plex1_board.create('point', [-1,-2]); - * var plex1_p4 = plex1_board.create('point', [ 0, 0]); - * var plex1_p5 = plex1_board.create('point', [ 4,-2]); - * var plex1_c1 = plex1_board.create('conic',[plex1_p1,plex1_p2,plex1_p3,plex1_p4,plex1_p5]); - * var plex1_p6 = plex1_board.create('point', [-1, 1]); - * var plex1_l1 = plex1_board.create('polarline', [plex1_c1, plex1_p6]); - * </script><pre> - * @example - * // Create the polar line of a point with respect to a circle. - * var p1 = board.create('point', [ 1, 1]); - * var p2 = board.create('point', [ 2, 3]); - * var c1 = board.create('circle',[p1,p2]); - * var p3 = board.create('point', [ 6, 6]); - * var l1 = board.create('polarline', [c1, p3]); - * </pre><div class="jxgbox" id="JXG7b7233a0-f363-47dd-9df5-7018d0d17a98" class="jxgbox" style="width:400px; height:400px;"></div> - * <script type='text/javascript'> - * var plex2_board = JXG.JSXGraph.initBoard('JXG7b7233a0-f363-47dd-9df5-7018d0d17a98', {boundingbox: [-3, 7, 7, -3], axis: true, showcopyright: false, shownavigation: false}); - * var plex2_p1 = plex2_board.create('point', [ 1, 1]); - * var plex2_p2 = plex2_board.create('point', [ 2, 3]); - * var plex2_c1 = plex2_board.create('circle',[plex2_p1,plex2_p2]); - * var plex2_p3 = plex2_board.create('point', [ 6, 6]); - * var plex2_l1 = plex2_board.create('polarline', [plex2_c1, plex2_p3]); - * </script><pre> - */ - JXG.createPolarLine = function (board, parents, attributes) { - var el, el1, el2, - firstParentIsConic, secondParentIsConic, - firstParentIsPoint, secondParentIsPoint; + /** + * Triggered on iOS/Safari while the user inputs a gesture (e.g. pinch) and is used to zoom into the board. + * Works on iOS/Safari and Android. + * @param {Event} evt Browser event object + * @returns {Boolean} + */ + gestureChangeListener: function (evt) { + var c, + dir1 = [], + dir2 = [], + angle, + mi = 10, + isPinch = false, + // Save zoomFactors + zx = this.attr.zoom.factorx, + zy = this.attr.zoom.factory, + factor, + dist, + dx, dy, theta, cx, cy, bound; - if (parents.length > 1) { - firstParentIsConic = (parents[0].type === Const.OBJECT_TYPE_CONIC || - parents[0].elementClass === Const.OBJECT_CLASS_CIRCLE); - secondParentIsConic = (parents[1].type === Const.OBJECT_TYPE_CONIC || - parents[1].elementClass === Const.OBJECT_CLASS_CIRCLE); + if (this.mode !== this.BOARD_MODE_ZOOM) { + return true; + } + evt.preventDefault(); - firstParentIsPoint = (Type.isPoint(parents[0])); - secondParentIsPoint = (Type.isPoint(parents[1])); - } + dist = Geometry.distance([evt.touches[0].clientX, evt.touches[0].clientY], + [evt.touches[1].clientX, evt.touches[1].clientY], 2); - if (parents.length !== 2 || - !((firstParentIsConic && secondParentIsPoint) || - (firstParentIsPoint && secondParentIsConic))) { - // Failure - throw new Error("JSXGraph: Can't create 'polar line' with parent types '" + - (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + - "\nPossible parent type: [conic|circle,point], [point,conic|circle]"); - } + // Android pinch to zoom + // evt.scale was available in iOS touch events (pre iOS 13) + // evt.scale is undefined in Android + if (evt.scale === undefined) { + evt.scale = dist / this.prevDist; + } - if (secondParentIsPoint) { - el1 = board.select(parents[0]); - el2 = board.select(parents[1]); - } else { - el1 = board.select(parents[1]); - el2 = board.select(parents[0]); - } + if (!Type.exists(this.prevCoords)) { + return false; + } + // Compute the angle of the two finger directions + dir1 = [evt.touches[0].clientX - this.prevCoords[0][0], + evt.touches[0].clientY - this.prevCoords[0][1]]; + dir2 = [evt.touches[1].clientX - this.prevCoords[1][0], + evt.touches[1].clientY - this.prevCoords[1][1]]; - // Polar lines have been already provided in the tangent element. - el = board.create('tangent', [el1, el2], attributes); + if ((dir1[0] * dir1[0] + dir1[1] * dir1[1] < mi * mi) && + (dir2[0] * dir2[0] + dir2[1] * dir2[1] < mi * mi)) { + return false; + } - el.elType = 'polarline'; - return el; - }; + angle = Geometry.rad(dir1, [0,0], dir2); + if (this.isPreviousGesture !== 'pan' && + Math.abs(angle) > Math.PI * 0.2 && + Math.abs(angle) < Math.PI * 1.8) { + isPinch = true; + } - /** - * Register the element type tangent at JSXGraph - * @private - */ - JXG.registerElement('tangent', JXG.createTangent); - JXG.registerElement('polar', JXG.createTangent); - JXG.registerElement('radicalaxis', JXG.createRadicalAxis); - JXG.registerElement('polarline', JXG.createPolarLine); + if (this.isPreviousGesture !== 'pan' && !isPinch) { + if (Math.abs(evt.scale) < 0.77 || Math.abs(evt.scale) > 1.3) { + isPinch = true; + } + } - return { - Line: JXG.Line, - createLine: JXG.createLine, - createTangent: JXG.createTangent, - createPolar: JXG.createTangent, - createSegment: JXG.createSegment, - createAxis: JXG.createAxis, - createArrow: JXG.createArrow, - createRadicalAxis: JXG.createRadicalAxis, - createPolarLine: JXG.createPolarLine - }; -}); + factor = evt.scale / this.prevScale; + this.prevScale = evt.scale; + this.prevCoords = [[evt.touches[0].clientX, evt.touches[0].clientY], + [evt.touches[1].clientX, evt.touches[1].clientY]]; -/* - Copyright 2008-2021 - Matthias Ehmann, - Michael Gerhaeuser, - Carsten Miller, - Bianca Valentin, - Alfred Wassermann, - Peter Wilfahrt + c = new Coords(Const.COORDS_BY_SCREEN, this.getMousePosition(evt, 0), this); - This file is part of JSXGraph. + if (this.attr.pan.enabled && + this.attr.pan.needtwofingers && + !isPinch) { + // Pan detected - JSXGraph is free software dual licensed under the GNU LGPL or MIT License. + this.isPreviousGesture = 'pan'; - You can redistribute it and/or modify it under the terms of the + this.moveOrigin(c.scrCoords[1], c.scrCoords[2], true); + } else if (this.attr.zoom.enabled && + Math.abs(factor - 1.0) < 0.5) { + // Pinch detected - * GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version - OR - * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT + if (this.attr.zoom.pinchhorizontal || this.attr.zoom.pinchvertical) { + dx = Math.abs(evt.touches[0].clientX - evt.touches[1].clientX); + dy = Math.abs(evt.touches[0].clientY - evt.touches[1].clientY); + theta = Math.abs(Math.atan2(dy, dx)); + bound = Math.PI * this.attr.zoom.pinchsensitivity / 90.0; + } - JSXGraph is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. + if (this.attr.zoom.pinchhorizontal && theta < bound) { + this.attr.zoom.factorx = factor; + this.attr.zoom.factory = 1.0; + cx = 0; + cy = 0; + } else if (this.attr.zoom.pinchvertical && Math.abs(theta - Math.PI * 0.5) < bound) { + this.attr.zoom.factorx = 1.0; + this.attr.zoom.factory = factor; + cx = 0; + cy = 0; + } else { + this.attr.zoom.factorx = factor; + this.attr.zoom.factory = factor; + cx = c.usrCoords[1]; + cy = c.usrCoords[2]; + } - You should have received a copy of the GNU Lesser General Public License and - the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> - and <http://opensource.org/licenses/MIT/>. - */ + this.zoomIn(cx, cy); + // Restore zoomFactors + this.attr.zoom.factorx = zx; + this.attr.zoom.factory = zy; + } -/*global JXG: true, define: true*/ -/*jslint nomen: true, plusplus: true*/ + return false; + }, -/* depends: - jxg - base/constants - base/coords - base/element - math/math - math/geometry - math/statistics - math/numerics - parser/geonext - utils/type - elements: - transform - */ - -/** - * @fileoverview In this file the geometry element Curve is defined. - */ - -define('base/curve',[ - 'jxg', 'base/constants', 'base/coords', 'base/element', 'math/math', 'math/numerics', - 'math/plot', 'math/geometry', 'parser/geonext', 'utils/type', 'math/qdt' -], function (JXG, Const, Coords, GeometryElement, Mat, Numerics, Plot, Geometry, GeonextParser, Type, QDT) { - - "use strict"; - - /** - * Curves are the common object for function graphs, parametric curves, polar curves, and data plots. - * @class Creates a new curve object. Do not use this constructor to create a curve. Use {@link JXG.Board#create} with - * type {@link Curve}, or {@link Functiongraph} instead. - * @augments JXG.GeometryElement - * @param {String|JXG.Board} board The board the new curve is drawn on. - * @param {Array} parents defining terms An array with the functon terms or the data points of the curve. - * @param {Object} attributes Defines the visual appearance of the curve. - * @see JXG.Board#generateName - * @see JXG.Board#addCurve - */ - JXG.Curve = function (board, parents, attributes) { - this.constructor(board, attributes, Const.OBJECT_TYPE_CURVE, Const.OBJECT_CLASS_CURVE); - - this.points = []; /** - * Number of points on curves. This value changes - * between numberPointsLow and numberPointsHigh. - * It is set in {@link JXG.Curve#updateCurve}. + * Called by iOS/Safari as soon as the user starts a gesture. Works natively on iOS/Safari, + * on Android we emulate it. + * @param {Event} evt + * @returns {Boolean} */ - this.numberPoints = Type.evaluate(this.visProp.numberpointshigh); - - this.bezierDegree = 1; + gestureStartListener: function (evt) { + var pos; - /** - * Array holding the x-coordinates of a data plot. - * This array can be updated during run time by overwriting - * the method {@link JXG.Curve#updateDataArray}. - * @type {array} - */ - this.dataX = null; + evt.preventDefault(); + this.prevScale = 1.0; + // Android pinch to zoom + this.prevDist = Geometry.distance([evt.touches[0].clientX, evt.touches[0].clientY], + [evt.touches[1].clientX, evt.touches[1].clientY], 2); + this.prevCoords = [[evt.touches[0].clientX, evt.touches[0].clientY], + [evt.touches[1].clientX, evt.touches[1].clientY]]; + this.isPreviousGesture = 'none'; - /** - * Array holding the y-coordinates of a data plot. - * This array can be updated during run time by overwriting - * the method {@link JXG.Curve#updateDataArray}. - * @type {array} - */ - this.dataY = null; + // If pinch-to-zoom is interpreted as panning + // we have to prepare move origin + pos = this.getMousePosition(evt, 0); + this.initMoveOrigin(pos[0], pos[1]); - /** - * Array of ticks storing all the ticks on this curve. Do not set this field directly and use - * {@link JXG.Curve#addTicks} and {@link JXG.Curve#removeTicks} to add and remove ticks to and - * from the curve. - * @type Array - * @see JXG.Ticks - */ - this.ticks = []; + this.mode = this.BOARD_MODE_ZOOM; + return false; + }, /** - * Stores a quad tree if it is required. The quad tree is generated in the curve - * updates and can be used to speed up the hasPoint method. - * @type {JXG.Math.Quadtree} + * Test if the required key combination is pressed for wheel zoom, move origin and + * selection + * @private + * @param {Object} evt Mouse or pen event + * @param {String} action String containing the action: 'zoom', 'pan', 'selection'. + * Corresponds to the attribute subobject. + * @return {Boolean} true or false. */ - this.qdt = null; - - if (Type.exists(parents[0])) { - this.varname = parents[0]; - } else { - this.varname = 'x'; - } - - // function graphs: "x" - this.xterm = parents[1]; - // function graphs: e.g. "x^2" - this.yterm = parents[2]; - - // Converts GEONExT syntax into JavaScript syntax - this.generateTerm(this.varname, this.xterm, this.yterm, parents[3], parents[4]); - // First evaluation of the curve - this.updateCurve(); - - this.id = this.board.setId(this, 'G'); - this.board.renderer.drawCurve(this); - - this.board.finalizeAdding(this); - - this.createGradient(); - this.elType = 'curve'; - this.createLabel(); - - if (Type.isString(this.xterm)) { - this.notifyParents(this.xterm); - } - if (Type.isString(this.yterm)) { - this.notifyParents(this.yterm); - } + _isRequiredKeyPressed: function (evt, action) { + var obj = this.attr[action]; + if (!obj.enabled) { + return false; + } - this.methodMap = Type.deepCopy(this.methodMap, { - generateTerm: 'generateTerm', - setTerm: 'generateTerm', - move: 'moveTo', - moveTo: 'moveTo' - }); - }; + if (((obj.needshift && evt.shiftKey) || (!obj.needshift && !evt.shiftKey)) && + ((obj.needctrl && evt.ctrlKey) || (!obj.needctrl && !evt.ctrlKey)) + ) { + return true; + } - JXG.Curve.prototype = new GeometryElement(); + return false; + }, - JXG.extend(JXG.Curve.prototype, /** @lends JXG.Curve.prototype */ { + /* + * Pointer events + */ /** - * Gives the default value of the left bound for the curve. - * May be overwritten in {@link JXG.Curve#generateTerm}. - * @returns {Number} Left bound for the curve. + * + * Check if pointer event is already registered in {@link JXG.Board#_board_touches}. + * + * @param {Object} evt Event object + * @return {Boolean} true if down event has already been sent. + * @private */ - minX: function () { - var leftCoords; + _isPointerRegistered: function(evt) { + var i, len = this._board_touches.length; - if (Type.evaluate(this.visProp.curvetype) === 'polar') { - return 0; + for (i = 0; i < len; i++) { + if (this._board_touches[i].pointerId === evt.pointerId) { + return true; + } } - - leftCoords = new Coords(Const.COORDS_BY_SCREEN, [-this.board.canvasWidth * 0.1, 0], this.board, false); - return leftCoords.usrCoords[1]; + return false; }, /** - * Gives the default value of the right bound for the curve. - * May be overwritten in {@link JXG.Curve#generateTerm}. - * @returns {Number} Right bound for the curve. + * + * Store the position of a pointer event. + * If not yet done, registers a pointer event in {@link JXG.Board#_board_touches}. + * Allows to follow the path of that finger on the screen. + * Only two simultaneous touches are supported. + * + * @param {Object} evt Event object + * @returns {JXG.Board} Reference to the board + * @private */ - maxX: function () { - var rightCoords; + _pointerStorePosition: function (evt) { + var i, found; - if (Type.evaluate(this.visProp.curvetype) === 'polar') { - return 2 * Math.PI; + for (i = 0, found = false; i < this._board_touches.length; i++) { + if (this._board_touches[i].pointerId === evt.pointerId) { + this._board_touches[i].clientX = evt.clientX; + this._board_touches[i].clientY = evt.clientY; + found = true; + break; + } } - rightCoords = new Coords(Const.COORDS_BY_SCREEN, [this.board.canvasWidth * 1.1, 0], this.board, false); - return rightCoords.usrCoords[1]; + // Restrict the number of simultaneous touches to 2 + if (!found && this._board_touches.length < 2) { + this._board_touches.push({ + pointerId: evt.pointerId, + clientX: evt.clientX, + clientY: evt.clientY + }); + } + + return this; }, /** - * The parametric function which defines the x-coordinate of the curve. - * @param {Number} t A number between {@link JXG.Curve#minX} and {@link JXG.Curve#maxX}. - * @param {Boolean} suspendUpdate A boolean flag which is false for the - * first call of the function during a fresh plot of the curve and true - * for all subsequent calls of the function. This may be used to speed up the - * plotting of the curve, if the e.g. the curve depends on some input elements. - * @returns {Number} x-coordinate of the curve at t. + * Deregisters a pointer event in {@link JXG.Board#_board_touches}. + * It happens if a finger has been lifted from the screen. + * + * @param {Object} evt Event object + * @returns {JXG.Board} Reference to the board + * @private */ - X: function (t) { - return NaN; + _pointerRemoveTouches: function (evt) { + var i; + for (i = 0; i < this._board_touches.length; i++) { + if (this._board_touches[i].pointerId === evt.pointerId) { + this._board_touches.splice(i, 1); + break; + } + } + + return this; }, /** - * The parametric function which defines the y-coordinate of the curve. - * @param {Number} t A number between {@link JXG.Curve#minX} and {@link JXG.Curve#maxX}. - * @param {Boolean} suspendUpdate A boolean flag which is false for the - * first call of the function during a fresh plot of the curve and true - * for all subsequent calls of the function. This may be used to speed up the - * plotting of the curve, if the e.g. the curve depends on some input elements. - * @returns {Number} y-coordinate of the curve at t. + * Remove all registered fingers from {@link JXG.Board#_board_touches}. + * This might be necessary if too many fingers have been registered. + * @returns {JXG.Board} Reference to the board + * @private */ - Y: function (t) { - return NaN; + _pointerClearTouches: function() { + if (this._board_touches.length > 0) { + this.dehighlightAll(); + } + this.updateQuality = this.BOARD_QUALITY_HIGH; + this.mode = this.BOARD_MODE_NONE; + this._board_touches = []; + this.touches = []; }, /** - * Treat the curve as curve with homogeneous coordinates. - * @param {Number} t A number between {@link JXG.Curve#minX} and {@link JXG.Curve#maxX}. - * @returns {Number} Always 1.0 + * Determine which input device is used for this action. + * Possible devices are 'touch', 'pen' and 'mouse'. + * This affects the precision and certain events. + * In case of no browser, 'mouse' is used. + * + * @see JXG.Board#pointerDownListener + * @see JXG.Board#pointerMoveListener + * @see JXG.Board#initMoveObject + * @see JXG.Board#moveObject + * + * @param {Event} evt The browsers event object. + * @returns {String} 'mouse', 'pen', or 'touch' + * @private */ - Z: function (t) { - return 1; + _getPointerInputDevice: function(evt) { + if (Env.isBrowser) { + if (evt.pointerType === 'touch' || // New + (window.navigator.msMaxTouchPoints && // Old + window.navigator.msMaxTouchPoints > 1)) { + return 'touch'; + } + if (evt.pointerType === 'mouse') { + return 'mouse'; + } + if (evt.pointerType === 'pen') { + return 'pen'; + } + } + return 'mouse'; }, /** - * Checks whether (x,y) is near the curve. - * @param {Number} x Coordinate in x direction, screen coordinates. - * @param {Number} y Coordinate in y direction, screen coordinates. - * @param {Number} start Optional start index for search on data plots. - * @returns {Boolean} True if (x,y) is near the curve, False otherwise. + * This method is called by the browser when a pointing device is pressed on the screen. + * @param {Event} evt The browsers event object. + * @param {Object} object If the object to be dragged is already known, it can be submitted via this parameter + * @returns {Boolean} ... */ - hasPoint: function (x, y, start) { - var t, checkPoint, len, invMat, c, - i, tX, tY, - res = [], - points, qdt, - steps = Type.evaluate(this.visProp.numberpointslow), - d = (this.maxX() - this.minX()) / steps, - prec, type, - dist = Infinity, - ux2, uy2, - ev_ct, - mi, ma, - suspendUpdate = true; + pointerDownListener: function (evt, object) { + var i, j, k, pos, elements, sel, + target_obj, + type = 'mouse', // Used in case of no browser + found, target; + // Fix for Firefox browser: When using a second finger, the + // touch event for the first finger is sent again. + if (!object && this._isPointerRegistered(evt)) { + return false; + } - if (Type.isObject(Type.evaluate(this.visProp.precision))) { - type = this.board._inputDevice; - prec = Type.evaluate(this.visProp.precision[type]); - } else { - // 'inherit' - prec = this.board.options.precision.hasPoint; + if (!object && evt.isPrimary) { + // First finger down. To be on the safe side this._board_touches is cleared. + this._pointerClearTouches(); } - checkPoint = new Coords(Const.COORDS_BY_SCREEN, [x, y], this.board, false); - x = checkPoint.usrCoords[1]; - y = checkPoint.usrCoords[2]; - // We use usrCoords. Only in the final distance calculation - // screen coords are used - prec += Type.evaluate(this.visProp.strokewidth) * 0.5; - prec *= prec; // We do not want to take sqrt - ux2 = this.board.unitX * this.board.unitX; - uy2 = this.board.unitY * this.board.unitY; + if (!this.hasPointerUp) { + if (window.navigator.msPointerEnabled) { // IE10- + Env.addEvent(this.document, 'MSPointerUp', this.pointerUpListener, this); + } else { + // 'pointercancel' is fired e.g. if the finger leaves the browser and drags down the system menu on Android + Env.addEvent(this.document, 'pointerup', this.pointerUpListener, this); + Env.addEvent(this.document, 'pointercancel', this.pointerUpListener, this); + } + this.hasPointerUp = true; + } - mi = this.minX(); - ma = this.maxX(); - if (Type.exists(this._visibleArea)) { - mi = this._visibleArea[0]; - ma = this._visibleArea[1]; - d = (ma - mi) / steps; + if (this.hasMouseHandlers) { + this.removeMouseEventHandlers(); } - ev_ct = Type.evaluate(this.visProp.curvetype); - if (ev_ct === 'parameter' || ev_ct === 'polar') { - if (this.transformations.length > 0) { - /** - * Transform the mouse/touch coordinates - * back to the original position of the curve. - */ - this.updateTransformMatrix(); - invMat = Mat.inverse(this.transformMat); - c = Mat.matVecMult(invMat, [1, x, y]); - x = c[1]; - y = c[2]; + if (this.hasTouchHandlers) { + this.removeTouchEventHandlers(); + } + + // Prevent accidental selection of text + if (this.document.selection && Type.isFunction(this.document.selection.empty)) { + this.document.selection.empty(); + } else if (window.getSelection) { + sel = window.getSelection(); + if (sel.removeAllRanges) { + try { + sel.removeAllRanges(); + } catch (e) {} } + } - // Brute force search for a point on the curve close to the mouse pointer - for (i = 0, t = mi; i < steps; i++) { - tX = this.X(t, suspendUpdate); - tY = this.Y(t, suspendUpdate); + // Mouse, touch or pen device + this._inputDevice = this._getPointerInputDevice(evt); + type = this._inputDevice; + this.options.precision.hasPoint = this.options.precision[type]; - dist = (x - tX) * (x - tX) * ux2 + (y - tY) * (y - tY) * uy2; + // Handling of multi touch with pointer events should be easier than the touch events. + // Every pointer device has its own pointerId, e.g. the mouse + // always has id 1 or 0, fingers and pens get unique ids every time a pointerDown event is fired and they will + // keep this id until a pointerUp event is fired. What we have to do here is: + // 1. collect all elements under the current pointer + // 2. run through the touches control structure + // a. look for the object collected in step 1. + // b. if an object is found, check the number of pointers. If appropriate, add the pointer. + pos = this.getMousePosition(evt); - if (dist <= prec) { - return true; - } + // selection + this._testForSelection(evt); + if (this.selectingMode) { + this._startSelecting(pos); + this.triggerEventHandlers(['touchstartselecting', 'pointerstartselecting', 'startselecting'], [evt]); + return; // don't continue as a normal click + } - t += d; - } - } else if (ev_ct === 'plot' || - ev_ct === 'functiongraph') { + if (this.attr.drag.enabled && object) { + elements = [ object ]; + this.mode = this.BOARD_MODE_DRAG; + } else { + elements = this.initMoveObject(pos[0], pos[1], evt, type); + } - if (!Type.exists(start) || start < 0) { - start = 0; - } + target_obj = { + num: evt.pointerId, + X: pos[0], + Y: pos[1], + Xprev: NaN, + Yprev: NaN, + Xstart: [], + Ystart: [], + Zstart: [] + }; - if (Type.exists(this.qdt) && - Type.evaluate(this.visProp.useqdt) && - this.bezierDegree !== 3 - ) { - qdt = this.qdt.query(new Coords(Const.COORDS_BY_USER, [x, y], this.board)); - points = qdt.points; - len = points.length; - } else { - points = this.points; - len = this.numberPoints - 1; + // If no draggable object can be found, get out here immediately + if (elements.length > 0) { + // check touches structure + target = elements[elements.length - 1]; + found = false; + + // Reminder: this.touches is the list of elements which + // currently "possess" a pointer (mouse, pen, finger) + for (i = 0; i < this.touches.length; i++) { + // An element receives a further touch, i.e. + // the target is already in our touches array, add the pointer to the existing touch + if (this.touches[i].obj === target) { + j = i; + k = this.touches[i].targets.push(target_obj) - 1; + found = true; + break; + } + } + if (!found) { + // An new element hae been touched. + k = 0; + j = this.touches.push({ + obj: target, + targets: [target_obj] + }) - 1; } - for (i = start; i < len; i++) { - if (this.bezierDegree === 3) { - res.push(Geometry.projectCoordsToBeziersegment([1, x, y], this, i)); - } else { - if (qdt) { - if (points[i].prev) { - res = Geometry.projectCoordsToSegment( - [1, x, y], - points[i].prev.usrCoords, - points[i].usrCoords - ); - } + this.dehighlightAll(); + target.highlight(true); - // If the next point in the array is the same as the current points - // next neighbor we don't have to project it onto that segment because - // that will already be done in the next iteration of this loop. - if (points[i].next && points[i + 1] !== points[i].next) { - res = Geometry.projectCoordsToSegment( - [1, x, y], - points[i].usrCoords, - points[i].next.usrCoords - ); - } - } else { - res = Geometry.projectCoordsToSegment( - [1, x, y], - points[i].usrCoords, - points[i + 1].usrCoords - ); - } - } + this.saveStartPos(target, this.touches[j].targets[k]); - if (res[1] >= 0 && res[1] <= 1 && - (x - res[0][1]) * (x - res[0][1]) * ux2 + - (y - res[0][2]) * (y - res[0][2]) * uy2 <= prec) { - return true; - } + // Prevent accidental text selection + // this could get us new trouble: input fields, links and drop down boxes placed as text + // on the board don't work anymore. + if (evt && evt.preventDefault) { + evt.preventDefault(); + } else if (window.event) { + window.event.returnValue = false; } - return false; } - return (dist < prec); - }, - - /** - * Allocate points in the Coords array this.points - */ - allocatePoints: function () { - var i, len; - len = this.numberPoints; + if (this.touches.length > 0) { + evt.preventDefault(); + evt.stopPropagation(); + } - if (this.points.length < this.numberPoints) { - for (i = this.points.length; i < len; i++) { - this.points[i] = new Coords(Const.COORDS_BY_USER, [0, 0], this.board, false); - } + if (!Env.isBrowser) { + return false; } - }, + if (this._getPointerInputDevice(evt) !== 'touch') { + if (this.mode === this.BOARD_MODE_NONE) { + this.mouseOriginMoveStart(evt); + } + } else { + this._pointerStorePosition(evt); + evt.touches = this._board_touches; - /** - * Computes for equidistant points on the x-axis the values of the function - * @returns {JXG.Curve} Reference to the curve object. - * @see JXG.Curve#updateCurve - */ - update: function () { - if (this.needsUpdate) { - if (Type.evaluate(this.visProp.trace)) { - this.cloneToBackground(true); + // Touch events on empty areas of the board are handled here, see also touchStartListener + // 1. case: one finger. If allowed, this triggers pan with one finger + if (evt.touches.length === 1 && + this.mode === this.BOARD_MODE_NONE && + this.touchStartMoveOriginOneFinger(evt)) { + // Empty by purpose + } else if (evt.touches.length === 2 && + (this.mode === this.BOARD_MODE_NONE || this.mode === this.BOARD_MODE_MOVE_ORIGIN) + ) { + // 2. case: two fingers: pinch to zoom or pan with two fingers needed. + // This happens when the second finger hits the device. First, the + // "one finger pan mode" has to be cancelled. + if (this.mode === this.BOARD_MODE_MOVE_ORIGIN) { + this.originMoveEnd(); + } + + this.gestureStartListener(evt); } - this.updateCurve(); } - return this; + this.triggerEventHandlers(['touchstart', 'down', 'pointerdown', 'MSPointerDown'], [evt]); + return false; }, + // /** + // * Called if pointer leaves an HTML tag. It is called by the inner-most tag. + // * That means, if a JSXGraph text, i.e. an HTML div, is placed close + // * to the border of the board, this pointerout event will be ignored. + // * @param {Event} evt + // * @return {Boolean} + // */ + // pointerOutListener: function (evt) { + // if (evt.target === this.containerObj || + // (this.renderer.type === 'svg' && evt.target === this.renderer.foreignObjLayer)) { + // this.pointerUpListener(evt); + // } + // return this.mode === this.BOARD_MODE_NONE; + // }, + /** - * Updates the visual contents of the curve. - * @returns {JXG.Curve} Reference to the curve object. + * Called periodically by the browser while the user moves a pointing device across the screen. + * @param {Event} evt + * @returns {Boolean} */ - updateRenderer: function () { - //var wasReal; + pointerMoveListener: function (evt) { + var i, j, pos, touchTargets, + type = 'mouse'; // in case of no browser - if (!this.needsUpdate) { - return this; + if (this._getPointerInputDevice(evt) === 'touch' && !this._isPointerRegistered(evt)) { + // Test, if there was a previous down event of this _getPointerId + // (in case it is a touch event). + // Otherwise this move event is ignored. This is necessary e.g. for sketchometry. + return this.BOARD_MODE_NONE; } - if (this.visPropCalc.visible) { - // wasReal = this.isReal; - - this.isReal = Plot.checkReal(this.points); - - if (//wasReal && - !this.isReal) { - this.updateVisibility(false); - } + if (!this.checkFrameRate(evt)) { + return false; } - if (this.visPropCalc.visible) { - this.board.renderer.updateCurve(this); + if (this.mode !== this.BOARD_MODE_DRAG) { + this.dehighlightAll(); + this.displayInfobox(false); } - /* Update the label if visible. */ - if (this.hasLabel && this.visPropCalc.visible && this.label && - this.label.visPropCalc.visible && this.isReal) { - - this.label.update(); - this.board.renderer.updateText(this.label); + if (this.mode !== this.BOARD_MODE_NONE) { + evt.preventDefault(); + evt.stopPropagation(); } - // Update rendNode display - this.setDisplayRendNode(); - // if (this.visPropCalc.visible !== this.visPropOld.visible) { - // this.board.renderer.display(this, this.visPropCalc.visible); - // this.visPropOld.visible = this.visPropCalc.visible; - // - // if (this.hasLabel) { - // this.board.renderer.display(this.label, this.label.visPropCalc.visible); - // } - // } - - this.needsUpdate = false; - return this; - }, - - /** - * For dynamic dataplots updateCurve can be used to compute new entries - * for the arrays {@link JXG.Curve#dataX} and {@link JXG.Curve#dataY}. It - * is used in {@link JXG.Curve#updateCurve}. Default is an empty method, can - * be overwritten by the user. - * - * - * @example - * // This example overwrites the updateDataArray method. - * // There, new values for the arrays JXG.Curve.dataX and JXG.Curve.dataY - * // are computed from the value of the slider N - * - * var N = board.create('slider', [[0,1.5],[3,1.5],[1,3,40]], {name:'n',snapWidth:1}); - * var circ = board.create('circle',[[4,-1.5],1],{strokeWidth:1, strokecolor:'black', strokeWidth:2, - * fillColor:'#0055ff13'}); - * - * var c = board.create('curve', [[0],[0]],{strokecolor:'red', strokeWidth:2}); - * c.updateDataArray = function() { - * var r = 1, n = Math.floor(N.Value()), - * x = [0], y = [0], - * phi = Math.PI/n, - * h = r*Math.cos(phi), - * s = r*Math.sin(phi), - * i, j, - * px = 0, py = 0, sgn = 1, - * d = 16, - * dt = phi/d, - * pt; - * - * for (i = 0; i < n; i++) { - * for (j = -d; j <= d; j++) { - * pt = dt*j; - * x.push(px + r*Math.sin(pt)); - * y.push(sgn*r*Math.cos(pt) - (sgn-1)*h*0.5); - * } - * px += s; - * sgn *= (-1); - * } - * x.push((n - 1)*s); - * y.push(h + (sgn - 1)*h*0.5); - * this.dataX = x; - * this.dataY = y; - * } - * - * var c2 = board.create('curve', [[0],[0]],{strokecolor:'red', strokeWidth:1}); - * c2.updateDataArray = function() { - * var r = 1, n = Math.floor(N.Value()), - * px = circ.midpoint.X(), py = circ.midpoint.Y(), - * x = [px], y = [py], - * phi = Math.PI/n, - * s = r*Math.sin(phi), - * i, j, - * d = 16, - * dt = phi/d, - * pt = Math.PI*0.5+phi; - * - * for (i = 0; i < n; i++) { - * for (j= -d; j <= d; j++) { - * x.push(px + r*Math.cos(pt)); - * y.push(py + r*Math.sin(pt)); - * pt -= dt; - * } - * x.push(px); - * y.push(py); - * pt += dt; - * } - * this.dataX = x; - * this.dataY = y; - * } - * board.update(); - * - * </pre><div id="JXG20bc7802-e69e-11e5-b1bf-901b0e1b8723" class="jxgbox" style="width: 600px; height: 400px;"></div> - * <script type="text/javascript"> - * (function() { - * var board = JXG.JSXGraph.initBoard('JXG20bc7802-e69e-11e5-b1bf-901b0e1b8723', - * {boundingbox: [-1.5,2,8,-3], keepaspectratio: true, axis: true, showcopyright: false, shownavigation: false}); - * var N = board.create('slider', [[0,1.5],[3,1.5],[1,3,40]], {name:'n',snapWidth:1}); - * var circ = board.create('circle',[[4,-1.5],1],{strokeWidth:1, strokecolor:'black', - * strokeWidth:2, fillColor:'#0055ff13'}); - * - * var c = board.create('curve', [[0],[0]],{strokecolor:'red', strokeWidth:2}); - * c.updateDataArray = function() { - * var r = 1, n = Math.floor(N.Value()), - * x = [0], y = [0], - * phi = Math.PI/n, - * h = r*Math.cos(phi), - * s = r*Math.sin(phi), - * i, j, - * px = 0, py = 0, sgn = 1, - * d = 16, - * dt = phi/d, - * pt; - * - * for (i=0;i<n;i++) { - * for (j=-d;j<=d;j++) { - * pt = dt*j; - * x.push(px+r*Math.sin(pt)); - * y.push(sgn*r*Math.cos(pt)-(sgn-1)*h*0.5); - * } - * px += s; - * sgn *= (-1); - * } - * x.push((n-1)*s); - * y.push(h+(sgn-1)*h*0.5); - * this.dataX = x; - * this.dataY = y; - * } - * - * var c2 = board.create('curve', [[0],[0]],{strokecolor:'red', strokeWidth:1}); - * c2.updateDataArray = function() { - * var r = 1, n = Math.floor(N.Value()), - * px = circ.midpoint.X(), py = circ.midpoint.Y(), - * x = [px], y = [py], - * phi = Math.PI/n, - * s = r*Math.sin(phi), - * i, j, - * d = 16, - * dt = phi/d, - * pt = Math.PI*0.5+phi; - * - * for (i=0;i<n;i++) { - * for (j=-d;j<=d;j++) { - * x.push(px+r*Math.cos(pt)); - * y.push(py+r*Math.sin(pt)); - * pt -= dt; - * } - * x.push(px); - * y.push(py); - * pt += dt; - * } - * this.dataX = x; - * this.dataY = y; - * } - * board.update(); - * - * })(); - * - * </script><pre> - * - * @example - * // This is an example which overwrites updateDataArray and produces - * // a Bezier curve of degree three. - * var A = board.create('point', [-3,3]); - * var B = board.create('point', [3,-2]); - * var line = board.create('segment', [A,B]); - * - * var height = 0.5; // height of the curly brace - * - * // Curly brace - * var crl = board.create('curve', [[0],[0]], {strokeWidth:1, strokeColor:'black'}); - * crl.bezierDegree = 3; - * crl.updateDataArray = function() { - * var d = [B.X()-A.X(), B.Y()-A.Y()], - * dl = Math.sqrt(d[0]*d[0]+d[1]*d[1]), - * mid = [(A.X()+B.X())*0.5, (A.Y()+B.Y())*0.5]; - * - * d[0] *= height/dl; - * d[1] *= height/dl; - * - * this.dataX = [ A.X(), A.X()-d[1], mid[0], mid[0]-d[1], mid[0], B.X()-d[1], B.X() ]; - * this.dataY = [ A.Y(), A.Y()+d[0], mid[1], mid[1]+d[0], mid[1], B.Y()+d[0], B.Y() ]; - * }; - * - * // Text - * var txt = board.create('text', [ - * function() { - * var d = [B.X()-A.X(), B.Y()-A.Y()], - * dl = Math.sqrt(d[0]*d[0]+d[1]*d[1]), - * mid = (A.X()+B.X())*0.5; - * - * d[1] *= height/dl; - * return mid-d[1]+0.1; - * }, - * function() { - * var d = [B.X()-A.X(), B.Y()-A.Y()], - * dl = Math.sqrt(d[0]*d[0]+d[1]*d[1]), - * mid = (A.Y()+B.Y())*0.5; - * - * d[0] *= height/dl; - * return mid+d[0]+0.1; - * }, - * function() { return "length=" + JXG.toFixed(B.Dist(A), 2); } - * ]); - * - * - * board.update(); // This update is necessary to call updateDataArray the first time. - * - * </pre><div id="JXGa61a4d66-e69f-11e5-b1bf-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function() { - * var board = JXG.JSXGraph.initBoard('JXGa61a4d66-e69f-11e5-b1bf-901b0e1b8723', - * {boundingbox: [-4, 4, 4,-4], axis: true, showcopyright: false, shownavigation: false}); - * var A = board.create('point', [-3,3]); - * var B = board.create('point', [3,-2]); - * var line = board.create('segment', [A,B]); - * - * var height = 0.5; // height of the curly brace - * - * // Curly brace - * var crl = board.create('curve', [[0],[0]], {strokeWidth:1, strokeColor:'black'}); - * crl.bezierDegree = 3; - * crl.updateDataArray = function() { - * var d = [B.X()-A.X(), B.Y()-A.Y()], - * dl = Math.sqrt(d[0]*d[0]+d[1]*d[1]), - * mid = [(A.X()+B.X())*0.5, (A.Y()+B.Y())*0.5]; - * - * d[0] *= height/dl; - * d[1] *= height/dl; - * - * this.dataX = [ A.X(), A.X()-d[1], mid[0], mid[0]-d[1], mid[0], B.X()-d[1], B.X() ]; - * this.dataY = [ A.Y(), A.Y()+d[0], mid[1], mid[1]+d[0], mid[1], B.Y()+d[0], B.Y() ]; - * }; - * - * // Text - * var txt = board.create('text', [ - * function() { - * var d = [B.X()-A.X(), B.Y()-A.Y()], - * dl = Math.sqrt(d[0]*d[0]+d[1]*d[1]), - * mid = (A.X()+B.X())*0.5; - * - * d[1] *= height/dl; - * return mid-d[1]+0.1; - * }, - * function() { - * var d = [B.X()-A.X(), B.Y()-A.Y()], - * dl = Math.sqrt(d[0]*d[0]+d[1]*d[1]), - * mid = (A.Y()+B.Y())*0.5; - * - * d[0] *= height/dl; - * return mid+d[0]+0.1; - * }, - * function() { return "length="+JXG.toFixed(B.Dist(A), 2); } - * ]); - * - * - * board.update(); // This update is necessary to call updateDataArray the first time. - * - * })(); - * - * </script><pre> - * - * - */ - updateDataArray: function () { - // this used to return this, but we shouldn't rely on the user to implement it. - }, + this.updateQuality = this.BOARD_QUALITY_LOW; + // Mouse, touch or pen device + this._inputDevice = this._getPointerInputDevice(evt); + type = this._inputDevice; + this.options.precision.hasPoint = this.options.precision[type]; - /** - * Computes the curve path - * @see JXG.Curve#update - * @returns {JXG.Curve} Reference to the curve object. - */ - updateCurve: function () { - var len, mi, ma, x, y, i, - version = this.visProp.plotversion, - //t1, t2, l1, - suspendUpdate = false; + // selection + if (this.selectingMode) { + pos = this.getMousePosition(evt); + this._moveSelecting(pos); + this.triggerEventHandlers(['touchmoveselecting', 'moveselecting', 'pointermoveselecting'], [evt, this.mode]); + } else if (!this.mouseOriginMove(evt)) { + if (this.mode === this.BOARD_MODE_DRAG) { + // Run through all jsxgraph elements which are touched by at least one finger. + for (i = 0; i < this.touches.length; i++) { + touchTargets = this.touches[i].targets; + // Run through all touch events which have been started on this jsxgraph element. + for (j = 0; j < touchTargets.length; j++) { + if (touchTargets[j].num === evt.pointerId) { - this.updateTransformMatrix(); - this.updateDataArray(); - mi = this.minX(); - ma = this.maxX(); + pos = this.getMousePosition(evt); + touchTargets[j].X = pos[0]; + touchTargets[j].Y = pos[1]; - // Discrete data points - // x-coordinates are in an array - if (Type.exists(this.dataX)) { - this.numberPoints = this.dataX.length; - len = this.numberPoints; + if (touchTargets.length === 1) { + // Touch by one finger: this is possible for all elements that can be dragged + this.moveObject(pos[0], pos[1], this.touches[i], evt, type); + } else if (touchTargets.length === 2) { + // Touch by two fingers: e.g. moving lines + this.twoFingerMove(this.touches[i], evt.pointerId, evt); - // It is possible, that the array length has increased. - this.allocatePoints(); + touchTargets[j].Xprev = pos[0]; + touchTargets[j].Yprev = pos[1]; + } - for (i = 0; i < len; i++) { - x = i; + // There is only one pointer in the evt object, so there's no point in looking further + break; + } + } + } + } else { + if (this._getPointerInputDevice(evt) === 'touch') { + this._pointerStorePosition(evt); - // y-coordinates are in an array - if (Type.exists(this.dataY)) { - y = i; - // The last parameter prevents rounding in usr2screen(). - this.points[i].setCoordinates(Const.COORDS_BY_USER, [this.dataX[i], this.dataY[i]], false); - } else { - // discrete x data, continuous y data - y = this.X(x); - // The last parameter prevents rounding in usr2screen(). - this.points[i].setCoordinates(Const.COORDS_BY_USER, [this.dataX[i], this.Y(y, suspendUpdate)], false); + if (this._board_touches.length === 2) { + evt.touches = this._board_touches; + this.gestureChangeListener(evt); + } } - this.points[i]._t = i; - // this.updateTransform(this.points[i]); - suspendUpdate = true; + // Move event without dragging an element + pos = this.getMousePosition(evt); + this.highlightElements(pos[0], pos[1], evt, -1); } - // continuous x data - } else { - if (Type.evaluate(this.visProp.doadvancedplot)) { - // console.time("plot"); + } - if (version === 1 || Type.evaluate(this.visProp.doadvancedplotold)) { - Plot.updateParametricCurveOld(this, mi, ma); - } else if (version === 2) { - Plot.updateParametricCurve_v2(this, mi, ma); - } else if (version === 4) { - Plot.updateParametricCurve_v4(this, mi, ma); - } else { - Plot.updateParametricCurve(this, mi, ma); - } - // console.timeEnd("plot"); - } else { - if (this.board.updateQuality === this.board.BOARD_QUALITY_HIGH) { - this.numberPoints = Type.evaluate(this.visProp.numberpointshigh); - } else { - this.numberPoints = Type.evaluate(this.visProp.numberpointslow); - } + // Hiding the infobox is commented out, since it prevents showing the infobox + // on IE 11+ on 'over' + //if (this.mode !== this.BOARD_MODE_DRAG) { + //this.displayInfobox(false); + //} + this.triggerEventHandlers(['touchmove', 'move', 'pointermove', 'MSPointerMove'], [evt, this.mode]); + this.updateQuality = this.BOARD_QUALITY_HIGH; - // It is possible, that the array length has increased. - this.allocatePoints(); - Plot.updateParametricCurveNaive(this, mi, ma, this.numberPoints); - } - len = this.numberPoints; + return this.mode === this.BOARD_MODE_NONE; + }, - if (Type.evaluate(this.visProp.useqdt) && - this.board.updateQuality === this.board.BOARD_QUALITY_HIGH) { - this.qdt = new QDT(this.board.getBoundingBox()); - for (i = 0; i < this.points.length; i++) { - this.qdt.insert(this.points[i]); + /** + * Triggered as soon as the user stops touching the device with at least one finger. + * @param {Event} evt + * @returns {Boolean} + */ + pointerUpListener: function (evt) { + var i, j, found, touchTargets; - if (i > 0) { - this.points[i].prev = this.points[i - 1]; - } + this.triggerEventHandlers(['touchend', 'up', 'pointerup', 'MSPointerUp'], [evt]); + this.displayInfobox(false); - if (i < len - 1) { - this.points[i].next = this.points[i + 1]; + if (evt) { + for (i = 0; i < this.touches.length; i++) { + touchTargets = this.touches[i].targets; + for (j = 0; j < touchTargets.length; j++) { + if (touchTargets[j].num === evt.pointerId) { + touchTargets.splice(j, 1); + if (touchTargets.length === 0) { + this.touches.splice(i, 1); + } + break; } } } - - // for (i = 0; i < len; i++) { - // this.updateTransform(this.points[i]); - // } } - if (Type.evaluate(this.visProp.curvetype) !== 'plot' && - Type.evaluate(this.visProp.rdpsmoothing)) { - // console.time("rdp"); - this.points = Numerics.RamerDouglasPeucker(this.points, 0.2); - this.numberPoints = this.points.length; - // console.timeEnd("rdp"); - // console.log(this.numberPoints); - } + this.originMoveEnd(); + this.update(); - len = this.numberPoints; - for (i = 0; i < len; i++) { - this.updateTransform(this.points[i]); + // selection + if (this.selectingMode) { + this._stopSelecting(evt); + this.triggerEventHandlers(['touchstopselecting', 'pointerstopselecting', 'stopselecting'], [evt]); + this.stopSelectionMode(); + } else { + for (i = this.downObjects.length - 1; i > -1; i--) { + found = false; + for (j = 0; j < this.touches.length; j++) { + if (this.touches[j].obj.id === this.downObjects[i].id) { + found = true; + } + } + if (!found) { + this.downObjects[i].triggerEventHandlers(['touchend', 'up', 'pointerup', 'MSPointerUp'], [evt]); + // this.downObjects[i].snapToGrid(); + // this.downObjects[i].snapToPoints(); + this.downObjects.splice(i, 1); + } + } } - return this; - }, - - updateTransformMatrix: function () { - var t, i, - len = this.transformations.length; + if (this.hasPointerUp) { + if (window.navigator.msPointerEnabled) { // IE10- + Env.removeEvent(this.document, 'MSPointerUp', this.pointerUpListener, this); + } else { + Env.removeEvent(this.document, 'pointerup', this.pointerUpListener, this); + Env.removeEvent(this.document, 'pointercancel', this.pointerUpListener, this); + } + this.hasPointerUp = false; + } - this.transformMat = [[1, 0, 0], [0, 1, 0], [0, 0, 1]]; + // this.dehighlightAll(); + // this.updateQuality = this.BOARD_QUALITY_HIGH; + // this.mode = this.BOARD_MODE_NONE; - for (i = 0; i < len; i++) { - t = this.transformations[i]; - t.update(); - this.transformMat = Mat.matMatMult(t.matrix, this.transformMat); - } + // this.originMoveEnd(); + // this.update(); - return this; + // After one finger leaves the screen the gesture is stopped. + this._pointerClearTouches(); + return true; }, /** - * Applies the transformations of the curve to the given point <tt>p</tt>. - * Before using it, {@link JXG.Curve#updateTransformMatrix} has to be called. - * @param {JXG.Point} p - * @returns {JXG.Point} The given point. + * Touch-Events */ - updateTransform: function (p) { - var c, - len = this.transformations.length; - - if (len > 0) { - c = Mat.matVecMult(this.transformMat, p.usrCoords); - p.setCoordinates(Const.COORDS_BY_USER, c, false, true); - } - - return p; - }, /** - * Add transformations to this curve. - * @param {JXG.Transformation|Array} transform Either one {@link JXG.Transformation} or an array of {@link JXG.Transformation}s. - * @returns {JXG.Curve} Reference to the curve object. + * This method is called by the browser when a finger touches the surface of the touch-device. + * @param {Event} evt The browsers event object. + * @returns {Boolean} ... */ - addTransform: function (transform) { - var i, - list = Type.isArray(transform) ? transform : [transform], - len = list.length; + touchStartListener: function (evt) { + var i, pos, elements, j, k, + eps = this.options.precision.touch, + obj, found, targets, + evtTouches = evt[JXG.touchProperty], + target, touchTargets; - for (i = 0; i < len; i++) { - this.transformations.push(list[i]); + if (!this.hasTouchEnd) { + Env.addEvent(this.document, 'touchend', this.touchEndListener, this); + this.hasTouchEnd = true; } - return this; - }, + // Do not remove mouseHandlers, since Chrome on win tablets sends mouseevents if used with pen. + //if (this.hasMouseHandlers) { this.removeMouseEventHandlers(); } - /** - * Generate the method curve.X() in case curve.dataX is an array - * and generate the method curve.Y() in case curve.dataY is an array. - * @private - * @param {String} which Either 'X' or 'Y' - * @returns {function} - **/ - interpolationFunctionFromArray: function (which) { - var data = 'data' + which, - that = this; + // prevent accidental selection of text + if (this.document.selection && Type.isFunction(this.document.selection.empty)) { + this.document.selection.empty(); + } else if (window.getSelection) { + window.getSelection().removeAllRanges(); + } - return function (t, suspendedUpdate) { - var i, j, t0, t1, - arr = that[data], - len = arr.length, - last, - f = []; + // multitouch + this._inputDevice = 'touch'; + this.options.precision.hasPoint = this.options.precision.touch; - if (isNaN(t)) { - return NaN; - } + // This is the most critical part. first we should run through the existing touches and collect all targettouches that don't belong to our + // previous touches. once this is done we run through the existing touches again and watch out for free touches that can be attached to our existing + // touches, e.g. we translate (parallel translation) a line with one finger, now a second finger is over this line. this should change the operation to + // a rotational translation. or one finger moves a circle, a second finger can be attached to the circle: this now changes the operation from translation to + // stretching. as a last step we're going through the rest of the targettouches and initiate new move operations: + // * points have higher priority over other elements. + // * if we find a targettouch over an element that could be transformed with more than one finger, we search the rest of the targettouches, if they are over + // this element and add them. + // ADDENDUM 11/10/11: + // (1) run through the touches control object, + // (2) try to find the targetTouches for every touch. on touchstart only new touches are added, hence we can find a targettouch + // for every target in our touches objects + // (3) if one of the targettouches was bound to a touches targets array, mark it + // (4) run through the targettouches. if the targettouch is marked, continue. otherwise check for elements below the targettouch: + // (a) if no element could be found: mark the target touches and continue + // --- in the following cases, "init" means: + // (i) check if the element is already used in another touches element, if so, mark the targettouch and continue + // (ii) if not, init a new touches element, add the targettouch to the touches property and mark it + // (b) if the element is a point, init + // (c) if the element is a line, init and try to find a second targettouch on that line. if a second one is found, add and mark it + // (d) if the element is a circle, init and try to find TWO other targettouches on that circle. if only one is found, mark it and continue. otherwise + // add both to the touches array and mark them. + for (i = 0; i < evtTouches.length; i++) { + evtTouches[i].jxg_isused = false; + } - if (t < 0) { - if (Type.isFunction(arr[0])) { - return arr[0](); + for (i = 0; i < this.touches.length; i++) { + touchTargets = this.touches[i].targets; + for (j = 0; j < touchTargets.length; j++) { + touchTargets[j].num = -1; + eps = this.options.precision.touch; + + do { + for (k = 0; k < evtTouches.length; k++) { + // find the new targettouches + if (Math.abs(Math.pow(evtTouches[k].screenX - touchTargets[j].X, 2) + + Math.pow(evtTouches[k].screenY - touchTargets[j].Y, 2)) < eps * eps) { + touchTargets[j].num = k; + touchTargets[j].X = evtTouches[k].screenX; + touchTargets[j].Y = evtTouches[k].screenY; + evtTouches[k].jxg_isused = true; + break; + } + } + + eps *= 2; + + } while (touchTargets[j].num === -1 && + eps < this.options.precision.touchMax); + + if (touchTargets[j].num === -1) { + JXG.debug('i couldn\'t find a targettouches for target no ' + j + ' on ' + this.touches[i].obj.name + ' (' + this.touches[i].obj.id + '). Removed the target.'); + JXG.debug('eps = ' + eps + ', touchMax = ' + Options.precision.touchMax); + touchTargets.splice(i, 1); } - return arr[0]; } + } - if (that.bezierDegree === 3) { - last = (len - 1) / 3; - - if (t >= last) { - if (Type.isFunction(arr[arr.length - 1])) { - return arr[arr.length - 1](); - } + // we just re-mapped the targettouches to our existing touches list. + // now we have to initialize some touches from additional targettouches + for (i = 0; i < evtTouches.length; i++) { + if (!evtTouches[i].jxg_isused) { - return arr[arr.length - 1]; + pos = this.getMousePosition(evt, i); + // selection + // this._testForSelection(evt); // we do not have shift or ctrl keys yet. + if (this.selectingMode) { + this._startSelecting(pos); + this.triggerEventHandlers(['touchstartselecting', 'startselecting'], [evt]); + evt.preventDefault(); + evt.stopPropagation(); + this.options.precision.hasPoint = this.options.precision.mouse; + return this.touches.length > 0; // don't continue as a normal click } - i = Math.floor(t) * 3; - t0 = t % 1; - t1 = 1 - t0; + elements = this.initMoveObject(pos[0], pos[1], evt, 'touch'); + if (elements.length !== 0) { + obj = elements[elements.length - 1]; + target = {num: i, + X: evtTouches[i].screenX, + Y: evtTouches[i].screenY, + Xprev: NaN, + Yprev: NaN, + Xstart: [], + Ystart: [], + Zstart: [] + }; - for (j = 0; j < 4; j++) { - if (Type.isFunction(arr[i + j])) { - f[j] = arr[i + j](); - } else { - f[j] = arr[i + j]; + if (Type.isPoint(obj) || + obj.elementClass === Const.OBJECT_CLASS_TEXT || + obj.type === Const.OBJECT_TYPE_TICKS || + obj.type === Const.OBJECT_TYPE_IMAGE) { + // It's a point, so it's single touch, so we just push it to our touches + targets = [target]; + + // For the UNDO/REDO of object moves + this.saveStartPos(obj, targets[0]); + + this.touches.push({ obj: obj, targets: targets }); + obj.highlight(true); + + } else if (obj.elementClass === Const.OBJECT_CLASS_LINE || + obj.elementClass === Const.OBJECT_CLASS_CIRCLE || + obj.elementClass === Const.OBJECT_CLASS_CURVE || + obj.type === Const.OBJECT_TYPE_POLYGON) { + found = false; + + // first check if this geometric object is already captured in this.touches + for (j = 0; j < this.touches.length; j++) { + if (obj.id === this.touches[j].obj.id) { + found = true; + // only add it, if we don't have two targets in there already + if (this.touches[j].targets.length === 1) { + // For the UNDO/REDO of object moves + this.saveStartPos(obj, target); + this.touches[j].targets.push(target); + } + + evtTouches[i].jxg_isused = true; + } + } + + // we couldn't find it in touches, so we just init a new touches + // IF there is a second touch targetting this line, we will find it later on, and then add it to + // the touches control object. + if (!found) { + targets = [target]; + + // For the UNDO/REDO of object moves + this.saveStartPos(obj, targets[0]); + this.touches.push({ obj: obj, targets: targets }); + obj.highlight(true); + } } } - return t1 * t1 * (t1 * f[0] + 3 * t0 * f[1]) + (3 * t1 * f[2] + t0 * f[3]) * t0 * t0; + evtTouches[i].jxg_isused = true; } + } - if (t > len - 2) { - i = len - 2; - } else { - i = parseInt(Math.floor(t), 10); - } + if (this.touches.length > 0) { + evt.preventDefault(); + evt.stopPropagation(); + } - if (i === t) { - if (Type.isFunction(arr[i])) { - return arr[i](); - } - return arr[i]; + // Touch events on empty areas of the board are handled here: + // 1. case: one finger. If allowed, this triggers pan with one finger + if (evtTouches.length === 1 && this.mode === this.BOARD_MODE_NONE && this.touchStartMoveOriginOneFinger(evt)) { + } else if (evtTouches.length === 2 && + (this.mode === this.BOARD_MODE_NONE || this.mode === this.BOARD_MODE_MOVE_ORIGIN) + ) { + // 2. case: two fingers: pinch to zoom or pan with two fingers needed. + // This happens when the second finger hits the device. First, the + // "one finger pan mode" has to be cancelled. + if (this.mode === this.BOARD_MODE_MOVE_ORIGIN) { + this.originMoveEnd(); } + this.gestureStartListener(evt); + } - for (j = 0; j < 2; j++) { - if (Type.isFunction(arr[i + j])) { - f[j] = arr[i + j](); - } else { - f[j] = arr[i + j]; - } - } - return f[0] + (f[1] - f[0]) * (t - i); - }; + this.options.precision.hasPoint = this.options.precision.mouse; + this.triggerEventHandlers(['touchstart', 'down'], [evt]); + + return false; + //return this.touches.length > 0; }, /** - * Converts the JavaScript/JessieCode/GEONExT syntax of the defining function term into JavaScript. - * New methods X() and Y() for the Curve object are generated, further - * new methods for minX() and maxX(). - * @see JXG.GeonextParser.geonext2JS. + * Called periodically by the browser while the user moves his fingers across the device. + * @param {Event} evt + * @returns {Boolean} */ - generateTerm: function (varname, xterm, yterm, mi, ma) { - var fx, fy; + touchMoveListener: function (evt) { + var i, pos1, pos2, + touchTargets, + evtTouches = evt[JXG.touchProperty]; - // Generate the methods X() and Y() - if (Type.isArray(xterm)) { - // Discrete data - this.dataX = xterm; + if (!this.checkFrameRate(evt)) { + return false; + } - this.numberPoints = this.dataX.length; - this.X = this.interpolationFunctionFromArray.apply(this, ['X']); - this.visProp.curvetype = 'plot'; - this.isDraggable = true; - } else { - // Continuous data - this.X = Type.createFunction(xterm, this.board, varname); - if (Type.isString(xterm)) { - this.visProp.curvetype = 'functiongraph'; - } else if (Type.isFunction(xterm) || Type.isNumber(xterm)) { - this.visProp.curvetype = 'parameter'; - } + if (this.mode !== this.BOARD_MODE_NONE) { + evt.preventDefault(); + evt.stopPropagation(); + } - this.isDraggable = true; + if (this.mode !== this.BOARD_MODE_DRAG) { + this.dehighlightAll(); + this.displayInfobox(false); } - if (Type.isArray(yterm)) { - this.dataY = yterm; - this.Y = this.interpolationFunctionFromArray.apply(this, ['Y']); + this._inputDevice = 'touch'; + this.options.precision.hasPoint = this.options.precision.touch; + this.updateQuality = this.BOARD_QUALITY_LOW; + + // selection + if (this.selectingMode) { + for (i = 0; i < evtTouches.length; i++) { + if (!evtTouches[i].jxg_isused) { + pos1 = this.getMousePosition(evt, i); + this._moveSelecting(pos1); + this.triggerEventHandlers(['touchmoves', 'moveselecting'], [evt, this.mode]); + break; + } + } } else { - this.Y = Type.createFunction(yterm, this.board, varname); - } + if (!this.touchOriginMove(evt)) { + if (this.mode === this.BOARD_MODE_DRAG) { + // Runs over through all elements which are touched + // by at least one finger. + for (i = 0; i < this.touches.length; i++) { + touchTargets = this.touches[i].targets; + if (touchTargets.length === 1) { - /** - * Polar form - * Input data is function xterm() and offset coordinates yterm - */ - if (Type.isFunction(xterm) && Type.isArray(yterm)) { - // Xoffset, Yoffset - fx = Type.createFunction(yterm[0], this.board, ''); - fy = Type.createFunction(yterm[1], this.board, ''); - this.X = function (phi) { - return xterm(phi) * Math.cos(phi) + fx(); - }; + // Touch by one finger: this is possible for all elements that can be dragged + if (evtTouches[touchTargets[0].num]) { + pos1 = this.getMousePosition(evt, touchTargets[0].num); + if (pos1[0] < 0 || pos1[0] > this.canvasWidth || + pos1[1] < 0 || pos1[1] > this.canvasHeight) { + return; + } + touchTargets[0].X = pos1[0]; + touchTargets[0].Y = pos1[1]; + this.moveObject(pos1[0], pos1[1], this.touches[i], evt, 'touch'); + } - this.Y = function (phi) { - return xterm(phi) * Math.sin(phi) + fy(); - }; + } else if (touchTargets.length === 2 && + touchTargets[0].num > -1 && + touchTargets[1].num > -1) { - this.visProp.curvetype = 'polar'; - } + // Touch by two fingers: moving lines, ... + if (evtTouches[touchTargets[0].num] && + evtTouches[touchTargets[1].num]) { - // Set the bounds lower bound - if (Type.exists(mi)) { - this.minX = Type.createFunction(mi, this.board, ''); - } - if (Type.exists(ma)) { - this.maxX = Type.createFunction(ma, this.board, ''); - } - }, + // Get coordinates of the two touches + pos1 = this.getMousePosition(evt, touchTargets[0].num); + pos2 = this.getMousePosition(evt, touchTargets[1].num); + if (pos1[0] < 0 || pos1[0] > this.canvasWidth || + pos1[1] < 0 || pos1[1] > this.canvasHeight || + pos2[0] < 0 || pos2[0] > this.canvasWidth || + pos2[1] < 0 || pos2[1] > this.canvasHeight) { + return; + } - /** - * Finds dependencies in a given term and notifies the parents by adding the - * dependent object to the found objects child elements. - * @param {String} contentStr String containing dependencies for the given object. - */ - notifyParents: function (contentStr) { - var fstr, dep, - isJessieCode = false, - obj; + touchTargets[0].X = pos1[0]; + touchTargets[0].Y = pos1[1]; + touchTargets[1].X = pos2[0]; + touchTargets[1].Y = pos2[1]; - // Read dependencies found by the JessieCode parser - obj = {'xterm': 1, 'yterm': 1}; - for (fstr in obj) { - if (obj.hasOwnProperty(fstr) && this.hasOwnProperty(fstr) && this[fstr].origin) { - isJessieCode = true; - for (dep in this[fstr].origin.deps) { - if (this[fstr].origin.deps.hasOwnProperty(dep)) { - this[fstr].origin.deps[dep].addChild(this); + this.twoFingerMove(this.touches[i], touchTargets[0].num, evt); + this.twoFingerMove(this.touches[i], touchTargets[1].num); + + touchTargets[0].Xprev = pos1[0]; + touchTargets[0].Yprev = pos1[1]; + touchTargets[1].Xprev = pos2[0]; + touchTargets[1].Yprev = pos2[1]; + } + } + } + } else { + if (evtTouches.length === 2) { + this.gestureChangeListener(evt); } + // Move event without dragging an element + pos1 = this.getMousePosition(evt, 0); + this.highlightElements(pos1[0], pos1[1], evt, -1); } } } - if (!isJessieCode) { - GeonextParser.findDependencies(this, contentStr, this.board); + if (this.mode !== this.BOARD_MODE_DRAG) { + this.displayInfobox(false); } + + this.triggerEventHandlers(['touchmove', 'move'], [evt, this.mode]); + this.options.precision.hasPoint = this.options.precision.mouse; + this.updateQuality = this.BOARD_QUALITY_HIGH; + + return this.mode === this.BOARD_MODE_NONE; }, - // documented in geometry element - getLabelAnchor: function () { - var c, x, y, - ax = 0.05 * this.board.canvasWidth, - ay = 0.05 * this.board.canvasHeight, - bx = 0.95 * this.board.canvasWidth, - by = 0.95 * this.board.canvasHeight; + /** + * Triggered as soon as the user stops touching the device with at least one finger. + * @param {Event} evt + * @returns {Boolean} + */ + touchEndListener: function (evt) { + var i, j, k, + eps = this.options.precision.touch, + tmpTouches = [], found, foundNumber, + evtTouches = evt && evt[JXG.touchProperty], + touchTargets; - switch (Type.evaluate(this.visProp.label.position)) { - case 'ulft': - x = ax; - y = ay; - break; - case 'llft': - x = ax; - y = by; - break; - case 'rt': - x = bx; - y = 0.5 * by; - break; - case 'lrt': - x = bx; - y = by; - break; - case 'urt': - x = bx; - y = ay; - break; - case 'top': - x = 0.5 * bx; - y = ay; - break; - case 'bot': - x = 0.5 * bx; - y = by; - break; - default: - // includes case 'lft' - x = ax; - y = 0.5 * by; - } + this.triggerEventHandlers(['touchend', 'up'], [evt]); + this.displayInfobox(false); - c = new Coords(Const.COORDS_BY_SCREEN, [x, y], this.board, false); - return Geometry.projectCoordsToCurve(c.usrCoords[1], c.usrCoords[2], 0, this, this.board)[0]; - }, + // selection + if (this.selectingMode) { + this._stopSelecting(evt); + this.triggerEventHandlers(['touchstopselecting', 'stopselecting'], [evt]); + this.stopSelectionMode(); + } else if (evtTouches && evtTouches.length > 0) { + for (i = 0; i < this.touches.length; i++) { + tmpTouches[i] = this.touches[i]; + } + this.touches.length = 0; - // documented in geometry element - cloneToBackground: function () { - var er, - copy = { - id: this.id + 'T' + this.numTraces, - elementClass: Const.OBJECT_CLASS_CURVE, + // try to convert the operation, e.g. if a lines is rotated and translated with two fingers and one finger is lifted, + // convert the operation to a simple one-finger-translation. + // ADDENDUM 11/10/11: + // see addendum to touchStartListener from 11/10/11 + // (1) run through the tmptouches + // (2) check the touches.obj, if it is a + // (a) point, try to find the targettouch, if found keep it and mark the targettouch, else drop the touch. + // (b) line with + // (i) one target: try to find it, if found keep it mark the targettouch, else drop the touch. + // (ii) two targets: if none can be found, drop the touch. if one can be found, remove the other target. mark all found targettouches + // (c) circle with [proceed like in line] - points: this.points.slice(0), - bezierDegree: this.bezierDegree, - numberPoints: this.numberPoints, - board: this.board, - visProp: Type.deepCopy(this.visProp, this.visProp.traceattributes, true) - }; + // init the targettouches marker + for (i = 0; i < evtTouches.length; i++) { + evtTouches[i].jxg_isused = false; + } - copy.visProp.layer = this.board.options.layer.trace; - copy.visProp.curvetype = this.visProp.curvetype; - this.numTraces++; + for (i = 0; i < tmpTouches.length; i++) { + // could all targets of the current this.touches.obj be assigned to targettouches? + found = false; + foundNumber = 0; + touchTargets = tmpTouches[i].targets; - Type.clearVisPropOld(copy); - copy.visPropCalc = { - visible: Type.evaluate(copy.visProp.visible) - }; - er = this.board.renderer.enhancedRendering; - this.board.renderer.enhancedRendering = true; - this.board.renderer.drawCurve(copy); - this.board.renderer.enhancedRendering = er; - this.traces[copy.id] = copy.rendNode; + for (j = 0; j < touchTargets.length; j++) { + touchTargets[j].found = false; + for (k = 0; k < evtTouches.length; k++) { + if (Math.abs(Math.pow(evtTouches[k].screenX - touchTargets[j].X, 2) + Math.pow(evtTouches[k].screenY - touchTargets[j].Y, 2)) < eps * eps) { + touchTargets[j].found = true; + touchTargets[j].num = k; + touchTargets[j].X = evtTouches[k].screenX; + touchTargets[j].Y = evtTouches[k].screenY; + foundNumber += 1; + break; + } + } + } - return this; - }, + if (Type.isPoint(tmpTouches[i].obj)) { + found = (touchTargets[0] && touchTargets[0].found); + } else if (tmpTouches[i].obj.elementClass === Const.OBJECT_CLASS_LINE) { + found = (touchTargets[0] && touchTargets[0].found) || (touchTargets[1] && touchTargets[1].found); + } else if (tmpTouches[i].obj.elementClass === Const.OBJECT_CLASS_CIRCLE) { + found = foundNumber === 1 || foundNumber === 3; + } - // already documented in GeometryElement - bounds: function () { - var minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity, - l = this.points.length, i, - bezier, up; + // if we found this object to be still dragged by the user, add it back to this.touches + if (found) { + this.touches.push({ + obj: tmpTouches[i].obj, + targets: [] + }); - if (this.bezierDegree === 3) { - // Add methods X(), Y() - for (i = 0; i < l; i++) { - this.points[i].X = Type.bind(function() { return this.usrCoords[1]; }, this.points[i]); - this.points[i].Y = Type.bind(function() { return this.usrCoords[2]; }, this.points[i]); + for (j = 0; j < touchTargets.length; j++) { + if (touchTargets[j].found) { + this.touches[this.touches.length - 1].targets.push({ + num: touchTargets[j].num, + X: touchTargets[j].screenX, + Y: touchTargets[j].screenY, + Xprev: NaN, + Yprev: NaN, + Xstart: touchTargets[j].Xstart, + Ystart: touchTargets[j].Ystart, + Zstart: touchTargets[j].Zstart + }); + } + } + + } else { + tmpTouches[i].obj.noHighlight(); + } } - bezier = Numerics.bezier(this.points); - up = bezier[3](); - minX = Numerics.fminbr(function(t) { return bezier[0](t); }, [0, up]); - maxX = Numerics.fminbr(function(t) { return -bezier[0](t); }, [0, up]); - minY = Numerics.fminbr(function(t) { return bezier[1](t); }, [0, up]); - maxY = Numerics.fminbr(function(t) { return -bezier[1](t); }, [0, up]); - minX = bezier[0](minX); - maxX = bezier[0](maxX); - minY = bezier[1](minY); - maxY = bezier[1](maxY); - return [minX, maxY, maxX, minY]; + } else { + this.touches.length = 0; } - // Linear segments - for (i = 0; i < l; i++) { - if (minX > this.points[i].usrCoords[1]) { - minX = this.points[i].usrCoords[1]; + for (i = this.downObjects.length - 1; i > -1; i--) { + found = false; + for (j = 0; j < this.touches.length; j++) { + if (this.touches[j].obj.id === this.downObjects[i].id) { + found = true; + } } - - if (maxX < this.points[i].usrCoords[1]) { - maxX = this.points[i].usrCoords[1]; + if (!found) { + this.downObjects[i].triggerEventHandlers(['touchup', 'up'], [evt]); + // this.downObjects[i].snapToGrid(); + // this.downObjects[i].snapToPoints(); + this.downObjects.splice(i, 1); } + } - if (minY > this.points[i].usrCoords[2]) { - minY = this.points[i].usrCoords[2]; - } + if (!evtTouches || evtTouches.length === 0) { - if (maxY < this.points[i].usrCoords[2]) { - maxY = this.points[i].usrCoords[2]; + if (this.hasTouchEnd) { + Env.removeEvent(this.document, 'touchend', this.touchEndListener, this); + this.hasTouchEnd = false; } - } - return [minX, maxY, maxX, minY]; - }, - - // documented in element.js - getParents: function () { - var p = [this.xterm, this.yterm, this.minX(), this.maxX()]; + this.dehighlightAll(); + this.updateQuality = this.BOARD_QUALITY_HIGH; - if (this.parents.length !== 0) { - p = this.parents; + this.originMoveEnd(); + this.update(); } - return p; + return true; }, /** - * Shift the curve by the vector 'where'. - * - * @param {Array} where Array containing the x and y coordinate of the target location. - * @returns {JXG.Curve} Reference to itself. - */ - moveTo: function(where) { - // TODO add animation - var delta = [], p; - if (this.points.length > 0 && !Type.evaluate(this.visProp.fixed)) { - p = this.points[0]; - if (where.length === 3) { - delta = [where[0] - p.usrCoords[0], - where[1] - p.usrCoords[1], - where[2] - p.usrCoords[2]]; - } else { - delta = [where[0] - p.usrCoords[1], - where[1] - p.usrCoords[2]]; - } - this.setPosition(Const.COORDS_BY_USER, delta); + * This method is called by the browser when the mouse button is clicked. + * @param {Event} evt The browsers event object. + * @returns {Boolean} True if no element is found under the current mouse pointer, false otherwise. + */ + mouseDownListener: function (evt) { + var pos, elements, result; + + // prevent accidental selection of text + if (this.document.selection && Type.isFunction(this.document.selection.empty)) { + this.document.selection.empty(); + } else if (window.getSelection) { + window.getSelection().removeAllRanges(); } - return this; - }, - /** - * If the curve is the result of a transformation applied - * to a continuous curve, the glider projection has to be done - * on the original curve. Otherwise there will be problems - * when changing between high and low precision plotting, - * since there number of points changes. - * - * @private - * @returns {Array} [Boolean, curve]: Array contining 'true' if curve is result of a transformation, - * and the source curve of the transformation. - */ - getTransformationSource: function() { - var isTransformed, curve_org; - if (Type.exists(this._transformationSource)) { - curve_org = this._transformationSource; - if (curve_org.elementClass === Const.OBJECT_CLASS_CURVE //&& - //Type.evaluate(curve_org.visProp.curvetype) !== 'plot' - ) { - isTransformed = true; - } + if (!this.hasMouseUp) { + Env.addEvent(this.document, 'mouseup', this.mouseUpListener, this); + this.hasMouseUp = true; + } else { + // In case this.hasMouseUp==true, it may be that there was a + // mousedown event before which was not followed by an mouseup event. + // This seems to happen with interactive whiteboard pens sometimes. + return; } - return [isTransformed, curve_org]; - } - }); + this._inputDevice = 'mouse'; + this.options.precision.hasPoint = this.options.precision.mouse; + pos = this.getMousePosition(evt); - /** - * @class This element is used to provide a constructor for curve, which is just a wrapper for element {@link Curve}. - * A curve is a mapping from R to R^2. t mapsto (x(t),y(t)). The graph is drawn for t in the interval [a,b]. - * <p> - * The following types of curves can be plotted: - * <ul> - * <li> parametric curves: t mapsto (x(t),y(t)), where x() and y() are univariate functions. - * <li> polar curves: curves commonly written with polar equations like spirals and cardioids. - * <li> data plots: plot line segments through a given list of coordinates. - * </ul> - * @pseudo - * @description - * @name Curve - * @augments JXG.Curve - * @constructor - * @type JXG.Curve - * - * @param {function,number_function,number_function,number_function,number} x,y,a_,b_ Parent elements for Parametric Curves. - * <p> - * x describes the x-coordinate of the curve. It may be a function term in one variable, e.g. x(t). - * In case of x being of type number, x(t) is set to a constant function. - * this function at the values of the array. - * </p> - * <p> - * y describes the y-coordinate of the curve. In case of a number, y(t) is set to the constant function - * returning this number. - * </p> - * <p> - * Further parameters are an optional number or function for the left interval border a, - * and an optional number or function for the right interval border b. - * </p> - * <p> - * Default values are a=-10 and b=10. - * </p> - * @param {array_array,function,number} x,y Parent elements for Data Plots. - * <p> - * x and y are arrays contining the x and y coordinates of the data points which are connected by - * line segments. The individual entries of x and y may also be functions. - * In case of x being an array the curve type is data plot, regardless of the second parameter and - * if additionally the second parameter y is a function term the data plot evaluates. - * </p> - * @param {function_array,function,number_function,number_function,number} r,offset_,a_,b_ Parent elements for Polar Curves. - * <p> - * The first parameter is a function term r(phi) describing the polar curve. - * </p> - * <p> - * The second parameter is the offset of the curve. It has to be - * an array containing numbers or functions describing the offset. Default value is the origin [0,0]. - * </p> - * <p> - * Further parameters are an optional number or function for the left interval border a, - * and an optional number or function for the right interval border b. - * </p> - * <p> - * Default values are a=-10 and b=10. - * </p> - * <p> - * Additionally, a curve can be created by providing a curve and a transformation (or an array of transformations). - * The result is a curve which is the transformation of the supplied curve. - * - * @see JXG.Curve - * @example - * // Parametric curve - * // Create a curve of the form (t-sin(t), 1-cos(t), i.e. - * // the cycloid curve. - * var graph = board.create('curve', - * [function(t){ return t-Math.sin(t);}, - * function(t){ return 1-Math.cos(t);}, - * 0, 2*Math.PI] - * ); - * </pre><div class="jxgbox" id="JXGaf9f818b-f3b6-4c4d-8c4c-e4a4078b726d" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * var c1_board = JXG.JSXGraph.initBoard('JXGaf9f818b-f3b6-4c4d-8c4c-e4a4078b726d', {boundingbox: [-1, 5, 7, -1], axis: true, showcopyright: false, shownavigation: false}); - * var graph1 = c1_board.create('curve', [function(t){ return t-Math.sin(t);},function(t){ return 1-Math.cos(t);},0, 2*Math.PI]); - * </script><pre> - * @example - * // Data plots - * // Connect a set of points given by coordinates with dashed line segments. - * // The x- and y-coordinates of the points are given in two separate - * // arrays. - * var x = [0,1,2,3,4,5,6,7,8,9]; - * var y = [9.2,1.3,7.2,-1.2,4.0,5.3,0.2,6.5,1.1,0.0]; - * var graph = board.create('curve', [x,y], {dash:2}); - * </pre><div class="jxgbox" id="JXG7dcbb00e-b6ff-481d-b4a8-887f5d8c6a83" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * var c3_board = JXG.JSXGraph.initBoard('JXG7dcbb00e-b6ff-481d-b4a8-887f5d8c6a83', {boundingbox: [-1,10,10,-1], axis: true, showcopyright: false, shownavigation: false}); - * var x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; - * var y = [9.2, 1.3, 7.2, -1.2, 4.0, 5.3, 0.2, 6.5, 1.1, 0.0]; - * var graph3 = c3_board.create('curve', [x,y], {dash:2}); - * </script><pre> - * @example - * // Polar plot - * // Create a curve with the equation r(phi)= a*(1+phi), i.e. - * // a cardioid. - * var a = board.create('slider',[[0,2],[2,2],[0,1,2]]); - * var graph = board.create('curve', - * [function(phi){ return a.Value()*(1-Math.cos(phi));}, - * [1,0], - * 0, 2*Math.PI], - * {curveType: 'polar'} - * ); - * </pre><div class="jxgbox" id="JXGd0bc7a2a-8124-45ca-a6e7-142321a8f8c2" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * var c2_board = JXG.JSXGraph.initBoard('JXGd0bc7a2a-8124-45ca-a6e7-142321a8f8c2', {boundingbox: [-3,3,3,-3], axis: true, showcopyright: false, shownavigation: false}); - * var a = c2_board.create('slider',[[0,2],[2,2],[0,1,2]]); - * var graph2 = c2_board.create('curve', [function(phi){ return a.Value()*(1-Math.cos(phi));}, [1,0], 0, 2*Math.PI], {curveType: 'polar'}); - * </script><pre> - * - * @example - * // Draggable Bezier curve - * var col, p, c; - * col = 'blue'; - * p = []; - * p.push(board.create('point',[-2, -1 ], {size: 5, strokeColor:col, fillColor:col})); - * p.push(board.create('point',[1, 2.5 ], {size: 5, strokeColor:col, fillColor:col})); - * p.push(board.create('point',[-1, -2.5 ], {size: 5, strokeColor:col, fillColor:col})); - * p.push(board.create('point',[2, -2], {size: 5, strokeColor:col, fillColor:col})); - * - * c = board.create('curve', JXG.Math.Numerics.bezier(p), - * {strokeColor:'red', name:"curve", strokeWidth:5, fixed: false}); // Draggable curve - * c.addParents(p); - * </pre><div class="jxgbox" id="JXG7bcc6280-f6eb-433e-8281-c837c3387849" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function(){ - * var board, col, p, c; - * board = JXG.JSXGraph.initBoard('JXG7bcc6280-f6eb-433e-8281-c837c3387849', {boundingbox: [-3,3,3,-3], axis: true, showcopyright: false, shownavigation: false}); - * col = 'blue'; - * p = []; - * p.push(board.create('point',[-2, -1 ], {size: 5, strokeColor:col, fillColor:col})); - * p.push(board.create('point',[1, 2.5 ], {size: 5, strokeColor:col, fillColor:col})); - * p.push(board.create('point',[-1, -2.5 ], {size: 5, strokeColor:col, fillColor:col})); - * p.push(board.create('point',[2, -2], {size: 5, strokeColor:col, fillColor:col})); - * - * c = board.create('curve', JXG.Math.Numerics.bezier(p), - * {strokeColor:'red', name:"curve", strokeWidth:5, fixed: false}); // Draggable curve - * c.addParents(p); - * })(); - * </script><pre> - * - * @example - * // The curve cu2 is the reflection of cu1 against line li - * var li = board.create('line', [1,1,1], {strokeColor: '#aaaaaa'}); - * var reflect = board.create('transform', [li], {type: 'reflect'}); - * var cu1 = board.create('curve', [[-1, -1, -0.5, -1, -1, -0.5], [-3, -2, -2, -2, -2.5, -2.5]]); - * var cu2 = board.create('curve', [cu1, reflect], {strokeColor: 'red'}); - * - * </pre><div id="JXG866dc7a2-d448-11e7-93b3-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function() { - * var board = JXG.JSXGraph.initBoard('JXG866dc7a2-d448-11e7-93b3-901b0e1b8723', - * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); - * var li = board.create('line', [1,1,1], {strokeColor: '#aaaaaa'}); - * var reflect = board.create('transform', [li], {type: 'reflect'}); - * var cu1 = board.create('curve', [[-1, -1, -0.5, -1, -1, -0.5], [-3, -2, -2, -2, -2.5, -2.5]]); - * var cu2 = board.create('curve', [cu1, reflect], {strokeColor: 'red'}); - * - * })(); - * - * </script><pre> - */ - JXG.createCurve = function (board, parents, attributes) { - var obj, cu, - attr = Type.copyAttributes(attributes, board.options, 'curve'); + // selection + this._testForSelection(evt); + if (this.selectingMode) { + this._startSelecting(pos); + this.triggerEventHandlers(['mousestartselecting', 'startselecting'], [evt]); + return; // don't continue as a normal click + } - obj = board.select(parents[0], true); - if (Type.isObject(obj) && - (obj.type === Const.OBJECT_TYPE_CURVE || - obj.type === Const.OBJECT_TYPE_ANGLE || - obj.type === Const.OBJECT_TYPE_ARC || - obj.type === Const.OBJECT_TYPE_CONIC || - obj.type === Const.OBJECT_TYPE_SECTOR) && - Type.isTransformationOrArray(parents[1])) { + elements = this.initMoveObject(pos[0], pos[1], evt, 'mouse'); - if (obj.type === Const.OBJECT_TYPE_SECTOR) { - attr = Type.copyAttributes(attributes, board.options, 'sector'); - } else if (obj.type === Const.OBJECT_TYPE_ARC) { - attr = Type.copyAttributes(attributes, board.options, 'arc'); - } else if (obj.type === Const.OBJECT_TYPE_ANGLE) { - if (!Type.exists(attributes.withLabel)) { - attributes.withLabel = false; - } - attr = Type.copyAttributes(attributes, board.options, 'angle'); + // if no draggable object can be found, get out here immediately + if (elements.length === 0) { + this.mode = this.BOARD_MODE_NONE; + result = true; } else { - attr = Type.copyAttributes(attributes, board.options, 'curve'); - } - attr = Type.copyAttributes(attr, board.options, 'curve'); - - cu = new JXG.Curve(board, ['x', [], []], attr); - cu.updateDataArray = function() { - var i, le = obj.numberPoints; - this.bezierDegree = obj.bezierDegree; - this.dataX = []; - this.dataY = []; - for (i = 0; i < le; i++) { - this.dataX.push(obj.points[i].usrCoords[1]); - this.dataY.push(obj.points[i].usrCoords[2]); - } - return this; + /** @ignore */ + this.mouse = { + obj: null, + targets: [{ + X: pos[0], + Y: pos[1], + Xprev: NaN, + Yprev: NaN + }] }; - cu.addTransform(parents[1]); - obj.addChild(cu); - cu.setParents([obj]); - cu._transformationSource = obj; + this.mouse.obj = elements[elements.length - 1]; - return cu; - } - attr = Type.copyAttributes(attributes, board.options, 'curve'); - return new JXG.Curve(board, ['x'].concat(parents), attr); - }; + this.dehighlightAll(); + this.mouse.obj.highlight(true); - JXG.registerElement('curve', JXG.createCurve); + this.mouse.targets[0].Xstart = []; + this.mouse.targets[0].Ystart = []; + this.mouse.targets[0].Zstart = []; - /** - * @class This element is used to provide a constructor for functiongraph, - * which is just a wrapper for element {@link Curve} with {@link JXG.Curve#X}() - * set to x. The graph is drawn for x in the interval [a,b]. - * @pseudo - * @description - * @name Functiongraph - * @augments JXG.Curve - * @constructor - * @type JXG.Curve - * @param {function_number,function_number,function} f,a_,b_ Parent elements are a function term f(x) describing the function graph. - * <p> - * Further, an optional number or function for the left interval border a, - * and an optional number or function for the right interval border b. - * <p> - * Default values are a=-10 and b=10. - * @see JXG.Curve - * @example - * // Create a function graph for f(x) = 0.5*x*x-2*x - * var graph = board.create('functiongraph', - * [function(x){ return 0.5*x*x-2*x;}, -2, 4] - * ); - * </pre><div class="jxgbox" id="JXGefd432b5-23a3-4846-ac5b-b471e668b437" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * var alex1_board = JXG.JSXGraph.initBoard('JXGefd432b5-23a3-4846-ac5b-b471e668b437', {boundingbox: [-3, 7, 5, -3], axis: true, showcopyright: false, shownavigation: false}); - * var graph = alex1_board.create('functiongraph', [function(x){ return 0.5*x*x-2*x;}, -2, 4]); - * </script><pre> - * @example - * // Create a function graph for f(x) = 0.5*x*x-2*x with variable interval - * var s = board.create('slider',[[0,4],[3,4],[-2,4,5]]); - * var graph = board.create('functiongraph', - * [function(x){ return 0.5*x*x-2*x;}, - * -2, - * function(){return s.Value();}] - * ); - * </pre><div class="jxgbox" id="JXG4a203a84-bde5-4371-ad56-44619690bb50" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * var alex2_board = JXG.JSXGraph.initBoard('JXG4a203a84-bde5-4371-ad56-44619690bb50', {boundingbox: [-3, 7, 5, -3], axis: true, showcopyright: false, shownavigation: false}); - * var s = alex2_board.create('slider',[[0,4],[3,4],[-2,4,5]]); - * var graph = alex2_board.create('functiongraph', [function(x){ return 0.5*x*x-2*x;}, -2, function(){return s.Value();}]); - * </script><pre> - */ - JXG.createFunctiongraph = function (board, parents, attributes) { - var attr, - par = ['x', 'x'].concat(parents); + this.saveStartPos(this.mouse.obj, this.mouse.targets[0]); - attr = Type.copyAttributes(attributes, board.options, 'curve'); - attr.curvetype = 'functiongraph'; - return new JXG.Curve(board, par, attr); - }; + // prevent accidental text selection + // this could get us new trouble: input fields, links and drop down boxes placed as text + // on the board don't work anymore. + if (evt && evt.preventDefault) { + evt.preventDefault(); + } else if (window.event) { + window.event.returnValue = false; + } + } - JXG.registerElement('functiongraph', JXG.createFunctiongraph); - JXG.registerElement('plot', JXG.createFunctiongraph); + if (this.mode === this.BOARD_MODE_NONE) { + result = this.mouseOriginMoveStart(evt); + } - /** - * @class This element is used to provide a constructor for (natural) cubic spline curves. - * Create a dynamic spline interpolated curve given by sample points p_1 to p_n. - * @pseudo - * @description - * @name Spline - * @augments JXG.Curve - * @constructor - * @type JXG.Curve - * @param {JXG.Board} board Reference to the board the spline is drawn on. - * @param {Array} parents Array of points the spline interpolates. This can be - * <ul> - * <li> an array of JXGGraph points</li> - * <li> an array of coordinate pairs</li> - * <li> an array of functions returning coordinate pairs</li> - * <li> an array consisting of an array with x-coordinates and an array of y-coordinates</li> - * </ul> - * All individual entries of coordinates arrays may be numbers or functions returning numbers. - * @param {Object} attributes Define color, width, ... of the spline - * @returns {JXG.Curve} Returns reference to an object of type JXG.Curve. - * @see JXG.Curve - * @example - * - * var p = []; - * p[0] = board.create('point', [-2,2], {size: 4, face: 'o'}); - * p[1] = board.create('point', [0,-1], {size: 4, face: 'o'}); - * p[2] = board.create('point', [2,0], {size: 4, face: 'o'}); - * p[3] = board.create('point', [4,1], {size: 4, face: 'o'}); - * - * var c = board.create('spline', p, {strokeWidth:3}); - * </pre><div id="JXG6c197afc-e482-11e5-b1bf-901b0e1b8723" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function() { - * var board = JXG.JSXGraph.initBoard('JXG6c197afc-e482-11e5-b1bf-901b0e1b8723', - * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); - * - * var p = []; - * p[0] = board.create('point', [-2,2], {size: 4, face: 'o'}); - * p[1] = board.create('point', [0,-1], {size: 4, face: 'o'}); - * p[2] = board.create('point', [2,0], {size: 4, face: 'o'}); - * p[3] = board.create('point', [4,1], {size: 4, face: 'o'}); - * - * var c = board.create('spline', p, {strokeWidth:3}); - * })(); - * - * </script><pre> - * - */ - JXG.createSpline = function (board, parents, attributes) { - var el, funcs, ret; + this.triggerEventHandlers(['mousedown', 'down'], [evt]); - funcs = function () { - var D, x = [], y = []; + return result; + }, - return [function (t, suspended) { // Function term - var i, j, c; + /** + * This method is called by the browser when the mouse is moved. + * @param {Event} evt The browsers event object. + */ + mouseMoveListener: function (evt) { + var pos; - if (!suspended) { - x = []; - y = []; + if (!this.checkFrameRate(evt)) { + return false; + } - // given as [x[], y[]] - if (parents.length === 2 && Type.isArray(parents[0]) && Type.isArray(parents[1]) && parents[0].length === parents[1].length) { - for (i = 0; i < parents[0].length; i++) { - if (Type.isFunction(parents[0][i])) { - x.push(parents[0][i]()); - } else { - x.push(parents[0][i]); - } + pos = this.getMousePosition(evt); - if (Type.isFunction(parents[1][i])) { - y.push(parents[1][i]()); - } else { - y.push(parents[1][i]); - } - } - } else { - for (i = 0; i < parents.length; i++) { - if (Type.isPoint(parents[i])) { - x.push(parents[i].X()); - y.push(parents[i].Y()); - // given as [[x1,y1], [x2, y2], ...] - } else if (Type.isArray(parents[i]) && parents[i].length === 2) { - for (j = 0; j < parents.length; j++) { - if (Type.isFunction(parents[j][0])) { - x.push(parents[j][0]()); - } else { - x.push(parents[j][0]); - } + this.updateQuality = this.BOARD_QUALITY_LOW; - if (Type.isFunction(parents[j][1])) { - y.push(parents[j][1]()); - } else { - y.push(parents[j][1]); - } - } - } else if (Type.isFunction(parents[i]) && parents[i]().length === 2) { - c = parents[i](); - x.push(c[0]); - y.push(c[1]); - } - } - } + if (this.mode !== this.BOARD_MODE_DRAG) { + this.dehighlightAll(); + this.displayInfobox(false); + } - // The array D has only to be calculated when the position of one or more sample points - // changes. Otherwise D is always the same for all points on the spline. - D = Numerics.splineDef(x, y); - } + // we have to check for four cases: + // * user moves origin + // * user drags an object + // * user just moves the mouse, here highlight all elements at + // the current mouse position + // * the user is selecting - return Numerics.splineEval(t, x, y, D); - }, - // minX() - function() { - return x[0]; - }, - //maxX() - function() { - return x[x.length -1]; - }]; + // selection + if (this.selectingMode) { + this._moveSelecting(pos); + this.triggerEventHandlers(['mousemoveselecting', 'moveselecting'], [evt, this.mode]); + } else if (!this.mouseOriginMove(evt)) { + if (this.mode === this.BOARD_MODE_DRAG) { + this.moveObject(pos[0], pos[1], this.mouse, evt, 'mouse'); + } else { // BOARD_MODE_NONE + // Move event without dragging an element + this.highlightElements(pos[0], pos[1], evt, -1); + } + this.triggerEventHandlers(['mousemove', 'move'], [evt, this.mode]); + } + this.updateQuality = this.BOARD_QUALITY_HIGH; + }, - }; + /** + * This method is called by the browser when the mouse button is released. + * @param {Event} evt + */ + mouseUpListener: function (evt) { + var i; - attributes = Type.copyAttributes(attributes, board.options, 'curve'); - attributes.curvetype = 'functiongraph'; - ret = funcs(); - el = new JXG.Curve(board, ['x', 'x', ret[0], ret[1], ret[2]], attributes); - el.setParents(parents); - el.elType = 'spline'; + if (this.selectingMode === false) { + this.triggerEventHandlers(['mouseup', 'up'], [evt]); + } - return el; - }; + // redraw with high precision + this.updateQuality = this.BOARD_QUALITY_HIGH; - /** - * Register the element type spline at JSXGraph - * @private - */ - JXG.registerElement('spline', JXG.createSpline); + // if (this.mouse && this.mouse.obj) { + // // The parameter is needed for lines with snapToGrid enabled + // this.mouse.obj.snapToGrid(this.mouse.targets[0]); + // this.mouse.obj.snapToPoints(); + // } - /** - * @class This element is used to provide a constructor for cardinal spline curves. - * Create a dynamic cardinal spline interpolated curve given by sample points p_1 to p_n. - * @pseudo - * @description - * @name Cardinalspline - * @augments JXG.Curve - * @constructor - * @type JXG.Curve - * @param {JXG.Board} board Reference to the board the cardinal spline is drawn on. - * @param {Array} parents Array with three entries. - * <p> - * First entry: Array of points the spline interpolates. This can be - * <ul> - * <li> an array of JXGGraph points</li> - * <li> an array of coordinate pairs</li> - * <li> an array of functions returning coordinate pairs</li> - * <li> an array consisting of an array with x-coordinates and an array of y-coordinates</li> - * </ul> - * All individual entries of coordinates arrays may be numbers or functions returning numbers. - * <p> - * Second entry: tau number or function - * <p> - * Third entry: type string containing 'uniform' (default) or 'centripetal'. - * @param {Object} attributes Define color, width, ... of the cardinal spline - * @returns {JXG.Curve} Returns reference to an object of type JXG.Curve. - * @see JXG.Curve - * @example - * //create a cardinal spline out of an array of JXG points with adjustable tension - * //create array of points - * var p1 = board.create('point',[0,0]) - * var p2 = board.create('point',[1,4]) - * var p3 = board.create('point',[4,5]) - * var p4 = board.create('point',[2,3]) - * var p5 = board.create('point',[3,0]) - * var p = [p1,p2,p3,p4,p5] - * - * // tension - * tau = board.create('slider', [[4,3],[9,3],[0.001,0.5,1]], {name:'tau'}); - * c = board.create('curve', JXG.Math.Numerics.CardinalSpline(p, function(){ return tau.Value();}), {strokeWidth:3}); - * </pre><div id="JXG6c197afc-e482-11e5-b2af-901b0e1b8723" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function() { - * var board = JXG.JSXGraph.initBoard('JXG6c197afc-e482-11e5-b2af-901b0e1b8723', - * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); - * - * var p = []; - * p[0] = board.create('point', [-2,2], {size: 4, face: 'o'}); - * p[1] = board.create('point', [0,-1], {size: 4, face: 'o'}); - * p[2] = board.create('point', [2,0], {size: 4, face: 'o'}); - * p[3] = board.create('point', [4,1], {size: 4, face: 'o'}); - * - * var c = board.create('spline', p, {strokeWidth:3}); - * })(); - * - * </script><pre> - */ - JXG.createCardinalSpline = function (board, parents, attributes) { - var el, - points, tau, type, - p, q, i, le, - splineArr, - errStr = "\nPossible parent types: [points:array, tau:number|function, type:string]"; + this.originMoveEnd(); + this.dehighlightAll(); + this.update(); - if (!Type.exists(parents[0]) || !Type.isArray(parents[0])) { - throw new Error("JSXGraph: JXG.createCardinalSpline: argument 1 'points' has to be array of points or coordinate pairs" + errStr); - } - if (!Type.exists(parents[1]) || (!Type.isNumber(parents[1]) && !Type.isFunction(parents[1]))) { - throw new Error("JSXGraph: JXG.createCardinalSpline: argument 2 'tau' has to be number between [0,1] or function'" + errStr); - } - if (!Type.exists(parents[2]) || !Type.isString(parents[2])) { - throw new Error("JSXGraph: JXG.createCardinalSpline: argument 3 'type' has to be string 'uniform' or 'centripetal'" + errStr); - } + // selection + if (this.selectingMode) { + this._stopSelecting(evt); + this.triggerEventHandlers(['mousestopselecting', 'stopselecting'], [evt]); + this.stopSelectionMode(); + } else { + for (i = 0; i < this.downObjects.length; i++) { + this.downObjects[i].triggerEventHandlers(['mouseup', 'up'], [evt]); + } + } - attributes = Type.copyAttributes(attributes, board.options, 'curve'); - attributes = Type.copyAttributes(attributes, board.options, 'cardinalspline'); - attributes.curvetype = 'parameter'; + this.downObjects.length = 0; - p = parents[0]; - q = []; + if (this.hasMouseUp) { + Env.removeEvent(this.document, 'mouseup', this.mouseUpListener, this); + this.hasMouseUp = false; + } - // given as [x[], y[]] - if (!attributes.isarrayofcoordinates && - p.length === 2 && Type.isArray(p[0]) && Type.isArray(p[1]) && - p[0].length === p[1].length) { - for (i = 0; i < p[0].length; i++) { - q[i] = []; - if (Type.isFunction(p[0][i])) { - q[i].push(p[0][i]()); - } else { - q[i].push(p[0][i]); - } + // release dragged mouse object + /** @ignore */ + this.mouse = null; + }, - if (Type.isFunction(p[1][i])) { - q[i].push(p[1][i]()); - } else { - q[i].push(p[1][i]); - } + /** + * Handler for mouse wheel events. Used to zoom in and out of the board. + * @param {Event} evt + * @returns {Boolean} + */ + mouseWheelListener: function (evt) { + if (!this.attr.zoom.wheel || !this._isRequiredKeyPressed(evt, 'zoom')) { + return true; } - } else { - // given as [[x0, y0], [x1, y1], point, ...] - for (i = 0; i < p.length; i++) { - if (Type.isString(p[i])) { - q.push(board.select(p[i])); - } else if (Type.isPoint(p[i])) { - q.push(p[i]); - // given as [[x0,y0], [x1, y2], ...] - } else if (Type.isArray(p[i]) && p[i].length === 2) { - q[i] = []; - if (Type.isFunction(p[i][0])) { - q[i].push(p[i][0]()); - } else { - q[i].push(p[i][0]); - } - if (Type.isFunction(p[i][1])) { - q[i].push(p[i][1]()); - } else { - q[i].push(p[i][1]); - } - } else if (Type.isFunction(p[i]) && p[i]().length === 2) { - q.push(parents[i]()); - } - } - } + evt = evt || window.event; + var wd = evt.detail ? -evt.detail : evt.wheelDelta / 40, + pos = new Coords(Const.COORDS_BY_SCREEN, this.getMousePosition(evt), this); - if (attributes.createpoints === true) { - points = Type.providePoints(board, q, attributes, 'cardinalspline', ['points']); - } else { - points = []; - for (i = 0; i < q.length; i++) { - if (Type.isPoint(q[i])) { - points.push(q[i]); - } else { - points.push( - (function(ii) { return { - X: function() { return q[ii][0]; }, - Y: function() { return q[ii][1]; }, - Dist: function(p) { - var dx = this.X() - p.X(), - dy = this.Y() - p.Y(); - return Math.sqrt(dx * dx + dy * dy); - } - }; - })(i) - ); - } + if (wd > 0) { + this.zoomIn(pos.usrCoords[1], pos.usrCoords[2]); + } else { + this.zoomOut(pos.usrCoords[1], pos.usrCoords[2]); } - } - tau = parents[1]; - type = parents[2]; + this.triggerEventHandlers(['mousewheel'], [evt]); - splineArr = ['x'].concat(Numerics.CardinalSpline(points, tau, type)); + evt.preventDefault(); + return false; + }, - el = new JXG.Curve(board, splineArr, attributes); - le = points.length; - el.setParents(points); - for (i = 0; i < le; i++) { - if (Type.isPoint(points[i])) { - points[i].addChild(el); + /** + * Allow moving of JSXGraph elements with arrow keys + * and zooming of the construction with + / -. + * Panning of the construction is done with arrow keys + * if the pan key (shift or ctrl) is pressed. + * The selection of the element is done with the tab key. + * + * @param {Event} evt The browser's event object + * + * @see JXG.Board#keyboard + * @see JXG.Board#keyFocusInListener + * @see JXG.Board#keyFocusOutListener + * + */ + keyDownListener: function (evt) { + var id_node = evt.target.id, + id, el, res, + sX = 0, + sY = 0, + // dx, dy are provided in screen units and + // are converted to user coordinates + dx = Type.evaluate(this.attr.keyboard.dx) / this.unitX, + dy = Type.evaluate(this.attr.keyboard.dy) / this.unitY, + doZoom = false, + done = true, + dir, actPos; + + if (!this.attr.keyboard.enabled || id_node === '') { + return false; } - } - el.elType = 'cardinalspline'; - return el; - }; + // Get the JSXGraph id from the id of the SVG node. + id = id_node.replace(this.containerObj.id + '_', ''); + el = this.select(id); - /** - * Register the element type cardinalspline at JSXGraph - * @private - */ - JXG.registerElement('cardinalspline', JXG.createCardinalSpline); + if (Type.exists(el.coords)) { + actPos = el.coords.usrCoords.slice(1); + } - /** - * @class This element is used to provide a constructor for metapost spline curves. - * Create a dynamic metapost spline interpolated curve given by sample points p_1 to p_n. - * @pseudo - * @description - * @name Metapostspline - * @augments JXG.Curve - * @constructor - * @type JXG.Curve - * @param {JXG.Board} board Reference to the board the metapost spline is drawn on. - * @param {Array} parents Array with two entries. - * <p> - * First entry: Array of points the spline interpolates. This can be - * <ul> - * <li> an array of JXGGraph points</li> - * <li> an object of coordinate pairs</li> - * <li> an array of functions returning coordinate pairs</li> - * <li> an array consisting of an array with x-coordinates and an array of y-coordinates</li> - * </ul> - * All individual entries of coordinates arrays may be numbers or functions returning numbers. - * <p> - * Second entry: JavaScript object containing the control values like tension, direction, curl. - * @param {Object} attributes Define color, width, ... of the metapost spline - * @returns {JXG.Curve} Returns reference to an object of type JXG.Curve. - * @see JXG.Curve - * @example - * var po = [], - * attr = { - * size: 5, - * color: 'red' - * }, - * controls; - * - * var tension = board.create('slider', [[-3, 6], [3, 6], [0, 1, 20]], {name: 'tension'}); - * var curl = board.create('slider', [[-3, 5], [3, 5], [0, 1, 30]], {name: 'curl A, D'}); - * var dir = board.create('slider', [[-3, 4], [3, 4], [-180, 0, 180]], {name: 'direction B'}); - * - * po.push(board.create('point', [-3, -3])); - * po.push(board.create('point', [0, -3])); - * po.push(board.create('point', [4, -5])); - * po.push(board.create('point', [6, -2])); - * - * var controls = { - * tension: function() {return tension.Value(); }, - * direction: { 1: function() {return dir.Value(); } }, - * curl: { 0: function() {return curl.Value(); }, - * 3: function() {return curl.Value(); } - * }, - * isClosed: false - * }; - * - * // Plot a metapost curve - * var cu = board.create('metapostspline', [po, controls], {strokeColor: 'blue', strokeWidth: 2}); - * - * - * </pre><div id="JXGb8c6ffed-7419-41a3-9e55-3754b2327ae9" class="jxgbox" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function() { - * var board = JXG.JSXGraph.initBoard('JXGb8c6ffed-7419-41a3-9e55-3754b2327ae9', - * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); - * var po = [], - * attr = { - * size: 5, - * color: 'red' - * }, - * controls; - * - * var tension = board.create('slider', [[-3, 6], [3, 6], [0, 1, 20]], {name: 'tension'}); - * var curl = board.create('slider', [[-3, 5], [3, 5], [0, 1, 30]], {name: 'curl A, D'}); - * var dir = board.create('slider', [[-3, 4], [3, 4], [-180, 0, 180]], {name: 'direction B'}); - * - * po.push(board.create('point', [-3, -3])); - * po.push(board.create('point', [0, -3])); - * po.push(board.create('point', [4, -5])); - * po.push(board.create('point', [6, -2])); - * - * var controls = { - * tension: function() {return tension.Value(); }, - * direction: { 1: function() {return dir.Value(); } }, - * curl: { 0: function() {return curl.Value(); }, - * 3: function() {return curl.Value(); } - * }, - * isClosed: false - * }; - * - * // Plot a metapost curve - * var cu = board.create('metapostspline', [po, controls], {strokeColor: 'blue', strokeWidth: 2}); - * - * - * })(); - * - * </script><pre> - * - */ - JXG.createMetapostSpline = function (board, parents, attributes) { - var el, - points, controls, - p, q, i, le, - errStr = "\nPossible parent types: [points:array, controls:object"; + if (Type.evaluate(this.attr.keyboard.panshift) || Type.evaluate(this.attr.keyboard.panctrl)) { + doZoom = true; + } - if (!Type.exists(parents[0]) || !Type.isArray(parents[0])) { - throw new Error("JSXGraph: JXG.createMetapostSpline: argument 1 'points' has to be array of points or coordinate pairs" + errStr); - } - if (!Type.exists(parents[1]) || !Type.isObject(parents[1])) { - throw new Error("JSXGraph: JXG.createMetapostSpline: argument 2 'controls' has to be a JavaScript object'" + errStr); - } + if ((Type.evaluate(this.attr.keyboard.panshift) && evt.shiftKey) || + (Type.evaluate(this.attr.keyboard.panctrl) && evt.ctrlKey)) { + if (evt.keyCode === 38) { // up + this.clickUpArrow(); + } else if (evt.keyCode === 40) { // down + this.clickDownArrow(); + } else if (evt.keyCode === 37) { // left + this.clickLeftArrow(); + } else if (evt.keyCode === 39) { // right + this.clickRightArrow(); + } else { + done = false; + } + } else { + // Adapt dx, dy to snapToGrid and attractToGrid + // snapToGrid has priority. + if (Type.exists(el.visProp)) { + if (Type.exists(el.visProp.snaptogrid) && + el.visProp.snaptogrid && + Type.evaluate(el.visProp.snapsizex) && + Type.evaluate(el.visProp.snapsizey)) { + + // Adapt dx, dy such that snapToGrid is possible + res = el.getSnapSizes(); + sX = res[0]; + sY = res[1]; + dx = Math.max(sX, dx); + dy = Math.max(sY, dy); + + } else if (Type.exists(el.visProp.attracttogrid) && + el.visProp.attracttogrid && + Type.evaluate(el.visProp.attractordistance) && + Type.evaluate(el.visProp.attractorunit)) { + + // Adapt dx, dy such that attractToGrid is possible + sX = 1.1 * Type.evaluate(el.visProp.attractordistance); + sY = sX; + + if (Type.evaluate(el.visProp.attractorunit) === 'screen') { + sX /= this.unitX; + sY /= this.unitX; + } + dx = Math.max(sX, dx); + dy = Math.max(sY, dy); + } - attributes = Type.copyAttributes(attributes, board.options, 'curve'); - attributes = Type.copyAttributes(attributes, board.options, 'metapostspline'); - attributes.curvetype = 'parameter'; + } - p = parents[0]; - q = []; + if (evt.keyCode === 38) { // up + dir = [0, dy]; + } else if (evt.keyCode === 40) { // down + dir = [0, -dy]; + } else if (evt.keyCode === 37) { // left + dir = [-dx, 0]; + } else if (evt.keyCode === 39) { // right + dir = [dx, 0]; + // } else if (evt.keyCode === 9) { // tab - // given as [x[], y[]] - if (!attributes.isarrayofcoordinates && - p.length === 2 && Type.isArray(p[0]) && Type.isArray(p[1]) && - p[0].length === p[1].length) { - for (i = 0; i < p[0].length; i++) { - q[i] = []; - if (Type.isFunction(p[0][i])) { - q[i].push(p[0][i]()); + } else if (doZoom && evt.key === '+') { // + + this.zoomIn(); + } else if (doZoom && evt.key === '-') { // - + this.zoomOut(); + } else if (doZoom && evt.key === 'o') { // o + this.zoom100(); } else { - q[i].push(p[0][i]); + done = false; } - if (Type.isFunction(p[1][i])) { - q[i].push(p[1][i]()); - } else { - q[i].push(p[1][i]); - } - } - } else { - // given as [[x0, y0], [x1, y1], point, ...] - for (i = 0; i < p.length; i++) { - if (Type.isString(p[i])) { - q.push(board.select(p[i])); - } else if (Type.isPoint(p[i])) { - q.push(p[i]); - // given as [[x0,y0], [x1, y2], ...] - } else if (Type.isArray(p[i]) && p[i].length === 2) { - q[i] = []; - if (Type.isFunction(p[i][0])) { - q[i].push(p[i][0]()); - } else { - q[i].push(p[i][0]); - } + if (dir && el.isDraggable && + el.visPropCalc.visible && + ((this.geonextCompatibilityMode && + (Type.isPoint(el) || + el.elementClass === Const.OBJECT_CLASS_TEXT) + ) || !this.geonextCompatibilityMode) && + !Type.evaluate(el.visProp.fixed) + ) { - if (Type.isFunction(p[i][1])) { - q[i].push(p[i][1]()); - } else { - q[i].push(p[i][1]); + if (Type.exists(el.coords)) { + dir[0] += actPos[0]; + dir[1] += actPos[1]; } - } else if (Type.isFunction(p[i]) && p[i]().length === 2) { - q.push(parents[i]()); + // For coordsElement setPosition has to call setPositionDirectly. + // Otherwise the position is set by a translation. + el.setPosition(JXG.COORDS_BY_USER, dir); + if (Type.exists(el.coords)) { + this.updateInfobox(el); + } + this.triggerEventHandlers(['hit'], [evt, el]); } } - } - if (attributes.createpoints === true) { - points = Type.providePoints(board, q, attributes, 'metapostspline', ['points']); - } else { - points = []; - for (i = 0; i < q.length; i++) { - if (Type.isPoint(q[i])) { - points.push(q[i]); - } else { - points.push( - (function(ii) { return { - X: function() { return q[ii][0]; }, - Y: function() { return q[ii][1]; } - }; - })(i) - ); - } - } - } + this.update(); - controls = parents[1]; + if (done && Type.exists(evt.preventDefault)) { + evt.preventDefault(); + } + return true; + }, - el = new JXG.Curve(board, ['t', [], [], 0, p.length - 1], attributes); - el.updateDataArray = function () { - var res, i, - len = points.length, - p = []; + /** + * Event listener for SVG elements getting focus. + * This is needed for highlighting when using keyboard control. + * + * @see JXG.Board#keyFocusOutListener + * @see JXG.Board#keyDownListener + * @see JXG.Board#keyboard + * + * @param {Event} evt The browser's event object + */ + keyFocusInListener: function (evt) { + var id_node = evt.target.id, + id, el; - for (i = 0; i < len; i++) { - p.push([points[i].X(), points[i].Y()]); + if (!this.attr.keyboard.enabled || id_node === '') { + return false; } - res = JXG.Math.Metapost.curve(p, controls); - this.dataX = res[0]; - this.dataY = res[1]; - }; - el.bezierDegree = 3; - - le = points.length; - el.setParents(points); - for (i = 0; i < le; i++) { - if (Type.isPoint(points[i])) { - points[i].addChild(el); + id = id_node.replace(this.containerObj.id + '_', ''); + el = this.select(id); + if (Type.exists(el.highlight)) { + el.highlight(true); } - } - el.elType = 'metapostspline'; + if (Type.exists(el.coords)) { + this.updateInfobox(el); + } + this.triggerEventHandlers(['hit'], [evt, el]); + }, - return el; - }; + /** + * Event listener for SVG elements losing focus. + * This is needed for dehighlighting when using keyboard control. + * + * @see JXG.Board#keyFocusInListener + * @see JXG.Board#keyDownListener + * @see JXG.Board#keyboard + * + * @param {Event} evt The browser's event object + */ + keyFocusOutListener: function (evt) { + if (!this.attr.keyboard.enabled) { + return false; + } + // var id_node = evt.target.id, + // id, el; - JXG.registerElement('metapostspline', JXG.createMetapostSpline); + // id = id_node.replace(this.containerObj.id + '_', ''); + // el = this.select(id); + this.dehighlightAll(); + this.displayInfobox(false); + }, + /** + * Update the width and height of the JSXGraph container div element. + * Read actual values with getBoundingClientRect(), + * and call board.resizeContainer() with this values. + * <p> + * If necessary, also call setBoundingBox(). + * + * @see JXG.Board#startResizeObserver + * @see JXG.Board#resizeListener + * @see JXG.Board#resizeContainer + * @see JXG.Board#setBoundingBox + * + */ + updateContainerDims: function() { + var w, h, + bb, css; - /** - * @class This element is used to provide a constructor for Riemann sums, which is realized as a special curve. - * The returned element has the method Value() which returns the sum of the areas of the bars. - * @pseudo - * @description - * @name Riemannsum - * @augments JXG.Curve - * @constructor - * @type JXG.Curve - * @param {function,array_number,function_string,function_function,number_function,number} f,n,type_,a_,b_ Parent elements of Riemannsum are a - * Either a function term f(x) describing the function graph which is filled by the Riemann bars, or - * an array consisting of two functions and the area between is filled by the Riemann bars. - * <p> - * n determines the number of bars, it is either a fixed number or a function. - * <p> - * type is a string or function returning one of the values: 'left', 'right', 'middle', 'lower', 'upper', 'random', 'simpson', or 'trapezoidal'. - * Default value is 'left'. - * <p> - * Further parameters are an optional number or function for the left interval border a, - * and an optional number or function for the right interval border b. - * <p> - * Default values are a=-10 and b=10. - * @see JXG.Curve - * @example - * // Create Riemann sums for f(x) = 0.5*x*x-2*x. - * var s = board.create('slider',[[0,4],[3,4],[0,4,10]],{snapWidth:1}); - * var f = function(x) { return 0.5*x*x-2*x; }; - * var r = board.create('riemannsum', - * [f, function(){return s.Value();}, 'upper', -2, 5], - * {fillOpacity:0.4} - * ); - * var g = board.create('functiongraph',[f, -2, 5]); - * var t = board.create('text',[-2,-2, function(){ return 'Sum=' + JXG.toFixed(r.Value(), 4); }]); - * </pre><div class="jxgbox" id="JXG940f40cc-2015-420d-9191-c5d83de988cf" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function(){ - * var board = JXG.JSXGraph.initBoard('JXG940f40cc-2015-420d-9191-c5d83de988cf', {boundingbox: [-3, 7, 5, -3], axis: true, showcopyright: false, shownavigation: false}); - * var f = function(x) { return 0.5*x*x-2*x; }; - * var s = board.create('slider',[[0,4],[3,4],[0,4,10]],{snapWidth:1}); - * var r = board.create('riemannsum', [f, function(){return s.Value();}, 'upper', -2, 5], {fillOpacity:0.4}); - * var g = board.create('functiongraph', [f, -2, 5]); - * var t = board.create('text',[-2,-2, function(){ return 'Sum=' + JXG.toFixed(r.Value(), 4); }]); - * })(); - * </script><pre> - * - * @example - * // Riemann sum between two functions - * var s = board.create('slider',[[0,4],[3,4],[0,4,10]],{snapWidth:1}); - * var g = function(x) { return 0.5*x*x-2*x; }; - * var f = function(x) { return -x*(x-4); }; - * var r = board.create('riemannsum', - * [[g,f], function(){return s.Value();}, 'lower', 0, 4], - * {fillOpacity:0.4} - * ); - * var f = board.create('functiongraph',[f, -2, 5]); - * var g = board.create('functiongraph',[g, -2, 5]); - * var t = board.create('text',[-2,-2, function(){ return 'Sum=' + JXG.toFixed(r.Value(), 4); }]); - * </pre><div class="jxgbox" id="JXGf9a7ba38-b50f-4a32-a873-2f3bf9caee79" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function(){ - * var board = JXG.JSXGraph.initBoard('JXGf9a7ba38-b50f-4a32-a873-2f3bf9caee79', {boundingbox: [-3, 7, 5, -3], axis: true, showcopyright: false, shownavigation: false}); - * var s = board.create('slider',[[0,4],[3,4],[0,4,10]],{snapWidth:1}); - * var g = function(x) { return 0.5*x*x-2*x; }; - * var f = function(x) { return -x*(x-4); }; - * var r = board.create('riemannsum', - * [[g,f], function(){return s.Value();}, 'lower', 0, 4], - * {fillOpacity:0.4} - * ); - * var f = board.create('functiongraph',[f, -2, 5]); - * var g = board.create('functiongraph',[g, -2, 5]); - * var t = board.create('text',[-2,-2, function(){ return 'Sum=' + JXG.toFixed(r.Value(), 4); }]); - * })(); - * </script><pre> - */ - JXG.createRiemannsum = function (board, parents, attributes) { - var n, type, f, par, c, attr; + // Get size of the board's container div + bb = this.containerObj.getBoundingClientRect(); + w = bb.width; + h = bb.height; - attr = Type.copyAttributes(attributes, board.options, 'riemannsum'); - attr.curvetype = 'plot'; + // Subtract the border size + if (window && window.getComputedStyle) { + css = window.getComputedStyle(this.containerObj, null); + w -= parseFloat(css.getPropertyValue('border-left-width')) + parseFloat(css.getPropertyValue('border-right-width')); + h -= parseFloat(css.getPropertyValue('border-top-width')) + parseFloat(css.getPropertyValue('border-bottom-width')); + } - f = parents[0]; - n = Type.createFunction(parents[1], board, ''); + // If div is invisible - do nothing + if (w <= 0 || h <= 0 || Type.isNaN(w) || Type.isNaN(h)) { + return; + } - if (!Type.exists(n)) { - throw new Error("JSXGraph: JXG.createRiemannsum: argument '2' n has to be number or function." + - "\nPossible parent types: [function,n:number|function,type,start:number|function,end:number|function]"); - } + // If bounding box is not yet initialized, do it now. + if (isNaN(this.getBoundingBox()[0])) { + this.setBoundingBox(this.attr.boundingbox, this.keepaspectratio, 'keep'); + } - type = Type.createFunction(parents[2], board, '', false); - if (!Type.exists(type)) { - throw new Error("JSXGraph: JXG.createRiemannsum: argument 3 'type' has to be string or function." + - "\nPossible parent types: [function,n:number|function,type,start:number|function,end:number|function]"); - } + // Do nothing if the dimension did not change since being visible + // the last time. Note that if the div had display:none in the mean time, + // we did not store this._prevDim. + if (Type.exists(this._prevDim) && + this._prevDim.w === w && this._prevDim.h === h) { + return; + } - par = [[0], [0]].concat(parents.slice(3)); + // Set the size of the SVG or canvas element + this.resizeContainer(w, h, true); + this._prevDim = { + w: w, + h: h + }; + }, - c = board.create('curve', par, attr); - - c.sum = 0.0; /** - * Returns the value of the Riemann sum, i.e. the sum of the (signed) areas of the rectangles. - * @name Value - * @memberOf Riemann.prototype - * @function - * @returns {Number} value of Riemann sum. + * Start observer which reacts to size changes of the JSXGraph + * container div element. Calls updateContainerDims(). + * If not available, an event listener for the window-resize event is started. + * On mobile devices also scrolling might trigger resizes. + * However, resize events triggered by scrolling events should be ignored. + * Therefore, also a scrollListener is started. + * Resize can be controlled with the board attribute resize. + * + * @see JXG.Board#updateContainerDims + * @see JXG.Board#resizeListener + * @see JXG.Board#scrollListener + * @see JXG.Board#resize + * */ - c.Value = function () { - return this.sum; - }; - - c.updateDataArray = function () { - var u = Numerics.riemann(f, n(), type(), this.minX(), this.maxX()); - this.dataX = u[0]; - this.dataY = u[1]; + startResizeObserver: function() { + var that = this; - // Update "Riemann sum" - this.sum = u[2]; - }; + if (!Env.isBrowser || !this.attr.resize || !this.attr.resize.enabled) { + return; + } - return c; - }; + this.resizeObserver = new ResizeObserver(function(entries) { + if (!that._isResizing) { + that._isResizing = true; + window.setTimeout(function() { + try { + that.updateContainerDims(); + } catch (err) { + that.stopResizeObserver(); + } finally { + that._isResizing = false; + } + }, that.attr.resize.throttle); + } + }); + this.resizeObserver.observe(this.containerObj); + }, - JXG.registerElement('riemannsum', JXG.createRiemannsum); + /** + * Stops the resize observer. + * @see JXG.Board#startResizeObserver + * + */ + stopResizeObserver: function() { + if (!Env.isBrowser || !this.attr.resize || !this.attr.resize.enabled) { + return; + } - /** - * @class This element is used to provide a constructor for trace curve (simple locus curve), which is realized as a special curve. - * @pseudo - * @description - * @name Tracecurve - * @augments JXG.Curve - * @constructor - * @type JXG.Curve - * @param {Point,Point} Parent elements of Tracecurve are a - * glider point and a point whose locus is traced. - * @see JXG.Curve - * @example - * // Create trace curve. - * var c1 = board.create('circle',[[0, 0], [2, 0]]), - * p1 = board.create('point',[-3, 1]), - * g1 = board.create('glider',[2, 1, c1]), - * s1 = board.create('segment',[g1, p1]), - * p2 = board.create('midpoint',[s1]), - * curve = board.create('tracecurve', [g1, p2]); - * - * </pre><div class="jxgbox" id="JXG5749fb7d-04fc-44d2-973e-45c1951e29ad" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * var tc1_board = JXG.JSXGraph.initBoard('JXG5749fb7d-04fc-44d2-973e-45c1951e29ad', {boundingbox: [-4, 4, 4, -4], axis: false, showcopyright: false, shownavigation: false}); - * var c1 = tc1_board.create('circle',[[0, 0], [2, 0]]), - * p1 = tc1_board.create('point',[-3, 1]), - * g1 = tc1_board.create('glider',[2, 1, c1]), - * s1 = tc1_board.create('segment',[g1, p1]), - * p2 = tc1_board.create('midpoint',[s1]), - * curve = tc1_board.create('tracecurve', [g1, p2]); - * </script><pre> - */ - JXG.createTracecurve = function (board, parents, attributes) { - var c, glider, tracepoint, attr; + if (Type.exists(this.resizeObserver)) { + this.resizeObserver.unobserve(this.containerObj); + } + }, - if (parents.length !== 2) { - throw new Error("JSXGraph: Can't create trace curve with given parent'" + - "\nPossible parent types: [glider, point]"); - } + /** + * Fallback solutions if there is no resizeObserver available in the browser. + * Reacts to resize events of the window (only). Otherwise similar to + * startResizeObserver(). To handle changes of the visibility + * of the JSXGraph container element, additionally an intersection observer is used. + * which watches changes in the visibility of the JSXGraph container element. + * This is necessary e.g. for register tabs or dia shows. + * + * @see JXG.Board#startResizeObserver + * @see JXG.Board#startIntersectionObserver + */ + resizeListener: function() { + var that = this; - glider = board.select(parents[0]); - tracepoint = board.select(parents[1]); + if (!Env.isBrowser || !this.attr.resize || !this.attr.resize.enabled) { + return; + } + if (!this._isScrolling && !this._isResizing) { + this._isResizing = true; + window.setTimeout(function() { + that.updateContainerDims(); + that._isResizing = false; + }, this.attr.resize.throttle); + } + }, - if (glider.type !== Const.OBJECT_TYPE_GLIDER || !Type.isPoint(tracepoint)) { - throw new Error("JSXGraph: Can't create trace curve with parent types '" + - (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + - "\nPossible parent types: [glider, point]"); - } + /** + * Listener to watch for scroll events. Sets board._isScrolling = true + * @param {Event} evt The browser's event object + * + * @see JXG.Board#startResizeObserver + * @see JXG.Board#resizeListener + * + */ + scrollListener: function(evt) { + var that = this; - attr = Type.copyAttributes(attributes, board.options, 'tracecurve'); - attr.curvetype = 'plot'; - c = board.create('curve', [[0], [0]], attr); + if (!Env.isBrowser) { + return; + } + if (!this._isScrolling) { + this._isScrolling = true; + window.setTimeout(function() { + that._isScrolling = false; + }, 66); + } + }, - c.updateDataArray = function () { - var i, step, t, el, pEl, x, y, from, savetrace, - le = attr.numberpoints, - savePos = glider.position, - slideObj = glider.slideObject, - mi = slideObj.minX(), - ma = slideObj.maxX(); + /** + * Watch for changes of the visibility of the JSXGraph container element. + * + * @see JXG.Board#startResizeObserver + * @see JXG.Board#resizeListener + * + */ + startIntersectionObserver: function() { + var that = this, + options = { + root: null, + rootMargin: '0px', + threshold: 0.8 + }; - // set step width - step = (ma - mi) / le; - this.dataX = []; - this.dataY = []; + try { + this.intersectionObserver = new IntersectionObserver(function(entries) { + // If bounding box is not yet initialized, do it now. + if (isNaN(that.getBoundingBox()[0])) { + that.updateContainerDims(); + } + }, options); + this.intersectionObserver.observe(that.containerObj); + } catch (err) { + console.log('JSXGraph: IntersectionObserver not available in this browser.'); + } + }, - /* - * For gliders on circles and lines a closed curve is computed. - * For gliders on curves the curve is not closed. - */ - if (slideObj.elementClass !== Const.OBJECT_CLASS_CURVE) { - le++; + /** + * Stop the intersection observer + * + * @see JXG.Board#startIntersectionObserver + * + */ + stopIntersectionObserver: function() { + if (Type.exists(this.intersectionObserver)) { + this.intersectionObserver.unobserve(this.containerObj); } + }, - // Loop over all steps - for (i = 0; i < le; i++) { - t = mi + i * step; - x = slideObj.X(t) / slideObj.Z(t); - y = slideObj.Y(t) / slideObj.Z(t); + /********************************************************** + * + * End of Event Handlers + * + **********************************************************/ - // Position the glider - glider.setPositionDirectly(Const.COORDS_BY_USER, [x, y]); - from = false; + /** + * Initialize the info box object which is used to display + * the coordinates of points near the mouse pointer, + * @returns {JXG.Board} Reference to the board + */ + initInfobox: function () { + var attr = Type.copyAttributes({}, this.options, 'infobox'); - // Update all elements from the glider up to the trace element - for (el in this.board.objects) { - if (this.board.objects.hasOwnProperty(el)) { - pEl = this.board.objects[el]; + attr.id = this.id + '_infobox'; + /** + * Infobox close to points in which the points' coordinates are displayed. + * This is simply a JXG.Text element. Access through board.infobox. + * Uses CSS class .JXGinfobox. + * @type JXG.Text + * + */ + this.infobox = this.create('text', [0, 0, '0,0'], attr); - if (pEl === glider) { - from = true; - } + this.infobox.distanceX = -20; + this.infobox.distanceY = 25; + // this.infobox.needsUpdateSize = false; // That is not true, but it speeds drawing up. - if (from && pEl.needsRegularUpdate) { - // Save the trace mode of the element - savetrace = pEl.visProp.trace; - pEl.visProp.trace = false; - pEl.needsUpdate = true; - pEl.update(true); + this.infobox.dump = false; - // Restore the trace mode - pEl.visProp.trace = savetrace; - if (pEl === tracepoint) { - break; - } - } - } - } + this.displayInfobox(false); + return this; + }, - // Store the position of the trace point - this.dataX[i] = tracepoint.X(); - this.dataY[i] = tracepoint.Y(); - } + /** + * Updates and displays a little info box to show coordinates of current selected points. + * @param {JXG.GeometryElement} el A GeometryElement + * @returns {JXG.Board} Reference to the board + * @see JXG.Board#displayInfobox + * @see JXG.Board#showInfobox + * @see Point#showInfobox + * + */ + updateInfobox: function (el) { + var x, y, xc, yc, + vpinfoboxdigits, + vpsi = Type.evaluate(el.visProp.showinfobox); - // Restore the original position of the glider - glider.position = savePos; - from = false; + if ((!Type.evaluate(this.attr.showinfobox) && vpsi === 'inherit') || + !vpsi) { + return this; + } - // Update all elements from the glider to the trace point - for (el in this.board.objects) { - if (this.board.objects.hasOwnProperty(el)) { - pEl = this.board.objects[el]; - if (pEl === glider) { - from = true; - } + if (Type.isPoint(el)) { + xc = el.coords.usrCoords[1]; + yc = el.coords.usrCoords[2]; - if (from && pEl.needsRegularUpdate) { - savetrace = pEl.visProp.trace; - pEl.visProp.trace = false; - pEl.needsUpdate = true; - pEl.update(true); - pEl.visProp.trace = savetrace; + vpinfoboxdigits = Type.evaluate(el.visProp.infoboxdigits); + this.infobox.setCoords(xc + this.infobox.distanceX / this.unitX, + yc + this.infobox.distanceY / this.unitY); - if (pEl === tracepoint) { - break; - } + if (typeof el.infoboxText !== 'string') { + if (vpinfoboxdigits === 'auto') { + x = Type.autoDigits(xc); + y = Type.autoDigits(yc); + } else if (Type.isNumber(vpinfoboxdigits)) { + x = Type.toFixed(xc, vpinfoboxdigits); + y = Type.toFixed(yc, vpinfoboxdigits); + } else { + x = xc; + y = yc; } + + this.highlightInfobox(x, y, el); + } else { + this.highlightCustomInfobox(el.infoboxText, el); } + + this.displayInfobox(true); } - }; + return this; + }, - return c; - }; + /** + * Set infobox visible / invisible. + * + * It uses its property hiddenByParent to memorize its status. + * In this way, many DOM access can be avoided. + * + * @param {Boolean} val true for visible, false for invisible + * @returns {JXG.Board} Reference to the board. + * @see JXG.Board#updateInfobox + * + */ + displayInfobox: function(val) { + if (this.infobox.hiddenByParent === val) { + this.infobox.hiddenByParent = !val; + this.infobox.prepareUpdate().updateVisibility(val).updateRenderer(); + } + return this; + }, - JXG.registerElement('tracecurve', JXG.createTracecurve); + // Alias for displayInfobox to be backwards compatible. + // The method showInfobox clashes with the board attribute showInfobox + showInfobox: function(val) { + return this.displayInfobox(val); + }, - /** - * @class This element is used to provide a constructor for step function, which is realized as a special curve. - * - * In case the data points should be updated after creation time, they can be accessed by curve.xterm and curve.yterm. - * @pseudo - * @description - * @name Stepfunction - * @augments JXG.Curve - * @constructor - * @type JXG.Curve - * @param {Array,Array|Function} Parent elements of Stepfunction are two arrays containing the coordinates. - * @see JXG.Curve - * @example - * // Create step function. - var curve = board.create('stepfunction', [[0,1,2,3,4,5], [1,3,0,2,2,1]]); + /** + * Changes the text of the info box to show the given coordinates. + * @param {Number} x + * @param {Number} y + * @param {JXG.GeometryElement} [el] The element the mouse is pointing at + * @returns {JXG.Board} Reference to the board. + */ + highlightInfobox: function (x, y, el) { + this.highlightCustomInfobox('(' + x + ', ' + y + ')', el); + return this; + }, - * </pre><div class="jxgbox" id="JXG32342ec9-ad17-4339-8a97-ff23dc34f51a" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * var sf1_board = JXG.JSXGraph.initBoard('JXG32342ec9-ad17-4339-8a97-ff23dc34f51a', {boundingbox: [-1, 5, 6, -2], axis: true, showcopyright: false, shownavigation: false}); - * var curve = sf1_board.create('stepfunction', [[0,1,2,3,4,5], [1,3,0,2,2,1]]); - * </script><pre> - */ - JXG.createStepfunction = function (board, parents, attributes) { - var c, attr; - if (parents.length !== 2) { - throw new Error("JSXGraph: Can't create step function with given parent'" + - "\nPossible parent types: [array, array|function]"); - } + /** + * Changes the text of the info box to what is provided via text. + * @param {String} text + * @param {JXG.GeometryElement} [el] + * @returns {JXG.Board} Reference to the board. + */ + highlightCustomInfobox: function (text, el) { + this.infobox.setText(text); + return this; + }, - attr = Type.copyAttributes(attributes, board.options, 'stepfunction'); - c = board.create('curve', parents, attr); - c.updateDataArray = function () { - var i, j = 0, - len = this.xterm.length; + /** + * Remove highlighting of all elements. + * @returns {JXG.Board} Reference to the board. + */ + dehighlightAll: function () { + var el, pEl, needsDehighlight = false; - this.dataX = []; - this.dataY = []; + for (el in this.highlightedObjects) { + if (this.highlightedObjects.hasOwnProperty(el)) { + pEl = this.highlightedObjects[el]; - if (len === 0) { - return; + if (this.hasMouseHandlers || this.hasPointerHandlers) { + pEl.noHighlight(); + } + + needsDehighlight = true; + + // In highlightedObjects should only be objects which fulfill all these conditions + // And in case of complex elements, like a turtle based fractal, it should be faster to + // just de-highlight the element instead of checking hasPoint... + // if ((!Type.exists(pEl.hasPoint)) || !pEl.hasPoint(x, y) || !pEl.visPropCalc.visible) + } } - this.dataX[j] = this.xterm[0]; - this.dataY[j] = this.yterm[0]; - ++j; + this.highlightedObjects = {}; - for (i = 1; i < len; ++i) { - this.dataX[j] = this.xterm[i]; - this.dataY[j] = this.dataY[j - 1]; - ++j; - this.dataX[j] = this.xterm[i]; - this.dataY[j] = this.yterm[i]; - ++j; + // We do not need to redraw during dehighlighting in CanvasRenderer + // because we are redrawing anyhow + // -- We do need to redraw during dehighlighting. Otherwise objects won't be dehighlighted until + // another object is highlighted. + if (this.renderer.type === 'canvas' && needsDehighlight) { + this.prepareUpdate(); + this.renderer.suspendRedraw(this); + this.updateRenderer(); + this.renderer.unsuspendRedraw(); } - }; - return c; - }; + return this; + }, - JXG.registerElement('stepfunction', JXG.createStepfunction); + /** + * Returns the input parameters in an array. This method looks pointless and it really is, but it had a purpose + * once. + * @private + * @param {Number} x X coordinate in screen coordinates + * @param {Number} y Y coordinate in screen coordinates + * @returns {Array} Coordinates [x, y] of the mouse in screen coordinates. + * @see JXG.Board#getUsrCoordsOfMouse + */ + getScrCoordsOfMouse: function (x, y) { + return [x, y]; + }, - /** - * @class This element is used to provide a constructor for the graph showing - * the (numerical) derivative of a given curve. - * - * @pseudo - * @description - * @name Derivative - * @augments JXG.Curve - * @constructor - * @type JXG.Curve - * @param {JXG.Curve} Parent Curve for which the derivative is generated. - * @see JXG.Curve - * @example - * var cu = board.create('cardinalspline', [[[-3,0], [-1,2], [0,1], [2,0], [3,1]], 0.5, 'centripetal'], {createPoints: false}); - * var d = board.create('derivative', [cu], {dash: 2}); - * - * </pre><div id="JXGb9600738-1656-11e8-8184-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function() { - * var board = JXG.JSXGraph.initBoard('JXGb9600738-1656-11e8-8184-901b0e1b8723', - * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); - * var cu = board.create('cardinalspline', [[[-3,0], [-1,2], [0,1], [2,0], [3,1]], 0.5, 'centripetal'], {createPoints: false}); - * var d = board.create('derivative', [cu], {dash: 2}); - * - * })(); - * - * </script><pre> - * - */ - JXG.createDerivative = function (board, parents, attributes) { - var c, - curve, dx, dy, - attr; + /** + * This method calculates the user coords of the current mouse coordinates. + * @param {Event} evt Event object containing the mouse coordinates. + * @returns {Array} Coordinates [x, y] of the mouse in user coordinates. + * @example + * board.on('up', function (evt) { + * var a = board.getUsrCoordsOfMouse(evt), + * x = a[0], + * y = a[1], + * somePoint = board.create('point', [x,y], {name:'SomePoint',size:4}); + * // Shorter version: + * //somePoint = board.create('point', a, {name:'SomePoint',size:4}); + * }); + * + * </pre><div id="JXG48d5066b-16ba-4920-b8ea-a4f8eff6b746" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG48d5066b-16ba-4920-b8ea-a4f8eff6b746', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * board.on('up', function (evt) { + * var a = board.getUsrCoordsOfMouse(evt), + * x = a[0], + * y = a[1], + * somePoint = board.create('point', [x,y], {name:'SomePoint',size:4}); + * // Shorter version: + * //somePoint = board.create('point', a, {name:'SomePoint',size:4}); + * }); + * + * })(); + * + * </script><pre> + * + * @see JXG.Board#getScrCoordsOfMouse + * @see JXG.Board#getAllUnderMouse + */ + getUsrCoordsOfMouse: function (evt) { + var cPos = this.getCoordsTopLeftCorner(), + absPos = Env.getPosition(evt, null, this.document), + x = absPos[0] - cPos[0], + y = absPos[1] - cPos[1], + newCoords = new Coords(Const.COORDS_BY_SCREEN, [x, y], this); - if (parents.length !== 1 && parents[0].class !== Const.OBJECT_CLASS_CURVE) { - throw new Error("JSXGraph: Can't create derivative curve with given parent'" + - "\nPossible parent types: [curve]"); - } + return newCoords.usrCoords.slice(1); + }, - attr = Type.copyAttributes(attributes, board.options, 'curve'); + /** + * Collects all elements under current mouse position plus current user coordinates of mouse cursor. + * @param {Event} evt Event object containing the mouse coordinates. + * @returns {Array} Array of elements at the current mouse position plus current user coordinates of mouse. + * @see JXG.Board#getUsrCoordsOfMouse + * @see JXG.Board#getAllObjectsUnderMouse + */ + getAllUnderMouse: function (evt) { + var elList = this.getAllObjectsUnderMouse(evt); + elList.push(this.getUsrCoordsOfMouse(evt)); - curve = parents[0]; - dx = Numerics.D(curve.X); - dy = Numerics.D(curve.Y); + return elList; + }, - c = board.create('curve', [ - function(t) { return curve.X(t); }, - function(t) { return dy(t) / dx(t); }, - curve.minX(), curve.maxX() - ], attr); + /** + * Collects all elements under current mouse position. + * @param {Event} evt Event object containing the mouse coordinates. + * @returns {Array} Array of elements at the current mouse position. + * @see JXG.Board#getAllUnderMouse + */ + getAllObjectsUnderMouse: function (evt) { + var cPos = this.getCoordsTopLeftCorner(), + absPos = Env.getPosition(evt, null, this.document), + dx = absPos[0] - cPos[0], + dy = absPos[1] - cPos[1], + elList = [], + el, + pEl, + len = this.objectsList.length; - c.setParents(curve); + for (el = 0; el < len; el++) { + pEl = this.objectsList[el]; + if (pEl.visPropCalc.visible && pEl.hasPoint && pEl.hasPoint(dx, dy)) { + elList[elList.length] = pEl; + } + } - return c; - }; + return elList; + }, - JXG.registerElement('derivative', JXG.createDerivative); + /** + * Update the coords object of all elements which possess this + * property. This is necessary after changing the viewport. + * @returns {JXG.Board} Reference to this board. + **/ + updateCoords: function () { + var el, ob, len = this.objectsList.length; - return { - Curve: JXG.Curve, - createCurve: JXG.createCurve, - createFunctiongraph: JXG.createFunctiongraph, - createPlot: JXG.createPlot, - createSpline: JXG.createSpline, - createRiemannsum: JXG.createRiemannsum, - createTracecurve: JXG.createTracecurve, - createStepfunction: JXG.createStepfunction - }; -}); + for (ob = 0; ob < len; ob++) { + el = this.objectsList[ob]; -/* - Copyright 2008-2021 - Matthias Ehmann, - Michael Gerhaeuser, - Carsten Miller, - Bianca Valentin, - Alfred Wassermann, - Peter Wilfahrt + if (Type.exists(el.coords)) { + if (Type.evaluate(el.visProp.frozen)) { + el.coords.screen2usr(); + } else { + el.coords.usr2screen(); + } + } + } + return this; + }, - This file is part of JSXGraph. + /** + * Moves the origin and initializes an update of all elements. + * @param {Number} x + * @param {Number} y + * @param {Boolean} [diff=false] + * @returns {JXG.Board} Reference to this board. + */ + moveOrigin: function (x, y, diff) { + var ox, oy, ul, lr; + if (Type.exists(x) && Type.exists(y)) { + ox = this.origin.scrCoords[1]; + oy = this.origin.scrCoords[2]; - JSXGraph is free software dual licensed under the GNU LGPL or MIT License. + this.origin.scrCoords[1] = x; + this.origin.scrCoords[2] = y; - You can redistribute it and/or modify it under the terms of the + if (diff) { + this.origin.scrCoords[1] -= this.drag_dx; + this.origin.scrCoords[2] -= this.drag_dy; + } - * GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version - OR - * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT + ul = (new Coords(Const.COORDS_BY_SCREEN, [0, 0], this)).usrCoords; + lr = (new Coords(Const.COORDS_BY_SCREEN, [this.canvasWidth, this.canvasHeight], this)).usrCoords; + if (ul[1] < this.maxboundingbox[0] || + ul[2] > this.maxboundingbox[1] || + lr[1] > this.maxboundingbox[2] || + lr[2] < this.maxboundingbox[3]) { - JSXGraph is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. + this.origin.scrCoords[1] = ox; + this.origin.scrCoords[2] = oy; + } + } - You should have received a copy of the GNU Lesser General Public License and - the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> - and <http://opensource.org/licenses/MIT/>. - */ + this.updateCoords().clearTraces().fullUpdate(); + this.triggerEventHandlers(['boundingbox']); + return this; + }, -/*global JXG: true, define: true*/ -/*jslint nomen: true, plusplus: true*/ + /** + * Add conditional updates to the elements. + * @param {String} str String containing coniditional update in geonext syntax + */ + addConditions: function (str) { + var term, m, left, right, name, el, property, + functions = [], + // plaintext = 'var el, x, y, c, rgbo;\n', + i = str.indexOf('<data>'), + j = str.indexOf('<' + '/data>'), -/* depends: - jxg - base/constants - math/math - math/geometry - math/numerics - utils/type - elements: - point - curve - */ + xyFun = function (board, el, f, what) { + return function () { + var e, t; -/** - * @fileoverview In this file the conic sections defined. - */ + e = board.select(el.id); + t = e.coords.usrCoords[what]; -define('element/conic',[ - 'jxg', 'base/constants', 'base/coords', 'math/math', 'math/numerics', 'math/geometry', 'utils/type', 'base/point', 'base/curve' -], function (JXG, Const, Coords, Mat, Numerics, Geometry, Type, Point, Curve) { + if (what === 2) { + e.setPositionDirectly(Const.COORDS_BY_USER, [f(), t]); + } else { + e.setPositionDirectly(Const.COORDS_BY_USER, [t, f()]); + } + e.prepareUpdate().update(); + }; + }, - "use strict"; + visFun = function (board, el, f) { + return function () { + var e, v; - /** - * @class This element is used to provide a constructor for an ellipse. An ellipse is given by two points (the foci) and a third point on the the ellipse or - * the length of the major axis. - * @pseudo - * @description - * @name Ellipse - * @augments Conic - * @constructor - * @type JXG.Curve - * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {JXG.Point,array_JXG.Point,array_JXG.Point,array} point1,point2,point3 Parent elements can be three elements either of type {@link JXG.Point} or array of - * numbers describing the coordinates of a point. In the latter case the point will be constructed automatically as a fixed invisible point. - * @param {JXG.Point,array_JXG.Point,array_number,function} point1,point2,number Parent elements can be two elements either of type {@link JXG.Point} or array of - * numbers describing the coordinates of a point. The third parameter is a number/function which defines the length of the major axis - * Optional parameters four and five are numbers which define the curve length (e.g. start/end). Default values are -pi and pi. - * @example - * // Create an Ellipse by three points - * var A = board.create('point', [-1,4]); - * var B = board.create('point', [-1,-4]); - * var C = board.create('point', [1,1]); - * var el = board.create('ellipse',[A,B,C]); - * </pre><div class="jxgbox" id="JXGa4d7fb6f-8708-4e45-87f2-2379ae2bd2c0" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * var glex1_board = JXG.JSXGraph.initBoard('JXGa4d7fb6f-8708-4e45-87f2-2379ae2bd2c0', {boundingbox:[-6,6,6,-6], keepaspectratio:true, showcopyright: false, shownavigation: false}); - * var A = glex1_board.create('point', [-1,4]); - * var B = glex1_board.create('point', [-1,-4]); - * var C = glex1_board.create('point', [1,1]); - * var el = glex1_board.create('ellipse',[A,B,C]); - * </script><pre> - */ - JXG.createEllipse = function (board, parents, attributes) { - var polarForm, curve, M, C, majorAxis, i, - hasPointOrg, - // focus 1 and focus 2 - F = [], - attr_foci = Type.copyAttributes(attributes, board.options, 'conic', 'foci'), - attr_center = Type.copyAttributes(attributes, board.options, 'conic', 'center'), - attr_curve = Type.copyAttributes(attributes, board.options, 'conic'); + e = board.select(el.id); + v = f(); - // The foci and the third point are either points or coordinate arrays. - for (i = 0; i < 2; i++) { - // focus i given by coordinates - if (parents[i].length > 1) { - F[i] = board.create('point', parents[i], attr_foci); - // focus i given by point - } else if (Type.isPoint(parents[i])) { - F[i] = board.select(parents[i]); - // given by function - } else if (Type.isFunction(parents[i]) && Type.isPoint(parents[i]()) ) { - F[i] = parents[i](); - // focus i given by point name - } else if (Type.isString(parents[i])) { - F[i] = board.select(parents[i]); - } else { - throw new Error("JSXGraph: Can't create Ellipse with parent types '" + - (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + - "\nPossible parent types: [point,point,point], [point,point,number|function]"); - } - } + e.setAttribute({visible: v}); + }; + }, - // length of major axis - if (Type.isNumber(parents[2])) { - majorAxis = Type.createFunction(parents[2], board); - } else if (Type.isFunction(parents[2]) && Type.isNumber(parents[2]())) { - majorAxis = parents[2]; - } else { - // point on ellipse - if (Type.isPoint(parents[2])) { - C = board.select(parents[2]); - // point on ellipse given by coordinates - } else if (parents[2].length > 1) { - C = board.create('point', parents[2], attr_foci); - // given by function - } else if (Type.isFunction(parents[2]) && Type.isPoint(parents[2]()) ) { - C = parents[2](); - // focus i given by point name - } else if (Type.isString(parents[2])) { - C = board.select(parents[2]); - } else { - throw new Error("JSXGraph: Can't create Ellipse with parent types '" + - (typeof parents[0]) + "' and '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." + - "\nPossible parent types: [point,point,point], [point,point,number|function]"); - } - /** @ignore */ - majorAxis = function () { - return C.Dist(F[0]) + C.Dist(F[1]); - }; - } + colFun = function (board, el, f, what) { + return function () { + var e, v; - // to - if (!Type.exists(parents[4])) { - parents[4] = 2 * Math.PI; - } + e = board.select(el.id); + v = f(); - // from - if (!Type.exists(parents[3])) { - parents[3] = 0.0; - } + if (what === 'strokewidth') { + e.visProp.strokewidth = v; + } else { + v = Color.rgba2rgbo(v); + e.visProp[what + 'color'] = v[0]; + e.visProp[what + 'opacity'] = v[1]; + } + }; + }, - M = board.create('point', [ - function () { - return (F[0].X() + F[1].X()) * 0.5; - }, - function () { - return (F[0].Y() + F[1].Y()) * 0.5; - } - ], attr_center); + posFun = function (board, el, f) { + return function () { + var e = board.select(el.id); - curve = board.create('curve', [ - function (x) { - return 0; - }, - function (x) { - return 0; - }, - parents[3], - parents[4]], attr_curve); + e.position = f(); + }; + }, - curve.majorAxis = majorAxis; + styleFun = function (board, el, f) { + return function () { + var e = board.select(el.id); - // Save the original hasPoint method. It will be called inside of the new hasPoint method. - hasPointOrg = curve.hasPoint; + e.setStyle(f()); + }; + }; - /** @ignore */ - polarForm = function (phi, suspendUpdate) { - var r, rr, ax, ay, bx, by, axbx, ayby, f; + if (i < 0) { + return; + } - if (!suspendUpdate) { - r = majorAxis(); - rr = r * r; - ax = F[0].X(); - ay = F[0].Y(); - bx = F[1].X(); - by = F[1].Y(); - axbx = ax - bx; - ayby = ay - by; - f = (rr - ax * ax - ay * ay + bx * bx + by * by) / (2 * r); + while (i >= 0) { + term = str.slice(i + 6, j); // throw away <data> + m = term.indexOf('='); + left = term.slice(0, m); + right = term.slice(m + 1); + m = left.indexOf('.'); // Dies erzeugt Probleme bei Variablennamen der Form " Steuern akt." + name = left.slice(0, m); //.replace(/\s+$/,''); // do NOT cut out name (with whitespace) + el = this.elementsByName[Type.unescapeHTML(name)]; - curve.quadraticform = [ - [f * f - bx * bx - by * by, f * axbx / r + bx, f * ayby / r + by], - [f * axbx / r + bx, (axbx * axbx) / rr - 1, axbx * ayby / rr ], - [f * ayby / r + by, axbx * ayby / rr, (ayby * ayby) / rr - 1] - ]; - } - }; + property = left.slice(m + 1).replace(/\s+/g, '').toLowerCase(); // remove whitespace in property + right = Type.createFunction (right, this, '', true); - /** @ignore */ - curve.X = function (phi, suspendUpdate) { - var r = majorAxis(), - c = F[1].Dist(F[0]), - b = 0.5 * (c * c - r * r) / (c * Math.cos(phi) - r), - beta = Math.atan2(F[1].Y() - F[0].Y(), F[1].X() - F[0].X()); + // Debug + if (!Type.exists(this.elementsByName[name])) { + JXG.debug("debug conditions: |" + name + "| undefined"); + } else { + // plaintext += "el = this.objects[\"" + el.id + "\"];\n"; - if (!suspendUpdate) { - polarForm(phi, suspendUpdate); + switch (property) { + case 'x': + functions.push(xyFun(this, el, right, 2)); + break; + case 'y': + functions.push(xyFun(this, el, right, 1)); + break; + case 'visible': + functions.push(visFun(this, el, right)); + break; + case 'position': + functions.push(posFun(this, el, right)); + break; + case 'stroke': + functions.push(colFun(this, el, right, 'stroke')); + break; + case 'style': + functions.push(styleFun(this, el, right)); + break; + case 'strokewidth': + functions.push(colFun(this, el, right, 'strokewidth')); + break; + case 'fill': + functions.push(colFun(this, el, right, 'fill')); + break; + case 'label': + break; + default: + JXG.debug("property '" + property + "' in conditions not yet implemented:" + right); + break; + } + } + str = str.slice(j + 7); // cut off "</data>" + i = str.indexOf('<data>'); + j = str.indexOf('<' + '/data>'); } - return F[0].X() + Math.cos(beta + phi) * b; - }; - - /** @ignore */ - curve.Y = function (phi, suspendUpdate) { - var r = majorAxis(), - c = F[1].Dist(F[0]), - b = 0.5 * (c * c - r * r) / (c * Math.cos(phi) - r), - beta = Math.atan2(F[1].Y() - F[0].Y(), F[1].X() - F[0].X()); + this.updateConditions = function () { + var i; - return F[0].Y() + Math.sin(beta + phi) * b; - }; + for (i = 0; i < functions.length; i++) { + functions[i](); + } - curve.midpoint = curve.center = M; - curve.type = Const.OBJECT_TYPE_CONIC; - curve.subs = { - center: curve.center + this.prepareUpdate().updateElements(); + return true; }; - curve.inherits.push(curve.center, F[0], F[1]); - if (Type.isPoint(C)) { - curve.inherits.push(C); - } + this.updateConditions(); + }, /** - * Checks whether (x,y) is near the ellipse line or inside of the ellipse - * (in case JXG.Options.conic#hasInnerPoints is true). - * @param {Number} x Coordinate in x direction, screen coordinates. - * @param {Number} y Coordinate in y direction, screen coordinates. - * @returns {Boolean} True if (x,y) is near the ellipse, False otherwise. + * Computes the commands in the conditions-section of the gxt file. + * It is evaluated after an update, before the unsuspendRedraw. + * The function is generated in + * @see JXG.Board#addConditions * @private */ - curve.hasPoint = function (x, y) { - var ac, bc, r, p, dist; + updateConditions: function () { + return false; + }, - if (Type.evaluate(this.visProp.hasinnerpoints)) { - ac = F[0].coords; - bc = F[1].coords; - r = this.majorAxis(); - p = new Coords(Const.COORDS_BY_SCREEN, [x, y], this.board); - dist = p.distance(Const.COORDS_BY_USER, ac) + p.distance(Const.COORDS_BY_USER, bc); + /** + * Calculates adequate snap sizes. + * @returns {JXG.Board} Reference to the board. + */ + calculateSnapSizes: function () { + var p1 = new Coords(Const.COORDS_BY_USER, [0, 0], this), + p2 = new Coords(Const.COORDS_BY_USER, [this.options.grid.gridX, this.options.grid.gridY], this), + x = p1.scrCoords[1] - p2.scrCoords[1], + y = p1.scrCoords[2] - p2.scrCoords[2]; - return (dist <= r); + this.options.grid.snapSizeX = this.options.grid.gridX; + while (Math.abs(x) > 25) { + this.options.grid.snapSizeX *= 2; + x /= 2; } - return hasPointOrg.apply(this, arguments); - }; - - M.addChild(curve); - for (i = 0; i < 2; i++) { - if (Type.isPoint(F[i])) { - F[i].addChild(curve); + this.options.grid.snapSizeY = this.options.grid.gridY; + while (Math.abs(y) > 25) { + this.options.grid.snapSizeY *= 2; + y /= 2; } - } - if (Type.isPoint(C)) { - C.addChild(curve); - } - curve.setParents(parents); - return curve; - }; + return this; + }, - /** - * @class This element is used to provide a constructor for an hyperbola. An hyperbola is given by two points (the foci) and a third point on the the hyperbola or - * the length of the major axis. - * @pseudo - * @description - * @name Hyperbola - * @augments Conic - * @constructor - * @type JXG.Curve - * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {JXG.Point,array_JXG.Point,array_JXG.Point,array} point1,point2,point3 Parent elements can be three elements either of type {@link JXG.Point} or array of - * numbers describing the coordinates of a point. In the latter case the point will be constructed automatically as a fixed invisible point. - * @param {JXG.Point,array_JXG.Point,array_number,function} point1,point2,number Parent elements can be two elements either of type {@link JXG.Point} or array of - * numbers describing the coordinates of a point. The third parameter is a number/function which defines the length of the major axis - * Optional parameters four and five are numbers which define the curve length (e.g. start/end). Default values are -pi and pi. - * @example - * // Create an Hyperbola by three points - * var A = board.create('point', [-1,4]); - * var B = board.create('point', [-1,-4]); - * var C = board.create('point', [1,1]); - * var el = board.create('hyperbola',[A,B,C]); - * </pre><div class="jxgbox" id="JXGcf99049d-a3fe-407f-b936-27d76550f8c4" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * var glex1_board = JXG.JSXGraph.initBoard('JXGcf99049d-a3fe-407f-b936-27d76550f8c4', {boundingbox:[-6,6,6,-6], keepaspectratio:true, showcopyright: false, shownavigation: false}); - * var A = glex1_board.create('point', [-1,4]); - * var B = glex1_board.create('point', [-1,-4]); - * var C = glex1_board.create('point', [1,1]); - * var el = glex1_board.create('hyperbola',[A,B,C]); - * </script><pre> - */ - JXG.createHyperbola = function (board, parents, attributes) { - var polarForm, curve, M, C, majorAxis, i, - // focus 1 and focus 2 - F = [], - attr_foci = Type.copyAttributes(attributes, board.options, 'conic', 'foci'), - attr_center = Type.copyAttributes(attributes, board.options, 'conic', 'center'), - attr_curve = Type.copyAttributes(attributes, board.options, 'conic'); + /** + * Apply update on all objects with the new zoom-factors. Clears all traces. + * @returns {JXG.Board} Reference to the board. + */ + applyZoom: function () { + this.updateCoords().calculateSnapSizes().clearTraces().fullUpdate(); - // The foci and the third point are either points or coordinate arrays. - for (i = 0; i < 2; i++) { - // focus i given by coordinates - if (parents[i].length > 1) { - F[i] = board.create('point', parents[i], attr_foci); - // focus i given by point - } else if (Type.isPoint(parents[i])) { - F[i] = board.select(parents[i]); - // given by function - } else if (Type.isFunction(parents[i]) && Type.isPoint(parents[i]()) ) { - F[i] = parents[i](); - // focus i given by point name - } else if (Type.isString(parents[i])) { - F[i] = board.select(parents[i]); - } else { - throw new Error("JSXGraph: Can't create Hyperbola with parent types '" + - (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + - "\nPossible parent types: [point,point,point], [point,point,number|function]"); + return this; + }, + + /** + * Zooms into the board by the factors board.attr.zoom.factorX and board.attr.zoom.factorY and applies the zoom. + * The zoom operation is centered at x, y. + * @param {Number} [x] + * @param {Number} [y] + * @returns {JXG.Board} Reference to the board + */ + zoomIn: function (x, y) { + var bb = this.getBoundingBox(), + zX = this.attr.zoom.factorx, + zY = this.attr.zoom.factory, + dX = (bb[2] - bb[0]) * (1.0 - 1.0 / zX), + dY = (bb[1] - bb[3]) * (1.0 - 1.0 / zY), + lr = 0.5, + tr = 0.5, + mi = this.attr.zoom.eps || this.attr.zoom.min || 0.001; // this.attr.zoom.eps is deprecated + + if ((this.zoomX > this.attr.zoom.max && zX > 1.0) || + (this.zoomY > this.attr.zoom.max && zY > 1.0) || + (this.zoomX < mi && zX < 1.0) || // zoomIn is used for all zooms on touch devices + (this.zoomY < mi && zY < 1.0)) { + return this; } - } - // length of major axis - if (Type.isNumber(parents[2])) { - majorAxis = Type.createFunction(parents[2], board); - } else if (Type.isFunction(parents[2]) && Type.isNumber(parents[2]())) { - majorAxis = parents[2]; - } else { - // point on ellipse - if (Type.isPoint(parents[2])) { - C = board.select(parents[2]); - // point on ellipse given by coordinates - } else if (parents[2].length > 1) { - C = board.create('point', parents[2], attr_foci); - // given by function - } else if (Type.isFunction(parents[2]) && Type.isPoint(parents[2]())) { - C = parents[2](); - // focus i given by point name - } else if (Type.isString(parents[2])) { - C = board.select(parents[2]); - } else { - throw new Error("JSXGraph: Can't create Hyperbola with parent types '" + - (typeof parents[0]) + "' and '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." + - "\nPossible parent types: [point,point,point], [point,point,number|function]"); + if (Type.isNumber(x) && Type.isNumber(y)) { + lr = (x - bb[0]) / (bb[2] - bb[0]); + tr = (bb[1] - y) / (bb[1] - bb[3]); } - /** @ignore */ - majorAxis = function () { - return C.Dist(F[0]) - C.Dist(F[1]); - }; - } - // to - if (!Type.exists(parents[4])) { - parents[4] = 1.0001 * Math.PI; - } + this.setBoundingBox([bb[0] + dX * lr, bb[1] - dY * tr, bb[2] - dX * (1 - lr), bb[3] + dY * (1 - tr)], this.keepaspectratio, 'update'); + return this.applyZoom(); + }, - // from - if (!Type.exists(parents[3])) { - parents[3] = -1.0001 * Math.PI; - } + /** + * Zooms out of the board by the factors board.attr.zoom.factorX and board.attr.zoom.factorY and applies the zoom. + * The zoom operation is centered at x, y. + * + * @param {Number} [x] + * @param {Number} [y] + * @returns {JXG.Board} Reference to the board + */ + zoomOut: function (x, y) { + var bb = this.getBoundingBox(), + zX = this.attr.zoom.factorx, + zY = this.attr.zoom.factory, + dX = (bb[2] - bb[0]) * (1.0 - zX), + dY = (bb[1] - bb[3]) * (1.0 - zY), + lr = 0.5, + tr = 0.5, + mi = this.attr.zoom.eps || this.attr.zoom.min || 0.001; // this.attr.zoom.eps is deprecated - M = board.create('point', [ - function () { - return (F[0].X() + F[1].X()) * 0.5; - }, - function () { - return (F[0].Y() + F[1].Y()) * 0.5; + if (this.zoomX < mi || this.zoomY < mi) { + return this; } - ], attr_center); - curve = board.create('curve', [ - function (x) { - return 0; - }, - function (x) { - return 0; - }, parents[3], parents[4]], attr_curve); + if (Type.isNumber(x) && Type.isNumber(y)) { + lr = (x - bb[0]) / (bb[2] - bb[0]); + tr = (bb[1] - y) / (bb[1] - bb[3]); + } - curve.majorAxis = majorAxis; + this.setBoundingBox([bb[0] + dX * lr, bb[1] - dY * tr, bb[2] - dX * (1 - lr), bb[3] + dY * (1 - tr)], this.keepaspectratio, 'update'); - // Hyperbola is defined by (a*sec(t),b*tan(t)) and sec(t) = 1/cos(t) - /** @ignore */ - polarForm = function (phi, suspendUpdate) { - var r, rr, ax, ay, bx, by, axbx, ayby, f; + return this.applyZoom(); + }, - if (!suspendUpdate) { - r = majorAxis(); - rr = r * r; - ax = F[0].X(); - ay = F[0].Y(); - bx = F[1].X(); - by = F[1].Y(); - axbx = ax - bx; - ayby = ay - by; - f = (rr - ax * ax - ay * ay + bx * bx + by * by) / (2 * r); + /** + * Reset the zoom level to the original zoom level from initBoard(); + * Additionally, if the board as been initialized with a boundingBox (which is the default), + * restore the viewport to the original viewport during initialization. Otherwise, + * (i.e. if the board as been initialized with unitX/Y and originX/Y), + * just set the zoom level to 100%. + * + * @returns {JXG.Board} Reference to the board + */ + zoom100: function () { + var bb, dX, dY; - curve.quadraticform = [ - [f * f - bx * bx - by * by, f * axbx / r + bx, f * ayby / r + by], - [f * axbx / r + bx, (axbx * axbx) / rr - 1, axbx * ayby / rr ], - [f * ayby / r + by, axbx * ayby / rr, (ayby * ayby) / rr - 1] - ]; + if (Type.exists(this.attr.boundingbox)) { + this.setBoundingBox(this.attr.boundingbox, this.keepaspectratio, 'reset'); + } else { + // Board has been set up with unitX/Y and originX/Y + bb = this.getBoundingBox(); + dX = (bb[2] - bb[0]) * (1.0 - this.zoomX) * 0.5; + dY = (bb[1] - bb[3]) * (1.0 - this.zoomY) * 0.5; + this.setBoundingBox([bb[0] + dX, bb[1] - dY, bb[2] - dX, bb[3] + dY], this.keepaspectratio, 'reset'); } - }; + return this.applyZoom(); + }, - /** @ignore */ - curve.X = function (phi, suspendUpdate) { - var r = majorAxis(), - c = F[1].Dist(F[0]), - b = 0.5 * (c * c - r * r) / (c * Math.cos(phi) + r), - beta = Math.atan2(F[1].Y() - F[0].Y(), F[1].X() - F[0].X()); + /** + * Zooms the board so every visible point is shown. Keeps aspect ratio. + * @returns {JXG.Board} Reference to the board + */ + zoomAllPoints: function () { + var el, border, borderX, borderY, pEl, + minX = 0, + maxX = 0, + minY = 0, + maxY = 0, + len = this.objectsList.length; - if (!suspendUpdate) { - polarForm(phi, suspendUpdate); + for (el = 0; el < len; el++) { + pEl = this.objectsList[el]; + + if (Type.isPoint(pEl) && pEl.visPropCalc.visible) { + if (pEl.coords.usrCoords[1] < minX) { + minX = pEl.coords.usrCoords[1]; + } else if (pEl.coords.usrCoords[1] > maxX) { + maxX = pEl.coords.usrCoords[1]; + } + if (pEl.coords.usrCoords[2] > maxY) { + maxY = pEl.coords.usrCoords[2]; + } else if (pEl.coords.usrCoords[2] < minY) { + minY = pEl.coords.usrCoords[2]; + } + } } - return F[0].X() + Math.cos(beta + phi) * b; - }; + border = 50; + borderX = border / this.unitX; + borderY = border / this.unitY; - /** @ignore */ - curve.Y = function (phi, suspendUpdate) { - var r = majorAxis(), - c = F[1].Dist(F[0]), - b = 0.5 * (c * c - r * r) / (c * Math.cos(phi) + r), - beta = Math.atan2(F[1].Y() - F[0].Y(), F[1].X() - F[0].X()); + this.setBoundingBox([minX - borderX, maxY + borderY, maxX + borderX, minY - borderY], this.keepaspectratio, 'update'); - return F[0].Y() + Math.sin(beta + phi) * b; - }; + return this.applyZoom(); + }, - curve.midpoint = curve.center = M; - curve.subs = { - center: curve.center - }; - curve.inherits.push(curve.center, F[0], F[1]); - if (Type.isPoint(C)) { - curve.inherits.push(C); - } - curve.type = Const.OBJECT_TYPE_CONIC; + /** + * Reset the bounding box and the zoom level to 100% such that a given set of elements is + * within the board's viewport. + * @param {Array} elements A set of elements given by id, reference, or name. + * @returns {JXG.Board} Reference to the board. + */ + zoomElements: function (elements) { + var i, e, box, + newBBox = [Infinity, -Infinity, -Infinity, Infinity], + cx, cy, dx, dy, d; - M.addChild(curve); - for (i = 0; i < 2; i++) { - if (Type.isPoint(F[i])) { - F[i].addChild(curve); + if (!Type.isArray(elements) || elements.length === 0) { + return this; } - } - if (Type.isPoint(C)) { - C.addChild(curve); - } - curve.setParents(parents); - return curve; - }; + for (i = 0; i < elements.length; i++) { + e = this.select(elements[i]); - /** - * @class This element is used to provide a constructor for a parabola. A parabola is given by one point (the focus) and a line (the directrix). - * @pseudo - * @description - * @name Parabola - * @augments Conic - * @constructor - * @type JXG.Curve - * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {JXG.Point,array_JXG.Line} point,line Parent elements are a point and a line or a pair of coordinates. - * Optional parameters three and four are numbers which define the curve length (e.g. start/end). Default values are -pi and pi. - * @example - * // Create a parabola by a point C and a line l. - * var A = board.create('point', [-1,4]); - * var B = board.create('point', [-1,-4]); - * var l = board.create('line', [A,B]); - * var C = board.create('point', [1,1]); - * var el = board.create('parabola',[C,l]); - * </pre><div class="jxgbox" id="JXG524d1aae-217d-44d4-ac58-a19c7ab1de36" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * var glex1_board = JXG.JSXGraph.initBoard('JXG524d1aae-217d-44d4-ac58-a19c7ab1de36', {boundingbox:[-6,6,6,-6], keepaspectratio:true, showcopyright: false, shownavigation: false}); - * var A = glex1_board.create('point', [-1,4]); - * var B = glex1_board.create('point', [-1,-4]); - * var l = glex1_board.create('line', [A,B]); - * var C = glex1_board.create('point', [1,1]); - * var el = glex1_board.create('parabola',[C,l]); - * </script><pre> - * - * @example - * var par = board.create('parabola',[[3.25, 0], [[0.25, 1],[0.25, 0]]]); - * - * </pre><div id="JXG09252542-b77a-4990-a109-66ffb649a472" class="jxgbox" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function() { - * var board = JXG.JSXGraph.initBoard('JXG09252542-b77a-4990-a109-66ffb649a472', - * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); - * var par = board.create('parabola',[[3.25, 0], [[0.25, 1],[0.25, 0]]]); - * - * })(); - * - * </script><pre> - * - */ - JXG.createParabola = function (board, parents, attributes) { - var polarForm, curve, M, i, - // focus - F1 = parents[0], - // directrix - l = parents[1], - attr_foci = Type.copyAttributes(attributes, board.options, 'conic', 'foci'), - attr_center = Type.copyAttributes(attributes, board.options, 'conic', 'center'), - attr_curve = Type.copyAttributes(attributes, board.options, 'conic'), - attr_line; + box = e.bounds(); + if (Type.isArray(box)) { + if (box[0] < newBBox[0]) { newBBox[0] = box[0]; } + if (box[1] > newBBox[1]) { newBBox[1] = box[1]; } + if (box[2] > newBBox[2]) { newBBox[2] = box[2]; } + if (box[3] < newBBox[3]) { newBBox[3] = box[3]; } + } + } - // focus 1 given by coordinates - if (parents[0].length > 1) { - F1 = board.create('point', parents[0], attr_foci); - // focus 1 given by point - } else if (Type.isPoint(parents[0])) { - F1 = board.select(parents[0]); - // given by function - } else if (Type.isFunction(parents[0]) && Type.isPoint(parents[0]()) ) { - F1 = parents[0](); - // focus 1 given by point name - } else if (Type.isString(parents[0])) { - F1 = board.select(parents[0]); - } else { - throw new Error("JSXGraph: Can't create Parabola with parent types '" + - (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + - "\nPossible parent types: [point,line]"); - } + if (Type.isArray(newBBox)) { + cx = 0.5 * (newBBox[0] + newBBox[2]); + cy = 0.5 * (newBBox[1] + newBBox[3]); + dx = 1.5 * (newBBox[2] - newBBox[0]) * 0.5; + dy = 1.5 * (newBBox[1] - newBBox[3]) * 0.5; + d = Math.max(dx, dy); + this.setBoundingBox([cx - d, cy + d, cx + d, cy - d], this.keepaspectratio, 'update'); + } - // Create line if given as array of two points. - if (Type.isArray(l) && l.length == 2) { - attr_line = Type.copyAttributes(attributes, board.options, 'conic', 'line'); - l = board.create('line', l, attr_line); - } + return this; + }, - // to - if (!Type.exists(parents[3])) { - parents[3] = 10; - } + /** + * Sets the zoom level to <tt>fX</tt> resp <tt>fY</tt>. + * @param {Number} fX + * @param {Number} fY + * @returns {JXG.Board} Reference to the board. + */ + setZoom: function (fX, fY) { + var oX = this.attr.zoom.factorx, + oY = this.attr.zoom.factory; - // from - if (!Type.exists(parents[2])) { - parents[2] = -10; - } + this.attr.zoom.factorx = fX / this.zoomX; + this.attr.zoom.factory = fY / this.zoomY; - M = board.create('point', [ - function () { - /* - var v = [0, l.stdform[1], l.stdform[2]]; - v = Mat.crossProduct(v, F1.coords.usrCoords); - return Geometry.meetLineLine(v, l.stdform, 0, board).usrCoords; - */ - return Geometry.projectPointToLine(F1, l, board).usrCoords; - } - ], attr_center); + this.zoomIn(); - /** @ignore */ - curve = board.create('curve', [ - function (x) { - return 0; - }, - function (x) { - return 0; - }, parents[2], parents[3]], attr_curve); + this.attr.zoom.factorx = oX; + this.attr.zoom.factory = oY; - curve.midpoint = curve.center = M; - curve.subs = { - center: curve.center - }; - curve.inherits.push(curve.center); + return this; + }, - /** @ignore */ - polarForm = function (t, suspendUpdate) { - var a, b, c, ab, px, py; + /** + * Removes object from board and renderer. + * <p> + * <b>Performance hints:</b> It is recommended to use the object's id. + * If many elements are removed, it is best to call <tt>board.suspendUpdate()</tt> + * before looping through the elements to be removed and call + * <tt>board.unsuspendUpdate()</tt> after the loop. Further, it is advisable to loop + * in reverse order, i.e. remove the object in reverse order of their creation time. + * + * @param {JXG.GeometryElement|Array} object The object to remove or array of objects to be removed. + * The element(s) is/are given by name, id or a reference. + * @param {Boolean} saveMethod If true, the algorithm runs through all elements + * and tests if the element to be deleted is a child element. If yes, it will be + * removed from the list of child elements. If false (default), the element + * is removed from the lists of child elements of all its ancestors. + * This should be much faster. + * @returns {JXG.Board} Reference to the board + */ + removeObject: function (object, saveMethod) { + var el, i; - if (!suspendUpdate) { - a = l.stdform[1]; - b = l.stdform[2]; - c = l.stdform[0]; - ab = a * a + b * b; - px = F1.X(); - py = F1.Y(); + if (Type.isArray(object)) { + for (i = 0; i < object.length; i++) { + this.removeObject(object[i]); + } - curve.quadraticform = [ - [(c * c - ab * (px * px + py * py)), c * a + ab * px, c * b + ab * py], - [c * a + ab * px, -b * b, a * b], - [c * b + ab * py, a * b, -a * a] - ]; + return this; } - }; - /** @ignore */ - curve.X = function (phi, suspendUpdate) { - var a, det, - beta = l.getAngle(), - d = Geometry.distPointLine(F1.coords.usrCoords, l.stdform), - A = l.point1.coords.usrCoords, - B = l.point2.coords.usrCoords, - M = F1.coords.usrCoords; + object = this.select(object); - // Handle the case if one of the two defining points of the line is an ideal point - if (A[0] === 0) { - A = [1, B[1] + l.stdform[2], B[2] - l.stdform[1]]; - } else if (B[0] === 0) { - B = [1, A[1] + l.stdform[2], A[2] - l.stdform[1]]; + // If the object which is about to be removed unknown or a string, do nothing. + // it is a string if a string was given and could not be resolved to an element. + if (!Type.exists(object) || Type.isString(object)) { + return this; } - det = ((B[1] - A[1]) * (M[2] - A[2]) - (B[2] - A[2]) * (M[1] - A[1]) >= 0) ? 1 : -1; - a = det * d / (1 - Math.sin(phi)); - if (!suspendUpdate) { - polarForm(phi, suspendUpdate); + try { + // remove all children. + for (el in object.childElements) { + if (object.childElements.hasOwnProperty(el)) { + object.childElements[el].board.removeObject(object.childElements[el]); + } + } + + // Remove all children in elements like turtle + for (el in object.objects) { + if (object.objects.hasOwnProperty(el)) { + object.objects[el].board.removeObject(object.objects[el]); + } + } + + // Remove the element from the childElement list and the descendant list of all elements. + if (saveMethod) { + // Running through all objects has quadratic complexity if many objects are deleted. + for (el in this.objects) { + if (this.objects.hasOwnProperty(el)) { + if (Type.exists(this.objects[el].childElements) && + Type.exists(this.objects[el].childElements.hasOwnProperty(object.id)) + ) { + delete this.objects[el].childElements[object.id]; + delete this.objects[el].descendants[object.id]; + } + } + } + } else if (Type.exists(object.ancestors)) { + // Running through the ancestors should be much more efficient. + for (el in object.ancestors) { + if (object.ancestors.hasOwnProperty(el)) { + if (Type.exists(object.ancestors[el].childElements) && + Type.exists(object.ancestors[el].childElements.hasOwnProperty(object.id)) + ) { + delete object.ancestors[el].childElements[object.id]; + delete object.ancestors[el].descendants[object.id]; + } + } + } + } + + // remove the object itself from our control structures + if (object._pos > -1) { + this.objectsList.splice(object._pos, 1); + for (el = object._pos; el < this.objectsList.length; el++) { + this.objectsList[el]._pos--; + } + } else if (object.type !== Const.OBJECT_TYPE_TURTLE) { + JXG.debug('Board.removeObject: object ' + object.id + ' not found in list.'); + } + + delete this.objects[object.id]; + delete this.elementsByName[object.name]; + + if (object.visProp && Type.evaluate(object.visProp.trace)) { + object.clearTrace(); + } + + // the object deletion itself is handled by the object. + if (Type.exists(object.remove)) { + object.remove(); + } + } catch (e) { + JXG.debug(object.id + ': Could not be removed: ' + e); } - return F1.X() + Math.cos(phi + beta) * a; - }; + this.update(); - /** @ignore */ - curve.Y = function (phi, suspendUpdate) { - var a, det, - beta = l.getAngle(), - d = Geometry.distPointLine(F1.coords.usrCoords, l.stdform), - A = l.point1.coords.usrCoords, - B = l.point2.coords.usrCoords, - M = F1.coords.usrCoords; + return this; + }, - // Handle the case if one of the two defining points of the line is an ideal point - if (A[0] === 0) { - A = [1, B[1] + l.stdform[2], B[2] - l.stdform[1]]; - } else if (B[0] === 0) { - B = [1, A[1] + l.stdform[2], A[2] - l.stdform[1]]; + /** + * Removes the ancestors of an object an the object itself from board and renderer. + * @param {JXG.GeometryElement} object The object to remove. + * @returns {JXG.Board} Reference to the board + */ + removeAncestors: function (object) { + var anc; + + for (anc in object.ancestors) { + if (object.ancestors.hasOwnProperty(anc)) { + this.removeAncestors(object.ancestors[anc]); + } } - det = ((B[1] - A[1]) * (M[2] - A[2]) - (B[2] - A[2]) * (M[1] - A[1]) >= 0) ? 1 : -1; - a = det * d / (1 - Math.sin(phi)); - return F1.Y() + Math.sin(phi + beta) * a; - }; + this.removeObject(object); - curve.type = Const.OBJECT_TYPE_CONIC; - M.addChild(curve); + return this; + }, - if (Type.isPoint(F1)) { - F1.addChild(curve); - curve.inherits.push(F1); - } + /** + * Initialize some objects which are contained in every GEONExT construction by default, + * but are not contained in the gxt files. + * @returns {JXG.Board} Reference to the board + */ + initGeonextBoard: function () { + var p1, p2, p3; - l.addChild(curve); - curve.setParents(parents); + p1 = this.create('point', [0, 0], { + id: this.id + 'g00e0', + name: 'Ursprung', + withLabel: false, + visible: false, + fixed: true + }); - return curve; - }; + p2 = this.create('point', [1, 0], { + id: this.id + 'gX0e0', + name: 'Punkt_1_0', + withLabel: false, + visible: false, + fixed: true + }); - /** - * - * @class This element is used to provide a constructor for a generic conic section uniquely defined by five points or - * a conic defined by the coefficients of the equation - * <p><i>Ax<sup>2</sup>+ Bxy+Cy<sup>2</sup> + Dx + Ey + F = 0</i></p>. - * Then the parameters are as follows: - * <pre> - * board.create('conic', [A, C, F, B/2, D/2, E/2]); - * </pre> - * @pseudo - * @description - * @name Conic - * @augments JXG.Curve - * @constructor - * @type JXG.Conic - * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {JXG.Point,Array_JXG.Point,Array_JXG.Point,Array_JXG.Point,Array_JXG.Point,Array} a,b,c,d,e Parent elements are five points. - * @param {Number_Number_Number_Number_Number_Number} a_00,a_11,a_22,a_01,a_02,a_12 6 numbers, i.e. A, C, F, B/2, D/2, E/2 - * @example - * // Create a conic section through the points A, B, C, D, and E. - * var A = board.create('point', [1,5]); - * var B = board.create('point', [1,2]); - * var C = board.create('point', [2,0]); - * var D = board.create('point', [0,0]); - * var E = board.create('point', [-1,5]); - * var conic = board.create('conic',[A,B,C,D,E]); - * </pre><div class="jxgbox" id="JXG2d79bd6a-db9b-423c-9cba-2497f0b06320" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * var glex1_board = JXG.JSXGraph.initBoard('JXG2d79bd6a-db9b-423c-9cba-2497f0b06320', {boundingbox:[-6,6,6,-6], keepaspectratio:true, showcopyright: false, shownavigation: false}); - * var A = glex1_board.create('point', [1,5]); - * var B = glex1_board.create('point', [1,2]); - * var C = glex1_board.create('point', [2,0]); - * var D = glex1_board.create('point', [0,0]); - * var E = glex1_board.create('point', [-1,5]); - * var conic = glex1_board.create('conic',[A,B,C,D,E]); - * </script><pre> - * - * @example - * // Parameters: A, C, F, B/2, D/2, E/2 - * var conic = board.create('conic', [1, 2, -4, 0, 0, 0]s); - * - * </pre><div id="JXG8576a04a-52d8-4a7e-8d54-e32443910b97" class="jxgbox" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function() { - * var board = JXG.JSXGraph.initBoard('JXG8576a04a-52d8-4a7e-8d54-e32443910b97', - * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); - * // Parameters: A, C, F, B/2, D/2, E/2 - * var conic = board.create('conic', [1, 2, -4, 0, 0, 0]s); - * })(); - * - * </script><pre> - * - */ - JXG.createConic = function (board, parents, attributes) { - var polarForm, curve, fitConic, degconic, sym, - eigen, a, b, c, c1, c2, - i, definingMat, givenByPoints, - rotationMatrix = [ - [1, 0, 0], - [0, 1, 0], - [0, 0, 1] - ], - M = [ - [1, 0, 0], - [0, 1, 0], - [0, 0, 1] - ], - points = [], - p = [], - attr_point = Type.copyAttributes(attributes, board.options, 'conic', 'point'), - attr_center = Type.copyAttributes(attributes, board.options, 'conic', 'center'), - attr_curve = Type.copyAttributes(attributes, board.options, 'conic'); + p3 = this.create('point', [0, 1], { + id: this.id + 'gY0e0', + name: 'Punkt_0_1', + withLabel: false, + visible: false, + fixed: true + }); - if (parents.length === 5) { - givenByPoints = true; - } else if (parents.length === 6) { - givenByPoints = false; - } else { - throw new Error("JSXGraph: Can't create generic Conic with " + parents.length + " parameters."); - } + this.create('line', [p1, p2], { + id: this.id + 'gXLe0', + name: 'X-Achse', + withLabel: false, + visible: false + }); - if (givenByPoints) { - for (i = 0; i < 5; i++) { - // point i given by coordinates - if (parents[i].length > 1) { - points[i] = board.create('point', parents[i], attr_point); - // point i given by point - } else if (Type.isPoint(parents[i])) { - points[i] = board.select(parents[i]); - // given by function - } else if (Type.isFunction(parents[i]) && Type.isPoint(parents[i]()) ) { - points[i] = parents[i](); - // point i given by point name - } else if (Type.isString(parents[i])) { - points[i] = board.select(parents[i]); - } else { - throw new Error("JSXGraph: Can't create Conic section with parent types '" + (typeof parents[i]) + "'." + - "\nPossible parent types: [point,point,point,point,point], [a00,a11,a22,a01,a02,a12]"); - } - } - } else { - /* Usual notation (x,y,z): - * [[A0,A3,A4], - * [A3,A1,A5], - * [A4,A5,A2]]. - * Our notation (z,x,y): - * [[A2, A4, A5], - * [A4, A0, A3], - * [A5, A3, A1]] - */ - definingMat = [ - [0, 0, 0], - [0, 0, 0], - [0, 0, 0] - ]; - definingMat[0][0] = (Type.isFunction(parents[2])) ? function () { return parents[2](); } : function () { return parents[2]; }; - definingMat[0][1] = (Type.isFunction(parents[4])) ? function () { return parents[4](); } : function () { return parents[4]; }; - definingMat[0][2] = (Type.isFunction(parents[5])) ? function () { return parents[5](); } : function () { return parents[5]; }; - definingMat[1][1] = (Type.isFunction(parents[0])) ? function () { return parents[0](); } : function () { return parents[0]; }; - definingMat[1][2] = (Type.isFunction(parents[3])) ? function () { return parents[3](); } : function () { return parents[3]; }; - definingMat[2][2] = (Type.isFunction(parents[1])) ? function () { return parents[1](); } : function () { return parents[1]; }; - } + this.create('line', [p1, p3], { + id: this.id + 'gYLe0', + name: 'Y-Achse', + withLabel: false, + visible: false + }); - // sym(A) = A + A^t . Manipulates A in place. - sym = function (A) { - var i, j; - for (i = 0; i < 3; i++) { - for (j = i; j < 3; j++) { - A[i][j] += A[j][i]; - } - } - for (i = 0; i < 3; i++) { - for (j = 0; j < i; j++) { - A[i][j] = A[j][i]; - } - } - return A; - }; + return this; + }, - // degconic(v,w) = sym(v*w^t) - degconic = function (v, w) { - var i, j, mat = [ - [0, 0, 0], - [0, 0, 0], - [0, 0, 0] - ]; + /** + * Change the height and width of the board's container. + * After doing so, {@link JXG.JSXGraph.setBoundingBox} is called using + * the actual size of the bounding box and the actual value of keepaspectratio. + * If setBoundingbox() should not be called automatically, + * call resizeContainer with dontSetBoundingBox == true. + * @param {Number} canvasWidth New width of the container. + * @param {Number} canvasHeight New height of the container. + * @param {Boolean} [dontset=false] If true do not set the CSS width and height of the DOM element. + * @param {Boolean} [dontSetBoundingBox=false] If true do not call setBoundingBox(). + * @returns {JXG.Board} Reference to the board + */ + resizeContainer: function (canvasWidth, canvasHeight, dontset, dontSetBoundingBox) { + var box; + // w, h, cx, cy; + // box_act, + // shift_x = 0, + // shift_y = 0; - for (i = 0; i < 3; i++) { - for (j = 0; j < 3; j++) { - mat[i][j] = v[i] * w[j]; - } + if (!dontSetBoundingBox) { + // box_act = this.getBoundingBox(); // This is the actual bounding box. + box = this.getBoundingBox(); // This is the actual bounding box. } - return sym(mat); - }; + this.canvasWidth = parseFloat(canvasWidth); + this.canvasHeight = parseFloat(canvasHeight); - // (p^t*B*p)*A-(p^t*A*p)*B - fitConic = function (A, B, p) { - var i, j, pBp, pAp, Mv, - mat = [ - [0, 0, 0], - [0, 0, 0], - [0, 0, 0] - ]; + // if (!dontSetBoundingBox) { + // box = this.attr.boundingbox; // This is the intended bounding box. - Mv = Mat.matVecMult(B, p); - pBp = Mat.innerProduct(p, Mv); - Mv = Mat.matVecMult(A, p); - pAp = Mat.innerProduct(p, Mv); + // // The shift values compensate the follow-up correction + // // in setBoundingBox in case of "this.keepaspectratio==true" + // // Otherwise, shift_x and shift_y will be zero. + // // Obsolet since setBoundingBox centers in case of "this.keepaspectratio==true". + // // shift_x = box_act[0] - box[0] / this.zoomX; + // // shift_y = box_act[1] - box[1] / this.zoomY; - for (i = 0; i < 3; i++) { - for (j = 0; j < 3; j++) { - mat[i][j] = pBp * A[i][j] - pAp * B[i][j]; - } + // cx = (box[2] + box[0]) * 0.5; // + shift_x; + // cy = (box[3] + box[1]) * 0.5; // + shift_y; + + // w = (box[2] - box[0]) * 0.5 / this.zoomX; + // h = (box[1] - box[3]) * 0.5 / this.zoomY; + + // box = [cx - w, cy + h, cx + w, cy - h]; + // } + + if (!dontset) { + this.containerObj.style.width = (this.canvasWidth) + 'px'; + this.containerObj.style.height = (this.canvasHeight) + 'px'; } - return mat; - }; + this.renderer.resize(this.canvasWidth, this.canvasHeight); - // Here, the defining functions for the curve are just dummy functions. - // In polarForm there is a reference to curve.quadraticform. - curve = board.create('curve', [ - function (x) { - return 0; - }, - function (x) { - return 0; - }, 0, 2 * Math.PI], attr_curve); + if (!dontSetBoundingBox) { + this.setBoundingBox(box, this.keepaspectratio, 'keep'); + } - /** @ignore */ - polarForm = function (phi, suspendUpdate) { - var i, j, len, v; + return this; + }, - if (!suspendUpdate) { - if (givenByPoints) { - // Copy the point coordinate vectors - for (i = 0; i < 5; i++) { - p[i] = points[i].coords.usrCoords; + /** + * Lists the dependencies graph in a new HTML-window. + * @returns {JXG.Board} Reference to the board + */ + showDependencies: function () { + var el, t, c, f, i; + + t = '<p>\n'; + for (el in this.objects) { + if (this.objects.hasOwnProperty(el)) { + i = 0; + for (c in this.objects[el].childElements) { + if (this.objects[el].childElements.hasOwnProperty(c)) { + i += 1; + } + } + if (i >= 0) { + t += '<strong>' + this.objects[el].id + ':<' + '/strong> '; } - // Compute the quadratic form - c1 = degconic(Mat.crossProduct(p[0], p[1]), Mat.crossProduct(p[2], p[3])); - c2 = degconic(Mat.crossProduct(p[0], p[2]), Mat.crossProduct(p[1], p[3])); - M = fitConic(c1, c2, p[4]); - } else { - for (i = 0; i < 3; i++) { - for (j = i; j < 3; j++) { - M[i][j] = definingMat[i][j](); - if (j > i) { - M[j][i] = M[i][j]; - } + for (c in this.objects[el].childElements) { + if (this.objects[el].childElements.hasOwnProperty(c)) { + t += this.objects[el].childElements[c].id + '(' + this.objects[el].childElements[c].name + ')' + ', '; } } + t += '<p>\n'; } + } + t += '<' + '/p>\n'; + f = window.open(); + f.document.open(); + f.document.write(t); + f.document.close(); + return this; + }, - // Here is the reference back to the curve. - curve.quadraticform = M; - - // Compute Eigenvalues and Eigenvectors - eigen = Numerics.Jacobi(M); - - // Scale the Eigenvalues such that the first Eigenvalue is positive - if (eigen[0][0][0] < 0) { - eigen[0][0][0] *= (-1); - eigen[0][1][1] *= (-1); - eigen[0][2][2] *= (-1); - } + /** + * Lists the XML code of the construction in a new HTML-window. + * @returns {JXG.Board} Reference to the board + */ + showXML: function () { + var f = window.open(''); + f.document.open(); + f.document.write('<pre>' + Type.escapeHTML(this.xmlString) + '<' + '/pre>'); + f.document.close(); + return this; + }, - // Normalize the Eigenvectors - for (i = 0; i < 3; i++) { - len = 0.0; - for (j = 0; j < 3; j++) { - len += eigen[1][j][i] * eigen[1][j][i]; - } - len = Math.sqrt(len); - /*for (j = 0; j < 3; j++) { - //eigen[1][j][i] /= len; - }*/ - } - rotationMatrix = eigen[1]; - c = Math.sqrt(Math.abs(eigen[0][0][0])); - a = Math.sqrt(Math.abs(eigen[0][1][1])); - b = Math.sqrt(Math.abs(eigen[0][2][2])); + /** + * Sets for all objects the needsUpdate flag to "true". + * @returns {JXG.Board} Reference to the board + */ + prepareUpdate: function () { + var el, pEl, len = this.objectsList.length; + /* + if (this.attr.updatetype === 'hierarchical') { + return this; } + */ - // The degenerate cases with eigen[0][i][i]==0 are not handled correct yet. - if (eigen[0][1][1] <= 0.0 && eigen[0][2][2] <= 0.0) { - v = Mat.matVecMult(rotationMatrix, [1 / c, Math.cos(phi) / a, Math.sin(phi) / b]); - } else if (eigen[0][1][1] <= 0.0 && eigen[0][2][2] > 0.0) { - v = Mat.matVecMult(rotationMatrix, [Math.cos(phi) / c, 1 / a, Math.sin(phi) / b]); - } else if (eigen[0][2][2] < 0.0) { - v = Mat.matVecMult(rotationMatrix, [Math.sin(phi) / c, Math.cos(phi) / a, 1 / b]); + for (el = 0; el < len; el++) { + pEl = this.objectsList[el]; + pEl.needsUpdate = pEl.needsRegularUpdate || this.needsFullUpdate; } - if (Type.exists(v)) { - // Normalize - v[1] /= v[0]; - v[2] /= v[0]; - v[0] = 1.0; - } else { - v = [1, NaN, NaN]; + for (el in this.groups) { + if (this.groups.hasOwnProperty(el)) { + pEl = this.groups[el]; + pEl.needsUpdate = pEl.needsRegularUpdate || this.needsFullUpdate; + } } - return v; - }; - - /** @ignore */ - curve.X = function (phi, suspendUpdate) { - return polarForm(phi, suspendUpdate)[1]; - }; + return this; + }, - /** @ignore */ - curve.Y = function (phi, suspendUpdate) { - return polarForm(phi, suspendUpdate)[2]; - }; + /** + * Runs through all elements and calls their update() method. + * @param {JXG.GeometryElement} drag Element that caused the update. + * @returns {JXG.Board} Reference to the board + */ + updateElements: function (drag) { + var el, pEl; + //var childId, i = 0; - // Center coordinates see http://en.wikipedia.org/wiki/Matrix_representation_of_conic_sections - curve.midpoint = board.create('point', [ - function () { - var m = curve.quadraticform; + drag = this.select(drag); - return [ - m[1][1] * m[2][2] - m[1][2] * m[1][2], - m[1][2] * m[0][2] - m[2][2] * m[0][1], - m[0][1] * m[1][2] - m[1][1] * m[0][2] - ]; + /* + if (Type.exists(drag)) { + for (el = 0; el < this.objectsList.length; el++) { + pEl = this.objectsList[el]; + if (pEl.id === drag.id) { + i = el; + break; + } + } } - ], attr_center); - - curve.type = Const.OBJECT_TYPE_CONIC; - curve.center = curve.midpoint; - curve.subs = { - center: curve.center - }; - curve.inherits.push(curve.center); - curve.inherits = curve.inherits.concat(points); + */ - if (givenByPoints) { - for (i = 0; i < 5; i++) { - if (Type.isPoint(points[i])) { - points[i].addChild(curve); + for (el = 0; el < this.objectsList.length; el++) { + pEl = this.objectsList[el]; + if (this.needsFullUpdate && pEl.elementClass === Const.OBJECT_CLASS_TEXT) { + pEl.updateSize(); } - } - curve.setParents(parents); - } - curve.addChild(curve.center); - return curve; - }; + // For updates of an element we distinguish if the dragged element is updated or + // other elements are updated. + // The difference lies in the treatment of gliders and points based on transformations. + pEl.update(!Type.exists(drag) || pEl.id !== drag.id) + .updateVisibility(); + } - JXG.registerElement('ellipse', JXG.createEllipse); - JXG.registerElement('hyperbola', JXG.createHyperbola); - JXG.registerElement('parabola', JXG.createParabola); - JXG.registerElement('conic', JXG.createConic); + // update groups last + for (el in this.groups) { + if (this.groups.hasOwnProperty(el)) { + this.groups[el].update(drag); + } + } - return { - createEllipse: JXG.createEllipse, - createHyperbola: JXG.createHyperbola, - createParabola: JXG.createParabola, - createConic: JXG.createConic - }; -}); + return this; + }, -/* - Copyright 2008-2021 - Matthias Ehmann, - Michael Gerhaeuser, - Carsten Miller, - Bianca Valentin, - Alfred Wassermann, - Peter Wilfahrt + /** + * Runs through all elements and calls their update() method. + * @returns {JXG.Board} Reference to the board + */ + updateRenderer: function () { + var el, + len = this.objectsList.length; - This file is part of JSXGraph. + /* + objs = this.objectsList.slice(0); + objs.sort(function (a, b) { + if (a.visProp.layer < b.visProp.layer) { + return -1; + } else if (a.visProp.layer === b.visProp.layer) { + return b.lastDragTime.getTime() - a.lastDragTime.getTime(); + } else { + return 1; + } + }); + */ - JSXGraph is free software dual licensed under the GNU LGPL or MIT License. + if (this.renderer.type === 'canvas') { + this.updateRendererCanvas(); + } else { + for (el = 0; el < len; el++) { + this.objectsList[el].updateRenderer(); + } + } + return this; + }, - You can redistribute it and/or modify it under the terms of the + /** + * Runs through all elements and calls their update() method. + * This is a special version for the CanvasRenderer. + * Here, we have to do our own layer handling. + * @returns {JXG.Board} Reference to the board + */ + updateRendererCanvas: function () { + var el, pEl, i, mini, la, + olen = this.objectsList.length, + layers = this.options.layer, + len = this.options.layer.numlayers, + last = Number.NEGATIVE_INFINITY; - * GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version - OR - * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT + for (i = 0; i < len; i++) { + mini = Number.POSITIVE_INFINITY; - JSXGraph is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. + for (la in layers) { + if (layers.hasOwnProperty(la)) { + if (layers[la] > last && layers[la] < mini) { + mini = layers[la]; + } + } + } - You should have received a copy of the GNU Lesser General Public License and - the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> - and <http://opensource.org/licenses/MIT/>. - */ + last = mini; + for (el = 0; el < olen; el++) { + pEl = this.objectsList[el]; -/*global JXG: true, define: true*/ -/*jslint nomen: true, plusplus: true*/ + if (pEl.visProp.layer === mini) { + pEl.prepareUpdate().updateRenderer(); + } + } + } + return this; + }, -/* depends: - jxg - base/element - base/constants - base/coords - parser/geonext - math/geometry - math/statistics - utils/type - elements: - transform - point - */ - -/** - * @fileoverview The geometry object Circle is defined in this file. Circle stores all - * style and functional properties that are required to draw and move a circle on - * a board. - */ + /** + * Please use {@link JXG.Board.on} instead. + * @param {Function} hook A function to be called by the board after an update occurred. + * @param {String} [m='update'] When the hook is to be called. Possible values are <i>mouseup</i>, <i>mousedown</i> and <i>update</i>. + * @param {Object} [context=board] Determines the execution context the hook is called. This parameter is optional, default is the + * board object the hook is attached to. + * @returns {Number} Id of the hook, required to remove the hook from the board. + * @deprecated + */ + addHook: function (hook, m, context) { + JXG.deprecated('Board.addHook()', 'Board.on()'); + m = Type.def(m, 'update'); -define('base/circle',[ - 'jxg', 'base/element', 'base/coords', 'base/constants', 'element/conic', 'parser/geonext', 'utils/type' -], function (JXG, GeometryElement, Coords, Const, Conic, GeonextParser, Type) { + context = Type.def(context, this); - "use strict"; + this.hooks.push([m, hook]); + this.on(m, hook, context); - /** - * A circle consists of all points with a given distance from one point. This point is called center, the distance is called radius. - * A circle can be constructed by providing a center and a point on the circle or a center and a radius (given as a number, function, - * line, or circle). - * @class Creates a new circle object. Do not use this constructor to create a circle. Use {@link JXG.Board#create} with - * type {@link Circle} instead. - * @constructor - * @augments JXG.GeometryElement - * @param {JXG.Board} board The board the new circle is drawn on. - * @param {String} method Can be - * <ul><li> <b>'twoPoints'</b> which means the circle is defined by its center and a point on the circle.</li> - * <li><b>'pointRadius'</b> which means the circle is defined by its center and its radius in user units</li> - * <li><b>'pointLine'</b> which means the circle is defined by its center and its radius given by the distance from the startpoint and the endpoint of the line</li> - * <li><b>'pointCircle'</b> which means the circle is defined by its center and its radius given by the radius of another circle</li></ul> - * The parameters p1, p2 and radius must be set according to this method parameter. - * @param {JXG.Point} par1 center of the circle. - * @param {JXG.Point|JXG.Line|JXG.Circle} par2 Can be - * <ul><li>a point on the circle if method is 'twoPoints'</li> - * <li>a line if the method is 'pointLine'</li> - * <li>a circle if the method is 'pointCircle'</li></ul> - * @param {Object} attributes - * @see JXG.Board#generateName - */ - JXG.Circle = function (board, method, par1, par2, attributes) { - // Call the constructor of GeometryElement - this.constructor(board, attributes, Const.OBJECT_TYPE_CIRCLE, Const.OBJECT_CLASS_CIRCLE); + return this.hooks.length - 1; + }, /** - * Stores the given method. - * Can be - * <ul><li><b>'twoPoints'</b> which means the circle is defined by its center and a point on the circle.</li> - * <li><b>'pointRadius'</b> which means the circle is defined by its center and its radius given in user units or as term.</li> - * <li><b>'pointLine'</b> which means the circle is defined by its center and its radius given by the distance from the startpoint and the endpoint of the line.</li> - * <li><b>'pointCircle'</b> which means the circle is defined by its center and its radius given by the radius of another circle.</li></ul> - * @type String - * @see #center - * @see #point2 - * @see #radius - * @see #line - * @see #circle + * Alias of {@link JXG.Board.on}. */ - this.method = method; - - // this is kept so existing code won't ne broken - this.midpoint = this.board.select(par1); + addEvent: JXG.shortcut(JXG.Board.prototype, 'on'), /** - * The circles center. Do not set this parameter directly as it will break JSXGraph's update system. - * @type JXG.Point - */ - this.center = this.board.select(par1); - - /** Point on the circle only set if method equals 'twoPoints'. Do not set this parameter directly as it will break JSXGraph's update system. - * @type JXG.Point - * @see #method + * Please use {@link JXG.Board.off} instead. + * @param {Number|function} id The number you got when you added the hook or a reference to the event handler. + * @returns {JXG.Board} Reference to the board + * @deprecated */ - this.point2 = null; + removeHook: function (id) { + JXG.deprecated('Board.removeHook()', 'Board.off()'); + if (this.hooks[id]) { + this.off(this.hooks[id][0], this.hooks[id][1]); + this.hooks[id] = null; + } - /** Radius of the circle - * only set if method equals 'pointRadius' - * @type Number - * @default null - * @see #method - */ - this.radius = 0; + return this; + }, - /** Line defining the radius of the circle given by the distance from the startpoint and the endpoint of the line - * only set if method equals 'pointLine'. Do not set this parameter directly as it will break JSXGraph's update system. - * @type JXG.Line - * @default null - * @see #method + /** + * Alias of {@link JXG.Board.off}. */ - this.line = null; + removeEvent: JXG.shortcut(JXG.Board.prototype, 'off'), - /** Circle defining the radius of the circle given by the radius of the other circle - * only set if method equals 'pointLine'. Do not set this parameter directly as it will break JSXGraph's update system. - * @type JXG.Circle - * @default null - * @see #method + /** + * Runs through all hooked functions and calls them. + * @returns {JXG.Board} Reference to the board + * @deprecated */ - this.circle = null; - - if (method === 'twoPoints') { - this.point2 = board.select(par2); - this.radius = this.Radius(); - } else if (method === 'pointRadius') { - this.gxtterm = par2; - // Converts GEONExT syntax into JavaScript syntax and generally ensures that the radius is a function - this.updateRadius = Type.createFunction(par2, this.board, null, true); - // First evaluation of the radius function - this.updateRadius(); - } else if (method === 'pointLine') { - // dann ist p2 die Id eines Objekts vom Typ Line! - this.line = board.select(par2); - this.radius = this.line.point1.coords.distance(Const.COORDS_BY_USER, this.line.point2.coords); - } else if (method === 'pointCircle') { - // dann ist p2 die Id eines Objekts vom Typ Circle! - this.circle = board.select(par2); - this.radius = this.circle.Radius(); - } - - // create Label - this.id = this.board.setId(this, 'C'); - this.board.renderer.drawEllipse(this); - this.board.finalizeAdding(this); - - this.createGradient(); - this.elType = 'circle'; - this.createLabel(); - - this.center.addChild(this); + updateHooks: function (m) { + var arg = Array.prototype.slice.call(arguments, 0); - if (method === 'pointRadius') { - this.notifyParents(par2); - } else if (method === 'pointLine') { - this.line.addChild(this); - } else if (method === 'pointCircle') { - this.circle.addChild(this); - } else if (method === 'twoPoints') { - this.point2.addChild(this); - } + JXG.deprecated('Board.updateHooks()', 'Board.triggerEventHandlers()'); - this.methodMap = Type.deepCopy(this.methodMap, { - setRadius: 'setRadius', - getRadius: 'getRadius', - Area: 'Area', - area: 'Area', - radius: 'Radius', - center: 'center', - line: 'line', - point2: 'point2' - }); - }; + arg[0] = Type.def(arg[0], 'update'); + this.triggerEventHandlers([arg[0]], arguments); - JXG.Circle.prototype = new GeometryElement(); + return this; + }, - JXG.extend(JXG.Circle.prototype, /** @lends JXG.Circle.prototype */ { /** - * Checks whether (x,y) is near the circle line or inside of the ellipse - * (in case JXG.Options.conic#hasInnerPoints is true). - * @param {Number} x Coordinate in x direction, screen coordinates. - * @param {Number} y Coordinate in y direction, screen coordinates. - * @returns {Boolean} True if (x,y) is near the circle, False otherwise. - * @private + * Adds a dependent board to this board. + * @param {JXG.Board} board A reference to board which will be updated after an update of this board occurred. + * @returns {JXG.Board} Reference to the board */ - hasPoint: function (x, y) { - var prec, type, - mp = this.center.coords.usrCoords, - p = new Coords(Const.COORDS_BY_SCREEN, [x, y], this.board), - r = this.Radius(), - dx, dy, dist; - - - if (Type.isObject(Type.evaluate(this.visProp.precision))) { - type = this.board._inputDevice; - prec = Type.evaluate(this.visProp.precision[type]); - } else { - // 'inherit' - prec = this.board.options.precision.hasPoint; - } - dx = mp[1] - p.usrCoords[1]; - dy = mp[2] - p.usrCoords[2]; - dist = Math.sqrt(dx * dx + dy * dy); - // We have to use usrCoords, since Radius is available in usrCoords only. - prec += Type.evaluate(this.visProp.strokewidth) * 0.5; - prec /= Math.sqrt(this.board.unitX * this.board.unitY); - - if (Type.evaluate(this.visProp.hasinnerpoints)) { - return (dist < r + prec); + addChild: function (board) { + if (Type.exists(board) && Type.exists(board.containerObj)) { + this.dependentBoards.push(board); + this.update(); } - - return (Math.abs(dist - r) < prec); + return this; }, /** - * Used to generate a polynomial for a point p that lies on this circle. - * @param {JXG.Point} p The point for which the polynomial is generated. - * @returns {Array} An array containing the generated polynomial. - * @private + * Deletes a board from the list of dependent boards. + * @param {JXG.Board} board Reference to the board which will be removed. + * @returns {JXG.Board} Reference to the board */ - generatePolynomial: function (p) { - /* - * We have four methods to construct a circle: - * (a) Two points - * (b) center and radius - * (c) center and radius given by length of a segment - * (d) center and radius given by another circle - * - * In case (b) we have to distinguish two cases: - * (i) radius is given as a number - * (ii) radius is given as a function - * In the latter case there's no guarantee the radius depends on other geometry elements - * in a polynomial way so this case has to be omitted. - * - * Another tricky case is case (d): - * The radius depends on another circle so we have to cycle through the ancestors of each circle - * until we reach one that's radius does not depend on another circles radius. - * - * - * All cases (a) to (d) vary only in calculation of the radius. So the basic formulae for - * a glider G (g1,g2) on a circle with center M (m1,m2) and radius r is just: - * - * (g1-m1)^2 + (g2-m2)^2 - r^2 = 0 - * - * So the easiest case is (b) with a fixed radius given as a number. The other two cases (a) - * and (c) are quite the same: Euclidean distance between two points A (a1,a2) and B (b1,b2), - * squared: - * - * r^2 = (a1-b1)^2 + (a2-b2)^2 - * - * For case (d) we have to cycle recursively through all defining circles and finally return the - * formulae for calculating r^2. For that we use JXG.Circle.symbolic.generateRadiusSquared(). - */ - var m1 = this.center.symbolic.x, - m2 = this.center.symbolic.y, - g1 = p.symbolic.x, - g2 = p.symbolic.y, - rsq = this.generateRadiusSquared(); + removeChild: function (board) { + var i; - /* No radius can be calculated (Case b.ii) */ - if (rsq === '') { - return []; + for (i = this.dependentBoards.length - 1; i >= 0; i--) { + if (this.dependentBoards[i] === board) { + this.dependentBoards.splice(i, 1); + } } - - return ['((' + g1 + ')-(' + m1 + '))^2 + ((' + g2 + ')-(' + m2 + '))^2 - (' + rsq + ')']; + return this; }, /** - * Generate symbolic radius calculation for loci determination with Groebner-Basis algorithm. - * @returns {String} String containing symbolic calculation of the circle's radius or an empty string - * if the radius can't be expressed in a polynomial equation. - * @private + * Runs through most elements and calls their update() method and update the conditions. + * @param {JXG.GeometryElement} [drag] Element that caused the update. + * @returns {JXG.Board} Reference to the board */ - generateRadiusSquared: function () { - /* - * Four cases: - * - * (a) Two points - * (b) center and radius - * (c) center and radius given by length of a segment - * (d) center and radius given by another circle - */ - var m1, m2, p1, p2, q1, q2, - rsq = ''; - - if (this.method === "twoPoints") { - m1 = this.center.symbolic.x; - m2 = this.center.symbolic.y; - p1 = this.point2.symbolic.x; - p2 = this.point2.symbolic.y; + update: function (drag) { + var i, len, b, insert, + storeActiveEl; - rsq = '((' + p1 + ')-(' + m1 + '))^2 + ((' + p2 + ')-(' + m2 + '))^2'; - } else if (this.method === "pointRadius") { - if (Type.isNumber(this.radius)) { - rsq = (this.radius * this.radius).toString(); - } - } else if (this.method === "pointLine") { - p1 = this.line.point1.symbolic.x; - p2 = this.line.point1.symbolic.y; + if (this.inUpdate || this.isSuspendedUpdate) { + return this; + } + this.inUpdate = true; - q1 = this.line.point2.symbolic.x; - q2 = this.line.point2.symbolic.y; + if (this.attr.minimizereflow === 'all' && this.containerObj && this.renderer.type !== 'vml') { + storeActiveEl = this.document.activeElement; // Store focus element + insert = this.renderer.removeToInsertLater(this.containerObj); + } - rsq = '((' + p1 + ')-(' + q1 + '))^2 + ((' + p2 + ')-(' + q2 + '))^2'; - } else if (this.method === "pointCircle") { - rsq = this.circle.Radius(); + if (this.attr.minimizereflow === 'svg' && this.renderer.type === 'svg') { + storeActiveEl = this.document.activeElement; + insert = this.renderer.removeToInsertLater(this.renderer.svgRoot); } - return rsq; - }, + this.prepareUpdate().updateElements(drag).updateConditions(); + this.renderer.suspendRedraw(this); + this.updateRenderer(); + this.renderer.unsuspendRedraw(); + this.triggerEventHandlers(['update'], []); - /** - * Uses the boards renderer to update the circle. - */ - update: function () { - if (this.needsUpdate) { - if (Type.evaluate(this.visProp.trace)) { - this.cloneToBackground(true); - } + if (insert) { + insert(); + storeActiveEl.focus(); // Restore focus element + } - if (this.method === 'pointLine') { - this.radius = this.line.point1.coords.distance(Const.COORDS_BY_USER, this.line.point2.coords); - } else if (this.method === 'pointCircle') { - this.radius = this.circle.Radius(); - } else if (this.method === 'pointRadius') { - this.radius = this.updateRadius(); + // To resolve dependencies between boards + // for (var board in JXG.boards) { + len = this.dependentBoards.length; + for (i = 0; i < len; i++) { + b = this.dependentBoards[i]; + if (Type.exists(b) && b !== this) { + b.updateQuality = this.updateQuality; + b.prepareUpdate().updateElements().updateConditions(); + b.renderer.suspendRedraw(); + b.updateRenderer(); + b.renderer.unsuspendRedraw(); + b.triggerEventHandlers(['update'], []); } - this.updateStdform(); - this.updateQuadraticform(); } + this.inUpdate = false; return this; }, /** - * Updates this circle's {@link JXG.Circle#quadraticform}. - * @private + * Runs through all elements and calls their update() method and update the conditions. + * This is necessary after zooming and changing the bounding box. + * @returns {JXG.Board} Reference to the board */ - updateQuadraticform: function () { - var m = this.center, - mX = m.X(), - mY = m.Y(), - r = this.Radius(); + fullUpdate: function () { + this.needsFullUpdate = true; + this.update(); + this.needsFullUpdate = false; + return this; + }, - this.quadraticform = [ - [mX * mX + mY * mY - r * r, -mX, -mY], - [-mX, 1, 0], - [-mY, 0, 1] - ]; + /** + * Adds a grid to the board according to the settings given in board.options. + * @returns {JXG.Board} Reference to the board. + */ + addGrid: function () { + this.create('grid', []); + + return this; }, /** - * Updates the stdform derived from the position of the center and the circle's radius. - * @private + * Removes all grids assigned to this board. Warning: This method also removes all objects depending on one or + * more of the grids. + * @returns {JXG.Board} Reference to the board object. */ - updateStdform: function () { - this.stdform[3] = 0.5; - this.stdform[4] = this.Radius(); - this.stdform[1] = -this.center.coords.usrCoords[1]; - this.stdform[2] = -this.center.coords.usrCoords[2]; - if (!isFinite(this.stdform[4])) { - this.stdform[0] = Type.exists(this.point2) ? -( - this.stdform[1] * this.point2.coords.usrCoords[1] + - this.stdform[2] * this.point2.coords.usrCoords[2] - ) : 0; + removeGrids: function () { + var i; + + for (i = 0; i < this.grids.length; i++) { + this.removeObject(this.grids[i]); } - this.normalize(); + + this.grids.length = 0; + this.update(); // required for canvas renderer + + return this; }, /** - * Uses the boards renderer to update the circle. - * @private + * Creates a new geometric element of type elementType. + * @param {String} elementType Type of the element to be constructed given as a string e.g. 'point' or 'circle'. + * @param {Array} parents Array of parent elements needed to construct the element e.g. coordinates for a point or two + * points to construct a line. This highly depends on the elementType that is constructed. See the corresponding JXG.create* + * methods for a list of possible parameters. + * @param {Object} [attributes] An object containing the attributes to be set. This also depends on the elementType. + * Common attributes are name, visible, strokeColor. + * @returns {Object} Reference to the created element. This is usually a GeometryElement, but can be an array containing + * two or more elements. */ - updateRenderer: function () { - // var wasReal; + create: function (elementType, parents, attributes) { + var el, i; - if (!this.needsUpdate) { - return this; + elementType = elementType.toLowerCase(); + + if (!Type.exists(parents)) { + parents = []; } - if (this.visPropCalc.visible) { - // wasReal = this.isReal; - this.isReal = (!isNaN(this.center.coords.usrCoords[1] + this.center.coords.usrCoords[2] + this.Radius())) && this.center.isReal; + if (!Type.exists(attributes)) { + attributes = {}; + } - if (//wasReal && - !this.isReal) { - this.updateVisibility(false); + for (i = 0; i < parents.length; i++) { + if (Type.isString(parents[i]) && + !(elementType === 'text' && i === 2) && + !(elementType === 'solidofrevolution3d' && i === 2) && + !((elementType === 'input' || elementType === 'checkbox' || elementType === 'button') && + (i === 2 || i === 3)) && + !(elementType === 'curve' && i > 0) // Allow curve plots with jessiecode + ) { + parents[i] = this.select(parents[i]); } } - // Update the position - if (this.visPropCalc.visible) { - this.board.renderer.updateEllipse(this); + if (Type.isFunction(JXG.elements[elementType])) { + el = JXG.elements[elementType](this, parents, attributes); + } else { + throw new Error("JSXGraph: create: Unknown element type given: " + elementType); } - // Update the label if visible. - if (this.hasLabel && this.visPropCalc.visible && this.label && - this.label.visPropCalc.visible && this.isReal) { - - this.label.update(); - this.board.renderer.updateText(this.label); + if (!Type.exists(el)) { + JXG.debug("JSXGraph: create: failure creating " + elementType); + return el; } - // Update rendNode display - this.setDisplayRendNode(); - // if (this.visPropCalc.visible !== this.visPropOld.visible) { - // this.board.renderer.display(this, this.visPropCalc.visible); - // this.visPropOld.visible = this.visPropCalc.visible; - // - // if (this.hasLabel) { - // this.board.renderer.display(this.label, this.label.visPropCalc.visible); - // } - // } - - this.needsUpdate = false; - return this; + if (el.prepareUpdate && el.update && el.updateRenderer) { + el.fullUpdate(); + } + return el; }, /** - * Finds dependencies in a given term and resolves them by adding the elements referenced in this - * string to the circle's list of ancestors. - * @param {String} contentStr - * @private + * Deprecated name for {@link JXG.Board.create}. + * @deprecated */ - notifyParents: function (contentStr) { - if (Type.isString(contentStr)) { - GeonextParser.findDependencies(this, contentStr, this.board); - } + createElement: function () { + JXG.deprecated('Board.createElement()', 'Board.create()'); + return this.create.apply(this, arguments); }, /** - * Set a new radius, then update the board. - * @param {String|Number|function} r A string, function or number describing the new radius. - * @returns {JXG.Circle} Reference to this circle - */ - setRadius: function (r) { - this.updateRadius = Type.createFunction(r, this.board, null, true); - this.board.update(); + * Delete the elements drawn as part of a trace of an element. + * @returns {JXG.Board} Reference to the board + */ + clearTraces: function () { + var el; + for (el = 0; el < this.objectsList.length; el++) { + this.objectsList[el].clearTrace(); + } + + this.numTraces = 0; return this; }, /** - * Calculates the radius of the circle. - * @param {String|Number|function} [value] Set new radius - * @returns {Number} The radius of the circle + * Stop updates of the board. + * @returns {JXG.Board} Reference to the board */ - Radius: function (value) { - if (Type.exists(value)) { - this.setRadius(value); - return this.Radius(); + suspendUpdate: function () { + if (!this.inUpdate) { + this.isSuspendedUpdate = true; } + return this; + }, - if (this.method === 'twoPoints') { - if (Type.cmpArrays(this.point2.coords.usrCoords, [0, 0, 0]) || - Type.cmpArrays(this.center.coords.usrCoords, [0, 0, 0])) { + /** + * Enable updates of the board. + * @returns {JXG.Board} Reference to the board + */ + unsuspendUpdate: function () { + if (this.isSuspendedUpdate) { + this.isSuspendedUpdate = false; + this.fullUpdate(); + } + return this; + }, - return NaN; - } + /** + * Set the bounding box of the board. + * @param {Array} bbox New bounding box [x1,y1,x2,y2] + * @param {Boolean} [keepaspectratio=false] If set to true, the aspect ratio will be 1:1, but + * the resulting viewport may be larger. + * @param {String} [setZoom='reset'] Reset, keep or update the zoom level of the board. 'reset' + * sets {@link JXG.Board#zoomX} and {@link JXG.Board#zoomY} to the start values (or 1.0). + * 'update' adapts these values accoring to the new bounding box and 'keep' does nothing. + * @returns {JXG.Board} Reference to the board + */ + setBoundingBox: function (bbox, keepaspectratio, setZoom) { + var h, w, ux, uy, + offX = 0, + offY = 0, + dim = Env.getDimensions(this.container, this.document); - return this.center.Dist(this.point2); + if (!Type.isArray(bbox)) { + return this; } - if (this.method === 'pointLine' || this.method === 'pointCircle') { - return this.radius; + if (bbox[0] < this.maxboundingbox[0] || + bbox[1] > this.maxboundingbox[1] || + bbox[2] > this.maxboundingbox[2] || + bbox[3] < this.maxboundingbox[3]) { + return this; } - if (this.method === 'pointRadius') { - return this.updateRadius(); + if (!Type.exists(setZoom)) { + setZoom = 'reset'; } - return NaN; + ux = this.unitX; + uy = this.unitY; + + this.canvasWidth = parseInt(dim.width, 10); + this.canvasHeight = parseInt(dim.height, 10); + w = this.canvasWidth; + h = this.canvasHeight; + if (keepaspectratio) { + this.unitX = w / (bbox[2] - bbox[0]); + this.unitY = h / (bbox[1] - bbox[3]); + if (Math.abs(this.unitX) < Math.abs(this.unitY)) { + this.unitY = Math.abs(this.unitX) * this.unitY / Math.abs(this.unitY); + // Add the additional units in equal portions above and below + offY = (h / this.unitY - (bbox[1] - bbox[3])) * 0.5; + } else { + this.unitX = Math.abs(this.unitY) * this.unitX / Math.abs(this.unitX); + // Add the additional units in equal portions left and right + offX = (w / this.unitX - (bbox[2] - bbox[0])) * 0.5; + } + this.keepaspectratio = true; + } else { + this.unitX = w / (bbox[2] - bbox[0]); + this.unitY = h / (bbox[1] - bbox[3]); + this.keepaspectratio = false; + } + + this.moveOrigin(-this.unitX * (bbox[0] - offX), this.unitY * (bbox[1] + offY)); + + if (setZoom === 'update') { + this.zoomX *= this.unitX / ux; + this.zoomY *= this.unitY / uy; + } else if (setZoom === 'reset') { + this.zoomX = Type.exists(this.attr.zoomx) ? this.attr.zoomx : 1.0; + this.zoomY = Type.exists(this.attr.zoomy) ? this.attr.zoomy : 1.0; + } + + return this; }, /** - * Use {@link JXG.Circle#Radius}. - * @deprecated + * Get the bounding box of the board. + * @returns {Array} bounding box [x1,y1,x2,y2] upper left corner, lower right corner */ - getRadius: function () { - JXG.deprecated('Circle.getRadius()', 'Circle.Radius()'); - return this.Radius(); - }, + getBoundingBox: function () { + var ul = (new Coords(Const.COORDS_BY_SCREEN, [0, 0], this)).usrCoords, + lr = (new Coords(Const.COORDS_BY_SCREEN, [this.canvasWidth, this.canvasHeight], this)).usrCoords; - // documented in geometry element - getTextAnchor: function () { - return this.center.coords; + return [ul[1], ul[2], lr[1], lr[2]]; }, - // documented in geometry element - getLabelAnchor: function () { - var x, y, - r = this.Radius(), - c = this.center.coords.usrCoords; + /** + * Adds an animation. Animations are controlled by the boards, so the boards need to be aware of the + * animated elements. This function tells the board about new elements to animate. + * @param {JXG.GeometryElement} element The element which is to be animated. + * @returns {JXG.Board} Reference to the board + */ + addAnimation: function (element) { + var that = this; - switch (Type.evaluate(this.visProp.label.position)) { - case 'lft': - x = c[1] - r; - y = c[2]; - break; - case 'llft': - x = c[1] - Math.sqrt(0.5) * r; - y = c[2] - Math.sqrt(0.5) * r; - break; - case 'rt': - x = c[1] + r; - y = c[2]; - break; - case 'lrt': - x = c[1] + Math.sqrt(0.5) * r; - y = c[2] - Math.sqrt(0.5) * r; - break; - case 'urt': - x = c[1] + Math.sqrt(0.5) * r; - y = c[2] + Math.sqrt(0.5) * r; - break; - case 'top': - x = c[1]; - y = c[2] + r; - break; - case 'bot': - x = c[1]; - y = c[2] - r; - break; - default: - // includes case 'ulft' - x = c[1] - Math.sqrt(0.5) * r; - y = c[2] + Math.sqrt(0.5) * r; - break; + this.animationObjects[element.id] = element; + + if (!this.animationIntervalCode) { + this.animationIntervalCode = window.setInterval(function () { + that.animate(); + }, element.board.attr.animationdelay); } - return new Coords(Const.COORDS_BY_USER, [x, y], this.board); + return this; }, - // documented in geometry element - cloneToBackground: function () { - var er, - r = this.Radius(), - copy = { - id: this.id + 'T' + this.numTraces, - elementClass: Const.OBJECT_CLASS_CIRCLE, - center: { - coords: this.center.coords - }, - Radius: function () { - return r; - }, - getRadius: function () { - return r; - }, - board: this.board, - visProp: Type.deepCopy(this.visProp, this.visProp.traceattributes, true) - }; - - copy.visProp.layer = this.board.options.layer.trace; + /** + * Cancels all running animations. + * @returns {JXG.Board} Reference to the board + */ + stopAllAnimation: function () { + var el; - this.numTraces++; - Type.clearVisPropOld(copy); - copy.visPropCalc = { - visible: Type.evaluate(copy.visProp.visible) - }; + for (el in this.animationObjects) { + if (this.animationObjects.hasOwnProperty(el) && Type.exists(this.animationObjects[el])) { + this.animationObjects[el] = null; + delete this.animationObjects[el]; + } + } - er = this.board.renderer.enhancedRendering; - this.board.renderer.enhancedRendering = true; - this.board.renderer.drawEllipse(copy); - this.board.renderer.enhancedRendering = er; - this.traces[copy.id] = copy.rendNode; + window.clearInterval(this.animationIntervalCode); + delete this.animationIntervalCode; return this; }, /** - * Add transformations to this circle. - * @param {JXG.Transformation|Array} transform Either one {@link JXG.Transformation} or an array of {@link JXG.Transformation}s. - * @returns {JXG.Circle} Reference to this circle object. + * General purpose animation function. This currently only supports moving points from one place to another. This + * is faster than managing the animation per point, especially if there is more than one animated point at the same time. + * @returns {JXG.Board} Reference to the board */ - addTransform: function (transform) { - var i, - list = Type.isArray(transform) ? transform : [transform], - len = list.length; + animate: function () { + var props, el, o, newCoords, r, p, c, cbtmp, + count = 0, + obj = null; - for (i = 0; i < len; i++) { - this.center.transformations.push(list[i]); + for (el in this.animationObjects) { + if (this.animationObjects.hasOwnProperty(el) && Type.exists(this.animationObjects[el])) { + count += 1; + o = this.animationObjects[el]; - if (this.method === 'twoPoints') { - this.point2.transformations.push(list[i]); + if (o.animationPath) { + if (Type.isFunction(o.animationPath)) { + newCoords = o.animationPath(new Date().getTime() - o.animationStart); + } else { + newCoords = o.animationPath.pop(); + } + + if ((!Type.exists(newCoords)) || (!Type.isArray(newCoords) && isNaN(newCoords))) { + delete o.animationPath; + } else { + o.setPositionDirectly(Const.COORDS_BY_USER, newCoords); + o.fullUpdate(); + obj = o; + } + } + if (o.animationData) { + c = 0; + + for (r in o.animationData) { + if (o.animationData.hasOwnProperty(r)) { + p = o.animationData[r].pop(); + + if (!Type.exists(p)) { + delete o.animationData[p]; + } else { + c += 1; + props = {}; + props[r] = p; + o.setAttribute(props); + } + } + } + + if (c === 0) { + delete o.animationData; + } + } + + if (!Type.exists(o.animationData) && !Type.exists(o.animationPath)) { + this.animationObjects[el] = null; + delete this.animationObjects[el]; + + if (Type.exists(o.animationCallback)) { + cbtmp = o.animationCallback; + o.animationCallback = null; + cbtmp(); + } + } } } + if (count === 0) { + window.clearInterval(this.animationIntervalCode); + delete this.animationIntervalCode; + } else { + this.update(obj); + } + return this; }, - // see element.js - snapToGrid: function () { - var forceIt = Type.evaluate(this.visProp.snaptogrid); + /** + * Migrate the dependency properties of the point src + * to the point dest and delete the point src. + * For example, a circle around the point src + * receives the new center dest. The old center src + * will be deleted. + * @param {JXG.Point} src Original point which will be deleted + * @param {JXG.Point} dest New point with the dependencies of src. + * @param {Boolean} copyName Flag which decides if the name of the src element is copied to the + * dest element. + * @returns {JXG.Board} Reference to the board + */ + migratePoint: function (src, dest, copyName) { + var child, childId, prop, found, i, srcLabelId, srcHasLabel = false; - this.center.handleSnapToGrid(forceIt, true); - if (this.method === 'twoPoints') { - this.point2.handleSnapToGrid(forceIt, true); + src = this.select(src); + dest = this.select(dest); + + if (Type.exists(src.label)) { + srcLabelId = src.label.id; + srcHasLabel = true; + this.removeObject(src.label); } - return this; - }, + for (childId in src.childElements) { + if (src.childElements.hasOwnProperty(childId)) { + child = src.childElements[childId]; + found = false; - // see element.js - snapToPoints: function () { - var forceIt = Type.evaluate(this.visProp.snaptopoints); + for (prop in child) { + if (child.hasOwnProperty(prop)) { + if (child[prop] === src) { + child[prop] = dest; + found = true; + } + } + } - this.center.handleSnapToPoints(forceIt); - if (this.method === 'twoPoints') { - this.point2.handleSnapToPoints(forceIt); + if (found) { + delete src.childElements[childId]; + } + + for (i = 0; i < child.parents.length; i++) { + if (child.parents[i] === src.id) { + child.parents[i] = dest.id; + } + } + + dest.addChild(child); + } + } + + // The destination object should receive the name + // and the label of the originating (src) object + if (copyName) { + if (srcHasLabel) { + delete dest.childElements[srcLabelId]; + delete dest.descendants[srcLabelId]; + } + + if (dest.label) { + this.removeObject(dest.label); + } + + delete this.elementsByName[dest.name]; + dest.name = src.name; + if (srcHasLabel) { + dest.createLabel(); + } + } + + this.removeObject(src); + + if (Type.exists(dest.name) && dest.name !== '') { + this.elementsByName[dest.name] = dest; } + this.fullUpdate(); + return this; }, /** - * Treats the circle as parametric curve and calculates its X coordinate. - * @param {Number} t Number between 0 and 1. - * @returns {Number} <tt>X(t)= radius*cos(t)+centerX</tt>. + * Initializes color blindness simulation. + * @param {String} deficiency Describes the color blindness deficiency which is simulated. Accepted values are 'protanopia', 'deuteranopia', and 'tritanopia'. + * @returns {JXG.Board} Reference to the board */ - X: function (t) { - return this.Radius() * Math.cos(t * 2 * Math.PI) + this.center.coords.usrCoords[1]; - }, + emulateColorblindness: function (deficiency) { + var e, o; - /** - * Treats the circle as parametric curve and calculates its Y coordinate. - * @param {Number} t Number between 0 and 1. - * @returns {Number} <tt>X(t)= radius*sin(t)+centerY</tt>. - */ - Y: function (t) { - return this.Radius() * Math.sin(t * 2 * Math.PI) + this.center.coords.usrCoords[2]; - }, + if (!Type.exists(deficiency)) { + deficiency = 'none'; + } - /** - * Treat the circle as parametric curve and calculates its Z coordinate. - * @param {Number} t ignored - * @returns {Number} 1.0 - */ - Z: function (t) { - return 1.0; - }, + if (this.currentCBDef === deficiency) { + return this; + } - /** - * Returns 0. - * @private - */ - minX: function () { - return 0.0; - }, + for (e in this.objects) { + if (this.objects.hasOwnProperty(e)) { + o = this.objects[e]; - /** - * Returns 1. - * @private - */ - maxX: function () { - return 1.0; + if (deficiency !== 'none') { + if (this.currentCBDef === 'none') { + // this could be accomplished by JXG.extend, too. But do not use + // JXG.deepCopy as this could result in an infinite loop because in + // visProp there could be geometry elements which contain the board which + // contains all objects which contain board etc. + o.visPropOriginal = { + strokecolor: o.visProp.strokecolor, + fillcolor: o.visProp.fillcolor, + highlightstrokecolor: o.visProp.highlightstrokecolor, + highlightfillcolor: o.visProp.highlightfillcolor + }; + } + o.setAttribute({ + strokecolor: Color.rgb2cb(Type.evaluate(o.visPropOriginal.strokecolor), deficiency), + fillcolor: Color.rgb2cb(Type.evaluate(o.visPropOriginal.fillcolor), deficiency), + highlightstrokecolor: Color.rgb2cb(Type.evaluate(o.visPropOriginal.highlightstrokecolor), deficiency), + highlightfillcolor: Color.rgb2cb(Type.evaluate(o.visPropOriginal.highlightfillcolor), deficiency) + }); + } else if (Type.exists(o.visPropOriginal)) { + JXG.extend(o.visProp, o.visPropOriginal); + } + } + } + this.currentCBDef = deficiency; + this.update(); + + return this; }, /** - * Circle area - * @returns {Number} area of the circle. + * Select a single or multiple elements at once. + * @param {String|Object|function} str The name, id or a reference to a JSXGraph element on this board. An object will + * be used as a filter to return multiple elements at once filtered by the properties of the object. + * @param {Boolean} onlyByIdOrName If true (default:false) elements are only filtered by their id, name or groupId. + * The advanced filters consisting of objects or functions are ignored. + * @returns {JXG.GeometryElement|JXG.Composition} + * @example + * // select the element with name A + * board.select('A'); + * + * // select all elements with strokecolor set to 'red' (but not '#ff0000') + * board.select({ + * strokeColor: 'red' + * }); + * + * // select all points on or below the x axis and make them black. + * board.select({ + * elementClass: JXG.OBJECT_CLASS_POINT, + * Y: function (v) { + * return v <= 0; + * } + * }).setAttribute({color: 'black'}); + * + * // select all elements + * board.select(function (el) { + * return true; + * }); */ - Area: function () { - var r = this.Radius(); + select: function (str, onlyByIdOrName) { + var flist, olist, i, l, + s = str; - return r * r * Math.PI; - }, + if (s === null) { + return s; + } - /** - * Get bounding box of the circle. - * @returns {Array} [x1, y1, x2, y2] - */ - bounds: function () { - var uc = this.center.coords.usrCoords, - r = this.Radius(); + // it's a string, most likely an id or a name. + if (Type.isString(s) && s !== '') { + // Search by ID + if (Type.exists(this.objects[s])) { + s = this.objects[s]; + // Search by name + } else if (Type.exists(this.elementsByName[s])) { + s = this.elementsByName[s]; + // Search by group ID + } else if (Type.exists(this.groups[s])) { + s = this.groups[s]; + } + // it's a function or an object, but not an element + } else if (!onlyByIdOrName && + (Type.isFunction(s) || + (Type.isObject(s) && !Type.isFunction(s.setAttribute)) + )) { + flist = Type.filterElements(this.objectsList, s); - return [uc[1] - r, uc[2] + r, uc[1] + r, uc[2] - r]; + olist = {}; + l = flist.length; + for (i = 0; i < l; i++) { + olist[flist[i].id] = flist[i]; + } + s = new Composition(olist); + // it's an element which has been deleted (and still hangs around, e.g. in an attractor list + } else if (Type.isObject(s) && Type.exists(s.id) && !Type.exists(this.objects[s.id])) { + s = null; + } + + return s; }, /** - * Get data to construct this element. Data consists of the parent elements - * and static data like radius. - * @returns {Array} data necessary to construct this element + * Checks if the given point is inside the boundingbox. + * @param {Number|JXG.Coords} x User coordinate or {@link JXG.Coords} object. + * @param {Number} [y] User coordinate. May be omitted in case <tt>x</tt> is a {@link JXG.Coords} object. + * @returns {Boolean} */ - getParents: function() { - if (this.parents.length === 1) { // i.e. this.method === 'pointRadius' - return this.parents.concat(this.radius); + hasPoint: function (x, y) { + var px = x, + py = y, + bbox = this.getBoundingBox(); + + if (Type.exists(x) && Type.isArray(x.usrCoords)) { + px = x.usrCoords[1]; + py = x.usrCoords[2]; } - return this.parents; - } - }); - /** - * @class This element is used to provide a constructor for a circle. - * @pseudo - * @description A circle consists of all points with a given distance from one point. This point is called center, the distance is called radius. - * A circle can be constructed by providing a center and a point on the circle or a center and a radius (given as a number, function, - * line, or circle). - * @name Circle - * @augments JXG.Circle - * @constructor - * @type JXG.Circle - * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {JXG.Point_number,JXG.Point,JXG.Line,JXG.Circle} center,radius The center must be given as a {@link JXG.Point}, see {@link JXG.providePoints}, but the radius can be given - * as a number (which will create a circle with a fixed radius), another {@link JXG.Point}, a {@link JXG.Line} (the distance of start and end point of the - * line will determine the radius), or another {@link JXG.Circle}. - * @example - * // Create a circle providing two points - * var p1 = board.create('point', [2.0, 2.0]), - * p2 = board.create('point', [2.0, 0.0]), - * c1 = board.create('circle', [p1, p2]); - * - * // Create another circle using the above circle - * var p3 = board.create('point', [3.0, 2.0]), - * c2 = board.create('circle', [p3, c1]); - * </pre><div class="jxgbox" id="JXG5f304d31-ef20-4a8e-9c0e-ea1a2b6c79e0" style="width: 400px; height: 400px;"></div> - * <script type="text/javascript"> - * (function() { - * var cex1_board = JXG.JSXGraph.initBoard('JXG5f304d31-ef20-4a8e-9c0e-ea1a2b6c79e0', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); - * cex1_p1 = cex1_board.create('point', [2.0, 2.0]), - * cex1_p2 = cex1_board.create('point', [2.0, 0.0]), - * cex1_c1 = cex1_board.create('circle', [cex1_p1, cex1_p2]), - * cex1_p3 = cex1_board.create('point', [3.0, 2.0]), - * cex1_c2 = cex1_board.create('circle', [cex1_p3, cex1_c1]); - * })(); - * </script><pre> - * @example - * // Create a circle providing two points - * var p1 = board.create('point', [2.0, 2.0]), - * c1 = board.create('circle', [p1, 3]); - * - * // Create another circle using the above circle - * var c2 = board.create('circle', [function() { return [p1.X(), p1.Y() + 1];}, function() { return c1.Radius(); }]); - * </pre><div class="jxgbox" id="JXG54165f60-93b9-441d-8979-ac5d0f193020" style="width: 400px; height: 400px;"></div> - * <script type="text/javascript"> - * (function() { - * var board = JXG.JSXGraph.initBoard('JXG54165f60-93b9-441d-8979-ac5d0f193020', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); - * var p1 = board.create('point', [2.0, 2.0]); - * var c1 = board.create('circle', [p1, 3]); - * - * // Create another circle using the above circle - * var c2 = board.create('circle', [function() { return [p1.X(), p1.Y() + 1];}, function() { return c1.Radius(); }]); - * })(); - * </script><pre> - * @example - * var li = board.create('line', [1,1,1], {strokeColor: '#aaaaaa'}); - * var reflect = board.create('transform', [li], {type: 'reflect'}); - * - * var c1 = board.create('circle', [[-2,-2], [-2, -1]], {center: {visible:true}}); - * var c2 = board.create('circle', [c1, reflect]); - * * </pre><div id="JXGa2a5a870-5dbb-11e8-9fb9-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function() { - * var board = JXG.JSXGraph.initBoard('JXGa2a5a870-5dbb-11e8-9fb9-901b0e1b8723', - * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); - * var li = board.create('line', [1,1,1], {strokeColor: '#aaaaaa'}); - * var reflect = board.create('transform', [li], {type: 'reflect'}); - * - * var c1 = board.create('circle', [[-2,-2], [-2, -1]], {center: {visible:true}}); - * var c2 = board.create('circle', [c1, reflect]); - * })(); - * - * </script><pre> - * - * @example - * var t = board.create('transform', [2, 1.5], {type: 'scale'}); - * var c1 = board.create('circle', [[1.3, 1.3], [0, 1.3]], {strokeColor: 'black', center: {visible:true}}); - * var c2 = board.create('circle', [c1, t], {strokeColor: 'black'}); - * - * </pre><div id="JXG0686a222-6339-11e8-9fb9-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function() { - * var board = JXG.JSXGraph.initBoard('JXG0686a222-6339-11e8-9fb9-901b0e1b8723', - * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); - * var t = board.create('transform', [2, 1.5], {type: 'scale'}); - * var c1 = board.create('circle', [[1.3, 1.3], [0, 1.3]], {strokeColor: 'black', center: {visible:true}}); - * var c2 = board.create('circle', [c1, t], {strokeColor: 'black'}); - * - * })(); - * - * </script><pre> - * - */ - JXG.createCircle = function (board, parents, attributes) { - var el, p, i, attr, obj, - isDraggable = true; + return !!(Type.isNumber(px) && Type.isNumber(py) && + bbox[0] < px && px < bbox[2] && bbox[1] > py && py > bbox[3]); + }, - p = []; - obj = board.select(parents[0]); - if (Type.isObject(obj) && obj.elementClass === Const.OBJECT_CLASS_CIRCLE && - Type.isTransformationOrArray(parents[1])) { + /** + * Update CSS transformations of type scaling. It is used to correct the mouse position + * in {@link JXG.Board.getMousePosition}. + * The inverse transformation matrix is updated on each mouseDown and touchStart event. + * + * It is up to the user to call this method after an update of the CSS transformation + * in the DOM. + */ + updateCSSTransforms: function () { + var obj = this.containerObj, + o = obj, + o2 = obj; - attr = Type.copyAttributes(attributes, board.options, 'circle'); - // if (!Type.exists(attr.type) || attr.type.toLowerCase() !== 'euclidean') { - // // Create a circle element from a circle and a Euclidean transformation - // el = JXG.createCircle(board, [obj.center, function() { return obj.Radius(); }], attr); - // } else { - // Create a conic element from a circle and a projective transformation - el = Conic.createEllipse(board, [obj.center, obj.center, function() { return 2 * obj.Radius(); }], attr); - // } - el.addTransform(parents[1]); - return el; + this.cssTransMat = Env.getCSSTransformMatrix(o); - } - // Circle defined by points - for (i = 0; i < parents.length; i++) { - if (Type.isPointType(board, parents[i])) { - p = p.concat(Type.providePoints(board, [parents[i]], attributes, 'circle', ['center'])); - if (p[p.length - 1] === false) { - throw new Error('JSXGraph: Can\'t create circle from this type. Please provide a point type.'); - } - } else { - p.push(parents[i]); - } - } + /* + * In Mozilla and Webkit: offsetParent seems to jump at least to the next iframe, + * if not to the body. In IE and if we are in an position:absolute environment + * offsetParent walks up the DOM hierarchy. + * In order to walk up the DOM hierarchy also in Mozilla and Webkit + * we need the parentNode steps. + */ + o = o.offsetParent; + while (o) { + this.cssTransMat = Mat.matMatMult(Env.getCSSTransformMatrix(o), this.cssTransMat); - attr = Type.copyAttributes(attributes, board.options, 'circle'); + o2 = o2.parentNode; + while (o2 !== o) { + this.cssTransMat = Mat.matMatMult(Env.getCSSTransformMatrix(o), this.cssTransMat); + o2 = o2.parentNode || o2.host; + } - if (p.length === 2 && Type.isPoint(p[0]) && Type.isPoint(p[1])) { - // Point/Point - el = new JXG.Circle(board, 'twoPoints', p[0], p[1], attr); - } else if ((Type.isNumber(p[0]) || Type.isFunction(p[0]) || Type.isString(p[0])) && - Type.isPoint(p[1])) { - // Number/Point - el = new JXG.Circle(board, 'pointRadius', p[1], p[0], attr); - } else if ((Type.isNumber(p[1]) || Type.isFunction(p[1]) || Type.isString(p[1])) && - Type.isPoint(p[0])) { - // Point/Number - el = new JXG.Circle(board, 'pointRadius', p[0], p[1], attr); - } else if ((p[0].elementClass === Const.OBJECT_CLASS_CIRCLE) && Type.isPoint(p[1])) { - // Circle/Point - el = new JXG.Circle(board, 'pointCircle', p[1], p[0], attr); - } else if ((p[1].elementClass === Const.OBJECT_CLASS_CIRCLE) && Type.isPoint(p[0])) { - // Point/Circle - el = new JXG.Circle(board, 'pointCircle', p[0], p[1], attr); - } else if ((p[0].elementClass === Const.OBJECT_CLASS_LINE) && Type.isPoint(p[1])) { - // Line/Point - el = new JXG.Circle(board, 'pointLine', p[1], p[0], attr); - } else if ((p[1].elementClass === Const.OBJECT_CLASS_LINE) && Type.isPoint(p[0])) { - // Point/Line - el = new JXG.Circle(board, 'pointLine', p[0], p[1], attr); - } else if (parents.length === 3 && Type.isPoint(p[0]) && Type.isPoint(p[1]) && Type.isPoint(p[2])) { - // Circle through three points - // Check if circumcircle element is available - if (JXG.elements.circumcircle) { - el = JXG.elements.circumcircle(board, p, attr); - } else { - throw new Error('JSXGraph: Can\'t create circle with three points. Please include the circumcircle element (element/composition).'); + o = o.offsetParent; } + this.cssTransMat = Mat.inverse(this.cssTransMat); - } else { - throw new Error("JSXGraph: Can't create circle with parent types '" + - (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + - "\nPossible parent types: [point,point], [point,number], [point,function], [point,circle], [point,point,point], [circle,transformation]"); - } + return this; + }, - el.isDraggable = isDraggable; - el.setParents(p); - el.elType = 'circle'; - for (i = 0; i < p.length; i++) { - if (Type.isPoint(p[i])) { - el.inherits.push(p[i]); - } - } - return el; - }; + /** + * Start selection mode. This function can either be triggered from outside or by + * a down event together with correct key pressing. The default keys are + * shift+ctrl. But this can be changed in the options. + * + * Starting from out side can be realized for example with a button like this: + * <pre> + * <button onclick="board.startSelectionMode()">Start</button> + * </pre> + * @example + * // + * // Set a new bounding box from the selection rectangle + * // + * var board = JXG.JSXGraph.initBoard('jxgbox', { + * boundingBox:[-3,2,3,-2], + * keepAspectRatio: false, + * axis:true, + * selection: { + * enabled: true, + * needShift: false, + * needCtrl: true, + * withLines: false, + * vertices: { + * visible: false + * }, + * fillColor: '#ffff00', + * } + * }); + * + * var f = function f(x) { return Math.cos(x); }, + * curve = board.create('functiongraph', [f]); + * + * board.on('stopselecting', function(){ + * var box = board.stopSelectionMode(), + * + * // bbox has the coordinates of the selection rectangle. + * // Attention: box[i].usrCoords have the form [1, x, y], i.e. + * // are homogeneous coordinates. + * bbox = box[0].usrCoords.slice(1).concat(box[1].usrCoords.slice(1)); + * + * // Set a new bounding box + * board.setBoundingBox(bbox, false); + * }); + * + * + * </pre><div class="jxgbox" id="JXG11eff3a6-8c50-11e5-b01d-901b0e1b8723" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * // + * // Set a new bounding box from the selection rectangle + * // + * var board = JXG.JSXGraph.initBoard('JXG11eff3a6-8c50-11e5-b01d-901b0e1b8723', { + * boundingBox:[-3,2,3,-2], + * keepAspectRatio: false, + * axis:true, + * selection: { + * enabled: true, + * needShift: false, + * needCtrl: true, + * withLines: false, + * vertices: { + * visible: false + * }, + * fillColor: '#ffff00', + * } + * }); + * + * var f = function f(x) { return Math.cos(x); }, + * curve = board.create('functiongraph', [f]); + * + * board.on('stopselecting', function(){ + * var box = board.stopSelectionMode(), + * + * // bbox has the coordinates of the selection rectangle. + * // Attention: box[i].usrCoords have the form [1, x, y], i.e. + * // are homogeneous coordinates. + * bbox = box[0].usrCoords.slice(1).concat(box[1].usrCoords.slice(1)); + * + * // Set a new bounding box + * board.setBoundingBox(bbox, false); + * }); + * })(); + * + * </script><pre> + * + */ + startSelectionMode: function () { + this.selectingMode = true; + this.selectionPolygon.setAttribute({visible: true}); + this.selectingBox = [[0, 0], [0, 0]]; + this._setSelectionPolygonFromBox(); + this.selectionPolygon.fullUpdate(); + }, - JXG.registerElement('circle', JXG.createCircle); + /** + * Finalize the selection: disable selection mode and return the coordinates + * of the selection rectangle. + * @returns {Array} Coordinates of the selection rectangle. The array + * contains two {@link JXG.Coords} objects. One the upper left corner and + * the second for the lower right corner. + */ + stopSelectionMode: function () { + this.selectingMode = false; + this.selectionPolygon.setAttribute({visible: false}); + return [this.selectionPolygon.vertices[0].coords, this.selectionPolygon.vertices[2].coords]; + }, - return { - Circle: JXG.Circle, - createCircle: JXG.createCircle - }; -}); + /** + * Start the selection of a region. + * @private + * @param {Array} pos Screen coordiates of the upper left corner of the + * selection rectangle. + */ + _startSelecting: function (pos) { + this.isSelecting = true; + this.selectingBox = [ [pos[0], pos[1]], [pos[0], pos[1]] ]; + this._setSelectionPolygonFromBox(); + }, -/* - Copyright 2008-2021 - Matthias Ehmann, - Michael Gerhaeuser, - Carsten Miller, - Bianca Valentin, - Alfred Wassermann, - Peter Wilfahrt + /** + * Update the selection rectangle during a move event. + * @private + * @param {Array} pos Screen coordiates of the move event + */ + _moveSelecting: function (pos) { + if (this.isSelecting) { + this.selectingBox[1] = [pos[0], pos[1]]; + this._setSelectionPolygonFromBox(); + this.selectionPolygon.fullUpdate(); + } + }, - This file is part of JSXGraph. + /** + * Update the selection rectangle during an up event. Stop selection. + * @private + * @param {Object} evt Event object + */ + _stopSelecting: function (evt) { + var pos = this.getMousePosition(evt); - JSXGraph is free software dual licensed under the GNU LGPL or MIT License. + this.isSelecting = false; + this.selectingBox[1] = [pos[0], pos[1]]; + this._setSelectionPolygonFromBox(); + }, - You can redistribute it and/or modify it under the terms of the + /** + * Update the Selection rectangle. + * @private + */ + _setSelectionPolygonFromBox: function () { + var A = this.selectingBox[0], + B = this.selectingBox[1]; - * GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version - OR - * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT + this.selectionPolygon.vertices[0].setPositionDirectly(JXG.COORDS_BY_SCREEN, [A[0], A[1]]); + this.selectionPolygon.vertices[1].setPositionDirectly(JXG.COORDS_BY_SCREEN, [A[0], B[1]]); + this.selectionPolygon.vertices[2].setPositionDirectly(JXG.COORDS_BY_SCREEN, [B[0], B[1]]); + this.selectionPolygon.vertices[3].setPositionDirectly(JXG.COORDS_BY_SCREEN, [B[0], A[1]]); + }, - JSXGraph is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. + /** + * Test if a down event should start a selection. Test if the + * required keys are pressed. If yes, {@link JXG.Board.startSelectionMode} is called. + * @param {Object} evt Event object + */ + _testForSelection: function (evt) { + if (this._isRequiredKeyPressed(evt, 'selection')) { + if (!Type.exists(this.selectionPolygon)) { + this._createSelectionPolygon(this.attr); + } + this.startSelectionMode(); + } + }, - You should have received a copy of the GNU Lesser General Public License and - the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> - and <http://opensource.org/licenses/MIT/>. - */ + /** + * Create the internal selection polygon, which will be available as board.selectionPolygon. + * @private + * @param {Object} attr board attributes, e.g. the subobject board.attr. + * @returns {Object} pointer to the board to enable chaining. + */ + _createSelectionPolygon: function(attr) { + var selectionattr; + if (!Type.exists(this.selectionPolygon)) { + selectionattr = Type.copyAttributes(attr, Options, 'board', 'selection'); + if (selectionattr.enabled === true) { + this.selectionPolygon = this.create('polygon', [[0, 0], [0, 0], [0, 0], [0, 0]], selectionattr); + } + } -/*global JXG: true, define: true*/ -/*jslint nomen: true, plusplus: true*/ + return this; + }, -/* depends: - jxg - utils/type - */ + /* ************************** + * EVENT DEFINITION + * for documentation purposes + * ************************** */ -define('base/composition',['jxg', 'utils/type'], function (JXG, Type) { + //region Event handler documentation - "use strict"; + /** + * @event + * @description Whenever the user starts to touch or click the board. + * @name JXG.Board#down + * @param {Event} e The browser's event object. + */ + __evt__down: function (e) { }, - /** - * A composition is a simple container that manages none or more {@link JXG.GeometryElement}s. - * @param {Object} elements A list of elements with a descriptive name for the element as the key and a reference - * to the element as the value of every list entry. The name is used to access the element later on. - * @example - * var p1 = board.create('point', [1, 2]), - * p2 = board.create('point', [2, 3]), - * c = new JXG.Composition({ - * start: p1, - * end: p2 - * }); - * - * // moves p1 to [3, 3] - * c.start.moveTo([3, 3]); - * @class JXG.Composition - */ - JXG.Composition = function (elements) { - var e, - that = this, - genericMethods = [ - /** - * Invokes setAttribute for every stored element with a setAttribute method and hands over the given arguments. - * See {@link JXG.GeometryElement#setAttribute} for further description, valid parameters and return values. - * @name setAttribute - * @memberOf JXG.Composition.prototype - * @function - */ - 'setAttribute', + /** + * @event + * @description Whenever the user starts to click on the board. + * @name JXG.Board#mousedown + * @param {Event} e The browser's event object. + */ + __evt__mousedown: function (e) { }, - /** - * Invokes setParents for every stored element with a setParents method and hands over the given arguments. - * See {@link JXG.GeometryElement#setParents} for further description, valid parameters and return values. - * @name setParents - * @memberOf JXG.Composition.prototype - * @function - */ - 'setParents', + /** + * @event + * @description Whenever the user taps the pen on the board. + * @name JXG.Board#pendown + * @param {Event} e The browser's event object. + */ + __evt__pendown: function (e) { }, - /** - * Invokes prepareUpdate for every stored element with a prepareUpdate method and hands over the given arguments. - * See {@link JXG.GeometryElement#prepareUpdate} for further description, valid parameters and return values. - * @name prepareUpdate - * @memberOf JXG.Composition.prototype - * @function - */ - 'prepareUpdate', + /** + * @event + * @description Whenever the user starts to click on the board with a + * device sending pointer events. + * @name JXG.Board#pointerdown + * @param {Event} e The browser's event object. + */ + __evt__pointerdown: function (e) { }, - /** - * Invokes updateRenderer for every stored element with a updateRenderer method and hands over the given arguments. - * See {@link JXG.GeometryElement#updateRenderer} for further description, valid parameters and return values. - * @name updateRenderer - * @memberOf JXG.Composition.prototype - * @function - */ - 'updateRenderer', + /** + * @event + * @description Whenever the user starts to touch the board. + * @name JXG.Board#touchstart + * @param {Event} e The browser's event object. + */ + __evt__touchstart: function (e) { }, - /** - * Invokes update for every stored element with a update method and hands over the given arguments. - * See {@link JXG.GeometryElement#update} for further description, valid parameters and return values. - * @name update - * @memberOf JXG.Composition.prototype - * @function - */ - 'update', + /** + * @event + * @description Whenever the user stops to touch or click the board. + * @name JXG.Board#up + * @param {Event} e The browser's event object. + */ + __evt__up: function (e) { }, - /** - * Invokes fullUpdate for every stored element with a fullUpdate method and hands over the given arguments. - * See {@link JXG.GeometryElement#fullUpdate} for further description, valid parameters and return values. - * @name fullUpdate - * @memberOf JXG.Composition.prototype - * @function - */ - 'fullUpdate', + /** + * @event + * @description Whenever the user releases the mousebutton over the board. + * @name JXG.Board#mouseup + * @param {Event} e The browser's event object. + */ + __evt__mouseup: function (e) { }, - /** - * Invokes highlight for every stored element with a highlight method and hands over the given arguments. - * See {@link JXG.GeometryElement#highlight} for further description, valid parameters and return values. - * @name highlight - * @memberOf JXG.Composition.prototype - * @function - */ - 'highlight', + /** + * @event + * @description Whenever the user releases the mousebutton over the board with a + * device sending pointer events. + * @name JXG.Board#pointerup + * @param {Event} e The browser's event object. + */ + __evt__pointerup: function (e) { }, - /** - * Invokes noHighlight for every stored element with a noHighlight method and hands over the given arguments. - * See {@link JXG.GeometryElement#noHighlight} for further description, valid parameters and return values. - * @name noHighlight - * @memberOf JXG.Composition.prototype - * @function - */ - 'noHighlight' - ], - generateMethod = function (what) { - return function () { - var i; + /** + * @event + * @description Whenever the user stops touching the board. + * @name JXG.Board#touchend + * @param {Event} e The browser's event object. + */ + __evt__touchend: function (e) { }, - for (i in that.elements) { - if (that.elements.hasOwnProperty(i)) { - if (Type.exists(that.elements[i][what])) { - that.elements[i][what].apply(that.elements[i], arguments); - } - } - } - return that; - }; - }; + /** + * @event + * @description This event is fired whenever the user is moving the finger or mouse pointer over the board. + * @name JXG.Board#move + * @param {Event} e The browser's event object. + * @param {Number} mode The mode the board currently is in + * @see JXG.Board#mode + */ + __evt__move: function (e, mode) { }, - for (e = 0; e < genericMethods.length; e++) { - this[genericMethods[e]] = generateMethod(genericMethods[e]); - } + /** + * @event + * @description This event is fired whenever the user is moving the mouse over the board. + * @name JXG.Board#mousemove + * @param {Event} e The browser's event object. + * @param {Number} mode The mode the board currently is in + * @see JXG.Board#mode + */ + __evt__mousemove: function (e, mode) { }, - this.elements = {}; - this.objects = this.elements; + /** + * @event + * @description This event is fired whenever the user is moving the pen over the board. + * @name JXG.Board#penmove + * @param {Event} e The browser's event object. + * @param {Number} mode The mode the board currently is in + * @see JXG.Board#mode + */ + __evt__penmove: function (e, mode) { }, - this.elementsByName = {}; - this.objectsList = []; + /** + * @event + * @description This event is fired whenever the user is moving the mouse over the board with a + * device sending pointer events. + * @name JXG.Board#pointermove + * @param {Event} e The browser's event object. + * @param {Number} mode The mode the board currently is in + * @see JXG.Board#mode + */ + __evt__pointermove: function (e, mode) { }, - // unused, required for select() - this.groups = {}; + /** + * @event + * @description This event is fired whenever the user is moving the finger over the board. + * @name JXG.Board#touchmove + * @param {Event} e The browser's event object. + * @param {Number} mode The mode the board currently is in + * @see JXG.Board#mode + */ + __evt__touchmove: function (e, mode) { }, - this.methodMap = { - setAttribute: 'setAttribute', - setProperty: 'setAttribute', - setParents: 'setParents', - add: 'add', - remove: 'remove', - select: 'select' - }; + /** + * @event + * @description Whenever an element is highlighted this event is fired. + * @name JXG.Board#hit + * @param {Event} e The browser's event object. + * @param {JXG.GeometryElement} el The hit element. + * @param target + * + * @example + * var c = board.create('circle', [[1, 1], 2]); + * board.on('hit', function(evt, el) { + * console.log("Hit element", el); + * }); + * + * </pre><div id="JXG19eb31ac-88e6-11e8-bcb5-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG19eb31ac-88e6-11e8-bcb5-901b0e1b8723', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * var c = board.create('circle', [[1, 1], 2]); + * board.on('hit', function(evt, el) { + * console.log("Hit element", el); + * }); + * + * })(); + * + * </script><pre> + */ + __evt__hit: function (e, el, target) { }, - for (e in elements) { - if (elements.hasOwnProperty(e)) { - this.add(e, elements[e]); - } - } + /** + * @event + * @description Whenever an element is highlighted this event is fired. + * @name JXG.Board#mousehit + * @see JXG.Board#hit + * @param {Event} e The browser's event object. + * @param {JXG.GeometryElement} el The hit element. + * @param target + */ + __evt__mousehit: function (e, el, target) { }, - this.dump = true; - this.subs = {}; - }; + /** + * @event + * @description This board is updated. + * @name JXG.Board#update + */ + __evt__update: function () { }, - JXG.extend(JXG.Composition.prototype, /** @lends JXG.Composition.prototype */ { + /** + * @event + * @description The bounding box of the board has changed. + * @name JXG.Board#boundingbox + */ + __evt__boundingbox: function () { }, /** - * Adds an element to the composition container. - * @param {String} what Descriptive name for the element, e.g. <em>startpoint</em> or <em>area</em>. This is used to - * access the element later on. There are some reserved names: <em>elements, add, remove, update, prepareUpdate, - * updateRenderer, highlight, noHighlight</em>, and all names that would form invalid object property names in - * JavaScript. - * @param {JXG.GeometryElement|JXG.Composition} element A reference to the element that is to be added. This can be - * another composition, too. - * @returns {Boolean} True, if the element was added successfully. Reasons why adding the element failed include - * using a reserved name and providing an invalid element. + * @event + * @description Select a region is started during a down event or by calling + * {@link JXG.Board.startSelectionMode} + * @name JXG.Board#startselecting */ - add: function (what, element) { - if (!Type.exists(this[what]) && Type.exists(element)) { - if (Type.exists(element.id)) { - this.elements[element.id] = element; - } else { - this.elements[what] = element; - } + __evt__startselecting: function () { }, - if (Type.exists(element.name)) { - this.elementsByName[element.name] = element; - } + /** + * @event + * @description Select a region is started during a down event + * from a device sending mouse events or by calling + * {@link JXG.Board.startSelectionMode}. + * @name JXG.Board#mousestartselecting + */ + __evt__mousestartselecting: function () { }, - element.on('attribute:name', this.nameListener, this); + /** + * @event + * @description Select a region is started during a down event + * from a device sending pointer events or by calling + * {@link JXG.Board.startSelectionMode}. + * @name JXG.Board#pointerstartselecting + */ + __evt__pointerstartselecting: function () { }, - this.objectsList.push(element); - this[what] = element; - this.methodMap[what] = element; + /** + * @event + * @description Select a region is started during a down event + * from a device sending touch events or by calling + * {@link JXG.Board.startSelectionMode}. + * @name JXG.Board#touchstartselecting + */ + __evt__touchstartselecting: function () { }, - return true; - } + /** + * @event + * @description Selection of a region is stopped during an up event. + * @name JXG.Board#stopselecting + */ + __evt__stopselecting: function () { }, - return false; - }, + /** + * @event + * @description Selection of a region is stopped during an up event + * from a device sending mouse events. + * @name JXG.Board#mousestopselecting + */ + __evt__mousestopselecting: function () { }, - /** - * Remove an element from the composition container. - * @param {String} what The name used to access the element. - * @returns {Boolean} True, if the element has been removed successfully. + /** + * @event + * @description Selection of a region is stopped during an up event + * from a device sending pointer events. + * @name JXG.Board#pointerstopselecting */ - remove: function (what) { - var found = false, - e; + __evt__pointerstopselecting: function () { }, - for (e in this.elements) { - if (this.elements.hasOwnProperty(e)) { - if (this.elements[e].id === this[what].id) { - found = true; - break; - } - } - } + /** + * @event + * @description Selection of a region is stopped during an up event + * from a device sending touch events. + * @name JXG.Board#touchstopselecting + */ + __evt__touchstopselecting: function () { }, - if (found) { - delete this.elements[this[what].id]; - delete this[what]; - } + /** + * @event + * @description A move event while selecting of a region is active. + * @name JXG.Board#moveselecting + */ + __evt__moveselecting: function () { }, - return found; - }, + /** + * @event + * @description A move event while selecting of a region is active + * from a device sending mouse events. + * @name JXG.Board#mousemoveselecting + */ + __evt__mousemoveselecting: function () { }, - nameListener: function (oval, nval, el) { - delete this.elementsByName[oval]; - this.elementsByName[nval] = el; - }, + /** + * @event + * @description Select a region is started during a down event + * from a device sending mouse events. + * @name JXG.Board#pointermoveselecting + */ + __evt__pointermoveselecting: function () { }, - select: function (filter) { - // for now, hijack JXG.Board's select() method - if (Type.exists(JXG.Board)) { - return JXG.Board.prototype.select.call(this, filter); - } + /** + * @event + * @description Select a region is started during a down event + * from a device sending touch events. + * @name JXG.Board#touchmoveselecting + */ + __evt__touchmoveselecting: function () { }, - return new JXG.Composition(); - }, + /** + * @ignore + */ + __evt: function () {}, - getParents: function () { - return this.parents; - }, + //endregion - getType: function () { - return this.elType; - }, + /** + * Expand the JSXGraph construction to fullscreen. + * In order to preserve the proportions of the JSXGraph element, + * a wrapper div is created which is set to fullscreen. + * <p> + * The wrapping div has the CSS class 'jxgbox_wrap_private' which is + * defined in the file 'jsxgraph.css' + * <p> + * This feature is not available on iPhones (as of December 2021). + * + * @param {String} id (Optional) id of the div element which is brought to fullscreen. + * If not provided, this defaults to the JSXGraph div. However, it may be necessary for the aspect ratio trick + * which using padding-bottom/top and an out div element. Then, the id of the outer div has to be supplied. + * + * @return {JXG.Board} Reference to the board + * + * @example + * <div id='jxgbox' class='jxgbox' style='width:500px; height:200px;'></div> + * <button onClick="board.toFullscreen()">Fullscreen</button> + * + * <script language="Javascript" type='text/javascript'> + * var board = JXG.JSXGraph.initBoard('jxgbox', {axis:true, boundingbox:[-5,5,5,-5]}); + * var p = board.create('point', [0, 1]); + * </script> + * + * </pre><div id="JXGd5bab8b6-fd40-11e8-ab14-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * var board_d5bab8b6; + * (function() { + * var board = JXG.JSXGraph.initBoard('JXGd5bab8b6-fd40-11e8-ab14-901b0e1b8723', + * {boundingbox:[-5,5,5,-5], axis: true, showcopyright: false, shownavigation: false}); + * var p = board.create('point', [0, 1]); + * board_d5bab8b6 = board; + * })(); + * </script> + * <button onClick="board_d5bab8b6.toFullscreen()">Fullscreen</button> + * <pre> + * + * @example + * <div id='outer' style='max-width: 500px; margin: 0 auto;'> + * <div id='jxgbox' class='jxgbox' style='height: 0; padding-bottom: 100%'></div> + * </div> + * <button onClick="board.toFullscreen('outer')">Fullscreen</button> + * + * <script language="Javascript" type='text/javascript'> + * var board = JXG.JSXGraph.initBoard('jxgbox', { + * axis:true, + * boundingbox:[-5,5,5,-5], + * fullscreen: { id: 'outer' }, + * showFullscreen: true + * }); + * var p = board.create('point', [-2, 3], {}); + * </script> + * + * </pre><div id="JXG7103f6b_outer" style='max-width: 500px; margin: 0 auto;'> + * <div id="JXG7103f6be-6993-4ff8-8133-c78e50a8afac" class="jxgbox" style="height: 0; padding-bottom: 100%;"></div> + * </div> + * <button onClick="board_JXG7103f6be.toFullscreen('JXG7103f6b_outer')">Fullscreen</button> + * <script type="text/javascript"> + * var board_JXG7103f6be; + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG7103f6be-6993-4ff8-8133-c78e50a8afac', + * {boundingbox: [-8, 8, 8,-8], axis: true, fullscreen: { id: 'JXG7103f6b_outer' }, showFullscreen: true, + * showcopyright: false, shownavigation: false}); + * var p = board.create('point', [-2, 3], {}); + * board_JXG7103f6be = board; + * })(); + * + * </script><pre> + * + * + */ + toFullscreen: function (id) { + var wrap_id, wrap_node, inner_node; - getAttributes: function () { - var attr = {}, - e; + id = id || this.container; + this._fullscreen_inner_id = id; + inner_node = this.document.getElementById(id); + wrap_id = 'fullscreenwrap_' + id; - for (e in this.subs) { - if (this.subs.hasOwnProperty(e)) { - attr[e] = this.subs[e].visProp; - } + // Wrap a div around the JSXGraph div. + if (this.document.getElementById(wrap_id)) { + wrap_node = this.document.getElementById(wrap_id); + } else { + wrap_node = document.createElement('div'); + wrap_node.classList.add('JXG_wrap_private'); + wrap_node.setAttribute('id', wrap_id); + inner_node.parentNode.insertBefore(wrap_node, inner_node); + wrap_node.appendChild(inner_node); } - return this.attr; - } - }); - - return JXG.Composition; -}); - -/* - Copyright 2008-2021 - Matthias Ehmann, - Michael Gerhaeuser, - Carsten Miller, - Bianca Valentin, - Alfred Wassermann, - Peter Wilfahrt - - This file is part of JSXGraph. - - JSXGraph is free software dual licensed under the GNU LGPL or MIT License. + // Get the real width and height of the JSXGraph div + // and determine the scaling and vertical shift amount + this._fullscreen_res = Env._getScaleFactors(inner_node); - You can redistribute it and/or modify it under the terms of the + // Trigger fullscreen mode + wrap_node.requestFullscreen = wrap_node.requestFullscreen || + wrap_node.webkitRequestFullscreen || + wrap_node.mozRequestFullScreen || + wrap_node.msRequestFullscreen; - * GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version - OR - * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT + if (wrap_node.requestFullscreen) { + wrap_node.requestFullscreen(); + } - JSXGraph is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. + return this; + }, - You should have received a copy of the GNU Lesser General Public License and - the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> - and <http://opensource.org/licenses/MIT/>. - */ + /** + * If fullscreen mode is toggled, the possible CSS transformations + * which are applied to the JSXGraph canvas have to be reread. + * Otherwise the position of upper left corner is wrongly interpreted. + * + * @param {Object} evt fullscreen event object (unused) + */ + fullscreenListener: function (evt) { + var res, inner_id, inner_node; + inner_id = this._fullscreen_inner_id; + if (!Type.exists(inner_id)) { + return; + } -/*global JXG:true, define: true*/ -/*jslint nomen: true, plusplus: true*/ + this.document.fullscreenElement = this.document.fullscreenElement || + this.document.webkitFullscreenElement || + this.document.mozFullscreenElement || + this.document.msFullscreenElement; + + inner_node = this.document.getElementById(inner_id); + // If full screen mode is started we have to remove CSS margin around the JSXGraph div. + // Otherwise, the positioning of the fullscreen div will be false. + // When leaving the fullscreen mode, the margin is put back in. + if (this.document.fullscreenElement) { + // Just entered fullscreen mode + + // Get the data computed in board.toFullscreen() + res = this._fullscreen_res; + + // Store the scaling data. + // It is used in AbstractRenderer.updateText to restore the scaling matrix + // which is removed by MathJax. + // Further, the CSS margin has to be removed when in fullscreen mode, + // and must be restored later. + inner_node._cssFullscreenStore = { + id: this.document.fullscreenElement.id, + isFullscreen: true, + margin: inner_node.style.margin, + width: inner_node.style.width, + scale: res.scale, + vshift: res.vshift + }; -/* depends: - jxg - base/constants - base/coords - math/statistics - utils/type - base/element - elements: - segment - transform - */ + inner_node.style.margin = ''; + inner_node.style.width = res.width + 'px'; -define('base/polygon',[ - 'jxg', 'base/constants', 'base/coords', 'math/statistics', 'math/geometry', 'utils/type', 'base/element', 'base/line', 'base/transformation' -], function (JXG, Const, Coords, Statistics, Geometry, Type, GeometryElement, Line, Transform) { + // Do the shifting and scaling via CSS pseudo rules + // We do this after fullscreen mode has been established to get the correct size + // of the JSXGraph div. + Env.scaleJSXGraphDiv(document.fullscreenElement.id, inner_id, res.scale, res.vshift); - "use strict"; + // Clear this.document.fullscreenElement, because Safari doesn't to it and + // when leaving full screen mode it is still set. + this.document.fullscreenElement = null; - /** - * Creates a new instance of JXG.Polygon. - * @class Polygon stores all style and functional properties that are required - * to draw and to interactact with a polygon. - * @param {JXG.Board} board Reference to the board the polygon is to be drawn on. - * @param {Array} vertices Unique identifiers for the points defining the polygon. - * Last point must be first point. Otherwise, the first point will be added at the list. - * @param {Object} attributes An object which contains properties as given in {@link JXG.Options.elements} - * and {@link JXG.Options.polygon}. - * @constructor - * @extends JXG.GeometryElement - */ + } else if (Type.exists(inner_node._cssFullscreenStore)) { + // Just left the fullscreen mode - JXG.Polygon = function (board, vertices, attributes) { - this.constructor(board, attributes, Const.OBJECT_TYPE_POLYGON, Const.OBJECT_CLASS_AREA); + // Remove the CSS rules added in Env.scaleJSXGraphDiv + try { + this.document.styleSheets[this.document.styleSheets.length - 1].deleteRule(0); + } catch (err) { + console.log('JSXGraph: Could not remove CSS rules for full screen mode'); + } - var i, l, len, j, - attr_line = Type.copyAttributes(attributes, board.options, 'polygon', 'borders'); + inner_node._cssFullscreenStore.isFullscreen = false; + inner_node.style.margin = inner_node._cssFullscreenStore.margin; + inner_node.style.width = inner_node._cssFullscreenStore.width; + } - this.withLines = attributes.withlines; - this.attr_line = attr_line; + this.updateCSSTransforms(); + }, /** - * References to the points defining the polygon. The last vertex is the same as the first vertex. - * @type Array - */ - this.vertices = []; - for (i = 0; i < vertices.length; i++) { - this.vertices[i] = this.board.select(vertices[i]); - } - - // Close the polygon - if (this.vertices.length > 0 && this.vertices[this.vertices.length - 1].id !== this.vertices[0].id) { - this.vertices.push(this.vertices[0]); - } - - /** - * References to the border lines of the polygon. - * @type Array + * Function to animate a curve rolling on another curve. + * @param {Curve} c1 JSXGraph curve building the floor where c2 rolls + * @param {Curve} c2 JSXGraph curve which rolls on c1. + * @param {number} start_c1 The parameter t such that c1(t) touches c2. This is the start position of the + * rolling process + * @param {Number} stepsize Increase in t in each step for the curve c1 + * @param {Number} direction + * @param {Number} time Delay time for setInterval() + * @param {Array} pointlist Array of points which are rolled in each step. This list should contain + * all points which define c2 and gliders on c2. + * + * @example + * + * // Line which will be the floor to roll upon. + * var line = brd.create('curve', [function (t) { return t;}, function (t){ return 1;}], {strokeWidth:6}); + * // Center of the rolling circle + * var C = brd.create('point',[0,2],{name:'C'}); + * // Starting point of the rolling circle + * var P = brd.create('point',[0,1],{name:'P', trace:true}); + * // Circle defined as a curve. The circle "starts" at P, i.e. circle(0) = P + * var circle = brd.create('curve',[ + * function (t){var d = P.Dist(C), + * beta = JXG.Math.Geometry.rad([C.X()+1,C.Y()],C,P); + * t += beta; + * return C.X()+d*Math.cos(t); + * }, + * function (t){var d = P.Dist(C), + * beta = JXG.Math.Geometry.rad([C.X()+1,C.Y()],C,P); + * t += beta; + * return C.Y()+d*Math.sin(t); + * }, + * 0,2*Math.PI], + * {strokeWidth:6, strokeColor:'green'}); + * + * // Point on circle + * var B = brd.create('glider',[0,2,circle],{name:'B', color:'blue',trace:false}); + * var roll = brd.createRoulette(line, circle, 0, Math.PI/20, 1, 100, [C,P,B]); + * roll.start() // Start the rolling, to be stopped by roll.stop() + * + * </pre><div class="jxgbox" id="JXGe5e1b53c-a036-4a46-9e35-190d196beca5" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * var brd = JXG.JSXGraph.initBoard('JXGe5e1b53c-a036-4a46-9e35-190d196beca5', {boundingbox: [-5, 5, 5, -5], axis: true, showcopyright:false, shownavigation: false}); + * // Line which will be the floor to roll upon. + * var line = brd.create('curve', [function (t) { return t;}, function (t){ return 1;}], {strokeWidth:6}); + * // Center of the rolling circle + * var C = brd.create('point',[0,2],{name:'C'}); + * // Starting point of the rolling circle + * var P = brd.create('point',[0,1],{name:'P', trace:true}); + * // Circle defined as a curve. The circle "starts" at P, i.e. circle(0) = P + * var circle = brd.create('curve',[ + * function (t){var d = P.Dist(C), + * beta = JXG.Math.Geometry.rad([C.X()+1,C.Y()],C,P); + * t += beta; + * return C.X()+d*Math.cos(t); + * }, + * function (t){var d = P.Dist(C), + * beta = JXG.Math.Geometry.rad([C.X()+1,C.Y()],C,P); + * t += beta; + * return C.Y()+d*Math.sin(t); + * }, + * 0,2*Math.PI], + * {strokeWidth:6, strokeColor:'green'}); + * + * // Point on circle + * var B = brd.create('glider',[0,2,circle],{name:'B', color:'blue',trace:false}); + * var roll = brd.createRoulette(line, circle, 0, Math.PI/20, 1, 100, [C,P,B]); + * roll.start() // Start the rolling, to be stopped by roll.stop() + * </script><pre> */ - this.borders = []; - - if (this.withLines) { - len = this.vertices.length - 1; - for (j = 0; j < len; j++) { - // This sets the "correct" labels for the first triangle of a construction. - i = (j + 1) % len; - attr_line.id = attr_line.ids && attr_line.ids[i]; - attr_line.name = attr_line.names && attr_line.names[i]; - attr_line.strokecolor = (Type.isArray(attr_line.colors) && attr_line.colors[i % attr_line.colors.length]) || - attr_line.strokecolor; - attr_line.visible = Type.exists(attributes.borders.visible) ? attributes.borders.visible : attributes.visible; - - if (attr_line.strokecolor === false) { - attr_line.strokecolor = 'none'; - } + createRoulette: function (c1, c2, start_c1, stepsize, direction, time, pointlist) { + var brd = this, + Roulette = function () { + var alpha = 0, Tx = 0, Ty = 0, + t1 = start_c1, + t2 = Numerics.root( + function (t) { + var c1x = c1.X(t1), + c1y = c1.Y(t1), + c2x = c2.X(t), + c2y = c2.Y(t); - l = board.create('segment', [this.vertices[i], this.vertices[i + 1]], attr_line); - l.dump = false; - this.borders[i] = l; - l.parentPolygon = this; - } - } - this.inherits.push(this.vertices, this.borders); + return (c1x - c2x) * (c1x - c2x) + (c1y - c2y) * (c1y - c2y); + }, + [0, Math.PI * 2] + ), + t1_new = 0.0, t2_new = 0.0, + c1dist, - // Register polygon at board - // This needs to be done BEFORE the points get this polygon added in their descendants list - this.id = this.board.setId(this, 'Py'); + rotation = brd.create('transform', [ + function () { + return alpha; + } + ], {type: 'rotate'}), - // Add polygon as child to defining points - for (i = 0; i < this.vertices.length - 1; i++) { - this.board.select(this.vertices[i]).addChild(this); - } + rotationLocal = brd.create('transform', [ + function () { + return alpha; + }, + function () { + return c1.X(t1); + }, + function () { + return c1.Y(t1); + } + ], {type: 'rotate'}), - this.board.renderer.drawPolygon(this); - this.board.finalizeAdding(this); + translate = brd.create('transform', [ + function () { + return Tx; + }, + function () { + return Ty; + } + ], {type: 'translate'}), - this.createGradient(); - this.elType = 'polygon'; + // arc length via Simpson's rule. + arclen = function (c, a, b) { + var cpxa = Numerics.D(c.X)(a), + cpya = Numerics.D(c.Y)(a), + cpxb = Numerics.D(c.X)(b), + cpyb = Numerics.D(c.Y)(b), + cpxab = Numerics.D(c.X)((a + b) * 0.5), + cpyab = Numerics.D(c.Y)((a + b) * 0.5), - // create label - this.createLabel(); + fa = Math.sqrt(cpxa * cpxa + cpya * cpya), + fb = Math.sqrt(cpxb * cpxb + cpyb * cpyb), + fab = Math.sqrt(cpxab * cpxab + cpyab * cpyab); - this.methodMap = JXG.deepCopy(this.methodMap, { - borders: 'borders', - vertices: 'vertices', - A: 'Area', - Area: 'Area', - Perimeter: 'Perimeter', - L: 'Perimeter', - Length: 'Perimeter', - boundingBox: 'boundingBox', - bounds: 'bounds', - addPoints: 'addPoints', - insertPoints: 'insertPoints', - removePoints: 'removePoints' - }); - }; + return (fa + 4 * fab + fb) * (b - a) / 6; + }, - JXG.Polygon.prototype = new GeometryElement(); + exactDist = function (t) { + return c1dist - arclen(c2, t2, t); + }, - JXG.extend(JXG.Polygon.prototype, /** @lends JXG.Polygon.prototype */ { - /** - * Checks whether (x,y) is near the polygon. - * @param {Number} x Coordinate in x direction, screen coordinates. - * @param {Number} y Coordinate in y direction, screen coordinates. - * @returns {Boolean} Returns true, if (x,y) is inside or at the boundary the polygon, otherwise false. - */ - hasPoint: function (x, y) { + beta = Math.PI / 18, + beta9 = beta * 9, + interval = null; - var i, j, len, c = false; + this.rolling = function () { + var h, g, hp, gp, z; - if (Type.evaluate(this.visProp.hasinnerpoints)) { - // All points of the polygon trigger hasPoint: inner and boundary points - len = this.vertices.length; - // See http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html - // for a reference of Jordan method - for (i = 0, j = len - 2; i < len - 1; j = i++) { - if (((this.vertices[i].coords.scrCoords[2] > y) !== (this.vertices[j].coords.scrCoords[2] > y)) && - (x < (this.vertices[j].coords.scrCoords[1] - this.vertices[i].coords.scrCoords[1]) * (y - this.vertices[i].coords.scrCoords[2]) / - (this.vertices[j].coords.scrCoords[2] - this.vertices[i].coords.scrCoords[2]) + this.vertices[i].coords.scrCoords[1])) { - c = !c; - } - } - if (c) { - return true; - } - } + t1_new = t1 + direction * stepsize; - // Only boundary points trigger hasPoint - // We additionally test the boundary also in case hasInnerPoints. - // Since even if the above test has failed, the strokewidth may be large and (x, y) may - // be inside of hasPoint() of a vertices. - len = this.borders.length; - for (i = 0; i < len; i++) { - if (this.borders[i].hasPoint(x, y)) { - c = true; - break; - } - } + // arc length between c1(t1) and c1(t1_new) + c1dist = arclen(c1, t1, t1_new); - return c; - }, + // find t2_new such that arc length between c2(t2) and c1(t2_new) equals c1dist. + t2_new = Numerics.root(exactDist, t2); - /** - * Uses the boards renderer to update the polygon. - */ - updateRenderer: function () { - var i, len; // wasReal, + // c1(t) as complex number + h = new Complex(c1.X(t1_new), c1.Y(t1_new)); + // c2(t) as complex number + g = new Complex(c2.X(t2_new), c2.Y(t2_new)); - if (!this.needsUpdate) { - return this; - } + hp = new Complex(Numerics.D(c1.X)(t1_new), Numerics.D(c1.Y)(t1_new)); + gp = new Complex(Numerics.D(c2.X)(t2_new), Numerics.D(c2.Y)(t2_new)); - if (this.visPropCalc.visible) { - // wasReal = this.isReal; + // z is angle between the tangents of c1 at t1_new, and c2 at t2_new + z = Complex.C.div(hp, gp); - len = this.vertices.length; - this.isReal = true; - for (i = 0; i < len; ++i) { - if (!this.vertices[i].isReal) { - this.isReal = false; - break; - } - } + alpha = Math.atan2(z.imaginary, z.real); + // Normalizing the quotient + z.div(Complex.C.abs(z)); + z.mult(g); + Tx = h.real - z.real; - if (//wasReal && - !this.isReal) { - this.updateVisibility(false); - } - } + // T = h(t1_new)-g(t2_new)*h'(t1_new)/g'(t2_new); + Ty = h.imaginary - z.imaginary; - if (this.visPropCalc.visible) { - this.board.renderer.updatePolygon(this); - } + // -(10-90) degrees: make corners roll smoothly + if (alpha < -beta && alpha > -beta9) { + alpha = -beta; + rotationLocal.applyOnce(pointlist); + } else if (alpha > beta && alpha < beta9) { + alpha = beta; + rotationLocal.applyOnce(pointlist); + } else { + rotation.applyOnce(pointlist); + translate.applyOnce(pointlist); + t1 = t1_new; + t2 = t2_new; + } + brd.update(); + }; - /* Update the label if visible. */ - if (this.hasLabel && this.visPropCalc.visible && this.label && - this.label.visPropCalc.visible && this.isReal) { + this.start = function () { + if (time > 0) { + interval = window.setInterval(this.rolling, time); + } + return this; + }; - this.label.update(); - this.board.renderer.updateText(this.label); - } + this.stop = function () { + window.clearInterval(interval); + return this; + }; + return this; + }; + return new Roulette(); + } + }); - // Update rendNode display - this.setDisplayRendNode(); - // if (this.visPropCalc.visible !== this.visPropOld.visible) { - // this.board.renderer.display(this, this.visPropCalc.visible); - // this.visPropOld.visible = this.visPropCalc.visible; - // - // if (this.hasLabel) { - // this.board.renderer.display(this.label, this.label.visPropCalc.visible); - // } - // } + return JXG.Board; +}); - this.needsUpdate = false; - return this; - }, +/* + Copyright 2008-2022 + Matthias Ehmann, + Michael Gerhaeuser, + Carsten Miller, + Bianca Valentin, + Alfred Wassermann, + Peter Wilfahrt - /** - * return TextAnchor - */ - getTextAnchor: function () { - var a, b, x, y, i; + This file is part of JSXGraph. - if (this.vertices.length === 0) { - return new Coords(Const.COORDS_BY_USER, [1, 0, 0], this.board); - } + JSXGraph is free software dual licensed under the GNU LGPL or MIT License. - a = this.vertices[0].X(); - b = this.vertices[0].Y(); - x = a; - y = b; - for (i = 0; i < this.vertices.length; i++) { - if (this.vertices[i].X() < a) { - a = this.vertices[i].X(); - } + You can redistribute it and/or modify it under the terms of the - if (this.vertices[i].X() > x) { - x = this.vertices[i].X(); - } + * GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version + OR + * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT - if (this.vertices[i].Y() > b) { - b = this.vertices[i].Y(); - } + JSXGraph is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. - if (this.vertices[i].Y() < y) { - y = this.vertices[i].Y(); - } - } + You should have received a copy of the GNU Lesser General Public License and + the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> + and <http://opensource.org/licenses/MIT/>. + */ - return new Coords(Const.COORDS_BY_USER, [(a + x) * 0.5, (b + y) * 0.5], this.board); - }, +/*global JXG: true, define: true, AMprocessNode: true, MathJax: true, document: true */ +/*jslint nomen: true, plusplus: true, newcap:true*/ - getLabelAnchor: JXG.shortcut(JXG.Polygon.prototype, 'getTextAnchor'), +/* depends: + jxg + options + renderer/abstract + base/constants + utils/type + utils/env + utils/color + math/numerics +*/ - // documented in geometry element - cloneToBackground: function () { - var copy = {}, er; +define('renderer/svg',[ + 'jxg', 'options', 'renderer/abstract', 'base/constants', 'utils/type', 'utils/color', 'utils/base64', 'math/numerics' +], function (JXG, Options, AbstractRenderer, Const, Type, Color, Base64, Numerics) { - copy.id = this.id + 'T' + this.numTraces; - this.numTraces++; - copy.vertices = this.vertices; - copy.visProp = Type.deepCopy(this.visProp, this.visProp.traceattributes, true); - copy.visProp.layer = this.board.options.layer.trace; - copy.board = this.board; - Type.clearVisPropOld(copy); + "use strict"; - copy.visPropCalc = { - visible: Type.evaluate(copy.visProp.visible) - }; + /** + * Uses SVG to implement the rendering methods defined in {@link JXG.AbstractRenderer}. + * @class JXG.SVGRenderer + * @augments JXG.AbstractRenderer + * @param {Node} container Reference to a DOM node containing the board. + * @param {Object} dim The dimensions of the board + * @param {Number} dim.width + * @param {Number} dim.height + * @see JXG.AbstractRenderer + */ + JXG.SVGRenderer = function (container, dim) { + var i; - er = this.board.renderer.enhancedRendering; - this.board.renderer.enhancedRendering = true; - this.board.renderer.drawPolygon(copy); - this.board.renderer.enhancedRendering = er; - this.traces[copy.id] = copy.rendNode; + // docstring in AbstractRenderer + this.type = 'svg'; - return this; - }, + this.isIE = navigator.appVersion.indexOf("MSIE") !== -1 || navigator.userAgent.match(/Trident\//); /** - * Hide the polygon including its border lines. It will still exist but not visible on the board. - * @param {Boolean} [borderless=false] If set to true, the polygon is treated as a polygon without - * borders, i.e. the borders will not be hidden. + * SVG root node + * @type Node */ - hideElement: function (borderless) { - var i; + this.svgRoot = null; - JXG.deprecated('Element.hideElement()', 'Element.setDisplayRendNode()'); + /** + * The SVG Namespace used in JSXGraph. + * @see http://www.w3.org/TR/SVG/ + * @type String + * @default http://www.w3.org/2000/svg + */ + this.svgNamespace = 'http://www.w3.org/2000/svg'; - this.visPropCalc.visible = false; - this.board.renderer.display(this, false); + /** + * The xlink namespace. This is used for images. + * @see http://www.w3.org/TR/xlink/ + * @type String + * @default http://www.w3.org/1999/xlink + */ + this.xlinkNamespace = 'http://www.w3.org/1999/xlink'; - if (!borderless) { - for (i = 0; i < this.borders.length; i++) { - this.borders[i].hideElement(); - } - } + // container is documented in AbstractRenderer + this.container = container; - if (this.hasLabel && Type.exists(this.label)) { - this.label.hiddenByParent = true; - if (this.label.visPropCalc.visible) { - this.label.hideElement(); - } - } - }, + // prepare the div container and the svg root node for use with JSXGraph + this.container.style.MozUserSelect = 'none'; + this.container.style.userSelect = 'none'; - /** - * Make the element visible. - * @param {Boolean} [borderless=false] If set to true, the polygon is treated as a polygon without - * borders, i.e. the borders will not be shown. - */ - showElement: function (borderless) { - var i; + this.container.style.overflow = 'hidden'; + if (this.container.style.position === '') { + this.container.style.position = 'relative'; + } - JXG.deprecated('Element.showElement()', 'Element.setDisplayRendNode()'); + this.svgRoot = this.container.ownerDocument.createElementNS(this.svgNamespace, "svg"); + this.svgRoot.style.overflow = 'hidden'; + this.svgRoot.style.display = 'block'; - this.visPropCalc.visible = true; - this.board.renderer.display(this, true); + this.resize(dim.width, dim.height); - if (!borderless) { - for (i = 0; i < this.borders.length; i++) { - this.borders[i].showElement().updateRenderer(); - } - } + //this.svgRoot.setAttributeNS(null, 'shape-rendering', 'crispEdge'); //'optimizeQuality'); //geometricPrecision'); - if (Type.exists(this.label) && this.hasLabel && this.label.hiddenByParent) { - this.label.hiddenByParent = false; - if (!this.label.visPropCalc.visible) { - this.label.showElement().updateRenderer(); - } - } - return this; - }, + this.container.appendChild(this.svgRoot); /** - * Area of (not self-intersecting) polygon - * @returns {Number} Area of (not self-intersecting) polygon + * The <tt>defs</tt> element is a container element to reference reusable SVG elements. + * @type Node + * @see http://www.w3.org/TR/SVG/struct.html#DefsElement */ - Area: function () { - return Math.abs(Geometry.signedPolygon(this.vertices, true)); - }, + this.defs = this.container.ownerDocument.createElementNS(this.svgNamespace, 'defs'); + this.svgRoot.appendChild(this.defs); /** - * Perimeter of polygon. - * @returns {Number} Perimeter of polygon in user units. - * - * @example - * var p = [[0.0, 2.0], [2.0, 1.0], [4.0, 6.0], [1.0, 3.0]]; - * - * var pol = board.create('polygon', p, {hasInnerPoints: true}); - * var t = board.create('text', [5, 5, function() { return pol.Perimeter(); }]); - * </pre><div class="jxgbox" id="JXGb10b734d-89fc-4b9d-b4a7-e3f0c1c6bf77" style="width: 400px; height: 400px;"></div> - * <script type="text/javascript"> - * (function () { - * var board = JXG.JSXGraph.initBoard('JXGb10b734d-89fc-4b9d-b4a7-e3f0c1c6bf77', {boundingbox: [-1, 9, 9, -1], axis: false, showcopyright: false, shownavigation: false}), - * p = [[0.0, 2.0], [2.0, 1.0], [4.0, 6.0], [1.0, 4.0]], - * cc1 = board.create('polygon', p, {hasInnerPoints: true}), - * t = board.create('text', [5, 5, function() { return cc1.Perimeter(); }]); - * })(); - * </script><pre> - * + * Filters are used to apply shadows. + * @type Node + * @see http://www.w3.org/TR/SVG/filters.html#FilterElement */ - Perimeter: function() { - var i, - len = this.vertices.length, - val = 0.0; - - for (i = 1; i < len; ++i) { - val += this.vertices[i].Dist(this.vertices[i - 1]); - } + this.filter = this.container.ownerDocument.createElementNS(this.svgNamespace, 'filter'); + this.filter.setAttributeNS(null, 'id', this.container.id + '_' + 'f1'); + /* + this.filter.setAttributeNS(null, 'x', '-100%'); + this.filter.setAttributeNS(null, 'y', '-100%'); + this.filter.setAttributeNS(null, 'width', '400%'); + this.filter.setAttributeNS(null, 'height', '400%'); + //this.filter.setAttributeNS(null, 'filterUnits', 'userSpaceOnUse'); + */ + this.filter.setAttributeNS(null, 'width', '300%'); + this.filter.setAttributeNS(null, 'height', '300%'); + this.filter.setAttributeNS(null, 'filterUnits', 'userSpaceOnUse'); - return val; - }, + this.feOffset = this.container.ownerDocument.createElementNS(this.svgNamespace, 'feOffset'); + this.feOffset.setAttributeNS(null, 'result', 'offOut'); + this.feOffset.setAttributeNS(null, 'in', 'SourceAlpha'); + this.feOffset.setAttributeNS(null, 'dx', '5'); + this.feOffset.setAttributeNS(null, 'dy', '5'); + this.filter.appendChild(this.feOffset); - /** - * Bounding box of a polygon. The bounding box is an array of four numbers: the first two numbers - * determine the upper left corner, the last two number determine the lower right corner of the bounding box. - * - * The width and height of a polygon can then determined like this: - * @example - * var box = polygon.boundingBox(); - * var width = box[2] - box[0]; - * var height = box[1] - box[3]; - * - * @returns {Array} Array containing four numbers: [minX, maxY, maxX, minY] - */ - boundingBox: function () { - var box = [0, 0, 0, 0], i, v, - le = this.vertices.length - 1; + this.feGaussianBlur = this.container.ownerDocument.createElementNS(this.svgNamespace, 'feGaussianBlur'); + this.feGaussianBlur.setAttributeNS(null, 'result', 'blurOut'); + this.feGaussianBlur.setAttributeNS(null, 'in', 'offOut'); + this.feGaussianBlur.setAttributeNS(null, 'stdDeviation', '3'); + this.filter.appendChild(this.feGaussianBlur); - if (le === 0) { - return box; - } - box[0] = this.vertices[0].X(); - box[2] = box[0]; - box[1] = this.vertices[0].Y(); - box[3] = box[1]; + this.feBlend = this.container.ownerDocument.createElementNS(this.svgNamespace, 'feBlend'); + this.feBlend.setAttributeNS(null, 'in', 'SourceGraphic'); + this.feBlend.setAttributeNS(null, 'in2', 'blurOut'); + this.feBlend.setAttributeNS(null, 'mode', 'normal'); + this.filter.appendChild(this.feBlend); - for (i = 1; i < le; ++i) { - v = this.vertices[i].X(); - if (v < box[0]) { - box[0] = v; - } else if (v > box[2]) { - box[2] = v; - } + this.defs.appendChild(this.filter); - v = this.vertices[i].Y(); - if (v > box[1]) { - box[1] = v; - } else if (v < box[3]) { - box[3] = v; - } - } + /** + * JSXGraph uses a layer system to sort the elements on the board. This puts certain types of elements in front + * of other types of elements. For the order used see {@link JXG.Options.layer}. The number of layers is documented + * there, too. The higher the number, the "more on top" are the elements on this layer. + * @type Array + */ + this.layer = []; + for (i = 0; i < Options.layer.numlayers; i++) { + this.layer[i] = this.container.ownerDocument.createElementNS(this.svgNamespace, 'g'); + this.svgRoot.appendChild(this.layer[i]); + } - return box; - }, + // Already documented in JXG.AbstractRenderer + this.supportsForeignObject = document.implementation.hasFeature("http://w3.org/TR/SVG11/feature#Extensibility", "1.1"); - // already documented in GeometryElement - bounds: function () { - return this.boundingBox(); - }, + if (this.supportsForeignObject) { + this.foreignObjLayer = this.container.ownerDocument.createElementNS(this.svgNamespace, 'foreignObject'); + this.foreignObjLayer.setAttribute("display", "none"); + this.foreignObjLayer.setAttribute("x", 0); + this.foreignObjLayer.setAttribute("y", 0); + this.foreignObjLayer.setAttribute("width", "100%"); + this.foreignObjLayer.setAttribute("height", "100%"); + this.foreignObjLayer.setAttribute('id', this.container.id + '_foreignObj'); + this.svgRoot.appendChild(this.foreignObjLayer); + } /** - * This method removes the SVG or VML nodes of the lines and the filled area from the renderer, to remove - * the object completely you should use {@link JXG.Board#removeObject}. + * Defines dash patterns. Defined styles are: <ol> + * <li value="-1"> 2px dash, 2px space</li> + * <li> 5px dash, 5px space</li> + * <li> 10px dash, 10px space</li> + * <li> 20px dash, 20px space</li> + * <li> 20px dash, 10px space, 10px dash, 10px dash</li> + * <li> 20px dash, 5px space, 10px dash, 5px space</li></ol> + * @type Array + * @default ['2, 2', '5, 5', '10, 10', '20, 20', '20, 10, 10, 10', '20, 5, 10, 5'] + * @see http://www.w3.org/TR/SVG/painting.html#StrokeProperties */ - remove: function () { - var i; + this.dashArray = ['2, 2', '5, 5', '10, 10', '20, 20', '20, 10, 10, 10', '20, 5, 10, 5']; + }; - for (i = 0; i < this.borders.length; i++) { - this.board.removeObject(this.borders[i]); - } + JXG.SVGRenderer.prototype = new AbstractRenderer(); - GeometryElement.prototype.remove.call(this); - }, + JXG.extend(JXG.SVGRenderer.prototype, /** @lends JXG.SVGRenderer.prototype */ { /** - * Finds the index to a given point reference. - * @param {JXG.Point} p Reference to an element of type {@link JXG.Point} + * Creates an arrow DOM node. Arrows are displayed in SVG with a <em>marker</em> tag. + * @private + * @param {JXG.GeometryElement} el A JSXGraph element, preferably one that can have an arrow attached. + * @param {String} [idAppendix=''] A string that is added to the node's id. + * @returns {Node} Reference to the node added to the DOM. */ - findPoint: function (p) { - var i; - - if (!Type.isPoint(p)) { - return -1; - } + _createArrowHead: function (el, idAppendix, type) { + var node2, node3, + id = el.id + 'Triangle', + //type = null, + v, h; - for (i = 0; i < this.vertices.length; i++) { - if (this.vertices[i].id === p.id) { - return i; - } + if (Type.exists(idAppendix)) { + id += idAppendix; } + node2 = this.createPrim('marker', id); - return -1; - }, - - /** - * Add more points to the polygon. The new points will be inserted at the end. - * @param {JXG.Point} p Arbitrary number of points - * @returns {JXG.Polygon} Reference to the polygon - */ - addPoints: function (p) { - var args = Array.prototype.slice.call(arguments); + node2.setAttributeNS(null, 'stroke', Type.evaluate(el.visProp.strokecolor)); + node2.setAttributeNS(null, 'stroke-opacity', Type.evaluate(el.visProp.strokeopacity)); + node2.setAttributeNS(null, 'fill', Type.evaluate(el.visProp.strokecolor)); + node2.setAttributeNS(null, 'fill-opacity', Type.evaluate(el.visProp.strokeopacity)); + node2.setAttributeNS(null, 'stroke-width', 0); // this is the stroke-width of the arrow head. + // Should be zero to simplify the calculations - return this.insertPoints.apply(this, [this.vertices.length - 2].concat(args)); - }, + node2.setAttributeNS(null, 'orient', 'auto'); + node2.setAttributeNS(null, 'markerUnits', 'strokeWidth'); // 'strokeWidth' 'userSpaceOnUse'); - /** - * Adds more points to the vertex list of the polygon, starting with index <tt><i</tt> - * @param {Number} idx The position where the new vertices are inserted, starting with 0. - * @param {JXG.Point} p Arbitrary number of points to insert. - * @returns {JXG.Polygon} Reference to the polygon object - */ - insertPoints: function (idx, p) { - var i, npoints = [], tmp; + /* + Types 1, 2: + The arrow head is an isosceles triangle with base length 10 and height 10. - if (arguments.length === 0) { - return this; - } + Type 3: + A rectangle + Types 4, 5, 6: + Defined by Bezier curves from mp_arrowheads.html - if (idx < 0 || idx > this.vertices.length - 2) { - return this; - } + In any case but type 3 the arrow head is 10 units long, + type 3 is 10 unitsb high. + These 10 units are scaled to strokeWidth * arrowSize pixels, see + this._setArrowWidth(). - for (i = 1; i < arguments.length; i++) { - if (Type.isPoint(arguments[i])) { - npoints.push(arguments[i]); - } - } + See also abstractRenderer.updateLine() where the line path is shortened accordingly. - tmp = this.vertices.slice(0, idx + 1).concat(npoints); - this.vertices = tmp.concat(this.vertices.slice(idx + 1)); + Changes here are also necessary in setArrowWidth(). - if (this.withLines) { - tmp = this.borders.slice(0, idx); - this.board.removeObject(this.borders[idx]); + So far, lines with arrow heads are shortenend to avoid overlapping of + arrow head and line. This is not the case for curves, yet. + Therefore, the offset refX has to be adapted to the path type. + */ + node3 = this.container.ownerDocument.createElementNS(this.svgNamespace, 'path'); + h = 5; + if (idAppendix === 'End') { + // First arrow + //type = a.typeFirst; + // if (JXG.exists(ev_fa.type)) { + // type = Type.evaluate(ev_fa.type); + // } - for (i = 0; i < npoints.length; i++) { - tmp.push(this.board.create('segment', [this.vertices[idx + i], this.vertices[idx + i + 1]], this.attr_line)); + v = 0; + if (type === 2) { + node3.setAttributeNS(null, 'd', 'M 10,0 L 0,5 L 10,10 L 5,5 z'); + } else if (type === 3) { + node3.setAttributeNS(null, 'd', 'M 0,0 L 3.33,0 L 3.33,10 L 0,10 z'); + } else if (type === 4) { + // insetRatio:0.8 tipAngle:45 wingCurve:15 tailCurve:0 + h = 3.31; + node3.setAttributeNS(null, 'd', 'M 0.00,3.31 C 3.53,3.84 7.13,4.50 10.00,6.63 C 9.33,5.52 8.67,4.42 8.00,3.31 C 8.67,2.21 9.33,1.10 10.00,0.00 C 7.13,2.13 3.53,2.79 0.00,3.31'); + } else if (type === 5) { + // insetRatio:0.9 tipAngle:40 wingCurve:5 tailCurve:15 + h = 3.28; + node3.setAttributeNS(null, 'd', 'M 0.00,3.28 C 3.39,4.19 6.81,5.07 10.00,6.55 C 9.38,5.56 9.00,4.44 9.00,3.28 C 9.00,2.11 9.38,0.99 10.00,0.00 C 6.81,1.49 3.39,2.37 0.00,3.28'); + } else if (type === 6) { + // insetRatio:0.9 tipAngle:35 wingCurve:5 tailCurve:0 + h = 2.84; + node3.setAttributeNS(null, 'd', 'M 0.00,2.84 C 3.39,3.59 6.79,4.35 10.00,5.68 C 9.67,4.73 9.33,3.78 9.00,2.84 C 9.33,1.89 9.67,0.95 10.00,0.00 C 6.79,1.33 3.39,2.09 0.00,2.84'); + } else if (type === 7) { + // insetRatio:0.9 tipAngle:60 wingCurve:30 tailCurve:0 + h = 5.20; + node3.setAttributeNS(null, 'd', 'M 0.00,5.20 C 4.04,5.20 7.99,6.92 10.00,10.39 M 10.00,0.00 C 7.99,3.47 4.04,5.20 0.00,5.20'); + } else { + // type == 1 or > 6 + node3.setAttributeNS(null, 'd', 'M 10,0 L 0,5 L 10,10 z'); + } + if (/*!Type.exists(el.rendNode.getTotalLength) && */el.elementClass === Const.OBJECT_CLASS_LINE) { + if (type === 2) { + v = 4.9; + } else if (type === 3) { + v = 3.3; + } else if (type === 4 || type === 5 || type === 6) { + v = 6.66; + } else if (type === 7) { + v = 0.0; + } else { + v = 10.0; + } } + } else { + // Last arrow + // if (JXG.exists(ev_la.type)) { + // type = Type.evaluate(ev_la.type); + // } + //type = a.typeLast; - tmp.push(this.board.create('segment', [this.vertices[idx + npoints.length], this.vertices[idx + npoints.length + 1]], this.attr_line)); - this.borders = tmp.concat(this.borders.slice(idx + 1)); + v = 10.0; + if (type === 2) { + node3.setAttributeNS(null, 'd', 'M 0,0 L 10,5 L 0,10 L 5,5 z'); + } else if (type === 3) { + v = 3.3; + node3.setAttributeNS(null, 'd', 'M 0,0 L 3.33,0 L 3.33,10 L 0,10 z'); + } else if (type === 4) { + // insetRatio:0.8 tipAngle:45 wingCurve:15 tailCurve:0 + h = 3.31; + node3.setAttributeNS(null, 'd', 'M 10.00,3.31 C 6.47,3.84 2.87,4.50 0.00,6.63 C 0.67,5.52 1.33,4.42 2.00,3.31 C 1.33,2.21 0.67,1.10 0.00,0.00 C 2.87,2.13 6.47,2.79 10.00,3.31'); + } else if (type === 5) { + // insetRatio:0.9 tipAngle:40 wingCurve:5 tailCurve:15 + h = 3.28; + node3.setAttributeNS(null, 'd', 'M 10.00,3.28 C 6.61,4.19 3.19,5.07 0.00,6.55 C 0.62,5.56 1.00,4.44 1.00,3.28 C 1.00,2.11 0.62,0.99 0.00,0.00 C 3.19,1.49 6.61,2.37 10.00,3.28'); + } else if (type === 6) { + // insetRatio:0.9 tipAngle:35 wingCurve:5 tailCurve:0 + h = 2.84; + node3.setAttributeNS(null, 'd', 'M 10.00,2.84 C 6.61,3.59 3.21,4.35 0.00,5.68 C 0.33,4.73 0.67,3.78 1.00,2.84 C 0.67,1.89 0.33,0.95 0.00,0.00 C 3.21,1.33 6.61,2.09 10.00,2.84'); + } else if (type === 7) { + // insetRatio:0.9 tipAngle:60 wingCurve:30 tailCurve:0 + h = 5.20; + node3.setAttributeNS(null, 'd', 'M 10.00,5.20 C 5.96,5.20 2.01,6.92 0.00,10.39 M 0.00,0.00 C 2.01,3.47 5.96,5.20 10.00,5.20'); + } else { + // type == 1 or > 6 + node3.setAttributeNS(null, 'd', 'M 0,0 L 10,5 L 0,10 z'); + } + if (/*!Type.exists(el.rendNode.getTotalLength) &&*/ el.elementClass === Const.OBJECT_CLASS_LINE) { + if (type === 2) { + v = 5.1; + } else if (type === 3) { + v = 0.02; + } else if (type === 4 || type === 5 || type === 6) { + v = 3.33; + } else if (type === 7) { + v = 10.0; + } else { + v = 0.05; + } + } } + if (type === 7) { + node2.setAttributeNS(null, 'fill', 'none'); + node2.setAttributeNS(null, 'stroke-width', 1); // this is the stroke-width of the arrow head. + } + node2.setAttributeNS(null, 'refY', h); + node2.setAttributeNS(null, 'refX', v); - this.board.update(); - - return this; + node2.appendChild(node3); + return node2; }, /** - * Removes given set of vertices from the polygon - * @param {JXG.Point} p Arbitrary number of vertices as {@link JXG.Point} elements or index numbers - * @returns {JXG.Polygon} Reference to the polygon + * Updates color of an arrow DOM node. + * @param {Node} node The arrow node. + * @param {String} color Color value in a HTML compatible format, e.g. <tt>#00ff00</tt> or <tt>green</tt> for green. + * @param {Number} opacity + * @param {JXG.GeometryElement} el The element the arrows are to be attached to */ - removePoints: function (p) { - var i, j, idx, nvertices = [], nborders = [], - nidx = [], partition = []; - - // partition: - // in order to keep the borders which could be recycled, we have to partition - // the set of removed points. I.e. if the points 1, 2, 5, 6, 7, 10 are removed, - // the partitions are - // 1-2, 5-7, 10-10 - // this gives us the borders, that can be removed and the borders we have to create. - - - // remove the last vertex which is identical to the first - this.vertices = this.vertices.slice(0, this.vertices.length - 1); - - // collect all valid parameters as indices in nidx - for (i = 0; i < arguments.length; i++) { - idx = arguments[i]; - if (Type.isPoint(idx)) { - idx = this.findPoint(idx); + _setArrowColor: function (node, color, opacity, el, type) { + if (node) { + if (Type.isString(color)) { + if (type !== 7) { + this._setAttribute(function () { + node.setAttributeNS(null, 'stroke', color); + node.setAttributeNS(null, 'fill', color); + node.setAttributeNS(null, 'stroke-opacity', opacity); + node.setAttributeNS(null, 'fill-opacity', opacity); + }, el.visPropOld.fillcolor); + } else { + this._setAttribute(function () { + node.setAttributeNS(null, 'fill', 'none'); + node.setAttributeNS(null, 'stroke', color); + node.setAttributeNS(null, 'stroke-opacity', opacity); + }, el.visPropOld.fillcolor); + } } - if (Type.isNumber(idx) && idx > -1 && idx < this.vertices.length && Type.indexOf(nidx, idx) === -1) { - nidx.push(idx); + if (this.isIE) { + el.rendNode.parentNode.insertBefore(el.rendNode, el.rendNode); } } - // remove the polygon from each removed point's children - for (i = 0; i < nidx.length; i++) { - this.vertices[nidx[i]].removeChild(this); - } - - // sort the elements to be eliminated - nidx = nidx.sort(); - nvertices = this.vertices.slice(); - nborders = this.borders.slice(); + }, - // initialize the partition - if (this.withLines) { - partition.push([nidx[nidx.length - 1]]); - } + // Already documented in JXG.AbstractRenderer + _setArrowWidth: function (node, width, parentNode, size) { + var s, d; - // run through all existing vertices and copy all remaining ones to nvertices - // compute the partition - for (i = nidx.length - 1; i > -1; i--) { - nvertices[nidx[i]] = -1; + if (node) { + // if (width === 0) { + // // display:none does not work well in webkit + // node.setAttributeNS(null, 'display', 'none'); + // } else { + s = width; + d = s * size; + node.setAttributeNS(null, 'viewBox', (0) + ' ' + (0) + ' ' + (s * 10) + ' ' + (s * 10)); + node.setAttributeNS(null, 'markerHeight', d); + node.setAttributeNS(null, 'markerWidth', d); + node.setAttributeNS(null, 'display', 'inherit'); + // } - if (this.withLines && (nidx[i] - 1 > nidx[i - 1])) { - partition[partition.length - 1][1] = nidx[i]; - partition.push([nidx[i - 1]]); + if (this.isIE) { + parentNode.parentNode.insertBefore(parentNode, parentNode); } } + }, - // finalize the partition computation - if (this.withLines) { - partition[partition.length - 1][1] = nidx[0]; - } + /* ******************************** * + * This renderer does not need to + * override draw/update* methods + * since it provides draw/update*Prim + * methods except for some cases like + * internal texts or images. + * ******************************** */ - // update vertices - this.vertices = []; - for (i = 0; i < nvertices.length; i++) { - if (Type.isPoint(nvertices[i])) { - this.vertices.push(nvertices[i]); - } - } - if (this.vertices[this.vertices.length - 1].id !== this.vertices[0].id) { - this.vertices.push(this.vertices[0]); - } + /* ************************** + * Lines + * **************************/ - // delete obsolete and create missing borders - if (this.withLines) { - for (i = 0; i < partition.length; i++) { - for (j = partition[i][1] - 1; j < partition[i][0] + 1; j++) { - // special cases - if (j < 0) { - // first vertex is removed, so the last border has to be removed, too - j = 0; - this.board.removeObject(this.borders[nborders.length - 1]); - nborders[nborders.length - 1] = -1; - } else if (j > nborders.length - 1) { - j = nborders.length - 1; - } + // documented in AbstractRenderer + updateTicks: function (ticks) { + var i, j, c, node, x, y, + tickStr = '', + len = ticks.ticks.length, + len2, str, + isReal = true; - this.board.removeObject(this.borders[j]); - nborders[j] = -1; - } + for (i = 0; i < len; i++) { + c = ticks.ticks[i]; + x = c[0]; + y = c[1]; - // only create the new segment if it's not the closing border. the closing border is getting a special treatment at the end - // the if clause is newer than the min/max calls inside createSegment; i'm sure this makes the min/max calls obsolete, but - // just to be sure... - if (partition[i][1] !== 0 && partition[i][0] !== nvertices.length - 1) { - nborders[partition[i][0] - 1] = this.board.create('segment', [nvertices[Math.max(partition[i][1] - 1, 0)], nvertices[Math.min(partition[i][0] + 1, this.vertices.length - 1)]], this.attr_line); - } + len2 = x.length; + str = ' M ' + x[0] + ' ' + y[0]; + if (!Type.isNumber(x[0])) { + isReal = false; } - - this.borders = []; - for (i = 0; i < nborders.length; i++) { - if (nborders[i] !== -1) { - this.borders.push(nborders[i]); + for (j = 1; isReal && j < len2; ++j) { + if (Type.isNumber(x[j])) { + str += ' L ' + x[j] + ' ' + y[j]; + } else { + isReal = false; } - } - // if the first and/or the last vertex is removed, the closing border is created at the end. - if (partition[0][1] === this.vertices.length - 1 || partition[partition.length - 1][1] === 0) { - this.borders.push(this.board.create('segment', [this.vertices[0], this.vertices[this.vertices.length - 2]], this.attr_line)); + } + if (isReal) { + tickStr += str; } } - this.board.update(); + node = ticks.rendNode; - return this; + if (!Type.exists(node)) { + node = this.createPrim('path', ticks.id); + this.appendChildPrim(node, Type.evaluate(ticks.visProp.layer)); + ticks.rendNode = node; + } + + node.setAttributeNS(null, 'stroke', Type.evaluate(ticks.visProp.strokecolor)); + node.setAttributeNS(null, 'fill', 'none'); + // node.setAttributeNS(null, 'fill', Type.evaluate(ticks.visProp.fillcolor)); + // node.setAttributeNS(null, 'fill-opacity', Type.evaluate(ticks.visProp.fillopacity)); + node.setAttributeNS(null, 'stroke-opacity', Type.evaluate(ticks.visProp.strokeopacity)); + node.setAttributeNS(null, 'stroke-width', Type.evaluate(ticks.visProp.strokewidth)); + this.updatePathPrim(node, tickStr, ticks.board); }, - // documented in element.js - getParents: function () { - this.setParents(this.vertices); - return this.parents; + /* ************************** + * Text related stuff + * **************************/ + + // Already documented in JXG.AbstractRenderer + displayCopyright: function (str, fontsize) { + var node = this.createPrim('text', 'licenseText'), + t; + node.setAttributeNS(null, 'x', '20px'); + node.setAttributeNS(null, 'y', (2 + fontsize) + 'px'); + node.setAttributeNS(null, "style", "font-family:Arial,Helvetica,sans-serif; font-size:" + fontsize + "px; fill:#356AA0; opacity:0.3;"); + t = this.container.ownerDocument.createTextNode(str); + node.appendChild(t); + this.appendChildPrim(node, 0); }, - getAttributes: function () { - var attr = GeometryElement.prototype.getAttributes.call(this), i; + // Already documented in JXG.AbstractRenderer + drawInternalText: function (el) { + var node = this.createPrim('text', el.id); - if (this.withLines) { - attr.lines = attr.lines || {}; - attr.lines.ids = []; - attr.lines.colors = []; + //node.setAttributeNS(null, "style", "alignment-baseline:middle"); // Not yet supported by Firefox + // Preserve spaces + //node.setAttributeNS("http://www.w3.org/XML/1998/namespace", "space", "preserve"); + node.style.whiteSpace = 'nowrap'; - for (i = 0; i < this.borders.length; i++) { - attr.lines.ids.push(this.borders[i].id); - attr.lines.colors.push(this.borders[i].visProp.strokecolor); - } - } + el.rendNodeText = this.container.ownerDocument.createTextNode(''); + node.appendChild(el.rendNodeText); + this.appendChildPrim(node, Type.evaluate(el.visProp.layer)); - return attr; + return node; }, - snapToGrid: function () { - var i, force; - - if (Type.evaluate(this.visProp.snaptogrid)) { - force = true; - } else { - force = false; - } + // Already documented in JXG.AbstractRenderer + updateInternalText: function (el) { + var content = el.plaintext, v, + ev_ax = el.getAnchorX(), + ev_ay = el.getAnchorY(); - for (i = 0; i < this.vertices.length; i++) { - this.vertices[i].handleSnapToGrid(force, true); + if (el.rendNode.getAttributeNS(null, "class") !== el.visProp.cssclass) { + el.rendNode.setAttributeNS(null, "class", Type.evaluate(el.visProp.cssclass)); + el.needsSizeUpdate = true; } - }, + if (!isNaN(el.coords.scrCoords[1] + el.coords.scrCoords[2])) { + // Horizontal + v = el.coords.scrCoords[1]; + if (el.visPropOld.left !== (ev_ax + v)) { + el.rendNode.setAttributeNS(null, 'x', v + 'px'); - /** - * Moves the polygon by the difference of two coordinates. - * @param {Number} method The type of coordinates used here. Possible values are {@link JXG.COORDS_BY_USER} and {@link JXG.COORDS_BY_SCREEN}. - * @param {Array} coords coordinates in screen/user units - * @param {Array} oldcoords previous coordinates in screen/user units - * @returns {JXG.Polygon} this element - */ - setPositionDirectly: function (method, coords, oldcoords) { - var dc, t, i, len, - c = new Coords(method, coords, this.board), - oldc = new Coords(method, oldcoords, this.board); - - len = this.vertices.length - 1; - for (i = 0; i < len; i++) { - if (!this.vertices[i].draggable()) { - return this; + if (ev_ax === 'left') { + el.rendNode.setAttributeNS(null, 'text-anchor', 'start'); + } else if (ev_ax === 'right') { + el.rendNode.setAttributeNS(null, 'text-anchor', 'end'); + } else if (ev_ax === 'middle') { + el.rendNode.setAttributeNS(null, 'text-anchor', 'middle'); + } + el.visPropOld.left = ev_ax + v; } - } - dc = Statistics.subtract(c.usrCoords, oldc.usrCoords); - t = this.board.create('transform', dc.slice(1), {type: 'translate'}); - t.applyOnce(this.vertices.slice(0, -1)); + // Vertical + v = el.coords.scrCoords[2]; + if (el.visPropOld.top !== (ev_ay + v)) { + el.rendNode.setAttributeNS(null, 'y', (v + this.vOffsetText * 0.5) + 'px'); - return this; + if (ev_ay === 'bottom') { + el.rendNode.setAttributeNS(null, 'dominant-baseline', 'text-after-edge'); + } else if (ev_ay === 'top') { + el.rendNode.setAttributeNS(null, 'dy', '1.6ex'); + //el.rendNode.setAttributeNS(null, 'dominant-baseline', 'text-before-edge'); // Not supported by IE, edge + } else if (ev_ay === 'middle') { + //el.rendNode.setAttributeNS(null, 'dominant-baseline', 'middle'); + el.rendNode.setAttributeNS(null, 'dy', '0.6ex'); + } + el.visPropOld.top = ev_ay + v; + } + } + if (el.htmlStr !== content) { + el.rendNodeText.data = content; + el.htmlStr = content; + } + this.transformImage(el, el.transformations); }, /** - * Algorithm by Sutherland and Hodgman to compute the intersection of two convex polygons. - * The polygon itself is the clipping polygon, it expects as parameter a polygon to be clipped. - * See <a href="https://en.wikipedia.org/wiki/Sutherland%E2%80%93Hodgman_algorithm">wikipedia entry</a>. - * Called by {@link JXG.Polygon#intersect}. - * + * Set color and opacity of internal texts. + * SVG needs its own version. * @private - * - * @param {JXG.Polygon} polygon Polygon which will be clipped. - * - * @returns {Array} of (normalized homogeneous user) coordinates (i.e. [z, x, y], where z==1 in most cases, - * representing the vertices of the intersection polygon. - * + * @see JXG.AbstractRenderer#updateTextStyle + * @see JXG.AbstractRenderer#updateInternalTextStyle */ - sutherlandHodgman: function(polygon) { - // First the two polygons are sorted counter clockwise - var clip = JXG.Math.Geometry.sortVertices(this.vertices), // "this" is the clipping polygon - subject = JXG.Math.Geometry.sortVertices(polygon.vertices), // "polygon" is the subject polygon - - lenClip = clip.length - 1, - lenSubject = subject.length - 1, - lenIn, + updateInternalTextStyle: function (el, strokeColor, strokeOpacity, duration) { + this.setObjectFillColor(el, strokeColor, strokeOpacity); + }, - outputList = [], - inputList, i, j, S, E, cross, + /* ************************** + * Image related stuff + * **************************/ - // Determines if the point c3 is right of the line through c1 and c2. - // Since the polygons are sorted counter clockwise, "right of" and therefore >= is needed here - isInside = function(c1, c2, c3) { - return ((c2[1] - c1[1]) * (c3[2] - c1[2]) - (c2[2] - c1[2]) * (c3[1] - c1[1])) >= 0; - }; + // Already documented in JXG.AbstractRenderer + drawImage: function (el) { + var node = this.createPrim('image', el.id); - for (i = 0; i < lenSubject; i++) { - outputList.push(subject[i]); - } + node.setAttributeNS(null, 'preserveAspectRatio', 'none'); + this.appendChildPrim(node, Type.evaluate(el.visProp.layer)); + el.rendNode = node; - for (i = 0; i < lenClip; i++) { - inputList = outputList.slice(0); - lenIn = inputList.length; - outputList = []; + this.updateImage(el); + }, - S = inputList[lenIn - 1]; + // Already documented in JXG.AbstractRenderer + transformImage: function (el, t) { + var s, m, + node = el.rendNode, + str = "", + len = t.length; - for (j = 0; j < lenIn; j++) { - E = inputList[j]; - if (isInside(clip[i], clip[i + 1], E)) { - if (!isInside(clip[i], clip[i + 1], S)) { - cross = JXG.Math.Geometry.meetSegmentSegment(S, E, clip[i], clip[i + 1]); - cross[0][1] /= cross[0][0]; - cross[0][2] /= cross[0][0]; - cross[0][0] = 1; - outputList.push(cross[0]); - } - outputList.push(E); - } else if (isInside(clip[i], clip[i + 1], S)) { - cross = JXG.Math.Geometry.meetSegmentSegment(S, E, clip[i], clip[i + 1]); - cross[0][1] /= cross[0][0]; - cross[0][2] /= cross[0][0]; - cross[0][0] = 1; - outputList.push(cross[0]); - } - S = E; - } + if (len > 0) { + m = this.joinTransforms(el, t); + s = [m[1][1], m[2][1], m[1][2], m[2][2], m[1][0], m[2][0]].join(','); + str += ' matrix(' + s + ') '; + node.setAttributeNS(null, 'transform', str); } - - return outputList; }, - /** - * Generic method for the intersection of this polygon with another polygon. - * The parent object is the clipping polygon, it expects as parameter a polygon to be clipped. - * Both polygons have to be convex. - * Calls the algorithm by Sutherland, Hodgman, {@link JXG.Polygon#sutherlandHodgman}. - * <p> - * An alternative is to use the methods from {@link JXG.Math.Clip}, where the algorithm by Greiner and Hormann - * is used. - * - * @param {JXG.Polygon} polygon Polygon which will be clipped. - * - * @returns {Array} of (normalized homogeneous user) coordinates (i.e. [z, x, y], where z==1 in most cases, - * representing the vertices of the intersection polygon. - * - * @example - * // Static intersection of two polygons pol1 and pol2 - * var pol1 = board.create('polygon', [[-2, 3], [-4, -3], [2, 0], [4, 4]], { - * name:'pol1', withLabel: true, - * fillColor: 'yellow' - * }); - * var pol2 = board.create('polygon', [[-2, -3], [-4, 1], [0, 4], [5, 1]], { - * name:'pol2', withLabel: true - * }); - * - * // Static version: - * // the intersection polygon does not adapt to changes of pol1 or pol2. - * var pol3 = board.create('polygon', pol1.intersect(pol2), {fillColor: 'blue'}); - * </pre><div class="jxgbox" id="JXGd1fe5ea9-309f-494a-af07-ee3d033acb7c" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function() { - * var board = JXG.JSXGraph.initBoard('JXGd1fe5ea9-309f-494a-af07-ee3d033acb7c', {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); - * // Intersect two polygons pol1 and pol2 - * var pol1 = board.create('polygon', [[-2, 3], [-4, -3], [2, 0], [4, 4]], { - * name:'pol1', withLabel: true, - * fillColor: 'yellow' - * }); - * var pol2 = board.create('polygon', [[-2, -3], [-4, 1], [0, 4], [5, 1]], { - * name:'pol2', withLabel: true - * }); - * - * // Static version: the intersection polygon does not adapt to changes of pol1 or pol2. - * var pol3 = board.create('polygon', pol1.intersect(pol2), {fillColor: 'blue'}); - * })(); - * </script><pre> - * - * @example - * // Dynamic intersection of two polygons pol1 and pol2 - * var pol1 = board.create('polygon', [[-2, 3], [-4, -3], [2, 0], [4, 4]], { - * name:'pol1', withLabel: true, - * fillColor: 'yellow' - * }); - * var pol2 = board.create('polygon', [[-2, -3], [-4, 1], [0, 4], [5, 1]], { - * name:'pol2', withLabel: true - * }); - * - * // Dynamic version: - * // the intersection polygon does adapt to changes of pol1 or pol2. - * // For this a curve element is used. - * var curve = board.create('curve', [[],[]], {fillColor: 'blue', fillOpacity: 0.4}); - * curve.updateDataArray = function() { - * var mat = JXG.Math.transpose(pol1.intersect(pol2)); - * - * if (mat.length == 3) { - * this.dataX = mat[1]; - * this.dataY = mat[2]; - * } else { - * this.dataX = []; - * this.dataY = []; - * } - * }; - * board.update(); - * </pre><div class="jxgbox" id="JXGf870d516-ca1a-4140-8fe3-5d64fb42e5f2" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function() { - * var board = JXG.JSXGraph.initBoard('JXGf870d516-ca1a-4140-8fe3-5d64fb42e5f2', {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); - * // Intersect two polygons pol1 and pol2 - * var pol1 = board.create('polygon', [[-2, 3], [-4, -3], [2, 0], [4, 4]], { - * name:'pol1', withLabel: true, - * fillColor: 'yellow' - * }); - * var pol2 = board.create('polygon', [[-2, -3], [-4, 1], [0, 4], [5, 1]], { - * name:'pol2', withLabel: true - * }); - * - * // Dynamic version: - * // the intersection polygon does adapt to changes of pol1 or pol2. - * // For this a curve element is used. - * var curve = board.create('curve', [[],[]], {fillColor: 'blue', fillOpacity: 0.4}); - * curve.updateDataArray = function() { - * var mat = JXG.Math.transpose(pol1.intersect(pol2)); - * - * if (mat.length == 3) { - * this.dataX = mat[1]; - * this.dataY = mat[2]; - * } else { - * this.dataX = []; - * this.dataY = []; - * } - * }; - * board.update(); - * })(); - * </script><pre> - * - */ - intersect: function(polygon) { - return this.sutherlandHodgman(polygon); - } + // Already documented in JXG.AbstractRenderer + updateImageURL: function (el) { + var url = Type.evaluate(el.url); + if (el._src !== url) { + el.imgIsLoaded = false; + el.rendNode.setAttributeNS(this.xlinkNamespace, 'xlink:href', url); + el._src = url; - }); + return true; + } + return false; + }, - /** - * @class A polygon is an area enclosed by a set of border lines which are determined by - * <ul> - * <li> a list of points or - * <li> a list of coordinate arrays or - * <li> a function returning a list of coordinate arrays. - * </ul> - * Each two consecutive points of the list define a line. - * @pseudo - * @constructor - * @name Polygon - * @type Polygon - * @augments JXG.Polygon - * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {Array} vertices The polygon's vertices. If the first and the last vertex don't match the first one will be - * added to the array by the creator. Here, two points match if they have the same 'id' attribute. - * - * Additionally, a polygon can be created by providing a polygon and a transformation (or an array of transformations). - * The result is a polygon which is the transformation of the supplied polygon. - * - * @example - * var p1 = board.create('point', [0.0, 2.0]); - * var p2 = board.create('point', [2.0, 1.0]); - * var p3 = board.create('point', [4.0, 6.0]); - * var p4 = board.create('point', [1.0, 4.0]); - * - * var pol = board.create('polygon', [p1, p2, p3, p4]); - * </pre><div class="jxgbox" id="JXG682069e9-9e2c-4f63-9b73-e26f8a2b2bb1" style="width: 400px; height: 400px;"></div> - * <script type="text/javascript"> - * (function () { - * var board = JXG.JSXGraph.initBoard('JXG682069e9-9e2c-4f63-9b73-e26f8a2b2bb1', {boundingbox: [-1, 9, 9, -1], axis: false, showcopyright: false, shownavigation: false}), - * p1 = board.create('point', [0.0, 2.0]), - * p2 = board.create('point', [2.0, 1.0]), - * p3 = board.create('point', [4.0, 6.0]), - * p4 = board.create('point', [1.0, 4.0]), - * cc1 = board.create('polygon', [p1, p2, p3, p4]); - * })(); - * </script><pre> - * - * @example - * var p = [[0.0, 2.0], [2.0, 1.0], [4.0, 6.0], [1.0, 3.0]]; - * - * var pol = board.create('polygon', p, {hasInnerPoints: true}); - * </pre><div class="jxgbox" id="JXG9f9a5946-112a-4768-99ca-f30792bcdefb" style="width: 400px; height: 400px;"></div> - * <script type="text/javascript"> - * (function () { - * var board = JXG.JSXGraph.initBoard('JXG9f9a5946-112a-4768-99ca-f30792bcdefb', {boundingbox: [-1, 9, 9, -1], axis: false, showcopyright: false, shownavigation: false}), - * p = [[0.0, 2.0], [2.0, 1.0], [4.0, 6.0], [1.0, 4.0]], - * cc1 = board.create('polygon', p, {hasInnerPoints: true}); - * })(); - * </script><pre> - * - * @example - * var f1 = function() { return [0.0, 2.0]; }, - * f2 = function() { return [2.0, 1.0]; }, - * f3 = function() { return [4.0, 6.0]; }, - * f4 = function() { return [1.0, 4.0]; }, - * cc1 = board.create('polygon', [f1, f2, f3, f4]); - * board.update(); - * - * </pre><div class="jxgbox" id="JXGceb09915-b783-44db-adff-7877ae3534c8" style="width: 400px; height: 400px;"></div> - * <script type="text/javascript"> - * (function () { - * var board = JXG.JSXGraph.initBoard('JXGceb09915-b783-44db-adff-7877ae3534c8', {boundingbox: [-1, 9, 9, -1], axis: false, showcopyright: false, shownavigation: false}), - * f1 = function() { return [0.0, 2.0]; }, - * f2 = function() { return [2.0, 1.0]; }, - * f3 = function() { return [4.0, 6.0]; }, - * f4 = function() { return [1.0, 4.0]; }, - * cc1 = board.create('polygon', [f1, f2, f3, f4]); - * board.update(); - * })(); - * </script><pre> - * - * @example - * var t = board.create('transform', [2, 1.5], {type: 'scale'}); - * var a = board.create('point', [-3,-2], {name: 'a'}); - * var b = board.create('point', [-1,-4], {name: 'b'}); - * var c = board.create('point', [-2,-0.5], {name: 'c'}); - * var pol1 = board.create('polygon', [a,b,c], {vertices: {withLabel: false}}); - * var pol2 = board.create('polygon', [pol1, t], {vertices: {withLabel: true}}); - * - * </pre><div id="JXG6530a69c-6339-11e8-9fb9-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function() { - * var board = JXG.JSXGraph.initBoard('JXG6530a69c-6339-11e8-9fb9-901b0e1b8723', - * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); - * var t = board.create('transform', [2, 1.5], {type: 'scale'}); - * var a = board.create('point', [-3,-2], {name: 'a'}); - * var b = board.create('point', [-1,-4], {name: 'b'}); - * var c = board.create('point', [-2,-0.5], {name: 'c'}); - * var pol1 = board.create('polygon', [a,b,c], {vertices: {withLabel: false}}); - * var pol2 = board.create('polygon', [pol1, t], {vertices: {withLabel: true}}); - * - * })(); - * - * </script><pre> - * - */ - JXG.createPolygon = function (board, parents, attributes) { - var el, i, le, obj, - points = [], - attr, attr_points, - is_transform = false; + // Already documented in JXG.AbstractRenderer + updateImageStyle: function (el, doHighlight) { + var css = Type.evaluate(doHighlight ? el.visProp.highlightcssclass : el.visProp.cssclass); - attr = Type.copyAttributes(attributes, board.options, 'polygon'); - obj = board.select(parents[0]); - if (Type.isObject(obj) && obj.type === Const.OBJECT_TYPE_POLYGON && - Type.isTransformationOrArray(parents[1])) { + el.rendNode.setAttributeNS(null, 'class', css); + }, - is_transform = true; - le = obj.vertices.length - 1; - attr_points = Type.copyAttributes(attributes, board.options, 'polygon', 'vertices'); - for (i = 0; i < le; i++) { - if (attr_points.withlabel) { - attr_points.name = (obj.vertices[i].name === '') ? '' : (obj.vertices[i].name + "'"); - } - points.push(board.create('point', [obj.vertices[i], parents[1]], attr_points)); - } - } else { - points = Type.providePoints(board, parents, attributes, 'polygon', ['vertices']); - if (points === false) { - throw new Error("JSXGraph: Can't create polygon with parent types other than 'point' and 'coordinate arrays' or a function returning an array of coordinates. Alternatively, a polygon and a transformation can be supplied"); - } - } + // Already documented in JXG.AbstractRenderer + drawForeignObject: function (el) { + el.rendNode = this.appendChildPrim(this.createPrim('foreignObject', el.id), + Type.evaluate(el.visProp.layer)); - attr = Type.copyAttributes(attributes, board.options, 'polygon'); - el = new JXG.Polygon(board, points, attr); - el.isDraggable = true; + this.appendNodesToElement(el, 'foreignObject'); + this.updateForeignObject(el); + }, - // Put the points to their position - if (is_transform) { - le = obj.vertices.length - 1; - for (i = 0; i < le; i++) { - points[i].prepareUpdate().update().updateVisibility(Type.evaluate(el.visProp.visible)).updateRenderer(); + // Already documented in JXG.AbstractRenderer + updateForeignObject: function(el) { + if (el._useUserSize) { + el.rendNode.style.overflow = 'hidden'; + } else { + el.rendNode.style.overflow = 'visible'; } - } - return el; - }; + this.updateRectPrim(el.rendNode, el.coords.scrCoords[1], + el.coords.scrCoords[2] - el.size[1], el.size[0], el.size[1]); - /** - * @class Constructs a regular polygon. It needs two points which define the base line and the number of vertices. - * @pseudo - * @description Constructs a regular polygon. It needs two points which define the base line and the number of vertices, or a set of points. - * @constructor - * @name RegularPolygon - * @type Polygon - * @augments Polygon - * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {JXG.Point_JXG.Point_Number} p1,p2,n The constructed regular polygon has n vertices and the base line defined by p1 and p2. - * @example - * var p1 = board.create('point', [0.0, 2.0]); - * var p2 = board.create('point', [2.0, 1.0]); - * - * var pol = board.create('regularpolygon', [p1, p2, 5]); - * </pre><div class="jxgbox" id="JXG682069e9-9e2c-4f63-9b73-e26f8a2b2bb1" style="width: 400px; height: 400px;"></div> - * <script type="text/javascript"> - * (function () { - * var board = JXG.JSXGraph.initBoard('JXG682069e9-9e2c-4f63-9b73-e26f8a2b2bb1', {boundingbox: [-1, 9, 9, -1], axis: false, showcopyright: false, shownavigation: false}), - * p1 = board.create('point', [0.0, 2.0]), - * p2 = board.create('point', [2.0, 1.0]), - * cc1 = board.create('regularpolygon', [p1, p2, 5]); - * })(); - * </script><pre> - * @example - * var p1 = board.create('point', [0.0, 2.0]); - * var p2 = board.create('point', [4.0,4.0]); - * var p3 = board.create('point', [2.0,0.0]); - * - * var pol = board.create('regularpolygon', [p1, p2, p3]); - * </pre><div class="jxgbox" id="JXG096a78b3-bd50-4bac-b958-3be5e7df17ed" style="width: 400px; height: 400px;"></div> - * <script type="text/javascript"> - * (function () { - * var board = JXG.JSXGraph.initBoard('JXG096a78b3-bd50-4bac-b958-3be5e7df17ed', {boundingbox: [-1, 9, 9, -1], axis: false, showcopyright: false, shownavigation: false}), - * p1 = board.create('point', [0.0, 2.0]), - * p2 = board.create('point', [4.0, 4.0]), - * p3 = board.create('point', [2.0,0.0]), - * cc1 = board.create('regularpolygon', [p1, p2, p3]); - * })(); - * </script><pre> - * - * @example - * // Line of reflection - * var li = board.create('line', [1,1,1], {strokeColor: '#aaaaaa'}); - * var reflect = board.create('transform', [li], {type: 'reflect'}); - * var pol1 = board.create('polygon', [[-3,-2], [-1,-4], [-2,-0.5]]); - * var pol2 = board.create('polygon', [pol1, reflect]); - * - * </pre><div id="JXG58fc3078-d8d1-11e7-93b3-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function() { - * var board = JXG.JSXGraph.initBoard('JXG58fc3078-d8d1-11e7-93b3-901b0e1b8723', - * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); - * var li = board.create('line', [1,1,1], {strokeColor: '#aaaaaa'}); - * var reflect = board.create('transform', [li], {type: 'reflect'}); - * var pol1 = board.create('polygon', [[-3,-2], [-1,-4], [-2,-0.5]]); - * var pol2 = board.create('polygon', [pol1, reflect]); - * - * })(); - * - * </script><pre> - * - */ - JXG.createRegularPolygon = function (board, parents, attributes) { - var el, i, n, - p = [], rot, len, pointsExist, attr; + el.rendNode.innerHTML = el.content; + this._updateVisual(el, {stroke: true, dash: true}, true); + }, - len = parents.length; - n = parents[len - 1]; + /* ************************** + * Render primitive objects + * **************************/ - if (Type.isNumber(n) && (parents.length !== 3 || n < 3)) { - throw new Error("JSXGraph: A regular polygon needs two point types and a number > 2 as input."); - } + // Already documented in JXG.AbstractRenderer + appendChildPrim: function (node, level) { + if (!Type.exists(level)) { // trace nodes have level not set + level = 0; + } else if (level >= Options.layer.numlayers) { + level = Options.layer.numlayers - 1; + } - if (Type.isNumber(board.select(n))) { // Regular polygon given by 2 points and a number - len--; - pointsExist = false; - } else { // Regular polygon given by n points - n = len; - pointsExist = true; - } + this.layer[level].appendChild(node); - p = Type.providePoints(board, parents.slice(0, len), attributes, 'regularpolygon', ['vertices']); - if (p === false) { - throw new Error("JSXGraph: Can't create regular polygon with parent types other than 'point' and 'coordinate arrays' or a function returning an array of coordinates"); - } + return node; + }, - attr = Type.copyAttributes(attributes, board.options, 'regularpolygon', 'vertices'); - for (i = 2; i < n; i++) { - rot = board.create('transform', [Math.PI * (2 - (n - 2) / n), p[i - 1]], {type: 'rotate'}); - if (pointsExist) { - p[i].addTransform(p[i - 2], rot); - p[i].fullUpdate(); - } else { - if (Type.isArray(attr.ids) && attr.ids.length >= n - 2) { - attr.id = attr.ids[i - 2]; - } - p[i] = board.create('point', [p[i - 2], rot], attr); - p[i].type = Const.OBJECT_TYPE_CAS; + // Already documented in JXG.AbstractRenderer + createPrim: function (type, id) { + var node = this.container.ownerDocument.createElementNS(this.svgNamespace, type); + node.setAttributeNS(null, 'id', this.container.id + '_' + id); + node.style.position = 'absolute'; + if (type === 'path') { + node.setAttributeNS(null, 'stroke-linecap', 'round'); + node.setAttributeNS(null, 'stroke-linejoin', 'round'); + node.setAttributeNS(null, 'fill-rule', 'evenodd'); + } + return node; + }, - // The next two lines of code are needed to make regular polgonmes draggable - // The new helper points are set to be draggable. - p[i].isDraggable = true; - p[i].visProp.fixed = false; + // Already documented in JXG.AbstractRenderer + remove: function (shape) { + if (Type.exists(shape) && Type.exists(shape.parentNode)) { + shape.parentNode.removeChild(shape); } - } + }, - attr = Type.copyAttributes(attributes, board.options, 'regularpolygon'); - el = board.create('polygon', p, attr); - el.elType = 'regularpolygon'; + // Already documented in JXG.AbstractRenderer + setLayer: function (el, level) { + if (!Type.exists(level)) { + level = 0; + } else if (level >= Options.layer.numlayers) { + level = Options.layer.numlayers - 1; + } - return el; - }; + this.layer[level].appendChild(el.rendNode); + }, - /** - * @class A polygonal chain is a connected series of line segments determined by - * <ul> - * <li> a list of points or - * <li> a list of coordinate arrays or - * <li> a function returning a list of coordinate arrays. - * </ul> - * Each two consecutive points of the list define a line. - * In JSXGraph, a polygonal chain is simply realized as polygon without the last - closing - point. - * This may lead to unexpected results. Polygonal chains can be distinguished from polygons by the attribute 'elType' which - * is 'polygonalchain' for the first and 'polygon' for the latter. - * @pseudo - * @constructor - * @name PolygonalChain - * @type Polygon - * @augments JXG.Polygon - * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {Array} vertices The polygon's vertices. - * - * Additionally, a polygonal chain can be created by providing a polygonal chain and a transformation (or an array of transformations). - * The result is a polygonal chain which is the transformation of the supplied polygona chain. - * - * @example - * var attr = { - * snapToGrid: true - * }, - * p = []; - * - * p.push(board.create('point', [-4, 0], attr)); - * p.push(board.create('point', [-1, -3], attr)); - * p.push(board.create('point', [0, 2], attr)); - * p.push(board.create('point', [2, 1], attr)); - * p.push(board.create('point', [4, -2], attr)); - * - * var chain = board.create('polygonalchain', p, {borders: {strokeWidth: 3}}); - * - * </pre><div id="JXG878f93d8-3e49-46cf-aca2-d3bb7d60c5ae" class="jxgbox" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function() { - * var board = JXG.JSXGraph.initBoard('JXG878f93d8-3e49-46cf-aca2-d3bb7d60c5ae', - * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); - * var attr = { - * snapToGrid: true - * }, - * p = []; - * - * p.push(board.create('point', [-4, 0], attr)); - * p.push(board.create('point', [-1, -3], attr)); - * p.push(board.create('point', [0, 2], attr)); - * p.push(board.create('point', [2, 1], attr)); - * p.push(board.create('point', [4, -2], attr)); - * - * var chain = board.create('polygonalchain', p, {borders: {strokeWidth: 3}}); - * - * })(); - * - * </script><pre> - * - */ - JXG.createPolygonalChain = function (board, parents, attributes) { - var attr, el; + // Already documented in JXG.AbstractRenderer + makeArrows: function (el, a) { + var node2, + ev_fa = a.evFirst, + ev_la = a.evLast; - attr = Type.copyAttributes(attributes, board.options, 'polygonalchain'); - el = board.create('polygon', parents, attr); - el.elType = 'polygonalchain'; + // Test if the arrow heads already exist + if (el.visPropOld.firstarrow === ev_fa && + el.visPropOld.lastarrow === ev_la) { + if (this.isIE && el.visPropCalc.visible && + (ev_fa || ev_la)) { + el.rendNode.parentNode.insertBefore(el.rendNode, el.rendNode); + } + return; + } - // A polygonal chain is not necessarily closed. - el.vertices.pop(); - board.removeObject(el.borders[el.borders.length - 1]); - el.borders.pop(); + if (ev_fa) { + node2 = el.rendNodeTriangleStart; + if (!Type.exists(node2)) { + node2 = this._createArrowHead(el, 'End', a.typeFirst); + this.defs.appendChild(node2); + el.rendNodeTriangleStart = node2; + el.rendNode.setAttributeNS(null, 'marker-start', 'url(#' + this.container.id + '_' + el.id + 'TriangleEnd)'); + } else { + this.defs.appendChild(node2); + } + } else { + node2 = el.rendNodeTriangleStart; + if (Type.exists(node2)) { + this.remove(node2); + } + } + if (ev_la) { + node2 = el.rendNodeTriangleEnd; + if (!Type.exists(node2)) { + node2 = this._createArrowHead(el, 'Start', a.typeLast); + this.defs.appendChild(node2); + el.rendNodeTriangleEnd = node2; + el.rendNode.setAttributeNS(null, 'marker-end', 'url(#' + this.container.id + '_' + el.id + 'TriangleStart)'); + } else { + this.defs.appendChild(node2); + } + } else { + node2 = el.rendNodeTriangleEnd; + if (Type.exists(node2)) { + this.remove(node2); + } + } + el.visPropOld.firstarrow = ev_fa; + el.visPropOld.lastarrow = ev_la; + }, - return el; - }; + // Already documented in JXG.AbstractRenderer + updateEllipsePrim: function (node, x, y, rx, ry) { + var huge = 1000000; - JXG.registerElement('polygon', JXG.createPolygon); - JXG.registerElement('regularpolygon', JXG.createRegularPolygon); - JXG.registerElement('polygonalchain', JXG.createPolygonalChain); + huge = 200000; // IE + // webkit does not like huge values if the object is dashed + // iE doesn't like huge values above 216000 + x = Math.abs(x) < huge ? x : huge * x / Math.abs(x); + y = Math.abs(y) < huge ? y : huge * y / Math.abs(y); + rx = Math.abs(rx) < huge ? rx : huge * rx / Math.abs(rx); + ry = Math.abs(ry) < huge ? ry : huge * ry / Math.abs(ry); - return { - Polygon: JXG.Polygon, - createPolygon: JXG.createPolygon, - createRegularPolygon: JXG.createRegularPolygon - }; -}); + node.setAttributeNS(null, 'cx', x); + node.setAttributeNS(null, 'cy', y); + node.setAttributeNS(null, 'rx', Math.abs(rx)); + node.setAttributeNS(null, 'ry', Math.abs(ry)); + }, -/* - Copyright 2008-2021 - Matthias Ehmann, - Michael Gerhaeuser, - Carsten Miller, - Bianca Valentin, - Alfred Wassermann, - Peter Wilfahrt + // Already documented in JXG.AbstractRenderer + updateLinePrim: function (node, p1x, p1y, p2x, p2y) { + var huge = 1000000; - This file is part of JSXGraph. + huge = 200000; //IE + if (!isNaN(p1x + p1y + p2x + p2y)) { + // webkit does not like huge values if the object is dashed + // IE doesn't like huge values above 216000 + p1x = Math.abs(p1x) < huge ? p1x : huge * p1x / Math.abs(p1x); + p1y = Math.abs(p1y) < huge ? p1y : huge * p1y / Math.abs(p1y); + p2x = Math.abs(p2x) < huge ? p2x : huge * p2x / Math.abs(p2x); + p2y = Math.abs(p2y) < huge ? p2y : huge * p2y / Math.abs(p2y); - JSXGraph is free software dual licensed under the GNU LGPL or MIT License. + node.setAttributeNS(null, 'x1', p1x); + node.setAttributeNS(null, 'y1', p1y); + node.setAttributeNS(null, 'x2', p2x); + node.setAttributeNS(null, 'y2', p2y); + } + }, - You can redistribute it and/or modify it under the terms of the + // Already documented in JXG.AbstractRenderer + updatePathPrim: function (node, pointString) { + if (pointString === '') { + pointString = 'M 0 0'; + } + node.setAttributeNS(null, 'd', pointString); + }, - * GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version - OR - * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT + // Already documented in JXG.AbstractRenderer + updatePathStringPoint: function (el, size, type) { + var s = '', + scr = el.coords.scrCoords, + sqrt32 = size * Math.sqrt(3) * 0.5, + s05 = size * 0.5; - JSXGraph is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. + if (type === 'x') { + s = ' M ' + (scr[1] - size) + ' ' + (scr[2] - size) + + ' L ' + (scr[1] + size) + ' ' + (scr[2] + size) + + ' M ' + (scr[1] + size) + ' ' + (scr[2] - size) + + ' L ' + (scr[1] - size) + ' ' + (scr[2] + size); + } else if (type === '+') { + s = ' M ' + (scr[1] - size) + ' ' + (scr[2]) + + ' L ' + (scr[1] + size) + ' ' + (scr[2]) + + ' M ' + (scr[1]) + ' ' + (scr[2] - size) + + ' L ' + (scr[1]) + ' ' + (scr[2] + size); + } else if (type === '<>') { + s = ' M ' + (scr[1] - size) + ' ' + (scr[2]) + + ' L ' + (scr[1]) + ' ' + (scr[2] + size) + + ' L ' + (scr[1] + size) + ' ' + (scr[2]) + + ' L ' + (scr[1]) + ' ' + (scr[2] - size) + ' Z '; + } else if (type === '^') { + s = ' M ' + (scr[1]) + ' ' + (scr[2] - size) + + ' L ' + (scr[1] - sqrt32) + ' ' + (scr[2] + s05) + + ' L ' + (scr[1] + sqrt32) + ' ' + (scr[2] + s05) + + ' Z '; // close path + } else if (type === 'v') { + s = ' M ' + (scr[1]) + ' ' + (scr[2] + size) + + ' L ' + (scr[1] - sqrt32) + ' ' + (scr[2] - s05) + + ' L ' + (scr[1] + sqrt32) + ' ' + (scr[2] - s05) + + ' Z '; + } else if (type === '>') { + s = ' M ' + (scr[1] + size) + ' ' + (scr[2]) + + ' L ' + (scr[1] - s05) + ' ' + (scr[2] - sqrt32) + + ' L ' + (scr[1] - s05) + ' ' + (scr[2] + sqrt32) + + ' Z '; + } else if (type === '<') { + s = ' M ' + (scr[1] - size) + ' ' + (scr[2]) + + ' L ' + (scr[1] + s05) + ' ' + (scr[2] - sqrt32) + + ' L ' + (scr[1] + s05) + ' ' + (scr[2] + sqrt32) + + ' Z '; + } + return s; + }, - You should have received a copy of the GNU Lesser General Public License and - the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> - and <http://opensource.org/licenses/MIT/>. - */ + // Already documented in JXG.AbstractRenderer + updatePathStringPrim: function (el) { + var i, scr, len, + symbm = ' M ', + symbl = ' L ', + symbc = ' C ', + nextSymb = symbm, + maxSize = 5000.0, + pStr = ''; + if (el.numberPoints <= 0) { + return ''; + } -/*global JXG: true, define: true*/ -/*jslint nomen: true, plusplus: true*/ + len = Math.min(el.points.length, el.numberPoints); -/* depends: - jxg - math/math - math/geometry - math/numerics - math/statistics - math/symbolic - base/composition - base/coords - base/constants - utils/type - elements: - line - circle - transform - point - glider - text - curve - */ + if (el.bezierDegree === 1) { + for (i = 0; i < len; i++) { + scr = el.points[i].scrCoords; + if (isNaN(scr[1]) || isNaN(scr[2])) { // PenUp + nextSymb = symbm; + } else { + // Chrome has problems with values being too far away. + scr[1] = Math.max(Math.min(scr[1], maxSize), -maxSize); + scr[2] = Math.max(Math.min(scr[2], maxSize), -maxSize); -/** - * @fileoverview This file contains our composition elements, i.e. these elements are mostly put together - * from one or more {@link JXG.GeometryElement} but with a special meaning. E.g. the midpoint element is contained here - * and this is just a {@link JXG.Point} with coordinates dependent from two other points. Currently in this file the - * following compositions can be found: <ul> - * <li>{@link Arrowparallel} (currently private)</li> - * <li>{@link Bisector}</li> - * <li>{@link Msector}</li> - * <li>{@link Circumcircle}</li> - * <li>{@link Circumcirclemidpoint}</li> - * <li>{@link Integral}</li> - * <li>{@link Midpoint}</li> - * <li>{@link Mirrorpoint}</li> - * <li>{@link Normal}</li> - * <li>{@link Orthogonalprojection}</li> - * <li>{@link Parallel}</li> - * <li>{@link Perpendicular}</li> - * <li>{@link Perpendicularpoint}</li> - * <li>{@link Perpendicularsegment}</li> - * <li>{@link Reflection}</li></ul> - */ + // Attention: first coordinate may be inaccurate if far way + //pStr += [nextSymb, scr[1], ' ', scr[2]].join(''); + pStr += nextSymb + scr[1] + ' ' + scr[2]; // Seems to be faster now (webkit and firefox) + nextSymb = symbl; + } + } + } else if (el.bezierDegree === 3) { + i = 0; + while (i < len) { + scr = el.points[i].scrCoords; + if (isNaN(scr[1]) || isNaN(scr[2])) { // PenUp + nextSymb = symbm; + } else { + pStr += nextSymb + scr[1] + ' ' + scr[2]; + if (nextSymb === symbc) { + i += 1; + scr = el.points[i].scrCoords; + pStr += ' ' + scr[1] + ' ' + scr[2]; + i += 1; + scr = el.points[i].scrCoords; + pStr += ' ' + scr[1] + ' ' + scr[2]; + } + nextSymb = symbc; + } + i += 1; + } + } + return pStr; + }, -define('element/composition',[ - 'jxg', 'math/math', 'math/geometry', 'math/numerics', 'base/coords', - 'utils/type', 'base/constants', 'base/point', 'base/line', 'base/circle', 'base/transformation', - 'base/composition', 'base/curve', 'base/polygon' -], function (JXG, Mat, Geometry, Numerics, Coords, - Type, Const, Point, Line, Circle, Transform, - Composition, Curve, Polygon) { + // Already documented in JXG.AbstractRenderer + updatePathStringBezierPrim: function (el) { + var i, j, k, scr, lx, ly, len, + symbm = ' M ', + symbl = ' C ', + nextSymb = symbm, + maxSize = 5000.0, + pStr = '', + f = Type.evaluate(el.visProp.strokewidth), + isNoPlot = (Type.evaluate(el.visProp.curvetype) !== 'plot'); - "use strict"; + if (el.numberPoints <= 0) { + return ''; + } - /** - * @class This is used to construct a point that is the orthogonal projection of a point to a line. - * @pseudo - * @description An orthogonal projection is given by a point and a line. It is determined by projecting the given point - * orthogonal onto the given line. - * @constructor - * @name Orthogonalprojection - * @type JXG.Point - * @augments JXG.Point - * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {JXG.Line_JXG.Point} p,l The constructed point is the orthogonal projection of p onto l. - * @example - * var p1 = board.create('point', [0.0, 4.0]); - * var p2 = board.create('point', [6.0, 1.0]); - * var l1 = board.create('line', [p1, p2]); - * var p3 = board.create('point', [3.0, 3.0]); - * - * var pp1 = board.create('orthogonalprojection', [p3, l1]); - * </pre><div class="jxgbox" id="JXG7708b215-39fa-41b6-b972-19d73d77d791" style="width: 400px; height: 400px;"></div> - * <script type="text/javascript"> - * var ppex1_board = JXG.JSXGraph.initBoard('JXG7708b215-39fa-41b6-b972-19d73d77d791', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); - * var ppex1_p1 = ppex1_board.create('point', [0.0, 4.0]); - * var ppex1_p2 = ppex1_board.create('point', [6.0, 1.0]); - * var ppex1_l1 = ppex1_board.create('line', [ppex1_p1, ppex1_p2]); - * var ppex1_p3 = ppex1_board.create('point', [3.0, 3.0]); - * var ppex1_pp1 = ppex1_board.create('orthogonalprojection', [ppex1_p3, ppex1_l1]); - * </script><pre> - */ - JXG.createOrthogonalProjection = function (board, parents, attributes) { - var l, p, t, attr; + if (isNoPlot && el.board.options.curve.RDPsmoothing) { + el.points = Numerics.RamerDouglasPeucker(el.points, 0.5); + } - parents[0] = board.select(parents[0]); - parents[1] = board.select(parents[1]); + len = Math.min(el.points.length, el.numberPoints); + for (j = 1; j < 3; j++) { + nextSymb = symbm; + for (i = 0; i < len; i++) { + scr = el.points[i].scrCoords; - if (Type.isPointType(board, parents[0]) && parents[1].elementClass === Const.OBJECT_CLASS_LINE) { - p = Type.providePoints(board, [parents[0]], attributes, 'point')[0]; - l = parents[1]; - } else if (Type.isPointType(board, parents[1]) && parents[0].elementClass === Const.OBJECT_CLASS_LINE) { - p = Type.providePoints(board, [parents[1]], attributes, 'point')[0]; - l = parents[0]; - } else { - throw new Error("JSXGraph: Can't create perpendicular point with parent types '" + - (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + - "\nPossible parent types: [point,line]"); - } + if (isNaN(scr[1]) || isNaN(scr[2])) { // PenUp + nextSymb = symbm; + } else { + // Chrome has problems with values being too far away. + scr[1] = Math.max(Math.min(scr[1], maxSize), -maxSize); + scr[2] = Math.max(Math.min(scr[2], maxSize), -maxSize); - attr = Type.copyAttributes(attributes, board.options, 'orthogonalprojection'); + // Attention: first coordinate may be inaccurate if far way + if (nextSymb === symbm) { + //pStr += [nextSymb, scr[1], ' ', scr[2]].join(''); + pStr += nextSymb + scr[1] + ' ' + scr[2]; // Seems to be faster now (webkit and firefox) + } else { + k = 2 * j; + pStr += [nextSymb, + (lx + (scr[1] - lx) * 0.333 + f * (k * Math.random() - j)), ' ', + (ly + (scr[2] - ly) * 0.333 + f * (k * Math.random() - j)), ' ', + (lx + (scr[1] - lx) * 0.666 + f * (k * Math.random() - j)), ' ', + (ly + (scr[2] - ly) * 0.666 + f * (k * Math.random() - j)), ' ', + scr[1], ' ', scr[2]].join(''); + } - t = board.create('point', [ - function () { - return Geometry.projectPointToLine(p, l, board); + nextSymb = symbl; + lx = scr[1]; + ly = scr[2]; + } + } } - ], attr); + return pStr; + }, - p.addChild(t); - l.addChild(t); + // Already documented in JXG.AbstractRenderer + updatePolygonPrim: function (node, el) { + var i, + pStr = '', + scrCoords, + len = el.vertices.length; - t.elType = 'orthogonalprojection'; - t.setParents([p.id, t.id]); + node.setAttributeNS(null, 'stroke', 'none'); + if (el.elType === 'polygonalchain') { + len++; + } - t.update(); + for (i = 0; i < len - 1; i++) { + if (el.vertices[i].isReal) { + scrCoords = el.vertices[i].coords.scrCoords; + pStr = pStr + scrCoords[1] + "," + scrCoords[2]; + } else { + node.setAttributeNS(null, 'points', ''); + return; + } - t.generatePolynomial = function () { - /* - * Perpendicular takes point P and line L and creates point T and line M: - * - * | M - * | - * x P (p1,p2) - * | - * | - * L | - * ----------x-------------x------------------------x-------- - * A (a1,a2) |T (t1,t2) B (b1,b2) - * | - * | - * - * So we have two conditions: - * - * (a) AT || TB (collinearity condition) - * (b) PT _|_ AB (orthogonality condition) - * - * a2-t2 t2-b2 - * ------- = ------- (1) - * a1-t1 t1-b1 - * - * p2-t2 a1-b1 - * ------- = - ------- (2) - * p1-t1 a2-b2 - * - * Multiplying (1) and (2) with denominators and simplifying gives - * - * a2t1 - a2b1 + t2b1 - a1t2 + a1b2 - t1b2 = 0 (1') - * - * p2a2 - p2b2 - t2a2 + t2b2 + p1a1 - p1b1 - t1a1 + t1b1 = 0 (2') - * - */ + if (i < len - 2) { + pStr += " "; + } + } + if (pStr.indexOf('NaN') === -1) { + node.setAttributeNS(null, 'points', pStr); + } + }, - var a1 = l.point1.symbolic.x, - a2 = l.point1.symbolic.y, - b1 = l.point2.symbolic.x, - b2 = l.point2.symbolic.y, + // Already documented in JXG.AbstractRenderer + updateRectPrim: function (node, x, y, w, h) { + node.setAttributeNS(null, 'x', x); + node.setAttributeNS(null, 'y', y); + node.setAttributeNS(null, 'width', w); + node.setAttributeNS(null, 'height', h); + }, - p1 = p.symbolic.x, - p2 = p.symbolic.y, - t1 = t.symbolic.x, - t2 = t.symbolic.y, + /* ************************** + * Set Attributes + * **************************/ - poly1 = '(' + a2 + ')*(' + t1 + ')-(' + a2 + ')*(' + b1 + ')+(' + t2 + ')*(' + b1 + ')-(' + - a1 + ')*(' + t2 + ')+(' + a1 + ')*(' + b2 + ')-(' + t1 + ')*(' + b2 + ')', - poly2 = '(' + p2 + ')*(' + a2 + ')-(' + p2 + ')*(' + b2 + ')-(' + t2 + ')*(' + a2 + ')+(' + - t2 + ')*(' + b2 + ')+(' + p1 + ')*(' + a1 + ')-(' + p1 + ')*(' + b1 + ')-(' + t1 + ')*(' + - a1 + ')+(' + t1 + ')*(' + b1 + ')'; + // documented in JXG.AbstractRenderer + setPropertyPrim: function (node, key, val) { + if (key === 'stroked') { + return; + } + node.setAttributeNS(null, key, val); + }, - return [poly1, poly2]; - }; + display: function (el, val) { + var node; - return t; - }; + if (el && el.rendNode) { + el.visPropOld.visible = val; + node = el.rendNode; + if (val) { + node.setAttributeNS(null, 'display', 'inline'); + node.style.visibility = "inherit"; + } else { + node.setAttributeNS(null, 'display', 'none'); + node.style.visibility = "hidden"; + } + } + }, - /** + // documented in JXG.AbstractRenderer + show: function (el) { + JXG.deprecated('Board.renderer.show()', 'Board.renderer.display()'); + this.display(el, true); + // var node; + // + // if (el && el.rendNode) { + // node = el.rendNode; + // node.setAttributeNS(null, 'display', 'inline'); + // node.style.visibility = "inherit"; + // } + }, - * @class This element is used to provide a constructor for a perpendicular. - * @pseudo - * @description A perpendicular is a composition of two elements: a line and a point. The line is orthogonal - * to a given line and contains a given point. - * @name Perpendicular - * @constructor - * @type JXG.Line - * @augments Segment - * @returns A {@link JXG.Line} object through the given point that is orthogonal to the given line. - * @throws {Error} If the elements cannot be constructed with the given parent objects an exception is thrown. - * @param {JXG.Line_JXG.Point} l,p The perpendicular line will be orthogonal to l and - * will contain p. - * @example - * // Create a perpendicular - * var p1 = board.create('point', [0.0, 2.0]); - * var p2 = board.create('point', [2.0, 1.0]); - * var l1 = board.create('line', [p1, p2]); - * - * var p3 = board.create('point', [3.0, 3.0]); - * var perp1 = board.create('perpendicular', [l1, p3]); - * </pre><div class="jxgbox" id="JXGd5b78842-7b27-4d37-b608-d02519e6cd03" style="width: 400px; height: 400px;"></div> - * <script type="text/javascript"> - * var pex1_board = JXG.JSXGraph.initBoard('JXGd5b78842-7b27-4d37-b608-d02519e6cd03', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); - * var pex1_p1 = pex1_board.create('point', [0.0, 2.0]); - * var pex1_p2 = pex1_board.create('point', [2.0, 1.0]); - * var pex1_l1 = pex1_board.create('line', [pex1_p1, pex1_p2]); - * var pex1_p3 = pex1_board.create('point', [3.0, 3.0]); - * var pex1_perp1 = pex1_board.create('perpendicular', [pex1_l1, pex1_p3]); - * </script><pre> - */ - JXG.createPerpendicular = function (board, parents, attributes) { - var p, l, pd, attr; + // documented in JXG.AbstractRenderer + hide: function (el) { + JXG.deprecated('Board.renderer.hide()', 'Board.renderer.display()'); + this.display(el, false); + // var node; + // + // if (el && el.rendNode) { + // node = el.rendNode; + // node.setAttributeNS(null, 'display', 'none'); + // node.style.visibility = "hidden"; + // } + }, - parents[0] = board.select(parents[0]); - parents[1] = board.select(parents[1]); + // documented in JXG.AbstractRenderer + setBuffering: function (el, type) { + el.rendNode.setAttribute('buffered-rendering', type); + }, - if (Type.isPointType(board, parents[0]) && parents[1].elementClass === Const.OBJECT_CLASS_LINE) { - l = parents[1]; - p = Type.providePoints(board, [parents[0]], attributes, 'point')[0]; - } else if (Type.isPointType(board, parents[1]) && parents[0].elementClass === Const.OBJECT_CLASS_LINE) { - l = parents[0]; - p = Type.providePoints(board, [parents[1]], attributes, 'point')[0]; - } else { - throw new Error("JSXGraph: Can't create perpendicular with parent types '" + - (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + - "\nPossible parent types: [line,point]"); - } + // documented in JXG.AbstractRenderer + setDashStyle: function (el) { + var dashStyle = Type.evaluate(el.visProp.dash), + node = el.rendNode; - attr = Type.copyAttributes(attributes, board.options, 'perpendicular'); - pd = Line.createLine(board, [ - function () { - return l.stdform[2] * p.X() - l.stdform[1] * p.Y(); - }, - function () { - return -l.stdform[2] * p.Z(); - }, - function () { - return l.stdform[1] * p.Z(); + if (dashStyle > 0) { + node.setAttributeNS(null, 'stroke-dasharray', this.dashArray[dashStyle - 1]); + } else { + if (node.hasAttributeNS(null, 'stroke-dasharray')) { + node.removeAttributeNS(null, 'stroke-dasharray'); + } } - ], attr); - - pd.elType = 'perpendicular'; - pd.setParents([l.id, p.id]); + }, - return pd; - }; + // documented in JXG.AbstractRenderer + setGradient: function (el) { + var fillNode = el.rendNode, + node, node2, node3, + ev_g = Type.evaluate(el.visProp.gradient); - /** - * @class This is used to construct a perpendicular point. - * @pseudo - * @description A perpendicular point is given by a point and a line. It is determined by projecting the given point - * orthogonal onto the given line. This element should be used in GEONExTReader only. All other applications should - * use orthogonal projection {@link Orthogonalprojection}. - * @constructor - * @name PerpendicularPoint - * @type JXG.Point - * @augments JXG.Point - * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {JXG.Line_JXG.Point} p,l The constructed point is the orthogonal projection of p onto l. - * @example - * var p1 = board.create('point', [0.0, 4.0]); - * var p2 = board.create('point', [6.0, 1.0]); - * var l1 = board.create('line', [p1, p2]); - * var p3 = board.create('point', [3.0, 3.0]); - * - * var pp1 = board.create('perpendicularpoint', [p3, l1]); - * </pre><div class="jxgbox" id="JXGded148c9-3536-44c0-ab81-1bb8fa48f3f4" style="width: 400px; height: 400px;"></div> - * <script type="text/javascript"> - * var ppex1_board = JXG.JSXGraph.initBoard('JXGded148c9-3536-44c0-ab81-1bb8fa48f3f4', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); - * var ppex1_p1 = ppex1_board.create('point', [0.0, 4.0]); - * var ppex1_p2 = ppex1_board.create('point', [6.0, 1.0]); - * var ppex1_l1 = ppex1_board.create('line', [ppex1_p1, ppex1_p2]); - * var ppex1_p3 = ppex1_board.create('point', [3.0, 3.0]); - * var ppex1_pp1 = ppex1_board.create('perpendicularpoint', [ppex1_p3, ppex1_l1]); - * </script><pre> - */ - JXG.createPerpendicularPoint = function (board, parents, attributes) { - var l, p, t; + if (ev_g === 'linear' || ev_g === 'radial') { + node = this.createPrim(ev_g + 'Gradient', el.id + '_gradient'); + node2 = this.createPrim('stop', el.id + '_gradient1'); + node3 = this.createPrim('stop', el.id + '_gradient2'); + node.appendChild(node2); + node.appendChild(node3); + this.defs.appendChild(node); + fillNode.setAttributeNS(null, 'style', 'fill:url(#' + this.container.id + '_' + el.id + '_gradient)'); + el.gradNode1 = node2; + el.gradNode2 = node3; + el.gradNode = node; + } else { + fillNode.removeAttributeNS(null, 'style'); + } + }, - parents[0] = board.select(parents[0]); - parents[1] = board.select(parents[1]); - if (Type.isPointType(board, parents[0]) && parents[1].elementClass === Const.OBJECT_CLASS_LINE) { - p = Type.providePoints(board, [parents[0]], attributes, 'point')[0]; - l = parents[1]; - } else if (Type.isPointType(board, parents[1]) && parents[0].elementClass === Const.OBJECT_CLASS_LINE) { - p = Type.providePoints(board, [parents[1]], attributes, 'point')[0]; - l = parents[0]; - } else { - throw new Error("JSXGraph: Can't create perpendicular point with parent types '" + - (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + - "\nPossible parent types: [point,line]"); - } + /** + * Set the gradient angle for linear color gradients. + * + * @private + * @param {SVGnode} node SVG gradient node of an arbitrary JSXGraph element. + * @param {Number} radians angle value in radians. 0 is horizontal from left to right, Pi/4 is vertical from top to bottom. + */ + updateGradientAngle: function(node, radians) { + // Angles: + // 0: -> + // 90: down + // 180: <- + // 90: up + var f = 1.0, + co = Math.cos(radians), + si = Math.sin(radians); - t = board.create('point', [ - function () { - return Geometry.perpendicular(l, p, board)[0]; + if (Math.abs(co) > Math.abs(si)) { + f /= Math.abs(co); + } else { + f /= Math.abs(si); } - ], attributes); - p.addChild(t); - l.addChild(t); + if (co >= 0) { + node.setAttributeNS(null, 'x1', 0); + node.setAttributeNS(null, 'x2', co * f); + } else { + node.setAttributeNS(null, 'x1', -co * f); + node.setAttributeNS(null, 'x2', 0); + } + if (si >= 0) { + node.setAttributeNS(null, 'y1', 0); + node.setAttributeNS(null, 'y2', si * f); + } else { + node.setAttributeNS(null, 'y1', -si * f); + node.setAttributeNS(null, 'y2', 0); + } + }, - t.elType = 'perpendicularpoint'; - t.setParents([p.id, l.id]); + /** + * Set circles for radial color gradients. + * + * @private + * @param {SVGnode} node SVG gradient node + * @param {Number} cx SVG value cx (value between 0 and 1) + * @param {Number} cy SVG value cy (value between 0 and 1) + * @param {Number} r SVG value r (value between 0 and 1) + * @param {Number} fx SVG value fx (value between 0 and 1) + * @param {Number} fy SVG value fy (value between 0 and 1) + * @param {Number} fr SVG value fr (value between 0 and 1) + */ + updateGradientCircle: function(node, cx, cy, r, fx, fy, fr) { + node.setAttributeNS(null, 'cx', cx * 100 + '%'); // Center first color + node.setAttributeNS(null, 'cy', cy * 100 + '%'); + node.setAttributeNS(null, 'r', r * 100 + '%'); + node.setAttributeNS(null, 'fx', fx * 100 + '%'); // Center second color / focal point + node.setAttributeNS(null, 'fy', fy * 100 + '%'); + node.setAttributeNS(null, 'fr', fr * 100 + '%'); + }, - t.update(); + // documented in JXG.AbstractRenderer + updateGradient: function (el) { + var col, op, + node2 = el.gradNode1, + node3 = el.gradNode2, + ev_g = Type.evaluate(el.visProp.gradient); - t.generatePolynomial = function () { - /* - * Perpendicular takes point P and line L and creates point T and line M: - * - * | M - * | - * x P (p1,p2) - * | - * | - * L | - * ----------x-------------x------------------------x-------- - * A (a1,a2) |T (t1,t2) B (b1,b2) - * | - * | - * - * So we have two conditions: - * - * (a) AT || TB (collinearity condition) - * (b) PT _|_ AB (orthogonality condition) - * - * a2-t2 t2-b2 - * ------- = ------- (1) - * a1-t1 t1-b1 - * - * p2-t2 a1-b1 - * ------- = - ------- (2) - * p1-t1 a2-b2 - * - * Multiplying (1) and (2) with denominators and simplifying gives - * - * a2t1 - a2b1 + t2b1 - a1t2 + a1b2 - t1b2 = 0 (1') - * - * p2a2 - p2b2 - t2a2 + t2b2 + p1a1 - p1b1 - t1a1 + t1b1 = 0 (2') - * - */ - var a1 = l.point1.symbolic.x, - a2 = l.point1.symbolic.y, - b1 = l.point2.symbolic.x, - b2 = l.point2.symbolic.y, - p1 = p.symbolic.x, - p2 = p.symbolic.y, - t1 = t.symbolic.x, - t2 = t.symbolic.y, + if (!Type.exists(node2) || !Type.exists(node3)) { + return; + } - poly1 = '(' + a2 + ')*(' + t1 + ')-(' + a2 + ')*(' + b1 + ')+(' + t2 + ')*(' + b1 + ')-(' + - a1 + ')*(' + t2 + ')+(' + a1 + ')*(' + b2 + ')-(' + t1 + ')*(' + b2 + ')', - poly2 = '(' + p2 + ')*(' + a2 + ')-(' + p2 + ')*(' + b2 + ')-(' + t2 + ')*(' + a2 + ')+(' + - t2 + ')*(' + b2 + ')+(' + p1 + ')*(' + a1 + ')-(' + p1 + ')*(' + b1 + ')-(' + t1 + ')*(' + - a1 + ')+(' + t1 + ')*(' + b1 + ')'; + op = Type.evaluate(el.visProp.fillopacity); + op = (op > 0) ? op : 0; + col = Type.evaluate(el.visProp.fillcolor); - return [poly1, poly2]; - }; + node2.setAttributeNS(null, 'style', 'stop-color:' + col + ';stop-opacity:' + op); + node3.setAttributeNS(null, 'style', + 'stop-color:' + Type.evaluate(el.visProp.gradientsecondcolor) + + ';stop-opacity:' + Type.evaluate(el.visProp.gradientsecondopacity) + ); + node2.setAttributeNS(null, 'offset', Type.evaluate(el.visProp.gradientstartoffset) * 100 + '%'); + node3.setAttributeNS(null, 'offset', Type.evaluate(el.visProp.gradientendoffset) * 100 + '%'); + if (ev_g === 'linear') { + this.updateGradientAngle(el.gradNode, Type.evaluate(el.visProp.gradientangle)); + } else if (ev_g === 'radial') { + this.updateGradientCircle(el.gradNode, + Type.evaluate(el.visProp.gradientcx), + Type.evaluate(el.visProp.gradientcy), + Type.evaluate(el.visProp.gradientr), + Type.evaluate(el.visProp.gradientfx), + Type.evaluate(el.visProp.gradientfy), + Type.evaluate(el.visProp.gradientfr) + ); + } + }, - return t; - }; + // documented in JXG.AbstractRenderer + setObjectTransition: function (el, duration) { + var node, transitionStr, + i, len, + nodes = ['rendNode', + 'rendNodeTriangleStart', + 'rendNodeTriangleEnd']; - /** - * @class This element is used to provide a constructor for a perpendicular segment. - * @pseudo - * @description A perpendicular is a composition of two elements: a line segment and a point. The line segment is orthogonal - * to a given line and contains a given point and meets the given line in the perpendicular point. - * @name PerpendicularSegment - * @constructor - * @type JXG.Line - * @augments Segment - * @returns An array containing two elements: A {@link JXG.Line} object in the first component and a - * {@link JXG.Point} element in the second component. The line segment is orthogonal to the given line and meets it - * in the returned point. - * @throws {Error} If the elements cannot be constructed with the given parent objects an exception is thrown. - * @param {JXG.Line_JXG.Point} l,p The perpendicular line will be orthogonal to l and - * will contain p. The perpendicular point is the intersection point of the two lines. - * @example - * // Create a perpendicular - * var p1 = board.create('point', [0.0, 2.0]); - * var p2 = board.create('point', [2.0, 1.0]); - * var l1 = board.create('line', [p1, p2]); - * - * var p3 = board.create('point', [3.0, 3.0]); - * var perp1 = board.create('perpendicularsegment', [l1, p3]); - * </pre><div class="jxgbox" id="JXG037a6eb2-781d-4b71-b286-763619a63f22" style="width: 400px; height: 400px;"></div> - * <script type="text/javascript"> - * var pex1_board = JXG.JSXGraph.initBoard('JXG037a6eb2-781d-4b71-b286-763619a63f22', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); - * var pex1_p1 = pex1_board.create('point', [0.0, 2.0]); - * var pex1_p2 = pex1_board.create('point', [2.0, 1.0]); - * var pex1_l1 = pex1_board.create('line', [pex1_p1, pex1_p2]); - * var pex1_p3 = pex1_board.create('point', [3.0, 3.0]); - * var pex1_perp1 = pex1_board.create('perpendicularsegment', [pex1_l1, pex1_p3]); - * </script><pre> - */ - JXG.createPerpendicularSegment = function (board, parents, attributes) { - var p, l, pd, t, attr; + if (duration === undefined) { + duration = Type.evaluate(el.visProp.transitionduration); + } - parents[0] = board.select(parents[0]); - parents[1] = board.select(parents[1]); - if (Type.isPointType(board, parents[0]) && parents[1].elementClass === Const.OBJECT_CLASS_LINE) { - l = parents[1]; - p = Type.providePoints(board, [parents[0]], attributes, 'point')[0]; - } else if (Type.isPointType(board, parents[1]) && parents[0].elementClass === Const.OBJECT_CLASS_LINE) { - l = parents[0]; - p = Type.providePoints(board, [parents[1]], attributes, 'point')[0]; - } else { - throw new Error("JSXGraph: Can't create perpendicular with parent types '" + - (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + - "\nPossible parent types: [line,point]"); - } - attr = Type.copyAttributes(attributes, board.options, 'perpendicularsegment', 'point'); - t = JXG.createPerpendicularPoint(board, [l, p], attr); - t.dump = false; + if (duration === el.visPropOld.transitionduration) { + return; + } - if (!Type.exists(attributes.layer)) { - attributes.layer = board.options.layer.line; - } + if (el.elementClass === Const.OBJECT_CLASS_TEXT && + Type.evaluate(el.visProp.display) === 'html') { + transitionStr = ' color ' + duration + 'ms,' + + ' opacity ' + duration + 'ms'; + } else { + transitionStr = ' fill ' + duration + 'ms,' + + ' fill-opacity ' + duration + 'ms,' + + ' stroke ' + duration + 'ms,' + + ' stroke-opacity ' + duration + 'ms'; + } - attr = Type.copyAttributes(attributes, board.options, 'perpendicularsegment'); - pd = Line.createLine(board, [ - function () { - return (Geometry.perpendicular(l, p, board)[1] ? [t, p] : [p, t]); + len = nodes.length; + for (i = 0; i < len; ++i) { + if (el[nodes[i]]) { + node = el[nodes[i]]; + node.style.transition = transitionStr; + } } - ], attr); + + el.visPropOld.transitionduration = duration; + }, /** - * Helper point - * @memberOf PerpendicularSegment.prototype - * @type PerpendicularPoint - * @name point + * Call user-defined function to set visual attributes. + * If "testAttribute" is the empty string, the function + * is called immediately, otherwise it is called in a timeOut. + * + * This is necessary to realize smooth transitions but avoid transitions + * when first creating the objects. + * + * Usually, the string in testAttribute is the visPropOld attribute + * of the values which are set. + * + * @param {Function} setFunc Some function which usually sets some attributes + * @param {String} testAttribute If this string is the empty string the function is called immediately, + * otherwise it is called in a setImeout. + * @see JXG.SVGRenderer#setObjectFillColor + * @see JXG.SVGRenderer#setObjectStrokeColor + * @see JXG.SVGRenderer#_setArrowColor + * @private */ - pd.point = t; - - pd.elType = 'perpendicularsegment'; - pd.setParents([p.id, l.id]); - pd.subs = { - point: t - }; - pd.inherits.push(t); + _setAttribute: function (setFunc, testAttribute) { + if (testAttribute === '') { + setFunc(); + } else { + window.setTimeout(setFunc, 1); + } + }, - return pd; - }; + // documented in JXG.AbstractRenderer + setObjectFillColor: function (el, color, opacity, rendNode) { + var node, c, rgbo, oo, + rgba = Type.evaluate(color), + o = Type.evaluate(opacity), + grad = Type.evaluate(el.visProp.gradient); - /** - * @class The midpoint element constructs a point in the middle of two given points. - * @pseudo - * @description A midpoint is given by two points. It is collinear to the given points and the distance - * is the same to each of the given points, i.e. it is in the middle of the given points. - * @constructor - * @name Midpoint - * @type JXG.Point - * @augments JXG.Point - * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {JXG.Point_JXG.Point} p1,p2 The constructed point will be in the middle of p1 and p2. - * @param {JXG.Line} l The midpoint will be in the middle of {@link JXG.Line#point1} and {@link JXG.Line#point2} of - * the given line l. - * @example - * // Create base elements: 2 points and 1 line - * var p1 = board.create('point', [0.0, 2.0]); - * var p2 = board.create('point', [2.0, 1.0]); - * var l1 = board.create('segment', [[0.0, 3.0], [3.0, 3.0]]); - * - * var mp1 = board.create('midpoint', [p1, p2]); - * var mp2 = board.create('midpoint', [l1]); - * </pre><div class="jxgbox" id="JXG7927ef86-24ae-40cc-afb0-91ff61dd0de7" style="width: 400px; height: 400px;"></div> - * <script type="text/javascript"> - * var mpex1_board = JXG.JSXGraph.initBoard('JXG7927ef86-24ae-40cc-afb0-91ff61dd0de7', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); - * var mpex1_p1 = mpex1_board.create('point', [0.0, 2.0]); - * var mpex1_p2 = mpex1_board.create('point', [2.0, 1.0]); - * var mpex1_l1 = mpex1_board.create('segment', [[0.0, 3.0], [3.0, 3.0]]); - * var mpex1_mp1 = mpex1_board.create('midpoint', [mpex1_p1, mpex1_p2]); - * var mpex1_mp2 = mpex1_board.create('midpoint', [mpex1_l1]); - * </script><pre> - */ - JXG.createMidpoint = function (board, parents, attributes) { - var a, b, t, i, - attr; + o = (o > 0) ? o : 0; - for (i = 0; i < parents.length; ++i) { - parents[i] = board.select(parents[i]); - } - if (parents.length === 2 && Type.isPointType(board, parents[0]) && Type.isPointType(board, parents[1])) { - parents = Type.providePoints(board, parents, attributes, 'point'); - a = parents[0]; - b = parents[1]; - } else if (parents.length === 1 && parents[0].elementClass === Const.OBJECT_CLASS_LINE) { - a = parents[0].point1; - b = parents[0].point2; - } else { - throw new Error("JSXGraph: Can't create midpoint." + - "\nPossible parent types: [point,point], [line]"); - } + // TODO save gradient and gradientangle + if (el.visPropOld.fillcolor === rgba && el.visPropOld.fillopacity === o && grad === null) { + return; + } - attr = Type.copyAttributes(attributes, board.options, 'midpoint'); - t = board.create('point', [ - function () { - var x = a.coords.usrCoords[1] + b.coords.usrCoords[1]; - if (isNaN(x) || Math.abs(a.coords.usrCoords[0]) < Mat.eps || Math.abs(b.coords.usrCoords[0]) < Mat.eps) { - return NaN; + if (Type.exists(rgba) && rgba !== false) { + if (rgba.length !== 9) { // RGB, not RGBA + c = rgba; + oo = o; + } else { // True RGBA, not RGB + rgbo = Color.rgba2rgbo(rgba); + c = rgbo[0]; + oo = o * rgbo[1]; } - return x * 0.5; - }, - function () { - var y = a.coords.usrCoords[2] + b.coords.usrCoords[2]; - if (isNaN(y) || Math.abs(a.coords.usrCoords[0]) < Mat.eps || Math.abs(b.coords.usrCoords[0]) < Mat.eps) { - return NaN; + if (rendNode === undefined) { + node = el.rendNode; + } else { + node = rendNode; } - return y * 0.5; - }], attr); - a.addChild(t); - b.addChild(t); + if (c !== 'none') { + this._setAttribute(function () { + node.setAttributeNS(null, 'fill', c); + }, el.visPropOld.fillcolor); + } - t.elType = 'midpoint'; - t.setParents([a.id, b.id]); + if (el.type === JXG.OBJECT_TYPE_IMAGE) { + this._setAttribute(function () { + node.setAttributeNS(null, 'opacity', oo); + }, el.visPropOld.fillopacity); + //node.style['opacity'] = oo; // This would overwrite values set by CSS class. + } else { + if (c === 'none') { // This is done only for non-images + // because images have no fill color. + oo = 0; + // This is necessary if there is a foreignObject below. + node.setAttributeNS(null, 'pointer-events', 'visibleStroke'); + } else { + // This is the default + node.setAttributeNS(null, 'pointer-events', 'visiblePainted'); + } + this._setAttribute(function () { + node.setAttributeNS(null, 'fill-opacity', oo); + }, el.visPropOld.fillopacity); + } - t.prepareUpdate().update(); + if (grad === 'linear' || grad === 'radial') { + this.updateGradient(el); + } + } + el.visPropOld.fillcolor = rgba; + el.visPropOld.fillopacity = o; + }, - t.generatePolynomial = function () { - /* - * Midpoint takes two point A and B or line L (with points P and Q) and creates point T: - * - * L (not necessarily) - * ----------x------------------x------------------x-------- - * A (a1,a2) T (t1,t2) B (b1,b2) - * - * So we have two conditions: - * - * (a) AT || TB (collinearity condition) - * (b) [AT] == [TB] (equidistant condition) - * - * a2-t2 t2-b2 - * ------- = ------- (1) - * a1-t1 t1-b1 - * - * (a1 - t1)^2 + (a2 - t2)^2 = (b1 - t1)^2 + (b2 - t2)^2 (2) - * - * - * Multiplying (1) with denominators and simplifying (1) and (2) gives - * - * a2t1 - a2b1 + t2b1 - a1t2 + a1b2 - t1b2 = 0 (1') - * - * a1^2 - 2a1t1 + a2^2 - 2a2t2 - b1^2 + 2b1t1 - b2^2 + 2b2t2 = 0 (2') - * - */ - var a1 = a.symbolic.x, - a2 = a.symbolic.y, - b1 = b.symbolic.x, - b2 = b.symbolic.y, - t1 = t.symbolic.x, - t2 = t.symbolic.y, + // documented in JXG.AbstractRenderer + setObjectStrokeColor: function (el, color, opacity) { + var rgba = Type.evaluate(color), c, rgbo, + o = Type.evaluate(opacity), oo, + node; - poly1 = '(' + a2 + ')*(' + t1 + ')-(' + a2 + ')*(' + b1 + ')+(' + t2 + ')*(' + b1 + ')-(' + - a1 + ')*(' + t2 + ')+(' + a1 + ')*(' + b2 + ')-(' + t1 + ')*(' + b2 + ')', - poly2 = '(' + a1 + ')^2 - 2*(' + a1 + ')*(' + t1 + ')+(' + a2 + ')^2-2*(' + a2 + ')*(' + - t2 + ')-(' + b1 + ')^2+2*(' + b1 + ')*(' + t1 + ')-(' + b2 + ')^2+2*(' + b2 + ')*(' + t2 + ')'; + o = (o > 0) ? o : 0; - return [poly1, poly2]; - }; + if (el.visPropOld.strokecolor === rgba && el.visPropOld.strokeopacity === o) { + return; + } - return t; - }; + if (Type.exists(rgba) && rgba !== false) { + if (rgba.length !== 9) { // RGB, not RGBA + c = rgba; + oo = o; + } else { // True RGBA, not RGB + rgbo = Color.rgba2rgbo(rgba); + c = rgbo[0]; + oo = o * rgbo[1]; + } - /** - * @class This element is used to construct a parallel point. - * @pseudo - * @description A parallel point is given by three points. Taking the Euclidean vector from the first to the - * second point, the parallel point is determined by adding that vector to the third point. - * The line determined by the first two points is parallel to the line determined by the third point and the constructed point. - * @constructor - * @name Parallelpoint - * @type JXG.Point - * @augments JXG.Point - * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 Taking the Euclidean vector <tt>v=p2-p1</tt> the parallel point is determined by - * <tt>p4 = p3+v</tt> - * @param {JXG.Line_JXG.Point} l,p The resulting point will together with p specify a line which is parallel to l. - * @example - * var p1 = board.create('point', [0.0, 2.0]); - * var p2 = board.create('point', [2.0, 1.0]); - * var p3 = board.create('point', [3.0, 3.0]); - * - * var pp1 = board.create('parallelpoint', [p1, p2, p3]); - * </pre><div class="jxgbox" id="JXG488c4be9-274f-40f0-a469-c5f70abe1f0e" style="width: 400px; height: 400px;"></div> - * <script type="text/javascript"> - * var ppex1_board = JXG.JSXGraph.initBoard('JXG488c4be9-274f-40f0-a469-c5f70abe1f0e', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); - * var ppex1_p1 = ppex1_board.create('point', [0.0, 2.0]); - * var ppex1_p2 = ppex1_board.create('point', [2.0, 1.0]); - * var ppex1_p3 = ppex1_board.create('point', [3.0, 3.0]); - * var ppex1_pp1 = ppex1_board.create('parallelpoint', [ppex1_p1, ppex1_p2, ppex1_p3]); - * </script><pre> - */ - JXG.createParallelPoint = function (board, parents, attributes) { - var a, b, c, p, i; + node = el.rendNode; - for (i = 0; i < parents.length; ++i) { - parents[i] = board.select(parents[i]); - } - if (parents.length === 3 && - Type.isPointType(board, parents[0]) && - Type.isPointType(board, parents[1]) && - Type.isPointType(board, parents[2])) { - parents = Type.providePoints(board, parents, attributes, 'point'); - a = parents[0]; - b = parents[1]; - c = parents[2]; - } else if (Type.isPointType(board, parents[0]) && - parents[1].elementClass === Const.OBJECT_CLASS_LINE) { - c = Type.providePoints(board, [parents[0]], attributes, 'point')[0]; - a = parents[1].point1; - b = parents[1].point2; - } else if (Type.isPointType(board, parents[1]) && - parents[0].elementClass === Const.OBJECT_CLASS_LINE) { - c = Type.providePoints(board, [parents[1]], attributes, 'point')[0]; - a = parents[0].point1; - b = parents[0].point2; - } else { - throw new Error("JSXGraph: Can't create parallel point with parent types '" + - (typeof parents[0]) + "', '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." + - "\nPossible parent types: [line,point], [point,point,point]"); - } + if (el.elementClass === Const.OBJECT_CLASS_TEXT) { + if (Type.evaluate(el.visProp.display) === 'html') { + this._setAttribute(function () { + node.style.color = c; + node.style.opacity = oo; + }, el.visPropOld.strokecolor); - p = board.create('point', [ - function () { - return c.coords.usrCoords[1] + b.coords.usrCoords[1] - a.coords.usrCoords[1]; - }, - function () { - return c.coords.usrCoords[2] + b.coords.usrCoords[2] - a.coords.usrCoords[2]; + } else { + this._setAttribute(function () { + node.setAttributeNS(null, "style", "fill:" + c); + node.setAttributeNS(null, "style", "fill-opacity:" + oo); + }, el.visPropOld.strokecolor); + } + } else { + this._setAttribute(function () { + node.setAttributeNS(null, 'stroke', c); + node.setAttributeNS(null, 'stroke-opacity', oo); + }, el.visPropOld.strokecolor); + } + + if (el.elementClass === Const.OBJECT_CLASS_CURVE || + el.elementClass === Const.OBJECT_CLASS_LINE) { + if (Type.evaluate(el.visProp.firstarrow)) { + this._setArrowColor(el.rendNodeTriangleStart, c, oo, el, el.visPropCalc.typeFirst); + } + + if (Type.evaluate(el.visProp.lastarrow)) { + this._setArrowColor(el.rendNodeTriangleEnd, c, oo, el, el.visPropCalc.typeLast); + } + } } - ], attributes); - // required for algorithms requiring dependencies between elements - a.addChild(p); - b.addChild(p); - c.addChild(p); + el.visPropOld.strokecolor = rgba; + el.visPropOld.strokeopacity = o; + }, - p.elType = 'parallelpoint'; - p.setParents([a.id, b.id, c.id]); + // documented in JXG.AbstractRenderer + setObjectStrokeWidth: function (el, width) { + var node, + w = Type.evaluate(width); - // required to set the coordinates because functions are considered as constraints. hence, the coordinates get set first after an update. - // can be removed if the above issue is resolved. - p.prepareUpdate().update(); + if (isNaN(w) || el.visPropOld.strokewidth === w) { + return; + } - p.generatePolynomial = function () { - /* - * Parallelpoint takes three points A, B and C or line L (with points B and C) and creates point T: - * - * - * C (c1,c2) T (t1,t2) - * x x - * / / - * / / - * / / - * / / - * / / - * / / - * / / - * / / - * L (opt) / / - * ----------x-------------------------------------x-------- - * A (a1,a2) B (b1,b2) - * - * So we have two conditions: - * - * (a) CT || AB (collinearity condition I) - * (b) BT || AC (collinearity condition II) - * - * The corresponding equations are - * - * (b2 - a2)(t1 - c1) - (t2 - c2)(b1 - a1) = 0 (1) - * (t2 - b2)(a1 - c1) - (t1 - b1)(a2 - c2) = 0 (2) - * - * Simplifying (1) and (2) gives - * - * b2t1 - b2c1 - a2t1 + a2c1 - t2b1 + t2a1 + c2b1 - c2a1 = 0 (1') - * t2a1 - t2c1 - b2a1 + b2c1 - t1a2 + t1c2 + b1a2 - b1c2 = 0 (2') - * - */ - var a1 = a.symbolic.x, - a2 = a.symbolic.y, - b1 = b.symbolic.x, - b2 = b.symbolic.y, - c1 = c.symbolic.x, - c2 = c.symbolic.y, - t1 = p.symbolic.x, - t2 = p.symbolic.y, + node = el.rendNode; + this.setPropertyPrim(node, 'stroked', 'true'); + if (Type.exists(w)) { + this.setPropertyPrim(node, 'stroke-width', w + 'px'); - poly1 = '(' + b2 + ')*(' + t1 + ')-(' + b2 + ')*(' + c1 + ')-(' + a2 + ')*(' + t1 + ')+(' + - a2 + ')*(' + c1 + ')-(' + t2 + ')*(' + b1 + ')+(' + t2 + ')*(' + a1 + ')+(' + c2 + ')*(' + - b1 + ')-(' + c2 + ')*(' + a1 + ')', - poly2 = '(' + t2 + ')*(' + a1 + ')-(' + t2 + ')*(' + c1 + ')-(' + b2 + ')*(' + a1 + ')+(' + - b2 + ')*(' + c1 + ')-(' + t1 + ')*(' + a2 + ')+(' + t1 + ')*(' + c2 + ')+(' + b1 + ')*(' + - a2 + ')-(' + b1 + ')*(' + c2 + ')'; + // if (el.elementClass === Const.OBJECT_CLASS_CURVE || + // el.elementClass === Const.OBJECT_CLASS_LINE) { + // if (Type.evaluate(el.visProp.firstarrow)) { + // this._setArrowWidth(el.rendNodeTriangleStart, w, el.rendNode); + // } + // + // if (Type.evaluate(el.visProp.lastarrow)) { + // this._setArrowWidth(el.rendNodeTriangleEnd, w, el.rendNode); + // } + // } + } + el.visPropOld.strokewidth = w; + }, - return [poly1, poly2]; - }; + // documented in JXG.AbstractRenderer + setLineCap: function (el) { + var capStyle = Type.evaluate(el.visProp.linecap); - return p; - }; + if (capStyle === undefined || capStyle === '' || el.visPropOld.linecap === capStyle || + !Type.exists(el.rendNode)) { + return; + } - /** - * @class A parallel is a line through a given point with the same slope as a given line. - * @pseudo - * @name Parallel - * @augments Line - * @constructor - * @type JXG.Line - * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {JXG.Line_JXG.Point} l,p The constructed line contains p and has the same slope as l. - * @example - * // Create a parallel - * var p1 = board.create('point', [0.0, 2.0]); - * var p2 = board.create('point', [2.0, 1.0]); - * var l1 = board.create('line', [p1, p2]); - * - * var p3 = board.create('point', [3.0, 3.0]); - * var pl1 = board.create('parallel', [l1, p3]); - * </pre><div class="jxgbox" id="JXG24e54f9e-5c4e-4afb-9228-0ef27a59d627" style="width: 400px; height: 400px;"></div> - * <script type="text/javascript"> - * var plex1_board = JXG.JSXGraph.initBoard('JXG24e54f9e-5c4e-4afb-9228-0ef27a59d627', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); - * var plex1_p1 = plex1_board.create('point', [0.0, 2.0]); - * var plex1_p2 = plex1_board.create('point', [2.0, 1.0]); - * var plex1_l1 = plex1_board.create('line', [plex1_p1, plex1_p2]); - * var plex1_p3 = plex1_board.create('point', [3.0, 3.0]); - * var plex1_pl1 = plex1_board.create('parallel', [plex1_l1, plex1_p3]); - * </script><pre> - */ - JXG.createParallel = function (board, parents, attributes) { - var p, pp, pl, li, i, attr; + this.setPropertyPrim(el.rendNode, 'stroke-linecap', capStyle); + el.visPropOld.linecap = capStyle; - for (i = 0; i < parents.length; ++i) { - parents[i] = board.select(parents[i]); - } - p = null; - if (parents.length === 3) { - parents = Type.providePoints(board, parents, attributes, 'point'); - // line through point parents[2] which is parallel to line through parents[0] and parents[1] - p = parents[2]; - /** @ignore */ - li = function () { - return Mat.crossProduct(parents[0].coords.usrCoords, parents[1].coords.usrCoords); - }; - } else if (Type.isPointType(board, parents[0])) { - // Parallel to line parents[1] through point parents[0] - p = Type.providePoints(board, [parents[0]], attributes, 'point')[0]; - /** @ignore */ - li = function () { - return parents[1].stdform; - }; - } else if (Type.isPointType(board, parents[1])) { - // Parallel to line parents[0] through point parents[1] - p = Type.providePoints(board, [parents[1]], attributes, 'point')[0]; - /** @ignore */ - li = function () { - return parents[0].stdform; - }; - } + }, - if (!Type.exists(attributes.layer)) { - attributes.layer = board.options.layer.line; - } + // documented in JXG.AbstractRenderer + setShadow: function (el) { + var ev_s = Type.evaluate(el.visProp.shadow); + if (el.visPropOld.shadow === ev_s) { + return; + } - attr = Type.copyAttributes(attributes, board.options, 'parallel', 'point'); - pp = board.create('point', [ - function () { - return Mat.crossProduct([1, 0, 0], li()); + if (Type.exists(el.rendNode)) { + if (ev_s) { + el.rendNode.setAttributeNS(null, 'filter', 'url(#' + this.container.id + '_' + 'f1)'); + } else { + el.rendNode.removeAttributeNS(null, 'filter'); + } } - ], attr); - pp.isDraggable = true; + el.visPropOld.shadow = ev_s; + }, - attr = Type.copyAttributes(attributes, board.options, 'parallel'); - pl = board.create('line', [p, pp], attr); + /* ************************** + * renderer control + * **************************/ - pl.elType = 'parallel'; - pl.subs = { - point: pp - }; - pl.inherits.push(pp); - pl.setParents([parents[0].id, parents[1].id]); - if (parents.length === 3) { - pl.addParents(parents[2].id); - } + // documented in JXG.AbstractRenderer + suspendRedraw: function () { + // It seems to be important for the Linux version of firefox + //this.suspendHandle = this.svgRoot.suspendRedraw(10000); + }, - /** - * Helper point used to create the parallel line. This point lies on the line at infinity, hence it's not visible, - * not even with visible set to <tt>true</tt>. Creating another line through this point would make that other line - * parallel to the create parallel. - * @memberOf Parallel.prototype - * @name point - * @type JXG.Point - */ - pl.point = pp; + // documented in JXG.AbstractRenderer + unsuspendRedraw: function () { + //this.svgRoot.unsuspendRedraw(this.suspendHandle); + //this.svgRoot.unsuspendRedrawAll(); + //this.svgRoot.forceRedraw(); + }, - return pl; - }; + // documented in AbstractRenderer + resize: function (w, h) { + // this.svgRoot.style.width = parseFloat(w) + 'px'; + // this.svgRoot.style.height = parseFloat(h) + 'px'; - /** - * @class An arrow parallel is a parallel segment with an arrow attached. - * @pseudo - * @constructor - * @name Arrowparallel - * @type Parallel - * @augments Parallel - * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {JXG.Line_JXG.Point} l,p The constructed arrow contains p and has the same slope as l. - * @example - * // Create a parallel - * var p1 = board.create('point', [0.0, 2.0]); - * var p2 = board.create('point', [2.0, 1.0]); - * var l1 = board.create('line', [p1, p2]); - * - * var p3 = board.create('point', [3.0, 3.0]); - * var pl1 = board.create('arrowparallel', [l1, p3]); - * </pre><div class="jxgbox" id="JXGeeacdf99-036f-4e83-aeb6-f7388423e369" style="width: 400px; height: 400px;"></div> - * <script type="text/javascript"> - * (function () { - * var plex1_board = JXG.JSXGraph.initBoard('JXGeeacdf99-036f-4e83-aeb6-f7388423e369', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); - * var plex1_p1 = plex1_board.create('point', [0.0, 2.0]); - * var plex1_p2 = plex1_board.create('point', [2.0, 1.0]); - * var plex1_l1 = plex1_board.create('line', [plex1_p1, plex1_p2]); - * var plex1_p3 = plex1_board.create('point', [3.0, 3.0]); - * var plex1_pl1 = plex1_board.create('arrowparallel', [plex1_l1, plex1_p3]); - * })(); - * </script><pre> - */ - JXG.createArrowParallel = function (board, parents, attributes) { - var p; + this.svgRoot.setAttribute('width', parseFloat(w)); + this.svgRoot.setAttribute('height', parseFloat(h)); + // this.svgRoot.setAttribute('width', '100%'); + // this.svgRoot.setAttribute('height', '100%'); + }, - /* parallel arrow point polynomials are done in createParallelPoint */ - try { - attributes.firstArrow = false; - attributes.lastArrow = true; - p = JXG.createParallel(board, parents, attributes).setAttribute({straightFirst: false, straightLast: false}); - p.elType = 'arrowparallel'; + // documented in JXG.AbstractRenderer + createTouchpoints: function (n) { + var i, na1, na2, node; + this.touchpoints = []; + for (i = 0; i < n; i++) { + na1 = 'touchpoint1_' + i; + node = this.createPrim('path', na1); + this.appendChildPrim(node, 19); + node.setAttributeNS(null, 'd', 'M 0 0'); + this.touchpoints.push(node); - // parents are set in createParallel + this.setPropertyPrim(node, 'stroked', 'true'); + this.setPropertyPrim(node, 'stroke-width', '1px'); + node.setAttributeNS(null, 'stroke', '#000000'); + node.setAttributeNS(null, 'stroke-opacity', 1.0); + node.setAttributeNS(null, 'display', 'none'); - return p; - } catch (e) { - throw new Error("JSXGraph: Can't create arrowparallel with parent types '" + - (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + - "\nPossible parent types: [line,point], [point,point,point]"); - } - }; + na2 = 'touchpoint2_' + i; + node = this.createPrim('ellipse', na2); + this.appendChildPrim(node, 19); + this.updateEllipsePrim(node, 0, 0, 0, 0); + this.touchpoints.push(node); - /** - * @class Constructs a normal. - * @pseudo - * @description A normal is a line through a given point on a element of type line, circle, curve, or turtle and orthogonal to that object. - * @constructor - * @name Normal - * @type JXG.Line - * @augments JXG.Line - * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {JXG.Line,JXG.Circle,JXG.Curve,JXG.Turtle_JXG.Point} o,p The constructed line contains p which lies on the object and is orthogonal - * to the tangent to the object in the given point. - * @param {Glider} p Works like above, however the object is given by {@link JXG.CoordsElement#slideObject}. - * @example - * // Create a normal to a circle. - * var p1 = board.create('point', [2.0, 2.0]); - * var p2 = board.create('point', [3.0, 2.0]); - * var c1 = board.create('circle', [p1, p2]); - * - * var norm1 = board.create('normal', [c1, p2]); - * </pre><div class="jxgbox" id="JXG4154753d-3d29-40fb-a860-0b08aa4f3743" style="width: 400px; height: 400px;"></div> - * <script type="text/javascript"> - * var nlex1_board = JXG.JSXGraph.initBoard('JXG4154753d-3d29-40fb-a860-0b08aa4f3743', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); - * var nlex1_p1 = nlex1_board.create('point', [2.0, 2.0]); - * var nlex1_p2 = nlex1_board.create('point', [3.0, 2.0]); - * var nlex1_c1 = nlex1_board.create('circle', [nlex1_p1, nlex1_p2]); - * - * // var nlex1_p3 = nlex1_board.create('point', [1.0, 2.0]); - * var nlex1_norm1 = nlex1_board.create('normal', [nlex1_c1, nlex1_p2]); - * </script><pre> - */ - JXG.createNormal = function (board, parents, attributes) { - var p, c, l, i, g, f, attr, pp, attrp; + this.setPropertyPrim(node, 'stroked', 'true'); + this.setPropertyPrim(node, 'stroke-width', '1px'); + node.setAttributeNS(null, 'stroke', '#000000'); + node.setAttributeNS(null, 'stroke-opacity', 1.0); + node.setAttributeNS(null, 'fill', '#ffffff'); + node.setAttributeNS(null, 'fill-opacity', 0.0); - for (i = 0; i < parents.length; ++i) { - parents[i] = board.select(parents[i]); - } - // One arguments: glider on line, circle or curve - if (parents.length === 1) { - p = parents[0]; - c = p.slideObject; - // Two arguments: (point,line), (point,circle), (line,point) or (circle,point) - } else if (parents.length === 2) { - if (Type.isPointType(board, parents[0])) { - p = Type.providePoints(board, [parents[0]], attributes, 'point')[0]; - c = parents[1]; - } else if (Type.isPointType(board, parents[1])) { - c = parents[0]; - p = Type.providePoints(board, [parents[1]], attributes, 'point')[0]; - } else { - throw new Error("JSXGraph: Can't create normal with parent types '" + - (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + - "\nPossible parent types: [point,line], [point,circle], [glider]"); + node.setAttributeNS(null, 'display', 'none'); } - } else { - throw new Error("JSXGraph: Can't create normal with parent types '" + - (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + - "\nPossible parent types: [point,line], [point,circle], [glider]"); - } - - attr = Type.copyAttributes(attributes, board.options, 'normal'); - if (c.elementClass === Const.OBJECT_CLASS_LINE) { - // Private point - attrp = Type.copyAttributes(attributes, board.options, 'normal', 'point'); - pp = board.create('point', [ - function () { - var p = Mat.crossProduct([1, 0, 0], c.stdform); - return [p[0], -p[2], p[1]]; - } - ], attrp); - pp.isDraggable = true; - - l = board.create('line', [p, pp], attr); - - /** - * A helper point used to create a normal to a {@link JXG.Line} object. For normals to circles or curves this - * element is <tt>undefined</tt>. - * @type JXG.Point - * @name point - * @memberOf Normal.prototype - */ - l.point = pp; - l.subs = { - point: pp - }; - l.inherits.push(pp); - } else if (c.elementClass === Const.OBJECT_CLASS_CIRCLE) { - l = board.create('line', [c.midpoint, p], attr); - } else if (c.elementClass === Const.OBJECT_CLASS_CURVE) { - if (Type.evaluate(c.visProp.curvetype) !== 'plot') { - g = c.X; - f = c.Y; - l = board.create('line', [ - function () { - return -p.X() * Numerics.D(g)(p.position) - p.Y() * Numerics.D(f)(p.position); - }, - function () { - return Numerics.D(g)(p.position); - }, - function () { - return Numerics.D(f)(p.position); - } - ], attr); - } else { // curveType 'plot' - l = board.create('line', [ - function () { - var i = Math.floor(p.position), - lbda = p.position - i; - - if (i === c.numberPoints - 1) { - i -= 1; - lbda = 1; - } - - if (i < 0) { - return 1; - } - - return (c.Y(i) + lbda * (c.Y(i + 1) - c.Y(i))) * (c.Y(i) - c.Y(i + 1)) - (c.X(i) + lbda * (c.X(i + 1) - c.X(i))) * (c.X(i + 1) - c.X(i)); - }, - function () { - var i = Math.floor(p.position); + }, - if (i === c.numberPoints - 1) { - i -= 1; - } + // documented in JXG.AbstractRenderer + showTouchpoint: function (i) { + if (this.touchpoints && i >= 0 && 2 * i < this.touchpoints.length) { + this.touchpoints[2 * i].setAttributeNS(null, 'display', 'inline'); + this.touchpoints[2 * i + 1].setAttributeNS(null, 'display', 'inline'); + } + }, - if (i < 0) { - return 0; - } + // documented in JXG.AbstractRenderer + hideTouchpoint: function (i) { + if (this.touchpoints && i >= 0 && 2 * i < this.touchpoints.length) { + this.touchpoints[2 * i].setAttributeNS(null, 'display', 'none'); + this.touchpoints[2 * i + 1].setAttributeNS(null, 'display', 'none'); + } + }, - return c.X(i + 1) - c.X(i); - }, - function () { - var i = Math.floor(p.position); + // documented in JXG.AbstractRenderer + updateTouchpoint: function (i, pos) { + var x, y, + d = 37; - if (i === c.numberPoints - 1) { - i -= 1; - } + if (this.touchpoints && i >= 0 && 2 * i < this.touchpoints.length) { + x = pos[0]; + y = pos[1]; - if (i < 0) { - return 0; - } + this.touchpoints[2 * i].setAttributeNS(null, 'd', 'M ' + (x - d) + ' ' + y + ' ' + + 'L ' + (x + d) + ' ' + y + ' ' + + 'M ' + x + ' ' + (y - d) + ' ' + + 'L ' + x + ' ' + (y + d)); + this.updateEllipsePrim(this.touchpoints[2 * i + 1], pos[0], pos[1], 25, 25); + } + }, - return c.Y(i + 1) - c.Y(i); + /** + * Walk recursively through the DOM subtree of a node and collect all + * value attributes together with the id of that node. + * <b>Attention:</b> Only values of nodes having a valid id are taken. + * @param {Node} node root node of DOM subtree that will be searched recursively. + * @return {Array} Array with entries of the form [id, value] + * @private + */ + _getValuesOfDOMElements: function (node) { + var values = []; + if (node.nodeType === 1) { + node = node.firstChild; + while (node) { + if (node.id !== undefined && node.value !== undefined) { + values.push([node.id, node.value]); } - ], attr); + values = values.concat(this._getValuesOfDOMElements(node)); + node = node.nextSibling; + } } - } else if (c.type === Const.OBJECT_TYPE_TURTLE) { - l = board.create('line', [ - function () { - var el, j, - i = Math.floor(p.position), - lbda = p.position - i; - - // run through all curves of this turtle - for (j = 0; j < c.objects.length; j++) { - el = c.objects[j]; + return values; + }, - if (el.type === Const.OBJECT_TYPE_CURVE) { - if (i < el.numberPoints) { - break; - } + _getDataUri: function (url, callback) { + var image = new Image(); - i -= el.numberPoints; - } - } + image.onload = function () { + var canvas = document.createElement('canvas'); + canvas.width = this.naturalWidth; // or 'width' if you want a special/scaled size + canvas.height = this.naturalHeight; // or 'height' if you want a special/scaled size - if (i === el.numberPoints - 1) { - i -= 1; - lbda = 1; - } + canvas.getContext('2d').drawImage(this, 0, 0); - if (i < 0) { - return 1; - } + callback(canvas.toDataURL('image/png')); + canvas.remove(); + }; - return (el.Y(i) + lbda * (el.Y(i + 1) - el.Y(i))) * (el.Y(i) - el.Y(i + 1)) - (el.X(i) + lbda * (el.X(i + 1) - el.X(i))) * (el.X(i + 1) - el.X(i)); - }, - function () { - var el, j, - i = Math.floor(p.position); + image.src = url; + }, - // run through all curves of this turtle - for (j = 0; j < c.objects.length; j++) { - el = c.objects[j]; - if (el.type === Const.OBJECT_TYPE_CURVE) { - if (i < el.numberPoints) { - break; - } + _getImgDataURL: function(svgRoot) { + var images, len, canvas, ctx, + ur, i; - i -= el.numberPoints; - } - } + images = svgRoot.getElementsByTagName("image"); + len = images.length; + if (len > 0) { + canvas = document.createElement('canvas'); + //img = new Image(); + for (i = 0; i < len; i++) { + images[i].setAttribute("crossorigin", "anonymous"); + //img.src = images[i].href; + //img.onload = function() { + // img.crossOrigin = "anonymous"; + ctx = canvas.getContext('2d'); + canvas.width = images[i].getAttribute("width"); + canvas.height = images[i].getAttribute("height"); + try { + ctx.drawImage(images[i], 0, 0, canvas.width, canvas.height); - if (i === el.numberPoints - 1) { - i -= 1; + // If the image is not png, the format must be specified here + ur = canvas.toDataURL(); + images[i].setAttribute("xlink:href", ur); + } catch (err) { + console.log("CORS problem! Image can not be used", err); } + } + //canvas.remove(); + } + return true; + }, - if (i < 0) { - return 0; - } + /** + * Return a data URI of the SVG code representeing the construction. + * The SVG code of the construction is base64 encoded. The return string starts + * with "data:image/svg+xml;base64,...". + * + * @param {Boolean} ignoreTexts If true, the foreignObject tag is set to display=none. + * This is necessary for older versions of Safari. Default: false + * @returns {String} data URI string + */ + dumpToDataURI: function (ignoreTexts) { + var svgRoot = this.svgRoot, + btoa = window.btoa || Base64.encode, + svg, + virtualNode, doc, + i, len, + values = []; - return el.X(i + 1) - el.X(i); - }, - function () { - var el, j, - i = Math.floor(p.position); + // Move all HTML tags (beside the SVG root) of the container + // to the foreignObject element inside of the svgRoot node + // Problem: + // input values are not copied. This can be verified by looking at an innerHTML output + // of an input element. Therefore, we do it "by hand". + if (this.container.hasChildNodes() && Type.exists(this.foreignObjLayer)) { + if (!ignoreTexts) { + this.foreignObjLayer.setAttribute('display', 'inline'); + } + while (svgRoot.nextSibling) { - // run through all curves of this turtle - for (j = 0; j < c.objects.length; j++) { - el = c.objects[j]; - if (el.type === Const.OBJECT_TYPE_CURVE) { - if (i < el.numberPoints) { - break; - } + // Copy all value attributes + values = values.concat(this._getValuesOfDOMElements(svgRoot.nextSibling)); - i -= el.numberPoints; - } - } + this.foreignObjLayer.appendChild(svgRoot.nextSibling); + } + } - if (i === el.numberPoints - 1) { - i -= 1; - } + this._getImgDataURL(svgRoot); - if (i < 0) { - return 0; - } + // Convert the SVG graphic into a string containing SVG code + svgRoot.setAttribute("xmlns", "http://www.w3.org/2000/svg"); + svg = new XMLSerializer().serializeToString(svgRoot); - return el.Y(i + 1) - el.Y(i); + if (ignoreTexts !== true) { + // Handle SVG texts + // Insert all value attributes back into the svg string + len = values.length; + for (i = 0; i < len; i++) { + svg = svg.replace('id="' + values[i][0] + '"', 'id="' + values[i][0] + '" value="' + values[i][1] + '"'); } - ], attr); - } else { - throw new Error("JSXGraph: Can't create normal with parent types '" + - (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + - "\nPossible parent types: [point,line], [point,circle], [glider]"); - } - - l.elType = 'normal'; - l.setParents(parents); + } - return l; - }; + // if (false) { + // // Debug: use example svg image + // svg = '<svg xmlns="http://www.w3.org/2000/svg" version="1.0" width="220" height="220"><rect width="66" height="30" x="21" y="32" stroke="#204a87" stroke-width="2" fill="none" /></svg>'; + // } - /** - * @class A bisector is a line which divides an angle into two equal angles. It is given by three points A, B, and - * C and divides the angle ABC into two equal sized parts. - * @pseudo - * @constructor - * @name Bisector - * @type JXG.Line - * @augments JXG.Line - * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The angle described by <tt>p1</tt>, <tt>p2</tt> and <tt>p3</tt> will - * be divided into two equal angles. - * @example - * var p1 = board.create('point', [6.0, 4.0]); - * var p2 = board.create('point', [3.0, 2.0]); - * var p3 = board.create('point', [1.0, 7.0]); - * - * var bi1 = board.create('bisector', [p1, p2, p3]); - * </pre><div class="jxgbox" id="JXG0d58cea8-b06a-407c-b27c-0908f508f5a4" style="width: 400px; height: 400px;"></div> - * <script type="text/javascript"> - * (function () { - * var board = JXG.JSXGraph.initBoard('JXG0d58cea8-b06a-407c-b27c-0908f508f5a4', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); - * var p1 = board.create('point', [6.0, 4.0]); - * var p2 = board.create('point', [3.0, 2.0]); - * var p3 = board.create('point', [1.0, 7.0]); - * var bi1 = board.create('bisector', [p1, p2, p3]); - * })(); - * </script><pre> - */ - JXG.createBisector = function (board, parents, attributes) { - var p, l, i, attr; + // In IE we have to remove the namespace again. + if ((svg.match(/xmlns="http:\/\/www.w3.org\/2000\/svg"/g) || []).length > 1) { + svg = svg.replace(/xmlns="http:\/\/www.w3.org\/2000\/svg"/g, ''); + } - parents = Type.providePoints(board, parents, attributes, 'point'); - if (Type.isPoint(parents[0]) && Type.isPoint(parents[1]) && Type.isPoint(parents[2])) { - // hidden and fixed helper - attr = Type.copyAttributes(attributes, board.options, 'bisector', 'point'); - attr.snapToGrid = false; + // Safari fails if the svg string contains a " " + // Obsolete with Safari 12+ + svg = svg.replace(/ /g, ' '); - p = board.create('point', [ - function () { - return Geometry.angleBisector(parents[0], parents[1], parents[2], board); + // Move all HTML tags back from + // the foreignObject element to the container + if (Type.exists(this.foreignObjLayer) && this.foreignObjLayer.hasChildNodes()) { + // Restore all HTML elements + while (this.foreignObjLayer.firstChild) { + this.container.appendChild(this.foreignObjLayer.firstChild); } - ], attr); - p.dump = false; - - for (i = 0; i < 3; i++) { - // required for algorithm requiring dependencies between elements - parents[i].addChild(p); + this.foreignObjLayer.setAttribute("display", "none"); } - if (!Type.exists(attributes.layer)) { - attributes.layer = board.options.layer.line; - } + return 'data:image/svg+xml;base64,' + btoa(unescape(encodeURIComponent(svg))); + }, - attr = Type.copyAttributes(attributes, board.options, 'bisector'); - l = Line.createLine(board, [parents[1], p], attr); + /** + * Convert the SVG construction into an HTML canvas image. + * This works for all SVG supporting browsers. Implemented as Promise. + * <p> + * For IE, it is realized as function. + * It works from version 9, with the exception that HTML texts + * are ignored on IE. The drawing is done with a delay of + * 200 ms. Otherwise there would be problems with IE. + * + * @param {String} canvasId Id of an HTML canvas element + * @param {Number} w Width in pixel of the dumped image, i.e. of the canvas tag. + * @param {Number} h Height in pixel of the dumped image, i.e. of the canvas tag. + * @param {Boolean} ignoreTexts If true, the foreignObject tag is taken out from the SVG root. + * This is necessary for older versions of Safari. Default: false + * @returns {Promise} Promise object + * + * @example + * board.renderer.dumpToCanvas('canvas').then(function() { console.log('done'); }); + * + * @example + * // IE 11 example: + * board.renderer.dumpToCanvas('canvas'); + * setTimeout(function() { console.log('done'); }, 400); + */ + dumpToCanvas: function (canvasId, w, h, ignoreTexts) { + var svg, tmpImg, cv, ctx, + doc = this.container.ownerDocument; - /** - * Helper point - * @memberOf Bisector.prototype - * @type Point - * @name point - */ - l.point = p; + // Prepare the canvas element + cv = doc.getElementById(canvasId); - l.elType = 'bisector'; - l.setParents(parents); - l.subs = { - point: p - }; - l.inherits.push(p); + // Clear the canvas + /* eslint-disable no-self-assign */ + cv.width = cv.width; + /* eslint-enable no-self-assign */ - return l; - } + ctx = cv.getContext("2d"); + if (w !== undefined && h !== undefined) { + cv.style.width = parseFloat(w) + 'px'; + cv.style.height = parseFloat(h) + 'px'; + // Scale twice the CSS size to make the image crisp + // cv.setAttribute('width', 2 * parseFloat(wOrg)); + // cv.setAttribute('height', 2 * parseFloat(hOrg)); + // ctx.scale(2 * wOrg / w, 2 * hOrg / h); + cv.setAttribute('width', parseFloat(w)); + cv.setAttribute('height', parseFloat(h)); + } - throw new Error("JSXGraph: Can't create angle bisector with parent types '" + - (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + - "\nPossible parent types: [point,point,point]"); - }; + // Display the SVG string as data-uri in an HTML img. + tmpImg = new Image(); + svg = this.dumpToDataURI(ignoreTexts); + tmpImg.src = svg; - /** - * @class Bisector lines are similar to {@link Bisector} but takes two lines as parent elements. The resulting element is - * a composition of two lines. - * @pseudo - * @constructor - * @name Bisectorlines - * @type JXG.Composition - * @augments JXG.Composition - * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {JXG.Line_JXG.Line} l1,l2 The four angles described by the lines <tt>l1</tt> and <tt>l2</tt> will each - * be divided into two equal angles. - * @example - * var p1 = board.create('point', [6.0, 4.0]); - * var p2 = board.create('point', [3.0, 2.0]); - * var p3 = board.create('point', [1.0, 7.0]); - * var p4 = board.create('point', [3.0, 0.0]); - * var l1 = board.create('line', [p1, p2]); - * var l2 = board.create('line', [p3, p4]); - * - * var bi1 = board.create('bisectorlines', [l1, l2]); - * </pre><div class="jxgbox" id="JXG3121ff67-44f0-4dda-bb10-9cda0b80bf18" style="width: 400px; height: 400px;"></div> - * <script type="text/javascript"> - * (function () { - * var board = JXG.JSXGraph.initBoard('JXG3121ff67-44f0-4dda-bb10-9cda0b80bf18', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); - * var p1 = board.create('point', [6.0, 4.0]); - * var p2 = board.create('point', [3.0, 2.0]); - * var p3 = board.create('point', [1.0, 7.0]); - * var p4 = board.create('point', [3.0, 0.0]); - * var l1 = board.create('line', [p1, p2]); - * var l2 = board.create('line', [p3, p4]); - * var bi1 = board.create('bisectorlines', [l1, l2]); - * })(); - * </script><pre> - */ - JXG.createAngularBisectorsOfTwoLines = function (board, parents, attributes) { - // The angular bisectors of two line [c1,a1,b1] and [c2,a2,b2] are determined by the equation: - // (a1*x+b1*y+c1*z)/sqrt(a1^2+b1^2) = +/- (a2*x+b2*y+c2*z)/sqrt(a2^2+b2^2) + // Finally, draw the HTML img in the canvas. + if (!('Promise' in window)) { + tmpImg.onload = function () { + // IE needs a pause... + // Seems to be broken + window.setTimeout(function() { + try { + ctx.drawImage(tmpImg, 0, 0, w, h); + } catch (err) { + console.log("screenshots not longer supported on IE"); + } + }, 200); + }; + return this; + } - var g1, g2, attr, ret, - l1 = board.select(parents[0]), - l2 = board.select(parents[1]); + return new Promise(function(resolve, reject) { + try { + tmpImg.onload = function () { + ctx.drawImage(tmpImg, 0, 0, w, h); + resolve(); + }; + } catch (e) { + reject(e); + } + }); - if (l1.elementClass !== Const.OBJECT_CLASS_LINE || l2.elementClass !== Const.OBJECT_CLASS_LINE) { - throw new Error("JSXGraph: Can't create angle bisectors of two lines with parent types '" + - (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + - "\nPossible parent types: [line,line]"); - } + }, - if (!Type.exists(attributes.layer)) { - attributes.layer = board.options.layer.line; - } - - attr = Type.copyAttributes(attributes, board.options, 'bisectorlines', 'line1'); - g1 = board.create('line', [ - function () { - var d1 = Math.sqrt(l1.stdform[1] * l1.stdform[1] + l1.stdform[2] * l1.stdform[2]), - d2 = Math.sqrt(l2.stdform[1] * l2.stdform[1] + l2.stdform[2] * l2.stdform[2]); - - return l1.stdform[0] / d1 - l2.stdform[0] / d2; - }, - function () { - var d1 = Math.sqrt(l1.stdform[1] * l1.stdform[1] + l1.stdform[2] * l1.stdform[2]), - d2 = Math.sqrt(l2.stdform[1] * l2.stdform[1] + l2.stdform[2] * l2.stdform[2]); - - return l1.stdform[1] / d1 - l2.stdform[1] / d2; - }, - function () { - var d1 = Math.sqrt(l1.stdform[1] * l1.stdform[1] + l1.stdform[2] * l1.stdform[2]), - d2 = Math.sqrt(l2.stdform[1] * l2.stdform[1] + l2.stdform[2] * l2.stdform[2]); + /** + * Display SVG image in html img-tag which enables + * easy download for the user. + * + * Support: + * <ul> + * <li> IE: No + * <li> Edge: full + * <li>Firefox: full + * <li> Chrome: full + * <li> Safari: full (No text support in versions prior to 12). + * </ul> + * + * @param {JXG.Board} board Link to the board. + * @param {String} imgId Optional id of an img object. If given and different from the empty string, + * the screenshot is copied to this img object. The width and height will be set to the values of the + * JSXGraph container. + * @param {Boolean} ignoreTexts If set to true, the foreignObject is taken out of the + * SVGRoot and texts are not displayed. This is mandatory for Safari. Default: false + * @return {Object} the svg renderer object + */ + screenshot: function (board, imgId, ignoreTexts) { + var node, + doc = this.container.ownerDocument, + parent = this.container.parentNode, + cPos, + canvas, id, + img, + button, buttonText, + w, h, + bas = board.attr.screenshot, + zbar, zbarDisplay, cssTxt, + newImg = false, + _copyCanvasToImg, + isDebug = false; - return l1.stdform[2] / d1 - l2.stdform[2] / d2; + if (this.type === 'no') { + return this; } - ], attr); - - if (!Type.exists(attributes.layer)) { - attributes.layer = board.options.layer.line; - } - attr = Type.copyAttributes(attributes, board.options, 'bisectorlines', 'line2'); - g2 = board.create('line', [ - function () { - var d1 = Math.sqrt(l1.stdform[1] * l1.stdform[1] + l1.stdform[2] * l1.stdform[2]), - d2 = Math.sqrt(l2.stdform[1] * l2.stdform[1] + l2.stdform[2] * l2.stdform[2]); - - return l1.stdform[0] / d1 + l2.stdform[0] / d2; - }, - function () { - var d1 = Math.sqrt(l1.stdform[1] * l1.stdform[1] + l1.stdform[2] * l1.stdform[2]), - d2 = Math.sqrt(l2.stdform[1] * l2.stdform[1] + l2.stdform[2] * l2.stdform[2]); - return l1.stdform[1] / d1 + l2.stdform[1] / d2; - }, - function () { - var d1 = Math.sqrt(l1.stdform[1] * l1.stdform[1] + l1.stdform[2] * l1.stdform[2]), - d2 = Math.sqrt(l2.stdform[1] * l2.stdform[1] + l2.stdform[2] * l2.stdform[2]); + w = bas.scale * this.container.getBoundingClientRect().width; + h = bas.scale * this.container.getBoundingClientRect().height; - return l1.stdform[2] / d1 + l2.stdform[2] / d2; + if (imgId === undefined || imgId === '') { + newImg = true; + img = new Image(); //doc.createElement('img'); + img.style.width = w + 'px'; + img.style.height = h + 'px'; + } else { + newImg = false; + img = doc.getElementById(imgId); } - ], attr); - - // documentation - /** - * First line. - * @memberOf Bisectorlines.prototype - * @name line1 - * @type Line - */ + // img.crossOrigin = 'anonymous'; - /** - * Second line. - * @memberOf Bisectorlines.prototype - * @name line2 - * @type Line - */ + // Create div which contains canvas element and close button + if (newImg) { + node = doc.createElement('div'); + node.style.cssText = bas.css; + node.style.width = (w) + 'px'; + node.style.height = (h) + 'px'; + node.style.zIndex = this.container.style.zIndex + 120; - ret = new Composition({line1: g1, line2: g2}); + // Try to position the div exactly over the JSXGraph board + node.style.position = 'absolute'; + node.style.top = this.container.offsetTop + 'px'; + node.style.left = this.container.offsetLeft + 'px'; + } - g1.dump = false; - g2.dump = false; + if (!isDebug) { + // Create canvas element and add it to the DOM + // It will be removed after the image has been stored. + canvas = doc.createElement('canvas'); + id = Math.random().toString(36).substr(2, 5); + canvas.setAttribute('id', id); + canvas.setAttribute('width', w); + canvas.setAttribute('height', h); + canvas.style.width = w + 'px'; + canvas.style.height = w + 'px'; + canvas.style.display = 'none'; + parent.appendChild(canvas); + } else { + // Debug: use canvas element 'jxgbox_canvas' from jsxdev/dump.html + id = 'jxgbox_canvas'; + // canvas = document.getElementById(id); + canvas = doc.getElementById(id); + } - ret.elType = 'bisectorlines'; - ret.setParents([l1.id, l2.id]); - ret.subs = { - line1: g1, - line2: g2 - }; - // ret.inherits.push(g1, g2); + if (newImg) { + // Create close button + button = doc.createElement('span'); + buttonText = doc.createTextNode('\u2716'); + button.style.cssText = bas.cssButton; + button.appendChild(buttonText); + button.onclick = function () { + node.parentNode.removeChild(node); + }; - return ret; - }; + // Add all nodes + node.appendChild(img); + node.appendChild(button); + parent.insertBefore(node, this.container.nextSibling); + } - // /** - // * @class An m-sector is a line which divides an angle into two angles. It is given by three points A, B, and - // * C and a real number m, and divides an angle into two angles, an angle with amplitude m and an angle with - // * amplitude (1-m) - // * @pseudo - // * @constructor - // * @name Msector - // * @type JXG.Line - // * @augments JXG.Line - // * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. - // * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The angle described by <tt>p1</tt>, <tt>p2</tt> and <tt>p3</tt> will - // * be divided into two angles according to the value of <tt>m</tt>. - // * @example - // * var p1 = board.create('point', [6.0, 4.0]); - // * var p2 = board.create('point', [3.0, 2.0]); - // * var p3 = board.create('point', [1.0, 7.0]); - // * - // * var bi1 = board.create('msector', [p1, p2, p3], 1/5); - // * </pre><div id="JXG0d58cea8-b06a-407c-b27c-0908f508f5a4" style="width: 400px; height: 400px;"></div> - // * <script type="text/javascript"> - // * (function () { - // * var board = JXG.JSXGraph.initBoard('JXG0d58cea8-b06a-407c-b27c-0908f508f5a4', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); - // * var p1 = board.create('point', [6.0, 4.0]); - // * var p2 = board.create('point', [3.0, 2.0]); - // * var p3 = board.create('point', [1.0, 7.0]); - // * var bi1 = board.create('msector', [p1, p2, p3], 1/5); - // * })(); - // * </script><pre> - // */ - // JXG.createMsector = function (board, parents, attributes) { - // var p, l, i, attr; + // Hide navigation bar in board + // zbar = document.getElementById(this.container.id + '_navigationbar'); + zbar = doc.getElementById(this.container.id + '_navigationbar'); + if (Type.exists(zbar)) { + zbarDisplay = zbar.style.display; + zbar.style.display = 'none'; + } - // if (parents[0].elementClass === Const.OBJECT_CLASS_POINT && - // parents[1].elementClass === Const.OBJECT_CLASS_POINT && - // parents[2].elementClass === Const.OBJECT_CLASS_POINT) { - // // hidden and fixed helper - // attr = Type.copyAttributes(attributes, board.options, 'msector', 'point'); - // p = board.create('point', [ - // function () { - // return Geometry.angleMsector(parents[0], parents[1], parents[2], parents[3], board); - // } - // ], attr); - // p.dump = false; + _copyCanvasToImg = function() { + // Show image in img tag + img.src = canvas.toDataURL('image/png'); - // for (i = 0; i < 3; i++) { - // // required for algorithm requiring dependencies between elements - // parents[i].addChild(p); - // } + // Remove canvas node + if (!isDebug) { + parent.removeChild(canvas); + } + }; - // if (!Type.exists(attributes.layer)) { - // attributes.layer = board.options.layer.line; - // } + // Create screenshot in image element + if ('Promise' in window) { + this.dumpToCanvas(id, w, h, ignoreTexts).then(_copyCanvasToImg); + } else { + // IE + this.dumpToCanvas(id, w, h, ignoreTexts); + window.setTimeout(_copyCanvasToImg, 200); + } - // attr = Type.copyAttributes(attributes, board.options, 'msector'); - // l = Line.createLine(board, [parents[1], p], attr); + // Show navigation bar in board + if (Type.exists(zbar)) { + zbar.style.display = zbarDisplay; + } - // /** - // * Helper point - // * @memberOf Msector.prototype - // * @type Point - // * @name point - // */ - // l.point = p; + return this; + } - // l.elType = 'msector'; - // l.parents = [parents[0].id, parents[1].id, parents[2].id]; - // l.subs = { - // point: p - // }; - // l.inherits.push(p); + }); - // return l; - // } + return JXG.SVGRenderer; +}); - // throw new Error("JSXGraph: Can't create angle msector with parent types '" + - // (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + - // "\nPossible parent types: [point,point,point,Number]"); - // }; +/* + Copyright 2008-2022 + Matthias Ehmann, + Michael Gerhaeuser, + Carsten Miller, + Bianca Valentin, + Alfred Wassermann, + Peter Wilfahrt - /** - * @class Constructs the midpoint of a {@link Circumcircle}. Like the circumcircle the circumcenter - * is constructed by providing three points. - * @pseudo - * @description A circumcenter is given by three points which are all lying on the circle with the - * constructed circumcenter as the midpoint. - * @constructor - * @name Circumcenter - * @type JXG.Point - * @augments JXG.Point - * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The constructed point is the midpoint of the circle determined - * by p1, p2, and p3. - * @example - * var p1 = board.create('point', [0.0, 2.0]); - * var p2 = board.create('point', [2.0, 1.0]); - * var p3 = board.create('point', [3.0, 3.0]); - * - * var cc1 = board.create('circumcenter', [p1, p2, p3]); - * </pre><div class="jxgbox" id="JXGe8a40f95-bf30-4eb4-88a8-f4d5495261fd" style="width: 400px; height: 400px;"></div> - * <script type="text/javascript"> - * var ccmex1_board = JXG.JSXGraph.initBoard('JXGe8a40f95-bf30-4eb4-88a8-f4d5495261fd', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); - * var ccmex1_p1 = ccmex1_board.create('point', [0.0, 2.0]); - * var ccmex1_p2 = ccmex1_board.create('point', [6.0, 1.0]); - * var ccmex1_p3 = ccmex1_board.create('point', [3.0, 7.0]); - * var ccmex1_cc1 = ccmex1_board.create('circumcenter', [ccmex1_p1, ccmex1_p2, ccmex1_p3]); - * </script><pre> - */ - JXG.createCircumcenter = function (board, parents, attributes) { - var p, i, a, b, c; + This file is part of JSXGraph. - parents = Type.providePoints(board, parents, attributes, 'point'); - if (Type.isPoint(parents[0]) && Type.isPoint(parents[1]) && Type.isPoint(parents[2])) { + JSXGraph is free software dual licensed under the GNU LGPL or MIT License. - a = parents[0]; - b = parents[1]; - c = parents[2]; + You can redistribute it and/or modify it under the terms of the - p = Point.createPoint(board, [ - function () { - return Geometry.circumcenter(a, b, c, board); - } - ], attributes); + * GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version + OR + * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT - for (i = 0; i < 3; i++) { - parents[i].addChild(p); - } + JSXGraph is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. - p.elType = 'circumcenter'; - p.setParents(parents); + You should have received a copy of the GNU Lesser General Public License and + the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> + and <http://opensource.org/licenses/MIT/>. + */ - p.generatePolynomial = function () { - /* - * CircumcircleMidpoint takes three points A, B and C and creates point M, which is the circumcenter of A, B, and C. - * - * - * So we have two conditions: - * - * (a) CT == AT (distance condition I) - * (b) BT == AT (distance condition II) - * - */ - var a1 = a.symbolic.x, - a2 = a.symbolic.y, - b1 = b.symbolic.x, - b2 = b.symbolic.y, - c1 = c.symbolic.x, - c2 = c.symbolic.y, - t1 = p.symbolic.x, - t2 = p.symbolic.y, - poly1 = ['((', t1, ')-(', a1, '))^2+((', t2, ')-(', a2, '))^2-((', t1, ')-(', b1, '))^2-((', t2, ')-(', b2, '))^2'].join(''), - poly2 = ['((', t1, ')-(', a1, '))^2+((', t2, ')-(', a2, '))^2-((', t1, ')-(', c1, '))^2-((', t2, ')-(', c2, '))^2'].join(''); +/*global JXG: true, define: true, AMprocessNode: true, MathJax: true, document: true */ +/*jslint nomen: true, plusplus: true, newcap:true*/ - return [poly1, poly2]; - }; +/* depends: + jxg + renderer/abstract + base/constants + utils/type + utils/color + math/math + math/numerics +*/ - return p; - } +define('renderer/vml',[ + 'jxg', 'renderer/abstract', 'base/constants', 'utils/type', 'utils/color', 'math/math', 'math/numerics' +], function (JXG, AbstractRenderer, Const, Type, Color, Mat, Numerics) { - throw new Error("JSXGraph: Can't create circumcircle midpoint with parent types '" + - (typeof parents[0]) + "', '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." + - "\nPossible parent types: [point,point,point]"); - }; + "use strict"; /** - * @class Constructs the incenter of the triangle described by the three given points.{@link http://mathworld.wolfram.com/Incenter.html} - * @pseudo - * @constructor - * @name Incenter - * @type JXG.Point - * @augments JXG.Point - * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The constructed point is the incenter of the triangle described - * by p1, p2, and p3. - * @example - * var p1 = board.create('point', [0.0, 2.0]); - * var p2 = board.create('point', [2.0, 1.0]); - * var p3 = board.create('point', [3.0, 3.0]); - * - * var ic1 = board.create('incenter', [p1, p2, p3]); - * </pre><div class="jxgbox" id="JXGe8a40f95-bf30-4eb4-88a8-a2d5495261fd" style="width: 400px; height: 400px;"></div> - * <script type="text/javascript"> - * var icmex1_board = JXG.JSXGraph.initBoard('JXGe8a40f95-bf30-4eb4-88a8-a2d5495261fd', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); - * var icmex1_p1 = icmex1_board.create('point', [0.0, 2.0]); - * var icmex1_p2 = icmex1_board.create('point', [6.0, 1.0]); - * var icmex1_p3 = icmex1_board.create('point', [3.0, 7.0]); - * var icmex1_ic1 = icmex1_board.create('incenter', [icmex1_p1, icmex1_p2, icmex1_p3]); - * </script><pre> + * Uses VML to implement the rendering methods defined in {@link JXG.AbstractRenderer}. + * VML was used in very old Internet Explorer versions upto IE 8. + * + * + * @class JXG.VMLRenderer + * @augments JXG.AbstractRenderer + * @param {Node} container Reference to a DOM node containing the board. + * @see JXG.AbstractRenderer + * @deprecated */ - JXG.createIncenter = function (board, parents, attributes) { - var p, A, B, C; - - parents = Type.providePoints(board, parents, attributes, 'point'); - if (parents.length >= 3 && Type.isPoint(parents[0]) && Type.isPoint(parents[1]) && Type.isPoint(parents[2])) { - A = parents[0]; - B = parents[1]; - C = parents[2]; - - p = board.create('point', [function () { - var a, b, c; - - a = Math.sqrt((B.X() - C.X()) * (B.X() - C.X()) + (B.Y() - C.Y()) * (B.Y() - C.Y())); - b = Math.sqrt((A.X() - C.X()) * (A.X() - C.X()) + (A.Y() - C.Y()) * (A.Y() - C.Y())); - c = Math.sqrt((B.X() - A.X()) * (B.X() - A.X()) + (B.Y() - A.Y()) * (B.Y() - A.Y())); - - return new Coords(Const.COORDS_BY_USER, [(a * A.X() + b * B.X() + c * C.X()) / (a + b + c), (a * A.Y() + b * B.Y() + c * C.Y()) / (a + b + c)], board); - }], attributes); - - p.elType = 'incenter'; - p.setParents(parents); + JXG.VMLRenderer = function (container) { + this.type = 'vml'; - } else { - throw new Error("JSXGraph: Can't create incenter with parent types '" + - (typeof parents[0]) + "', '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." + - "\nPossible parent types: [point,point,point]"); + this.container = container; + this.container.style.overflow = 'hidden'; + if (this.container.style.position === '') { + this.container.style.position = 'relative'; } + this.container.onselectstart = function () { + return false; + }; - return p; - }; - - /** - * @class A circumcircle is given by three points which are all lying on the circle. - * @pseudo - * @constructor - * @name Circumcircle - * @type JXG.Circle - * @augments JXG.Circle - * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The constructed element is the circle determined by <tt>p1</tt>, <tt>p2</tt>, and <tt>p3</tt>. - * @example - * var p1 = board.create('point', [0.0, 2.0]); - * var p2 = board.create('point', [2.0, 1.0]); - * var p3 = board.create('point', [3.0, 3.0]); - * - * var cc1 = board.create('circumcircle', [p1, p2, p3]); - * </pre><div class="jxgbox" id="JXGe65c9861-0bf0-402d-af57-3ab11962f5ac" style="width: 400px; height: 400px;"></div> - * <script type="text/javascript"> - * var ccex1_board = JXG.JSXGraph.initBoard('JXGe65c9861-0bf0-402d-af57-3ab11962f5ac', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); - * var ccex1_p1 = ccex1_board.create('point', [0.0, 2.0]); - * var ccex1_p2 = ccex1_board.create('point', [6.0, 1.0]); - * var ccex1_p3 = ccex1_board.create('point', [3.0, 7.0]); - * var ccex1_cc1 = ccex1_board.create('circumcircle', [ccex1_p1, ccex1_p2, ccex1_p3]); - * </script><pre> - */ - JXG.createCircumcircle = function (board, parents, attributes) { - var p, c, attr; + this.resolution = 10; // Paths are drawn with a a resolution of this.resolution/pixel. - parents = Type.providePoints(board, parents, attributes, 'point'); - if (parents === false) { - throw new Error("JSXGraph: Can't create circumcircle with parent types '" + - (typeof parents[0]) + "', '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." + - "\nPossible parent types: [point,point,point]"); + // Add VML includes and namespace + // Original: IE <=7 + //container.ownerDocument.createStyleSheet().addRule("v\\:*", "behavior: url(#default#VML);"); + if (!Type.exists(JXG.vmlStylesheet)) { + container.ownerDocument.namespaces.add("jxgvml", "urn:schemas-microsoft-com:vml"); + JXG.vmlStylesheet = this.container.ownerDocument.createStyleSheet(); + JXG.vmlStylesheet.addRule(".jxgvml", "behavior:url(#default#VML)"); } try { - attr = Type.copyAttributes(attributes, board.options, 'circumcircle', 'center'); - p = JXG.createCircumcenter(board, parents, attr); - - p.dump = false; - - if (!Type.exists(attributes.layer)) { - attributes.layer = board.options.layer.circle; + if (!container.ownerDocument.namespaces.jxgvml) { + container.ownerDocument.namespaces.add("jxgvml", "urn:schemas-microsoft-com:vml"); } - attr = Type.copyAttributes(attributes, board.options, 'circumcircle'); - c = Circle.createCircle(board, [p, parents[0]], attr); - c.elType = 'circumcircle'; - c.setParents(parents); - c.subs = { - center: p + this.createNode = function (tagName) { + return container.ownerDocument.createElement('<jxgvml:' + tagName + ' class="jxgvml">'); }; - c.inherits.push(c); } catch (e) { - throw new Error("JSXGraph: Can't create circumcircle with parent types '" + - (typeof parents[0]) + "', '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." + - "\nPossible parent types: [point,point,point]"); + this.createNode = function (tagName) { + return container.ownerDocument.createElement('<' + tagName + ' xmlns="urn:schemas-microsoft.com:vml" class="jxgvml">'); + }; } - // p is already stored as midpoint in c so there's no need to store it explicitly. - - return c; + // dash styles + this.dashArray = ['Solid', '1 1', 'ShortDash', 'Dash', 'LongDash', 'ShortDashDot', 'LongDashDot']; }; - /** - * @class An incircle is given by three points. - * @pseudo - * @constructor - * @name Incircle - * @type JXG.Circle - * @augments JXG.Circle - * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The constructed point is the midpoint of the incircle of - * <tt>p1</tt>, <tt>p2</tt>, and <tt>p3</tt>. - * @example - * var p1 = board.create('point', [0.0, 2.0]); - * var p2 = board.create('point', [2.0, 1.0]); - * var p3 = board.create('point', [3.0, 3.0]); - * - * var ic1 = board.create('incircle', [p1, p2, p3]); - * </pre><div class="jxgbox" id="JXGe65c9861-0bf0-402d-af57-2ab12962f8ac" style="width: 400px; height: 400px;"></div> - * <script type="text/javascript"> - * var icex1_board = JXG.JSXGraph.initBoard('JXGe65c9861-0bf0-402d-af57-2ab12962f8ac', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); - * var icex1_p1 = icex1_board.create('point', [0.0, 2.0]); - * var icex1_p2 = icex1_board.create('point', [6.0, 1.0]); - * var icex1_p3 = icex1_board.create('point', [3.0, 7.0]); - * var icex1_ic1 = icex1_board.create('incircle', [icex1_p1, icex1_p2, icex1_p3]); - * </script><pre> - */ - JXG.createIncircle = function (board, parents, attributes) { - var p, c, attr; - - parents = Type.providePoints(board, parents, attributes, 'point'); - if (parents === false) { - throw new Error("JSXGraph: Can't create circumcircle with parent types '" + - (typeof parents[0]) + "', '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." + - "\nPossible parent types: [point,point,point]"); - } - try { - attr = Type.copyAttributes(attributes, board.options, 'incircle', 'center'); - p = JXG.createIncenter(board, parents, attr); + JXG.VMLRenderer.prototype = new AbstractRenderer(); - p.dump = false; + JXG.extend(JXG.VMLRenderer.prototype, /** @lends JXG.VMLRenderer.prototype */ { - if (!Type.exists(attributes.layer)) { - attributes.layer = board.options.layer.circle; + /** + * Sets attribute <tt>key</tt> of node <tt>node</tt> to <tt>value</tt>. + * @param {Node} node A DOM node. + * @param {String} key Name of the attribute. + * @param {String} val New value of the attribute. + * @param {Boolean} [iFlag=false] If false, the attribute's name is case insensitive. + */ + _setAttr: function (node, key, val, iFlag) { + try { + if (this.container.ownerDocument.documentMode === 8) { + node[key] = val; + } else { + node.setAttribute(key, val, iFlag); + } + } catch (e) { + JXG.debug('_setAttr:'/*node.id*/ + ' ' + key + ' ' + val + '<br>\n'); } - attr = Type.copyAttributes(attributes, board.options, 'incircle'); - c = Circle.createCircle(board, [p, function () { - var a = Math.sqrt((parents[1].X() - parents[2].X()) * (parents[1].X() - parents[2].X()) + (parents[1].Y() - parents[2].Y()) * (parents[1].Y() - parents[2].Y())), - b = Math.sqrt((parents[0].X() - parents[2].X()) * (parents[0].X() - parents[2].X()) + (parents[0].Y() - parents[2].Y()) * (parents[0].Y() - parents[2].Y())), - c = Math.sqrt((parents[1].X() - parents[0].X()) * (parents[1].X() - parents[0].X()) + (parents[1].Y() - parents[0].Y()) * (parents[1].Y() - parents[0].Y())), - s = (a + b + c) / 2; + }, - return Math.sqrt(((s - a) * (s - b) * (s - c)) / s); - }], attr); + /* ******************************** * + * This renderer does not need to + * override draw/update* methods + * since it provides draw/update*Prim + * methods. + * ******************************** */ - c.elType = 'incircle'; - c.setParents(parents); + /* ************************** + * Lines + * **************************/ - /** - * The center of the incircle - * @memberOf Incircle.prototype - * @type Incenter - * @name center - */ - c.center = p; + // documented in AbstractRenderer + updateTicks: function (ticks) { + var i, len, c, x, y, + r = this.resolution, + tickArr = []; - c.subs = { - center: c.center - }; - c.inherits.push(p); + len = ticks.ticks.length; + for (i = 0; i < len; i++) { + c = ticks.ticks[i]; + x = c[0]; + y = c[1]; - } catch (e) { - throw new Error("JSXGraph: Can't create circumcircle with parent types '" + - (typeof parents[0]) + "', '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." + - "\nPossible parent types: [point,point,point]"); - } + if (Type.isNumber(x[0]) && Type.isNumber(x[1])) { + tickArr.push(' m ' + Math.round(r * x[0]) + ', ' + Math.round(r * y[0]) + + ' l ' + Math.round(r * x[1]) + ', ' + Math.round(r * y[1]) + ' '); + } + } - // p is already stored as midpoint in c so there's no need to store it explicitly. + if (!Type.exists(ticks.rendNode)) { + ticks.rendNode = this.createPrim('path', ticks.id); + this.appendChildPrim(ticks.rendNode, Type.evaluate(ticks.visProp.layer)); + } - return c; - }; + this._setAttr(ticks.rendNode, 'stroked', 'true'); + this._setAttr(ticks.rendNode, 'strokecolor', Type.evaluate(ticks.visProp.strokecolor), 1); + this._setAttr(ticks.rendNode, 'strokeweight', Type.evaluate(ticks.visProp.strokewidth)); + this._setAttr(ticks.rendNodeStroke, 'opacity', (Type.evaluate(ticks.visProp.strokeopacity) * 100) + '%'); + this.updatePathPrim(ticks.rendNode, tickArr, ticks.board); + }, - /** - * @class This element is used to construct a reflected point. - * @pseudo - * @description A reflected element (point, line or curve) is given by a given - * object of the same type and a line of reflection. - * It is determined by the reflection of the given element - * across the given line. - * @constructor - * @name Reflection - * @type JXG.GeometryElement - * @augments JXG.GeometryElement - * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {JXG.Point|JXG.Line|JXG.Curve|JXG.Polygon_JXG.Line} p,l The reflection element is the reflection of p across the line l. - * @example - * var p1 = board.create('point', [0.0, 4.0]); - * var p2 = board.create('point', [6.0, 1.0]); - * var l1 = board.create('line', [p1, p2]); - * var p3 = board.create('point', [3.0, 3.0]); - * - * var rp1 = board.create('reflection', [p3, l1]); - * </pre><div class="jxgbox" id="JXG087a798e-a36a-4f52-a2b4-29a23a69393b" style="width: 400px; height: 400px;"></div> - * <script type="text/javascript"> - * var rpex1_board = JXG.JSXGraph.initBoard('JXG087a798e-a36a-4f52-a2b4-29a23a69393b', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); - * var rpex1_p1 = rpex1_board.create('point', [0.0, 4.0]); - * var rpex1_p2 = rpex1_board.create('point', [6.0, 1.0]); - * var rpex1_l1 = rpex1_board.create('line', [rpex1_p1, rpex1_p2]); - * var rpex1_p3 = rpex1_board.create('point', [3.0, 3.0]); - * var rpex1_rp1 = rpex1_board.create('reflection', [rpex1_p3, rpex1_l1]); - * </script><pre> - * @example - * // Reflection of more elements - * // reflection line - * var li = board.create('line', [1,1,1], {strokeColor: '#aaaaaa'}); - * - * var p1 = board.create('point', [-3,-1], {name: "A"}); - * var q1 = board.create('reflection', [p1, li], {name: "A'"}); - * - * var l1 = board.create('line', [1,-5,1]); - * var l2 = board.create('reflection', [l1, li]); - * - * var cu1 = board.create('curve', [[-3, -3, -2.5, -3, -3, -2.5], [-3, -2, -2, -2, -2.5, -2.5]], {strokeWidth:3}); - * var cu2 = board.create('reflection', [cu1, li], {strokeColor: 'red', strokeWidth:3}); - * - * var pol1 = board.create('polygon', [[-6,-3], [-4,-5], [-5,-1.5]]); - * var pol2 = board.create('reflection', [pol1, li]); - * - * var c1 = board.create('circle', [[-2,-2], [-2, -1]]); - * var c2 = board.create('reflection', [c1, li]); - * - * var a1 = board.create('arc', [[1, 1], [0, 1], [1, 0]], {strokeColor: 'red'}); - * var a2 = board.create('reflection', [a1, li], {strokeColor: 'red'}); - * - * var s1 = board.create('sector', [[-3.5,-3], [-3.5, -2], [-3.5,-4]], { - * anglePoint: {visible:true}, center: {visible: true}, radiusPoint: {visible: true}, - * fillColor: 'yellow', strokeColor: 'black'}); - * var s2 = board.create('reflection', [s1, li], {fillColor: 'yellow', strokeColor: 'black', fillOpacity: 0.5}); - * - * var an1 = board.create('angle', [[-4,3.9], [-3, 4], [-3, 3]]); - * var an2 = board.create('reflection', [an1, li]); - * - * </pre><div id="JXG8f763af4-d449-11e7-93b3-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function() { - * var board = JXG.JSXGraph.initBoard('JXG8f763af4-d449-11e7-93b3-901b0e1b8723', - * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); - * // reflection line - * var li = board.create('line', [1,1,1], {strokeColor: '#aaaaaa'}); - * - * var p1 = board.create('point', [-3,-1], {name: "A"}); - * var q1 = board.create('reflection', [p1, li], {name: "A'"}); - * - * var l1 = board.create('line', [1,-5,1]); - * var l2 = board.create('reflection', [l1, li]); - * - * var cu1 = board.create('curve', [[-3, -3, -2.5, -3, -3, -2.5], [-3, -2, -2, -2, -2.5, -2.5]], {strokeWidth:3}); - * var cu2 = board.create('reflection', [cu1, li], {strokeColor: 'red', strokeWidth:3}); - * - * var pol1 = board.create('polygon', [[-6,-3], [-4,-5], [-5,-1.5]]); - * var pol2 = board.create('reflection', [pol1, li]); - * - * var c1 = board.create('circle', [[-2,-2], [-2, -1]]); - * var c2 = board.create('reflection', [c1, li]); - * - * var a1 = board.create('arc', [[1, 1], [0, 1], [1, 0]], {strokeColor: 'red'}); - * var a2 = board.create('reflection', [a1, li], {strokeColor: 'red'}); - * - * var s1 = board.create('sector', [[-3.5,-3], [-3.5, -2], [-3.5,-4]], { - * anglePoint: {visible:true}, center: {visible: true}, radiusPoint: {visible: true}, - * fillColor: 'yellow', strokeColor: 'black'}); - * var s2 = board.create('reflection', [s1, li], {fillColor: 'yellow', strokeColor: 'black', fillOpacity: 0.5}); - * - * var an1 = board.create('angle', [[-4,3.9], [-3, 4], [-3, 3]]); - * var an2 = board.create('reflection', [an1, li]); - * - * })(); - * - * </script><pre> - * - */ - JXG.createReflection = function (board, parents, attributes) { - var l, org, r, r_c, t, i, - attr, attr2, - errStr = "\nPossible parent types: [point|line|curve|polygon|circle|arc|sector, line]"; + /* ************************** + * Text related stuff + * **************************/ - for (i = 0; i < parents.length; ++i) { - parents[i] = board.select(parents[i]); - } + // Already documented in JXG.AbstractRenderer + displayCopyright: function (str, fontsize) { + var node, t; - attr = Type.copyAttributes(attributes, board.options, 'reflection'); + node = this.createNode('textbox'); + node.style.position = 'absolute'; + this._setAttr(node, 'id', this.container.id + '_' + 'licenseText'); - if (Type.isPoint(parents[0])) { - org = Type.providePoints(board, [parents[0]], attr2)[0]; - } else if (parents[0].elementClass === Const.OBJECT_CLASS_CURVE || - parents[0].elementClass === Const.OBJECT_CLASS_LINE || - parents[0].type === Const.OBJECT_TYPE_POLYGON || - parents[0].elementClass === Const.OBJECT_CLASS_CIRCLE) { - org = parents[0]; - } else { - throw new Error("JSXGraph: Can't create reflection element with parent types '" + - (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + errStr); - } + node.style.left = 20; + node.style.top = 2; + node.style.fontSize = fontsize; + node.style.color = '#356AA0'; + node.style.fontFamily = 'Arial,Helvetica,sans-serif'; + this._setAttr(node, 'opacity', '30%'); + node.style.filter = "progid:DXImageTransform.Microsoft.Matrix(M11='1.0', sizingMethod='auto expand', enabled = false) progid:DXImageTransform.Microsoft.Alpha(opacity = 30, enabled = true)"; - if (parents[1].elementClass === Const.OBJECT_CLASS_LINE) { - l = parents[1]; - } else { - throw new Error("JSXGraph: Can't create reflected element with parent types '" + - (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + errStr); - } + t = this.container.ownerDocument.createTextNode(str); + node.appendChild(t); + this.appendChildPrim(node, 0); + }, - t = Transform.createTransform(board, [l], {type: 'reflect'}); - if (Type.isPoint(org)) { - r = Point.createPoint(board, [org, t], attr); - // Arcs and sectors are treated as curves - } else if (org.elementClass === Const.OBJECT_CLASS_CURVE){ - r = Curve.createCurve(board, [org, t], attr); - } else if (org.elementClass === Const.OBJECT_CLASS_LINE){ - r = Line.createLine(board, [org, t], attr); - } else if (org.type === Const.OBJECT_TYPE_POLYGON){ - r = Polygon.createPolygon(board, [org, t], attr); - } else if (org.elementClass === Const.OBJECT_CLASS_CIRCLE) { - if (attr.type.toLowerCase() === 'euclidean') { - // Create a circle element from a circle and a Euclidean transformation - attr2 = Type.copyAttributes(attributes, board.options, 'reflection', 'center'); - r_c = Point.createPoint(board, [org.center, t], attr2); - r = Circle.createCircle(board, [r_c, function() {return org.Radius(); }], attr); - } else { - // Create a conic element from a circle and a projective transformation - r = Circle.createCircle(board, [org, t], attr); - } - } else { - throw new Error("JSXGraph: Can't create reflected element with parent types '" + - (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + errStr); - } - //org.addChild(r); - l.addChild(r); - r.elType = 'reflection'; - r.addParents(l); - r.prepareUpdate().update(); //.updateVisibility(Type.evaluate(r.visProp.visible)).updateRenderer(); + // documented in AbstractRenderer + drawInternalText: function (el) { + var node; + node = this.createNode('textbox'); + node.style.position = 'absolute'; + el.rendNodeText = this.container.ownerDocument.createTextNode(''); + node.appendChild(el.rendNodeText); + this.appendChildPrim(node, 9); + node.style.filter = "progid:DXImageTransform.Microsoft.Matrix(M11='1.0', sizingMethod='auto expand', enabled = false) progid:DXImageTransform.Microsoft.Alpha(opacity = 100, enabled = false)"; - if (Type.isPoint(r)) { - r.generatePolynomial = function () { - /* - * Reflection takes a point R and a line L and creates point P, which is the reflection of R on L. - * L is defined by two points A and B. - * - * So we have two conditions: - * - * (a) RP _|_ AB (orthogonality condition) - * (b) AR == AP (distance condition) - * - */ - var a1 = l.point1.symbolic.x, - a2 = l.point1.symbolic.y, - b1 = l.point2.symbolic.x, - b2 = l.point2.symbolic.y, - p1 = org.symbolic.x, - p2 = org.symbolic.y, - r1 = r.symbolic.x, - r2 = r.symbolic.y, + return node; + }, - poly1 = ['((', r2, ')-(', p2, '))*((', a2, ')-(', b2, '))+((', a1, ')-(', b1, '))*((', r1, ')-(', p1, '))'].join(''), - poly2 = ['((', r1, ')-(', a1, '))^2+((', r2, ')-(', a2, '))^2-((', p1, ')-(', a1, '))^2-((', p2, ')-(', a2, '))^2'].join(''); + // documented in AbstractRenderer + updateInternalText: function (el) { + var v, content = el.plaintext, + m = this.joinTransforms(el, el.transformations), + offset = [0, 0], + maxX, maxY, minX, minY, i, + node = el.rendNode, + p = [], + ev_ax = el.getAnchorX(), + ev_ay = el.getAnchorY(); - return [poly1, poly2]; - }; - } + if (!isNaN(el.coords.scrCoords[1] + el.coords.scrCoords[2])) { + // Horizontal + if (ev_ax === 'right') { + offset[0] = 1; + } else if (ev_ax === 'middle') { + offset[0] = 0.5; + } // default (ev_ax === 'left') offset[0] = 0; - return r; - }; + // Vertical + if (ev_ay === 'bottom') { + offset[1] = 1; + } else if (ev_ay === 'middle') { + offset[1] = 0.5; + } // default (ev_ay === 'top') offset[1] = 0; - /** - * @class A mirror element will be constructed. - * @pseudo - * @description A mirror element is determined by the reflection of a given point across another given point. - * @constructor - * @name Mirrorelement - * @type JXG.GeometryElement - * @augments JXG.GeometryElement - * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {JXG.Point|JXG.Line|JXG.Curve|JXG.Ppolygon_JXG.Point} p1,p2 The constructed element is the mirror image of p2 across p1. - * @example - * // point of reflection - * var mirr = board.create('point', [-1,-1], {color: '#aaaaaa'}); - * - * var p1 = board.create('point', [-3,-1], {name: "A"}); - * var q1 = board.create('mirrorelement', [p1, mirr], {name: "A'"}); - * - * var l1 = board.create('line', [1, -5, 1]); - * var l2 = board.create('mirrorelement', [l1, mirr]); - * - * var cu1 = board.create('curve', [[-3, -3, -2.5, -3, -3, -2.5], [-3, -2, -2, -2, -2.5, -2.5]], {strokeWidth:3}); - * var cu2 = board.create('mirrorelement', [cu1, mirr], {strokeColor: 'red', strokeWidth:3}); - * - * var pol1 = board.create('polygon', [[-6,-2], [-4,-4], [-5,-0.5]]); - * var pol2 = board.create('mirrorelement', [pol1, mirr]); - * - * var c1 = board.create('circle', [[-6,-6], [-6, -5]]); - * var c2 = board.create('mirrorelement', [c1, mirr]); - * - * var a1 = board.create('arc', [[1, 1], [0, 1], [1, 0]], {strokeColor: 'red'}); - * var a2 = board.create('mirrorelement', [a1, mirr], {strokeColor: 'red'}); - * - * var s1 = board.create('sector', [[-3.5,-3], [-3.5, -2], [-3.5,-4]], { - * anglePoint: {visible:true}, center: {visible: true}, radiusPoint: {visible: true}, - * fillColor: 'yellow', strokeColor: 'black'}); - * var s2 = board.create('mirrorelement', [s1, mirr], {fillColor: 'yellow', strokeColor: 'black', fillOpacity: 0.5}); - * - * var an1 = board.create('angle', [[-4,3.9], [-3, 4], [-3, 3]]); - * var an2 = board.create('mirrorelement', [an1, mirr]); - * - * - * </pre><div id="JXG026c779c-d8d9-11e7-93b3-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function() { - * var board = JXG.JSXGraph.initBoard('JXG026c779c-d8d9-11e7-93b3-901b0e1b8723', - * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); - * // point of reflection - * var mirr = board.create('point', [-1,-1], {color: '#aaaaaa'}); - * - * var p1 = board.create('point', [-3,-1], {name: "A"}); - * var q1 = board.create('mirrorelement', [p1, mirr], {name: "A'"}); - * - * var l1 = board.create('line', [1,-5, 1]); - * var l2 = board.create('mirrorelement', [l1, mirr]); - * - * var cu1 = board.create('curve', [[-3, -3, -2.5, -3, -3, -2.5], [-3, -2, -2, -2, -2.5, -2.5]], {strokeWidth:3}); - * var cu2 = board.create('mirrorelement', [cu1, mirr], {strokeColor: 'red', strokeWidth:3}); - * - * var pol1 = board.create('polygon', [[-6,-2], [-4,-4], [-5,-0.5]]); - * var pol2 = board.create('mirrorelement', [pol1, mirr]); - * - * var c1 = board.create('circle', [[-6,-6], [-6, -5]]); - * var c2 = board.create('mirrorelement', [c1, mirr]); - * - * var a1 = board.create('arc', [[1, 1], [0, 1], [1, 0]], {strokeColor: 'red'}); - * var a2 = board.create('mirrorelement', [a1, mirr], {strokeColor: 'red'}); - * - * var s1 = board.create('sector', [[-3.5,-3], [-3.5, -2], [-3.5,-4]], { - * anglePoint: {visible:true}, center: {visible: true}, radiusPoint: {visible: true}, - * fillColor: 'yellow', strokeColor: 'black'}); - * var s2 = board.create('mirrorelement', [s1, mirr], {fillColor: 'yellow', strokeColor: 'black', fillOpacity: 0.5}); - * - * var an1 = board.create('angle', [[-4,3.9], [-3, 4], [-3, 3]]); - * var an2 = board.create('mirrorelement', [an1, mirr]); - * - * })(); - * - * </script><pre> - */ - JXG.createMirrorElement = function (board, parents, attributes) { - var org, i, m, r, r_c, t, - attr, attr2, - errStr = "\nPossible parent types: [point|line|curve|polygon|circle|arc|sector, point]"; + // Compute maxX, maxY, minX, minY + p[0] = Mat.matVecMult(m, [1, + el.coords.scrCoords[1] - offset[0] * el.size[0], + el.coords.scrCoords[2] + (1 - offset[1]) * el.size[1] + this.vOffsetText]); + p[0][1] /= p[0][0]; + p[0][2] /= p[0][0]; + p[1] = Mat.matVecMult(m, [1, + el.coords.scrCoords[1] + (1 - offset[0]) * el.size[0], + el.coords.scrCoords[2] + (1 - offset[1]) * el.size[1] + this.vOffsetText]); + p[1][1] /= p[1][0]; + p[1][2] /= p[1][0]; + p[2] = Mat.matVecMult(m, [1, + el.coords.scrCoords[1] + (1 - offset[0]) * el.size[0], + el.coords.scrCoords[2] - offset[1] * el.size[1] + this.vOffsetText]); + p[2][1] /= p[2][0]; + p[2][2] /= p[2][0]; + p[3] = Mat.matVecMult(m, [1, + el.coords.scrCoords[1] - offset[0] * el.size[0], + el.coords.scrCoords[2] - offset[1] * el.size[1] + this.vOffsetText]); + p[3][1] /= p[3][0]; + p[3][2] /= p[3][0]; + maxX = p[0][1]; + minX = p[0][1]; + maxY = p[0][2]; + minY = p[0][2]; - for (i = 0; i < parents.length; ++i) { - parents[i] = board.select(parents[i]); - } + for (i = 1; i < 4; i++) { + maxX = Math.max(maxX, p[i][1]); + minX = Math.min(minX, p[i][1]); + maxY = Math.max(maxY, p[i][2]); + minY = Math.min(minY, p[i][2]); + } - attr = Type.copyAttributes(attributes, board.options, 'mirrorelement'); - if (Type.isPoint(parents[0])) { - // Create point to be mirrored if supplied by coords array. - org = Type.providePoints(board, [parents[0]], attr)[0]; - } else if (parents[0].elementClass === Const.OBJECT_CLASS_CURVE || - parents[0].elementClass === Const.OBJECT_CLASS_LINE || - parents[0].type === Const.OBJECT_TYPE_POLYGON || - parents[0].elementClass === Const.OBJECT_CLASS_CIRCLE) { - org = parents[0]; - } else { - throw new Error("JSXGraph: Can't create mirror element with parent types '" + - (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + errStr); - } + // Horizontal + v = offset[0] === 1 ? Math.floor(el.board.canvasWidth - maxX) : Math.floor(minX); + if (el.visPropOld.left !== (ev_ax + v)) { + if (offset[0] === 1) { + el.rendNode.style.right = v + 'px'; + el.rendNode.style.left = 'auto'; + } else { + el.rendNode.style.left = v + 'px'; + el.rendNode.style.right = 'auto'; + } + el.visPropOld.left = ev_ax + v; + } - if (Type.isPoint(parents[1])) { - attr2 = Type.copyAttributes(attributes, board.options, 'mirrorelement', 'point'); - // Create mirror point if supplied by coords array. - m = Type.providePoints(board, [parents[1]], attr2)[0]; - } else { - throw new Error("JSXGraph: Can't create mirror element with parent types '" + - (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + errStr); - } + // Vertical + v = offset[1] === 1 ? Math.floor(el.board.canvasHeight - maxY) : Math.floor(minY); + if (el.visPropOld.top !== (ev_ay + v)) { + if (offset[1] === 1) { + el.rendNode.style.bottom = v + 'px'; + el.rendNode.style.top = 'auto'; + } else { + el.rendNode.style.top = v + 'px'; + el.rendNode.style.bottom = 'auto'; + } + el.visPropOld.top = ev_ay + v; + } - t = Transform.createTransform(board, [Math.PI, m], {type: 'rotate'}); - if (Type.isPoint(org)) { - r = Point.createPoint(board, [org, t], attr); + } - // Arcs and sectors are treated as curves - } else if (org.elementClass === Const.OBJECT_CLASS_CURVE){ - r = Curve.createCurve(board, [org, t], attr); - } else if (org.elementClass === Const.OBJECT_CLASS_LINE){ - r = Line.createLine(board, [org, t], attr); - } else if (org.type === Const.OBJECT_TYPE_POLYGON){ - r = Polygon.createPolygon(board, [org, t], attr); - } else if (org.elementClass === Const.OBJECT_CLASS_CIRCLE){ - if (attr.type.toLowerCase() === 'euclidean') { - // Create a circle element from a circle and a Euclidean transformation - attr2 = Type.copyAttributes(attributes, board.options, 'mirrorelement', 'center'); - r_c = Point.createPoint(board, [org.center, t], attr2); - r = Circle.createCircle(board, [r_c, function() {return org.Radius(); }], attr); - } else { - // Create a conic element from a circle and a projective transformation - r = Circle.createCircle(board, [org, t], attr); + if (el.htmlStr !== content) { + el.rendNodeText.data = content; + el.htmlStr = content; } - } else { - throw new Error("JSXGraph: Can't create mirror element with parent types '" + - (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + errStr); - } - - //org.addChild(r); - m.addChild(r); - r.elType = 'mirrorelement'; - r.addParents(m); - r.prepareUpdate().update(); - - return r; - }; - - /** - * @class A mirror point will be constructed. - * @pseudo - * @description A mirror point is determined by the reflection of a given point against another given point. - * @constructor - * @name Mirrorpoint - * @type JXG.Point - * @augments JXG.Point - * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {JXG.Point_JXG.Point} p1,p2 The constructed point is the reflection of p2 against p1. - * - * This method is superseeded by the more general {@link JXG.createMirrorElement}. - * @example - * var p1 = board.create('point', [3.0, 3.0]); - * var p2 = board.create('point', [6.0, 1.0]); - * - * var mp1 = board.create('mirrorpoint', [p1, p2]); - * </pre><div class="jxgbox" id="JXG7eb2a814-6c4b-4caa-8cfa-4183a948d25b" style="width: 400px; height: 400px;"></div> - * <script type="text/javascript"> - * var mpex1_board = JXG.JSXGraph.initBoard('JXG7eb2a814-6c4b-4caa-8cfa-4183a948d25b', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); - * var mpex1_p1 = mpex1_board.create('point', [3.0, 3.0]); - * var mpex1_p2 = mpex1_board.create('point', [6.0, 1.0]); - * var mpex1_mp1 = mpex1_board.create('mirrorpoint', [mpex1_p1, mpex1_p2]); - * </script><pre> - */ - JXG.createMirrorPoint = function (board, parents, attributes) { - var el = JXG.createMirrorElement(board, parents, attributes); - el.elType = 'mirrorpoint'; - return el; - }; - - /** - * @class This element is used to visualize the integral of a given curve over a given interval. - * @pseudo - * @description The Integral element is used to visualize the area under a given curve over a given interval - * and to calculate the area's value. For that a polygon and gliders are used. The polygon displays the area, - * the gliders are used to change the interval dynamically. - * @constructor - * @name Integral - * @type JXG.Curve - * @augments JXG.Curve - * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {Array_JXG.Curve} i,c The constructed element covers the area between the curve <tt>c</tt> and the x-axis - * within the interval <tt>i</tt>. - * @example - * var c1 = board.create('functiongraph', [function (t) { return t*t*t; }]); - * var i1 = board.create('integral', [[-1.0, 4.0], c1]); - * </pre><div class="jxgbox" id="JXGd45d7188-6624-4d6e-bebb-1efa2a305c8a" style="width: 400px; height: 400px;"></div> - * <script type="text/javascript"> - * var intex1_board = JXG.JSXGraph.initBoard('JXGd45d7188-6624-4d6e-bebb-1efa2a305c8a', {boundingbox: [-5, 5, 5, -5], axis: true, showcopyright: false, shownavigation: false}); - * var intex1_c1 = intex1_board.create('functiongraph', [function (t) { return Math.cos(t)*t; }]); - * var intex1_i1 = intex1_board.create('integral', [[-2.0, 2.0], intex1_c1]); - * </script><pre> - */ - JXG.createIntegral = function (board, parents, attributes) { - var interval, curve, attr, - start, end, startx, starty, endx, endy, - pa_on_curve, pa_on_axis, pb_on_curve, pb_on_axis, - t = null, p; - if (Type.isArray(parents[0]) && parents[1].elementClass === Const.OBJECT_CLASS_CURVE) { - interval = parents[0]; - curve = parents[1]; - } else if (Type.isArray(parents[1]) && parents[0].elementClass === Const.OBJECT_CLASS_CURVE) { - interval = parents[1]; - curve = parents[0]; - } else { - throw new Error("JSXGraph: Can't create integral with parent types '" + - (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + - "\nPossible parent types: [[number|function,number|function],curve]"); - } + //this.transformImage(el, el.transformations); + node.filters.item(0).M11 = m[1][1]; + node.filters.item(0).M12 = m[1][2]; + node.filters.item(0).M21 = m[2][1]; + node.filters.item(0).M22 = m[2][2]; + node.filters.item(0).enabled = true; + }, - attr = Type.copyAttributes(attributes, board.options, 'integral'); - attr.withLabel = false; // There is a custom 'label' below. - p = board.create('curve', [[0], [0]], attr); + /* ************************** + * Image related stuff + * **************************/ - // Correct the interval if necessary - NOT ANYMORE, GGB's fault - start = interval[0]; - end = interval[1]; + // Already documented in JXG.AbstractRenderer + drawImage: function (el) { + // IE 8: Bilder ueber data URIs werden bis 32kB unterstuetzt. + var node; - if (Type.isFunction(start)) { - startx = start; - starty = function () { return curve.Y(startx()); }; - start = startx(); - } else { - startx = start; - starty = curve.Y(start); - } + node = this.container.ownerDocument.createElement('img'); + node.style.position = 'absolute'; + this._setAttr(node, 'id', this.container.id + '_' + el.id); - if (Type.isFunction(end)) { - endx = end; - endy = function () { return curve.Y(endx()); }; - end = endx(); - } else { - endx = end; - endy = curve.Y(end); - } + this.container.appendChild(node); + this.appendChildPrim(node, Type.evaluate(el.visProp.layer)); - attr = Type.copyAttributes(attributes, board.options, 'integral', 'curveLeft'); - pa_on_curve = board.create('glider', [startx, starty, curve], attr); - if (Type.isFunction(startx)) { - pa_on_curve.hideElement(); - } + // Adding the rotation filter. This is always filter item 0: + // node.filters.item(0), see transformImage + // Also add the alpha filter. This is always filter item 1 + // node.filters.item(1), see setObjectFillColor and setObjectSTrokeColor + //node.style.filter = node.style['-ms-filter'] = "progid:DXImageTransform.Microsoft.Matrix(M11='1.0', sizingMethod='auto expand')"; + node.style.filter = "progid:DXImageTransform.Microsoft.Matrix(M11='1.0', sizingMethod='auto expand') progid:DXImageTransform.Microsoft.Alpha(opacity = 100, enabled = false)"; + el.rendNode = node; + this.updateImage(el); + }, - attr = Type.copyAttributes(attributes, board.options, 'integral', 'baseLeft'); - pa_on_axis = board.create('point', [ - function () { - if (Type.evaluate(p.visProp.axis) === 'y') { - return 0; - } + // Already documented in JXG.AbstractRenderer + transformImage: function (el, t) { + var m, s, maxX, maxY, minX, minY, i, nt, + node = el.rendNode, + p = [], + len = t.length; - return pa_on_curve.X(); - }, - function () { - if (Type.evaluate(p.visProp.axis) === 'y') { - return pa_on_curve.Y(); + if (len > 0) { + /* + nt = el.rendNode.style.filter.toString(); + if (!nt.match(/DXImageTransform/)) { + node.style.filter = "progid:DXImageTransform.Microsoft.Matrix(M11='1.0', sizingMethod='auto expand') " + nt; } + */ - return 0; - } - ], attr); - - attr = Type.copyAttributes(attributes, board.options, 'integral', 'curveRight'); - pb_on_curve = board.create('glider', [endx, endy, curve], attr); - if (Type.isFunction(endx)) { - pb_on_curve.hideElement(); - } + m = this.joinTransforms(el, t); + p[0] = Mat.matVecMult(m, el.coords.scrCoords); + p[0][1] /= p[0][0]; + p[0][2] /= p[0][0]; + p[1] = Mat.matVecMult(m, [1, el.coords.scrCoords[1] + el.size[0], el.coords.scrCoords[2]]); + p[1][1] /= p[1][0]; + p[1][2] /= p[1][0]; + p[2] = Mat.matVecMult(m, [1, el.coords.scrCoords[1] + el.size[0], el.coords.scrCoords[2] - el.size[1]]); + p[2][1] /= p[2][0]; + p[2][2] /= p[2][0]; + p[3] = Mat.matVecMult(m, [1, el.coords.scrCoords[1], el.coords.scrCoords[2] - el.size[1]]); + p[3][1] /= p[3][0]; + p[3][2] /= p[3][0]; + maxX = p[0][1]; + minX = p[0][1]; + maxY = p[0][2]; + minY = p[0][2]; - attr = Type.copyAttributes(attributes, board.options, 'integral', 'baseRight'); - pb_on_axis = board.create('point', [ - function () { - if (Type.evaluate(p.visProp.axis) === 'y') { - return 0; - } - return pb_on_curve.X(); - }, - function () { - if (Type.evaluate(p.visProp.axis) === 'y') { - return pb_on_curve.Y(); + for (i = 1; i < 4; i++) { + maxX = Math.max(maxX, p[i][1]); + minX = Math.min(minX, p[i][1]); + maxY = Math.max(maxY, p[i][2]); + minY = Math.min(minY, p[i][2]); } + node.style.left = Math.floor(minX) + 'px'; + node.style.top = Math.floor(minY) + 'px'; - return 0; + node.filters.item(0).M11 = m[1][1]; + node.filters.item(0).M12 = m[1][2]; + node.filters.item(0).M21 = m[2][1]; + node.filters.item(0).M22 = m[2][2]; + node.filters.item(0).enabled = true; } - ], attr); - - attr = Type.copyAttributes(attributes, board.options, 'integral'); - if (attr.withlabel !== false && attr.axis !== 'y') { - attr = Type.copyAttributes(attributes, board.options, 'integral', 'label'); - attr = Type.copyAttributes(attr, board.options, 'label'); + }, - t = board.create('text', [ - function () { - var off = new Coords(Const.COORDS_BY_SCREEN, [ - Type.evaluate(this.visProp.offset[0]) + this.board.origin.scrCoords[1], - 0 - ], this.board, false), - bb = this.board.getBoundingBox(), - dx = (bb[2] - bb[0]) * 0.1, - x = pb_on_curve.X(); + // Already documented in JXG.AbstractRenderer + updateImageURL: function (el) { + var url = Type.evaluate(el.url); - if (x < bb[0]) { - x = bb[0] + dx; - } else if (x > bb[2]) { - x = bb[2] - dx; - } + this._setAttr(el.rendNode, 'src', url); + }, - return x + off.usrCoords[1]; - }, - function () { - var off = new Coords(Const.COORDS_BY_SCREEN, [ - 0, - Type.evaluate(this.visProp.offset[1]) + this.board.origin.scrCoords[2] - ], this.board, false), - bb = this.board.getBoundingBox(), - dy = (bb[1] - bb[3]) * 0.1, - y = pb_on_curve.Y(); + /* ************************** + * Render primitive objects + * **************************/ - if (y > bb[1]) { - y = bb[1] - dy; - } else if (y < bb[3]) { - y = bb[3] + dy; - } + // Already documented in JXG.AbstractRenderer + appendChildPrim: function (node, level) { + // For trace nodes + if (!Type.exists(level)) { + level = 0; + } - return y + off.usrCoords[2]; - }, - function () { - var Int = Numerics.NewtonCotes([pa_on_axis.X(), pb_on_axis.X()], curve.Y); - return '∫ = ' + Type.toFixed(Int, 4); - } - ], attr); + node.style.zIndex = level; + this.container.appendChild(node); - t.dump = false; + return node; + }, - pa_on_curve.addChild(t); - pb_on_curve.addChild(t); - } + // Already documented in JXG.AbstractRenderer + appendNodesToElement: function (el, type) { + if (type === 'shape' || type === 'path' || type === 'polygon') { + el.rendNodePath = this.getElementById(el.id + '_path'); + } + el.rendNodeFill = this.getElementById(el.id + '_fill'); + el.rendNodeStroke = this.getElementById(el.id + '_stroke'); + el.rendNodeShadow = this.getElementById(el.id + '_shadow'); + el.rendNode = this.getElementById(el.id); + }, - // dump stuff - pa_on_curve.dump = false; - pa_on_axis.dump = false; + // Already documented in JXG.AbstractRenderer + createPrim: function (type, id) { + var node, pathNode, + fillNode = this.createNode('fill'), + strokeNode = this.createNode('stroke'), + shadowNode = this.createNode('shadow'); - pb_on_curve.dump = false; - pb_on_axis.dump = false; + this._setAttr(fillNode, 'id', this.container.id + '_' + id + '_fill'); + this._setAttr(strokeNode, 'id', this.container.id + '_' + id + '_stroke'); + this._setAttr(shadowNode, 'id', this.container.id + '_' + id + '_shadow'); - p.elType = 'integral'; - p.setParents([curve.id, interval]); - p.subs = { - curveLeft: pa_on_curve, - baseLeft: pa_on_axis, - curveRight: pb_on_curve, - baseRight: pb_on_axis - }; - p.inherits.push(pa_on_curve, pa_on_axis, pb_on_curve, pb_on_axis); + if (type === 'circle' || type === 'ellipse') { + node = this.createNode('oval'); + node.appendChild(fillNode); + node.appendChild(strokeNode); + node.appendChild(shadowNode); + } else if (type === 'polygon' || type === 'path' || type === 'shape' || type === 'line') { + node = this.createNode('shape'); + node.appendChild(fillNode); + node.appendChild(strokeNode); + node.appendChild(shadowNode); + pathNode = this.createNode('path'); + this._setAttr(pathNode, 'id', this.container.id + '_' + id + '_path'); + node.appendChild(pathNode); + } else { + node = this.createNode(type); + node.appendChild(fillNode); + node.appendChild(strokeNode); + node.appendChild(shadowNode); + } - if (attr.withLabel) { - p.subs.label = t; - p.inherits.push(t); - } + node.style.position = 'absolute'; + node.style.left = '0px'; + node.style.top = '0px'; + this._setAttr(node, 'id', this.container.id + '_' + id); - /** - * Returns the current value of the integral. - * @memberOf Integral - * @name Value - * @function - * @returns {Number} - */ - p.Value = function () { - return Numerics.I([pa_on_axis.X(), pb_on_axis.X()], curve.Y); - }; + return node; + }, - /** - * documented in JXG.Curve - * @ignore - */ - p.updateDataArray = function () { - var x, y, - i, left, right, - lowx, upx, - lowy, upy; + // Already documented in JXG.AbstractRenderer + remove: function (node) { + if (Type.exists(node)) { + node.removeNode(true); + } + }, - if (Type.evaluate(this.visProp.axis) === 'y') { - if (pa_on_curve.Y() < pb_on_curve.Y()) { - lowx = pa_on_curve.X(); - lowy = pa_on_curve.Y(); - upx = pb_on_curve.X(); - upy = pb_on_curve.Y(); - } else { - lowx = pb_on_curve.X(); - lowy = pb_on_curve.Y(); - upx = pa_on_curve.X(); - upy = pa_on_curve.Y(); - } - left = Math.min(lowx, upx); - right = Math.max(lowx, upx); + // Already documented in JXG.AbstractRenderer + makeArrows: function (el) { + var nodeStroke, + ev_fa = Type.evaluate(el.visProp.firstarrow), + ev_la = Type.evaluate(el.visProp.lastarrow); - x = [0, lowx]; - y = [lowy, lowy]; + if (el.visPropOld.firstarrow === ev_fa && el.visPropOld.lastarrow === ev_la) { + return; + } - for (i = 0; i < curve.numberPoints; i++) { - if (lowy <= curve.points[i].usrCoords[2] && - left <= curve.points[i].usrCoords[1] && - curve.points[i].usrCoords[2] <= upy && - curve.points[i].usrCoords[1] <= right) { - x.push(curve.points[i].usrCoords[1]); - y.push(curve.points[i].usrCoords[2]); - } + if (ev_fa) { + nodeStroke = el.rendNodeStroke; + this._setAttr(nodeStroke, 'startarrow', 'block'); + this._setAttr(nodeStroke, 'startarrowlength', 'long'); + } else { + nodeStroke = el.rendNodeStroke; + if (Type.exists(nodeStroke)) { + this._setAttr(nodeStroke, 'startarrow', 'none'); } - x.push(upx); - y.push(upy); - x.push(0); - y.push(upy); + } - // close the curve - x.push(0); - y.push(lowy); + if (ev_la) { + nodeStroke = el.rendNodeStroke; + this._setAttr(nodeStroke, 'id', this.container.id + '_' + el.id + "stroke"); + this._setAttr(nodeStroke, 'endarrow', 'block'); + this._setAttr(nodeStroke, 'endarrowlength', 'long'); } else { - if (pa_on_axis.X() < pb_on_axis.X()) { - left = pa_on_axis.X(); - right = pb_on_axis.X(); - } else { - left = pb_on_axis.X(); - right = pa_on_axis.X(); + nodeStroke = el.rendNodeStroke; + if (Type.exists(nodeStroke)) { + this._setAttr(nodeStroke, 'endarrow', 'none'); } + } + el.visPropOld.firstarrow = ev_fa; + el.visPropOld.lastarrow = ev_la; + }, - x = [left, left]; - y = [0, curve.Y(left)]; + // Already documented in JXG.AbstractRenderer + updateEllipsePrim: function (node, x, y, rx, ry) { + node.style.left = Math.floor(x - rx) + 'px'; + node.style.top = Math.floor(y - ry) + 'px'; + node.style.width = Math.floor(Math.abs(rx) * 2) + 'px'; + node.style.height = Math.floor(Math.abs(ry) * 2) + 'px'; + }, - for (i = 0; i < curve.numberPoints; i++) { - if ((left <= curve.points[i].usrCoords[1]) && (curve.points[i].usrCoords[1] <= right)) { - x.push(curve.points[i].usrCoords[1]); - y.push(curve.points[i].usrCoords[2]); - } - } - x.push(right); - y.push(curve.Y(right)); - x.push(right); - y.push(0); + // Already documented in JXG.AbstractRenderer + updateLinePrim: function (node, p1x, p1y, p2x, p2y, board) { + var s, r = this.resolution; - // close the curve - x.push(left); - y.push(0); + if (!isNaN(p1x + p1y + p2x + p2y)) { + s = ['m ', Math.floor(r * p1x), ', ', Math.floor(r * p1y), ' l ', Math.floor(r * p2x), ', ', Math.floor(r * p2y)]; + this.updatePathPrim(node, s, board); } + }, - this.dataX = x; - this.dataY = y; - }; + // Already documented in JXG.AbstractRenderer + updatePathPrim: function (node, pointString, board) { + var x = board.canvasWidth, + y = board.canvasHeight; + if (pointString.length <= 0) { + pointString = ['m 0,0']; + } + node.style.width = x; + node.style.height = y; + this._setAttr(node, 'coordsize', [Math.floor(this.resolution * x), Math.floor(this.resolution * y)].join(',')); + this._setAttr(node, 'path', pointString.join("")); + }, - pa_on_curve.addChild(p); - pb_on_curve.addChild(p); - pa_on_axis.addChild(p); - pb_on_axis.addChild(p); + // Already documented in JXG.AbstractRenderer + updatePathStringPoint: function (el, size, type) { + var s = [], + mround = Math.round, + scr = el.coords.scrCoords, + sqrt32 = size * Math.sqrt(3) * 0.5, + s05 = size * 0.5, + r = this.resolution; - /** - * The point on the axis initially corresponding to the lower value of the interval. - * - * @name baseLeft - * @memberOf Integral - * @type JXG.Point - */ - p.baseLeft = pa_on_axis; + if (type === 'x') { + s.push([ + ' m ', mround(r * (scr[1] - size)), ', ', mround(r * (scr[2] - size)), + ' l ', mround(r * (scr[1] + size)), ', ', mround(r * (scr[2] + size)), + ' m ', mround(r * (scr[1] + size)), ', ', mround(r * (scr[2] - size)), + ' l ', mround(r * (scr[1] - size)), ', ', mround(r * (scr[2] + size)) + ].join('')); + } else if (type === '+') { + s.push([ + ' m ', mround(r * (scr[1] - size)), ', ', mround(r * (scr[2])), + ' l ', mround(r * (scr[1] + size)), ', ', mround(r * (scr[2])), + ' m ', mround(r * (scr[1])), ', ', mround(r * (scr[2] - size)), + ' l ', mround(r * (scr[1])), ', ', mround(r * (scr[2] + size)) + ].join('')); + } else if (type === '<>') { - /** - * The point on the axis initially corresponding to the higher value of the interval. - * - * @name baseRight - * @memberOf Integral - * @type JXG.Point - */ - p.baseRight = pb_on_axis; - - /** - * The glider on the curve corresponding to the lower value of the interval. - * - * @name curveLeft - * @memberOf Integral - * @type Glider - */ - p.curveLeft = pa_on_curve; + s.push([ + ' m ', mround(r * (scr[1] - size)), ', ', mround(r * (scr[2])), + ' l ', mround(r * (scr[1])), ', ', mround(r * (scr[2] + size)), + ' l ', mround(r * (scr[1] + size)), ', ', mround(r * (scr[2])), + ' l ', mround(r * (scr[1])), ', ', mround(r * (scr[2] - size)), + ' x e ' + ].join('')); + } else if (type === '^') { + s.push([ + ' m ', mround(r * (scr[1])), ', ', mround(r * (scr[2] - size)), + ' l ', mround(r * (scr[1] - sqrt32)), ', ', mround(r * (scr[2] + s05)), + ' l ', mround(r * (scr[1] + sqrt32)), ', ', mround(r * (scr[2] + s05)), + ' x e ' + ].join('')); + } else if (type === 'v') { + s.push([ + ' m ', mround(r * (scr[1])), ', ', mround(r * (scr[2] + size)), + ' l ', mround(r * (scr[1] - sqrt32)), ', ', mround(r * (scr[2] - s05)), + ' l ', mround(r * (scr[1] + sqrt32)), ', ', mround(r * (scr[2] - s05)), + ' x e ' + ].join('')); + } else if (type === '>') { + s.push([ + ' m ', mround(r * (scr[1] + size)), ', ', mround(r * (scr[2])), + ' l ', mround(r * (scr[1] - s05)), ', ', mround(r * (scr[2] - sqrt32)), + ' l ', mround(r * (scr[1] - s05)), ', ', mround(r * (scr[2] + sqrt32)), + ' l ', mround(r * (scr[1] + size)), ', ', mround(r * (scr[2])) + ].join('')); + } else if (type === '<') { + s.push([ + ' m ', mround(r * (scr[1] - size)), ', ', mround(r * (scr[2])), + ' l ', mround(r * (scr[1] + s05)), ', ', mround(r * (scr[2] - sqrt32)), + ' l ', mround(r * (scr[1] + s05)), ', ', mround(r * (scr[2] + sqrt32)), + ' x e ' + ].join('')); + } - /** - * The glider on the axis corresponding to the higher value of the interval. - * - * @name curveRight - * @memberOf Integral - * @type Glider - */ - p.curveRight = pb_on_curve; + return s; + }, - p.methodMap = JXG.deepCopy(p.methodMap, { - curveLeft: 'curveLeft', - baseLeft: 'baseLeft', - curveRight: 'curveRight', - baseRight: 'baseRight', - Value: 'Value' - }); + // Already documented in JXG.AbstractRenderer + updatePathStringPrim: function (el) { + var i, scr, + pStr = [], + r = this.resolution, + mround = Math.round, + symbm = ' m ', + symbl = ' l ', + symbc = ' c ', + nextSymb = symbm, + len = Math.min(el.numberPoints, 8192); // otherwise IE 7 crashes in hilbert.html - /** - * documented in GeometryElement - * @ignore - */ - p.label = t; + if (el.numberPoints <= 0) { + return ''; + } + len = Math.min(len, el.points.length); - return p; - }; + if (el.bezierDegree === 1) { + /* + if (isNotPlot && el.board.options.curve.RDPsmoothing) { + el.points = Numerics.RamerDouglasPeucker(el.points, 1.0); + } + */ - /** - * @class Creates a grid to support the user with element placement. - * @pseudo - * @description A grid is a set of vertical and horizontal lines to support the user with element placement. This method - * draws such a grid on the given board. This method does not - * take any parent elements. It is usually instantiated on the board's creation via the attribute <tt>grid</tt> set - * to true. - * @parameter None. - * @constructor - * @name Grid - * @type JXG.Curve - * @augments JXG.Curve - * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. - * @example - * grid = board.create('grid', []); - * </pre><div class="jxgbox" id="JXGa9a0671f-7a51-4fa2-8697-241142c00940" style="width: 400px; height: 400px;"></div> - * <script type="text/javascript"> - * (function () { - * board = JXG.JSXGraph.initBoard('JXGa9a0671f-7a51-4fa2-8697-241142c00940', {boundingbox:[-4, 6, 10, -6], axis: false, grid: false, keepaspectratio: true}); - * grid = board.create('grid', []); - * })(); - * </script><pre> - */ - JXG.createGrid = function (board, parents, attributes) { - var c, attr; + for (i = 0; i < len; i++) { + scr = el.points[i].scrCoords; + if (isNaN(scr[1]) || isNaN(scr[2])) { // PenUp + nextSymb = symbm; + } else { + // IE has problems with values being too far away. + if (scr[1] > 20000.0) { + scr[1] = 20000.0; + } else if (scr[1] < -20000.0) { + scr[1] = -20000.0; + } - attr = Type.copyAttributes(attributes, board.options, 'grid'); - c = board.create('curve', [[null], [null]], attr); + if (scr[2] > 20000.0) { + scr[2] = 20000.0; + } else if (scr[2] < -20000.0) { + scr[2] = -20000.0; + } - c.elType = 'grid'; - c.type = Const.OBJECT_TYPE_GRID; + pStr.push([nextSymb, mround(r * scr[1]), ', ', mround(r * scr[2])].join('')); + nextSymb = symbl; + } + } + } else if (el.bezierDegree === 3) { + i = 0; + while (i < len) { + scr = el.points[i].scrCoords; + if (isNaN(scr[1]) || isNaN(scr[2])) { // PenUp + nextSymb = symbm; + } else { + pStr.push([nextSymb, mround(r * scr[1]), ', ', mround(r * scr[2])].join('')); + if (nextSymb === symbc) { + i += 1; + scr = el.points[i].scrCoords; + pStr.push([' ', mround(r * scr[1]), ', ', mround(r * scr[2])].join('')); + i += 1; + scr = el.points[i].scrCoords; + pStr.push([' ', mround(r * scr[1]), ', ', mround(r * scr[2])].join('')); + } + nextSymb = symbc; + } + i += 1; + } + } + pStr.push(' e'); + return pStr; + }, - c.updateDataArray = function () { - var start, end, i, topLeft, bottomRight, - gridX = Type.evaluate(this.visProp.gridx), - gridY = Type.evaluate(this.visProp.gridy); + // Already documented in JXG.AbstractRenderer + updatePathStringBezierPrim: function (el) { + var i, j, k, scr, lx, ly, + pStr = [], + f = Type.evaluate(el.visProp.strokewidth), + r = this.resolution, + mround = Math.round, + symbm = ' m ', + symbl = ' c ', + nextSymb = symbm, + isNoPlot = (Type.evaluate(el.visProp.curvetype) !== 'plot'), + len = Math.min(el.numberPoints, 8192); // otherwise IE 7 crashes in hilbert.html - if (Type.isArray(this.visProp.topleft)) { - topLeft = new Coords(Type.evaluate(this.visProp.tltype) || Const.COORDS_BY_USER, - this.visProp.topleft, board); - } else { - topLeft = new Coords(Const.COORDS_BY_SCREEN, [0, 0], board); + if (el.numberPoints <= 0) { + return ''; } - - if (Type.isArray(this.visProp.bottomright)) { - bottomRight = new Coords(Type.evaluate(this.visProp.brtype) || Const.COORDS_BY_USER, - this.visProp.bottomright, board); - } else { - bottomRight = new Coords(Const.COORDS_BY_SCREEN, [board.canvasWidth, board.canvasHeight], board); + if (isNoPlot && el.board.options.curve.RDPsmoothing) { + el.points = Numerics.RamerDouglasPeucker(el.points, 1.0); } + len = Math.min(len, el.points.length); + for (j = 1; j < 3; j++) { + nextSymb = symbm; + for (i = 0; i < len; i++) { + scr = el.points[i].scrCoords; + if (isNaN(scr[1]) || isNaN(scr[2])) { // PenUp + nextSymb = symbm; + } else { + // IE has problems with values being too far away. + if (scr[1] > 20000.0) { + scr[1] = 20000.0; + } else if (scr[1] < -20000.0) { + scr[1] = -20000.0; + } - // - // | | | - // ----+---------+---------+----- - // | /| | - // | gridY| <---+------ Grid Cell - // | \| | - // ----+---------+---------+----- - // | |\ gridX /| - // | | | - // - // uc: usercoordinates - // - // currently one grid cell is 1/JXG.Options.grid.gridX uc wide and 1/JXG.Options.grid.gridY uc high. - // this may work perfectly with GeonextReader (#readGeonext, initialization of gridX and gridY) but it - // is absolutely not user friendly when it comes to use it as an API interface. - // i changed this to use gridX and gridY as the actual width and height of the grid cell. for this i - // had to refactor these methods: - // - // DONE JXG.Board.calculateSnapSizes (init p1, p2) - // DONE JXG.GeonextReader.readGeonext (init gridX, gridY) - // - - board.options.grid.hasGrid = true; + if (scr[2] > 20000.0) { + scr[2] = 20000.0; + } else if (scr[2] < -20000.0) { + scr[2] = -20000.0; + } - // fix_grid: adding integer function to calculation of start and end values, and adding to calculation of start and end values below - // To allow this: - // (axes on the outside, min value of grid = 0.25) - // - // | | | | - // 1.5 -+----+---------+----------+----- - // | | | | - // | | | | - // | | | | - // 1 -+----+---------+----------+----- - // | | | | - // | | | | - // | | | | - // 0.5 -+----+---------+----------+----- - // | | | | - // +----+---------+----------+----- - // | | | - // 0.5 1 1.5 - // - // fix_grid: these lines disabled: - // topLeft.setCoordinates(Const.COORDS_BY_USER, [Math.ceil(topLeft.usrCoords[1] / gridX) * gridX, Math.floor(topLeft.usrCoords[2] / gridY) * gridY]); - // bottomRight.setCoordinates(Const.COORDS_BY_USER, [Math.floor(bottomRight.usrCoords[1] / gridX) * gridX, Math.ceil(bottomRight.usrCoords[2] / gridY) * gridY]); + if (nextSymb === symbm) { + pStr.push([nextSymb, + mround(r * (scr[1])), ' ', mround(r * (scr[2]))].join('')); + } else { + k = 2 * j; + pStr.push([nextSymb, + mround(r * (lx + (scr[1] - lx) * 0.333 + f * (k * Math.random() - j))), ' ', + mround(r * (ly + (scr[2] - ly) * 0.333 + f * (k * Math.random() - j))), ' ', + mround(r * (lx + (scr[1] - lx) * 0.666 + f * (k * Math.random() - j))), ' ', + mround(r * (ly + (scr[2] - ly) * 0.666 + f * (k * Math.random() - j))), ' ', + mround(r * scr[1]), ' ', + mround(r * scr[2])].join('')); + } + nextSymb = symbl; + lx = scr[1]; + ly = scr[2]; + } + } + } + pStr.push(' e'); + return pStr; + }, - c.dataX = []; - c.dataY = []; + // Already documented in JXG.AbstractRenderer + updatePolygonPrim: function (node, el) { + var i, + len = el.vertices.length, + r = this.resolution, + scr, + pStr = []; - // Sometimes the bounding box is used to invert the axis. We have to take this into account here. - // fix_grid: adding integer function to calculation of start and end values - start = Math.floor(topLeft.usrCoords[2] / gridY) * gridY; - end = Math.ceil(bottomRight.usrCoords[2] / gridY) * gridY; + this._setAttr(node, 'stroked', 'false'); + scr = el.vertices[0].coords.scrCoords; - if (topLeft.usrCoords[2] < bottomRight.usrCoords[2]) { - start = Math.ceil(bottomRight.usrCoords[2] / gridY) * gridY; // bottomRight.usrCoords[2]; - end = Math.floor(topLeft.usrCoords[2] / gridY) * gridY; + if (isNaN(scr[1] + scr[2])) { + return; } - // start with the horizontal grid: - for (i = start; i > end - gridY; i -= gridY) { - c.dataX.push(topLeft.usrCoords[1], bottomRight.usrCoords[1], NaN); - c.dataY.push(i, i, NaN); + pStr.push(["m ", Math.floor(r * scr[1]), ",", Math.floor(r * scr[2]), " l "].join('')); + + for (i = 1; i < len - 1; i++) { + if (el.vertices[i].isReal) { + scr = el.vertices[i].coords.scrCoords; + + if (isNaN(scr[1] + scr[2])) { + return; + } + + pStr.push(Math.floor(r * scr[1]) + "," + Math.floor(r * scr[2])); + } else { + this.updatePathPrim(node, '', el.board); + return; + } + if (i < len - 2) { + pStr.push(", "); + } } + pStr.push(" x e"); + this.updatePathPrim(node, pStr, el.board); + }, - // fix_grid: adding integer function to calculation of start and end values - start = Math.ceil(topLeft.usrCoords[1] / gridX) * gridX; - end = Math.floor(bottomRight.usrCoords[1] / gridX) * gridX; + // Already documented in JXG.AbstractRenderer + updateRectPrim: function (node, x, y, w, h) { + node.style.left = Math.floor(x) + 'px'; + node.style.top = Math.floor(y) + 'px'; - if (topLeft.usrCoords[1] > bottomRight.usrCoords[1]) { - start = Math.floor(bottomRight.usrCoords[1] / gridX) * gridX; - end = Math.ceil(topLeft.usrCoords[1] / gridX) * gridX; + if (w >= 0) { + node.style.width = w + 'px'; } - // build vertical grid - for (i = start; i < end + gridX; i += gridX) { - c.dataX.push(i, i, NaN); - c.dataY.push(topLeft.usrCoords[2], bottomRight.usrCoords[2], NaN); + if (h >= 0) { + node.style.height = h + 'px'; } + }, - }; + /* ************************** + * Set Attributes + * **************************/ - // we don't care about highlighting so we turn it off completely to save a lot of - // time on every mouse move - c.hasPoint = function () { - return false; - }; + // Already documented in JXG.AbstractRenderer + setPropertyPrim: function (node, key, val) { + var keyVml = '', + v; - board.grids.push(c); + switch (key) { + case 'stroke': + keyVml = 'strokecolor'; + break; + case 'stroke-width': + keyVml = 'strokeweight'; + break; + case 'stroke-dasharray': + keyVml = 'dashstyle'; + break; + } - return c; - }; + if (keyVml !== '') { + v = Type.evaluate(val); + this._setAttr(node, keyVml, v); + } + }, - /** - * @class Creates an area indicating the solution of a linear inequality or an inequality - * of a function graph, i.e. an inequality of type y <= f(x). - * @pseudo - * @description Display the solution set of a linear inequality (less than or equal to). - * To be precise, the solution set of the inequality <i>y <= b/a * x + c/a</i> is shown. - * In case <i>a = 0</i>, that is if the equation of the line is <i>bx + c = 0</i>, - * the area of the inequality <i>bx + c <= 0</i> is shown. - * <p> - * For function graphs the area below the function graph is filled, i.e. the - * area of the inequality y <= f(x). - * With the attribute inverse:true the area of the inequality y >= f(x) is filled. - * - * @param {JXG.Line} l The area drawn will be the area below this line. With the attribute - * inverse:true, the inequality 'greater than or equal to' is shown. - * @constructor - * @name Inequality - * @type JXG.Curve - * @augments JXG.Curve - * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. - * @example - * var p = board.create('point', [1, 3]), - * q = board.create('point', [-2, -4]), - * l = board.create('line', [p, q]), - * ineq = board.create('inequality', [l]); - * ineq = board.create('inequality', [l]); - * </pre><div class="jxgbox" id="JXG2b703006-fd98-11e1-b79e-ef9e591c002e" style="width: 400px; height: 400px;"></div> - * <script type="text/javascript"> - * (function () { - * var board = JXG.JSXGraph.initBoard('JXG2b703006-fd98-11e1-b79e-ef9e591c002e', {boundingbox:[-4, 6, 10, -6], axis: false, grid: false, keepaspectratio: true}), - * p = board.create('point', [1, 3]), - * q = board.create('point', [-2, -4]), - * l = board.create('line', [p, q]), - * ineq = board.create('inequality', [l]); - * })(); - * </script><pre> - * - * @example - * // Plot the inequality - * // y >= 2/3 x + 1 - * // or - * // 0 >= -3y + 2x +1 - * var l = board.create('line', [1, 2, -3]), - * ineq = board.create('inequality', [l], {inverse:true}); - * </pre><div class="jxgbox" id="JXG1ded3812-2da4-4323-abaf-1db4bad1bfbd" style="width: 400px; height: 400px;"></div> - * <script type="text/javascript"> - * (function () { - * var board = JXG.JSXGraph.initBoard('JXG1ded3812-2da4-4323-abaf-1db4bad1bfbd', {boundingbox:[-4, 6, 10, -6], axis: false, grid: false, keepaspectratio: true}), - * l = board.create('line', [1, 2, -3]), - * ineq = board.create('inequality', [l], {inverse:true}); - * })(); - * </script><pre> - * - * @example - * var f = board.create('functiongraph', ['sin(x)', -2*Math.PI, 2*Math.PI]); - * - * var ineq_lower = board.create('inequality', [f]); - * var ineq_greater = board.create('inequality', [f], {inverse: true, fillColor: 'yellow'}); - * - * - * </pre><div id="JXGdb68c574-414c-11e8-839a-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function() { - * var board = JXG.JSXGraph.initBoard('JXGdb68c574-414c-11e8-839a-901b0e1b8723', - * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); - * var f = board.create('functiongraph', ['sin(x)', -2*Math.PI, 2*Math.PI]); - * - * var ineq_lower = board.create('inequality', [f]); - * var ineq_greater = board.create('inequality', [f], {inverse: true, fillColor: 'yellow'}); - * - * - * })(); - * - * </script><pre> - * - */ - JXG.createInequality = function (board, parents, attributes) { - var f, a, attr; + // Already documented in JXG.AbstractRenderer + display: function(el, val) { + if (el && el.rendNode) { + el.visPropOld.visible = val; + if (val) { + el.rendNode.style.visibility = "inherit"; + } else { + el.rendNode.style.visibility = "hidden"; + } + } + }, - attr = Type.copyAttributes(attributes, board.options, 'inequality'); - if (parents[0].elementClass === Const.OBJECT_CLASS_LINE) { - a = board.create('curve', [[], []], attr); - a.hasPoint = function () { - return false; - }; - a.updateDataArray = function () { - var i1, i2, - // This will be the height of the area. We mustn't rely upon the board height because if we pan the view - // such that the line is not visible anymore, the borders of the area will get visible in some cases. - h, - bb = board.getBoundingBox(), - factor = attr.inverse ? -1 : 1, - expansion = 1.5, - w = expansion * Math.max(bb[2] - bb[0], bb[1] - bb[3]), - // Fake a point (for Math.Geometry.perpendicular) - // contains centroid of the board - dp = { - coords: { - usrCoords: [1, (bb[0] + bb[2]) / 2, attr.inverse ? bb[1] : bb[3]] - } - }, + // Already documented in JXG.AbstractRenderer + show: function (el) { + JXG.deprecated('Board.renderer.show()', 'Board.renderer.display()'); - slope1 = parents[0].stdform.slice(1), - slope2 = slope1; + if (el && el.rendNode) { + el.rendNode.style.visibility = "inherit"; + } + }, - // This is wrong. Example: - // var line = board.create('line', [0, -1, -1]); - // var ineq = board.create('inequality', [line]); - // - // if (slope1[1] > 0) { - // slope1 = Statistics.multiply(slope1, -1); - // slope2 = slope1; - // } + // Already documented in JXG.AbstractRenderer + hide: function (el) { + JXG.deprecated('Board.renderer.hide()', 'Board.renderer.display()'); - // Calculate the area height as - // expansion times the distance of the line to the - // point in the middle of the top/bottom border. - h = expansion * Math.max(Geometry.perpendicular(parents[0], dp, board)[0].distance(Const.COORDS_BY_USER, dp.coords), w); - h *= factor; + if (el && el.rendNode) { + el.rendNode.style.visibility = "hidden"; + } + }, - // reuse dp - dp = { - coords: { - usrCoords: [1, (bb[0] + bb[2]) / 2, (bb[1] + bb[3]) / 2] - } - }; + // Already documented in JXG.AbstractRenderer + setDashStyle: function (el, visProp) { + var node; + if (visProp.dash >= 0) { + node = el.rendNodeStroke; + this._setAttr(node, 'dashstyle', this.dashArray[visProp.dash]); + } + }, - // If dp is on the line, Geometry.perpendicular will return a point not on the line. - // Since this somewhat odd behavior of Geometry.perpendicular is needed in GEONExT, - // it is circumvented here. - if (Math.abs(Mat.innerProduct(dp.coords.usrCoords, parents[0].stdform, 3)) >= Mat.eps) { - dp = Geometry.perpendicular(parents[0], dp, board)[0].usrCoords; - } else { - dp = dp.coords.usrCoords; - } - i1 = [1, dp[1] + slope1[1] * w, dp[2] - slope1[0] * w]; - i2 = [1, dp[1] - slope2[1] * w, dp[2] + slope2[0] * w]; + // Already documented in JXG.AbstractRenderer + setGradient: function (el) { + var nodeFill = el.rendNodeFill, + ev_g = Type.evaluate(el.visProp.gradient); - // One of the vectors based in i1 and orthogonal to the parent line has the direction d1 = (slope1, -1) - // We will go from i1 to to i1 + h*d1, from there to i2 + h*d2 (with d2 calculated equivalent to d1) and - // end up in i2. - this.dataX = [i1[1], i1[1] + slope1[0] * h, i2[1] + slope2[0] * h, i2[1], i1[1]]; - this.dataY = [i1[2], i1[2] + slope1[1] * h, i2[2] + slope2[1] * h, i2[2], i1[2]]; - }; - } else if (parents[0].elementClass === Const.OBJECT_CLASS_CURVE && - parents[0].visProp.curvetype === 'functiongraph') { + if (ev_g === 'linear') { + this._setAttr(nodeFill, 'type', 'gradient'); + this._setAttr(nodeFill, 'color2', Type.evaluate(el.visProp.gradientsecondcolor)); + this._setAttr(nodeFill, 'opacity2', Type.evaluate(el.visProp.gradientsecondopacity)); + this._setAttr(nodeFill, 'angle', Type.evaluate(el.visProp.gradientangle)); + } else if (ev_g === 'radial') { + this._setAttr(nodeFill, 'type', 'gradientradial'); + this._setAttr(nodeFill, 'color2', Type.evaluate(el.visProp.gradientsecondcolor)); + this._setAttr(nodeFill, 'opacity2', Type.evaluate(el.visProp.gradientsecondopacity)); + this._setAttr(nodeFill, 'focusposition', Type.evaluate(el.visProp.gradientpositionx) * 100 + '%,' + + Type.evaluate(el.visProp.gradientpositiony) * 100 + '%'); + this._setAttr(nodeFill, 'focussize', '0,0'); + } else { + this._setAttr(nodeFill, 'type', 'solid'); + } + }, - a = board.create('curve', [[], []], attr); - a.updateDataArray = function() { - var bbox = this.board.getBoundingBox(), - points = [], - infty, first, last, - len, i, - mi = parents[0].minX(), - ma = parents[0].maxX(), - curve_mi, curve_ma, - firstx, - lastx, - enlarge = (bbox[1] - bbox[3]) * 0.3, // enlarge the bbox vertically by this amount - inverse = Type.evaluate(this.visProp.inverse); + // Already documented in JXG.AbstractRenderer + setObjectFillColor: function (el, color, opacity) { + var rgba = Type.evaluate(color), c, rgbo, + o = Type.evaluate(opacity), oo, + node = el.rendNode, + t; - // inverse == true <=> Fill area with y >= f(x) - infty = (inverse) ? 1 : 3; // we will use either bbox[1] or bbox[3] below + o = (o > 0) ? o : 0; - this.dataX = []; - this.dataY = []; - len = parents[0].points.length; - if (len == 0) { - return; + if (el.visPropOld.fillcolor === rgba && el.visPropOld.fillopacity === o) { + return; + } + + if (Type.exists(rgba) && rgba !== false) { + // RGB, not RGBA + if (rgba.length !== 9) { + c = rgba; + oo = o; + // True RGBA, not RGB + } else { + rgbo = Color.rgba2rgbo(rgba); + c = rgbo[0]; + oo = o * rgbo[1]; } + if (c === 'none' || c === false) { + this._setAttr(el.rendNode, 'filled', 'false'); + } else { + this._setAttr(el.rendNode, 'filled', 'true'); + this._setAttr(el.rendNode, 'fillcolor', c); - bbox[1] += enlarge; - bbox[3] -= enlarge; + if (Type.exists(oo) && el.rendNodeFill) { + this._setAttr(el.rendNodeFill, 'opacity', (oo * 100) + '%'); + } + } + if (el.type === Const.OBJECT_TYPE_IMAGE) { + /* + t = el.rendNode.style.filter.toString(); + if (t.match(/alpha/)) { + el.rendNode.style.filter = t.replace(/alpha\(opacity *= *[0-9\.]+\)/, 'alpha(opacity = ' + (oo * 100) + ')'); + } else { + el.rendNode.style.filter += ' alpha(opacity = ' + (oo * 100) + ')'; + } + */ + if (node.filters.length > 1) { + // Why am I sometimes seeing node.filters.length==0 here when I move the pointer around near [0,0]? + // Setting axes:true shows text labels! + node.filters.item(1).opacity = Math.round(oo * 100); // Why does setObjectFillColor not use Math.round? + node.filters.item(1).enabled = true; + } + } + } + el.visPropOld.fillcolor = rgba; + el.visPropOld.fillopacity = o; + }, - last = -1; - while (last < len - 1) { + // Already documented in JXG.AbstractRenderer + setObjectStrokeColor: function (el, color, opacity) { + var rgba = Type.evaluate(color), c, rgbo, t, + o = Type.evaluate(opacity), oo, + node = el.rendNode, nodeStroke; - // Find the first point with real coordinates on this curve segment - for (i = last + 1, first = len; i < len; i++) { - if (parents[0].points[i].isReal()) { - first = i; - break; - } + o = (o > 0) ? o : 0; + + if (el.visPropOld.strokecolor === rgba && el.visPropOld.strokeopacity === o) { + return; + } + + // this looks like it could be merged with parts of VMLRenderer.setObjectFillColor + + if (Type.exists(rgba) && rgba !== false) { + // RGB, not RGBA + if (rgba.length !== 9) { + c = rgba; + oo = o; + // True RGBA, not RGB + } else { + rgbo = color.rgba2rgbo(rgba); + c = rgbo[0]; + oo = o * rgbo[1]; + } + if (el.elementClass === Const.OBJECT_CLASS_TEXT) { + //node.style.filter = ' alpha(opacity = ' + oo + ')'; + /* + t = node.style.filter.toString(); + if (t.match(/alpha/)) { + node.style.filter = + t.replace(/alpha\(opacity *= *[0-9\.]+\)/, 'alpha(opacity = ' + oo + ')'); + } else { + node.style.filter += ' alpha(opacity = ' + oo + ')'; } - // No real points found -> exit - if (first >= len) { - break; + */ + if (node.filters.length > 1) { + // Why am I sometimes seeing node.filters.length==0 here when I move the pointer around near [0,0]? + // Setting axes:true shows text labels! + node.filters.item(1).opacity = Math.round(oo * 100); + node.filters.item(1).enabled = true; } - // Find the last point with real coordinates on this curve segment - for (i = first, last = len - 1; i < len - 1; i++) { - if (!parents[0].points[i + 1].isReal()) { - last = i; - break; - } + node.style.color = c; + } else { + if (c !== false) { + this._setAttr(node, 'stroked', 'true'); + this._setAttr(node, 'strokecolor', c); } - firstx = parents[0].points[first].usrCoords[1]; - lastx = parents[0].points[last].usrCoords[1]; - - // Restrict the plot interval if the function ends inside of the board - curve_mi = (bbox[0] < mi) ? mi : bbox[0]; - curve_ma = (bbox[2] > ma) ? ma : bbox[2]; + nodeStroke = el.rendNodeStroke; + if (Type.exists(oo) && el.type !== Const.OBJECT_TYPE_IMAGE) { + this._setAttr(nodeStroke, 'opacity', (oo * 100) + '%'); + } + } + } + el.visPropOld.strokecolor = rgba; + el.visPropOld.strokeopacity = o; + }, - // Found NaNs - curve_mi = (first === 0) ? curve_mi : Math.max(curve_mi, firstx); - curve_ma = (last === len - 1) ? curve_ma : Math.min(curve_ma, lastx); + // Already documented in JXG.AbstractRenderer + setObjectStrokeWidth: function (el, width) { + var w = Type.evaluate(width), + node; - // First and last relevant x-coordinate of the curve - curve_mi = (first === 0) ? mi: firstx; - curve_ma = (last === len - 1)? ma: lastx; + if (isNaN(w) || el.visPropOld.strokewidth === w) { + return; + } + node = el.rendNode; + this.setPropertyPrim(node, 'stroked', 'true'); - // Copy the curve points - points = []; + if (Type.exists(w)) { - points.push([1, curve_mi, bbox[infty]]); - points.push([1, curve_mi, parents[0].points[first].usrCoords[2]]); - for (i = first; i <= last; i++) { - points.push(parents[0].points[i].usrCoords); - } - points.push([1, curve_ma, parents[0].points[last].usrCoords[2]]); - points.push([1, curve_ma, bbox[infty]]); - points.push(points[0]); + this.setPropertyPrim(node, 'stroke-width', w); + if (w === 0 && Type.exists(el.rendNodeStroke)) { + this._setAttr(node, 'stroked', 'false'); + } + } - for (i = 0; i < points.length; i++) { - this.dataX.push(points[i][1]); - this.dataY.push(points[i][2]); - } + el.visPropOld.strokewidth = w; + }, - if (last < len - 1) { - this.dataX.push(NaN); - this.dataY.push(NaN); - } - } + // Already documented in JXG.AbstractRenderer + setShadow: function (el) { + var nodeShadow = el.rendNodeShadow, + ev_s = Type.evaluate(el.visProp.shadow); - }; + if (!nodeShadow || el.visPropOld.shadow === ev_s) { + return; + } - // Previous code: - a.hasPoint = function () { - return false; - }; - } else { - // Not yet practical? - f = Type.createFunction(parents[0]); - if (!Type.exists(f)) { - throw new Error("JSXGraph: Can't create area with the given parents." + - "\nPossible parent types: [line], [function]"); + if (ev_s) { + this._setAttr(nodeShadow, 'On', 'True'); + this._setAttr(nodeShadow, 'Offset', '3pt,3pt'); + this._setAttr(nodeShadow, 'Opacity', '60%'); + this._setAttr(nodeShadow, 'Color', '#aaaaaa'); + } else { + this._setAttr(nodeShadow, 'On', 'False'); } - } - a.addParents(parents[0]); - return a; - }; + el.visPropOld.shadow = ev_s; + }, + /* ************************** + * renderer control + * **************************/ - JXG.registerElement('arrowparallel', JXG.createArrowParallel); - JXG.registerElement('bisector', JXG.createBisector); - JXG.registerElement('bisectorlines', JXG.createAngularBisectorsOfTwoLines); - JXG.registerElement('msector', JXG.createMsector); - JXG.registerElement('circumcircle', JXG.createCircumcircle); - JXG.registerElement('circumcirclemidpoint', JXG.createCircumcenter); - JXG.registerElement('circumcenter', JXG.createCircumcenter); - JXG.registerElement('incenter', JXG.createIncenter); - JXG.registerElement('incircle', JXG.createIncircle); - JXG.registerElement('integral', JXG.createIntegral); - JXG.registerElement('midpoint', JXG.createMidpoint); - JXG.registerElement('mirrorelement', JXG.createMirrorElement); - JXG.registerElement('mirrorpoint', JXG.createMirrorPoint); - JXG.registerElement('normal', JXG.createNormal); - JXG.registerElement('orthogonalprojection', JXG.createOrthogonalProjection); - JXG.registerElement('parallel', JXG.createParallel); - JXG.registerElement('parallelpoint', JXG.createParallelPoint); - JXG.registerElement('perpendicular', JXG.createPerpendicular); - JXG.registerElement('perpendicularpoint', JXG.createPerpendicularPoint); - JXG.registerElement('perpendicularsegment', JXG.createPerpendicularSegment); - JXG.registerElement('reflection', JXG.createReflection); - JXG.registerElement('grid', JXG.createGrid); - JXG.registerElement('inequality', JXG.createInequality); + // Already documented in JXG.AbstractRenderer + suspendRedraw: function () { + this.container.style.display = 'none'; + }, - return { - createArrowParallel: JXG.createArrowParallel, - createBisector: JXG.createBisector, - createAngularBisectorOfTwoLines: JXG.createAngularBisectorsOfTwoLines, - createCircumcircle: JXG.createCircumcircle, - createCircumcenter: JXG.createCircumcenter, - createIncenter: JXG.createIncenter, - createIncircle: JXG.createIncircle, - createIntegral: JXG.createIntegral, - createMidpoint: JXG.createMidpoint, - createMirrorElement: JXG.createMirrorElement, - createMirrorPoint: JXG.createMirrorPoint, - createNormal: JXG.createNormal, - createOrthogonalProjection: JXG.createOrthogonalProjection, - createParallel: JXG.createParallel, - createParallelPoint: JXG.createParallelPoint, - createPerpendicular: JXG.createPerpendicular, - createPerpendicularPoint: JXG.createPerpendicularPoint, - createPerpendicularSegmen: JXG.createPerpendicularSegment, - createReflection: JXG.createReflection, - createGrid: JXG.createGrid, - createInequality: JXG.createInequality - }; + // Already documented in JXG.AbstractRenderer + unsuspendRedraw: function () { + this.container.style.display = ''; + } + }); + + return JXG.VMLRenderer; }); /* - Copyright 2008-2021 + Copyright 2008-2022 Matthias Ehmann, Michael Gerhaeuser, Carsten Miller, @@ -50552,5557 +52807,5670 @@ define('element/composition',[ */ -/*global JXG: true, define: true, AMprocessNode: true, MathJax: true, window: true, document: true, init: true, translateASCIIMath: true, google: true*/ - -/*jslint nomen: true, plusplus: true*/ +/*global JXG: true, define: true, AMprocessNode: true, document: true, Image: true, module: true, require: true */ +/*jslint nomen: true, plusplus: true, newcap:true*/ /* depends: jxg + renderer/abstract base/constants + utils/env + utils/type + utils/uuid + utils/color base/coords - options - math/numerics math/math math/geometry - math/complex - parser/jessiecode - parser/geonext - utils/color - utils/type - utils/event - utils/env - elements: - transform - point - line - text - grid - */ - -/** - * @fileoverview The JXG.Board class is defined in this file. JXG.Board controls all properties and methods - * used to manage a geonext board like managing geometric elements, managing mouse and touch events, etc. - */ + math/numerics +*/ -define('base/board',[ - 'jxg', 'base/constants', 'base/coords', 'options', 'math/numerics', 'math/math', 'math/geometry', 'math/complex', - 'math/statistics', - 'parser/jessiecode', 'parser/geonext', 'utils/color', 'utils/type', 'utils/event', 'utils/env', 'base/transformation', - 'base/point', 'base/line', 'base/text', 'element/composition', 'base/composition' -], function (JXG, Const, Coords, Options, Numerics, Mat, Geometry, Complex, Statistics, JessieCode, GeonextParser, Color, Type, - EventEmitter, Env, Transform, Point, Line, Text, Composition, EComposition) { +define('renderer/canvas',[ + 'jxg', 'renderer/abstract', 'base/constants', 'utils/env', 'utils/type', 'utils/uuid', 'utils/color', + 'base/coords', 'math/math', 'math/geometry', 'math/numerics' +], function (JXG, AbstractRenderer, Const, Env, Type, UUID, Color, Coords, Mat, Geometry, Numerics) { - 'use strict'; + "use strict"; /** - * Constructs a new Board object. - * @class JXG.Board controls all properties and methods used to manage a geonext board like managing geometric - * elements, managing mouse and touch events, etc. You probably don't want to use this constructor directly. - * Please use {@link JXG.JSXGraph.initBoard} to initialize a board. - * @constructor - * @param {String} container The id or reference of the HTML DOM element the board is drawn in. This is usually a HTML div. - * @param {JXG.AbstractRenderer} renderer The reference of a renderer. - * @param {String} id Unique identifier for the board, may be an empty string or null or even undefined. - * @param {JXG.Coords} origin The coordinates where the origin is placed, in user coordinates. - * @param {Number} zoomX Zoom factor in x-axis direction - * @param {Number} zoomY Zoom factor in y-axis direction - * @param {Number} unitX Units in x-axis direction - * @param {Number} unitY Units in y-axis direction - * @param {Number} canvasWidth The width of canvas - * @param {Number} canvasHeight The height of canvas - * @param {Object} attributes The attributes object given to {@link JXG.JSXGraph.initBoard} - * @borrows JXG.EventEmitter#on as this.on - * @borrows JXG.EventEmitter#off as this.off - * @borrows JXG.EventEmitter#triggerEventHandlers as this.triggerEventHandlers - * @borrows JXG.EventEmitter#eventHandlers as this.eventHandlers + * Uses HTML Canvas to implement the rendering methods defined in {@link JXG.AbstractRenderer}. + * + * @class JXG.CanvasRenderer + * @augments JXG.AbstractRenderer + * @param {Node} container Reference to a DOM node containing the board. + * @param {Object} dim The dimensions of the board + * @param {Number} dim.width + * @param {Number} dim.height + * @see JXG.AbstractRenderer */ - JXG.Board = function (container, renderer, id, origin, zoomX, zoomY, unitX, unitY, canvasWidth, canvasHeight, attributes) { - /** - * Board is in no special mode, objects are highlighted on mouse over and objects may be - * clicked to start drag&drop. - * @type Number - * @constant - */ - this.BOARD_MODE_NONE = 0x0000; + JXG.CanvasRenderer = function (container, dim) { + this.type = 'canvas'; - /** - * Board is in drag mode, objects aren't highlighted on mouse over and the object referenced in - * {@link JXG.Board#mouse} is updated on mouse movement. - * @type Number - * @constant - * @see JXG.Board#drag_obj - */ - this.BOARD_MODE_DRAG = 0x0001; + this.canvasRoot = null; + this.suspendHandle = null; + this.canvasId = UUID.genUUID(); - /** - * In this mode a mouse move changes the origin's screen coordinates. - * @type Number - * @constant - */ - this.BOARD_MODE_MOVE_ORIGIN = 0x0002; + this.canvasNamespace = null; - /** - * Update is made with low quality, e.g. graphs are evaluated at a lesser amount of points. - * @type Number - * @constant - * @see JXG.Board#updateQuality - */ - this.BOARD_QUALITY_LOW = 0x1; + if (Env.isBrowser) { + this.container = container; + this.container.style.MozUserSelect = 'none'; + this.container.style.userSelect = 'none'; - /** - * Update is made with high quality, e.g. graphs are evaluated at much more points. - * @type Number - * @constant - * @see JXG.Board#updateQuality - */ - this.BOARD_QUALITY_HIGH = 0x2; + this.container.style.overflow = 'hidden'; + if (this.container.style.position === '') { + this.container.style.position = 'relative'; + } - /** - * Update is made with high quality, e.g. graphs are evaluated at much more points. - * @type Number - * @constant - * @see JXG.Board#updateQuality - */ - this.BOARD_MODE_ZOOM = 0x0011; + this.container.innerHTML = ['<canvas id="', this.canvasId, + '" width="', dim.width, + 'px" height="', dim.height, + 'px"><', '/canvas>'].join(''); + this.canvasRoot = this.container.ownerDocument.getElementById(this.canvasId); + this.canvasRoot.style.display = 'block'; + this.context = this.canvasRoot.getContext('2d'); - /** - * Pointer to the document element containing the board. - * @type Object - */ - // Former version: - // this.document = attributes.document || document; - if (Type.exists(attributes.document) && attributes.document !== false) { - this.document = attributes.document; - } else if (document !== undefined && Type.isObject(document)) { - this.document = document; + } else if (Env.isNode()) { + try { + this.canvasId = (typeof module === 'object' ? module.require('canvas') : require('canvas')); + this.canvasRoot = new this.canvasId(500, 500); + this.context = this.canvasRoot.getContext('2d'); + } catch (err) { + console.log("Warning: 'canvas' not found. You might need to call 'npm install canvas'"); + } } - /** - * The html-id of the html element containing the board. - * @type String - */ - this.container = container; - - /** - * Pointer to the html element containing the board. - * @type Object - */ - this.containerObj = (Env.isBrowser ? this.document.getElementById(this.container) : null); + this.dashArray = [[2, 2], [5, 5], [10, 10], [20, 20], [20, 10, 10, 10], [20, 5, 10, 5]]; + }; - if (Env.isBrowser && renderer.type !== 'no' && this.containerObj === null) { - throw new Error("\nJSXGraph: HTML container element '" + container + "' not found."); - } + JXG.CanvasRenderer.prototype = new AbstractRenderer(); - /** - * A reference to this boards renderer. - * @type JXG.AbstractRenderer - */ - this.renderer = renderer; + JXG.extend(JXG.CanvasRenderer.prototype, /** @lends JXG.CanvasRenderer.prototype */ { - /** - * Grids keeps track of all grids attached to this board. - */ - this.grids = []; + /* ************************** + * private methods only used + * in this renderer. Should + * not be called from outside. + * **************************/ /** - * Some standard options - * @type JXG.Options + * Draws a filled polygon. + * @param {Array} shape A matrix presented by a two dimensional array of numbers. + * @see JXG.AbstractRenderer#drawArrows + * @private */ - this.options = Type.deepCopy(Options); - this.attr = attributes; + _drawPolygon: function (shape, degree, doFill) { + var i, len = shape.length, + context = this.context; - /** - * Dimension of the board. - * @default 2 - * @type Number - */ - this.dimension = 2; - - this.jc = new JessieCode(); - this.jc.use(this); + if (len > 0) { + if (doFill) { + context.lineWidth = 0; + } + context.beginPath(); + context.moveTo(shape[0][0], shape[0][1]); + if (degree === 1) { + for (i = 1; i < len; i++) { + context.lineTo(shape[i][0], shape[i][1]); + } + } else { + for (i = 1; i < len; i += 3) { + context.bezierCurveTo(shape[i][0], shape[i][1], shape[i + 1][0], shape[i + 1][1], shape[i + 2][0], shape[i + 2][1]); + } + } + if (doFill) { + context.lineTo(shape[0][0], shape[0][1]); + context.closePath(); + context.fill(); + } else { + context.stroke(); + } + } + }, /** - * Coordinates of the boards origin. This a object with the two properties - * usrCoords and scrCoords. usrCoords always equals [1, 0, 0] and scrCoords - * stores the boards origin in homogeneous screen coordinates. - * @type Object + * Sets the fill color and fills an area. + * @param {JXG.GeometryElement} el An arbitrary JSXGraph element, preferably one with an area. + * @private */ - this.origin = {}; - this.origin.usrCoords = [1, 0, 0]; - this.origin.scrCoords = [1, origin[0], origin[1]]; + _fill: function (el) { + var context = this.context; - /** - * Zoom factor in X direction. It only stores the zoom factor to be able - * to get back to 100% in zoom100(). - * @type Number - */ - this.zoomX = zoomX; + context.save(); + if (this._setColor(el, 'fill')) { + context.fill(); + } + context.restore(); + }, /** - * Zoom factor in Y direction. It only stores the zoom factor to be able - * to get back to 100% in zoom100(). - * @type Number + * Rotates a point around <tt>(0, 0)</tt> by a given angle. + * @param {Number} angle An angle, given in rad. + * @param {Number} x X coordinate of the point. + * @param {Number} y Y coordinate of the point. + * @returns {Array} An array containing the x and y coordinate of the rotated point. + * @private */ - this.zoomY = zoomY; + _rotatePoint: function (angle, x, y) { + return [ + (x * Math.cos(angle)) - (y * Math.sin(angle)), + (x * Math.sin(angle)) + (y * Math.cos(angle)) + ]; + }, /** - * The number of pixels which represent one unit in user-coordinates in x direction. - * @type Number + * Rotates an array of points around <tt>(0, 0)</tt>. + * @param {Array} shape An array of array of point coordinates. + * @param {Number} angle The angle in rad the points are rotated by. + * @returns {Array} Array of array of two dimensional point coordinates. + * @private */ - this.unitX = unitX * this.zoomX; + _rotateShape: function (shape, angle) { + var i, rv = [], len = shape.length; - /** - * The number of pixels which represent one unit in user-coordinates in y direction. - * @type Number - */ - this.unitY = unitY * this.zoomY; + if (len <= 0) { + return shape; + } - /** - * Keep aspect ratio if bounding box is set and the width/height ratio differs from the - * width/height ratio of the canvas. - */ - this.keepaspectratio = false; + for (i = 0; i < len; i++) { + rv.push(this._rotatePoint(angle, shape[i][0], shape[i][1])); + } - /** - * Canvas width. - * @type Number - */ - this.canvasWidth = canvasWidth; + return rv; + }, /** - * Canvas Height - * @type Number + * Set the gradient angle for linear color gradients. + * + * @private + * @param {JXG.GeometryElement} node An arbitrary JSXGraph element, preferably one with an area. + * @param {Number} radians angle value in radians. 0 is horizontal from left to right, Pi/4 is vertical from top to bottom. */ - this.canvasHeight = canvasHeight; - - // If the given id is not valid, generate an unique id - if (Type.exists(id) && id !== '' && Env.isBrowser && !Type.exists(this.document.getElementById(id))) { - this.id = id; - } else { - this.id = this.generateId(); - } + updateGradientAngle: function(el, radians) { + // Angles: + // 0: -> + // 90: down + // 180: <- + // 90: up + var f = 1.0, + co = Math.cos(-radians), + si = Math.sin(-radians), + bb = el.getBoundingBox(), + c1, c2, x1, x2, y1, y2, x1s, x2s, y1s, y2s, dx, dy; - EventEmitter.eventify(this); + if (Math.abs(co) > Math.abs(si)) { + f /= Math.abs(co); + } else { + f /= Math.abs(si); + } + if (co >= 0) { + x1 = 0; + x2 = co * f; + } else { + x1 = -co * f; + x2 = 0; + } + if (si >= 0) { + y1 = 0; + y2 = si * f; + } else { + y1 = -si * f; + y2 = 0; + } - this.hooks = []; + c1 = new Coords(Const.COORDS_BY_USER, [bb[0], bb[1]], el.board); + c2 = new Coords(Const.COORDS_BY_USER, [bb[2], bb[3]], el.board); + dx = c2.scrCoords[1] - c1.scrCoords[1]; + dy = c2.scrCoords[2] - c1.scrCoords[2]; + x1s = c1.scrCoords[1] + dx * x1; + y1s = c1.scrCoords[2] + dy * y1; + x2s = c1.scrCoords[1] + dx * x2; + y2s = c1.scrCoords[2] + dy * y2; - /** - * An array containing all other boards that are updated after this board has been updated. - * @type Array - * @see JXG.Board#addChild - * @see JXG.Board#removeChild - */ - this.dependentBoards = []; + return this.context.createLinearGradient(x1s, y1s, x2s, y2s); + }, /** - * During the update process this is set to false to prevent an endless loop. - * @default false - * @type Boolean + * Set circles for radial color gradients. + * + * @private + * @param {SVGnode} node SVG gradient node + * @param {Number} cx Canvas value x1 (but value between 0 and 1) + * @param {Number} cy Canvas value y1 (but value between 0 and 1) + * @param {Number} r Canvas value r1 (but value between 0 and 1) + * @param {Number} fx Canvas value x0 (but value between 0 and 1) + * @param {Number} fy Canvas value x1 (but value between 0 and 1) + * @param {Number} fr Canvas value r0 (but value between 0 and 1) */ - this.inUpdate = false; + updateGradientCircle: function(el, cx, cy, r, fx, fy, fr) { + var bb = el.getBoundingBox(), + c1, c2, cxs, cys, rs, fxs, fys, frs, dx, dy; - /** - * An associative array containing all geometric objects belonging to the board. Key is the id of the object and value is a reference to the object. - * @type Object - */ - this.objects = {}; + c1 = new Coords(Const.COORDS_BY_USER, [bb[0], bb[1]], el.board); + c2 = new Coords(Const.COORDS_BY_USER, [bb[2], bb[3]], el.board); + dx = c2.scrCoords[1] - c1.scrCoords[1]; + dy = c1.scrCoords[2] - c2.scrCoords[2]; - /** - * An array containing all geometric objects on the board in the order of construction. - * @type Array - */ - this.objectsList = []; + cxs = c1.scrCoords[1] + dx * cx; + cys = c2.scrCoords[2] + dy * cy; + fxs = c1.scrCoords[1] + dx * fx; + fys = c2.scrCoords[2] + dy * fy; + rs = r * (dx + dy) * 0.5; + frs = fr * (dx + dy) * 0.5; - /** - * An associative array containing all groups belonging to the board. Key is the id of the group and value is a reference to the object. - * @type Object - */ - this.groups = {}; + return this.context.createRadialGradient(fxs, fys, frs, cxs, cys, rs); + }, - /** - * Stores all the objects that are currently running an animation. - * @type Object - */ - this.animationObjects = {}; + // documented in JXG.AbstractRenderer + updateGradient: function(el) { + var col, op, + ev_g = Type.evaluate(el.visProp.gradient), + gradient; - /** - * An associative array containing all highlighted elements belonging to the board. - * @type Object - */ - this.highlightedObjects = {}; + op = Type.evaluate(el.visProp.fillopacity); + op = (op > 0) ? op : 0; + col = Type.evaluate(el.visProp.fillcolor); - /** - * Number of objects ever created on this board. This includes every object, even invisible and deleted ones. - * @type Number - */ - this.numObjects = 0; + if (ev_g === 'linear') { + gradient = this.updateGradientAngle(el, Type.evaluate(el.visProp.gradientangle)); + } else if (ev_g === 'radial') { + gradient = this.updateGradientCircle(el, + Type.evaluate(el.visProp.gradientcx), + Type.evaluate(el.visProp.gradientcy), + Type.evaluate(el.visProp.gradientr), + Type.evaluate(el.visProp.gradientfx), + Type.evaluate(el.visProp.gradientfy), + Type.evaluate(el.visProp.gradientfr) + ); + } + gradient.addColorStop(Type.evaluate(el.visProp.gradientstartoffset), col); + gradient.addColorStop(Type.evaluate(el.visProp.gradientendoffset), + Type.evaluate(el.visProp.gradientsecondcolor)); + return gradient; + }, /** - * An associative array to store the objects of the board by name. the name of the object is the key and value is a reference to the object. - * @type Object + * Sets color and opacity for filling and stroking. + * type is the attribute from visProp and targetType the context[targetTypeStyle]. + * This is necessary, because the fill style of a text is set by the stroke attributes of the text element. + * @param {JXG.GeometryElement} el Any JSXGraph element. + * @param {String} [type='stroke'] Either <em>fill</em> or <em>stroke</em>. + * @param {String} [targetType=type] (optional) Either <em>fill</em> or <em>stroke</em>. + * @returns {Boolean} If the color could be set, <tt>true</tt> is returned. + * @private */ - this.elementsByName = {}; + _setColor: function (el, type, targetType) { + var hasColor = true, + ev = el.visProp, hl, sw, + rgba, rgbo, c, o, oo, + grad; - /** - * The board mode the board is currently in. Possible values are - * <ul> - * <li>JXG.Board.BOARD_MODE_NONE</li> - * <li>JXG.Board.BOARD_MODE_DRAG</li> - * <li>JXG.Board.BOARD_MODE_MOVE_ORIGIN</li> - * </ul> - * @type Number - */ - this.mode = this.BOARD_MODE_NONE; + type = type || 'stroke'; + targetType = targetType || type; - /** - * The update quality of the board. In most cases this is set to {@link JXG.Board#BOARD_QUALITY_HIGH}. - * If {@link JXG.Board#mode} equals {@link JXG.Board#BOARD_MODE_DRAG} this is set to - * {@link JXG.Board#BOARD_QUALITY_LOW} to speed up the update process by e.g. reducing the number of - * evaluation points when plotting functions. Possible values are - * <ul> - * <li>BOARD_QUALITY_LOW</li> - * <li>BOARD_QUALITY_HIGH</li> - * </ul> - * @type Number - * @see JXG.Board#mode - */ - this.updateQuality = this.BOARD_QUALITY_HIGH; + hl = this._getHighlighted(el); - /** - * If true updates are skipped. - * @type Boolean - */ - this.isSuspendedRedraw = false; + grad = Type.evaluate(el.visProp.gradient); + if (grad === 'linear' || grad === 'radial') { + // TODO: opacity + this.context[targetType + 'Style'] = this.updateGradient(el); + return hasColor; + } - this.calculateSnapSizes(); + // type is equal to 'fill' or 'stroke' + rgba = Type.evaluate(ev[hl + type + 'color']); + if (rgba !== 'none' && rgba !== false) { + o = Type.evaluate(ev[hl + type + 'opacity']); + o = (o > 0) ? o : 0; - /** - * The distance from the mouse to the dragged object in x direction when the user clicked the mouse button. - * @type Number - * @see JXG.Board#drag_dy - * @see JXG.Board#drag_obj - */ - this.drag_dx = 0; + // RGB, not RGBA + if (rgba.length !== 9) { + c = rgba; + oo = o; + // True RGBA, not RGB + } else { + rgbo = Color.rgba2rgbo(rgba); + c = rgbo[0]; + oo = o * rgbo[1]; + } + this.context.globalAlpha = oo; - /** - * The distance from the mouse to the dragged object in y direction when the user clicked the mouse button. - * @type Number - * @see JXG.Board#drag_dx - * @see JXG.Board#drag_obj - */ - this.drag_dy = 0; + this.context[targetType + 'Style'] = c; - /** - * The last position where a drag event has been fired. - * @type Array - * @see JXG.Board#moveObject - */ - this.drag_position = [0, 0]; + } else { + hasColor = false; + } - /** - * References to the object that is dragged with the mouse on the board. - * @type {@link JXG.GeometryElement}. - * @see {JXG.Board#touches} - */ - this.mouse = {}; + sw = parseFloat(Type.evaluate(ev[hl + 'strokewidth'])); + if (type === 'stroke' && !isNaN(sw)) { + if (sw === 0) { + this.context.globalAlpha = 0; + } else { + this.context.lineWidth = sw; + } + } - /** - * Keeps track on touched elements, like {@link JXG.Board#mouse} does for mouse events. - * @type Array - * @see {JXG.Board#mouse} - */ - this.touches = []; + if (type === 'stroke' && ev.linecap !== undefined && ev.linecap !== '') { + this.context.lineCap = ev.linecap; + } - /** - * A string containing the XML text of the construction. - * This is set in {@link JXG.FileReader.parseString}. - * Only useful if a construction is read from a GEONExT-, Intergeo-, Geogebra-, or Cinderella-File. - * @type String - */ - this.xmlString = ''; + return hasColor; + }, /** - * Cached result of getCoordsTopLeftCorner for touch/mouseMove-Events to save some DOM operations. - * @type Array + * Sets color and opacity for drawing paths and lines and draws the paths and lines. + * @param {JXG.GeometryElement} el An JSXGraph element with a stroke. + * @private */ - this.cPos = []; + _stroke: function (el) { + var context = this.context, + ev_dash = Type.evaluate(el.visProp.dash); - /** - * Contains the last time (epoch, msec) since the last touchMove event which was not thrown away or since - * touchStart because Android's Webkit browser fires too much of them. - * @type Number - */ - this.touchMoveLast = 0; + context.save(); - /** - * Contains the last time (epoch, msec) since the last getCoordsTopLeftCorner call which was not thrown away. - * @type Number - */ - this.positionAccessLast = 0; + if (ev_dash > 0) { + if (context.setLineDash) { + context.setLineDash(this.dashArray[ev_dash]); + } + } else { + this.context.lineDashArray = []; + } - /** - * Collects all elements that triggered a mouse down event. - * @type Array - */ - this.downObjects = []; + if (this._setColor(el, 'stroke')) { + context.stroke(); + } - if (this.attr.showcopyright) { - this.renderer.displayCopyright(Const.licenseText, parseInt(this.options.text.fontSize, 10)); - } + context.restore(); + }, /** - * Full updates are needed after zoom and axis translates. This saves some time during an update. - * @default false - * @type Boolean + * Translates a set of points. + * @param {Array} shape An array of point coordinates. + * @param {Number} x Translation in X direction. + * @param {Number} y Translation in Y direction. + * @returns {Array} An array of translated point coordinates. + * @private */ - this.needsFullUpdate = false; + _translateShape: function (shape, x, y) { + var i, rv = [], len = shape.length; - /** - * If reducedUpdate is set to true then only the dragged element and few (e.g. 2) following - * elements are updated during mouse move. On mouse up the whole construction is - * updated. This enables us to be fast even on very slow devices. - * @type Boolean - * @default false - */ - this.reducedUpdate = false; + if (len <= 0) { + return shape; + } - /** - * The current color blindness deficiency is stored in this property. If color blindness is not emulated - * at the moment, it's value is 'none'. - */ - this.currentCBDef = 'none'; + for (i = 0; i < len; i++) { + rv.push([ shape[i][0] + x, shape[i][1] + y ]); + } - /** - * If GEONExT constructions are displayed, then this property should be set to true. - * At the moment there should be no difference. But this may change. - * This is set in {@link JXG.GeonextReader.readGeonext}. - * @type Boolean - * @default false - * @see JXG.GeonextReader.readGeonext - */ - this.geonextCompatibilityMode = false; + return rv; + }, - if (this.options.text.useASCIIMathML && translateASCIIMath) { - init(); - } else { - this.options.text.useASCIIMathML = false; - } + /* ******************************** * + * Point drawing and updating * + * ******************************** */ - /** - * A flag which tells if the board registers mouse events. - * @type Boolean - * @default false - */ - this.hasMouseHandlers = false; + // documented in AbstractRenderer + drawPoint: function (el) { + var f = Type.evaluate(el.visProp.face), + size = Type.evaluate(el.visProp.size), + scr = el.coords.scrCoords, + sqrt32 = size * Math.sqrt(3) * 0.5, + s05 = size * 0.5, + stroke05 = parseFloat(Type.evaluate(el.visProp.strokewidth)) / 2.0, + context = this.context; - /** - * A flag which tells if the board registers touch events. - * @type Boolean - * @default false - */ - this.hasTouchHandlers = false; + if (!el.visPropCalc.visible) { + return; + } - /** - * A flag which stores if the board registered pointer events. - * @type {Boolean} - * @default false - */ - this.hasPointerHandlers = false; + switch (f) { + case 'cross': // x + case 'x': + context.beginPath(); + context.moveTo(scr[1] - size, scr[2] - size); + context.lineTo(scr[1] + size, scr[2] + size); + context.moveTo(scr[1] + size, scr[2] - size); + context.lineTo(scr[1] - size, scr[2] + size); + context.lineCap = 'round'; + context.lineJoin = 'round'; + context.closePath(); + this._stroke(el); + break; + case 'circle': // dot + case 'o': + context.beginPath(); + context.arc(scr[1], scr[2], size + 1 + stroke05, 0, 2 * Math.PI, false); + context.closePath(); + this._fill(el); + this._stroke(el); + break; + case 'square': // rectangle + case '[]': + if (size <= 0) { + break; + } - /** - * A flag which tells if the board the JXG.Board#mouseUpListener is currently registered. - * @type Boolean - * @default false - */ - this.hasMouseUp = false; - - /** - * A flag which tells if the board the JXG.Board#touchEndListener is currently registered. - * @type Boolean - * @default false - */ - this.hasTouchEnd = false; + context.save(); + if (this._setColor(el, 'stroke', 'fill')) { + context.fillRect(scr[1] - size - stroke05, scr[2] - size - stroke05, size * 2 + 3 * stroke05, size * 2 + 3 * stroke05); + } + context.restore(); + context.save(); + this._setColor(el, 'fill'); + context.fillRect(scr[1] - size + stroke05, scr[2] - size + stroke05, size * 2 - stroke05, size * 2 - stroke05); + context.restore(); + break; + case 'plus': // + + case '+': + context.beginPath(); + context.moveTo(scr[1] - size, scr[2]); + context.lineTo(scr[1] + size, scr[2]); + context.moveTo(scr[1], scr[2] - size); + context.lineTo(scr[1], scr[2] + size); + context.lineCap = 'round'; + context.lineJoin = 'round'; + context.closePath(); + this._stroke(el); + break; + case 'diamond': // <> + case '<>': + context.beginPath(); + context.moveTo(scr[1] - size, scr[2]); + context.lineTo(scr[1], scr[2] + size); + context.lineTo(scr[1] + size, scr[2]); + context.lineTo(scr[1], scr[2] - size); + context.closePath(); + this._fill(el); + this._stroke(el); + break; + case 'triangleup': + case 'a': + case '^': + context.beginPath(); + context.moveTo(scr[1], scr[2] - size); + context.lineTo(scr[1] - sqrt32, scr[2] + s05); + context.lineTo(scr[1] + sqrt32, scr[2] + s05); + context.closePath(); + this._fill(el); + this._stroke(el); + break; + case 'triangledown': + case 'v': + context.beginPath(); + context.moveTo(scr[1], scr[2] + size); + context.lineTo(scr[1] - sqrt32, scr[2] - s05); + context.lineTo(scr[1] + sqrt32, scr[2] - s05); + context.closePath(); + this._fill(el); + this._stroke(el); + break; + case 'triangleleft': + case '<': + context.beginPath(); + context.moveTo(scr[1] - size, scr[2]); + context.lineTo(scr[1] + s05, scr[2] - sqrt32); + context.lineTo(scr[1] + s05, scr[2] + sqrt32); + context.closePath(); + this._fill(el); + this._stroke(el); + break; + case 'triangleright': + case '>': + context.beginPath(); + context.moveTo(scr[1] + size, scr[2]); + context.lineTo(scr[1] - s05, scr[2] - sqrt32); + context.lineTo(scr[1] - s05, scr[2] + sqrt32); + context.closePath(); + this._fill(el); + this._stroke(el); + break; + } + }, - /** - * A flag which tells us if the board has a pointerUp event registered at the moment. - * @type {Boolean} - * @default false - */ - this.hasPointerUp = false; + // documented in AbstractRenderer + updatePoint: function (el) { + this.drawPoint(el); + }, - /** - * Offset for large coords elements like images - * @type {Array} - * @private - * @default [0, 0] - */ - this._drag_offset = [0, 0]; + /* ******************************** * + * Lines * + * ******************************** */ /** - * Stores the input device used in the last down or move event. - * @type {String} + * Draws arrows of an element (usually a line) in canvas renderer. + * @param {JXG.GeometryElement} el Line to be drawn. + * @param {Array} scr1 Screen coordinates of the start position of the line or curve. + * @param {Array} scr2 Screen coordinates of the end position of the line or curve. + * @param {String} hl String which carries information if the element is highlighted. Used for getting the correct attribute. * @private - * @default 'mouse' */ - this._inputDevice = 'mouse'; + drawArrows: function (el, scr1, scr2, hl, a) { + var x1, y1, x2, y2, + w0, w, + arrowHead, + arrowTail, + context = this.context, + size = 6, + type = 1, + type_fa, type_la, + degree_fa = 1, + degree_la = 1, + doFill, + i, len, + d1x, d1y, d2x, d2y, last, + ang1, ang2, + ev_fa = a.evFirst, + ev_la = a.evLast; - this._board_touches = []; + if (Type.evaluate(el.visProp.strokecolor) !== 'none' && + (ev_fa || ev_la)) { - /** - * A flag which tells us if the board is in the selecting mode - * @type {Boolean} - * @default false - */ - this.selectingMode = false; + if (el.elementClass === Const.OBJECT_CLASS_LINE) { + x1 = scr1.scrCoords[1]; + y1 = scr1.scrCoords[2]; + x2 = scr2.scrCoords[1]; + y2 = scr2.scrCoords[2]; + ang1 = ang2 = Math.atan2(y2 - y1, x2 - x1); + } else { + x1 = el.points[0].scrCoords[1]; + y1 = el.points[0].scrCoords[2]; - /** - * A flag which tells us if the user is selecting - * @type {Boolean} - * @default false - */ - this.isSelecting = false; + last = el.points.length - 1; + if (last < 1) { + // No arrows for curves consisting of 1 point + return; + } + x2 = el.points[el.points.length - 1].scrCoords[1]; + y2 = el.points[el.points.length - 1].scrCoords[2]; - /** - * A bounding box for the selection - * @type {Array} - * @default [ [0,0], [0,0] ] - */ - this.selectingBox = [[0, 0], [0, 0]]; + d1x = el.points[1].scrCoords[1] - el.points[0].scrCoords[1]; + d1y = el.points[1].scrCoords[2] - el.points[0].scrCoords[2]; + d2x = el.points[last].scrCoords[1] - el.points[last - 1].scrCoords[1]; + d2y = el.points[last].scrCoords[2] - el.points[last - 1].scrCoords[2]; + if (ev_fa) { + ang1 = Math.atan2(d1y, d1x); + } + if (ev_la) { + ang2 = Math.atan2(d2y, d2x); + } + } - this.mathLib = Math; // Math or JXG.Math.IntervalArithmetic - this.mathLibJXG = JXG.Math; // JXG.Math or JXG.Math.IntervalArithmetic + w0 = Type.evaluate(el.visProp[hl + 'strokewidth']); - if (this.attr.registerevents) { - this.addEventHandlers(); - } + if (ev_fa) { + size = a.sizeFirst; - this.methodMap = { - update: 'update', - fullUpdate: 'fullUpdate', - on: 'on', - off: 'off', - trigger: 'trigger', - setView: 'setBoundingBox', - setBoundingBox: 'setBoundingBox', - migratePoint: 'migratePoint', - colorblind: 'emulateColorblindness', - suspendUpdate: 'suspendUpdate', - unsuspendUpdate: 'unsuspendUpdate', - clearTraces: 'clearTraces', - left: 'clickLeftArrow', - right: 'clickRightArrow', - up: 'clickUpArrow', - down: 'clickDownArrow', - zoomIn: 'zoomIn', - zoomOut: 'zoomOut', - zoom100: 'zoom100', - zoomElements: 'zoomElements', - remove: 'removeObject', - removeObject: 'removeObject' - }; - }; + w = w0 * size; - JXG.extend(JXG.Board.prototype, /** @lends JXG.Board.prototype */ { + type = a.typeFirst; + type_fa = type; - /** - * Generates an unique name for the given object. The result depends on the objects type, if the - * object is a {@link JXG.Point}, capital characters are used, if it is of type {@link JXG.Line} - * only lower case characters are used. If object is of type {@link JXG.Polygon}, a bunch of lower - * case characters prefixed with P_ are used. If object is of type {@link JXG.Circle} the name is - * generated using lower case characters. prefixed with k_ is used. In any other case, lower case - * chars prefixed with s_ is used. - * @param {Object} object Reference of an JXG.GeometryElement that is to be named. - * @returns {String} Unique name for the object. - */ - generateName: function (object) { - var possibleNames, i, - maxNameLength = this.attr.maxnamelength, - pre = '', - post = '', - indices = [], - name = ''; + if (type === 2) { + arrowTail = [ + [ w, -w * 0.5], + [ 0.0, 0.0], + [ w, w * 0.5], + [ w * 0.5, 0.0], + ]; + } else if (type === 3) { + arrowTail = [ + [ w / 3.0, -w * 0.5], + [ 0.0, -w * 0.5], + [ 0.0, w * 0.5], + [ w / 3.0, w * 0.5] + ]; + } else if (type === 4) { + w /= 10; + degree_fa = 3; + arrowTail = [ + [10.00, 3.31], + [6.47, 3.84], + [2.87, 4.50], + [0.00, 6.63], + [0.67, 5.52], + [1.33, 4.42], + [2.00, 3.31], + [1.33, 2.21], + [0.67, 1.10], + [0.00, 0.00], + [2.87, 2.13], + [6.47, 2.79], + [10.00, 3.31] + ]; + len = arrowTail.length; + for (i = 0; i < len; i++) { + arrowTail[i][0] *= -w; + arrowTail[i][1] *= w; + arrowTail[i][0] += 10 * w; + arrowTail[i][1] -= 3.31 * w; + } + } else if (type === 5) { + w /= 10; + degree_fa = 3; + arrowTail = [ + [10.00,3.28], + [6.61,4.19], + [3.19,5.07], + [0.00,6.55], + [0.62,5.56], + [1.00,4.44], + [1.00,3.28], + [1.00,2.11], + [0.62,0.99], + [0.00,0.00], + [3.19,1.49], + [6.61,2.37], + [10.00,3.28] + ]; + len = arrowTail.length; + for (i = 0; i < len; i++) { + arrowTail[i][0] *= -w; + arrowTail[i][1] *= w; + arrowTail[i][0] += 10 * w; + arrowTail[i][1] -= 3.28 * w; + } + } else if (type === 6) { + w /= 10; + degree_fa = 3; + arrowTail = [ + [10.00,2.84], + [6.61,3.59], + [3.21,4.35], + [0.00,5.68], + [0.33,4.73], + [0.67,3.78], + [1.00,2.84], + [0.67,1.89], + [0.33,0.95], + [0.00,0.00], + [3.21,1.33], + [6.61,2.09], + [10.00,2.84] + ]; + len = arrowTail.length; + for (i = 0; i < len; i++) { + arrowTail[i][0] *= -w; + arrowTail[i][1] *= w; + arrowTail[i][0] += 10 * w; + arrowTail[i][1] -= 2.84 * w; + } + } else if (type === 7) { + w = w0; + degree_fa = 3; + arrowTail = [ + [0.00,10.39], + [2.01,6.92], + [5.96,5.20], + [10.00,5.20], + [5.96,5.20], + [2.01,3.47], + [0.00,0.00] + ]; + len = arrowTail.length; + for (i = 0; i < len; i++) { + arrowTail[i][0] *= -w; + arrowTail[i][1] *= w; + arrowTail[i][0] += 10 * w; + arrowTail[i][1] -= 5.20 * w; + } + } else { + arrowTail = [ + [ w, -w * 0.5], + [ 0.0, 0.0], + [ w, w * 0.5] + ]; + } + } - if (object.type === Const.OBJECT_TYPE_TICKS) { - return ''; - } + if (ev_la) { + size = a.sizeLast; + w = w0 * size; - if (Type.isPoint(object)) { - // points have capital letters - possibleNames = ['', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', - 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']; - } else if (object.type === Const.OBJECT_TYPE_ANGLE) { - possibleNames = ['', 'α', 'β', 'γ', 'δ', 'ε', 'ζ', 'η', 'θ', - 'ι', 'κ', 'λ', 'μ', 'ν', 'ξ', 'ο', 'π', 'ρ', - 'σ', 'τ', 'υ', 'φ', 'χ', 'ψ', 'ω']; - } else { - // all other elements get lowercase labels - possibleNames = ['', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', - 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']; - } + type = a.typeLast; + type_la = type; + if (type === 2) { + arrowHead = [ + [ -w, -w * 0.5], + [ 0.0, 0.0], + [ -w, w * 0.5], + [ -w * 0.5, 0.0] + ]; + } else if (type === 3) { + arrowHead = [ + [-w / 3.0, -w * 0.5], + [ 0.0, -w * 0.5], + [ 0.0, w * 0.5], + [-w / 3.0, w * 0.5] + ]; + } else if (type === 4) { + w /= 10; + degree_la = 3; + arrowHead = [ + [10.00, 3.31], + [6.47, 3.84], + [2.87, 4.50], + [0.00, 6.63], + [0.67, 5.52], + [1.33, 4.42], + [2.00, 3.31], + [1.33, 2.21], + [0.67, 1.10], + [0.00, 0.00], + [2.87, 2.13], + [6.47, 2.79], + [10.00, 3.31] + ]; + len = arrowHead.length; + for (i = 0; i < len; i++) { + arrowHead[i][0] *= w; + arrowHead[i][1] *= w; + arrowHead[i][0] -= 10 * w; + arrowHead[i][1] -= 3.31 * w; - if (!Type.isPoint(object) && - object.elementClass !== Const.OBJECT_CLASS_LINE && - object.type !== Const.OBJECT_TYPE_ANGLE) { - if (object.type === Const.OBJECT_TYPE_POLYGON) { - pre = 'P_{'; - } else if (object.elementClass === Const.OBJECT_CLASS_CIRCLE) { - pre = 'k_{'; - } else if (object.elementClass === Const.OBJECT_CLASS_TEXT) { - pre = 't_{'; - } else { - pre = 's_{'; - } - post = '}'; - } + } + } else if (type === 5) { + w /= 10; + degree_la = 3; + arrowHead = [ + [10.00,3.28], + [6.61,4.19], + [3.19,5.07], + [0.00,6.55], + [0.62,5.56], + [1.00,4.44], + [1.00,3.28], + [1.00,2.11], + [0.62,0.99], + [0.00,0.00], + [3.19,1.49], + [6.61,2.37], + [10.00,3.28] + ]; + len = arrowHead.length; + for (i = 0; i < len; i++) { + arrowHead[i][0] *= w; + arrowHead[i][1] *= w; + arrowHead[i][0] -= 10 * w; + arrowHead[i][1] -= 3.28 * w; - for (i = 0; i < maxNameLength; i++) { - indices[i] = 0; - } + } + } else if (type === 6) { + w /= 10; + degree_la = 3; + arrowHead = [ + [10.00,2.84], + [6.61,3.59], + [3.21,4.35], + [0.00,5.68], + [0.33,4.73], + [0.67,3.78], + [1.00,2.84], + [0.67,1.89], + [0.33,0.95], + [0.00,0.00], + [3.21,1.33], + [6.61,2.09], + [10.00,2.84] + ]; + len = arrowHead.length; + for (i = 0; i < len; i++) { + arrowHead[i][0] *= w; + arrowHead[i][1] *= w; + arrowHead[i][0] -= 10 * w; + arrowHead[i][1] -= 2.84 * w; - while (indices[maxNameLength - 1] < possibleNames.length) { - for (indices[0] = 1; indices[0] < possibleNames.length; indices[0]++) { - name = pre; + } - for (i = maxNameLength; i > 0; i--) { - name += possibleNames[indices[i - 1]]; - } + } else if (type === 7) { + w = w0; + degree_la = 3; + arrowHead = [ + [0.00,10.39], + [2.01,6.92], + [5.96,5.20], + [10.00,5.20], + [5.96,5.20], + [2.01,3.47], + [0.00,0.00] + ]; + len = arrowHead.length; + for (i = 0; i < len; i++) { + arrowHead[i][0] *= w; + arrowHead[i][1] *= w; + arrowHead[i][0] -= 10 * w; + arrowHead[i][1] -= 5.20 * w; - if (!Type.exists(this.elementsByName[name + post])) { - return name + post; + } + } else { + arrowHead = [ + [ -w, -w * 0.5], + [ 0.0, 0.0], + [ -w, w * 0.5] + ]; } - } - indices[0] = possibleNames.length; - for (i = 1; i < maxNameLength; i++) { - if (indices[i - 1] === possibleNames.length) { - indices[i - 1] = 1; - indices[i] += 1; + context.save(); + if (this._setColor(el, 'stroke', 'fill')) { + this._setColor(el, 'stroke'); + if (ev_fa) { + if (type_fa === 7) { + doFill = false; + } else { + doFill = true; + } + this._drawPolygon(this._translateShape(this._rotateShape(arrowTail, ang1), x1, y1), degree_fa, doFill); + } + if (ev_la) { + if (type_la === 7) { + doFill = false; + } else { + doFill = true; + } + this._drawPolygon(this._translateShape(this._rotateShape(arrowHead, ang2), x2, y2), degree_la, doFill); } } + context.restore(); } - - return ''; }, - /** - * Generates unique id for a board. The result is randomly generated and prefixed with 'jxgBoard'. - * @returns {String} Unique id for a board. - */ - generateId: function () { - var r = 1; + // documented in AbstractRenderer + drawLine: function (el) { + var c1_org, c2_org, + c1 = new Coords(Const.COORDS_BY_USER, el.point1.coords.usrCoords, el.board), + c2 = new Coords(Const.COORDS_BY_USER, el.point2.coords.usrCoords, el.board), + margin = null, + hl, w, arrowData; - // as long as we don't have a unique id generate a new one - while (Type.exists(JXG.boards['jxgBoard' + r])) { - r = Math.round(Math.random() * 65535); + if (!el.visPropCalc.visible) { + return; } - return ('jxgBoard' + r); - }, + hl = this._getHighlighted(el); + w = Type.evaluate(el.visProp[hl + 'strokewidth']); + arrowData = this.getArrowHeadData(el, w, hl); - /** - * Composes an id for an element. If the ID is empty ('' or null) a new ID is generated, depending on the - * object type. As a side effect {@link JXG.Board#numObjects} - * is updated. - * @param {Object} obj Reference of an geometry object that needs an id. - * @param {Number} type Type of the object. - * @returns {String} Unique id for an element. - */ - setId: function (obj, type) { - var randomNumber, - num = this.numObjects, - elId = obj.id; + if (arrowData.evFirst || arrowData.evLast) { + margin = -4; + } + Geometry.calcStraight(el, c1, c2, margin); + this.handleTouchpoints(el, c1, c2, arrowData); - this.numObjects += 1; + c1_org = new Coords(Const.COORDS_BY_USER, c1.usrCoords, el.board); + c2_org = new Coords(Const.COORDS_BY_USER, c2.usrCoords, el.board); - // If no id is provided or id is empty string, a new one is chosen - if (elId === '' || !Type.exists(elId)) { - elId = this.id + type + num; - while (Type.exists(this.objects[elId])) { - randomNumber = Math.round(Math.random() * 65535); - elId = this.id + type + num + '-' + randomNumber; - } - } + this.getPositionArrowHead(el, c1, c2, arrowData); - obj.id = elId; - this.objects[elId] = obj; - obj._pos = this.objectsList.length; - this.objectsList[this.objectsList.length] = obj; + this.context.beginPath(); + this.context.moveTo(c1.scrCoords[1], c1.scrCoords[2]); + this.context.lineTo(c2.scrCoords[1], c2.scrCoords[2]); + this._stroke(el); - return elId; - }, + if ((arrowData.evFirst/* && obj.sFirst > 0*/) || + (arrowData.evLast/* && obj.sLast > 0*/)) { - /** - * After construction of the object the visibility is set - * and the label is constructed if necessary. - * @param {Object} obj The object to add. - */ - finalizeAdding: function (obj) { - if (Type.evaluate(obj.visProp.visible) === false) { - this.renderer.display(obj, false); + this.drawArrows(el, c1_org, c2_org, hl, arrowData); } }, - finalizeLabel: function (obj) { - if (obj.hasLabel && - !Type.evaluate(obj.label.visProp.islabel) && - Type.evaluate(obj.label.visProp.visible) === false) { - this.renderer.display(obj.label, false); - } + // documented in AbstractRenderer + updateLine: function (el) { + this.drawLine(el); }, - /********************************************************** - * - * Event Handler helpers - * - **********************************************************/ - - /** - * Returns false if the event has been triggered faster than the maximum frame rate. - * - * @param {Event} evt Event object given by the browser (unused) - * @returns {Boolean} If the event has been triggered faster than the maximum frame rate, false is returned. - * @private - * @see JXG.Board#pointerMoveListener - * @see JXG.Board#touchMoveListener - * @see JXG.Board#mouseMoveListener - */ - checkFrameRate: function(evt) { - var time = new Date().getTime(); - - if ((time - this.touchMoveLast) * this.attr.maxframerate < 1000) { - // this.updateQuality = this.BOARD_QUALITY_HIGH; - // this.triggerEventHandlers(['touchmove', 'move'], [evt, this.mode]); - - return false; - } - - this.touchMoveLast = time; - return true; + // documented in AbstractRenderer + drawTicks: function () { + // this function is supposed to initialize the svg/vml nodes in the SVG/VMLRenderer. + // but in canvas there are no such nodes, hence we just do nothing and wait until + // updateTicks is called. }, - /** - * Calculates mouse coordinates relative to the boards container. - * @returns {Array} Array of coordinates relative the boards container top left corner. - */ - getCoordsTopLeftCorner: function () { - var cPos, doc, crect, - docElement = this.document.documentElement || this.document.body.parentNode, - docBody = this.document.body, - container = this.containerObj, - viewport, content, - zoom, o; - - /** - * During drags and origin moves the container element is usually not changed. - * Check the position of the upper left corner at most every 1000 msecs - */ - if (this.cPos.length > 0 && - (this.mode === this.BOARD_MODE_DRAG || this.mode === this.BOARD_MODE_MOVE_ORIGIN || - (new Date()).getTime() - this.positionAccessLast < 1000)) { - return this.cPos; - } - this.positionAccessLast = (new Date()).getTime(); + // documented in AbstractRenderer + updateTicks: function (ticks) { + var i, c, x, y, + len = ticks.ticks.length, + len2, j, + context = this.context; - // Check if getBoundingClientRect exists. If so, use this as this covers *everything* - // even CSS3D transformations etc. - // Supported by all browsers but IE 6, 7. + context.beginPath(); + for (i = 0; i < len; i++) { + c = ticks.ticks[i]; + x = c[0]; + y = c[1]; - if (container.getBoundingClientRect) { - crect = container.getBoundingClientRect(); + // context.moveTo(x[0], y[0]); + // context.lineTo(x[1], y[1]); + len2 = x.length; + context.moveTo(x[0], y[0]); + for (j = 1; j < len2; ++j) { + context.lineTo(x[j], y[j]); + } + } + // Labels + // for (i = 0; i < len; i++) { + // c = ticks.ticks[i].scrCoords; + // if (ticks.ticks[i].major && + // (ticks.board.needsFullUpdate || ticks.needsRegularUpdate) && + // ticks.labels[i] && + // ticks.labels[i].visPropCalc.visible) { + // this.updateText(ticks.labels[i]); + // } + // } + context.lineCap = 'round'; + this._stroke(ticks); + }, - zoom = 1.0; - // Recursively search for zoom style entries. - // This is necessary for reveal.js on webkit. - // It fails if the user does zooming - o = container; - while (o && Type.exists(o.parentNode)) { - if (Type.exists(o.style) && Type.exists(o.style.zoom) && o.style.zoom !== '') { - zoom *= parseFloat(o.style.zoom); - } - o = o.parentNode; - } - cPos = [crect.left * zoom, crect.top * zoom]; + /* ************************** + * Curves + * **************************/ - // add border width - cPos[0] += Env.getProp(container, 'border-left-width'); - cPos[1] += Env.getProp(container, 'border-top-width'); + // documented in AbstractRenderer + drawCurve: function (el) { + var hl, w, arrowData; - // vml seems to ignore paddings - if (this.renderer.type !== 'vml') { - // add padding - cPos[0] += Env.getProp(container, 'padding-left'); - cPos[1] += Env.getProp(container, 'padding-top'); + if (Type.evaluate(el.visProp.handdrawing)) { + this.updatePathStringBezierPrim(el); + } else { + this.updatePathStringPrim(el); + } + if (el.numberPoints > 1) { + hl = this._getHighlighted(el); + w = Type.evaluate(el.visProp[hl + 'strokewidth']); + arrowData = this.getArrowHeadData(el, w, hl); + if ((arrowData.evFirst/* && obj.sFirst > 0*/) || + (arrowData.evLast/* && obj.sLast > 0*/)) { + this.drawArrows(el, null, null, hl, arrowData); } - - this.cPos = cPos.slice(); - return this.cPos; } + }, - // - // OLD CODE - // IE 6-7 only: - // - cPos = Env.getOffset(container); - doc = this.document.documentElement.ownerDocument; - - if (!this.containerObj.currentStyle && doc.defaultView) { // Non IE - // this is for hacks like this one used in wordpress for the admin bar: - // html { margin-top: 28px } - // seems like it doesn't work in IE + // documented in AbstractRenderer + updateCurve: function (el) { + this.drawCurve(el); + }, - cPos[0] += Env.getProp(docElement, 'margin-left'); - cPos[1] += Env.getProp(docElement, 'margin-top'); + /* ************************** + * Circle related stuff + * **************************/ - cPos[0] += Env.getProp(docElement, 'border-left-width'); - cPos[1] += Env.getProp(docElement, 'border-top-width'); + // documented in AbstractRenderer + drawEllipse: function (el) { + var m1 = el.center.coords.scrCoords[1], + m2 = el.center.coords.scrCoords[2], + sX = el.board.unitX, + sY = el.board.unitY, + rX = 2 * el.Radius(), + rY = 2 * el.Radius(), + aWidth = rX * sX, + aHeight = rY * sY, + aX = m1 - aWidth / 2, + aY = m2 - aHeight / 2, + hB = (aWidth / 2) * 0.5522848, + vB = (aHeight / 2) * 0.5522848, + eX = aX + aWidth, + eY = aY + aHeight, + mX = aX + aWidth / 2, + mY = aY + aHeight / 2, + context = this.context; - cPos[0] += Env.getProp(docElement, 'padding-left'); - cPos[1] += Env.getProp(docElement, 'padding-top'); + if (rX > 0.0 && rY > 0.0 && !isNaN(m1 + m2)) { + context.beginPath(); + context.moveTo(aX, mY); + context.bezierCurveTo(aX, mY - vB, mX - hB, aY, mX, aY); + context.bezierCurveTo(mX + hB, aY, eX, mY - vB, eX, mY); + context.bezierCurveTo(eX, mY + vB, mX + hB, eY, mX, eY); + context.bezierCurveTo(mX - hB, eY, aX, mY + vB, aX, mY); + context.closePath(); + this._fill(el); + this._stroke(el); } + }, - if (docBody) { - cPos[0] += Env.getProp(docBody, 'left'); - cPos[1] += Env.getProp(docBody, 'top'); - } + // documented in AbstractRenderer + updateEllipse: function (el) { + return this.drawEllipse(el); + }, - // Google Translate offers widgets for web authors. These widgets apparently tamper with the clientX - // and clientY coordinates of the mouse events. The minified sources seem to be the only publicly - // available version so we're doing it the hacky way: Add a fixed offset. - // see https://groups.google.com/d/msg/google-translate-general/H2zj0TNjjpY/jw6irtPlCw8J - if (typeof google === 'object' && google.translate) { - cPos[0] += 10; - cPos[1] += 25; - } + /* ************************** + * Polygon + * **************************/ - // add border width - cPos[0] += Env.getProp(container, 'border-left-width'); - cPos[1] += Env.getProp(container, 'border-top-width'); + // nothing here, using AbstractRenderer implementations - // vml seems to ignore paddings - if (this.renderer.type !== 'vml') { - // add padding - cPos[0] += Env.getProp(container, 'padding-left'); - cPos[1] += Env.getProp(container, 'padding-top'); - } + /* ************************** + * Text related stuff + * **************************/ - cPos[0] += this.attr.offsetx; - cPos[1] += this.attr.offsety; + // Already documented in JXG.AbstractRenderer + displayCopyright: function (str, fontSize) { + var context = this.context; - this.cPos = cPos.slice(); - return this.cPos; + // this should be called on EVERY update, otherwise it won't be shown after the first update + context.save(); + context.font = fontSize + 'px Arial'; + context.fillStyle = '#aaa'; + context.lineWidth = 0.5; + context.fillText(str, 10, 2 + fontSize); + context.restore(); }, - /** - * Get the position of the mouse in screen coordinates, relative to the upper left corner - * of the host tag. - * @param {Event} e Event object given by the browser. - * @param {Number} [i] Only use in case of touch events. This determines which finger to use and should not be set - * for mouseevents. - * @returns {Array} Contains the mouse coordinates in screen coordinates, ready for {@link JXG.Coords} - */ - getMousePosition: function (e, i) { - var cPos = this.getCoordsTopLeftCorner(), - absPos, - v; + // Already documented in JXG.AbstractRenderer + drawInternalText: function (el) { + var ev_fs = Type.evaluate(el.visProp.fontsize), + fontUnit = Type.evaluate(el.visProp.fontunit), + ev_ax = el.getAnchorX(), + ev_ay = el.getAnchorY(), + context = this.context; - // position of mouse cursor relative to containers position of container - absPos = Env.getPosition(e, i, this.document); + context.save(); + if (this._setColor(el, 'stroke', 'fill') && + !isNaN(el.coords.scrCoords[1] + el.coords.scrCoords[2])) { + context.font = (ev_fs > 0 ? ev_fs : 0) + fontUnit + ' Arial'; - /** - * In case there has been no down event before. - */ - if (!Type.exists(this.cssTransMat)) { - this.updateCSSTransforms(); + this.transformImage(el, el.transformations); + if (ev_ax === 'left') { + context.textAlign = 'left'; + } else if (ev_ax === 'right') { + context.textAlign = 'right'; + } else if (ev_ax === 'middle') { + context.textAlign = 'center'; + } + if (ev_ay === 'bottom') { + context.textBaseline = 'bottom'; + } else if (ev_ay === 'top') { + context.textBaseline = 'top'; + } else if (ev_ay === 'middle') { + context.textBaseline = 'middle'; + } + context.fillText(el.plaintext, el.coords.scrCoords[1], el.coords.scrCoords[2]); } - v = [1, absPos[0] - cPos[0], absPos[1] - cPos[1]]; - v = Mat.matVecMult(this.cssTransMat, v); - v[1] /= v[0]; - v[2] /= v[0]; - return [v[1], v[2]]; + context.restore(); + return null; + }, - // Method without CSS transformation - /* - return [absPos[0] - cPos[0], absPos[1] - cPos[1]]; - */ + // Already documented in JXG.AbstractRenderer + updateInternalText: function (el) { + this.drawInternalText(el); }, - /** - * Initiate moving the origin. This is used in mouseDown and touchStart listeners. - * @param {Number} x Current mouse/touch coordinates - * @param {Number} y Current mouse/touch coordinates - */ - initMoveOrigin: function (x, y) { - this.drag_dx = x - this.origin.scrCoords[1]; - this.drag_dy = y - this.origin.scrCoords[2]; + // documented in JXG.AbstractRenderer + // Only necessary for texts + setObjectStrokeColor: function (el, color, opacity) { + var rgba = Type.evaluate(color), c, rgbo, + o = Type.evaluate(opacity), oo, + node; - this.mode = this.BOARD_MODE_MOVE_ORIGIN; - this.updateQuality = this.BOARD_QUALITY_LOW; - }, + o = (o > 0) ? o : 0; - /** - * Collects all elements below the current mouse pointer and fulfilling the following constraints: - * <ul><li>isDraggable</li><li>visible</li><li>not fixed</li><li>not frozen</li></ul> - * @param {Number} x Current mouse/touch coordinates - * @param {Number} y current mouse/touch coordinates - * @param {Object} evt An event object - * @param {String} type What type of event? 'touch', 'mouse' or 'pen'. - * @returns {Array} A list of geometric elements. - */ - initMoveObject: function (x, y, evt, type) { - var pEl, - el, - collect = [], - offset = [], - haspoint, - len = this.objectsList.length, - dragEl = {visProp: {layer: -10000}}; + if (el.visPropOld.strokecolor === rgba && el.visPropOld.strokeopacity === o) { + return; + } - //for (el in this.objects) { - for (el = 0; el < len; el++) { - pEl = this.objectsList[el]; - haspoint = pEl.hasPoint && pEl.hasPoint(x, y); + // Check if this could be merged with _setColor - if (pEl.visPropCalc.visible && haspoint) { - pEl.triggerEventHandlers([type + 'down', 'down'], [evt]); - this.downObjects.push(pEl); + if (Type.exists(rgba) && rgba !== false) { + // RGB, not RGBA + if (rgba.length !== 9) { + c = rgba; + oo = o; + // True RGBA, not RGB + } else { + rgbo = Color.rgba2rgbo(rgba); + c = rgbo[0]; + oo = o * rgbo[1]; + } + node = el.rendNode; + if (el.elementClass === Const.OBJECT_CLASS_TEXT && Type.evaluate(el.visProp.display) === 'html') { + node.style.color = c; + node.style.opacity = oo; } + } - if (haspoint && - pEl.isDraggable && - pEl.visPropCalc.visible && - ((this.geonextCompatibilityMode && - (Type.isPoint(pEl) || - pEl.elementClass === Const.OBJECT_CLASS_TEXT) - ) || - !this.geonextCompatibilityMode - ) && - !Type.evaluate(pEl.visProp.fixed) - /*(!pEl.visProp.frozen) &&*/ - ) { + el.visPropOld.strokecolor = rgba; + el.visPropOld.strokeopacity = o; + }, - // Elements in the highest layer get priority. - if (pEl.visProp.layer > dragEl.visProp.layer || - (pEl.visProp.layer === dragEl.visProp.layer && - pEl.lastDragTime.getTime() >= dragEl.lastDragTime.getTime() - )) { - // If an element and its label have the focus - // simultaneously, the element is taken. - // This only works if we assume that every browser runs - // through this.objects in the right order, i.e. an element A - // added before element B turns up here before B does. - if (!this.attr.ignorelabels || - (!Type.exists(dragEl.label) || pEl !== dragEl.label)) { - dragEl = pEl; - collect.push(dragEl); + /* ************************** + * Image related stuff + * **************************/ - // Save offset for large coords elements. - if (Type.exists(dragEl.coords)) { - offset.push(Statistics.subtract(dragEl.coords.scrCoords.slice(1), [x, y])); - } else { - offset.push([0, 0]); - } + // Already documented in JXG.AbstractRenderer + drawImage: function (el) { + el.rendNode = new Image(); + // Store the file name of the image. + // Before, this was done in el.rendNode.src + // But there, the file name is expanded to + // the full url. This may be different from + // the url computed in updateImageURL(). + el._src = ''; + this.updateImage(el); + }, - // we can't drop out of this loop because of the event handling system - //if (this.attr.takefirst) { - // return collect; - //} - } + // Already documented in JXG.AbstractRenderer + updateImage: function (el) { + var context = this.context, + o = Type.evaluate(el.visProp.fillopacity), + paintImg = Type.bind(function () { + el.imgIsLoaded = true; + if (el.size[0] <= 0 || el.size[1] <= 0) { + return; } + context.save(); + context.globalAlpha = o; + // If det(el.transformations)=0, FireFox 3.6. breaks down. + // This is tested in transformImage + this.transformImage(el, el.transformations); + context.drawImage(el.rendNode, + el.coords.scrCoords[1], + el.coords.scrCoords[2] - el.size[1], + el.size[0], + el.size[1]); + context.restore(); + }, this); + + if (this.updateImageURL(el)) { + el.rendNode.onload = paintImg; + } else { + if (el.imgIsLoaded) { + paintImg(); } } + }, - if (this.attr.drag.enabled && collect.length > 0) { - this.mode = this.BOARD_MODE_DRAG; - } + // Already documented in JXG.AbstractRenderer + transformImage: function (el, t) { + var m, len = t.length, + ctx = this.context; - // A one-element array is returned. - if (this.attr.takefirst) { - collect.length = 1; - this._drag_offset = offset[0]; - } else { - collect = collect.slice(-1); - this._drag_offset = offset[offset.length - 1]; + if (len > 0) { + m = this.joinTransforms(el, t); + if (Math.abs(Numerics.det(m)) >= Mat.eps) { + ctx.transform(m[1][1], m[2][1], m[1][2], m[2][2], m[1][0], m[2][0]); + } } + }, - if (!this._drag_offset) { - this._drag_offset = [0, 0]; + // Already documented in JXG.AbstractRenderer + updateImageURL: function (el) { + var url; + + url = Type.evaluate(el.url); + if (el._src !== url) { + el.imgIsLoaded = false; + el.rendNode.src = url; + el._src = url; + return true; } - // Move drag element to the top of the layer - if (this.renderer.type === 'svg' && - Type.exists(collect[0]) && - Type.evaluate(collect[0].visProp.dragtotopoflayer) && - collect.length === 1 && - Type.exists(collect[0].rendNode)) { - - collect[0].rendNode.parentNode.appendChild(collect[0].rendNode); - } + return false; + }, - // Init rotation angle and scale factor for two finger movements - this.previousRotation = 0.0; - this.previousScale = 1.0; + /* ************************** + * Render primitive objects + * **************************/ - if (collect.length >= 1) { - collect[0].highlight(true); - this.triggerEventHandlers(['mousehit', 'hit'], [evt, collect[0]]); + // documented in AbstractRenderer + remove: function (shape) { + // sounds odd for a pixel based renderer but we need this for html texts + if (Type.exists(shape) && Type.exists(shape.parentNode)) { + shape.parentNode.removeChild(shape); } - - return collect; }, - /** - * Moves an object. - * @param {Number} x Coordinate - * @param {Number} y Coordinate - * @param {Object} o The touch object that is dragged: {JXG.Board#mouse} or {JXG.Board#touches}. - * @param {Object} evt The event object. - * @param {String} type Mouse or touch event? - */ - moveObject: function (x, y, o, evt, type) { - var newPos = new Coords(Const.COORDS_BY_SCREEN, this.getScrCoordsOfMouse(x, y), this), - drag, - dragScrCoords, newDragScrCoords; + // documented in AbstractRenderer + updatePathStringPrim: function (el) { + var i, scr, scr1, scr2, len, + symbm = 'M', + symbl = 'L', + symbc = 'C', + nextSymb = symbm, + maxSize = 5000.0, + context = this.context; - if (!(o && o.obj)) { + if (el.numberPoints <= 0) { return; } - drag = o.obj; - - // Save updates for very small movements of coordsElements, see below - if (drag.coords) { - dragScrCoords = drag.coords.scrCoords.slice(); - } - /* - * Save the position. - */ - this.drag_position = [newPos.scrCoords[1], newPos.scrCoords[2]]; - this.drag_position = Statistics.add(this.drag_position, this._drag_offset); - // - // We have to distinguish between CoordsElements and other elements like lines. - // The latter need the difference between two move events. - if (Type.exists(drag.coords)) { - drag.setPositionDirectly(Const.COORDS_BY_SCREEN, this.drag_position); - } else { - this.displayInfobox(false); - // Hide infobox in case the user has touched an intersection point - // and drags the underlying line now. + len = Math.min(el.points.length, el.numberPoints); + context.beginPath(); - if (!isNaN(o.targets[0].Xprev + o.targets[0].Yprev)) { - drag.setPositionDirectly(Const.COORDS_BY_SCREEN, - [newPos.scrCoords[1], newPos.scrCoords[2]], - [o.targets[0].Xprev, o.targets[0].Yprev] - ); + if (el.bezierDegree === 1) { + /* + if (isNotPlot && el.board.options.curve.RDPsmoothing) { + el.points = Numerics.RamerDouglasPeucker(el.points, 0.5); } - // Remember the actual position for the next move event. Then we are able to - // compute the difference vector. - o.targets[0].Xprev = newPos.scrCoords[1]; - o.targets[0].Yprev = newPos.scrCoords[2]; - } - // This may be necessary for some gliders and labels - if (Type.exists(drag.coords)) { - drag.prepareUpdate().update(false).updateRenderer(); - this.updateInfobox(drag); - drag.prepareUpdate().update(true).updateRenderer(); - } + */ - if (drag.coords) { - newDragScrCoords = drag.coords.scrCoords; - } - // No updates for very small movements of coordsElements - if (!drag.coords || - dragScrCoords[1] !== newDragScrCoords[1] || - dragScrCoords[2] !== newDragScrCoords[2]) { + for (i = 0; i < len; i++) { + scr = el.points[i].scrCoords; - drag.triggerEventHandlers([type + 'drag', 'drag'], [evt]); + if (isNaN(scr[1]) || isNaN(scr[2])) { // PenUp + nextSymb = symbm; + } else { + // Chrome has problems with values being too far away. + if (scr[1] > maxSize) { + scr[1] = maxSize; + } else if (scr[1] < -maxSize) { + scr[1] = -maxSize; + } - this.update(); - } - drag.highlight(true); - this.triggerEventHandlers(['mousehit', 'hit'], [evt, drag]); + if (scr[2] > maxSize) { + scr[2] = maxSize; + } else if (scr[2] < -maxSize) { + scr[2] = -maxSize; + } - drag.lastDragTime = new Date(); + if (nextSymb === symbm) { + context.moveTo(scr[1], scr[2]); + } else { + context.lineTo(scr[1], scr[2]); + } + nextSymb = symbl; + } + } + } else if (el.bezierDegree === 3) { + i = 0; + while (i < len) { + scr = el.points[i].scrCoords; + if (isNaN(scr[1]) || isNaN(scr[2])) { // PenUp + nextSymb = symbm; + } else { + if (nextSymb === symbm) { + context.moveTo(scr[1], scr[2]); + } else { + i += 1; + scr1 = el.points[i].scrCoords; + i += 1; + scr2 = el.points[i].scrCoords; + context.bezierCurveTo(scr[1], scr[2], scr1[1], scr1[2], scr2[1], scr2[2]); + } + nextSymb = symbc; + } + i += 1; + } + } + context.lineCap = 'round'; + this._fill(el); + this._stroke(el); }, - /** - * Moves elements in multitouch mode. - * @param {Array} p1 x,y coordinates of first touch - * @param {Array} p2 x,y coordinates of second touch - * @param {Object} o The touch object that is dragged: {JXG.Board#touches}. - * @param {Object} evt The event object that lead to this movement. - */ - twoFingerMove: function (p1, p2, o, evt) { - var np1c, np2c, drag; + // Already documented in JXG.AbstractRenderer + updatePathStringBezierPrim: function (el) { + var i, j, k, scr, lx, ly, len, + symbm = 'M', + symbl = 'C', + nextSymb = symbm, + maxSize = 5000.0, + f = Type.evaluate(el.visProp.strokewidth), + isNoPlot = (Type.evaluate(el.visProp.curvetype) !== 'plot'), + context = this.context; - if (Type.exists(o) && Type.exists(o.obj)) { - drag = o.obj; - } else { + if (el.numberPoints <= 0) { return; } - // New finger position - np1c = new Coords(Const.COORDS_BY_SCREEN, this.getScrCoordsOfMouse(p1[0], p1[1]), this); - np2c = new Coords(Const.COORDS_BY_SCREEN, this.getScrCoordsOfMouse(p2[0], p2[1]), this); - - if (drag.elementClass === Const.OBJECT_CLASS_LINE || - drag.type === Const.OBJECT_TYPE_POLYGON) { - this.twoFingerTouchObject(np1c, np2c, o, drag, evt); - } else if (drag.elementClass === Const.OBJECT_CLASS_CIRCLE) { - this.twoFingerTouchCircle(np1c, np2c, o, drag); + if (isNoPlot && el.board.options.curve.RDPsmoothing) { + el.points = Numerics.RamerDouglasPeucker(el.points, 0.5); } - drag.triggerEventHandlers(['touchdrag', 'drag'], [evt]); - - o.targets[0].Xprev = np1c.scrCoords[1]; - o.targets[0].Yprev = np1c.scrCoords[2]; - o.targets[1].Xprev = np2c.scrCoords[1]; - o.targets[1].Yprev = np2c.scrCoords[2]; - }, - - /** - * Moves, rotates and scales a line or polygon with two fingers. - * @param {JXG.Coords} np1c x,y coordinates of first touch - * @param {JXG.Coords} np2c x,y coordinates of second touch - * @param {object} o The touch object that is dragged: {JXG.Board#touches}. - * @param {object} drag The object that is dragged: - * @param {Object} evt The event object that lead to this movement. - */ - twoFingerTouchObject: function (np1c, np2c, o, drag, evt) { - var np1, np2, op1, op2, - nmid, omid, nd, od, - d, alpha, - S, t1, t2, t3, t4, t5, - ar, i, len, - pi180 = 0.017453292519943295; // Math.PI / 180.0 - - if (Type.exists(o.targets[0]) && - Type.exists(o.targets[1]) && - !isNaN(o.targets[0].Xprev + o.targets[0].Yprev + o.targets[1].Xprev + o.targets[1].Yprev)) { - - // Actual fingers' position - np1 = np1c.usrCoords; - np2 = np2c.usrCoords; - - // Previous fingers' position - op1 = (new Coords(Const.COORDS_BY_SCREEN, [o.targets[0].Xprev, o.targets[0].Yprev], this)).usrCoords; - op2 = (new Coords(Const.COORDS_BY_SCREEN, [o.targets[1].Xprev, o.targets[1].Yprev], this)).usrCoords; - - // Affine mid points of the old and new positions - omid = [1, (op1[1] + op2[1]) * 0.5, (op1[2] + op2[2]) * 0.5]; - nmid = [1, (np1[1] + np2[1]) * 0.5, (np1[2] + np2[2]) * 0.5]; - - // Old and new directions - od = Mat.crossProduct(op1, op2); - nd = Mat.crossProduct(np1, np2); - - // Intersection between the two directions - S = Mat.crossProduct(od, nd); - - // If parallel translate, otherwise rotate - if (Math.abs(S[0]) < Mat.eps) { - return; - } - - // Normalize the coordinates - S[1] /= S[0]; - S[2] /= S[0]; - - if (Type.exists(evt.rotation) && evt.type !== 'pointermove') { - // iOS touch events contain the angle for free - alpha = evt.rotation - this.previousRotation; - this.previousRotation = evt.rotation; - alpha *= -pi180; - } else { - // For pointer events, the rotation angle has to be calculated. - alpha = Geometry.rad(omid.slice(1), S.slice(1), nmid.slice(1)); - } - - t1 = this.create('transform', [alpha, S[1], S[2]], {type: 'rotate'}); - - // Old midpoint of fingers after first transformation: - t1.update(); - omid = Mat.matVecMult(t1.matrix, omid); - omid[1] /= omid[0]; - omid[2] /= omid[0]; + len = Math.min(el.points.length, el.numberPoints); + context.beginPath(); - // Shift to the new mid point - t2 = this.create('transform', [nmid[1] - omid[1], nmid[2] - omid[2]], {type: 'translate'}); - t2.update(); + for (j = 1; j < 3; j++) { + nextSymb = symbm; + for (i = 0; i < len; i++) { + scr = el.points[i].scrCoords; - t1.melt(t2); - if (Type.evaluate(drag.visProp.scalable)) { - // Scale - if (Type.exists(evt.scale)) { - d = evt.scale / this.previousScale; - this.previousScale = evt.scale; + if (isNaN(scr[1]) || isNaN(scr[2])) { // PenUp + nextSymb = symbm; } else { - d = Geometry.distance(np1, np2) / Geometry.distance(op1, op2); - } + // Chrome has problems with values being too far away. + if (scr[1] > maxSize) { + scr[1] = maxSize; + } else if (scr[1] < -maxSize) { + scr[1] = -maxSize; + } - t3 = this.create('transform', [-nmid[1], -nmid[2]], {type: 'translate'}); - t4 = this.create('transform', [d, d], {type: 'scale'}); - t5 = this.create('transform', [nmid[1], nmid[2]], {type: 'translate'}); - t1.melt(t3).melt(t4).melt(t5); - } + if (scr[2] > maxSize) { + scr[2] = maxSize; + } else if (scr[2] < -maxSize) { + scr[2] = -maxSize; + } - if (drag.elementClass === Const.OBJECT_CLASS_LINE) { - ar = []; - if (drag.point1.draggable()) { - ar.push(drag.point1); - } - if (drag.point2.draggable()) { - ar.push(drag.point2); - } - t1.applyOnce(ar); - } else if (drag.type === Const.OBJECT_TYPE_POLYGON) { - ar = []; - len = drag.vertices.length - 1; - for (i = 0; i < len; ++i) { - if (drag.vertices[i].draggable()) { - ar.push(drag.vertices[i]); + if (nextSymb === symbm) { + context.moveTo(scr[1], scr[2]); + } else { + k = 2 * j; + context.bezierCurveTo( + (lx + (scr[1] - lx) * 0.333 + f * (k * Math.random() - j)), + (ly + (scr[2] - ly) * 0.333 + f * (k * Math.random() - j)), + (lx + (scr[1] - lx) * 0.666 + f * (k * Math.random() - j)), + (ly + (scr[2] - ly) * 0.666 + f * (k * Math.random() - j)), + scr[1], + scr[2] + ); } + nextSymb = symbl; + lx = scr[1]; + ly = scr[2]; } - t1.applyOnce(ar); } - - this.update(); - drag.highlight(true); } + context.lineCap = 'round'; + this._fill(el); + this._stroke(el); }, - /* - * Moves, rotates and scales a circle with two fingers. - * @param {JXG.Coords} np1c x,y coordinates of first touch - * @param {JXG.Coords} np2c x,y coordinates of second touch - * @param {object} o The touch object that is dragged: {JXG.Board#touches}. - * @param {object} drag The object that is dragged: - */ - twoFingerTouchCircle: function (np1c, np2c, o, drag) { - var np1, np2, op1, op2, - d, alpha, t1, t2, t3, t4, t5; + // documented in AbstractRenderer + updatePolygonPrim: function (node, el) { + var scrCoords, i, j, + len = el.vertices.length, + context = this.context, + isReal = true; - if (drag.method === 'pointCircle' || - drag.method === 'pointLine') { + if (len <= 0 || !el.visPropCalc.visible) { return; } + if (el.elType === 'polygonalchain') { + len++; + } - if (Type.exists(o.targets[0]) && - Type.exists(o.targets[1]) && - !isNaN(o.targets[0].Xprev + o.targets[0].Yprev + o.targets[1].Xprev + o.targets[1].Yprev)) { - - np1 = np1c.usrCoords; - np2 = np2c.usrCoords; - // Previous finger position - op1 = (new Coords(Const.COORDS_BY_SCREEN, [o.targets[0].Xprev, o.targets[0].Yprev], this)).usrCoords; - op2 = (new Coords(Const.COORDS_BY_SCREEN, [o.targets[1].Xprev, o.targets[1].Yprev], this)).usrCoords; - - // Shift by the movement of the first finger - t1 = this.create('transform', [np1[1] - op1[1], np1[2] - op1[2]], {type: 'translate'}); - alpha = Geometry.rad(op2.slice(1), np1.slice(1), np2.slice(1)); - - // Rotate and scale by the movement of the second finger - t2 = this.create('transform', [-np1[1], -np1[2]], {type: 'translate'}); - t3 = this.create('transform', [alpha], {type: 'rotate'}); - t1.melt(t2).melt(t3); - - if (Type.evaluate(drag.visProp.scalable)) { - d = Geometry.distance(np1, np2) / Geometry.distance(op1, op2); - t4 = this.create('transform', [d, d], {type: 'scale'}); - t1.melt(t4); - } - t5 = this.create('transform', [np1[1], np1[2]], {type: 'translate'}); - t1.melt(t5); - - if (drag.center.draggable()) { - t1.applyOnce([drag.center]); - } + context.beginPath(); + i = 0; + while (!el.vertices[i].isReal && i < len - 1) { + i++; + isReal = false; + } + scrCoords = el.vertices[i].coords.scrCoords; + context.moveTo(scrCoords[1], scrCoords[2]); - if (drag.method === 'twoPoints') { - if (drag.point2.draggable()) { - t1.applyOnce([drag.point2]); - } - } else if (drag.method === 'pointRadius') { - if (Type.isNumber(drag.updateRadius.origin)) { - drag.setRadius(drag.radius * d); - } + for (j = i; j < len - 1; j++) { + if (!el.vertices[j].isReal) { + isReal = false; } + scrCoords = el.vertices[j].coords.scrCoords; + context.lineTo(scrCoords[1], scrCoords[2]); + } + context.closePath(); - this.update(drag.center); - drag.highlight(true); + if (isReal) { + this._fill(el); // The edges of a polygon are displayed separately (as segments). } }, - highlightElements: function (x, y, evt, target) { - var el, pEl, pId, - overObjects = {}, - len = this.objectsList.length; + // ************************** Set Attributes ************************* - // Elements below the mouse pointer which are not highlighted yet will be highlighted. - for (el = 0; el < len; el++) { - pEl = this.objectsList[el]; - pId = pEl.id; - if (Type.exists(pEl.hasPoint) && pEl.visPropCalc.visible && pEl.hasPoint(x, y)) { - // this is required in any case because otherwise the box won't be shown until the point is dragged - this.updateInfobox(pEl); + // Already documented in JXG.AbstractRenderer + display: function(el, val) { + if (el && el.rendNode) { + el.visPropOld.visible = val; + if (val) { + el.rendNode.style.visibility = "inherit"; + } else { + el.rendNode.style.visibility = "hidden"; + } + } + }, - if (!Type.exists(this.highlightedObjects[pId])) { // highlight only if not highlighted - overObjects[pId] = pEl; - pEl.highlight(); - // triggers board event. - this.triggerEventHandlers(['mousehit', 'hit'], [evt, pEl, target]); - } + // documented in AbstractRenderer + show: function (el) { + JXG.deprecated('Board.renderer.show()', 'Board.renderer.display()'); - if (pEl.mouseover) { - pEl.triggerEventHandlers(['mousemove', 'move'], [evt]); - } else { - pEl.triggerEventHandlers(['mouseover', 'over'], [evt]); - pEl.mouseover = true; - } - } + if (Type.exists(el.rendNode)) { + el.rendNode.style.visibility = "inherit"; } + }, - for (el = 0; el < len; el++) { - pEl = this.objectsList[el]; - pId = pEl.id; - if (pEl.mouseover) { - if (!overObjects[pId]) { - pEl.triggerEventHandlers(['mouseout', 'out'], [evt]); - pEl.mouseover = false; - } - } + // documented in AbstractRenderer + hide: function (el) { + JXG.deprecated('Board.renderer.hide()', 'Board.renderer.display()'); + + if (Type.exists(el.rendNode)) { + el.rendNode.style.visibility = "hidden"; } }, - /** - * Helper function which returns a reasonable starting point for the object being dragged. - * Formerly known as initXYstart(). - * @private - * @param {JXG.GeometryElement} obj The object to be dragged - * @param {Array} targets Array of targets. It is changed by this function. - */ - saveStartPos: function (obj, targets) { - var xy = [], i, len; + // documented in AbstractRenderer + setGradient: function (el) { + var // col, + op; - if (obj.type === Const.OBJECT_TYPE_TICKS) { - xy.push([1, NaN, NaN]); - } else if (obj.elementClass === Const.OBJECT_CLASS_LINE) { - xy.push(obj.point1.coords.usrCoords); - xy.push(obj.point2.coords.usrCoords); - } else if (obj.elementClass === Const.OBJECT_CLASS_CIRCLE) { - xy.push(obj.center.coords.usrCoords); - if (obj.method === 'twoPoints') { - xy.push(obj.point2.coords.usrCoords); - } - } else if (obj.type === Const.OBJECT_TYPE_POLYGON) { - len = obj.vertices.length - 1; - for (i = 0; i < len; i++) { - xy.push(obj.vertices[i].coords.usrCoords); - } - } else if (obj.type === Const.OBJECT_TYPE_SECTOR) { - xy.push(obj.point1.coords.usrCoords); - xy.push(obj.point2.coords.usrCoords); - xy.push(obj.point3.coords.usrCoords); - } else if (Type.isPoint(obj) || obj.type === Const.OBJECT_TYPE_GLIDER) { - xy.push(obj.coords.usrCoords); - } else if (obj.elementClass === Const.OBJECT_CLASS_CURVE) { - // if (Type.exists(obj.parents)) { - // len = obj.parents.length; - // if (len > 0) { - // for (i = 0; i < len; i++) { - // xy.push(this.select(obj.parents[i]).coords.usrCoords); - // } - // } else - // } - if (obj.points.length > 0) { - xy.push(obj.points[0].usrCoords); - } - } else { - try { - xy.push(obj.coords.usrCoords); - } catch (e) { - JXG.debug('JSXGraph+ saveStartPos: obj.coords.usrCoords not available: ' + e); - } - } + op = Type.evaluate(el.visProp.fillopacity); + op = (op > 0) ? op : 0; - len = xy.length; - for (i = 0; i < len; i++) { - targets.Zstart.push(xy[i][0]); - targets.Xstart.push(xy[i][1]); - targets.Ystart.push(xy[i][2]); - } + // col = Type.evaluate(el.visProp.fillcolor); }, - mouseOriginMoveStart: function (evt) { - var r, pos; - - r = this._isRequiredKeyPressed(evt, 'pan'); - if (r) { - pos = this.getMousePosition(evt); - this.initMoveOrigin(pos[0], pos[1]); + // documented in AbstractRenderer + setShadow: function (el) { + if (el.visPropOld.shadow === el.visProp.shadow) { + return; } - return r; - }, + // not implemented yet + // we simply have to redraw the element + // probably the best way to do so would be to call el.updateRenderer(), i think. - mouseOriginMove: function (evt) { - var r = (this.mode === this.BOARD_MODE_MOVE_ORIGIN), - pos; + el.visPropOld.shadow = el.visProp.shadow; + }, - if (r) { - pos = this.getMousePosition(evt); - this.moveOrigin(pos[0], pos[1], true); + // documented in AbstractRenderer + highlight: function (obj) { + if (obj.elementClass === Const.OBJECT_CLASS_TEXT && Type.evaluate(obj.visProp.display) === 'html') { + this.updateTextStyle(obj, true); + } else { + obj.board.prepareUpdate(); + obj.board.renderer.suspendRedraw(obj.board); + obj.board.updateRenderer(); + obj.board.renderer.unsuspendRedraw(); } + return this; + }, - return r; + // documented in AbstractRenderer + noHighlight: function (obj) { + if (obj.elementClass === Const.OBJECT_CLASS_TEXT && Type.evaluate(obj.visProp.display) === 'html') { + this.updateTextStyle(obj, false); + } else { + obj.board.prepareUpdate(); + obj.board.renderer.suspendRedraw(obj.board); + obj.board.updateRenderer(); + obj.board.renderer.unsuspendRedraw(); + } + return this; }, - /** - * Start moving the origin with one finger. - * @private - * @param {Object} evt Event from touchStartListener - * @return {Boolean} returns if the origin is moved. - */ - touchOriginMoveStart: function (evt) { - var touches = evt[JXG.touchProperty], - r, pos; + /* ************************** + * renderer control + * **************************/ - r = this.attr.pan.enabled && - !this.attr.pan.needtwofingers && - touches.length === 1; + // documented in AbstractRenderer + suspendRedraw: function (board) { + this.context.save(); + this.context.clearRect(0, 0, this.canvasRoot.width, this.canvasRoot.height); - if (r) { - pos = this.getMousePosition(evt, 0); - this.initMoveOrigin(pos[0], pos[1]); + if (board && board.attr.showcopyright) { + this.displayCopyright(JXG.licenseText, 12); } + }, - return r; + // documented in AbstractRenderer + unsuspendRedraw: function () { + this.context.restore(); }, - /** - * Move the origin with one finger - * @private - * @param {Object} evt Event from touchMoveListener - * @return {Boolean} returns if the origin is moved. - */ - touchOriginMove: function (evt) { - var r = (this.mode === this.BOARD_MODE_MOVE_ORIGIN), - pos; + // document in AbstractRenderer + resize: function (w, h) { + if (this.container) { + this.canvasRoot.style.width = parseFloat(w) + 'px'; + this.canvasRoot.style.height = parseFloat(h) + 'px'; - if (r) { - pos = this.getMousePosition(evt, 0); - this.moveOrigin(pos[0], pos[1], true); + this.canvasRoot.setAttribute('width', (2 * parseFloat(w)) + 'px'); + this.canvasRoot.setAttribute('height',(2 * parseFloat(h)) + 'px'); + } else { + this.canvasRoot.width = 2 * parseFloat(w); + this.canvasRoot.height = 2 * parseFloat(h); } - - return r; + this.context = this.canvasRoot.getContext('2d'); + // The width and height of the canvas is set to twice the CSS values, + // followed by an appropiate scaling. + // See http://stackoverflow.com/questions/22416462/canvas-element-with-blurred-lines + this.context.scale(2, 2); }, + removeToInsertLater: function () { + return function () {}; + } + }); + + return JXG.CanvasRenderer; +}); + +/* + Copyright 2008-2022 + Matthias Ehmann, + Michael Gerhaeuser, + Carsten Miller, + Bianca Valentin, + Alfred Wassermann, + Peter Wilfahrt + + This file is part of JSXGraph. + + JSXGraph is free software dual licensed under the GNU LGPL or MIT License. + + You can redistribute it and/or modify it under the terms of the + + * GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version + OR + * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT + + JSXGraph is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License and + the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> + and <http://opensource.org/licenses/MIT/>. + */ + + +/*global JXG: true, define: true, AMprocessNode: true, MathJax: true, document: true */ +/*jslint nomen: true, plusplus: true, newcap:true, unparam: true*/ +/*eslint no-unused-vars: "off"*/ + +/* depends: + jxg + renderer/abstract +*/ + +/** + * @fileoverview JSXGraph can use various technologies to render the contents of a construction, e.g. + * SVG, VML, and HTML5 Canvas. To accomplish this, The rendering and the logic and control mechanisms + * are completely separated from each other. Every rendering technology has it's own class, called + * Renderer, e.g. SVGRenderer for SVG, the same for VML and Canvas. The common base for all available + * renderers is the class AbstractRenderer. + */ + +define('renderer/no',['jxg', 'renderer/abstract'], function (JXG, AbstractRenderer) { + + "use strict"; + + /** + * This renderer draws nothing. It is intended to be used in environments where none of our rendering engines + * are available, e.g. WebWorkers. All methods are empty. + * + * @class JXG.NoRenderer + * @augments JXG.AbstractRenderer + * @see JXG.AbstractRenderer + */ + JXG.NoRenderer = function () { /** - * Stop moving the origin with one finger - * @return {null} null - * @private + * If this property is set to <tt>true</tt> the visual properties of the elements are updated + * on every update. Visual properties means: All the stuff stored in the + * {@link JXG.GeometryElement#visProp} property won't be set if enhancedRendering is <tt>false</tt> + * @type Boolean + * @default true */ - originMoveEnd: function () { - this.updateQuality = this.BOARD_QUALITY_HIGH; - this.mode = this.BOARD_MODE_NONE; - }, - - /********************************************************** - * - * Event Handler - * - **********************************************************/ + this.enhancedRendering = false; /** - * Add all possible event handlers to the board object + * This is used to easily determine which renderer we are using + * @example if (board.renderer.type === 'vml') { + * // do something + * } + * @type String */ - addEventHandlers: function () { - if (Env.supportsPointerEvents()) { - this.addPointerEventHandlers(); - } else { - this.addMouseEventHandlers(); - this.addTouchEventHandlers(); - } - //if (Env.isBrowser) { - //Env.addEvent(window, 'resize', this.update, this); - //} + this.type = 'no'; + }; - // This one produces errors on IE - //Env.addEvent(this.containerObj, 'contextmenu', function (e) { e.preventDefault(); return false;}, this); - // This one works on IE, Firefox and Chromium with default configurations. On some Safari - // or Opera versions the user must explicitly allow the deactivation of the context menu. - if (this.containerObj !== null) { - this.containerObj.oncontextmenu = function (e) { - if (Type.exists(e)) { - e.preventDefault(); - } - return false; - }; - } + JXG.extend(JXG.NoRenderer.prototype, /** @lends JXG.NoRenderer.prototype */ { + /* ******************************** * + * Point drawing and updating * + * ******************************** */ - this.addFullscreenEventHandlers(); - }, + /** + * Draws a point on the {@link JXG.Board}. + * @param {JXG.Point} element Reference to a {@link JXG.Point} object that has to be drawn. + * @see Point + * @see JXG.Point + * @see JXG.AbstractRenderer#updatePoint + * @see JXG.AbstractRenderer#changePointStyle + */ + drawPoint: function (element) {}, /** - * Registers the MSPointer* event handlers. + * Updates visual appearance of the renderer element assigned to the given {@link JXG.Point}. + * @param {JXG.Point} element Reference to a {@link JXG.Point} object, that has to be updated. + * @see Point + * @see JXG.Point + * @see JXG.AbstractRenderer#drawPoint + * @see JXG.AbstractRenderer#changePointStyle */ - addPointerEventHandlers: function () { - if (!this.hasPointerHandlers && Env.isBrowser) { - if (window.navigator.msPointerEnabled) { // IE10- - Env.addEvent(this.containerObj, 'MSPointerDown', this.pointerDownListener, this); - Env.addEvent(this.containerObj, 'MSPointerMove', this.pointerMoveListener, this); - } else { - Env.addEvent(this.containerObj, 'pointerdown', this.pointerDownListener, this); - Env.addEvent(this.containerObj, 'pointermove', this.pointerMoveListener, this); - // Env.addEvent(this.containerObj, 'pointerout', this.pointerOutListener, this); - } - Env.addEvent(this.containerObj, 'mousewheel', this.mouseWheelListener, this); - Env.addEvent(this.containerObj, 'DOMMouseScroll', this.mouseWheelListener, this); + updatePoint: function (element) { }, - if (this.containerObj !== null) { - // This is needed for capturing touch events. - // It is also in jsxgraph.css, but one never knows... - this.containerObj.style.touchAction = 'none'; - } + /** + * Changes the style of a {@link JXG.Point}. This is required because the point styles differ in what + * elements have to be drawn, e.g. if the point is marked by a "x" or a "+" two lines are drawn, if + * it's marked by spot a circle is drawn. This method removes the old renderer element(s) and creates + * the new one(s). + * @param {JXG.Point} element Reference to a {@link JXG.Point} object, that's style is changed. + * @see Point + * @see JXG.Point + * @see JXG.AbstractRenderer#updatePoint + * @see JXG.AbstractRenderer#drawPoint + */ + changePointStyle: function (element) { }, - this.hasPointerHandlers = true; - } - }, + /* ******************************** * + * Lines * + * ******************************** */ /** - * Registers mouse move, down and wheel event handlers. + * Draws a line on the {@link JXG.Board}. + * @param {JXG.Line} element Reference to a line object, that has to be drawn. + * @see Line + * @see JXG.Line + * @see JXG.AbstractRenderer#updateLine */ - addMouseEventHandlers: function () { - if (!this.hasMouseHandlers && Env.isBrowser) { - Env.addEvent(this.containerObj, 'mousedown', this.mouseDownListener, this); - Env.addEvent(this.containerObj, 'mousemove', this.mouseMoveListener, this); + drawLine: function (element) { }, - Env.addEvent(this.containerObj, 'mousewheel', this.mouseWheelListener, this); - Env.addEvent(this.containerObj, 'DOMMouseScroll', this.mouseWheelListener, this); + /** + * Updates visual appearance of the renderer element assigned to the given {@link JXG.Line}. + * @param {JXG.Line} element Reference to the {@link JXG.Line} object that has to be updated. + * @see Line + * @see JXG.Line + * @see JXG.AbstractRenderer#drawLine + */ + updateLine: function (element) { }, - this.hasMouseHandlers = true; - } - }, + /** + * Creates a rendering node for ticks added to a line. + * @param {JXG.Line} element A arbitrary line. + * @see Line + * @see Ticks + * @see JXG.Line + * @see JXG.Ticks + * @see JXG.AbstractRenderer#updateTicks + */ + drawTicks: function (element) { }, /** - * Register touch start and move and gesture start and change event handlers. - * @param {Boolean} appleGestures If set to false the gesturestart and gesturechange event handlers - * will not be registered. - * - * Since iOS 13, touch events were abandoned in favour of pointer events + * Update {@link Ticks} on a {@link JXG.Line}. This method is only a stub and has to be implemented + * in any descendant renderer class. + * @param {JXG.Line} element Reference of an line object, thats ticks have to be updated. + * @see Line + * @see Ticks + * @see JXG.Line + * @see JXG.Ticks + * @see JXG.AbstractRenderer#drawTicks */ - addTouchEventHandlers: function (appleGestures) { - if (!this.hasTouchHandlers && Env.isBrowser) { - Env.addEvent(this.containerObj, 'touchstart', this.touchStartListener, this); - Env.addEvent(this.containerObj, 'touchmove', this.touchMoveListener, this); + updateTicks: function (element) { /* stub */ }, - /* - if (!Type.exists(appleGestures) || appleGestures) { - // Gesture listener are called in touchStart and touchMove. - //Env.addEvent(this.containerObj, 'gesturestart', this.gestureStartListener, this); - //Env.addEvent(this.containerObj, 'gesturechange', this.gestureChangeListener, this); - } - */ + /* ************************** + * Curves + * **************************/ - this.hasTouchHandlers = true; - } - }, + /** + * Draws a {@link JXG.Curve} on the {@link JXG.Board}. + * @param {JXG.Curve} element Reference to a graph object, that has to be plotted. + * @see Curve + * @see JXG.Curve + * @see JXG.AbstractRenderer#updateCurve + */ + drawCurve: function (element) { }, /** - * Add fullscreen events which update the CSS transformation matrix to correct - * the mouse/touch/pointer positions in case of CSS transformations. + * Updates visual appearance of the renderer element assigned to the given {@link JXG.Curve}. + * @param {JXG.Curve} element Reference to a {@link JXG.Curve} object, that has to be updated. + * @see Curve + * @see JXG.Curve + * @see JXG.AbstractRenderer#drawCurve */ - addFullscreenEventHandlers: function() { - var i, - // standard/Edge, firefox, chrome/safari, IE11 - events = ['fullscreenchange', 'mozfullscreenchange', 'webkitfullscreenchange', 'msfullscreenchange'], - le = events.length; + updateCurve: function (element) { }, - for (i = 0; i < le; i++) { - Env.addEvent(this.document, events[i], this.fullscreenListener, this); - } - this.hasFullsceenEventHandlers = true; - }, + /* ************************** + * Circle related stuff + * **************************/ /** - * Remove all registered event handlers regarding fullscreen mode. + * Draws a {@link JXG.Circle} + * @param {JXG.Circle} element Reference to a {@link JXG.Circle} object that has to be drawn. + * @see Circle + * @see JXG.Circle + * @see JXG.AbstractRenderer#updateEllipse */ - removeFullscreenEventHandlers: function() { - var i, - // standard/Edge, firefox, chrome/safari, IE11 - events = ['fullscreenchange', 'mozfullscreenchange', 'webkitfullscreenchange', 'msfullscreenchange'], - le = events.length; - - if (this.hasFullsceenEventHandlers && Env.isBrowser) { - for (i = 0; i < le; i++) { - Env.removeEvent(this.document, events[i], this.fullscreenListener, this); - } - } - }, + drawEllipse: function (element) { }, /** - * Remove MSPointer* Event handlers. + * Updates visual appearance of a given {@link JXG.Circle} on the {@link JXG.Board}. + * @param {JXG.Circle} element Reference to a {@link JXG.Circle} object, that has to be updated. + * @see Circle + * @see JXG.Circle + * @see JXG.AbstractRenderer#drawEllipse */ - removePointerEventHandlers: function () { - if (this.hasPointerHandlers && Env.isBrowser) { - if (window.navigator.msPointerEnabled) { // IE10- - Env.removeEvent(this.containerObj, 'MSPointerDown', this.pointerDownListener, this); - Env.removeEvent(this.containerObj, 'MSPointerMove', this.pointerMoveListener, this); - } else { - Env.removeEvent(this.containerObj, 'pointerdown', this.pointerDownListener, this); - Env.removeEvent(this.containerObj, 'pointermove', this.pointerMoveListener, this); - // Env.removeEvent(this.containerObj, 'pointerout', this.pointerOutListener, this); - } + updateEllipse: function (element) { }, - Env.removeEvent(this.containerObj, 'mousewheel', this.mouseWheelListener, this); - Env.removeEvent(this.containerObj, 'DOMMouseScroll', this.mouseWheelListener, this); - if (this.hasPointerUp) { - if (window.navigator.msPointerEnabled) { // IE10- - Env.removeEvent(this.document, 'MSPointerUp', this.pointerUpListener, this); - } else { - Env.removeEvent(this.document, 'pointerup', this.pointerUpListener, this); - } - this.hasPointerUp = false; - } + /* ************************** + * Polygon related stuff + * **************************/ - this.hasPointerHandlers = false; - } - }, + /** + * Draws a {@link JXG.Polygon} on the {@link JXG.Board}. + * @param {JXG.Polygon} element Reference to a Polygon object, that is to be drawn. + * @see Polygon + * @see JXG.Polygon + * @see JXG.AbstractRenderer#updatePolygon + */ + drawPolygon: function (element) { }, /** - * De-register mouse event handlers. + * Updates properties of a {@link JXG.Polygon}'s rendering node. + * @param {JXG.Polygon} element Reference to a {@link JXG.Polygon} object, that has to be updated. + * @see Polygon + * @see JXG.Polygon + * @see JXG.AbstractRenderer#drawPolygon */ - removeMouseEventHandlers: function () { - if (this.hasMouseHandlers && Env.isBrowser) { - Env.removeEvent(this.containerObj, 'mousedown', this.mouseDownListener, this); - Env.removeEvent(this.containerObj, 'mousemove', this.mouseMoveListener, this); + updatePolygon: function (element) { }, - if (this.hasMouseUp) { - Env.removeEvent(this.document, 'mouseup', this.mouseUpListener, this); - this.hasMouseUp = false; - } + /* ************************** + * Text related stuff + * **************************/ - Env.removeEvent(this.containerObj, 'mousewheel', this.mouseWheelListener, this); - Env.removeEvent(this.containerObj, 'DOMMouseScroll', this.mouseWheelListener, this); + /** + * Shows a small copyright notice in the top left corner of the board. + * @param {String} str The copyright notice itself + * @param {Number} fontsize Size of the font the copyright notice is written in + */ + displayCopyright: function (str, fontsize) { /* stub */ }, - this.hasMouseHandlers = false; - } - }, + /** + * An internal text is a {@link JXG.Text} element which is drawn using only + * the given renderer but no HTML. This method is only a stub, the drawing + * is done in the special renderers. + * @param {JXG.Text} element Reference to a {@link JXG.Text} object + * @see Text + * @see JXG.Text + * @see JXG.AbstractRenderer#updateInternalText + * @see JXG.AbstractRenderer#drawText + * @see JXG.AbstractRenderer#updateText + * @see JXG.AbstractRenderer#updateTextStyle + */ + drawInternalText: function (element) { /* stub */ }, /** - * Remove all registered touch event handlers. + * Updates visual properties of an already existing {@link JXG.Text} element. + * @param {JXG.Text} element Reference to an {@link JXG.Text} object, that has to be updated. + * @see Text + * @see JXG.Text + * @see JXG.AbstractRenderer#drawInternalText + * @see JXG.AbstractRenderer#drawText + * @see JXG.AbstractRenderer#updateText + * @see JXG.AbstractRenderer#updateTextStyle */ - removeTouchEventHandlers: function () { - if (this.hasTouchHandlers && Env.isBrowser) { - Env.removeEvent(this.containerObj, 'touchstart', this.touchStartListener, this); - Env.removeEvent(this.containerObj, 'touchmove', this.touchMoveListener, this); + updateInternalText: function (element) { /* stub */ }, - if (this.hasTouchEnd) { - Env.removeEvent(this.document, 'touchend', this.touchEndListener, this); - this.hasTouchEnd = false; - } + /** + * Displays a {@link JXG.Text} on the {@link JXG.Board} by putting a HTML div over it. + * @param {JXG.Text} element Reference to an {@link JXG.Text} object, that has to be displayed + * @see Text + * @see JXG.Text + * @see JXG.AbstractRenderer#drawInternalText + * @see JXG.AbstractRenderer#updateText + * @see JXG.AbstractRenderer#updateInternalText + * @see JXG.AbstractRenderer#updateTextStyle + */ + drawText: function (element) { }, - this.hasTouchHandlers = false; - } - }, + /** + * Updates visual properties of an already existing {@link JXG.Text} element. + * @param {JXG.Text} element Reference to an {@link JXG.Text} object, that has to be updated. + * @see Text + * @see JXG.Text + * @see JXG.AbstractRenderer#drawText + * @see JXG.AbstractRenderer#drawInternalText + * @see JXG.AbstractRenderer#updateInternalText + * @see JXG.AbstractRenderer#updateTextStyle + */ + updateText: function (element) { }, /** - * Remove all event handlers from the board object + * Updates CSS style properties of a {@link JXG.Text} node. + * @param {JXG.Text} element Reference to the {@link JXG.Text} object, that has to be updated. + * @param {Boolean} doHighlight + * @see Text + * @see JXG.Text + * @see JXG.AbstractRenderer#drawText + * @see JXG.AbstractRenderer#drawInternalText + * @see JXG.AbstractRenderer#updateText + * @see JXG.AbstractRenderer#updateInternalText */ - removeEventHandlers: function () { - this.removeMouseEventHandlers(); - this.removeTouchEventHandlers(); - this.removePointerEventHandlers(); + updateTextStyle: function (element, doHighlight) { }, - this.removeFullscreenEventHandlers(); + /** + * Set color and opacity of internal texts. + * SVG needs its own version. + * @private + * @see JXG.AbstractRenderer#updateTextStyle + * @see JXG.AbstractRenderer#updateInternalTextStyle + */ + updateInternalTextStyle: function (element, strokeColor, strokeOpacity) { /* stub */ }, - }, + /* ************************** + * Image related stuff + * **************************/ /** - * Handler for click on left arrow in the navigation bar - * @returns {JXG.Board} Reference to the board + * Draws an {@link JXG.Image} on a board; This is just a template that has to be implemented by special renderers. + * @param {JXG.Image} element Reference to the image object that is to be drawn + * @see Image + * @see JXG.Image + * @see JXG.AbstractRenderer#updateImage */ - clickLeftArrow: function () { - this.moveOrigin(this.origin.scrCoords[1] + this.canvasWidth * 0.1, this.origin.scrCoords[2]); - return this; - }, + drawImage: function (element) { /* stub */ }, /** - * Handler for click on right arrow in the navigation bar - * @returns {JXG.Board} Reference to the board + * Updates the properties of an {@link JXG.Image} element. + * @param {JXG.Image} element Reference to an {@link JXG.Image} object, that has to be updated. + * @see Image + * @see JXG.Image + * @see JXG.AbstractRenderer#drawImage */ - clickRightArrow: function () { - this.moveOrigin(this.origin.scrCoords[1] - this.canvasWidth * 0.1, this.origin.scrCoords[2]); - return this; - }, + updateImage: function (element) { }, /** - * Handler for click on up arrow in the navigation bar - * @returns {JXG.Board} Reference to the board + * Applies transformations on images and text elements. This method is just a stub and has to be implemented in all + * descendant classes where text and image transformations are to be supported. + * @param {JXG.Image|JXG.Text} element A {@link JXG.Image} or {@link JXG.Text} object. + * @param {Array} transformations An array of {@link JXG.Transformation} objects. This is usually the transformations property + * of the given element <tt>el</tt>. */ - clickUpArrow: function () { - this.moveOrigin(this.origin.scrCoords[1], this.origin.scrCoords[2] - this.canvasHeight * 0.1); - return this; - }, + transformImage: function (element, transformations) { /* stub */ }, /** - * Handler for click on down arrow in the navigation bar - * @returns {JXG.Board} Reference to the board + * If the URL of the image is provided by a function the URL has to be updated during updateImage() + * @param {JXG.Image} element Reference to an image object. + * @see JXG.AbstractRenderer#updateImage */ - clickDownArrow: function () { - this.moveOrigin(this.origin.scrCoords[1], this.origin.scrCoords[2] + this.canvasHeight * 0.1); - return this; - }, + updateImageURL: function (element) { /* stub */ }, + + /* ************************** + * Render primitive objects + * **************************/ /** - * Triggered on iOS/Safari while the user inputs a gesture (e.g. pinch) and is used to zoom into the board. - * Works on iOS/Safari and Android. - * @param {Event} evt Browser event object - * @returns {Boolean} + * Appends a node to a specific layer level. This is just an abstract method and has to be implemented + * in all renderers that want to use the <tt>createPrim</tt> model to draw. + * @param {Node} node A DOM tree node. + * @param {Number} level The layer the node is attached to. This is the index of the layer in + * {@link JXG.SVGRenderer#layer} or the <tt>z-index</tt> style property of the node in VMLRenderer. */ - gestureChangeListener: function (evt) { - var c, - dir1 = [], - dir2 = [], - angle, - mi = 10, - isPinch = false, - // Save zoomFactors - zx = this.attr.zoom.factorx, - zy = this.attr.zoom.factory, - factor, - dist, - dx, dy, theta, cx, cy, bound; + appendChildPrim: function (node, level) { /* stub */ }, - if (this.mode !== this.BOARD_MODE_ZOOM) { - return true; - } - evt.preventDefault(); + /** + * Stores the rendering nodes. This is an abstract method which has to be implemented in all renderers that use + * the <tt>createPrim</tt> method. + * @param {JXG.GeometryElement} element A JSXGraph element. + * @param {String} type The XML node name. Only used in VMLRenderer. + */ + appendNodesToElement: function (element, type) { /* stub */ }, - dist = Geometry.distance([evt.touches[0].clientX, evt.touches[0].clientY], - [evt.touches[1].clientX, evt.touches[1].clientY], 2); + /** + * Creates a node of a given type with a given id. + * @param {String} type The type of the node to create. + * @param {String} id Set the id attribute to this. + * @returns {Node} Reference to the created node. + */ + createPrim: function (type, id) { + /* stub */ + return null; + }, - // Android pinch to zoom - // evt.scale was available in iOS touch events (pre iOS 13) - // evt.scale is undefined in Android - if (evt.scale === undefined) { - evt.scale = dist / this.prevDist; - } + /** + * Removes an element node. Just a stub. + * @param {Node} node The node to remove. + */ + remove: function (node) { /* stub */ }, - if (!Type.exists(this.prevCoords)) { - return false; - } - // Compute the angle of the two finger directions - dir1 = [evt.touches[0].clientX - this.prevCoords[0][0], - evt.touches[0].clientY - this.prevCoords[0][1]]; - dir2 = [evt.touches[1].clientX - this.prevCoords[1][0], - evt.touches[1].clientY - this.prevCoords[1][1]]; + /** + * Can be used to create the nodes to display arrows. This is an abstract method which has to be implemented + * in any descendant renderer. + * @param {JXG.GeometryElement} element The element the arrows are to be attached to. + */ + makeArrows: function (element) { /* stub */ }, - if ((dir1[0] * dir1[0] + dir1[1] * dir1[1] < mi * mi) && - (dir2[0] * dir2[0] + dir2[1] * dir2[1] < mi * mi)) { - return false; - } + /** + * Updates an ellipse node primitive. This is an abstract method which has to be implemented in all renderers + * that use the <tt>createPrim</tt> method. + * @param {Node} node Reference to the node. + * @param {Number} x Centre X coordinate + * @param {Number} y Centre Y coordinate + * @param {Number} rx The x-axis radius. + * @param {Number} ry The y-axis radius. + */ + updateEllipsePrim: function (node, x, y, rx, ry) { /* stub */ }, - angle = Geometry.rad(dir1, [0,0], dir2); - if (this.isPreviousGesture !== 'pan' && - Math.abs(angle) > Math.PI * 0.2 && - Math.abs(angle) < Math.PI * 1.8) { - isPinch = true; - } + /** + * Refreshes a line node. This is an abstract method which has to be implemented in all renderers that use + * the <tt>createPrim</tt> method. + * @param {Node} node The node to be refreshed. + * @param {Number} p1x The first point's x coordinate. + * @param {Number} p1y The first point's y coordinate. + * @param {Number} p2x The second point's x coordinate. + * @param {Number} p2y The second point's y coordinate. + * @param {JXG.Board} board + */ + updateLinePrim: function (node, p1x, p1y, p2x, p2y, board) { /* stub */ }, - if (this.isPreviousGesture !== 'pan' && !isPinch) { - if (Math.abs(evt.scale) < 0.77 || Math.abs(evt.scale) > 1.3) { - isPinch = true; - } - } + /** + * Updates a path element. This is an abstract method which has to be implemented in all renderers that use + * the <tt>createPrim</tt> method. + * @param {Node} node The path node. + * @param {String} pathString A string formatted like e.g. <em>'M 1,2 L 3,1 L5,5'</em>. The format of the string + * depends on the rendering engine. + * @param {JXG.Board} board Reference to the element's board. + */ + updatePathPrim: function (node, pathString, board) { /* stub */ }, - factor = evt.scale / this.prevScale; - this.prevScale = evt.scale; - this.prevCoords = [[evt.touches[0].clientX, evt.touches[0].clientY], - [evt.touches[1].clientX, evt.touches[1].clientY]]; + /** + * Builds a path data string to draw a point with a face other than <em>rect</em> and <em>circle</em>. Since + * the format of such a string usually depends on the renderer this method + * is only an abstract method. Therefore, it has to be implemented in the descendant renderer itself unless + * the renderer does not use the createPrim interface but the draw* interfaces to paint. + * @param {JXG.Point} element The point element + * @param {Number} size A positive number describing the size. Usually the half of the width and height of + * the drawn point. + * @param {String} type A string describing the point's face. This method only accepts the shortcut version of + * each possible face: <tt>x, +, <>, ^, v, >, < + */ + updatePathStringPoint: function (element, size, type) { /* stub */ }, - c = new Coords(Const.COORDS_BY_SCREEN, this.getMousePosition(evt, 0), this); + /** + * Builds a path data string from a {@link JXG.Curve} element. Since the path data strings heavily depend on the + * underlying rendering technique this method is just a stub. Although such a path string is of no use for the + * CanvasRenderer, this method is used there to draw a path directly. + * @param element + */ + updatePathStringPrim: function (element) { /* stub */ }, - if (this.attr.pan.enabled && - this.attr.pan.needtwofingers && - !isPinch) { - // Pan detected + /** + * Builds a path data string from a {@link JXG.Curve} element such that the curve looks like + * hand drawn. + * Since the path data strings heavily depend on the + * underlying rendering technique this method is just a stub. Although such a path string is of no use for the + * CanvasRenderer, this method is used there to draw a path directly. + * @param element + */ + updatePathStringBezierPrim: function (element) { /* stub */ }, - this.isPreviousGesture = 'pan'; - this.moveOrigin(c.scrCoords[1], c.scrCoords[2], true); - } else if (this.attr.zoom.enabled && - Math.abs(factor - 1.0) < 0.5) { - // Pinch detected + /** + * Update a polygon primitive. + * @param {Node} node + * @param {JXG.Polygon} element A JSXGraph element of type {@link JXG.Polygon} + */ + updatePolygonPrim: function (node, element) { /* stub */ }, - if (this.attr.zoom.pinchhorizontal || this.attr.zoom.pinchvertical) { - dx = Math.abs(evt.touches[0].clientX - evt.touches[1].clientX); - dy = Math.abs(evt.touches[0].clientY - evt.touches[1].clientY); - theta = Math.abs(Math.atan2(dy, dx)); - bound = Math.PI * this.attr.zoom.pinchsensitivity / 90.0; - } + /** + * Update a rectangle primitive. This is used only for points with face of type 'rect'. + * @param {Node} node The node yearning to be updated. + * @param {Number} x x coordinate of the top left vertex. + * @param {Number} y y coordinate of the top left vertex. + * @param {Number} w Width of the rectangle. + * @param {Number} h The rectangle's height. + */ + updateRectPrim: function (node, x, y, w, h) { /* stub */ }, - if (this.attr.zoom.pinchhorizontal && theta < bound) { - this.attr.zoom.factorx = factor; - this.attr.zoom.factory = 1.0; - cx = 0; - cy = 0; - } else if (this.attr.zoom.pinchvertical && Math.abs(theta - Math.PI * 0.5) < bound) { - this.attr.zoom.factorx = 1.0; - this.attr.zoom.factory = factor; - cx = 0; - cy = 0; - } else { - this.attr.zoom.factorx = factor; - this.attr.zoom.factory = factor; - cx = c.usrCoords[1]; - cy = c.usrCoords[2]; - } + /* ************************** + * Set Attributes + * **************************/ - this.zoomIn(cx, cy); + /** + * Sets a node's attribute. + * @param {Node} node The node that is to be updated. + * @param {String} key Name of the attribute. + * @param {String} val New value for the attribute. + */ + setPropertyPrim: function (node, key, val) { /* stub */ }, - // Restore zoomFactors - this.attr.zoom.factorx = zx; - this.attr.zoom.factory = zy; + /** + * Shows or hides an element on the canvas; Only a stub, requires implementation in the derived renderer. + * @param {JXG.GeometryElement} element Reference to the object that has to appear. + * @param {Boolean} value true to show the element, false to hide the element. + */ + display: function (element, value) { + if (element) { + element.visPropOld.visible = value; } - - return false; }, /** - * Called by iOS/Safari as soon as the user starts a gesture. Works natively on iOS/Safari, - * on Android we emulate it. - * @param {Event} evt - * @returns {Boolean} + * Shows a hidden element on the canvas; Only a stub, requires implementation in the derived renderer. + * + * Please use JXG.AbstractRenderer#display instead + * @param {JXG.GeometryElement} element Reference to the object that has to appear. + * @see JXG.AbstractRenderer#hide + * @deprecated */ - gestureStartListener: function (evt) { - var pos; + show: function (element) { /* stub */ }, - evt.preventDefault(); - this.prevScale = 1.0; - // Android pinch to zoom - this.prevDist = Geometry.distance([evt.touches[0].clientX, evt.touches[0].clientY], - [evt.touches[1].clientX, evt.touches[1].clientY], 2); - this.prevCoords = [[evt.touches[0].clientX, evt.touches[0].clientY], - [evt.touches[1].clientX, evt.touches[1].clientY]]; - this.isPreviousGesture = 'none'; + /** + * Hides an element on the canvas; Only a stub, requires implementation in the derived renderer. + * + * Please use JXG.AbstractRenderer#display instead + * @param {JXG.GeometryElement} element Reference to the geometry element that has to disappear. + * @see JXG.AbstractRenderer#show + * @deprecated + */ + hide: function (element) { /* stub */ }, - // If pinch-to-zoom is interpreted as panning - // we have to prepare move origin - pos = this.getMousePosition(evt, 0); - this.initMoveOrigin(pos[0], pos[1]); + /** + * Sets the buffering as recommended by SVGWG. Until now only Opera supports this and will be ignored by + * other browsers. Although this feature is only supported by SVG we have this method in {@link JXG.AbstractRenderer} + * because it is called from outside the renderer. + * @param {Node} node The SVG DOM Node which buffering type to update. + * @param {String} type Either 'auto', 'dynamic', or 'static'. For an explanation see + * {@link http://www.w3.org/TR/SVGTiny12/painting.html#BufferedRenderingProperty}. + */ + setBuffering: function (node, type) { /* stub */ }, - this.mode = this.BOARD_MODE_ZOOM; - return false; - }, + /** + * Sets an element's dash style. + * @param {JXG.GeometryElement} element An JSXGraph element. + */ + setDashStyle: function (element) { /* stub */ }, /** - * Test if the required key combination is pressed for wheel zoom, move origin and - * selection - * @private - * @param {Object} evt Mouse or pen event - * @param {String} action String containing the action: 'zoom', 'pan', 'selection'. - * Corresponds to the attribute subobject. - * @return {Boolean} true or false. + * Puts an object into draft mode, i.e. it's visual appearance will be changed. For GEONE<sub>x</sub>T backwards compatibility. + * @param {JXG.GeometryElement} element Reference of the object that is in draft mode. */ - _isRequiredKeyPressed: function (evt, action) { - var obj = this.attr[action]; - if (!obj.enabled) { - return false; - } + setDraft: function (element) { }, - if (((obj.needshift && evt.shiftKey) || (!obj.needshift && !evt.shiftKey)) && - ((obj.needctrl && evt.ctrlKey) || (!obj.needctrl && !evt.ctrlKey)) - ) { - return true; - } + /** + * Puts an object from draft mode back into normal mode. + * @param {JXG.GeometryElement} element Reference of the object that no longer is in draft mode. + */ + removeDraft: function (element) { }, - return false; - }, + /** + * Sets up nodes for rendering a gradient fill. + * @param element + */ + setGradient: function (element) { /* stub */ }, /** - * Fix for Firefox browser: When using a second finger, the - * touch event for the first finger is sent again. - * - * @param {[type]} evt Event object - * @return {Boolean} true if down event has already been sent. - * @private + * Updates the gradient fill. + * @param {JXG.GeometryElement} element An JSXGraph element with an area that can be filled. */ - _isPointerEventAlreadyThere: function (evt) { - var i; + updateGradient: function (element) { /* stub */ }, - for (i = 0; i < this._board_touches.length; i++) { - if (this._board_touches[i].pointerId === evt.pointerId) { - return true; - } - } + /** + * Sets the transition duration (in milliseconds) for fill color and stroke + * color and opacity. + * @param {JXG.GeometryElement} element Reference of the object that wants a + * new transition duration. + * @param {Number} duration (Optional) duration in milliseconds. If not given, + * element.visProp.transitionDuration is taken. This is the default. + */ + setObjectTransition: function (element, duration) { /* stub */ }, - return false; - }, + /** + * Sets an objects fill color. + * @param {JXG.GeometryElement} element Reference of the object that wants a new fill color. + * @param {String} color Color in a HTML/CSS compatible format. If you don't want any fill color at all, choose 'none'. + * @param {Number} opacity Opacity of the fill color. Must be between 0 and 1. + */ + setObjectFillColor: function (element, color, opacity) { /* stub */ }, /** - * pointer-Events + * Changes an objects stroke color to the given color. + * @param {JXG.GeometryElement} element Reference of the {@link JXG.GeometryElement} that gets a new stroke color. + * @param {String} color Color value in a HTML compatible format, e.g. <strong>#00ff00</strong> or <strong>green</strong> for green. + * @param {Number} opacity Opacity of the fill color. Must be between 0 and 1. */ - _pointerIsTouchRegistered: function(evt) { - var i, - len = this._board_touches.length, - found = false; + setObjectStrokeColor: function (element, color, opacity) { /* stub */ }, - for (i = 0; i < len; i++) { - if (this._board_touches[i].pointerId === evt.pointerId) { - return true; - } - } - return false; - }, + /** + * Sets an element's stroke width. + * @param {JXG.GeometryElement} element Reference to the geometry element. + * @param {Number} width The new stroke width to be assigned to the element. + */ + setObjectStrokeWidth: function (element, width) { /* stub */ }, - _pointerAddBoardTouches: function (evt) { - var i, found; + /** + * Sets the shadow properties to a geometry element. This method is only a stub, it is implemented in the actual renderers. + * @param {JXG.GeometryElement} element Reference to a geometry object, that should get a shadow + */ + setShadow: function (element) { /* stub */ }, - for (i = 0, found = false; i < this._board_touches.length; i++) { - if (this._board_touches[i].pointerId === evt.pointerId) { - this._board_touches[i].clientX = evt.clientX; - this._board_touches[i].clientY = evt.clientY; - found = true; - break; - } - } + /** + * Highlights an object, i.e. changes the current colors of the object to its highlighting colors + * @param {JXG.GeometryElement} element Reference of the object that will be highlighted. + * @returns {JXG.AbstractRenderer} Reference to the renderer + */ + highlight: function (element) { }, - if (!found) { - this._board_touches.push({ - pointerId: evt.pointerId, - clientX: evt.clientX, - clientY: evt.clientY - }); - } + /** + * Uses the normal colors of an object, i.e. the opposite of {@link JXG.AbstractRenderer#highlight}. + * @param {JXG.GeometryElement} element Reference of the object that will get its normal colors. + * @returns {JXG.AbstractRenderer} Reference to the renderer + */ + noHighlight: function (element) { }, - return this; - }, - _pointerRemoveBoardTouches: function (evt) { - var i; - for (i = 0; i < this._board_touches.length; i++) { - if (this._board_touches[i].pointerId === evt.pointerId) { - this._board_touches.splice(i, 1); - break; - } - } + /* ************************** + * renderer control + * **************************/ - return this; - }, + /** + * Stop redraw. This method is called before every update, so a non-vector-graphics based renderer + * can use this method to delete the contents of the drawing panel. This is an abstract method every + * descendant renderer should implement, if appropriate. + * @see JXG.AbstractRenderer#unsuspendRedraw + */ + suspendRedraw: function () { /* stub */ }, /** - * Determine which input device is used for this action. - * Possible devices are 'touch', 'pen' and 'mouse'. - * This affects the precision and certain events. - * In case of no browser, 'mouse' is used. - * - * @see JXG.Board#pointerDownListener - * @see JXG.Board#pointerMoveListener - * @see JXG.Board#initMoveObject - * @see JXG.Board#moveObject - * - * @param {Event} evt The browsers event object. - * @returns {String} 'mouse', 'pen', or 'touch' - * @private + * Restart redraw. This method is called after updating all the rendering node attributes. + * @see JXG.AbstractRenderer#suspendRedraw */ - _getPointerInputDevice: function(evt) { - if (Env.isBrowser) { - if (evt.pointerType === 'touch' || // New - (window.navigator.msMaxTouchPoints && // Old - window.navigator.msMaxTouchPoints > 1)) { - return 'touch'; - } - if (evt.pointerType === 'mouse') { - return 'mouse'; - } - if (evt.pointerType === 'pen') { - return 'pen'; - } - } - return 'mouse'; + unsuspendRedraw: function () { /* stub */ }, + + /** + * The tiny zoom bar shown on the bottom of a board (if showNavigation on board creation is true). + * @param {JXG.Board} board Reference to a JSXGraph board. + */ + drawZoomBar: function (board) { }, + + /** + * Wrapper for getElementById for maybe other renderers which elements are not directly accessible by DOM methods like document.getElementById(). + * @param {String} id Unique identifier for element. + * @returns {Object} Reference to a JavaScript object. In case of SVG/VMLRenderer it's a reference to a SVG/VML node. + */ + getElementById: function (id) { + return null; }, /** - * This method is called by the browser when a pointing device is pressed on the screen. - * @param {Event} evt The browsers event object. - * @param {Object} object If the object to be dragged is already known, it can be submitted via this parameter - * @returns {Boolean} ... + * Resizes the rendering element + * @param {Number} w New width + * @param {Number} h New height */ - pointerDownListener: function (evt, object) { - var i, j, k, pos, elements, sel, - type = 'mouse', // in case of no browser - found, target, result; + resize: function (w, h) { /* stub */}, - // Temporary fix for Firefox pointer events: - // When using two fingers, the first touch down event is fired again. - if (!object && this._isPointerEventAlreadyThere(evt)) { - return false; - } + removeToInsertLater: function () { + return function () {}; + } - if (!this.hasPointerUp) { - if (window.navigator.msPointerEnabled) { // IE10- - Env.addEvent(this.document, 'MSPointerUp', this.pointerUpListener, this); - } else { - Env.addEvent(this.document, 'pointerup', this.pointerUpListener, this); - } - this.hasPointerUp = true; - } + }); - if (this.hasMouseHandlers) { - this.removeMouseEventHandlers(); - } + /** + * @ignore + */ + JXG.NoRenderer.prototype = new AbstractRenderer(); - if (this.hasTouchHandlers) { - this.removeTouchEventHandlers(); - } + return JXG.NoRenderer; +}); - // Prevent accidental selection of text - if (this.document.selection && Type.isFunction(this.document.selection.empty)) { - this.document.selection.empty(); - } else if (window.getSelection) { - sel = window.getSelection(); - if (sel.removeAllRanges) { - try { - sel.removeAllRanges(); - } catch (e) {} - } - } +/* + Copyright 2008-2022 + Matthias Ehmann, + Michael Gerhaeuser, + Carsten Miller, + Bianca Valentin, + Alfred Wassermann, + Peter Wilfahrt - // Mouse, touch or pen device - this._inputDevice = this._getPointerInputDevice(evt); - type = this._inputDevice; - this.options.precision.hasPoint = this.options.precision[type]; + This file is part of JSXGraph. - // This should be easier than the touch events. Every pointer device gets its own pointerId, e.g. the mouse - // always has id 1, fingers and pens get unique ids every time a pointerDown event is fired and they will - // keep this id until a pointerUp event is fired. What we have to do here is: - // 1. collect all elements under the current pointer - // 2. run through the touches control structure - // a. look for the object collected in step 1. - // b. if an object is found, check the number of pointers. If appropriate, add the pointer. + JSXGraph is free software dual licensed under the GNU LGPL or MIT License. - pos = this.getMousePosition(evt); + You can redistribute it and/or modify it under the terms of the - // selection - this._testForSelection(evt); - if (this.selectingMode) { - this._startSelecting(pos); - this.triggerEventHandlers(['touchstartselecting', 'pointerstartselecting', 'startselecting'], [evt]); - return; // don't continue as a normal click - } + * GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version + OR + * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT - if (this.attr.drag.enabled && object) { - elements = [ object ]; - this.mode = this.BOARD_MODE_DRAG; - } else { - elements = this.initMoveObject(pos[0], pos[1], evt, type); - } - - // if no draggable object can be found, get out here immediately - if (elements.length > 0) { - // check touches structure - target = elements[elements.length - 1]; - found = false; - for (i = 0; i < this.touches.length; i++) { - // the target is already in our touches array, try to add the pointer to the existing touch - if (this.touches[i].obj === target) { - j = i; - k = this.touches[i].targets.push({ - num: evt.pointerId, - X: pos[0], - Y: pos[1], - Xprev: NaN, - Yprev: NaN, - Xstart: [], - Ystart: [], - Zstart: [] - }) - 1; - - found = true; - break; - } - } - - if (!found) { - k = 0; - j = this.touches.push({ - obj: target, - targets: [{ - num: evt.pointerId, - X: pos[0], - Y: pos[1], - Xprev: NaN, - Yprev: NaN, - Xstart: [], - Ystart: [], - Zstart: [] - }] - }) - 1; - } - - this.dehighlightAll(); - target.highlight(true); + JSXGraph is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. - this.saveStartPos(target, this.touches[j].targets[k]); + You should have received a copy of the GNU Lesser General Public License and + the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> + and <http://opensource.org/licenses/MIT/>. + */ - // prevent accidental text selection - // this could get us new trouble: input fields, links and drop down boxes placed as text - // on the board don't work anymore. - if (evt && evt.preventDefault) { - evt.preventDefault(); - } else if (window.event) { - window.event.returnValue = false; - } - } - if (this.touches.length > 0) { - evt.preventDefault(); - evt.stopPropagation(); - } +/*global JXG: true, document:true, jQuery:true, define: true, window: true*/ +/*jslint nomen: true, plusplus: true*/ - if (Env.isBrowser && this._getPointerInputDevice(evt) !== 'touch') { - if (this.mode === this.BOARD_MODE_NONE) { - this.mouseOriginMoveStart(evt); - } - } else { - this._pointerAddBoardTouches(evt); - evt.touches = this._board_touches; +/* depends: + jxg + utils/env + utils/type + base/board + reader/file + options + renderer/svg + renderer/vml + renderer/canvas + renderer/no + */ - // See touchStartListener - if (this.mode === this.BOARD_MODE_NONE && this.touchOriginMoveStart(evt)) { - } else if ((this.mode === this.BOARD_MODE_NONE || - this.mode === this.BOARD_MODE_MOVE_ORIGIN) && - evt.touches.length == 2) { - if (this.mode === this.BOARD_MODE_MOVE_ORIGIN) { - this.originMoveEnd(); - } +/** + * @fileoverview The JSXGraph object is defined in this file. JXG.JSXGraph controls all boards. + * It has methods to create, save, load and free boards. Additionally some helper functions are + * defined in this file directly in the JXG namespace. + * @version 0.99 + */ - this.gestureStartListener(evt); - } - } +define('jsxgraph',[ + 'jxg', 'utils/env', 'utils/type', 'base/board', 'reader/file', 'options', + 'renderer/svg', 'renderer/vml', 'renderer/canvas', 'renderer/no' +], function (JXG, Env, Type, Board, FileReader, Options, SVGRenderer, VMLRenderer, CanvasRenderer, NoRenderer) { - this.triggerEventHandlers(['touchstart', 'down', 'pointerdown', 'MSPointerDown'], [evt]); - return false; - }, + "use strict"; + /** + * Constructs a new JSXGraph singleton object. + * @class The JXG.JSXGraph singleton stores all properties required + * to load, save, create and free a board. + */ + JXG.JSXGraph = { /** - * Called if pointer leaves an HTML tag. Is called by the inner-most tag. - * That means, if a JSXGraph text, i.e. an HTML div, is placed close - * to the border of the board, this pointerout event will be ignored. - * @param {Event} evt - * @return {Boolean} + * Stores the renderer that is used to draw the boards. + * @type String */ - pointerOutListener: function (evt) { - if (evt.target === this.containerObj || - (this.renderer.type === 'svg' && evt.target === this.renderer.foreignObjLayer)) { - this.pointerUpListener(evt); - } - return this.mode === this.BOARD_MODE_NONE; - }, + rendererType: (function () { + Options.board.renderer = 'no'; - /** - * Called periodically by the browser while the user moves a pointing device across the screen. - * @param {Event} evt - * @returns {Boolean} - */ - pointerMoveListener: function (evt) { - var i, j, pos, - type = 'mouse'; // in case of no browser + if (Env.supportsVML()) { + Options.board.renderer = 'vml'; + // Ok, this is some real magic going on here. IE/VML always was so + // terribly slow, except in one place: Examples placed in a moodle course + // was almost as fast as in other browsers. So i grabbed all the css and + // lib scripts from our moodle, added them to a jsxgraph example and it + // worked. next step was to strip all the css/lib code which didn't affect + // the VML update speed. The following five lines are what was left after + // the last step and yes - it basically does nothing but reads two + // properties of document.body on every mouse move. why? we don't know. if + // you know, please let us know. + // + // If we want to use the strict mode we have to refactor this a little bit. Let's + // hope the magic isn't gone now. Anywho... it's only useful in old versions of IE + // which should not be used anymore. + document.onmousemove = function () { + var t; - if (this._getPointerInputDevice(evt) === 'touch' && !this._pointerIsTouchRegistered(evt)) { - // Test, if there was a previous down event of this _getPointerId - // (in case it is a touch event). - // Otherwise this move event is ignored. This is necessary e.g. for sketchometry. - return this.BOARD_MODE_NONE; + if (document.body) { + t = document.body.scrollLeft; + t += document.body.scrollTop; + } + + return t; + }; } - if (!this.checkFrameRate(evt)) { - return false; + if (Env.supportsCanvas()) { + Options.board.renderer = 'canvas'; } - if (this.mode !== this.BOARD_MODE_DRAG) { - this.dehighlightAll(); - this.displayInfobox(false); + if (Env.supportsSVG()) { + Options.board.renderer = 'svg'; } - if (this.mode !== this.BOARD_MODE_NONE) { - evt.preventDefault(); - evt.stopPropagation(); + // we are inside node + if (Env.isNode() && Env.supportsCanvas()) { + Options.board.renderer = 'canvas'; } - this.updateQuality = this.BOARD_QUALITY_LOW; - // Mouse, touch or pen device - this._inputDevice = this._getPointerInputDevice(evt); - type = this._inputDevice; - this.options.precision.hasPoint = this.options.precision[type]; + if (Env.isNode() || Options.renderer === 'no') { + Options.text.display = 'internal'; + Options.infobox.display = 'internal'; + } - // selection - if (this.selectingMode) { - pos = this.getMousePosition(evt); - this._moveSelecting(pos); - this.triggerEventHandlers(['touchmoveselecting', 'moveselecting', 'pointermoveselecting'], [evt, this.mode]); - } else if (!this.mouseOriginMove(evt)) { - if (this.mode === this.BOARD_MODE_DRAG) { - // Runs through all jsxgraph elements which are touched by at least one finger. - for (i = 0; i < this.touches.length; i++) { - // Run through all touch events which have been started on this jsxgraph element. - for (j = 0; j < this.touches[i].targets.length; j++) { - if (this.touches[i].targets[j].num === evt.pointerId) { - if (this.touches[i].targets.length === 1) { - - // Touch by one finger: this is possible for all elements that can be dragged - this.touches[i].targets[j].X = evt.pageX; - this.touches[i].targets[j].Y = evt.pageY; - pos = this.getMousePosition(evt); - this.moveObject(pos[0], pos[1], this.touches[i], evt, type); + return Options.board.renderer; + }()), - } else if (this.touches[i].targets.length === 2) { + /** + * Initialize the rendering engine + * + * @param {String} box HTML id of the div-element which hosts the JSXGraph construction + * @param {Object} dim The dimensions of the board + * @param {Object} doc Usually, this is document object of the browser window. If false or null, this defaults + * to the document object of the browser. + * @param {Object} attrRenderer Attribute 'renderer', speficies the rendering engine. Possible values are 'auto', 'svg', + * 'canvas', 'no', and 'vml'. + * @returns {Object} Reference to the rendering engine object. + * @private + */ + initRenderer: function (box, dim, doc, attrRenderer) { + var boxid, renderer; - // Touch by two fingers: e.g. moving lines - this.touches[i].targets[j].X = evt.pageX; - this.touches[i].targets[j].Y = evt.pageY; - - this.twoFingerMove( - this.getMousePosition({ - clientX: this.touches[i].targets[0].X, - clientY: this.touches[i].targets[0].Y - }), - this.getMousePosition({ - clientX: this.touches[i].targets[1].X, - clientY: this.touches[i].targets[1].Y - }), - this.touches[i], evt); - } + // Former version: + // doc = doc || document + if ((!Type.exists(doc) || doc === false) && typeof document === 'object') { + doc = document; + } - // there is only one pointer in the evt object, there's no point in looking further - break; - } - } - } - } else { - if (this._getPointerInputDevice(evt) === 'touch') { - this._pointerAddBoardTouches(evt); - if (this._board_touches.length === 2) { - evt.touches = this._board_touches; - this.gestureChangeListener(evt); - } - } + if (typeof doc === 'object' && box !== null) { + boxid = doc.getElementById(box); - // Move event without dragging an element - pos = this.getMousePosition(evt); - this.highlightElements(pos[0], pos[1], evt, -1); + // Remove everything from the container before initializing the renderer and the board + while (boxid.firstChild) { + boxid.removeChild(boxid.firstChild); } + } else { + boxid = box; } - // Hiding the infobox is commented out, since it prevents showing the infobox - // on IE 11+ on 'over' - //if (this.mode !== this.BOARD_MODE_DRAG) { - //this.displayInfobox(false); - //} - this.triggerEventHandlers(['touchmove', 'move', 'pointermove', 'MSPointerMove'], [evt, this.mode]); - this.updateQuality = this.BOARD_QUALITY_HIGH; + // If attrRenderer is not supplied take the first available renderer + if (attrRenderer === undefined || attrRenderer === 'auto') { + attrRenderer = this.rendererType; + } + // create the renderer + if (attrRenderer === 'svg') { + renderer = new SVGRenderer(boxid, dim); + } else if (attrRenderer === 'vml') { + renderer = new VMLRenderer(boxid); + } else if (attrRenderer === 'canvas') { + renderer = new CanvasRenderer(boxid, dim); + } else { + renderer = new NoRenderer(); + } - return this.mode === this.BOARD_MODE_NONE; + return renderer; }, /** - * Triggered as soon as the user stops touching the device with at least one finger. - * @param {Event} evt - * @returns {Boolean} + * Merge the user supplied attributes with the attributes in options.js + * + * @param {Object} attributes User supplied attributes + * @returns {Object} Merged attributes for the board + * + * @private */ - pointerUpListener: function (evt) { - var i, j, found; + _setAttributes: function(attributes) { + // merge attributes + var attr = Type.copyAttributes(attributes, Options, 'board'); - this.triggerEventHandlers(['touchend', 'up', 'pointerup', 'MSPointerUp'], [evt]); - this.displayInfobox(false); + // The attributes which are objects have to be copied separately + attr.zoom = Type.copyAttributes(attr, Options, 'board', 'zoom'); + attr.pan = Type.copyAttributes(attr, Options, 'board', 'pan'); + attr.drag = Type.copyAttributes(attr, Options, 'board', 'drag'); + attr.keyboard = Type.copyAttributes(attr, Options, 'board', 'keyboard'); + attr.selection = Type.copyAttributes(attr, Options, 'board', 'selection'); + attr.navbar = Type.copyAttributes(attr.navbar, Options, 'navbar'); + attr.screenshot = Type.copyAttributes(attr, Options, 'board', 'screenshot'); + attr.resize = Type.copyAttributes(attr, Options, 'board', 'resize'); + attr.fullscreen = Type.copyAttributes(attr, Options, 'board', 'fullscreen'); - if (evt) { - for (i = 0; i < this.touches.length; i++) { - for (j = 0; j < this.touches[i].targets.length; j++) { - if (this.touches[i].targets[j].num === evt.pointerId) { - this.touches[i].targets.splice(j, 1); + // Treat moveTarget separately, because deepCopy will not work here. + // Reason: moveTarget will be an HTML node and it is prevented that Type.deepCopy will copy it. + attr.movetarget = attributes.moveTarget || attributes.movetarget || Options.board.moveTarget; - if (this.touches[i].targets.length === 0) { - this.touches.splice(i, 1); - } + return attr; + }, - break; - } - } - } - } + /** + * Further initialization of the board. Set some properties from attribute values. + * + * @param {JXG.Board} board + * @param {Object} attr attributes object + * @param {Object} dimensions Object containing dimensions of the canvas + * + * @private + */ + _fillBoard: function(board, attr, dimensions) { + board.initInfobox(); + board.maxboundingbox = attr.maxboundingbox; + board.resizeContainer(dimensions.width, dimensions.height, true, true); + board._createSelectionPolygon(attr); + board.renderer.drawZoomBar(board, attr.navbar); + JXG.boards[board.id] = board; + }, - // selection - if (this.selectingMode) { - this._stopSelecting(evt); - this.triggerEventHandlers(['touchstopselecting', 'pointerstopselecting', 'stopselecting'], [evt]); - } else { - for (i = this.downObjects.length - 1; i > -1; i--) { - found = false; - for (j = 0; j < this.touches.length; j++) { - if (this.touches[j].obj.id === this.downObjects[i].id) { - found = true; - } - } - if (!found) { - this.downObjects[i].triggerEventHandlers(['touchend', 'up', 'pointerup', 'MSPointerUp'], [evt]); - this.downObjects[i].snapToGrid(); - this.downObjects[i].snapToPoints(); - this.downObjects.splice(i, 1); - } - } + /** + * + * @param {String} container HTML-ID to the HTML-element in which the board is painted. + * @param {*} attr An object that sets some of the board properties. + * + * @private + */ + _setARIA: function(container, attr) { + var doc = attr.document || document, + doc_glob, + node_jsx, newNode, parent, + id_label, id_description; + + if (typeof doc !== 'object') { + return; } - this._pointerRemoveBoardTouches(evt); + node_jsx = doc.getElementById(container); + doc_glob = node_jsx.ownerDocument; // This is the window.document element, needed below. + parent = node_jsx.parentNode; - // if (this.touches.length === 0) { - if (this._board_touches.length === 0) { - if (this.hasPointerUp) { - if (window.navigator.msPointerEnabled) { // IE10- - Env.removeEvent(this.document, 'MSPointerUp', this.pointerUpListener, this); - } else { - Env.removeEvent(this.document, 'pointerup', this.pointerUpListener, this); - } - this.hasPointerUp = false; - } + id_label = container + '_ARIAlabel'; + id_description = container + '_ARIAdescription'; - this.dehighlightAll(); - this.updateQuality = this.BOARD_QUALITY_HIGH; - this.mode = this.BOARD_MODE_NONE; + newNode = doc_glob.createElement('div'); + newNode.innerHTML = attr.title; + newNode.setAttribute('id', id_label); + newNode.style.display = 'none'; + parent.insertBefore(newNode, node_jsx); - this.originMoveEnd(); - this.update(); - } + newNode = doc_glob.createElement('div'); + newNode.innerHTML = attr.description; + newNode.setAttribute('id', id_description); + newNode.style.display = 'none'; + parent.insertBefore(newNode, node_jsx); - return true; + node_jsx.setAttribute('aria-labelledby', id_label); + node_jsx.setAttribute('aria-describedby', id_description); }, /** - * Touch-Events - */ - - /** - * This method is called by the browser when a finger touches the surface of the touch-device. - * @param {Event} evt The browsers event object. - * @returns {Boolean} ... + * Remove the two corresponding ARIA divs when freeing a board + * + * @param {JXG.Board} board + * + * @private */ - touchStartListener: function (evt) { - var i, pos, elements, j, k, time, - eps = this.options.precision.touch, - obj, found, targets, - evtTouches = evt[JXG.touchProperty], - target; + _removeARIANodes: function(board) { + var node, id, doc; - if (!this.hasTouchEnd) { - Env.addEvent(this.document, 'touchend', this.touchEndListener, this); - this.hasTouchEnd = true; + doc = board.document || document; + if (typeof doc !== 'object') { + return; } - // Do not remove mouseHandlers, since Chrome on win tablets sends mouseevents if used with pen. - //if (this.hasMouseHandlers) { this.removeMouseEventHandlers(); } - - // prevent accidental selection of text - if (this.document.selection && Type.isFunction(this.document.selection.empty)) { - this.document.selection.empty(); - } else if (window.getSelection) { - window.getSelection().removeAllRanges(); + id = board.containerObj.getAttribute('aria-labelledby'); + node = doc.getElementById(id); + if (node && node.parentNode) { + node.parentNode.removeChild(node); } - - // multitouch - this._inputDevice = 'touch'; - this.options.precision.hasPoint = this.options.precision.touch; - - // This is the most critical part. first we should run through the existing touches and collect all targettouches that don't belong to our - // previous touches. once this is done we run through the existing touches again and watch out for free touches that can be attached to our existing - // touches, e.g. we translate (parallel translation) a line with one finger, now a second finger is over this line. this should change the operation to - // a rotational translation. or one finger moves a circle, a second finger can be attached to the circle: this now changes the operation from translation to - // stretching. as a last step we're going through the rest of the targettouches and initiate new move operations: - // * points have higher priority over other elements. - // * if we find a targettouch over an element that could be transformed with more than one finger, we search the rest of the targettouches, if they are over - // this element and add them. - // ADDENDUM 11/10/11: - // (1) run through the touches control object, - // (2) try to find the targetTouches for every touch. on touchstart only new touches are added, hence we can find a targettouch - // for every target in our touches objects - // (3) if one of the targettouches was bound to a touches targets array, mark it - // (4) run through the targettouches. if the targettouch is marked, continue. otherwise check for elements below the targettouch: - // (a) if no element could be found: mark the target touches and continue - // --- in the following cases, "init" means: - // (i) check if the element is already used in another touches element, if so, mark the targettouch and continue - // (ii) if not, init a new touches element, add the targettouch to the touches property and mark it - // (b) if the element is a point, init - // (c) if the element is a line, init and try to find a second targettouch on that line. if a second one is found, add and mark it - // (d) if the element is a circle, init and try to find TWO other targettouches on that circle. if only one is found, mark it and continue. otherwise - // add both to the touches array and mark them. - for (i = 0; i < evtTouches.length; i++) { - evtTouches[i].jxg_isused = false; + id = board.containerObj.getAttribute('aria-describedby'); + node = doc.getElementById(id); + if (node && node.parentNode) { + node.parentNode.removeChild(node); } + }, - for (i = 0; i < this.touches.length; i++) { - for (j = 0; j < this.touches[i].targets.length; j++) { - this.touches[i].targets[j].num = -1; - eps = this.options.precision.touch; + /** + * Initialise a new board. + * @param {String} box HTML-ID to the HTML-element in which the board is painted. + * @param {Object} attributes An object that sets some of the board properties. Most of these properties can be set via JXG.Options. + * @param {Array} [attributes.boundingbox=[-5, 5, 5, -5]] An array containing four numbers describing the left, top, right and bottom boundary of the board in user coordinates + * @param {Boolean} [attributes.keepaspectratio=false] If <tt>true</tt>, the bounding box is adjusted to the same aspect ratio as the aspect ratio of the div containing the board. + * @param {Boolean} [attributes.showCopyright=false] Show the copyright string in the top left corner. + * @param {Boolean} [attributes.showNavigation=false] Show the navigation buttons in the bottom right corner. + * @param {Object} [attributes.zoom] Allow the user to zoom with the mouse wheel or the two-fingers-zoom gesture. + * @param {Object} [attributes.pan] Allow the user to pan with shift+drag mouse or two-fingers-pan gesture. + * @param {Object} [attributes.drag] Allow the user to drag objects with a pointer device. + * @param {Object} [attributes.keyboard] Allow the user to drag objects with arrow keys on keyboard. + * @param {Boolean} [attributes.axis=false] If set to true, show the axis. Can also be set to an object that is given to both axes as an attribute object. + * @param {Boolean|Object} [attributes.grid] If set to true, shows the grid. Can also be set to an object that is given to the grid as its attribute object. + * @param {Boolean} [attributes.registerEvents=true] Register mouse / touch events. + * @returns {JXG.Board} Reference to the created board. + */ + initBoard: function (box, attributes) { + var originX, originY, unitX, unitY, + renderer, + offX = 0, + offY = 0, + w, h, dimensions, + bbox, attr, axattr, axattr_x, axattr_y, + board; - do { - for (k = 0; k < evtTouches.length; k++) { - // find the new targettouches - if (Math.abs(Math.pow(evtTouches[k].screenX - this.touches[i].targets[j].X, 2) + - Math.pow(evtTouches[k].screenY - this.touches[i].targets[j].Y, 2)) < eps * eps) { - this.touches[i].targets[j].num = k; + attributes = attributes || {}; + attr = this._setAttributes(attributes); - this.touches[i].targets[j].X = evtTouches[k].screenX; - this.touches[i].targets[j].Y = evtTouches[k].screenY; - evtTouches[k].jxg_isused = true; - break; - } - } + dimensions = Env.getDimensions(box, attr.document); - eps *= 2; + if (attr.unitx || attr.unity) { + originX = Type.def(attr.originx, 150); + originY = Type.def(attr.originy, 150); + unitX = Type.def(attr.unitx, 50); + unitY = Type.def(attr.unity, 50); + } else { + bbox = attr.boundingbox; + if (bbox[0] < attr.maxboundingbox[0]) { bbox[0] = attr.maxboundingbox[0]; } + if (bbox[1] > attr.maxboundingbox[1]) { bbox[1] = attr.maxboundingbox[1]; } + if (bbox[2] > attr.maxboundingbox[2]) { bbox[2] = attr.maxboundingbox[2]; } + if (bbox[3] < attr.maxboundingbox[3]) { bbox[3] = attr.maxboundingbox[3]; } - } while (this.touches[i].targets[j].num === -1 && - eps < this.options.precision.touchMax); + w = parseInt(dimensions.width, 10); + h = parseInt(dimensions.height, 10); - if (this.touches[i].targets[j].num === -1) { - JXG.debug('i couldn\'t find a targettouches for target no ' + j + ' on ' + this.touches[i].obj.name + ' (' + this.touches[i].obj.id + '). Removed the target.'); - JXG.debug('eps = ' + eps + ', touchMax = ' + Options.precision.touchMax); - this.touches[i].targets.splice(i, 1); - } + if (Type.exists(bbox) && attr.keepaspectratio) { + /* + * If the boundingbox attribute is given and the ratio of height and width of the + * sides defined by the bounding box and the ratio of the dimensions of the div tag + * which contains the board do not coincide, then the smaller side is chosen. + */ + unitX = w / (bbox[2] - bbox[0]); + unitY = h / (bbox[1] - bbox[3]); + if (Math.abs(unitX) < Math.abs(unitY)) { + unitY = Math.abs(unitX) * unitY / Math.abs(unitY); + // Add the additional units in equal portions above and below + offY = (h / unitY - (bbox[1] - bbox[3])) * 0.5; + } else { + unitX = Math.abs(unitY) * unitX / Math.abs(unitX); + // Add the additional units in equal portions left and right + offX = (w / unitX - (bbox[2] - bbox[0])) * 0.5; + } + } else { + unitX = w / (bbox[2] - bbox[0]); + unitY = h / (bbox[1] - bbox[3]); } + originX = -unitX * (bbox[0] - offX); + originY = unitY * (bbox[1] + offY); } - // we just re-mapped the targettouches to our existing touches list. - // now we have to initialize some touches from additional targettouches - for (i = 0; i < evtTouches.length; i++) { - if (!evtTouches[i].jxg_isused) { - - pos = this.getMousePosition(evt, i); - // selection - // this._testForSelection(evt); // we do not have shift or ctrl keys yet. - if (this.selectingMode) { - this._startSelecting(pos); - this.triggerEventHandlers(['touchstartselecting', 'startselecting'], [evt]); - evt.preventDefault(); - evt.stopPropagation(); - this.options.precision.hasPoint = this.options.precision.mouse; - return this.touches.length > 0; // don't continue as a normal click - } + renderer = this.initRenderer(box, dimensions, attr.document, attr.renderer); + this._setARIA(box, attr); - elements = this.initMoveObject(pos[0], pos[1], evt, 'touch'); - if (elements.length !== 0) { - obj = elements[elements.length - 1]; + // create the board + board = new Board(box, renderer, attr.id, [originX, originY], + attr.zoomfactor * attr.zoomx, + attr.zoomfactor * attr.zoomy, + unitX, unitY, + dimensions.width, dimensions.height, + attr); - if (Type.isPoint(obj) || - obj.elementClass === Const.OBJECT_CLASS_TEXT || - obj.type === Const.OBJECT_TYPE_TICKS || - obj.type === Const.OBJECT_TYPE_IMAGE) { - // it's a point, so it's single touch, so we just push it to our touches - targets = [{num: i, - X: evtTouches[i].screenX, - Y: evtTouches[i].screenY, - Xprev: NaN, - Yprev: NaN, - Xstart: [], - Ystart: [], - Zstart: [] }]; + board.keepaspectratio = attr.keepaspectratio; - // For the UNDO/REDO of object moves - this.saveStartPos(obj, targets[0]); + this._fillBoard(board, attr, dimensions); - this.touches.push({ obj: obj, targets: targets }); - obj.highlight(true); + // create elements like axes, grid, navigation, ... + board.suspendUpdate(); + if (attr.axis) { + axattr = typeof attr.axis === 'object' ? attr.axis : {}; - } else if (obj.elementClass === Const.OBJECT_CLASS_LINE || - obj.elementClass === Const.OBJECT_CLASS_CIRCLE || - obj.elementClass === Const.OBJECT_CLASS_CURVE || - obj.type === Const.OBJECT_TYPE_POLYGON) { - found = false; + // The defaultAxes attributes are overwritten by user supplied axis object. + axattr_x = Type.deepCopy(Options.board.defaultAxes.x, axattr); + axattr_y = Type.deepCopy(Options.board.defaultAxes.y, axattr); + // The user supplied defaultAxes attributes are merged in. + if (attr.defaultaxes.x) { + axattr_x = Type.deepCopy(axattr_x, attr.defaultaxes.x); + } + if (attr.defaultaxes.y) { + axattr_y = Type.deepCopy(axattr_y, attr.defaultaxes.y); + } - // first check if this geometric object is already captured in this.touches - for (j = 0; j < this.touches.length; j++) { - if (obj.id === this.touches[j].obj.id) { - found = true; - // only add it, if we don't have two targets in there already - if (this.touches[j].targets.length === 1) { - target = {num: i, - X: evtTouches[i].screenX, - Y: evtTouches[i].screenY, - Xprev: NaN, - Yprev: NaN, - Xstart: [], - Ystart: [], - Zstart: [] }; + board.defaultAxes = {}; + board.defaultAxes.x = board.create('axis', [[0, 0], [1, 0]], axattr_x); + board.defaultAxes.y = board.create('axis', [[0, 0], [0, 1]], axattr_y); + } + if (attr.grid) { + board.create('grid', [], (typeof attr.grid === 'object' ? attr.grid : {})); + } + board.unsuspendUpdate(); - // For the UNDO/REDO of object moves - this.saveStartPos(obj, target); - this.touches[j].targets.push(target); - } + return board; + }, - evtTouches[i].jxg_isused = true; - } - } + /** + * Load a board from a file containing a construction made with either GEONExT, + * Intergeo, Geogebra, or Cinderella. + * @param {String} box HTML-ID to the HTML-element in which the board is painted. + * @param {String} file base64 encoded string. + * @param {String} format containing the file format: 'Geonext' or 'Intergeo'. + * @param {Object} attributes Attributes for the board and 'encoding'. + * Compressed files need encoding 'iso-8859-1'. Otherwise it probably is 'utf-8'. + * @param {Function} callback + * @returns {JXG.Board} Reference to the created board. + * @see JXG.FileReader + * @see JXG.GeonextReader + * @see JXG.GeogebraReader + * @see JXG.IntergeoReader + * @see JXG.CinderellaReader + * + * @example + * // Uncompressed file + * var board = JXG.JSXGraph.loadBoardFromFile('jxgbox', 'filename', 'geonext', + * {encoding: 'utf-8'}, + * function (board) { console.log("Done loading"); } + * ); + * // Compressed file + * var board = JXG.JSXGraph.loadBoardFromFile('jxgbox', 'filename', 'geonext', + * {encoding: 'iso-8859-1'}, + * function (board) { console.log("Done loading"); } + * ); + * + * @example + * // From <input type="file" id="localfile" /> + * var file = document.getElementById('localfile').files[0]; + * JXG.JSXGraph.loadBoardFromFile('jxgbox', file, 'geonext', + * {encoding: 'utf-8'}, + * function (board) { console.log("Done loading"); } + * ); + */ + loadBoardFromFile: function (box, file, format, attributes, callback) { + var attr, renderer, board, dimensions, encoding; - // we couldn't find it in touches, so we just init a new touches - // IF there is a second touch targetting this line, we will find it later on, and then add it to - // the touches control object. - if (!found) { - targets = [{num: i, - X: evtTouches[i].screenX, - Y: evtTouches[i].screenY, - Xprev: NaN, - Yprev: NaN, - Xstart: [], - Ystart: [], - Zstart: [] }]; + attributes = attributes || {}; + attr = this._setAttributes(attributes); - // For the UNDO/REDO of object moves - this.saveStartPos(obj, targets[0]); - this.touches.push({ obj: obj, targets: targets }); - obj.highlight(true); - } - } - } + dimensions = Env.getDimensions(box, attr.document); + renderer = this.initRenderer(box, dimensions, attr.document, attr.renderer); + this._setARIA(box, attr); - evtTouches[i].jxg_isused = true; - } - } + /* User default parameters, in parse* the values in the gxt files are submitted to board */ + board = new Board(box, renderer, '', [150, 150], 1, 1, 50, 50, dimensions.width, dimensions.height, attr); + this._fillBoard(board, attr, dimensions); + encoding = attr.encoding || 'iso-8859-1'; + FileReader.parseFileContent(file, board, format, true, encoding, callback); - if (this.touches.length > 0) { - evt.preventDefault(); - evt.stopPropagation(); - } + return board; + }, - // Touch events on empty areas of the board are handled here: - // 1. case: one finger. If allowed, this triggers pan with one finger - if (this.mode === this.BOARD_MODE_NONE && this.touchOriginMoveStart(evt)) { - } else if (evtTouches.length === 2 && - (this.mode === this.BOARD_MODE_NONE || - this.mode === this.BOARD_MODE_MOVE_ORIGIN /*|| - (this.mode === this.BOARD_MODE_DRAG && this.touches.length == 1) */ - )) { - // 2. case: two fingers: pinch to zoom or pan with two fingers needed. - // This happens when the second finger hits the device. First, the - // "one finger pan mode" has to be cancelled. - if (this.mode === this.BOARD_MODE_MOVE_ORIGIN) { - this.originMoveEnd(); - } - this.gestureStartListener(evt); - } + /** + * Load a board from a base64 encoded string containing a construction made with either GEONExT, + * Intergeo, Geogebra, or Cinderella. + * @param {String} box HTML-ID to the HTML-element in which the board is painted. + * @param {String} string base64 encoded string. + * @param {String} format containing the file format: 'Geonext', 'Intergeo', 'Geogebra'. + * @param {Object} attributes Attributes for the board and 'encoding'. + * Compressed files need encoding 'iso-8859-1'. Otherwise it probably is 'utf-8'. + * @param {Function} callback + * @returns {JXG.Board} Reference to the created board. + * @see JXG.FileReader + * @see JXG.GeonextReader + * @see JXG.GeogebraReader + * @see JXG.IntergeoReader + * @see JXG.CinderellaReader + */ + loadBoardFromString: function (box, string, format, attributes, callback) { + var attr, renderer, board, dimensions; - this.options.precision.hasPoint = this.options.precision.mouse; - this.triggerEventHandlers(['touchstart', 'down'], [evt]); + attributes = attributes || {}; + attr = this._setAttributes(attributes); - return false; - //return this.touches.length > 0; + dimensions = Env.getDimensions(box, attr.document); + renderer = this.initRenderer(box, dimensions, attr.document); + this._setARIA(box, attr); + + /* User default parameters, in parse* the values in the gxt files are submitted to board */ + board = new Board(box, renderer, '', [150, 150], 1.0, 1.0, 50, 50, dimensions.width, dimensions.height, attr); + this._fillBoard(board, attr, dimensions); + FileReader.parseString(string, board, format, true, callback); + + return board; }, /** - * Called periodically by the browser while the user moves his fingers across the device. - * @param {Event} evt - * @returns {Boolean} + * Delete a board and all its contents. + * @param {JXG.Board,String} board HTML-ID to the DOM-element in which the board is drawn. */ - touchMoveListener: function (evt) { - var i, pos1, pos2, time, - evtTouches = evt[JXG.touchProperty]; - - if (!this.checkFrameRate(evt)) { - return false; - } - - if (this.mode !== this.BOARD_MODE_NONE) { - evt.preventDefault(); - evt.stopPropagation(); - } + freeBoard: function (board) { + var el; - if (this.mode !== this.BOARD_MODE_DRAG) { - this.dehighlightAll(); - this.displayInfobox(false); + if (typeof board === 'string') { + board = JXG.boards[board]; } - this._inputDevice = 'touch'; - this.options.precision.hasPoint = this.options.precision.touch; - this.updateQuality = this.BOARD_QUALITY_LOW; + this._removeARIANodes(board); + board.removeEventHandlers(); + board.suspendUpdate(); - // selection - if (this.selectingMode) { - for (i = 0; i < evtTouches.length; i++) { - if (!evtTouches[i].jxg_isused) { - pos1 = this.getMousePosition(evt, i); - this._moveSelecting(pos1); - this.triggerEventHandlers(['touchmoves', 'moveselecting'], [evt, this.mode]); - break; - } + // Remove all objects from the board. + for (el in board.objects) { + if (board.objects.hasOwnProperty(el)) { + board.objects[el].remove(); } - } else { - if (!this.touchOriginMove(evt)) { - if (this.mode === this.BOARD_MODE_DRAG) { - // Runs over through all elements which are touched - // by at least one finger. - for (i = 0; i < this.touches.length; i++) { - if (this.touches[i].targets.length === 1) { - // Touch by one finger: this is possible for all elements that can be dragged - if (evtTouches[this.touches[i].targets[0].num]) { - pos1 = this.getMousePosition(evt, this.touches[i].targets[0].num); - if (pos1[0] < 0 || pos1[0] > this.canvasWidth || - pos1[1] < 0 || pos1[1] > this.canvasHeight) { - return; - } - this.touches[i].targets[0].X = evtTouches[this.touches[i].targets[0].num].screenX; - this.touches[i].targets[0].Y = evtTouches[this.touches[i].targets[0].num].screenY; - this.moveObject(pos1[0], pos1[1], this.touches[i], evt, 'touch'); - } + } - } else if (this.touches[i].targets.length === 2 && - this.touches[i].targets[0].num > -1 && - this.touches[i].targets[1].num > -1) { - // Touch by two fingers: moving lines, ... - if (evtTouches[this.touches[i].targets[0].num] && - evtTouches[this.touches[i].targets[1].num]) { + // Remove all the other things, left on the board, XHTML save + while (board.containerObj.firstChild) { + board.containerObj.removeChild(board.containerObj.firstChild); + } - // Get coordinates of the two touches - pos1 = this.getMousePosition(evt, this.touches[i].targets[0].num); - pos2 = this.getMousePosition(evt, this.touches[i].targets[1].num); - if (pos1[0] < 0 || pos1[0] > this.canvasWidth || - pos1[1] < 0 || pos1[1] > this.canvasHeight || - pos2[0] < 0 || pos2[0] > this.canvasWidth || - pos2[1] < 0 || pos2[1] > this.canvasHeight) { - return; - } - this.touches[i].targets[0].X = evtTouches[this.touches[i].targets[0].num].screenX; - this.touches[i].targets[0].Y = evtTouches[this.touches[i].targets[0].num].screenY; - this.touches[i].targets[1].X = evtTouches[this.touches[i].targets[1].num].screenX; - this.touches[i].targets[1].Y = evtTouches[this.touches[i].targets[1].num].screenY; - this.twoFingerMove(pos1, pos2, this.touches[i], evt); - } - } - } - } else { - if (evtTouches.length === 2) { - this.gestureChangeListener(evt); - } - // Move event without dragging an element - pos1 = this.getMousePosition(evt, 0); - this.highlightElements(pos1[0], pos1[1], evt, -1); - } + // Tell the browser the objects aren't needed anymore + for (el in board.objects) { + if (board.objects.hasOwnProperty(el)) { + delete board.objects[el]; } } - if (this.mode !== this.BOARD_MODE_DRAG) { - this.displayInfobox(false); - } + // Free the renderer and the algebra object + delete board.renderer; - this.triggerEventHandlers(['touchmove', 'move'], [evt, this.mode]); - this.options.precision.hasPoint = this.options.precision.mouse; - this.updateQuality = this.BOARD_QUALITY_HIGH; + // clear the creator cache + board.jc.creator.clearCache(); + delete board.jc; - return this.mode === this.BOARD_MODE_NONE; + // Finally remove the board itself from the boards array + delete JXG.boards[board.id]; }, /** - * Triggered as soon as the user stops touching the device with at least one finger. - * @param {Event} evt - * @returns {Boolean} + * @deprecated Use JXG#registerElement + * @param element + * @param creator */ - touchEndListener: function (evt) { - var i, j, k, - eps = this.options.precision.touch, - tmpTouches = [], found, foundNumber, - evtTouches = evt && evt[JXG.touchProperty]; + registerElement: function (element, creator) { + JXG.deprecated('JXG.JSXGraph.registerElement()', 'JXG.registerElement()'); + JXG.registerElement(element, creator); + } + }; - this.triggerEventHandlers(['touchend', 'up'], [evt]); - this.displayInfobox(false); + // JessieScript/JessieCode startup: Search for script tags of type text/jessiescript and interprete them. + if (Env.isBrowser && typeof window === 'object' && typeof document === 'object') { + Env.addEvent(window, 'load', function () { + var type, i, j, div, + id, board, txt, + width, height, maxWidth, aspectRatio, cssClasses, + bbox, axis, grid, code, + src, request, postpone = false, + scripts = document.getElementsByTagName('script'), + init = function (code, type, bbox) { + var board = JXG.JSXGraph.initBoard(id, {boundingbox: bbox, keepaspectratio: true, grid: grid, axis: axis, showReload: true}); - // selection - if (this.selectingMode) { - this._stopSelecting(evt); - this.triggerEventHandlers(['touchstopselecting', 'stopselecting'], [evt]); - } else if (evtTouches && evtTouches.length > 0) { - for (i = 0; i < this.touches.length; i++) { - tmpTouches[i] = this.touches[i]; - } - this.touches.length = 0; + if (type.toLowerCase().indexOf('script') > -1) { + board.construct(code); + } else { + try { + board.jc.parse(code); + } catch (e2) { + JXG.debug(e2); + } + } - // try to convert the operation, e.g. if a lines is rotated and translated with two fingers and one finger is lifted, - // convert the operation to a simple one-finger-translation. - // ADDENDUM 11/10/11: - // see addendum to touchStartListener from 11/10/11 - // (1) run through the tmptouches - // (2) check the touches.obj, if it is a - // (a) point, try to find the targettouch, if found keep it and mark the targettouch, else drop the touch. - // (b) line with - // (i) one target: try to find it, if found keep it mark the targettouch, else drop the touch. - // (ii) two targets: if none can be found, drop the touch. if one can be found, remove the other target. mark all found targettouches - // (c) circle with [proceed like in line] + return board; + }, + makeReload = function (board, code, type, bbox) { + return function () { + var newBoard; - // init the targettouches marker - for (i = 0; i < evtTouches.length; i++) { - evtTouches[i].jxg_isused = false; - } + JXG.JSXGraph.freeBoard(board); + newBoard = init(code, type, bbox); + newBoard.reload = makeReload(newBoard, code, type, bbox); + }; + }; - for (i = 0; i < tmpTouches.length; i++) { - // could all targets of the current this.touches.obj be assigned to targettouches? - found = false; - foundNumber = 0; + for (i = 0; i < scripts.length; i++) { + type = scripts[i].getAttribute('type', false); - for (j = 0; j < tmpTouches[i].targets.length; j++) { - tmpTouches[i].targets[j].found = false; - for (k = 0; k < evtTouches.length; k++) { - if (Math.abs(Math.pow(evtTouches[k].screenX - tmpTouches[i].targets[j].X, 2) + Math.pow(evtTouches[k].screenY - tmpTouches[i].targets[j].Y, 2)) < eps * eps) { - tmpTouches[i].targets[j].found = true; - tmpTouches[i].targets[j].num = k; - tmpTouches[i].targets[j].X = evtTouches[k].screenX; - tmpTouches[i].targets[j].Y = evtTouches[k].screenY; - foundNumber += 1; - break; - } + if (Type.exists(type) && + (type.toLowerCase() === 'text/jessiescript' || type.toLowerCase() === 'jessiescript' || + type.toLowerCase() === 'text/jessiecode' || type.toLowerCase() === 'jessiecode')) { + cssClasses = scripts[i].getAttribute('class', false) || ''; + width = scripts[i].getAttribute('width', false) || ''; + height = scripts[i].getAttribute('height', false) || ''; + maxWidth = scripts[i].getAttribute('maxwidth', false) || '100%'; + aspectRatio = scripts[i].getAttribute('aspectratio', false) || '1/1'; + bbox = scripts[i].getAttribute('boundingbox', false) || '-5, 5, 5, -5'; + id = scripts[i].getAttribute('container', false); + src = scripts[i].getAttribute('src', false); + + bbox = bbox.split(','); + if (bbox.length !== 4) { + bbox = [-5, 5, 5, -5]; + } else { + for (j = 0; j < bbox.length; j++) { + bbox[j] = parseFloat(bbox[j]); } } + axis = Type.str2Bool(scripts[i].getAttribute('axis', false) || 'false'); + grid = Type.str2Bool(scripts[i].getAttribute('grid', false) || 'false'); - if (Type.isPoint(tmpTouches[i].obj)) { - found = (tmpTouches[i].targets[0] && tmpTouches[i].targets[0].found); - } else if (tmpTouches[i].obj.elementClass === Const.OBJECT_CLASS_LINE) { - found = (tmpTouches[i].targets[0] && tmpTouches[i].targets[0].found) || (tmpTouches[i].targets[1] && tmpTouches[i].targets[1].found); - } else if (tmpTouches[i].obj.elementClass === Const.OBJECT_CLASS_CIRCLE) { - found = foundNumber === 1 || foundNumber === 3; - } + if (!Type.exists(id)) { + id = 'jessiescript_autgen_jxg_' + i; + div = document.createElement('div'); + div.setAttribute('id', id); - // if we found this object to be still dragged by the user, add it back to this.touches - if (found) { - this.touches.push({ - obj: tmpTouches[i].obj, - targets: [] - }); + txt = (width !== '') ? ('width:' + width + ';') : ''; + txt += (height !== '') ? ('height:' + height + ';') : ''; + txt += (maxWidth !== '') ? ('max-width:' + maxWidth + ';') : ''; + txt += (aspectRatio !== '') ? ('aspect-ratio:' + aspectRatio + ';') : ''; - for (j = 0; j < tmpTouches[i].targets.length; j++) { - if (tmpTouches[i].targets[j].found) { - this.touches[this.touches.length - 1].targets.push({ - num: tmpTouches[i].targets[j].num, - X: tmpTouches[i].targets[j].screenX, - Y: tmpTouches[i].targets[j].screenY, - Xprev: NaN, - Yprev: NaN, - Xstart: tmpTouches[i].targets[j].Xstart, - Ystart: tmpTouches[i].targets[j].Ystart, - Zstart: tmpTouches[i].targets[j].Zstart - }); + div.setAttribute('style', txt); + div.setAttribute('class', 'jxgbox ' + cssClasses); + try { + document.body.insertBefore(div, scripts[i]); + } catch (e) { + // there's probably jquery involved... + if (typeof jQuery === 'object') { + jQuery(div).insertBefore(scripts[i]); } } - } else { - tmpTouches[i].obj.noHighlight(); + div = document.getElementById(id); } - } - } else { - this.touches.length = 0; - } + code = ''; - for (i = this.downObjects.length - 1; i > -1; i--) { - found = false; - for (j = 0; j < this.touches.length; j++) { - if (this.touches[j].obj.id === this.downObjects[i].id) { - found = true; + if (Type.exists(src)) { + postpone = true; + request = new XMLHttpRequest(); + request.open("GET", src); + request.overrideMimeType("text/plain; charset=x-user-defined"); + /* jshint ignore:start */ + request.addEventListener("load", function() { + if (this.status < 400) { + code = this.responseText + '\n' + code; + board = init(code, type, bbox); + board.reload = makeReload(board, code, type, bbox); + } else { + throw new Error("\nJSXGraph: failed to load file", src, ":", this.responseText); + } + }); + request.addEventListener("error", function(e) { + throw new Error("\nJSXGraph: failed to load file", src, ":", e); + }); + /* jshint ignore:end */ + request.send(); + } else { + postpone = false; } - } - if (!found) { - this.downObjects[i].triggerEventHandlers(['touchup', 'up'], [evt]); - this.downObjects[i].snapToGrid(); - this.downObjects[i].snapToPoints(); - this.downObjects.splice(i, 1); - } - } - if (!evtTouches || evtTouches.length === 0) { + if (document.getElementById(id)) { + code = scripts[i].innerHTML; + code = code.replace(/<!\[CDATA\[/g, '').replace(/\]\]>/g, ''); + scripts[i].innerHTML = code; - if (this.hasTouchEnd) { - Env.removeEvent(this.document, 'touchend', this.touchEndListener, this); - this.hasTouchEnd = false; + if (!postpone) { + // Do no wait for data from "src" attribute + board = init(code, type, bbox); + board.reload = makeReload(board, code, type, bbox); + } + } else { + JXG.debug('JSXGraph: Apparently the div injection failed. Can\'t create a board, sorry.'); + } } - - this.dehighlightAll(); - this.updateQuality = this.BOARD_QUALITY_HIGH; - - this.originMoveEnd(); - this.update(); } + }, window); + } - return true; - }, - - /** - * This method is called by the browser when the mouse button is clicked. - * @param {Event} evt The browsers event object. - * @returns {Boolean} True if no element is found under the current mouse pointer, false otherwise. - */ - mouseDownListener: function (evt) { - var pos, elements, result; + return JXG.JSXGraph; +}); - // prevent accidental selection of text - if (this.document.selection && Type.isFunction(this.document.selection.empty)) { - this.document.selection.empty(); - } else if (window.getSelection) { - window.getSelection().removeAllRanges(); - } +/* + Copyright 2008-2022 + Matthias Ehmann, + Michael Gerhaeuser, + Carsten Miller, + Bianca Valentin, + Alfred Wassermann, + Peter Wilfahrt - if (!this.hasMouseUp) { - Env.addEvent(this.document, 'mouseup', this.mouseUpListener, this); - this.hasMouseUp = true; - } else { - // In case this.hasMouseUp==true, it may be that there was a - // mousedown event before which was not followed by an mouseup event. - // This seems to happen with interactive whiteboard pens sometimes. - return; - } + This file is part of JSXGraph. - this._inputDevice = 'mouse'; - this.options.precision.hasPoint = this.options.precision.mouse; - pos = this.getMousePosition(evt); + JSXGraph is free software dual licensed under the GNU LGPL or MIT License. - // selection - this._testForSelection(evt); - if (this.selectingMode) { - this._startSelecting(pos); - this.triggerEventHandlers(['mousestartselecting', 'startselecting'], [evt]); - return; // don't continue as a normal click - } + You can redistribute it and/or modify it under the terms of the - elements = this.initMoveObject(pos[0], pos[1], evt, 'mouse'); + * GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version + OR + * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT - // if no draggable object can be found, get out here immediately - if (elements.length === 0) { - this.mode = this.BOARD_MODE_NONE; - result = true; - } else { - this.mouse = { - obj: null, - targets: [{ - X: pos[0], - Y: pos[1], - Xprev: NaN, - Yprev: NaN - }] - }; - this.mouse.obj = elements[elements.length - 1]; + JSXGraph is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. - this.dehighlightAll(); - this.mouse.obj.highlight(true); + You should have received a copy of the GNU Lesser General Public License and + the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> + and <http://opensource.org/licenses/MIT/>. + */ - this.mouse.targets[0].Xstart = []; - this.mouse.targets[0].Ystart = []; - this.mouse.targets[0].Zstart = []; - this.saveStartPos(this.mouse.obj, this.mouse.targets[0]); +/*global JXG: true, define: true, console: true, window: true*/ +/*jslint nomen: true, plusplus: true*/ - // prevent accidental text selection - // this could get us new trouble: input fields, links and drop down boxes placed as text - // on the board don't work anymore. - if (evt && evt.preventDefault) { - evt.preventDefault(); - } else if (window.event) { - window.event.returnValue = false; - } - } - - if (this.mode === this.BOARD_MODE_NONE) { - result = this.mouseOriginMoveStart(evt); - } +/* depends: + jxg + options + math/math + math/geometry + math/numerics + base/coords + base/constants + base/element + parser/geonext + utils/type + elements: + transform + */ - this.triggerEventHandlers(['mousedown', 'down'], [evt]); +/** + * @fileoverview The geometry object Point is defined in this file. Point stores all + * style and functional properties that are required to draw and move a point on + * a board. + */ - return result; - }, +define('base/point',[ + 'jxg', 'options', 'math/math', 'math/geometry', 'base/constants', 'base/element', + 'utils/type', 'base/coordselement' +], function (JXG, Options, Mat, Geometry, Const, GeometryElement, Type, CoordsElement) { - /** - * This method is called by the browser when the mouse is moved. - * @param {Event} evt The browsers event object. - */ - mouseMoveListener: function (evt) { - var pos; + "use strict"; - if (!this.checkFrameRate(evt)) { - return false; - } + /** + * A point is the basic geometric element. Based on points lines and circles can be constructed which can be intersected + * which in turn are points again which can be used to construct new lines, circles, polygons, etc. This class holds methods for + * all kind of points like free points, gliders, and intersection points. + * @class Creates a new point object. Do not use this constructor to create a point. Use {@link JXG.Board#create} with + * type {@link Point}, {@link Glider}, or {@link Intersection} instead. + * @augments JXG.GeometryElement + * @augments JXG.CoordsElement + * @param {string|JXG.Board} board The board the new point is drawn on. + * @param {Array} coordinates An array with the user coordinates of the point. + * @param {Object} attributes An object containing visual properties like in {@link JXG.Options#point} and + * {@link JXG.Options#elements}, and optional a name and an id. + * @see JXG.Board#generateName + */ + JXG.Point = function (board, coordinates, attributes) { + this.constructor(board, attributes, Const.OBJECT_TYPE_POINT, Const.OBJECT_CLASS_POINT); + this.element = this.board.select(attributes.anchor); + this.coordsConstructor(coordinates); - pos = this.getMousePosition(evt); + this.elType = 'point'; - this.updateQuality = this.BOARD_QUALITY_LOW; + /* Register point at board. */ + this.id = this.board.setId(this, 'P'); + this.board.renderer.drawPoint(this); + this.board.finalizeAdding(this); - if (this.mode !== this.BOARD_MODE_DRAG) { - this.dehighlightAll(); - this.displayInfobox(false); - } + this.createGradient(); + this.createLabel(); - // we have to check for four cases: - // * user moves origin - // * user drags an object - // * user just moves the mouse, here highlight all elements at - // the current mouse position - // * the user is selecting + }; - // selection - if (this.selectingMode) { - this._moveSelecting(pos); - this.triggerEventHandlers(['mousemoveselecting', 'moveselecting'], [evt, this.mode]); - } else if (!this.mouseOriginMove(evt)) { - if (this.mode === this.BOARD_MODE_DRAG) { - this.moveObject(pos[0], pos[1], this.mouse, evt, 'mouse'); - } else { // BOARD_MODE_NONE - // Move event without dragging an element - this.highlightElements(pos[0], pos[1], evt, -1); - } - this.triggerEventHandlers(['mousemove', 'move'], [evt, this.mode]); - } - this.updateQuality = this.BOARD_QUALITY_HIGH; - }, + /** + * Inherits here from {@link JXG.GeometryElement}. + */ + JXG.Point.prototype = new GeometryElement(); + Type.copyPrototypeMethods(JXG.Point, CoordsElement, 'coordsConstructor'); + JXG.extend(JXG.Point.prototype, /** @lends JXG.Point.prototype */ { /** - * This method is called by the browser when the mouse button is released. - * @param {Event} evt + * Checks whether (x,y) is near the point. + * @param {Number} x Coordinate in x direction, screen coordinates. + * @param {Number} y Coordinate in y direction, screen coordinates. + * @returns {Boolean} True if (x,y) is near the point, False otherwise. + * @private */ - mouseUpListener: function (evt) { - var i; - - if (this.selectingMode === false) { - this.triggerEventHandlers(['mouseup', 'up'], [evt]); - } - - // redraw with high precision - this.updateQuality = this.BOARD_QUALITY_HIGH; - - if (this.mouse && this.mouse.obj) { - // The parameter is needed for lines with snapToGrid enabled - this.mouse.obj.snapToGrid(this.mouse.targets[0]); - this.mouse.obj.snapToPoints(); - } - - this.originMoveEnd(); - this.dehighlightAll(); - this.update(); + hasPoint: function (x, y) { + var coordsScr = this.coords.scrCoords, r, + prec, type, + unit = Type.evaluate(this.visProp.sizeunit); - // selection - if (this.selectingMode) { - this._stopSelecting(evt); - this.triggerEventHandlers(['mousestopselecting', 'stopselecting'], [evt]); + if (Type.isObject(Type.evaluate(this.visProp.precision))) { + type = this.board._inputDevice; + prec = Type.evaluate(this.visProp.precision[type]); } else { - for (i = 0; i < this.downObjects.length; i++) { - this.downObjects[i].triggerEventHandlers(['mouseup', 'up'], [evt]); - } + // 'inherit' + prec = this.board.options.precision.hasPoint; + } + r = parseFloat(Type.evaluate(this.visProp.size)); + if (unit === 'user') { + r *= Math.sqrt(this.board.unitX * this.board.unitY); } - this.downObjects.length = 0; - - if (this.hasMouseUp) { - Env.removeEvent(this.document, 'mouseup', this.mouseUpListener, this); - this.hasMouseUp = false; + r += parseFloat(Type.evaluate(this.visProp.strokewidth)) * 0.5; + if (r < prec) { + r = prec; } - // release dragged mouse object - this.mouse = null; + return ((Math.abs(coordsScr[1] - x) < r + 2) && (Math.abs(coordsScr[2] - y) < r + 2)); }, /** - * Handler for mouse wheel events. Used to zoom in and out of the board. - * @param {Event} evt - * @returns {Boolean} + * Updates the position of the point. */ - mouseWheelListener: function (evt) { - if (!this.attr.zoom.wheel || !this._isRequiredKeyPressed(evt, 'zoom')) { - return true; + update: function (fromParent) { + if (!this.needsUpdate) { + return this; } - evt = evt || window.event; - var wd = evt.detail ? -evt.detail : evt.wheelDelta / 40, - pos = new Coords(Const.COORDS_BY_SCREEN, this.getMousePosition(evt), this); + this.updateCoords(fromParent); - if (wd > 0) { - this.zoomIn(pos.usrCoords[1], pos.usrCoords[2]); - } else { - this.zoomOut(pos.usrCoords[1], pos.usrCoords[2]); + if (Type.evaluate(this.visProp.trace)) { + this.cloneToBackground(true); } - this.triggerEventHandlers(['mousewheel'], [evt]); - - evt.preventDefault(); - return false; - }, - - /********************************************************** - * - * End of Event Handlers - * - **********************************************************/ - - /** - * Initialize the info box object which is used to display - * the coordinates of points near the mouse pointer, - * @returns {JXG.Board} Reference to the board - */ - initInfobox: function () { - var attr = Type.copyAttributes({}, this.options, 'infobox'); - - attr.id = this.id + '_infobox'; - this.infobox = this.create('text', [0, 0, '0,0'], attr); - - this.infobox.distanceX = -20; - this.infobox.distanceY = 25; - // this.infobox.needsUpdateSize = false; // That is not true, but it speeds drawing up. - - this.infobox.dump = false; - - this.displayInfobox(false); return this; }, /** - * Updates and displays a little info box to show coordinates of current selected points. - * @param {JXG.GeometryElement} el A GeometryElement - * @returns {JXG.Board} Reference to the board - * @see JXG.Board#displayInfobox - * @see JXG.Board#showInfobox - * @see Point#showInfobox - * + * Applies the transformations of the element to {@link JXG.Point#baseElement}. + * Point transformations are relative to a base element. + * @param {Boolean} fromParent True if the drag comes from a child element. This is the case if a line + * through two points is dragged. Otherwise, the element is the drag element and we apply the + * the inverse transformation to the baseElement if is different from the element. + * @returns {JXG.CoordsElement} Reference to this object. */ - updateInfobox: function (el) { - var x, y, xc, yc, - vpinfoboxdigits, - vpsi = Type.evaluate(el.visProp.showinfobox); + updateTransform: function (fromParent) { + var c, i; - if ((!Type.evaluate(this.attr.showinfobox) && vpsi === 'inherit') || - !vpsi) { + if (this.transformations.length === 0 || this.baseElement === null) { return this; } - if (Type.isPoint(el)) { - xc = el.coords.usrCoords[1]; - yc = el.coords.usrCoords[2]; - - vpinfoboxdigits = Type.evaluate(el.visProp.infoboxdigits); - this.infobox.setCoords(xc + this.infobox.distanceX / this.unitX, - yc + this.infobox.distanceY / this.unitY); - - if (typeof el.infoboxText !== 'string') { - if (vpinfoboxdigits === 'auto') { - x = Type.autoDigits(xc); - y = Type.autoDigits(yc); - } else if (Type.isNumber(vpinfoboxdigits)) { - x = Type.toFixed(xc, vpinfoboxdigits); - y = Type.toFixed(yc, vpinfoboxdigits); - } else { - x = xc; - y = yc; - } - - this.highlightInfobox(x, y, el); - } else { - this.highlightCustomInfobox(el.infoboxText, el); - } + if (this === this.baseElement) { + // Case of bindTo + c = this.transformations[0].apply(this.baseElement, 'self'); + this.coords.setCoordinates(Const.COORDS_BY_USER, c); + } else { + c = this.transformations[0].apply(this.baseElement); + } + this.coords.setCoordinates(Const.COORDS_BY_USER, c); - this.displayInfobox(true); + for (i = 1; i < this.transformations.length; i++) { + this.coords.setCoordinates(Const.COORDS_BY_USER, this.transformations[i].apply(this)); } return this; }, /** - * Set infobox visible / invisible. - * - * It uses its property hiddenByParent to memorize its status. - * In this way, many DOM access can be avoided. - * - * @param {Boolean} val true for visible, false for invisible - * @returns {JXG.Board} Reference to the board. - * @see JXG.Board#updateInfobox - * + * Calls the renderer to update the drawing. + * @private */ - displayInfobox: function(val) { - if (this.infobox.hiddenByParent == val) { - this.infobox.hiddenByParent = !val; - this.infobox.prepareUpdate().updateVisibility(val).updateRenderer(); - } + updateRenderer: function () { + this.updateRendererGeneric('updatePoint'); return this; }, - // Alias for displayInfobox to be backwards compatible. - // The method showInfobox clashes with the board attribute showInfobox - showInfobox: function(val) { - return this.displayInfobox(val); + // documented in JXG.GeometryElement + bounds: function () { + return this.coords.usrCoords.slice(1).concat(this.coords.usrCoords.slice(1)); }, /** - * Changes the text of the info box to show the given coordinates. - * @param {Number} x - * @param {Number} y - * @param {JXG.GeometryElement} [el] The element the mouse is pointing at - * @returns {JXG.Board} Reference to the board. - */ - highlightInfobox: function (x, y, el) { - this.highlightCustomInfobox('(' + x + ', ' + y + ')', el); - return this; - }, + * Convert the point to intersection point and update the construction. + * To move the point visual onto the intersection, a call of board update is necessary. + * + * @param {String|Object} el1, el2, i, j The intersecting objects and the numbers. + **/ + makeIntersection: function (el1, el2, i, j) { + var func; - /** - * Changes the text of the info box to what is provided via text. - * @param {String} text - * @param {JXG.GeometryElement} [el] - * @returns {JXG.Board} Reference to the board. - */ - highlightCustomInfobox: function (text, el) { - this.infobox.setText(text); - return this; - }, + el1 = this.board.select(el1); + el2 = this.board.select(el2); - /** - * Remove highlighting of all elements. - * @returns {JXG.Board} Reference to the board. - */ - dehighlightAll: function () { - var el, pEl, needsDehighlight = false; + func = Geometry.intersectionFunction(this.board, el1, el2, i, j, + Type.evaluate(this.visProp.alwaysintersect)); + this.addConstraint([func]); - for (el in this.highlightedObjects) { - if (this.highlightedObjects.hasOwnProperty(el)) { - pEl = this.highlightedObjects[el]; + try { + el1.addChild(this); + el2.addChild(this); + } catch (e) { + throw new Error("JSXGraph: Can't create 'intersection' with parent types '" + + (typeof el1) + "' and '" + (typeof el2) + "'."); + } - if (this.hasMouseHandlers || this.hasPointerHandlers) { - pEl.noHighlight(); - } + this.type = Const.OBJECT_TYPE_INTERSECTION; + this.elType = 'intersection'; + this.parents = [el1.id, el2.id, i, j]; - needsDehighlight = true; + this.generatePolynomial = function () { + var poly1 = el1.generatePolynomial(this), + poly2 = el2.generatePolynomial(this); - // In highlightedObjects should only be objects which fulfill all these conditions - // And in case of complex elements, like a turtle based fractal, it should be faster to - // just de-highlight the element instead of checking hasPoint... - // if ((!Type.exists(pEl.hasPoint)) || !pEl.hasPoint(x, y) || !pEl.visPropCalc.visible) + if ((poly1.length === 0) || (poly2.length === 0)) { + return []; } - } - - this.highlightedObjects = {}; - // We do not need to redraw during dehighlighting in CanvasRenderer - // because we are redrawing anyhow - // -- We do need to redraw during dehighlighting. Otherwise objects won't be dehighlighted until - // another object is highlighted. - if (this.renderer.type === 'canvas' && needsDehighlight) { - this.prepareUpdate(); - this.renderer.suspendRedraw(this); - this.updateRenderer(); - this.renderer.unsuspendRedraw(); - } + return [poly1[0], poly2[0]]; + }; - return this; + this.prepareUpdate().update(); }, /** - * Returns the input parameters in an array. This method looks pointless and it really is, but it had a purpose - * once. - * @param {Number} x X coordinate in screen coordinates - * @param {Number} y Y coordinate in screen coordinates - * @returns {Array} Coordinates of the mouse in screen coordinates. + * Set the style of a point. + * Used for GEONExT import and should not be used to set the point's face and size. + * @param {Number} i Integer to determine the style. + * @private */ - getScrCoordsOfMouse: function (x, y) { - return [x, y]; + setStyle: function (i) { + var facemap = [ + // 0-2 + 'cross', 'cross', 'cross', + // 3-6 + 'circle', 'circle', 'circle', 'circle', + // 7-9 + 'square', 'square', 'square', + // 10-12 + 'plus', 'plus', 'plus' + ], sizemap = [ + // 0-2 + 2, 3, 4, + // 3-6 + 1, 2, 3, 4, + // 7-9 + 2, 3, 4, + // 10-12 + 2, 3, 4 + ]; + + this.visProp.face = facemap[i]; + this.visProp.size = sizemap[i]; + + this.board.renderer.changePointStyle(this); + return this; }, /** - * This method calculates the user coords of the current mouse coordinates. - * @param {Event} evt Event object containing the mouse coordinates. - * @returns {Array} Coordinates of the mouse in screen coordinates. + * @deprecated Use JXG#normalizePointFace instead + * @param s + * @returns {*} */ - getUsrCoordsOfMouse: function (evt) { - var cPos = this.getCoordsTopLeftCorner(), - absPos = Env.getPosition(evt, null, this.document), - x = absPos[0] - cPos[0], - y = absPos[1] - cPos[1], - newCoords = new Coords(Const.COORDS_BY_SCREEN, [x, y], this); - - return newCoords.usrCoords.slice(1); + normalizeFace: function (s) { + JXG.deprecated('Point.normalizeFace()', 'JXG.normalizePointFace()'); + return Options.normalizePointFace(s); }, /** - * Collects all elements under current mouse position plus current user coordinates of mouse cursor. - * @param {Event} evt Event object containing the mouse coordinates. - * @returns {Array} Array of elements at the current mouse position plus current user coordinates of mouse. + * Set the face of a point element. + * @param {String} f String which determines the face of the point. See {@link JXG.GeometryElement#face} for a list of available faces. + * @see JXG.GeometryElement#face + * @deprecated Use setAttribute() */ - getAllUnderMouse: function (evt) { - var elList = this.getAllObjectsUnderMouse(evt); - elList.push(this.getUsrCoordsOfMouse(evt)); - - return elList; + face: function (f) { + JXG.deprecated('Point.face()', 'Point.setAttribute()'); + this.setAttribute({face: f}); }, /** - * Collects all elements under current mouse position. - * @param {Event} evt Event object containing the mouse coordinates. - * @returns {Array} Array of elements at the current mouse position. + * Set the size of a point element + * @param {Number} s Integer which determines the size of the point. + * @see JXG.GeometryElement#size + * @deprecated Use setAttribute() */ - getAllObjectsUnderMouse: function (evt) { - var cPos = this.getCoordsTopLeftCorner(), - absPos = Env.getPosition(evt, null, this.document), - dx = absPos[0] - cPos[0], - dy = absPos[1] - cPos[1], - elList = [], - el, - pEl, - len = this.objectsList.length; - - for (el = 0; el < len; el++) { - pEl = this.objectsList[el]; - if (pEl.visPropCalc.visible && pEl.hasPoint && pEl.hasPoint(dx, dy)) { - elList[elList.length] = pEl; - } - } - - return elList; + size: function (s) { + JXG.deprecated('Point.size()', 'Point.setAttribute()'); + this.setAttribute({size: s}); }, /** - * Update the coords object of all elements which possess this - * property. This is necessary after changing the viewport. - * @returns {JXG.Board} Reference to this board. - **/ - updateCoords: function () { - var el, ob, len = this.objectsList.length; + * Test if the point is on (is incident with) element "el". + * + * @param {JXG.GeometryElement} el + * @param {Number} tol + * @returns {Boolean} + * + * @example + * var circ = board.create('circle', [[-2, -2], 1]); + * var seg = board.create('segment', [[-1, -3], [0,0]]); + * var line = board.create('line', [[1, 3], [2, -2]]); + * var po = board.create('point', [-1, 0], {color: 'blue'}); + * var curve = board.create('functiongraph', ['sin(x)'], {strokeColor: 'blue'}); + * var pol = board.create('polygon', [[2,2], [4,2], [4,3]], {strokeColor: 'blue'}); + * + * var point = board.create('point', [-1, 1], { + * attractors: [line, seg, circ, po, curve, pol], + * attractorDistance: 0.2 + * }); + * + * var txt = board.create('text', [-4, 3, function() { + * return 'point on line: ' + point.isOn(line) + '<br>' + + * 'point on seg: ' + point.isOn(seg) + '<br>' + + * 'point on circ = ' + point.isOn(circ) + '<br>' + + * 'point on point = ' + point.isOn(po) + '<br>' + + * 'point on curve = ' + point.isOn(curve) + '<br>' + + * 'point on polygon = ' + point.isOn(pol) + '<br>'; + * }]); + * + * </pre><div id="JXG6c7d7404-758a-44eb-802c-e9644b9fab71" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG6c7d7404-758a-44eb-802c-e9644b9fab71', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * var circ = board.create('circle', [[-2, -2], 1]); + * var seg = board.create('segment', [[-1, -3], [0,0]]); + * var line = board.create('line', [[1, 3], [2, -2]]); + * var po = board.create('point', [-1, 0], {color: 'blue'}); + * var curve = board.create('functiongraph', ['sin(x)'], {strokeColor: 'blue'}); + * var pol = board.create('polygon', [[2,2], [4,2], [4,3]], {strokeColor: 'blue'}); + * + * var point = board.create('point', [-1, 1], { + * attractors: [line, seg, circ, po, curve, pol], + * attractorDistance: 0.2 + * }); + * + * var txt = board.create('text', [-4, 3, function() { + * return 'point on line: ' + point.isOn(line) + '<br>' + + * 'point on seg: ' + point.isOn(seg) + '<br>' + + * 'point on circ = ' + point.isOn(circ) + '<br>' + + * 'point on point = ' + point.isOn(po) + '<br>' + + * 'point on curve = ' + point.isOn(curve) + '<br>' + + * 'point on polygon = ' + point.isOn(pol) + '<br>'; + * }]); + * + * })(); + * + * </script><pre> + * + */ + isOn: function(el, tol) { + var arr, crds; - for (ob = 0; ob < len; ob++) { - el = this.objectsList[ob]; + tol = tol || Mat.eps; - if (Type.exists(el.coords)) { - if (Type.evaluate(el.visProp.frozen)) { - el.coords.screen2usr(); + if (Type.isPoint(el)) { + return this.Dist(el) < tol; + } else if (el.elementClass === Const.OBJECT_CLASS_LINE) { + if (el.elType === 'segment' && !Type.evaluate(this.visProp.alwaysintersect)) { + arr = JXG.Math.Geometry.projectCoordsToSegment( + this.coords.usrCoords, + el.point1.coords.usrCoords, + el.point2.coords.usrCoords); + if (arr[1] >= 0 && arr[1] <= 1 && + Geometry.distPointLine(this.coords.usrCoords, el.stdform) < tol) { + return true; } else { - el.coords.usr2screen(); + return false; + } + } else { + return Geometry.distPointLine(this.coords.usrCoords, el.stdform) < tol; + } + } else if (el.elementClass === Const.OBJECT_CLASS_CIRCLE) { + if (Type.evaluate(el.visProp.hasinnerpoints)) { + return this.Dist(el.center) < el.Radius() + tol; + } + return Math.abs(this.Dist(el.center) - el.Radius()) < tol; + } else if (el.elementClass === Const.OBJECT_CLASS_CURVE) { + crds = Geometry.projectPointToCurve(this, el, this.board)[0]; + return Geometry.distance(this.coords.usrCoords, crds.usrCoords, 3) < tol; + } else if (el.type === Const.OBJECT_TYPE_POLYGON) { + if (Type.evaluate(el.visProp.hasinnerpoints)) { + if (el.pnpoly(this.coords.usrCoords[1], this.coords.usrCoords[2], JXG.COORDS_BY_USER)) { + return true; } } + arr = Geometry.projectCoordsToPolygon(this.coords.usrCoords, el); + return Geometry.distance(this.coords.usrCoords, arr, 3) < tol; + } else if (el.type === Const.OBJECT_TYPE_TURTLE) { + crds = Geometry.projectPointToTurtle(this, el, this.board); + return Geometry.distance(this.coords.usrCoords, crds.usrCoords, 3) < tol; } - return this; + + // TODO: Arc, Sector + return false; }, - /** - * Moves the origin and initializes an update of all elements. - * @param {Number} x - * @param {Number} y - * @param {Boolean} [diff=false] - * @returns {JXG.Board} Reference to this board. - */ - moveOrigin: function (x, y, diff) { - var ox, oy, ul, lr; - if (Type.exists(x) && Type.exists(y)) { - ox = this.origin.scrCoords[1]; - oy = this.origin.scrCoords[2]; - - this.origin.scrCoords[1] = x; - this.origin.scrCoords[2] = y; + // Already documented in GeometryElement + cloneToBackground: function () { + var copy = {}; - if (diff) { - this.origin.scrCoords[1] -= this.drag_dx; - this.origin.scrCoords[2] -= this.drag_dy; - } + copy.id = this.id + 'T' + this.numTraces; + this.numTraces += 1; - ul = (new Coords(Const.COORDS_BY_SCREEN, [0, 0], this)).usrCoords; - lr = (new Coords(Const.COORDS_BY_SCREEN, [this.canvasWidth, this.canvasHeight], this)).usrCoords; - if (ul[1] < this.maxboundingbox[0] || - ul[2] > this.maxboundingbox[1] || - lr[1] > this.maxboundingbox[2] || - lr[2] < this.maxboundingbox[3]) { + copy.coords = this.coords; + copy.visProp = Type.deepCopy(this.visProp, this.visProp.traceattributes, true); + copy.visProp.layer = this.board.options.layer.trace; + copy.elementClass = Const.OBJECT_CLASS_POINT; + copy.board = this.board; + Type.clearVisPropOld(copy); - this.origin.scrCoords[1] = ox; - this.origin.scrCoords[2] = oy; - } - } + copy.visPropCalc = { + visible: Type.evaluate(copy.visProp.visible) + }; - this.updateCoords().clearTraces().fullUpdate(); - this.triggerEventHandlers(['boundingbox']); + this.board.renderer.drawPoint(copy); + this.traces[copy.id] = copy.rendNode; return this; - }, - - /** - * Add conditional updates to the elements. - * @param {String} str String containing coniditional update in geonext syntax - */ - addConditions: function (str) { - var term, m, left, right, name, el, property, - functions = [], - plaintext = 'var el, x, y, c, rgbo;\n', - i = str.indexOf('<data>'), - j = str.indexOf('<' + '/data>'), - - xyFun = function (board, el, f, what) { - return function () { - var e, t; - - e = board.select(el.id); - t = e.coords.usrCoords[what]; - - if (what === 2) { - e.setPositionDirectly(Const.COORDS_BY_USER, [f(), t]); - } else { - e.setPositionDirectly(Const.COORDS_BY_USER, [t, f()]); - } - e.prepareUpdate().update(); - }; - }, - - visFun = function (board, el, f) { - return function () { - var e, v; + } - e = board.select(el.id); - v = f(); + }); - e.setAttribute({visible: v}); - }; - }, + /** + * @class This element is used to provide a constructor for a general point. A free point is created if the given parent elements are all numbers + * and the property fixed is not set or set to false. If one or more parent elements is not a number but a string containing a GEONE<sub>x</sub>T + * constraint or a function the point will be considered as constrained). That means that the user won't be able to change the point's + * position directly. + * @pseudo + * @description + * @name Point + * @augments JXG.Point + * @constructor + * @type JXG.Point + * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {Number,string,function_Number,string,function_Number,string,function} z_,x,y Parent elements can be two or three elements of type number, a string containing a GEONE<sub>x</sub>T + * constraint, or a function which takes no parameter and returns a number. Every parent element determines one coordinate. If a coordinate is + * given by a number, the number determines the initial position of a free point. If given by a string or a function that coordinate will be constrained + * that means the user won't be able to change the point's position directly by mouse because it will be calculated automatically depending on the string + * or the function's return value. If two parent elements are given the coordinates will be interpreted as 2D affine Euclidean coordinates, if three such + * parent elements are given they will be interpreted as homogeneous coordinates. + * @param {JXG.Point_JXG.Transformation_Array} Point,Transformation A point can also be created providing a transformation or an array of transformations. + * The resulting point is a clone of the base point transformed by the given Transformation. {@see JXG.Transformation}. + * + * @example + * // Create a free point using affine Euclidean coordinates + * var p1 = board.create('point', [3.5, 2.0]); + * </pre><div class="jxgbox" id="JXG672f1764-7dfa-4abc-a2c6-81fbbf83e44b" style="width: 200px; height: 200px;"></div> + * <script type="text/javascript"> + * var board = JXG.JSXGraph.initBoard('JXG672f1764-7dfa-4abc-a2c6-81fbbf83e44b', {boundingbox: [-1, 5, 5, -1], axis: true, showcopyright: false, shownavigation: false}); + * var p1 = board.create('point', [3.5, 2.0]); + * </script><pre> + * @example + * // Create a constrained point using anonymous function + * var p2 = board.create('point', [3.5, function () { return p1.X(); }]); + * </pre><div class="jxgbox" id="JXG4fd4410c-3383-4e80-b1bb-961f5eeef224" style="width: 200px; height: 200px;"></div> + * <script type="text/javascript"> + * var fpex1_board = JXG.JSXGraph.initBoard('JXG4fd4410c-3383-4e80-b1bb-961f5eeef224', {boundingbox: [-1, 5, 5, -1], axis: true, showcopyright: false, shownavigation: false}); + * var fpex1_p1 = fpex1_board.create('point', [3.5, 2.0]); + * var fpex1_p2 = fpex1_board.create('point', [3.5, function () { return fpex1_p1.X(); }]); + * </script><pre> + * @example + * // Create a point using transformations + * var trans = board.create('transform', [2, 0.5], {type:'scale'}); + * var p3 = board.create('point', [p2, trans]); + * </pre><div class="jxgbox" id="JXG630afdf3-0a64-46e0-8a44-f51bd197bb8d" style="width: 400px; height: 400px;"></div> + * <script type="text/javascript"> + * var fpex2_board = JXG.JSXGraph.initBoard('JXG630afdf3-0a64-46e0-8a44-f51bd197bb8d', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); + * var fpex2_trans = fpex2_board.create('transform', [2, 0.5], {type:'scale'}); + * var fpex2_p2 = fpex2_board.create('point', [3.5, 2.0]); + * var fpex2_p3 = fpex2_board.create('point', [fpex2_p2, fpex2_trans]); + * </script><pre> + */ + JXG.createPoint = function (board, parents, attributes) { + var el, attr; - colFun = function (board, el, f, what) { - return function () { - var e, v; + attr = Type.copyAttributes(attributes, board.options, 'point'); + el = CoordsElement.create(JXG.Point, board, parents, attr); + if (!el) { + throw new Error("JSXGraph: Can't create point with parent types '" + + (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + + "\nPossible parent types: [x,y], [z,x,y], [element,transformation]"); + } - e = board.select(el.id); - v = f(); + return el; + }; - if (what === 'strokewidth') { - e.visProp.strokewidth = v; - } else { - v = Color.rgba2rgbo(v); - e.visProp[what + 'color'] = v[0]; - e.visProp[what + 'opacity'] = v[1]; - } - }; - }, + /** + * @class This element is used to provide a constructor for a glider point. + * @pseudo + * @description A glider is a point which lives on another geometric element like a line, circle, curve, turtle. + * @name Glider + * @augments JXG.Point + * @constructor + * @type JXG.Point + * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {Number_Number_Number_JXG.GeometryElement} z_,x_,y_,GlideObject Parent elements can be two or three elements of type number and the object the glider lives on. + * The coordinates are completely optional. If not given the origin is used. If you provide two numbers for coordinates they will be interpreted as affine Euclidean + * coordinates, otherwise they will be interpreted as homogeneous coordinates. In any case the point will be projected on the glide object. + * @example + * // Create a glider with user defined coordinates. If the coordinates are not on + * // the circle (like in this case) the point will be projected onto the circle. + * var p1 = board.create('point', [2.0, 2.0]); + * var c1 = board.create('circle', [p1, 2.0]); + * var p2 = board.create('glider', [2.0, 1.5, c1]); + * </pre><div class="jxgbox" id="JXG4f65f32f-e50a-4b50-9b7c-f6ec41652930" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * var gpex1_board = JXG.JSXGraph.initBoard('JXG4f65f32f-e50a-4b50-9b7c-f6ec41652930', {boundingbox: [-1, 5, 5, -1], axis: true, showcopyright: false, shownavigation: false}); + * var gpex1_p1 = gpex1_board.create('point', [2.0, 2.0]); + * var gpex1_c1 = gpex1_board.create('circle', [gpex1_p1, 2.0]); + * var gpex1_p2 = gpex1_board.create('glider', [2.0, 1.5, gpex1_c1]); + * </script><pre> + * @example + * // Create a glider with default coordinates (1,0,0). Same premises as above. + * var p1 = board.create('point', [2.0, 2.0]); + * var c1 = board.create('circle', [p1, 2.0]); + * var p2 = board.create('glider', [c1]); + * </pre><div class="jxgbox" id="JXG4de7f181-631a-44b1-a12f-bc4d995609e8" style="width: 200px; height: 200px;"></div> + * <script type="text/javascript"> + * var gpex2_board = JXG.JSXGraph.initBoard('JXG4de7f181-631a-44b1-a12f-bc4d995609e8', {boundingbox: [-1, 5, 5, -1], axis: true, showcopyright: false, shownavigation: false}); + * var gpex2_p1 = gpex2_board.create('point', [2.0, 2.0]); + * var gpex2_c1 = gpex2_board.create('circle', [gpex2_p1, 2.0]); + * var gpex2_p2 = gpex2_board.create('glider', [gpex2_c1]); + * </script><pre> + *@example + * //animate example 2 + * var p1 = board.create('point', [2.0, 2.0]); + * var c1 = board.create('circle', [p1, 2.0]); + * var p2 = board.create('glider', [c1]); + * var button1 = board.create('button', [1, 7, 'start animation',function(){p2.startAnimation(1,4)}]); + * var button2 = board.create('button', [1, 5, 'stop animation',function(){p2.stopAnimation()}]); + * </pre><div class="jxgbox" id="JXG4de7f181-631a-44b1-a12f-bc4d133709e8" style="width: 200px; height: 200px;"></div> + * <script type="text/javascript"> + * var gpex3_board = JXG.JSXGraph.initBoard('JXG4de7f181-631a-44b1-a12f-bc4d133709e8', {boundingbox: [-1, 10, 10, -1], axis: true, showcopyright: false, shownavigation: false}); + * var gpex3_p1 = gpex3_board.create('point', [2.0, 2.0]); + * var gpex3_c1 = gpex3_board.create('circle', [gpex3_p1, 2.0]); + * var gpex3_p2 = gpex3_board.create('glider', [gpex3_c1]); + * gpex3_board.create('button', [1, 7, 'start animation',function(){gpex3_p2.startAnimation(1,4)}]); + * gpex3_board.create('button', [1, 5, 'stop animation',function(){gpex3_p2.stopAnimation()}]); + * </script><pre> + */ + JXG.createGlider = function (board, parents, attributes) { + var el, coords, + attr = Type.copyAttributes(attributes, board.options, 'glider'); - posFun = function (board, el, f) { - return function () { - var e = board.select(el.id); + if (parents.length === 1) { + coords = [0, 0]; + } else { + coords = parents.slice(0, 2); + } + el = board.create('point', coords, attr); - e.position = f(); - }; - }, + // eltype is set in here + el.makeGlider(parents[parents.length - 1]); - styleFun = function (board, el, f) { - return function () { - var e = board.select(el.id); + return el; + }; - e.setStyle(f()); - }; - }; - if (i < 0) { - return; - } + /** + * @class An intersection point is a point which lives on two JSXGraph elements, i.e. it is one point of the the set + * consisting of the intersection points of the two elements. The following element types can be (mutually) intersected: line, circle, + * curve, polygon, polygonal chain. + * + * @pseudo + * @name Intersection + * @augments JXG.Point + * @constructor + * @type JXG.Point + * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {JXG.Line,JXG.Circle_JXG.Line,JXG.Circle_Number} el1,el2,i The result will be a intersection point on el1 and el2. i determines the + * intersection point if two points are available: <ul> + * <li>i==0: use the positive square root,</li> + * <li>i==1: use the negative square root.</li></ul> + * @example + * // Create an intersection point of circle and line + * var p1 = board.create('point', [2.0, 2.0]); + * var c1 = board.create('circle', [p1, 2.0]); + * + * var p2 = board.create('point', [2.0, 2.0]); + * var p3 = board.create('point', [2.0, 2.0]); + * var l1 = board.create('line', [p2, p3]); + * + * var i = board.create('intersection', [c1, l1, 0]); + * </pre><div class="jxgbox" id="JXGe5b0e190-5200-4bc3-b995-b6cc53dc5dc0" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * var ipex1_board = JXG.JSXGraph.initBoard('JXGe5b0e190-5200-4bc3-b995-b6cc53dc5dc0', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}); + * var ipex1_p1 = ipex1_board.create('point', [4.0, 4.0]); + * var ipex1_c1 = ipex1_board.create('circle', [ipex1_p1, 2.0]); + * var ipex1_p2 = ipex1_board.create('point', [1.0, 1.0]); + * var ipex1_p3 = ipex1_board.create('point', [5.0, 3.0]); + * var ipex1_l1 = ipex1_board.create('line', [ipex1_p2, ipex1_p3]); + * var ipex1_i = ipex1_board.create('intersection', [ipex1_c1, ipex1_l1, 0]); + * </script><pre> + */ + JXG.createIntersectionPoint = function (board, parents, attributes) { + var el, el1, el2, func, i, j, + attr = Type.copyAttributes(attributes, board.options, 'intersection'); - while (i >= 0) { - term = str.slice(i + 6, j); // throw away <data> - m = term.indexOf('='); - left = term.slice(0, m); - right = term.slice(m + 1); - m = left.indexOf('.'); // Dies erzeugt Probleme bei Variablennamen der Form " Steuern akt." - name = left.slice(0, m); //.replace(/\s+$/,''); // do NOT cut out name (with whitespace) - el = this.elementsByName[Type.unescapeHTML(name)]; + // make sure we definitely have the indices + parents.push(0, 0); - property = left.slice(m + 1).replace(/\s+/g, '').toLowerCase(); // remove whitespace in property - right = Type.createFunction (right, this, '', true); + el1 = board.select(parents[0]); + el2 = board.select(parents[1]); - // Debug - if (!Type.exists(this.elementsByName[name])) { - JXG.debug("debug conditions: |" + name + "| undefined"); - } else { - plaintext += "el = this.objects[\"" + el.id + "\"];\n"; + i = parents[2] || 0; + j = parents[3] || 0; - switch (property) { - case 'x': - functions.push(xyFun(this, el, right, 2)); - break; - case 'y': - functions.push(xyFun(this, el, right, 1)); - break; - case 'visible': - functions.push(visFun(this, el, right)); - break; - case 'position': - functions.push(posFun(this, el, right)); - break; - case 'stroke': - functions.push(colFun(this, el, right, 'stroke')); - break; - case 'style': - functions.push(styleFun(this, el, right)); - break; - case 'strokewidth': - functions.push(colFun(this, el, right, 'strokewidth')); - break; - case 'fill': - functions.push(colFun(this, el, right, 'fill')); - break; - case 'label': - break; - default: - JXG.debug("property '" + property + "' in conditions not yet implemented:" + right); - break; - } - } - str = str.slice(j + 7); // cut off "</data>" - i = str.indexOf('<data>'); - j = str.indexOf('<' + '/data>'); - } + el = board.create('point', [0, 0, 0], attr); - this.updateConditions = function () { - var i; + // el.visProp.alwaysintersect is evaluated as late as in the returned function + func = Geometry.intersectionFunction(board, el1, el2, i, j, el.visProp.alwaysintersect); + el.addConstraint([func]); - for (i = 0; i < functions.length; i++) { - functions[i](); - } + try { + el1.addChild(el); + el2.addChild(el); + } catch (e) { + throw new Error("JSXGraph: Can't create 'intersection' with parent types '" + + (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'."); + } - this.prepareUpdate().updateElements(); - return true; - }; - this.updateConditions(); - }, + el.type = Const.OBJECT_TYPE_INTERSECTION; + el.elType = 'intersection'; + el.setParents([el1.id, el2.id]); /** - * Computes the commands in the conditions-section of the gxt file. - * It is evaluated after an update, before the unsuspendRedraw. - * The function is generated in - * @see JXG.Board#addConditions + * Array of length 2 containing the numbers i and j. + * The intersection point is i-th intersection point. + * j is unused. + * @type Array * @private */ - updateConditions: function () { - return false; - }, + el.intersectionNumbers = [i, j]; + el.getParents = function() { + return this.parents.concat(this.intersectionNumbers); + }; - /** - * Calculates adequate snap sizes. - * @returns {JXG.Board} Reference to the board. - */ - calculateSnapSizes: function () { - var p1 = new Coords(Const.COORDS_BY_USER, [0, 0], this), - p2 = new Coords(Const.COORDS_BY_USER, [this.options.grid.gridX, this.options.grid.gridY], this), - x = p1.scrCoords[1] - p2.scrCoords[1], - y = p1.scrCoords[2] - p2.scrCoords[2]; + el.generatePolynomial = function () { + var poly1 = el1.generatePolynomial(el), + poly2 = el2.generatePolynomial(el); - this.options.grid.snapSizeX = this.options.grid.gridX; - while (Math.abs(x) > 25) { - this.options.grid.snapSizeX *= 2; - x /= 2; + if ((poly1.length === 0) || (poly2.length === 0)) { + return []; } - this.options.grid.snapSizeY = this.options.grid.gridY; - while (Math.abs(y) > 25) { - this.options.grid.snapSizeY *= 2; - y /= 2; - } + return [poly1[0], poly2[0]]; + }; - return this; - }, + return el; + }; - /** - * Apply update on all objects with the new zoom-factors. Clears all traces. - * @returns {JXG.Board} Reference to the board. - */ - applyZoom: function () { - this.updateCoords().calculateSnapSizes().clearTraces().fullUpdate(); + /** + * @class This element is used to provide a constructor for the "other" intersection point. + * @pseudo + * @description An intersection point is a point which lives on two Lines or Circles or one Line and one Circle at the same time, i.e. + * an intersection point of the two elements. Additionally, one intersection point is provided. The function returns the other intersection point. + * @name OtherIntersection + * @augments JXG.Point + * @constructor + * @type JXG.Point + * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {JXG.Line,JXG.Circle_JXG.Line,JXG.Circle_JXG.Point} el1,el2,p The result will be a intersection point on el1 and el2. i determines the + * intersection point different from p: + * @example + * // Create an intersection point of circle and line + * var p1 = board.create('point', [2.0, 2.0]); + * var c1 = board.create('circle', [p1, 2.0]); + * + * var p2 = board.create('point', [2.0, 2.0]); + * var p3 = board.create('point', [2.0, 2.0]); + * var l1 = board.create('line', [p2, p3]); + * + * var i = board.create('intersection', [c1, l1, 0]); + * var j = board.create('otherintersection', [c1, l1, i]); + * </pre><div class="jxgbox" id="JXG45e25f12-a1de-4257-a466-27a2ae73614c" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * var ipex2_board = JXG.JSXGraph.initBoard('JXG45e25f12-a1de-4257-a466-27a2ae73614c', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}); + * var ipex2_p1 = ipex2_board.create('point', [4.0, 4.0]); + * var ipex2_c1 = ipex2_board.create('circle', [ipex2_p1, 2.0]); + * var ipex2_p2 = ipex2_board.create('point', [1.0, 1.0]); + * var ipex2_p3 = ipex2_board.create('point', [5.0, 3.0]); + * var ipex2_l1 = ipex2_board.create('line', [ipex2_p2, ipex2_p3]); + * var ipex2_i = ipex2_board.create('intersection', [ipex2_c1, ipex2_l1, 0], {name:'D'}); + * var ipex2_j = ipex2_board.create('otherintersection', [ipex2_c1, ipex2_l1, ipex2_i], {name:'E'}); + * </script><pre> + */ + JXG.createOtherIntersectionPoint = function (board, parents, attributes) { + var el, el1, el2, other; - return this; - }, + if (parents.length !== 3 || + !Type.isPoint(parents[2]) || + (parents[0].elementClass !== Const.OBJECT_CLASS_LINE && parents[0].elementClass !== Const.OBJECT_CLASS_CIRCLE) || + (parents[1].elementClass !== Const.OBJECT_CLASS_LINE && parents[1].elementClass !== Const.OBJECT_CLASS_CIRCLE)) { + // Failure + throw new Error("JSXGraph: Can't create 'other intersection point' with parent types '" + + (typeof parents[0]) + "', '" + (typeof parents[1]) + "'and '" + (typeof parents[2]) + "'." + + "\nPossible parent types: [circle|line,circle|line,point]"); + } - /** - * Zooms into the board by the factors board.attr.zoom.factorX and board.attr.zoom.factorY and applies the zoom. - * The zoom operation is centered at x, y. - * @param {Number} [x] - * @param {Number} [y] - * @returns {JXG.Board} Reference to the board - */ - zoomIn: function (x, y) { - var bb = this.getBoundingBox(), - zX = this.attr.zoom.factorx, - zY = this.attr.zoom.factory, - dX = (bb[2] - bb[0]) * (1.0 - 1.0 / zX), - dY = (bb[1] - bb[3]) * (1.0 - 1.0 / zY), - lr = 0.5, - tr = 0.5, - mi = this.attr.zoom.eps || this.attr.zoom.min || 0.001; // this.attr.zoom.eps is deprecated + el1 = board.select(parents[0]); + el2 = board.select(parents[1]); + other = board.select(parents[2]); - if ((this.zoomX > this.attr.zoom.max && zX > 1.0) || - (this.zoomY > this.attr.zoom.max && zY > 1.0) || - (this.zoomX < mi && zX < 1.0) || // zoomIn is used for all zooms on touch devices - (this.zoomY < mi && zY < 1.0)) { - return this; - } + el = board.create('point', [function () { + var c = Geometry.meet(el1.stdform, el2.stdform, 0, el1.board); - if (Type.isNumber(x) && Type.isNumber(y)) { - lr = (x - bb[0]) / (bb[2] - bb[0]); - tr = (bb[1] - y) / (bb[1] - bb[3]); + if (Math.abs(other.X() - c.usrCoords[1]) > Mat.eps || + Math.abs(other.Y() - c.usrCoords[2]) > Mat.eps || + Math.abs(other.Z() - c.usrCoords[0]) > Mat.eps) { + return c; } - this.setBoundingBox([bb[0] + dX * lr, bb[1] - dY * tr, bb[2] - dX * (1 - lr), bb[3] + dY * (1 - tr)], false); - this.zoomX *= zX; - this.zoomY *= zY; - return this.applyZoom(); - }, + return Geometry.meet(el1.stdform, el2.stdform, 1, el1.board); + }], attributes); - /** - * Zooms out of the board by the factors board.attr.zoom.factorX and board.attr.zoom.factorY and applies the zoom. - * The zoom operation is centered at x, y. - * - * @param {Number} [x] - * @param {Number} [y] - * @returns {JXG.Board} Reference to the board - */ - zoomOut: function (x, y) { - var bb = this.getBoundingBox(), - zX = this.attr.zoom.factorx, - zY = this.attr.zoom.factory, - dX = (bb[2] - bb[0]) * (1.0 - zX), - dY = (bb[1] - bb[3]) * (1.0 - zY), - lr = 0.5, - tr = 0.5, - mi = this.attr.zoom.eps || this.attr.zoom.min || 0.001; // this.attr.zoom.eps is deprecated + el.type = Const.OBJECT_TYPE_INTERSECTION; + el.elType = 'otherintersection'; + el.setParents([el1.id, el2.id, other]); - if (this.zoomX < mi || this.zoomY < mi) { - return this; - } + el1.addChild(el); + el2.addChild(el); - if (Type.isNumber(x) && Type.isNumber(y)) { - lr = (x - bb[0]) / (bb[2] - bb[0]); - tr = (bb[1] - y) / (bb[1] - bb[3]); + el.generatePolynomial = function () { + var poly1 = el1.generatePolynomial(el), + poly2 = el2.generatePolynomial(el); + + if ((poly1.length === 0) || (poly2.length === 0)) { + return []; } - this.setBoundingBox([bb[0] + dX * lr, bb[1] - dY * tr, bb[2] - dX * (1 - lr), bb[3] + dY * (1 - tr)], false); - this.zoomX /= zX; - this.zoomY /= zY; + return [poly1[0], poly2[0]]; + }; - return this.applyZoom(); - }, - - /** - * Resets zoom factor to 100%. - * @returns {JXG.Board} Reference to the board - */ - zoom100: function () { - var bb = this.getBoundingBox(), - dX = (bb[2] - bb[0]) * (1.0 - this.zoomX) * 0.5, - dY = (bb[1] - bb[3]) * (1.0 - this.zoomY) * 0.5; + return el; + }; - this.setBoundingBox([bb[0] + dX, bb[1] - dY, bb[2] - dX, bb[3] + dY], false); - this.zoomX = 1.0; - this.zoomY = 1.0; - return this.applyZoom(); - }, + /** + * @class This element is used to provide a constructor for the pole point of a line with respect to a conic or a circle. + * @pseudo + * @description The pole point is the unique reciprocal relationship of a line with respect to a conic. + * The lines tangent to the intersections of a conic and a line intersect at the pole point of that line with respect to that conic. + * A line tangent to a conic has the pole point of that line with respect to that conic as the tangent point. + * See {@link http://en.wikipedia.org/wiki/Pole_and_polar} for more information on pole and polar. + * @name PolePoint + * @augments JXG.Point + * @constructor + * @type JXG.Point + * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {JXG.Conic,JXG.Circle_JXG.Point} el1,el2 or + * @param {JXG.Point_JXG.Conic,JXG.Circle} el1,el2 The result will be the pole point of the line with respect to the conic or the circle. + * @example + * // Create the pole point of a line with respect to a conic + * var p1 = board.create('point', [-1, 2]); + * var p2 = board.create('point', [ 1, 4]); + * var p3 = board.create('point', [-1,-2]); + * var p4 = board.create('point', [ 0, 0]); + * var p5 = board.create('point', [ 4,-2]); + * var c1 = board.create('conic',[p1,p2,p3,p4,p5]); + * var p6 = board.create('point', [-1, 4]); + * var p7 = board.create('point', [2, -2]); + * var l1 = board.create('line', [p6, p7]); + * var p8 = board.create('polepoint', [c1, l1]); + * </pre><div class="jxgbox" id="JXG7b7233a0-f363-47dd-9df5-8018d0d17a98" class="jxgbox" style="width:400px; height:400px;"></div> + * <script type='text/javascript'> + * var ppex1_board = JXG.JSXGraph.initBoard('JXG7b7233a0-f363-47dd-9df5-8018d0d17a98', {boundingbox: [-3, 5, 5, -3], axis: true, showcopyright: false, shownavigation: false}); + * var ppex1_p1 = ppex1_board.create('point', [-1, 2]); + * var ppex1_p2 = ppex1_board.create('point', [ 1, 4]); + * var ppex1_p3 = ppex1_board.create('point', [-1,-2]); + * var ppex1_p4 = ppex1_board.create('point', [ 0, 0]); + * var ppex1_p5 = ppex1_board.create('point', [ 4,-2]); + * var ppex1_c1 = ppex1_board.create('conic',[ppex1_p1,ppex1_p2,ppex1_p3,ppex1_p4,ppex1_p5]); + * var ppex1_p6 = ppex1_board.create('point', [-1, 4]); + * var ppex1_p7 = ppex1_board.create('point', [2, -2]); + * var ppex1_l1 = ppex1_board.create('line', [ppex1_p6, ppex1_p7]); + * var ppex1_p8 = ppex1_board.create('polepoint', [ppex1_c1, ppex1_l1]); + * </script><pre> + * @example + * // Create the pole point of a line with respect to a circle + * var p1 = board.create('point', [1, 1]); + * var p2 = board.create('point', [2, 3]); + * var c1 = board.create('circle',[p1,p2]); + * var p3 = board.create('point', [-1, 4]); + * var p4 = board.create('point', [4, -1]); + * var l1 = board.create('line', [p3, p4]); + * var p5 = board.create('polepoint', [c1, l1]); + * </pre><div class="jxgbox" id="JXG7b7233a0-f363-47dd-9df5-9018d0d17a98" class="jxgbox" style="width:400px; height:400px;"></div> + * <script type='text/javascript'> + * var ppex2_board = JXG.JSXGraph.initBoard('JXG7b7233a0-f363-47dd-9df5-9018d0d17a98', {boundingbox: [-3, 7, 7, -3], axis: true, showcopyright: false, shownavigation: false}); + * var ppex2_p1 = ppex2_board.create('point', [1, 1]); + * var ppex2_p2 = ppex2_board.create('point', [2, 3]); + * var ppex2_c1 = ppex2_board.create('circle',[ppex2_p1,ppex2_p2]); + * var ppex2_p3 = ppex2_board.create('point', [-1, 4]); + * var ppex2_p4 = ppex2_board.create('point', [4, -1]); + * var ppex2_l1 = ppex2_board.create('line', [ppex2_p3, ppex2_p4]); + * var ppex2_p5 = ppex2_board.create('polepoint', [ppex2_c1, ppex2_l1]); + * </script><pre> + */ + JXG.createPolePoint = function (board, parents, attributes) { + var el, el1, el2, + firstParentIsConic, secondParentIsConic, + firstParentIsLine, secondParentIsLine; - /** - * Zooms the board so every visible point is shown. Keeps aspect ratio. - * @returns {JXG.Board} Reference to the board - */ - zoomAllPoints: function () { - var el, border, borderX, borderY, pEl, - minX = 0, - maxX = 0, - minY = 0, - maxY = 0, - len = this.objectsList.length; + if (parents.length > 1) { + firstParentIsConic = (parents[0].type === Const.OBJECT_TYPE_CONIC || + parents[0].elementClass === Const.OBJECT_CLASS_CIRCLE); + secondParentIsConic = (parents[1].type === Const.OBJECT_TYPE_CONIC || + parents[1].elementClass === Const.OBJECT_CLASS_CIRCLE); - for (el = 0; el < len; el++) { - pEl = this.objectsList[el]; + firstParentIsLine = (parents[0].elementClass === Const.OBJECT_CLASS_LINE); + secondParentIsLine = (parents[1].elementClass === Const.OBJECT_CLASS_LINE); + } - if (Type.isPoint(pEl) && pEl.visPropCalc.visible) { - if (pEl.coords.usrCoords[1] < minX) { - minX = pEl.coords.usrCoords[1]; - } else if (pEl.coords.usrCoords[1] > maxX) { - maxX = pEl.coords.usrCoords[1]; - } - if (pEl.coords.usrCoords[2] > maxY) { - maxY = pEl.coords.usrCoords[2]; - } else if (pEl.coords.usrCoords[2] < minY) { - minY = pEl.coords.usrCoords[2]; - } - } - } +/* if (parents.length !== 2 || !(( + parents[0].type === Const.OBJECT_TYPE_CONIC || + parents[0].elementClass === Const.OBJECT_CLASS_CIRCLE) && + parents[1].elementClass === Const.OBJECT_CLASS_LINE || + parents[0].elementClass === Const.OBJECT_CLASS_LINE && ( + parents[1].type === Const.OBJECT_TYPE_CONIC || + parents[1].elementClass === Const.OBJECT_CLASS_CIRCLE))) {*/ + if (parents.length !== 2 || + !((firstParentIsConic && secondParentIsLine) || + (firstParentIsLine && secondParentIsConic))) { + // Failure + throw new Error("JSXGraph: Can't create 'pole point' with parent types '" + + (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + + "\nPossible parent type: [conic|circle,line], [line,conic|circle]"); + } - border = 50; - borderX = border / this.unitX; - borderY = border / this.unitY; + if (secondParentIsLine) { + el1 = board.select(parents[0]); + el2 = board.select(parents[1]); + } else { + el1 = board.select(parents[1]); + el2 = board.select(parents[0]); + } - this.zoomX = 1.0; - this.zoomY = 1.0; + el = board.create('point', + [function () { + var q = el1.quadraticform, + s = el2.stdform.slice(0, 3); - this.setBoundingBox([minX - borderX, maxY + borderY, maxX + borderX, minY - borderY], true); + return [JXG.Math.Numerics.det([s, q[1], q[2]]), + JXG.Math.Numerics.det([q[0], s, q[2]]), + JXG.Math.Numerics.det([q[0], q[1], s])]; + }], attributes); - return this.applyZoom(); - }, + el.elType = 'polepoint'; + el.setParents([el1.id, el2.id]); - /** - * Reset the bounding box and the zoom level to 100% such that a given set of elements is - * within the board's viewport. - * @param {Array} elements A set of elements given by id, reference, or name. - * @returns {JXG.Board} Reference to the board. - */ - zoomElements: function (elements) { - var i, e, box, - newBBox = [Infinity, -Infinity, -Infinity, Infinity], - cx, cy, dx, dy, d; + el1.addChild(el); + el2.addChild(el); - if (!Type.isArray(elements) || elements.length === 0) { - return this; - } + return el; + }; - for (i = 0; i < elements.length; i++) { - e = this.select(elements[i]); + JXG.registerElement('point', JXG.createPoint); + JXG.registerElement('glider', JXG.createGlider); + JXG.registerElement('intersection', JXG.createIntersectionPoint); + JXG.registerElement('otherintersection', JXG.createOtherIntersectionPoint); + JXG.registerElement('polepoint', JXG.createPolePoint); - box = e.bounds(); - if (Type.isArray(box)) { - if (box[0] < newBBox[0]) { newBBox[0] = box[0]; } - if (box[1] > newBBox[1]) { newBBox[1] = box[1]; } - if (box[2] > newBBox[2]) { newBBox[2] = box[2]; } - if (box[3] < newBBox[3]) { newBBox[3] = box[3]; } - } - } + return { + Point: JXG.Point, + createPoint: JXG.createPoint, + createGlider: JXG.createGlider, + createIntersection: JXG.createIntersectionPoint, + createOtherIntersection: JXG.createOtherIntersectionPoint, + createPolePoint: JXG.createPolePoint + }; +}); - if (Type.isArray(newBBox)) { - this.zoomX = 1.0; - this.zoomY = 1.0; - cx = 0.5 * (newBBox[0] + newBBox[2]); - cy = 0.5 * (newBBox[1] + newBBox[3]); - dx = 1.5 * (newBBox[2] - newBBox[0]) * 0.5; - dy = 1.5 * (newBBox[1] - newBBox[3]) * 0.5; - d = Math.max(dx, dy); - this.setBoundingBox([cx - d, cy + d, cx + d, cy - d], true); - } +/* + Copyright 2008-2022 + Matthias Ehmann, + Michael Gerhaeuser, + Carsten Miller, + Bianca Valentin, + Alfred Wassermann, + Peter Wilfahrt - return this; - }, + This file is part of JSXGraph. - zoomElementsOld: function (elements) { - var i, j, e, box, - newBBox = [0, 0, 0, 0], - dir = [1, -1, -1, 1]; + JSXGraph is free software dual licensed under the GNU LGPL or MIT License. - if (!Type.isArray(elements) || elements.length === 0) { - return this; - } + You can redistribute it and/or modify it under the terms of the - for (i = 0; i < elements.length; i++) { - e = this.select(elements[i]); + * GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version + OR + * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT - box = e.bounds(); - if (Type.isArray(box)) { - if (Type.isArray(newBBox)) { - for (j = 0; j < 4; j++) { - if (dir[j] * box[j] < dir[j] * newBBox[j]) { - newBBox[j] = box[j]; - } - } - } else { - newBBox = box; - } - } - } + JSXGraph is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. - if (Type.isArray(newBBox)) { - for (j = 0; j < 4; j++) { - newBBox[j] -= dir[j]; - } + You should have received a copy of the GNU Lesser General Public License and + the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> + and <http://opensource.org/licenses/MIT/>. + */ - this.zoomX = 1.0; - this.zoomY = 1.0; - this.setBoundingBox(newBBox, true); - } - return this; - }, +/*global JXG: true, define: true*/ +/*jslint nomen: true, plusplus: true*/ - /** - * Sets the zoom level to <tt>fX</tt> resp <tt>fY</tt>. - * @param {Number} fX - * @param {Number} fY - * @returns {JXG.Board} Reference to the board. - */ - setZoom: function (fX, fY) { - var oX = this.attr.zoom.factorx, - oY = this.attr.zoom.factory; +/* depends: + jxg + math/math + math/geometry + math/numerics + math/statistics + base/constants + base/coords + base/element + utils/type + elements: + transform + point + ticks + */ - this.attr.zoom.factorx = fX / this.zoomX; - this.attr.zoom.factory = fY / this.zoomY; +/** + * @fileoverview The geometry object Line is defined in this file. Line stores all + * style and functional properties that are required to draw and move a line on + * a board. + */ - this.zoomIn(); +define('base/line',[ + 'jxg', 'math/math', 'math/geometry', 'math/numerics', 'math/statistics', 'base/constants', 'base/coords', + 'base/element', 'utils/type', 'base/point' +], function (JXG, Mat, Geometry, Numerics, Statistics, Const, Coords, GeometryElement, Type, Point) { - this.attr.zoom.factorx = oX; - this.attr.zoom.factory = oY; + "use strict"; - return this; - }, + /** + * The Line class is a basic class for all kind of line objects, e.g. line, arrow, and axis. It is usually defined by two points and can + * be intersected with some other geometry elements. + * @class Creates a new basic line object. Do not use this constructor to create a line. + * Use {@link JXG.Board#create} with + * type {@link Line}, {@link Arrow}, or {@link Axis} instead. + * @constructor + * @augments JXG.GeometryElement + * @param {String,JXG.Board} board The board the new line is drawn on. + * @param {Point} p1 Startpoint of the line. + * @param {Point} p2 Endpoint of the line. + * @param {Object} attributes Javascript object containing attributes like name, id and colors. + */ + JXG.Line = function (board, p1, p2, attributes) { + this.constructor(board, attributes, Const.OBJECT_TYPE_LINE, Const.OBJECT_CLASS_LINE); /** - * Removes object from board and renderer. - * <p> - * <b>Performance hints:</b> It is recommended to use the object's id. - * If many elements are removed, it is best to call <tt>board.suspendUpdate()</tt> - * before looping through the elements to be removed and call - * <tt>board.unsuspendUpdate()</tt> after the loop. Further, it is advisable to loop - * in reverse order, i.e. remove the object in reverse order of their creation time. - * - * @param {JXG.GeometryElement|Array} object The object to remove or array of objects to be removed. - * The element(s) is/are given by name, id or a reference. - * @param {Boolean} saveMethod If true, the algorithm runs through all elements - * and tests if the element to be deleted is a child element. If yes, it will be - * removed from the list of child elements. If false (default), the element - * is removed from the lists of child elements of all its ancestors. - * This should be much faster. - * @returns {JXG.Board} Reference to the board + * Startpoint of the line. You really should not set this field directly as it may break JSXGraph's + * update system so your construction won't be updated properly. + * @type JXG.Point */ - removeObject: function (object, saveMethod) { - var el, i; - - if (Type.isArray(object)) { - for (i = 0; i < object.length; i++) { - this.removeObject(object[i]); - } + this.point1 = this.board.select(p1); - return this; - } + /** + * Endpoint of the line. Just like {@link JXG.Line.point1} you shouldn't write this field directly. + * @type JXG.Point + */ + this.point2 = this.board.select(p2); - object = this.select(object); + /** + * Array of ticks storing all the ticks on this line. Do not set this field directly and use + * {@link JXG.Line#addTicks} and {@link JXG.Line#removeTicks} to add and remove ticks to and from the line. + * @type Array + * @see JXG.Ticks + */ + this.ticks = []; - // If the object which is about to be removed unknown or a string, do nothing. - // it is a string if a string was given and could not be resolved to an element. - if (!Type.exists(object) || Type.isString(object)) { - return this; - } + /** + * Reference of the ticks created automatically when constructing an axis. + * @type JXG.Ticks + * @see JXG.Ticks + */ + this.defaultTicks = null; - try { - // remove all children. - for (el in object.childElements) { - if (object.childElements.hasOwnProperty(el)) { - object.childElements[el].board.removeObject(object.childElements[el]); - } - } + /** + * If the line is the border of a polygon, the polygon object is stored, otherwise null. + * @type JXG.Polygon + * @default null + * @private + */ + this.parentPolygon = null; - // Remove all children in elements like turtle - for (el in object.objects) { - if (object.objects.hasOwnProperty(el)) { - object.objects[el].board.removeObject(object.objects[el]); - } - } + /* Register line at board */ + this.id = this.board.setId(this, 'L'); + this.board.renderer.drawLine(this); + this.board.finalizeAdding(this); - // Remove the element from the childElement list and the descendant list of all elements. - if (saveMethod) { - // Running through all objects has quadratic complexity if many objects are deleted. - for (el in this.objects) { - if (this.objects.hasOwnProperty(el)) { - if (Type.exists(this.objects[el].childElements) && - Type.exists(this.objects[el].childElements.hasOwnProperty(object.id)) - ) { - delete this.objects[el].childElements[object.id]; - delete this.objects[el].descendants[object.id]; - } - } - } - } else if (Type.exists(object.ancestors)) { - // Running through the ancestors should be much more efficient. - for (el in object.ancestors) { - if (object.ancestors.hasOwnProperty(el)) { - if (Type.exists(object.ancestors[el].childElements) && - Type.exists(object.ancestors[el].childElements.hasOwnProperty(object.id)) - ) { - delete object.ancestors[el].childElements[object.id]; - delete object.ancestors[el].descendants[object.id]; - } - } - } - } + this.elType = 'line'; - // remove the object itself from our control structures - if (object._pos > -1) { - this.objectsList.splice(object._pos, 1); - for (el = object._pos; el < this.objectsList.length; el++) { - this.objectsList[el]._pos--; - } - } else if (object.type !== Const.OBJECT_TYPE_TURTLE) { - JXG.debug('Board.removeObject: object ' + object.id + ' not found in list.'); - } + /* Add line as child to defining points */ + if (this.point1._is_new) { + this.addChild(this.point1); + delete this.point1._is_new; + } else { + this.point1.addChild(this); + } + if (this.point2._is_new) { + this.addChild(this.point2); + delete this.point2._is_new; + } else { + this.point2.addChild(this); + } - delete this.objects[object.id]; - delete this.elementsByName[object.name]; + this.inherits.push(this.point1, this.point2); - if (object.visProp && Type.evaluate(object.visProp.trace)) { - object.clearTrace(); - } + this.updateStdform(); // This is needed in the following situation: + // * the line is defined by three coordinates + // * and it will have a glider + // * and board.suspendUpdate() has been called. - // the object deletion itself is handled by the object. - if (Type.exists(object.remove)) { - object.remove(); - } - } catch (e) { - JXG.debug(object.id + ': Could not be removed: ' + e); - } + // create Label + this.createLabel(); - this.update(); + this.methodMap = JXG.deepCopy(this.methodMap, { + point1: 'point1', + point2: 'point2', + getSlope: 'getSlope', + getRise: 'getRise', + getYIntersect: 'getRise', + getAngle: 'getAngle', + L: 'L', + length: 'L' + }); + }; - return this; - }, + JXG.Line.prototype = new GeometryElement(); + JXG.extend(JXG.Line.prototype, /** @lends JXG.Line.prototype */ { /** - * Removes the ancestors of an object an the object itself from board and renderer. - * @param {JXG.GeometryElement} object The object to remove. - * @returns {JXG.Board} Reference to the board + * Checks whether (x,y) is near the line. + * @param {Number} x Coordinate in x direction, screen coordinates. + * @param {Number} y Coordinate in y direction, screen coordinates. + * @returns {Boolean} True if (x,y) is near the line, False otherwise. */ - removeAncestors: function (object) { - var anc; + hasPoint: function (x, y) { + // Compute the stdform of the line in screen coordinates. + var c = [], s, + v = [1, x, y], + vnew, + p1c, p2c, d, pos, i, + prec, type, + sw = Type.evaluate(this.visProp.strokewidth); - for (anc in object.ancestors) { - if (object.ancestors.hasOwnProperty(anc)) { - this.removeAncestors(object.ancestors[anc]); - } + if (Type.isObject(Type.evaluate(this.visProp.precision))) { + type = this.board._inputDevice; + prec = Type.evaluate(this.visProp.precision[type]); + } else { + // 'inherit' + prec = this.board.options.precision.hasPoint; } + prec += sw * 0.5; - this.removeObject(object); - - return this; - }, + c[0] = this.stdform[0] - + this.stdform[1] * this.board.origin.scrCoords[1] / this.board.unitX + + this.stdform[2] * this.board.origin.scrCoords[2] / this.board.unitY; + c[1] = this.stdform[1] / this.board.unitX; + c[2] = this.stdform[2] / (-this.board.unitY); - /** - * Initialize some objects which are contained in every GEONExT construction by default, - * but are not contained in the gxt files. - * @returns {JXG.Board} Reference to the board - */ - initGeonextBoard: function () { - var p1, p2, p3; + s = Geometry.distPointLine(v, c); + if (isNaN(s) || s > prec) { + return false; + } - p1 = this.create('point', [0, 0], { - id: this.id + 'g00e0', - name: 'Ursprung', - withLabel: false, - visible: false, - fixed: true - }); + if (Type.evaluate(this.visProp.straightfirst) && + Type.evaluate(this.visProp.straightlast)) { + return true; + } - p2 = this.create('point', [1, 0], { - id: this.id + 'gX0e0', - name: 'Punkt_1_0', - withLabel: false, - visible: false, - fixed: true - }); + // If the line is a ray or segment we have to check if the projected point is between P1 and P2. + p1c = this.point1.coords; + p2c = this.point2.coords; - p3 = this.create('point', [0, 1], { - id: this.id + 'gY0e0', - name: 'Punkt_0_1', - withLabel: false, - visible: false, - fixed: true - }); + // Project the point orthogonally onto the line + vnew = [0, c[1], c[2]]; + // Orthogonal line to c through v + vnew = Mat.crossProduct(vnew, v); + // Intersect orthogonal line with line + vnew = Mat.crossProduct(vnew, c); - this.create('line', [p1, p2], { - id: this.id + 'gXLe0', - name: 'X-Achse', - withLabel: false, - visible: false - }); + // Normalize the projected point + vnew[1] /= vnew[0]; + vnew[2] /= vnew[0]; + vnew[0] = 1; - this.create('line', [p1, p3], { - id: this.id + 'gYLe0', - name: 'Y-Achse', - withLabel: false, - visible: false - }); + vnew = (new Coords(Const.COORDS_BY_SCREEN, vnew.slice(1), this.board)).usrCoords; + d = p1c.distance(Const.COORDS_BY_USER, p2c); + p1c = p1c.usrCoords.slice(0); + p2c = p2c.usrCoords.slice(0); - return this; - }, + // The defining points are identical + if (d < Mat.eps) { + pos = 0; + } else { + /* + * Handle the cases, where one of the defining points is an ideal point. + * d is set to something close to infinity, namely 1/eps. + * The ideal point is (temporarily) replaced by a finite point which has + * distance d from the other point. + * This is accomplished by extracting the x- and y-coordinates (x,y)=:v of the ideal point. + * v determines the direction of the line. v is normalized, i.e. set to length 1 by dividing through its length. + * Finally, the new point is the sum of the other point and v*d. + * + */ - /** - * Change the height and width of the board's container. - * After doing so, {@link JXG.JSXGraph.setBoundingBox} is called using - * the actual size of the bounding box and the actual value of keepaspectratio. - * If setBoundingbox() should not be called automatically, - * call resizeContainer with dontSetBoundingBox == true. - * @param {Number} canvasWidth New width of the container. - * @param {Number} canvasHeight New height of the container. - * @param {Boolean} [dontset=false] If true do not set the CSS width and height of the DOM element. - * @param {Boolean} [dontSetBoundingBox=false] If true do not call setBoundingBox(). - * @returns {JXG.Board} Reference to the board - */ - resizeContainer: function (canvasWidth, canvasHeight, dontset, dontSetBoundingBox) { - var box; + // At least one point is an ideal point + if (d === Number.POSITIVE_INFINITY) { + d = 1 / Mat.eps; - if (!dontSetBoundingBox) { - box = this.getBoundingBox(); - } - this.canvasWidth = parseInt(canvasWidth, 10); - this.canvasHeight = parseInt(canvasHeight, 10); + // The second point is an ideal point + if (Math.abs(p2c[0]) < Mat.eps) { + d /= Geometry.distance([0, 0, 0], p2c); + p2c = [1, p1c[1] + p2c[1] * d, p1c[2] + p2c[2] * d]; + // The first point is an ideal point + } else { + d /= Geometry.distance([0, 0, 0], p1c); + p1c = [1, p2c[1] + p1c[1] * d, p2c[2] + p1c[2] * d]; + } + } + i = 1; + d = p2c[i] - p1c[i]; - if (!dontset) { - this.containerObj.style.width = (this.canvasWidth) + 'px'; - this.containerObj.style.height = (this.canvasHeight) + 'px'; + if (Math.abs(d) < Mat.eps) { + i = 2; + d = p2c[i] - p1c[i]; + } + pos = (vnew[i] - p1c[i]) / d; } - this.renderer.resize(this.canvasWidth, this.canvasHeight); - - if (!dontSetBoundingBox) { - this.setBoundingBox(box, this.keepaspectratio); + if (!Type.evaluate(this.visProp.straightfirst) && pos < 0) { + return false; } - return this; + return !(!Type.evaluate(this.visProp.straightlast) && pos > 1); + }, - /** - * Lists the dependencies graph in a new HTML-window. - * @returns {JXG.Board} Reference to the board - */ - showDependencies: function () { - var el, t, c, f, i; + // documented in base/element + update: function () { + var funps; - t = '<p>\n'; - for (el in this.objects) { - if (this.objects.hasOwnProperty(el)) { - i = 0; - for (c in this.objects[el].childElements) { - if (this.objects[el].childElements.hasOwnProperty(c)) { - i += 1; - } + if (!this.needsUpdate) { + return this; + } + + if (this.constrained) { + if (Type.isFunction(this.funps)) { + funps = this.funps(); + if (funps && funps.length && funps.length === 2) { + this.point1 = funps[0]; + this.point2 = funps[1]; } - if (i >= 0) { - t += '<strong>' + this.objects[el].id + ':<' + '/strong> '; + } else { + if (Type.isFunction(this.funp1)) { + funps = this.funp1(); + if (Type.isPoint(funps)) { + this.point1 = funps; + } else if (funps && funps.length && funps.length === 2) { + this.point1.setPositionDirectly(Const.COORDS_BY_USER, funps); + } } - for (c in this.objects[el].childElements) { - if (this.objects[el].childElements.hasOwnProperty(c)) { - t += this.objects[el].childElements[c].id + '(' + this.objects[el].childElements[c].name + ')' + ', '; + if (Type.isFunction(this.funp2)) { + funps = this.funp2(); + if (Type.isPoint(funps)) { + this.point2 = funps; + } else if (funps && funps.length && funps.length === 2) { + this.point2.setPositionDirectly(Const.COORDS_BY_USER, funps); } } - t += '<p>\n'; } } - t += '<' + '/p>\n'; - f = window.open(); - f.document.open(); - f.document.write(t); - f.document.close(); - return this; - }, - /** - * Lists the XML code of the construction in a new HTML-window. - * @returns {JXG.Board} Reference to the board - */ - showXML: function () { - var f = window.open(''); - f.document.open(); - f.document.write('<pre>' + Type.escapeHTML(this.xmlString) + '<' + '/pre>'); - f.document.close(); + this.updateSegmentFixedLength(); + this.updateStdform(); + + if (Type.evaluate(this.visProp.trace)) { + this.cloneToBackground(true); + } + return this; }, /** - * Sets for all objects the needsUpdate flag to "true". - * @returns {JXG.Board} Reference to the board + * Update segments with fixed length and at least one movable point. + * @private */ - prepareUpdate: function () { - var el, pEl, len = this.objectsList.length; + updateSegmentFixedLength: function () { + var d, dnew, d1, d2, drag1, drag2, x, y; - /* - if (this.attr.updatetype === 'hierarchical') { + if (!this.hasFixedLength) { return this; } - */ - - for (el = 0; el < len; el++) { - pEl = this.objectsList[el]; - pEl.needsUpdate = pEl.needsRegularUpdate || this.needsFullUpdate; - } - for (el in this.groups) { - if (this.groups.hasOwnProperty(el)) { - pEl = this.groups[el]; - pEl.needsUpdate = pEl.needsRegularUpdate || this.needsFullUpdate; - } - } - - return this; - }, - - /** - * Runs through all elements and calls their update() method. - * @param {JXG.GeometryElement} drag Element that caused the update. - * @returns {JXG.Board} Reference to the board - */ - updateElements: function (drag) { - var el, pEl; - //var childId, i = 0; + // Compute the actual length of the segment + d = this.point1.Dist(this.point2); + // Determine the length the segment ought to have + dnew = this.fixedLength(); + // Distances between the two points and their respective + // position before the update + d1 = this.fixedLengthOldCoords[0].distance(Const.COORDS_BY_USER, this.point1.coords); + d2 = this.fixedLengthOldCoords[1].distance(Const.COORDS_BY_USER, this.point2.coords); - drag = this.select(drag); + // If the position of the points or the fixed length function has been changed we have to work. + if (d1 > Mat.eps || d2 > Mat.eps || d !== dnew) { + drag1 = this.point1.isDraggable && + (this.point1.type !== Const.OBJECT_TYPE_GLIDER) && + !Type.evaluate(this.point1.visProp.fixed); + drag2 = this.point2.isDraggable && + (this.point2.type !== Const.OBJECT_TYPE_GLIDER) && + !Type.evaluate(this.point2.visProp.fixed); - /* - if (Type.exists(drag)) { - for (el = 0; el < this.objectsList.length; el++) { - pEl = this.objectsList[el]; - if (pEl.id === drag.id) { - i = el; - break; + // First case: the two points are different + // Then we try to adapt the point that was not dragged + // If this point can not be moved (e.g. because it is a glider) + // we try move the other point + if (d > Mat.eps) { + if ((d1 > d2 && drag2) || + (d1 <= d2 && drag2 && !drag1)) { + this.point2.setPositionDirectly(Const.COORDS_BY_USER, [ + this.point1.X() + (this.point2.X() - this.point1.X()) * dnew / d, + this.point1.Y() + (this.point2.Y() - this.point1.Y()) * dnew / d + ]); + this.point2.fullUpdate(); + } else if ((d1 <= d2 && drag1) || + (d1 > d2 && drag1 && !drag2)) { + this.point1.setPositionDirectly(Const.COORDS_BY_USER, [ + this.point2.X() + (this.point1.X() - this.point2.X()) * dnew / d, + this.point2.Y() + (this.point1.Y() - this.point2.Y()) * dnew / d + ]); + this.point1.fullUpdate(); } - } - } - */ - - for (el = 0; el < this.objectsList.length; el++) { - pEl = this.objectsList[el]; - // For updates of an element we distinguish if the dragged element is updated or - // other elements are updated. - // The difference lies in the treatment of gliders. - pEl.update(!Type.exists(drag) || pEl.id !== drag.id) - .updateVisibility(); - } + // Second case: the two points are identical. In this situation + // we choose a random direction. + } else { + x = Math.random() - 0.5; + y = Math.random() - 0.5; + d = Math.sqrt(x * x + y * y); - // update groups last - for (el in this.groups) { - if (this.groups.hasOwnProperty(el)) { - this.groups[el].update(drag); + if (drag2) { + this.point2.setPositionDirectly(Const.COORDS_BY_USER, [ + this.point1.X() + x * dnew / d, + this.point1.Y() + y * dnew / d + ]); + this.point2.fullUpdate(); + } else if (drag1) { + this.point1.setPositionDirectly(Const.COORDS_BY_USER, [ + this.point2.X() + x * dnew / d, + this.point2.Y() + y * dnew / d + ]); + this.point1.fullUpdate(); + } } + // Finally, we save the position of the two points. + this.fixedLengthOldCoords[0].setCoordinates(Const.COORDS_BY_USER, this.point1.coords.usrCoords); + this.fixedLengthOldCoords[1].setCoordinates(Const.COORDS_BY_USER, this.point2.coords.usrCoords); } - return this; }, /** - * Runs through all elements and calls their update() method. - * @returns {JXG.Board} Reference to the board + * Updates the stdform derived from the parent point positions. + * @private */ - updateRenderer: function () { - var el, - len = this.objectsList.length; + updateStdform: function () { + var v = Mat.crossProduct(this.point1.coords.usrCoords, this.point2.coords.usrCoords); - /* - objs = this.objectsList.slice(0); - objs.sort(function (a, b) { - if (a.visProp.layer < b.visProp.layer) { - return -1; - } else if (a.visProp.layer === b.visProp.layer) { - return b.lastDragTime.getTime() - a.lastDragTime.getTime(); - } else { - return 1; - } - }); - */ + this.stdform[0] = v[0]; + this.stdform[1] = v[1]; + this.stdform[2] = v[2]; + this.stdform[3] = 0; - if (this.renderer.type === 'canvas') { - this.updateRendererCanvas(); - } else { - for (el = 0; el < len; el++) { - this.objectsList[el].updateRenderer(); - } - } - return this; + this.normalize(); }, /** - * Runs through all elements and calls their update() method. - * This is a special version for the CanvasRenderer. - * Here, we have to do our own layer handling. - * @returns {JXG.Board} Reference to the board + * Uses the boards renderer to update the line. + * @private */ - updateRendererCanvas: function () { - var el, pEl, i, mini, la, - olen = this.objectsList.length, - layers = this.options.layer, - len = this.options.layer.numlayers, - last = Number.NEGATIVE_INFINITY; + updateRenderer: function () { + //var wasReal; - for (i = 0; i < len; i++) { - mini = Number.POSITIVE_INFINITY; + if (!this.needsUpdate) { + return this; + } - for (la in layers) { - if (layers.hasOwnProperty(la)) { - if (layers[la] > last && layers[la] < mini) { - mini = layers[la]; - } - } + if (this.visPropCalc.visible) { + // wasReal = this.isReal; + this.isReal = (!isNaN(this.point1.coords.usrCoords[1] + this.point1.coords.usrCoords[2] + + this.point2.coords.usrCoords[1] + this.point2.coords.usrCoords[2]) && + (Mat.innerProduct(this.stdform, this.stdform, 3) >= Mat.eps * Mat.eps)); + + if (//wasReal && + !this.isReal) { + this.updateVisibility(false); } + } - last = mini; + if (this.visPropCalc.visible) { + this.board.renderer.updateLine(this); + } - for (el = 0; el < olen; el++) { - pEl = this.objectsList[el]; + /* Update the label if visible. */ + if (this.hasLabel && this.visPropCalc.visible && this.label && + this.label.visPropCalc.visible && this.isReal) { - if (pEl.visProp.layer === mini) { - pEl.prepareUpdate().updateRenderer(); - } - } + this.label.update(); + this.board.renderer.updateText(this.label); } + + // Update rendNode display + this.setDisplayRendNode(); + // if (this.visPropCalc.visible !== this.visPropOld.visible) { + // this.setDisplayRendNode(this.visPropCalc.visible); + // if (this.hasLabel) { + // this.board.renderer.display(this.label, this.label.visPropCalc.visible); + // } + // } + + this.needsUpdate = false; return this; }, /** - * Please use {@link JXG.Board.on} instead. - * @param {Function} hook A function to be called by the board after an update occurred. - * @param {String} [m='update'] When the hook is to be called. Possible values are <i>mouseup</i>, <i>mousedown</i> and <i>update</i>. - * @param {Object} [context=board] Determines the execution context the hook is called. This parameter is optional, default is the - * board object the hook is attached to. - * @returns {Number} Id of the hook, required to remove the hook from the board. - * @deprecated + * Used to generate a polynomial for a point p that lies on this line, i.e. p is collinear to + * {@link JXG.Line#point1} and {@link JXG.Line#point2}. + * + * @param {JXG.Point} p The point for that the polynomial is generated. + * @returns {Array} An array containing the generated polynomial. + * @private */ - addHook: function (hook, m, context) { - JXG.deprecated('Board.addHook()', 'Board.on()'); - m = Type.def(m, 'update'); - - context = Type.def(context, this); + generatePolynomial: function (p) { + var u1 = this.point1.symbolic.x, + u2 = this.point1.symbolic.y, + v1 = this.point2.symbolic.x, + v2 = this.point2.symbolic.y, + w1 = p.symbolic.x, + w2 = p.symbolic.y; - this.hooks.push([m, hook]); - this.on(m, hook, context); + /* + * The polynomial in this case is determined by three points being collinear: + * + * U (u1,u2) W (w1,w2) V (v1,v2) + * ----x--------------x------------------------x---------------- + * + * The collinearity condition is + * + * u2-w2 w2-v2 + * ------- = ------- (1) + * u1-w1 w1-v1 + * + * Multiplying (1) with denominators and simplifying is + * + * u2w1 - u2v1 + w2v1 - u1w2 + u1v2 - w1v2 = 0 + */ - return this.hooks.length - 1; + return [['(', u2, ')*(', w1, ')-(', u2, ')*(', v1, ')+(', w2, ')*(', v1, ')-(', u1, ')*(', w2, ')+(', u1, ')*(', v2, ')-(', w1, ')*(', v2, ')'].join('')]; }, /** - * Alias of {@link JXG.Board.on}. + * Calculates the y intersect of the line. + * @returns {Number} The y intersect. */ - addEvent: JXG.shortcut(JXG.Board.prototype, 'on'), + getRise: function () { + if (Math.abs(this.stdform[2]) >= Mat.eps) { + return -this.stdform[0] / this.stdform[2]; + } + + return Infinity; + }, /** - * Please use {@link JXG.Board.off} instead. - * @param {Number|function} id The number you got when you added the hook or a reference to the event handler. - * @returns {JXG.Board} Reference to the board - * @deprecated + * Calculates the slope of the line. + * @returns {Number} The slope of the line or Infinity if the line is parallel to the y-axis. */ - removeHook: function (id) { - JXG.deprecated('Board.removeHook()', 'Board.off()'); - if (this.hooks[id]) { - this.off(this.hooks[id][0], this.hooks[id][1]); - this.hooks[id] = null; + getSlope: function () { + if (Math.abs(this.stdform[2]) >= Mat.eps) { + return -this.stdform[1] / this.stdform[2]; } - return this; + return Infinity; }, /** - * Alias of {@link JXG.Board.off}. + * Determines the angle between the positive x axis and the line. + * @returns {Number} */ - removeEvent: JXG.shortcut(JXG.Board.prototype, 'off'), + getAngle: function () { + return Math.atan2(-this.stdform[1], this.stdform[2]); + }, /** - * Runs through all hooked functions and calls them. - * @returns {JXG.Board} Reference to the board - * @deprecated + * Determines whether the line is drawn beyond {@link JXG.Line#point1} and + * {@link JXG.Line#point2} and updates the line. + * @param {Boolean} straightFirst True if the Line shall be drawn beyond + * {@link JXG.Line#point1}, false otherwise. + * @param {Boolean} straightLast True if the Line shall be drawn beyond + * {@link JXG.Line#point2}, false otherwise. + * @see #straightFirst + * @see #straightLast + * @private */ - updateHooks: function (m) { - var arg = Array.prototype.slice.call(arguments, 0); - - JXG.deprecated('Board.updateHooks()', 'Board.triggerEventHandlers()'); - - arg[0] = Type.def(arg[0], 'update'); - this.triggerEventHandlers([arg[0]], arguments); + setStraight: function (straightFirst, straightLast) { + this.visProp.straightfirst = straightFirst; + this.visProp.straightlast = straightLast; + this.board.renderer.updateLine(this); return this; }, + // documented in geometry element + getTextAnchor: function () { + return new Coords(Const.COORDS_BY_USER, [0.5 * (this.point2.X() + this.point1.X()), 0.5 * (this.point2.Y() + this.point1.Y())], this.board); + }, + /** - * Adds a dependent board to this board. - * @param {JXG.Board} board A reference to board which will be updated after an update of this board occurred. - * @returns {JXG.Board} Reference to the board + * Adjusts Label coords relative to Anchor. DESCRIPTION + * @private */ - addChild: function (board) { - if (Type.exists(board) && Type.exists(board.containerObj)) { - this.dependentBoards.push(board); - this.update(); + setLabelRelativeCoords: function (relCoords) { + if (Type.exists(this.label)) { + this.label.relativeCoords = new Coords(Const.COORDS_BY_SCREEN, [relCoords[0], -relCoords[1]], this.board); } - return this; }, - /** - * Deletes a board from the list of dependent boards. - * @param {JXG.Board} board Reference to the board which will be removed. - * @returns {JXG.Board} Reference to the board - */ - removeChild: function (board) { - var i; + // documented in geometry element + getLabelAnchor: function () { + var x, y, + fs = 0, + c1 = new Coords(Const.COORDS_BY_USER, this.point1.coords.usrCoords, this.board), + c2 = new Coords(Const.COORDS_BY_USER, this.point2.coords.usrCoords, this.board), + ev_sf = Type.evaluate(this.visProp.straightfirst), + ev_sl = Type.evaluate(this.visProp.straightlast); - for (i = this.dependentBoards.length - 1; i >= 0; i--) { - if (this.dependentBoards[i] === board) { - this.dependentBoards.splice(i, 1); - } + if (ev_sf || ev_sl) { + Geometry.calcStraight(this, c1, c2, 0); } - return this; - }, - - /** - * Runs through most elements and calls their update() method and update the conditions. - * @param {JXG.GeometryElement} [drag] Element that caused the update. - * @returns {JXG.Board} Reference to the board - */ - update: function (drag) { - var i, len, b, insert; - if (this.inUpdate || this.isSuspendedUpdate) { - return this; - } - this.inUpdate = true; + c1 = c1.scrCoords; + c2 = c2.scrCoords; - if (this.attr.minimizereflow === 'all' && this.containerObj && this.renderer.type !== 'vml') { - insert = this.renderer.removeToInsertLater(this.containerObj); + if (!Type.exists(this.label)) { + return new Coords(Const.COORDS_BY_SCREEN, [NaN, NaN], this.board); } - if (this.attr.minimizereflow === 'svg' && this.renderer.type === 'svg') { - insert = this.renderer.removeToInsertLater(this.renderer.svgRoot); + switch (Type.evaluate(this.label.visProp.position)) { + case 'lft': + case 'llft': + case 'ulft': + if (c1[1] <= c2[1]) { + x = c1[1]; + y = c1[2]; + } else { + x = c2[1]; + y = c2[2]; + } + break; + case 'rt': + case 'lrt': + case 'urt': + if (c1[1] > c2[1]) { + x = c1[1]; + y = c1[2]; + } else { + x = c2[1]; + y = c2[2]; + } + break; + default: + x = 0.5 * (c1[1] + c2[1]); + y = 0.5 * (c1[2] + c2[2]); } - this.prepareUpdate().updateElements(drag).updateConditions(); - this.renderer.suspendRedraw(this); - this.updateRenderer(); - this.renderer.unsuspendRedraw(); - this.triggerEventHandlers(['update'], []); - if (insert) { - insert(); - } + // Correct coordinates if the label seems to be outside of canvas. + if (ev_sf || ev_sl) { + if (Type.exists(this.label)) { // Does not exist during createLabel + fs = Type.evaluate(this.label.visProp.fontsize); + } - // To resolve dependencies between boards - // for (var board in JXG.boards) { - len = this.dependentBoards.length; - for (i = 0; i < len; i++) { - b = this.dependentBoards[i]; - if (Type.exists(b) && b !== this) { - b.updateQuality = this.updateQuality; - b.prepareUpdate().updateElements().updateConditions(); - b.renderer.suspendRedraw(); - b.updateRenderer(); - b.renderer.unsuspendRedraw(); - b.triggerEventHandlers(['update'], []); + if (Math.abs(x) < Mat.eps) { + x = fs; + } else if (this.board.canvasWidth + Mat.eps > x && + x > this.board.canvasWidth - fs - Mat.eps) { + x = this.board.canvasWidth - fs; } + if (Mat.eps + fs > y && y > -Mat.eps) { + y = fs; + } else if (this.board.canvasHeight + Mat.eps > y && + y > this.board.canvasHeight - fs - Mat.eps) { + y = this.board.canvasHeight - fs; + } } - this.inUpdate = false; - return this; + return new Coords(Const.COORDS_BY_SCREEN, [x, y], this.board); }, - /** - * Runs through all elements and calls their update() method and update the conditions. - * This is necessary after zooming and changing the bounding box. - * @returns {JXG.Board} Reference to the board - */ - fullUpdate: function () { - this.needsFullUpdate = true; - this.update(); - this.needsFullUpdate = false; - return this; - }, + // documented in geometry element + cloneToBackground: function () { + var copy = {}, r, s, er; - /** - * Adds a grid to the board according to the settings given in board.options. - * @returns {JXG.Board} Reference to the board. - */ - addGrid: function () { - this.create('grid', []); + copy.id = this.id + 'T' + this.numTraces; + copy.elementClass = Const.OBJECT_CLASS_LINE; + this.numTraces++; + copy.point1 = this.point1; + copy.point2 = this.point2; - return this; - }, + copy.stdform = this.stdform; - /** - * Removes all grids assigned to this board. Warning: This method also removes all objects depending on one or - * more of the grids. - * @returns {JXG.Board} Reference to the board object. - */ - removeGrids: function () { - var i; + copy.board = this.board; - for (i = 0; i < this.grids.length; i++) { - this.removeObject(this.grids[i]); - } + copy.visProp = Type.deepCopy(this.visProp, this.visProp.traceattributes, true); + copy.visProp.layer = this.board.options.layer.trace; + Type.clearVisPropOld(copy); + copy.visPropCalc = { + visible: Type.evaluate(copy.visProp.visible) + }; - this.grids.length = 0; - this.update(); // required for canvas renderer + s = this.getSlope(); + r = this.getRise(); + copy.getSlope = function () { + return s; + }; + copy.getRise = function () { + return r; + }; + + er = this.board.renderer.enhancedRendering; + this.board.renderer.enhancedRendering = true; + this.board.renderer.drawLine(copy); + this.board.renderer.enhancedRendering = er; + this.traces[copy.id] = copy.rendNode; return this; }, /** - * Creates a new geometric element of type elementType. - * @param {String} elementType Type of the element to be constructed given as a string e.g. 'point' or 'circle'. - * @param {Array} parents Array of parent elements needed to construct the element e.g. coordinates for a point or two - * points to construct a line. This highly depends on the elementType that is constructed. See the corresponding JXG.create* - * methods for a list of possible parameters. - * @param {Object} [attributes] An object containing the attributes to be set. This also depends on the elementType. - * Common attributes are name, visible, strokeColor. - * @returns {Object} Reference to the created element. This is usually a GeometryElement, but can be an array containing - * two or more elements. + * Add transformations to this line. + * @param {JXG.Transformation|Array} transform Either one {@link JXG.Transformation} or an array of + * {@link JXG.Transformation}s. + * @returns {JXG.Line} Reference to this line object. */ - create: function (elementType, parents, attributes) { - var el, i; - - elementType = elementType.toLowerCase(); + addTransform: function (transform) { + var i, + list = Type.isArray(transform) ? transform : [transform], + len = list.length; - if (!Type.exists(parents)) { - parents = []; + for (i = 0; i < len; i++) { + this.point1.transformations.push(list[i]); + this.point2.transformations.push(list[i]); } - if (!Type.exists(attributes)) { - attributes = {}; - } + return this; + }, - for (i = 0; i < parents.length; i++) { - if (Type.isString(parents[i]) && - !(elementType === 'text' && i === 2) && - !((elementType === 'input' || elementType === 'checkbox' || elementType === 'button') && - (i === 2 || i === 3)) - ) { - parents[i] = this.select(parents[i]); - } - } + // see GeometryElement.js + snapToGrid: function (pos) { + var c1, c2, dc, t, ticks, + x, y, sX, sY; - if (Type.isFunction(JXG.elements[elementType])) { - el = JXG.elements[elementType](this, parents, attributes); - } else { - throw new Error("JSXGraph: create: Unknown element type given: " + elementType); - } + if (Type.evaluate(this.visProp.snaptogrid)) { + if (this.parents.length < 3) { // Line through two points + this.point1.handleSnapToGrid(true, true); + this.point2.handleSnapToGrid(true, true); + } else if (Type.exists(pos)) { // Free line + sX = Type.evaluate(this.visProp.snapsizex); + sY = Type.evaluate(this.visProp.snapsizey); - if (!Type.exists(el)) { - JXG.debug("JSXGraph: create: failure creating " + elementType); - return el; - } + c1 = new Coords(Const.COORDS_BY_SCREEN, [pos.Xprev, pos.Yprev], this.board); - if (el.prepareUpdate && el.update && el.updateRenderer) { - el.fullUpdate(); - } - return el; - }, + x = c1.usrCoords[1]; + y = c1.usrCoords[2]; - /** - * Deprecated name for {@link JXG.Board.create}. - * @deprecated - */ - createElement: function () { - JXG.deprecated('Board.createElement()', 'Board.create()'); - return this.create.apply(this, arguments); - }, + if (sX <= 0 && this.board.defaultAxes && this.board.defaultAxes.x.defaultTicks) { + ticks = this.board.defaultAxes.x.defaultTicks; + sX = ticks.ticksDelta * (Type.evaluate(ticks.visProp.minorticks) + 1); + } + if (sY <= 0 && this.board.defaultAxes && this.board.defaultAxes.y.defaultTicks) { + ticks = this.board.defaultAxes.y.defaultTicks; + sY = ticks.ticksDelta * (Type.evaluate(ticks.visProp.minorticks) + 1); + } - /** - * Delete the elements drawn as part of a trace of an element. - * @returns {JXG.Board} Reference to the board - */ - clearTraces: function () { - var el; + // if no valid snap sizes are available, don't change the coords. + if (sX > 0 && sY > 0) { + // projectCoordsToLine + /* + v = [0, this.stdform[1], this.stdform[2]]; + v = Mat.crossProduct(v, c1.usrCoords); + c2 = Geometry.meetLineLine(v, this.stdform, 0, this.board); + */ + c2 = Geometry.projectPointToLine({coords: c1}, this, this.board); - for (el = 0; el < this.objectsList.length; el++) { - this.objectsList[el].clearTrace(); + dc = Statistics.subtract([1, Math.round(x / sX) * sX, Math.round(y / sY) * sY], c2.usrCoords); + t = this.board.create('transform', dc.slice(1), {type: 'translate'}); + t.applyOnce([this.point1, this.point2]); + } + } + } else { + this.point1.handleSnapToGrid(false, true); + this.point2.handleSnapToGrid(false, true); } - this.numTraces = 0; return this; }, - /** - * Stop updates of the board. - * @returns {JXG.Board} Reference to the board - */ - suspendUpdate: function () { - if (!this.inUpdate) { - this.isSuspendedUpdate = true; - } - return this; - }, + // see element.js + snapToPoints: function () { + var forceIt = Type.evaluate(this.visProp.snaptopoints); - /** - * Enable updates of the board. - * @returns {JXG.Board} Reference to the board - */ - unsuspendUpdate: function () { - if (this.isSuspendedUpdate) { - this.isSuspendedUpdate = false; - this.fullUpdate(); + if (this.parents.length < 3) { // Line through two points + this.point1.handleSnapToPoints(forceIt); + this.point2.handleSnapToPoints(forceIt); } + return this; }, /** - * Set the bounding box of the board. - * @param {Array} bbox New bounding box [x1,y1,x2,y2] - * @param {Boolean} [keepaspectratio=false] If set to true, the aspect ratio will be 1:1, but - * the resulting viewport may be larger. - * @returns {JXG.Board} Reference to the board - */ - setBoundingBox: function (bbox, keepaspectratio) { - var h, w, - dim = Env.getDimensions(this.container, this.document); - - if (!Type.isArray(bbox)) { - return this; - } - if (bbox[0] < this.maxboundingbox[0] || - bbox[1] > this.maxboundingbox[1] || - bbox[2] > this.maxboundingbox[2] || - bbox[3] < this.maxboundingbox[3]) { - return this; - } - - this.plainBB = bbox; - - this.canvasWidth = parseInt(dim.width, 10); - this.canvasHeight = parseInt(dim.height, 10); - w = this.canvasWidth; - h = this.canvasHeight; + * Treat the line as parametric curve in homogeneous coordinates, where the parameter t runs from 0 to 1. + * First we transform the interval [0,1] to [-1,1]. + * If the line has homogeneous coordinates [c, a, b] = stdform[] then the direction of the line is [b, -a]. + * Now, we take one finite point that defines the line, i.e. we take either point1 or point2 + * (in case the line is not the ideal line). + * Let the coordinates of that point be [z, x, y]. + * Then, the curve runs linearly from + * [0, b, -a] (t=-1) to [z, x, y] (t=0) + * and + * [z, x, y] (t=0) to [0, -b, a] (t=1) + * + * @param {Number} t Parameter running from 0 to 1. + * @returns {Number} X(t) x-coordinate of the line treated as parametric curve. + * */ + X: function (t) { + var x, + b = this.stdform[2]; - if (keepaspectratio) { - this.unitX = w / (bbox[2] - bbox[0]); - this.unitY = h / (bbox[1] - bbox[3]); - if (Math.abs(this.unitX) < Math.abs(this.unitY)) { - this.unitY = Math.abs(this.unitX) * this.unitY / Math.abs(this.unitY); - } else { - this.unitX = Math.abs(this.unitY) * this.unitX / Math.abs(this.unitX); - } - this.keepaspectratio = true; - } else { - this.unitX = w / (bbox[2] - bbox[0]); - this.unitY = h / (bbox[1] - bbox[3]); - this.keepaspectratio = false; - } + x = (Math.abs(this.point1.coords.usrCoords[0]) > Mat.eps) ? + this.point1.coords.usrCoords[1] : + this.point2.coords.usrCoords[1]; - this.moveOrigin(-this.unitX * bbox[0], this.unitY * bbox[1]); + t = (t - 0.5) * 2; - return this; + return (1 - Math.abs(t)) * x - t * b; }, /** - * Get the bounding box of the board. - * @returns {Array} bounding box [x1,y1,x2,y2] upper left corner, lower right corner + * Treat the line as parametric curve in homogeneous coordinates. + * See {@link JXG.Line#X} for a detailed description. + * @param {Number} t Parameter running from 0 to 1. + * @returns {Number} Y(t) y-coordinate of the line treated as parametric curve. */ - getBoundingBox: function () { - var ul = (new Coords(Const.COORDS_BY_SCREEN, [0, 0], this)).usrCoords, - lr = (new Coords(Const.COORDS_BY_SCREEN, [this.canvasWidth, this.canvasHeight], this)).usrCoords; + Y: function (t) { + var y, + a = this.stdform[1]; - return [ul[1], ul[2], lr[1], lr[2]]; + y = (Math.abs(this.point1.coords.usrCoords[0]) > Mat.eps) ? + this.point1.coords.usrCoords[2] : + this.point2.coords.usrCoords[2]; + + t = (t - 0.5) * 2; + + return (1 - Math.abs(t)) * y + t * a; }, /** - * Adds an animation. Animations are controlled by the boards, so the boards need to be aware of the - * animated elements. This function tells the board about new elements to animate. - * @param {JXG.GeometryElement} element The element which is to be animated. - * @returns {JXG.Board} Reference to the board + * Treat the line as parametric curve in homogeneous coordinates. + * See {@link JXG.Line#X} for a detailed description. + * + * @param {Number} t Parameter running from 0 to 1. + * @returns {Number} Z(t) z-coordinate of the line treated as parametric curve. */ - addAnimation: function (element) { - var that = this; - - this.animationObjects[element.id] = element; + Z: function (t) { + var z = (Math.abs(this.point1.coords.usrCoords[0]) > Mat.eps) ? + this.point1.coords.usrCoords[0] : + this.point2.coords.usrCoords[0]; - if (!this.animationIntervalCode) { - this.animationIntervalCode = window.setInterval(function () { - that.animate(); - }, element.board.attr.animationdelay); - } + t = (t - 0.5) * 2; - return this; + return (1 - Math.abs(t)) * z; }, /** - * Cancels all running animations. - * @returns {JXG.Board} Reference to the board + * The distance between the two points defining the line. + * @returns {Number} */ - stopAllAnimation: function () { - var el; - - for (el in this.animationObjects) { - if (this.animationObjects.hasOwnProperty(el) && Type.exists(this.animationObjects[el])) { - this.animationObjects[el] = null; - delete this.animationObjects[el]; - } - } - - window.clearInterval(this.animationIntervalCode); - delete this.animationIntervalCode; - - return this; + L: function () { + return this.point1.Dist(this.point2); }, /** - * General purpose animation function. This currently only supports moving points from one place to another. This - * is faster than managing the animation per point, especially if there is more than one animated point at the same time. - * @returns {JXG.Board} Reference to the board + * Treat the element as a parametric curve + * @private */ - animate: function () { - var props, el, o, newCoords, r, p, c, cbtmp, - count = 0, - obj = null; - - for (el in this.animationObjects) { - if (this.animationObjects.hasOwnProperty(el) && Type.exists(this.animationObjects[el])) { - count += 1; - o = this.animationObjects[el]; - - if (o.animationPath) { - if (Type.isFunction(o.animationPath)) { - newCoords = o.animationPath(new Date().getTime() - o.animationStart); - } else { - newCoords = o.animationPath.pop(); - } - - if ((!Type.exists(newCoords)) || (!Type.isArray(newCoords) && isNaN(newCoords))) { - delete o.animationPath; - } else { - o.setPositionDirectly(Const.COORDS_BY_USER, newCoords); - o.fullUpdate(); - obj = o; - } - } - if (o.animationData) { - c = 0; - - for (r in o.animationData) { - if (o.animationData.hasOwnProperty(r)) { - p = o.animationData[r].pop(); - - if (!Type.exists(p)) { - delete o.animationData[p]; - } else { - c += 1; - props = {}; - props[r] = p; - o.setAttribute(props); - } - } - } - - if (c === 0) { - delete o.animationData; - } - } + minX: function () { + return 0.0; + }, - if (!Type.exists(o.animationData) && !Type.exists(o.animationPath)) { - this.animationObjects[el] = null; - delete this.animationObjects[el]; + /** + * Treat the element as parametric curve + * @private + */ + maxX: function () { + return 1.0; + }, - if (Type.exists(o.animationCallback)) { - cbtmp = o.animationCallback; - o.animationCallback = null; - cbtmp(); - } - } - } - } + // documented in geometry element + bounds: function () { + var p1c = this.point1.coords.usrCoords, + p2c = this.point2.coords.usrCoords; - if (count === 0) { - window.clearInterval(this.animationIntervalCode); - delete this.animationIntervalCode; - } else { - this.update(obj); - } + return [Math.min(p1c[1], p2c[1]), Math.max(p1c[2], p2c[2]), Math.max(p1c[1], p2c[1]), Math.min(p1c[2], p2c[2])]; + }, - return this; + // documented in GeometryElement.js + remove: function () { + this.removeAllTicks(); + GeometryElement.prototype.remove.call(this); }, - /** - * Migrate the dependency properties of the point src - * to the point dest and delete the point src. - * For example, a circle around the point src - * receives the new center dest. The old center src - * will be deleted. - * @param {JXG.Point} src Original point which will be deleted - * @param {JXG.Point} dest New point with the dependencies of src. - * @param {Boolean} copyName Flag which decides if the name of the src element is copied to the - * dest element. - * @returns {JXG.Board} Reference to the board - */ - migratePoint: function (src, dest, copyName) { - var child, childId, prop, found, i, srcLabelId, srcHasLabel = false; + // hideElement: function () { + // var i; + // + // GeometryElement.prototype.hideElement.call(this); + // + // for (i = 0; i < this.ticks.length; i++) { + // this.ticks[i].hideElement(); + // } + // }, + // + // showElement: function () { + // var i; + // GeometryElement.prototype.showElement.call(this); + // + // for (i = 0; i < this.ticks.length; i++) { + // this.ticks[i].showElement(); + // } + // } + }); - src = this.select(src); - dest = this.select(dest); + /** + * @class This element is used to provide a constructor for a general line. A general line is given by two points. By setting additional properties + * a line can be used as an arrow and/or axis. + * @pseudo + * @description + * @name Line + * @augments JXG.Line + * @constructor + * @type JXG.Line + * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {JXG.Point,array,function_JXG.Point,array,function} point1,point2 Parent elements can be two elements either of type {@link JXG.Point} or array of + * numbers describing the coordinates of a point. In the latter case the point will be constructed automatically as a fixed invisible point. + * It is possible to provide a function returning an array or a point, instead of providing an array or a point. + * @param {Number,function_Number,function_Number,function} a,b,c A line can also be created providing three numbers. The line is then described by + * the set of solutions of the equation <tt>a*z+b*x+c*y = 0</tt>. For all finite points, z is normalized to the value 1. + * It is possible to provide three functions returning numbers, too. + * @param {function} f This function must return an array containing three numbers forming the line's homogeneous coordinates. + * <p> + * Additionally, a line can be created by providing a line and a transformation (or an array of transformations). + * Then, the result is a line which is the transformation of the supplied line. + * @example + * // Create a line using point and coordinates/ + * // The second point will be fixed and invisible. + * var p1 = board.create('point', [4.5, 2.0]); + * var l1 = board.create('line', [p1, [1.0, 1.0]]); + * </pre><div class="jxgbox" id="JXGc0ae3461-10c4-4d39-b9be-81d74759d122" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * var glex1_board = JXG.JSXGraph.initBoard('JXGc0ae3461-10c4-4d39-b9be-81d74759d122', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}); + * var glex1_p1 = glex1_board.create('point', [4.5, 2.0]); + * var glex1_l1 = glex1_board.create('line', [glex1_p1, [1.0, 1.0]]); + * </script><pre> + * @example + * // Create a line using three coordinates + * var l1 = board.create('line', [1.0, -2.0, 3.0]); + * </pre><div class="jxgbox" id="JXGcf45e462-f964-4ba4-be3a-c9db94e2593f" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * var glex2_board = JXG.JSXGraph.initBoard('JXGcf45e462-f964-4ba4-be3a-c9db94e2593f', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}); + * var glex2_l1 = glex2_board.create('line', [1.0, -2.0, 3.0]); + * </script><pre> + * @example + * // Create a line (l2) as reflection of another line (l1) + * // reflection line + * var li = board.create('line', [1,1,1], {strokeColor: '#aaaaaa'}); + * var reflect = board.create('transform', [li], {type: 'reflect'}); + * + * var l1 = board.create('line', [1,-5,1]); + * var l2 = board.create('line', [l1, reflect]); + * + * </pre><div id="JXGJXGa00d7dd6-d38c-11e7-93b3-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXGJXGa00d7dd6-d38c-11e7-93b3-901b0e1b8723', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * // reflection line + * var li = board.create('line', [1,1,1], {strokeColor: '#aaaaaa'}); + * var reflect = board.create('transform', [li], {type: 'reflect'}); + * + * var l1 = board.create('line', [1,-5,1]); + * var l2 = board.create('line', [l1, reflect]); + * })(); + * + * </script><pre> + * + * @example + * var t = board.create('transform', [2, 1.5], {type: 'scale'}); + * var l1 = board.create('line', [1, -5, 1]); + * var l2 = board.create('line', [l1, t]); + * + * </pre><div id="d16d5b58-6338-11e8-9fb9-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('d16d5b58-6338-11e8-9fb9-901b0e1b8723', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * var t = board.create('transform', [2, 1.5], {type: 'scale'}); + * var l1 = board.create('line', [1, -5, 1]); + * var l2 = board.create('line', [l1, t]); + * + * })(); + * + * </script><pre> + * + * @example + * //create line between two points + * var p1 = board.create('point', [0,0]); + * var p2 = board.create('point', [2,2]); + * var l1 = board.create('line', [p1,p2], {straightFirst:false, straightLast:false}); + * </pre><div id="d21d5b58-6338-11e8-9fb9-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('d21d5b58-6338-11e8-9fb9-901b0e1b8723', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * var ex5p1 = board.create('point', [0,0]); + * var ex5p2 = board.create('point', [2,2]); + * var ex5l1 = board.create('line', [ex5p1,ex5p2], {straightFirst:false, straightLast:false}); + * })(); + * + * </script><pre> + */ + JXG.createLine = function (board, parents, attributes) { + var ps, el, p1, p2, i, attr, + c = [], + doTransform = false, + constrained = false, + isDraggable; - if (Type.exists(src.label)) { - srcLabelId = src.label.id; - srcHasLabel = true; - this.removeObject(src.label); + /** + * The line is defined by two points or coordinates of two points. + * In the latter case, the points are created. + */ + if (parents.length === 2) { + // point 1 given by coordinates + if (Type.isArray(parents[0]) && parents[0].length > 1) { + attr = Type.copyAttributes(attributes, board.options, 'line', 'point1'); + p1 = board.create('point', parents[0], attr); + } else if (Type.isString(parents[0]) || Type.isPoint(parents[0])) { + p1 = board.select(parents[0]); + } else if (Type.isFunction(parents[0]) && Type.isPoint(parents[0]())) { + p1 = parents[0](); + constrained = true; + } else if (Type.isFunction(parents[0]) && parents[0]().length && parents[0]().length >= 2) { + attr = Type.copyAttributes(attributes, board.options, 'line', 'point1'); + p1 = Point.createPoint(board, parents[0](), attr); + constrained = true; + } else if (Type.isObject(parents[0]) && Type.isTransformationOrArray(parents[1])) { + doTransform = true; + attr = Type.copyAttributes(attributes, board.options, 'line', 'point1'); + p1 = board.create('point', [parents[0].point1, parents[1]], attr); + } else { + throw new Error("JSXGraph: Can't create line with parent types '" + + (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + + "\nPossible parent types: [point,point], [[x1,y1],[x2,y2]], [a,b,c]"); } - for (childId in src.childElements) { - if (src.childElements.hasOwnProperty(childId)) { - child = src.childElements[childId]; - found = false; - - for (prop in child) { - if (child.hasOwnProperty(prop)) { - if (child[prop] === src) { - child[prop] = dest; - found = true; - } - } - } - - if (found) { - delete src.childElements[childId]; - } - - for (i = 0; i < child.parents.length; i++) { - if (child.parents[i] === src.id) { - child.parents[i] = dest.id; - } - } - - dest.addChild(child); - } + // point 2 given by coordinates + if (doTransform) { + attr = Type.copyAttributes(attributes, board.options, 'line', 'point2'); + p2 = board.create('point', [parents[0].point2, parents[1]], attr); + } else if (Type.isArray(parents[1]) && parents[1].length > 1) { + attr = Type.copyAttributes(attributes, board.options, 'line', 'point2'); + p2 = board.create('point', parents[1], attr); + } else if (Type.isString(parents[1]) || Type.isPoint(parents[1])) { + p2 = board.select(parents[1]); + } else if (Type.isFunction(parents[1]) && Type.isPoint(parents[1]()) ) { + p2 = parents[1](); + constrained = true; + } else if (Type.isFunction(parents[1]) && parents[1]().length && parents[1]().length >= 2) { + attr = Type.copyAttributes(attributes, board.options, 'line', 'point2'); + p2 = Point.createPoint(board, parents[1](), attr); + constrained = true; + } else { + throw new Error("JSXGraph: Can't create line with parent types '" + + (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + + "\nPossible parent types: [point,point], [[x1,y1],[x2,y2]], [a,b,c]"); } - // The destination object should receive the name - // and the label of the originating (src) object - if (copyName) { - if (srcHasLabel) { - delete dest.childElements[srcLabelId]; - delete dest.descendants[srcLabelId]; - } - - if (dest.label) { - this.removeObject(dest.label); - } - - delete this.elementsByName[dest.name]; - dest.name = src.name; - if (srcHasLabel) { - dest.createLabel(); - } - } + attr = Type.copyAttributes(attributes, board.options, 'line'); - this.removeObject(src); + el = new JXG.Line(board, p1, p2, attr); - if (Type.exists(dest.name) && dest.name !== '') { - this.elementsByName[dest.name] = dest; + if (constrained) { + el.constrained = true; + el.funp1 = parents[0]; + el.funp2 = parents[1]; + } else if (!doTransform) { + el.isDraggable = true; } - this.fullUpdate(); - - return this; - }, - - /** - * Initializes color blindness simulation. - * @param {String} deficiency Describes the color blindness deficiency which is simulated. Accepted values are 'protanopia', 'deuteranopia', and 'tritanopia'. - * @returns {JXG.Board} Reference to the board - */ - emulateColorblindness: function (deficiency) { - var e, o; + //if (!el.constrained) { + el.setParents([p1.id, p2.id]); + //} - if (!Type.exists(deficiency)) { - deficiency = 'none'; + // Line is defined by three homogeneous coordinates. + // Also in this case points are created. + } else if (parents.length === 3) { + // free line + isDraggable = true; + for (i = 0; i < 3; i++) { + if (Type.isNumber(parents[i])) { + // createFunction will just wrap a function around our constant number + // that does nothing else but to return that number. + c[i] = Type.createFunction(parents[i]); + } else if (Type.isFunction(parents[i])) { + c[i] = parents[i]; + isDraggable = false; + } else { + throw new Error("JSXGraph: Can't create line with parent types '" + + (typeof parents[0]) + "' and '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." + + "\nPossible parent types: [point,point], [[x1,y1],[x2,y2]], [a,b,c]"); + } } - if (this.currentCBDef === deficiency) { - return this; + // point 1 is the midpoint between (0,c,-b) and point 2. => point1 is finite. + attr = Type.copyAttributes(attributes, board.options, 'line', 'point1'); + if (isDraggable) { + p1 = board.create('point', [ + c[2]() * c[2]() + c[1]() * c[1](), + c[2]() - c[1]() * c[0]() + c[2](), + -c[1]() - c[2]() * c[0]() - c[1]() + ], attr); + } else { + p1 = board.create('point', [ + function () { + return (c[2]() * c[2]() + c[1]() * c[1]()) * 0.5; + }, + function () { + return (c[2]() - c[1]() * c[0]() + c[2]()) * 0.5; + }, + function () { + return (-c[1]() - c[2]() * c[0]() - c[1]()) * 0.5; + }], attr); } - for (e in this.objects) { - if (this.objects.hasOwnProperty(e)) { - o = this.objects[e]; - - if (deficiency !== 'none') { - if (this.currentCBDef === 'none') { - // this could be accomplished by JXG.extend, too. But do not use - // JXG.deepCopy as this could result in an infinite loop because in - // visProp there could be geometry elements which contain the board which - // contains all objects which contain board etc. - o.visPropOriginal = { - strokecolor: o.visProp.strokecolor, - fillcolor: o.visProp.fillcolor, - highlightstrokecolor: o.visProp.highlightstrokecolor, - highlightfillcolor: o.visProp.highlightfillcolor - }; - } - o.setAttribute({ - strokecolor: Color.rgb2cb(Type.evaluate(o.visPropOriginal.strokecolor), deficiency), - fillcolor: Color.rgb2cb(Type.evaluate(o.visPropOriginal.fillcolor), deficiency), - highlightstrokecolor: Color.rgb2cb(Type.evaluate(o.visPropOriginal.highlightstrokecolor), deficiency), - highlightfillcolor: Color.rgb2cb(Type.evaluate(o.visPropOriginal.highlightfillcolor), deficiency) - }); - } else if (Type.exists(o.visPropOriginal)) { - JXG.extend(o.visProp, o.visPropOriginal); - } - } + // point 2: (b^2+c^2,-ba+c,-ca-b) + attr = Type.copyAttributes(attributes, board.options, 'line', 'point2'); + if (isDraggable) { + p2 = board.create('point', [ + c[2]() * c[2]() + c[1]() * c[1](), + -c[1]() * c[0]() + c[2](), + -c[2]() * c[0]() - c[1]() + ], attr); + } else { + p2 = board.create('point', [ + function () { + return c[2]() * c[2]() + c[1]() * c[1](); + }, + function () { + return -c[1]() * c[0]() + c[2](); + }, + function () { + return -c[2]() * c[0]() - c[1](); + }], attr); } - this.currentCBDef = deficiency; - this.update(); - - return this; - }, - /** - * Select a single or multiple elements at once. - * @param {String|Object|function} str The name, id or a reference to a JSXGraph element on this board. An object will - * be used as a filter to return multiple elements at once filtered by the properties of the object. - * @param {Boolean} onlyByIdOrName If true (default:false) elements are only filtered by their id, name or groupId. - * The advanced filters consisting of objects or functions are ignored. - * @returns {JXG.GeometryElement|JXG.Composition} - * @example - * // select the element with name A - * board.select('A'); - * - * // select all elements with strokecolor set to 'red' (but not '#ff0000') - * board.select({ - * strokeColor: 'red' - * }); - * - * // select all points on or below the x axis and make them black. - * board.select({ - * elementClass: JXG.OBJECT_CLASS_POINT, - * Y: function (v) { - * return v <= 0; - * } - * }).setAttribute({color: 'black'}); - * - * // select all elements - * board.select(function (el) { - * return true; - * }); - */ - select: function (str, onlyByIdOrName) { - var flist, olist, i, l, - s = str; + // If the line will have a glider and board.suspendUpdate() has been called, we + // need to compute the initial position of the two points p1 and p2. + p1.prepareUpdate().update(); + p2.prepareUpdate().update(); + attr = Type.copyAttributes(attributes, board.options, 'line'); + el = new JXG.Line(board, p1, p2, attr); + // Not yet working, because the points are not draggable. + el.isDraggable = isDraggable; + el.setParents([p1, p2]); - if (s === null) { - return s; - } + // The parent array contains a function which returns two points. + } else if (parents.length === 1 && Type.isFunction(parents[0]) && parents[0]().length === 2 && + Type.isPoint(parents[0]()[0]) && + Type.isPoint(parents[0]()[1])) { + ps = parents[0](); + attr = Type.copyAttributes(attributes, board.options, 'line'); + el = new JXG.Line(board, ps[0], ps[1], attr); + el.constrained = true; + el.funps = parents[0]; + el.setParents(ps); - // it's a string, most likely an id or a name. - if (Type.isString(s) && s !== '') { - // Search by ID - if (Type.exists(this.objects[s])) { - s = this.objects[s]; - // Search by name - } else if (Type.exists(this.elementsByName[s])) { - s = this.elementsByName[s]; - // Search by group ID - } else if (Type.exists(this.groups[s])) { - s = this.groups[s]; - } - // it's a function or an object, but not an element - } else if (!onlyByIdOrName && - (Type.isFunction(s) || - (Type.isObject(s) && !Type.isFunction(s.setAttribute)) - )) { - flist = Type.filterElements(this.objectsList, s); + } else if (parents.length === 1 && Type.isFunction(parents[0]) && parents[0]().length === 3 && + Type.isNumber(parents[0]()[0]) && + Type.isNumber(parents[0]()[1]) && + Type.isNumber(parents[0]()[2])) { + ps = parents[0]; - olist = {}; - l = flist.length; - for (i = 0; i < l; i++) { - olist[flist[i].id] = flist[i]; - } - s = new EComposition(olist); - // it's an element which has been deleted (and still hangs around, e.g. in an attractor list - } else if (Type.isObject(s) && Type.exists(s.id) && !Type.exists(this.objects[s.id])) { - s = null; - } + attr = Type.copyAttributes(attributes, board.options, 'line', 'point1'); + p1 = board.create('point', [ + function () { + var c = ps(); - return s; - }, + return [ + (c[2] * c[2] + c[1] * c[1]) * 0.5, + (c[2] - c[1] * c[0] + c[2]) * 0.5, + (-c[1] - c[2] * c[0] - c[1]) * 0.5 + ]; + }], attr); - /** - * Checks if the given point is inside the boundingbox. - * @param {Number|JXG.Coords} x User coordinate or {@link JXG.Coords} object. - * @param {Number} [y] User coordinate. May be omitted in case <tt>x</tt> is a {@link JXG.Coords} object. - * @returns {Boolean} - */ - hasPoint: function (x, y) { - var px = x, - py = y, - bbox = this.getBoundingBox(); + attr = Type.copyAttributes(attributes, board.options, 'line', 'point2'); + p2 = board.create('point', [ + function () { + var c = ps(); - if (Type.exists(x) && Type.isArray(x.usrCoords)) { - px = x.usrCoords[1]; - py = x.usrCoords[2]; - } + return [ + c[2] * c[2] + c[1] * c[1], + -c[1] * c[0] + c[2], + -c[2] * c[0] - c[1] + ]; + }], attr); - return !!(Type.isNumber(px) && Type.isNumber(py) && - bbox[0] < px && px < bbox[2] && bbox[1] > py && py > bbox[3]); - }, + attr = Type.copyAttributes(attributes, board.options, 'line'); + el = new JXG.Line(board, p1, p2, attr); - /** - * Update CSS transformations of sclaing type. It is used to correct the mouse position - * in {@link JXG.Board.getMousePosition}. - * The inverse transformation matrix is updated on each mouseDown and touchStart event. - * - * It is up to the user to call this method after an update of the CSS transformation - * in the DOM. - */ - updateCSSTransforms: function () { - var obj = this.containerObj, - o = obj, - o2 = obj; + el.constrained = true; + el.funps = parents[0]; + el.setParents([p1, p2]); - this.cssTransMat = Env.getCSSTransformMatrix(o); + } else { + throw new Error("JSXGraph: Can't create line with parent types '" + + (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + + "\nPossible parent types: [point,point], [[x1,y1],[x2,y2]], [a,b,c]"); + } - /* - * In Mozilla and Webkit: offsetParent seems to jump at least to the next iframe, - * if not to the body. In IE and if we are in an position:absolute environment - * offsetParent walks up the DOM hierarchy. - * In order to walk up the DOM hierarchy also in Mozilla and Webkit - * we need the parentNode steps. - */ - o = o.offsetParent; - while (o) { - this.cssTransMat = Mat.matMatMult(Env.getCSSTransformMatrix(o), this.cssTransMat); + return el; + }; - o2 = o2.parentNode; - while (o2 !== o) { - this.cssTransMat = Mat.matMatMult(Env.getCSSTransformMatrix(o), this.cssTransMat); - o2 = o2.parentNode; - } + JXG.registerElement('line', JXG.createLine); - o = o.offsetParent; - } - this.cssTransMat = Mat.inverse(this.cssTransMat); - - return this; - }, + /** + * @class This element is used to provide a constructor for a segment. + * It's strictly spoken just a wrapper for element {@link Line} with {@link Line#straightFirst} + * and {@link Line#straightLast} properties set to false. If there is a third variable then the + * segment has a fixed length (which may be a function, too). + * @pseudo + * @description + * @name Segment + * @augments JXG.Line + * @constructor + * @type JXG.Line + * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {JXG.Point,array_JXG.Point,array} point1,point2 Parent elements can be two elements either of type {@link JXG.Point} + * or array of numbers describing the + * coordinates of a point. In the latter case the point will be constructed automatically as a fixed invisible point. + * @param {number,function} length (optional) The points are adapted - if possible - such that their distance + * has this value. + * @see Line + * @example + * // Create a segment providing two points. + * var p1 = board.create('point', [4.5, 2.0]); + * var p2 = board.create('point', [1.0, 1.0]); + * var l1 = board.create('segment', [p1, p2]); + * </pre><div class="jxgbox" id="JXGd70e6aac-7c93-4525-a94c-a1820fa38e2f" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * var slex1_board = JXG.JSXGraph.initBoard('JXGd70e6aac-7c93-4525-a94c-a1820fa38e2f', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}); + * var slex1_p1 = slex1_board.create('point', [4.5, 2.0]); + * var slex1_p2 = slex1_board.create('point', [1.0, 1.0]); + * var slex1_l1 = slex1_board.create('segment', [slex1_p1, slex1_p2]); + * </script><pre> + * + * @example + * // Create a segment providing two points. + * var p1 = board.create('point', [4.0, 1.0]); + * var p2 = board.create('point', [1.0, 1.0]); + * var l1 = board.create('segment', [p1, p2]); + * var p3 = board.create('point', [4.0, 2.0]); + * var p4 = board.create('point', [1.0, 2.0]); + * var l2 = board.create('segment', [p3, p4, 3]); + * var p5 = board.create('point', [4.0, 3.0]); + * var p6 = board.create('point', [1.0, 4.0]); + * var l3 = board.create('segment', [p5, p6, function(){ return l1.L();} ]); + * </pre><div class="jxgbox" id="JXG617336ba-0705-4b2b-a236-c87c28ef25be" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * var slex2_board = JXG.JSXGraph.initBoard('JXG617336ba-0705-4b2b-a236-c87c28ef25be', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}); + * var slex2_p1 = slex2_board.create('point', [4.0, 1.0]); + * var slex2_p2 = slex2_board.create('point', [1.0, 1.0]); + * var slex2_l1 = slex2_board.create('segment', [slex2_p1, slex2_p2]); + * var slex2_p3 = slex2_board.create('point', [4.0, 2.0]); + * var slex2_p4 = slex2_board.create('point', [1.0, 2.0]); + * var slex2_l2 = slex2_board.create('segment', [slex2_p3, slex2_p4, 3]); + * var slex2_p5 = slex2_board.create('point', [4.0, 2.0]); + * var slex2_p6 = slex2_board.create('point', [1.0, 2.0]); + * var slex2_l3 = slex2_board.create('segment', [slex2_p5, slex2_p6, function(){ return slex2_l1.L();}]); + * </script><pre> + * + */ + JXG.createSegment = function (board, parents, attributes) { + var el, attr; - /** - * Start selection mode. This function can either be triggered from outside or by - * a down event together with correct key pressing. The default keys are - * shift+ctrl. But this can be changed in the options. - * - * Starting from out side can be realized for example with a button like this: - * <pre> - * <button onclick="board.startSelectionMode()">Start</button> - * </pre> - * @example - * // - * // Set a new bounding box from the selection rectangle - * // - * var board = JXG.JSXGraph.initBoard('jxgbox', { - * boundingBox:[-3,2,3,-2], - * keepAspectRatio: false, - * axis:true, - * selection: { - * enabled: true, - * needShift: false, - * needCtrl: true, - * withLines: false, - * vertices: { - * visible: false - * }, - * fillColor: '#ffff00', - * } - * }); - * - * var f = function f(x) { return Math.cos(x); }, - * curve = board.create('functiongraph', [f]); - * - * board.on('stopselecting', function(){ - * var box = board.stopSelectionMode(), - * - * // bbox has the coordinates of the selection rectangle. - * // Attention: box[i].usrCoords have the form [1, x, y], i.e. - * // are homogeneous coordinates. - * bbox = box[0].usrCoords.slice(1).concat(box[1].usrCoords.slice(1)); - * - * // Set a new bounding box - * board.setBoundingBox(bbox, false); - * }); - * - * - * </pre><div class="jxgbox" id="JXG11eff3a6-8c50-11e5-b01d-901b0e1b8723" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function() { - * // - * // Set a new bounding box from the selection rectangle - * // - * var board = JXG.JSXGraph.initBoard('JXG11eff3a6-8c50-11e5-b01d-901b0e1b8723', { - * boundingBox:[-3,2,3,-2], - * keepAspectRatio: false, - * axis:true, - * selection: { - * enabled: true, - * needShift: false, - * needCtrl: true, - * withLines: false, - * vertices: { - * visible: false - * }, - * fillColor: '#ffff00', - * } - * }); - * - * var f = function f(x) { return Math.cos(x); }, - * curve = board.create('functiongraph', [f]); - * - * board.on('stopselecting', function(){ - * var box = board.stopSelectionMode(), - * - * // bbox has the coordinates of the selection rectangle. - * // Attention: box[i].usrCoords have the form [1, x, y], i.e. - * // are homogeneous coordinates. - * bbox = box[0].usrCoords.slice(1).concat(box[1].usrCoords.slice(1)); - * - * // Set a new bounding box - * board.setBoundingBox(bbox, false); - * }); - * })(); - * - * </script><pre> - * - */ - startSelectionMode: function () { - this.selectingMode = true; - this.selectionPolygon.setAttribute({visible: true}); - this.selectingBox = [[0, 0], [0, 0]]; - this._setSelectionPolygonFromBox(); - this.selectionPolygon.fullUpdate(); - }, + attributes.straightFirst = false; + attributes.straightLast = false; + attr = Type.copyAttributes(attributes, board.options, 'segment'); - /** - * Finalize the selection: disable selection mode and return the coordinates - * of the selection rectangle. - * @returns {Array} Coordinates of the selection rectangle. The array - * contains two {@link JXG.Coords} objects. One the upper left corner and - * the second for the lower right corner. - */ - stopSelectionMode: function () { - this.selectingMode = false; - this.selectionPolygon.setAttribute({visible: false}); - return [this.selectionPolygon.vertices[0].coords, this.selectionPolygon.vertices[2].coords]; - }, + el = board.create('line', parents.slice(0, 2), attr); - /** - * Start the selection of a region. - * @private - * @param {Array} pos Screen coordiates of the upper left corner of the - * selection rectangle. - */ - _startSelecting: function (pos) { - this.isSelecting = true; - this.selectingBox = [ [pos[0], pos[1]], [pos[0], pos[1]] ]; - this._setSelectionPolygonFromBox(); - }, + if (parents.length === 3) { + el.hasFixedLength = true; - /** - * Update the selection rectangle during a move event. - * @private - * @param {Array} pos Screen coordiates of the move event - */ - _moveSelecting: function (pos) { - if (this.isSelecting) { - this.selectingBox[1] = [pos[0], pos[1]]; - this._setSelectionPolygonFromBox(); - this.selectionPolygon.fullUpdate(); + if (Type.isNumber(parents[2])) { + el.fixedLength = function () { + return parents[2]; + }; + } else if (Type.isFunction(parents[2])) { + el.fixedLength = parents[2]; + } else { + throw new Error("JSXGraph: Can't create segment with third parent type '" + + (typeof parents[2]) + "'." + + "\nPossible third parent types: number or function"); } - }, - /** - * Update the selection rectangle during an up event. Stop selection. - * @private - * @param {Object} evt Event object - */ - _stopSelecting: function (evt) { - var pos = this.getMousePosition(evt); + el.getParents = function() { + return this.parents.concat(this.fixedLength()); + }; - this.isSelecting = false; - this.selectingBox[1] = [pos[0], pos[1]]; - this._setSelectionPolygonFromBox(); - }, + el.fixedLengthOldCoords = []; + el.fixedLengthOldCoords[0] = new Coords(Const.COORDS_BY_USER, el.point1.coords.usrCoords.slice(1, 3), board); + el.fixedLengthOldCoords[1] = new Coords(Const.COORDS_BY_USER, el.point2.coords.usrCoords.slice(1, 3), board); + } - /** - * Update the Selection rectangle. - * @private - */ - _setSelectionPolygonFromBox: function () { - var A = this.selectingBox[0], - B = this.selectingBox[1]; + el.elType = 'segment'; - this.selectionPolygon.vertices[0].setPositionDirectly(JXG.COORDS_BY_SCREEN, [A[0], A[1]]); - this.selectionPolygon.vertices[1].setPositionDirectly(JXG.COORDS_BY_SCREEN, [A[0], B[1]]); - this.selectionPolygon.vertices[2].setPositionDirectly(JXG.COORDS_BY_SCREEN, [B[0], B[1]]); - this.selectionPolygon.vertices[3].setPositionDirectly(JXG.COORDS_BY_SCREEN, [B[0], A[1]]); - }, + return el; + }; - /** - * Test if a down event should start a selection. Test if the - * required keys are pressed. If yes, {@link JXG.Board.startSelectionMode} is called. - * @param {Object} evt Event object - */ - _testForSelection: function (evt) { - if (this._isRequiredKeyPressed(evt, 'selection')) { - if (!Type.exists(this.selectionPolygon)) { - this._createSelectionPolygon(this.attr); - } - this.startSelectionMode(); - } - }, + JXG.registerElement('segment', JXG.createSegment); - /** - * Create the internal selection polygon, which will be available as board.selectionPolygon. - * @private - * @param {Object} attr board attributes, e.g. the subobject board.attr. - * @returns {Object} pointer to the board to enable chaining. - */ - _createSelectionPolygon: function(attr) { - var selectionattr; + /** + * @class This element is used to provide a constructor for arrow, which is just a wrapper for element + * {@link Line} with {@link Line#straightFirst} + * and {@link Line#straightLast} properties set to false and {@link Line#lastArrow} set to true. + * @pseudo + * @description + * @name Arrow + * @augments JXG.Line + * @constructor + * @type JXG.Line + * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {JXG.Point,array_JXG.Point,array} point1,point2 Parent elements can be two elements either of type {@link JXG.Point} or array of numbers describing the + * coordinates of a point. In the latter case the point will be constructed automatically as a fixed invisible point. + * @param {Number_Number_Number} a,b,c A line can also be created providing three numbers. The line is then described by the set of solutions + * of the equation <tt>a*x+b*y+c*z = 0</tt>. + * @see Line + * @example + * // Create an arrow providing two points. + * var p1 = board.create('point', [4.5, 2.0]); + * var p2 = board.create('point', [1.0, 1.0]); + * var l1 = board.create('arrow', [p1, p2]); + * </pre><div class="jxgbox" id="JXG1d26bd22-7d6d-4018-b164-4c8bc8d22ccf" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * var alex1_board = JXG.JSXGraph.initBoard('JXG1d26bd22-7d6d-4018-b164-4c8bc8d22ccf', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}); + * var alex1_p1 = alex1_board.create('point', [4.5, 2.0]); + * var alex1_p2 = alex1_board.create('point', [1.0, 1.0]); + * var alex1_l1 = alex1_board.create('arrow', [alex1_p1, alex1_p2]); + * </script><pre> + */ + JXG.createArrow = function (board, parents, attributes) { + var el, attr; - if (!Type.exists(this.selectionPolygon)) { - selectionattr = Type.copyAttributes(attr, Options, 'board', 'selection'); - if (selectionattr.enabled === true) { - this.selectionPolygon = this.create('polygon', [[0, 0], [0, 0], [0, 0], [0, 0]], selectionattr); - } - } + attributes.straightFirst = false; + attributes.straightLast = false; + attr = Type.copyAttributes(attributes, board.options, 'arrow'); + el = board.create('line', parents, attr); + //el.setArrow(false, true); + el.type = Const.OBJECT_TYPE_VECTOR; + el.elType = 'arrow'; - return this; - }, + return el; + }; - /* ************************** - * EVENT DEFINITION - * for documentation purposes - * ************************** */ + JXG.registerElement('arrow', JXG.createArrow); - //region Event handler documentation + /** + * @class This element is used to provide a constructor for an axis. It's strictly spoken just a wrapper for element {@link Line} with {@link Line#straightFirst} + * and {@link Line#straightLast} properties set to true. Additionally {@link Line#lastArrow} is set to true and default {@link Ticks} will be created. + * @pseudo + * @description + * @name Axis + * @augments JXG.Line + * @constructor + * @type JXG.Line + * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {JXG.Point,array_JXG.Point,array} point1,point2 Parent elements can be two elements either of type {@link JXG.Point} or array of numbers describing the + * coordinates of a point. In the latter case, the point will be constructed automatically as a fixed invisible point. + * @param {Number_Number_Number} a,b,c A line can also be created providing three numbers. The line is then described by the set of solutions + * of the equation <tt>a*x+b*y+c*z = 0</tt>. + * @example + * // Create an axis providing two coord pairs. + * var l1 = board.create('axis', [[0.0, 1.0], [1.0, 1.3]]); + * </pre><div class="jxgbox" id="JXG4f414733-624c-42e4-855c-11f5530383ae" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * var axex1_board = JXG.JSXGraph.initBoard('JXG4f414733-624c-42e4-855c-11f5530383ae', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}); + * var axex1_l1 = axex1_board.create('axis', [[0.0, 1.0], [1.0, 1.3]]); + * </script><pre> + */ + JXG.createAxis = function (board, parents, attributes) { + var attr, attr_ticks, el, els, dist; - /** - * @event - * @description Whenever the user starts to touch or click the board. - * @name JXG.Board#down - * @param {Event} e The browser's event object. - */ - __evt__down: function (e) { }, + // Arrays or points, that is all we need. + if ((Type.isArray(parents[0]) || Type.isPoint(parents[0])) && (Type.isArray(parents[1]) || Type.isPoint(parents[1]))) { - /** - * @event - * @description Whenever the user starts to click on the board. - * @name JXG.Board#mousedown - * @param {Event} e The browser's event object. - */ - __evt__mousedown: function (e) { }, + // Create line + attr = Type.copyAttributes(attributes, board.options, 'axis'); + el = board.create('line', parents, attr); + el.type = Const.OBJECT_TYPE_AXIS; + el.isDraggable = false; + el.point1.isDraggable = false; + el.point2.isDraggable = false; - /** - * @event - * @description Whenever the user taps the pen on the board. - * @name JXG.Board#pendown - * @param {Event} e The browser's event object. - */ - __evt__pendown: function (e) { }, + for (els in el.ancestors) { + if (el.ancestors.hasOwnProperty(els)) { + el.ancestors[els].type = Const.OBJECT_TYPE_AXISPOINT; + } + } - /** - * @event - * @description Whenever the user starts to click on the board with a - * device sending pointer events. - * @name JXG.Board#pointerdown - * @param {Event} e The browser's event object. - */ - __evt__pointerdown: function (e) { }, + // Create ticks + attr_ticks = Type.copyAttributes(attributes, board.options, 'axis', 'ticks'); + if (Type.exists(attr_ticks.ticksdistance)) { + dist = attr_ticks.ticksdistance; + } else if (Type.isArray(attr_ticks.ticks)) { + dist = attr_ticks.ticks; + } else { + dist = 1.0; + } - /** - * @event - * @description Whenever the user starts to touch the board. - * @name JXG.Board#touchstart - * @param {Event} e The browser's event object. - */ - __evt__touchstart: function (e) { }, + /** + * The ticks attached to the axis. + * @memberOf Axis.prototype + * @name defaultTicks + * @type JXG.Ticks + */ + el.defaultTicks = board.create('ticks', [el, dist], attr_ticks); + el.defaultTicks.dump = false; + el.elType = 'axis'; + el.subs = { + ticks: el.defaultTicks + }; + el.inherits.push(el.defaultTicks); - /** - * @event - * @description Whenever the user stops to touch or click the board. - * @name JXG.Board#up - * @param {Event} e The browser's event object. - */ - __evt__up: function (e) { }, + } else { + throw new Error("JSXGraph: Can't create axis with parent types '" + + (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + + "\nPossible parent types: [point,point], [[x1,y1],[x2,y2]]"); + } - /** - * @event - * @description Whenever the user releases the mousebutton over the board. - * @name JXG.Board#mouseup - * @param {Event} e The browser's event object. - */ - __evt__mouseup: function (e) { }, + return el; + }; - /** - * @event - * @description Whenever the user releases the mousebutton over the board with a - * device sending pointer events. - * @name JXG.Board#pointerup - * @param {Event} e The browser's event object. - */ - __evt__pointerup: function (e) { }, + JXG.registerElement('axis', JXG.createAxis); - /** - * @event - * @description Whenever the user stops touching the board. - * @name JXG.Board#touchend - * @param {Event} e The browser's event object. - */ - __evt__touchend: function (e) { }, + /** + * @class With the element tangent the slope of a line, circle, or curve in a certain point can be visualized. A tangent is always constructed + * by a glider on a line, circle, or curve and describes the tangent in the glider point on that line, circle, or curve. + * @pseudo + * @description + * @name Tangent + * @augments JXG.Line + * @constructor + * @type JXG.Line + * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {Glider} g A glider on a line, circle, or curve. + * @example + * // Create a tangent providing a glider on a function graph + * var c1 = board.create('curve', [function(t){return t},function(t){return t*t*t;}]); + * var g1 = board.create('glider', [0.6, 1.2, c1]); + * var t1 = board.create('tangent', [g1]); + * </pre><div class="jxgbox" id="JXG7b7233a0-f363-47dd-9df5-4018d0d17a98" style="width: 400px; height: 400px;"></div> + * <script type="text/javascript"> + * var tlex1_board = JXG.JSXGraph.initBoard('JXG7b7233a0-f363-47dd-9df5-4018d0d17a98', {boundingbox: [-6, 6, 6, -6], axis: true, showcopyright: false, shownavigation: false}); + * var tlex1_c1 = tlex1_board.create('curve', [function(t){return t},function(t){return t*t*t;}]); + * var tlex1_g1 = tlex1_board.create('glider', [0.6, 1.2, tlex1_c1]); + * var tlex1_t1 = tlex1_board.create('tangent', [tlex1_g1]); + * </script><pre> + */ + JXG.createTangent = function (board, parents, attributes) { + var p, c, j, el, tangent; - /** - * @event - * @description This event is fired whenever the user is moving the finger or mouse pointer over the board. - * @name JXG.Board#move - * @param {Event} e The browser's event object. - * @param {Number} mode The mode the board currently is in - * @see {JXG.Board#mode} - */ - __evt__move: function (e, mode) { }, + // One argument: glider on line, circle or curve + if (parents.length === 1) { + p = parents[0]; + c = p.slideObject; + // Two arguments: (point,F"|conic) or (line|curve|circle|conic,point). // Not yet: curve! + } else if (parents.length === 2) { + // In fact, for circles and conics it is the polar + if (Type.isPoint(parents[0])) { + p = parents[0]; + c = parents[1]; + } else if (Type.isPoint(parents[1])) { + c = parents[0]; + p = parents[1]; + } else { + throw new Error("JSXGraph: Can't create tangent with parent types '" + + (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + + "\nPossible parent types: [glider], [point,line|curve|circle|conic]"); + } + } else { + throw new Error("JSXGraph: Can't create tangent with parent types '" + + (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + + "\nPossible parent types: [glider], [point,line|curve|circle|conic]"); + } - /** - * @event - * @description This event is fired whenever the user is moving the mouse over the board. - * @name JXG.Board#mousemove - * @param {Event} e The browser's event object. - * @param {Number} mode The mode the board currently is in - * @see {JXG.Board#mode} - */ - __evt__mousemove: function (e, mode) { }, - - /** - * @event - * @description This event is fired whenever the user is moving the pen over the board. - * @name JXG.Board#penmove - * @param {Event} e The browser's event object. - * @param {Number} mode The mode the board currently is in - * @see {JXG.Board#mode} - */ - __evt__penmove: function (e, mode) { }, - - /** - * @event - * @description This event is fired whenever the user is moving the mouse over the board with a - * device sending pointer events. - * @name JXG.Board#pointermove - * @param {Event} e The browser's event object. - * @param {Number} mode The mode the board currently is in - * @see {JXG.Board#mode} - */ - __evt__pointermove: function (e, mode) { }, - - /** - * @event - * @description This event is fired whenever the user is moving the finger over the board. - * @name JXG.Board#touchmove - * @param {Event} e The browser's event object. - * @param {Number} mode The mode the board currently is in - * @see {JXG.Board#mode} - */ - __evt__touchmove: function (e, mode) { }, - - /** - * @event - * @description Whenever an element is highlighted this event is fired. - * @name JXG.Board#hit - * @param {Event} e The browser's event object. - * @param {JXG.GeometryElement} el The hit element. - * @param target - * - * @example - * var c = board.create('circle', [[1, 1], 2]); - * board.on('hit', function(evt, el) { - * console.log("Hit element", el); - * }); - * - * </pre><div id="JXG19eb31ac-88e6-11e8-bcb5-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function() { - * var board = JXG.JSXGraph.initBoard('JXG19eb31ac-88e6-11e8-bcb5-901b0e1b8723', - * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); - * var c = board.create('circle', [[1, 1], 2]); - * board.on('hit', function(evt, el) { - * console.log("Hit element", el); - * }); - * - * })(); - * - * </script><pre> - */ - __evt__hit: function (e, el, target) { }, - - /** - * @event - * @description Whenever an element is highlighted this event is fired. - * @name JXG.Board#mousehit - * @see JXG.Board#hit - * @param {Event} e The browser's event object. - * @param {JXG.GeometryElement} el The hit element. - * @param target - */ - __evt__mousehit: function (e, el, target) { }, + if (c.elementClass === Const.OBJECT_CLASS_LINE) { + tangent = board.create('line', [c.point1, c.point2], attributes); + tangent.glider = p; + } else if (c.elementClass === Const.OBJECT_CLASS_CURVE && c.type !== Const.OBJECT_TYPE_CONIC) { + if (Type.evaluate(c.visProp.curvetype) !== 'plot') { + tangent = board.create('line', [ + function () { + var g = c.X, + f = c.Y; + return -p.X() * Numerics.D(f)(p.position) + p.Y() * Numerics.D(g)(p.position); + }, + function () { + return Numerics.D(c.Y)(p.position); + }, + function () { + return -Numerics.D(c.X)(p.position); + } + ], attributes); - /** - * @event - * @description This board is updated. - * @name JXG.Board#update - */ - __evt__update: function () { }, + p.addChild(tangent); + // this is required for the geogebra reader to display a slope + tangent.glider = p; + } else { // curveType 'plot' + // In case of bezierDegree == 1: + // Find two points p1, p2 enclosing the glider. + // Then the equation of the line segment is: 0 = y*(x1-x2) + x*(y2-y1) + y1*x2-x1*y2, + // which is the cross product of p1 and p2. + // + // In case of bezieDegree === 3: + // The slope dy / dx of the tangent is determined. Then the + // tangent is computed as cross product between + // the glider p and [1, p.X() + dx, p.Y() + dy] + // + tangent = board.create('line', [ + function () { + var i = Math.floor(p.position), + p1, p2, t, A, B, C, D, dx, dy, d; - /** - * @event - * @description The bounding box of the board has changed. - * @name JXG.Board#boundingbox - */ - __evt__boundingbox: function () { }, + if (c.bezierDegree === 1) { + if (i === c.numberPoints - 1) { + i--; + } + } else if (c.bezierDegree === 3) { + // i is start of the Bezier segment + // t is the position in the Bezier segment + i = Math.floor(p.position * (c.numberPoints - 1) / 3) * 3; + t = (p.position * (c.numberPoints - 1) - i) / 3; + if (i >= c.numberPoints - 1) { + i = c.numberPoints - 4; + t = 1; + } + } else { + return 0; + } - /** - * @event - * @description Select a region is started during a down event or by calling - * {@link JXG.Board.startSelectionMode} - * @name JXG.Board#startselecting - */ - __evt__startselecting: function () { }, + if (i < 0) { + return 1; + } - /** - * @event - * @description Select a region is started during a down event - * from a device sending mouse events or by calling - * {@link JXG.Board.startSelectionMode}. - * @name JXG.Board#mousestartselecting - */ - __evt__mousestartselecting: function () { }, + // The curve points are transformed (if there is a transformation) + // c.X(i) is not transformed. + if (c.bezierDegree === 1) { + p1 = c.points[i].usrCoords; + p2 = c.points[i + 1].usrCoords; + } else { + A = c.points[i].usrCoords; + B = c.points[i + 1].usrCoords; + C = c.points[i + 2].usrCoords; + D = c.points[i + 3].usrCoords; + dx = (1 - t) * (1 - t) * (B[1] - A[1]) + 2 * (1 - t) * t * (C[1] - B[1]) + t * t * (D[1]- C[1]); + dy = (1 - t) * (1 - t) * (B[2] - A[2]) + 2 * (1 - t) * t * (C[2] - B[2]) + t * t * (D[2]- C[2]); + d = Math.sqrt(dx * dx + dy * dy); + dx /= d; + dy /= d; + p1 = p.coords.usrCoords; + p2 = [1, p1[1] + dx, p1[2] + dy]; + } + return p1[2] * p2[1] - p1[1] * p2[2]; + }, + function () { + var i = Math.floor(p.position), + p1, p2, t, A, B, C, D, dx, dy, d; - /** - * @event - * @description Select a region is started during a down event - * from a device sending pointer events or by calling - * {@link JXG.Board.startSelectionMode}. - * @name JXG.Board#pointerstartselecting - */ - __evt__pointerstartselecting: function () { }, + if (c.bezierDegree === 1) { + if (i === c.numberPoints - 1) { + i--; + } + } else if (c.bezierDegree === 3) { + // i is start of the Bezier segment + // t is the position in the Bezier segment + i = Math.floor(p.position * (c.numberPoints - 1) / 3) * 3; + t = (p.position * (c.numberPoints - 1) - i) / 3; + if (i >= c.numberPoints - 1) { + i = c.numberPoints - 4; + t = 1; + } + } else { + return 0; + } - /** - * @event - * @description Select a region is started during a down event - * from a device sending touch events or by calling - * {@link JXG.Board.startSelectionMode}. - * @name JXG.Board#touchstartselecting - */ - __evt__touchstartselecting: function () { }, + if (i < 0) { + return 0; + } - /** - * @event - * @description Selection of a region is stopped during an up event. - * @name JXG.Board#stopselecting - */ - __evt__stopselecting: function () { }, + // The curve points are transformed (if there is a transformation) + // c.X(i) is not transformed. + if (c.bezierDegree === 1) { + p1 = c.points[i].usrCoords; + p2 = c.points[i + 1].usrCoords; + } else { + A = c.points[i].usrCoords; + B = c.points[i + 1].usrCoords; + C = c.points[i + 2].usrCoords; + D = c.points[i + 3].usrCoords; + dx = (1 - t) * (1 - t) * (B[1] - A[1]) + 2 * (1 - t) * t * (C[1] - B[1]) + t * t * (D[1]- C[1]); + dy = (1 - t) * (1 - t) * (B[2] - A[2]) + 2 * (1 - t) * t * (C[2] - B[2]) + t * t * (D[2]- C[2]); + d = Math.sqrt(dx * dx + dy * dy); + dx /= d; + dy /= d; + p1 = p.coords.usrCoords; + p2 = [1, p1[1] + dx, p1[2] + dy]; + } + return p2[2] - p1[2]; + }, + function () { + var i = Math.floor(p.position), + p1, p2, t, A, B, C, D, dx, dy, d; - /** - * @event - * @description Selection of a region is stopped during an up event - * from a device sending mouse events. - * @name JXG.Board#mousestopselecting - */ - __evt__mousestopselecting: function () { }, + if (c.bezierDegree === 1) { + if (i === c.numberPoints - 1) { + i--; + } + } else if (c.bezierDegree === 3) { + // i is start of the Bezier segment + // t is the position in the Bezier segment + i = Math.floor(p.position * (c.numberPoints - 1) / 3) * 3; + t = (p.position * (c.numberPoints - 1) - i) / 3; + if (i >= c.numberPoints - 1) { + i = c.numberPoints - 4; + t = 1; + } + } else { + return 0; + } - /** - * @event - * @description Selection of a region is stopped during an up event - * from a device sending pointer events. - * @name JXG.Board#pointerstopselecting - */ - __evt__pointerstopselecting: function () { }, + if (i < 0) { + return 0.0; + } - /** - * @event - * @description Selection of a region is stopped during an up event - * from a device sending touch events. - * @name JXG.Board#touchstopselecting - */ - __evt__touchstopselecting: function () { }, + // The curve points are transformed (if there is a transformation) + // c.X(i) is not transformed. + if (c.bezierDegree === 1) { + p1 = c.points[i].usrCoords; + p2 = c.points[i + 1].usrCoords; + } else { + A = c.points[i].usrCoords; + B = c.points[i + 1].usrCoords; + C = c.points[i + 2].usrCoords; + D = c.points[i + 3].usrCoords; + dx = (1 - t) * (1 - t) * (B[1] - A[1]) + 2 * (1 - t) * t * (C[1] - B[1]) + t * t * (D[1]- C[1]); + dy = (1 - t) * (1 - t) * (B[2] - A[2]) + 2 * (1 - t) * t * (C[2] - B[2]) + t * t * (D[2]- C[2]); + d = Math.sqrt(dx * dx + dy * dy); + dx /= d; + dy /= d; + p1 = p.coords.usrCoords; + p2 = [1, p1[1] + dx, p1[2] + dy]; + } + return p1[1] - p2[1]; + }], attributes); - /** - * @event - * @description A move event while selecting of a region is active. - * @name JXG.Board#moveselecting - */ - __evt__moveselecting: function () { }, + p.addChild(tangent); + // this is required for the geogebra reader to display a slope + tangent.glider = p; + } + } else if (c.type === Const.OBJECT_TYPE_TURTLE) { + tangent = board.create('line', [ + function () { + var i = Math.floor(p.position); - /** - * @event - * @description A move event while selecting of a region is active - * from a device sending mouse events. - * @name JXG.Board#mousemoveselecting - */ - __evt__mousemoveselecting: function () { }, + // run through all curves of this turtle + for (j = 0; j < c.objects.length; j++) { + el = c.objects[j]; - /** - * @event - * @description Select a region is started during a down event - * from a device sending mouse events. - * @name JXG.Board#pointermoveselecting - */ - __evt__pointermoveselecting: function () { }, + if (el.type === Const.OBJECT_TYPE_CURVE) { + if (i < el.numberPoints) { + break; + } - /** - * @event - * @description Select a region is started during a down event - * from a device sending touch events. - * @name JXG.Board#touchmoveselecting - */ - __evt__touchmoveselecting: function () { }, + i -= el.numberPoints; + } + } - /** - * @ignore - */ - __evt: function () {}, + if (i === el.numberPoints - 1) { + i--; + } - //endregion + if (i < 0) { + return 1; + } - /** - * Expand the JSXGraph construction to fullscreen. - * In order to preserve the proportions of the JSXGraph element, - * a wrapper div is created which is set to fullscreen. - * <p> - * The wrapping div has the CSS class 'jxgbox_wrap_private' which is - * defined in the file 'jsxgraph.css' - * - * @return {JXG.Board} Reference to the board - * - * @example - * <div id='jxgbox' class='jxgbox' style='width:500px; height:200px;'></div> - * <button onClick="board.toFullscreen()">Fullscreen</button> - * - * <script language="Javascript" type='text/javascript'> - * var board = JXG.JSXGraph.initBoard('jxgbox', {axis:true, boundingbox:[-5,5,5,-5]}); - * var p = board.create('point', [0, 1]); - * </script> - * - * </pre><div id="JXGd5bab8b6-fd40-11e8-ab14-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * var board_d5bab8b6; - * (function() { - * var board = JXG.JSXGraph.initBoard('JXGd5bab8b6-fd40-11e8-ab14-901b0e1b8723', - * {boundingbox:[-5,5,5,-5], axis: true, showcopyright: false, shownavigation: false}); - * var p = board.create('point', [0, 1]); - * board_d5bab8b6 = board; - * })(); - * <button onClick="board_d5bab8b6.toFullscreen()">Fullscreen</button> - * - * </script> - * <pre> - * - */ - toFullscreen: function() { - var id = this.container, - wrap_id = 'fullscreenwrap_' + id, - wrapper = document.createElement('div'), - el; + return el.Y(i) * el.X(i + 1) - el.X(i) * el.Y(i + 1); + }, + function () { + var i = Math.floor(p.position); - // If necessary, wrap a div around the JSXGraph div. - if (!this.document.getElementById(wrap_id)) { - wrapper.classList.add('JXG_wrap_private'); - wrapper.setAttribute('id', wrap_id); - el = this.containerObj; - el.parentNode.insertBefore(wrapper, el); - wrapper.appendChild(el); - } + // run through all curves of this turtle + for (j = 0; j < c.objects.length; j++) { + el = c.objects[j]; - Env.toFullscreen(wrap_id, id); - return this; - }, + if (el.type === Const.OBJECT_TYPE_CURVE) { + if (i < el.numberPoints) { + break; + } - /** - * If fullscreen mode is toggled, the possible CSS transformations - * which are applied to the JSXGraph canvas have to be reread. - * Otherwise the position of upper left corner is wrongly interpreted. - * - * @param {Object} evt fullscreen event object - */ - fullscreenListener: function(evt) { - this.updateCSSTransforms(); - }, + i -= el.numberPoints; + } + } - /** - * Function to animate a curve rolling on another curve. - * @param {Curve} c1 JSXGraph curve building the floor where c2 rolls - * @param {Curve} c2 JSXGraph curve which rolls on c1. - * @param {number} start_c1 The parameter t such that c1(t) touches c2. This is the start position of the - * rolling process - * @param {Number} stepsize Increase in t in each step for the curve c1 - * @param {Number} direction - * @param {Number} time Delay time for setInterval() - * @param {Array} pointlist Array of points which are rolled in each step. This list should contain - * all points which define c2 and gliders on c2. - * - * @example - * - * // Line which will be the floor to roll upon. - * var line = brd.create('curve', [function (t) { return t;}, function (t){ return 1;}], {strokeWidth:6}); - * // Center of the rolling circle - * var C = brd.create('point',[0,2],{name:'C'}); - * // Starting point of the rolling circle - * var P = brd.create('point',[0,1],{name:'P', trace:true}); - * // Circle defined as a curve. The circle "starts" at P, i.e. circle(0) = P - * var circle = brd.create('curve',[ - * function (t){var d = P.Dist(C), - * beta = JXG.Math.Geometry.rad([C.X()+1,C.Y()],C,P); - * t += beta; - * return C.X()+d*Math.cos(t); - * }, - * function (t){var d = P.Dist(C), - * beta = JXG.Math.Geometry.rad([C.X()+1,C.Y()],C,P); - * t += beta; - * return C.Y()+d*Math.sin(t); - * }, - * 0,2*Math.PI], - * {strokeWidth:6, strokeColor:'green'}); - * - * // Point on circle - * var B = brd.create('glider',[0,2,circle],{name:'B', color:'blue',trace:false}); - * var roll = brd.createRoulette(line, circle, 0, Math.PI/20, 1, 100, [C,P,B]); - * roll.start() // Start the rolling, to be stopped by roll.stop() - * - * </pre><div class="jxgbox" id="JXGe5e1b53c-a036-4a46-9e35-190d196beca5" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * var brd = JXG.JSXGraph.initBoard('JXGe5e1b53c-a036-4a46-9e35-190d196beca5', {boundingbox: [-5, 5, 5, -5], axis: true, showcopyright:false, shownavigation: false}); - * // Line which will be the floor to roll upon. - * var line = brd.create('curve', [function (t) { return t;}, function (t){ return 1;}], {strokeWidth:6}); - * // Center of the rolling circle - * var C = brd.create('point',[0,2],{name:'C'}); - * // Starting point of the rolling circle - * var P = brd.create('point',[0,1],{name:'P', trace:true}); - * // Circle defined as a curve. The circle "starts" at P, i.e. circle(0) = P - * var circle = brd.create('curve',[ - * function (t){var d = P.Dist(C), - * beta = JXG.Math.Geometry.rad([C.X()+1,C.Y()],C,P); - * t += beta; - * return C.X()+d*Math.cos(t); - * }, - * function (t){var d = P.Dist(C), - * beta = JXG.Math.Geometry.rad([C.X()+1,C.Y()],C,P); - * t += beta; - * return C.Y()+d*Math.sin(t); - * }, - * 0,2*Math.PI], - * {strokeWidth:6, strokeColor:'green'}); - * - * // Point on circle - * var B = brd.create('glider',[0,2,circle],{name:'B', color:'blue',trace:false}); - * var roll = brd.createRoulette(line, circle, 0, Math.PI/20, 1, 100, [C,P,B]); - * roll.start() // Start the rolling, to be stopped by roll.stop() - * </script><pre> - */ - createRoulette: function (c1, c2, start_c1, stepsize, direction, time, pointlist) { - var brd = this, - Roulette = function () { - var alpha = 0, Tx = 0, Ty = 0, - t1 = start_c1, - t2 = Numerics.root( - function (t) { - var c1x = c1.X(t1), - c1y = c1.Y(t1), - c2x = c2.X(t), - c2y = c2.Y(t); + if (i === el.numberPoints - 1) { + i--; + } + if (i < 0) { + return 0; + } - return (c1x - c2x) * (c1x - c2x) + (c1y - c2y) * (c1y - c2y); - }, - [0, Math.PI * 2] - ), - t1_new = 0.0, t2_new = 0.0, - c1dist, + return el.Y(i + 1) - el.Y(i); + }, + function () { + var i = Math.floor(p.position); - rotation = brd.create('transform', [ - function () { - return alpha; + // run through all curves of this turtle + for (j = 0; j < c.objects.length; j++) { + el = c.objects[j]; + if (el.type === Const.OBJECT_TYPE_CURVE) { + if (i < el.numberPoints) { + break; } - ], {type: 'rotate'}), + i -= el.numberPoints; + } + } + if (i === el.numberPoints - 1) { + i--; + } - rotationLocal = brd.create('transform', [ - function () { - return alpha; - }, - function () { - return c1.X(t1); - }, - function () { - return c1.Y(t1); - } - ], {type: 'rotate'}), + if (i < 0) { + return 0; + } - translate = brd.create('transform', [ - function () { - return Tx; - }, - function () { - return Ty; - } - ], {type: 'translate'}), + return el.X(i) - el.X(i + 1); + }], attributes); + p.addChild(tangent); - // arc length via Simpson's rule. - arclen = function (c, a, b) { - var cpxa = Numerics.D(c.X)(a), - cpya = Numerics.D(c.Y)(a), - cpxb = Numerics.D(c.X)(b), - cpyb = Numerics.D(c.Y)(b), - cpxab = Numerics.D(c.X)((a + b) * 0.5), - cpyab = Numerics.D(c.Y)((a + b) * 0.5), + // this is required for the geogebra reader to display a slope + tangent.glider = p; + } else if (c.elementClass === Const.OBJECT_CLASS_CIRCLE || c.type === Const.OBJECT_TYPE_CONIC) { + // If p is not on c, the tangent is the polar. + // This construction should work on conics, too. p has to lie on c. + tangent = board.create('line', [ + function () { + return Mat.matVecMult(c.quadraticform, p.coords.usrCoords)[0]; + }, + function () { + return Mat.matVecMult(c.quadraticform, p.coords.usrCoords)[1]; + }, + function () { + return Mat.matVecMult(c.quadraticform, p.coords.usrCoords)[2]; + }], attributes); - fa = Math.sqrt(cpxa * cpxa + cpya * cpya), - fb = Math.sqrt(cpxb * cpxb + cpyb * cpyb), - fab = Math.sqrt(cpxab * cpxab + cpyab * cpyab); + p.addChild(tangent); + // this is required for the geogebra reader to display a slope + tangent.glider = p; + } - return (fa + 4 * fab + fb) * (b - a) / 6; - }, + if (!Type.exists(tangent)) { + throw new Error('JSXGraph: Couldn\'t create tangent with the given parents.'); + } - exactDist = function (t) { - return c1dist - arclen(c2, t2, t); - }, + tangent.elType = 'tangent'; + tangent.type = Const.OBJECT_TYPE_TANGENT; + tangent.setParents(parents); - beta = Math.PI / 18, - beta9 = beta * 9, - interval = null; + return tangent; + }; - this.rolling = function () { - var h, g, hp, gp, z; + /** + * @class This element is used to provide a constructor for the radical axis with respect to two circles with distinct centers. + * The angular bisector of the polar lines of the circle centers with respect to the other circle is always the radical axis. + * The radical axis passes through the intersection points when the circles intersect. + * When a circle about the midpoint of circle centers, passing through the circle centers, intersects the circles, the polar lines pass through those intersection points. + * @pseudo + * @description + * @name RadicalAxis + * @augments JXG.Line + * @constructor + * @type JXG.Line + * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {JXG.Circle} circle Circle one of the two respective circles. + * @param {JXG.Circle} circle Circle the other of the two respective circles. + * @example + * // Create the radical axis line with respect to two circles + * var board = JXG.JSXGraph.initBoard('7b7233a0-f363-47dd-9df5-5018d0d17a98', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); + * var p1 = board.create('point', [2, 3]); + * var p2 = board.create('point', [1, 4]); + * var c1 = board.create('circle', [p1, p2]); + * var p3 = board.create('point', [6, 5]); + * var p4 = board.create('point', [8, 6]); + * var c2 = board.create('circle', [p3, p4]); + * var r1 = board.create('radicalaxis', [c1, c2]); + * </pre><div class="jxgbox" id="JXG7b7233a0-f363-47dd-9df5-5018d0d17a98" class="jxgbox" style="width:400px; height:400px;"></div> + * <script type='text/javascript'> + * var rlex1_board = JXG.JSXGraph.initBoard('JXG7b7233a0-f363-47dd-9df5-5018d0d17a98', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); + * var rlex1_p1 = rlex1_board.create('point', [2, 3]); + * var rlex1_p2 = rlex1_board.create('point', [1, 4]); + * var rlex1_c1 = rlex1_board.create('circle', [rlex1_p1, rlex1_p2]); + * var rlex1_p3 = rlex1_board.create('point', [6, 5]); + * var rlex1_p4 = rlex1_board.create('point', [8, 6]); + * var rlex1_c2 = rlex1_board.create('circle', [rlex1_p3, rlex1_p4]); + * var rlex1_r1 = rlex1_board.create('radicalaxis', [rlex1_c1, rlex1_c2]); + * </script><pre> + */ + JXG.createRadicalAxis = function (board, parents, attributes) { + var el, el1, el2; - t1_new = t1 + direction * stepsize; + if (parents.length !== 2 || + parents[0].elementClass !== Const.OBJECT_CLASS_CIRCLE || + parents[1].elementClass !== Const.OBJECT_CLASS_CIRCLE) { + // Failure + throw new Error("JSXGraph: Can't create 'radical axis' with parent types '" + + (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + + "\nPossible parent type: [circle,circle]"); + } - // arc length between c1(t1) and c1(t1_new) - c1dist = arclen(c1, t1, t1_new); + el1 = board.select(parents[0]); + el2 = board.select(parents[1]); - // find t2_new such that arc length between c2(t2) and c1(t2_new) equals c1dist. - t2_new = Numerics.root(exactDist, t2); + el = board.create('line', [function () { + var a = el1.stdform, + b = el2.stdform; - // c1(t) as complex number - h = new Complex(c1.X(t1_new), c1.Y(t1_new)); + return Mat.matVecMult(Mat.transpose([a.slice(0, 3), b.slice(0, 3)]), [b[3], -a[3]]); + }], attributes); - // c2(t) as complex number - g = new Complex(c2.X(t2_new), c2.Y(t2_new)); + el.elType = 'radicalaxis'; + el.setParents([el1.id, el2.id]); - hp = new Complex(Numerics.D(c1.X)(t1_new), Numerics.D(c1.Y)(t1_new)); - gp = new Complex(Numerics.D(c2.X)(t2_new), Numerics.D(c2.Y)(t2_new)); + el1.addChild(el); + el2.addChild(el); - // z is angle between the tangents of c1 at t1_new, and c2 at t2_new - z = Complex.C.div(hp, gp); + return el; + }; - alpha = Math.atan2(z.imaginary, z.real); - // Normalizing the quotient - z.div(Complex.C.abs(z)); - z.mult(g); - Tx = h.real - z.real; + /** + * @class This element is used to provide a constructor for the polar line of a point with respect to a conic or a circle. + * @pseudo + * @description The polar line is the unique reciprocal relationship of a point with respect to a conic. + * The lines through the intersections of a conic and the polar line of a point with respect to that conic and through that point are tangent to the conic. + * A point on a conic has the polar line of that point with respect to that conic as the tangent line to that conic at that point. + * See {@link http://en.wikipedia.org/wiki/Pole_and_polar} for more information on pole and polar. + * @name PolarLine + * @augments JXG.Line + * @constructor + * @type JXG.Line + * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {JXG.Conic,JXG.Circle_JXG.Point} el1,el2 or + * @param {JXG.Point_JXG.Conic,JXG.Circle} el1,el2 The result will be the polar line of the point with respect to the conic or the circle. + * @example + * // Create the polar line of a point with respect to a conic + * var p1 = board.create('point', [-1, 2]); + * var p2 = board.create('point', [ 1, 4]); + * var p3 = board.create('point', [-1,-2]); + * var p4 = board.create('point', [ 0, 0]); + * var p5 = board.create('point', [ 4,-2]); + * var c1 = board.create('conic',[p1,p2,p3,p4,p5]); + * var p6 = board.create('point', [-1, 1]); + * var l1 = board.create('polarline', [c1, p6]); + * </pre><div class="jxgbox" id="JXG7b7233a0-f363-47dd-9df5-6018d0d17a98" class="jxgbox" style="width:400px; height:400px;"></div> + * <script type='text/javascript'> + * var plex1_board = JXG.JSXGraph.initBoard('JXG7b7233a0-f363-47dd-9df5-6018d0d17a98', {boundingbox: [-3, 5, 5, -3], axis: true, showcopyright: false, shownavigation: false}); + * var plex1_p1 = plex1_board.create('point', [-1, 2]); + * var plex1_p2 = plex1_board.create('point', [ 1, 4]); + * var plex1_p3 = plex1_board.create('point', [-1,-2]); + * var plex1_p4 = plex1_board.create('point', [ 0, 0]); + * var plex1_p5 = plex1_board.create('point', [ 4,-2]); + * var plex1_c1 = plex1_board.create('conic',[plex1_p1,plex1_p2,plex1_p3,plex1_p4,plex1_p5]); + * var plex1_p6 = plex1_board.create('point', [-1, 1]); + * var plex1_l1 = plex1_board.create('polarline', [plex1_c1, plex1_p6]); + * </script><pre> + * @example + * // Create the polar line of a point with respect to a circle. + * var p1 = board.create('point', [ 1, 1]); + * var p2 = board.create('point', [ 2, 3]); + * var c1 = board.create('circle',[p1,p2]); + * var p3 = board.create('point', [ 6, 6]); + * var l1 = board.create('polarline', [c1, p3]); + * </pre><div class="jxgbox" id="JXG7b7233a0-f363-47dd-9df5-7018d0d17a98" class="jxgbox" style="width:400px; height:400px;"></div> + * <script type='text/javascript'> + * var plex2_board = JXG.JSXGraph.initBoard('JXG7b7233a0-f363-47dd-9df5-7018d0d17a98', {boundingbox: [-3, 7, 7, -3], axis: true, showcopyright: false, shownavigation: false}); + * var plex2_p1 = plex2_board.create('point', [ 1, 1]); + * var plex2_p2 = plex2_board.create('point', [ 2, 3]); + * var plex2_c1 = plex2_board.create('circle',[plex2_p1,plex2_p2]); + * var plex2_p3 = plex2_board.create('point', [ 6, 6]); + * var plex2_l1 = plex2_board.create('polarline', [plex2_c1, plex2_p3]); + * </script><pre> + */ + JXG.createPolarLine = function (board, parents, attributes) { + var el, el1, el2, + firstParentIsConic, secondParentIsConic, + firstParentIsPoint, secondParentIsPoint; - // T = h(t1_new)-g(t2_new)*h'(t1_new)/g'(t2_new); - Ty = h.imaginary - z.imaginary; + if (parents.length > 1) { + firstParentIsConic = (parents[0].type === Const.OBJECT_TYPE_CONIC || + parents[0].elementClass === Const.OBJECT_CLASS_CIRCLE); + secondParentIsConic = (parents[1].type === Const.OBJECT_TYPE_CONIC || + parents[1].elementClass === Const.OBJECT_CLASS_CIRCLE); - // -(10-90) degrees: make corners roll smoothly - if (alpha < -beta && alpha > -beta9) { - alpha = -beta; - rotationLocal.applyOnce(pointlist); - } else if (alpha > beta && alpha < beta9) { - alpha = beta; - rotationLocal.applyOnce(pointlist); - } else { - rotation.applyOnce(pointlist); - translate.applyOnce(pointlist); - t1 = t1_new; - t2 = t2_new; - } - brd.update(); - }; + firstParentIsPoint = (Type.isPoint(parents[0])); + secondParentIsPoint = (Type.isPoint(parents[1])); + } - this.start = function () { - if (time > 0) { - interval = window.setInterval(this.rolling, time); - } - return this; - }; + if (parents.length !== 2 || + !((firstParentIsConic && secondParentIsPoint) || + (firstParentIsPoint && secondParentIsConic))) { + // Failure + throw new Error("JSXGraph: Can't create 'polar line' with parent types '" + + (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + + "\nPossible parent type: [conic|circle,point], [point,conic|circle]"); + } - this.stop = function () { - window.clearInterval(interval); - return this; - }; - return this; - }; - return new Roulette(); + if (secondParentIsPoint) { + el1 = board.select(parents[0]); + el2 = board.select(parents[1]); + } else { + el1 = board.select(parents[1]); + el2 = board.select(parents[0]); } - }); - return JXG.Board; + // Polar lines have been already provided in the tangent element. + el = board.create('tangent', [el1, el2], attributes); + + el.elType = 'polarline'; + return el; + }; + + /** + * Register the element type tangent at JSXGraph + * @private + */ + JXG.registerElement('tangent', JXG.createTangent); + JXG.registerElement('polar', JXG.createTangent); + JXG.registerElement('radicalaxis', JXG.createRadicalAxis); + JXG.registerElement('polarline', JXG.createPolarLine); + + return { + Line: JXG.Line, + createLine: JXG.createLine, + createTangent: JXG.createTangent, + createPolar: JXG.createTangent, + createSegment: JXG.createSegment, + createAxis: JXG.createAxis, + createArrow: JXG.createArrow, + createRadicalAxis: JXG.createRadicalAxis, + createPolarLine: JXG.createPolarLine + }; }); /* - Copyright 2008-2021 + Copyright 2008-2022 Matthias Ehmann, Michael Gerhaeuser, Carsten Miller, @@ -56132,2879 +58500,9891 @@ define('base/board',[ and <http://opensource.org/licenses/MIT/>. */ -/*global JXG: true, define: true, AMprocessNode: true, MathJax: true, document: true */ -/*jslint nomen: true, plusplus: true, newcap:true*/ + +/*global JXG: true, define: true*/ +/*jslint nomen: true, plusplus: true*/ /* depends: jxg - options - renderer/abstract base/constants utils/type - utils/env - utils/color - math/numerics -*/ + */ -define('renderer/svg',[ - 'jxg', 'options', 'renderer/abstract', 'base/constants', 'utils/type', 'utils/color', 'utils/base64', 'math/numerics' -], function (JXG, Options, AbstractRenderer, Const, Type, Color, Base64, Numerics) { +/** + * @fileoverview In this file the class Group is defined, a class for + * managing grouping of points. + */ + +define('base/group',[ + 'jxg', 'base/constants', 'math/math', 'math/geometry', 'utils/type' +], function (JXG, Const, Mat, Geometry, Type) { "use strict"; /** - * Uses SVG to implement the rendering methods defined in {@link JXG.AbstractRenderer}. - * @class JXG.AbstractRenderer - * @augments JXG.AbstractRenderer - * @param {Node} container Reference to a DOM node containing the board. - * @param {Object} dim The dimensions of the board - * @param {Number} dim.width - * @param {Number} dim.height - * @see JXG.AbstractRenderer + * Creates a new instance of Group. + * @class In this class all group management is done. + * @param {JXG.Board} board + * @param {String} id Unique identifier for this object. If null or an empty string is given, + * an unique id will be generated by Board + * @param {String} name Not necessarily unique name, displayed on the board. If null or an + * empty string is given, an unique name will be generated. + * @param {Array} objects Array of points to add to this group. + * @param {Object} attributes Defines the visual appearance of the group. + * @constructor */ - JXG.SVGRenderer = function (container, dim) { - var i; + JXG.Group = function (board, id, name, objects, attributes) { + var number, objArray, i, obj; - // docstring in AbstractRenderer - this.type = 'svg'; + this.board = board; + this.objects = {}; + number = this.board.numObjects; + this.board.numObjects += 1; - this.isIE = navigator.appVersion.indexOf("MSIE") !== -1 || navigator.userAgent.match(/Trident\//); + if ((id === '') || !Type.exists(id)) { + this.id = this.board.id + 'Group' + number; + } else { + this.id = id; + } + this.board.groups[this.id] = this; - /** - * SVG root node - * @type Node - */ - this.svgRoot = null; + this.type = Const.OBJECT_TYPE_POINT; + this.elementClass = Const.OBJECT_CLASS_POINT; - /** - * The SVG Namespace used in JSXGraph. - * @see http://www.w3.org/TR/SVG/ - * @type String - * @default http://www.w3.org/2000/svg - */ - this.svgNamespace = 'http://www.w3.org/2000/svg'; + if ((name === '') || !Type.exists(name)) { + this.name = 'group_' + this.board.generateName(this); + } else { + this.name = name; + } + delete this.type; /** - * The xlink namespace. This is used for images. - * @see http://www.w3.org/TR/xlink/ - * @type String - * @default http://www.w3.org/1999/xlink + * Cache coordinates of points. From this and the actual position + * of the points, the translation is determined. + * It has to be kept updated in this class "by hand"- + * + * @private + * @type Object + * @see JXG.Group#_updateCoordsCache */ - this.xlinkNamespace = 'http://www.w3.org/1999/xlink'; + this.coords = {}; + this.needsRegularUpdate = attributes.needsregularupdate; - // container is documented in AbstractRenderer - this.container = container; + this.rotationCenter = 'centroid'; + this.scaleCenter = null; + this.rotationPoints = []; + this.translationPoints = []; + this.scalePoints = []; + this.scaleDirections = {}; - // prepare the div container and the svg root node for use with JSXGraph - this.container.style.MozUserSelect = 'none'; - this.container.style.userSelect = 'none'; + this.parents = []; - this.container.style.overflow = 'hidden'; - if (this.container.style.position === '') { - this.container.style.position = 'relative'; + if (Type.isArray(objects)) { + objArray = objects; + } else { + objArray = Array.prototype.slice.call(arguments, 3); } - this.svgRoot = this.container.ownerDocument.createElementNS(this.svgNamespace, "svg"); - this.svgRoot.style.overflow = 'hidden'; - - this.resize(dim.width, dim.height); + for (i = 0; i < objArray.length; i++) { + obj = this.board.select(objArray[i]); - //this.svgRoot.setAttributeNS(null, 'shape-rendering', 'crispEdge'); //'optimizeQuality'); //geometricPrecision'); + if ((!Type.evaluate(obj.visProp.fixed)) && Type.exists(obj.coords)) { + this.addPoint(obj); + } + } - this.container.appendChild(this.svgRoot); + this.methodMap = { + ungroup: 'ungroup', + add: 'addPoint', + addPoint: 'addPoint', + addPoints: 'addPoints', + addGroup: 'addGroup', + remove: 'removePoint', + removePoint: 'removePoint', + setAttribute: 'setAttribute', + setProperty: 'setAttribute' + }; + }; + JXG.extend(JXG.Group.prototype, /** @lends JXG.Group.prototype */ { /** - * The <tt>defs</tt> element is a container element to reference reusable SVG elements. - * @type Node - * @see http://www.w3.org/TR/SVG/struct.html#DefsElement + * Releases all elements of this group. + * @returns {JXG.Group} returns this (empty) group */ - this.defs = this.container.ownerDocument.createElementNS(this.svgNamespace, 'defs'); - this.svgRoot.appendChild(this.defs); + ungroup: function () { + var el, p, i; + for (el in this.objects) { + if (this.objects.hasOwnProperty(el)) { + p = this.objects[el].point; + if (Type.isArray(p.groups)) { + i = Type.indexOf(p.groups, this.id); + if (i >= 0) { + delete p.groups[i]; + } + } + } + } + + this.objects = {}; + return this; + }, /** - * Filters are used to apply shadows. - * @type Node - * @see http://www.w3.org/TR/SVG/filters.html#FilterElement - */ - this.filter = this.container.ownerDocument.createElementNS(this.svgNamespace, 'filter'); - this.filter.setAttributeNS(null, 'id', this.container.id + '_' + 'f1'); - /* - this.filter.setAttributeNS(null, 'x', '-100%'); - this.filter.setAttributeNS(null, 'y', '-100%'); - this.filter.setAttributeNS(null, 'width', '400%'); - this.filter.setAttributeNS(null, 'height', '400%'); - //this.filter.setAttributeNS(null, 'filterUnits', 'userSpaceOnUse'); - */ - this.filter.setAttributeNS(null, 'width', '300%'); - this.filter.setAttributeNS(null, 'height', '300%'); - this.filter.setAttributeNS(null, 'filterUnits', 'userSpaceOnUse'); + * Adds ids of elements to the array this.parents. This is a copy + * of {@link Element.addParents}. + * @param {Array} parents Array of elements or ids of elements. + * Alternatively, one can give a list of objects as parameters. + * @returns {JXG.Object} reference to the object itself. + **/ + addParents: function (parents) { + var i, len, par; - this.feOffset = this.container.ownerDocument.createElementNS(this.svgNamespace, 'feOffset'); - this.feOffset.setAttributeNS(null, 'result', 'offOut'); - this.feOffset.setAttributeNS(null, 'in', 'SourceAlpha'); - this.feOffset.setAttributeNS(null, 'dx', '5'); - this.feOffset.setAttributeNS(null, 'dy', '5'); - this.filter.appendChild(this.feOffset); + if (Type.isArray(parents)) { + par = parents; + } else { + par = arguments; + } - this.feGaussianBlur = this.container.ownerDocument.createElementNS(this.svgNamespace, 'feGaussianBlur'); - this.feGaussianBlur.setAttributeNS(null, 'result', 'blurOut'); - this.feGaussianBlur.setAttributeNS(null, 'in', 'offOut'); - this.feGaussianBlur.setAttributeNS(null, 'stdDeviation', '3'); - this.filter.appendChild(this.feGaussianBlur); + len = par.length; + for (i = 0; i < len; ++i) { + if (Type.isId(this.board, par[i])) { + this.parents.push(par[i]); + } else if (Type.exists(par[i].id)) { + this.parents.push(par[i].id); + } + } - this.feBlend = this.container.ownerDocument.createElementNS(this.svgNamespace, 'feBlend'); - this.feBlend.setAttributeNS(null, 'in', 'SourceGraphic'); - this.feBlend.setAttributeNS(null, 'in2', 'blurOut'); - this.feBlend.setAttributeNS(null, 'mode', 'normal'); - this.filter.appendChild(this.feBlend); + this.parents = Type.uniqueArray(this.parents); + }, - this.defs.appendChild(this.filter); + /** + * Sets ids of elements to the array this.parents. This is a copy + * of {@link Element.setParents} + * First, this.parents is cleared. See {@link Group#addParents}. + * @param {Array} parents Array of elements or ids of elements. + * Alternatively, one can give a list of objects as parameters. + * @returns {JXG.Object} reference to the object itself. + **/ + setParents: function(parents) { + this.parents = []; + this.addParents(parents); + return this; + }, /** - * JSXGraph uses a layer system to sort the elements on the board. This puts certain types of elements in front - * of other types of elements. For the order used see {@link JXG.Options.layer}. The number of layers is documented - * there, too. The higher the number, the "more on top" are the elements on this layer. - * @type Array + * List of the element ids resp. values used as parents in {@link JXG.Board#create}. + * @returns {Array} */ - this.layer = []; - for (i = 0; i < Options.layer.numlayers; i++) { - this.layer[i] = this.container.ownerDocument.createElementNS(this.svgNamespace, 'g'); - this.svgRoot.appendChild(this.layer[i]); - } - - // already documented in JXG.AbstractRenderer - this.supportsForeignObject = document.implementation.hasFeature("http://w3.org/TR/SVG11/feature#Extensibility", "1.1"); - - if (this.supportsForeignObject) { - this.foreignObjLayer = this.container.ownerDocument.createElementNS(this.svgNamespace, 'foreignObject'); - this.foreignObjLayer.setAttribute("x", 0); - this.foreignObjLayer.setAttribute("y", 0); - this.foreignObjLayer.setAttribute("width", "100%"); - this.foreignObjLayer.setAttribute("height", "100%"); - this.foreignObjLayer.setAttribute('id', this.container.id + '_foreignObj'); - this.svgRoot.appendChild(this.foreignObjLayer); - } + getParents: function () { + return Type.isArray(this.parents) ? this.parents : []; + }, /** - * Defines dash patterns. Defined styles are: <ol> - * <li value="-1"> 2px dash, 2px space</li> - * <li> 5px dash, 5px space</li> - * <li> 10px dash, 10px space</li> - * <li> 20px dash, 20px space</li> - * <li> 20px dash, 10px space, 10px dash, 10px dash</li> - * <li> 20px dash, 5px space, 10px dash, 5px space</li></ol> - * @type Array - * @default ['2, 2', '5, 5', '10, 10', '20, 20', '20, 10, 10, 10', '20, 5, 10, 5'] - * @see http://www.w3.org/TR/SVG/painting.html#StrokeProperties + * Update the cached coordinates of a group element. + * @param {String} el element id of the group element whose cached coordinates + * are going to be updated. + * @return null */ - this.dashArray = ['2, 2', '5, 5', '10, 10', '20, 20', '20, 10, 10, 10', '20, 5, 10, 5']; - }; - - JXG.SVGRenderer.prototype = new AbstractRenderer(); - - JXG.extend(JXG.SVGRenderer.prototype, /** @lends JXG.SVGRenderer.prototype */ { + _updateCoordsCache: function(el) { + var obj; + if (el !== "" && Type.exists(this.objects[el])) { + obj = this.objects[el].point; + this.coords[obj.id] = {usrCoords: obj.coords.usrCoords.slice(0)}; + } + }, /** - * Creates an arrow DOM node. Arrows are displayed in SVG with a <em>marker</em> tag. - * @private - * @param {JXG.GeometryElement} el A JSXGraph element, preferably one that can have an arrow attached. - * @param {String} [idAppendix=''] A string that is added to the node's id. - * @returns {Node} Reference to the node added to the DOM. + * Sends an update to all group members. + * This method is called from the points' coords object event listeners + * and not by the board. + * @returns {JXG.Group} returns this group */ - _createArrowHead: function (el, idAppendix) { - var node2, node3, - id = el.id + 'Triangle', - type = null, - v, h, - ev_fa = Type.evaluate(el.visProp.firstarrow), - ev_la = Type.evaluate(el.visProp.lastarrow); + update: function () { + var drag, el, actionCenter, desc, s, sx, sy, alpha, t, center, obj = null; - if (Type.exists(idAppendix)) { - id += idAppendix; + if (!this.needsUpdate) { + return this; } - node2 = this.createPrim('marker', id); - - node2.setAttributeNS(null, 'stroke', Type.evaluate(el.visProp.strokecolor)); - node2.setAttributeNS(null, 'stroke-opacity', Type.evaluate(el.visProp.strokeopacity)); - node2.setAttributeNS(null, 'fill', Type.evaluate(el.visProp.strokecolor)); - node2.setAttributeNS(null, 'fill-opacity', Type.evaluate(el.visProp.strokeopacity)); - node2.setAttributeNS(null, 'stroke-width', 0); // this is the stroke-width of the arrow head. - // Should be zero to simplify the calculations - - node2.setAttributeNS(null, 'orient', 'auto'); - node2.setAttributeNS(null, 'markerUnits', 'strokeWidth'); // 'strokeWidth' 'userSpaceOnUse'); - - /* - Types 1, 2: - The arrow head is an isosceles triangle with base length 10 and height 10. - - Type 3: - A rectangle - - Types 4, 5, 6: - Defined by Bezier curves from mp_arrowheads.html - In any case but type 3 the arrow head is 10 units long, - type 3 is 10 unitsb high. - These 10 units are scaled to strokeWidth * arrowSize pixels, see - this._setArrowWidth(). + drag = this._update_find_drag_type(); + if (drag.action === 'nothing') { + this._updateCoordsCache(drag.id); + return this; + } - See also abstractRenderer.updateLine() where the line path is shortened accordingly. + obj = this.objects[drag.id].point; - Changes here are also necessary in setArrowWidth(). + // Prepare translation, scaling or rotation + if (drag.action === 'translation') { + t = [ + obj.coords.usrCoords[1] - this.coords[drag.id].usrCoords[1], + obj.coords.usrCoords[2] - this.coords[drag.id].usrCoords[2] + ]; - So far, lines with arrow heads are shortenend to avoid overlapping of - arrow head and line. This is not the case for curves, yet. - Therefore, the offset refX has to be adapted to the path type. - */ - node3 = this.container.ownerDocument.createElementNS(this.svgNamespace, 'path'); - h = 5; - if (idAppendix === 'End') { - // First arrow - if (JXG.exists(ev_fa.type)) { - type = Type.evaluate(ev_fa.type); + } else if (drag.action === 'rotation' || drag.action === 'scaling') { + if (drag.action === 'rotation') { + actionCenter = 'rotationCenter'; + } else { + actionCenter = 'scaleCenter'; } - v = 0; - if (type === 2) { - node3.setAttributeNS(null, 'd', 'M 10,0 L 0,5 L 10,10 L 5,5 z'); - } else if (type === 3) { - node3.setAttributeNS(null, 'd', 'M 0,0 L 3.33,0 L 3.33,10 L 0,10 z'); - } else if (type === 4) { - // insetRatio:0.8 tipAngle:45 wingCurve:15 tailCurve:0 - h = 3.31; - node3.setAttributeNS(null, 'd', 'M 0.00,3.31 C 3.53,3.84 7.13,4.50 10.00,6.63 C 9.33,5.52 8.67,4.42 8.00,3.31 C 8.67,2.21 9.33,1.10 10.00,0.00 C 7.13,2.13 3.53,2.79 0.00,3.31'); - } else if (type === 5) { - // insetRatio:0.9 tipAngle:40 wingCurve:5 tailCurve:15 - h = 3.28; - node3.setAttributeNS(null, 'd', 'M 0.00,3.28 C 3.39,4.19 6.81,5.07 10.00,6.55 C 9.38,5.56 9.00,4.44 9.00,3.28 C 9.00,2.11 9.38,0.99 10.00,0.00 C 6.81,1.49 3.39,2.37 0.00,3.28'); - } else if (type === 6) { - // insetRatio:0.9 tipAngle:35 wingCurve:5 tailCurve:0 - h = 2.84; - node3.setAttributeNS(null, 'd', 'M 0.00,2.84 C 3.39,3.59 6.79,4.35 10.00,5.68 C 9.67,4.73 9.33,3.78 9.00,2.84 C 9.33,1.89 9.67,0.95 10.00,0.00 C 6.79,1.33 3.39,2.09 0.00,2.84'); + if (Type.isPoint(this[actionCenter])) { + center = this[actionCenter].coords.usrCoords.slice(1); + } else if (this[actionCenter] === 'centroid') { + center = this._update_centroid_center(); + } else if (Type.isArray(this[actionCenter])) { + center = this[actionCenter]; + } else if (Type.isFunction(this[actionCenter])) { + center = this[actionCenter](); } else { - // type == 1 or > 6 - node3.setAttributeNS(null, 'd', 'M 10,0 L 0,5 L 10,10 z'); + return this; } - if (/*!Type.exists(el.rendNode.getTotalLength) && */el.elementClass === Const.OBJECT_CLASS_LINE) { - if (type === 2) { - v = 4.9; - } else if (type === 3) { - v = 3.3; - } else if (type === 4 || type === 5 || type === 6) { - v = 6.66; - } else { - v = 10.0; + + if (drag.action === 'rotation') { + alpha = Geometry.rad(this.coords[drag.id].usrCoords.slice(1), center, this.objects[drag.id].point); + t = this.board.create('transform', [alpha, center[0], center[1]], {type: 'rotate'}); + t.update(); // This initializes t.matrix, which is needed if the action element is the first group element. + } else if (drag.action === 'scaling') { + s = Geometry.distance(this.coords[drag.id].usrCoords.slice(1), center); + if (Math.abs(s) < Mat.eps) { + return this; } - } - } else { - // Last arrow - if (JXG.exists(ev_la.type)) { - type = Type.evaluate(ev_la.type); - } + s = Geometry.distance(obj.coords.usrCoords.slice(1), center) / s; + sx = (this.scaleDirections[drag.id].indexOf('x') >= 0) ? s : 1.0; + sy = (this.scaleDirections[drag.id].indexOf('y') >= 0) ? s : 1.0; - v = 10.0; - if (type === 2) { - node3.setAttributeNS(null, 'd', 'M 0,0 L 10,5 L 0,10 L 5,5 z'); - } else if (type === 3) { - v = 3.3; - node3.setAttributeNS(null, 'd', 'M 0,0 L 3.33,0 L 3.33,10 L 0,10 z'); - } else if (type === 4) { - // insetRatio:0.8 tipAngle:45 wingCurve:15 tailCurve:0 - h = 3.31; - node3.setAttributeNS(null, 'd', 'M 10.00,3.31 C 6.47,3.84 2.87,4.50 0.00,6.63 C 0.67,5.52 1.33,4.42 2.00,3.31 C 1.33,2.21 0.67,1.10 0.00,0.00 C 2.87,2.13 6.47,2.79 10.00,3.31'); - } else if (type === 5) { - // insetRatio:0.9 tipAngle:40 wingCurve:5 tailCurve:15 - h = 3.28; - node3.setAttributeNS(null, 'd', 'M 10.00,3.28 C 6.61,4.19 3.19,5.07 0.00,6.55 C 0.62,5.56 1.00,4.44 1.00,3.28 C 1.00,2.11 0.62,0.99 0.00,0.00 C 3.19,1.49 6.61,2.37 10.00,3.28'); - } else if (type === 6) { - // insetRatio:0.9 tipAngle:35 wingCurve:5 tailCurve:0 - h = 2.84; - node3.setAttributeNS(null, 'd', 'M 10.00,2.84 C 6.61,3.59 3.21,4.35 0.00,5.68 C 0.33,4.73 0.67,3.78 1.00,2.84 C 0.67,1.89 0.33,0.95 0.00,0.00 C 3.21,1.33 6.61,2.09 10.00,2.84'); + // Shift scale center to origin, scale and shift the scale center back. + t = this.board.create('transform', + [1, 0, 0, + center[0] * (1 - sx), sx, 0, + center[1] * (1 - sy), 0, sy], {type: 'generic'}); + t.update(); // This initializes t.matrix, which is needed if the action element is the first group element. } else { - // type == 1 or > 6 - node3.setAttributeNS(null, 'd', 'M 0,0 L 10,5 L 0,10 z'); - } - if (/*!Type.exists(el.rendNode.getTotalLength) &&*/ el.elementClass === Const.OBJECT_CLASS_LINE) { - if (type === 2) { - v = 5.1; - } else if (type === 3) { - v = 0.02; - } else if (type === 4 || type === 5 || type === 6) { - v = 3.33; - } else { - v = 0.05; - } + return this; } } - node2.setAttributeNS(null, 'refY', h); - node2.setAttributeNS(null, 'refX', v); - node2.appendChild(node3); - return node2; - }, + this._update_apply_transformation(drag, t); - /** - * Updates color of an arrow DOM node. - * @param {Node} node The arrow node. - * @param {String} color Color value in a HTML compatible format, e.g. <tt>#00ff00</tt> or <tt>green</tt> for green. - * @param {Number} opacity - * @param {JXG.GeometryElement} el The element the arrows are to be attached to - */ - _setArrowColor: function (node, color, opacity, el) { - if (node) { - if (Type.isString(color)) { - this._setAttribute(function () { - node.setAttributeNS(null, 'stroke', color); - node.setAttributeNS(null, 'fill', color); - node.setAttributeNS(null, 'stroke-opacity', opacity); - node.setAttributeNS(null, 'fill-opacity', opacity); - }, el.visPropOld.fillcolor); - } + this.needsUpdate = false; // This is needed here to prevent infinite recursion because + // of the board.updateElements call below, - if (this.isIE) { - el.rendNode.parentNode.insertBefore(el.rendNode, el.rendNode); + // Prepare dependent objects for update + for (el in this.objects) { + if (this.objects.hasOwnProperty(el)) { + for (desc in this.objects[el].descendants) { + if (this.objects[el].descendants.hasOwnProperty(desc)) { + this.objects[el].descendants.needsUpdate = this.objects[el].descendants.needsRegularUpdate || this.board.needsFullUpdate; + } + } } } + this.board.updateElements(drag); - }, - - // already documented in JXG.AbstractRenderer - _setArrowWidth: function (node, width, parentNode, size) { - var s, d; - - if (node) { - // if (width === 0) { - // // display:none does not work well in webkit - // node.setAttributeNS(null, 'display', 'none'); - // } else { - s = width; - d = s * size; - node.setAttributeNS(null, 'viewBox', (0) + ' ' + (0) + ' ' + (s * 10) + ' ' + (s * 10)); - node.setAttributeNS(null, 'markerHeight', d); - node.setAttributeNS(null, 'markerWidth', d); - node.setAttributeNS(null, 'display', 'inherit'); - // } - - if (this.isIE) { - parentNode.parentNode.insertBefore(parentNode, parentNode); + // Now, all group elements have their new position and + // we can update the bookkeeping of the coordinates of the group elements. + for (el in this.objects) { + if (this.objects.hasOwnProperty(el)) { + this._updateCoordsCache(el); } } - }, - // already documented in JXG.AbstractRenderer - shortenPath: function(node, offFirst, offLast) { - var le, stroke; - - if (!(offFirst === 0 && offLast === 0) && Type.exists(node.getTotalLength)) { - try { - le = node.getTotalLength(); - stroke = le - offFirst - offLast; - node.style.strokeDasharray = stroke + ' ' + offFirst + ' ' + stroke + ' ' + offLast; - node.style.strokeDashoffset = stroke; - } catch (err) {} - } + return this; }, - /* ******************************** * - * This renderer does not need to - * override draw/update* methods - * since it provides draw/update*Prim - * methods except for some cases like - * internal texts or images. - * ******************************** */ - - /* ************************** - * Lines - * **************************/ - - // documented in AbstractRenderer - updateTicks: function (ticks) { - var i, j, c, node, x, y, - tickStr = '', - len = ticks.ticks.length, - len2, str, - isReal = true; + /** + * @private + * Determine what the dragging of a group element should do: + * rotation, translation, scaling or nothing. + */ + _update_find_drag_type: function () { + var el, obj, + action = 'nothing', + changed = [], + dragObjId; - for (i = 0; i < len; i++) { - c = ticks.ticks[i]; - x = c[0]; - y = c[1]; + // Determine how many elements have changed their position + // If more than one element changed its position, it is a translation. + // If exactly one element changed its position we have to find the type of the point. + for (el in this.objects) { + if (this.objects.hasOwnProperty(el)) { + obj = this.objects[el].point; - len2 = x.length; - str = ' M ' + x[0] + ' ' + y[0]; - if (!Type.isNumber(x[0])) { - isReal = false; - } - for (j = 1; isReal && j < len2; ++j) { - if (Type.isNumber(x[j])) { - str += ' L ' + x[j] + ' ' + y[j]; - } else { - isReal = false; + if (obj.coords.distance(Const.COORDS_BY_USER, this.coords[el]) > Mat.eps) { + changed.push(obj.id); } - - } - if (isReal) { - tickStr += str; } } - node = ticks.rendNode; - - if (!Type.exists(node)) { - node = this.createPrim('path', ticks.id); - this.appendChildPrim(node, Type.evaluate(ticks.visProp.layer)); - ticks.rendNode = node; + // Determine type of action: translation, scaling or rotation + if (changed.length === 0) { + return { + 'action': action, + 'id': '', + 'changed': changed + }; } - node.setAttributeNS(null, 'stroke', Type.evaluate(ticks.visProp.strokecolor)); - node.setAttributeNS(null, 'fill', 'none'); - // node.setAttributeNS(null, 'fill', Type.evaluate(ticks.visProp.fillcolor)); - // node.setAttributeNS(null, 'fill-opacity', Type.evaluate(ticks.visProp.fillopacity)); - node.setAttributeNS(null, 'stroke-opacity', Type.evaluate(ticks.visProp.strokeopacity)); - node.setAttributeNS(null, 'stroke-width', Type.evaluate(ticks.visProp.strokewidth)); - this.updatePathPrim(node, tickStr, ticks.board); - }, - - /* ************************** - * Text related stuff - * **************************/ - - // already documented in JXG.AbstractRenderer - displayCopyright: function (str, fontsize) { - var node = this.createPrim('text', 'licenseText'), - t; - node.setAttributeNS(null, 'x', '20px'); - node.setAttributeNS(null, 'y', (2 + fontsize) + 'px'); - node.setAttributeNS(null, "style", "font-family:Arial,Helvetica,sans-serif; font-size:" + fontsize + "px; fill:#356AA0; opacity:0.3;"); - t = this.container.ownerDocument.createTextNode(str); - node.appendChild(t); - this.appendChildPrim(node, 0); - }, - - // already documented in JXG.AbstractRenderer - drawInternalText: function (el) { - var node = this.createPrim('text', el.id); - - //node.setAttributeNS(null, "style", "alignment-baseline:middle"); // Not yet supported by Firefox - // Preserve spaces - //node.setAttributeNS("http://www.w3.org/XML/1998/namespace", "space", "preserve"); - node.style.whiteSpace = 'nowrap'; + dragObjId = changed[0]; + obj = this.objects[dragObjId].point; - el.rendNodeText = this.container.ownerDocument.createTextNode(''); - node.appendChild(el.rendNodeText); - this.appendChildPrim(node, Type.evaluate(el.visProp.layer)); + if (changed.length > 1) { // More than one point moved => translation + action = 'translation'; + } else { // One point moved => we have to determine the type + if (Type.isInArray(this.rotationPoints, obj) && Type.exists(this.rotationCenter)) { + action = 'rotation'; + } else if (Type.isInArray(this.scalePoints, obj) && Type.exists(this.scaleCenter)) { + action = 'scaling'; + } else if (Type.isInArray(this.translationPoints, obj)) { + action = 'translation'; + } + } - return node; + return { + 'action': action, + 'id': dragObjId, + 'changed': changed + }; }, - // already documented in JXG.AbstractRenderer - updateInternalText: function (el) { - var content = el.plaintext, v, - ev_ax = el.getAnchorX(), - ev_ay = el.getAnchorY(); + /** + * @private + * Determine the Euclidean coordinates of the centroid of the group. + * @returns {Array} array of length two, + */ + _update_centroid_center: function () { + var center, len, el; - if (el.rendNode.getAttributeNS(null, "class") !== el.visProp.cssclass) { - el.rendNode.setAttributeNS(null, "class", Type.evaluate(el.visProp.cssclass)); - el.needsSizeUpdate = true; + center = [0, 0]; + len = 0; + for (el in this.coords) { + if (this.coords.hasOwnProperty(el)) { + center[0] += this.coords[el].usrCoords[1]; + center[1] += this.coords[el].usrCoords[2]; + ++len; + } + } + if (len > 0) { + center[0] /= len; + center[1] /= len; } - if (!isNaN(el.coords.scrCoords[1] + el.coords.scrCoords[2])) { - // Horizontal - v = el.coords.scrCoords[1]; - if (el.visPropOld.left !== (ev_ax + v)) { - el.rendNode.setAttributeNS(null, 'x', v + 'px'); + return center; + }, - if (ev_ax === 'left') { - el.rendNode.setAttributeNS(null, 'text-anchor', 'start'); - } else if (ev_ax === 'right') { - el.rendNode.setAttributeNS(null, 'text-anchor', 'end'); - } else if (ev_ax === 'middle') { - el.rendNode.setAttributeNS(null, 'text-anchor', 'middle'); - } - el.visPropOld.left = ev_ax + v; - } + /** + * @private + * Apply the transformation to all elements of the group + */ + _update_apply_transformation: function (drag, t) { + var el, obj; - // Vertical - v = el.coords.scrCoords[2]; - if (el.visPropOld.top !== (ev_ay + v)) { - el.rendNode.setAttributeNS(null, 'y', (v + this.vOffsetText * 0.5) + 'px'); + for (el in this.objects) { + if (this.objects.hasOwnProperty(el)) { + if (Type.exists(this.board.objects[el])) { + obj = this.objects[el].point; - if (ev_ay === 'bottom') { - el.rendNode.setAttributeNS(null, 'dominant-baseline', 'text-after-edge'); - } else if (ev_ay === 'top') { - el.rendNode.setAttributeNS(null, 'dy', '1.6ex'); - //el.rendNode.setAttributeNS(null, 'dominant-baseline', 'text-before-edge'); // Not supported by IE, edge - } else if (ev_ay === 'middle') { - //el.rendNode.setAttributeNS(null, 'dominant-baseline', 'middle'); - el.rendNode.setAttributeNS(null, 'dy', '0.6ex'); + // Here, it is important that we change the position + // of elements by using setCoordinates. + // Thus, we avoid the call of snapToGrid(). + // This is done in the subsequent call of board.updateElements() + // in Group.update() above. + if (obj.id !== drag.id) { + if (drag.action === 'translation') { + if (!Type.isInArray(drag.changed, obj.id)) { + obj.coords.setCoordinates(Const.COORDS_BY_USER, + [this.coords[el].usrCoords[1] + t[0], + this.coords[el].usrCoords[2] + t[1]]); + } + } else if (drag.action === 'rotation' || drag.action === 'scaling') { + t.applyOnce([obj]); + } + } else { + if (drag.action === 'rotation' || drag.action === 'scaling') { + obj.coords.setCoordinates(Const.COORDS_BY_USER, + Mat.matVecMult(t.matrix, this.coords[obj.id].usrCoords)); + } + } + } else { + delete this.objects[el]; } - el.visPropOld.top = ev_ay + v; } } - if (el.htmlStr !== content) { - el.rendNodeText.data = content; - el.htmlStr = content; - } - this.transformImage(el, el.transformations); }, /** - * Set color and opacity of internal texts. - * SVG needs its own version. - * @private - * @see JXG.AbstractRenderer#updateTextStyle - * @see JXG.AbstractRenderer#updateInternalTextStyle + * Adds an Point to this group. + * @param {JXG.Point} object The point added to the group. + * @returns {JXG.Group} returns this group */ - updateInternalTextStyle: function (el, strokeColor, strokeOpacity, duration) { - this.setObjectFillColor(el, strokeColor, strokeOpacity); - }, - - /* ************************** - * Image related stuff - * **************************/ - - // already documented in JXG.AbstractRenderer - drawImage: function (el) { - var node = this.createPrim('image', el.id); + addPoint: function (object) { + this.objects[object.id] = {point: this.board.select(object)}; + this._updateCoordsCache(object.id); + //this.coords[object.id] = {usrCoords: object.coords.usrCoords.slice(0) }; + this.translationPoints.push(object); - node.setAttributeNS(null, 'preserveAspectRatio', 'none'); - this.appendChildPrim(node, Type.evaluate(el.visProp.layer)); - el.rendNode = node; + object.groups.push(this.id); + object.groups = Type.uniqueArray(object.groups); - this.updateImage(el); + return this; }, - // already documented in JXG.AbstractRenderer - transformImage: function (el, t) { - var s, m, - node = el.rendNode, - str = "", - len = t.length; + /** + * Adds multiple points to this group. + * @param {Array} objects An array of points to add to the group. + * @returns {JXG.Group} returns this group + */ + addPoints: function (objects) { + var p; - if (len > 0) { - m = this.joinTransforms(el, t); - s = [m[1][1], m[2][1], m[1][2], m[2][2], m[1][0], m[2][0]].join(','); - str += ' matrix(' + s + ') '; - node.setAttributeNS(null, 'transform', str); + for (p = 0; p < objects.length; p++) { + this.addPoint(objects[p]); } - }, - // already documented in JXG.AbstractRenderer - updateImageURL: function (el) { - var url = Type.evaluate(el.url); + return this; + }, - if (el._src !== url) { - el.imgIsLoaded = false; - el.rendNode.setAttributeNS(this.xlinkNamespace, 'xlink:href', url); - el._src = url; + /** + * Adds all points in a group to this group. + * @param {JXG.Group} group The group added to this group. + * @returns {JXG.Group} returns this group + */ + addGroup: function (group) { + var el; - return true; + for (el in group.objects) { + if (group.objects.hasOwnProperty(el)) { + this.addPoint(group.objects[el].point); + } } - return false; + return this; }, - // already documented in JXG.AbstractRenderer - updateImageStyle: function (el, doHighlight) { - var css = Type.evaluate(doHighlight ? el.visProp.highlightcssclass : el.visProp.cssclass); + /** + * Removes a point from the group. + * @param {JXG.Point} point + * @returns {JXG.Group} returns this group + */ + removePoint: function (point) { + delete this.objects[point.id]; - el.rendNode.setAttributeNS(null, 'class', css); + return this; }, - /* ************************** - * Render primitive objects - * **************************/ - - // already documented in JXG.AbstractRenderer - appendChildPrim: function (node, level) { - if (!Type.exists(level)) { // trace nodes have level not set - level = 0; - } else if (level >= Options.layer.numlayers) { - level = Options.layer.numlayers - 1; - } - - this.layer[level].appendChild(node); - - return node; - }, - - // already documented in JXG.AbstractRenderer - createPrim: function (type, id) { - var node = this.container.ownerDocument.createElementNS(this.svgNamespace, type); - node.setAttributeNS(null, 'id', this.container.id + '_' + id); - node.style.position = 'absolute'; - if (type === 'path') { - node.setAttributeNS(null, 'stroke-linecap', 'round'); - node.setAttributeNS(null, 'stroke-linejoin', 'round'); - } - return node; - }, + /** + * Sets the center of rotation for the group. This is either a point or the centroid of the group. + * @param {JXG.Point|String} object A point which will be the center of rotation, the string "centroid", or + * an array of length two, or a function returning an array of length two. + * @default 'centroid' + * @returns {JXG.Group} returns this group + */ + setRotationCenter: function (object) { + this.rotationCenter = object; - // already documented in JXG.AbstractRenderer - remove: function (shape) { - if (Type.exists(shape) && Type.exists(shape.parentNode)) { - shape.parentNode.removeChild(shape); - } + return this; }, - // already documented in JXG.AbstractRenderer - setLayer: function (el, level) { - if (!Type.exists(level)) { - level = 0; - } else if (level >= Options.layer.numlayers) { - level = Options.layer.numlayers - 1; - } - - this.layer[level].appendChild(el.rendNode); + /** + * Sets the rotation points of the group. Dragging at one of these points results into a rotation of the whole group around + * the rotation center of the group {@see JXG.Group#setRotationCenter}. + * @param {Array|JXG.Point} objects Array of {@link JXG.Point} or arbitrary number of {@link JXG.Point} elements. + * @returns {JXG.Group} returns this group + */ + setRotationPoints: function (objects) { + return this._setActionPoints('rotation', objects); }, - // already documented in JXG.AbstractRenderer - makeArrows: function (el) { - var node2, - ev_fa = Type.evaluate(el.visProp.firstarrow), - ev_la = Type.evaluate(el.visProp.lastarrow); - - // Test if the arrow heads already exist - if (el.visPropOld.firstarrow === ev_fa && - el.visPropOld.lastarrow === ev_la) { - if (this.isIE && el.visPropCalc.visible && - (ev_fa || ev_la)) { - el.rendNode.parentNode.insertBefore(el.rendNode, el.rendNode); - } - return; - } - - if (ev_fa) { - node2 = el.rendNodeTriangleStart; - if (!Type.exists(node2)) { - node2 = this._createArrowHead(el, 'End'); - this.defs.appendChild(node2); - el.rendNodeTriangleStart = node2; - el.rendNode.setAttributeNS(null, 'marker-start', 'url(#' + this.container.id + '_' + el.id + 'TriangleEnd)'); - } else { - this.defs.appendChild(node2); - } - } else { - node2 = el.rendNodeTriangleStart; - if (Type.exists(node2)) { - this.remove(node2); - } - } - if (ev_la) { - node2 = el.rendNodeTriangleEnd; - if (!Type.exists(node2)) { - node2 = this._createArrowHead(el, 'Start'); - this.defs.appendChild(node2); - el.rendNodeTriangleEnd = node2; - el.rendNode.setAttributeNS(null, 'marker-end', 'url(#' + this.container.id + '_' + el.id + 'TriangleStart)'); - } else { - this.defs.appendChild(node2); - } - } else { - node2 = el.rendNodeTriangleEnd; - if (Type.exists(node2)) { - this.remove(node2); - } - } - el.visPropOld.firstarrow = ev_fa; - el.visPropOld.lastarrow = ev_la; + /** + * Adds a point to the set of rotation points of the group. Dragging at one of these points results into a rotation of the whole group around + * the rotation center of the group {@see JXG.Group#setRotationCenter}. + * @param {JXG.Point} point {@link JXG.Point} element. + * @returns {JXG.Group} returns this group + */ + addRotationPoint: function (point) { + return this._addActionPoint('rotation', point); }, - // already documented in JXG.AbstractRenderer - updateEllipsePrim: function (node, x, y, rx, ry) { - var huge = 1000000; - - huge = 200000; // IE - // webkit does not like huge values if the object is dashed - // iE doesn't like huge values above 216000 - x = Math.abs(x) < huge ? x : huge * x / Math.abs(x); - y = Math.abs(y) < huge ? y : huge * y / Math.abs(y); - rx = Math.abs(rx) < huge ? rx : huge * rx / Math.abs(rx); - ry = Math.abs(ry) < huge ? ry : huge * ry / Math.abs(ry); - - node.setAttributeNS(null, 'cx', x); - node.setAttributeNS(null, 'cy', y); - node.setAttributeNS(null, 'rx', Math.abs(rx)); - node.setAttributeNS(null, 'ry', Math.abs(ry)); + /** + * Removes the rotation property from a point of the group. + * @param {JXG.Point} point {@link JXG.Point} element. + * @returns {JXG.Group} returns this group + */ + removeRotationPoint: function (point) { + return this._removeActionPoint('rotation', point); }, - // already documented in JXG.AbstractRenderer - updateLinePrim: function (node, p1x, p1y, p2x, p2y) { - var huge = 1000000; - - huge = 200000; //IE - if (!isNaN(p1x + p1y + p2x + p2y)) { - // webkit does not like huge values if the object is dashed - // IE doesn't like huge values above 216000 - p1x = Math.abs(p1x) < huge ? p1x : huge * p1x / Math.abs(p1x); - p1y = Math.abs(p1y) < huge ? p1y : huge * p1y / Math.abs(p1y); - p2x = Math.abs(p2x) < huge ? p2x : huge * p2x / Math.abs(p2x); - p2y = Math.abs(p2y) < huge ? p2y : huge * p2y / Math.abs(p2y); - - node.setAttributeNS(null, 'x1', p1x); - node.setAttributeNS(null, 'y1', p1y); - node.setAttributeNS(null, 'x2', p2x); - node.setAttributeNS(null, 'y2', p2y); - } + /** + * Sets the translation points of the group. Dragging at one of these points results into a translation of the whole group. + * @param {Array|JXG.Point} objects Array of {@link JXG.Point} or arbitrary number of {@link JXG.Point} elements. + * + * By default, all points of the group are translation points. + * @returns {JXG.Group} returns this group + */ + setTranslationPoints: function (objects) { + return this._setActionPoints('translation', objects); }, - // already documented in JXG.AbstractRenderer - updatePathPrim: function (node, pointString) { - if (pointString === '') { - pointString = 'M 0 0'; - } - node.setAttributeNS(null, 'd', pointString); + /** + * Adds a point to the set of the translation points of the group. + * Dragging one of these points results into a translation of the whole group. + * @param {JXG.Point} point {@link JXG.Point} element. + * @returns {JXG.Group} returns this group + */ + addTranslationPoint: function (point) { + return this._addActionPoint('translation', point); }, - // already documented in JXG.AbstractRenderer - updatePathStringPoint: function (el, size, type) { - var s = '', - scr = el.coords.scrCoords, - sqrt32 = size * Math.sqrt(3) * 0.5, - s05 = size * 0.5; - - if (type === 'x') { - s = ' M ' + (scr[1] - size) + ' ' + (scr[2] - size) + - ' L ' + (scr[1] + size) + ' ' + (scr[2] + size) + - ' M ' + (scr[1] + size) + ' ' + (scr[2] - size) + - ' L ' + (scr[1] - size) + ' ' + (scr[2] + size); - } else if (type === '+') { - s = ' M ' + (scr[1] - size) + ' ' + (scr[2]) + - ' L ' + (scr[1] + size) + ' ' + (scr[2]) + - ' M ' + (scr[1]) + ' ' + (scr[2] - size) + - ' L ' + (scr[1]) + ' ' + (scr[2] + size); - } else if (type === '<>') { - s = ' M ' + (scr[1] - size) + ' ' + (scr[2]) + - ' L ' + (scr[1]) + ' ' + (scr[2] + size) + - ' L ' + (scr[1] + size) + ' ' + (scr[2]) + - ' L ' + (scr[1]) + ' ' + (scr[2] - size) + ' Z '; - } else if (type === '^') { - s = ' M ' + (scr[1]) + ' ' + (scr[2] - size) + - ' L ' + (scr[1] - sqrt32) + ' ' + (scr[2] + s05) + - ' L ' + (scr[1] + sqrt32) + ' ' + (scr[2] + s05) + - ' Z '; // close path - } else if (type === 'v') { - s = ' M ' + (scr[1]) + ' ' + (scr[2] + size) + - ' L ' + (scr[1] - sqrt32) + ' ' + (scr[2] - s05) + - ' L ' + (scr[1] + sqrt32) + ' ' + (scr[2] - s05) + - ' Z '; - } else if (type === '>') { - s = ' M ' + (scr[1] + size) + ' ' + (scr[2]) + - ' L ' + (scr[1] - s05) + ' ' + (scr[2] - sqrt32) + - ' L ' + (scr[1] - s05) + ' ' + (scr[2] + sqrt32) + - ' Z '; - } else if (type === '<') { - s = ' M ' + (scr[1] - size) + ' ' + (scr[2]) + - ' L ' + (scr[1] + s05) + ' ' + (scr[2] - sqrt32) + - ' L ' + (scr[1] + s05) + ' ' + (scr[2] + sqrt32) + - ' Z '; - } - return s; + /** + * Removes the translation property from a point of the group. + * @param {JXG.Point} point {@link JXG.Point} element. + * @returns {JXG.Group} returns this group + */ + removeTranslationPoint: function (point) { + return this._removeActionPoint('translation', point); }, - // already documented in JXG.AbstractRenderer - updatePathStringPrim: function (el) { - var i, scr, len, - symbm = ' M ', - symbl = ' L ', - symbc = ' C ', - nextSymb = symbm, - maxSize = 5000.0, - pStr = ''; - - if (el.numberPoints <= 0) { - return ''; - } - - len = Math.min(el.points.length, el.numberPoints); - - if (el.bezierDegree === 1) { - for (i = 0; i < len; i++) { - scr = el.points[i].scrCoords; - if (isNaN(scr[1]) || isNaN(scr[2])) { // PenUp - nextSymb = symbm; - } else { - // Chrome has problems with values being too far away. - scr[1] = Math.max(Math.min(scr[1], maxSize), -maxSize); - scr[2] = Math.max(Math.min(scr[2], maxSize), -maxSize); + /** + * Sets the center of scaling for the group. This is either a point or the centroid of the group. + * @param {JXG.Point|String} object A point which will be the center of scaling, the string "centroid", or + * an array of length two, or a function returning an array of length two. + * @returns {JXG.Group} returns this group + */ + setScaleCenter: function (object) { + this.scaleCenter = object; - // Attention: first coordinate may be inaccurate if far way - //pStr += [nextSymb, scr[1], ' ', scr[2]].join(''); - pStr += nextSymb + scr[1] + ' ' + scr[2]; // Seems to be faster now (webkit and firefox) - nextSymb = symbl; - } - } - } else if (el.bezierDegree === 3) { - i = 0; - while (i < len) { - scr = el.points[i].scrCoords; - if (isNaN(scr[1]) || isNaN(scr[2])) { // PenUp - nextSymb = symbm; - } else { - pStr += nextSymb + scr[1] + ' ' + scr[2]; - if (nextSymb === symbc) { - i += 1; - scr = el.points[i].scrCoords; - pStr += ' ' + scr[1] + ' ' + scr[2]; - i += 1; - scr = el.points[i].scrCoords; - pStr += ' ' + scr[1] + ' ' + scr[2]; - } - nextSymb = symbc; - } - i += 1; - } - } - return pStr; + return this; }, - // already documented in JXG.AbstractRenderer - updatePathStringBezierPrim: function (el) { - var i, j, k, scr, lx, ly, len, - symbm = ' M ', - symbl = ' C ', - nextSymb = symbm, - maxSize = 5000.0, - pStr = '', - f = Type.evaluate(el.visProp.strokewidth), - isNoPlot = (Type.evaluate(el.visProp.curvetype) !== 'plot'); - - if (el.numberPoints <= 0) { - return ''; + /** + * Sets the scale points of the group. Dragging at one of these points results into a scaling of the whole group. + * @param {Array|JXG.Point} objects Array of {@link JXG.Point} or arbitrary number of {@link JXG.Point} elements. + * @param {String} direction Restricts the directions to be scaled. Possible values are 'x', 'y', 'xy'. Default value is 'xy'. + * + * By default, all points of the group are translation points. + * @returns {JXG.Group} returns this group + */ + setScalePoints: function (objects, direction) { + var objs, i, len; + if (Type.isArray(objects)) { + objs = objects; + } else { + objs = arguments; } - if (isNoPlot && el.board.options.curve.RDPsmoothing) { - el.points = Numerics.RamerDouglasPeucker(el.points, 0.5); + len = objs.length; + for (i = 0; i < len; ++i) { + this.scaleDirections[this.board.select(objs[i]).id] = direction || 'xy'; } - len = Math.min(el.points.length, el.numberPoints); - for (j = 1; j < 3; j++) { - nextSymb = symbm; - for (i = 0; i < len; i++) { - scr = el.points[i].scrCoords; - - if (isNaN(scr[1]) || isNaN(scr[2])) { // PenUp - nextSymb = symbm; - } else { - // Chrome has problems with values being too far away. - scr[1] = Math.max(Math.min(scr[1], maxSize), -maxSize); - scr[2] = Math.max(Math.min(scr[2], maxSize), -maxSize); + return this._setActionPoints('scale', objects); + }, - // Attention: first coordinate may be inaccurate if far way - if (nextSymb === symbm) { - //pStr += [nextSymb, scr[1], ' ', scr[2]].join(''); - pStr += nextSymb + scr[1] + ' ' + scr[2]; // Seems to be faster now (webkit and firefox) - } else { - k = 2 * j; - pStr += [nextSymb, - (lx + (scr[1] - lx) * 0.333 + f * (k * Math.random() - j)), ' ', - (ly + (scr[2] - ly) * 0.333 + f * (k * Math.random() - j)), ' ', - (lx + (scr[1] - lx) * 0.666 + f * (k * Math.random() - j)), ' ', - (ly + (scr[2] - ly) * 0.666 + f * (k * Math.random() - j)), ' ', - scr[1], ' ', scr[2]].join(''); - } + /** + * Adds a point to the set of the scale points of the group. Dragging at one of these points results into a scaling of the whole group. + * @param {JXG.Point} point {@link JXG.Point} element. + * @param {String} direction Restricts the directions to be scaled. Possible values are 'x', 'y', 'xy'. Default value is 'xy'. + * @returns {JXG.Group} returns this group + */ + addScalePoint: function (point, direction) { + this._addActionPoint('scale', point); + this.scaleDirections[this.board.select(point).id] = direction || 'xy'; - nextSymb = symbl; - lx = scr[1]; - ly = scr[2]; - } - } - } - return pStr; + return this; }, - // already documented in JXG.AbstractRenderer - updatePolygonPrim: function (node, el) { - var i, - pStr = '', - scrCoords, - len = el.vertices.length; + /** + * Removes the scaling property from a point of the group. + * @param {JXG.Point} point {@link JXG.Point} element. + * @returns {JXG.Group} returns this group + */ + removeScalePoint: function (point) { + return this._removeActionPoint('scale', point); + }, - node.setAttributeNS(null, 'stroke', 'none'); - if (el.elType === 'polygonalchain') { - len++; + /** + * Generic method for {@link JXG.Group@setTranslationPoints} and {@link JXG.Group@setRotationPoints} + * @private + */ + _setActionPoints: function (action, objects) { + var objs, i, len; + if (Type.isArray(objects)) { + objs = objects; + } else { + objs = arguments; } - for (i = 0; i < len - 1; i++) { - if (el.vertices[i].isReal) { - scrCoords = el.vertices[i].coords.scrCoords; - pStr = pStr + scrCoords[1] + "," + scrCoords[2]; - } else { - node.setAttributeNS(null, 'points', ''); - return; - } - - if (i < len - 2) { - pStr += " "; - } - } - if (pStr.indexOf('NaN') === -1) { - node.setAttributeNS(null, 'points', pStr); + len = objs.length; + this[action + 'Points'] = []; + for (i = 0; i < len; ++i) { + this._addActionPoint(action, objs[i]); } - }, - // already documented in JXG.AbstractRenderer - updateRectPrim: function (node, x, y, w, h) { - node.setAttributeNS(null, 'x', x); - node.setAttributeNS(null, 'y', y); - node.setAttributeNS(null, 'width', w); - node.setAttributeNS(null, 'height', h); + return this; }, - /* ************************** - * Set Attributes - * **************************/ + /** + * Generic method for {@link JXG.Group@addTranslationPoint} and {@link JXG.Group@addRotationPoint} + * @private + */ + _addActionPoint: function (action, point) { + this[action + 'Points'].push(this.board.select(point)); - // documented in JXG.AbstractRenderer - setPropertyPrim: function (node, key, val) { - if (key === 'stroked') { - return; - } - node.setAttributeNS(null, key, val); + return this; }, - display: function (el, val) { - var node; - - if (el && el.rendNode) { - el.visPropOld.visible = val; - node = el.rendNode; - if (val) { - node.setAttributeNS(null, 'display', 'inline'); - node.style.visibility = "inherit"; - } else { - node.setAttributeNS(null, 'display', 'none'); - node.style.visibility = "hidden"; - } + /** + * Generic method for {@link JXG.Group@removeTranslationPoint} and {@link JXG.Group@removeRotationPoint} + * @private + */ + _removeActionPoint: function (action, point) { + var idx = this[action + 'Points'].indexOf(this.board.select(point)); + if (idx > -1) { + this[action + 'Points'].splice(idx, 1); } - }, - - // documented in JXG.AbstractRenderer - show: function (el) { - JXG.deprecated('Board.renderer.show()', 'Board.renderer.display()'); - this.display(el, true); - // var node; - // - // if (el && el.rendNode) { - // node = el.rendNode; - // node.setAttributeNS(null, 'display', 'inline'); - // node.style.visibility = "inherit"; - // } - }, - // documented in JXG.AbstractRenderer - hide: function (el) { - JXG.deprecated('Board.renderer.hide()', 'Board.renderer.display()'); - this.display(el, false); - // var node; - // - // if (el && el.rendNode) { - // node = el.rendNode; - // node.setAttributeNS(null, 'display', 'none'); - // node.style.visibility = "hidden"; - // } + return this; }, - // documented in JXG.AbstractRenderer - setBuffering: function (el, type) { - el.rendNode.setAttribute('buffered-rendering', type); + /** + * @deprecated + * Use setAttribute + */ + setProperty: function () { + JXG.deprecated('Group.setProperty', 'Group.setAttribute()'); + this.setAttribute.apply(this, arguments); }, - // documented in JXG.AbstractRenderer - setDashStyle: function (el) { - var dashStyle = Type.evaluate(el.visProp.dash), - node = el.rendNode; + setAttribute: function () { + var el; - if (dashStyle > 0) { - node.setAttributeNS(null, 'stroke-dasharray', this.dashArray[dashStyle - 1]); - } else { - if (node.hasAttributeNS(null, 'stroke-dasharray')) { - node.removeAttributeNS(null, 'stroke-dasharray'); + for (el in this.objects) { + if (this.objects.hasOwnProperty(el)) { + this.objects[el].point.setAttribute.apply(this.objects[el].point, arguments); } } - }, - // documented in JXG.AbstractRenderer - setGradient: function (el) { - var fillNode = el.rendNode, - node, node2, node3, - ev_g = Type.evaluate(el.visProp.gradient); + return this; + } + }); - if (ev_g === 'linear' || ev_g === 'radial') { - node = this.createPrim(ev_g + 'Gradient', el.id + '_gradient'); - node2 = this.createPrim('stop', el.id + '_gradient1'); - node3 = this.createPrim('stop', el.id + '_gradient2'); - node.appendChild(node2); - node.appendChild(node3); - this.defs.appendChild(node); - fillNode.setAttributeNS(null, 'style', 'fill:url(#' + this.container.id + '_' + el.id + '_gradient)'); - el.gradNode1 = node2; - el.gradNode2 = node3; - el.gradNode = node; - } else { - fillNode.removeAttributeNS(null, 'style'); + /** + * @class This element combines a given set of {@link JXG.Point} elements to a + * group. The elements of the group and dependent elements can be translated, rotated and scaled by + * dragging one of the group elements. + * + * + * @pseudo + * @description + * @name Group + * @augments JXG.Group + * @constructor + * @type JXG.Group + * @param {JXG.Board} board The board the points are on. + * @param {Array} parents Array of points to group. + * @param {Object} attributes Visual properties (unused). + * @returns {JXG.Group} + * + * @example + * + * // Create some free points. e.g. A, B, C, D + * // Create a group + * + * var p, col, g; + * col = 'blue'; + * p = []; + * p.push(board.create('point',[-2, -1 ], {size: 5, strokeColor:col, fillColor:col})); + * p.push(board.create('point',[2, -1 ], {size: 5, strokeColor:col, fillColor:col})); + * p.push(board.create('point',[2, 1 ], {size: 5, strokeColor:col, fillColor:col})); + * p.push(board.create('point',[-2, 1], {size: 5, strokeColor:col, fillColor:col})); + * g = board.create('group', p); + * + * </pre><div class="jxgbox" id="JXGa2204533-db91-4af9-b720-70394de4d367" style="width: 400px; height: 300px;"></div> + * <script type="text/javascript"> + * (function () { + * var board, p, col, g; + * board = JXG.JSXGraph.initBoard('JXGa2204533-db91-4af9-b720-70394de4d367', {boundingbox:[-5,5,5,-5], keepaspectratio:true, axis:true, showcopyright: false}); + * col = 'blue'; + * p = []; + * p.push(board.create('point',[-2, -1 ], {size: 5, strokeColor:col, fillColor:col})); + * p.push(board.create('point',[2, -1 ], {size: 5, strokeColor:col, fillColor:col})); + * p.push(board.create('point',[2, 1 ], {size: 5, strokeColor:col, fillColor:col})); + * p.push(board.create('point',[-2, 1], {size: 5, strokeColor:col, fillColor:col})); + * g = board.create('group', p); + * })(); + * </script><pre> + * + * + * @example + * + * // Create some free points. e.g. A, B, C, D + * // Create a group + * // If the points define a polygon and the polygon has the attribute hasInnerPoints:true, + * // the polygon can be dragged around. + * + * var p, col, pol, g; + * col = 'blue'; + * p = []; + * p.push(board.create('point',[-2, -1 ], {size: 5, strokeColor:col, fillColor:col})); + * p.push(board.create('point',[2, -1 ], {size: 5, strokeColor:col, fillColor:col})); + * p.push(board.create('point',[2, 1 ], {size: 5, strokeColor:col, fillColor:col})); + * p.push(board.create('point',[-2, 1], {size: 5, strokeColor:col, fillColor:col})); + * + * pol = board.create('polygon', p, {hasInnerPoints: true}); + * g = board.create('group', p); + * + * </pre><div class="jxgbox" id="JXG781b5564-a671-4327-81c6-de915c8f924e" style="width: 400px; height: 300px;"></div> + * <script type="text/javascript"> + * (function () { + * var board, p, col, pol, g; + * board = JXG.JSXGraph.initBoard('JXG781b5564-a671-4327-81c6-de915c8f924e', {boundingbox:[-5,5,5,-5], keepaspectratio:true, axis:true, showcopyright: false}); + * col = 'blue'; + * p = []; + * p.push(board.create('point',[-2, -1 ], {size: 5, strokeColor:col, fillColor:col})); + * p.push(board.create('point',[2, -1 ], {size: 5, strokeColor:col, fillColor:col})); + * p.push(board.create('point',[2, 1 ], {size: 5, strokeColor:col, fillColor:col})); + * p.push(board.create('point',[-2, 1], {size: 5, strokeColor:col, fillColor:col})); + * pol = board.create('polygon', p, {hasInnerPoints: true}); + * g = board.create('group', p); + * })(); + * </script><pre> + * + * @example + * + * // Allow rotations: + * // Define a center of rotation and declare points of the group as "rotation points". + * + * var p, col, pol, g; + * col = 'blue'; + * p = []; + * p.push(board.create('point',[-2, -1 ], {size: 5, strokeColor:col, fillColor:col})); + * p.push(board.create('point',[2, -1 ], {size: 5, strokeColor:'red', fillColor:'red'})); + * p.push(board.create('point',[2, 1 ], {size: 5, strokeColor:'red', fillColor:'red'})); + * p.push(board.create('point',[-2, 1], {size: 5, strokeColor:col, fillColor:col})); + * + * pol = board.create('polygon', p, {hasInnerPoints: true}); + * g = board.create('group', p); + * g.setRotationCenter(p[0]); + * g.setRotationPoints([p[1], p[2]]); + * + * </pre><div class="jxgbox" id="JXGf0491b62-b377-42cb-b55c-4ef5374b39fc" style="width: 400px; height: 300px;"></div> + * <script type="text/javascript"> + * (function () { + * var board, p, col, pol, g; + * board = JXG.JSXGraph.initBoard('JXGf0491b62-b377-42cb-b55c-4ef5374b39fc', {boundingbox:[-5,5,5,-5], keepaspectratio:true, axis:true, showcopyright: false}); + * col = 'blue'; + * p = []; + * p.push(board.create('point',[-2, -1 ], {size: 5, strokeColor:col, fillColor:col})); + * p.push(board.create('point',[2, -1 ], {size: 5, strokeColor:'red', fillColor:'red'})); + * p.push(board.create('point',[2, 1 ], {size: 5, strokeColor:'red', fillColor:'red'})); + * p.push(board.create('point',[-2, 1], {size: 5, strokeColor:col, fillColor:col})); + * pol = board.create('polygon', p, {hasInnerPoints: true}); + * g = board.create('group', p); + * g.setRotationCenter(p[0]); + * g.setRotationPoints([p[1], p[2]]); + * })(); + * </script><pre> + * + * @example + * + * // Allow rotations: + * // As rotation center, arbitrary points, coordinate arrays, + * // or functions returning coordinate arrays can be given. + * // Another possibility is to use the predefined string 'centroid'. + * + * // The methods to define the rotation points can be chained. + * + * var p, col, pol, g; + * col = 'blue'; + * p = []; + * p.push(board.create('point',[-2, -1 ], {size: 5, strokeColor:col, fillColor:col})); + * p.push(board.create('point',[2, -1 ], {size: 5, strokeColor:'red', fillColor:'red'})); + * p.push(board.create('point',[2, 1 ], {size: 5, strokeColor:'red', fillColor:'red'})); + * p.push(board.create('point',[-2, 1], {size: 5, strokeColor:col, fillColor:col})); + * + * pol = board.create('polygon', p, {hasInnerPoints: true}); + * g = board.create('group', p).setRotationCenter('centroid').setRotationPoints([p[1], p[2]]); + * + * </pre><div class="jxgbox" id="JXG8785b099-a75e-4769-bfd8-47dd4376fe27" style="width: 400px; height: 300px;"></div> + * <script type="text/javascript"> + * (function () { + * var board, p, col, pol, g; + * board = JXG.JSXGraph.initBoard('JXG8785b099-a75e-4769-bfd8-47dd4376fe27', {boundingbox:[-5,5,5,-5], keepaspectratio:true, axis:true, showcopyright: false}); + * col = 'blue'; + * p = []; + * p.push(board.create('point',[-2, -1 ], {size: 5, strokeColor:col, fillColor:col})); + * p.push(board.create('point',[2, -1 ], {size: 5, strokeColor:'red', fillColor:'red'})); + * p.push(board.create('point',[2, 1 ], {size: 5, strokeColor:'red', fillColor:'red'})); + * p.push(board.create('point',[-2, 1], {size: 5, strokeColor:col, fillColor:col})); + * pol = board.create('polygon', p, {hasInnerPoints: true}); + * g = board.create('group', p).setRotationCenter('centroid').setRotationPoints([p[1], p[2]]); + * })(); + * </script><pre> + * + * @example + * + * // Allow scaling: + * // As for rotation one can declare points of the group to trigger a scaling operation. + * // For this, one has to define a scaleCenter, in analogy to rotations. + * + * // Here, the yellow point enables scaling, the red point a rotation. + * + * var p, col, pol, g; + * col = 'blue'; + * p = []; + * p.push(board.create('point',[-2, -1 ], {size: 5, strokeColor:col, fillColor:col})); + * p.push(board.create('point',[2, -1 ], {size: 5, strokeColor:'yellow', fillColor:'yellow'})); + * p.push(board.create('point',[2, 1 ], {size: 5, strokeColor:'red', fillColor:'red'})); + * p.push(board.create('point',[-2, 1], {size: 5, strokeColor:col, fillColor:col})); + * + * pol = board.create('polygon', p, {hasInnerPoints: true}); + * g = board.create('group', p).setRotationCenter('centroid').setRotationPoints([p[2]]); + * g.setScaleCenter(p[0]).setScalePoints(p[1]); + * + * </pre><div class="jxgbox" id="JXGc3ca436b-e4fc-4de5-bab4-09790140c675" style="width: 400px; height: 300px;"></div> + * <script type="text/javascript"> + * (function () { + * var board, p, col, pol, g; + * board = JXG.JSXGraph.initBoard('JXGc3ca436b-e4fc-4de5-bab4-09790140c675', {boundingbox:[-5,5,5,-5], keepaspectratio:true, axis:true, showcopyright: false}); + * col = 'blue'; + * p = []; + * p.push(board.create('point',[-2, -1 ], {size: 5, strokeColor:col, fillColor:col})); + * p.push(board.create('point',[2, -1 ], {size: 5, strokeColor:'yellow', fillColor:'yellow'})); + * p.push(board.create('point',[2, 1 ], {size: 5, strokeColor:'red', fillColor:'red'})); + * p.push(board.create('point',[-2, 1], {size: 5, strokeColor:col, fillColor:col})); + * pol = board.create('polygon', p, {hasInnerPoints: true}); + * g = board.create('group', p).setRotationCenter('centroid').setRotationPoints([p[2]]); + * g.setScaleCenter(p[0]).setScalePoints(p[1]); + * })(); + * </script><pre> + * + * @example + * + * // Allow Translations: + * // By default, every point of a group triggers a translation. + * // There may be situations, when this is not wanted. + * + * // In this example, E triggers nothing, but itself is rotation center + * // and is translated, if other points are moved around. + * + * var p, q, col, pol, g; + * col = 'blue'; + * p = []; + * p.push(board.create('point',[-2, -1 ], {size: 5, strokeColor:col, fillColor:col})); + * p.push(board.create('point',[2, -1 ], {size: 5, strokeColor:'yellow', fillColor:'yellow'})); + * p.push(board.create('point',[2, 1 ], {size: 5, strokeColor:'red', fillColor:'red'})); + * p.push(board.create('point',[-2, 1], {size: 5, strokeColor:col, fillColor:col})); + * q = board.create('point',[0, 0], {size: 5, strokeColor:col, fillColor:col}); + * + * pol = board.create('polygon', p, {hasInnerPoints: true}); + * g = board.create('group', p.concat(q)).setRotationCenter('centroid').setRotationPoints([p[2]]); + * g.setScaleCenter(p[0]).setScalePoints(p[1]); + * g.removeTranslationPoint(q); + * + * </pre><div class="jxgbox" id="JXGd19b800a-57a9-4303-b49a-8f5b7a5488f0" style="width: 400px; height: 300px;"></div> + * <script type="text/javascript"> + * (function () { + * var board, p, q, col, pol, g; + * board = JXG.JSXGraph.initBoard('JXGd19b800a-57a9-4303-b49a-8f5b7a5488f0', {boundingbox:[-5,5,5,-5], keepaspectratio:true, axis:true, showcopyright: false}); + * col = 'blue'; + * p = []; + * p.push(board.create('point',[-2, -1 ], {size: 5, strokeColor:col, fillColor:col})); + * p.push(board.create('point',[2, -1 ], {size: 5, strokeColor:'yellow', fillColor:'yellow'})); + * p.push(board.create('point',[2, 1 ], {size: 5, strokeColor:'red', fillColor:'red'})); + * p.push(board.create('point',[-2, 1], {size: 5, strokeColor:col, fillColor:col})); + * q = board.create('point',[0, 0], {size: 5, strokeColor:col, fillColor:col}); + * + * pol = board.create('polygon', p, {hasInnerPoints: true}); + * g = board.create('group', p.concat(q)).setRotationCenter('centroid').setRotationPoints([p[2]]); + * g.setScaleCenter(p[0]).setScalePoints(p[1]); + * g.removeTranslationPoint(q); + * })(); + * </script><pre> + * + * + */ + JXG.createGroup = function (board, parents, attributes) { + var attr = Type.copyAttributes(attributes, board.options, 'group'), + g = new JXG.Group(board, attr.id, attr.name, parents, attr); + + g.elType = 'group'; + g.setParents(parents); + + return g; + }; + + JXG.registerElement('group', JXG.createGroup); + + return { + Group: JXG.Group, + createGroup: JXG.createGroup + }; +}); + +/* + Copyright 2008-2022 + Matthias Ehmann, + Michael Gerhaeuser, + Carsten Miller, + Bianca Valentin, + Alfred Wassermann, + Peter Wilfahrt + + This file is part of JSXGraph. + + JSXGraph is free software dual licensed under the GNU LGPL or MIT License. + + You can redistribute it and/or modify it under the terms of the + + * GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version + OR + * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT + + JSXGraph is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License and + the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> + and <http://opensource.org/licenses/MIT/>. + */ + + +/*global JXG: true, define: true*/ +/*jslint nomen: true, plusplus: true*/ + +/* depends: + jxg + base/constants + math/math + math/geometry + math/numerics + utils/type + elements: + point + curve + */ + +/** + * @fileoverview In this file the conic sections defined. + */ + +define('element/conic',[ + 'jxg', 'base/constants', 'base/coords', 'math/math', 'math/numerics', 'math/geometry', 'utils/type' +], function (JXG, Const, Coords, Mat, Numerics, Geometry, Type) { + + "use strict"; + + /** + * @class This element is used to provide a constructor for an ellipse. An ellipse is given by two points (the foci) and a third point on the the ellipse or + * the length of the major axis. + * @pseudo + * @description + * @name Ellipse + * @augments Conic + * @constructor + * @type JXG.Curve + * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {JXG.Point,array_JXG.Point,array_JXG.Point,array} point1,point2,point3 Parent elements can be three elements either of type {@link JXG.Point} or array of + * numbers describing the coordinates of a point. In the latter case the point will be constructed automatically as a fixed invisible point. + * @param {JXG.Point,array_JXG.Point,array_number,function} point1,point2,number Parent elements can be two elements either of type {@link JXG.Point} or array of + * numbers describing the coordinates of a point. The third parameter is a number/function which defines the length of the major axis + * @param {Number} start (Optional) parameter of the curve start, default: 0. + * @param {Number} end (Optional) parameter for the curve end, default: 2π. + * @example + * // Create an Ellipse by three points + * var A = board.create('point', [-1,4]); + * var B = board.create('point', [-1,-4]); + * var C = board.create('point', [1,1]); + * var el = board.create('ellipse',[A,B,C]); + * </pre><div class="jxgbox" id="JXGa4d7fb6f-8708-4e45-87f2-2379ae2bd2c0" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var glex1_board = JXG.JSXGraph.initBoard('JXGa4d7fb6f-8708-4e45-87f2-2379ae2bd2c0', {boundingbox:[-6,6,6,-6], keepaspectratio:true, showcopyright: false, shownavigation: false}); + * var A = glex1_board.create('point', [-1,4]); + * var B = glex1_board.create('point', [-1,-4]); + * var C = glex1_board.create('point', [1,1]); + * var el = glex1_board.create('ellipse',[A,B,C]); + * })(); + * </script><pre> + * + * @example + * // Create an elliptical arc + * var p1 = board.create('point', [-1, 2]); + * var p2 = board.create('point', [ 1, 2]); + * var p3 = board.create('point', [0, 3]); + * + * var ell = board.create('ellipse', [ + * p1, p2, p3, 0, Math.PI], { + * lastArrow: {type: 7} + * }); + * + * </pre><div id="JXG950f7c07-27a4-4c67-9505-c73c22ce9345" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG950f7c07-27a4-4c67-9505-c73c22ce9345', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * var p1 = board.create('point', [-1, 2]); + * var p2 = board.create('point', [ 1, 2]); + * var p3 = board.create('point', [0, 3]); + * + * var ell = board.create('ellipse', [ + * p1, p2, p3, 0, Math.PI], { + * lastArrow: {type: 7} + * }); + * + * })(); + * + * </script><pre> + * +* + */ + JXG.createEllipse = function (board, parents, attributes) { + var polarForm, curve, M, C, majorAxis, i, + hasPointOrg, + // focus 1 and focus 2 + F = [], + attr_foci = Type.copyAttributes(attributes, board.options, 'conic', 'foci'), + attr_center = Type.copyAttributes(attributes, board.options, 'conic', 'center'), + attr_curve = Type.copyAttributes(attributes, board.options, 'conic'); + + // The foci and the third point are either points or coordinate arrays. + for (i = 0; i < 2; i++) { + // focus i given by coordinates + if (parents[i].length > 1) { + F[i] = board.create('point', parents[i], attr_foci); + // focus i given by point + } else if (Type.isPoint(parents[i])) { + F[i] = board.select(parents[i]); + // given by function + } else if (Type.isFunction(parents[i]) && Type.isPoint(parents[i]()) ) { + F[i] = parents[i](); + // focus i given by point name + } else if (Type.isString(parents[i])) { + F[i] = board.select(parents[i]); + } else { + throw new Error("JSXGraph: Can't create Ellipse with parent types '" + + (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + + "\nPossible parent types: [point,point,point], [point,point,number|function]"); + } + } + + // length of major axis + if (Type.isNumber(parents[2])) { + majorAxis = Type.createFunction(parents[2], board); + } else if (Type.isFunction(parents[2]) && Type.isNumber(parents[2]())) { + majorAxis = parents[2]; + } else { + // point on ellipse + if (Type.isPoint(parents[2])) { + C = board.select(parents[2]); + // point on ellipse given by coordinates + } else if (parents[2].length > 1) { + C = board.create('point', parents[2], attr_foci); + // given by function + } else if (Type.isFunction(parents[2]) && Type.isPoint(parents[2]()) ) { + C = parents[2](); + // focus i given by point name + } else if (Type.isString(parents[2])) { + C = board.select(parents[2]); + } else { + throw new Error("JSXGraph: Can't create Ellipse with parent types '" + + (typeof parents[0]) + "' and '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." + + "\nPossible parent types: [point,point,point], [point,point,number|function]"); + } + /** @ignore */ + majorAxis = function () { + return C.Dist(F[0]) + C.Dist(F[1]); + }; + } + + // to + if (!Type.exists(parents[4])) { + parents[4] = 2 * Math.PI; + } + + // from + if (!Type.exists(parents[3])) { + parents[3] = 0.0; + } + + M = board.create('point', [ + function () { + return (F[0].X() + F[1].X()) * 0.5; + }, + function () { + return (F[0].Y() + F[1].Y()) * 0.5; + } + ], attr_center); + + curve = board.create('curve', [ + function (x) { + return 0; + }, + function (x) { + return 0; + }, + parents[3], + parents[4]], attr_curve); + + curve.majorAxis = majorAxis; + + // Save the original hasPoint method. It will be called inside of the new hasPoint method. + hasPointOrg = curve.hasPoint; + + /** @ignore */ + polarForm = function (phi, suspendUpdate) { + var r, rr, ax, ay, bx, by, axbx, ayby, f; + + if (!suspendUpdate) { + r = majorAxis(); + rr = r * r; + ax = F[0].X(); + ay = F[0].Y(); + bx = F[1].X(); + by = F[1].Y(); + axbx = ax - bx; + ayby = ay - by; + f = (rr - ax * ax - ay * ay + bx * bx + by * by) / (2 * r); + + curve.quadraticform = [ + [f * f - bx * bx - by * by, f * axbx / r + bx, f * ayby / r + by], + [f * axbx / r + bx, (axbx * axbx) / rr - 1, axbx * ayby / rr ], + [f * ayby / r + by, axbx * ayby / rr, (ayby * ayby) / rr - 1] + ]; + } + }; + + /** @ignore */ + curve.X = function (phi, suspendUpdate) { + var r = majorAxis(), + c = F[1].Dist(F[0]), + b = 0.5 * (c * c - r * r) / (c * Math.cos(phi) - r), + beta = Math.atan2(F[1].Y() - F[0].Y(), F[1].X() - F[0].X()); + + if (!suspendUpdate) { + polarForm(phi, suspendUpdate); + } + + return F[0].X() + Math.cos(beta + phi) * b; + }; + + /** @ignore */ + curve.Y = function (phi, suspendUpdate) { + var r = majorAxis(), + c = F[1].Dist(F[0]), + b = 0.5 * (c * c - r * r) / (c * Math.cos(phi) - r), + beta = Math.atan2(F[1].Y() - F[0].Y(), F[1].X() - F[0].X()); + + return F[0].Y() + Math.sin(beta + phi) * b; + }; + + curve.midpoint = curve.center = M; + curve.type = Const.OBJECT_TYPE_CONIC; + curve.subs = { + center: curve.center + }; + curve.inherits.push(curve.center, F[0], F[1]); + if (Type.isPoint(C)) { + curve.inherits.push(C); + } + + /** + * Checks whether (x,y) is near the ellipse line or inside of the ellipse + * (in case JXG.Options.conic#hasInnerPoints is true). + * @param {Number} x Coordinate in x direction, screen coordinates. + * @param {Number} y Coordinate in y direction, screen coordinates. + * @returns {Boolean} True if (x,y) is near the ellipse, False otherwise. + * @private + */ + curve.hasPoint = function (x, y) { + var ac, bc, r, p, dist; + + if (Type.evaluate(this.visProp.hasinnerpoints)) { + ac = F[0].coords; + bc = F[1].coords; + r = this.majorAxis(); + p = new Coords(Const.COORDS_BY_SCREEN, [x, y], this.board); + dist = p.distance(Const.COORDS_BY_USER, ac) + p.distance(Const.COORDS_BY_USER, bc); + + return (dist <= r); + } + + return hasPointOrg.apply(this, arguments); + }; + + M.addChild(curve); + for (i = 0; i < 2; i++) { + if (Type.isPoint(F[i])) { + F[i].addChild(curve); + } + } + if (Type.isPoint(C)) { + C.addChild(curve); + } + curve.setParents(parents); + + return curve; + }; + + /** + * @class This element is used to provide a constructor for an hyperbola. An hyperbola is given by two points (the foci) and a third point on the the hyperbola or + * the length of the major axis. + * @pseudo + * @description + * @name Hyperbola + * @augments Conic + * @constructor + * @type JXG.Curve + * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {JXG.Point,array_JXG.Point,array_JXG.Point,array} point1,point2,point3 Parent elements can be three elements either of type {@link JXG.Point} or array of + * numbers describing the coordinates of a point. In the latter case the point will be constructed automatically as a fixed invisible point. + * @param {JXG.Point,array_JXG.Point,array_number,function} point1,point2,number Parent elements can be two elements either of type {@link JXG.Point} or array of + * numbers describing the coordinates of a point. The third parameter is a number/function which defines the length of the major axis + * @param {Number} start (Optional) parameter of the curve start, default: -π. + * @param {Number} end (Optional) parameter for the curve end, default: π. + * @example + * // Create an Hyperbola by three points + * var A = board.create('point', [-1,4]); + * var B = board.create('point', [-1,-4]); + * var C = board.create('point', [1,1]); + * var el = board.create('hyperbola',[A,B,C]); + * </pre><div class="jxgbox" id="JXGcf99049d-a3fe-407f-b936-27d76550f8c4" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function(){ + * var glex1_board = JXG.JSXGraph.initBoard('JXGcf99049d-a3fe-407f-b936-27d76550f8c4', {boundingbox:[-6,6,6,-6], keepaspectratio:true, showcopyright: false, shownavigation: false}); + * var A = glex1_board.create('point', [-1,4]); + * var B = glex1_board.create('point', [-1,-4]); + * var C = glex1_board.create('point', [1,1]); + * var el = glex1_board.create('hyperbola',[A,B,C]); + * })(); + * </script><pre> + */ + JXG.createHyperbola = function (board, parents, attributes) { + var polarForm, curve, M, C, majorAxis, i, + // focus 1 and focus 2 + F = [], + attr_foci = Type.copyAttributes(attributes, board.options, 'conic', 'foci'), + attr_center = Type.copyAttributes(attributes, board.options, 'conic', 'center'), + attr_curve = Type.copyAttributes(attributes, board.options, 'conic'); + + // The foci and the third point are either points or coordinate arrays. + for (i = 0; i < 2; i++) { + // focus i given by coordinates + if (parents[i].length > 1) { + F[i] = board.create('point', parents[i], attr_foci); + // focus i given by point + } else if (Type.isPoint(parents[i])) { + F[i] = board.select(parents[i]); + // given by function + } else if (Type.isFunction(parents[i]) && Type.isPoint(parents[i]()) ) { + F[i] = parents[i](); + // focus i given by point name + } else if (Type.isString(parents[i])) { + F[i] = board.select(parents[i]); + } else { + throw new Error("JSXGraph: Can't create Hyperbola with parent types '" + + (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + + "\nPossible parent types: [point,point,point], [point,point,number|function]"); + } + } + + // length of major axis + if (Type.isNumber(parents[2])) { + majorAxis = Type.createFunction(parents[2], board); + } else if (Type.isFunction(parents[2]) && Type.isNumber(parents[2]())) { + majorAxis = parents[2]; + } else { + // point on ellipse + if (Type.isPoint(parents[2])) { + C = board.select(parents[2]); + // point on ellipse given by coordinates + } else if (parents[2].length > 1) { + C = board.create('point', parents[2], attr_foci); + // given by function + } else if (Type.isFunction(parents[2]) && Type.isPoint(parents[2]())) { + C = parents[2](); + // focus i given by point name + } else if (Type.isString(parents[2])) { + C = board.select(parents[2]); + } else { + throw new Error("JSXGraph: Can't create Hyperbola with parent types '" + + (typeof parents[0]) + "' and '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." + + "\nPossible parent types: [point,point,point], [point,point,number|function]"); + } + /** @ignore */ + majorAxis = function () { + return C.Dist(F[0]) - C.Dist(F[1]); + }; + } + + // to + if (!Type.exists(parents[4])) { + parents[4] = 1.0001 * Math.PI; + } + + // from + if (!Type.exists(parents[3])) { + parents[3] = -1.0001 * Math.PI; + } + + M = board.create('point', [ + function () { + return (F[0].X() + F[1].X()) * 0.5; + }, + function () { + return (F[0].Y() + F[1].Y()) * 0.5; + } + ], attr_center); + + curve = board.create('curve', [ + function (x) { + return 0; + }, + function (x) { + return 0; + }, parents[3], parents[4]], attr_curve); + + curve.majorAxis = majorAxis; + + // Hyperbola is defined by (a*sec(t),b*tan(t)) and sec(t) = 1/cos(t) + /** @ignore */ + polarForm = function (phi, suspendUpdate) { + var r, rr, ax, ay, bx, by, axbx, ayby, f; + + if (!suspendUpdate) { + r = majorAxis(); + rr = r * r; + ax = F[0].X(); + ay = F[0].Y(); + bx = F[1].X(); + by = F[1].Y(); + axbx = ax - bx; + ayby = ay - by; + f = (rr - ax * ax - ay * ay + bx * bx + by * by) / (2 * r); + + curve.quadraticform = [ + [f * f - bx * bx - by * by, f * axbx / r + bx, f * ayby / r + by], + [f * axbx / r + bx, (axbx * axbx) / rr - 1, axbx * ayby / rr ], + [f * ayby / r + by, axbx * ayby / rr, (ayby * ayby) / rr - 1] + ]; + } + }; + + /** @ignore */ + curve.X = function (phi, suspendUpdate) { + var r = majorAxis(), + c = F[1].Dist(F[0]), + b = 0.5 * (c * c - r * r) / (c * Math.cos(phi) + r), + beta = Math.atan2(F[1].Y() - F[0].Y(), F[1].X() - F[0].X()); + + if (!suspendUpdate) { + polarForm(phi, suspendUpdate); + } + + return F[0].X() + Math.cos(beta + phi) * b; + }; + + /** @ignore */ + curve.Y = function (phi, suspendUpdate) { + var r = majorAxis(), + c = F[1].Dist(F[0]), + b = 0.5 * (c * c - r * r) / (c * Math.cos(phi) + r), + beta = Math.atan2(F[1].Y() - F[0].Y(), F[1].X() - F[0].X()); + + return F[0].Y() + Math.sin(beta + phi) * b; + }; + + curve.midpoint = curve.center = M; + curve.subs = { + center: curve.center + }; + curve.inherits.push(curve.center, F[0], F[1]); + if (Type.isPoint(C)) { + curve.inherits.push(C); + } + curve.type = Const.OBJECT_TYPE_CONIC; + + M.addChild(curve); + for (i = 0; i < 2; i++) { + if (Type.isPoint(F[i])) { + F[i].addChild(curve); + } + } + if (Type.isPoint(C)) { + C.addChild(curve); + } + curve.setParents(parents); + + return curve; + }; + + /** + * @class This element is used to provide a constructor for a parabola. A parabola is given by one point (the focus) and a line (the directrix). + * @pseudo + * @description + * @name Parabola + * @augments Conic + * @constructor + * @type JXG.Curve + * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {JXG.Point,array_JXG.Line} point,line Parent elements are a point and a line or a pair of coordinates. + * Optional parameters three and four are numbers which define the curve length (e.g. start/end). Default values are -pi and pi. + * @example + * // Create a parabola by a point C and a line l. + * var A = board.create('point', [-1,4]); + * var B = board.create('point', [-1,-4]); + * var l = board.create('line', [A,B]); + * var C = board.create('point', [1,1]); + * var el = board.create('parabola',[C,l]); + * </pre><div class="jxgbox" id="JXG524d1aae-217d-44d4-ac58-a19c7ab1de36" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var glex1_board = JXG.JSXGraph.initBoard('JXG524d1aae-217d-44d4-ac58-a19c7ab1de36', {boundingbox:[-6,6,6,-6], keepaspectratio:true, showcopyright: false, shownavigation: false}); + * var A = glex1_board.create('point', [-1,4]); + * var B = glex1_board.create('point', [-1,-4]); + * var l = glex1_board.create('line', [A,B]); + * var C = glex1_board.create('point', [1,1]); + * var el = glex1_board.create('parabola',[C,l]); + * })(); + * </script><pre> + * + * @example + * var par = board.create('parabola',[[3.25, 0], [[0.25, 1],[0.25, 0]]]); + * + * </pre><div id="JXG09252542-b77a-4990-a109-66ffb649a472" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG09252542-b77a-4990-a109-66ffb649a472', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * var par = board.create('parabola',[[3.25, 0], [[0.25, 1],[0.25, 0]]]); + * + * })(); + * + * </script><pre> + * + */ + JXG.createParabola = function (board, parents, attributes) { + var polarForm, curve, M, + // focus + F1 = parents[0], + // directrix + l = parents[1], + attr_foci = Type.copyAttributes(attributes, board.options, 'conic', 'foci'), + attr_center = Type.copyAttributes(attributes, board.options, 'conic', 'center'), + attr_curve = Type.copyAttributes(attributes, board.options, 'conic'), + attr_line; + + // focus 1 given by coordinates + if (parents[0].length > 1) { + F1 = board.create('point', parents[0], attr_foci); + // focus 1 given by point + } else if (Type.isPoint(parents[0])) { + F1 = board.select(parents[0]); + // given by function + } else if (Type.isFunction(parents[0]) && Type.isPoint(parents[0]()) ) { + F1 = parents[0](); + // focus 1 given by point name + } else if (Type.isString(parents[0])) { + F1 = board.select(parents[0]); + } else { + throw new Error("JSXGraph: Can't create Parabola with parent types '" + + (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + + "\nPossible parent types: [point,line]"); + } + + // Create line if given as array of two points. + if (Type.isArray(l) && l.length === 2) { + attr_line = Type.copyAttributes(attributes, board.options, 'conic', 'line'); + l = board.create('line', l, attr_line); + } + + // to + if (!Type.exists(parents[3])) { + parents[3] = 2 * Math.PI; + } + + // from + if (!Type.exists(parents[2])) { + parents[2] = 0; + } + + M = board.create('point', [ + function () { + /* + var v = [0, l.stdform[1], l.stdform[2]]; + v = Mat.crossProduct(v, F1.coords.usrCoords); + return Geometry.meetLineLine(v, l.stdform, 0, board).usrCoords; + */ + return Geometry.projectPointToLine(F1, l, board).usrCoords; + } + ], attr_center); + + /** @ignore */ + curve = board.create('curve', [ + function (x) { + return 0; + }, + function (x) { + return 0; + }, parents[2], parents[3]], attr_curve); + + curve.midpoint = curve.center = M; + curve.subs = { + center: curve.center + }; + curve.inherits.push(curve.center); + + /** @ignore */ + polarForm = function (t, suspendUpdate) { + var a, b, c, ab, px, py; + + if (!suspendUpdate) { + a = l.stdform[1]; + b = l.stdform[2]; + c = l.stdform[0]; + ab = a * a + b * b; + px = F1.X(); + py = F1.Y(); + + curve.quadraticform = [ + [(c * c - ab * (px * px + py * py)), c * a + ab * px, c * b + ab * py], + [c * a + ab * px, -b * b, a * b], + [c * b + ab * py, a * b, -a * a] + ]; + } + }; + + /** @ignore */ + curve.X = function (phi, suspendUpdate) { + var a, det, + beta = l.getAngle(), + d = Geometry.distPointLine(F1.coords.usrCoords, l.stdform), + A = l.point1.coords.usrCoords, + B = l.point2.coords.usrCoords, + M = F1.coords.usrCoords; + + // Handle the case if one of the two defining points of the line is an ideal point + if (A[0] === 0) { + A = [1, B[1] + l.stdform[2], B[2] - l.stdform[1]]; + } else if (B[0] === 0) { + B = [1, A[1] + l.stdform[2], A[2] - l.stdform[1]]; + } + det = ((B[1] - A[1]) * (M[2] - A[2]) - (B[2] - A[2]) * (M[1] - A[1]) >= 0) ? 1 : -1; + a = det * d / (1 - Math.sin(phi)); + + if (!suspendUpdate) { + polarForm(phi, suspendUpdate); + } + + return F1.X() + Math.cos(phi + beta) * a; + }; + + /** @ignore */ + curve.Y = function (phi, suspendUpdate) { + var a, det, + beta = l.getAngle(), + d = Geometry.distPointLine(F1.coords.usrCoords, l.stdform), + A = l.point1.coords.usrCoords, + B = l.point2.coords.usrCoords, + M = F1.coords.usrCoords; + + // Handle the case if one of the two defining points of the line is an ideal point + if (A[0] === 0) { + A = [1, B[1] + l.stdform[2], B[2] - l.stdform[1]]; + } else if (B[0] === 0) { + B = [1, A[1] + l.stdform[2], A[2] - l.stdform[1]]; + } + det = ((B[1] - A[1]) * (M[2] - A[2]) - (B[2] - A[2]) * (M[1] - A[1]) >= 0) ? 1 : -1; + a = det * d / (1 - Math.sin(phi)); + + return F1.Y() + Math.sin(phi + beta) * a; + }; + + curve.type = Const.OBJECT_TYPE_CONIC; + M.addChild(curve); + + if (Type.isPoint(F1)) { + F1.addChild(curve); + curve.inherits.push(F1); + } + + l.addChild(curve); + curve.setParents(parents); + + return curve; + }; + + /** + * + * @class This element is used to provide a constructor for a generic conic section uniquely defined by five points or + * a conic defined by the coefficients of the equation + * <p><i>Ax<sup>2</sup>+ Bxy+Cy<sup>2</sup> + Dx + Ey + F = 0</i></p>. + * Then the parameters are as follows: + * <pre> + * board.create('conic', [A, C, F, B/2, D/2, E/2]); + * </pre> + * @pseudo + * @description + * @name Conic + * @augments JXG.Curve + * @constructor + * @type JXG.Conic + * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {JXG.Point,Array_JXG.Point,Array_JXG.Point,Array_JXG.Point,Array_JXG.Point,Array} a,b,c,d,e Parent elements are five points. + * @param {Number_Number_Number_Number_Number_Number} a_00,a_11,a_22,a_01,a_02,a_12 6 numbers, i.e. A, C, F, B/2, D/2, E/2 + * @example + * // Create a conic section through the points A, B, C, D, and E. + * var A = board.create('point', [1,5]); + * var B = board.create('point', [1,2]); + * var C = board.create('point', [2,0]); + * var D = board.create('point', [0,0]); + * var E = board.create('point', [-1,5]); + * var conic = board.create('conic',[A,B,C,D,E]); + * </pre><div class="jxgbox" id="JXG2d79bd6a-db9b-423c-9cba-2497f0b06320" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function(){ + * var glex1_board = JXG.JSXGraph.initBoard('JXG2d79bd6a-db9b-423c-9cba-2497f0b06320', {boundingbox:[-6,6,6,-6], keepaspectratio:true, showcopyright: false, shownavigation: false}); + * var A = glex1_board.create('point', [1,5]); + * var B = glex1_board.create('point', [1,2]); + * var C = glex1_board.create('point', [2,0]); + * var D = glex1_board.create('point', [0,0]); + * var E = glex1_board.create('point', [-1,5]); + * var conic = glex1_board.create('conic',[A,B,C,D,E]); + * })(); + * </script><pre> + * + * @example + * // Parameters: A, C, F, B/2, D/2, E/2 + * var conic = board.create('conic', [1, 2, -4, 0, 0, 0]s); + * + * </pre><div id="JXG8576a04a-52d8-4a7e-8d54-e32443910b97" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG8576a04a-52d8-4a7e-8d54-e32443910b97', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * // Parameters: A, C, F, B/2, D/2, E/2 + * var conic = board.create('conic', [1, 2, -4, 0, 0, 0]s); + * })(); + * + * </script><pre> + * + */ + JXG.createConic = function (board, parents, attributes) { + var polarForm, curve, fitConic, degconic, sym, + eigen, a, b, c, c1, c2, + i, definingMat, givenByPoints, + rotationMatrix = [ + [1, 0, 0], + [0, 1, 0], + [0, 0, 1] + ], + M = [ + [1, 0, 0], + [0, 1, 0], + [0, 0, 1] + ], + points = [], + p = [], + attr_point = Type.copyAttributes(attributes, board.options, 'conic', 'point'), + attr_center = Type.copyAttributes(attributes, board.options, 'conic', 'center'), + attr_curve = Type.copyAttributes(attributes, board.options, 'conic'); + + if (parents.length === 5) { + givenByPoints = true; + } else if (parents.length === 6) { + givenByPoints = false; + } else { + throw new Error("JSXGraph: Can't create generic Conic with " + parents.length + " parameters."); + } + + if (givenByPoints) { + for (i = 0; i < 5; i++) { + // point i given by coordinates + if (parents[i].length > 1) { + points[i] = board.create('point', parents[i], attr_point); + // point i given by point + } else if (Type.isPoint(parents[i])) { + points[i] = board.select(parents[i]); + // given by function + } else if (Type.isFunction(parents[i]) && Type.isPoint(parents[i]()) ) { + points[i] = parents[i](); + // point i given by point name + } else if (Type.isString(parents[i])) { + points[i] = board.select(parents[i]); + } else { + throw new Error("JSXGraph: Can't create Conic section with parent types '" + (typeof parents[i]) + "'." + + "\nPossible parent types: [point,point,point,point,point], [a00,a11,a22,a01,a02,a12]"); + } + } + } else { + /* Usual notation (x,y,z): + * [[A0,A3,A4], + * [A3,A1,A5], + * [A4,A5,A2]]. + * Our notation (z,x,y): + * [[A2, A4, A5], + * [A4, A0, A3], + * [A5, A3, A1]] + */ + definingMat = [ + [0, 0, 0], + [0, 0, 0], + [0, 0, 0] + ]; + definingMat[0][0] = (Type.isFunction(parents[2])) ? function () { return parents[2](); } : function () { return parents[2]; }; + definingMat[0][1] = (Type.isFunction(parents[4])) ? function () { return parents[4](); } : function () { return parents[4]; }; + definingMat[0][2] = (Type.isFunction(parents[5])) ? function () { return parents[5](); } : function () { return parents[5]; }; + definingMat[1][1] = (Type.isFunction(parents[0])) ? function () { return parents[0](); } : function () { return parents[0]; }; + definingMat[1][2] = (Type.isFunction(parents[3])) ? function () { return parents[3](); } : function () { return parents[3]; }; + definingMat[2][2] = (Type.isFunction(parents[1])) ? function () { return parents[1](); } : function () { return parents[1]; }; + } + + // sym(A) = A + A^t . Manipulates A in place. + sym = function (A) { + var i, j; + for (i = 0; i < 3; i++) { + for (j = i; j < 3; j++) { + A[i][j] += A[j][i]; + } + } + for (i = 0; i < 3; i++) { + for (j = 0; j < i; j++) { + A[i][j] = A[j][i]; + } + } + return A; + }; + + // degconic(v,w) = sym(v*w^t) + degconic = function (v, w) { + var i, j, mat = [ + [0, 0, 0], + [0, 0, 0], + [0, 0, 0] + ]; + + for (i = 0; i < 3; i++) { + for (j = 0; j < 3; j++) { + mat[i][j] = v[i] * w[j]; + } + } + + return sym(mat); + }; + + // (p^t*B*p)*A-(p^t*A*p)*B + fitConic = function (A, B, p) { + var i, j, pBp, pAp, Mv, + mat = [ + [0, 0, 0], + [0, 0, 0], + [0, 0, 0] + ]; + + Mv = Mat.matVecMult(B, p); + pBp = Mat.innerProduct(p, Mv); + Mv = Mat.matVecMult(A, p); + pAp = Mat.innerProduct(p, Mv); + + for (i = 0; i < 3; i++) { + for (j = 0; j < 3; j++) { + mat[i][j] = pBp * A[i][j] - pAp * B[i][j]; + } + } + return mat; + }; + + // Here, the defining functions for the curve are just dummy functions. + // In polarForm there is a reference to curve.quadraticform. + curve = board.create('curve', [ + function (x) { + return 0; + }, + function (x) { + return 0; + }, 0, 2 * Math.PI], attr_curve); + + /** @ignore */ + polarForm = function (phi, suspendUpdate) { + var i, j, len, v; + + if (!suspendUpdate) { + if (givenByPoints) { + // Copy the point coordinate vectors + for (i = 0; i < 5; i++) { + p[i] = points[i].coords.usrCoords; + } + + // Compute the quadratic form + c1 = degconic(Mat.crossProduct(p[0], p[1]), Mat.crossProduct(p[2], p[3])); + c2 = degconic(Mat.crossProduct(p[0], p[2]), Mat.crossProduct(p[1], p[3])); + M = fitConic(c1, c2, p[4]); + } else { + for (i = 0; i < 3; i++) { + for (j = i; j < 3; j++) { + M[i][j] = definingMat[i][j](); + if (j > i) { + M[j][i] = M[i][j]; + } + } + } + } + + // Here is the reference back to the curve. + curve.quadraticform = M; + + // Compute Eigenvalues and Eigenvectors + eigen = Numerics.Jacobi(M); + + // Scale the Eigenvalues such that the first Eigenvalue is positive + if (eigen[0][0][0] < 0) { + eigen[0][0][0] *= (-1); + eigen[0][1][1] *= (-1); + eigen[0][2][2] *= (-1); + } + + // Normalize the Eigenvectors + for (i = 0; i < 3; i++) { + len = 0.0; + for (j = 0; j < 3; j++) { + len += eigen[1][j][i] * eigen[1][j][i]; + } + len = Math.sqrt(len); + /*for (j = 0; j < 3; j++) { + //eigen[1][j][i] /= len; + }*/ + } + rotationMatrix = eigen[1]; + c = Math.sqrt(Math.abs(eigen[0][0][0])); + a = Math.sqrt(Math.abs(eigen[0][1][1])); + b = Math.sqrt(Math.abs(eigen[0][2][2])); + + } + + // The degenerate cases with eigen[0][i][i]==0 are not handled correct yet. + if (eigen[0][1][1] <= 0.0 && eigen[0][2][2] <= 0.0) { + v = Mat.matVecMult(rotationMatrix, [1 / c, Math.cos(phi) / a, Math.sin(phi) / b]); + } else if (eigen[0][1][1] <= 0.0 && eigen[0][2][2] > 0.0) { + v = Mat.matVecMult(rotationMatrix, [Math.cos(phi) / c, 1 / a, Math.sin(phi) / b]); + } else if (eigen[0][2][2] < 0.0) { + v = Mat.matVecMult(rotationMatrix, [Math.sin(phi) / c, Math.cos(phi) / a, 1 / b]); + } + + if (Type.exists(v)) { + // Normalize + v[1] /= v[0]; + v[2] /= v[0]; + v[0] = 1.0; + } else { + v = [1, NaN, NaN]; + } + + return v; + }; + + /** @ignore */ + curve.X = function (phi, suspendUpdate) { + return polarForm(phi, suspendUpdate)[1]; + }; + + /** @ignore */ + curve.Y = function (phi, suspendUpdate) { + return polarForm(phi, suspendUpdate)[2]; + }; + + // Center coordinates see http://en.wikipedia.org/wiki/Matrix_representation_of_conic_sections + curve.midpoint = board.create('point', [ + function () { + var m = curve.quadraticform; + + return [ + m[1][1] * m[2][2] - m[1][2] * m[1][2], + m[1][2] * m[0][2] - m[2][2] * m[0][1], + m[0][1] * m[1][2] - m[1][1] * m[0][2] + ]; + } + ], attr_center); + + curve.type = Const.OBJECT_TYPE_CONIC; + curve.center = curve.midpoint; + curve.subs = { + center: curve.center + }; + curve.inherits.push(curve.center); + curve.inherits = curve.inherits.concat(points); + + if (givenByPoints) { + for (i = 0; i < 5; i++) { + if (Type.isPoint(points[i])) { + points[i].addChild(curve); + } + } + curve.setParents(parents); + } + curve.addChild(curve.center); + + return curve; + }; + + JXG.registerElement('ellipse', JXG.createEllipse); + JXG.registerElement('hyperbola', JXG.createHyperbola); + JXG.registerElement('parabola', JXG.createParabola); + JXG.registerElement('conic', JXG.createConic); + + return { + createEllipse: JXG.createEllipse, + createHyperbola: JXG.createHyperbola, + createParabola: JXG.createParabola, + createConic: JXG.createConic + }; +}); + +/* + Copyright 2008-2022 + Matthias Ehmann, + Michael Gerhaeuser, + Carsten Miller, + Bianca Valentin, + Alfred Wassermann, + Peter Wilfahrt + + This file is part of JSXGraph. + + JSXGraph is free software dual licensed under the GNU LGPL or MIT License. + + You can redistribute it and/or modify it under the terms of the + + * GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version + OR + * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT + + JSXGraph is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License and + the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> + and <http://opensource.org/licenses/MIT/>. + */ + + +/*global JXG: true, define: true*/ +/*jslint nomen: true, plusplus: true*/ + +/* depends: + jxg + base/element + base/constants + base/coords + parser/geonext + math/geometry + math/statistics + utils/type + elements: + transform + point + */ + +/** + * @fileoverview The geometry object Circle is defined in this file. Circle stores all + * style and functional properties that are required to draw and move a circle on + * a board. + */ + +define('base/circle',[ + 'jxg', 'base/element', 'base/coords', 'base/constants', 'element/conic', 'parser/geonext', 'utils/type' +], function (JXG, GeometryElement, Coords, Const, Conic, GeonextParser, Type) { + + "use strict"; + + /** + * A circle consists of all points with a given distance from one point. This point is called center, the distance is called radius. + * A circle can be constructed by providing a center and a point on the circle or a center and a radius (given as a number, function, + * line, or circle). + * @class Creates a new circle object. Do not use this constructor to create a circle. Use {@link JXG.Board#create} with + * type {@link Circle} instead. + * @constructor + * @augments JXG.GeometryElement + * @param {JXG.Board} board The board the new circle is drawn on. + * @param {String} method Can be + * <ul><li> <b>'twoPoints'</b> which means the circle is defined by its center and a point on the circle.</li> + * <li><b>'pointRadius'</b> which means the circle is defined by its center and its radius in user units</li> + * <li><b>'pointLine'</b> which means the circle is defined by its center and its radius given by the distance from the startpoint and the endpoint of the line</li> + * <li><b>'pointCircle'</b> which means the circle is defined by its center and its radius given by the radius of another circle</li></ul> + * The parameters p1, p2 and radius must be set according to this method parameter. + * @param {JXG.Point} par1 center of the circle. + * @param {JXG.Point|JXG.Line|JXG.Circle} par2 Can be + * <ul><li>a point on the circle if method is 'twoPoints'</li> + * <li>a line if the method is 'pointLine'</li> + * <li>a circle if the method is 'pointCircle'</li></ul> + * @param {Object} attributes + * @see JXG.Board#generateName + */ + JXG.Circle = function (board, method, par1, par2, attributes) { + // Call the constructor of GeometryElement + this.constructor(board, attributes, Const.OBJECT_TYPE_CIRCLE, Const.OBJECT_CLASS_CIRCLE); + + /** + * Stores the given method. + * Can be + * <ul><li><b>'twoPoints'</b> which means the circle is defined by its center and a point on the circle.</li> + * <li><b>'pointRadius'</b> which means the circle is defined by its center and its radius given in user units or as term.</li> + * <li><b>'pointLine'</b> which means the circle is defined by its center and its radius given by the distance from the startpoint and the endpoint of the line.</li> + * <li><b>'pointCircle'</b> which means the circle is defined by its center and its radius given by the radius of another circle.</li></ul> + * @type String + * @see #center + * @see #point2 + * @see #radius + * @see #line + * @see #circle + */ + this.method = method; + + // this is kept so existing code won't ne broken + this.midpoint = this.board.select(par1); + + /** + * The circles center. Do not set this parameter directly as it will break JSXGraph's update system. + * @type JXG.Point + */ + this.center = this.board.select(par1); + + /** Point on the circle only set if method equals 'twoPoints'. Do not set this parameter directly as it will break JSXGraph's update system. + * @type JXG.Point + * @see #method + */ + this.point2 = null; + + /** Radius of the circle + * only set if method equals 'pointRadius' + * @type Number + * @default null + * @see #method + */ + this.radius = 0; + + /** Line defining the radius of the circle given by the distance from the startpoint and the endpoint of the line + * only set if method equals 'pointLine'. Do not set this parameter directly as it will break JSXGraph's update system. + * @type JXG.Line + * @default null + * @see #method + */ + this.line = null; + + /** Circle defining the radius of the circle given by the radius of the other circle + * only set if method equals 'pointLine'. Do not set this parameter directly as it will break JSXGraph's update system. + * @type JXG.Circle + * @default null + * @see #method + */ + this.circle = null; + + this.points = []; + + if (method === 'twoPoints') { + this.point2 = board.select(par2); + this.radius = this.Radius(); + } else if (method === 'pointRadius') { + this.gxtterm = par2; + // Converts GEONExT syntax into JavaScript syntax and generally ensures that the radius is a function + this.updateRadius = Type.createFunction(par2, this.board, null, true); + // First evaluation of the radius function + this.updateRadius(); + } else if (method === 'pointLine') { + // dann ist p2 die Id eines Objekts vom Typ Line! + this.line = board.select(par2); + this.radius = this.line.point1.coords.distance(Const.COORDS_BY_USER, this.line.point2.coords); + } else if (method === 'pointCircle') { + // dann ist p2 die Id eines Objekts vom Typ Circle! + this.circle = board.select(par2); + this.radius = this.circle.Radius(); + } + + // create Label + this.id = this.board.setId(this, 'C'); + this.board.renderer.drawEllipse(this); + this.board.finalizeAdding(this); + + this.createGradient(); + this.elType = 'circle'; + this.createLabel(); + + if (Type.exists(this.center._is_new)) { + this.addChild(this.center); + delete this.center._is_new; + } else { + this.center.addChild(this); + } + + if (method === 'pointRadius') { + this.notifyParents(par2); + } else if (method === 'pointLine') { + this.line.addChild(this); + } else if (method === 'pointCircle') { + this.circle.addChild(this); + } else if (method === 'twoPoints') { + if (Type.exists(this.point2._is_new)) { + this.addChild(this.point2); + delete this.point2._is_new; + } else { + this.point2.addChild(this); + } + } + + this.methodMap = Type.deepCopy(this.methodMap, { + setRadius: 'setRadius', + getRadius: 'getRadius', + Area: 'Area', + area: 'Area', + radius: 'Radius', + center: 'center', + line: 'line', + point2: 'point2' + }); + }; + + JXG.Circle.prototype = new GeometryElement(); + + JXG.extend(JXG.Circle.prototype, /** @lends JXG.Circle.prototype */ { + /** + * Checks whether (x,y) is near the circle line or inside of the ellipse + * (in case JXG.Options.conic#hasInnerPoints is true). + * @param {Number} x Coordinate in x direction, screen coordinates. + * @param {Number} y Coordinate in y direction, screen coordinates. + * @returns {Boolean} True if (x,y) is near the circle, False otherwise. + * @private + */ + hasPoint: function (x, y) { + var prec, type, + mp = this.center.coords.usrCoords, + p = new Coords(Const.COORDS_BY_SCREEN, [x, y], this.board), + r = this.Radius(), + dx, dy, dist; + + + if (Type.isObject(Type.evaluate(this.visProp.precision))) { + type = this.board._inputDevice; + prec = Type.evaluate(this.visProp.precision[type]); + } else { + // 'inherit' + prec = this.board.options.precision.hasPoint; + } + dx = mp[1] - p.usrCoords[1]; + dy = mp[2] - p.usrCoords[2]; + dist = Math.sqrt(dx * dx + dy * dy); + // We have to use usrCoords, since Radius is available in usrCoords only. + prec += Type.evaluate(this.visProp.strokewidth) * 0.5; + prec /= Math.sqrt(this.board.unitX * this.board.unitY); + + if (Type.evaluate(this.visProp.hasinnerpoints)) { + return (dist < r + prec); + } + + return (Math.abs(dist - r) < prec); + }, + + /** + * Used to generate a polynomial for a point p that lies on this circle. + * @param {JXG.Point} p The point for which the polynomial is generated. + * @returns {Array} An array containing the generated polynomial. + * @private + */ + generatePolynomial: function (p) { + /* + * We have four methods to construct a circle: + * (a) Two points + * (b) center and radius + * (c) center and radius given by length of a segment + * (d) center and radius given by another circle + * + * In case (b) we have to distinguish two cases: + * (i) radius is given as a number + * (ii) radius is given as a function + * In the latter case there's no guarantee the radius depends on other geometry elements + * in a polynomial way so this case has to be omitted. + * + * Another tricky case is case (d): + * The radius depends on another circle so we have to cycle through the ancestors of each circle + * until we reach one that's radius does not depend on another circles radius. + * + * + * All cases (a) to (d) vary only in calculation of the radius. So the basic formulae for + * a glider G (g1,g2) on a circle with center M (m1,m2) and radius r is just: + * + * (g1-m1)^2 + (g2-m2)^2 - r^2 = 0 + * + * So the easiest case is (b) with a fixed radius given as a number. The other two cases (a) + * and (c) are quite the same: Euclidean distance between two points A (a1,a2) and B (b1,b2), + * squared: + * + * r^2 = (a1-b1)^2 + (a2-b2)^2 + * + * For case (d) we have to cycle recursively through all defining circles and finally return the + * formulae for calculating r^2. For that we use JXG.Circle.symbolic.generateRadiusSquared(). + */ + var m1 = this.center.symbolic.x, + m2 = this.center.symbolic.y, + g1 = p.symbolic.x, + g2 = p.symbolic.y, + rsq = this.generateRadiusSquared(); + + /* No radius can be calculated (Case b.ii) */ + if (rsq === '') { + return []; + } + + return ['((' + g1 + ')-(' + m1 + '))^2 + ((' + g2 + ')-(' + m2 + '))^2 - (' + rsq + ')']; + }, + + /** + * Generate symbolic radius calculation for loci determination with Groebner-Basis algorithm. + * @returns {String} String containing symbolic calculation of the circle's radius or an empty string + * if the radius can't be expressed in a polynomial equation. + * @private + */ + generateRadiusSquared: function () { + /* + * Four cases: + * + * (a) Two points + * (b) center and radius + * (c) center and radius given by length of a segment + * (d) center and radius given by another circle + */ + var m1, m2, p1, p2, q1, q2, + rsq = ''; + + if (this.method === "twoPoints") { + m1 = this.center.symbolic.x; + m2 = this.center.symbolic.y; + p1 = this.point2.symbolic.x; + p2 = this.point2.symbolic.y; + + rsq = '((' + p1 + ')-(' + m1 + '))^2 + ((' + p2 + ')-(' + m2 + '))^2'; + } else if (this.method === "pointRadius") { + if (Type.isNumber(this.radius)) { + rsq = (this.radius * this.radius).toString(); + } + } else if (this.method === "pointLine") { + p1 = this.line.point1.symbolic.x; + p2 = this.line.point1.symbolic.y; + + q1 = this.line.point2.symbolic.x; + q2 = this.line.point2.symbolic.y; + + rsq = '((' + p1 + ')-(' + q1 + '))^2 + ((' + p2 + ')-(' + q2 + '))^2'; + } else if (this.method === "pointCircle") { + rsq = this.circle.Radius(); + } + + return rsq; + }, + + /** + * Uses the boards renderer to update the circle. + */ + update: function () { + var x, y, z, r, c, i; + + if (this.needsUpdate) { + if (Type.evaluate(this.visProp.trace)) { + this.cloneToBackground(true); + } + + if (this.method === 'pointLine') { + this.radius = this.line.point1.coords.distance(Const.COORDS_BY_USER, this.line.point2.coords); + } else if (this.method === 'pointCircle') { + this.radius = this.circle.Radius(); + } else if (this.method === 'pointRadius') { + this.radius = this.updateRadius(); + } + + this.updateStdform(); + this.updateQuadraticform(); + + // Approximate the circle by 4 Bezier segments + // This will be used for intersections of type curve / circle. + // See https://spencermortensen.com/articles/bezier-circle/ + z = this.center.coords.usrCoords[0]; + x = this.center.coords.usrCoords[1] / z; + y = this.center.coords.usrCoords[2] / z; + z /= z; + r = this.Radius(); + c = 0.551915024494; + + this.numberPoints = 13; + this.dataX = [x + r, x + r, x + r * c, x, x - r * c, x - r, x - r, x - r, x - r * c, x, x + r * c, x + r, x + r]; + this.dataY = [y, y + r * c, y + r, y + r, y + r, y + r * c, y, y - r * c, y - r, y - r, y - r, y - r * c, y]; + this.bezierDegree = 3; + for (i = 0; i < this.numberPoints; i++) { + this.points[i] = new Coords(Const.COORDS_BY_USER, [this.dataX[i], this.dataY[i]], this.board); + } + } + + return this; + }, + + /** + * Updates this circle's {@link JXG.Circle#quadraticform}. + * @private + */ + updateQuadraticform: function () { + var m = this.center, + mX = m.X(), + mY = m.Y(), + r = this.Radius(); + + this.quadraticform = [ + [mX * mX + mY * mY - r * r, -mX, -mY], + [-mX, 1, 0], + [-mY, 0, 1] + ]; + }, + + /** + * Updates the stdform derived from the position of the center and the circle's radius. + * @private + */ + updateStdform: function () { + this.stdform[3] = 0.5; + this.stdform[4] = this.Radius(); + this.stdform[1] = -this.center.coords.usrCoords[1]; + this.stdform[2] = -this.center.coords.usrCoords[2]; + if (!isFinite(this.stdform[4])) { + this.stdform[0] = Type.exists(this.point2) ? -( + this.stdform[1] * this.point2.coords.usrCoords[1] + + this.stdform[2] * this.point2.coords.usrCoords[2] + ) : 0; + } + this.normalize(); + }, + + /** + * Uses the boards renderer to update the circle. + * @private + */ + updateRenderer: function () { + // var wasReal; + + if (!this.needsUpdate) { + return this; + } + + if (this.visPropCalc.visible) { + // wasReal = this.isReal; + this.isReal = (!isNaN(this.center.coords.usrCoords[1] + this.center.coords.usrCoords[2] + this.Radius())) && this.center.isReal; + + if (//wasReal && + !this.isReal) { + this.updateVisibility(false); + } + } + + // Update the position + if (this.visPropCalc.visible) { + this.board.renderer.updateEllipse(this); + } + + // Update the label if visible. + if (this.hasLabel && this.visPropCalc.visible && this.label && + this.label.visPropCalc.visible && this.isReal) { + + this.label.update(); + this.board.renderer.updateText(this.label); + } + + // Update rendNode display + this.setDisplayRendNode(); + // if (this.visPropCalc.visible !== this.visPropOld.visible) { + // this.board.renderer.display(this, this.visPropCalc.visible); + // this.visPropOld.visible = this.visPropCalc.visible; + // + // if (this.hasLabel) { + // this.board.renderer.display(this.label, this.label.visPropCalc.visible); + // } + // } + + this.needsUpdate = false; + return this; + }, + + /** + * Finds dependencies in a given term and resolves them by adding the elements referenced in this + * string to the circle's list of ancestors. + * @param {String} contentStr + * @private + */ + notifyParents: function (contentStr) { + if (Type.isString(contentStr)) { + GeonextParser.findDependencies(this, contentStr, this.board); + } + }, + + /** + * Set a new radius, then update the board. + * @param {String|Number|function} r A string, function or number describing the new radius. + * @returns {JXG.Circle} Reference to this circle + */ + setRadius: function (r) { + this.updateRadius = Type.createFunction(r, this.board, null, true); + this.board.update(); + + return this; + }, + + /** + * Calculates the radius of the circle. + * @param {String|Number|function} [value] Set new radius + * @returns {Number} The radius of the circle + */ + Radius: function (value) { + if (Type.exists(value)) { + this.setRadius(value); + return this.Radius(); + } + + if (this.method === 'twoPoints') { + if (Type.cmpArrays(this.point2.coords.usrCoords, [0, 0, 0]) || + Type.cmpArrays(this.center.coords.usrCoords, [0, 0, 0])) { + + return NaN; + } + + return this.center.Dist(this.point2); + } + + if (this.method === 'pointLine' || this.method === 'pointCircle') { + return this.radius; + } + + if (this.method === 'pointRadius') { + return this.updateRadius(); + } + + return NaN; + }, + + /** + * Use {@link JXG.Circle#Radius}. + * @deprecated + */ + getRadius: function () { + JXG.deprecated('Circle.getRadius()', 'Circle.Radius()'); + return this.Radius(); + }, + + // documented in geometry element + getTextAnchor: function () { + return this.center.coords; + }, + + // documented in geometry element + getLabelAnchor: function () { + var x, y, + r = this.Radius(), + c = this.center.coords.usrCoords, + SQRTH = 7.07106781186547524401E-1; // sqrt(2)/2 + + switch (Type.evaluate(this.visProp.label.position)) { + case 'lft': + x = c[1] - r; + y = c[2]; + break; + case 'llft': + x = c[1] - SQRTH * r; + y = c[2] - SQRTH * r; + break; + case 'rt': + x = c[1] + r; + y = c[2]; + break; + case 'lrt': + x = c[1] + SQRTH * r; + y = c[2] - SQRTH * r; + break; + case 'urt': + x = c[1] + SQRTH * r; + y = c[2] + SQRTH * r; + break; + case 'top': + x = c[1]; + y = c[2] + r; + break; + case 'bot': + x = c[1]; + y = c[2] - r; + break; + default: + // includes case 'ulft' + x = c[1] - SQRTH * r; + y = c[2] + SQRTH * r; + break; + } + + return new Coords(Const.COORDS_BY_USER, [x, y], this.board); + }, + + // documented in geometry element + cloneToBackground: function () { + var er, + r = this.Radius(), + copy = { + id: this.id + 'T' + this.numTraces, + elementClass: Const.OBJECT_CLASS_CIRCLE, + center: { + coords: this.center.coords + }, + Radius: function () { + return r; + }, + getRadius: function () { + return r; + }, + board: this.board, + visProp: Type.deepCopy(this.visProp, this.visProp.traceattributes, true) + }; + + copy.visProp.layer = this.board.options.layer.trace; + + this.numTraces++; + Type.clearVisPropOld(copy); + copy.visPropCalc = { + visible: Type.evaluate(copy.visProp.visible) + }; + + er = this.board.renderer.enhancedRendering; + this.board.renderer.enhancedRendering = true; + this.board.renderer.drawEllipse(copy); + this.board.renderer.enhancedRendering = er; + this.traces[copy.id] = copy.rendNode; + + return this; + }, + + /** + * Add transformations to this circle. + * @param {JXG.Transformation|Array} transform Either one {@link JXG.Transformation} or an array of {@link JXG.Transformation}s. + * @returns {JXG.Circle} Reference to this circle object. + */ + addTransform: function (transform) { + var i, + list = Type.isArray(transform) ? transform : [transform], + len = list.length; + + for (i = 0; i < len; i++) { + this.center.transformations.push(list[i]); + + if (this.method === 'twoPoints') { + this.point2.transformations.push(list[i]); + } + } + + return this; + }, + + // see element.js + snapToGrid: function () { + var forceIt = Type.evaluate(this.visProp.snaptogrid); + + this.center.handleSnapToGrid(forceIt, true); + if (this.method === 'twoPoints') { + this.point2.handleSnapToGrid(forceIt, true); + } + + return this; + }, + + // see element.js + snapToPoints: function () { + var forceIt = Type.evaluate(this.visProp.snaptopoints); + + this.center.handleSnapToPoints(forceIt); + if (this.method === 'twoPoints') { + this.point2.handleSnapToPoints(forceIt); + } + + return this; + }, + + /** + * Treats the circle as parametric curve and calculates its X coordinate. + * @param {Number} t Number between 0 and 1. + * @returns {Number} <tt>X(t)= radius*cos(t)+centerX</tt>. + */ + X: function (t) { + return this.Radius() * Math.cos(t * 2 * Math.PI) + this.center.coords.usrCoords[1]; + }, + + /** + * Treats the circle as parametric curve and calculates its Y coordinate. + * @param {Number} t Number between 0 and 1. + * @returns {Number} <tt>X(t)= radius*sin(t)+centerY</tt>. + */ + Y: function (t) { + return this.Radius() * Math.sin(t * 2 * Math.PI) + this.center.coords.usrCoords[2]; + }, + + /** + * Treat the circle as parametric curve and calculates its Z coordinate. + * @param {Number} t ignored + * @returns {Number} 1.0 + */ + Z: function (t) { + return 1.0; + }, + + /** + * Returns 0. + * @private + */ + minX: function () { + return 0.0; + }, + + /** + * Returns 1. + * @private + */ + maxX: function () { + return 1.0; + }, + + /** + * Circle area + * @returns {Number} area of the circle. + */ + Area: function () { + var r = this.Radius(); + + return r * r * Math.PI; + }, + + /** + * Get bounding box of the circle. + * @returns {Array} [x1, y1, x2, y2] + */ + bounds: function () { + var uc = this.center.coords.usrCoords, + r = this.Radius(); + + return [uc[1] - r, uc[2] + r, uc[1] + r, uc[2] - r]; + }, + + /** + * Get data to construct this element. Data consists of the parent elements + * and static data like radius. + * @returns {Array} data necessary to construct this element + */ + getParents: function() { + if (this.parents.length === 1) { // i.e. this.method === 'pointRadius' + return this.parents.concat(this.radius); + } + return this.parents; + } + }); + + /** + * @class This element is used to provide a constructor for a circle. + * @pseudo + * @description A circle consists of all points with a given distance from one point. This point is called center, the distance is called radius. + * A circle can be constructed by providing a center and a point on the circle or a center and a radius (given as a number, function, + * line, or circle). + * @name Circle + * @augments JXG.Circle + * @constructor + * @type JXG.Circle + * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {JXG.Point_number,JXG.Point,JXG.Line,JXG.Circle} center,radius The center must be given as a {@link JXG.Point}, see {@link JXG.providePoints}, but the radius can be given + * as a number (which will create a circle with a fixed radius), another {@link JXG.Point}, a {@link JXG.Line} (the distance of start and end point of the + * line will determine the radius), or another {@link JXG.Circle}. + * @example + * // Create a circle providing two points + * var p1 = board.create('point', [2.0, 2.0]), + * p2 = board.create('point', [2.0, 0.0]), + * c1 = board.create('circle', [p1, p2]); + * + * // Create another circle using the above circle + * var p3 = board.create('point', [3.0, 2.0]), + * c2 = board.create('circle', [p3, c1]); + * </pre><div class="jxgbox" id="JXG5f304d31-ef20-4a8e-9c0e-ea1a2b6c79e0" style="width: 400px; height: 400px;"></div> + * <script type="text/javascript"> + * (function() { + * var cex1_board = JXG.JSXGraph.initBoard('JXG5f304d31-ef20-4a8e-9c0e-ea1a2b6c79e0', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); + * cex1_p1 = cex1_board.create('point', [2.0, 2.0]), + * cex1_p2 = cex1_board.create('point', [2.0, 0.0]), + * cex1_c1 = cex1_board.create('circle', [cex1_p1, cex1_p2]), + * cex1_p3 = cex1_board.create('point', [3.0, 2.0]), + * cex1_c2 = cex1_board.create('circle', [cex1_p3, cex1_c1]); + * })(); + * </script><pre> + * @example + * // Create a circle providing two points + * var p1 = board.create('point', [2.0, 2.0]), + * c1 = board.create('circle', [p1, 3]); + * + * // Create another circle using the above circle + * var c2 = board.create('circle', [function() { return [p1.X(), p1.Y() + 1];}, function() { return c1.Radius(); }]); + * </pre><div class="jxgbox" id="JXG54165f60-93b9-441d-8979-ac5d0f193020" style="width: 400px; height: 400px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG54165f60-93b9-441d-8979-ac5d0f193020', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); + * var p1 = board.create('point', [2.0, 2.0]); + * var c1 = board.create('circle', [p1, 3]); + * + * // Create another circle using the above circle + * var c2 = board.create('circle', [function() { return [p1.X(), p1.Y() + 1];}, function() { return c1.Radius(); }]); + * })(); + * </script><pre> + * @example + * var li = board.create('line', [1,1,1], {strokeColor: '#aaaaaa'}); + * var reflect = board.create('transform', [li], {type: 'reflect'}); + * + * var c1 = board.create('circle', [[-2,-2], [-2, -1]], {center: {visible:true}}); + * var c2 = board.create('circle', [c1, reflect]); + * * </pre><div id="JXGa2a5a870-5dbb-11e8-9fb9-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXGa2a5a870-5dbb-11e8-9fb9-901b0e1b8723', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * var li = board.create('line', [1,1,1], {strokeColor: '#aaaaaa'}); + * var reflect = board.create('transform', [li], {type: 'reflect'}); + * + * var c1 = board.create('circle', [[-2,-2], [-2, -1]], {center: {visible:true}}); + * var c2 = board.create('circle', [c1, reflect]); + * })(); + * + * </script><pre> + * + * @example + * var t = board.create('transform', [2, 1.5], {type: 'scale'}); + * var c1 = board.create('circle', [[1.3, 1.3], [0, 1.3]], {strokeColor: 'black', center: {visible:true}}); + * var c2 = board.create('circle', [c1, t], {strokeColor: 'black'}); + * + * </pre><div id="JXG0686a222-6339-11e8-9fb9-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG0686a222-6339-11e8-9fb9-901b0e1b8723', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * var t = board.create('transform', [2, 1.5], {type: 'scale'}); + * var c1 = board.create('circle', [[1.3, 1.3], [0, 1.3]], {strokeColor: 'black', center: {visible:true}}); + * var c2 = board.create('circle', [c1, t], {strokeColor: 'black'}); + * + * })(); + * + * </script><pre> + * + */ + JXG.createCircle = function (board, parents, attributes) { + var el, p, i, attr, obj, + isDraggable = true, + point_style = ['center', 'point2']; + + p = []; + obj = board.select(parents[0]); + if (Type.isObject(obj) && obj.elementClass === Const.OBJECT_CLASS_CIRCLE && + Type.isTransformationOrArray(parents[1])) { + + attr = Type.copyAttributes(attributes, board.options, 'circle'); + // if (!Type.exists(attr.type) || attr.type.toLowerCase() !== 'euclidean') { + // // Create a circle element from a circle and a Euclidean transformation + // el = JXG.createCircle(board, [obj.center, function() { return obj.Radius(); }], attr); + // } else { + // Create a conic element from a circle and a projective transformation + el = Conic.createEllipse(board, [obj.center, obj.center, function() { return 2 * obj.Radius(); }], attr); + // } + el.addTransform(parents[1]); + return el; + + } + // Circle defined by points + for (i = 0; i < parents.length; i++) { + if (Type.isPointType(board, parents[i])) { + p = p.concat(Type.providePoints(board, [parents[i]], attributes, 'circle', [point_style[i]])); + if (p[p.length - 1] === false) { + throw new Error('JSXGraph: Can\'t create circle from this type. Please provide a point type.'); + } + } else { + p.push(parents[i]); + } + } + + attr = Type.copyAttributes(attributes, board.options, 'circle'); + + if (p.length === 2 && Type.isPoint(p[0]) && Type.isPoint(p[1])) { + // Point/Point + el = new JXG.Circle(board, 'twoPoints', p[0], p[1], attr); + } else if ((Type.isNumber(p[0]) || Type.isFunction(p[0]) || Type.isString(p[0])) && + Type.isPoint(p[1])) { + // Number/Point + el = new JXG.Circle(board, 'pointRadius', p[1], p[0], attr); + } else if ((Type.isNumber(p[1]) || Type.isFunction(p[1]) || Type.isString(p[1])) && + Type.isPoint(p[0])) { + // Point/Number + el = new JXG.Circle(board, 'pointRadius', p[0], p[1], attr); + } else if ((p[0].elementClass === Const.OBJECT_CLASS_CIRCLE) && Type.isPoint(p[1])) { + // Circle/Point + el = new JXG.Circle(board, 'pointCircle', p[1], p[0], attr); + } else if ((p[1].elementClass === Const.OBJECT_CLASS_CIRCLE) && Type.isPoint(p[0])) { + // Point/Circle + el = new JXG.Circle(board, 'pointCircle', p[0], p[1], attr); + } else if ((p[0].elementClass === Const.OBJECT_CLASS_LINE) && Type.isPoint(p[1])) { + // Line/Point + el = new JXG.Circle(board, 'pointLine', p[1], p[0], attr); + } else if ((p[1].elementClass === Const.OBJECT_CLASS_LINE) && Type.isPoint(p[0])) { + // Point/Line + el = new JXG.Circle(board, 'pointLine', p[0], p[1], attr); + } else if (parents.length === 3 && Type.isPoint(p[0]) && Type.isPoint(p[1]) && Type.isPoint(p[2])) { + // Circle through three points + // Check if circumcircle element is available + if (JXG.elements.circumcircle) { + el = JXG.elements.circumcircle(board, p, attr); + } else { + throw new Error('JSXGraph: Can\'t create circle with three points. Please include the circumcircle element (element/composition).'); + } + + } else { + throw new Error("JSXGraph: Can't create circle with parent types '" + + (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + + "\nPossible parent types: [point,point], [point,number], [point,function], [point,circle], [point,point,point], [circle,transformation]"); + } + + el.isDraggable = isDraggable; + el.setParents(p); + el.elType = 'circle'; + for (i = 0; i < p.length; i++) { + if (Type.isPoint(p[i])) { + el.inherits.push(p[i]); + } + } + return el; + }; + + JXG.registerElement('circle', JXG.createCircle); + + return { + Circle: JXG.Circle, + createCircle: JXG.createCircle + }; +}); + +/* + Copyright 2008-2022 + Matthias Ehmann, + Michael Gerhaeuser, + Carsten Miller, + Bianca Valentin, + Alfred Wassermann, + Peter Wilfahrt + + This file is part of JSXGraph. + + JSXGraph is free software dual licensed under the GNU LGPL or MIT License. + + You can redistribute it and/or modify it under the terms of the + + * GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version + OR + * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT + + JSXGraph is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License and + the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> + and <http://opensource.org/licenses/MIT/>. + */ + + +/*global JXG:true, define: true*/ +/*jslint nomen: true, plusplus: true*/ + +/* depends: + jxg + base/constants + base/coords + math/statistics + utils/type + base/element + elements: + segment + transform + */ + +define('base/polygon',[ + 'jxg', 'base/constants', 'base/coords', 'math/statistics', 'math/geometry', 'utils/type', 'base/element' +], function (JXG, Const, Coords, Statistics, Geometry, Type, GeometryElement) { + + "use strict"; + + /** + * Creates a new instance of JXG.Polygon. + * @class Polygon stores all style and functional properties that are required + * to draw and to interactact with a polygon. + * @param {JXG.Board} board Reference to the board the polygon is to be drawn on. + * @param {Array} vertices Unique identifiers for the points defining the polygon. + * Last point must be first point. Otherwise, the first point will be added at the list. + * @param {Object} attributes An object which contains properties as given in {@link JXG.Options.elements} + * and {@link JXG.Options.polygon}. + * @constructor + * @extends JXG.GeometryElement + */ + + JXG.Polygon = function (board, vertices, attributes) { + this.constructor(board, attributes, Const.OBJECT_TYPE_POLYGON, Const.OBJECT_CLASS_AREA); + + var i, l, len, j, p, + attr_line = Type.copyAttributes(attributes, board.options, 'polygon', 'borders'); + + this.withLines = attributes.withlines; + this.attr_line = attr_line; + + /** + * References to the points defining the polygon. The last vertex is the same as the first vertex. + * @type Array + */ + this.vertices = []; + for (i = 0; i < vertices.length; i++) { + this.vertices[i] = this.board.select(vertices[i]); + } + + // Close the polygon + if (this.vertices.length > 0 && this.vertices[this.vertices.length - 1].id !== this.vertices[0].id) { + this.vertices.push(this.vertices[0]); + } + + /** + * References to the border lines of the polygon. + * @type Array + */ + this.borders = []; + + if (this.withLines) { + len = this.vertices.length - 1; + for (j = 0; j < len; j++) { + // This sets the "correct" labels for the first triangle of a construction. + i = (j + 1) % len; + attr_line.id = attr_line.ids && attr_line.ids[i]; + attr_line.name = attr_line.names && attr_line.names[i]; + attr_line.strokecolor = (Type.isArray(attr_line.colors) && attr_line.colors[i % attr_line.colors.length]) || + attr_line.strokecolor; + attr_line.visible = Type.exists(attributes.borders.visible) ? attributes.borders.visible : attributes.visible; + + if (attr_line.strokecolor === false) { + attr_line.strokecolor = 'none'; + } + + l = board.create('segment', [this.vertices[i], this.vertices[i + 1]], attr_line); + l.dump = false; + this.borders[i] = l; + l.parentPolygon = this; + } + } + + this.inherits.push(this.vertices, this.borders); + + // Register polygon at board + // This needs to be done BEFORE the points get this polygon added in their descendants list + this.id = this.board.setId(this, 'Py'); + + // Add dependencies: either + // - add polygon as child to an existing point + // or + // - add points (supplied as coordinate arrays by the user and created by Type.providePoints) as children to the polygon + for (i = 0; i < this.vertices.length - 1; i++) { + p = this.board.select(this.vertices[i]); + if (Type.exists(p._is_new)) { + this.addChild(p); + delete p._is_new; + } else { + p.addChild(this); + } + } + + this.board.renderer.drawPolygon(this); + this.board.finalizeAdding(this); + + this.createGradient(); + this.elType = 'polygon'; + + // create label + this.createLabel(); + + this.methodMap = JXG.deepCopy(this.methodMap, { + borders: 'borders', + vertices: 'vertices', + A: 'Area', + Area: 'Area', + Perimeter: 'Perimeter', + L: 'Perimeter', + Length: 'Perimeter', + boundingBox: 'boundingBox', + bounds: 'bounds', + addPoints: 'addPoints', + insertPoints: 'insertPoints', + removePoints: 'removePoints' + }); + }; + + JXG.Polygon.prototype = new GeometryElement(); + + JXG.extend(JXG.Polygon.prototype, /** @lends JXG.Polygon.prototype */ { + + /** + * Decides if a point (x,y) is inside of the polygon. + * Implements W. Randolf Franklin's pnpoly method. + * + * See <a href="https://wrf.ecse.rpi.edu/Research/Short_Notes/pnpoly.html">https://wrf.ecse.rpi.edu/Research/Short_Notes/pnpoly.html</a>. + * + * @param {Number} x_in x-coordinate (screen or user coordinates) + * @param {Number} y_in y-coordinate (screen or user coordinates) + * @param {Number} coord_type (Optional) the type of coordinates used here. + * Possible values are <b>JXG.COORDS_BY_USER</b> and <b>JXG.COORDS_BY_SCREEN</b>. + * Default value is JXG.COORDS_BY_SCREEN + * + * @returns {Boolean} if (x,y) is inside of the polygon. + * @example + * var pol = board.create('polygon', [[-1,2], [2,2], [-1,4]]); + * var p = board.create('point', [4, 3]); + * var txt = board.create('text', [-1, 0.5, function() { + * return 'Point A is inside of the polygon = ' + + * pol.pnpoly(p.X(), p.Y(), JXG.COORDS_BY_USER); + * }]); + * + * </pre><div id="JXG7f96aec7-4e3d-4ffc-a3f5-d3f967b6691c" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG7f96aec7-4e3d-4ffc-a3f5-d3f967b6691c', + * {boundingbox: [-2, 5, 5,-2], axis: true, showcopyright: false, shownavigation: false}); + * var pol = board.create('polygon', [[-1,2], [2,2], [-1,4]]); + * var p = board.create('point', [4, 3]); + * var txt = board.create('text', [-1, 0.5, function() { + * return 'Point A is inside of the polygon = ' + pol.pnpoly(p.X(), p.Y(), JXG.COORDS_BY_USER); + * }]); + * + * })(); + * + * </script><pre> + * + */ + pnpoly: function(x_in, y_in, coord_type) { + var i, j, len, + x, y, crds, + v = this.vertices, + isIn = false; + + if (coord_type === Const.COORDS_BY_USER) { + crds = new Coords(Const.COORDS_BY_USER, [x_in, y_in], this.board); + x = crds.scrCoords[1]; + y = crds.scrCoords[2]; + } else { + x = x_in; + y = y_in; + } + + len = this.vertices.length; + for (i = 0, j = len - 2; i < len - 1; j = i++) { + if (((v[i].coords.scrCoords[2] > y) !== (v[j].coords.scrCoords[2] > y)) && + (x < (v[j].coords.scrCoords[1] - v[i].coords.scrCoords[1]) * + (y - v[i].coords.scrCoords[2]) / (v[j].coords.scrCoords[2] - v[i].coords.scrCoords[2]) + v[i].coords.scrCoords[1]) + ) { + isIn = !isIn; + } + } + + return isIn; + }, + + /** + * Checks whether (x,y) is near the polygon. + * @param {Number} x Coordinate in x direction, screen coordinates. + * @param {Number} y Coordinate in y direction, screen coordinates. + * @returns {Boolean} Returns true, if (x,y) is inside or at the boundary the polygon, otherwise false. + */ + hasPoint: function (x, y) { + var i, len; + + if (Type.evaluate(this.visProp.hasinnerpoints)) { + // All points of the polygon trigger hasPoint: inner and boundary points + if (this.pnpoly(x, y)) { + return true; + } + } + + // Only boundary points trigger hasPoint + // We additionally test the boundary also in case hasInnerPoints. + // Since even if the above test has failed, the strokewidth may be large and (x, y) may + // be inside of hasPoint() of a vertices. + len = this.borders.length; + for (i = 0; i < len; i++) { + if (this.borders[i].hasPoint(x, y)) { + return true; + } + } + + return false; + }, + + /** + * Uses the boards renderer to update the polygon. + */ + updateRenderer: function () { + var i, len; // wasReal, + + + if (!this.needsUpdate) { + return this; + } + + if (this.visPropCalc.visible) { + // wasReal = this.isReal; + + len = this.vertices.length; + this.isReal = true; + for (i = 0; i < len; ++i) { + if (!this.vertices[i].isReal) { + this.isReal = false; + break; + } + } + + if (//wasReal && + !this.isReal) { + this.updateVisibility(false); + } + } + + if (this.visPropCalc.visible) { + this.board.renderer.updatePolygon(this); + } + + /* Update the label if visible. */ + if (this.hasLabel && this.visPropCalc.visible && this.label && + this.label.visPropCalc.visible && this.isReal) { + + this.label.update(); + this.board.renderer.updateText(this.label); + } + + // Update rendNode display + this.setDisplayRendNode(); + // if (this.visPropCalc.visible !== this.visPropOld.visible) { + // this.board.renderer.display(this, this.visPropCalc.visible); + // this.visPropOld.visible = this.visPropCalc.visible; + // + // if (this.hasLabel) { + // this.board.renderer.display(this.label, this.label.visPropCalc.visible); + // } + // } + + this.needsUpdate = false; + return this; + }, + + /** + * return TextAnchor + */ + getTextAnchor: function () { + var a, b, x, y, i; + + if (this.vertices.length === 0) { + return new Coords(Const.COORDS_BY_USER, [1, 0, 0], this.board); + } + + a = this.vertices[0].X(); + b = this.vertices[0].Y(); + x = a; + y = b; + for (i = 0; i < this.vertices.length; i++) { + if (this.vertices[i].X() < a) { + a = this.vertices[i].X(); + } + + if (this.vertices[i].X() > x) { + x = this.vertices[i].X(); + } + + if (this.vertices[i].Y() > b) { + b = this.vertices[i].Y(); + } + + if (this.vertices[i].Y() < y) { + y = this.vertices[i].Y(); + } + } + + return new Coords(Const.COORDS_BY_USER, [(a + x) * 0.5, (b + y) * 0.5], this.board); + }, + + getLabelAnchor: JXG.shortcut(JXG.Polygon.prototype, 'getTextAnchor'), + + // documented in geometry element + cloneToBackground: function () { + var copy = {}, er; + + copy.id = this.id + 'T' + this.numTraces; + this.numTraces++; + copy.vertices = this.vertices; + copy.visProp = Type.deepCopy(this.visProp, this.visProp.traceattributes, true); + copy.visProp.layer = this.board.options.layer.trace; + copy.board = this.board; + Type.clearVisPropOld(copy); + + copy.visPropCalc = { + visible: Type.evaluate(copy.visProp.visible) + }; + + er = this.board.renderer.enhancedRendering; + this.board.renderer.enhancedRendering = true; + this.board.renderer.drawPolygon(copy); + this.board.renderer.enhancedRendering = er; + this.traces[copy.id] = copy.rendNode; + + return this; + }, + + /** + * Hide the polygon including its border lines. It will still exist but not visible on the board. + * @param {Boolean} [borderless=false] If set to true, the polygon is treated as a polygon without + * borders, i.e. the borders will not be hidden. + */ + hideElement: function (borderless) { + var i; + + JXG.deprecated('Element.hideElement()', 'Element.setDisplayRendNode()'); + + this.visPropCalc.visible = false; + this.board.renderer.display(this, false); + + if (!borderless) { + for (i = 0; i < this.borders.length; i++) { + this.borders[i].hideElement(); + } + } + + if (this.hasLabel && Type.exists(this.label)) { + this.label.hiddenByParent = true; + if (this.label.visPropCalc.visible) { + this.label.hideElement(); + } + } + }, + + /** + * Make the element visible. + * @param {Boolean} [borderless=false] If set to true, the polygon is treated as a polygon without + * borders, i.e. the borders will not be shown. + */ + showElement: function (borderless) { + var i; + + JXG.deprecated('Element.showElement()', 'Element.setDisplayRendNode()'); + + this.visPropCalc.visible = true; + this.board.renderer.display(this, true); + + if (!borderless) { + for (i = 0; i < this.borders.length; i++) { + this.borders[i].showElement().updateRenderer(); + } + } + + if (Type.exists(this.label) && this.hasLabel && this.label.hiddenByParent) { + this.label.hiddenByParent = false; + if (!this.label.visPropCalc.visible) { + this.label.showElement().updateRenderer(); + } + } + return this; + }, + + /** + * Area of (not self-intersecting) polygon + * @returns {Number} Area of (not self-intersecting) polygon + */ + Area: function () { + return Math.abs(Geometry.signedPolygon(this.vertices, true)); + }, + + /** + * Perimeter of polygon. + * @returns {Number} Perimeter of polygon in user units. + * + * @example + * var p = [[0.0, 2.0], [2.0, 1.0], [4.0, 6.0], [1.0, 3.0]]; + * + * var pol = board.create('polygon', p, {hasInnerPoints: true}); + * var t = board.create('text', [5, 5, function() { return pol.Perimeter(); }]); + * </pre><div class="jxgbox" id="JXGb10b734d-89fc-4b9d-b4a7-e3f0c1c6bf77" style="width: 400px; height: 400px;"></div> + * <script type="text/javascript"> + * (function () { + * var board = JXG.JSXGraph.initBoard('JXGb10b734d-89fc-4b9d-b4a7-e3f0c1c6bf77', {boundingbox: [-1, 9, 9, -1], axis: false, showcopyright: false, shownavigation: false}), + * p = [[0.0, 2.0], [2.0, 1.0], [4.0, 6.0], [1.0, 4.0]], + * cc1 = board.create('polygon', p, {hasInnerPoints: true}), + * t = board.create('text', [5, 5, function() { return cc1.Perimeter(); }]); + * })(); + * </script><pre> + * + */ + Perimeter: function() { + var i, + len = this.vertices.length, + val = 0.0; + + for (i = 1; i < len; ++i) { + val += this.vertices[i].Dist(this.vertices[i - 1]); + } + + return val; + }, + + /** + * Bounding box of a polygon. The bounding box is an array of four numbers: the first two numbers + * determine the upper left corner, the last two number determine the lower right corner of the bounding box. + * + * The width and height of a polygon can then determined like this: + * @example + * var box = polygon.boundingBox(); + * var width = box[2] - box[0]; + * var height = box[1] - box[3]; + * + * @returns {Array} Array containing four numbers: [minX, maxY, maxX, minY] + */ + boundingBox: function () { + var box = [0, 0, 0, 0], i, v, + le = this.vertices.length - 1; + + if (le === 0) { + return box; + } + box[0] = this.vertices[0].X(); + box[2] = box[0]; + box[1] = this.vertices[0].Y(); + box[3] = box[1]; + + for (i = 1; i < le; ++i) { + v = this.vertices[i].X(); + if (v < box[0]) { + box[0] = v; + } else if (v > box[2]) { + box[2] = v; + } + + v = this.vertices[i].Y(); + if (v > box[1]) { + box[1] = v; + } else if (v < box[3]) { + box[3] = v; + } + } + + return box; + }, + + // Already documented in GeometryElement + bounds: function () { + return this.boundingBox(); + }, + + /** + * This method removes the SVG or VML nodes of the lines and the filled area from the renderer, to remove + * the object completely you should use {@link JXG.Board#removeObject}. + * + * @private + */ + remove: function () { + var i; + + for (i = 0; i < this.borders.length; i++) { + this.board.removeObject(this.borders[i]); + } + + GeometryElement.prototype.remove.call(this); + }, + + /** + * Finds the index to a given point reference. + * @param {JXG.Point} p Reference to an element of type {@link JXG.Point} + * @returns {Number} Index of the point or -1. + */ + findPoint: function (p) { + var i; + + if (!Type.isPoint(p)) { + return -1; + } + + for (i = 0; i < this.vertices.length; i++) { + if (this.vertices[i].id === p.id) { + return i; + } + } + + return -1; + }, + + /** + * Add more points to the polygon. The new points will be inserted at the end. + * The attributes of new border segments are set to the same values + * as those used when the polygon was created. + * If new vertices are supplied by coordinates, the default attributes of polygon + * vertices are taken as their attributes. Therefore, the visual attributes of + * new vertices and borders may have to be adapted afterwards. + * @param {JXG.Point} p Arbitrary number of points or coordinate arrays + * @returns {JXG.Polygon} Reference to the polygon + * @example + * const board = JXG.JSXGraph.initBoard('jxgbox', {axis:true}); + * var pg = board.create('polygon', [[1,2], [3,4], [-3,1]], {hasInnerPoints: true}); + * var newPoint = board.create('point', [-1, -1]); + * var newPoint2 = board.create('point', [-1, -2]); + * pg.addPoints(newPoint, newPoint2, [1, -2]); + * + * </pre><div id="JXG70eb0fd2-d20f-4ba9-9ab6-0eac92aabfa5" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG70eb0fd2-d20f-4ba9-9ab6-0eac92aabfa5', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * const board = JXG.JSXGraph.initBoard('jxgbox', {axis:true}); + * var pg = board.create('polygon', [[1,2], [3,4], [-3,1]], {hasInnerPoints: true}); + * var newPoint = board.create('point', [-1, -1]); + * var newPoint2 = board.create('point', [-1, -2]); + * pg.addPoints(newPoint, newPoint2, [1, -2]); + * + * })(); + * + * </script><pre> + * + */ + addPoints: function (p) { + var args = Array.prototype.slice.call(arguments); + + return this.insertPoints.apply(this, [this.vertices.length - 2].concat(args)); + }, + + /** + * Insert points to the vertex list of the polygon after index <tt><idx</tt>. + * The attributes of new border segments are set to the same values + * as those used when the polygon was created. + * If new vertices are supplied by coordinates, the default attributes of polygon + * vertices are taken as their attributes. Therefore, the visual attributes of + * new vertices and borders may have to be adapted afterwards. + * + * @param {Number} idx The position after which the new vertices are inserted. + * Setting idx to -1 inserts the new points at the front, i.e. at position 0. + * @param {JXG.Point} p Arbitrary number of points or coordinate arrays to insert. + * @returns {JXG.Polygon} Reference to the polygon object + * + * @example + * const board = JXG.JSXGraph.initBoard('jxgbox', {axis:true}); + * var pg = board.create('polygon', [[1,2], [3,4], [-3,1]], {hasInnerPoints: true}); + * var newPoint = board.create('point', [-1, -1]); + * pg.insertPoints(0, newPoint, newPoint, [1, -2]); + * + * </pre><div id="JXG17b84b2a-a851-4e3f-824f-7f6a60f166ca" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG17b84b2a-a851-4e3f-824f-7f6a60f166ca', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * const board = JXG.JSXGraph.initBoard('jxgbox', {axis:true}); + * var pg = board.create('polygon', [[1,2], [3,4], [-3,1]], {hasInnerPoints: true}); + * var newPoint = board.create('point', [-1, -1]); + * pg.insertPoints(0, newPoint, newPoint, [1, -2]); + * + * })(); + * + * </script><pre> + * + */ + insertPoints: function (idx, p) { + var i, le; + + if (arguments.length === 0) { + return this; + } + + + if (idx < -1 || idx > this.vertices.length - 2) { + return this; + } + + le = arguments.length - 1; + for (i = 1; i < le + 1; i++) { + this.vertices.splice(idx + i, 0, + Type.providePoints(this.board, [arguments[i]], {}, 'polygon', ['vertices'])[0] + ); + } + if (idx === -1) { + this.vertices[this.vertices.length - 1] = this.vertices[0]; + } + if (this.withLines) { + if (idx < 0) { + this.borders[this.borders.length - 1].point2 = this.vertices[this.vertices.length - 1]; + } else { + this.borders[idx].point2 = this.vertices[idx + 1]; + } + for (i = idx + 1; i < idx + 1 + le; i++) { + this.borders.splice(i, 0, + this.board.create('segment', [this.vertices[i], this.vertices[i + 1]], this.attr_line) + ); + } + } + this.board.update(); + + return this; + }, + + /** + * Removes given set of vertices from the polygon + * @param {JXG.Point} p Arbitrary number of vertices as {@link JXG.Point} elements or index numbers + * @returns {JXG.Polygon} Reference to the polygon + */ + removePoints: function (p) { + var i, j, idx, nvertices = [], nborders = [], + nidx = [], partition = []; + + // Partition: + // in order to keep the borders which could be recycled, we have to partition + // the set of removed points. I.e. if the points 1, 2, 5, 6, 7, 10 are removed, + // the partitions are + // 1-2, 5-7, 10-10 + // this gives us the borders, that can be removed and the borders we have to create. + + + // Remove the last vertex which is identical to the first + this.vertices = this.vertices.slice(0, this.vertices.length - 1); + + // Collect all valid parameters as indices in nidx + for (i = 0; i < arguments.length; i++) { + idx = arguments[i]; + if (Type.isPoint(idx)) { + idx = this.findPoint(idx); + } + + if (Type.isNumber(idx) && idx > -1 && idx < this.vertices.length && Type.indexOf(nidx, idx) === -1) { + nidx.push(idx); + } + } + + // Remove the polygon from each removed point's children + for (i = 0; i < nidx.length; i++) { + this.vertices[nidx[i]].removeChild(this); + } + + // Sort the elements to be eliminated + nidx = nidx.sort(); + nvertices = this.vertices.slice(); + nborders = this.borders.slice(); + + // Initialize the partition + if (this.withLines) { + partition.push([nidx[nidx.length - 1]]); + } + + // Run through all existing vertices and copy all remaining ones to nvertices, + // compute the partition + for (i = nidx.length - 1; i > -1; i--) { + nvertices[nidx[i]] = -1; + + if (this.withLines && (nidx[i] - 1 > nidx[i - 1])) { + partition[partition.length - 1][1] = nidx[i]; + partition.push([nidx[i - 1]]); + } + } + + // Finalize the partition computation + if (this.withLines) { + partition[partition.length - 1][1] = nidx[0]; + } + + // Update vertices + this.vertices = []; + for (i = 0; i < nvertices.length; i++) { + if (Type.isPoint(nvertices[i])) { + this.vertices.push(nvertices[i]); + } + } + if (this.vertices[this.vertices.length - 1].id !== this.vertices[0].id) { + this.vertices.push(this.vertices[0]); + } + + // Delete obsolete and create missing borders + if (this.withLines) { + for (i = 0; i < partition.length; i++) { + for (j = partition[i][1] - 1; j < partition[i][0] + 1; j++) { + // special cases + if (j < 0) { + // first vertex is removed, so the last border has to be removed, too + j = 0; + this.board.removeObject(this.borders[nborders.length - 1]); + nborders[nborders.length - 1] = -1; + } else if (j > nborders.length - 1) { + j = nborders.length - 1; + } + + this.board.removeObject(this.borders[j]); + nborders[j] = -1; + } + + // only create the new segment if it's not the closing border. the closing border is getting a special treatment at the end + // the if clause is newer than the min/max calls inside createSegment; i'm sure this makes the min/max calls obsolete, but + // just to be sure... + if (partition[i][1] !== 0 && partition[i][0] !== nvertices.length - 1) { + nborders[partition[i][0] - 1] = this.board.create('segment', [nvertices[Math.max(partition[i][1] - 1, 0)], nvertices[Math.min(partition[i][0] + 1, this.vertices.length - 1)]], this.attr_line); + } + } + + this.borders = []; + for (i = 0; i < nborders.length; i++) { + if (nborders[i] !== -1) { + this.borders.push(nborders[i]); + } + } + + // if the first and/or the last vertex is removed, the closing border is created at the end. + if (partition[0][1] === this.vertices.length - 1 || partition[partition.length - 1][1] === 0) { + this.borders.push(this.board.create('segment', [this.vertices[0], this.vertices[this.vertices.length - 2]], this.attr_line)); + } + } + + this.board.update(); + + return this; + }, + + // documented in element.js + getParents: function () { + this.setParents(this.vertices); + return this.parents; + }, + + getAttributes: function () { + var attr = GeometryElement.prototype.getAttributes.call(this), i; + + if (this.withLines) { + attr.lines = attr.lines || {}; + attr.lines.ids = []; + attr.lines.colors = []; + + for (i = 0; i < this.borders.length; i++) { + attr.lines.ids.push(this.borders[i].id); + attr.lines.colors.push(this.borders[i].visProp.strokecolor); + } + } + + return attr; + }, + + snapToGrid: function () { + var i, force; + + if (Type.evaluate(this.visProp.snaptogrid)) { + force = true; + } else { + force = false; + } + + for (i = 0; i < this.vertices.length; i++) { + this.vertices[i].handleSnapToGrid(force, true); + } + + }, + + /** + * Moves the polygon by the difference of two coordinates. + * @param {Number} method The type of coordinates used here. Possible values are {@link JXG.COORDS_BY_USER} and {@link JXG.COORDS_BY_SCREEN}. + * @param {Array} coords coordinates in screen/user units + * @param {Array} oldcoords previous coordinates in screen/user units + * @returns {JXG.Polygon} this element + */ + setPositionDirectly: function (method, coords, oldcoords) { + var dc, t, i, len, + c = new Coords(method, coords, this.board), + oldc = new Coords(method, oldcoords, this.board); + + len = this.vertices.length - 1; + for (i = 0; i < len; i++) { + if (!this.vertices[i].draggable()) { + return this; + } + } + + dc = Statistics.subtract(c.usrCoords, oldc.usrCoords); + t = this.board.create('transform', dc.slice(1), {type: 'translate'}); + t.applyOnce(this.vertices.slice(0, -1)); + + return this; + }, + + /** + * Algorithm by Sutherland and Hodgman to compute the intersection of two convex polygons. + * The polygon itself is the clipping polygon, it expects as parameter a polygon to be clipped. + * See <a href="https://en.wikipedia.org/wiki/Sutherland%E2%80%93Hodgman_algorithm">wikipedia entry</a>. + * Called by {@link JXG.Polygon#intersect}. + * + * @private + * + * @param {JXG.Polygon} polygon Polygon which will be clipped. + * + * @returns {Array} of (normalized homogeneous user) coordinates (i.e. [z, x, y], where z==1 in most cases, + * representing the vertices of the intersection polygon. + * + */ + sutherlandHodgman: function(polygon) { + // First the two polygons are sorted counter clockwise + var clip = JXG.Math.Geometry.sortVertices(this.vertices), // "this" is the clipping polygon + subject = JXG.Math.Geometry.sortVertices(polygon.vertices), // "polygon" is the subject polygon + + lenClip = clip.length - 1, + lenSubject = subject.length - 1, + lenIn, + + outputList = [], + inputList, i, j, S, E, cross, + + // Determines if the point c3 is right of the line through c1 and c2. + // Since the polygons are sorted counter clockwise, "right of" and therefore >= is needed here + isInside = function(c1, c2, c3) { + return ((c2[1] - c1[1]) * (c3[2] - c1[2]) - (c2[2] - c1[2]) * (c3[1] - c1[1])) >= 0; + }; + + for (i = 0; i < lenSubject; i++) { + outputList.push(subject[i]); + } + + for (i = 0; i < lenClip; i++) { + inputList = outputList.slice(0); + lenIn = inputList.length; + outputList = []; + + S = inputList[lenIn - 1]; + + for (j = 0; j < lenIn; j++) { + E = inputList[j]; + if (isInside(clip[i], clip[i + 1], E)) { + if (!isInside(clip[i], clip[i + 1], S)) { + cross = JXG.Math.Geometry.meetSegmentSegment(S, E, clip[i], clip[i + 1]); + cross[0][1] /= cross[0][0]; + cross[0][2] /= cross[0][0]; + cross[0][0] = 1; + outputList.push(cross[0]); + } + outputList.push(E); + } else if (isInside(clip[i], clip[i + 1], S)) { + cross = JXG.Math.Geometry.meetSegmentSegment(S, E, clip[i], clip[i + 1]); + cross[0][1] /= cross[0][0]; + cross[0][2] /= cross[0][0]; + cross[0][0] = 1; + outputList.push(cross[0]); + } + S = E; + } + } + + return outputList; + }, + + /** + * Generic method for the intersection of this polygon with another polygon. + * The parent object is the clipping polygon, it expects as parameter a polygon to be clipped. + * Both polygons have to be convex. + * Calls the algorithm by Sutherland, Hodgman, {@link JXG.Polygon#sutherlandHodgman}. + * <p> + * An alternative is to use the methods from {@link JXG.Math.Clip}, where the algorithm by Greiner and Hormann + * is used. + * + * @param {JXG.Polygon} polygon Polygon which will be clipped. + * + * @returns {Array} of (normalized homogeneous user) coordinates (i.e. [z, x, y], where z==1 in most cases, + * representing the vertices of the intersection polygon. + * + * @example + * // Static intersection of two polygons pol1 and pol2 + * var pol1 = board.create('polygon', [[-2, 3], [-4, -3], [2, 0], [4, 4]], { + * name:'pol1', withLabel: true, + * fillColor: 'yellow' + * }); + * var pol2 = board.create('polygon', [[-2, -3], [-4, 1], [0, 4], [5, 1]], { + * name:'pol2', withLabel: true + * }); + * + * // Static version: + * // the intersection polygon does not adapt to changes of pol1 or pol2. + * var pol3 = board.create('polygon', pol1.intersect(pol2), {fillColor: 'blue'}); + * </pre><div class="jxgbox" id="JXGd1fe5ea9-309f-494a-af07-ee3d033acb7c" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXGd1fe5ea9-309f-494a-af07-ee3d033acb7c', {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * // Intersect two polygons pol1 and pol2 + * var pol1 = board.create('polygon', [[-2, 3], [-4, -3], [2, 0], [4, 4]], { + * name:'pol1', withLabel: true, + * fillColor: 'yellow' + * }); + * var pol2 = board.create('polygon', [[-2, -3], [-4, 1], [0, 4], [5, 1]], { + * name:'pol2', withLabel: true + * }); + * + * // Static version: the intersection polygon does not adapt to changes of pol1 or pol2. + * var pol3 = board.create('polygon', pol1.intersect(pol2), {fillColor: 'blue'}); + * })(); + * </script><pre> + * + * @example + * // Dynamic intersection of two polygons pol1 and pol2 + * var pol1 = board.create('polygon', [[-2, 3], [-4, -3], [2, 0], [4, 4]], { + * name:'pol1', withLabel: true, + * fillColor: 'yellow' + * }); + * var pol2 = board.create('polygon', [[-2, -3], [-4, 1], [0, 4], [5, 1]], { + * name:'pol2', withLabel: true + * }); + * + * // Dynamic version: + * // the intersection polygon does adapt to changes of pol1 or pol2. + * // For this a curve element is used. + * var curve = board.create('curve', [[],[]], {fillColor: 'blue', fillOpacity: 0.4}); + * curve.updateDataArray = function() { + * var mat = JXG.Math.transpose(pol1.intersect(pol2)); + * + * if (mat.length == 3) { + * this.dataX = mat[1]; + * this.dataY = mat[2]; + * } else { + * this.dataX = []; + * this.dataY = []; + * } + * }; + * board.update(); + * </pre><div class="jxgbox" id="JXGf870d516-ca1a-4140-8fe3-5d64fb42e5f2" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXGf870d516-ca1a-4140-8fe3-5d64fb42e5f2', {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * // Intersect two polygons pol1 and pol2 + * var pol1 = board.create('polygon', [[-2, 3], [-4, -3], [2, 0], [4, 4]], { + * name:'pol1', withLabel: true, + * fillColor: 'yellow' + * }); + * var pol2 = board.create('polygon', [[-2, -3], [-4, 1], [0, 4], [5, 1]], { + * name:'pol2', withLabel: true + * }); + * + * // Dynamic version: + * // the intersection polygon does adapt to changes of pol1 or pol2. + * // For this a curve element is used. + * var curve = board.create('curve', [[],[]], {fillColor: 'blue', fillOpacity: 0.4}); + * curve.updateDataArray = function() { + * var mat = JXG.Math.transpose(pol1.intersect(pol2)); + * + * if (mat.length == 3) { + * this.dataX = mat[1]; + * this.dataY = mat[2]; + * } else { + * this.dataX = []; + * this.dataY = []; + * } + * }; + * board.update(); + * })(); + * </script><pre> + * + */ + intersect: function(polygon) { + return this.sutherlandHodgman(polygon); + } + + + }); + + + /** + * @class A polygon is an area enclosed by a set of border lines which are determined by + * <ul> + * <li> a list of points or + * <li> a list of coordinate arrays or + * <li> a function returning a list of coordinate arrays. + * </ul> + * Each two consecutive points of the list define a line. + * @pseudo + * @constructor + * @name Polygon + * @type Polygon + * @augments JXG.Polygon + * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {Array} vertices The polygon's vertices. If the first and the last vertex don't match the first one will be + * added to the array by the creator. Here, two points match if they have the same 'id' attribute. + * + * Additionally, a polygon can be created by providing a polygon and a transformation (or an array of transformations). + * The result is a polygon which is the transformation of the supplied polygon. + * + * @example + * var p1 = board.create('point', [0.0, 2.0]); + * var p2 = board.create('point', [2.0, 1.0]); + * var p3 = board.create('point', [4.0, 6.0]); + * var p4 = board.create('point', [1.0, 4.0]); + * + * var pol = board.create('polygon', [p1, p2, p3, p4]); + * </pre><div class="jxgbox" id="JXG682069e9-9e2c-4f63-9b73-e26f8a2b2bb1" style="width: 400px; height: 400px;"></div> + * <script type="text/javascript"> + * (function () { + * var board = JXG.JSXGraph.initBoard('JXG682069e9-9e2c-4f63-9b73-e26f8a2b2bb1', {boundingbox: [-1, 9, 9, -1], axis: false, showcopyright: false, shownavigation: false}), + * p1 = board.create('point', [0.0, 2.0]), + * p2 = board.create('point', [2.0, 1.0]), + * p3 = board.create('point', [4.0, 6.0]), + * p4 = board.create('point', [1.0, 4.0]), + * cc1 = board.create('polygon', [p1, p2, p3, p4]); + * })(); + * </script><pre> + * + * @example + * var p = [[0.0, 2.0], [2.0, 1.0], [4.0, 6.0], [1.0, 3.0]]; + * + * var pol = board.create('polygon', p, {hasInnerPoints: true}); + * </pre><div class="jxgbox" id="JXG9f9a5946-112a-4768-99ca-f30792bcdefb" style="width: 400px; height: 400px;"></div> + * <script type="text/javascript"> + * (function () { + * var board = JXG.JSXGraph.initBoard('JXG9f9a5946-112a-4768-99ca-f30792bcdefb', {boundingbox: [-1, 9, 9, -1], axis: false, showcopyright: false, shownavigation: false}), + * p = [[0.0, 2.0], [2.0, 1.0], [4.0, 6.0], [1.0, 4.0]], + * cc1 = board.create('polygon', p, {hasInnerPoints: true}); + * })(); + * </script><pre> + * + * @example + * var f1 = function() { return [0.0, 2.0]; }, + * f2 = function() { return [2.0, 1.0]; }, + * f3 = function() { return [4.0, 6.0]; }, + * f4 = function() { return [1.0, 4.0]; }, + * cc1 = board.create('polygon', [f1, f2, f3, f4]); + * board.update(); + * + * </pre><div class="jxgbox" id="JXGceb09915-b783-44db-adff-7877ae3534c8" style="width: 400px; height: 400px;"></div> + * <script type="text/javascript"> + * (function () { + * var board = JXG.JSXGraph.initBoard('JXGceb09915-b783-44db-adff-7877ae3534c8', {boundingbox: [-1, 9, 9, -1], axis: false, showcopyright: false, shownavigation: false}), + * f1 = function() { return [0.0, 2.0]; }, + * f2 = function() { return [2.0, 1.0]; }, + * f3 = function() { return [4.0, 6.0]; }, + * f4 = function() { return [1.0, 4.0]; }, + * cc1 = board.create('polygon', [f1, f2, f3, f4]); + * board.update(); + * })(); + * </script><pre> + * + * @example + * var t = board.create('transform', [2, 1.5], {type: 'scale'}); + * var a = board.create('point', [-3,-2], {name: 'a'}); + * var b = board.create('point', [-1,-4], {name: 'b'}); + * var c = board.create('point', [-2,-0.5], {name: 'c'}); + * var pol1 = board.create('polygon', [a,b,c], {vertices: {withLabel: false}}); + * var pol2 = board.create('polygon', [pol1, t], {vertices: {withLabel: true}}); + * + * </pre><div id="JXG6530a69c-6339-11e8-9fb9-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG6530a69c-6339-11e8-9fb9-901b0e1b8723', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * var t = board.create('transform', [2, 1.5], {type: 'scale'}); + * var a = board.create('point', [-3,-2], {name: 'a'}); + * var b = board.create('point', [-1,-4], {name: 'b'}); + * var c = board.create('point', [-2,-0.5], {name: 'c'}); + * var pol1 = board.create('polygon', [a,b,c], {vertices: {withLabel: false}}); + * var pol2 = board.create('polygon', [pol1, t], {vertices: {withLabel: true}}); + * + * })(); + * + * </script><pre> + * + */ + JXG.createPolygon = function (board, parents, attributes) { + var el, i, le, obj, + points = [], + attr, attr_points, + is_transform = false; + + attr = Type.copyAttributes(attributes, board.options, 'polygon'); + obj = board.select(parents[0]); + if (obj === null) { + // This is necessary if the original polygon is defined in another board. + obj = parents[0]; + } + if (Type.isObject(obj) && obj.type === Const.OBJECT_TYPE_POLYGON && + Type.isTransformationOrArray(parents[1])) { + + is_transform = true; + le = obj.vertices.length - 1; + attr_points = Type.copyAttributes(attributes, board.options, 'polygon', 'vertices'); + for (i = 0; i < le; i++) { + if (attr_points.withlabel) { + attr_points.name = (obj.vertices[i].name === '') ? '' : (obj.vertices[i].name + "'"); + } + points.push(board.create('point', [obj.vertices[i], parents[1]], attr_points)); + } + } else { + points = Type.providePoints(board, parents, attributes, 'polygon', ['vertices']); + if (points === false) { + throw new Error("JSXGraph: Can't create polygon / polygonalchain with parent types other than 'point' and 'coordinate arrays' or a function returning an array of coordinates. Alternatively, a polygon and a transformation can be supplied"); + } + } + + attr = Type.copyAttributes(attributes, board.options, 'polygon'); + el = new JXG.Polygon(board, points, attr); + el.isDraggable = true; + + // Put the points to their position + if (is_transform) { + el.prepareUpdate().update().updateVisibility().updateRenderer(); + le = obj.vertices.length - 1; + for (i = 0; i < le; i++) { + points[i].prepareUpdate().update().updateVisibility().updateRenderer(); + } + } + + return el; + }; + + /** + * @class Constructs a regular polygon. It needs two points which define the base line and the number of vertices. + * @pseudo + * @description Constructs a regular polygon. It needs two points which define the base line and the number of vertices, or a set of points. + * @constructor + * @name RegularPolygon + * @type Polygon + * @augments Polygon + * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {JXG.Point_JXG.Point_Number} p1,p2,n The constructed regular polygon has n vertices and the base line defined by p1 and p2. + * @example + * var p1 = board.create('point', [0.0, 2.0]); + * var p2 = board.create('point', [2.0, 1.0]); + * + * var pol = board.create('regularpolygon', [p1, p2, 5]); + * </pre><div class="jxgbox" id="JXG682069e9-9e2c-4f63-9b73-e26f8a2b2bb1" style="width: 400px; height: 400px;"></div> + * <script type="text/javascript"> + * (function () { + * var board = JXG.JSXGraph.initBoard('JXG682069e9-9e2c-4f63-9b73-e26f8a2b2bb1', {boundingbox: [-1, 9, 9, -1], axis: false, showcopyright: false, shownavigation: false}), + * p1 = board.create('point', [0.0, 2.0]), + * p2 = board.create('point', [2.0, 1.0]), + * cc1 = board.create('regularpolygon', [p1, p2, 5]); + * })(); + * </script><pre> + * @example + * var p1 = board.create('point', [0.0, 2.0]); + * var p2 = board.create('point', [4.0,4.0]); + * var p3 = board.create('point', [2.0,0.0]); + * + * var pol = board.create('regularpolygon', [p1, p2, p3]); + * </pre><div class="jxgbox" id="JXG096a78b3-bd50-4bac-b958-3be5e7df17ed" style="width: 400px; height: 400px;"></div> + * <script type="text/javascript"> + * (function () { + * var board = JXG.JSXGraph.initBoard('JXG096a78b3-bd50-4bac-b958-3be5e7df17ed', {boundingbox: [-1, 9, 9, -1], axis: false, showcopyright: false, shownavigation: false}), + * p1 = board.create('point', [0.0, 2.0]), + * p2 = board.create('point', [4.0, 4.0]), + * p3 = board.create('point', [2.0,0.0]), + * cc1 = board.create('regularpolygon', [p1, p2, p3]); + * })(); + * </script><pre> + * + * @example + * // Line of reflection + * var li = board.create('line', [1,1,1], {strokeColor: '#aaaaaa'}); + * var reflect = board.create('transform', [li], {type: 'reflect'}); + * var pol1 = board.create('polygon', [[-3,-2], [-1,-4], [-2,-0.5]]); + * var pol2 = board.create('polygon', [pol1, reflect]); + * + * </pre><div id="JXG58fc3078-d8d1-11e7-93b3-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG58fc3078-d8d1-11e7-93b3-901b0e1b8723', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * var li = board.create('line', [1,1,1], {strokeColor: '#aaaaaa'}); + * var reflect = board.create('transform', [li], {type: 'reflect'}); + * var pol1 = board.create('polygon', [[-3,-2], [-1,-4], [-2,-0.5]]); + * var pol2 = board.create('polygon', [pol1, reflect]); + * + * })(); + * + * </script><pre> + * + */ + JXG.createRegularPolygon = function (board, parents, attributes) { + var el, i, n, + p = [], rot, len, pointsExist, attr; + + len = parents.length; + n = parents[len - 1]; + + if (Type.isNumber(n) && (parents.length !== 3 || n < 3)) { + throw new Error("JSXGraph: A regular polygon needs two point types and a number > 2 as input."); + } + + if (Type.isNumber(board.select(n))) { // Regular polygon given by 2 points and a number + len--; + pointsExist = false; + } else { // Regular polygon given by n points + n = len; + pointsExist = true; + } + + p = Type.providePoints(board, parents.slice(0, len), attributes, 'regularpolygon', ['vertices']); + if (p === false) { + throw new Error("JSXGraph: Can't create regular polygon with parent types other than 'point' and 'coordinate arrays' or a function returning an array of coordinates"); + } + + attr = Type.copyAttributes(attributes, board.options, 'regularpolygon', 'vertices'); + for (i = 2; i < n; i++) { + rot = board.create('transform', [Math.PI * (2 - (n - 2) / n), p[i - 1]], {type: 'rotate'}); + if (pointsExist) { + p[i].addTransform(p[i - 2], rot); + p[i].fullUpdate(); + } else { + if (Type.isArray(attr.ids) && attr.ids.length >= n - 2) { + attr.id = attr.ids[i - 2]; + } + p[i] = board.create('point', [p[i - 2], rot], attr); + p[i].type = Const.OBJECT_TYPE_CAS; + + // The next two lines of code are needed to make regular polygones draggable + // The new helper points are set to be draggable. + p[i].isDraggable = true; + p[i].visProp.fixed = false; + } + } + + attr = Type.copyAttributes(attributes, board.options, 'regularpolygon'); + el = board.create('polygon', p, attr); + el.elType = 'regularpolygon'; + + return el; + }; + + /** + * @class A polygonal chain is a connected series of line segments determined by + * <ul> + * <li> a list of points or + * <li> a list of coordinate arrays or + * <li> a function returning a list of coordinate arrays. + * </ul> + * Each two consecutive points of the list define a line. + * In JSXGraph, a polygonal chain is simply realized as polygon without the last - closing - point. + * This may lead to unexpected results. Polygonal chains can be distinguished from polygons by the attribute 'elType' which + * is 'polygonalchain' for the first and 'polygon' for the latter. + * @pseudo + * @constructor + * @name PolygonalChain + * @type Polygon + * @augments JXG.Polygon + * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {Array} vertices The polygon's vertices. + * + * Additionally, a polygonal chain can be created by providing a polygonal chain and a transformation (or an array of transformations). + * The result is a polygonal chain which is the transformation of the supplied polygona chain. + * + * @example + * var attr = { + * snapToGrid: true + * }, + * p = []; + * + * p.push(board.create('point', [-4, 0], attr)); + * p.push(board.create('point', [-1, -3], attr)); + * p.push(board.create('point', [0, 2], attr)); + * p.push(board.create('point', [2, 1], attr)); + * p.push(board.create('point', [4, -2], attr)); + * + * var chain = board.create('polygonalchain', p, {borders: {strokeWidth: 3}}); + * + * </pre><div id="JXG878f93d8-3e49-46cf-aca2-d3bb7d60c5ae" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG878f93d8-3e49-46cf-aca2-d3bb7d60c5ae', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * var attr = { + * snapToGrid: true + * }, + * p = []; + * + * p.push(board.create('point', [-4, 0], attr)); + * p.push(board.create('point', [-1, -3], attr)); + * p.push(board.create('point', [0, 2], attr)); + * p.push(board.create('point', [2, 1], attr)); + * p.push(board.create('point', [4, -2], attr)); + * + * var chain = board.create('polygonalchain', p, {borders: {strokeWidth: 3}}); + * + * })(); + * + * </script><pre> + * + */ + JXG.createPolygonalChain = function (board, parents, attributes) { + var attr, el; + + attr = Type.copyAttributes(attributes, board.options, 'polygonalchain'); + el = board.create('polygon', parents, attr); + el.elType = 'polygonalchain'; + + // A polygonal chain is not necessarily closed. + el.vertices.pop(); + board.removeObject(el.borders[el.borders.length - 1]); + el.borders.pop(); + + return el; + }; + + JXG.registerElement('polygon', JXG.createPolygon); + JXG.registerElement('regularpolygon', JXG.createRegularPolygon); + JXG.registerElement('polygonalchain', JXG.createPolygonalChain); + + return { + Polygon: JXG.Polygon, + createPolygon: JXG.createPolygon, + createRegularPolygon: JXG.createRegularPolygon + }; +}); + +/* + Copyright 2008-2022 + Matthias Ehmann, + Michael Gerhaeuser, + Carsten Miller, + Bianca Valentin, + Alfred Wassermann, + Peter Wilfahrt + + This file is part of JSXGraph. + + JSXGraph is free software dual licensed under the GNU LGPL or MIT License. + + You can redistribute it and/or modify it under the terms of the + + * GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version + OR + * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT + + JSXGraph is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License and + the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> + and <http://opensource.org/licenses/MIT/>. + */ + + +/*global JXG: true, define: true*/ +/*jslint nomen: true, plusplus: true*/ + +/* depends: + jxg + base/constants + base/coords + base/element + math/math + math/geometry + math/statistics + math/numerics + parser/geonext + utils/type + elements: + transform + */ + +/** + * @fileoverview In this file the geometry element Curve is defined. + */ + +define('base/curve',[ + 'jxg', 'base/constants', 'base/coords', 'base/element', 'math/math', 'math/numerics', + 'math/plot', 'math/geometry', 'parser/geonext', 'utils/type', 'math/qdt' +], function (JXG, Const, Coords, GeometryElement, Mat, Numerics, Plot, Geometry, GeonextParser, Type, QDT) { + + "use strict"; + + /** + * Curves are the common object for function graphs, parametric curves, polar curves, and data plots. + * @class Creates a new curve object. Do not use this constructor to create a curve. Use {@link JXG.Board#create} with + * type {@link Curve}, or {@link Functiongraph} instead. + * @augments JXG.GeometryElement + * @param {String|JXG.Board} board The board the new curve is drawn on. + * @param {Array} parents defining terms An array with the functon terms or the data points of the curve. + * @param {Object} attributes Defines the visual appearance of the curve. + * @see JXG.Board#generateName + * @see JXG.Board#addCurve + */ + JXG.Curve = function (board, parents, attributes) { + this.constructor(board, attributes, Const.OBJECT_TYPE_CURVE, Const.OBJECT_CLASS_CURVE); + + this.points = []; + /** + * Number of points on curves. This value changes + * between numberPointsLow and numberPointsHigh. + * It is set in {@link JXG.Curve#updateCurve}. + */ + this.numberPoints = Type.evaluate(this.visProp.numberpointshigh); + + this.bezierDegree = 1; + + /** + * Array holding the x-coordinates of a data plot. + * This array can be updated during run time by overwriting + * the method {@link JXG.Curve#updateDataArray}. + * @type array + */ + this.dataX = null; + + /** + * Array holding the y-coordinates of a data plot. + * This array can be updated during run time by overwriting + * the method {@link JXG.Curve#updateDataArray}. + * @type array + */ + this.dataY = null; + + /** + * Array of ticks storing all the ticks on this curve. Do not set this field directly and use + * {@link JXG.Curve#addTicks} and {@link JXG.Curve#removeTicks} to add and remove ticks to and + * from the curve. + * @type Array + * @see JXG.Ticks + */ + this.ticks = []; + + /** + * Stores a quad tree if it is required. The quad tree is generated in the curve + * updates and can be used to speed up the hasPoint method. + * @type JXG.Math.Quadtree + */ + this.qdt = null; + + if (Type.exists(parents[0])) { + this.varname = parents[0]; + } else { + this.varname = 'x'; + } + + // function graphs: "x" + this.xterm = parents[1]; + // function graphs: e.g. "x^2" + this.yterm = parents[2]; + + // Converts GEONExT syntax into JavaScript syntax + this.generateTerm(this.varname, this.xterm, this.yterm, parents[3], parents[4]); + // First evaluation of the curve + this.updateCurve(); + + this.id = this.board.setId(this, 'G'); + this.board.renderer.drawCurve(this); + + this.board.finalizeAdding(this); + + this.createGradient(); + this.elType = 'curve'; + this.createLabel(); + + if (Type.isString(this.xterm)) { + this.notifyParents(this.xterm); + } + if (Type.isString(this.yterm)) { + this.notifyParents(this.yterm); + } + + this.methodMap = Type.deepCopy(this.methodMap, { + generateTerm: 'generateTerm', + setTerm: 'generateTerm', + move: 'moveTo', + moveTo: 'moveTo' + }); + }; + + JXG.Curve.prototype = new GeometryElement(); + + JXG.extend(JXG.Curve.prototype, /** @lends JXG.Curve.prototype */ { + + /** + * Gives the default value of the left bound for the curve. + * May be overwritten in {@link JXG.Curve#generateTerm}. + * @returns {Number} Left bound for the curve. + */ + minX: function () { + var leftCoords; + + if (Type.evaluate(this.visProp.curvetype) === 'polar') { + return 0; + } + + leftCoords = new Coords(Const.COORDS_BY_SCREEN, [-this.board.canvasWidth * 0.1, 0], this.board, false); + return leftCoords.usrCoords[1]; + }, + + /** + * Gives the default value of the right bound for the curve. + * May be overwritten in {@link JXG.Curve#generateTerm}. + * @returns {Number} Right bound for the curve. + */ + maxX: function () { + var rightCoords; + + if (Type.evaluate(this.visProp.curvetype) === 'polar') { + return 2 * Math.PI; + } + rightCoords = new Coords(Const.COORDS_BY_SCREEN, [this.board.canvasWidth * 1.1, 0], this.board, false); + + return rightCoords.usrCoords[1]; + }, + + /** + * The parametric function which defines the x-coordinate of the curve. + * @param {Number} t A number between {@link JXG.Curve#minX} and {@link JXG.Curve#maxX}. + * @param {Boolean} suspendUpdate A boolean flag which is false for the + * first call of the function during a fresh plot of the curve and true + * for all subsequent calls of the function. This may be used to speed up the + * plotting of the curve, if the e.g. the curve depends on some input elements. + * @returns {Number} x-coordinate of the curve at t. + */ + X: function (t) { + return NaN; + }, + + /** + * The parametric function which defines the y-coordinate of the curve. + * @param {Number} t A number between {@link JXG.Curve#minX} and {@link JXG.Curve#maxX}. + * @param {Boolean} suspendUpdate A boolean flag which is false for the + * first call of the function during a fresh plot of the curve and true + * for all subsequent calls of the function. This may be used to speed up the + * plotting of the curve, if the e.g. the curve depends on some input elements. + * @returns {Number} y-coordinate of the curve at t. + */ + Y: function (t) { + return NaN; + }, + + /** + * Treat the curve as curve with homogeneous coordinates. + * @param {Number} t A number between {@link JXG.Curve#minX} and {@link JXG.Curve#maxX}. + * @returns {Number} Always 1.0 + */ + Z: function (t) { + return 1; + }, + + /** + * Checks whether (x,y) is near the curve. + * @param {Number} x Coordinate in x direction, screen coordinates. + * @param {Number} y Coordinate in y direction, screen coordinates. + * @param {Number} start Optional start index for search on data plots. + * @returns {Boolean} True if (x,y) is near the curve, False otherwise. + */ + hasPoint: function (x, y, start) { + var t, checkPoint, len, invMat, c, + i, tX, tY, + res = [], + points, qdt, + steps = Type.evaluate(this.visProp.numberpointslow), + d = (this.maxX() - this.minX()) / steps, + prec, type, + dist = Infinity, + ux2, uy2, + ev_ct, + mi, ma, + suspendUpdate = true; + + + if (Type.isObject(Type.evaluate(this.visProp.precision))) { + type = this.board._inputDevice; + prec = Type.evaluate(this.visProp.precision[type]); + } else { + // 'inherit' + prec = this.board.options.precision.hasPoint; + } + checkPoint = new Coords(Const.COORDS_BY_SCREEN, [x, y], this.board, false); + x = checkPoint.usrCoords[1]; + y = checkPoint.usrCoords[2]; + + // We use usrCoords. Only in the final distance calculation + // screen coords are used + prec += Type.evaluate(this.visProp.strokewidth) * 0.5; + prec *= prec; // We do not want to take sqrt + ux2 = this.board.unitX * this.board.unitX; + uy2 = this.board.unitY * this.board.unitY; + + mi = this.minX(); + ma = this.maxX(); + if (Type.exists(this._visibleArea)) { + mi = this._visibleArea[0]; + ma = this._visibleArea[1]; + d = (ma - mi) / steps; + } + + ev_ct = Type.evaluate(this.visProp.curvetype); + if (ev_ct === 'parameter' || ev_ct === 'polar') { + if (this.transformations.length > 0) { + /** + * Transform the mouse/touch coordinates + * back to the original position of the curve. + */ + this.updateTransformMatrix(); + invMat = Mat.inverse(this.transformMat); + c = Mat.matVecMult(invMat, [1, x, y]); + x = c[1]; + y = c[2]; + } + + // Brute force search for a point on the curve close to the mouse pointer + for (i = 0, t = mi; i < steps; i++) { + tX = this.X(t, suspendUpdate); + tY = this.Y(t, suspendUpdate); + + dist = (x - tX) * (x - tX) * ux2 + (y - tY) * (y - tY) * uy2; + + if (dist <= prec) { + return true; + } + + t += d; + } + } else if (ev_ct === 'plot' || + ev_ct === 'functiongraph') { + + if (!Type.exists(start) || start < 0) { + start = 0; + } + + if (Type.exists(this.qdt) && + Type.evaluate(this.visProp.useqdt) && + this.bezierDegree !== 3 + ) { + qdt = this.qdt.query(new Coords(Const.COORDS_BY_USER, [x, y], this.board)); + points = qdt.points; + len = points.length; + } else { + points = this.points; + len = this.numberPoints - 1; + } + + for (i = start; i < len; i++) { + if (this.bezierDegree === 3) { + res.push(Geometry.projectCoordsToBeziersegment([1, x, y], this, i)); + } else { + if (qdt) { + if (points[i].prev) { + res = Geometry.projectCoordsToSegment( + [1, x, y], + points[i].prev.usrCoords, + points[i].usrCoords + ); + } + + // If the next point in the array is the same as the current points + // next neighbor we don't have to project it onto that segment because + // that will already be done in the next iteration of this loop. + if (points[i].next && points[i + 1] !== points[i].next) { + res = Geometry.projectCoordsToSegment( + [1, x, y], + points[i].usrCoords, + points[i].next.usrCoords + ); + } + } else { + res = Geometry.projectCoordsToSegment( + [1, x, y], + points[i].usrCoords, + points[i + 1].usrCoords + ); + } + } + + if (res[1] >= 0 && res[1] <= 1 && + (x - res[0][1]) * (x - res[0][1]) * ux2 + + (y - res[0][2]) * (y - res[0][2]) * uy2 <= prec) { + return true; + } + } + return false; + } + return (dist < prec); + }, + + /** + * Allocate points in the Coords array this.points + */ + allocatePoints: function () { + var i, len; + + len = this.numberPoints; + + if (this.points.length < this.numberPoints) { + for (i = this.points.length; i < len; i++) { + this.points[i] = new Coords(Const.COORDS_BY_USER, [0, 0], this.board, false); + } + } + }, + + /** + * Computes for equidistant points on the x-axis the values of the function + * @returns {JXG.Curve} Reference to the curve object. + * @see JXG.Curve#updateCurve + */ + update: function () { + if (this.needsUpdate) { + if (Type.evaluate(this.visProp.trace)) { + this.cloneToBackground(true); + } + this.updateCurve(); + } + + return this; + }, + + /** + * Updates the visual contents of the curve. + * @returns {JXG.Curve} Reference to the curve object. + */ + updateRenderer: function () { + //var wasReal; + + if (!this.needsUpdate) { + return this; + } + + if (this.visPropCalc.visible) { + // wasReal = this.isReal; + + this.isReal = Plot.checkReal(this.points); + + if (//wasReal && + !this.isReal) { + this.updateVisibility(false); + } + } + + if (this.visPropCalc.visible) { + this.board.renderer.updateCurve(this); + } + + /* Update the label if visible. */ + if (this.hasLabel && this.visPropCalc.visible && this.label && + this.label.visPropCalc.visible && this.isReal) { + + this.label.update(); + this.board.renderer.updateText(this.label); + } + + // Update rendNode display + this.setDisplayRendNode(); + // if (this.visPropCalc.visible !== this.visPropOld.visible) { + // this.board.renderer.display(this, this.visPropCalc.visible); + // this.visPropOld.visible = this.visPropCalc.visible; + // + // if (this.hasLabel) { + // this.board.renderer.display(this.label, this.label.visPropCalc.visible); + // } + // } + + this.needsUpdate = false; + return this; + }, + + /** + * For dynamic dataplots updateCurve can be used to compute new entries + * for the arrays {@link JXG.Curve#dataX} and {@link JXG.Curve#dataY}. It + * is used in {@link JXG.Curve#updateCurve}. Default is an empty method, can + * be overwritten by the user. + * + * + * @example + * // This example overwrites the updateDataArray method. + * // There, new values for the arrays JXG.Curve.dataX and JXG.Curve.dataY + * // are computed from the value of the slider N + * + * var N = board.create('slider', [[0,1.5],[3,1.5],[1,3,40]], {name:'n',snapWidth:1}); + * var circ = board.create('circle',[[4,-1.5],1],{strokeWidth:1, strokecolor:'black', strokeWidth:2, + * fillColor:'#0055ff13'}); + * + * var c = board.create('curve', [[0],[0]],{strokecolor:'red', strokeWidth:2}); + * c.updateDataArray = function() { + * var r = 1, n = Math.floor(N.Value()), + * x = [0], y = [0], + * phi = Math.PI/n, + * h = r*Math.cos(phi), + * s = r*Math.sin(phi), + * i, j, + * px = 0, py = 0, sgn = 1, + * d = 16, + * dt = phi/d, + * pt; + * + * for (i = 0; i < n; i++) { + * for (j = -d; j <= d; j++) { + * pt = dt*j; + * x.push(px + r*Math.sin(pt)); + * y.push(sgn*r*Math.cos(pt) - (sgn-1)*h*0.5); + * } + * px += s; + * sgn *= (-1); + * } + * x.push((n - 1)*s); + * y.push(h + (sgn - 1)*h*0.5); + * this.dataX = x; + * this.dataY = y; + * } + * + * var c2 = board.create('curve', [[0],[0]],{strokecolor:'red', strokeWidth:1}); + * c2.updateDataArray = function() { + * var r = 1, n = Math.floor(N.Value()), + * px = circ.midpoint.X(), py = circ.midpoint.Y(), + * x = [px], y = [py], + * phi = Math.PI/n, + * s = r*Math.sin(phi), + * i, j, + * d = 16, + * dt = phi/d, + * pt = Math.PI*0.5+phi; + * + * for (i = 0; i < n; i++) { + * for (j= -d; j <= d; j++) { + * x.push(px + r*Math.cos(pt)); + * y.push(py + r*Math.sin(pt)); + * pt -= dt; + * } + * x.push(px); + * y.push(py); + * pt += dt; + * } + * this.dataX = x; + * this.dataY = y; + * } + * board.update(); + * + * </pre><div id="JXG20bc7802-e69e-11e5-b1bf-901b0e1b8723" class="jxgbox" style="width: 600px; height: 400px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG20bc7802-e69e-11e5-b1bf-901b0e1b8723', + * {boundingbox: [-1.5,2,8,-3], keepaspectratio: true, axis: true, showcopyright: false, shownavigation: false}); + * var N = board.create('slider', [[0,1.5],[3,1.5],[1,3,40]], {name:'n',snapWidth:1}); + * var circ = board.create('circle',[[4,-1.5],1],{strokeWidth:1, strokecolor:'black', + * strokeWidth:2, fillColor:'#0055ff13'}); + * + * var c = board.create('curve', [[0],[0]],{strokecolor:'red', strokeWidth:2}); + * c.updateDataArray = function() { + * var r = 1, n = Math.floor(N.Value()), + * x = [0], y = [0], + * phi = Math.PI/n, + * h = r*Math.cos(phi), + * s = r*Math.sin(phi), + * i, j, + * px = 0, py = 0, sgn = 1, + * d = 16, + * dt = phi/d, + * pt; + * + * for (i=0;i<n;i++) { + * for (j=-d;j<=d;j++) { + * pt = dt*j; + * x.push(px+r*Math.sin(pt)); + * y.push(sgn*r*Math.cos(pt)-(sgn-1)*h*0.5); + * } + * px += s; + * sgn *= (-1); + * } + * x.push((n-1)*s); + * y.push(h+(sgn-1)*h*0.5); + * this.dataX = x; + * this.dataY = y; + * } + * + * var c2 = board.create('curve', [[0],[0]],{strokecolor:'red', strokeWidth:1}); + * c2.updateDataArray = function() { + * var r = 1, n = Math.floor(N.Value()), + * px = circ.midpoint.X(), py = circ.midpoint.Y(), + * x = [px], y = [py], + * phi = Math.PI/n, + * s = r*Math.sin(phi), + * i, j, + * d = 16, + * dt = phi/d, + * pt = Math.PI*0.5+phi; + * + * for (i=0;i<n;i++) { + * for (j=-d;j<=d;j++) { + * x.push(px+r*Math.cos(pt)); + * y.push(py+r*Math.sin(pt)); + * pt -= dt; + * } + * x.push(px); + * y.push(py); + * pt += dt; + * } + * this.dataX = x; + * this.dataY = y; + * } + * board.update(); + * + * })(); + * + * </script><pre> + * + * @example + * // This is an example which overwrites updateDataArray and produces + * // a Bezier curve of degree three. + * var A = board.create('point', [-3,3]); + * var B = board.create('point', [3,-2]); + * var line = board.create('segment', [A,B]); + * + * var height = 0.5; // height of the curly brace + * + * // Curly brace + * var crl = board.create('curve', [[0],[0]], {strokeWidth:1, strokeColor:'black'}); + * crl.bezierDegree = 3; + * crl.updateDataArray = function() { + * var d = [B.X()-A.X(), B.Y()-A.Y()], + * dl = Math.sqrt(d[0]*d[0]+d[1]*d[1]), + * mid = [(A.X()+B.X())*0.5, (A.Y()+B.Y())*0.5]; + * + * d[0] *= height/dl; + * d[1] *= height/dl; + * + * this.dataX = [ A.X(), A.X()-d[1], mid[0], mid[0]-d[1], mid[0], B.X()-d[1], B.X() ]; + * this.dataY = [ A.Y(), A.Y()+d[0], mid[1], mid[1]+d[0], mid[1], B.Y()+d[0], B.Y() ]; + * }; + * + * // Text + * var txt = board.create('text', [ + * function() { + * var d = [B.X()-A.X(), B.Y()-A.Y()], + * dl = Math.sqrt(d[0]*d[0]+d[1]*d[1]), + * mid = (A.X()+B.X())*0.5; + * + * d[1] *= height/dl; + * return mid-d[1]+0.1; + * }, + * function() { + * var d = [B.X()-A.X(), B.Y()-A.Y()], + * dl = Math.sqrt(d[0]*d[0]+d[1]*d[1]), + * mid = (A.Y()+B.Y())*0.5; + * + * d[0] *= height/dl; + * return mid+d[0]+0.1; + * }, + * function() { return "length=" + JXG.toFixed(B.Dist(A), 2); } + * ]); + * + * + * board.update(); // This update is necessary to call updateDataArray the first time. + * + * </pre><div id="JXGa61a4d66-e69f-11e5-b1bf-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXGa61a4d66-e69f-11e5-b1bf-901b0e1b8723', + * {boundingbox: [-4, 4, 4,-4], axis: true, showcopyright: false, shownavigation: false}); + * var A = board.create('point', [-3,3]); + * var B = board.create('point', [3,-2]); + * var line = board.create('segment', [A,B]); + * + * var height = 0.5; // height of the curly brace + * + * // Curly brace + * var crl = board.create('curve', [[0],[0]], {strokeWidth:1, strokeColor:'black'}); + * crl.bezierDegree = 3; + * crl.updateDataArray = function() { + * var d = [B.X()-A.X(), B.Y()-A.Y()], + * dl = Math.sqrt(d[0]*d[0]+d[1]*d[1]), + * mid = [(A.X()+B.X())*0.5, (A.Y()+B.Y())*0.5]; + * + * d[0] *= height/dl; + * d[1] *= height/dl; + * + * this.dataX = [ A.X(), A.X()-d[1], mid[0], mid[0]-d[1], mid[0], B.X()-d[1], B.X() ]; + * this.dataY = [ A.Y(), A.Y()+d[0], mid[1], mid[1]+d[0], mid[1], B.Y()+d[0], B.Y() ]; + * }; + * + * // Text + * var txt = board.create('text', [ + * function() { + * var d = [B.X()-A.X(), B.Y()-A.Y()], + * dl = Math.sqrt(d[0]*d[0]+d[1]*d[1]), + * mid = (A.X()+B.X())*0.5; + * + * d[1] *= height/dl; + * return mid-d[1]+0.1; + * }, + * function() { + * var d = [B.X()-A.X(), B.Y()-A.Y()], + * dl = Math.sqrt(d[0]*d[0]+d[1]*d[1]), + * mid = (A.Y()+B.Y())*0.5; + * + * d[0] *= height/dl; + * return mid+d[0]+0.1; + * }, + * function() { return "length="+JXG.toFixed(B.Dist(A), 2); } + * ]); + * + * + * board.update(); // This update is necessary to call updateDataArray the first time. + * + * })(); + * + * </script><pre> + * + * + */ + updateDataArray: function () { + // this used to return this, but we shouldn't rely on the user to implement it. + }, + + /** + * Computes the curve path + * @see JXG.Curve#update + * @returns {JXG.Curve} Reference to the curve object. + */ + updateCurve: function () { + var len, mi, ma, x, y, i, + version = this.visProp.plotversion, + //t1, t2, l1, + suspendUpdate = false; + + this.updateTransformMatrix(); + this.updateDataArray(); + mi = this.minX(); + ma = this.maxX(); + + // Discrete data points + // x-coordinates are in an array + if (Type.exists(this.dataX)) { + this.numberPoints = this.dataX.length; + len = this.numberPoints; + + // It is possible, that the array length has increased. + this.allocatePoints(); + + for (i = 0; i < len; i++) { + x = i; + + // y-coordinates are in an array + if (Type.exists(this.dataY)) { + y = i; + // The last parameter prevents rounding in usr2screen(). + this.points[i].setCoordinates(Const.COORDS_BY_USER, [this.dataX[i], this.dataY[i]], false); + } else { + // discrete x data, continuous y data + y = this.X(x); + // The last parameter prevents rounding in usr2screen(). + this.points[i].setCoordinates(Const.COORDS_BY_USER, [this.dataX[i], this.Y(y, suspendUpdate)], false); + } + this.points[i]._t = i; + + // this.updateTransform(this.points[i]); + suspendUpdate = true; + } + // continuous x data + } else { + if (Type.evaluate(this.visProp.doadvancedplot)) { + // console.time("plot"); + + if (version === 1 || Type.evaluate(this.visProp.doadvancedplotold)) { + Plot.updateParametricCurveOld(this, mi, ma); + } else if (version === 2) { + Plot.updateParametricCurve_v2(this, mi, ma); + } else if (version === 3) { + Plot.updateParametricCurve_v3(this, mi, ma); + } else if (version === 4) { + Plot.updateParametricCurve_v4(this, mi, ma); + } else { + Plot.updateParametricCurve_v2(this, mi, ma); + } + // console.timeEnd("plot"); + } else { + if (this.board.updateQuality === this.board.BOARD_QUALITY_HIGH) { + this.numberPoints = Type.evaluate(this.visProp.numberpointshigh); + } else { + this.numberPoints = Type.evaluate(this.visProp.numberpointslow); + } + + // It is possible, that the array length has increased. + this.allocatePoints(); + Plot.updateParametricCurveNaive(this, mi, ma, this.numberPoints); + } + len = this.numberPoints; + + if (Type.evaluate(this.visProp.useqdt) && + this.board.updateQuality === this.board.BOARD_QUALITY_HIGH) { + this.qdt = new QDT(this.board.getBoundingBox()); + for (i = 0; i < this.points.length; i++) { + this.qdt.insert(this.points[i]); + + if (i > 0) { + this.points[i].prev = this.points[i - 1]; + } + + if (i < len - 1) { + this.points[i].next = this.points[i + 1]; + } + } + } + + // for (i = 0; i < len; i++) { + // this.updateTransform(this.points[i]); + // } + } + + if (Type.evaluate(this.visProp.curvetype) !== 'plot' && + Type.evaluate(this.visProp.rdpsmoothing)) { + // console.time("rdp"); + this.points = Numerics.RamerDouglasPeucker(this.points, 0.2); + this.numberPoints = this.points.length; + // console.timeEnd("rdp"); + // console.log(this.numberPoints); + } + + len = this.numberPoints; + for (i = 0; i < len; i++) { + this.updateTransform(this.points[i]); + } + + return this; + }, + + updateTransformMatrix: function () { + var t, i, + len = this.transformations.length; + + this.transformMat = [[1, 0, 0], [0, 1, 0], [0, 0, 1]]; + + for (i = 0; i < len; i++) { + t = this.transformations[i]; + t.update(); + this.transformMat = Mat.matMatMult(t.matrix, this.transformMat); + } + + return this; + }, + + /** + * Applies the transformations of the curve to the given point <tt>p</tt>. + * Before using it, {@link JXG.Curve#updateTransformMatrix} has to be called. + * @param {JXG.Point} p + * @returns {JXG.Point} The given point. + */ + updateTransform: function (p) { + var c, + len = this.transformations.length; + + if (len > 0) { + c = Mat.matVecMult(this.transformMat, p.usrCoords); + p.setCoordinates(Const.COORDS_BY_USER, c, false, true); + } + + return p; + }, + + /** + * Add transformations to this curve. + * @param {JXG.Transformation|Array} transform Either one {@link JXG.Transformation} or an array of {@link JXG.Transformation}s. + * @returns {JXG.Curve} Reference to the curve object. + */ + addTransform: function (transform) { + var i, + list = Type.isArray(transform) ? transform : [transform], + len = list.length; + + for (i = 0; i < len; i++) { + this.transformations.push(list[i]); + } + + return this; + }, + + /** + * Generate the method curve.X() in case curve.dataX is an array + * and generate the method curve.Y() in case curve.dataY is an array. + * @private + * @param {String} which Either 'X' or 'Y' + * @returns {function} + **/ + interpolationFunctionFromArray: function (which) { + var data = 'data' + which, + that = this; + + return function (t, suspendedUpdate) { + var i, j, t0, t1, + arr = that[data], + len = arr.length, + last, + f = []; + + if (isNaN(t)) { + return NaN; + } + + if (t < 0) { + if (Type.isFunction(arr[0])) { + return arr[0](); + } + + return arr[0]; + } + + if (that.bezierDegree === 3) { + last = (len - 1) / 3; + + if (t >= last) { + if (Type.isFunction(arr[arr.length - 1])) { + return arr[arr.length - 1](); + } + + return arr[arr.length - 1]; + } + + i = Math.floor(t) * 3; + t0 = t % 1; + t1 = 1 - t0; + + for (j = 0; j < 4; j++) { + if (Type.isFunction(arr[i + j])) { + f[j] = arr[i + j](); + } else { + f[j] = arr[i + j]; + } + } + + return t1 * t1 * (t1 * f[0] + 3 * t0 * f[1]) + (3 * t1 * f[2] + t0 * f[3]) * t0 * t0; + } + + if (t > len - 2) { + i = len - 2; + } else { + i = parseInt(Math.floor(t), 10); + } + + if (i === t) { + if (Type.isFunction(arr[i])) { + return arr[i](); + } + return arr[i]; + } + + for (j = 0; j < 2; j++) { + if (Type.isFunction(arr[i + j])) { + f[j] = arr[i + j](); + } else { + f[j] = arr[i + j]; + } + } + return f[0] + (f[1] - f[0]) * (t - i); + }; + }, + + /** + * Converts the JavaScript/JessieCode/GEONExT syntax of the defining function term into JavaScript. + * New methods X() and Y() for the Curve object are generated, further + * new methods for minX() and maxX(). + * @see JXG.GeonextParser.geonext2JS. + */ + generateTerm: function (varname, xterm, yterm, mi, ma) { + var fx, fy; + + // Generate the methods X() and Y() + if (Type.isArray(xterm)) { + // Discrete data + this.dataX = xterm; + + this.numberPoints = this.dataX.length; + this.X = this.interpolationFunctionFromArray.apply(this, ['X']); + this.visProp.curvetype = 'plot'; + this.isDraggable = true; + } else { + // Continuous data + this.X = Type.createFunction(xterm, this.board, varname); + if (Type.isString(xterm)) { + this.visProp.curvetype = 'functiongraph'; + } else if (Type.isFunction(xterm) || Type.isNumber(xterm)) { + this.visProp.curvetype = 'parameter'; + } + + this.isDraggable = true; + } + + if (Type.isArray(yterm)) { + this.dataY = yterm; + this.Y = this.interpolationFunctionFromArray.apply(this, ['Y']); + } else { + this.Y = Type.createFunction(yterm, this.board, varname); + } + + /** + * Polar form + * Input data is function xterm() and offset coordinates yterm + */ + if (Type.isFunction(xterm) && Type.isArray(yterm)) { + // Xoffset, Yoffset + fx = Type.createFunction(yterm[0], this.board, ''); + fy = Type.createFunction(yterm[1], this.board, ''); + + this.X = function (phi) { + return xterm(phi) * Math.cos(phi) + fx(); + }; + + this.Y = function (phi) { + return xterm(phi) * Math.sin(phi) + fy(); + }; + + this.visProp.curvetype = 'polar'; + } + + // Set the bounds lower bound + if (Type.exists(mi)) { + this.minX = Type.createFunction(mi, this.board, ''); + } + if (Type.exists(ma)) { + this.maxX = Type.createFunction(ma, this.board, ''); + } + }, + + /** + * Finds dependencies in a given term and notifies the parents by adding the + * dependent object to the found objects child elements. + * @param {String} contentStr String containing dependencies for the given object. + */ + notifyParents: function (contentStr) { + var fstr, dep, + isJessieCode = false, + obj; + + // Read dependencies found by the JessieCode parser + obj = { 'xterm': 1, 'yterm': 1 }; + for (fstr in obj) { + if (obj.hasOwnProperty(fstr) && this.hasOwnProperty(fstr) && this[fstr].origin) { + isJessieCode = true; + for (dep in this[fstr].origin.deps) { + if (this[fstr].origin.deps.hasOwnProperty(dep)) { + this[fstr].origin.deps[dep].addChild(this); + } + } + } + } + + if (!isJessieCode) { + GeonextParser.findDependencies(this, contentStr, this.board); + } + }, + + // documented in geometry element + getLabelAnchor: function () { + var c, x, y, + ax = 0.05 * this.board.canvasWidth, + ay = 0.05 * this.board.canvasHeight, + bx = 0.95 * this.board.canvasWidth, + by = 0.95 * this.board.canvasHeight; + + switch (Type.evaluate(this.visProp.label.position)) { + case 'ulft': + x = ax; + y = ay; + break; + case 'llft': + x = ax; + y = by; + break; + case 'rt': + x = bx; + y = 0.5 * by; + break; + case 'lrt': + x = bx; + y = by; + break; + case 'urt': + x = bx; + y = ay; + break; + case 'top': + x = 0.5 * bx; + y = ay; + break; + case 'bot': + x = 0.5 * bx; + y = by; + break; + default: + // includes case 'lft' + x = ax; + y = 0.5 * by; + } + + c = new Coords(Const.COORDS_BY_SCREEN, [x, y], this.board, false); + return Geometry.projectCoordsToCurve(c.usrCoords[1], c.usrCoords[2], 0, this, this.board)[0]; + }, + + // documented in geometry element + cloneToBackground: function () { + var er, + copy = { + id: this.id + 'T' + this.numTraces, + elementClass: Const.OBJECT_CLASS_CURVE, + + points: this.points.slice(0), + bezierDegree: this.bezierDegree, + numberPoints: this.numberPoints, + board: this.board, + visProp: Type.deepCopy(this.visProp, this.visProp.traceattributes, true) + }; + + copy.visProp.layer = this.board.options.layer.trace; + copy.visProp.curvetype = this.visProp.curvetype; + this.numTraces++; + + Type.clearVisPropOld(copy); + copy.visPropCalc = { + visible: Type.evaluate(copy.visProp.visible) + }; + er = this.board.renderer.enhancedRendering; + this.board.renderer.enhancedRendering = true; + this.board.renderer.drawCurve(copy); + this.board.renderer.enhancedRendering = er; + this.traces[copy.id] = copy.rendNode; + + return this; + }, + + // Already documented in GeometryElement + bounds: function () { + var minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity, + l = this.points.length, i, + bezier, up; + + if (this.bezierDegree === 3) { + // Add methods X(), Y() + for (i = 0; i < l; i++) { + this.points[i].X = Type.bind(function () { return this.usrCoords[1]; }, this.points[i]); + this.points[i].Y = Type.bind(function () { return this.usrCoords[2]; }, this.points[i]); + } + bezier = Numerics.bezier(this.points); + up = bezier[3](); + minX = Numerics.fminbr(function (t) { return bezier[0](t); }, [0, up]); + maxX = Numerics.fminbr(function (t) { return -bezier[0](t); }, [0, up]); + minY = Numerics.fminbr(function (t) { return bezier[1](t); }, [0, up]); + maxY = Numerics.fminbr(function (t) { return -bezier[1](t); }, [0, up]); + + minX = bezier[0](minX); + maxX = bezier[0](maxX); + minY = bezier[1](minY); + maxY = bezier[1](maxY); + return [minX, maxY, maxX, minY]; + } + + // Linear segments + for (i = 0; i < l; i++) { + if (minX > this.points[i].usrCoords[1]) { + minX = this.points[i].usrCoords[1]; + } + + if (maxX < this.points[i].usrCoords[1]) { + maxX = this.points[i].usrCoords[1]; + } + + if (minY > this.points[i].usrCoords[2]) { + minY = this.points[i].usrCoords[2]; + } + + if (maxY < this.points[i].usrCoords[2]) { + maxY = this.points[i].usrCoords[2]; + } + } + + return [minX, maxY, maxX, minY]; + }, + + // documented in element.js + getParents: function () { + var p = [this.xterm, this.yterm, this.minX(), this.maxX()]; + + if (this.parents.length !== 0) { + p = this.parents; + } + + return p; + }, + + /** + * Shift the curve by the vector 'where'. + * + * @param {Array} where Array containing the x and y coordinate of the target location. + * @returns {JXG.Curve} Reference to itself. + */ + moveTo: function (where) { + // TODO add animation + var delta = [], p; + if (this.points.length > 0 && !Type.evaluate(this.visProp.fixed)) { + p = this.points[0]; + if (where.length === 3) { + delta = [where[0] - p.usrCoords[0], + where[1] - p.usrCoords[1], + where[2] - p.usrCoords[2]]; + } else { + delta = [where[0] - p.usrCoords[1], + where[1] - p.usrCoords[2]]; + } + this.setPosition(Const.COORDS_BY_USER, delta); + } + return this; + }, + + /** + * If the curve is the result of a transformation applied + * to a continuous curve, the glider projection has to be done + * on the original curve. Otherwise there will be problems + * when changing between high and low precision plotting, + * since there number of points changes. + * + * @private + * @returns {Array} [Boolean, curve]: Array contining 'true' if curve is result of a transformation, + * and the source curve of the transformation. + */ + getTransformationSource: function () { + var isTransformed, curve_org; + if (Type.exists(this._transformationSource)) { + curve_org = this._transformationSource; + if (curve_org.elementClass === Const.OBJECT_CLASS_CURVE //&& + //Type.evaluate(curve_org.visProp.curvetype) !== 'plot' + ) { + isTransformed = true; + } + } + return [isTransformed, curve_org]; + } + + }); + + /** + * @class This element is used to provide a constructor for curve, which is just a wrapper for element {@link Curve}. + * A curve is a mapping from R to R^2. t mapsto (x(t),y(t)). The graph is drawn for t in the interval [a,b]. + * <p> + * The following types of curves can be plotted: + * <ul> + * <li> parametric curves: t mapsto (x(t),y(t)), where x() and y() are univariate functions. + * <li> polar curves: curves commonly written with polar equations like spirals and cardioids. + * <li> data plots: plot line segments through a given list of coordinates. + * </ul> + * @pseudo + * @description + * @name Curve + * @augments JXG.Curve + * @constructor + * @type JXG.Curve + * + * @param {function,number_function,number_function,number_function,number} x,y,a_,b_ Parent elements for Parametric Curves. + * <p> + * x describes the x-coordinate of the curve. It may be a function term in one variable, e.g. x(t). + * In case of x being of type number, x(t) is set to a constant function. + * this function at the values of the array. + * </p> + * <p> + * y describes the y-coordinate of the curve. In case of a number, y(t) is set to the constant function + * returning this number. + * </p> + * <p> + * Further parameters are an optional number or function for the left interval border a, + * and an optional number or function for the right interval border b. + * </p> + * <p> + * Default values are a=-10 and b=10. + * </p> + * @param {array_array,function,number} x,y Parent elements for Data Plots. + * <p> + * x and y are arrays contining the x and y coordinates of the data points which are connected by + * line segments. The individual entries of x and y may also be functions. + * In case of x being an array the curve type is data plot, regardless of the second parameter and + * if additionally the second parameter y is a function term the data plot evaluates. + * </p> + * @param {function_array,function,number_function,number_function,number} r,offset_,a_,b_ Parent elements for Polar Curves. + * <p> + * The first parameter is a function term r(phi) describing the polar curve. + * </p> + * <p> + * The second parameter is the offset of the curve. It has to be + * an array containing numbers or functions describing the offset. Default value is the origin [0,0]. + * </p> + * <p> + * Further parameters are an optional number or function for the left interval border a, + * and an optional number or function for the right interval border b. + * </p> + * <p> + * Default values are a=-10 and b=10. + * </p> + * <p> + * Additionally, a curve can be created by providing a curve and a transformation (or an array of transformations). + * The result is a curve which is the transformation of the supplied curve. + * + * @see JXG.Curve + * @example + * // Parametric curve + * // Create a curve of the form (t-sin(t), 1-cos(t), i.e. + * // the cycloid curve. + * var graph = board.create('curve', + * [function(t){ return t-Math.sin(t);}, + * function(t){ return 1-Math.cos(t);}, + * 0, 2*Math.PI] + * ); + * </pre><div class="jxgbox" id="JXGaf9f818b-f3b6-4c4d-8c4c-e4a4078b726d" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * var c1_board = JXG.JSXGraph.initBoard('JXGaf9f818b-f3b6-4c4d-8c4c-e4a4078b726d', {boundingbox: [-1, 5, 7, -1], axis: true, showcopyright: false, shownavigation: false}); + * var graph1 = c1_board.create('curve', [function(t){ return t-Math.sin(t);},function(t){ return 1-Math.cos(t);},0, 2*Math.PI]); + * </script><pre> + * @example + * // Data plots + * // Connect a set of points given by coordinates with dashed line segments. + * // The x- and y-coordinates of the points are given in two separate + * // arrays. + * var x = [0,1,2,3,4,5,6,7,8,9]; + * var y = [9.2,1.3,7.2,-1.2,4.0,5.3,0.2,6.5,1.1,0.0]; + * var graph = board.create('curve', [x,y], {dash:2}); + * </pre><div class="jxgbox" id="JXG7dcbb00e-b6ff-481d-b4a8-887f5d8c6a83" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * var c3_board = JXG.JSXGraph.initBoard('JXG7dcbb00e-b6ff-481d-b4a8-887f5d8c6a83', {boundingbox: [-1,10,10,-1], axis: true, showcopyright: false, shownavigation: false}); + * var x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; + * var y = [9.2, 1.3, 7.2, -1.2, 4.0, 5.3, 0.2, 6.5, 1.1, 0.0]; + * var graph3 = c3_board.create('curve', [x,y], {dash:2}); + * </script><pre> + * @example + * // Polar plot + * // Create a curve with the equation r(phi)= a*(1+phi), i.e. + * // a cardioid. + * var a = board.create('slider',[[0,2],[2,2],[0,1,2]]); + * var graph = board.create('curve', + * [function(phi){ return a.Value()*(1-Math.cos(phi));}, + * [1,0], + * 0, 2*Math.PI], + * {curveType: 'polar'} + * ); + * </pre><div class="jxgbox" id="JXGd0bc7a2a-8124-45ca-a6e7-142321a8f8c2" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * var c2_board = JXG.JSXGraph.initBoard('JXGd0bc7a2a-8124-45ca-a6e7-142321a8f8c2', {boundingbox: [-3,3,3,-3], axis: true, showcopyright: false, shownavigation: false}); + * var a = c2_board.create('slider',[[0,2],[2,2],[0,1,2]]); + * var graph2 = c2_board.create('curve', [function(phi){ return a.Value()*(1-Math.cos(phi));}, [1,0], 0, 2*Math.PI], {curveType: 'polar'}); + * </script><pre> + * + * @example + * // Draggable Bezier curve + * var col, p, c; + * col = 'blue'; + * p = []; + * p.push(board.create('point',[-2, -1 ], {size: 5, strokeColor:col, fillColor:col})); + * p.push(board.create('point',[1, 2.5 ], {size: 5, strokeColor:col, fillColor:col})); + * p.push(board.create('point',[-1, -2.5 ], {size: 5, strokeColor:col, fillColor:col})); + * p.push(board.create('point',[2, -2], {size: 5, strokeColor:col, fillColor:col})); + * + * c = board.create('curve', JXG.Math.Numerics.bezier(p), + * {strokeColor:'red', name:"curve", strokeWidth:5, fixed: false}); // Draggable curve + * c.addParents(p); + * </pre><div class="jxgbox" id="JXG7bcc6280-f6eb-433e-8281-c837c3387849" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function(){ + * var board, col, p, c; + * board = JXG.JSXGraph.initBoard('JXG7bcc6280-f6eb-433e-8281-c837c3387849', {boundingbox: [-3,3,3,-3], axis: true, showcopyright: false, shownavigation: false}); + * col = 'blue'; + * p = []; + * p.push(board.create('point',[-2, -1 ], {size: 5, strokeColor:col, fillColor:col})); + * p.push(board.create('point',[1, 2.5 ], {size: 5, strokeColor:col, fillColor:col})); + * p.push(board.create('point',[-1, -2.5 ], {size: 5, strokeColor:col, fillColor:col})); + * p.push(board.create('point',[2, -2], {size: 5, strokeColor:col, fillColor:col})); + * + * c = board.create('curve', JXG.Math.Numerics.bezier(p), + * {strokeColor:'red', name:"curve", strokeWidth:5, fixed: false}); // Draggable curve + * c.addParents(p); + * })(); + * </script><pre> + * + * @example + * // The curve cu2 is the reflection of cu1 against line li + * var li = board.create('line', [1,1,1], {strokeColor: '#aaaaaa'}); + * var reflect = board.create('transform', [li], {type: 'reflect'}); + * var cu1 = board.create('curve', [[-1, -1, -0.5, -1, -1, -0.5], [-3, -2, -2, -2, -2.5, -2.5]]); + * var cu2 = board.create('curve', [cu1, reflect], {strokeColor: 'red'}); + * + * </pre><div id="JXG866dc7a2-d448-11e7-93b3-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG866dc7a2-d448-11e7-93b3-901b0e1b8723', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * var li = board.create('line', [1,1,1], {strokeColor: '#aaaaaa'}); + * var reflect = board.create('transform', [li], {type: 'reflect'}); + * var cu1 = board.create('curve', [[-1, -1, -0.5, -1, -1, -0.5], [-3, -2, -2, -2, -2.5, -2.5]]); + * var cu2 = board.create('curve', [cu1, reflect], {strokeColor: 'red'}); + * + * })(); + * + * </script><pre> + */ + JXG.createCurve = function (board, parents, attributes) { + var obj, cu, + attr = Type.copyAttributes(attributes, board.options, 'curve'); + + obj = board.select(parents[0], true); + if (Type.isObject(obj) && + (obj.type === Const.OBJECT_TYPE_CURVE || + obj.type === Const.OBJECT_TYPE_ANGLE || + obj.type === Const.OBJECT_TYPE_ARC || + obj.type === Const.OBJECT_TYPE_CONIC || + obj.type === Const.OBJECT_TYPE_SECTOR) && + Type.isTransformationOrArray(parents[1])) { + + if (obj.type === Const.OBJECT_TYPE_SECTOR) { + attr = Type.copyAttributes(attributes, board.options, 'sector'); + } else if (obj.type === Const.OBJECT_TYPE_ARC) { + attr = Type.copyAttributes(attributes, board.options, 'arc'); + } else if (obj.type === Const.OBJECT_TYPE_ANGLE) { + if (!Type.exists(attributes.withLabel)) { + attributes.withLabel = false; + } + attr = Type.copyAttributes(attributes, board.options, 'angle'); + } else { + attr = Type.copyAttributes(attributes, board.options, 'curve'); + } + attr = Type.copyAttributes(attr, board.options, 'curve'); + + cu = new JXG.Curve(board, ['x', [], []], attr); + cu.updateDataArray = function () { + var i, le = obj.numberPoints; + this.bezierDegree = obj.bezierDegree; + this.dataX = []; + this.dataY = []; + for (i = 0; i < le; i++) { + this.dataX.push(obj.points[i].usrCoords[1]); + this.dataY.push(obj.points[i].usrCoords[2]); + } + return this; + }; + cu.addTransform(parents[1]); + obj.addChild(cu); + cu.setParents([obj]); + cu._transformationSource = obj; + + return cu; + } + attr = Type.copyAttributes(attributes, board.options, 'curve'); + return new JXG.Curve(board, ['x'].concat(parents), attr); + }; + + JXG.registerElement('curve', JXG.createCurve); + + /** + * @class This element is used to provide a constructor for functiongraph, + * which is just a wrapper for element {@link Curve} with {@link JXG.Curve#X}() + * set to x. The graph is drawn for x in the interval [a,b]. + * @pseudo + * @description + * @name Functiongraph + * @augments JXG.Curve + * @constructor + * @type JXG.Curve + * @param {function_number,function_number,function} f,a_,b_ Parent elements are a function term f(x) describing the function graph. + * <p> + * Further, an optional number or function for the left interval border a, + * and an optional number or function for the right interval border b. + * <p> + * Default values are a=-10 and b=10. + * @see JXG.Curve + * @example + * // Create a function graph for f(x) = 0.5*x*x-2*x + * var graph = board.create('functiongraph', + * [function(x){ return 0.5*x*x-2*x;}, -2, 4] + * ); + * </pre><div class="jxgbox" id="JXGefd432b5-23a3-4846-ac5b-b471e668b437" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * var alex1_board = JXG.JSXGraph.initBoard('JXGefd432b5-23a3-4846-ac5b-b471e668b437', {boundingbox: [-3, 7, 5, -3], axis: true, showcopyright: false, shownavigation: false}); + * var graph = alex1_board.create('functiongraph', [function(x){ return 0.5*x*x-2*x;}, -2, 4]); + * </script><pre> + * @example + * // Create a function graph for f(x) = 0.5*x*x-2*x with variable interval + * var s = board.create('slider',[[0,4],[3,4],[-2,4,5]]); + * var graph = board.create('functiongraph', + * [function(x){ return 0.5*x*x-2*x;}, + * -2, + * function(){return s.Value();}] + * ); + * </pre><div class="jxgbox" id="JXG4a203a84-bde5-4371-ad56-44619690bb50" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * var alex2_board = JXG.JSXGraph.initBoard('JXG4a203a84-bde5-4371-ad56-44619690bb50', {boundingbox: [-3, 7, 5, -3], axis: true, showcopyright: false, shownavigation: false}); + * var s = alex2_board.create('slider',[[0,4],[3,4],[-2,4,5]]); + * var graph = alex2_board.create('functiongraph', [function(x){ return 0.5*x*x-2*x;}, -2, function(){return s.Value();}]); + * </script><pre> + */ + JXG.createFunctiongraph = function (board, parents, attributes) { + var attr, + par = ['x', 'x'].concat(parents); + + attr = Type.copyAttributes(attributes, board.options, 'curve'); + attr.curvetype = 'functiongraph'; + return new JXG.Curve(board, par, attr); + }; + + JXG.registerElement('functiongraph', JXG.createFunctiongraph); + JXG.registerElement('plot', JXG.createFunctiongraph); + + /** + * @class This element is used to provide a constructor for (natural) cubic spline curves. + * Create a dynamic spline interpolated curve given by sample points p_1 to p_n. + * @pseudo + * @description + * @name Spline + * @augments JXG.Curve + * @constructor + * @type JXG.Curve + * @param {JXG.Board} board Reference to the board the spline is drawn on. + * @param {Array} parents Array of points the spline interpolates. This can be + * <ul> + * <li> an array of JXGGraph points</li> + * <li> an array of coordinate pairs</li> + * <li> an array of functions returning coordinate pairs</li> + * <li> an array consisting of an array with x-coordinates and an array of y-coordinates</li> + * </ul> + * All individual entries of coordinates arrays may be numbers or functions returning numbers. + * @param {Object} attributes Define color, width, ... of the spline + * @returns {JXG.Curve} Returns reference to an object of type JXG.Curve. + * @see JXG.Curve + * @example + * + * var p = []; + * p[0] = board.create('point', [-2,2], {size: 4, face: 'o'}); + * p[1] = board.create('point', [0,-1], {size: 4, face: 'o'}); + * p[2] = board.create('point', [2,0], {size: 4, face: 'o'}); + * p[3] = board.create('point', [4,1], {size: 4, face: 'o'}); + * + * var c = board.create('spline', p, {strokeWidth:3}); + * </pre><div id="JXG6c197afc-e482-11e5-b1bf-901b0e1b8723" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG6c197afc-e482-11e5-b1bf-901b0e1b8723', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * + * var p = []; + * p[0] = board.create('point', [-2,2], {size: 4, face: 'o'}); + * p[1] = board.create('point', [0,-1], {size: 4, face: 'o'}); + * p[2] = board.create('point', [2,0], {size: 4, face: 'o'}); + * p[3] = board.create('point', [4,1], {size: 4, face: 'o'}); + * + * var c = board.create('spline', p, {strokeWidth:3}); + * })(); + * + * </script><pre> + * + */ + JXG.createSpline = function (board, parents, attributes) { + var el, funcs, ret; + + funcs = function () { + var D, x = [], y = []; + + return [function (t, suspended) { // Function term + var i, j, c; + + if (!suspended) { + x = []; + y = []; + + // given as [x[], y[]] + if (parents.length === 2 && Type.isArray(parents[0]) && Type.isArray(parents[1]) && parents[0].length === parents[1].length) { + for (i = 0; i < parents[0].length; i++) { + if (Type.isFunction(parents[0][i])) { + x.push(parents[0][i]()); + } else { + x.push(parents[0][i]); + } + + if (Type.isFunction(parents[1][i])) { + y.push(parents[1][i]()); + } else { + y.push(parents[1][i]); + } + } + } else { + for (i = 0; i < parents.length; i++) { + if (Type.isPoint(parents[i])) { + x.push(parents[i].X()); + y.push(parents[i].Y()); + // given as [[x1,y1], [x2, y2], ...] + } else if (Type.isArray(parents[i]) && parents[i].length === 2) { + for (j = 0; j < parents.length; j++) { + if (Type.isFunction(parents[j][0])) { + x.push(parents[j][0]()); + } else { + x.push(parents[j][0]); + } + + if (Type.isFunction(parents[j][1])) { + y.push(parents[j][1]()); + } else { + y.push(parents[j][1]); + } + } + } else if (Type.isFunction(parents[i]) && parents[i]().length === 2) { + c = parents[i](); + x.push(c[0]); + y.push(c[1]); + } + } + } + + // The array D has only to be calculated when the position of one or more sample points + // changes. Otherwise D is always the same for all points on the spline. + D = Numerics.splineDef(x, y); + } + + return Numerics.splineEval(t, x, y, D); + }, + // minX() + function () { + return x[0]; + }, + //maxX() + function () { + return x[x.length - 1]; + }]; + + }; + + attributes = Type.copyAttributes(attributes, board.options, 'curve'); + attributes.curvetype = 'functiongraph'; + ret = funcs(); + el = new JXG.Curve(board, ['x', 'x', ret[0], ret[1], ret[2]], attributes); + el.setParents(parents); + el.elType = 'spline'; + + return el; + }; + + /** + * Register the element type spline at JSXGraph + * @private + */ + JXG.registerElement('spline', JXG.createSpline); + + /** + * @class This element is used to provide a constructor for cardinal spline curves. + * Create a dynamic cardinal spline interpolated curve given by sample points p_1 to p_n. + * @pseudo + * @description + * @name Cardinalspline + * @augments JXG.Curve + * @constructor + * @type JXG.Curve + * @param {JXG.Board} board Reference to the board the cardinal spline is drawn on. + * @param {Array} parents Array with three entries. + * <p> + * First entry: Array of points the spline interpolates. This can be + * <ul> + * <li> an array of JXGGraph points</li> + * <li> an array of coordinate pairs</li> + * <li> an array of functions returning coordinate pairs</li> + * <li> an array consisting of an array with x-coordinates and an array of y-coordinates</li> + * </ul> + * All individual entries of coordinates arrays may be numbers or functions returning numbers. + * <p> + * Second entry: tau number or function + * <p> + * Third entry: type string containing 'uniform' (default) or 'centripetal'. + * @param {Object} attributes Define color, width, ... of the cardinal spline + * @returns {JXG.Curve} Returns reference to an object of type JXG.Curve. + * @see JXG.Curve + * @example + * //create a cardinal spline out of an array of JXG points with adjustable tension + * //create array of points + * var p1 = board.create('point',[0,0]) + * var p2 = board.create('point',[1,4]) + * var p3 = board.create('point',[4,5]) + * var p4 = board.create('point',[2,3]) + * var p5 = board.create('point',[3,0]) + * var p = [p1,p2,p3,p4,p5] + * + * // tension + * tau = board.create('slider', [[4,3],[9,3],[0.001,0.5,1]], {name:'tau'}); + * c = board.create('curve', JXG.Math.Numerics.CardinalSpline(p, function(){ return tau.Value();}), {strokeWidth:3}); + * </pre><div id="JXG6c197afc-e482-11e5-b2af-901b0e1b8723" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG6c197afc-e482-11e5-b2af-901b0e1b8723', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * + * var p = []; + * p[0] = board.create('point', [-2,2], {size: 4, face: 'o'}); + * p[1] = board.create('point', [0,-1], {size: 4, face: 'o'}); + * p[2] = board.create('point', [2,0], {size: 4, face: 'o'}); + * p[3] = board.create('point', [4,1], {size: 4, face: 'o'}); + * + * var c = board.create('spline', p, {strokeWidth:3}); + * })(); + * + * </script><pre> + */ + JXG.createCardinalSpline = function (board, parents, attributes) { + var el, getPointLike, + points, tau, type, + p, q, i, le, + splineArr, + errStr = "\nPossible parent types: [points:array, tau:number|function, type:string]"; + + if (!Type.exists(parents[0]) || !Type.isArray(parents[0])) { + throw new Error("JSXGraph: JXG.createCardinalSpline: argument 1 'points' has to be array of points or coordinate pairs" + errStr); + } + if (!Type.exists(parents[1]) || (!Type.isNumber(parents[1]) && !Type.isFunction(parents[1]))) { + throw new Error("JSXGraph: JXG.createCardinalSpline: argument 2 'tau' has to be number between [0,1] or function'" + errStr); + } + if (!Type.exists(parents[2]) || !Type.isString(parents[2])) { + throw new Error("JSXGraph: JXG.createCardinalSpline: argument 3 'type' has to be string 'uniform' or 'centripetal'" + errStr); + } + + attributes = Type.copyAttributes(attributes, board.options, 'curve'); + attributes = Type.copyAttributes(attributes, board.options, 'cardinalspline'); + attributes.curvetype = 'parameter'; + + p = parents[0]; + q = []; + + // given as [x[], y[]] + if (!attributes.isarrayofcoordinates && + p.length === 2 && Type.isArray(p[0]) && Type.isArray(p[1]) && + p[0].length === p[1].length) { + for (i = 0; i < p[0].length; i++) { + q[i] = []; + if (Type.isFunction(p[0][i])) { + q[i].push(p[0][i]()); + } else { + q[i].push(p[0][i]); + } + + if (Type.isFunction(p[1][i])) { + q[i].push(p[1][i]()); + } else { + q[i].push(p[1][i]); + } + } + } else { + // given as [[x0, y0], [x1, y1], point, ...] + for (i = 0; i < p.length; i++) { + if (Type.isString(p[i])) { + q.push(board.select(p[i])); + } else if (Type.isPoint(p[i])) { + q.push(p[i]); + // given as [[x0,y0], [x1, y2], ...] + } else if (Type.isArray(p[i]) && p[i].length === 2) { + q[i] = []; + if (Type.isFunction(p[i][0])) { + q[i].push(p[i][0]()); + } else { + q[i].push(p[i][0]); + } + + if (Type.isFunction(p[i][1])) { + q[i].push(p[i][1]()); + } else { + q[i].push(p[i][1]); + } + } else if (Type.isFunction(p[i]) && p[i]().length === 2) { + q.push(parents[i]()); + } + } + } + + if (attributes.createpoints === true) { + points = Type.providePoints(board, q, attributes, 'cardinalspline', ['points']); + } else { + points = []; + + /** + * @ignore + */ + getPointLike = function (ii) { + return { + X: function () { return q[ii][0]; }, + Y: function () { return q[ii][1]; }, + Dist: function (p) { + var dx = this.X() - p.X(), + dy = this.Y() - p.Y(); + return Math.sqrt(dx * dx + dy * dy); + } + }; + }; + + for (i = 0; i < q.length; i++) { + if (Type.isPoint(q[i])) { + points.push(q[i]); + } else { + points.push(getPointLike(i)); + } + } + } + + tau = parents[1]; + type = parents[2]; + + splineArr = ['x'].concat(Numerics.CardinalSpline(points, tau, type)); + + el = new JXG.Curve(board, splineArr, attributes); + le = points.length; + el.setParents(points); + for (i = 0; i < le; i++) { + p = points[i]; + if (Type.isPoint(p)) { + if (Type.exists(p._is_new)) { + el.addChild(p); + delete p._is_new; + } else { + p.addChild(el); + } + } + } + el.elType = 'cardinalspline'; + + return el; + }; + + /** + * Register the element type cardinalspline at JSXGraph + * @private + */ + JXG.registerElement('cardinalspline', JXG.createCardinalSpline); + + /** + * @class This element is used to provide a constructor for metapost spline curves. + * Create a dynamic metapost spline interpolated curve given by sample points p_1 to p_n. + * @pseudo + * @description + * @name Metapostspline + * @augments JXG.Curve + * @constructor + * @type JXG.Curve + * @param {JXG.Board} board Reference to the board the metapost spline is drawn on. + * @param {Array} parents Array with two entries. + * <p> + * First entry: Array of points the spline interpolates. This can be + * <ul> + * <li> an array of JXGGraph points</li> + * <li> an object of coordinate pairs</li> + * <li> an array of functions returning coordinate pairs</li> + * <li> an array consisting of an array with x-coordinates and an array of y-coordinates</li> + * </ul> + * All individual entries of coordinates arrays may be numbers or functions returning numbers. + * <p> + * Second entry: JavaScript object containing the control values like tension, direction, curl. + * @param {Object} attributes Define color, width, ... of the metapost spline + * @returns {JXG.Curve} Returns reference to an object of type JXG.Curve. + * @see JXG.Curve + * @example + * var po = [], + * attr = { + * size: 5, + * color: 'red' + * }, + * controls; + * + * var tension = board.create('slider', [[-3, 6], [3, 6], [0, 1, 20]], {name: 'tension'}); + * var curl = board.create('slider', [[-3, 5], [3, 5], [0, 1, 30]], {name: 'curl A, D'}); + * var dir = board.create('slider', [[-3, 4], [3, 4], [-180, 0, 180]], {name: 'direction B'}); + * + * po.push(board.create('point', [-3, -3])); + * po.push(board.create('point', [0, -3])); + * po.push(board.create('point', [4, -5])); + * po.push(board.create('point', [6, -2])); + * + * var controls = { + * tension: function() {return tension.Value(); }, + * direction: { 1: function() {return dir.Value(); } }, + * curl: { 0: function() {return curl.Value(); }, + * 3: function() {return curl.Value(); } + * }, + * isClosed: false + * }; + * + * // Plot a metapost curve + * var cu = board.create('metapostspline', [po, controls], {strokeColor: 'blue', strokeWidth: 2}); + * + * + * </pre><div id="JXGb8c6ffed-7419-41a3-9e55-3754b2327ae9" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXGb8c6ffed-7419-41a3-9e55-3754b2327ae9', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * var po = [], + * attr = { + * size: 5, + * color: 'red' + * }, + * controls; + * + * var tension = board.create('slider', [[-3, 6], [3, 6], [0, 1, 20]], {name: 'tension'}); + * var curl = board.create('slider', [[-3, 5], [3, 5], [0, 1, 30]], {name: 'curl A, D'}); + * var dir = board.create('slider', [[-3, 4], [3, 4], [-180, 0, 180]], {name: 'direction B'}); + * + * po.push(board.create('point', [-3, -3])); + * po.push(board.create('point', [0, -3])); + * po.push(board.create('point', [4, -5])); + * po.push(board.create('point', [6, -2])); + * + * var controls = { + * tension: function() {return tension.Value(); }, + * direction: { 1: function() {return dir.Value(); } }, + * curl: { 0: function() {return curl.Value(); }, + * 3: function() {return curl.Value(); } + * }, + * isClosed: false + * }; + * + * // Plot a metapost curve + * var cu = board.create('metapostspline', [po, controls], {strokeColor: 'blue', strokeWidth: 2}); + * + * + * })(); + * + * </script><pre> + * + */ + JXG.createMetapostSpline = function (board, parents, attributes) { + var el, getPointLike, + points, controls, + p, q, i, le, + errStr = "\nPossible parent types: [points:array, controls:object"; + + if (!Type.exists(parents[0]) || !Type.isArray(parents[0])) { + throw new Error("JSXGraph: JXG.createMetapostSpline: argument 1 'points' has to be array of points or coordinate pairs" + errStr); + } + if (!Type.exists(parents[1]) || !Type.isObject(parents[1])) { + throw new Error("JSXGraph: JXG.createMetapostSpline: argument 2 'controls' has to be a JavaScript object'" + errStr); + } + + attributes = Type.copyAttributes(attributes, board.options, 'curve'); + attributes = Type.copyAttributes(attributes, board.options, 'metapostspline'); + attributes.curvetype = 'parameter'; + + p = parents[0]; + q = []; + + // given as [x[], y[]] + if (!attributes.isarrayofcoordinates && + p.length === 2 && Type.isArray(p[0]) && Type.isArray(p[1]) && + p[0].length === p[1].length) { + for (i = 0; i < p[0].length; i++) { + q[i] = []; + if (Type.isFunction(p[0][i])) { + q[i].push(p[0][i]()); + } else { + q[i].push(p[0][i]); + } + + if (Type.isFunction(p[1][i])) { + q[i].push(p[1][i]()); + } else { + q[i].push(p[1][i]); + } + } + } else { + // given as [[x0, y0], [x1, y1], point, ...] + for (i = 0; i < p.length; i++) { + if (Type.isString(p[i])) { + q.push(board.select(p[i])); + } else if (Type.isPoint(p[i])) { + q.push(p[i]); + // given as [[x0,y0], [x1, y2], ...] + } else if (Type.isArray(p[i]) && p[i].length === 2) { + q[i] = []; + if (Type.isFunction(p[i][0])) { + q[i].push(p[i][0]()); + } else { + q[i].push(p[i][0]); + } + + if (Type.isFunction(p[i][1])) { + q[i].push(p[i][1]()); + } else { + q[i].push(p[i][1]); + } + } else if (Type.isFunction(p[i]) && p[i]().length === 2) { + q.push(parents[i]()); + } + } + } + + if (attributes.createpoints === true) { + points = Type.providePoints(board, q, attributes, 'metapostspline', ['points']); + } else { + points = []; + + /** + * @ignore + */ + getPointLike = function (ii) { + return { + X: function () { return q[ii][0]; }, + Y: function () { return q[ii][1]; } + }; + }; + + for (i = 0; i < q.length; i++) { + if (Type.isPoint(q[i])) { + points.push(q[i]); + } else { + points.push(getPointLike); + } + } + } + + controls = parents[1]; + + el = new JXG.Curve(board, ['t', [], [], 0, p.length - 1], attributes); + el.updateDataArray = function () { + var res, i, + len = points.length, + p = []; + + for (i = 0; i < len; i++) { + p.push([points[i].X(), points[i].Y()]); + } + + res = JXG.Math.Metapost.curve(p, controls); + this.dataX = res[0]; + this.dataY = res[1]; + }; + el.bezierDegree = 3; + + le = points.length; + el.setParents(points); + for (i = 0; i < le; i++) { + if (Type.isPoint(points[i])) { + points[i].addChild(el); + } + } + el.elType = 'metapostspline'; + + return el; + }; + + JXG.registerElement('metapostspline', JXG.createMetapostSpline); + + /** + * @class This element is used to provide a constructor for Riemann sums, which is realized as a special curve. + * The returned element has the method Value() which returns the sum of the areas of the bars. + * @pseudo + * @description + * @name Riemannsum + * @augments JXG.Curve + * @constructor + * @type JXG.Curve + * @param {function,array_number,function_string,function_function,number_function,number} f,n,type_,a_,b_ Parent elements of Riemannsum are a + * Either a function term f(x) describing the function graph which is filled by the Riemann bars, or + * an array consisting of two functions and the area between is filled by the Riemann bars. + * <p> + * n determines the number of bars, it is either a fixed number or a function. + * <p> + * type is a string or function returning one of the values: 'left', 'right', 'middle', 'lower', 'upper', 'random', 'simpson', or 'trapezoidal'. + * Default value is 'left'. + * <p> + * Further parameters are an optional number or function for the left interval border a, + * and an optional number or function for the right interval border b. + * <p> + * Default values are a=-10 and b=10. + * @see JXG.Curve + * @example + * // Create Riemann sums for f(x) = 0.5*x*x-2*x. + * var s = board.create('slider',[[0,4],[3,4],[0,4,10]],{snapWidth:1}); + * var f = function(x) { return 0.5*x*x-2*x; }; + * var r = board.create('riemannsum', + * [f, function(){return s.Value();}, 'upper', -2, 5], + * {fillOpacity:0.4} + * ); + * var g = board.create('functiongraph',[f, -2, 5]); + * var t = board.create('text',[-2,-2, function(){ return 'Sum=' + JXG.toFixed(r.Value(), 4); }]); + * </pre><div class="jxgbox" id="JXG940f40cc-2015-420d-9191-c5d83de988cf" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function(){ + * var board = JXG.JSXGraph.initBoard('JXG940f40cc-2015-420d-9191-c5d83de988cf', {boundingbox: [-3, 7, 5, -3], axis: true, showcopyright: false, shownavigation: false}); + * var f = function(x) { return 0.5*x*x-2*x; }; + * var s = board.create('slider',[[0,4],[3,4],[0,4,10]],{snapWidth:1}); + * var r = board.create('riemannsum', [f, function(){return s.Value();}, 'upper', -2, 5], {fillOpacity:0.4}); + * var g = board.create('functiongraph', [f, -2, 5]); + * var t = board.create('text',[-2,-2, function(){ return 'Sum=' + JXG.toFixed(r.Value(), 4); }]); + * })(); + * </script><pre> + * + * @example + * // Riemann sum between two functions + * var s = board.create('slider',[[0,4],[3,4],[0,4,10]],{snapWidth:1}); + * var g = function(x) { return 0.5*x*x-2*x; }; + * var f = function(x) { return -x*(x-4); }; + * var r = board.create('riemannsum', + * [[g,f], function(){return s.Value();}, 'lower', 0, 4], + * {fillOpacity:0.4} + * ); + * var f = board.create('functiongraph',[f, -2, 5]); + * var g = board.create('functiongraph',[g, -2, 5]); + * var t = board.create('text',[-2,-2, function(){ return 'Sum=' + JXG.toFixed(r.Value(), 4); }]); + * </pre><div class="jxgbox" id="JXGf9a7ba38-b50f-4a32-a873-2f3bf9caee79" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function(){ + * var board = JXG.JSXGraph.initBoard('JXGf9a7ba38-b50f-4a32-a873-2f3bf9caee79', {boundingbox: [-3, 7, 5, -3], axis: true, showcopyright: false, shownavigation: false}); + * var s = board.create('slider',[[0,4],[3,4],[0,4,10]],{snapWidth:1}); + * var g = function(x) { return 0.5*x*x-2*x; }; + * var f = function(x) { return -x*(x-4); }; + * var r = board.create('riemannsum', + * [[g,f], function(){return s.Value();}, 'lower', 0, 4], + * {fillOpacity:0.4} + * ); + * var f = board.create('functiongraph',[f, -2, 5]); + * var g = board.create('functiongraph',[g, -2, 5]); + * var t = board.create('text',[-2,-2, function(){ return 'Sum=' + JXG.toFixed(r.Value(), 4); }]); + * })(); + * </script><pre> + */ + JXG.createRiemannsum = function (board, parents, attributes) { + var n, type, f, par, c, attr; + + attr = Type.copyAttributes(attributes, board.options, 'riemannsum'); + attr.curvetype = 'plot'; + + f = parents[0]; + n = Type.createFunction(parents[1], board, ''); + + if (!Type.exists(n)) { + throw new Error("JSXGraph: JXG.createRiemannsum: argument '2' n has to be number or function." + + "\nPossible parent types: [function,n:number|function,type,start:number|function,end:number|function]"); + } + + type = Type.createFunction(parents[2], board, '', false); + if (!Type.exists(type)) { + throw new Error("JSXGraph: JXG.createRiemannsum: argument 3 'type' has to be string or function." + + "\nPossible parent types: [function,n:number|function,type,start:number|function,end:number|function]"); + } + + par = [[0], [0]].concat(parents.slice(3)); + + c = board.create('curve', par, attr); + + c.sum = 0.0; + /** + * Returns the value of the Riemann sum, i.e. the sum of the (signed) areas of the rectangles. + * @name Value + * @memberOf Riemann.prototype + * @function + * @returns {Number} value of Riemann sum. + */ + c.Value = function () { + return this.sum; + }; + + /** + * @ignore + */ + c.updateDataArray = function () { + var u = Numerics.riemann(f, n(), type(), this.minX(), this.maxX()); + this.dataX = u[0]; + this.dataY = u[1]; + + // Update "Riemann sum" + this.sum = u[2]; + }; + + return c; + }; + + JXG.registerElement('riemannsum', JXG.createRiemannsum); + + /** + * @class This element is used to provide a constructor for trace curve (simple locus curve), which is realized as a special curve. + * @pseudo + * @description + * @name Tracecurve + * @augments JXG.Curve + * @constructor + * @type JXG.Curve + * @param {Point,Point} Parent elements of Tracecurve are a + * glider point and a point whose locus is traced. + * @see JXG.Curve + * @example + * // Create trace curve. + * var c1 = board.create('circle',[[0, 0], [2, 0]]), + * p1 = board.create('point',[-3, 1]), + * g1 = board.create('glider',[2, 1, c1]), + * s1 = board.create('segment',[g1, p1]), + * p2 = board.create('midpoint',[s1]), + * curve = board.create('tracecurve', [g1, p2]); + * + * </pre><div class="jxgbox" id="JXG5749fb7d-04fc-44d2-973e-45c1951e29ad" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * var tc1_board = JXG.JSXGraph.initBoard('JXG5749fb7d-04fc-44d2-973e-45c1951e29ad', {boundingbox: [-4, 4, 4, -4], axis: false, showcopyright: false, shownavigation: false}); + * var c1 = tc1_board.create('circle',[[0, 0], [2, 0]]), + * p1 = tc1_board.create('point',[-3, 1]), + * g1 = tc1_board.create('glider',[2, 1, c1]), + * s1 = tc1_board.create('segment',[g1, p1]), + * p2 = tc1_board.create('midpoint',[s1]), + * curve = tc1_board.create('tracecurve', [g1, p2]); + * </script><pre> + */ + JXG.createTracecurve = function (board, parents, attributes) { + var c, glider, tracepoint, attr; + + if (parents.length !== 2) { + throw new Error("JSXGraph: Can't create trace curve with given parent'" + + "\nPossible parent types: [glider, point]"); + } + + glider = board.select(parents[0]); + tracepoint = board.select(parents[1]); + + if (glider.type !== Const.OBJECT_TYPE_GLIDER || !Type.isPoint(tracepoint)) { + throw new Error("JSXGraph: Can't create trace curve with parent types '" + + (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + + "\nPossible parent types: [glider, point]"); + } + + attr = Type.copyAttributes(attributes, board.options, 'tracecurve'); + attr.curvetype = 'plot'; + c = board.create('curve', [[0], [0]], attr); + + /** + * @ignore + */ + c.updateDataArray = function () { + var i, step, t, el, pEl, x, y, from, savetrace, + le = attr.numberpoints, + savePos = glider.position, + slideObj = glider.slideObject, + mi = slideObj.minX(), + ma = slideObj.maxX(); + + // set step width + step = (ma - mi) / le; + this.dataX = []; + this.dataY = []; + + /* + * For gliders on circles and lines a closed curve is computed. + * For gliders on curves the curve is not closed. + */ + if (slideObj.elementClass !== Const.OBJECT_CLASS_CURVE) { + le++; + } + + // Loop over all steps + for (i = 0; i < le; i++) { + t = mi + i * step; + x = slideObj.X(t) / slideObj.Z(t); + y = slideObj.Y(t) / slideObj.Z(t); + + // Position the glider + glider.setPositionDirectly(Const.COORDS_BY_USER, [x, y]); + from = false; + + // Update all elements from the glider up to the trace element + for (el in this.board.objects) { + if (this.board.objects.hasOwnProperty(el)) { + pEl = this.board.objects[el]; + + if (pEl === glider) { + from = true; + } + + if (from && pEl.needsRegularUpdate) { + // Save the trace mode of the element + savetrace = pEl.visProp.trace; + pEl.visProp.trace = false; + pEl.needsUpdate = true; + pEl.update(true); + + // Restore the trace mode + pEl.visProp.trace = savetrace; + if (pEl === tracepoint) { + break; + } + } + } + } + + // Store the position of the trace point + this.dataX[i] = tracepoint.X(); + this.dataY[i] = tracepoint.Y(); + } + + // Restore the original position of the glider + glider.position = savePos; + from = false; + + // Update all elements from the glider to the trace point + for (el in this.board.objects) { + if (this.board.objects.hasOwnProperty(el)) { + pEl = this.board.objects[el]; + if (pEl === glider) { + from = true; + } + + if (from && pEl.needsRegularUpdate) { + savetrace = pEl.visProp.trace; + pEl.visProp.trace = false; + pEl.needsUpdate = true; + pEl.update(true); + pEl.visProp.trace = savetrace; + + if (pEl === tracepoint) { + break; + } + } + } + } + }; + + return c; + }; + + JXG.registerElement('tracecurve', JXG.createTracecurve); + + /** + * @class This element is used to provide a constructor for step function, which is realized as a special curve. + * + * In case the data points should be updated after creation time, they can be accessed by curve.xterm and curve.yterm. + * @pseudo + * @description + * @name Stepfunction + * @augments JXG.Curve + * @constructor + * @type JXG.Curve + * @param {Array,Array|Function} Parent elements of Stepfunction are two arrays containing the coordinates. + * @see JXG.Curve + * @example + * // Create step function. + var curve = board.create('stepfunction', [[0,1,2,3,4,5], [1,3,0,2,2,1]]); + + * </pre><div class="jxgbox" id="JXG32342ec9-ad17-4339-8a97-ff23dc34f51a" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * var sf1_board = JXG.JSXGraph.initBoard('JXG32342ec9-ad17-4339-8a97-ff23dc34f51a', {boundingbox: [-1, 5, 6, -2], axis: true, showcopyright: false, shownavigation: false}); + * var curve = sf1_board.create('stepfunction', [[0,1,2,3,4,5], [1,3,0,2,2,1]]); + * </script><pre> + */ + JXG.createStepfunction = function (board, parents, attributes) { + var c, attr; + if (parents.length !== 2) { + throw new Error("JSXGraph: Can't create step function with given parent'" + + "\nPossible parent types: [array, array|function]"); + } + + attr = Type.copyAttributes(attributes, board.options, 'stepfunction'); + c = board.create('curve', parents, attr); + /** + * @ignore + */ + c.updateDataArray = function () { + var i, j = 0, + len = this.xterm.length; + + this.dataX = []; + this.dataY = []; + + if (len === 0) { + return; + } + + this.dataX[j] = this.xterm[0]; + this.dataY[j] = this.yterm[0]; + ++j; + + for (i = 1; i < len; ++i) { + this.dataX[j] = this.xterm[i]; + this.dataY[j] = this.dataY[j - 1]; + ++j; + this.dataX[j] = this.xterm[i]; + this.dataY[j] = this.yterm[i]; + ++j; + } + }; + + return c; + }; + + JXG.registerElement('stepfunction', JXG.createStepfunction); + + /** + * @class This element is used to provide a constructor for the graph showing + * the (numerical) derivative of a given curve. + * + * @pseudo + * @description + * @name Derivative + * @augments JXG.Curve + * @constructor + * @type JXG.Curve + * @param {JXG.Curve} Parent Curve for which the derivative is generated. + * @see JXG.Curve + * @example + * var cu = board.create('cardinalspline', [[[-3,0], [-1,2], [0,1], [2,0], [3,1]], 0.5, 'centripetal'], {createPoints: false}); + * var d = board.create('derivative', [cu], {dash: 2}); + * + * </pre><div id="JXGb9600738-1656-11e8-8184-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXGb9600738-1656-11e8-8184-901b0e1b8723', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * var cu = board.create('cardinalspline', [[[-3,0], [-1,2], [0,1], [2,0], [3,1]], 0.5, 'centripetal'], {createPoints: false}); + * var d = board.create('derivative', [cu], {dash: 2}); + * + * })(); + * + * </script><pre> + * + */ + JXG.createDerivative = function (board, parents, attributes) { + var c, + curve, dx, dy, + attr; + + if (parents.length !== 1 && parents[0].class !== Const.OBJECT_CLASS_CURVE) { + throw new Error("JSXGraph: Can't create derivative curve with given parent'" + + "\nPossible parent types: [curve]"); + } + + attr = Type.copyAttributes(attributes, board.options, 'curve'); + + curve = parents[0]; + dx = Numerics.D(curve.X); + dy = Numerics.D(curve.Y); + + c = board.create('curve', [ + function (t) { return curve.X(t); }, + function (t) { return dy(t) / dx(t); }, + curve.minX(), curve.maxX() + ], attr); + + c.setParents(curve); + + return c; + }; + + JXG.registerElement('derivative', JXG.createDerivative); + + /** + * @class Intersection of two closed path elements. The elements may be of type curve, circle, polygon, inequality. + * If one element is a curve, it has to be closed. + * The resulting element is of type curve. + * @pseudo + * @description + * @name CurveIntersection + * @param {JXG.Curve|JXG.Polygon|JXG.Circle} curve1 First element which is intersected + * @param {JXG.Curve|JXG.Polygon|JXG.Circle} curve2 Second element which is intersected + * @augments JXG.Curve + * @constructor + * @type JXG.Curve + * + * @example + * var f = board.create('functiongraph', ['cos(x)']); + * var ineq = board.create('inequality', [f], {inverse: true, fillOpacity: 0.1}); + * var circ = board.create('circle', [[0,0], 4]); + * var clip = board.create('curveintersection', [ineq, circ], {fillColor: 'yellow', fillOpacity: 0.6}); + * + * </pre><div id="JXGe2948257-8835-4276-9164-8acccb48e8d4" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXGe2948257-8835-4276-9164-8acccb48e8d4', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * var f = board.create('functiongraph', ['cos(x)']); + * var ineq = board.create('inequality', [f], {inverse: true, fillOpacity: 0.1}); + * var circ = board.create('circle', [[0,0], 4]); + * var clip = board.create('curveintersection', [ineq, circ], {fillColor: 'yellow', fillOpacity: 0.6}); + * + * })(); + * + * </script><pre> + * + */ + JXG.createCurveIntersection = function (board, parents, attributes) { + var c; + + if (parents.length !== 2) { + throw new Error("JSXGraph: Can't create curve intersection with given parent'" + + "\nPossible parent types: [array, array|function]"); + } + + c = board.create('curve', [[], []], attributes); + /** + * @ignore + */ + c.updateDataArray = function () { + var a = JXG.Math.Clip.intersection(parents[0], parents[1], this.board); + this.dataX = a[0]; + this.dataY = a[1]; + }; + return c; + }; + + /** + * @class Union of two closed path elements. The elements may be of type curve, circle, polygon, inequality. + * If one element is a curve, it has to be closed. + * The resulting element is of type curve. + * @pseudo + * @description + * @name CurveUnion + * @param {JXG.Curve|JXG.Polygon|JXG.Circle} curve1 First element defining the union + * @param {JXG.Curve|JXG.Polygon|JXG.Circle} curve2 Second element defining the union + * @augments JXG.Curve + * @constructor + * @type JXG.Curve + * + * @example + * var f = board.create('functiongraph', ['cos(x)']); + * var ineq = board.create('inequality', [f], {inverse: true, fillOpacity: 0.1}); + * var circ = board.create('circle', [[0,0], 4]); + * var clip = board.create('curveunion', [ineq, circ], {fillColor: 'yellow', fillOpacity: 0.6}); + * + * </pre><div id="JXGe2948257-8835-4276-9164-8acccb48e8d4" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXGe2948257-8835-4276-9164-8acccb48e8d4', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * var f = board.create('functiongraph', ['cos(x)']); + * var ineq = board.create('inequality', [f], {inverse: true, fillOpacity: 0.1}); + * var circ = board.create('circle', [[0,0], 4]); + * var clip = board.create('curveunion', [ineq, circ], {fillColor: 'yellow', fillOpacity: 0.6}); + * + * })(); + * + * </script><pre> + * + */ + JXG.createCurveUnion = function (board, parents, attributes) { + var c; + + if (parents.length !== 2) { + throw new Error("JSXGraph: Can't create curve union with given parent'" + + "\nPossible parent types: [array, array|function]"); + } + + c = board.create('curve', [[], []], attributes); + /** + * @ignore + */ + c.updateDataArray = function () { + var a = JXG.Math.Clip.union(parents[0], parents[1], this.board); + this.dataX = a[0]; + this.dataY = a[1]; + }; + return c; + }; + + /** + * @class Difference of two closed path elements. The elements may be of type curve, circle, polygon, inequality. + * If one element is a curve, it has to be closed. + * The resulting element is of type curve. + * @pseudo + * @description + * @name CurveDifference + * @param {JXG.Curve|JXG.Polygon|JXG.Circle} curve1 First element from which the second element is "subtracted" + * @param {JXG.Curve|JXG.Polygon|JXG.Circle} curve2 Second element which is subtracted from the first element + * @augments JXG.Curve + * @constructor + * @type JXG.Curve + * + * @example + * var f = board.create('functiongraph', ['cos(x)']); + * var ineq = board.create('inequality', [f], {inverse: true, fillOpacity: 0.1}); + * var circ = board.create('circle', [[0,0], 4]); + * var clip = board.create('curvedifference', [ineq, circ], {fillColor: 'yellow', fillOpacity: 0.6}); + * + * </pre><div id="JXGe2948257-8835-4276-9164-8acccb48e8d4" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXGe2948257-8835-4276-9164-8acccb48e8d4', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * var f = board.create('functiongraph', ['cos(x)']); + * var ineq = board.create('inequality', [f], {inverse: true, fillOpacity: 0.1}); + * var circ = board.create('circle', [[0,0], 4]); + * var clip = board.create('curvedifference', [ineq, circ], {fillColor: 'yellow', fillOpacity: 0.6}); + * + * })(); + * + * </script><pre> + * + */ + JXG.createCurveDifference = function (board, parents, attributes) { + var c; + + if (parents.length !== 2) { + throw new Error("JSXGraph: Can't create curve difference with given parent'" + + "\nPossible parent types: [array, array|function]"); + } + + c = board.create('curve', [[], []], attributes); + /** + * @ignore + */ + c.updateDataArray = function () { + var a = JXG.Math.Clip.difference(parents[0], parents[1], this.board); + this.dataX = a[0]; + this.dataY = a[1]; + }; + return c; + }; + + JXG.registerElement('curvedifference', JXG.createCurveDifference); + JXG.registerElement('curveintersection', JXG.createCurveIntersection); + JXG.registerElement('curveunion', JXG.createCurveUnion); + + /** + * @class Box plot curve. The direction of the box plot can be either vertical or horizontal which + * is controlled by the attribute "dir". + * @pseudo + * @description + * @name Boxplot + * @param {Array} quantiles Array conatining at least five quantiles. The elements can be of type number, function or string. + * @param {Number|Function} axis Axis position of the box plot + * @param {Number|Function} width Width of the rectangle part of the box plot. The width of the first and 4th quantile + * is relative to this width and can be controlled by the attribute "smallWidth". + * @augments JXG.Curve + * @constructor + * @type JXG.Curve + * + * @example + * var Q = [ -1, 2, 3, 3.5, 5 ]; + * + * var b = board.create('boxplot', [Q, 2, 4], {strokeWidth: 3}); + * + * </pre><div id="JXG13eb23a1-a641-41a2-be11-8e03e400a947" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG13eb23a1-a641-41a2-be11-8e03e400a947', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * var Q = [ -1, 2, 3, 3.5, 5 ]; + * var b = board.create('boxplot', [Q, 2, 4], {strokeWidth: 3}); + * + * })(); + * + * </script><pre> + * + * @example + * var Q = [ -1, 2, 3, 3.5, 5 ]; + * var b = board.create('boxplot', [Q, 3, 4], {dir: 'horizontal', smallWidth: 0.25, color:'red'}); + * + * </pre><div id="JXG0deb9cb2-84bc-470d-a6db-8be9a5694813" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG0deb9cb2-84bc-470d-a6db-8be9a5694813', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * var Q = [ -1, 2, 3, 3.5, 5 ]; + * var b = board.create('boxplot', [Q, 3, 4], {dir: 'horizontal', smallWidth: 0.25, color:'red'}); + * + * })(); + * + * </script><pre> + * + * @example + * var data = [57, 57, 57, 58, 63, 66, 66, 67, 67, 68, 69, 70, 70, 70, 70, 72, 73, 75, 75, 76, 76, 78, 79, 81]; + * var Q = []; + * + * Q[0] = JXG.Math.Statistics.min(data); + * Q = Q.concat(JXG.Math.Statistics.percentile(data, [25, 50, 75])); + * Q[4] = JXG.Math.Statistics.max(data); + * + * var b = board.create('boxplot', [Q, 0, 3]); + * + * </pre><div id="JXGef079e76-ae99-41e4-af29-1d07d83bf85a" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXGef079e76-ae99-41e4-af29-1d07d83bf85a', + * {boundingbox: [-5,90,5,30], axis: true, showcopyright: false, shownavigation: false}); + * var data = [57, 57, 57, 58, 63, 66, 66, 67, 67, 68, 69, 70, 70, 70, 70, 72, 73, 75, 75, 76, 76, 78, 79, 81]; + * var Q = []; + * + * Q[0] = JXG.Math.Statistics.min(data); + * Q = Q.concat(JXG.Math.Statistics.percentile(data, [25, 50, 75])); + * Q[4] = JXG.Math.Statistics.max(data); + * + * var b = board.create('boxplot', [Q, 0, 3]); + * + * })(); + * + * </script><pre> + * + * @example + * var mi = board.create('glider', [0, -1, board.defaultAxes.y]); + * var ma = board.create('glider', [0, 5, board.defaultAxes.y]); + * var Q = [function() { return mi.Y(); }, 2, 3, 3.5, function() { return ma.Y(); }]; + * + * var b = board.create('boxplot', [Q, 0, 2]); + * + * </pre><div id="JXG3b3225da-52f0-42fe-8396-be9016bf289b" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG3b3225da-52f0-42fe-8396-be9016bf289b', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * var mi = board.create('glider', [0, -1, board.defaultAxes.y]); + * var ma = board.create('glider', [0, 5, board.defaultAxes.y]); + * var Q = [function() { return mi.Y(); }, 2, 3, 3.5, function() { return ma.Y(); }]; + * + * var b = board.create('boxplot', [Q, 0, 2]); + * + * })(); + * + * </script><pre> + * + */ + JXG.createBoxPlot = function (board, parents, attributes) { + var box, i, len, w2, + attr = Type.copyAttributes(attributes, board.options, 'boxplot'); + + if (parents.length !== 3) { + throw new Error("JSXGraph: Can't create box plot with given parent'" + + "\nPossible parent types: [array, number|function, number|function] containing quantiles, axis, width"); + } + if (parents[0].length < 5) { + throw new Error("JSXGraph: Can't create box plot with given parent[0]'" + + "\nparent[0] has to conatin at least 5 quantiles."); + } + box = board.create('curve', [[],[]], attr); + + len = parents[0].length; // Quantiles + box.Q = []; + for (i = 0; i < len; i++) { + box.Q[i] = Type.createFunction(parents[0][i], board, null, true); + } + box.x = Type.createFunction(parents[1], board, null, true); + box.w = Type.createFunction(parents[2], board, null, true); + + box.updateDataArray = function() { + var v1, v2, l1, l2, r1, r2, w2, dir, x; + + w2 = Type.evaluate(this.visProp.smallwidth); + dir = Type.evaluate(this.visProp.dir); + x = this.x(); + l1 = x - this.w() * 0.5; + l2 = x - this.w() * 0.5 * w2; + r1 = x + this.w() * 0.5; + r2 = x + this.w() * 0.5 * w2; + v1 = [x, l2, r2, x, x, l1, l1, r1, r1, x, NaN, l1, r1, NaN, x, x, l2, r2, x]; + v2 = [this.Q[0](), + this.Q[0](), + this.Q[0](), + this.Q[0](), + this.Q[1](), + this.Q[1](), + this.Q[3](), + this.Q[3](), + this.Q[1](), + this.Q[1](), + NaN, + this.Q[2](), + this.Q[2](), + NaN, + this.Q[3](), + this.Q[4](), + this.Q[4](), + this.Q[4](), + this.Q[4]()]; + if (dir === 'vertical') { + this.dataX = v1; + this.dataY = v2; + } else { + this.dataX = v2; + this.dataY = v1; } - }, + }; + return box; + }; + + JXG.registerElement('boxplot', JXG.createBoxPlot); + + return { + Curve: JXG.Curve, + createCardinalSpline: JXG.createCardinalSpline, + createCurve: JXG.createCurve, + createCurveDifference: JXG.createCurveDifference, + createCurveIntersection: JXG.createCurveIntersection, + createCurveUnion: JXG.createCurveUnion, + createDerivative: JXG.createDerivative, + createFunctiongraph: JXG.createFunctiongraph, + createMetapostSpline: JXG.createMetapostSpline, + createPlot: JXG.createFunctiongraph, + createSpline: JXG.createSpline, + createRiemannsum: JXG.createRiemannsum, + createStepfunction: JXG.createStepfunction, + createTracecurve: JXG.createTracecurve + }; +}); + +/* + Copyright 2008-2022 + Matthias Ehmann, + Michael Gerhaeuser, + Carsten Miller, + Bianca Valentin, + Alfred Wassermann, + Peter Wilfahrt + + This file is part of JSXGraph. + + JSXGraph is free software dual licensed under the GNU LGPL or MIT License. + + You can redistribute it and/or modify it under the terms of the + + * GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version + OR + * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT + + JSXGraph is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License and + the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> + and <http://opensource.org/licenses/MIT/>. + */ + + +/*global JXG: true, define: true*/ +/*jslint nomen: true, plusplus: true*/ + +/* depends: + jxg + math/geometry + math/math + base/coords + base/circle + utils/type + base/constants + elements: + curve + midpoint + circumcenter + */ + +/** + * @fileoverview In this file the geometry object Arc is defined. Arc stores all + * style and functional properties that are required to draw an arc on a board. + */ + +define('element/arc',[ + 'jxg', 'math/geometry', 'math/math', 'base/coords', 'base/circle', 'utils/type', 'base/constants' +], function (JXG, Geometry, Mat, Coords, Circle, Type, Const) { + + "use strict"; + + /** + * @class An arc is a segment of the circumference of a circle. It is defined by a center, one point that + * defines the radius, and a third point that defines the angle of the arc. + * + * @pseudo + * @name Arc + * @augments Curve + * @constructor + * @type JXG.Curve + * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The result will be an arc of a circle around p1 through p2. The arc is drawn + * counter-clockwise from p2 to p3. + * @example + * // Create an arc out of three free points + * var p1 = board.create('point', [2.0, 2.0]); + * var p2 = board.create('point', [1.0, 0.5]); + * var p3 = board.create('point', [3.5, 1.0]); + * + * var a = board.create('arc', [p1, p2, p3]); + * board.create('text',[1,6,function(){return 'arclength: '+Math.round(a.Value()*100)/100}]) + * </pre><div class="jxgbox" id="JXG114ef584-4a5e-4686-8392-c97501befb5b" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function () { + * var board = JXG.JSXGraph.initBoard('JXG114ef584-4a5e-4686-8392-c97501befb5b', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}), + * p1 = board.create('point', [2.0, 2.0]), + * p2 = board.create('point', [1.0, 0.5]), + * p3 = board.create('point', [3.5, 1.0]), + * + * a = board.create('arc', [p1, p2, p3]); + * board.create('text',[1,6,function(){return 'arclength: '+Math.round(a.Value()*100)/100}]) + * })(); + * </script><pre> + * + * @example + * var t = board.create('transform', [2, 1.5], {type: 'scale'}); + * var a1 = board.create('arc', [[1, 1], [0, 1], [1, 0]], {strokeColor: 'red'}); + * var a2 = board.create('curve', [a1, t], {strokeColor: 'red'}); + * + * </pre><div id="JXG1949da46-6339-11e8-9fb9-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG1949da46-6339-11e8-9fb9-901b0e1b8723', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * var t = board.create('transform', [2, 1.5], {type: 'scale'}); + * var a1 = board.create('arc', [[1, 1], [0, 1], [1, 0]], {strokeColor: 'red'}); + * var a2 = board.create('curve', [a1, t], {strokeColor: 'red'}); + * + * })(); + * + * </script><pre> + * + */ + JXG.createArc = function (board, parents, attributes) { + var el, attr, points; + + points = Type.providePoints(board, parents, attributes, 'arc', ['center', 'radiusPoint', 'anglePoint']); + if (points === false || points.length < 3) { + throw new Error("JSXGraph: Can't create Arc with parent types '" + + (typeof parents[0]) + "' and '" + (typeof parents[1]) + "' and '" + + (typeof parents[2]) + "'." + + "\nPossible parent types: [point,point,point], [arc, transformation]"); + } + + attr = Type.copyAttributes(attributes, board.options, 'arc'); + el = board.create('curve', [[0], [0]], attr); + + el.elType = 'arc'; + el.setParents(points); + + /** + * documented in JXG.GeometryElement + * @ignore + */ + el.type = Const.OBJECT_TYPE_ARC; + + /** + * Center of the arc. + * @memberOf Arc.prototype + * @name center + * @type JXG.Point + */ + el.center = points[0]; + + /** + * Point defining the arc's radius. + * @memberOf Arc.prototype + * @name radiuspoint + * @type JXG.Point + */ + el.radiuspoint = points[1]; + el.point2 = el.radiuspoint; + + /** + * The point defining the arc's angle. + * @memberOf Arc.prototype + * @name anglepoint + * @type JXG.Point + */ + el.anglepoint = points[2]; + el.point3 = el.anglepoint; + + // Add arc as child to defining points + // or vice versa if the points are provided as coordinates + if (Type.exists(el.center._is_new)) { + el.addChild(el.center); + delete el.center._is_new; + } else { + el.center.addChild(el); + } + if (Type.exists(el.radiuspoint._is_new)) { + el.addChild(el.radiuspoint); + delete el.radiuspoint._is_new; + } else { + el.radiuspoint.addChild(el); + } + if (Type.exists(el.anglepoint._is_new)) { + el.addChild(el.anglepoint); + delete el.anglepoint._is_new; + } else { + el.anglepoint.addChild(el); + } + + // should be documented in options + el.useDirection = attr.usedirection; + + // documented in JXG.Curve + el.updateDataArray = function () { + var ar, phi, det, p0c, p1c, p2c, + sgn = 1, + A = this.radiuspoint, + B = this.center, + C = this.anglepoint, + ev_s = Type.evaluate(this.visProp.selection); + + phi = Geometry.rad(A, B, C); + if ((ev_s === 'minor' && phi > Math.PI) || + (ev_s === 'major' && phi < Math.PI)) { + sgn = -1; + } + + // This is true for circumCircleArcs. In that case there is + // a fourth parent element: [center, point1, point3, point2] + if (this.useDirection) { + p0c = points[1].coords.usrCoords; + p1c = points[3].coords.usrCoords; + p2c = points[2].coords.usrCoords; + det = (p0c[1] - p2c[1]) * (p0c[2] - p1c[2]) - (p0c[2] - p2c[2]) * (p0c[1] - p1c[1]); + + if (det < 0) { + this.radiuspoint = points[1]; + this.anglepoint = points[2]; + } else { + this.radiuspoint = points[2]; + this.anglepoint = points[1]; + } + } + + A = A.coords.usrCoords; + B = B.coords.usrCoords; + C = C.coords.usrCoords; + + ar = Geometry.bezierArc(A, B, C, false, sgn); + + this.dataX = ar[0]; + this.dataY = ar[1]; + + this.bezierDegree = 3; + + this.updateStdform(); + this.updateQuadraticform(); + }; + + /** + * Determines the arc's current radius. I.e. the distance between {@link Arc#center} and {@link Arc#radiuspoint}. + * @memberOf Arc.prototype + * @name Radius + * @function + * @returns {Number} The arc's radius + */ + el.Radius = function () { + return this.radiuspoint.Dist(this.center); + }; + + /** + * @deprecated Use {@link Arc#Radius} + * @memberOf Arc.prototype + * @name getRadius + * @function + * @returns {Number} + */ + el.getRadius = function () { + JXG.deprecated('Arc.getRadius()', 'Arc.Radius()'); + return this.Radius(); + }; + + /** + * Returns the length of the arc. + * @memberOf Arc.prototype + * @name Value + * @function + * @returns {Number} The arc length + */ + el.Value = function () { + return this.Radius() * Geometry.rad(this.radiuspoint, this.center, this.anglepoint); + }; + + // documented in geometry element + el.hasPoint = function (x, y) { + var dist, checkPoint, + has, + invMat, c, + prec, type, + r = this.Radius(); + + if (Type.evaluate(this.visProp.hasinnerpoints)) { + return this.hasPointSector(x, y); + } + + if (Type.isObject(Type.evaluate(this.visProp.precision))) { + type = this.board._inputDevice; + prec = Type.evaluate(this.visProp.precision[type]); + } else { + // 'inherit' + prec = this.board.options.precision.hasPoint; + } + prec /= Math.min(this.board.unitX, this.board.unitY); + checkPoint = new Coords(Const.COORDS_BY_SCREEN, [x, y], this.board); + + if (this.transformations.length > 0) { + // Transform the mouse/touch coordinates + // back to the original position of the curve. + this.updateTransformMatrix(); + invMat = Mat.inverse(this.transformMat); + c = Mat.matVecMult(invMat, checkPoint.usrCoords); + checkPoint = new Coords(Const.COORDS_BY_USER, c, this.board); + } + + dist = this.center.coords.distance(Const.COORDS_BY_USER, checkPoint); + has = (Math.abs(dist - r) < prec); + + /** + * At that point we know that the user has touched the circle line. + * Now, we have to check, if the user has hit the arc path. + */ + if (has) { + has = Geometry.coordsOnArc(this, checkPoint); + } + return has; + }; + + /** + * Checks whether (x,y) is within the sector defined by the arc. + * @memberOf Arc.prototype + * @name hasPointSector + * @function + * @param {Number} x Coordinate in x direction, screen coordinates. + * @param {Number} y Coordinate in y direction, screen coordinates. + * @returns {Boolean} True if (x,y) is within the sector defined by the arc, False otherwise. + */ + el.hasPointSector = function (x, y) { + var checkPoint = new Coords(Const.COORDS_BY_SCREEN, [x, y], this.board), + r = this.Radius(), + dist = this.center.coords.distance(Const.COORDS_BY_USER, checkPoint), + has = (dist < r); + + if (has) { + has = Geometry.coordsOnArc(this, checkPoint); + } + return has; + }; + + // documented in geometry element + el.getTextAnchor = function () { + return this.center.coords; + }; + + // documented in geometry element + el.getLabelAnchor = function () { + var coords, vec, vecx, vecy, len, + angle = Geometry.rad(this.radiuspoint, this.center, this.anglepoint), + dx = 10 / this.board.unitX, + dy = 10 / this.board.unitY, + p2c = this.point2.coords.usrCoords, + pmc = this.center.coords.usrCoords, + bxminusax = p2c[1] - pmc[1], + byminusay = p2c[2] - pmc[2], + ev_s = Type.evaluate(this.visProp.selection), + l_vp = this.label ? this.label.visProp : this.visProp.label; + + // If this is uncommented, the angle label can not be dragged + //if (Type.exists(this.label)) { + // this.label.relativeCoords = new Coords(Const.COORDS_BY_SCREEN, [0, 0], this.board); + //} + + if ((ev_s === 'minor' && angle > Math.PI) || + (ev_s === 'major' && angle < Math.PI)) { + angle = -(2 * Math.PI - angle); + } + + coords = new Coords(Const.COORDS_BY_USER, [ + pmc[1] + Math.cos(angle * 0.5) * bxminusax - Math.sin(angle * 0.5) * byminusay, + pmc[2] + Math.sin(angle * 0.5) * bxminusax + Math.cos(angle * 0.5) * byminusay + ], this.board); + + vecx = coords.usrCoords[1] - pmc[1]; + vecy = coords.usrCoords[2] - pmc[2]; + + len = Math.sqrt(vecx * vecx + vecy * vecy); + vecx = vecx * (len + dx) / len; + vecy = vecy * (len + dy) / len; + vec = [pmc[1] + vecx, pmc[2] + vecy]; + + l_vp.position = Geometry.calcLabelQuadrant(Geometry.rad([1,0],[0,0],vec)); + + return new Coords(Const.COORDS_BY_USER, vec, this.board); + }; + + // documentation in jxg.circle + el.updateQuadraticform = Circle.Circle.prototype.updateQuadraticform; + + // documentation in jxg.circle + el.updateStdform = Circle.Circle.prototype.updateStdform; + + el.methodMap = JXG.deepCopy(el.methodMap, { + getRadius: 'getRadius', + radius: 'Radius', + center: 'center', + radiuspoint: 'radiuspoint', + anglepoint: 'anglepoint', + Value: 'Value' + }); + + el.prepareUpdate().update(); + return el; + }; + + JXG.registerElement('arc', JXG.createArc); + + /** + * @class A semicircle is a special arc defined by two points. The arc hits both points. + * @pseudo + * @name Semicircle + * @augments Arc + * @constructor + * @type Arc + * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {JXG.Point_JXG.Point} p1,p2 The result will be a composition of an arc drawn clockwise from <tt>p1</tt> and + * <tt>p2</tt> and the midpoint of <tt>p1</tt> and <tt>p2</tt>. + * @example + * // Create an arc out of three free points + * var p1 = board.create('point', [4.5, 2.0]); + * var p2 = board.create('point', [1.0, 0.5]); + * + * var a = board.create('semicircle', [p1, p2]); + * </pre><div class="jxgbox" id="JXG5385d349-75d7-4078-b732-9ae808db1b0e" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function () { + * var board = JXG.JSXGraph.initBoard('JXG5385d349-75d7-4078-b732-9ae808db1b0e', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}), + * p1 = board.create('point', [4.5, 2.0]), + * p2 = board.create('point', [1.0, 0.5]), + * + * sc = board.create('semicircle', [p1, p2]); + * })(); + * </script><pre> + */ + JXG.createSemicircle = function (board, parents, attributes) { + var el, mp, attr, points; + + // we need 2 points + points = Type.providePoints(board, parents, attributes, 'point'); + if (points === false || points.length !== 2) { + throw new Error("JSXGraph: Can't create Semicircle with parent types '" + + (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + + "\nPossible parent types: [point,point]"); + } + + attr = Type.copyAttributes(attributes, board.options, 'semicircle', 'center'); + mp = board.create('midpoint', points, attr); + mp.dump = false; + + attr = Type.copyAttributes(attributes, board.options, 'semicircle'); + el = board.create('arc', [mp, points[1], points[0]], attr); + el.elType = 'semicircle'; + el.setParents([points[0].id, points[1].id]); + el.subs = { + midpoint: mp + }; + el.inherits.push(mp); /** - * Set the gradient angle for linear color gradients. - * - * @private - * @param {SVGnode} node SVG gradient node of an arbitrary JSXGraph element. - * @param {Number} radians angle value in radians. 0 is horizontal from left to right, Pi/4 is vertical from top to bottom. + * The midpoint of the two defining points. + * @memberOf Semicircle.prototype + * @name midpoint + * @type Midpoint */ - updateGradientAngle: function(node, radians) { - // Angles: - // 0: -> - // 90: down - // 180: <- - // 90: up - var f = 1.0, - co = Math.cos(radians), - si = Math.sin(radians); + el.midpoint = el.center = mp; - if (Math.abs(co) > Math.abs(si)) { - f /= Math.abs(co); - } else { - f /= Math.abs(si); - } + return el; + }; - if (co >= 0) { - node.setAttributeNS(null, 'x1', 0); - node.setAttributeNS(null, 'x2', co * f); - } else { - node.setAttributeNS(null, 'x1', -co * f); - node.setAttributeNS(null, 'x2', 0); - } - if (si >= 0) { - node.setAttributeNS(null, 'y1', 0); - node.setAttributeNS(null, 'y2', si * f); - } else { - node.setAttributeNS(null, 'y1', -si * f); - node.setAttributeNS(null, 'y2', 0); - } - }, + JXG.registerElement('semicircle', JXG.createSemicircle); + + /** + * @class A circumcircle arc is an {@link Arc} defined by three points. All three points lie on the arc. + * @pseudo + * @name CircumcircleArc + * @augments Arc + * @constructor + * @type Arc + * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The result will be a composition of an arc of the circumcircle of + * <tt>p1</tt>, <tt>p2</tt>, and <tt>p3</tt> and the midpoint of the circumcircle of the three points. The arc is drawn + * counter-clockwise from <tt>p1</tt> over <tt>p2</tt> to <tt>p3</tt>. + * @example + * // Create a circum circle arc out of three free points + * var p1 = board.create('point', [2.0, 2.0]); + * var p2 = board.create('point', [1.0, 0.5]); + * var p3 = board.create('point', [3.5, 1.0]); + * + * var a = board.create('circumcirclearc', [p1, p2, p3]); + * </pre><div class="jxgbox" id="JXG87125fd4-823a-41c1-88ef-d1a1369504e3" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function () { + * var board = JXG.JSXGraph.initBoard('JXG87125fd4-823a-41c1-88ef-d1a1369504e3', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}), + * p1 = board.create('point', [2.0, 2.0]), + * p2 = board.create('point', [1.0, 0.5]), + * p3 = board.create('point', [3.5, 1.0]), + * + * cca = board.create('circumcirclearc', [p1, p2, p3]); + * })(); + * </script><pre> + */ + JXG.createCircumcircleArc = function (board, parents, attributes) { + var el, mp, attr, points; + + // We need three points + points = Type.providePoints(board, parents, attributes, 'point'); + if (points === false || points.length !== 3) { + throw new Error("JSXGraph: create Circumcircle Arc with parent types '" + + (typeof parents[0]) + "' and '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." + + "\nPossible parent types: [point,point,point]"); + } + + attr = Type.copyAttributes(attributes, board.options, 'circumcirclearc', 'center'); + mp = board.create('circumcenter', points, attr); + mp.dump = false; + + attr = Type.copyAttributes(attributes, board.options, 'circumcirclearc'); + attr.usedirection = true; + el = board.create('arc', [mp, points[0], points[2], points[1]], attr); + + el.elType = 'circumcirclearc'; + el.setParents([points[0].id, points[1].id, points[2].id]); + el.subs = { + center: mp + }; + el.inherits.push(mp); /** - * Set circles for radial color gradients. - * - * @private - * @param {SVGnode} node SVG gradient node - * @param {Number} cx SVG value cx (value between 0 and 1) - * @param {Number} cy SVG value cy (value between 0 and 1) - * @param {Number} r SVG value r (value between 0 and 1) - * @param {Number} fx SVG value fx (value between 0 and 1) - * @param {Number} fy SVG value fy (value between 0 and 1) - * @param {Number} fr SVG value fr (value between 0 and 1) + * The midpoint of the circumcircle of the three points defining the circumcircle arc. + * @memberOf CircumcircleArc.prototype + * @name center + * @type Circumcenter */ - updateGradientCircle: function(node, cx, cy, r, fx, fy, fr) { - node.setAttributeNS(null, 'cx', cx * 100 + '%'); // Center first color - node.setAttributeNS(null, 'cy', cy * 100 + '%'); - node.setAttributeNS(null, 'r', r * 100 + '%'); - node.setAttributeNS(null, 'fx', fx * 100 + '%'); // Center second color / focal point - node.setAttributeNS(null, 'fy', fy * 100 + '%'); - node.setAttributeNS(null, 'fr', fr * 100 + '%'); - }, + el.center = mp; - // documented in JXG.AbstractRenderer - updateGradient: function (el) { - var col, op, - node2 = el.gradNode1, - node3 = el.gradNode2, - ev_g = Type.evaluate(el.visProp.gradient); + return el; + }; - if (!Type.exists(node2) || !Type.exists(node3)) { - return; - } + JXG.registerElement('circumcirclearc', JXG.createCircumcircleArc); - op = Type.evaluate(el.visProp.fillopacity); - op = (op > 0) ? op : 0; - col = Type.evaluate(el.visProp.fillcolor); + /** + * @class A minor arc is a segment of the circumference of a circle having measure less than or equal to + * 180 degrees (pi radians). It is defined by a center, one point that + * defines the radius, and a third point that defines the angle of the arc. + * @pseudo + * @name MinorArc + * @augments Curve + * @constructor + * @type JXG.Curve + * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 . Minor arc is an arc of a circle around p1 having measure less than or equal to + * 180 degrees (pi radians) and starts at p2. The radius is determined by p2, the angle by p3. + * @example + * // Create an arc out of three free points + * var p1 = board.create('point', [2.0, 2.0]); + * var p2 = board.create('point', [1.0, 0.5]); + * var p3 = board.create('point', [3.5, 1.0]); + * + * var a = board.create('arc', [p1, p2, p3]); + * </pre><div class="jxgbox" id="JXG64ba7ca2-8728-45f3-96e5-3c7a4414de2f" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function () { + * var board = JXG.JSXGraph.initBoard('JXG64ba7ca2-8728-45f3-96e5-3c7a4414de2f', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}), + * p1 = board.create('point', [2.0, 2.0]), + * p2 = board.create('point', [1.0, 0.5]), + * p3 = board.create('point', [3.5, 1.0]), + * + * a = board.create('minorarc', [p1, p2, p3]); + * })(); + * </script><pre> + */ - node2.setAttributeNS(null, 'style', 'stop-color:' + col + ';stop-opacity:' + op); - node3.setAttributeNS(null, 'style', - 'stop-color:' + Type.evaluate(el.visProp.gradientsecondcolor) + - ';stop-opacity:' + Type.evaluate(el.visProp.gradientsecondopacity) - ); - node2.setAttributeNS(null, 'offset', Type.evaluate(el.visProp.gradientstartoffset) * 100 + '%'); - node3.setAttributeNS(null, 'offset', Type.evaluate(el.visProp.gradientendoffset) * 100 + '%'); - if (ev_g === 'linear') { - this.updateGradientAngle(el.gradNode, Type.evaluate(el.visProp.gradientangle)); - } else if (ev_g === 'radial') { - this.updateGradientCircle(el.gradNode, - Type.evaluate(el.visProp.gradientcx), - Type.evaluate(el.visProp.gradientcy), - Type.evaluate(el.visProp.gradientr), - Type.evaluate(el.visProp.gradientfx), - Type.evaluate(el.visProp.gradientfy), - Type.evaluate(el.visProp.gradientfr) - ); - } - }, + JXG.createMinorArc = function (board, parents, attributes) { + attributes.selection = 'minor'; + return JXG.createArc(board, parents, attributes); + }; - // documented in JXG.AbstractRenderer - setObjectTransition: function (el, duration) { - var node, transitionStr, - i, len, - nodes = ['rendNode', - 'rendNodeTriangleStart', - 'rendNodeTriangleEnd']; + JXG.registerElement('minorarc', JXG.createMinorArc); - if (duration === undefined) { - duration = Type.evaluate(el.visProp.transitionduration); - } + /** + * @class A major arc is a segment of the circumference of a circle having measure greater than or equal to + * 180 degrees (pi radians). It is defined by a center, one point that + * defines the radius, and a third point that defines the angle of the arc. + * @pseudo + * @name MajorArc + * @augments Curve + * @constructor + * @type JXG.Curve + * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 . Major arc is an arc of a circle around p1 having measure greater than or equal to + * 180 degrees (pi radians) and starts at p2. The radius is determined by p2, the angle by p3. + * @example + * // Create an arc out of three free points + * var p1 = board.create('point', [2.0, 2.0]); + * var p2 = board.create('point', [1.0, 0.5]); + * var p3 = board.create('point', [3.5, 1.0]); + * + * var a = board.create('minorarc', [p1, p2, p3]); + * </pre><div class="jxgbox" id="JXG17a10d38-5629-40a4-b150-f41806edee9f" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function () { + * var board = JXG.JSXGraph.initBoard('JXG17a10d38-5629-40a4-b150-f41806edee9f', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}), + * p1 = board.create('point', [2.0, 2.0]), + * p2 = board.create('point', [1.0, 0.5]), + * p3 = board.create('point', [3.5, 1.0]), + * + * a = board.create('majorarc', [p1, p2, p3]); + * })(); + * </script><pre> + */ + JXG.createMajorArc = function (board, parents, attributes) { + attributes.selection = 'major'; + return JXG.createArc(board, parents, attributes); + }; - if (duration === el.visPropOld.transitionduration) { - return; - } + JXG.registerElement('majorarc', JXG.createMajorArc); - if (el.elementClass === Const.OBJECT_CLASS_TEXT && - Type.evaluate(el.visProp.display) === 'html') { - transitionStr = ' color ' + duration + 'ms,' + - ' opacity ' + duration + 'ms'; - } else { - transitionStr = ' fill ' + duration + 'ms,' + - ' fill-opacity ' + duration + 'ms,' + - ' stroke ' + duration + 'ms,' + - ' stroke-opacity ' + duration + 'ms'; - } + return { + createArc: JXG.createArc, + createSemicircle: JXG.createSemicircle, + createCircumcircleArc: JXG.createCircumcircleArc, + createMinorArc: JXG.createMinorArc, + createMajorArc: JXG.createMajorArc + }; +}); - len = nodes.length; - for (i = 0; i < len; ++i) { - if (el[nodes[i]]) { - node = el[nodes[i]]; - node.style.transition = transitionStr; - } - } +/* + Copyright 2008-2022 + Matthias Ehmann, + Michael Gerhaeuser, + Carsten Miller, + Bianca Valentin, + Alfred Wassermann, + Peter Wilfahrt - el.visPropOld.transitionduration = duration; - }, + This file is part of JSXGraph. - /** - * Call user-defined function to set visual attributes. - * If "testAttribute" is the empty string, the function - * is called immediately, otherwise it is called in a timeOut. - * - * This is necessary to realize smooth transitions but avoid transitions - * when first creating the objects. - * - * Usually, the string in testAttribute is the visPropOld attribute - * of the values which are set. - * - * @param {Function} setFunc Some function which usually sets some attributes - * @param {String} testAttribute If this string is the empty string the function is called immediately, - * otherwise it is called in a setImeout. - * @see JXG.SVGRenderer#setObjectFillColor - * @see JXG.SVGRenderer#setObjectStrokeColor - * @see JXG.SVGRenderer#_setArrowColor - * @private - */ - _setAttribute: function (setFunc, testAttribute) { - if (testAttribute === '') { - setFunc(); - } else { - window.setTimeout(setFunc, 1); - } - }, + JSXGraph is free software dual licensed under the GNU LGPL or MIT License. - // documented in JXG.AbstractRenderer - setObjectFillColor: function (el, color, opacity, rendNode) { - var node, c, rgbo, oo, - rgba = Type.evaluate(color), - o = Type.evaluate(opacity), - grad = Type.evaluate(el.visProp.gradient); + You can redistribute it and/or modify it under the terms of the - o = (o > 0) ? o : 0; + * GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version + OR + * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT - // TODO save gradient and gradientangle - if (el.visPropOld.fillcolor === rgba && el.visPropOld.fillopacity === o && grad === null) { - return; - } + JSXGraph is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. - if (Type.exists(rgba) && rgba !== false) { - if (rgba.length !== 9) { // RGB, not RGBA - c = rgba; - oo = o; - } else { // True RGBA, not RGB - rgbo = Color.rgba2rgbo(rgba); - c = rgbo[0]; - oo = o * rgbo[1]; - } + You should have received a copy of the GNU Lesser General Public License and + the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> + and <http://opensource.org/licenses/MIT/>. + */ - if (rendNode === undefined) { - node = el.rendNode; - } else { - node = rendNode; - } - if (c !== 'none') { - this._setAttribute(function () { - node.setAttributeNS(null, 'fill', c); - }, el.visPropOld.fillcolor); - } +/*global JXG: true, define: true*/ +/*jslint nomen: true, plusplus: true*/ - if (el.type === JXG.OBJECT_TYPE_IMAGE) { - this._setAttribute(function () { - node.setAttributeNS(null, 'opacity', oo); - }, el.visPropOld.fillopacity); - //node.style['opacity'] = oo; // This would overwrite values set by CSS class. - } else { - if (c === 'none') { // This is done only for non-images - // because images have no fill color. - oo = 0; - } - this._setAttribute(function () { - node.setAttributeNS(null, 'fill-opacity', oo); - }, el.visPropOld.fillopacity); - } +/* depends: + jxg + math/geometry + math/math + base/coords + base/constants + utils/type + elements: + point + curve + circumcentre + transform + */ - if (grad === 'linear' || grad === 'radial') { - this.updateGradient(el); - } +define('element/sector',[ + 'jxg', 'math/geometry', 'math/math', 'math/statistics', 'base/coords', 'base/constants', 'utils/type' +], function (JXG, Geometry, Mat, Statistics, Coords, Const, Type) { + + "use strict"; + + /** + * @class A circular sector is a subarea of the area enclosed by a circle. It is enclosed by two radii and an arc. + * @pseudo + * @name Sector + * @augments JXG.Curve + * @constructor + * @type JXG.Curve + * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. + * + * First possiblity of input parameters are: + * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 A sector is defined by three points: The sector's center <tt>p1</tt>, + * a second point <tt>p2</tt> defining the radius and a third point <tt>p3</tt> defining the angle of the sector. The + * Sector is always drawn counter clockwise from <tt>p2</tt> to <tt>p3</tt> + * <p> + * Second possibility of input parameters are: + * @param {JXG.Line_JXG.Line_array,number_array,number_number,function} line, line2, coords1 or direction1, coords2 or direction2, radius The sector is defined by two lines. + * The two legs which define the sector are given by two coordinates arrays which are project initially two the two lines or by two directions (+/- 1). + * The last parameter is the radius of the sector. + * + * + * @example + * // Create a sector out of three free points + * var p1 = board.create('point', [1.5, 5.0]), + * p2 = board.create('point', [1.0, 0.5]), + * p3 = board.create('point', [5.0, 3.0]), + * + * a = board.create('sector', [p1, p2, p3]); + * </pre><div class="jxgbox" id="JXG49f59123-f013-4681-bfd9-338b89893156" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function () { + * var board = JXG.JSXGraph.initBoard('JXG49f59123-f013-4681-bfd9-338b89893156', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}), + * p1 = board.create('point', [1.5, 5.0]), + * p2 = board.create('point', [1.0, 0.5]), + * p3 = board.create('point', [5.0, 3.0]), + * + * a = board.create('sector', [p1, p2, p3]); + * })(); + * </script><pre> + * + * @example + * // Create a sector out of two lines, two directions and a radius + * var p1 = board.create('point', [-1, 4]), + * p2 = board.create('point', [4, 1]), + * q1 = board.create('point', [-2, -3]), + * q2 = board.create('point', [4,3]), + * + * li1 = board.create('line', [p1,p2], {strokeColor:'black', lastArrow:true}), + * li2 = board.create('line', [q1,q2], {lastArrow:true}), + * + * sec1 = board.create('sector', [li1, li2, [5.5, 0], [4, 3], 3]), + * sec2 = board.create('sector', [li1, li2, 1, -1, 4]); + * + * </pre><div class="jxgbox" id="JXGbb9e2809-9895-4ff1-adfa-c9c71d50aa53" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function () { + * var board = JXG.JSXGraph.initBoard('JXGbb9e2809-9895-4ff1-adfa-c9c71d50aa53', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}), + * p1 = board.create('point', [-1, 4]), + * p2 = board.create('point', [4, 1]), + * q1 = board.create('point', [-2, -3]), + * q2 = board.create('point', [4,3]), + * + * li1 = board.create('line', [p1,p2], {strokeColor:'black', lastArrow:true}), + * li2 = board.create('line', [q1,q2], {lastArrow:true}), + * + * sec1 = board.create('sector', [li1, li2, [5.5, 0], [4, 3], 3]), + * sec2 = board.create('sector', [li1, li2, 1, -1, 4]); + * })(); + * </script><pre> + * + * @example + * var t = board.create('transform', [2, 1.5], {type: 'scale'}); + * var s1 = board.create('sector', [[-3.5,-3], [-3.5, -2], [-3.5,-4]], { + * anglePoint: {visible:true}, center: {visible: true}, radiusPoint: {visible: true}, + * fillColor: 'yellow', strokeColor: 'black'}); + * var s2 = board.create('curve', [s1, t], {fillColor: 'yellow', strokeColor: 'black'}); + * + * </pre><div id="JXG2e70ee14-6339-11e8-9fb9-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG2e70ee14-6339-11e8-9fb9-901b0e1b8723', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * var t = board.create('transform', [2, 1.5], {type: 'scale'}); + * var s1 = board.create('sector', [[-3.5,-3], [-3.5, -2], [-3.5,-4]], { + * anglePoint: {visible:true}, center: {visible: true}, radiusPoint: {visible: true}, + * fillColor: 'yellow', strokeColor: 'black'}); + * var s2 = board.create('curve', [s1, t], {fillColor: 'yellow', strokeColor: 'black'}); + * + * })(); + * + * </script><pre> + * + */ + JXG.createSector = function (board, parents, attributes) { + var el, attr, i, + type = 'invalid', + s, v, + attrPoints = ['center', 'radiusPoint', 'anglePoint'], + points; + + // Three points? + if (parents[0].elementClass === Const.OBJECT_CLASS_LINE && + parents[1].elementClass === Const.OBJECT_CLASS_LINE && + (Type.isArray(parents[2]) || Type.isNumber(parents[2])) && + (Type.isArray(parents[3]) || Type.isNumber(parents[3])) && + (Type.isNumber(parents[4]) || Type.isFunction(parents[4]) || Type.isString(parents[4]))) { + + type = '2lines'; + } else { + points = Type.providePoints(board, parents, attributes, 'sector', attrPoints); + if (points === false) { + throw new Error("JSXGraph: Can't create Sector with parent types '" + + (typeof parents[0]) + "' and '" + (typeof parents[1]) + "' and '" + + (typeof parents[2]) + "'."); } - el.visPropOld.fillcolor = rgba; - el.visPropOld.fillopacity = o; - }, + type = '3points'; + } - // documented in JXG.AbstractRenderer - setObjectStrokeColor: function (el, color, opacity) { - var rgba = Type.evaluate(color), c, rgbo, - o = Type.evaluate(opacity), oo, - node; - o = (o > 0) ? o : 0; + attr = Type.copyAttributes(attributes, board.options, 'sector'); + el = board.create('curve', [[0], [0]], attr); + el.type = Const.OBJECT_TYPE_SECTOR; + el.elType = 'sector'; - if (el.visPropOld.strokecolor === rgba && el.visPropOld.strokeopacity === o) { - return; + /** + * Set a radius if the attribute `radius` has value 'auto'. + * Sets a radius between 20 and 50 points, depending on the distance + * between the center and the radius point. + * This function is used in {@link Angle}. + * + * @returns {Number} returns a radius value in user coordinates. + */ + el.autoRadius = function() { + var r1 = 20 / el.board.unitX, // 20px + r2 = Infinity, + r3 = 50 / el.board.unitX; // 50px + + if (Type.isPoint(el.center)) { + // This does not work for 2-lines sectors / angles + r2 = el.center.Dist(el.point2) * 0.3333; } - if (Type.exists(rgba) && rgba !== false) { - if (rgba.length !== 9) { // RGB, not RGBA - c = rgba; - oo = o; - } else { // True RGBA, not RGB - rgbo = Color.rgba2rgbo(rgba); - c = rgbo[0]; - oo = o * rgbo[1]; + return Math.max(r1, Math.min(r2, r3)); + }; + + if (type === '2lines') { + /** + * @ignore + */ + el.Radius = function () { + var r = Type.evaluate(parents[4]); + if (r === 'auto') { + return this.autoRadius(); } + return r; + }; - node = el.rendNode; + el.line1 = board.select(parents[0]); + el.line2 = board.select(parents[1]); - if (el.elementClass === Const.OBJECT_CLASS_TEXT) { - if (Type.evaluate(el.visProp.display) === 'html') { - this._setAttribute(function () { - node.style.color = c; - node.style.opacity = oo; - }, el.visPropOld.strokecolor); + el.line1.addChild(el); + el.line2.addChild(el); + el.setParents(parents); - } else { - this._setAttribute(function () { - node.setAttributeNS(null, "style", "fill:" + c); - node.setAttributeNS(null, "style", "fill-opacity:" + oo); - }, el.visPropOld.strokecolor); - } - } else { - this._setAttribute(function () { - node.setAttributeNS(null, 'stroke', c); - node.setAttributeNS(null, 'stroke-opacity', oo); - }, el.visPropOld.strokecolor); - } + el.point1 = {visProp: {}}; + el.point2 = {visProp: {}}; + el.point3 = {visProp: {}}; - if (el.elementClass === Const.OBJECT_CLASS_CURVE || - el.elementClass === Const.OBJECT_CLASS_LINE) { - if (Type.evaluate(el.visProp.firstarrow)) { - this._setArrowColor(el.rendNodeTriangleStart, c, oo, el); - } + /* Intersection point */ + s = Geometry.meetLineLine(el.line1.stdform, el.line2.stdform, 0, board); - if (Type.evaluate(el.visProp.lastarrow)) { - this._setArrowColor(el.rendNodeTriangleEnd, c, oo, el); - } + if (Type.isArray(parents[2])) { + /* project p1 to l1 */ + if (parents[2].length === 2) { + parents[2] = [1].concat(parents[2]); } + /* + v = [0, el.line1.stdform[1], el.line1.stdform[2]]; + v = Mat.crossProduct(v, parents[2]); + v = Geometry.meetLineLine(v, el.line1.stdform, 0, board); + */ + v = Geometry.projectPointToLine({coords: {usrCoords: parents[2]}}, el.line1, board); + v = Statistics.subtract(v.usrCoords, s.usrCoords); + el.direction1 = (Mat.innerProduct(v, [0, el.line1.stdform[2], -el.line1.stdform[1]], 3) >= 0) ? +1 : -1; + } else { + el.direction1 = (parents[2] >= 0) ? 1 : -1; } - el.visPropOld.strokecolor = rgba; - el.visPropOld.strokeopacity = o; - }, - - // documented in JXG.AbstractRenderer - setObjectStrokeWidth: function (el, width) { - var node, - w = Type.evaluate(width); - - if (isNaN(w) || el.visPropOld.strokewidth === w) { - return; + if (Type.isArray(parents[3])) { + /* project p2 to l2 */ + if (parents[3].length === 2) { + parents[3] = [1].concat(parents[3]); + } + /* + v = [0, el.line2.stdform[1], el.line2.stdform[2]]; + v = Mat.crossProduct(v, parents[3]); + v = Geometry.meetLineLine(v, el.line2.stdform, 0, board); + */ + v = Geometry.projectPointToLine({coords: {usrCoords: parents[3]}}, el.line2, board); + v = Statistics.subtract(v.usrCoords, s.usrCoords); + el.direction2 = (Mat.innerProduct(v, [0, el.line2.stdform[2], -el.line2.stdform[1]], 3) >= 0) ? +1 : -1; + } else { + el.direction2 = (parents[3] >= 0) ? 1 : -1; } - node = el.rendNode; - this.setPropertyPrim(node, 'stroked', 'true'); - if (Type.exists(w)) { - this.setPropertyPrim(node, 'stroke-width', w + 'px'); - - // if (el.elementClass === Const.OBJECT_CLASS_CURVE || - // el.elementClass === Const.OBJECT_CLASS_LINE) { - // if (Type.evaluate(el.visProp.firstarrow)) { - // this._setArrowWidth(el.rendNodeTriangleStart, w, el.rendNode); - // } - // - // if (Type.evaluate(el.visProp.lastarrow)) { - // this._setArrowWidth(el.rendNodeTriangleEnd, w, el.rendNode); - // } - // } - } - el.visPropOld.strokewidth = w; - }, + el.updateDataArray = function () { + var r, l1, l2, + A = [0, 0, 0], + B = [0, 0, 0], + C = [0, 0, 0], + ar; - // documented in JXG.AbstractRenderer - setLineCap: function (el) { - var capStyle = Type.evaluate(el.visProp.linecap); + l1 = this.line1; + l2 = this.line2; - if (capStyle === undefined || capStyle === '' || el.visPropOld.linecap === capStyle || - !Type.exists(el.rendNode)) { - return; - } + // Intersection point of the lines + B = Mat.crossProduct(l1.stdform, l2.stdform); - this.setPropertyPrim(el.rendNode, 'stroke-linecap', capStyle); - el.visPropOld.linecap = capStyle; + if (Math.abs(B[0]) > Mat.eps * Mat.eps) { + B[1] /= B[0]; + B[2] /= B[0]; + B[0] /= B[0]; + } + // First point + r = this.direction1 * this.Radius(); + A = Statistics.add(B, [0, r * l1.stdform[2], -r * l1.stdform[1]]); - }, + // Second point + r = this.direction2 * this.Radius(); + C = Statistics.add(B, [0, r * l2.stdform[2], -r * l2.stdform[1]]); - // documented in JXG.AbstractRenderer - setShadow: function (el) { - var ev_s = Type.evaluate(el.visProp.shadow); - if (el.visPropOld.shadow === ev_s) { - return; - } + this.point2.coords = new Coords(Const.COORDS_BY_USER, A, el.board); + this.point1.coords = new Coords(Const.COORDS_BY_USER, B, el.board); + this.point3.coords = new Coords(Const.COORDS_BY_USER, C, el.board); - if (Type.exists(el.rendNode)) { - if (ev_s) { - el.rendNode.setAttributeNS(null, 'filter', 'url(#' + this.container.id + '_' + 'f1)'); - } else { - el.rendNode.removeAttributeNS(null, 'filter'); + if (Math.abs(A[0]) < Mat.eps || Math.abs(B[0]) < Mat.eps || Math.abs(C[0]) < Mat.eps) { + this.dataX = [NaN]; + this.dataY = [NaN]; + return; } - } - el.visPropOld.shadow = ev_s; - }, - /* ************************** - * renderer control - * **************************/ + ar = Geometry.bezierArc(A, B, C, true, 1); - // documented in JXG.AbstractRenderer - suspendRedraw: function () { - // It seems to be important for the Linux version of firefox - //this.suspendHandle = this.svgRoot.suspendRedraw(10000); - }, + this.dataX = ar[0]; + this.dataY = ar[1]; - // documented in JXG.AbstractRenderer - unsuspendRedraw: function () { - //this.svgRoot.unsuspendRedraw(this.suspendHandle); - //this.svgRoot.unsuspendRedrawAll(); - //this.svgRoot.forceRedraw(); - }, + this.bezierDegree = 3; + }; - // documented in AbstractRenderer - resize: function (w, h) { - this.svgRoot.style.width = parseFloat(w) + 'px'; - this.svgRoot.style.height = parseFloat(h) + 'px'; - this.svgRoot.setAttribute("width", parseFloat(w)); - this.svgRoot.setAttribute("height", parseFloat(h)); - }, + el.methodMap = JXG.deepCopy(el.methodMap, { + radius: 'Radius', + getRadius: 'Radius', + setRadius: 'setRadius' + }); - // documented in JXG.AbstractRenderer - createTouchpoints: function (n) { - var i, na1, na2, node; - this.touchpoints = []; - for (i = 0; i < n; i++) { - na1 = 'touchpoint1_' + i; - node = this.createPrim('path', na1); - this.appendChildPrim(node, 19); - node.setAttributeNS(null, 'd', 'M 0 0'); - this.touchpoints.push(node); + // el.prepareUpdate().update(); - this.setPropertyPrim(node, 'stroked', 'true'); - this.setPropertyPrim(node, 'stroke-width', '1px'); - node.setAttributeNS(null, 'stroke', '#000000'); - node.setAttributeNS(null, 'stroke-opacity', 1.0); - node.setAttributeNS(null, 'display', 'none'); + // end '2lines' - na2 = 'touchpoint2_' + i; - node = this.createPrim('ellipse', na2); - this.appendChildPrim(node, 19); - this.updateEllipsePrim(node, 0, 0, 0, 0); - this.touchpoints.push(node); + } else if (type === '3points') { - this.setPropertyPrim(node, 'stroked', 'true'); - this.setPropertyPrim(node, 'stroke-width', '1px'); - node.setAttributeNS(null, 'stroke', '#000000'); - node.setAttributeNS(null, 'stroke-opacity', 1.0); - node.setAttributeNS(null, 'fill', '#ffffff'); - node.setAttributeNS(null, 'fill-opacity', 0.0); + /** + * Midpoint of the sector. + * @memberOf Sector.prototype + * @name point1 + * @type JXG.Point + */ + el.point1 = points[0]; - node.setAttributeNS(null, 'display', 'none'); - } - }, + /** + * This point together with {@link Sector#point1} defines the radius.. + * @memberOf Sector.prototype + * @name point2 + * @type JXG.Point + */ + el.point2 = points[1]; - // documented in JXG.AbstractRenderer - showTouchpoint: function (i) { - if (this.touchpoints && i >= 0 && 2 * i < this.touchpoints.length) { - this.touchpoints[2 * i].setAttributeNS(null, 'display', 'inline'); - this.touchpoints[2 * i + 1].setAttributeNS(null, 'display', 'inline'); + /** + * Defines the sector's angle. + * @memberOf Sector.prototype + * @name point3 + * @type JXG.Point + */ + el.point3 = points[2]; + + /* Add arc as child to defining points */ + for (i = 0; i < 3; i++) { + if (Type.exists(points[i]._is_new)) { + el.addChild(points[i]); + delete points[i]._is_new; + } else { + points[i].addChild(el); + } } - }, - // documented in JXG.AbstractRenderer - hideTouchpoint: function (i) { - if (this.touchpoints && i >= 0 && 2 * i < this.touchpoints.length) { - this.touchpoints[2 * i].setAttributeNS(null, 'display', 'none'); - this.touchpoints[2 * i + 1].setAttributeNS(null, 'display', 'none'); + // useDirection is necessary for circumCircleSectors + el.useDirection = attributes.usedirection; + el.setParents(points); + + /** + * Defines the sectors orientation in case of circumCircleSectors. + * @memberOf Sector.prototype + * @name point4 + * @type JXG.Point + */ + if (Type.exists(points[3])) { + el.point4 = points[3]; + el.point4.addChild(el); } - }, - // documented in JXG.AbstractRenderer - updateTouchpoint: function (i, pos) { - var x, y, - d = 37; + el.methodMap = JXG.deepCopy(el.methodMap, { + arc: 'arc', + center: 'center', + radiuspoint: 'radiuspoint', + anglepoint: 'anglepoint', + radius: 'Radius', + getRadius: 'Radius', + setRadius: 'setRadius' + }); - if (this.touchpoints && i >= 0 && 2 * i < this.touchpoints.length) { - x = pos[0]; - y = pos[1]; + /** + * documented in JXG.Curve + * @ignore + */ + el.updateDataArray = function () { + var ar, det, p0c, p1c, p2c, + A = this.point2, + B = this.point1, + C = this.point3, + phi, sgn = 1, + vp_s = Type.evaluate(this.visProp.selection); - this.touchpoints[2 * i].setAttributeNS(null, 'd', 'M ' + (x - d) + ' ' + y + ' ' + - 'L ' + (x + d) + ' ' + y + ' ' + - 'M ' + x + ' ' + (y - d) + ' ' + - 'L ' + x + ' ' + (y + d)); - this.updateEllipsePrim(this.touchpoints[2 * i + 1], pos[0], pos[1], 25, 25); - } - }, + if (!A.isReal || !B.isReal || !C.isReal) { + this.dataX = [NaN]; + this.dataY = [NaN]; + return; + } - /** - * Walk recursively through the DOM subtree of a node and collect all - * value attributes together with the id of that node. - * <b>Attention:</b> Only values of nodes having a valid id are taken. - * @param {Node} node root node of DOM subtree that will be searched recursively. - * @return {Array} Array with entries of the form [id, value] - * @private - */ - _getValuesOfDOMElements: function (node) { - var values = []; - if (node.nodeType === 1) { - node = node.firstChild; - while (node) { - if (node.id !== undefined && node.value !== undefined) { - values.push([node.id, node.value]); + phi = Geometry.rad(A, B, C); + if ((vp_s === 'minor' && phi > Math.PI) || + (vp_s === 'major' && phi < Math.PI)) { + sgn = -1; + } + + // This is true for circumCircleSectors. In that case there is + // a fourth parent element: [midpoint, point1, point3, point2] + if (this.useDirection && Type.exists(this.point4)) { + p0c = this.point2.coords.usrCoords; + p1c = this.point4.coords.usrCoords; + p2c = this.point3.coords.usrCoords; + det = (p0c[1] - p2c[1]) * (p0c[2] - p1c[2]) - (p0c[2] - p2c[2]) * (p0c[1] - p1c[1]); + + if (det >= 0.0) { + C = this.point2; + A = this.point3; } - values = values.concat(this._getValuesOfDOMElements(node)); - node = node.nextSibling; } - } - return values; - }, - _getDataUri: function (url, callback) { - var image = new Image(); + A = A.coords.usrCoords; + B = B.coords.usrCoords; + C = C.coords.usrCoords; - image.onload = function () { - var canvas = document.createElement('canvas'); - canvas.width = this.naturalWidth; // or 'width' if you want a special/scaled size - canvas.height = this.naturalHeight; // or 'height' if you want a special/scaled size + ar = Geometry.bezierArc(A, B, C, true, sgn); - canvas.getContext('2d').drawImage(this, 0, 0); + this.dataX = ar[0]; + this.dataY = ar[1]; + this.bezierDegree = 3; + }; - callback(canvas.toDataURL('image/png')); - canvas.remove(); + /** + * Returns the radius of the sector. + * @memberOf Sector.prototype + * @name Radius + * @function + * @returns {Number} The distance between {@link Sector#point1} and {@link Sector#point2}. + */ + el.Radius = function () { + return this.point2.Dist(this.point1); }; - image.src = url; - }, + attr = Type.copyAttributes(attributes, board.options, 'sector', 'arc'); + attr.withLabel = false; + attr.name += '_arc'; + el.arc = board.create('arc', [el.point1, el.point2, el.point3], attr); + el.addChild(el.arc); + } // end '3points' - _getImgDataURL: function(svgRoot) { - var images, len, canvas, ctx, - ur, i; + el.center = el.point1; + el.radiuspoint = el.point2; + el.anglepoint = el.point3; - images = svgRoot.getElementsByTagName("image"); - len = images.length; - if (len > 0) { - canvas = document.createElement('canvas'); - //img = new Image(); - for (i = 0; i < len; i++) { - images[i].setAttribute("crossorigin", "anonymous"); - //img.src = images[i].href; - //img.onload = function() { - // img.crossOrigin = "anonymous"; - ctx = canvas.getContext('2d'); - canvas.width = images[i].getAttribute("width"); - canvas.height = images[i].getAttribute("height"); - try { - ctx.drawImage(images[i], 0, 0, canvas.width, canvas.height); - //ctx.drawImage(document.getElementById('testimg2'), 0, 0, canvas.width, canvas.height); + // Default hasPoint method. Documented in geometry element + el.hasPointCurve = function (x, y) { + var angle, alpha, beta, + prec, type, + checkPoint = new Coords(Const.COORDS_BY_SCREEN, [x, y], this.board), + r = this.Radius(), + dist = this.center.coords.distance(Const.COORDS_BY_USER, checkPoint), + has, + vp_s = Type.evaluate(this.visProp.selection); - // If the image is not png, the format must be specified here - ur = canvas.toDataURL(); - images[i].setAttribute("xlink:href", ur); - } catch (err) { - console.log("CORS problem! Image can not be used", err); - } - //}; + if (Type.isObject(Type.evaluate(this.visProp.precision))) { + type = this.board._inputDevice; + prec = Type.evaluate(this.visProp.precision[type]); + } else { + // 'inherit' + prec = this.board.options.precision.hasPoint; + } + prec /= Math.min(this.board.unitX, this.board.unitY); + has = (Math.abs(dist - r) < prec); + if (has) { + angle = Geometry.rad(this.point2, this.center, checkPoint.usrCoords.slice(1)); + alpha = 0; + beta = Geometry.rad(this.point2, this.center, this.point3); + + if ((vp_s === 'minor' && beta > Math.PI) || + (vp_s === 'major' && beta < Math.PI)) { + alpha = beta; + beta = 2 * Math.PI; + } + + if (angle < alpha || angle > beta) { + has = false; } - //canvas.remove(); } - return true; - }, - /** - * Return a data URI of the SVG code representeing the construction. - * The SVG code of the construction is base64 encoded. The return string starts - * with "data:image/svg+xml;base64,...". - * - * @param {Boolean} ignoreTexts If true, the foreignObject tag is taken out from the SVG root. - * This is necessary for older versions of Safari. Default: false - * @returns {String} data URI string - */ - dumpToDataURI: function (ignoreTexts) { - var svgRoot = this.svgRoot, - btoa = window.btoa || Base64.encode, - svg, - virtualNode, doc, - i, len, - values = []; + return has; + }; - // Move all HTML tags (beside the SVG root) of the container - // to the foreignObject element inside of the svgRoot node - // Problem: - // input values are not copied. This can be verified by looking at an innerHTML output - // of an input element. Therefore, we do it "by hand". - if (this.container.hasChildNodes() && Type.exists(this.foreignObjLayer)) { - while (svgRoot.nextSibling) { + /** + * Checks whether (x,y) is within the area defined by the sector. + * @memberOf Sector.prototype + * @name hasPointSector + * @function + * @param {Number} x Coordinate in x direction, screen coordinates. + * @param {Number} y Coordinate in y direction, screen coordinates. + * @returns {Boolean} True if (x,y) is within the sector defined by the arc, False otherwise. + */ + el.hasPointSector = function (x, y) { + var angle, + checkPoint = new Coords(Const.COORDS_BY_SCREEN, [x, y], this.board), + r = this.Radius(), + dist = this.point1.coords.distance(Const.COORDS_BY_USER, checkPoint), + alpha, + beta, + has = (dist < r), + vp_s = Type.evaluate(this.visProp.selection); - // Copy all value attributes - values = values.concat(this._getValuesOfDOMElements(svgRoot.nextSibling)); + if (has) { + angle = Geometry.rad(this.radiuspoint, this.center, checkPoint.usrCoords.slice(1)); + alpha = 0.0; + beta = Geometry.rad(this.radiuspoint, this.center, this.anglepoint); - this.foreignObjLayer.appendChild(svgRoot.nextSibling); + if ((vp_s === 'minor' && beta > Math.PI) || + (vp_s === 'major' && beta < Math.PI)) { + alpha = beta; + beta = 2 * Math.PI; } - if (ignoreTexts === true) { - // Take out foreignObjLayer, so that it will not be visible - // in the dump. - doc = this.container.ownerDocument; - virtualNode = doc.createElement('div'); - virtualNode.appendChild(this.foreignObjLayer); + //if (angle > Geometry.rad(this.point2, this.point1, this.point3)) { + if (angle < alpha || angle > beta) { + has = false; } } + return has; + }; + + el.hasPoint = function (x, y) { + if (Type.evaluate(this.visProp.highlightonsector) || + Type.evaluate(this.visProp.hasinnerpoints)) { + return this.hasPointSector(x, y); + } - this._getImgDataURL(svgRoot); + return this.hasPointCurve(x, y); + }; - // Convert the SVG graphic into a string containing SVG code - svgRoot.setAttribute("xmlns", "http://www.w3.org/2000/svg"); - svg = new XMLSerializer().serializeToString(svgRoot); + // documented in GeometryElement + el.getTextAnchor = function () { + return this.point1.coords; + }; - if (ignoreTexts !== true) { - // Handle SVG texts - // Insert all value attributes back into the svg string - len = values.length; - for (i = 0; i < len; i++) { - svg = svg.replace('id="' + values[i][0] + '"', 'id="' + values[i][0] + '" value="' + values[i][1] + '"'); - } - } + // documented in GeometryElement + // this method is very similar to arc.getLabelAnchor() + // there are some additions in the arc version though, mainly concerning + // "major" and "minor" arcs. but maybe these methods can be merged. + el.getLabelAnchor = function () { + var coords, vec, vecx, vecy, len, + angle = Geometry.rad(this.point2, this.point1, this.point3), + dx = 13 / this.board.unitX, + dy = 13 / this.board.unitY, + p2c = this.point2.coords.usrCoords, + pmc = this.point1.coords.usrCoords, + bxminusax = p2c[1] - pmc[1], + byminusay = p2c[2] - pmc[2], + vp_s = Type.evaluate(this.visProp.selection), + l_vp = this.label ? this.label.visProp : this.visProp.label; - // if (false) { - // // Debug: use example svg image - // svg = '<svg xmlns="http://www.w3.org/2000/svg" version="1.0" width="220" height="220"><rect width="66" height="30" x="21" y="32" stroke="#204a87" stroke-width="2" fill="none" /></svg>'; - // } + // If this is uncommented, the angle label can not be dragged + //if (Type.exists(this.label)) { + // this.label.relativeCoords = new Coords(Const.COORDS_BY_SCREEN, [0, 0], this.board); + //} - // In IE we have to remove the namespace again. - if ((svg.match(/xmlns=\"http:\/\/www.w3.org\/2000\/svg\"/g) || []).length > 1) { - svg = svg.replace(/xmlns=\"http:\/\/www.w3.org\/2000\/svg\"/g, ''); + if ((vp_s === 'minor' && angle > Math.PI) || + (vp_s === 'major' && angle < Math.PI)) { + angle = -(2 * Math.PI - angle); } - // Safari fails if the svg string contains a " " - // Obsolete with Safari 12+ - svg = svg.replace(/ /g, ' '); + coords = new Coords(Const.COORDS_BY_USER, [ + pmc[1] + Math.cos(angle * 0.5) * bxminusax - Math.sin(angle * 0.5) * byminusay, + pmc[2] + Math.sin(angle * 0.5) * bxminusax + Math.cos(angle * 0.5) * byminusay + ], this.board); - // Move all HTML tags back from - // the foreignObject element to the container - if (Type.exists(this.foreignObjLayer) && this.foreignObjLayer.hasChildNodes()) { - if (ignoreTexts === true) { - // Put foreignObjLayer back into the SVG - svgRoot.appendChild(this.foreignObjLayer); - } - // Restore all HTML elements - while (this.foreignObjLayer.firstChild) { - this.container.appendChild(this.foreignObjLayer.firstChild); - } - } + vecx = coords.usrCoords[1] - pmc[1]; + vecy = coords.usrCoords[2] - pmc[2]; - return 'data:image/svg+xml;base64,' + btoa(unescape(encodeURIComponent(svg))); - }, + len = Math.sqrt(vecx * vecx + vecy * vecy); + vecx = vecx * (len + dx) / len; + vecy = vecy * (len + dy) / len; + vec = [pmc[1] + vecx, pmc[2] + vecy]; + + l_vp.position = Geometry.calcLabelQuadrant(Geometry.rad([1,0],[0,0],vec)); + return new Coords(Const.COORDS_BY_USER, vec, this.board); + }; /** - * Convert the SVG construction into an HTML canvas image. - * This works for all SVG supporting browsers. Implemented as Promise. - * <p> - * For IE, it is realized as function. - * It works from version 9, with the exception that HTML texts - * are ignored on IE. The drawing is done with a delay of - * 200 ms. Otherwise there would be problems with IE. - * - * @param {String} canvasId Id of an HTML canvas element - * @param {Number} w Width in pixel of the dumped image, i.e. of the canvas tag. - * @param {Number} h Height in pixel of the dumped image, i.e. of the canvas tag. - * @param {Boolean} ignoreTexts If true, the foreignObject tag is taken out from the SVG root. - * This is necessary for older versions of Safari. Default: false - * @returns {Promise} Promise object - * - * @example - * board.renderer.dumpToCanvas('canvas').then(function() { console.log('done'); }); - * - * @example - * // IE 11 example: - * board.renderer.dumpToCanvas('canvas'); - * setTimeout(function() { console.log('done'); }, 400); + * Overwrite the Radius method of the sector. + * Used in {@link GeometryElement#setAttribute}. + * @param {Number, Function} value New radius. */ - dumpToCanvas: function (canvasId, w, h, ignoreTexts) { - var //svgRoot = this.svgRoot, - svg, tmpImg, cv, ctx; - // wOrg, hOrg; + el.setRadius = function (val) { + /** + * @ignore + */ + el.Radius = function () { + var r = Type.evaluate(val); + if (r === 'auto') { + return this.autoRadius(); + } + return r; + }; + }; - // wOrg = svgRoot.getAttribute('width'); - // hOrg = svgRoot.getAttribute('height'); + /** + * @deprecated + * @ignore + */ + el.getRadius = function () { + JXG.deprecated('Sector.getRadius()', 'Sector.Radius()'); + return this.Radius(); + }; - // Prepare the canvas element - cv = document.getElementById(canvasId); - // Clear the canvas - cv.width = cv.width; - ctx = cv.getContext("2d"); - if (w !== undefined && h !== undefined) { - cv.style.width = parseFloat(w) + 'px'; - cv.style.height = parseFloat(h) + 'px'; - // Scale twice the CSS size to make the image crisp - // cv.setAttribute('width', 2 * parseFloat(wOrg)); - // cv.setAttribute('height', 2 * parseFloat(hOrg)); - // ctx.scale(2 * wOrg / w, 2 * hOrg / h); - cv.setAttribute('width', parseFloat(w)); - cv.setAttribute('height', parseFloat(h)); - } + /** + * Moves the sector by the difference of two coordinates. + * @param {Number} method The type of coordinates used here. Possible values are {@link JXG.COORDS_BY_USER} and {@link JXG.COORDS_BY_SCREEN}. + * @param {Array} coords coordinates in screen/user units + * @param {Array} oldcoords previous coordinates in screen/user units + * @returns {JXG.Curve} this element + */ + if (type === '3points') { + el.setPositionDirectly = function (method, coords, oldcoords) { + var dc, t, i, + c = new Coords(method, coords, this.board), + oldc = new Coords(method, oldcoords, this.board); - // Display the SVG string as data-uri in an HTML img. - tmpImg = new Image(); - svg = this.dumpToDataURI(ignoreTexts); - tmpImg.src = svg; + if (!el.point1.draggable() || !el.point2.draggable() || !el.point3.draggable()) { + return this; + } + + dc = Statistics.subtract(c.usrCoords, oldc.usrCoords); + t = this.board.create('transform', dc.slice(1), {type: 'translate'}); + t.applyOnce([el.point1, el.point2, el.point3]); - // Finally, draw the HTML img in the canvas. - if (!('Promise' in window)) { - tmpImg.onload = function () { - // IE needs a pause... - // Seems to be broken - window.setTimeout(function() { - try { - ctx.drawImage(tmpImg, 0, 0, w, h); - } catch (err) { - console.log("screenshots not longer supported on IE"); - } - }, 200); - }; return this; - } + }; + } - return new Promise(function(resolve, reject) { - try { - tmpImg.onload = function () { - ctx.drawImage(tmpImg, 0, 0, w, h); - resolve(); - }; - } catch (e) { - reject(e); - } - }); + el.prepareUpdate().update(); - }, + return el; + }; - /** - * Display SVG image in html img-tag which enables - * easy download for the user. - * - * Support: - * <ul> - * <li> IE: No - * <li> Edge: full - * <li>Firefox: full - * <li> Chrome: full - * <li> Safari: full (No text support in versions prior to 12). - * </ul> - * - * @param {JXG.Board} board Link to the board. - * @param {String} imgId Optional id of an img object. If given and different from the empty string, - * the screenshot is copied to this img object. The width and height will be set to the values of the - * JSXGraph container. - * @param {Boolean} ignoreTexts If set to true, the foreignObject is taken out of the - * SVGRoot and texts are not displayed. This is mandatory for Safari. Default: false - * @return {Object} the svg renderer object - */ - screenshot: function (board, imgId, ignoreTexts) { - var node, - doc = this.container.ownerDocument, - parent = this.container.parentNode, - cPos, - canvas, id, - img, - button, buttonText, - w, h, - bas = board.attr.screenshot, - zbar, zbarDisplay, cssTxt, - newImg = false, - _copyCanvasToImg, - isDebug = false; + JXG.registerElement('sector', JXG.createSector); - if (this.type === 'no') { - return this; - } + /** + * @class A circumcircle sector is different from a {@link Sector} mostly in the way the parent elements are interpreted. + * At first, the circum centre is determined from the three given points. Then the sector is drawn from <tt>p1</tt> through + * <tt>p2</tt> to <tt>p3</tt>. + * @pseudo + * @name CircumcircleSector + * @augments Sector + * @constructor + * @type Sector + * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p1 A circumcircle sector is defined by the circumcircle which is determined + * by these three given points. The circumcircle sector is always drawn from <tt>p1</tt> through <tt>p2</tt> to <tt>p3</tt>. + * @example + * // Create an arc out of three free points + * var p1 = board.create('point', [1.5, 5.0]), + * p2 = board.create('point', [1.0, 0.5]), + * p3 = board.create('point', [5.0, 3.0]), + * + * a = board.create('circumcirclesector', [p1, p2, p3]); + * </pre><div class="jxgbox" id="JXG695cf0d6-6d7a-4d4d-bfc9-34c6aa28cd04" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function () { + * var board = JXG.JSXGraph.initBoard('JXG695cf0d6-6d7a-4d4d-bfc9-34c6aa28cd04', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}), + * p1 = board.create('point', [1.5, 5.0]), + * p2 = board.create('point', [1.0, 0.5]), + * p3 = board.create('point', [5.0, 3.0]), + * + * a = board.create('circumcirclesector', [p1, p2, p3]); + * })(); + * </script><pre> + */ + JXG.createCircumcircleSector = function (board, parents, attributes) { + var el, mp, attr, points, i; + + points = Type.providePoints(board, parents, attributes, 'point'); + if (points === false) { + throw new Error("JSXGraph: Can't create circumcircle sector with parent types '" + + (typeof parents[0]) + "' and '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'."); + } - w = bas.scale * parseFloat(this.container.style.width); - h = bas.scale * parseFloat(this.container.style.height); + mp = board.create('circumcenter', points.slice(0, 3), attr); + mp.dump = false; - if (imgId === undefined || imgId === '') { - newImg = true; - img = new Image(); //doc.createElement('img'); - img.style.width = w + 'px'; - img.style.height = h + 'px'; - } else { - newImg = false; - img = doc.getElementById(imgId); - } - // img.crossOrigin = 'anonymous'; + attr = Type.copyAttributes(attributes, board.options, 'circumcirclesector'); + el = board.create('sector', [mp, points[0], points[2], points[1]], attr); - // Create div which contains canvas element and close button - if (newImg) { - node = doc.createElement('div'); - node.style.cssText = bas.css; - node.style.width = (w) + 'px'; - node.style.height = (h) + 'px'; - node.style.zIndex = this.container.style.zIndex + 120; + el.elType = 'circumcirclesector'; + el.setParents(points); - // Try to position the div exactly over the JSXGraph board - node.style.position = 'absolute'; - node.style.top = this.container.offsetTop + 'px'; - node.style.left = this.container.offsetLeft + 'px'; - } + /** + * Center of the circumcirclesector + * @memberOf CircumcircleSector.prototype + * @name center + * @type Circumcenter + */ + el.center = mp; + el.subs = { + center: mp + }; - if (!isDebug) { - // Create canvas element and add it to the DOM - // It will be removed after the image has been stored. - canvas = doc.createElement('canvas'); - id = Math.random().toString(36).substr(2, 5); - canvas.setAttribute('id', id); - canvas.setAttribute('width', w); - canvas.setAttribute('height', h); - canvas.style.width = w + 'px'; - canvas.style.height = w + 'px'; - canvas.style.display = 'none'; - parent.appendChild(canvas); - } else { - // Debug: use canvas element 'jxgbox_canvas' from jsxdev/dump.html - id = 'jxgbox_canvas'; - canvas = document.getElementById(id); - } + return el; + }; - if (newImg) { - // Create close button - button = doc.createElement('span'); - buttonText = doc.createTextNode('\u2716'); - button.style.cssText = bas.cssButton; - button.appendChild(buttonText); - button.onclick = function () { - node.parentNode.removeChild(node); - }; + JXG.registerElement('circumcirclesector', JXG.createCircumcircleSector); - // Add all nodes - node.appendChild(img); - node.appendChild(button); - parent.insertBefore(node, this.container.nextSibling); - } + /** + * @class A minor sector is a sector of a circle having measure less than or equal to + * 180 degrees (pi radians). It is defined by a center, one point that + * defines the radius, and a third point that defines the angle of the sector. + * @pseudo + * @name MinorSector + * @augments Curve + * @constructor + * @type JXG.Curve + * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 . Minor sector is a sector of a circle around p1 having measure less than or equal to + * 180 degrees (pi radians) and starts at p2. The radius is determined by p2, the angle by p3. + * @example + * // Create sector out of three free points + * var p1 = board.create('point', [2.0, 2.0]); + * var p2 = board.create('point', [1.0, 0.5]); + * var p3 = board.create('point', [3.5, 1.0]); + * + * var a = board.create('minorsector', [p1, p2, p3]); + * </pre><div class="jxgbox" id="JXGaf27ddcc-265f-428f-90dd-d31ace945800" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function () { + * var board = JXG.JSXGraph.initBoard('JXGaf27ddcc-265f-428f-90dd-d31ace945800', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}), + * p1 = board.create('point', [2.0, 2.0]), + * p2 = board.create('point', [1.0, 0.5]), + * p3 = board.create('point', [3.5, 1.0]), + * + * a = board.create('minorsector', [p1, p2, p3]); + * })(); + * </script><pre> + */ + JXG.createMinorSector = function (board, parents, attributes) { + attributes.selection = 'minor'; + return JXG.createSector(board, parents, attributes); + }; - // Hide navigation bar in board - zbar = document.getElementById(this.container.id + '_navigationbar'); - if (Type.exists(zbar)) { - zbarDisplay = zbar.style.display; - zbar.style.display = 'none'; - } + JXG.registerElement('minorsector', JXG.createMinorSector); - _copyCanvasToImg = function() { - // Show image in img tag - img.src = canvas.toDataURL('image/png'); + /** + * @class A major sector is a sector of a circle having measure greater than or equal to + * 180 degrees (pi radians). It is defined by a center, one point that + * defines the radius, and a third point that defines the angle of the sector. + * @pseudo + * @name MajorSector + * @augments Curve + * @constructor + * @type JXG.Curve + * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 . Major sector is a sector of a circle around p1 having measure greater than or equal to + * 180 degrees (pi radians) and starts at p2. The radius is determined by p2, the angle by p3. + * @example + * // Create an arc out of three free points + * var p1 = board.create('point', [2.0, 2.0]); + * var p2 = board.create('point', [1.0, 0.5]); + * var p3 = board.create('point', [3.5, 1.0]); + * + * var a = board.create('majorsector', [p1, p2, p3]); + * </pre><div class="jxgbox" id="JXG83c6561f-7561-4047-b98d-036248a00932" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function () { + * var board = JXG.JSXGraph.initBoard('JXG83c6561f-7561-4047-b98d-036248a00932', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}), + * p1 = board.create('point', [2.0, 2.0]), + * p2 = board.create('point', [1.0, 0.5]), + * p3 = board.create('point', [3.5, 1.0]), + * + * a = board.create('majorsector', [p1, p2, p3]); + * })(); + * </script><pre> + */ + JXG.createMajorSector = function (board, parents, attributes) { + attributes.selection = 'major'; + return JXG.createSector(board, parents, attributes); + }; - // Remove canvas node - if (!isDebug) { - parent.removeChild(canvas); - } - }; + JXG.registerElement('majorsector', JXG.createMajorSector); + + /** + * @class The angle element is used to denote an angle defined by three points. Visually it is just a {@link Sector} + * element with a radius not defined by the parent elements but by an attribute <tt>radius</tt>. As opposed to the sector, + * an angle has two angle points and no radius point. + * Sector is displayed if type=="sector". + * If type=="square", instead of a sector a parallelogram is displayed. + * In case of type=="auto", a square is displayed if the angle is near orthogonal. + * If no name is provided the angle label is automatically set to a lower greek letter. + * @pseudo + * @name Angle + * @augments Sector + * @constructor + * @type Sector + * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. + * First possibility of input parameters are: + * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p1 An angle is always drawn counterclockwise from <tt>p1</tt> to + * <tt>p3</tt> around <tt>p2</tt>. + * + * Second possibility of input parameters are: + * @param {JXG.Line_JXG.Line_array|number_array|number} line, line2, coords1 or direction1, coords2 or direction2, radius The angle is defined by two lines. + * The two legs which define the angle are given by two coordinate arrays. + * The points given by these coordinate arrays are projected initially (i.e. only once) onto the two lines. + * The other possibility is to supply directions (+/- 1). + * + * @example + * // Create an angle out of three free points + * var p1 = board.create('point', [5.0, 3.0]), + * p2 = board.create('point', [1.0, 0.5]), + * p3 = board.create('point', [1.5, 5.0]), + * + * a = board.create('angle', [p1, p2, p3]), + * t = board.create('text', [4, 4, function() { return JXG.toFixed(a.Value(), 2); }]); + * </pre><div class="jxgbox" id="JXGa34151f9-bb26-480a-8d6e-9b8cbf789ae5" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function () { + * var board = JXG.JSXGraph.initBoard('JXGa34151f9-bb26-480a-8d6e-9b8cbf789ae5', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}), + * p1 = board.create('point', [5.0, 3.0]), + * p2 = board.create('point', [1.0, 0.5]), + * p3 = board.create('point', [1.5, 5.0]), + * + * a = board.create('angle', [p1, p2, p3]), + * t = board.create('text', [4, 4, function() { return JXG.toFixed(a.Value(), 2); }]); + * })(); + * </script><pre> + * + * @example + * // Create an angle out of two lines and two directions + * var p1 = board.create('point', [-1, 4]), + * p2 = board.create('point', [4, 1]), + * q1 = board.create('point', [-2, -3]), + * q2 = board.create('point', [4,3]), + * + * li1 = board.create('line', [p1,p2], {strokeColor:'black', lastArrow:true}), + * li2 = board.create('line', [q1,q2], {lastArrow:true}), + * + * a1 = board.create('angle', [li1, li2, [5.5, 0], [4, 3]], { radius:1 }), + * a2 = board.create('angle', [li1, li2, 1, -1], { radius:2 }); + * + * + * </pre><div class="jxgbox" id="JXG3a667ddd-63dc-4594-b5f1-afac969b371f" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function () { + * var board = JXG.JSXGraph.initBoard('JXG3a667ddd-63dc-4594-b5f1-afac969b371f', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}), + * p1 = board.create('point', [-1, 4]), + * p2 = board.create('point', [4, 1]), + * q1 = board.create('point', [-2, -3]), + * q2 = board.create('point', [4,3]), + * + * li1 = board.create('line', [p1,p2], {strokeColor:'black', lastArrow:true}), + * li2 = board.create('line', [q1,q2], {lastArrow:true}), + * + * a1 = board.create('angle', [li1, li2, [5.5, 0], [4, 3]], { radius:1 }), + * a2 = board.create('angle', [li1, li2, 1, -1], { radius:2 }); + * })(); + * </script><pre> + * + * + * @example + * // Display the angle value instead of the name + * var p1 = board.create('point', [0,2]); + * var p2 = board.create('point', [0,0]); + * var p3 = board.create('point', [-2,0.2]); + * + * var a = board.create('angle', [p1, p2, p3], { + * radius: 1, + * name: function() { + * return JXG.Math.Geometry.trueAngle(p1, p2, p3).toFixed(1) + '°'; + * }}); + * + * </pre><div id="JXGc813f601-8dd3-4030-9892-25c6d8671512" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXGc813f601-8dd3-4030-9892-25c6d8671512', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * + * var p1 = board.create('point', [0,2]); + * var p2 = board.create('point', [0,0]); + * var p3 = board.create('point', [-2,0.2]); + * + * var a = board.create('angle', [p1, p2, p3], { + * radius: 1, + * name: function() { + * return JXG.Math.Geometry.trueAngle(p1, p2, p3).toFixed(1) + '°'; + * }}); + * + * })(); + * + * </script><pre> + * + * + * @example + * // Apply a transformation to an angle. + * var t = board.create('transform', [2, 1.5], {type: 'scale'}); + * var an1 = board.create('angle', [[-4,3.9], [-3, 4], [-3, 3]]); + * var an2 = board.create('curve', [an1, t]); + * + * </pre><div id="JXG4c8d9ed8-6339-11e8-9fb9-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG4c8d9ed8-6339-11e8-9fb9-901b0e1b8723', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * var t = board.create('transform', [2, 1.5], {type: 'scale'}); + * var an1 = board.create('angle', [[-4,3.9], [-3, 4], [-3, 3]]); + * var an2 = board.create('curve', [an1, t]); + * + * })(); + * + * </script><pre> + * + */ + JXG.createAngle = function (board, parents, attributes) { + var el, radius, attr, attrsub, + i, points, + type = 'invalid'; - // Create screenshot in image element - if ('Promise' in window) { - this.dumpToCanvas(id, w, h, ignoreTexts).then(_copyCanvasToImg); - } else { - // IE - this.dumpToCanvas(id, w, h, ignoreTexts); - window.setTimeout(_copyCanvasToImg, 200); - } + // Two lines or three points? + if (parents[0].elementClass === Const.OBJECT_CLASS_LINE && + parents[1].elementClass === Const.OBJECT_CLASS_LINE && + (Type.isArray(parents[2]) || Type.isNumber(parents[2])) && + (Type.isArray(parents[3]) || Type.isNumber(parents[3]))) { - // Show navigation bar in board - if (Type.exists(zbar)) { - zbar.style.display = zbarDisplay; + type = '2lines'; + } else { + points = Type.providePoints(board, parents, attributes, 'point'); + if (points === false) { + throw new Error("JSXGraph: Can't create angle with parent types '" + + (typeof parents[0]) + "' and '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'."); } - - return this; + type = '3points'; } - }); - - return JXG.SVGRenderer; -}); - -/* - Copyright 2008-2021 - Matthias Ehmann, - Michael Gerhaeuser, - Carsten Miller, - Bianca Valentin, - Alfred Wassermann, - Peter Wilfahrt - - This file is part of JSXGraph. - - JSXGraph is free software dual licensed under the GNU LGPL or MIT License. - - You can redistribute it and/or modify it under the terms of the - - * GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version - OR - * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT - - JSXGraph is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License and - the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> - and <http://opensource.org/licenses/MIT/>. - */ - - -/*global JXG: true, define: true, AMprocessNode: true, MathJax: true, document: true */ -/*jslint nomen: true, plusplus: true, newcap:true*/ - -/* depends: - jxg - renderer/abstract - base/constants - utils/type - utils/color - math/math - math/numerics -*/ - -define('renderer/vml',[ - 'jxg', 'renderer/abstract', 'base/constants', 'utils/type', 'utils/color', 'math/math', 'math/numerics' -], function (JXG, AbstractRenderer, Const, Type, Color, Mat, Numerics) { - - "use strict"; - - /** - * Uses VML to implement the rendering methods defined in {@link JXG.AbstractRenderer}. - * @class JXG.AbstractRenderer - * @augments JXG.AbstractRenderer - * @param {Node} container Reference to a DOM node containing the board. - * @see JXG.AbstractRenderer - */ - JXG.VMLRenderer = function (container) { - this.type = 'vml'; + attr = Type.copyAttributes(attributes, board.options, 'angle'); - this.container = container; - this.container.style.overflow = 'hidden'; - if (this.container.style.position === '') { - this.container.style.position = 'relative'; + // If empty, create a new name + if (!Type.exists(attr.name) || attr.name === '') { + attr.name = board.generateName({type: Const.OBJECT_TYPE_ANGLE}); } - this.container.onselectstart = function () { - return false; - }; - this.resolution = 10; // Paths are drawn with a a resolution of this.resolution/pixel. - - // Add VML includes and namespace - // Original: IE <=7 - //container.ownerDocument.createStyleSheet().addRule("v\\:*", "behavior: url(#default#VML);"); - if (!Type.exists(JXG.vmlStylesheet)) { - container.ownerDocument.namespaces.add("jxgvml", "urn:schemas-microsoft-com:vml"); - JXG.vmlStylesheet = this.container.ownerDocument.createStyleSheet(); - JXG.vmlStylesheet.addRule(".jxgvml", "behavior:url(#default#VML)"); + if (Type.exists(attr.radius)) { + radius = attr.radius; + } else { + radius = 0; } - try { - if (!container.ownerDocument.namespaces.jxgvml) { - container.ownerDocument.namespaces.add("jxgvml", "urn:schemas-microsoft-com:vml"); - } + if (type === '2lines') { + parents.push(radius); + el = board.create('sector', parents, attr); + el.updateDataArraySector = el.updateDataArray; - this.createNode = function (tagName) { - return container.ownerDocument.createElement('<jxgvml:' + tagName + ' class="jxgvml">'); - }; - } catch (e) { - this.createNode = function (tagName) { - return container.ownerDocument.createElement('<' + tagName + ' xmlns="urn:schemas-microsoft.com:vml" class="jxgvml">'); - }; - } + // TODO + el.setAngle = function (val) {}; + el.free = function (val) {}; - // dash styles - this.dashArray = ['Solid', '1 1', 'ShortDash', 'Dash', 'LongDash', 'ShortDashDot', 'LongDashDot']; - }; + } else { + el = board.create('sector', [points[1], points[0], points[2]], attr); + el.arc.visProp.priv = true; - JXG.VMLRenderer.prototype = new AbstractRenderer(); + /** + * The point defining the radius of the angle element. + * Alias for {@link Sector#radiuspoint}. + * @type JXG.Point + * @name point + * @memberOf Angle.prototype + * + */ + el.point = el.point2 = el.radiuspoint = points[0]; - JXG.extend(JXG.VMLRenderer.prototype, /** @lends JXG.VMLRenderer */ { + /** + * Helper point for angles of type 'square'. + * @type JXG.Point + * @name pointsquare + * @memberOf Angle.prototype + */ + el.pointsquare = el.point3 = el.anglepoint = points[2]; - /** - * Sets attribute <tt>key</tt> of node <tt>node</tt> to <tt>value</tt>. - * @param {Node} node A DOM node. - * @param {String} key Name of the attribute. - * @param {String} val New value of the attribute. - * @param {Boolean} [iFlag=false] If false, the attribute's name is case insensitive. - */ - _setAttr: function (node, key, val, iFlag) { - try { - if (this.container.ownerDocument.documentMode === 8) { - node[key] = val; - } else { - node.setAttribute(key, val, iFlag); + /** + * @ignore + */ + el.Radius = function () { + // Set the angle radius, also @see @link Sector#autoRadius + var r = Type.evaluate(radius); + if (r === 'auto') { + return el.autoRadius(); } - } catch (e) { - JXG.debug('_setAttr:'/*node.id*/ + ' ' + key + ' ' + val + '<br>\n'); - } - }, - - /* ******************************** * - * This renderer does not need to - * override draw/update* methods - * since it provides draw/update*Prim - * methods. - * ******************************** */ - - /* ************************** - * Lines - * **************************/ - - // documented in AbstractRenderer - updateTicks: function (ticks) { - var i, len, c, x, y, - r = this.resolution, - tickArr = []; + return r; + }; - len = ticks.ticks.length; - for (i = 0; i < len; i++) { - c = ticks.ticks[i]; - x = c[0]; - y = c[1]; + el.updateDataArraySector = function () { + var A = this.point2, + B = this.point1, + C = this.point3, + r = this.Radius(), + d = B.Dist(A), + ar, + phi, + sgn = 1, + vp_s = Type.evaluate(this.visProp.selection); - if (Type.isNumber(x[0]) && Type.isNumber(x[1])) { - tickArr.push(' m ' + Math.round(r * x[0]) + ', ' + Math.round(r * y[0]) + - ' l ' + Math.round(r * x[1]) + ', ' + Math.round(r * y[1]) + ' '); + phi = Geometry.rad(A, B, C); + if ((vp_s === 'minor' && phi > Math.PI) || + (vp_s === 'major' && phi < Math.PI)) { + sgn = -1; } - } - - if (!Type.exists(ticks.rendNode)) { - ticks.rendNode = this.createPrim('path', ticks.id); - this.appendChildPrim(ticks.rendNode, Type.evaluate(ticks.visProp.layer)); - } - - this._setAttr(ticks.rendNode, 'stroked', 'true'); - this._setAttr(ticks.rendNode, 'strokecolor', Type.evaluate(ticks.visProp.strokecolor), 1); - this._setAttr(ticks.rendNode, 'strokeweight', Type.evaluate(ticks.visProp.strokewidth)); - this._setAttr(ticks.rendNodeStroke, 'opacity', (Type.evaluate(ticks.visProp.strokeopacity) * 100) + '%'); - this.updatePathPrim(ticks.rendNode, tickArr, ticks.board); - }, - /* ************************** - * Text related stuff - * **************************/ + A = A.coords.usrCoords; + B = B.coords.usrCoords; + C = C.coords.usrCoords; - // already documented in JXG.AbstractRenderer - displayCopyright: function (str, fontsize) { - var node, t; + A = [1, B[1] + (A[1] - B[1]) * r / d, B[2] + (A[2] - B[2]) * r / d]; + C = [1, B[1] + (C[1] - B[1]) * r / d, B[2] + (C[2] - B[2]) * r / d]; - node = this.createNode('textbox'); - node.style.position = 'absolute'; - this._setAttr(node, 'id', this.container.id + '_' + 'licenseText'); + ar = Geometry.bezierArc(A, B, C, true, sgn); - node.style.left = 20; - node.style.top = 2; - node.style.fontSize = fontsize; - node.style.color = '#356AA0'; - node.style.fontFamily = 'Arial,Helvetica,sans-serif'; - this._setAttr(node, 'opacity', '30%'); - node.style.filter = "progid:DXImageTransform.Microsoft.Matrix(M11='1.0', sizingMethod='auto expand', enabled = false) progid:DXImageTransform.Microsoft.Alpha(opacity = 30, enabled = true)"; + this.dataX = ar[0]; + this.dataY = ar[1]; + this.bezierDegree = 3; + }; - t = this.container.ownerDocument.createTextNode(str); - node.appendChild(t); - this.appendChildPrim(node, 0); - }, + /** + * Set an angle to a prescribed value given in radians. + * This is only possible if the third point of the angle, i.e. + * the anglepoint is a free point. + * Removing the constraint again is done by calling "angle.free()". + * + * Changing the angle requires to call the method "free()": + * + * <pre> + * angle.setAngle(Math.PI / 6); + * // ... + * angle.free().setAngle(Math.PI / 4); + * </pre> + * + * @name setAngle + * @function + * @param {Number|Function} val Number or Function which returns the size of the angle in Radians + * @returns {Object} Pointer to the angle element.. + * @memberOf Angle.prototype + * @see Angle#free + * + * @example + * var p1, p2, p3, c, a, s; + * + * p1 = board.create('point',[0,0]); + * p2 = board.create('point',[5,0]); + * p3 = board.create('point',[0,5]); + * + * c1 = board.create('circle',[p1, p2]); + * + * a = board.create('angle',[p2, p1, p3], {radius:3}); + * + * a.setAngle(function() { + * return Math.PI / 3; + * }); + * board.update(); + * + * </pre><div id="JXG987c-394f-11e6-af4a-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG987c-394f-11e6-af4a-901b0e1b8723', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * var p1, p2, p3, c, a, s; + * + * p1 = board.create('point',[0,0]); + * p2 = board.create('point',[5,0]); + * p3 = board.create('point',[0,5]); + * + * c1 = board.create('circle',[p1, p2]); + * + * a = board.create('angle',[p2, p1, p3], {radius: 3}); + * + * a.setAngle(function() { + * return Math.PI / 3; + * }); + * board.update(); + * + * })(); + * + * </script><pre> + * + * @example + * var p1, p2, p3, c, a, s; + * + * p1 = board.create('point',[0,0]); + * p2 = board.create('point',[5,0]); + * p3 = board.create('point',[0,5]); + * + * c1 = board.create('circle',[p1, p2]); + * + * a = board.create('angle',[p2, p1, p3], {radius:3}); + * s = board.create('slider',[[-2,1], [2,1], [0, Math.PI*0.5, 2*Math.PI]]); + * + * a.setAngle(function() { + * return s.Value(); + * }); + * board.update(); + * + * </pre><div id="JXG99957b1c-394f-11e6-af4a-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG99957b1c-394f-11e6-af4a-901b0e1b8723', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * var p1, p2, p3, c, a, s; + * + * p1 = board.create('point',[0,0]); + * p2 = board.create('point',[5,0]); + * p3 = board.create('point',[0,5]); + * + * c1 = board.create('circle',[p1, p2]); + * + * a = board.create('angle',[p2, p1, p3], {radius: 3}); + * s = board.create('slider',[[-2,1], [2,1], [0, Math.PI*0.5, 2*Math.PI]]); + * + * a.setAngle(function() { + * return s.Value(); + * }); + * board.update(); + * + * })(); + * + * </script><pre> + * + */ + el.setAngle = function (val) { + var t1, t2, val2, + p = this.anglepoint, + q = this.radiuspoint; - // documented in AbstractRenderer - drawInternalText: function (el) { - var node; - node = this.createNode('textbox'); - node.style.position = 'absolute'; - el.rendNodeText = this.container.ownerDocument.createTextNode(''); - node.appendChild(el.rendNodeText); - this.appendChildPrim(node, 9); - node.style.filter = "progid:DXImageTransform.Microsoft.Matrix(M11='1.0', sizingMethod='auto expand', enabled = false) progid:DXImageTransform.Microsoft.Alpha(opacity = 100, enabled = false)"; + if (p.draggable()) { + t1 = this.board.create('transform', [val, this.center], {type: 'rotate'}); + p.addTransform(q, t1); + // Immediately apply the transformation. + // This prevents that jumping elements can be watched. + t1.update(); + p.moveTo(Mat.matVecMult(t1.matrix, q.coords.usrCoords)); + + if (Type.isFunction(val)) { + /** + * @ignore + */ + val2 = function() { return Math.PI * 2 - val(); }; + } else { + /** + * @ignore + */ + val2 = function() { return Math.PI * 2 - val; }; + } + t2 = this.board.create('transform', [val2, this.center], {type: 'rotate'}); + p.coords.on('update', function() { + t2.update(); + q.moveTo(Mat.matVecMult(t2.matrix, p.coords.usrCoords)); + }); - return node; - }, + p.setParents(q); + } + return this; + }; - // documented in AbstractRenderer - updateInternalText: function (el) { - var v, content = el.plaintext, - m = this.joinTransforms(el, el.transformations), - offset = [0, 0], - maxX, maxY, minX, minY, i, - node = el.rendNode, - p = [], - ev_ax = el.getAnchorX(), - ev_ay = el.getAnchorY(); + /** + * Frees an angle from a prescribed value. This is only relevant if the angle size has been set by + * "setAngle()" previously. The anglepoint is set to a free point. + * @name free + * @function + * @returns {Object} Pointer to the angle element.. + * @memberOf Angle.prototype + * @see Angle#setAngle + */ + el.free = function () { + var p = this.anglepoint; - if (!isNaN(el.coords.scrCoords[1] + el.coords.scrCoords[2])) { - // Horizontal - if (ev_ax === 'right') { - offset[0] = 1; - } else if (ev_ax === 'middle') { - offset[0] = 0.5; - } // default (ev_ax === 'left') offset[0] = 0; + if (p.transformations.length > 0) { + p.transformations.pop(); + p.isDraggable = true; + p.parents = []; - // Vertical - if (ev_ay === 'bottom') { - offset[1] = 1; - } else if (ev_ay === 'middle') { - offset[1] = 0.5; - } // default (ev_ay === 'top') offset[1] = 0; + p.coords.off('update'); + } - // Compute maxX, maxY, minX, minY - p[0] = Mat.matVecMult(m, [1, - el.coords.scrCoords[1] - offset[0] * el.size[0], - el.coords.scrCoords[2] + (1 - offset[1]) * el.size[1] + this.vOffsetText]); - p[0][1] /= p[0][0]; - p[0][2] /= p[0][0]; - p[1] = Mat.matVecMult(m, [1, - el.coords.scrCoords[1] + (1 - offset[0]) * el.size[0], - el.coords.scrCoords[2] + (1 - offset[1]) * el.size[1] + this.vOffsetText]); - p[1][1] /= p[1][0]; - p[1][2] /= p[1][0]; - p[2] = Mat.matVecMult(m, [1, - el.coords.scrCoords[1] + (1 - offset[0]) * el.size[0], - el.coords.scrCoords[2] - offset[1] * el.size[1] + this.vOffsetText]); - p[2][1] /= p[2][0]; - p[2][2] /= p[2][0]; - p[3] = Mat.matVecMult(m, [1, - el.coords.scrCoords[1] - offset[0] * el.size[0], - el.coords.scrCoords[2] - offset[1] * el.size[1] + this.vOffsetText]); - p[3][1] /= p[3][0]; - p[3][2] /= p[3][0]; - maxX = p[0][1]; - minX = p[0][1]; - maxY = p[0][2]; - minY = p[0][2]; + return this; + }; - for (i = 1; i < 4; i++) { - maxX = Math.max(maxX, p[i][1]); - minX = Math.min(minX, p[i][1]); - maxY = Math.max(maxY, p[i][2]); - minY = Math.min(minY, p[i][2]); - } + el.setParents(points); // Important: This overwrites the parents order in underlying sector - // Horizontal - v = offset[0] === 1 ? Math.floor(el.board.canvasWidth - maxX) : Math.floor(minX); - if (el.visPropOld.left !== (ev_ax + v)) { - if (offset[0] === 1) { - el.rendNode.style.right = v + 'px'; - el.rendNode.style.left = 'auto'; - } else { - el.rendNode.style.left = v + 'px'; - el.rendNode.style.right = 'auto'; - } - el.visPropOld.left = ev_ax + v; - } + } // end '3points' - // Vertical - v = offset[1] === 1 ? Math.floor(el.board.canvasHeight - maxY) : Math.floor(minY); - if (el.visPropOld.top !== (ev_ay + v)) { - if (offset[1] === 1) { - el.rendNode.style.bottom = v + 'px'; - el.rendNode.style.top = 'auto'; - } else { - el.rendNode.style.top = v + 'px'; - el.rendNode.style.bottom = 'auto'; - } - el.visPropOld.top = ev_ay + v; - } + // GEONExT compatible labels. + if (Type.exists(el.visProp.text)) { + el.label.setText(Type.evaluate(el.visProp.text)); + } - } + el.elType = 'angle'; + el.type = Const.OBJECT_TYPE_ANGLE; + el.subs = {}; - if (el.htmlStr !== content) { - el.rendNodeText.data = content; - el.htmlStr = content; + el.updateDataArraySquare = function () { + var A, B, C, + r = this.Radius(), + d1, d2, + v, l1, l2; + + + if (type === '2lines') { + // This is necessary to update this.point1, this.point2, this.point3. + this.updateDataArraySector(); } - //this.transformImage(el, el.transformations); - node.filters.item(0).M11 = m[1][1]; - node.filters.item(0).M12 = m[1][2]; - node.filters.item(0).M21 = m[2][1]; - node.filters.item(0).M22 = m[2][2]; - node.filters.item(0).enabled = true; - }, + A = this.point2; + B = this.point1; + C = this.point3; - /* ************************** - * Image related stuff - * **************************/ + A = A.coords.usrCoords; + B = B.coords.usrCoords; + C = C.coords.usrCoords; - // already documented in JXG.AbstractRenderer - drawImage: function (el) { - // IE 8: Bilder ueber data URIs werden bis 32kB unterstuetzt. - var node; + d1 = Geometry.distance(A, B, 3); + d2 = Geometry.distance(C, B, 3); - node = this.container.ownerDocument.createElement('img'); - node.style.position = 'absolute'; - this._setAttr(node, 'id', this.container.id + '_' + el.id); + // In case of type=='2lines' this is redundant, because r == d1 == d2 + A = [1, B[1] + (A[1] - B[1]) * r / d1, B[2] + (A[2] - B[2]) * r / d1]; + C = [1, B[1] + (C[1] - B[1]) * r / d2, B[2] + (C[2] - B[2]) * r / d2]; - this.container.appendChild(node); - this.appendChildPrim(node, Type.evaluate(el.visProp.layer)); + v = Mat.crossProduct(C, B); + l1 = [-A[1] * v[1] - A[2] * v[2], A[0] * v[1], A[0] * v[2]]; + v = Mat.crossProduct(A, B); + l2 = [-C[1] * v[1] - C[2] * v[2], C[0] * v[1], C[0] * v[2]]; - // Adding the rotation filter. This is always filter item 0: - // node.filters.item(0), see transformImage - // Also add the alpha filter. This is always filter item 1 - // node.filters.item(1), see setObjectFillColor and setObjectSTrokeColor - //node.style.filter = node.style['-ms-filter'] = "progid:DXImageTransform.Microsoft.Matrix(M11='1.0', sizingMethod='auto expand')"; - node.style.filter = "progid:DXImageTransform.Microsoft.Matrix(M11='1.0', sizingMethod='auto expand') progid:DXImageTransform.Microsoft.Alpha(opacity = 100, enabled = false)"; - el.rendNode = node; - this.updateImage(el); - }, + v = Mat.crossProduct(l1, l2); + v[1] /= v[0]; + v[2] /= v[0]; - // already documented in JXG.AbstractRenderer - transformImage: function (el, t) { - var m, s, maxX, maxY, minX, minY, i, nt, - node = el.rendNode, - p = [], - len = t.length; + this.dataX = [B[1], A[1], v[1], C[1], B[1]]; + this.dataY = [B[2], A[2], v[2], C[2], B[2]]; - if (len > 0) { - /* - nt = el.rendNode.style.filter.toString(); - if (!nt.match(/DXImageTransform/)) { - node.style.filter = "progid:DXImageTransform.Microsoft.Matrix(M11='1.0', sizingMethod='auto expand') " + nt; - } - */ + this.bezierDegree = 1; + }; - m = this.joinTransforms(el, t); - p[0] = Mat.matVecMult(m, el.coords.scrCoords); - p[0][1] /= p[0][0]; - p[0][2] /= p[0][0]; - p[1] = Mat.matVecMult(m, [1, el.coords.scrCoords[1] + el.size[0], el.coords.scrCoords[2]]); - p[1][1] /= p[1][0]; - p[1][2] /= p[1][0]; - p[2] = Mat.matVecMult(m, [1, el.coords.scrCoords[1] + el.size[0], el.coords.scrCoords[2] - el.size[1]]); - p[2][1] /= p[2][0]; - p[2][2] /= p[2][0]; - p[3] = Mat.matVecMult(m, [1, el.coords.scrCoords[1], el.coords.scrCoords[2] - el.size[1]]); - p[3][1] /= p[3][0]; - p[3][2] /= p[3][0]; - maxX = p[0][1]; - minX = p[0][1]; - maxY = p[0][2]; - minY = p[0][2]; + el.updateDataArrayNone = function () { + this.dataX = [NaN]; + this.dataY = [NaN]; + this.bezierDegree = 1; + }; - for (i = 1; i < 4; i++) { - maxX = Math.max(maxX, p[i][1]); - minX = Math.min(minX, p[i][1]); - maxY = Math.max(maxY, p[i][2]); - minY = Math.min(minY, p[i][2]); + el.updateDataArray = function () { + var type = Type.evaluate(this.visProp.type), + deg = Geometry.trueAngle(this.point2, this.point1, this.point3), + vp_s = Type.evaluate(this.visProp.selection); + + if ((vp_s === 'minor' && deg > 180.0) || + (vp_s === 'major' && deg < 180.0)) { + deg = 360.0 - deg; + } + + if (Math.abs(deg - 90.0) < Type.evaluate(this.visProp.orthosensitivity) + Mat.eps) { + type = Type.evaluate(this.visProp.orthotype); + } + + if (type === 'none') { + this.updateDataArrayNone(); + } else if (type === 'square') { + this.updateDataArraySquare(); + } else if (type === 'sector') { + this.updateDataArraySector(); + } else if (type === 'sectordot') { + this.updateDataArraySector(); + if (!this.dot.visProp.visible) { + this.dot.setAttribute({visible: true}); } - node.style.left = Math.floor(minX) + 'px'; - node.style.top = Math.floor(minY) + 'px'; + } - node.filters.item(0).M11 = m[1][1]; - node.filters.item(0).M12 = m[1][2]; - node.filters.item(0).M21 = m[2][1]; - node.filters.item(0).M22 = m[2][2]; - node.filters.item(0).enabled = true; + if (!this.visProp.visible || (type !== 'sectordot' && this.dot.visProp.visible)) { + this.dot.setAttribute({visible: false}); } - }, + }; - // already documented in JXG.AbstractRenderer - updateImageURL: function (el) { - var url = Type.evaluate(el.url); + /** + * Indicates a right angle. Invisible by default, use <tt>dot.visible: true</tt> to show. + * Though this dot indicates a right angle, it can be visible even if the angle is not a right + * one. + * @type JXG.Point + * @name dot + * @memberOf Angle.prototype + */ + attrsub = Type.copyAttributes(attributes, board.options, 'angle', 'dot'); + el.dot = board.create('point', [function () { + var A, B, r, d, a2, co, si, mat, + vp_s; - this._setAttr(el.rendNode, 'src', url); - }, + if (Type.exists(el.dot) && !el.dot.visProp.visible) { + return [0, 0]; + } - /* ************************** - * Render primitive objects - * **************************/ + A = el.point2.coords.usrCoords; + B = el.point1.coords.usrCoords; + r = el.Radius(); + d = Geometry.distance(A, B, 3); + a2 = Geometry.rad(el.point2, el.point1, el.point3); - // already documented in JXG.AbstractRenderer - appendChildPrim: function (node, level) { - // For trace nodes - if (!Type.exists(level)) { - level = 0; + vp_s = Type.evaluate(el.visProp.selection); + if ((vp_s === 'minor' && a2 > Math.PI) || + (vp_s === 'major' && a2 < Math.PI)) { + a2 = -(2 * Math.PI - a2); } + a2 *= 0.5; - node.style.zIndex = level; - this.container.appendChild(node); + co = Math.cos(a2); + si = Math.sin(a2); - return node; - }, + A = [1, B[1] + (A[1] - B[1]) * r / d, B[2] + (A[2] - B[2]) * r / d]; - // already documented in JXG.AbstractRenderer - appendNodesToElement: function (el, type) { - if (type === 'shape' || type === 'path' || type === 'polygon') { - el.rendNodePath = this.getElementById(el.id + '_path'); + mat = [ + [1, 0, 0], + [B[1] - 0.5 * B[1] * co + 0.5 * B[2] * si, co * 0.5, -si * 0.5], + [B[2] - 0.5 * B[1] * si - 0.5 * B[2] * co, si * 0.5, co * 0.5] + ]; + return Mat.matVecMult(mat, A); + }], attrsub); + + el.dot.dump = false; + el.subs.dot = el.dot; + + if (type === '2lines') { + for (i = 0; i < 2; i++) { + board.select(parents[i]).addChild(el.dot); } - el.rendNodeFill = this.getElementById(el.id + '_fill'); - el.rendNodeStroke = this.getElementById(el.id + '_stroke'); - el.rendNodeShadow = this.getElementById(el.id + '_shadow'); - el.rendNode = this.getElementById(el.id); - }, + } else { + for (i = 0; i < 3; i++) { + board.select(points[i]).addChild(el.dot); + } + } - // already documented in JXG.AbstractRenderer - createPrim: function (type, id) { - var node, pathNode, - fillNode = this.createNode('fill'), - strokeNode = this.createNode('stroke'), - shadowNode = this.createNode('shadow'); + // documented in GeometryElement + el.getLabelAnchor = function () { + var vec, dx = 12, + A, B, r, d, a2, co, si, mat, + vp_s = Type.evaluate(el.visProp.selection), + l_vp = this.label ? this.label.visProp : this.visProp.label; - this._setAttr(fillNode, 'id', this.container.id + '_' + id + '_fill'); - this._setAttr(strokeNode, 'id', this.container.id + '_' + id + '_stroke'); - this._setAttr(shadowNode, 'id', this.container.id + '_' + id + '_shadow'); + // If this is uncommented, the angle label can not be dragged + //if (Type.exists(this.label)) { + // this.label.relativeCoords = new Coords(Const.COORDS_BY_SCREEN, [0, 0], this.board); + //} - if (type === 'circle' || type === 'ellipse') { - node = this.createNode('oval'); - node.appendChild(fillNode); - node.appendChild(strokeNode); - node.appendChild(shadowNode); - } else if (type === 'polygon' || type === 'path' || type === 'shape' || type === 'line') { - node = this.createNode('shape'); - node.appendChild(fillNode); - node.appendChild(strokeNode); - node.appendChild(shadowNode); - pathNode = this.createNode('path'); - this._setAttr(pathNode, 'id', this.container.id + '_' + id + '_path'); - node.appendChild(pathNode); - } else { - node = this.createNode(type); - node.appendChild(fillNode); - node.appendChild(strokeNode); - node.appendChild(shadowNode); + if (Type.exists(this.label.visProp.fontSize)) { + dx = Type.evaluate(this.label.visProp.fontSize); } + dx /= this.board.unitX; - node.style.position = 'absolute'; - node.style.left = '0px'; - node.style.top = '0px'; - this._setAttr(node, 'id', this.container.id + '_' + id); + A = el.point2.coords.usrCoords; + B = el.point1.coords.usrCoords; + r = el.Radius(); + d = Geometry.distance(A, B, 3); + a2 = Geometry.rad(el.point2, el.point1, el.point3); + if ((vp_s === 'minor' && a2 > Math.PI) || + (vp_s === 'major' && a2 < Math.PI)) { + a2 = -(2 * Math.PI - a2); + } + a2 *= 0.5; + co = Math.cos(a2); + si = Math.sin(a2); - return node; - }, + A = [1, B[1] + (A[1] - B[1]) * r / d, B[2] + (A[2] - B[2]) * r / d]; - // already documented in JXG.AbstractRenderer - remove: function (node) { - if (Type.exists(node)) { - node.removeNode(true); - } - }, + mat = [ + [1, 0, 0], + [B[1] - 0.5 * B[1] * co + 0.5 * B[2] * si, co * 0.5, -si * 0.5], + [B[2] - 0.5 * B[1] * si - 0.5 * B[2] * co, si * 0.5, co * 0.5] + ]; + vec = Mat.matVecMult(mat, A); + vec[1] /= vec[0]; + vec[2] /= vec[0]; + vec[0] /= vec[0]; - // already documented in JXG.AbstractRenderer - makeArrows: function (el) { - var nodeStroke, - ev_fa = Type.evaluate(el.visProp.firstarrow), - ev_la = Type.evaluate(el.visProp.lastarrow); + d = Geometry.distance(vec, B, 3); + vec = [vec[0], B[1] + (vec[1] - B[1]) * (r + dx) / d, B[2] + (vec[2] - B[2]) * (r + dx) / d]; - if (el.visPropOld.firstarrow === ev_fa && el.visPropOld.lastarrow === ev_la) { - return; - } + l_vp.position = Geometry.calcLabelQuadrant(Geometry.rad([1,0], [0,0], vec)); - if (ev_fa) { - nodeStroke = el.rendNodeStroke; - this._setAttr(nodeStroke, 'startarrow', 'block'); - this._setAttr(nodeStroke, 'startarrowlength', 'long'); - } else { - nodeStroke = el.rendNodeStroke; - if (Type.exists(nodeStroke)) { - this._setAttr(nodeStroke, 'startarrow', 'none'); - } - } + return new Coords(Const.COORDS_BY_USER, vec, this.board); + }; - if (ev_la) { - nodeStroke = el.rendNodeStroke; - this._setAttr(nodeStroke, 'id', this.container.id + '_' + el.id + "stroke"); - this._setAttr(nodeStroke, 'endarrow', 'block'); - this._setAttr(nodeStroke, 'endarrowlength', 'long'); - } else { - nodeStroke = el.rendNodeStroke; - if (Type.exists(nodeStroke)) { - this._setAttr(nodeStroke, 'endarrow', 'none'); - } - } - el.visPropOld.firstarrow = ev_fa; - el.visPropOld.lastarrow = ev_la; - }, + /** + * Returns the value of the angle in Radians. + * @memberOf Angle.prototype + * @name Value + * @function + * @returns {Number} The angle value in Radians + */ + el.Value = function () { + return Geometry.rad(this.point2, this.point1, this.point3); + }; - // already documented in JXG.AbstractRenderer - updateEllipsePrim: function (node, x, y, rx, ry) { - node.style.left = Math.floor(x - rx) + 'px'; - node.style.top = Math.floor(y - ry) + 'px'; - node.style.width = Math.floor(Math.abs(rx) * 2) + 'px'; - node.style.height = Math.floor(Math.abs(ry) * 2) + 'px'; - }, + el.methodMap = Type.deepCopy(el.methodMap, { + Value: 'Value', + setAngle: 'setAngle', + free: 'free' + }); - // already documented in JXG.AbstractRenderer - updateLinePrim: function (node, p1x, p1y, p2x, p2y, board) { - var s, r = this.resolution; + return el; + }; - if (!isNaN(p1x + p1y + p2x + p2y)) { - s = ['m ', Math.floor(r * p1x), ', ', Math.floor(r * p1y), ' l ', Math.floor(r * p2x), ', ', Math.floor(r * p2y)]; - this.updatePathPrim(node, s, board); - } - }, + JXG.registerElement('angle', JXG.createAngle); - // already documented in JXG.AbstractRenderer - updatePathPrim: function (node, pointString, board) { - var x = board.canvasWidth, - y = board.canvasHeight; - if (pointString.length <= 0) { - pointString = ['m 0,0']; - } - node.style.width = x; - node.style.height = y; - this._setAttr(node, 'coordsize', [Math.floor(this.resolution * x), Math.floor(this.resolution * y)].join(',')); - this._setAttr(node, 'path', pointString.join("")); - }, + /** + * @class A non-reflex angle is the acute or obtuse instance of an angle. + * It is defined by a center, one point that + * defines the radius, and a third point that defines the angle of the sector. + * @pseudo + * @name NonReflexAngle + * @augments Angle + * @constructor + * @type Sector + * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 . Minor sector is a sector of a circle around p1 having measure less than or equal to + * 180 degrees (pi radians) and starts at p2. The radius is determined by p2, the angle by p3. + * @example + * // Create a non-reflex angle out of three free points + * var p1 = board.create('point', [5.0, 3.0]), + * p2 = board.create('point', [1.0, 0.5]), + * p3 = board.create('point', [1.5, 5.0]), + * + * a = board.create('nonreflexangle', [p1, p2, p3], {radius: 2}), + * t = board.create('text', [4, 4, function() { return JXG.toFixed(a.Value(), 2); }]); + * </pre><div class="jxgbox" id="JXGd0ab6d6b-63a7-48b2-8749-b02bb5e744f9" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function () { + * var board = JXG.JSXGraph.initBoard('JXGd0ab6d6b-63a7-48b2-8749-b02bb5e744f9', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}), + * p1 = board.create('point', [5.0, 3.0]), + * p2 = board.create('point', [1.0, 0.5]), + * p3 = board.create('point', [1.5, 5.0]), + * + * a = board.create('nonreflexangle', [p1, p2, p3], {radius: 2}), + * t = board.create('text', [4, 4, function() { return JXG.toFixed(a.Value(), 2); }]); + * })(); + * </script><pre> + */ + JXG.createNonreflexAngle = function (board, parents, attributes) { + var el; - // already documented in JXG.AbstractRenderer - updatePathStringPoint: function (el, size, type) { - var s = [], - mround = Math.round, - scr = el.coords.scrCoords, - sqrt32 = size * Math.sqrt(3) * 0.5, - s05 = size * 0.5, - r = this.resolution; + attributes.selection = 'minor'; + el = JXG.createAngle(board, parents, attributes); - if (type === 'x') { - s.push([ - ' m ', mround(r * (scr[1] - size)), ', ', mround(r * (scr[2] - size)), - ' l ', mround(r * (scr[1] + size)), ', ', mround(r * (scr[2] + size)), - ' m ', mround(r * (scr[1] + size)), ', ', mround(r * (scr[2] - size)), - ' l ', mround(r * (scr[1] - size)), ', ', mround(r * (scr[2] + size)) - ].join('')); - } else if (type === '+') { - s.push([ - ' m ', mround(r * (scr[1] - size)), ', ', mround(r * (scr[2])), - ' l ', mround(r * (scr[1] + size)), ', ', mround(r * (scr[2])), - ' m ', mround(r * (scr[1])), ', ', mround(r * (scr[2] - size)), - ' l ', mround(r * (scr[1])), ', ', mround(r * (scr[2] + size)) - ].join('')); - } else if (type === '<>') { + // Documented in createAngle + el.Value = function () { + var v = Geometry.rad(this.point2, this.point1, this.point3); + return (v < Math.PI) ? v : 2.0 * Math.PI - v; + }; + return el; + }; - s.push([ - ' m ', mround(r * (scr[1] - size)), ', ', mround(r * (scr[2])), - ' l ', mround(r * (scr[1])), ', ', mround(r * (scr[2] + size)), - ' l ', mround(r * (scr[1] + size)), ', ', mround(r * (scr[2])), - ' l ', mround(r * (scr[1])), ', ', mround(r * (scr[2] - size)), - ' x e ' - ].join('')); - } else if (type === '^') { - s.push([ - ' m ', mround(r * (scr[1])), ', ', mround(r * (scr[2] - size)), - ' l ', mround(r * (scr[1] - sqrt32)), ', ', mround(r * (scr[2] + s05)), - ' l ', mround(r * (scr[1] + sqrt32)), ', ', mround(r * (scr[2] + s05)), - ' x e ' - ].join('')); - } else if (type === 'v') { - s.push([ - ' m ', mround(r * (scr[1])), ', ', mround(r * (scr[2] + size)), - ' l ', mround(r * (scr[1] - sqrt32)), ', ', mround(r * (scr[2] - s05)), - ' l ', mround(r * (scr[1] + sqrt32)), ', ', mround(r * (scr[2] - s05)), - ' x e ' - ].join('')); - } else if (type === '>') { - s.push([ - ' m ', mround(r * (scr[1] + size)), ', ', mround(r * (scr[2])), - ' l ', mround(r * (scr[1] - s05)), ', ', mround(r * (scr[2] - sqrt32)), - ' l ', mround(r * (scr[1] - s05)), ', ', mround(r * (scr[2] + sqrt32)), - ' l ', mround(r * (scr[1] + size)), ', ', mround(r * (scr[2])) - ].join('')); - } else if (type === '<') { - s.push([ - ' m ', mround(r * (scr[1] - size)), ', ', mround(r * (scr[2])), - ' l ', mround(r * (scr[1] + s05)), ', ', mround(r * (scr[2] - sqrt32)), - ' l ', mround(r * (scr[1] + s05)), ', ', mround(r * (scr[2] + sqrt32)), - ' x e ' - ].join('')); - } + JXG.registerElement('nonreflexangle', JXG.createNonreflexAngle); + + /** + * @class A reflex angle is the neither acute nor obtuse instance of an angle. + * It is defined by a center, one point that + * defines the radius, and a third point that defines the angle of the sector. + * @pseudo + * @name ReflexAngle + * @augments Angle + * @constructor + * @type Sector + * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 . Minor sector is a sector of a circle around p1 having measure less than or equal to + * 180 degrees (pi radians) and starts at p2. The radius is determined by p2, the angle by p3. + * @example + * // Create a non-reflex angle out of three free points + * var p1 = board.create('point', [5.0, 3.0]), + * p2 = board.create('point', [1.0, 0.5]), + * p3 = board.create('point', [1.5, 5.0]), + * + * a = board.create('reflexangle', [p1, p2, p3], {radius: 2}), + * t = board.create('text', [4, 4, function() { return JXG.toFixed(a.Value(), 2); }]); + * </pre><div class="jxgbox" id="JXGf2a577f2-553d-4f9f-a895-2d6d4b8c60e8" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function () { + * var board = JXG.JSXGraph.initBoard('JXGf2a577f2-553d-4f9f-a895-2d6d4b8c60e8', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}), + * p1 = board.create('point', [5.0, 3.0]), + * p2 = board.create('point', [1.0, 0.5]), + * p3 = board.create('point', [1.5, 5.0]), + * + * a = board.create('reflexangle', [p1, p2, p3], {radius: 2}), + * t = board.create('text', [4, 4, function() { return JXG.toFixed(a.Value(), 2); }]); + * })(); + * </script><pre> + */ + JXG.createReflexAngle = function (board, parents, attributes) { + var el; + + attributes.selection = 'major'; + el = JXG.createAngle(board, parents, attributes); + + // Documented in createAngle + el.Value = function () { + var v = Geometry.rad(this.point2, this.point1, this.point3); + return (v >= Math.PI) ? v : 2.0 * Math.PI - v; + }; + return el; + }; + + JXG.registerElement('reflexangle', JXG.createReflexAngle); - return s; - }, + return { + createSector: JXG.createSector, + createCircumcircleSector: JXG.createCircumcircleSector, + createMinorSector: JXG.createMinorSector, + createMajorSector: JXG.createMajorSector, + createAngle: JXG.createAngle, + createReflexAngle: JXG.createReflexAngle, + createNonreflexAngle: JXG.createNonreflexAngle + }; +}); - // already documented in JXG.AbstractRenderer - updatePathStringPrim: function (el) { - var i, scr, - pStr = [], - r = this.resolution, - mround = Math.round, - symbm = ' m ', - symbl = ' l ', - symbc = ' c ', - nextSymb = symbm, - len = Math.min(el.numberPoints, 8192); // otherwise IE 7 crashes in hilbert.html +/* + Copyright 2008-2022 + Matthias Ehmann, + Michael Gerhaeuser, + Carsten Miller, + Bianca Valentin, + Alfred Wassermann, + Peter Wilfahrt - if (el.numberPoints <= 0) { - return ''; - } - len = Math.min(len, el.points.length); + This file is part of JSXGraph. - if (el.bezierDegree === 1) { - /* - if (isNotPlot && el.board.options.curve.RDPsmoothing) { - el.points = Numerics.RamerDouglasPeucker(el.points, 1.0); - } - */ + JSXGraph is free software dual licensed under the GNU LGPL or MIT License. - for (i = 0; i < len; i++) { - scr = el.points[i].scrCoords; - if (isNaN(scr[1]) || isNaN(scr[2])) { // PenUp - nextSymb = symbm; - } else { - // IE has problems with values being too far away. - if (scr[1] > 20000.0) { - scr[1] = 20000.0; - } else if (scr[1] < -20000.0) { - scr[1] = -20000.0; - } + You can redistribute it and/or modify it under the terms of the - if (scr[2] > 20000.0) { - scr[2] = 20000.0; - } else if (scr[2] < -20000.0) { - scr[2] = -20000.0; - } + * GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version + OR + * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT - pStr.push([nextSymb, mround(r * scr[1]), ', ', mround(r * scr[2])].join('')); - nextSymb = symbl; - } - } - } else if (el.bezierDegree === 3) { - i = 0; - while (i < len) { - scr = el.points[i].scrCoords; - if (isNaN(scr[1]) || isNaN(scr[2])) { // PenUp - nextSymb = symbm; - } else { - pStr.push([nextSymb, mround(r * scr[1]), ', ', mround(r * scr[2])].join('')); - if (nextSymb === symbc) { - i += 1; - scr = el.points[i].scrCoords; - pStr.push([' ', mround(r * scr[1]), ', ', mround(r * scr[2])].join('')); - i += 1; - scr = el.points[i].scrCoords; - pStr.push([' ', mround(r * scr[1]), ', ', mround(r * scr[2])].join('')); - } - nextSymb = symbc; - } - i += 1; - } - } - pStr.push(' e'); - return pStr; - }, + JSXGraph is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. - // already documented in JXG.AbstractRenderer - updatePathStringBezierPrim: function (el) { - var i, j, k, scr, lx, ly, - pStr = [], - f = Type.evaluate(el.visProp.strokewidth), - r = this.resolution, - mround = Math.round, - symbm = ' m ', - symbl = ' c ', - nextSymb = symbm, - isNoPlot = (Type.evaluate(el.visProp.curvetype) !== 'plot'), - len = Math.min(el.numberPoints, 8192); // otherwise IE 7 crashes in hilbert.html + You should have received a copy of the GNU Lesser General Public License and + the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> + and <http://opensource.org/licenses/MIT/>. + */ - if (el.numberPoints <= 0) { - return ''; - } - if (isNoPlot && el.board.options.curve.RDPsmoothing) { - el.points = Numerics.RamerDouglasPeucker(el.points, 1.0); - } - len = Math.min(len, el.points.length); - for (j = 1; j < 3; j++) { - nextSymb = symbm; - for (i = 0; i < len; i++) { - scr = el.points[i].scrCoords; - if (isNaN(scr[1]) || isNaN(scr[2])) { // PenUp - nextSymb = symbm; - } else { - // IE has problems with values being too far away. - if (scr[1] > 20000.0) { - scr[1] = 20000.0; - } else if (scr[1] < -20000.0) { - scr[1] = -20000.0; - } +/*global JXG: true, define: true*/ +/*jslint nomen: true, plusplus: true*/ - if (scr[2] > 20000.0) { - scr[2] = 20000.0; - } else if (scr[2] < -20000.0) { - scr[2] = -20000.0; - } +/*depends: + jxg + base/constants + math/math + utils/type + */ - if (nextSymb === symbm) { - pStr.push([nextSymb, - mround(r * (scr[1])), ' ', mround(r * (scr[2]))].join('')); - } else { - k = 2 * j; - pStr.push([nextSymb, - mround(r * (lx + (scr[1] - lx) * 0.333 + f * (k * Math.random() - j))), ' ', - mround(r * (ly + (scr[2] - ly) * 0.333 + f * (k * Math.random() - j))), ' ', - mround(r * (lx + (scr[1] - lx) * 0.666 + f * (k * Math.random() - j))), ' ', - mround(r * (ly + (scr[2] - ly) * 0.666 + f * (k * Math.random() - j))), ' ', - mround(r * scr[1]), ' ', - mround(r * scr[2])].join('')); - } - nextSymb = symbl; - lx = scr[1]; - ly = scr[2]; - } - } - } - pStr.push(' e'); - return pStr; - }, +/** + * @fileoverview This file contains code for transformations of geometrical objects. + */ - // already documented in JXG.AbstractRenderer - updatePolygonPrim: function (node, el) { - var i, - len = el.vertices.length, - r = this.resolution, - scr, - pStr = []; +define('base/transformation',[ + 'jxg', 'base/constants', 'math/math', 'utils/type' +], function (JXG, Const, Mat, Type) { - this._setAttr(node, 'stroked', 'false'); - scr = el.vertices[0].coords.scrCoords; + "use strict"; - if (isNaN(scr[1] + scr[2])) { - return; - } + /** + * A transformation consists of a 3x3 matrix, i.e. it is a projective transformation. + * @class Creates a new transformation object. Do not use this constructor to create a transformation. + * Use {@link JXG.Board#create} with + * type {@link Transformation} instead. + * @constructor + * @param {JXG.Board} board The board the new circle is drawn on. + * @param {String} type Can be + * <ul><li> 'translate' + * <li> 'scale' + * <li> 'reflect' + * <li> 'rotate' + * <li> 'shear' + * <li> 'generic' + * </ul> + * @param {Object} params The parameters depend on the transformation type + * + * <p> + * Translation matrix: + * <pre> + * ( 1 0 0) ( z ) + * ( a 1 0) * ( x ) + * ( b 0 1) ( y ) + * </pre> + * + * <p> + * Scale matrix: + * <pre> + * ( 1 0 0) ( z ) + * ( 0 a 0) * ( x ) + * ( 0 0 b) ( y ) + * </pre> + * + * <p> + * A rotation matrix with angle a (in Radians) + * <pre> + * ( 1 0 0 ) ( z ) + * ( 0 cos(a) -sin(a)) * ( x ) + * ( 0 sin(a) cos(a) ) ( y ) + * </pre> + * + * <p> + * Shear matrix: + * <pre> + * ( 1 0 0) ( z ) + * ( 0 1 a) * ( x ) + * ( 0 b 1) ( y ) + * </pre> + * + * <p>Generic transformation: + * <pre> + * ( a b c ) ( z ) + * ( d e f ) * ( x ) + * ( g h i ) ( y ) + * </pre> + * + */ + JXG.Transformation = function (board, type, params) { + this.elementClass = Const.OBJECT_CLASS_OTHER; + this.type = Const.OBJECT_TYPE_TRANSFORMATION; + this.matrix = [ + [1, 0, 0], + [0, 1, 0], + [0, 0, 1] + ]; + this.board = board; + this.isNumericMatrix = false; + this.setMatrix(board, type, params); - pStr.push(["m ", Math.floor(r * scr[1]), ",", Math.floor(r * scr[2]), " l "].join('')); + this.methodMap = { + apply: 'apply', + applyOnce: 'applyOnce', + bindTo: 'bindTo', + bind: 'bindTo', + melt: 'melt' + }; + }; - for (i = 1; i < len - 1; i++) { - if (el.vertices[i].isReal) { - scr = el.vertices[i].coords.scrCoords; + JXG.Transformation.prototype = {}; - if (isNaN(scr[1] + scr[2])) { - return; - } + JXG.extend(JXG.Transformation.prototype, /** @lends JXG.Transformation.prototype */ { + /** + * Updates the numerical data for the transformation, i.e. the entry of the subobject matrix. + * @returns {JXG.Transform} returns pointer to itself + */ + update: function () { + return this; + }, - pStr.push(Math.floor(r * scr[1]) + "," + Math.floor(r * scr[2])); - } else { - this.updatePathPrim(node, '', el.board); - return; - } - if (i < len - 2) { - pStr.push(", "); + /** + * Set the transformation matrix for different types of standard transforms. + * @param {JXG.Board} board + * @param {String} type Transformation type, possible values are + * 'translate', 'scale', 'reflect', 'rotate', + * 'shear', 'generic'. + * @param {Array} params Parameters for the various transformation types. + * + * <p>These are + * @param {Array} x,y Shift vector (number or function) in case of 'translate'. + * @param {Array} scale_x,scale_y Scale vector (number or function) in case of 'scale'. + * @param {Array} line|point_pair|"four coordinates" In case of 'reflect' the parameters could + * be a line, a pair of points or four number (or functions) p_x, p_y, q_x, q_y, + * determining a line through points (p_x, p_y) and (q_x, q_y). + * @param {Array} angle,x,y|angle,[x,y] In case of 'rotate' the parameters are an angle or angle function, + * returning the angle in Radians and - optionally - a coordinate pair or a point defining the + * rotation center. If the rotation center is not given, the transformation rotates around (0,0). + * @param {Array} shear_x,shear_y Shear vector (number or function) in case of 'shear'. + * @param {Array} a,b,c,d,e,f,g,h,i Nine matrix entries (numbers or functions) for a generic + * projective transformation in case of 'generic'. + * + * <p>A transformation with a generic matrix looks like: + * <pre> + * ( a b c ) ( z ) + * ( d e f ) * ( x ) + * ( g h i ) ( y ) + * </pre> + * + */ + setMatrix: function (board, type, params) { + var i; + + this.isNumericMatrix = true; + + for (i = 0; i < params.length; i++) { + if (typeof params[i] !== 'number') { + this.isNumericMatrix = false; + break; } } - pStr.push(" x e"); - this.updatePathPrim(node, pStr, el.board); - }, - // already documented in JXG.AbstractRenderer - updateRectPrim: function (node, x, y, w, h) { - node.style.left = Math.floor(x) + 'px'; - node.style.top = Math.floor(y) + 'px'; + if (type === 'translate') { + if (params.length !== 2) { + throw new Error("JSXGraph: translate transformation needs 2 parameters."); + } + this.evalParam = Type.createEvalFunction(board, params, 2); + this.update = function () { + this.matrix[1][0] = this.evalParam(0); + this.matrix[2][0] = this.evalParam(1); + }; + } else if (type === 'scale') { + if (params.length !== 2) { + throw new Error("JSXGraph: scale transformation needs 2 parameters."); + } + this.evalParam = Type.createEvalFunction(board, params, 2); + this.update = function () { + this.matrix[1][1] = this.evalParam(0); // x + this.matrix[2][2] = this.evalParam(1); // y + }; + // Input: line or two points + } else if (type === 'reflect') { + // line or two points + if (params.length < 4) { + params[0] = board.select(params[0]); + } - if (w >= 0) { - node.style.width = w + 'px'; - } + // two points + if (params.length === 2) { + params[1] = board.select(params[1]); + } - if (h >= 0) { - node.style.height = h + 'px'; - } - }, + // 4 coordinates [px,py,qx,qy] + if (params.length === 4) { + this.evalParam = Type.createEvalFunction(board, params, 4); + } - /* ************************** - * Set Attributes - * **************************/ + this.update = function () { + var x, y, z, xoff, yoff, d, + v, p; + // Determine homogeneous coordinates of reflections axis + // line + if (params.length === 1) { + v = params[0].stdform; + // two points + } else if (params.length === 2) { + v = Mat.crossProduct(params[1].coords.usrCoords, params[0].coords.usrCoords); + // two points coordinates [px,py,qx,qy] + } else if (params.length === 4) { + v = Mat.crossProduct( + [1, this.evalParam(2), this.evalParam(3)], + [1, this.evalParam(0), this.evalParam(1)] + ); + } - // already documented in JXG.AbstractRenderer - setPropertyPrim: function (node, key, val) { - var keyVml = '', - v; + // Project origin to the line. This gives a finite point p + x = v[1]; + y = v[2]; + z = v[0]; + p = [-z * x, -z * y, x * x + y * y]; + d = p[2]; - switch (key) { - case 'stroke': - keyVml = 'strokecolor'; - break; - case 'stroke-width': - keyVml = 'strokeweight'; - break; - case 'stroke-dasharray': - keyVml = 'dashstyle'; - break; - } + // Normalize p + xoff = p[0] / p[2]; + yoff = p[1] / p[2]; - if (keyVml !== '') { - v = Type.evaluate(val); - this._setAttr(node, keyVml, v); - } - }, + // x, y is the direction of the line + x = -v[2]; + y = v[1]; - // already documented in JXG.AbstractRenderer - display: function(el, val) { - if (el && el.rendNode) { - el.visPropOld.visible = val; - if (val) { - el.rendNode.style.visibility = "inherit"; - } else { - el.rendNode.style.visibility = "hidden"; + this.matrix[1][1] = (x * x - y * y) / d; + this.matrix[1][2] = 2 * x * y / d; + this.matrix[2][1] = this.matrix[1][2]; + this.matrix[2][2] = -this.matrix[1][1]; + this.matrix[1][0] = xoff * (1 - this.matrix[1][1]) - yoff * this.matrix[1][2]; + this.matrix[2][0] = yoff * (1 - this.matrix[2][2]) - xoff * this.matrix[2][1]; + }; + } else if (type === 'rotate') { + // angle, x, y + if (params.length === 3) { + this.evalParam = Type.createEvalFunction(board, params, 3); + // angle, p or angle + } else if (params.length > 0 && params.length <= 2) { + this.evalParam = Type.createEvalFunction(board, params, 1); + + if (params.length === 2 && !Type.isArray(params[1])) { + params[1] = board.select(params[1]); + } } - } - }, - // already documented in JXG.AbstractRenderer - show: function (el) { - JXG.deprecated('Board.renderer.show()', 'Board.renderer.display()'); + this.update = function () { + var x, y, + beta = this.evalParam(0), + co = Math.cos(beta), + si = Math.sin(beta); - if (el && el.rendNode) { - el.rendNode.style.visibility = "inherit"; - } - }, + this.matrix[1][1] = co; + this.matrix[1][2] = -si; + this.matrix[2][1] = si; + this.matrix[2][2] = co; - // already documented in JXG.AbstractRenderer - hide: function (el) { - JXG.deprecated('Board.renderer.hide()', 'Board.renderer.display()'); + // rotate around [x,y] otherwise rotate around [0,0] + if (params.length > 1) { + if (params.length === 3) { + x = this.evalParam(1); + y = this.evalParam(2); + } else { + if (Type.isArray(params[1])) { + x = params[1][0]; + y = params[1][1]; + } else { + x = params[1].X(); + y = params[1].Y(); + } + } + this.matrix[1][0] = x * (1 - co) + y * si; + this.matrix[2][0] = y * (1 - co) - x * si; + } + }; + } else if (type === 'shear') { + if (params.length !== 2) { + throw new Error("JSXGraph: shear transformation needs 2 parameters."); + } - if (el && el.rendNode) { - el.rendNode.style.visibility = "hidden"; + this.evalParam = Type.createEvalFunction(board, params, 2); + this.update = function () { + this.matrix[1][2] = this.evalParam(0); + this.matrix[2][1] = this.evalParam(1); + }; + } else if (type === 'generic') { + if (params.length !== 9) { + throw new Error("JSXGraph: generic transformation needs 9 parameters."); + } + + this.evalParam = Type.createEvalFunction(board, params, 9); + + this.update = function () { + this.matrix[0][0] = this.evalParam(0); + this.matrix[0][1] = this.evalParam(1); + this.matrix[0][2] = this.evalParam(2); + this.matrix[1][0] = this.evalParam(3); + this.matrix[1][1] = this.evalParam(4); + this.matrix[1][2] = this.evalParam(5); + this.matrix[2][0] = this.evalParam(6); + this.matrix[2][1] = this.evalParam(7); + this.matrix[2][2] = this.evalParam(8); + }; } }, - // already documented in JXG.AbstractRenderer - setDashStyle: function (el, visProp) { - var node; - if (visProp.dash >= 0) { - node = el.rendNodeStroke; - this._setAttr(node, 'dashstyle', this.dashArray[visProp.dash]); + /** + * Transform a GeometryElement: + * First, the transformation matrix is updated, then do the matrix-vector-multiplication. + * @private + * @param {JXG.GeometryElement} p element which is transformed + * @param {String} 'self' Apply the transformation to the initialCoords instead of the coords if this is set. + * @returns {Array} + */ + apply: function (p, self) { + this.update(); + + if (Type.exists(self)) { + return Mat.matVecMult(this.matrix, p.initialCoords.usrCoords); } + return Mat.matVecMult(this.matrix, p.coords.usrCoords); }, - // already documented in JXG.AbstractRenderer - setGradient: function (el) { - var nodeFill = el.rendNodeFill, - ev_g = Type.evaluate(el.visProp.gradient); + /** + * Applies a transformation once to a GeometryElement or an array of elements. + * If it is a free point, then it can be dragged around later + * and will overwrite the transformed coordinates. + * @param {JXG.Point,Array} p + */ + applyOnce: function (p) { + var c, len, i; - if (ev_g === 'linear') { - this._setAttr(nodeFill, 'type', 'gradient'); - this._setAttr(nodeFill, 'color2', Type.evaluate(el.visProp.gradientsecondcolor)); - this._setAttr(nodeFill, 'opacity2', Type.evaluate(el.visProp.gradientsecondopacity)); - this._setAttr(nodeFill, 'angle', Type.evaluate(el.visProp.gradientangle)); - } else if (ev_g === 'radial') { - this._setAttr(nodeFill, 'type', 'gradientradial'); - this._setAttr(nodeFill, 'color2', Type.evaluate(el.visProp.gradientsecondcolor)); - this._setAttr(nodeFill, 'opacity2', Type.evaluate(el.visProp.gradientsecondopacity)); - this._setAttr(nodeFill, 'focusposition', Type.evaluate(el.visProp.gradientpositionx) * 100 + '%,' + - Type.evaluate(el.visProp.gradientpositiony) * 100 + '%'); - this._setAttr(nodeFill, 'focussize', '0,0'); - } else { - this._setAttr(nodeFill, 'type', 'solid'); + if (!Type.isArray(p)) { + p = [p]; } - }, - // already documented in JXG.AbstractRenderer - setObjectFillColor: function (el, color, opacity) { - var rgba = Type.evaluate(color), c, rgbo, - o = Type.evaluate(opacity), oo, - node = el.rendNode, - t; - - o = (o > 0) ? o : 0; + len = p.length; - if (el.visPropOld.fillcolor === rgba && el.visPropOld.fillopacity === o) { - return; + for (i = 0; i < len; i++) { + this.update(); + c = Mat.matVecMult(this.matrix, p[i].coords.usrCoords); + p[i].coords.setCoordinates(Const.COORDS_BY_USER, c); } + }, - if (Type.exists(rgba) && rgba !== false) { - // RGB, not RGBA - if (rgba.length !== 9) { - c = rgba; - oo = o; - // True RGBA, not RGB - } else { - rgbo = Color.rgba2rgbo(rgba); - c = rgbo[0]; - oo = o * rgbo[1]; - } - if (c === 'none' || c === false) { - this._setAttr(el.rendNode, 'filled', 'false'); - } else { - this._setAttr(el.rendNode, 'filled', 'true'); - this._setAttr(el.rendNode, 'fillcolor', c); + /** + * Binds a transformation to a GeometryElement or an array of elements. In every update of the + * GeometryElement(s), the transformation is executed. That means, in order to immediately + * apply the transformation, a call of board.update() has to follow. + * @param {Array,JXG.Object} p JXG.Object or array of JXG.Object to + * which the transformation is bound to. + */ + bindTo: function (p) { + var i, len; + if (Type.isArray(p)) { + len = p.length; - if (Type.exists(oo) && el.rendNodeFill) { - this._setAttr(el.rendNodeFill, 'opacity', (oo * 100) + '%'); - } - } - if (el.type === Const.OBJECT_TYPE_IMAGE) { - /* - t = el.rendNode.style.filter.toString(); - if (t.match(/alpha/)) { - el.rendNode.style.filter = t.replace(/alpha\(opacity *= *[0-9\.]+\)/, 'alpha(opacity = ' + (oo * 100) + ')'); - } else { - el.rendNode.style.filter += ' alpha(opacity = ' + (oo * 100) + ')'; - } - */ - if (node.filters.length > 1) { - // Why am I sometimes seeing node.filters.length==0 here when I move the pointer around near [0,0]? - // Setting axes:true shows text labels! - node.filters.item(1).opacity = Math.round(oo * 100); // Why does setObjectFillColor not use Math.round? - node.filters.item(1).enabled = true; - } + for (i = 0; i < len; i++) { + p[i].transformations.push(this); } + } else { + p.transformations.push(this); } - el.visPropOld.fillcolor = rgba; - el.visPropOld.fillopacity = o; }, - // already documented in JXG.AbstractRenderer - setObjectStrokeColor: function (el, color, opacity) { - var rgba = Type.evaluate(color), c, rgbo, t, - o = Type.evaluate(opacity), oo, - node = el.rendNode, nodeStroke; + /** + * Unused + * @deprecated Use setAttribute + * @param term + */ + setProperty: function (term) { + JXG.deprecated('Transformation.setProperty()', 'Transformation.setAttribute()'); + }, - o = (o > 0) ? o : 0; + /** + * Empty method. Unused. + * @param {Object} term Key-value pairs of the attributes. + */ + setAttribute: function (term) { }, - if (el.visPropOld.strokecolor === rgba && el.visPropOld.strokeopacity === o) { - return; - } + /** + * Combine two transformations to one transformation. This only works if + * both of transformation matrices consist solely of numbers, and do not + * contain functions. + * + * Multiplies the transformation with a transformation t from the left. + * i.e. (this) = (t) join (this) + * @param {JXG.Transform} t Transformation which is the left multiplicand + * @returns {JXG.Transform} the transformation object. + */ + melt: function (t) { + var res = [], i, len, len0, k, s, j; - // this looks like it could be merged with parts of VMLRenderer.setObjectFillColor + len = t.matrix.length; + len0 = this.matrix[0].length; - if (Type.exists(rgba) && rgba !== false) { - // RGB, not RGBA - if (rgba.length !== 9) { - c = rgba; - oo = o; - // True RGBA, not RGB - } else { - rgbo = color.rgba2rgbo(rgba); - c = rgbo[0]; - oo = o * rgbo[1]; - } - if (el.elementClass === Const.OBJECT_CLASS_TEXT) { - //node.style.filter = ' alpha(opacity = ' + oo + ')'; - /* - t = node.style.filter.toString(); - if (t.match(/alpha/)) { - node.style.filter = - t.replace(/alpha\(opacity *= *[0-9\.]+\)/, 'alpha(opacity = ' + oo + ')'); - } else { - node.style.filter += ' alpha(opacity = ' + oo + ')'; - } - */ - if (node.filters.length > 1) { - // Why am I sometimes seeing node.filters.length==0 here when I move the pointer around near [0,0]? - // Setting axes:true shows text labels! - node.filters.item(1).opacity = Math.round(oo * 100); - node.filters.item(1).enabled = true; - } + for (i = 0; i < len; i++) { + res[i] = []; + } - node.style.color = c; - } else { - if (c !== false) { - this._setAttr(node, 'stroked', 'true'); - this._setAttr(node, 'strokecolor', c); - } + this.update(); + t.update(); - nodeStroke = el.rendNodeStroke; - if (Type.exists(oo) && el.type !== Const.OBJECT_TYPE_IMAGE) { - this._setAttr(nodeStroke, 'opacity', (oo * 100) + '%'); + for (i = 0; i < len; i++) { + for (j = 0; j < len0; j++) { + s = 0; + for (k = 0; k < len; k++) { + s += t.matrix[i][k] * this.matrix[k][j]; } + res[i][j] = s; } } - el.visPropOld.strokecolor = rgba; - el.visPropOld.strokeopacity = o; - }, - - // already documented in JXG.AbstractRenderer - setObjectStrokeWidth: function (el, width) { - var w = Type.evaluate(width), - node; - - if (isNaN(w) || el.visPropOld.strokewidth === w) { - return; - } - - node = el.rendNode; - this.setPropertyPrim(node, 'stroked', 'true'); - if (Type.exists(w)) { + this.update = function () { + var len = this.matrix.length, + len0 = this.matrix[0].length; - this.setPropertyPrim(node, 'stroke-width', w); - if (w === 0 && Type.exists(el.rendNodeStroke)) { - this._setAttr(node, 'stroked', 'false'); + for (i = 0; i < len; i++) { + for (j = 0; j < len0; j++) { + this.matrix[i][j] = res[i][j]; + } } - } - - el.visPropOld.strokewidth = w; - + }; + return this; }, - // already documented in JXG.AbstractRenderer - setShadow: function (el) { - var nodeShadow = el.rendNodeShadow, - ev_s = Type.evaluate(el.visProp.shadow); - - if (!nodeShadow || el.visPropOld.shadow === ev_s) { - return; - } + // documented in element.js + // Not yet, since transformations are not listed in board.objects. + getParents: function () { + var p = [[].concat.apply([], this.matrix)]; - if (ev_s) { - this._setAttr(nodeShadow, 'On', 'True'); - this._setAttr(nodeShadow, 'Offset', '3pt,3pt'); - this._setAttr(nodeShadow, 'Opacity', '60%'); - this._setAttr(nodeShadow, 'Color', '#aaaaaa'); - } else { - this._setAttr(nodeShadow, 'On', 'False'); + if (this.parents.length !== 0) { + p = this.parents; } - el.visPropOld.shadow = ev_s; - }, + return p; + } - /* ************************** - * renderer control - * **************************/ + }); - // already documented in JXG.AbstractRenderer - suspendRedraw: function () { - this.container.style.display = 'none'; - }, + /** + * @class This element is used to provide projective transformations. + * @pseudo + * @description A transformation consists of a 3x3 matrix, i.e. it is a projective transformation. + * @name Transformation + * @augments JXG.Transformation + * @constructor + * @type JXG.Transformation + * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {numbers,functions} parameters The parameters depend on the transformation type, supplied as attribute 'type'. + * Possible transformation types are + * <ul><li> 'translate' + * <li> 'scale' + * <li> 'reflect' + * <li> 'rotate' + * <li> 'shear' + * <li> 'generic' + * </ul> + * The transformation matrix then looks like: + * <p> + * Translation matrix: + * <pre> + * ( 1 0 0) ( z ) + * ( a 1 0) * ( x ) + * ( b 0 1) ( y ) + * </pre> + * + * <p> + * Scale matrix: + * <pre> + * ( 1 0 0) ( z ) + * ( 0 a 0) * ( x ) + * ( 0 0 b) ( y ) + * </pre> + * + * <p> + * A rotation matrix with angle a (in Radians) + * <pre> + * ( 1 0 0 ) ( z ) + * ( 0 cos(a) -sin(a)) * ( x ) + * ( 0 sin(a) cos(a) ) ( y ) + * </pre> + * + * <p> + * Shear matrix: + * <pre> + * ( 1 0 0) ( z ) + * ( 0 1 a) * ( x ) + * ( 0 b 1) ( y ) + * </pre> + * + * <p>Generic transformation: + * <pre> + * ( a b c ) ( z ) + * ( d e f ) * ( x ) + * ( g h i ) ( y ) + * </pre> + * + * @see JXG.Transformation#setMatrix + * + * @example + * // The point B is determined by taking twice the vector A from the origin + * + * var p0 = board.create('point', [0, 3], {name: 'A'}), + * t = board.create('transform', [function(){ return p0.X(); }, "Y(A)"], {type: 'translate'}), + * p1 = board.create('point', [p0, t], {color: 'blue'}); + * + * </pre><div class="jxgbox" id="JXG14167b0c-2ad3-11e5-8dd9-901b0e1b8723" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG14167b0c-2ad3-11e5-8dd9-901b0e1b8723', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * var p0 = board.create('point', [0, 3], {name: 'A'}), + * t = board.create('transform', [function(){ return p0.X(); }, "Y(A)"], {type:'translate'}), + * p1 = board.create('point', [p0, t], {color: 'blue'}); + * + * })(); + * + * </script><pre> + * + * @example + * // The point B is the result of scaling the point A with factor 2 in horizontal direction + * // and with factor 0.5 in vertical direction. + * + * var p1 = board.create('point', [1, 1]), + * t = board.create('transform', [2, 0.5], {type: 'scale'}), + * p2 = board.create('point', [p1, t], {color: 'blue'}); + * + * </pre><div class="jxgbox" id="JXGa6827a72-2ad3-11e5-8dd9-901b0e1b8723" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXGa6827a72-2ad3-11e5-8dd9-901b0e1b8723', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * var p1 = board.create('point', [1, 1]), + * t = board.create('transform', [2, 0.5], {type: 'scale'}), + * p2 = board.create('point', [p1, t], {color: 'blue'}); + * + * })(); + * + * </script><pre> + * + * @example + * // The point B is rotated around C which gives point D. The angle is determined + * // by the vertical height of point A. + * + * var p0 = board.create('point', [0, 3], {name: 'A'}), + * p1 = board.create('point', [1, 1]), + * p2 = board.create('point', [2, 1], {name:'C', fixed: true}), + * + * // angle, rotation center: + * t = board.create('transform', ['Y(A)', p2], {type: 'rotate'}), + * p3 = board.create('point', [p1, t], {color: 'blue'}); + * + * </pre><div class="jxgbox" id="JXG747cf11e-2ad4-11e5-8dd9-901b0e1b8723" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG747cf11e-2ad4-11e5-8dd9-901b0e1b8723', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * var p0 = board.create('point', [0, 3], {name: 'A'}), + * p1 = board.create('point', [1, 1]), + * p2 = board.create('point', [2, 1], {name:'C', fixed: true}), + * + * // angle, rotation center: + * t = board.create('transform', ['Y(A)', p2], {type: 'rotate'}), + * p3 = board.create('point', [p1, t], {color: 'blue'}); + * + * })(); + * + * </script><pre> + * + * @example + * // A concatenation of several transformations. + * var p1 = board.create('point', [1, 1]), + * t1 = board.create('transform', [-2, -1], {type: 'translate'}), + * t2 = board.create('transform', [Math.PI/4], {type: 'rotate'}), + * t3 = board.create('transform', [2, 1], {type: 'translate'}), + * p2 = board.create('point', [p1, [t1, t2, t3]], {color: 'blue'}); + * + * </pre><div class="jxgbox" id="JXGf516d3de-2ad5-11e5-8dd9-901b0e1b8723" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXGf516d3de-2ad5-11e5-8dd9-901b0e1b8723', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * var p1 = board.create('point', [1, 1]), + * t1 = board.create('transform', [-2, -1], {type:'translate'}), + * t2 = board.create('transform', [Math.PI/4], {type:'rotate'}), + * t3 = board.create('transform', [2, 1], {type:'translate'}), + * p2 = board.create('point', [p1, [t1, t2, t3]], {color: 'blue'}); + * + * })(); + * + * </script><pre> + * + * @example + * // Reflection of point A + * var p1 = board.create('point', [1, 1]), + * p2 = board.create('point', [1, 3]), + * p3 = board.create('point', [-2, 0]), + * l = board.create('line', [p2, p3]), + * t = board.create('transform', [l], {type: 'reflect'}), // Possible are l, l.id, l.name + * p4 = board.create('point', [p1, t], {color: 'blue'}); + * + * </pre><div class="jxgbox" id="JXG6f374a04-2ad6-11e5-8dd9-901b0e1b8723" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG6f374a04-2ad6-11e5-8dd9-901b0e1b8723', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * var p1 = board.create('point', [1, 1]), + * p2 = board.create('point', [1, 3]), + * p3 = board.create('point', [-2, 0]), + * l = board.create('line', [p2, p3]), + * t = board.create('transform', [l], {type:'reflect'}), // Possible are l, l.id, l.name + * p4 = board.create('point', [p1, t], {color: 'blue'}); + * + * })(); + * + * </script><pre> + * + * @example + * // One time application of a transform to points A, B + * var p1 = board.create('point', [1, 1]), + * p2 = board.create('point', [1, 1]), + * t = board.create('transform', [3, 2], {type: 'shear'}); + * t.applyOnce([p1, p2]); + * + * </pre><div class="jxgbox" id="JXGb6cee1c4-2ad6-11e5-8dd9-901b0e1b8723" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXGb6cee1c4-2ad6-11e5-8dd9-901b0e1b8723', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * var p1 = board.create('point', [1, 1]), + * p2 = board.create('point', [-1, -2]), + * t = board.create('transform', [3, 2], {type: 'shear'}); + * t.applyOnce([p1, p2]); + * + * })(); + * + * </script><pre> + * + * @example + * // Construct a square of side length 2 with the + * // help of transformations + * var sq = [], + * right = board.create('transform', [2, 0], {type: 'translate'}), + * up = board.create('transform', [0, 2], {type: 'translate'}), + * pol, rot, p0; + * + * // The first point is free + * sq[0] = board.create('point', [0, 0], {name: 'Drag me'}), + * + * // Construct the other free points by transformations + * sq[1] = board.create('point', [sq[0], right]), + * sq[2] = board.create('point', [sq[0], [right, up]]), + * sq[3] = board.create('point', [sq[0], up]), + * + * // Polygon through these four points + * pol = board.create('polygon', sq, { + * fillColor:'blue', + * gradient:'radial', + * gradientsecondcolor:'white', + * gradientSecondOpacity:'0' + * }), + * + * p0 = board.create('point', [0, 3], {name: 'angle'}), + * // Rotate the square around point sq[0] by dragging A + * rot = board.create('transform', ['Y(angle)', sq[0]], {type: 'rotate'}); + * + * // Apply the rotation to all but the first point of the square + * rot.bindTo(sq.slice(1)); + * + * </pre><div class="jxgbox" id="JXGc7f9097e-2ad7-11e5-8dd9-901b0e1b8723" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXGc7f9097e-2ad7-11e5-8dd9-901b0e1b8723', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * // Construct a square of side length 2 with the + * // help of transformations + * var sq = [], + * right = board.create('transform', [2, 0], {type: 'translate'}), + * up = board.create('transform', [0, 2], {type: 'translate'}), + * pol, rot, p0; + * + * // The first point is free + * sq[0] = board.create('point', [0, 0], {name: 'Drag me'}), + * + * // Construct the other free points by transformations + * sq[1] = board.create('point', [sq[0], right]), + * sq[2] = board.create('point', [sq[0], [right, up]]), + * sq[3] = board.create('point', [sq[0], up]), + * + * // Polygon through these four points + * pol = board.create('polygon', sq, { + * fillColor:'blue', + * gradient:'radial', + * gradientsecondcolor:'white', + * gradientSecondOpacity:'0' + * }), + * + * p0 = board.create('point', [0, 3], {name: 'angle'}), + * // Rotate the square around point sq[0] by dragging A + * rot = board.create('transform', ['Y(angle)', sq[0]], {type: 'rotate'}); + * + * // Apply the rotation to all but the first point of the square + * rot.bindTo(sq.slice(1)); + * + * })(); + * + * </script><pre> + * + */ + JXG.createTransform = function (board, parents, attributes) { + return new JXG.Transformation(board, attributes.type, parents); + }; - // already documented in JXG.AbstractRenderer - unsuspendRedraw: function () { - this.container.style.display = ''; - } - }); + JXG.registerElement('transform', JXG.createTransform); - return JXG.VMLRenderer; + return { + Transformation: JXG.Transformation, + createTransform: JXG.createTransform + }; }); /* - Copyright 2008-2021 + Copyright 2008-2022 Matthias Ehmann, Michael Gerhaeuser, Carsten Miller, @@ -59035,2774 +68415,3112 @@ define('renderer/vml',[ */ -/*global JXG: true, define: true, AMprocessNode: true, document: true, Image: true, module: true, require: true */ -/*jslint nomen: true, plusplus: true, newcap:true*/ +/*global JXG: true, define: true*/ +/*jslint nomen: true, plusplus: true*/ /* depends: jxg - renderer/abstract - base/constants - utils/env - utils/type - utils/uuid - utils/color - base/coords math/math math/geometry math/numerics -*/ + math/statistics + math/symbolic + base/composition + base/coords + base/constants + utils/type + elements: + line + circle + transform + point + glider + text + curve + */ -define('renderer/canvas',[ - 'jxg', 'renderer/abstract', 'base/constants', 'utils/env', 'utils/type', 'utils/uuid', 'utils/color', - 'base/coords', 'math/math', 'math/geometry', 'math/numerics' -], function (JXG, AbstractRenderer, Const, Env, Type, UUID, Color, Coords, Mat, Geometry, Numerics) { +/** + * @fileoverview This file contains our composition elements, i.e. these elements are mostly put together + * from one or more {@link JXG.GeometryElement} but with a special meaning. E.g. the midpoint element is contained here + * and this is just a {@link JXG.Point} with coordinates dependent from two other points. Currently in this file the + * following compositions can be found: <ul> + * <li>{@link Arrowparallel} (currently private)</li> + * <li>{@link Bisector}</li> + * <li>{@link Msector}</li> + * <li>{@link Circumcircle}</li> + * <li>{@link Circumcirclemidpoint}</li> + * <li>{@link Integral}</li> + * <li>{@link Midpoint}</li> + * <li>{@link Mirrorpoint}</li> + * <li>{@link Normal}</li> + * <li>{@link Orthogonalprojection}</li> + * <li>{@link Parallel}</li> + * <li>{@link Perpendicular}</li> + * <li>{@link Perpendicularpoint}</li> + * <li>{@link Perpendicularsegment}</li> + * <li>{@link Reflection}</li></ul> + */ + +define('element/composition',[ + 'jxg', 'math/math', 'math/geometry', 'math/numerics', 'base/coords', + 'utils/type', 'base/constants', 'base/point', 'base/line', 'base/circle', 'base/transformation', + 'base/composition', 'base/curve', 'base/polygon' +], function (JXG, Mat, Geometry, Numerics, Coords, + Type, Const, Point, Line, Circle, Transform, + Composition, Curve, Polygon) { "use strict"; /** - * Uses HTML Canvas to implement the rendering methods defined in {@link JXG.AbstractRenderer}. - * @class JXG.AbstractRenderer - * @augments JXG.AbstractRenderer - * @param {Node} container Reference to a DOM node containing the board. - * @param {Object} dim The dimensions of the board - * @param {Number} dim.width - * @param {Number} dim.height - * @see JXG.AbstractRenderer + * @class This is used to construct a point that is the orthogonal projection of a point to a line. + * @pseudo + * @description An orthogonal projection is given by a point and a line. It is determined by projecting the given point + * orthogonal onto the given line. + * @constructor + * @name Orthogonalprojection + * @type JXG.Point + * @augments JXG.Point + * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {JXG.Line_JXG.Point} p,l The constructed point is the orthogonal projection of p onto l. + * @example + * var p1 = board.create('point', [0.0, 4.0]); + * var p2 = board.create('point', [6.0, 1.0]); + * var l1 = board.create('line', [p1, p2]); + * var p3 = board.create('point', [3.0, 3.0]); + * + * var pp1 = board.create('orthogonalprojection', [p3, l1]); + * </pre><div class="jxgbox" id="JXG7708b215-39fa-41b6-b972-19d73d77d791" style="width: 400px; height: 400px;"></div> + * <script type="text/javascript"> + * var ppex1_board = JXG.JSXGraph.initBoard('JXG7708b215-39fa-41b6-b972-19d73d77d791', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); + * var ppex1_p1 = ppex1_board.create('point', [0.0, 4.0]); + * var ppex1_p2 = ppex1_board.create('point', [6.0, 1.0]); + * var ppex1_l1 = ppex1_board.create('line', [ppex1_p1, ppex1_p2]); + * var ppex1_p3 = ppex1_board.create('point', [3.0, 3.0]); + * var ppex1_pp1 = ppex1_board.create('orthogonalprojection', [ppex1_p3, ppex1_l1]); + * </script><pre> */ - JXG.CanvasRenderer = function (container, dim) { - this.type = 'canvas'; - - this.canvasRoot = null; - this.suspendHandle = null; - this.canvasId = UUID.genUUID(); - - this.canvasNamespace = null; - - if (Env.isBrowser) { - this.container = container; - this.container.style.MozUserSelect = 'none'; - this.container.style.userSelect = 'none'; - - this.container.style.overflow = 'hidden'; - if (this.container.style.position === '') { - this.container.style.position = 'relative'; - } - - this.container.innerHTML = ['<canvas id="', this.canvasId, - '" width="', dim.width, - 'px" height="', dim.height, - 'px"><', '/canvas>'].join(''); - this.canvasRoot = this.container.ownerDocument.getElementById(this.canvasId); - this.context = this.canvasRoot.getContext('2d'); - } else if (Env.isNode()) { - this.canvasId = (typeof module === 'object' ? module.require('canvas') : require('canvas')); - this.canvasRoot = new this.canvasId(500, 500); - this.context = this.canvasRoot.getContext('2d'); - } - - this.dashArray = [[2, 2], [5, 5], [10, 10], [20, 20], [20, 10, 10, 10], [20, 5, 10, 5]]; - }; - - JXG.CanvasRenderer.prototype = new AbstractRenderer(); - - JXG.extend(JXG.CanvasRenderer.prototype, /** @lends JXG.CanvasRenderer.prototype */ { - - /* ************************** - * private methods only used - * in this renderer. Should - * not be called from outside. - * **************************/ - - /** - * Draws a filled polygon. - * @param {Array} shape A matrix presented by a two dimensional array of numbers. - * @see JXG.AbstractRenderer#drawArrows - * @private - */ - _drawFilledPolygon: function (shape, degree) { - var i, len = shape.length, - context = this.context; - - if (len > 0) { - context.beginPath(); - context.moveTo(shape[0][0], shape[0][1]); - if (degree == 1) { - for (i = 1; i < len; i++) { - context.lineTo(shape[i][0], shape[i][1]); - } - } else { - for (i = 1; i < len; i += 3) { - context.bezierCurveTo(shape[i][0], shape[i][1], shape[i + 1][0], shape[i + 1][1], shape[i + 2][0], shape[i + 2][1]); - } - } - context.lineTo(shape[0][0], shape[0][1]); - context.closePath(); - context.fill(); - context.stroke(); - } - }, - - /** - * Sets the fill color and fills an area. - * @param {JXG.GeometryElement} el An arbitrary JSXGraph element, preferably one with an area. - * @private - */ - _fill: function (el) { - var context = this.context; - - context.save(); - if (this._setColor(el, 'fill')) { - context.fill(); - } - context.restore(); - }, - - /** - * Rotates a point around <tt>(0, 0)</tt> by a given angle. - * @param {Number} angle An angle, given in rad. - * @param {Number} x X coordinate of the point. - * @param {Number} y Y coordinate of the point. - * @returns {Array} An array containing the x and y coordinate of the rotated point. - * @private - */ - _rotatePoint: function (angle, x, y) { - return [ - (x * Math.cos(angle)) - (y * Math.sin(angle)), - (x * Math.sin(angle)) + (y * Math.cos(angle)) - ]; - }, - - /** - * Rotates an array of points around <tt>(0, 0)</tt>. - * @param {Array} shape An array of array of point coordinates. - * @param {Number} angle The angle in rad the points are rotated by. - * @returns {Array} Array of array of two dimensional point coordinates. - * @private - */ - _rotateShape: function (shape, angle) { - var i, rv = [], len = shape.length; - - if (len <= 0) { - return shape; - } - - for (i = 0; i < len; i++) { - rv.push(this._rotatePoint(angle, shape[i][0], shape[i][1])); - } - - return rv; - }, - - /** - * Set the gradient angle for linear color gradients. - * - * @private - * @param {JXG.GeometryElement} node An arbitrary JSXGraph element, preferably one with an area. - * @param {Number} radians angle value in radians. 0 is horizontal from left to right, Pi/4 is vertical from top to bottom. - */ - updateGradientAngle: function(el, radians) { - // Angles: - // 0: -> - // 90: down - // 180: <- - // 90: up - var f = 1.0, - co = Math.cos(-radians), - si = Math.sin(-radians), - bb = el.getBoundingBox(), - c1, c2, x1, x2, y1, y2, x1s, x2s, y1s, y2s, dx, dy; - - if (Math.abs(co) > Math.abs(si)) { - f /= Math.abs(co); - } else { - f /= Math.abs(si); - } - if (co >= 0) { - x1 = 0; - x2 = co * f; - } else { - x1 = -co * f; - x2 = 0; - } - if (si >= 0) { - y1 = 0; - y2 = si * f; - } else { - y1 = -si * f; - y2 = 0; - } - - c1 = new Coords(Const.COORDS_BY_USER, [bb[0], bb[1]], el.board); - c2 = new Coords(Const.COORDS_BY_USER, [bb[2], bb[3]], el.board); - dx = c2.scrCoords[1] - c1.scrCoords[1]; - dy = c2.scrCoords[2] - c1.scrCoords[2]; - x1s = c1.scrCoords[1] + dx * x1; - y1s = c1.scrCoords[2] + dy * y1; - x2s = c1.scrCoords[1] + dx * x2; - y2s = c1.scrCoords[2] + dy * y2; - - return this.context.createLinearGradient(x1s, y1s, x2s, y2s); - }, - - /** - * Set circles for radial color gradients. - * - * @private - * @param {SVGnode} node SVG gradient node - * @param {Number} cx Canvas value x1 (but value between 0 and 1) - * @param {Number} cy Canvas value y1 (but value between 0 and 1) - * @param {Number} r Canvas value r1 (but value between 0 and 1) - * @param {Number} fx Canvas value x0 (but value between 0 and 1) - * @param {Number} fy Canvas value x1 (but value between 0 and 1) - * @param {Number} fr Canvas value r0 (but value between 0 and 1) - */ - updateGradientCircle: function(el, cx, cy, r, fx, fy, fr) { - var bb = el.getBoundingBox(), - c1, c2, cxs, cys, rs, fxs, fys, frs, dx, dy; - - c1 = new Coords(Const.COORDS_BY_USER, [bb[0], bb[1]], el.board); - c2 = new Coords(Const.COORDS_BY_USER, [bb[2], bb[3]], el.board); - dx = c2.scrCoords[1] - c1.scrCoords[1]; - dy = c1.scrCoords[2] - c2.scrCoords[2]; - - cxs = c1.scrCoords[1] + dx * cx; - cys = c2.scrCoords[2] + dy * cy; - fxs = c1.scrCoords[1] + dx * fx; - fys = c2.scrCoords[2] + dy * fy; - rs = r * (dx + dy) * 0.5; - frs = fr * (dx + dy) * 0.5; - - return this.context.createRadialGradient(fxs, fys, frs, cxs, cys, rs); - }, - - // documented in JXG.AbstractRenderer - updateGradient: function(el) { - var col, op, - ev_g = Type.evaluate(el.visProp.gradient), - gradient; - - op = Type.evaluate(el.visProp.fillopacity); - op = (op > 0) ? op : 0; - col = Type.evaluate(el.visProp.fillcolor); - - if (ev_g === 'linear') { - gradient = this.updateGradientAngle(el, Type.evaluate(el.visProp.gradientangle)); - } else if (ev_g === 'radial') { - gradient = this.updateGradientCircle(el, - Type.evaluate(el.visProp.gradientcx), - Type.evaluate(el.visProp.gradientcy), - Type.evaluate(el.visProp.gradientr), - Type.evaluate(el.visProp.gradientfx), - Type.evaluate(el.visProp.gradientfy), - Type.evaluate(el.visProp.gradientfr) - ); - } - gradient.addColorStop(Type.evaluate(el.visProp.gradientstartoffset), col); - gradient.addColorStop(Type.evaluate(el.visProp.gradientendoffset), - Type.evaluate(el.visProp.gradientsecondcolor)); - return gradient; - }, - - /** - * Sets color and opacity for filling and stroking. - * type is the attribute from visProp and targetType the context[targetTypeStyle]. - * This is necessary, because the fill style of a text is set by the stroke attributes of the text element. - * @param {JXG.GeometryElement} el Any JSXGraph element. - * @param {String} [type='stroke'] Either <em>fill</em> or <em>stroke</em>. - * @param {String} [targetType=type] (optional) Either <em>fill</em> or <em>stroke</em>. - * @returns {Boolean} If the color could be set, <tt>true</tt> is returned. - * @private - */ - _setColor: function (el, type, targetType) { - var hasColor = true, - ev = el.visProp, hl, sw, - rgba, rgbo, c, o, oo, - grad; - - type = type || 'stroke'; - targetType = targetType || type; - - hl = this._getHighlighted(el); - - grad = Type.evaluate(el.visProp.gradient); - if (grad === 'linear' || grad === 'radial') { - // TODO: opacity - this.context[targetType + 'Style'] = this.updateGradient(el); - return hasColor; - } - - // type is equal to 'fill' or 'stroke' - rgba = Type.evaluate(ev[hl + type + 'color']); - if (rgba !== 'none' && rgba !== false) { - o = Type.evaluate(ev[hl + type + 'opacity']); - o = (o > 0) ? o : 0; - - // RGB, not RGBA - if (rgba.length !== 9) { - c = rgba; - oo = o; - // True RGBA, not RGB - } else { - rgbo = Color.rgba2rgbo(rgba); - c = rgbo[0]; - oo = o * rgbo[1]; - } - this.context.globalAlpha = oo; - - this.context[targetType + 'Style'] = c; - - } else { - hasColor = false; - } - - sw = parseFloat(Type.evaluate(ev[hl + 'strokewidth'])); - if (type === 'stroke' && !isNaN(sw)) { - if (sw === 0) { - this.context.globalAlpha = 0; - } else { - this.context.lineWidth = sw; - } - } - - if (type === 'stroke' && ev.linecap !== undefined && ev.linecap !== '') { - this.context.lineCap = ev.linecap; - } - - return hasColor; - }, - - /** - * Sets color and opacity for drawing paths and lines and draws the paths and lines. - * @param {JXG.GeometryElement} el An JSXGraph element with a stroke. - * @private - */ - _stroke: function (el) { - var context = this.context, - ev_dash = Type.evaluate(el.visProp.dash); - - context.save(); - - if (ev_dash > 0) { - if (context.setLineDash) { - context.setLineDash(this.dashArray[ev_dash]); - } - } else { - this.context.lineDashArray = []; - } - - if (this._setColor(el, 'stroke')) { - context.stroke(); - } - - context.restore(); - }, - - /** - * Translates a set of points. - * @param {Array} shape An array of point coordinates. - * @param {Number} x Translation in X direction. - * @param {Number} y Translation in Y direction. - * @returns {Array} An array of translated point coordinates. - * @private - */ - _translateShape: function (shape, x, y) { - var i, rv = [], len = shape.length; - - if (len <= 0) { - return shape; - } - - for (i = 0; i < len; i++) { - rv.push([ shape[i][0] + x, shape[i][1] + y ]); - } - - return rv; - }, - - /* ******************************** * - * Point drawing and updating * - * ******************************** */ - - // documented in AbstractRenderer - drawPoint: function (el) { - var f = Type.evaluate(el.visProp.face), - size = Type.evaluate(el.visProp.size), - scr = el.coords.scrCoords, - sqrt32 = size * Math.sqrt(3) * 0.5, - s05 = size * 0.5, - stroke05 = parseFloat(Type.evaluate(el.visProp.strokewidth)) / 2.0, - context = this.context; + JXG.createOrthogonalProjection = function (board, parents, attributes) { + var l, p, t, attr; - if (!el.visPropCalc.visible) { - return; - } + parents[0] = board.select(parents[0]); + parents[1] = board.select(parents[1]); - switch (f) { - case 'cross': // x - case 'x': - context.beginPath(); - context.moveTo(scr[1] - size, scr[2] - size); - context.lineTo(scr[1] + size, scr[2] + size); - context.moveTo(scr[1] + size, scr[2] - size); - context.lineTo(scr[1] - size, scr[2] + size); - context.lineCap = 'round'; - context.lineJoin = 'round'; - context.closePath(); - this._stroke(el); - break; - case 'circle': // dot - case 'o': - context.beginPath(); - context.arc(scr[1], scr[2], size + 1 + stroke05, 0, 2 * Math.PI, false); - context.closePath(); - this._fill(el); - this._stroke(el); - break; - case 'square': // rectangle - case '[]': - if (size <= 0) { - break; - } + if (Type.isPointType(board, parents[0]) && parents[1].elementClass === Const.OBJECT_CLASS_LINE) { + p = Type.providePoints(board, [parents[0]], attributes, 'point')[0]; + l = parents[1]; + } else if (Type.isPointType(board, parents[1]) && parents[0].elementClass === Const.OBJECT_CLASS_LINE) { + p = Type.providePoints(board, [parents[1]], attributes, 'point')[0]; + l = parents[0]; + } else { + throw new Error("JSXGraph: Can't create perpendicular point with parent types '" + + (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + + "\nPossible parent types: [point,line]"); + } - context.save(); - if (this._setColor(el, 'stroke', 'fill')) { - context.fillRect(scr[1] - size - stroke05, scr[2] - size - stroke05, size * 2 + 3 * stroke05, size * 2 + 3 * stroke05); - } - context.restore(); - context.save(); - this._setColor(el, 'fill'); - context.fillRect(scr[1] - size + stroke05, scr[2] - size + stroke05, size * 2 - stroke05, size * 2 - stroke05); - context.restore(); - break; - case 'plus': // + - case '+': - context.beginPath(); - context.moveTo(scr[1] - size, scr[2]); - context.lineTo(scr[1] + size, scr[2]); - context.moveTo(scr[1], scr[2] - size); - context.lineTo(scr[1], scr[2] + size); - context.lineCap = 'round'; - context.lineJoin = 'round'; - context.closePath(); - this._stroke(el); - break; - case 'diamond': // <> - case '<>': - context.beginPath(); - context.moveTo(scr[1] - size, scr[2]); - context.lineTo(scr[1], scr[2] + size); - context.lineTo(scr[1] + size, scr[2]); - context.lineTo(scr[1], scr[2] - size); - context.closePath(); - this._fill(el); - this._stroke(el); - break; - case 'triangleup': - case 'a': - case '^': - context.beginPath(); - context.moveTo(scr[1], scr[2] - size); - context.lineTo(scr[1] - sqrt32, scr[2] + s05); - context.lineTo(scr[1] + sqrt32, scr[2] + s05); - context.closePath(); - this._fill(el); - this._stroke(el); - break; - case 'triangledown': - case 'v': - context.beginPath(); - context.moveTo(scr[1], scr[2] + size); - context.lineTo(scr[1] - sqrt32, scr[2] - s05); - context.lineTo(scr[1] + sqrt32, scr[2] - s05); - context.closePath(); - this._fill(el); - this._stroke(el); - break; - case 'triangleleft': - case '<': - context.beginPath(); - context.moveTo(scr[1] - size, scr[2]); - context.lineTo(scr[1] + s05, scr[2] - sqrt32); - context.lineTo(scr[1] + s05, scr[2] + sqrt32); - context.closePath(); - this.fill(el); - this._stroke(el); - break; - case 'triangleright': - case '>': - context.beginPath(); - context.moveTo(scr[1] + size, scr[2]); - context.lineTo(scr[1] - s05, scr[2] - sqrt32); - context.lineTo(scr[1] - s05, scr[2] + sqrt32); - context.closePath(); - this._fill(el); - this._stroke(el); - break; + attr = Type.copyAttributes(attributes, board.options, 'orthogonalprojection'); + + t = board.create('point', [ + function () { + return Geometry.projectPointToLine(p, l, board); } - }, + ], attr); - // documented in AbstractRenderer - updatePoint: function (el) { - this.drawPoint(el); - }, + if (Type.exists(p._is_new)) { + t.addChild(p); + delete p._is_new; + } else { + p.addChild(t); + } + l.addChild(t); - /* ******************************** * - * Lines * - * ******************************** */ + t.elType = 'orthogonalprojection'; + t.setParents([p.id, t.id]); + + t.update(); /** - * Draws arrows of an element (usually a line) in canvas renderer. - * @param {JXG.GeometryElement} el Line to be drawn. - * @param {Array} scr1 Screen coordinates of the start position of the line or curve. - * @param {Array} scr2 Screen coordinates of the end position of the line or curve. - * @param {String} hl String which carries information if the element is highlighted. Used for getting the correct attribute. + * Used to generate a polynomial for the orthogonal projection + * @name Orthogonalprojection#generatePolynomial + * @returns {Array} An array containing the generated polynomial. * @private */ - drawArrows: function (el, scr1, scr2, hl) { - var x1, y1, x2, y2, - w0, w, - arrowHead, - arrowTail, - context = this.context, - size = 6, - type = 1, - degree_fa = 1, - degree_la = 1, - i, len, - d1x, d1y, d2x, d2y, last, - ang1, ang2, - ev_fa = Type.evaluate(el.visProp.firstarrow), - ev_la = Type.evaluate(el.visProp.lastarrow); + t.generatePolynomial = function () { + /* + * Perpendicular takes point P and line L and creates point T and line M: + * + * | M + * | + * x P (p1,p2) + * | + * | + * L | + * ----------x-------------x------------------------x-------- + * A (a1,a2) |T (t1,t2) B (b1,b2) + * | + * | + * + * So we have two conditions: + * + * (a) AT || TB (collinearity condition) + * (b) PT _|_ AB (orthogonality condition) + * + * a2-t2 t2-b2 + * ------- = ------- (1) + * a1-t1 t1-b1 + * + * p2-t2 a1-b1 + * ------- = - ------- (2) + * p1-t1 a2-b2 + * + * Multiplying (1) and (2) with denominators and simplifying gives + * + * a2t1 - a2b1 + t2b1 - a1t2 + a1b2 - t1b2 = 0 (1') + * + * p2a2 - p2b2 - t2a2 + t2b2 + p1a1 - p1b1 - t1a1 + t1b1 = 0 (2') + * + */ - if (Type.evaluate(el.visProp.strokecolor) !== 'none' && - (ev_fa || ev_la)) { + var a1 = l.point1.symbolic.x, + a2 = l.point1.symbolic.y, + b1 = l.point2.symbolic.x, + b2 = l.point2.symbolic.y, - if (el.elementClass === Const.OBJECT_CLASS_LINE) { - x1 = scr1.scrCoords[1]; - y1 = scr1.scrCoords[2]; - x2 = scr2.scrCoords[1]; - y2 = scr2.scrCoords[2]; - ang1 = ang2 = Math.atan2(y2 - y1, x2 - x1); - } else { - x1 = el.points[0].scrCoords[1]; - y1 = el.points[0].scrCoords[2]; + p1 = p.symbolic.x, + p2 = p.symbolic.y, + t1 = t.symbolic.x, + t2 = t.symbolic.y, - last = el.points.length - 1; - if (last < 1) { - // No arrows for curves consisting of 1 point - return; - } - x2 = el.points[el.points.length - 1].scrCoords[1]; - y2 = el.points[el.points.length - 1].scrCoords[2]; + poly1 = '(' + a2 + ')*(' + t1 + ')-(' + a2 + ')*(' + b1 + ')+(' + t2 + ')*(' + b1 + ')-(' + + a1 + ')*(' + t2 + ')+(' + a1 + ')*(' + b2 + ')-(' + t1 + ')*(' + b2 + ')', + poly2 = '(' + p2 + ')*(' + a2 + ')-(' + p2 + ')*(' + b2 + ')-(' + t2 + ')*(' + a2 + ')+(' + + t2 + ')*(' + b2 + ')+(' + p1 + ')*(' + a1 + ')-(' + p1 + ')*(' + b1 + ')-(' + t1 + ')*(' + + a1 + ')+(' + t1 + ')*(' + b1 + ')'; - d1x = el.points[1].scrCoords[1] - el.points[0].scrCoords[1]; - d1y = el.points[1].scrCoords[2] - el.points[0].scrCoords[2]; - d2x = el.points[last].scrCoords[1] - el.points[last - 1].scrCoords[1]; - d2y = el.points[last].scrCoords[2] - el.points[last - 1].scrCoords[2]; - if (ev_fa) { - ang1 = Math.atan2(d1y, d1x); - } - if (ev_la) { - ang2 = Math.atan2(d2y, d2x); - } - } + return [poly1, poly2]; + }; - w0 = Type.evaluate(el.visProp[hl + 'strokewidth']); + return t; + }; - if (ev_fa) { - size = 6; - if (Type.exists(ev_fa.size)) { - size = Type.evaluate(ev_fa.size); - } - if (hl !== '' && Type.exists(ev_fa[hl + 'size'])) { - size = Type.evaluate(ev_fa[hl + 'size']); - } - w = w0 * size; + /** - if (Type.exists(ev_fa.type)) { - type = Type.evaluate(ev_fa.type); - } - if (type === 2) { - arrowTail = [ - [ w, -w * 0.5], - [ 0.0, 0.0], - [ w, w * 0.5], - [ w * 0.5, 0.0], - ]; - } else if (type === 3) { - arrowTail = [ - [ w / 3.0, -w * 0.5], - [ 0.0, -w * 0.5], - [ 0.0, w * 0.5], - [ w / 3.0, w * 0.5] - ]; - } else if (type === 4) { - w /= 10; - degree_fa = 3; - arrowTail = [ - [10.00, 3.31], - [6.47, 3.84], - [2.87, 4.50], - [0.00, 6.63], - [0.67, 5.52], - [1.33, 4.42], - [2.00, 3.31], - [1.33, 2.21], - [0.67, 1.10], - [0.00, 0.00], - [2.87, 2.13], - [6.47, 2.79], - [10.00, 3.31] - ]; - len = arrowTail.length; - for (i = 0; i < len; i++) { - arrowTail[i][0] *= -w; - arrowTail[i][1] *= w; - arrowTail[i][0] += 10 * w; - arrowTail[i][1] -= 3.31 * w; - } - } else if (type === 5) { - w /= 10; - degree_fa = 3; - arrowTail = [ - [10.00,3.28], - [6.61,4.19], - [3.19,5.07], - [0.00,6.55], - [0.62,5.56], - [1.00,4.44], - [1.00,3.28], - [1.00,2.11], - [0.62,0.99], - [0.00,0.00], - [3.19,1.49], - [6.61,2.37], - [10.00,3.28] - ]; - len = arrowTail.length; - for (i = 0; i < len; i++) { - arrowTail[i][0] *= -w; - arrowTail[i][1] *= w; - arrowTail[i][0] += 10 * w; - arrowTail[i][1] -= 3.28 * w; - } - } else if (type === 6) { - w /= 10; - degree_fa = 3; - arrowTail = [ - [10.00,2.84], - [6.61,3.59], - [3.21,4.35], - [0.00,5.68], - [0.33,4.73], - [0.67,3.78], - [1.00,2.84], - [0.67,1.89], - [0.33,0.95], - [0.00,0.00], - [3.21,1.33], - [6.61,2.09], - [10.00,2.84] - ]; - len = arrowTail.length; - for (i = 0; i < len; i++) { - arrowTail[i][0] *= -w; - arrowTail[i][1] *= w; - arrowTail[i][0] += 10 * w; - arrowTail[i][1] -= 2.84 * w; - } - } else { - arrowTail = [ - [ w, -w * 0.5], - [ 0.0, 0.0], - [ w, w * 0.5] - ]; - } - } + * @class This element is used to provide a constructor for a perpendicular. + * @pseudo + * @description A perpendicular is a composition of two elements: a line and a point. The line is orthogonal + * to a given line and contains a given point. + * @name Perpendicular + * @constructor + * @type JXG.Line + * @augments Segment + * @returns A {@link JXG.Line} object through the given point that is orthogonal to the given line. + * @throws {Error} If the elements cannot be constructed with the given parent objects an exception is thrown. + * @param {JXG.Line_JXG.Point} l,p The perpendicular line will be orthogonal to l and + * will contain p. + * @example + * // Create a perpendicular + * var p1 = board.create('point', [0.0, 2.0]); + * var p2 = board.create('point', [2.0, 1.0]); + * var l1 = board.create('line', [p1, p2]); + * + * var p3 = board.create('point', [3.0, 3.0]); + * var perp1 = board.create('perpendicular', [l1, p3]); + * </pre><div class="jxgbox" id="JXGd5b78842-7b27-4d37-b608-d02519e6cd03" style="width: 400px; height: 400px;"></div> + * <script type="text/javascript"> + * var pex1_board = JXG.JSXGraph.initBoard('JXGd5b78842-7b27-4d37-b608-d02519e6cd03', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); + * var pex1_p1 = pex1_board.create('point', [0.0, 2.0]); + * var pex1_p2 = pex1_board.create('point', [2.0, 1.0]); + * var pex1_l1 = pex1_board.create('line', [pex1_p1, pex1_p2]); + * var pex1_p3 = pex1_board.create('point', [3.0, 3.0]); + * var pex1_perp1 = pex1_board.create('perpendicular', [pex1_l1, pex1_p3]); + * </script><pre> + */ + JXG.createPerpendicular = function (board, parents, attributes) { + var p, l, pd, attr; - if (ev_la) { - size = 6; - if (Type.exists(ev_la.size)) { - size = Type.evaluate(ev_la.size); - } - if (hl !== '' && Type.exists(ev_la[hl + 'size'])) { - size = Type.evaluate(ev_la[hl + 'size']); - } - w = w0 * size; + parents[0] = board.select(parents[0]); + parents[1] = board.select(parents[1]); - if (Type.exists(ev_la.type)) { - type = Type.evaluate(ev_la.type); - } - if (type === 2) { - arrowHead = [ - [ -w, -w * 0.5], - [ 0.0, 0.0], - [ -w, w * 0.5], - [ -w * 0.5, 0.0] - ]; - } else if (type === 3) { - arrowHead = [ - [-w / 3.0, -w * 0.5], - [ 0.0, -w * 0.5], - [ 0.0, w * 0.5], - [-w / 3.0, w * 0.5] - ]; - } else if (type === 4) { - w /= 10; - degree_la = 3; - arrowHead = [ - [10.00, 3.31], - [6.47, 3.84], - [2.87, 4.50], - [0.00, 6.63], - [0.67, 5.52], - [1.33, 4.42], - [2.00, 3.31], - [1.33, 2.21], - [0.67, 1.10], - [0.00, 0.00], - [2.87, 2.13], - [6.47, 2.79], - [10.00, 3.31] - ]; - len = arrowHead.length; - for (i = 0; i < len; i++) { - arrowHead[i][0] *= w; - arrowHead[i][1] *= w; - arrowHead[i][0] -= 10 * w; - arrowHead[i][1] -= 3.31 * w; + if (Type.isPointType(board, parents[0]) && parents[1].elementClass === Const.OBJECT_CLASS_LINE) { + l = parents[1]; + p = Type.providePoints(board, [parents[0]], attributes, 'point')[0]; + } else if (Type.isPointType(board, parents[1]) && parents[0].elementClass === Const.OBJECT_CLASS_LINE) { + l = parents[0]; + p = Type.providePoints(board, [parents[1]], attributes, 'point')[0]; + } else { + throw new Error("JSXGraph: Can't create perpendicular with parent types '" + + (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + + "\nPossible parent types: [line,point]"); + } - } - } else if (type === 5) { - w /= 10; - degree_la = 3; - arrowHead = [ - [10.00,3.28], - [6.61,4.19], - [3.19,5.07], - [0.00,6.55], - [0.62,5.56], - [1.00,4.44], - [1.00,3.28], - [1.00,2.11], - [0.62,0.99], - [0.00,0.00], - [3.19,1.49], - [6.61,2.37], - [10.00,3.28] - ]; - len = arrowHead.length; - for (i = 0; i < len; i++) { - arrowHead[i][0] *= w; - arrowHead[i][1] *= w; - arrowHead[i][0] -= 10 * w; - arrowHead[i][1] -= 3.28 * w; + attr = Type.copyAttributes(attributes, board.options, 'perpendicular'); + pd = Line.createLine(board, [ + function () { + return l.stdform[2] * p.X() - l.stdform[1] * p.Y(); + }, + function () { + return -l.stdform[2] * p.Z(); + }, + function () { + return l.stdform[1] * p.Z(); + } + ], attr); - } - } else if (type === 6) { - w /= 10; - degree_la = 3; - arrowHead = [ - [10.00,2.84], - [6.61,3.59], - [3.21,4.35], - [0.00,5.68], - [0.33,4.73], - [0.67,3.78], - [1.00,2.84], - [0.67,1.89], - [0.33,0.95], - [0.00,0.00], - [3.21,1.33], - [6.61,2.09], - [10.00,2.84] - ]; - len = arrowHead.length; - for (i = 0; i < len; i++) { - arrowHead[i][0] *= w; - arrowHead[i][1] *= w; - arrowHead[i][0] -= 10 * w; - arrowHead[i][1] -= 2.84 * w; + pd.elType = 'perpendicular'; + pd.setParents([l.id, p.id]); - } + if (Type.exists(p._is_new)) { + pd.addChild(p); + delete p._is_new; + } else { + p.addChild(pd); + } + l.addChild(pd); - } else { - arrowHead = [ - [ -w, -w * 0.5], - [ 0.0, 0.0], - [ -w, w * 0.5] - ]; - } - } + return pd; + }; - context.save(); - if (this._setColor(el, 'stroke', 'fill')) { - this._setColor(el, 'stroke'); - if (ev_fa) { - this._drawFilledPolygon(this._translateShape(this._rotateShape(arrowTail, ang1), x1, y1), degree_fa); - } - if (ev_la) { - this._drawFilledPolygon(this._translateShape(this._rotateShape(arrowHead, ang2), x2, y2), degree_la); - } - } - context.restore(); - } - }, + /** + * @class This is used to construct a perpendicular point. + * @pseudo + * @description A perpendicular point is given by a point and a line. It is determined by projecting the given point + * orthogonal onto the given line. This element should be used in GEONExTReader only. All other applications should + * use orthogonal projection {@link Orthogonalprojection}. + * @constructor + * @name PerpendicularPoint + * @type JXG.Point + * @augments JXG.Point + * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {JXG.Line_JXG.Point} p,l The constructed point is the orthogonal projection of p onto l. + * @example + * var p1 = board.create('point', [0.0, 4.0]); + * var p2 = board.create('point', [6.0, 1.0]); + * var l1 = board.create('line', [p1, p2]); + * var p3 = board.create('point', [3.0, 3.0]); + * + * var pp1 = board.create('perpendicularpoint', [p3, l1]); + * </pre><div class="jxgbox" id="JXGded148c9-3536-44c0-ab81-1bb8fa48f3f4" style="width: 400px; height: 400px;"></div> + * <script type="text/javascript"> + * var ppex1_board = JXG.JSXGraph.initBoard('JXGded148c9-3536-44c0-ab81-1bb8fa48f3f4', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); + * var ppex1_p1 = ppex1_board.create('point', [0.0, 4.0]); + * var ppex1_p2 = ppex1_board.create('point', [6.0, 1.0]); + * var ppex1_l1 = ppex1_board.create('line', [ppex1_p1, ppex1_p2]); + * var ppex1_p3 = ppex1_board.create('point', [3.0, 3.0]); + * var ppex1_pp1 = ppex1_board.create('perpendicularpoint', [ppex1_p3, ppex1_l1]); + * </script><pre> + */ + JXG.createPerpendicularPoint = function (board, parents, attributes) { + var l, p, t; - // documented in AbstractRenderer - drawLine: function (el) { - var c1_org, c2_org, - c1 = new Coords(Const.COORDS_BY_USER, el.point1.coords.usrCoords, el.board), - c2 = new Coords(Const.COORDS_BY_USER, el.point2.coords.usrCoords, el.board), - margin = null, - hl, w, arrowData; + parents[0] = board.select(parents[0]); + parents[1] = board.select(parents[1]); + if (Type.isPointType(board, parents[0]) && parents[1].elementClass === Const.OBJECT_CLASS_LINE) { + p = Type.providePoints(board, [parents[0]], attributes, 'point')[0]; + l = parents[1]; + } else if (Type.isPointType(board, parents[1]) && parents[0].elementClass === Const.OBJECT_CLASS_LINE) { + p = Type.providePoints(board, [parents[1]], attributes, 'point')[0]; + l = parents[0]; + } else { + throw new Error("JSXGraph: Can't create perpendicular point with parent types '" + + (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + + "\nPossible parent types: [point,line]"); + } - if (!el.visPropCalc.visible) { - return; + t = board.create('point', [ + function () { + return Geometry.perpendicular(l, p, board)[0]; } + ], attributes); - hl = this._getHighlighted(el); - w = Type.evaluate(el.visProp[hl + 'strokewidth']); - arrowData = this.getArrowHeadData(el, w, hl); - - if (arrowData.evFirst || arrowData.evLast) { - margin = -4; - } - Geometry.calcStraight(el, c1, c2, margin); - c1_org = new Coords(Const.COORDS_BY_USER, c1.usrCoords, el.board); - c2_org = new Coords(Const.COORDS_BY_USER, c2.usrCoords, el.board); + if (Type.exists(p._is_new)) { + t.addChild(p); + delete p._is_new; + } else { + p.addChild(t); + } + l.addChild(t); - this.getPositionArrowHead(el, c1, c2, arrowData); + t.elType = 'perpendicularpoint'; + t.setParents([p.id, l.id]); - this.context.beginPath(); - this.context.moveTo(c1.scrCoords[1], c1.scrCoords[2]); - this.context.lineTo(c2.scrCoords[1], c2.scrCoords[2]); - this._stroke(el); + t.update(); - if ((arrowData.evFirst/* && obj.sFirst > 0*/) || - (arrowData.evLast/* && obj.sLast > 0*/)) { + /** + * Used to generate a polynomial for the perpendicular point + * @name PerpendicularPoint#generatePolynomial + * @returns {Array} An array containing the generated polynomial. + * @private + */ + t.generatePolynomial = function () { + /* + * Perpendicular takes point P and line L and creates point T and line M: + * + * | M + * | + * x P (p1,p2) + * | + * | + * L | + * ----------x-------------x------------------------x-------- + * A (a1,a2) |T (t1,t2) B (b1,b2) + * | + * | + * + * So we have two conditions: + * + * (a) AT || TB (collinearity condition) + * (b) PT _|_ AB (orthogonality condition) + * + * a2-t2 t2-b2 + * ------- = ------- (1) + * a1-t1 t1-b1 + * + * p2-t2 a1-b1 + * ------- = - ------- (2) + * p1-t1 a2-b2 + * + * Multiplying (1) and (2) with denominators and simplifying gives + * + * a2t1 - a2b1 + t2b1 - a1t2 + a1b2 - t1b2 = 0 (1') + * + * p2a2 - p2b2 - t2a2 + t2b2 + p1a1 - p1b1 - t1a1 + t1b1 = 0 (2') + * + */ + var a1 = l.point1.symbolic.x, + a2 = l.point1.symbolic.y, + b1 = l.point2.symbolic.x, + b2 = l.point2.symbolic.y, + p1 = p.symbolic.x, + p2 = p.symbolic.y, + t1 = t.symbolic.x, + t2 = t.symbolic.y, - this.drawArrows(el, c1_org, c2_org, hl); - } - }, + poly1 = '(' + a2 + ')*(' + t1 + ')-(' + a2 + ')*(' + b1 + ')+(' + t2 + ')*(' + b1 + ')-(' + + a1 + ')*(' + t2 + ')+(' + a1 + ')*(' + b2 + ')-(' + t1 + ')*(' + b2 + ')', + poly2 = '(' + p2 + ')*(' + a2 + ')-(' + p2 + ')*(' + b2 + ')-(' + t2 + ')*(' + a2 + ')+(' + + t2 + ')*(' + b2 + ')+(' + p1 + ')*(' + a1 + ')-(' + p1 + ')*(' + b1 + ')-(' + t1 + ')*(' + + a1 + ')+(' + t1 + ')*(' + b1 + ')'; - // documented in AbstractRenderer - updateLine: function (el) { - this.drawLine(el); - }, + return [poly1, poly2]; + }; - // documented in AbstractRenderer - drawTicks: function () { - // this function is supposed to initialize the svg/vml nodes in the SVG/VMLRenderer. - // but in canvas there are no such nodes, hence we just do nothing and wait until - // updateTicks is called. - }, + return t; + }; - // documented in AbstractRenderer - updateTicks: function (ticks) { - var i, c, x, y, - len = ticks.ticks.length, - len2, j, - context = this.context; + /** + * @class This element is used to provide a constructor for a perpendicular segment. + * @pseudo + * @description A perpendicular is a composition of two elements: a line segment and a point. The line segment is orthogonal + * to a given line and contains a given point and meets the given line in the perpendicular point. + * @name PerpendicularSegment + * @constructor + * @type JXG.Line + * @augments Segment + * @returns An array containing two elements: A {@link JXG.Line} object in the first component and a + * {@link JXG.Point} element in the second component. The line segment is orthogonal to the given line and meets it + * in the returned point. + * @throws {Error} If the elements cannot be constructed with the given parent objects an exception is thrown. + * @param {JXG.Line_JXG.Point} l,p The perpendicular line will be orthogonal to l and + * will contain p. The perpendicular point is the intersection point of the two lines. + * @example + * // Create a perpendicular + * var p1 = board.create('point', [0.0, 2.0]); + * var p2 = board.create('point', [2.0, 1.0]); + * var l1 = board.create('line', [p1, p2]); + * + * var p3 = board.create('point', [3.0, 3.0]); + * var perp1 = board.create('perpendicularsegment', [l1, p3]); + * </pre><div class="jxgbox" id="JXG037a6eb2-781d-4b71-b286-763619a63f22" style="width: 400px; height: 400px;"></div> + * <script type="text/javascript"> + * var pex1_board = JXG.JSXGraph.initBoard('JXG037a6eb2-781d-4b71-b286-763619a63f22', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); + * var pex1_p1 = pex1_board.create('point', [0.0, 2.0]); + * var pex1_p2 = pex1_board.create('point', [2.0, 1.0]); + * var pex1_l1 = pex1_board.create('line', [pex1_p1, pex1_p2]); + * var pex1_p3 = pex1_board.create('point', [3.0, 3.0]); + * var pex1_perp1 = pex1_board.create('perpendicularsegment', [pex1_l1, pex1_p3]); + * </script><pre> + */ + JXG.createPerpendicularSegment = function (board, parents, attributes) { + var p, l, pd, t, attr; - context.beginPath(); - for (i = 0; i < len; i++) { - c = ticks.ticks[i]; - x = c[0]; - y = c[1]; + parents[0] = board.select(parents[0]); + parents[1] = board.select(parents[1]); + if (Type.isPointType(board, parents[0]) && parents[1].elementClass === Const.OBJECT_CLASS_LINE) { + l = parents[1]; + p = Type.providePoints(board, [parents[0]], attributes, 'point')[0]; + } else if (Type.isPointType(board, parents[1]) && parents[0].elementClass === Const.OBJECT_CLASS_LINE) { + l = parents[0]; + p = Type.providePoints(board, [parents[1]], attributes, 'point')[0]; + } else { + throw new Error("JSXGraph: Can't create perpendicular with parent types '" + + (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + + "\nPossible parent types: [line,point]"); + } + attr = Type.copyAttributes(attributes, board.options, 'perpendicularsegment', 'point'); + t = JXG.createPerpendicularPoint(board, [l, p], attr); + t.dump = false; - // context.moveTo(x[0], y[0]); - // context.lineTo(x[1], y[1]); - len2 = x.length; - context.moveTo(x[0], y[0]); - for (j = 1; j < len2; ++j) { - context.lineTo(x[j], y[j]); - } + if (!Type.exists(attributes.layer)) { + attributes.layer = board.options.layer.line; + } + attr = Type.copyAttributes(attributes, board.options, 'perpendicularsegment'); + pd = Line.createLine(board, [ + function () { + return (Geometry.perpendicular(l, p, board)[1] ? [t, p] : [p, t]); } - // Labels - // for (i = 0; i < len; i++) { - // c = ticks.ticks[i].scrCoords; - // if (ticks.ticks[i].major && - // (ticks.board.needsFullUpdate || ticks.needsRegularUpdate) && - // ticks.labels[i] && - // ticks.labels[i].visPropCalc.visible) { - // this.updateText(ticks.labels[i]); - // } - // } - context.lineCap = 'round'; - this._stroke(ticks); - }, + ], attr); - /* ************************** - * Curves - * **************************/ + /** + * Helper point + * @memberOf PerpendicularSegment.prototype + * @type PerpendicularPoint + * @name point + */ + pd.point = t; - // documented in AbstractRenderer - drawCurve: function (el) { - var hl; + if (Type.exists(p._is_new)) { + pd.addChild(p); + delete p._is_new; + } else { + p.addChild(pd); + } + l.addChild(pd); - if (Type.evaluate(el.visProp.handdrawing)) { - this.updatePathStringBezierPrim(el); - } else { - this.updatePathStringPrim(el); - } - if (el.numberPoints > 1) { - hl = this._getHighlighted(el); - this.drawArrows(el, null, null, hl); - } - }, + pd.elType = 'perpendicularsegment'; + pd.setParents([p.id, l.id]); + pd.subs = { + point: t + }; + pd.inherits.push(t); - // documented in AbstractRenderer - updateCurve: function (el) { - this.drawCurve(el); - }, + return pd; + }; - /* ************************** - * Circle related stuff - * **************************/ + /** + * @class The midpoint element constructs a point in the middle of two given points. + * @pseudo + * @description A midpoint is given by two points. It is collinear to the given points and the distance + * is the same to each of the given points, i.e. it is in the middle of the given points. + * @constructor + * @name Midpoint + * @type JXG.Point + * @augments JXG.Point + * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {JXG.Point_JXG.Point} p1,p2 The constructed point will be in the middle of p1 and p2. + * @param {JXG.Line} l The midpoint will be in the middle of {@link JXG.Line#point1} and {@link JXG.Line#point2} of + * the given line l. + * @example + * // Create base elements: 2 points and 1 line + * var p1 = board.create('point', [0.0, 2.0]); + * var p2 = board.create('point', [2.0, 1.0]); + * var l1 = board.create('segment', [[0.0, 3.0], [3.0, 3.0]]); + * + * var mp1 = board.create('midpoint', [p1, p2]); + * var mp2 = board.create('midpoint', [l1]); + * </pre><div class="jxgbox" id="JXG7927ef86-24ae-40cc-afb0-91ff61dd0de7" style="width: 400px; height: 400px;"></div> + * <script type="text/javascript"> + * var mpex1_board = JXG.JSXGraph.initBoard('JXG7927ef86-24ae-40cc-afb0-91ff61dd0de7', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); + * var mpex1_p1 = mpex1_board.create('point', [0.0, 2.0]); + * var mpex1_p2 = mpex1_board.create('point', [2.0, 1.0]); + * var mpex1_l1 = mpex1_board.create('segment', [[0.0, 3.0], [3.0, 3.0]]); + * var mpex1_mp1 = mpex1_board.create('midpoint', [mpex1_p1, mpex1_p2]); + * var mpex1_mp2 = mpex1_board.create('midpoint', [mpex1_l1]); + * </script><pre> + */ + JXG.createMidpoint = function (board, parents, attributes) { + var a, b, t, i, + attr; - // documented in AbstractRenderer - drawEllipse: function (el) { - var m1 = el.center.coords.scrCoords[1], - m2 = el.center.coords.scrCoords[2], - sX = el.board.unitX, - sY = el.board.unitY, - rX = 2 * el.Radius(), - rY = 2 * el.Radius(), - aWidth = rX * sX, - aHeight = rY * sY, - aX = m1 - aWidth / 2, - aY = m2 - aHeight / 2, - hB = (aWidth / 2) * 0.5522848, - vB = (aHeight / 2) * 0.5522848, - eX = aX + aWidth, - eY = aY + aHeight, - mX = aX + aWidth / 2, - mY = aY + aHeight / 2, - context = this.context; + for (i = 0; i < parents.length; ++i) { + parents[i] = board.select(parents[i]); + } + if (parents.length === 2 && Type.isPointType(board, parents[0]) && Type.isPointType(board, parents[1])) { + parents = Type.providePoints(board, parents, attributes, 'point'); + a = parents[0]; + b = parents[1]; + } else if (parents.length === 1 && parents[0].elementClass === Const.OBJECT_CLASS_LINE) { + a = parents[0].point1; + b = parents[0].point2; + } else { + throw new Error("JSXGraph: Can't create midpoint." + + "\nPossible parent types: [point,point], [line]"); + } - if (rX > 0.0 && rY > 0.0 && !isNaN(m1 + m2)) { - context.beginPath(); - context.moveTo(aX, mY); - context.bezierCurveTo(aX, mY - vB, mX - hB, aY, mX, aY); - context.bezierCurveTo(mX + hB, aY, eX, mY - vB, eX, mY); - context.bezierCurveTo(eX, mY + vB, mX + hB, eY, mX, eY); - context.bezierCurveTo(mX - hB, eY, aX, mY + vB, aX, mY); - context.closePath(); - this._fill(el); - this._stroke(el); - } - }, + attr = Type.copyAttributes(attributes, board.options, 'midpoint'); + t = board.create('point', [ + function () { + var x = a.coords.usrCoords[1] + b.coords.usrCoords[1]; + if (isNaN(x) || Math.abs(a.coords.usrCoords[0]) < Mat.eps || Math.abs(b.coords.usrCoords[0]) < Mat.eps) { + return NaN; + } - // documented in AbstractRenderer - updateEllipse: function (el) { - return this.drawEllipse(el); - }, + return x * 0.5; + }, + function () { + var y = a.coords.usrCoords[2] + b.coords.usrCoords[2]; + if (isNaN(y) || Math.abs(a.coords.usrCoords[0]) < Mat.eps || Math.abs(b.coords.usrCoords[0]) < Mat.eps) { + return NaN; + } - /* ************************** - * Polygon - * **************************/ + return y * 0.5; + }], attr); + if (Type.exists(a._is_new)) { + t.addChild(a); + delete a._is_new; + } else { + a.addChild(t); + } + if (Type.exists(b._is_new)) { + t.addChild(b); + delete b._is_new; + } else { + b.addChild(t); + } - // nothing here, using AbstractRenderer implementations + t.elType = 'midpoint'; + t.setParents([a.id, b.id]); - /* ************************** - * Text related stuff - * **************************/ + t.prepareUpdate().update(); - // already documented in JXG.AbstractRenderer - displayCopyright: function (str, fontSize) { - var context = this.context; + /** + * Used to generate a polynomial for the midpoint. + * @name Midpoint#generatePolynomial + * @returns {Array} An array containing the generated polynomial. + * @private + */ + t.generatePolynomial = function () { + /* + * Midpoint takes two point A and B or line L (with points P and Q) and creates point T: + * + * L (not necessarily) + * ----------x------------------x------------------x-------- + * A (a1,a2) T (t1,t2) B (b1,b2) + * + * So we have two conditions: + * + * (a) AT || TB (collinearity condition) + * (b) [AT] == [TB] (equidistant condition) + * + * a2-t2 t2-b2 + * ------- = ------- (1) + * a1-t1 t1-b1 + * + * (a1 - t1)^2 + (a2 - t2)^2 = (b1 - t1)^2 + (b2 - t2)^2 (2) + * + * + * Multiplying (1) with denominators and simplifying (1) and (2) gives + * + * a2t1 - a2b1 + t2b1 - a1t2 + a1b2 - t1b2 = 0 (1') + * + * a1^2 - 2a1t1 + a2^2 - 2a2t2 - b1^2 + 2b1t1 - b2^2 + 2b2t2 = 0 (2') + * + */ + var a1 = a.symbolic.x, + a2 = a.symbolic.y, + b1 = b.symbolic.x, + b2 = b.symbolic.y, + t1 = t.symbolic.x, + t2 = t.symbolic.y, - // this should be called on EVERY update, otherwise it won't be shown after the first update - context.save(); - context.font = fontSize + 'px Arial'; - context.fillStyle = '#aaa'; - context.lineWidth = 0.5; - context.fillText(str, 10, 2 + fontSize); - context.restore(); - }, + poly1 = '(' + a2 + ')*(' + t1 + ')-(' + a2 + ')*(' + b1 + ')+(' + t2 + ')*(' + b1 + ')-(' + + a1 + ')*(' + t2 + ')+(' + a1 + ')*(' + b2 + ')-(' + t1 + ')*(' + b2 + ')', + poly2 = '(' + a1 + ')^2 - 2*(' + a1 + ')*(' + t1 + ')+(' + a2 + ')^2-2*(' + a2 + ')*(' + + t2 + ')-(' + b1 + ')^2+2*(' + b1 + ')*(' + t1 + ')-(' + b2 + ')^2+2*(' + b2 + ')*(' + t2 + ')'; - // already documented in JXG.AbstractRenderer - drawInternalText: function (el) { - var ev_fs = Type.evaluate(el.visProp.fontsize), - ev_ax = el.getAnchorX(), - ev_ay = el.getAnchorY(), - context = this.context; + return [poly1, poly2]; + }; - context.save(); - if (this._setColor(el, 'stroke', 'fill') && - !isNaN(el.coords.scrCoords[1] + el.coords.scrCoords[2])) { - context.font = (ev_fs > 0 ? ev_fs : 0) + 'px Arial'; + return t; + }; - this.transformImage(el, el.transformations); - if (ev_ax === 'left') { - context.textAlign = 'left'; - } else if (ev_ax === 'right') { - context.textAlign = 'right'; - } else if (ev_ax === 'middle') { - context.textAlign = 'center'; - } - if (ev_ay === 'bottom') { - context.textBaseline = 'bottom'; - } else if (ev_ay === 'top') { - context.textBaseline = 'top'; - } else if (ev_ay === 'middle') { - context.textBaseline = 'middle'; - } - context.fillText(el.plaintext, el.coords.scrCoords[1], el.coords.scrCoords[2]); - } - context.restore(); - return null; - }, + /** + * @class This element is used to construct a parallel point. + * @pseudo + * @description A parallel point is given by three points. Taking the Euclidean vector from the first to the + * second point, the parallel point is determined by adding that vector to the third point. + * The line determined by the first two points is parallel to the line determined by the third point and the constructed point. + * @constructor + * @name Parallelpoint + * @type JXG.Point + * @augments JXG.Point + * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 Taking the Euclidean vector <tt>v=p2-p1</tt> the parallel point is determined by + * <tt>p4 = p3+v</tt> + * @param {JXG.Line_JXG.Point} l,p The resulting point will together with p specify a line which is parallel to l. + * @example + * var p1 = board.create('point', [0.0, 2.0]); + * var p2 = board.create('point', [2.0, 1.0]); + * var p3 = board.create('point', [3.0, 3.0]); + * + * var pp1 = board.create('parallelpoint', [p1, p2, p3]); + * </pre><div class="jxgbox" id="JXG488c4be9-274f-40f0-a469-c5f70abe1f0e" style="width: 400px; height: 400px;"></div> + * <script type="text/javascript"> + * var ppex1_board = JXG.JSXGraph.initBoard('JXG488c4be9-274f-40f0-a469-c5f70abe1f0e', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); + * var ppex1_p1 = ppex1_board.create('point', [0.0, 2.0]); + * var ppex1_p2 = ppex1_board.create('point', [2.0, 1.0]); + * var ppex1_p3 = ppex1_board.create('point', [3.0, 3.0]); + * var ppex1_pp1 = ppex1_board.create('parallelpoint', [ppex1_p1, ppex1_p2, ppex1_p3]); + * </script><pre> + */ + JXG.createParallelPoint = function (board, parents, attributes) { + var a, b, c, p, i; + + for (i = 0; i < parents.length; ++i) { + parents[i] = board.select(parents[i]); + } + if (parents.length === 3 && + Type.isPointType(board, parents[0]) && + Type.isPointType(board, parents[1]) && + Type.isPointType(board, parents[2])) { + parents = Type.providePoints(board, parents, attributes, 'point'); + a = parents[0]; + b = parents[1]; + c = parents[2]; + } else if (Type.isPointType(board, parents[0]) && + parents[1].elementClass === Const.OBJECT_CLASS_LINE) { + c = Type.providePoints(board, [parents[0]], attributes, 'point')[0]; + a = parents[1].point1; + b = parents[1].point2; + } else if (Type.isPointType(board, parents[1]) && + parents[0].elementClass === Const.OBJECT_CLASS_LINE) { + c = Type.providePoints(board, [parents[1]], attributes, 'point')[0]; + a = parents[0].point1; + b = parents[0].point2; + } else { + throw new Error("JSXGraph: Can't create parallel point with parent types '" + + (typeof parents[0]) + "', '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." + + "\nPossible parent types: [line,point], [point,point,point]"); + } + + p = board.create('point', [ + function () { + return c.coords.usrCoords[1] + b.coords.usrCoords[1] - a.coords.usrCoords[1]; + }, + function () { + return c.coords.usrCoords[2] + b.coords.usrCoords[2] - a.coords.usrCoords[2]; + } + ], attributes); - // already documented in JXG.AbstractRenderer - updateInternalText: function (el) { - this.drawInternalText(el); - }, + // required for algorithms requiring dependencies between elements + if (Type.exists(a._is_new)) { + p.addChild(a); + delete a._is_new; + } else { + a.addChild(p); + } + if (Type.exists(b._is_new)) { + p.addChild(b); + delete b._is_new; + } else { + b.addChild(p); + } + if (Type.exists(c._is_new)) { + p.addChild(c); + delete c._is_new; + } else { + c.addChild(p); + } - // documented in JXG.AbstractRenderer - // Only necessary for texts - setObjectStrokeColor: function (el, color, opacity) { - var rgba = Type.evaluate(color), c, rgbo, - o = Type.evaluate(opacity), oo, - node; + p.elType = 'parallelpoint'; + p.setParents([a.id, b.id, c.id]); - o = (o > 0) ? o : 0; + // required to set the coordinates because functions are considered as constraints. hence, the coordinates get set first after an update. + // can be removed if the above issue is resolved. + p.prepareUpdate().update(); - if (el.visPropOld.strokecolor === rgba && el.visPropOld.strokeopacity === o) { - return; - } + p.generatePolynomial = function () { + /* + * Parallelpoint takes three points A, B and C or line L (with points B and C) and creates point T: + * + * + * C (c1,c2) T (t1,t2) + * x x + * / / + * / / + * / / + * / / + * / / + * / / + * / / + * / / + * L (opt) / / + * ----------x-------------------------------------x-------- + * A (a1,a2) B (b1,b2) + * + * So we have two conditions: + * + * (a) CT || AB (collinearity condition I) + * (b) BT || AC (collinearity condition II) + * + * The corresponding equations are + * + * (b2 - a2)(t1 - c1) - (t2 - c2)(b1 - a1) = 0 (1) + * (t2 - b2)(a1 - c1) - (t1 - b1)(a2 - c2) = 0 (2) + * + * Simplifying (1) and (2) gives + * + * b2t1 - b2c1 - a2t1 + a2c1 - t2b1 + t2a1 + c2b1 - c2a1 = 0 (1') + * t2a1 - t2c1 - b2a1 + b2c1 - t1a2 + t1c2 + b1a2 - b1c2 = 0 (2') + * + */ + var a1 = a.symbolic.x, + a2 = a.symbolic.y, + b1 = b.symbolic.x, + b2 = b.symbolic.y, + c1 = c.symbolic.x, + c2 = c.symbolic.y, + t1 = p.symbolic.x, + t2 = p.symbolic.y, - // Check if this could be merged with _setColor + poly1 = '(' + b2 + ')*(' + t1 + ')-(' + b2 + ')*(' + c1 + ')-(' + a2 + ')*(' + t1 + ')+(' + + a2 + ')*(' + c1 + ')-(' + t2 + ')*(' + b1 + ')+(' + t2 + ')*(' + a1 + ')+(' + c2 + ')*(' + + b1 + ')-(' + c2 + ')*(' + a1 + ')', + poly2 = '(' + t2 + ')*(' + a1 + ')-(' + t2 + ')*(' + c1 + ')-(' + b2 + ')*(' + a1 + ')+(' + + b2 + ')*(' + c1 + ')-(' + t1 + ')*(' + a2 + ')+(' + t1 + ')*(' + c2 + ')+(' + b1 + ')*(' + + a2 + ')-(' + b1 + ')*(' + c2 + ')'; - if (Type.exists(rgba) && rgba !== false) { - // RGB, not RGBA - if (rgba.length !== 9) { - c = rgba; - oo = o; - // True RGBA, not RGB - } else { - rgbo = Color.rgba2rgbo(rgba); - c = rgbo[0]; - oo = o * rgbo[1]; - } - node = el.rendNode; - if (el.elementClass === Const.OBJECT_CLASS_TEXT && Type.evaluate(el.visProp.display) === 'html') { - node.style.color = c; - node.style.opacity = oo; - } - } + return [poly1, poly2]; + }; - el.visPropOld.strokecolor = rgba; - el.visPropOld.strokeopacity = o; - }, + return p; + }; - /* ************************** - * Image related stuff - * **************************/ + /** + * @class A parallel is a line through a given point with the same slope as a given line or + * the line through two given point. + * <p> + * If original line is given as a JSXGraph line object, the resulting parallel line will be defined by the given point and an + * infinitely far away point (an ideal point). That means, the line can not be shortened to a segment. + * <p> + * If the original line is given as two points, the resulting parallel line can be shortened to a a segment. + * @pseudo + * @name Parallel + * @augments Line + * @constructor + * @type JXG.Line + * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {JXG.Line_JXG.Point} l,p The constructed line contains p and has the same slope as l. Alternative parameters are p1, p2, p: The + * constructed line contains p and has the same slope as the line through p1 and p2. + * @example + * // Create a parallel + * var p1 = board.create('point', [0.0, 2.0]); + * var p2 = board.create('point', [2.0, 1.0]); + * var l1 = board.create('line', [p1, p2]); + * + * var p3 = board.create('point', [3.0, 3.0]); + * var pl1 = board.create('parallel', [l1, p3]); + * </pre><div class="jxgbox" id="JXG24e54f9e-5c4e-4afb-9228-0ef27a59d627" style="width: 400px; height: 400px;"></div> + * <script type="text/javascript"> + * var plex1_board = JXG.JSXGraph.initBoard('JXG24e54f9e-5c4e-4afb-9228-0ef27a59d627', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); + * var plex1_p1 = plex1_board.create('point', [0.0, 2.0]); + * var plex1_p2 = plex1_board.create('point', [2.0, 1.0]); + * var plex1_l1 = plex1_board.create('line', [plex1_p1, plex1_p2]); + * var plex1_p3 = plex1_board.create('point', [3.0, 3.0]); + * var plex1_pl1 = plex1_board.create('parallel', [plex1_l1, plex1_p3]); + * </script><pre> + * @example + * var p1, p2, p3, l1, pl1; + * + * p1 = board.create('point', [0.0, 2.0]); + * p2 = board.create('point', [2.0, 1.0]); + * l1 = board.create('line', [p1, p2]); + * + * p3 = board.create('point', [1.0, 3.0]); + * pl1 = board.create('parallel', [p1, p2, p3], {straightFirst: false, straightLast: false}); + * + * </pre><div id="JXGd643305d-20c3-4a88-91f9-8d0c4448594f" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXGd643305d-20c3-4a88-91f9-8d0c4448594f', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * var p1, p2, p3, l1, pl1; + * + * p1 = board.create('point', [0.0, 2.0]); + * p2 = board.create('point', [2.0, 1.0]); + * l1 = board.create('line', [p1, p2]); + * + * p3 = board.create('point', [1.0, 3.0]); + * pl1 = board.create('parallel', [p1, p2, p3], {straightFirst: false, straightLast: false}); + * + * })(); + * + * </script><pre> + * + */ + JXG.createParallel = function (board, parents, attributes) { + var p, pp, pl, li, i, attr, ty = 1; - // already documented in JXG.AbstractRenderer - drawImage: function (el) { - el.rendNode = new Image(); - // Store the file name of the image. - // Before, this was done in el.rendNode.src - // But there, the file name is expanded to - // the full url. This may be different from - // the url computed in updateImageURL(). - el._src = ''; - this.updateImage(el); - }, + for (i = 0; i < parents.length; ++i) { + parents[i] = board.select(parents[i]); + } + p = null; + if (parents.length === 3) { + // Line / segment through point parents[2] which is parallel to line through parents[0] and parents[1] + parents = Type.providePoints(board, parents, attributes, 'point'); + p = parents[2]; + ty = 0; + } else if (Type.isPointType(board, parents[0])) { + // Parallel to line parents[1] through point parents[0] + p = Type.providePoints(board, [parents[0]], attributes, 'point')[0]; + /** @ignore */ + li = function () { + return parents[1].stdform; + }; + } else if (Type.isPointType(board, parents[1])) { + // Parallel to line parents[0] through point parents[1] + p = Type.providePoints(board, [parents[1]], attributes, 'point')[0]; + /** @ignore */ + li = function () { + return parents[0].stdform; + }; + } - // already documented in JXG.AbstractRenderer - updateImage: function (el) { - var context = this.context, - o = Type.evaluate(el.visProp.fillopacity), - paintImg = Type.bind(function () { - el.imgIsLoaded = true; - if (el.size[0] <= 0 || el.size[1] <= 0) { - return; - } - context.save(); - context.globalAlpha = o; - // If det(el.transformations)=0, FireFox 3.6. breaks down. - // This is tested in transformImage - this.transformImage(el, el.transformations); - context.drawImage(el.rendNode, - el.coords.scrCoords[1], - el.coords.scrCoords[2] - el.size[1], - el.size[0], - el.size[1]); - context.restore(); - }, this); + if (!Type.exists(attributes.layer)) { + attributes.layer = board.options.layer.line; + } - if (this.updateImageURL(el)) { - el.rendNode.onload = paintImg; - } else { - if (el.imgIsLoaded) { - paintImg(); + attr = Type.copyAttributes(attributes, board.options, 'parallel', 'point'); + if (ty === 1) { + // Line is given by line element. The parallel line is + // constructed as line through an ideal point. + pp = board.create('point', [ + function () { + return Mat.crossProduct([1, 0, 0], li()); } - } - }, + ], attr); + } else { + // Line is given by two points. The parallel line is + // constructed as line through two finite point. + pp = board.create('parallelpoint', parents, attr); + } + pp.isDraggable = true; - // already documented in JXG.AbstractRenderer - transformImage: function (el, t) { - var m, len = t.length, - ctx = this.context; + attr = Type.copyAttributes(attributes, board.options, 'parallel'); + // line creator also calls addChild + pl = board.create('line', [p, pp], attr); - if (len > 0) { - m = this.joinTransforms(el, t); - if (Math.abs(Numerics.det(m)) >= Mat.eps) { - ctx.transform(m[1][1], m[2][1], m[1][2], m[2][2], m[1][0], m[2][0]); - } - } - }, + pl.elType = 'parallel'; + pl.subs = { + point: pp + }; - // already documented in JXG.AbstractRenderer - updateImageURL: function (el) { - var url; + pl.inherits.push(pp); + pl.setParents([parents[0].id, parents[1].id]); + if (parents.length === 3) { + pl.addParents(parents[2].id); + } - url = Type.evaluate(el.url); - if (el._src !== url) { - el.imgIsLoaded = false; - el.rendNode.src = url; - el._src = url; - return true; - } + // p.addChild(pl); - return false; - }, + /** + * Helper point used to create the parallel line. This point lies on the line at infinity, hence it's not visible, + * not even with visible set to <tt>true</tt>. Creating another line through this point would make that other line + * parallel to the create parallel. + * @memberOf Parallel.prototype + * @name point + * @type JXG.Point + */ + pl.point = pp; - /* ************************** - * Render primitive objects - * **************************/ + return pl; + }; - // documented in AbstractRenderer - remove: function (shape) { - // sounds odd for a pixel based renderer but we need this for html texts - if (Type.exists(shape) && Type.exists(shape.parentNode)) { - shape.parentNode.removeChild(shape); - } - }, + /** + * @class An arrow parallel is a segment with an arrow attached which is parallel through a given segment, given by its defining two points, + * through a given point. + * <p> + * @pseudo + * @constructor + * @name Arrowparallel + * @type Parallel + * @augments Parallel + * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param JXG.Point_JXG.Point_JXG.Point} p1, p2,p3 The constructed arrow contains p3 and has the same slope as the line through p1 and p2. + * @example + * // Create a parallel + * var p1 = board.create('point', [0.0, 2.0]); + * var p2 = board.create('point', [2.0, 1.0]); + * var l1 = board.create('segment', [p1, p2]); + * + * var p3 = board.create('point', [3.0, 3.0]); + * var pl1 = board.create('arrowparallel', [p1, p2, p3]); + * </pre><div class="jxgbox" id="JXGeeacdf99-036f-4e83-aeb6-f7388423e369" style="width: 400px; height: 400px;"></div> + * <script type="text/javascript"> + * (function () { + * var plex1_board = JXG.JSXGraph.initBoard('JXGeeacdf99-036f-4e83-aeb6-f7388423e369', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); + * var plex1_p1 = plex1_board.create('point', [0.0, 2.0]); + * var plex1_p2 = plex1_board.create('point', [2.0, 1.0]); + * var plex1_l1 = plex1_board.create('segment', [plex1_p1, plex1_p2]); + * var plex1_p3 = plex1_board.create('point', [3.0, 3.0]); + * var plex1_pl1 = plex1_board.create('arrowparallel', [plex1_p1, plex1_p2, plex1_p3]); + * })(); + * </script><pre> + */ + JXG.createArrowParallel = function (board, parents, attributes) { + var p; - // documented in AbstractRenderer - updatePathStringPrim: function (el) { - var i, scr, scr1, scr2, len, - symbm = 'M', - symbl = 'L', - symbc = 'C', - nextSymb = symbm, - maxSize = 5000.0, - context = this.context; + /* parallel arrow point polynomials are done in createParallelPoint */ + try { + attributes.firstArrow = false; + attributes.lastArrow = true; + p = JXG.createParallel(board, parents, attributes).setAttribute({straightFirst: false, straightLast: false}); + p.elType = 'arrowparallel'; - if (el.numberPoints <= 0) { - return; - } + // parents are set in createParallel - len = Math.min(el.points.length, el.numberPoints); - context.beginPath(); + return p; + } catch (e) { + throw new Error("JSXGraph: Can't create arrowparallel with parent types '" + + (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + + "\nPossible parent types: [line,point], [point,point,point]"); + } + }; - if (el.bezierDegree === 1) { - /* - if (isNotPlot && el.board.options.curve.RDPsmoothing) { - el.points = Numerics.RamerDouglasPeucker(el.points, 0.5); + /** + * @class Constructs a normal. + * @pseudo + * @description A normal is a line through a given point on a element of type line, circle, curve, or turtle and orthogonal to that object. + * @constructor + * @name Normal + * @type JXG.Line + * @augments JXG.Line + * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {JXG.Line,JXG.Circle,JXG.Curve,JXG.Turtle_JXG.Point} o,p The constructed line contains p which lies on the object and is orthogonal + * to the tangent to the object in the given point. + * @param {Glider} p Works like above, however the object is given by {@link JXG.CoordsElement#slideObject}. + * @example + * // Create a normal to a circle. + * var p1 = board.create('point', [2.0, 2.0]); + * var p2 = board.create('point', [3.0, 2.0]); + * var c1 = board.create('circle', [p1, p2]); + * + * var norm1 = board.create('normal', [c1, p2]); + * </pre><div class="jxgbox" id="JXG4154753d-3d29-40fb-a860-0b08aa4f3743" style="width: 400px; height: 400px;"></div> + * <script type="text/javascript"> + * var nlex1_board = JXG.JSXGraph.initBoard('JXG4154753d-3d29-40fb-a860-0b08aa4f3743', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); + * var nlex1_p1 = nlex1_board.create('point', [2.0, 2.0]); + * var nlex1_p2 = nlex1_board.create('point', [3.0, 2.0]); + * var nlex1_c1 = nlex1_board.create('circle', [nlex1_p1, nlex1_p2]); + * + * // var nlex1_p3 = nlex1_board.create('point', [1.0, 2.0]); + * var nlex1_norm1 = nlex1_board.create('normal', [nlex1_c1, nlex1_p2]); + * </script><pre> + */ + JXG.createNormal = function (board, parents, attributes) { + var p, c, l, i, g, f, attr, pp, attrp; + + for (i = 0; i < parents.length; ++i) { + parents[i] = board.select(parents[i]); + } + // One arguments: glider on line, circle or curve + if (parents.length === 1) { + p = parents[0]; + c = p.slideObject; + // Two arguments: (point,line), (point,circle), (line,point) or (circle,point) + } else if (parents.length === 2) { + if (Type.isPointType(board, parents[0])) { + p = Type.providePoints(board, [parents[0]], attributes, 'point')[0]; + c = parents[1]; + } else if (Type.isPointType(board, parents[1])) { + c = parents[0]; + p = Type.providePoints(board, [parents[1]], attributes, 'point')[0]; + } else { + throw new Error("JSXGraph: Can't create normal with parent types '" + + (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + + "\nPossible parent types: [point,line], [point,circle], [glider]"); + } + } else { + throw new Error("JSXGraph: Can't create normal with parent types '" + + (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + + "\nPossible parent types: [point,line], [point,circle], [glider]"); + } + + attr = Type.copyAttributes(attributes, board.options, 'normal'); + if (c.elementClass === Const.OBJECT_CLASS_LINE) { + // Private point + attrp = Type.copyAttributes(attributes, board.options, 'normal', 'point'); + pp = board.create('point', [ + function () { + var p = Mat.crossProduct([1, 0, 0], c.stdform); + return [p[0], -p[2], p[1]]; } - */ + ], attrp); + pp.isDraggable = true; - for (i = 0; i < len; i++) { - scr = el.points[i].scrCoords; + l = board.create('line', [p, pp], attr); - if (isNaN(scr[1]) || isNaN(scr[2])) { // PenUp - nextSymb = symbm; - } else { - // Chrome has problems with values being too far away. - if (scr[1] > maxSize) { - scr[1] = maxSize; - } else if (scr[1] < -maxSize) { - scr[1] = -maxSize; + /** + * A helper point used to create a normal to a {@link JXG.Line} object. For normals to circles or curves this + * element is <tt>undefined</tt>. + * @type JXG.Point + * @name point + * @memberOf Normal.prototype + */ + l.point = pp; + l.subs = { + point: pp + }; + l.inherits.push(pp); + } else if (c.elementClass === Const.OBJECT_CLASS_CIRCLE) { + l = board.create('line', [c.midpoint, p], attr); + } else if (c.elementClass === Const.OBJECT_CLASS_CURVE) { + if (Type.evaluate(c.visProp.curvetype) !== 'plot') { + g = c.X; + f = c.Y; + l = board.create('line', [ + function () { + return -p.X() * Numerics.D(g)(p.position) - p.Y() * Numerics.D(f)(p.position); + }, + function () { + return Numerics.D(g)(p.position); + }, + function () { + return Numerics.D(f)(p.position); + } + ], attr); + } else { // curveType 'plot' + l = board.create('line', [ + function () { + var i = Math.floor(p.position), + lbda = p.position - i, + p1, p2, t, A, B, C, D, dx, dy, d; + + if (c.bezierdegree === 1) { + if (i === c.numberPoints - 1) { + i -= 1; + lbda = 1; + } + } else if (c.bezierDegree === 3) { + // i is start of the Bezier segment + // t is the position in the Bezier segment + i = Math.floor(p.position * (c.numberPoints - 1) / 3) * 3; + t = (p.position * (c.numberPoints - 1) - i) / 3; + if (i >= c.numberPoints - 1) { + i = c.numberPoints - 4; + t = 1; + } + } else { + return 0; } - if (scr[2] > maxSize) { - scr[2] = maxSize; - } else if (scr[2] < -maxSize) { - scr[2] = -maxSize; + if (i < 0) { + return 1; } - if (nextSymb === symbm) { - context.moveTo(scr[1], scr[2]); + if (c.bezierDegree === 1) { + return (c.Y(i) + lbda * (c.Y(i + 1) - c.Y(i))) * (c.Y(i) - c.Y(i + 1)) - (c.X(i) + lbda * (c.X(i + 1) - c.X(i))) * (c.X(i + 1) - c.X(i)); } else { - context.lineTo(scr[1], scr[2]); + A = c.points[i].usrCoords; + B = c.points[i + 1].usrCoords; + C = c.points[i + 2].usrCoords; + D = c.points[i + 3].usrCoords; + dx = (1 - t) * (1 - t) * (B[1] - A[1]) + 2 * (1 - t) * t * (C[1] - B[1]) + t * t * (D[1]- C[1]); + dy = (1 - t) * (1 - t) * (B[2] - A[2]) + 2 * (1 - t) * t * (C[2] - B[2]) + t * t * (D[2]- C[2]); + d = Math.sqrt(dx * dx + dy * dy); + dx /= d; + dy /= d; + p1 = p.coords.usrCoords; + p2 = [1, p1[1] - dy, p1[2] + dx]; + return p1[2] * p2[1] - p1[1] * p2[2]; } - nextSymb = symbl; - } - } - } else if (el.bezierDegree === 3) { - i = 0; - while (i < len) { - scr = el.points[i].scrCoords; - if (isNaN(scr[1]) || isNaN(scr[2])) { // PenUp - nextSymb = symbm; - } else { - if (nextSymb === symbm) { - context.moveTo(scr[1], scr[2]); + }, + function () { + var i = Math.floor(p.position), + p1, p2, t, A, B, C, D, dx, dy, d; + + if (c.bezierdegree === 1) { + if (i === c.numberPoints - 1) { + i -= 1; + } + } else if (c.bezierDegree === 3) { + // i is start of the Bezier segment + // t is the position in the Bezier segment + i = Math.floor(p.position * (c.numberPoints - 1) / 3) * 3; + t = (p.position * (c.numberPoints - 1) - i) / 3; + if (i >= c.numberPoints - 1) { + i = c.numberPoints - 4; + t = 1; + } } else { - i += 1; - scr1 = el.points[i].scrCoords; - i += 1; - scr2 = el.points[i].scrCoords; - context.bezierCurveTo(scr[1], scr[2], scr1[1], scr1[2], scr2[1], scr2[2]); + return 0; } - nextSymb = symbc; - } - i += 1; - } - } - context.lineCap = 'round'; - this._fill(el); - this._stroke(el); - }, - - // already documented in JXG.AbstractRenderer - updatePathStringBezierPrim: function (el) { - var i, j, k, scr, lx, ly, len, - symbm = 'M', - symbl = 'C', - nextSymb = symbm, - maxSize = 5000.0, - f = Type.evaluate(el.visProp.strokewidth), - isNoPlot = (Type.evaluate(el.visProp.curvetype) !== 'plot'), - context = this.context; - - if (el.numberPoints <= 0) { - return; - } - - if (isNoPlot && el.board.options.curve.RDPsmoothing) { - el.points = Numerics.RamerDouglasPeucker(el.points, 0.5); - } - len = Math.min(el.points.length, el.numberPoints); - context.beginPath(); + if (i < 0) { + return 0; + } + if (c.bezierDegree === 1) { + return c.X(i + 1) - c.X(i); + } else { + A = c.points[i].usrCoords; + B = c.points[i + 1].usrCoords; + C = c.points[i + 2].usrCoords; + D = c.points[i + 3].usrCoords; + dx = (1 - t) * (1 - t) * (B[1] - A[1]) + 2 * (1 - t) * t * (C[1] - B[1]) + t * t * (D[1]- C[1]); + dy = (1 - t) * (1 - t) * (B[2] - A[2]) + 2 * (1 - t) * t * (C[2] - B[2]) + t * t * (D[2]- C[2]); + d = Math.sqrt(dx * dx + dy * dy); + dx /= d; + dy /= d; + p1 = p.coords.usrCoords; + p2 = [1, p1[1] - dy, p1[2] + dx]; + return p2[2] - p1[2]; + } - for (j = 1; j < 3; j++) { - nextSymb = symbm; - for (i = 0; i < len; i++) { - scr = el.points[i].scrCoords; + }, + function () { + var i = Math.floor(p.position), + p1, p2, t, A, B, C, D, dx, dy, d; - if (isNaN(scr[1]) || isNaN(scr[2])) { // PenUp - nextSymb = symbm; - } else { - // Chrome has problems with values being too far away. - if (scr[1] > maxSize) { - scr[1] = maxSize; - } else if (scr[1] < -maxSize) { - scr[1] = -maxSize; + if (c.bezierdegree === 1) { + if (i === c.numberPoints - 1) { + i -= 1; + } + } else if (c.bezierDegree === 3) { + // i is start of the Bezier segment + // t is the position in the Bezier segment + i = Math.floor(p.position * (c.numberPoints - 1) / 3) * 3; + t = (p.position * (c.numberPoints - 1) - i) / 3; + if (i >= c.numberPoints - 1) { + i = c.numberPoints - 4; + t = 1; + } + } else { + return 0; } - if (scr[2] > maxSize) { - scr[2] = maxSize; - } else if (scr[2] < -maxSize) { - scr[2] = -maxSize; + if (i < 0) { + return 0; } - if (nextSymb === symbm) { - context.moveTo(scr[1], scr[2]); + if (c.bezierDegree === 1) { + return c.Y(i + 1) - c.Y(i); } else { - k = 2 * j; - context.bezierCurveTo( - (lx + (scr[1] - lx) * 0.333 + f * (k * Math.random() - j)), - (ly + (scr[2] - ly) * 0.333 + f * (k * Math.random() - j)), - (lx + (scr[1] - lx) * 0.666 + f * (k * Math.random() - j)), - (ly + (scr[2] - ly) * 0.666 + f * (k * Math.random() - j)), - scr[1], - scr[2] - ); + A = c.points[i].usrCoords; + B = c.points[i + 1].usrCoords; + C = c.points[i + 2].usrCoords; + D = c.points[i + 3].usrCoords; + dx = (1 - t) * (1 - t) * (B[1] - A[1]) + 2 * (1 - t) * t * (C[1] - B[1]) + t * t * (D[1]- C[1]); + dy = (1 - t) * (1 - t) * (B[2] - A[2]) + 2 * (1 - t) * t * (C[2] - B[2]) + t * t * (D[2]- C[2]); + d = Math.sqrt(dx * dx + dy * dy); + dx /= d; + dy /= d; + p1 = p.coords.usrCoords; + p2 = [1, p1[1] - dy, p1[2] + dx]; + return p1[1] - p2[1]; } - nextSymb = symbl; - lx = scr[1]; - ly = scr[2]; } - } - } - context.lineCap = 'round'; - this._fill(el); - this._stroke(el); - }, - - // documented in AbstractRenderer - updatePolygonPrim: function (node, el) { - var scrCoords, i, j, - len = el.vertices.length, - context = this.context, - isReal = true; - - if (len <= 0 || !el.visPropCalc.visible) { - return; - } - if (el.elType === 'polygonalchain') { - len++; + ], attr); } + } else if (c.type === Const.OBJECT_TYPE_TURTLE) { + l = board.create('line', [ + function () { + var el, j, + i = Math.floor(p.position), + lbda = p.position - i; - context.beginPath(); - i = 0; - while (!el.vertices[i].isReal && i < len - 1) { - i++; - isReal = false; - } - scrCoords = el.vertices[i].coords.scrCoords; - context.moveTo(scrCoords[1], scrCoords[2]); + // run through all curves of this turtle + for (j = 0; j < c.objects.length; j++) { + el = c.objects[j]; - for (j = i; j < len - 1; j++) { - if (!el.vertices[j].isReal) { - isReal = false; - } - scrCoords = el.vertices[j].coords.scrCoords; - context.lineTo(scrCoords[1], scrCoords[2]); - } - context.closePath(); + if (el.type === Const.OBJECT_TYPE_CURVE) { + if (i < el.numberPoints) { + break; + } - if (isReal) { - this._fill(el); // The edges of a polygon are displayed separately (as segments). - } - }, + i -= el.numberPoints; + } + } - // ************************** Set Attributes ************************* + if (i === el.numberPoints - 1) { + i -= 1; + lbda = 1; + } - // already documented in JXG.AbstractRenderer - display: function(el, val) { - if (el && el.rendNode) { - el.visPropOld.visible = val; - if (val) { - el.rendNode.style.visibility = "inherit"; - } else { - el.rendNode.style.visibility = "hidden"; - } - } - }, + if (i < 0) { + return 1; + } - // documented in AbstractRenderer - show: function (el) { - JXG.deprecated('Board.renderer.show()', 'Board.renderer.display()'); + return (el.Y(i) + lbda * (el.Y(i + 1) - el.Y(i))) * (el.Y(i) - el.Y(i + 1)) - (el.X(i) + lbda * (el.X(i + 1) - el.X(i))) * (el.X(i + 1) - el.X(i)); + }, + function () { + var el, j, + i = Math.floor(p.position); - if (Type.exists(el.rendNode)) { - el.rendNode.style.visibility = "inherit"; - } - }, + // run through all curves of this turtle + for (j = 0; j < c.objects.length; j++) { + el = c.objects[j]; + if (el.type === Const.OBJECT_TYPE_CURVE) { + if (i < el.numberPoints) { + break; + } - // documented in AbstractRenderer - hide: function (el) { - JXG.deprecated('Board.renderer.hide()', 'Board.renderer.display()'); + i -= el.numberPoints; + } + } - if (Type.exists(el.rendNode)) { - el.rendNode.style.visibility = "hidden"; - } - }, + if (i === el.numberPoints - 1) { + i -= 1; + } - // documented in AbstractRenderer - setGradient: function (el) { - var col, op; + if (i < 0) { + return 0; + } - op = Type.evaluate(el.visProp.fillopacity); - op = (op > 0) ? op : 0; + return el.X(i + 1) - el.X(i); + }, + function () { + var el, j, + i = Math.floor(p.position); - col = Type.evaluate(el.visProp.fillcolor); - }, + // run through all curves of this turtle + for (j = 0; j < c.objects.length; j++) { + el = c.objects[j]; + if (el.type === Const.OBJECT_TYPE_CURVE) { + if (i < el.numberPoints) { + break; + } - // documented in AbstractRenderer - setShadow: function (el) { - if (el.visPropOld.shadow === el.visProp.shadow) { - return; - } + i -= el.numberPoints; + } + } - // not implemented yet - // we simply have to redraw the element - // probably the best way to do so would be to call el.updateRenderer(), i think. + if (i === el.numberPoints - 1) { + i -= 1; + } - el.visPropOld.shadow = el.visProp.shadow; - }, + if (i < 0) { + return 0; + } - // documented in AbstractRenderer - highlight: function (obj) { - if (obj.elementClass === Const.OBJECT_CLASS_TEXT && Type.evaluate(obj.visProp.display) === 'html') { - this.updateTextStyle(obj, true); - } else { - obj.board.prepareUpdate(); - obj.board.renderer.suspendRedraw(obj.board); - obj.board.updateRenderer(); - obj.board.renderer.unsuspendRedraw(); - } - return this; - }, + return el.Y(i + 1) - el.Y(i); + } + ], attr); + } else { + throw new Error("JSXGraph: Can't create normal with parent types '" + + (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + + "\nPossible parent types: [point,line], [point,circle], [glider]"); + } - // documented in AbstractRenderer - noHighlight: function (obj) { - if (obj.elementClass === Const.OBJECT_CLASS_TEXT && Type.evaluate(obj.visProp.display) === 'html') { - this.updateTextStyle(obj, false); - } else { - obj.board.prepareUpdate(); - obj.board.renderer.suspendRedraw(obj.board); - obj.board.updateRenderer(); - obj.board.renderer.unsuspendRedraw(); - } - return this; - }, + l.elType = 'normal'; + l.setParents(parents); - /* ************************** - * renderer control - * **************************/ + if (Type.exists(p._is_new)) { + l.addChild(p); + delete p._is_new; + } else { + p.addChild(l); + } + c.addChild(l); - // documented in AbstractRenderer - suspendRedraw: function (board) { - this.context.save(); - this.context.clearRect(0, 0, this.canvasRoot.width, this.canvasRoot.height); + return l; + }; - if (board && board.attr.showcopyright) { - this.displayCopyright(JXG.licenseText, 12); - } - }, + /** + * @class A bisector is a line which divides an angle into two equal angles. It is given by three points A, B, and + * C and divides the angle ABC into two equal sized parts. + * @pseudo + * @constructor + * @name Bisector + * @type JXG.Line + * @augments JXG.Line + * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The angle described by <tt>p1</tt>, <tt>p2</tt> and <tt>p3</tt> will + * be divided into two equal angles. + * @example + * var p1 = board.create('point', [6.0, 4.0]); + * var p2 = board.create('point', [3.0, 2.0]); + * var p3 = board.create('point', [1.0, 7.0]); + * + * var bi1 = board.create('bisector', [p1, p2, p3]); + * </pre><div class="jxgbox" id="JXG0d58cea8-b06a-407c-b27c-0908f508f5a4" style="width: 400px; height: 400px;"></div> + * <script type="text/javascript"> + * (function () { + * var board = JXG.JSXGraph.initBoard('JXG0d58cea8-b06a-407c-b27c-0908f508f5a4', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); + * var p1 = board.create('point', [6.0, 4.0]); + * var p2 = board.create('point', [3.0, 2.0]); + * var p3 = board.create('point', [1.0, 7.0]); + * var bi1 = board.create('bisector', [p1, p2, p3]); + * })(); + * </script><pre> + */ + JXG.createBisector = function (board, parents, attributes) { + var p, l, i, attr; - // documented in AbstractRenderer - unsuspendRedraw: function () { - this.context.restore(); - }, + parents = Type.providePoints(board, parents, attributes, 'point'); + if (Type.isPoint(parents[0]) && Type.isPoint(parents[1]) && Type.isPoint(parents[2])) { + // hidden and fixed helper + attr = Type.copyAttributes(attributes, board.options, 'bisector', 'point'); + attr.snapToGrid = false; - // document in AbstractRenderer - resize: function (w, h) { - if (this.container) { - this.canvasRoot.style.width = parseFloat(w) + 'px'; - this.canvasRoot.style.height = parseFloat(h) + 'px'; + p = board.create('point', [ + function () { + return Geometry.angleBisector(parents[0], parents[1], parents[2], board); + } + ], attr); + p.dump = false; - this.canvasRoot.setAttribute('width', (2 * parseFloat(w)) + 'px'); - this.canvasRoot.setAttribute('height',(2 * parseFloat(h)) + 'px'); - } else { - this.canvasRoot.width = 2 * parseFloat(w); - this.canvasRoot.height = 2 * parseFloat(h); + for (i = 0; i < 3; i++) { + // required for algorithm requiring dependencies between elements + if (Type.exists(parents[i]._is_new)) { + p.addChild(parents[i]); + delete parents[i]._is_new; + } else { + parents[i].addChild(p); + } } - this.context = this.canvasRoot.getContext('2d'); - // The width and height of the canvas is set to twice the CSS values, - // followed by an appropiate scaling. - // See http://stackoverflow.com/questions/22416462/canvas-element-with-blurred-lines - this.context.scale(2, 2); - }, - - removeToInsertLater: function () { - return function () {}; - } - }); - return JXG.CanvasRenderer; -}); - -/* - Copyright 2008-2021 - Matthias Ehmann, - Michael Gerhaeuser, - Carsten Miller, - Bianca Valentin, - Alfred Wassermann, - Peter Wilfahrt - - This file is part of JSXGraph. - - JSXGraph is free software dual licensed under the GNU LGPL or MIT License. + if (!Type.exists(attributes.layer)) { + attributes.layer = board.options.layer.line; + } - You can redistribute it and/or modify it under the terms of the + attr = Type.copyAttributes(attributes, board.options, 'bisector'); + l = Line.createLine(board, [parents[1], p], attr); - * GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version - OR - * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT + /** + * Helper point + * @memberOf Bisector.prototype + * @type Point + * @name point + */ + l.point = p; - JSXGraph is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. + l.elType = 'bisector'; + l.setParents(parents); + l.subs = { + point: p + }; + l.inherits.push(p); - You should have received a copy of the GNU Lesser General Public License and - the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> - and <http://opensource.org/licenses/MIT/>. - */ + return l; + } + throw new Error("JSXGraph: Can't create angle bisector with parent types '" + + (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + + "\nPossible parent types: [point,point,point]"); + }; -/*global JXG: true, define: true, AMprocessNode: true, MathJax: true, document: true */ -/*jslint nomen: true, plusplus: true, newcap:true*/ + /** + * @class Bisector lines are similar to {@link Bisector} but take two lines as parent elements. The resulting element is + * a composition of two lines. + * @pseudo + * @constructor + * @name Bisectorlines + * @type JXG.Composition + * @augments JXG.Composition + * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {JXG.Line_JXG.Line} l1,l2 The four angles described by the lines <tt>l1</tt> and <tt>l2</tt> will each + * be divided into two equal angles. + * @example + * var p1 = board.create('point', [6.0, 4.0]); + * var p2 = board.create('point', [3.0, 2.0]); + * var p3 = board.create('point', [1.0, 7.0]); + * var p4 = board.create('point', [3.0, 0.0]); + * var l1 = board.create('line', [p1, p2]); + * var l2 = board.create('line', [p3, p4]); + * + * var bi1 = board.create('bisectorlines', [l1, l2]); + * </pre><div class="jxgbox" id="JXG3121ff67-44f0-4dda-bb10-9cda0b80bf18" style="width: 400px; height: 400px;"></div> + * <script type="text/javascript"> + * (function () { + * var board = JXG.JSXGraph.initBoard('JXG3121ff67-44f0-4dda-bb10-9cda0b80bf18', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); + * var p1 = board.create('point', [6.0, 4.0]); + * var p2 = board.create('point', [3.0, 2.0]); + * var p3 = board.create('point', [1.0, 7.0]); + * var p4 = board.create('point', [3.0, 0.0]); + * var l1 = board.create('line', [p1, p2]); + * var l2 = board.create('line', [p3, p4]); + * var bi1 = board.create('bisectorlines', [l1, l2]); + * })(); + * </script><pre> + */ + JXG.createAngularBisectorsOfTwoLines = function (board, parents, attributes) { + // The angular bisectors of two line [c1,a1,b1] and [c2,a2,b2] are determined by the equation: + // (a1*x+b1*y+c1*z)/sqrt(a1^2+b1^2) = +/- (a2*x+b2*y+c2*z)/sqrt(a2^2+b2^2) -/* depends: - jxg - renderer/abstract -*/ + var g1, g2, attr, ret, + l1 = board.select(parents[0]), + l2 = board.select(parents[1]); -/** - * @fileoverview JSXGraph can use various technologies to render the contents of a construction, e.g. - * SVG, VML, and HTML5 Canvas. To accomplish this, The rendering and the logic and control mechanisms - * are completely separated from each other. Every rendering technology has it's own class, called - * Renderer, e.g. SVGRenderer for SVG, the same for VML and Canvas. The common base for all available - * renderers is the class AbstractRenderer. - */ + if (l1.elementClass !== Const.OBJECT_CLASS_LINE || l2.elementClass !== Const.OBJECT_CLASS_LINE) { + throw new Error("JSXGraph: Can't create angle bisectors of two lines with parent types '" + + (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + + "\nPossible parent types: [line,line]"); + } -define('renderer/no',['jxg', 'renderer/abstract'], function (JXG, AbstractRenderer) { + if (!Type.exists(attributes.layer)) { + attributes.layer = board.options.layer.line; + } - "use strict"; + attr = Type.copyAttributes(attributes, board.options, 'bisectorlines', 'line1'); + g1 = board.create('line', [ + function () { + var d1 = Math.sqrt(l1.stdform[1] * l1.stdform[1] + l1.stdform[2] * l1.stdform[2]), + d2 = Math.sqrt(l2.stdform[1] * l2.stdform[1] + l2.stdform[2] * l2.stdform[2]); - /** - * This renderer draws nothing. It is intended to be used in environments where none of our rendering engines - * are available, e.g. WebWorkers. - * @class JXG.AbstractRenderer - */ - JXG.NoRenderer = function () { - /** - * If this property is set to <tt>true</tt> the visual properties of the elements are updated - * on every update. Visual properties means: All the stuff stored in the - * {@link JXG.GeometryElement#visProp} property won't be set if enhancedRendering is <tt>false</tt> - * @type Boolean - * @default true - */ - this.enhancedRendering = false; + return l1.stdform[0] / d1 - l2.stdform[0] / d2; + }, + function () { + var d1 = Math.sqrt(l1.stdform[1] * l1.stdform[1] + l1.stdform[2] * l1.stdform[2]), + d2 = Math.sqrt(l2.stdform[1] * l2.stdform[1] + l2.stdform[2] * l2.stdform[2]); - /** - * This is used to easily determine which renderer we are using - * @example if (board.renderer.type === 'vml') { - * // do something - * } - * @type String - */ - this.type = 'no'; - }; + return l1.stdform[1] / d1 - l2.stdform[1] / d2; + }, + function () { + var d1 = Math.sqrt(l1.stdform[1] * l1.stdform[1] + l1.stdform[2] * l1.stdform[2]), + d2 = Math.sqrt(l2.stdform[1] * l2.stdform[1] + l2.stdform[2] * l2.stdform[2]); - JXG.extend(JXG.NoRenderer.prototype, /** @lends JXG.AbstractRenderer.prototype */ { - /* ******************************** * - * Point drawing and updating * - * ******************************** */ + return l1.stdform[2] / d1 - l2.stdform[2] / d2; + } + ], attr); - /** - * Draws a point on the {@link JXG.Board}. - * @param {JXG.Point} element Reference to a {@link JXG.Point} object that has to be drawn. - * @see Point - * @see JXG.Point - * @see JXG.AbstractRenderer#updatePoint - * @see JXG.AbstractRenderer#changePointStyle - */ - drawPoint: function (element) {}, + if (!Type.exists(attributes.layer)) { + attributes.layer = board.options.layer.line; + } + attr = Type.copyAttributes(attributes, board.options, 'bisectorlines', 'line2'); + g2 = board.create('line', [ + function () { + var d1 = Math.sqrt(l1.stdform[1] * l1.stdform[1] + l1.stdform[2] * l1.stdform[2]), + d2 = Math.sqrt(l2.stdform[1] * l2.stdform[1] + l2.stdform[2] * l2.stdform[2]); - /** - * Updates visual appearance of the renderer element assigned to the given {@link JXG.Point}. - * @param {JXG.Point} element Reference to a {@link JXG.Point} object, that has to be updated. - * @see Point - * @see JXG.Point - * @see JXG.AbstractRenderer#drawPoint - * @see JXG.AbstractRenderer#changePointStyle - */ - updatePoint: function (element) { }, + return l1.stdform[0] / d1 + l2.stdform[0] / d2; + }, + function () { + var d1 = Math.sqrt(l1.stdform[1] * l1.stdform[1] + l1.stdform[2] * l1.stdform[2]), + d2 = Math.sqrt(l2.stdform[1] * l2.stdform[1] + l2.stdform[2] * l2.stdform[2]); - /** - * Changes the style of a {@link JXG.Point}. This is required because the point styles differ in what - * elements have to be drawn, e.g. if the point is marked by a "x" or a "+" two lines are drawn, if - * it's marked by spot a circle is drawn. This method removes the old renderer element(s) and creates - * the new one(s). - * @param {JXG.Point} element Reference to a {@link JXG.Point} object, that's style is changed. - * @see Point - * @see JXG.Point - * @see JXG.AbstractRenderer#updatePoint - * @see JXG.AbstractRenderer#drawPoint - */ - changePointStyle: function (element) { }, + return l1.stdform[1] / d1 + l2.stdform[1] / d2; + }, + function () { + var d1 = Math.sqrt(l1.stdform[1] * l1.stdform[1] + l1.stdform[2] * l1.stdform[2]), + d2 = Math.sqrt(l2.stdform[1] * l2.stdform[1] + l2.stdform[2] * l2.stdform[2]); - /* ******************************** * - * Lines * - * ******************************** */ + return l1.stdform[2] / d1 + l2.stdform[2] / d2; + } + ], attr); + // documentation /** - * Draws a line on the {@link JXG.Board}. - * @param {JXG.Line} element Reference to a line object, that has to be drawn. - * @see Line - * @see JXG.Line - * @see JXG.AbstractRenderer#updateLine + * First line. + * @memberOf Bisectorlines.prototype + * @name line1 + * @type Line */ - drawLine: function (element) { }, /** - * Updates visual appearance of the renderer element assigned to the given {@link JXG.Line}. - * @param {JXG.Line} element Reference to the {@link JXG.Line} object that has to be updated. - * @see Line - * @see JXG.Line - * @see JXG.AbstractRenderer#drawLine + * Second line. + * @memberOf Bisectorlines.prototype + * @name line2 + * @type Line */ - updateLine: function (element) { }, - /** - * Creates a rendering node for ticks added to a line. - * @param {JXG.Line} element A arbitrary line. - * @see Line - * @see Ticks - * @see JXG.Line - * @see JXG.Ticks - * @see JXG.AbstractRenderer#updateTicks - */ - drawTicks: function (element) { }, + ret = new Composition({line1: g1, line2: g2}); - /** - * Update {@link Ticks} on a {@link JXG.Line}. This method is only a stub and has to be implemented - * in any descendant renderer class. - * @param {JXG.Line} element Reference of an line object, thats ticks have to be updated. - * @see Line - * @see Ticks - * @see JXG.Line - * @see JXG.Ticks - * @see JXG.AbstractRenderer#drawTicks - */ - updateTicks: function (element) { /* stub */ }, + g1.dump = false; + g2.dump = false; - /* ************************** - * Curves - * **************************/ + ret.elType = 'bisectorlines'; + ret.setParents([l1.id, l2.id]); + ret.subs = { + line1: g1, + line2: g2 + }; + // ret.inherits.push(g1, g2); - /** - * Draws a {@link JXG.Curve} on the {@link JXG.Board}. - * @param {JXG.Curve} element Reference to a graph object, that has to be plotted. - * @see Curve - * @see JXG.Curve - * @see JXG.AbstractRenderer#updateCurve - */ - drawCurve: function (element) { }, + return ret; + }; - /** - * Updates visual appearance of the renderer element assigned to the given {@link JXG.Curve}. - * @param {JXG.Curve} element Reference to a {@link JXG.Curve} object, that has to be updated. - * @see Curve - * @see JXG.Curve - * @see JXG.AbstractRenderer#drawCurve - */ - updateCurve: function (element) { }, + // /** + // * @class An m-sector is a line which divides an angle into two angles. It is given by three points A, B, and + // * C and a real number m, and divides an angle into two angles, an angle with amplitude m and an angle with + // * amplitude (1-m) + // * @pseudo + // * @constructor + // * @name Msector + // * @type JXG.Line + // * @augments JXG.Line + // * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. + // * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The angle described by <tt>p1</tt>, <tt>p2</tt> and <tt>p3</tt> will + // * be divided into two angles according to the value of <tt>m</tt>. + // * @example + // * var p1 = board.create('point', [6.0, 4.0]); + // * var p2 = board.create('point', [3.0, 2.0]); + // * var p3 = board.create('point', [1.0, 7.0]); + // * + // * var bi1 = board.create('msector', [p1, p2, p3], 1/5); + // * </pre><div id="JXG0d58cea8-b06a-407c-b27c-0908f508f5a4" style="width: 400px; height: 400px;"></div> + // * <script type="text/javascript"> + // * (function () { + // * var board = JXG.JSXGraph.initBoard('JXG0d58cea8-b06a-407c-b27c-0908f508f5a4', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); + // * var p1 = board.create('point', [6.0, 4.0]); + // * var p2 = board.create('point', [3.0, 2.0]); + // * var p3 = board.create('point', [1.0, 7.0]); + // * var bi1 = board.create('msector', [p1, p2, p3], 1/5); + // * })(); + // * </script><pre> + // */ + // JXG.createMsector = function (board, parents, attributes) { + // var p, l, i, attr; - /* ************************** - * Circle related stuff - * **************************/ + // if (parents[0].elementClass === Const.OBJECT_CLASS_POINT && + // parents[1].elementClass === Const.OBJECT_CLASS_POINT && + // parents[2].elementClass === Const.OBJECT_CLASS_POINT) { + // // hidden and fixed helper + // attr = Type.copyAttributes(attributes, board.options, 'msector', 'point'); + // p = board.create('point', [ + // function () { + // return Geometry.angleMsector(parents[0], parents[1], parents[2], parents[3], board); + // } + // ], attr); + // p.dump = false; - /** - * Draws a {@link JXG.Circle} - * @param {JXG.Circle} element Reference to a {@link JXG.Circle} object that has to be drawn. - * @see Circle - * @see JXG.Circle - * @see JXG.AbstractRenderer#updateEllipse - */ - drawEllipse: function (element) { }, + // for (i = 0; i < 3; i++) { + // // required for algorithm requiring dependencies between elements + // parents[i].addChild(p); + // } - /** - * Updates visual appearance of a given {@link JXG.Circle} on the {@link JXG.Board}. - * @param {JXG.Circle} element Reference to a {@link JXG.Circle} object, that has to be updated. - * @see Circle - * @see JXG.Circle - * @see JXG.AbstractRenderer#drawEllipse - */ - updateEllipse: function (element) { }, + // if (!Type.exists(attributes.layer)) { + // attributes.layer = board.options.layer.line; + // } + // attr = Type.copyAttributes(attributes, board.options, 'msector'); + // l = Line.createLine(board, [parents[1], p], attr); - /* ************************** - * Polygon related stuff - * **************************/ + // /** + // * Helper point + // * @memberOf Msector.prototype + // * @type Point + // * @name point + // */ + // l.point = p; - /** - * Draws a {@link JXG.Polygon} on the {@link JXG.Board}. - * @param {JXG.Polygon} element Reference to a Polygon object, that is to be drawn. - * @see Polygon - * @see JXG.Polygon - * @see JXG.AbstractRenderer#updatePolygon - */ - drawPolygon: function (element) { }, + // l.elType = 'msector'; + // l.parents = [parents[0].id, parents[1].id, parents[2].id]; + // l.subs = { + // point: p + // }; + // l.inherits.push(p); - /** - * Updates properties of a {@link JXG.Polygon}'s rendering node. - * @param {JXG.Polygon} element Reference to a {@link JXG.Polygon} object, that has to be updated. - * @see Polygon - * @see JXG.Polygon - * @see JXG.AbstractRenderer#drawPolygon - */ - updatePolygon: function (element) { }, + // return l; + // } - /* ************************** - * Text related stuff - * **************************/ + // throw new Error("JSXGraph: Can't create angle msector with parent types '" + + // (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + + // "\nPossible parent types: [point,point,point,Number]"); + // }; - /** - * Shows a small copyright notice in the top left corner of the board. - * @param {String} str The copyright notice itself - * @param {Number} fontsize Size of the font the copyright notice is written in - */ - displayCopyright: function (str, fontsize) { /* stub */ }, + /** + * @class Constructs the midpoint of a {@link Circumcircle}. Like the circumcircle the circumcenter + * is constructed by providing three points. + * @pseudo + * @description A circumcenter is given by three points which are all lying on the circle with the + * constructed circumcenter as the midpoint. + * @constructor + * @name Circumcenter + * @type JXG.Point + * @augments JXG.Point + * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The constructed point is the midpoint of the circle determined + * by p1, p2, and p3. + * @example + * var p1 = board.create('point', [0.0, 2.0]); + * var p2 = board.create('point', [2.0, 1.0]); + * var p3 = board.create('point', [3.0, 3.0]); + * + * var cc1 = board.create('circumcenter', [p1, p2, p3]); + * </pre><div class="jxgbox" id="JXGe8a40f95-bf30-4eb4-88a8-f4d5495261fd" style="width: 400px; height: 400px;"></div> + * <script type="text/javascript"> + * var ccmex1_board = JXG.JSXGraph.initBoard('JXGe8a40f95-bf30-4eb4-88a8-f4d5495261fd', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); + * var ccmex1_p1 = ccmex1_board.create('point', [0.0, 2.0]); + * var ccmex1_p2 = ccmex1_board.create('point', [6.0, 1.0]); + * var ccmex1_p3 = ccmex1_board.create('point', [3.0, 7.0]); + * var ccmex1_cc1 = ccmex1_board.create('circumcenter', [ccmex1_p1, ccmex1_p2, ccmex1_p3]); + * </script><pre> + */ + JXG.createCircumcenter = function (board, parents, attributes) { + var p, i, a, b, c; - /** - * An internal text is a {@link JXG.Text} element which is drawn using only - * the given renderer but no HTML. This method is only a stub, the drawing - * is done in the special renderers. - * @param {JXG.Text} element Reference to a {@link JXG.Text} object - * @see Text - * @see JXG.Text - * @see JXG.AbstractRenderer#updateInternalText - * @see JXG.AbstractRenderer#drawText - * @see JXG.AbstractRenderer#updateText - * @see JXG.AbstractRenderer#updateTextStyle - */ - drawInternalText: function (element) { /* stub */ }, + parents = Type.providePoints(board, parents, attributes, 'point'); + if (Type.isPoint(parents[0]) && Type.isPoint(parents[1]) && Type.isPoint(parents[2])) { - /** - * Updates visual properties of an already existing {@link JXG.Text} element. - * @param {JXG.Text} element Reference to an {@link JXG.Text} object, that has to be updated. - * @see Text - * @see JXG.Text - * @see JXG.AbstractRenderer#drawInternalText - * @see JXG.AbstractRenderer#drawText - * @see JXG.AbstractRenderer#updateText - * @see JXG.AbstractRenderer#updateTextStyle - */ - updateInternalText: function (element) { /* stub */ }, + a = parents[0]; + b = parents[1]; + c = parents[2]; - /** - * Displays a {@link JXG.Text} on the {@link JXG.Board} by putting a HTML div over it. - * @param {JXG.Text} element Reference to an {@link JXG.Text} object, that has to be displayed - * @see Text - * @see JXG.Text - * @see JXG.AbstractRenderer#drawInternalText - * @see JXG.AbstractRenderer#updateText - * @see JXG.AbstractRenderer#updateInternalText - * @see JXG.AbstractRenderer#updateTextStyle - */ - drawText: function (element) { }, + p = Point.createPoint(board, [ + function () { + return Geometry.circumcenter(a, b, c, board); + } + ], attributes); - /** - * Updates visual properties of an already existing {@link JXG.Text} element. - * @param {JXG.Text} element Reference to an {@link JXG.Text} object, that has to be updated. - * @see Text - * @see JXG.Text - * @see JXG.AbstractRenderer#drawText - * @see JXG.AbstractRenderer#drawInternalText - * @see JXG.AbstractRenderer#updateInternalText - * @see JXG.AbstractRenderer#updateTextStyle - */ - updateText: function (element) { }, + for (i = 0; i < 3; i++) { + if (Type.exists(parents[i]._is_new)) { + p.addChild(parents[i]); + delete parents[i]._is_new; + } else { + parents[i].addChild(p); + } + } - /** - * Updates CSS style properties of a {@link JXG.Text} node. - * @param {JXG.Text} element Reference to the {@link JXG.Text} object, that has to be updated. - * @param {Boolean} doHighlight - * @see Text - * @see JXG.Text - * @see JXG.AbstractRenderer#drawText - * @see JXG.AbstractRenderer#drawInternalText - * @see JXG.AbstractRenderer#updateText - * @see JXG.AbstractRenderer#updateInternalText - */ - updateTextStyle: function (element, doHighlight) { }, + p.elType = 'circumcenter'; + p.setParents(parents); - /** - * Set color and opacity of internal texts. - * SVG needs its own version. - * @private - * @see JXG.AbstractRenderer#updateTextStyle - * @see JXG.AbstractRenderer#updateInternalTextStyle - */ - updateInternalTextStyle: function (element, strokeColor, strokeOpacity) { /* stub */ }, + p.generatePolynomial = function () { + /* + * CircumcircleMidpoint takes three points A, B and C and creates point M, which is the circumcenter of A, B, and C. + * + * + * So we have two conditions: + * + * (a) CT == AT (distance condition I) + * (b) BT == AT (distance condition II) + * + */ + var a1 = a.symbolic.x, + a2 = a.symbolic.y, + b1 = b.symbolic.x, + b2 = b.symbolic.y, + c1 = c.symbolic.x, + c2 = c.symbolic.y, + t1 = p.symbolic.x, + t2 = p.symbolic.y, - /* ************************** - * Image related stuff - * **************************/ + poly1 = ['((', t1, ')-(', a1, '))^2+((', t2, ')-(', a2, '))^2-((', t1, ')-(', b1, '))^2-((', t2, ')-(', b2, '))^2'].join(''), + poly2 = ['((', t1, ')-(', a1, '))^2+((', t2, ')-(', a2, '))^2-((', t1, ')-(', c1, '))^2-((', t2, ')-(', c2, '))^2'].join(''); - /** - * Draws an {@link JXG.Image} on a board; This is just a template that has to be implemented by special renderers. - * @param {JXG.Image} element Reference to the image object that is to be drawn - * @see Image - * @see JXG.Image - * @see JXG.AbstractRenderer#updateImage - */ - drawImage: function (element) { /* stub */ }, + return [poly1, poly2]; + }; - /** - * Updates the properties of an {@link JXG.Image} element. - * @param {JXG.Image} element Reference to an {@link JXG.Image} object, that has to be updated. - * @see Image - * @see JXG.Image - * @see JXG.AbstractRenderer#drawImage - */ - updateImage: function (element) { }, + return p; + } - /** - * Applies transformations on images and text elements. This method is just a stub and has to be implemented in all - * descendant classes where text and image transformations are to be supported. - * @param {JXG.Image|JXG.Text} element A {@link JXG.Image} or {@link JXG.Text} object. - * @param {Array} transformations An array of {@link JXG.Transformation} objects. This is usually the transformations property - * of the given element <tt>el</tt>. - */ - transformImage: function (element, transformations) { /* stub */ }, + throw new Error("JSXGraph: Can't create circumcircle midpoint with parent types '" + + (typeof parents[0]) + "', '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." + + "\nPossible parent types: [point,point,point]"); + }; - /** - * If the URL of the image is provided by a function the URL has to be updated during updateImage() - * @param {JXG.Image} element Reference to an image object. - * @see JXG.AbstractRenderer#updateImage - */ - updateImageURL: function (element) { /* stub */ }, + /** + * @class Constructs the incenter of the triangle described by the three given points.{@link http://mathworld.wolfram.com/Incenter.html} + * @pseudo + * @constructor + * @name Incenter + * @type JXG.Point + * @augments JXG.Point + * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The constructed point is the incenter of the triangle described + * by p1, p2, and p3. + * @example + * var p1 = board.create('point', [0.0, 2.0]); + * var p2 = board.create('point', [2.0, 1.0]); + * var p3 = board.create('point', [3.0, 3.0]); + * + * var ic1 = board.create('incenter', [p1, p2, p3]); + * </pre><div class="jxgbox" id="JXGe8a40f95-bf30-4eb4-88a8-a2d5495261fd" style="width: 400px; height: 400px;"></div> + * <script type="text/javascript"> + * var icmex1_board = JXG.JSXGraph.initBoard('JXGe8a40f95-bf30-4eb4-88a8-a2d5495261fd', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); + * var icmex1_p1 = icmex1_board.create('point', [0.0, 2.0]); + * var icmex1_p2 = icmex1_board.create('point', [6.0, 1.0]); + * var icmex1_p3 = icmex1_board.create('point', [3.0, 7.0]); + * var icmex1_ic1 = icmex1_board.create('incenter', [icmex1_p1, icmex1_p2, icmex1_p3]); + * </script><pre> + */ + JXG.createIncenter = function (board, parents, attributes) { + var p, A, B, C, i; - /* ************************** - * Render primitive objects - * **************************/ + parents = Type.providePoints(board, parents, attributes, 'point'); + if (parents.length >= 3 && Type.isPoint(parents[0]) && Type.isPoint(parents[1]) && Type.isPoint(parents[2])) { + A = parents[0]; + B = parents[1]; + C = parents[2]; - /** - * Appends a node to a specific layer level. This is just an abstract method and has to be implemented - * in all renderers that want to use the <tt>createPrim</tt> model to draw. - * @param {Node} node A DOM tree node. - * @param {Number} level The layer the node is attached to. This is the index of the layer in - * {@link JXG.SVGRenderer#layer} or the <tt>z-index</tt> style property of the node in VMLRenderer. - */ - appendChildPrim: function (node, level) { /* stub */ }, + p = board.create('point', [function () { + var a, b, c; - /** - * Stores the rendering nodes. This is an abstract method which has to be implemented in all renderers that use - * the <tt>createPrim</tt> method. - * @param {JXG.GeometryElement} element A JSXGraph element. - * @param {String} type The XML node name. Only used in VMLRenderer. - */ - appendNodesToElement: function (element, type) { /* stub */ }, + a = Math.sqrt((B.X() - C.X()) * (B.X() - C.X()) + (B.Y() - C.Y()) * (B.Y() - C.Y())); + b = Math.sqrt((A.X() - C.X()) * (A.X() - C.X()) + (A.Y() - C.Y()) * (A.Y() - C.Y())); + c = Math.sqrt((B.X() - A.X()) * (B.X() - A.X()) + (B.Y() - A.Y()) * (B.Y() - A.Y())); - /** - * Creates a node of a given type with a given id. - * @param {String} type The type of the node to create. - * @param {String} id Set the id attribute to this. - * @returns {Node} Reference to the created node. - */ - createPrim: function (type, id) { - /* stub */ - return null; - }, + return new Coords(Const.COORDS_BY_USER, [(a * A.X() + b * B.X() + c * C.X()) / (a + b + c), (a * A.Y() + b * B.Y() + c * C.Y()) / (a + b + c)], board); + }], attributes); - /** - * Removes an element node. Just a stub. - * @param {Node} node The node to remove. - */ - remove: function (node) { /* stub */ }, + for (i = 0; i < 3; i++) { + if (Type.exists(parents[i]._is_new)) { + p.addChild(parents[i]); + delete parents[i]._is_new; + } else { + parents[i].addChild(p); + } + } + + p.elType = 'incenter'; + p.setParents(parents); + + } else { + throw new Error("JSXGraph: Can't create incenter with parent types '" + + (typeof parents[0]) + "', '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." + + "\nPossible parent types: [point,point,point]"); + } + + return p; + }; + + /** + * @class A circumcircle is given by three points which are all lying on the circle. + * @pseudo + * @constructor + * @name Circumcircle + * @type JXG.Circle + * @augments JXG.Circle + * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The constructed element is the circle determined by <tt>p1</tt>, <tt>p2</tt>, and <tt>p3</tt>. + * @example + * var p1 = board.create('point', [0.0, 2.0]); + * var p2 = board.create('point', [2.0, 1.0]); + * var p3 = board.create('point', [3.0, 3.0]); + * + * var cc1 = board.create('circumcircle', [p1, p2, p3]); + * </pre><div class="jxgbox" id="JXGe65c9861-0bf0-402d-af57-3ab11962f5ac" style="width: 400px; height: 400px;"></div> + * <script type="text/javascript"> + * var ccex1_board = JXG.JSXGraph.initBoard('JXGe65c9861-0bf0-402d-af57-3ab11962f5ac', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); + * var ccex1_p1 = ccex1_board.create('point', [0.0, 2.0]); + * var ccex1_p2 = ccex1_board.create('point', [6.0, 1.0]); + * var ccex1_p3 = ccex1_board.create('point', [3.0, 7.0]); + * var ccex1_cc1 = ccex1_board.create('circumcircle', [ccex1_p1, ccex1_p2, ccex1_p3]); + * </script><pre> + */ + JXG.createCircumcircle = function (board, parents, attributes) { + var p, c, attr, i; + + parents = Type.providePoints(board, parents, attributes, 'point'); + if (parents === false) { + throw new Error("JSXGraph: Can't create circumcircle with parent types '" + + (typeof parents[0]) + "', '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." + + "\nPossible parent types: [point,point,point]"); + } + + try { + attr = Type.copyAttributes(attributes, board.options, 'circumcircle', 'center'); + p = JXG.createCircumcenter(board, parents, attr); + + p.dump = false; + + if (!Type.exists(attributes.layer)) { + attributes.layer = board.options.layer.circle; + } + attr = Type.copyAttributes(attributes, board.options, 'circumcircle'); + c = Circle.createCircle(board, [p, parents[0]], attr); + + c.elType = 'circumcircle'; + c.setParents(parents); + c.subs = { + center: p + }; + c.inherits.push(c); + for (i = 0; i < 3; i++) { + if (Type.exists(parents[i]._is_new)) { + c.addChild(parents[i]); + delete parents[i]._is_new; + } else { + parents[i].addChild(c); + } + } + + } catch (e) { + throw new Error("JSXGraph: Can't create circumcircle with parent types '" + + (typeof parents[0]) + "', '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." + + "\nPossible parent types: [point,point,point]"); + } - /** - * Can be used to create the nodes to display arrows. This is an abstract method which has to be implemented - * in any descendant renderer. - * @param {JXG.GeometryElement} element The element the arrows are to be attached to. - */ - makeArrows: function (element) { /* stub */ }, + // p is already stored as midpoint in c so there's no need to store it explicitly. - /** - * Updates an ellipse node primitive. This is an abstract method which has to be implemented in all renderers - * that use the <tt>createPrim</tt> method. - * @param {Node} node Reference to the node. - * @param {Number} x Centre X coordinate - * @param {Number} y Centre Y coordinate - * @param {Number} rx The x-axis radius. - * @param {Number} ry The y-axis radius. - */ - updateEllipsePrim: function (node, x, y, rx, ry) { /* stub */ }, + return c; + }; - /** - * Refreshes a line node. This is an abstract method which has to be implemented in all renderers that use - * the <tt>createPrim</tt> method. - * @param {Node} node The node to be refreshed. - * @param {Number} p1x The first point's x coordinate. - * @param {Number} p1y The first point's y coordinate. - * @param {Number} p2x The second point's x coordinate. - * @param {Number} p2y The second point's y coordinate. - * @param {JXG.Board} board - */ - updateLinePrim: function (node, p1x, p1y, p2x, p2y, board) { /* stub */ }, + /** + * @class An incircle is given by three points. + * @pseudo + * @constructor + * @name Incircle + * @type JXG.Circle + * @augments JXG.Circle + * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The constructed point is the midpoint of the incircle of + * <tt>p1</tt>, <tt>p2</tt>, and <tt>p3</tt>. + * @example + * var p1 = board.create('point', [0.0, 2.0]); + * var p2 = board.create('point', [2.0, 1.0]); + * var p3 = board.create('point', [3.0, 3.0]); + * + * var ic1 = board.create('incircle', [p1, p2, p3]); + * </pre><div class="jxgbox" id="JXGe65c9861-0bf0-402d-af57-2ab12962f8ac" style="width: 400px; height: 400px;"></div> + * <script type="text/javascript"> + * var icex1_board = JXG.JSXGraph.initBoard('JXGe65c9861-0bf0-402d-af57-2ab12962f8ac', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); + * var icex1_p1 = icex1_board.create('point', [0.0, 2.0]); + * var icex1_p2 = icex1_board.create('point', [6.0, 1.0]); + * var icex1_p3 = icex1_board.create('point', [3.0, 7.0]); + * var icex1_ic1 = icex1_board.create('incircle', [icex1_p1, icex1_p2, icex1_p3]); + * </script><pre> + */ + JXG.createIncircle = function (board, parents, attributes) { + var i, p, c, attr; - /** - * Updates a path element. This is an abstract method which has to be implemented in all renderers that use - * the <tt>createPrim</tt> method. - * @param {Node} node The path node. - * @param {String} pathString A string formatted like e.g. <em>'M 1,2 L 3,1 L5,5'</em>. The format of the string - * depends on the rendering engine. - * @param {JXG.Board} board Reference to the element's board. - */ - updatePathPrim: function (node, pathString, board) { /* stub */ }, + parents = Type.providePoints(board, parents, attributes, 'point'); + if (parents === false) { + throw new Error("JSXGraph: Can't create circumcircle with parent types '" + + (typeof parents[0]) + "', '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." + + "\nPossible parent types: [point,point,point]"); + } + try { + attr = Type.copyAttributes(attributes, board.options, 'incircle', 'center'); + p = JXG.createIncenter(board, parents, attr); - /** - * Builds a path data string to draw a point with a face other than <em>rect</em> and <em>circle</em>. Since - * the format of such a string usually depends on the renderer this method - * is only an abstract method. Therefore, it has to be implemented in the descendant renderer itself unless - * the renderer does not use the createPrim interface but the draw* interfaces to paint. - * @param {JXG.Point} element The point element - * @param {Number} size A positive number describing the size. Usually the half of the width and height of - * the drawn point. - * @param {String} type A string describing the point's face. This method only accepts the shortcut version of - * each possible face: <tt>x, +, <>, ^, v, >, < - */ - updatePathStringPoint: function (element, size, type) { /* stub */ }, + p.dump = false; - /** - * Builds a path data string from a {@link JXG.Curve} element. Since the path data strings heavily depend on the - * underlying rendering technique this method is just a stub. Although such a path string is of no use for the - * CanvasRenderer, this method is used there to draw a path directly. - * @param element - */ - updatePathStringPrim: function (element) { /* stub */ }, + if (!Type.exists(attributes.layer)) { + attributes.layer = board.options.layer.circle; + } + attr = Type.copyAttributes(attributes, board.options, 'incircle'); + c = Circle.createCircle(board, [p, function () { + var a = Math.sqrt((parents[1].X() - parents[2].X()) * (parents[1].X() - parents[2].X()) + (parents[1].Y() - parents[2].Y()) * (parents[1].Y() - parents[2].Y())), + b = Math.sqrt((parents[0].X() - parents[2].X()) * (parents[0].X() - parents[2].X()) + (parents[0].Y() - parents[2].Y()) * (parents[0].Y() - parents[2].Y())), + c = Math.sqrt((parents[1].X() - parents[0].X()) * (parents[1].X() - parents[0].X()) + (parents[1].Y() - parents[0].Y()) * (parents[1].Y() - parents[0].Y())), + s = (a + b + c) / 2; - /** - * Builds a path data string from a {@link JXG.Curve} element such that the curve looks like - * hand drawn. - * Since the path data strings heavily depend on the - * underlying rendering technique this method is just a stub. Although such a path string is of no use for the - * CanvasRenderer, this method is used there to draw a path directly. - * @param element - */ - updatePathStringBezierPrim: function (element) { /* stub */ }, + return Math.sqrt(((s - a) * (s - b) * (s - c)) / s); + }], attr); + c.elType = 'incircle'; + c.setParents(parents); + for (i = 0; i < 3; i++) { + if (Type.exists(parents[i]._is_new)) { + c.addChild(parents[i]); + delete parents[i]._is_new; + } else { + parents[i].addChild(c); + } + } - /** - * Update a polygon primitive. - * @param {Node} node - * @param {JXG.Polygon} element A JSXGraph element of type {@link JXG.Polygon} - */ - updatePolygonPrim: function (node, element) { /* stub */ }, + /** + * The center of the incircle + * @memberOf Incircle.prototype + * @type Incenter + * @name center + */ + c.center = p; - /** - * Update a rectangle primitive. This is used only for points with face of type 'rect'. - * @param {Node} node The node yearning to be updated. - * @param {Number} x x coordinate of the top left vertex. - * @param {Number} y y coordinate of the top left vertex. - * @param {Number} w Width of the rectangle. - * @param {Number} h The rectangle's height. - */ - updateRectPrim: function (node, x, y, w, h) { /* stub */ }, + c.subs = { + center: c.center + }; + c.inherits.push(p); - /* ************************** - * Set Attributes - * **************************/ + } catch (e) { + throw new Error("JSXGraph: Can't create circumcircle with parent types '" + + (typeof parents[0]) + "', '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." + + "\nPossible parent types: [point,point,point]"); + } - /** - * Sets a node's attribute. - * @param {Node} node The node that is to be updated. - * @param {String} key Name of the attribute. - * @param {String} val New value for the attribute. - */ - setPropertyPrim: function (node, key, val) { /* stub */ }, + // p is already stored as midpoint in c so there's no need to store it explicitly. - /** - * Shows or hides an element on the canvas; Only a stub, requires implementation in the derived renderer. - * @param {JXG.GeometryElement} element Reference to the object that has to appear. - * @param {Boolean} value true to show the element, false to hide the element. - */ - display: function (element, value) { - if (element) { - element.visPropOld.visible = value; - } - }, + return c; + }; - /** - * Shows a hidden element on the canvas; Only a stub, requires implementation in the derived renderer. - * - * Please use JXG.AbstractRenderer#display instead - * @param {JXG.GeometryElement} element Reference to the object that has to appear. - * @see JXG.AbstractRenderer#hide - * @deprecated - */ - show: function (element) { /* stub */ }, + /** + * @class This element is used to construct reflected elements (points, lines, circles, curves, polygons). + * @pseudo + * @description A reflected element (point, polygon, line or curve) is given by a given + * object of the same type and a line of reflection. + * It is determined by the reflection of the given element + * across the given line. + * @constructor + * @name Reflection + * @type JXG.GeometryElement + * @augments JXG.GeometryElement + * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {JXG.Point|JXG.Line|JXG.Curve|JXG.Polygon_JXG.Line} p,l The reflection element is the reflection of p across the line l. + * @example + * var p1 = board.create('point', [0.0, 4.0]); + * var p2 = board.create('point', [6.0, 1.0]); + * var l1 = board.create('line', [p1, p2]); + * var p3 = board.create('point', [3.0, 3.0]); + * + * var rp1 = board.create('reflection', [p3, l1]); + * </pre><div class="jxgbox" id="JXG087a798e-a36a-4f52-a2b4-29a23a69393b" style="width: 400px; height: 400px;"></div> + * <script type="text/javascript"> + * var rpex1_board = JXG.JSXGraph.initBoard('JXG087a798e-a36a-4f52-a2b4-29a23a69393b', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); + * var rpex1_p1 = rpex1_board.create('point', [0.0, 4.0]); + * var rpex1_p2 = rpex1_board.create('point', [6.0, 1.0]); + * var rpex1_l1 = rpex1_board.create('line', [rpex1_p1, rpex1_p2]); + * var rpex1_p3 = rpex1_board.create('point', [3.0, 3.0]); + * var rpex1_rp1 = rpex1_board.create('reflection', [rpex1_p3, rpex1_l1]); + * </script><pre> + * @example + * // Reflection of more elements + * // reflection line + * var li = board.create('line', [1,1,1], {strokeColor: '#aaaaaa'}); + * + * var p1 = board.create('point', [-3,-1], {name: "A"}); + * var q1 = board.create('reflection', [p1, li], {name: "A'"}); + * + * var l1 = board.create('line', [1,-5,1]); + * var l2 = board.create('reflection', [l1, li]); + * + * var cu1 = board.create('curve', [[-3, -3, -2.5, -3, -3, -2.5], [-3, -2, -2, -2, -2.5, -2.5]], {strokeWidth:3}); + * var cu2 = board.create('reflection', [cu1, li], {strokeColor: 'red', strokeWidth:3}); + * + * var pol1 = board.create('polygon', [[-6,-3], [-4,-5], [-5,-1.5]]); + * var pol2 = board.create('reflection', [pol1, li]); + * + * var c1 = board.create('circle', [[-2,-2], [-2, -1]]); + * var c2 = board.create('reflection', [c1, li]); + * + * var a1 = board.create('arc', [[1, 1], [0, 1], [1, 0]], {strokeColor: 'red'}); + * var a2 = board.create('reflection', [a1, li], {strokeColor: 'red'}); + * + * var s1 = board.create('sector', [[-3.5,-3], [-3.5, -2], [-3.5,-4]], { + * anglePoint: {visible:true}, center: {visible: true}, radiusPoint: {visible: true}, + * fillColor: 'yellow', strokeColor: 'black'}); + * var s2 = board.create('reflection', [s1, li], {fillColor: 'yellow', strokeColor: 'black', fillOpacity: 0.5}); + * + * var an1 = board.create('angle', [[-4,3.9], [-3, 4], [-3, 3]]); + * var an2 = board.create('reflection', [an1, li]); + * + * </pre><div id="JXG8f763af4-d449-11e7-93b3-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG8f763af4-d449-11e7-93b3-901b0e1b8723', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * // reflection line + * var li = board.create('line', [1,1,1], {strokeColor: '#aaaaaa'}); + * + * var p1 = board.create('point', [-3,-1], {name: "A"}); + * var q1 = board.create('reflection', [p1, li], {name: "A'"}); + * + * var l1 = board.create('line', [1,-5,1]); + * var l2 = board.create('reflection', [l1, li]); + * + * var cu1 = board.create('curve', [[-3, -3, -2.5, -3, -3, -2.5], [-3, -2, -2, -2, -2.5, -2.5]], {strokeWidth:3}); + * var cu2 = board.create('reflection', [cu1, li], {strokeColor: 'red', strokeWidth:3}); + * + * var pol1 = board.create('polygon', [[-6,-3], [-4,-5], [-5,-1.5]]); + * var pol2 = board.create('reflection', [pol1, li]); + * + * var c1 = board.create('circle', [[-2,-2], [-2, -1]]); + * var c2 = board.create('reflection', [c1, li]); + * + * var a1 = board.create('arc', [[1, 1], [0, 1], [1, 0]], {strokeColor: 'red'}); + * var a2 = board.create('reflection', [a1, li], {strokeColor: 'red'}); + * + * var s1 = board.create('sector', [[-3.5,-3], [-3.5, -2], [-3.5,-4]], { + * anglePoint: {visible:true}, center: {visible: true}, radiusPoint: {visible: true}, + * fillColor: 'yellow', strokeColor: 'black'}); + * var s2 = board.create('reflection', [s1, li], {fillColor: 'yellow', strokeColor: 'black', fillOpacity: 0.5}); + * + * var an1 = board.create('angle', [[-4,3.9], [-3, 4], [-3, 3]]); + * var an2 = board.create('reflection', [an1, li]); + * + * })(); + * + * </script><pre> + * + */ + JXG.createReflection = function (board, parents, attributes) { + var l, org, r, r_c, t, i, + attr, attr2, + errStr = "\nPossible parent types: [point|line|curve|polygon|circle|arc|sector, line]"; - /** - * Hides an element on the canvas; Only a stub, requires implementation in the derived renderer. - * - * Please use JXG.AbstractRenderer#display instead - * @param {JXG.GeometryElement} element Reference to the geometry element that has to disappear. - * @see JXG.AbstractRenderer#show - * @deprecated - */ - hide: function (element) { /* stub */ }, + for (i = 0; i < parents.length; ++i) { + parents[i] = board.select(parents[i]); + } - /** - * Sets the buffering as recommended by SVGWG. Until now only Opera supports this and will be ignored by - * other browsers. Although this feature is only supported by SVG we have this method in {@link JXG.AbstractRenderer} - * because it is called from outside the renderer. - * @param {Node} node The SVG DOM Node which buffering type to update. - * @param {String} type Either 'auto', 'dynamic', or 'static'. For an explanation see - * {@link http://www.w3.org/TR/SVGTiny12/painting.html#BufferedRenderingProperty}. - */ - setBuffering: function (node, type) { /* stub */ }, + attr = Type.copyAttributes(attributes, board.options, 'reflection'); - /** - * Sets an element's dash style. - * @param {JXG.GeometryElement} element An JSXGraph element. - */ - setDashStyle: function (element) { /* stub */ }, + if (Type.isPoint(parents[0])) { + org = Type.providePoints(board, [parents[0]], attr2)[0]; + } else if (parents[0].elementClass === Const.OBJECT_CLASS_CURVE || + parents[0].elementClass === Const.OBJECT_CLASS_LINE || + parents[0].type === Const.OBJECT_TYPE_POLYGON || + parents[0].elementClass === Const.OBJECT_CLASS_CIRCLE) { + org = parents[0]; + } else { + throw new Error("JSXGraph: Can't create reflection element with parent types '" + + (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + errStr); + } - /** - * Puts an object into draft mode, i.e. it's visual appearance will be changed. For GEONE<sub>x</sub>T backwards compatibility. - * @param {JXG.GeometryElement} element Reference of the object that is in draft mode. - */ - setDraft: function (element) { }, + if (parents[1].elementClass === Const.OBJECT_CLASS_LINE) { + l = parents[1]; + } else { + throw new Error("JSXGraph: Can't create reflected element with parent types '" + + (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + errStr); + } - /** - * Puts an object from draft mode back into normal mode. - * @param {JXG.GeometryElement} element Reference of the object that no longer is in draft mode. - */ - removeDraft: function (element) { }, + t = Transform.createTransform(board, [l], {type: 'reflect'}); + if (Type.isPoint(org)) { + r = Point.createPoint(board, [org, t], attr); + // Arcs and sectors are treated as curves + } else if (org.elementClass === Const.OBJECT_CLASS_CURVE){ + r = Curve.createCurve(board, [org, t], attr); + } else if (org.elementClass === Const.OBJECT_CLASS_LINE){ + r = Line.createLine(board, [org, t], attr); + } else if (org.type === Const.OBJECT_TYPE_POLYGON){ + r = Polygon.createPolygon(board, [org, t], attr); + } else if (org.elementClass === Const.OBJECT_CLASS_CIRCLE) { + if (attr.type.toLowerCase() === 'euclidean') { + // Create a circle element from a circle and a Euclidean transformation + attr2 = Type.copyAttributes(attributes, board.options, 'reflection', 'center'); + r_c = Point.createPoint(board, [org.center, t], attr2); + r_c.prepareUpdate().update().updateVisibility(Type.evaluate(r_c.visProp.visible)).updateRenderer(); + r = Circle.createCircle(board, [r_c, function() {return org.Radius(); }], attr); + } else { + // Create a conic element from a circle and a projective transformation + r = Circle.createCircle(board, [org, t], attr); + } + } else { + throw new Error("JSXGraph: Can't create reflected element with parent types '" + + (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + errStr); + } + if (Type.exists(org._is_new)) { + r.addChild(org); + delete org._is_new; + } else { + // org.addChild(r); + } + l.addChild(r); - /** - * Sets up nodes for rendering a gradient fill. - * @param element - */ - setGradient: function (element) { /* stub */ }, + r.elType = 'reflection'; + r.addParents(l); + r.prepareUpdate().update(); //.updateVisibility(Type.evaluate(r.visProp.visible)).updateRenderer(); - /** - * Updates the gradient fill. - * @param {JXG.GeometryElement} element An JSXGraph element with an area that can be filled. - */ - updateGradient: function (element) { /* stub */ }, + if (Type.isPoint(r)) { + r.generatePolynomial = function () { + /* + * Reflection takes a point R and a line L and creates point P, which is the reflection of R on L. + * L is defined by two points A and B. + * + * So we have two conditions: + * + * (a) RP _|_ AB (orthogonality condition) + * (b) AR == AP (distance condition) + * + */ + var a1 = l.point1.symbolic.x, + a2 = l.point1.symbolic.y, + b1 = l.point2.symbolic.x, + b2 = l.point2.symbolic.y, + p1 = org.symbolic.x, + p2 = org.symbolic.y, + r1 = r.symbolic.x, + r2 = r.symbolic.y, - /** - * Sets the transition duration (in milliseconds) for fill color and stroke - * color and opacity. - * @param {JXG.GeometryElement} element Reference of the object that wants a - * new transition duration. - * @param {Number} duration (Optional) duration in milliseconds. If not given, - * element.visProp.transitionDuration is taken. This is the default. - */ - setObjectTransition: function (element, duration) { /* stub */ }, + poly1 = ['((', r2, ')-(', p2, '))*((', a2, ')-(', b2, '))+((', a1, ')-(', b1, '))*((', r1, ')-(', p1, '))'].join(''), + poly2 = ['((', r1, ')-(', a1, '))^2+((', r2, ')-(', a2, '))^2-((', p1, ')-(', a1, '))^2-((', p2, ')-(', a2, '))^2'].join(''); - /** - * Sets an objects fill color. - * @param {JXG.GeometryElement} element Reference of the object that wants a new fill color. - * @param {String} color Color in a HTML/CSS compatible format. If you don't want any fill color at all, choose 'none'. - * @param {Number} opacity Opacity of the fill color. Must be between 0 and 1. - */ - setObjectFillColor: function (element, color, opacity) { /* stub */ }, + return [poly1, poly2]; + }; + } - /** - * Changes an objects stroke color to the given color. - * @param {JXG.GeometryElement} element Reference of the {@link JXG.GeometryElement} that gets a new stroke color. - * @param {String} color Color value in a HTML compatible format, e.g. <strong>#00ff00</strong> or <strong>green</strong> for green. - * @param {Number} opacity Opacity of the fill color. Must be between 0 and 1. - */ - setObjectStrokeColor: function (element, color, opacity) { /* stub */ }, + return r; + }; - /** - * Sets an element's stroke width. - * @param {JXG.GeometryElement} element Reference to the geometry element. - * @param {Number} width The new stroke width to be assigned to the element. - */ - setObjectStrokeWidth: function (element, width) { /* stub */ }, + /** + * @class A mirror element of a point, line, circle, curve, polygon will be constructed. + * @pseudo + * @description A mirror element is determined by the reflection of a given point, line, circle, curve, polygon across another given point. + * @constructor + * @name Mirrorelement + * @type JXG.GeometryElement + * @augments JXG.GeometryElement + * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {JXG.Point|JXG.Line|JXG.Curve|JXG.Ppolygon_JXG.Point} p1,p2 The constructed element is the mirror image of p2 across p1. + * @example + * // point of reflection + * var mirr = board.create('point', [-1,-1], {color: '#aaaaaa'}); + * + * var p1 = board.create('point', [-3,-1], {name: "A"}); + * var q1 = board.create('mirrorelement', [p1, mirr], {name: "A'"}); + * + * var l1 = board.create('line', [1, -5, 1]); + * var l2 = board.create('mirrorelement', [l1, mirr]); + * + * var cu1 = board.create('curve', [[-3, -3, -2.5, -3, -3, -2.5], [-3, -2, -2, -2, -2.5, -2.5]], {strokeWidth:3}); + * var cu2 = board.create('mirrorelement', [cu1, mirr], {strokeColor: 'red', strokeWidth:3}); + * + * var pol1 = board.create('polygon', [[-6,-2], [-4,-4], [-5,-0.5]]); + * var pol2 = board.create('mirrorelement', [pol1, mirr]); + * + * var c1 = board.create('circle', [[-6,-6], [-6, -5]]); + * var c2 = board.create('mirrorelement', [c1, mirr]); + * + * var a1 = board.create('arc', [[1, 1], [0, 1], [1, 0]], {strokeColor: 'red'}); + * var a2 = board.create('mirrorelement', [a1, mirr], {strokeColor: 'red'}); + * + * var s1 = board.create('sector', [[-3.5,-3], [-3.5, -2], [-3.5,-4]], { + * anglePoint: {visible:true}, center: {visible: true}, radiusPoint: {visible: true}, + * fillColor: 'yellow', strokeColor: 'black'}); + * var s2 = board.create('mirrorelement', [s1, mirr], {fillColor: 'yellow', strokeColor: 'black', fillOpacity: 0.5}); + * + * var an1 = board.create('angle', [[-4,3.9], [-3, 4], [-3, 3]]); + * var an2 = board.create('mirrorelement', [an1, mirr]); + * + * + * </pre><div id="JXG026c779c-d8d9-11e7-93b3-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG026c779c-d8d9-11e7-93b3-901b0e1b8723', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * // point of reflection + * var mirr = board.create('point', [-1,-1], {color: '#aaaaaa'}); + * + * var p1 = board.create('point', [-3,-1], {name: "A"}); + * var q1 = board.create('mirrorelement', [p1, mirr], {name: "A'"}); + * + * var l1 = board.create('line', [1,-5, 1]); + * var l2 = board.create('mirrorelement', [l1, mirr]); + * + * var cu1 = board.create('curve', [[-3, -3, -2.5, -3, -3, -2.5], [-3, -2, -2, -2, -2.5, -2.5]], {strokeWidth:3}); + * var cu2 = board.create('mirrorelement', [cu1, mirr], {strokeColor: 'red', strokeWidth:3}); + * + * var pol1 = board.create('polygon', [[-6,-2], [-4,-4], [-5,-0.5]]); + * var pol2 = board.create('mirrorelement', [pol1, mirr]); + * + * var c1 = board.create('circle', [[-6,-6], [-6, -5]]); + * var c2 = board.create('mirrorelement', [c1, mirr]); + * + * var a1 = board.create('arc', [[1, 1], [0, 1], [1, 0]], {strokeColor: 'red'}); + * var a2 = board.create('mirrorelement', [a1, mirr], {strokeColor: 'red'}); + * + * var s1 = board.create('sector', [[-3.5,-3], [-3.5, -2], [-3.5,-4]], { + * anglePoint: {visible:true}, center: {visible: true}, radiusPoint: {visible: true}, + * fillColor: 'yellow', strokeColor: 'black'}); + * var s2 = board.create('mirrorelement', [s1, mirr], {fillColor: 'yellow', strokeColor: 'black', fillOpacity: 0.5}); + * + * var an1 = board.create('angle', [[-4,3.9], [-3, 4], [-3, 3]]); + * var an2 = board.create('mirrorelement', [an1, mirr]); + * + * })(); + * + * </script><pre> + */ + JXG.createMirrorElement = function (board, parents, attributes) { + var org, i, m, r, r_c, t, + attr, attr2, + errStr = "\nPossible parent types: [point|line|curve|polygon|circle|arc|sector, point]"; - /** - * Sets the shadow properties to a geometry element. This method is only a stub, it is implemented in the actual renderers. - * @param {JXG.GeometryElement} element Reference to a geometry object, that should get a shadow - */ - setShadow: function (element) { /* stub */ }, + for (i = 0; i < parents.length; ++i) { + parents[i] = board.select(parents[i]); + } - /** - * Highlights an object, i.e. changes the current colors of the object to its highlighting colors - * @param {JXG.GeometryElement} element Reference of the object that will be highlighted. - * @returns {JXG.AbstractRenderer} Reference to the renderer - */ - highlight: function (element) { }, + attr = Type.copyAttributes(attributes, board.options, 'mirrorelement'); + if (Type.isPoint(parents[0])) { + // Create point to be mirrored if supplied by coords array. + org = Type.providePoints(board, [parents[0]], attr)[0]; + } else if (parents[0].elementClass === Const.OBJECT_CLASS_CURVE || + parents[0].elementClass === Const.OBJECT_CLASS_LINE || + parents[0].type === Const.OBJECT_TYPE_POLYGON || + parents[0].elementClass === Const.OBJECT_CLASS_CIRCLE) { + org = parents[0]; + } else { + throw new Error("JSXGraph: Can't create mirror element with parent types '" + + (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + errStr); + } - /** - * Uses the normal colors of an object, i.e. the opposite of {@link JXG.AbstractRenderer#highlight}. - * @param {JXG.GeometryElement} element Reference of the object that will get its normal colors. - * @returns {JXG.AbstractRenderer} Reference to the renderer - */ - noHighlight: function (element) { }, + if (Type.isPoint(parents[1])) { + attr2 = Type.copyAttributes(attributes, board.options, 'mirrorelement', 'point'); + // Create mirror point if supplied by coords array. + m = Type.providePoints(board, [parents[1]], attr2)[0]; + } else { + throw new Error("JSXGraph: Can't create mirror element with parent types '" + + (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + errStr); + } + t = Transform.createTransform(board, [Math.PI, m], {type: 'rotate'}); + if (Type.isPoint(org)) { + r = Point.createPoint(board, [org, t], attr); - /* ************************** - * renderer control - * **************************/ + // Arcs and sectors are treated as curves + } else if (org.elementClass === Const.OBJECT_CLASS_CURVE){ + r = Curve.createCurve(board, [org, t], attr); + } else if (org.elementClass === Const.OBJECT_CLASS_LINE){ + r = Line.createLine(board, [org, t], attr); + } else if (org.type === Const.OBJECT_TYPE_POLYGON){ + r = Polygon.createPolygon(board, [org, t], attr); + } else if (org.elementClass === Const.OBJECT_CLASS_CIRCLE){ + if (attr.type.toLowerCase() === 'euclidean') { + // Create a circle element from a circle and a Euclidean transformation + attr2 = Type.copyAttributes(attributes, board.options, 'mirrorelement', 'center'); + r_c = Point.createPoint(board, [org.center, t], attr2); + r_c.prepareUpdate().update().updateVisibility(Type.evaluate(r_c.visProp.visible)).updateRenderer(); + r = Circle.createCircle(board, [r_c, function() {return org.Radius(); }], attr); + } else { + // Create a conic element from a circle and a projective transformation + r = Circle.createCircle(board, [org, t], attr); + } + } else { + throw new Error("JSXGraph: Can't create mirror element with parent types '" + + (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + errStr); + } - /** - * Stop redraw. This method is called before every update, so a non-vector-graphics based renderer - * can use this method to delete the contents of the drawing panel. This is an abstract method every - * descendant renderer should implement, if appropriate. - * @see JXG.AbstractRenderer#unsuspendRedraw - */ - suspendRedraw: function () { /* stub */ }, + if (Type.exists(org._is_new)) { + r.addChild(org); + delete org._is_new; + } else { + // org.addChild(r); + } + m.addChild(r); - /** - * Restart redraw. This method is called after updating all the rendering node attributes. - * @see JXG.AbstractRenderer#suspendRedraw - */ - unsuspendRedraw: function () { /* stub */ }, + r.elType = 'mirrorelement'; + r.addParents(m); + r.prepareUpdate().update(); - /** - * The tiny zoom bar shown on the bottom of a board (if showNavigation on board creation is true). - * @param {JXG.Board} board Reference to a JSXGraph board. - */ - drawZoomBar: function (board) { }, + return r; + }; - /** - * Wrapper for getElementById for maybe other renderers which elements are not directly accessible by DOM methods like document.getElementById(). - * @param {String} id Unique identifier for element. - * @returns {Object} Reference to a JavaScript object. In case of SVG/VMLRenderer it's a reference to a SVG/VML node. - */ - getElementById: function (id) { - return null; - }, + /** + * @class A mirror point will be constructed. + * @pseudo + * @description A mirror point is determined by the reflection of a given point against another given point. + * @constructor + * @name Mirrorpoint + * @type JXG.Point + * @augments JXG.Point + * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {JXG.Point_JXG.Point} p1,p2 The constructed point is the reflection of p2 against p1. + * + * This method is superseeded by the more general {@link JXG.createMirrorElement}. + * @example + * var p1 = board.create('point', [3.0, 3.0]); + * var p2 = board.create('point', [6.0, 1.0]); + * + * var mp1 = board.create('mirrorpoint', [p1, p2]); + * </pre><div class="jxgbox" id="JXG7eb2a814-6c4b-4caa-8cfa-4183a948d25b" style="width: 400px; height: 400px;"></div> + * <script type="text/javascript"> + * var mpex1_board = JXG.JSXGraph.initBoard('JXG7eb2a814-6c4b-4caa-8cfa-4183a948d25b', {boundingbox: [-1, 9, 9, -1], axis: true, showcopyright: false, shownavigation: false}); + * var mpex1_p1 = mpex1_board.create('point', [3.0, 3.0]); + * var mpex1_p2 = mpex1_board.create('point', [6.0, 1.0]); + * var mpex1_mp1 = mpex1_board.create('mirrorpoint', [mpex1_p1, mpex1_p2]); + * </script><pre> + */ + JXG.createMirrorPoint = function (board, parents, attributes) { + var el = JXG.createMirrorElement(board, parents, attributes); + el.elType = 'mirrorpoint'; + return el; + }; - /** - * Resizes the rendering element - * @param {Number} w New width - * @param {Number} h New height - */ - resize: function (w, h) { /* stub */}, + /** + * @class This element is used to visualize the integral of a given curve over a given interval. + * @pseudo + * @description The Integral element is used to visualize the area under a given curve over a given interval + * and to calculate the area's value. For that a polygon and gliders are used. The polygon displays the area, + * the gliders are used to change the interval dynamically. + * @constructor + * @name Integral + * @type JXG.Curve + * @augments JXG.Curve + * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {Array_JXG.Curve} i,c The constructed element covers the area between the curve <tt>c</tt> and the x-axis + * within the interval <tt>i</tt>. + * @example + * var c1 = board.create('functiongraph', [function (t) { return t*t*t; }]); + * var i1 = board.create('integral', [[-2.0, 2.0], c1]); + * </pre><div class="jxgbox" id="JXGd45d7188-6624-4d6e-bebb-1efa2a305c8a" style="width: 400px; height: 400px;"></div> + * <script type="text/javascript"> + * var intex1_board = JXG.JSXGraph.initBoard('JXGd45d7188-6624-4d6e-bebb-1efa2a305c8a', {boundingbox: [-5, 5, 5, -5], axis: true, showcopyright: false, shownavigation: false}); + * var intex1_c1 = intex1_board.create('functiongraph', [function (t) { return Math.cos(t)*t; }]); + * var intex1_i1 = intex1_board.create('integral', [[-2.0, 2.0], intex1_c1]); + * </script><pre> + */ + JXG.createIntegral = function (board, parents, attributes) { + var interval, curve, attr, + start, end, startx, starty, endx, endy, + pa_on_curve, pa_on_axis, pb_on_curve, pb_on_axis, + t = null, p; - removeToInsertLater: function () { - return function () {}; + if (Type.isArray(parents[0]) && parents[1].elementClass === Const.OBJECT_CLASS_CURVE) { + interval = parents[0]; + curve = parents[1]; + } else if (Type.isArray(parents[1]) && parents[0].elementClass === Const.OBJECT_CLASS_CURVE) { + interval = parents[1]; + curve = parents[0]; + } else { + throw new Error("JSXGraph: Can't create integral with parent types '" + + (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + + "\nPossible parent types: [[number|function,number|function],curve]"); } - }); - - JXG.NoRenderer.prototype = new AbstractRenderer(); + attr = Type.copyAttributes(attributes, board.options, 'integral'); + attr.withLabel = false; // There is a custom 'label' below. + p = board.create('curve', [[0], [0]], attr); - return JXG.NoRenderer; -}); + // Correct the interval if necessary - NOT ANYMORE, GGB's fault + start = interval[0]; + end = interval[1]; -/* - Copyright 2008-2021 - Matthias Ehmann, - Michael Gerhaeuser, - Carsten Miller, - Bianca Valentin, - Alfred Wassermann, - Peter Wilfahrt + if (Type.isFunction(start)) { + startx = start; + starty = function () { return curve.Y(startx()); }; + start = startx(); + } else { + startx = start; + starty = curve.Y(start); + } - This file is part of JSXGraph. + if (Type.isFunction(end)) { + endx = end; + endy = function () { return curve.Y(endx()); }; + end = endx(); + } else { + endx = end; + endy = curve.Y(end); + } - JSXGraph is free software dual licensed under the GNU LGPL or MIT License. + attr = Type.copyAttributes(attributes, board.options, 'integral', 'curveLeft'); + pa_on_curve = board.create('glider', [startx, starty, curve], attr); + if (Type.isFunction(startx)) { + pa_on_curve.hideElement(); + } - You can redistribute it and/or modify it under the terms of the + attr = Type.copyAttributes(attributes, board.options, 'integral', 'baseLeft'); + pa_on_axis = board.create('point', [ + function () { + if (Type.evaluate(p.visProp.axis) === 'y') { + return 0; + } - * GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version - OR - * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT + return pa_on_curve.X(); + }, + function () { + if (Type.evaluate(p.visProp.axis) === 'y') { + return pa_on_curve.Y(); + } - JSXGraph is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. + return 0; + } + ], attr); - You should have received a copy of the GNU Lesser General Public License and - the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> - and <http://opensource.org/licenses/MIT/>. - */ + attr = Type.copyAttributes(attributes, board.options, 'integral', 'curveRight'); + pb_on_curve = board.create('glider', [endx, endy, curve], attr); + if (Type.isFunction(endx)) { + pb_on_curve.hideElement(); + } + attr = Type.copyAttributes(attributes, board.options, 'integral', 'baseRight'); + pb_on_axis = board.create('point', [ + function () { + if (Type.evaluate(p.visProp.axis) === 'y') { + return 0; + } + return pb_on_curve.X(); + }, + function () { + if (Type.evaluate(p.visProp.axis) === 'y') { + return pb_on_curve.Y(); + } -/*global JXG: true, document:true, jQuery:true, define: true, window: true*/ -/*jslint nomen: true, plusplus: true*/ + return 0; + } + ], attr); -/* depends: - jxg - utils/env - utils/type - base/board - reader/file - options - renderer/svg - renderer/vml - renderer/canvas - renderer/no - */ + attr = Type.copyAttributes(attributes, board.options, 'integral'); + if (attr.withlabel !== false && attr.axis !== 'y') { + attr = Type.copyAttributes(attributes, board.options, 'integral', 'label'); + attr = Type.copyAttributes(attr, board.options, 'label'); -/** - * @fileoverview The JSXGraph object is defined in this file. JXG.JSXGraph controls all boards. - * It has methods to create, save, load and free boards. Additionally some helper functions are - * defined in this file directly in the JXG namespace. - * @version 0.99 - */ + t = board.create('text', [ + function () { + var off = new Coords(Const.COORDS_BY_SCREEN, [ + Type.evaluate(this.visProp.offset[0]) + this.board.origin.scrCoords[1], + 0 + ], this.board, false), + bb = this.board.getBoundingBox(), + dx = (bb[2] - bb[0]) * 0.1, + x = pb_on_curve.X(); -define('jsxgraph',[ - 'jxg', 'utils/env', 'utils/type', 'base/board', 'reader/file', 'options', - 'renderer/svg', 'renderer/vml', 'renderer/canvas', 'renderer/no' -], function (JXG, Env, Type, Board, FileReader, Options, SVGRenderer, VMLRenderer, CanvasRenderer, NoRenderer) { + if (x < bb[0]) { + x = bb[0] + dx; + } else if (x > bb[2]) { + x = bb[2] - dx; + } - "use strict"; + return x + off.usrCoords[1]; + }, + function () { + var off = new Coords(Const.COORDS_BY_SCREEN, [ + 0, + Type.evaluate(this.visProp.offset[1]) + this.board.origin.scrCoords[2] + ], this.board, false), + bb = this.board.getBoundingBox(), + dy = (bb[1] - bb[3]) * 0.1, + y = pb_on_curve.Y(); - /** - * Constructs a new JSXGraph singleton object. - * @class The JXG.JSXGraph singleton stores all properties required - * to load, save, create and free a board. - */ - JXG.JSXGraph = { - /** - * Stores the renderer that is used to draw the boards. - * @type String - */ - rendererType: (function () { - Options.board.renderer = 'no'; + if (y > bb[1]) { + y = bb[1] - dy; + } else if (y < bb[3]) { + y = bb[3] + dy; + } - if (Env.supportsVML()) { - Options.board.renderer = 'vml'; - // Ok, this is some real magic going on here. IE/VML always was so - // terribly slow, except in one place: Examples placed in a moodle course - // was almost as fast as in other browsers. So i grabbed all the css and - // lib scripts from our moodle, added them to a jsxgraph example and it - // worked. next step was to strip all the css/lib code which didn't affect - // the VML update speed. The following five lines are what was left after - // the last step and yes - it basically does nothing but reads two - // properties of document.body on every mouse move. why? we don't know. if - // you know, please let us know. - // - // If we want to use the strict mode we have to refactor this a little bit. Let's - // hope the magic isn't gone now. Anywho... it's only useful in old versions of IE - // which should not be used anymore. - document.onmousemove = function () { - var t; + return y + off.usrCoords[2]; + }, + function () { + var Int = Numerics.NewtonCotes([pa_on_axis.X(), pb_on_axis.X()], curve.Y); + return '∫ = ' + Type.toFixed(Int, 4); + } + ], attr); - if (document.body) { - t = document.body.scrollLeft; - t += document.body.scrollTop; - } + t.dump = false; - return t; - }; - } + pa_on_curve.addChild(t); + pb_on_curve.addChild(t); + } - if (Env.supportsCanvas()) { - Options.board.renderer = 'canvas'; - } + // dump stuff + pa_on_curve.dump = false; + pa_on_axis.dump = false; - if (Env.supportsSVG()) { - Options.board.renderer = 'svg'; - } + pb_on_curve.dump = false; + pb_on_axis.dump = false; - // we are inside node - if (Env.isNode() && Env.supportsCanvas()) { - Options.board.renderer = 'canvas'; - } + p.elType = 'integral'; + p.setParents([curve.id, interval]); + p.subs = { + curveLeft: pa_on_curve, + baseLeft: pa_on_axis, + curveRight: pb_on_curve, + baseRight: pb_on_axis + }; + p.inherits.push(pa_on_curve, pa_on_axis, pb_on_curve, pb_on_axis); - if (Env.isNode() || Options.renderer === 'no') { - Options.text.display = 'internal'; - Options.infobox.display = 'internal'; - } + if (attr.withLabel) { + p.subs.label = t; + p.inherits.push(t); + } - return Options.board.renderer; - }()), + /** + * Returns the current value of the integral. + * @memberOf Integral + * @name Value + * @function + * @returns {Number} + */ + p.Value = function () { + return Numerics.I([pa_on_axis.X(), pb_on_axis.X()], curve.Y); + }; /** - * Initialize the rendering engine - * - * @param {String} box HTML id of the div-element which hosts the JSXGraph construction - * @param {Object} dim The dimensions of the board - * @param {Object} doc Usually, this is document object of the browser window. If false or null, this defaults - * to the document object of the browser. - * @param {Object} attrRenderer Attribute 'renderer', speficies the rendering engine. Possible values are 'auto', 'svg', - * 'canvas', 'no', and 'vml'. - * @returns {Object} Reference to the rendering engine object. - * @private + * documented in JXG.Curve + * @ignore */ - initRenderer: function (box, dim, doc, attrRenderer) { - var boxid, renderer; + p.updateDataArray = function () { + var x, y, + i, left, right, + lowx, upx, + lowy, upy; - // Former version: - // doc = doc || document - if ((!Type.exists(doc) || doc === false) && typeof document === 'object') { - doc = document; - } + if (Type.evaluate(this.visProp.axis) === 'y') { + if (pa_on_curve.Y() < pb_on_curve.Y()) { + lowx = pa_on_curve.X(); + lowy = pa_on_curve.Y(); + upx = pb_on_curve.X(); + upy = pb_on_curve.Y(); + } else { + lowx = pb_on_curve.X(); + lowy = pb_on_curve.Y(); + upx = pa_on_curve.X(); + upy = pa_on_curve.Y(); + } + left = Math.min(lowx, upx); + right = Math.max(lowx, upx); - if (typeof doc === 'object' && box !== null) { - boxid = doc.getElementById(box); + x = [0, lowx]; + y = [lowy, lowy]; - // Remove everything from the container before initializing the renderer and the board - while (boxid.firstChild) { - boxid.removeChild(boxid.firstChild); + for (i = 0; i < curve.numberPoints; i++) { + if (lowy <= curve.points[i].usrCoords[2] && + left <= curve.points[i].usrCoords[1] && + curve.points[i].usrCoords[2] <= upy && + curve.points[i].usrCoords[1] <= right) { + x.push(curve.points[i].usrCoords[1]); + y.push(curve.points[i].usrCoords[2]); + } } - } else { - boxid = box; - } + x.push(upx); + y.push(upy); + x.push(0); + y.push(upy); - // If attrRenderer is not supplied take the first available renderer - if (attrRenderer === undefined || attrRenderer === 'auto') { - attrRenderer = this.rendererType; - } - // create the renderer - if (attrRenderer === 'svg') { - renderer = new SVGRenderer(boxid, dim); - } else if (attrRenderer === 'vml') { - renderer = new VMLRenderer(boxid); - } else if (attrRenderer === 'canvas') { - renderer = new CanvasRenderer(boxid, dim); + // close the curve + x.push(0); + y.push(lowy); } else { - renderer = new NoRenderer(); + if (pa_on_axis.X() < pb_on_axis.X()) { + left = pa_on_axis.X(); + right = pb_on_axis.X(); + } else { + left = pb_on_axis.X(); + right = pa_on_axis.X(); + } + + x = [left, left]; + y = [0, curve.Y(left)]; + + for (i = 0; i < curve.numberPoints; i++) { + if ((left <= curve.points[i].usrCoords[1]) && (curve.points[i].usrCoords[1] <= right)) { + x.push(curve.points[i].usrCoords[1]); + y.push(curve.points[i].usrCoords[2]); + } + } + x.push(right); + y.push(curve.Y(right)); + x.push(right); + y.push(0); + + // close the curve + x.push(left); + y.push(0); } - return renderer; - }, + this.dataX = x; + this.dataY = y; + }; + + pa_on_curve.addChild(p); + pb_on_curve.addChild(p); + pa_on_axis.addChild(p); + pb_on_axis.addChild(p); /** - * Merge the user supplied attributes with the attributes in options.js - * - * @param {Object} attributes User supplied attributes - * @returns {Object} Merged attributes for the board + * The point on the axis initially corresponding to the lower value of the interval. * - * @private + * @name baseLeft + * @memberOf Integral + * @type JXG.Point */ - _setAttributes: function(attributes) { - // merge attributes - var attr = Type.copyAttributes(attributes, Options, 'board'); - - // The attributes which are objects have to be copied separately - attr.zoom = Type.copyAttributes(attr, Options, 'board', 'zoom'); - attr.pan = Type.copyAttributes(attr, Options, 'board', 'pan'); - attr.drag = Type.copyAttributes(attr, Options, 'board', 'drag'); - attr.selection = Type.copyAttributes(attr, Options, 'board', 'selection'); - attr.navbar = Type.copyAttributes(attr.navbar, Options, 'navbar'); - - return attr; - }, + p.baseLeft = pa_on_axis; /** - * Further initialization of the board. Set some properties from attribute values. - * - * @param {JXG.Board} board - * @param {Object} attr attributes object - * @param {Object} dimensions Object containing dimensions of the canvas + * The point on the axis initially corresponding to the higher value of the interval. * - * @private + * @name baseRight + * @memberOf Integral + * @type JXG.Point */ - _fillBoard: function(board, attr, dimensions) { - board.initInfobox(); - board.maxboundingbox = attr.maxboundingbox; - board.resizeContainer(dimensions.width, dimensions.height, true, true); - board._createSelectionPolygon(attr); - board.renderer.drawZoomBar(board, attr.navbar); - JXG.boards[board.id] = board; - }, + p.baseRight = pb_on_axis; /** + * The glider on the curve corresponding to the lower value of the interval. * - * @param {String} container HTML-ID to the HTML-element in which the board is painted. - * @param {*} attr An object that sets some of the board properties. - * - * @private + * @name curveLeft + * @memberOf Integral + * @type Glider */ - _setARIA: function(container, attr) { - var doc = attr.document || document, - node_jsx, newNode, parent, - id_label, id_description; - - if (typeof doc !== 'object') { - return; - } - - node_jsx = doc.getElementById(container); - parent = node_jsx.parentNode; - - id_label = container + '_ARIAlabel'; - id_description = container + '_ARIAdescription'; - - newNode = doc.createElement('div'); - newNode.innerHTML = attr.title; - newNode.setAttribute('id', id_label); - newNode.style.display = 'none'; - parent.insertBefore(newNode, node_jsx); - - newNode = doc.createElement('div'); - newNode.innerHTML = attr.description; - newNode.setAttribute('id', id_description); - newNode.style.display = 'none'; - parent.insertBefore(newNode, node_jsx); - - node_jsx.setAttribute('aria-labelledby', id_label); - node_jsx.setAttribute('aria-describedby', id_description); - }, + p.curveLeft = pa_on_curve; /** - * Remove the two corresponding ARIA divs when freeing a board - * - * @param {JXG.Board} board + * The glider on the axis corresponding to the higher value of the interval. * - * @private + * @name curveRight + * @memberOf Integral + * @type Glider */ - _removeARIANodes: function(board) { - var node, id, doc; - - doc = board.document || document; - if (typeof doc !== 'object') { - return; - } + p.curveRight = pb_on_curve; - id = board.containerObj.getAttribute('aria-labelledby'); - node = document.getElementById(id); - if (node && node.parentNode) { - node.parentNode.removeChild(node); - } - id = board.containerObj.getAttribute('aria-describedby'); - node = document.getElementById(id); - if (node && node.parentNode) { - node.parentNode.removeChild(node); - } - }, + p.methodMap = JXG.deepCopy(p.methodMap, { + curveLeft: 'curveLeft', + baseLeft: 'baseLeft', + curveRight: 'curveRight', + baseRight: 'baseRight', + Value: 'Value' + }); /** - * Initialise a new board. - * @param {String} box HTML-ID to the HTML-element in which the board is painted. - * @param {Object} attributes An object that sets some of the board properties. Most of these properties can be set via JXG.Options. - * @param {Array} [attributes.boundingbox=[-5, 5, 5, -5]] An array containing four numbers describing the left, top, right and bottom boundary of the board in user coordinates - * @param {Boolean} [attributes.keepaspectratio=false] If <tt>true</tt>, the bounding box is adjusted to the same aspect ratio as the aspect ratio of the div containing the board. - * @param {Boolean} [attributes.showCopyright=false] Show the copyright string in the top left corner. - * @param {Boolean} [attributes.showNavigation=false] Show the navigation buttons in the bottom right corner. - * @param {Object} [attributes.zoom] Allow the user to zoom with the mouse wheel or the two-fingers-zoom gesture. - * @param {Object} [attributes.pan] Allow the user to pan with shift+drag mouse or two-fingers-pan gesture. - * @param {Boolean} [attributes.axis=false] If set to true, show the axis. Can also be set to an object that is given to both axes as an attribute object. - * @param {Boolean|Object} [attributes.grid] If set to true, shows the grid. Can also be set to an object that is given to the grid as its attribute object. - * @param {Boolean} [attributes.registerEvents=true] Register mouse / touch events. - * @returns {JXG.Board} Reference to the created board. + * documented in GeometryElement + * @ignore */ - initBoard: function (box, attributes) { - var originX, originY, unitX, unitY, - renderer, - w, h, dimensions, - bbox, attr, axattr, axattr_x, axattr_y, - board; + p.label = t; - attributes = attributes || {}; - attr = this._setAttributes(attributes); + return p; + }; - dimensions = Env.getDimensions(box, attr.document); + /** + * @class Creates a grid to support the user with element placement. + * @pseudo + * @description A grid is a set of vertical and horizontal lines to support the user with element placement. This method + * draws such a grid on the given board. This method does not + * take any parent elements. It is usually instantiated on the board's creation via the attribute <tt>grid</tt> set + * to true. + * @parameter None. + * @constructor + * @name Grid + * @type JXG.Curve + * @augments JXG.Curve + * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. + * @example + * grid = board.create('grid', []); + * </pre><div class="jxgbox" id="JXGa9a0671f-7a51-4fa2-8697-241142c00940" style="width: 400px; height: 400px;"></div> + * <script type="text/javascript"> + * (function () { + * board = JXG.JSXGraph.initBoard('JXGa9a0671f-7a51-4fa2-8697-241142c00940', {boundingbox:[-4, 6, 10, -6], axis: false, grid: false, keepaspectratio: true}); + * grid = board.create('grid', []); + * })(); + * </script><pre> + */ + JXG.createGrid = function (board, parents, attributes) { + var c, attr; - if (attr.unitx || attr.unity) { - originX = Type.def(attr.originx, 150); - originY = Type.def(attr.originy, 150); - unitX = Type.def(attr.unitx, 50); - unitY = Type.def(attr.unity, 50); - } else { - bbox = attr.boundingbox; - if (bbox[0] < attr.maxboundingbox[0]) { bbox[0] = attr.maxboundingbox[0]; } - if (bbox[1] > attr.maxboundingbox[1]) { bbox[1] = attr.maxboundingbox[1]; } - if (bbox[2] > attr.maxboundingbox[2]) { bbox[2] = attr.maxboundingbox[2]; } - if (bbox[3] < attr.maxboundingbox[3]) { bbox[3] = attr.maxboundingbox[3]; } + attr = Type.copyAttributes(attributes, board.options, 'grid'); + c = board.create('curve', [[null], [null]], attr); - w = parseInt(dimensions.width, 10); - h = parseInt(dimensions.height, 10); + c.elType = 'grid'; + c.type = Const.OBJECT_TYPE_GRID; - if (Type.exists(bbox) && attr.keepaspectratio) { - /* - * If the boundingbox attribute is given and the ratio of height and width of the - * sides defined by the bounding box and the ratio of the dimensions of the div tag - * which contains the board do not coincide, then the smaller side is chosen. - */ - unitX = w / (bbox[2] - bbox[0]); - unitY = h / (bbox[1] - bbox[3]); + /** + * @ignore + */ + c.updateDataArray = function () { + var start, end, i, topLeft, bottomRight, + gridX = Type.evaluate(this.visProp.gridx), + gridY = Type.evaluate(this.visProp.gridy); - if (Math.abs(unitX) < Math.abs(unitY)) { - unitY = Math.abs(unitX) * unitY / Math.abs(unitY); - } else { - unitX = Math.abs(unitY) * unitX / Math.abs(unitX); - } - } else { - unitX = w / (bbox[2] - bbox[0]); - unitY = h / (bbox[1] - bbox[3]); - } - originX = -unitX * bbox[0]; - originY = unitY * bbox[1]; + if (Type.isArray(this.visProp.topleft)) { + topLeft = new Coords(Type.evaluate(this.visProp.tltype) || Const.COORDS_BY_USER, + this.visProp.topleft, board); + } else { + topLeft = new Coords(Const.COORDS_BY_SCREEN, [0, 0], board); } - renderer = this.initRenderer(box, dimensions, attr.document, attr.renderer); - this._setARIA(box, attr); + if (Type.isArray(this.visProp.bottomright)) { + bottomRight = new Coords(Type.evaluate(this.visProp.brtype) || Const.COORDS_BY_USER, + this.visProp.bottomright, board); + } else { + bottomRight = new Coords(Const.COORDS_BY_SCREEN, [board.canvasWidth, board.canvasHeight], board); + } - // create the board - board = new Board(box, renderer, attr.id, [originX, originY], - attr.zoomfactor * attr.zoomx, - attr.zoomfactor * attr.zoomy, - unitX, unitY, - dimensions.width, dimensions.height, - attr); - board.keepaspectratio = attr.keepaspectratio; + // + // | | | + // ----+---------+---------+----- + // | /| | + // | gridY| <---+------ Grid Cell + // | \| | + // ----+---------+---------+----- + // | |\ gridX /| + // | | | + // + // uc: usercoordinates + // + // currently one grid cell is 1/JXG.Options.grid.gridX uc wide and 1/JXG.Options.grid.gridY uc high. + // this may work perfectly with GeonextReader (#readGeonext, initialization of gridX and gridY) but it + // is absolutely not user friendly when it comes to use it as an API interface. + // i changed this to use gridX and gridY as the actual width and height of the grid cell. for this i + // had to refactor these methods: + // + // DONE JXG.Board.calculateSnapSizes (init p1, p2) + // DONE JXG.GeonextReader.readGeonext (init gridX, gridY) + // - this._fillBoard(board, attr, dimensions); + board.options.grid.hasGrid = true; - // create elements like axes, grid, navigation, ... - board.suspendUpdate(); - if (attr.axis) { - axattr = typeof attr.axis === 'object' ? attr.axis : {}; + // fix_grid: adding integer function to calculation of start and end values, and adding to calculation of start and end values below + // To allow this: + // (axes on the outside, min value of grid = 0.25) + // + // | | | | + // 1.5 -+----+---------+----------+----- + // | | | | + // | | | | + // | | | | + // 1 -+----+---------+----------+----- + // | | | | + // | | | | + // | | | | + // 0.5 -+----+---------+----------+----- + // | | | | + // +----+---------+----------+----- + // | | | + // 0.5 1 1.5 + // + // fix_grid: these lines disabled: + // topLeft.setCoordinates(Const.COORDS_BY_USER, [Math.ceil(topLeft.usrCoords[1] / gridX) * gridX, Math.floor(topLeft.usrCoords[2] / gridY) * gridY]); + // bottomRight.setCoordinates(Const.COORDS_BY_USER, [Math.floor(bottomRight.usrCoords[1] / gridX) * gridX, Math.ceil(bottomRight.usrCoords[2] / gridY) * gridY]); - // The defaultAxes attributes are overwritten by user supplied axis object. - axattr_x = Type.deepCopy(Options.board.defaultAxes.x, axattr); - axattr_y = Type.deepCopy(Options.board.defaultAxes.y, axattr); - // The user supplied defaultAxes attributes are merged in. - if (attr.defaultaxes.x) { - axattr_x = Type.deepCopy(axattr_x, attr.defaultaxes.x); - } - if (attr.defaultaxes.y) { - axattr_y = Type.deepCopy(axattr_y, attr.defaultaxes.y); - } + c.dataX = []; + c.dataY = []; - board.defaultAxes = {}; - board.defaultAxes.x = board.create('axis', [[0, 0], [1, 0]], axattr_x); - board.defaultAxes.y = board.create('axis', [[0, 0], [0, 1]], axattr_y); - } - if (attr.grid) { - board.create('grid', [], (typeof attr.grid === 'object' ? attr.grid : {})); + // Sometimes the bounding box is used to invert the axis. We have to take this into account here. + // fix_grid: adding integer function to calculation of start and end values + start = Math.floor(topLeft.usrCoords[2] / gridY) * gridY; + end = Math.ceil(bottomRight.usrCoords[2] / gridY) * gridY; + + if (topLeft.usrCoords[2] < bottomRight.usrCoords[2]) { + start = Math.ceil(bottomRight.usrCoords[2] / gridY) * gridY; // bottomRight.usrCoords[2]; + end = Math.floor(topLeft.usrCoords[2] / gridY) * gridY; } - board.unsuspendUpdate(); - return board; - }, + // start with the horizontal grid: + for (i = start; i > end - gridY; i -= gridY) { + c.dataX.push(topLeft.usrCoords[1], bottomRight.usrCoords[1], NaN); + c.dataY.push(i, i, NaN); + } - /** - * Load a board from a file containing a construction made with either GEONExT, - * Intergeo, Geogebra, or Cinderella. - * @param {String} box HTML-ID to the HTML-element in which the board is painted. - * @param {String} file base64 encoded string. - * @param {String} format containing the file format: 'Geonext' or 'Intergeo'. - * @param {Object} attributes Attributes for the board and 'encoding'. - * Compressed files need encoding 'iso-8859-1'. Otherwise it probably is 'utf-8'. - * @param {Function} callback - * @returns {JXG.Board} Reference to the created board. - * @see JXG.FileReader - * @see JXG.GeonextReader - * @see JXG.GeogebraReader - * @see JXG.IntergeoReader - * @see JXG.CinderellaReader - * - * @example - * // Uncompressed file - * var board = JXG.JSXGraph.loadBoardFromFile('jxgbox', 'filename', 'geonext', - * {encoding: 'utf-8'}, - * function (board) { console.log("Done loading"); } - * ); - * // Compressed file - * var board = JXG.JSXGraph.loadBoardFromFile('jxgbox', 'filename', 'geonext', - * {encoding: 'iso-8859-1'}, - * function (board) { console.log("Done loading"); } - * ); - * - * @example - * // From <input type="file" id="localfile" /> - * var file = document.getElementById('localfile').files[0]; - * JXG.JSXGraph.loadBoardFromFile('jxgbox', file, 'geonext', - * {encoding: 'utf-8'}, - * function (board) { console.log("Done loading"); } - * ); - */ - loadBoardFromFile: function (box, file, format, attributes, callback) { - var attr, renderer, board, dimensions, encoding; + // fix_grid: adding integer function to calculation of start and end values + start = Math.ceil(topLeft.usrCoords[1] / gridX) * gridX; + end = Math.floor(bottomRight.usrCoords[1] / gridX) * gridX; - attributes = attributes || {}; - attr = this._setAttributes(attributes); + if (topLeft.usrCoords[1] > bottomRight.usrCoords[1]) { + start = Math.floor(bottomRight.usrCoords[1] / gridX) * gridX; + end = Math.ceil(topLeft.usrCoords[1] / gridX) * gridX; + } - dimensions = Env.getDimensions(box, attr.document); - renderer = this.initRenderer(box, dimensions, attr.document, attr.renderer); - this._setARIA(box, attr); + // build vertical grid + for (i = start; i < end + gridX; i += gridX) { + c.dataX.push(i, i, NaN); + c.dataY.push(topLeft.usrCoords[2], bottomRight.usrCoords[2], NaN); + } - /* User default parameters, in parse* the values in the gxt files are submitted to board */ - board = new Board(box, renderer, '', [150, 150], 1, 1, 50, 50, dimensions.width, dimensions.height, attr); - this._fillBoard(board, attr, dimensions); - encoding = attr.encoding || 'iso-8859-1'; - FileReader.parseFileContent(file, board, format, true, encoding, callback); + }; - return board; - }, + // we don't care about highlighting so we turn it off completely to save a lot of + // time on every mouse move + c.hasPoint = function () { + return false; + }; - /** - * Load a board from a base64 encoded string containing a construction made with either GEONExT, - * Intergeo, Geogebra, or Cinderella. - * @param {String} box HTML-ID to the HTML-element in which the board is painted. - * @param {String} string base64 encoded string. - * @param {String} format containing the file format: 'Geonext', 'Intergeo', 'Geogebra'. - * @param {Object} attributes Attributes for the board and 'encoding'. - * Compressed files need encoding 'iso-8859-1'. Otherwise it probably is 'utf-8'. - * @param {Function} callback - * @returns {JXG.Board} Reference to the created board. - * @see JXG.FileReader - * @see JXG.GeonextReader - * @see JXG.GeogebraReader - * @see JXG.IntergeoReader - * @see JXG.CinderellaReader - */ - loadBoardFromString: function (box, string, format, attributes, callback) { - var attr, renderer, board, dimensions; + board.grids.push(c); - attributes = attributes || {}; - attr = this._setAttributes(attributes); + return c; + }; - dimensions = Env.getDimensions(box, attr.document); - renderer = this.initRenderer(box, dimensions, attr.document); - this._setARIA(box, attr); + /** + * @class Creates an area indicating the solution of a linear inequality or an inequality + * of a function graph, i.e. an inequality of type y <= f(x). + * @pseudo + * @description Display the solution set of a linear inequality (less than or equal to). + * To be precise, the solution set of the inequality <i>y <= b/a * x + c/a</i> is shown. + * In case <i>a = 0</i>, that is if the equation of the line is <i>bx + c = 0</i>, + * the area of the inequality <i>bx + c <= 0</i> is shown. + * <p> + * For function graphs the area below the function graph is filled, i.e. the + * area of the inequality y <= f(x). + * With the attribute inverse:true the area of the inequality y >= f(x) is filled. + * + * @param {JXG.Line} l The area drawn will be the area below this line. With the attribute + * inverse:true, the inequality 'greater than or equal to' is shown. + * @constructor + * @name Inequality + * @type JXG.Curve + * @augments JXG.Curve + * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. + * @example + * var p = board.create('point', [1, 3]), + * q = board.create('point', [-2, -4]), + * l = board.create('line', [p, q]), + * ineq = board.create('inequality', [l]); + * ineq = board.create('inequality', [l]); + * </pre><div class="jxgbox" id="JXG2b703006-fd98-11e1-b79e-ef9e591c002e" style="width: 400px; height: 400px;"></div> + * <script type="text/javascript"> + * (function () { + * var board = JXG.JSXGraph.initBoard('JXG2b703006-fd98-11e1-b79e-ef9e591c002e', {boundingbox:[-4, 6, 10, -6], axis: false, grid: false, keepaspectratio: true}), + * p = board.create('point', [1, 3]), + * q = board.create('point', [-2, -4]), + * l = board.create('line', [p, q]), + * ineq = board.create('inequality', [l]); + * })(); + * </script><pre> + * + * @example + * // Plot the inequality + * // y >= 2/3 x + 1 + * // or + * // 0 >= -3y + 2x +1 + * var l = board.create('line', [1, 2, -3]), + * ineq = board.create('inequality', [l], {inverse:true}); + * </pre><div class="jxgbox" id="JXG1ded3812-2da4-4323-abaf-1db4bad1bfbd" style="width: 400px; height: 400px;"></div> + * <script type="text/javascript"> + * (function () { + * var board = JXG.JSXGraph.initBoard('JXG1ded3812-2da4-4323-abaf-1db4bad1bfbd', {boundingbox:[-4, 6, 10, -6], axis: false, grid: false, keepaspectratio: true}), + * l = board.create('line', [1, 2, -3]), + * ineq = board.create('inequality', [l], {inverse:true}); + * })(); + * </script><pre> + * + * @example + * var f = board.create('functiongraph', ['sin(x)', -2*Math.PI, 2*Math.PI]); + * + * var ineq_lower = board.create('inequality', [f]); + * var ineq_greater = board.create('inequality', [f], {inverse: true, fillColor: 'yellow'}); + * + * + * </pre><div id="JXGdb68c574-414c-11e8-839a-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXGdb68c574-414c-11e8-839a-901b0e1b8723', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * var f = board.create('functiongraph', ['sin(x)', -2*Math.PI, 2*Math.PI]); + * + * var ineq_lower = board.create('inequality', [f]); + * var ineq_greater = board.create('inequality', [f], {inverse: true, fillColor: 'yellow'}); + * + * + * })(); + * + * </script><pre> + * + */ + JXG.createInequality = function (board, parents, attributes) { + var f, a, attr; - /* User default parameters, in parse* the values in the gxt files are submitted to board */ - board = new Board(box, renderer, '', [150, 150], 1.0, 1.0, 50, 50, dimensions.width, dimensions.height, attr); - this._fillBoard(board, attr, dimensions); - FileReader.parseString(string, board, format, true, callback); + attr = Type.copyAttributes(attributes, board.options, 'inequality'); + if (parents[0].elementClass === Const.OBJECT_CLASS_LINE) { + a = board.create('curve', [[], []], attr); + a.hasPoint = function () { + return false; + }; + a.updateDataArray = function () { + var i1, i2, + // This will be the height of the area. We mustn't rely upon the board height because if we pan the view + // such that the line is not visible anymore, the borders of the area will get visible in some cases. + h, + bb = board.getBoundingBox(), + factor = attr.inverse ? -1 : 1, + expansion = 1.5, + w = expansion * Math.max(bb[2] - bb[0], bb[1] - bb[3]), + // Fake a point (for Math.Geometry.perpendicular) + // contains centroid of the board + dp = { + coords: { + usrCoords: [1, (bb[0] + bb[2]) / 2, attr.inverse ? bb[1] : bb[3]] + } + }, - return board; - }, + slope1 = parents[0].stdform.slice(1), + slope2 = slope1; - /** - * Delete a board and all its contents. - * @param {JXG.Board,String} board HTML-ID to the DOM-element in which the board is drawn. - */ - freeBoard: function (board) { - var el; + // This is wrong. Example: + // var line = board.create('line', [0, -1, -1]); + // var ineq = board.create('inequality', [line]); + // + // if (slope1[1] > 0) { + // slope1 = Statistics.multiply(slope1, -1); + // slope2 = slope1; + // } - if (typeof board === 'string') { - board = JXG.boards[board]; - } + // Calculate the area height as + // expansion times the distance of the line to the + // point in the middle of the top/bottom border. + h = expansion * Math.max(Geometry.perpendicular(parents[0], dp, board)[0].distance(Const.COORDS_BY_USER, dp.coords), w); + h *= factor; - this._removeARIANodes(board); - board.removeEventHandlers(); - board.suspendUpdate(); + // reuse dp + dp = { + coords: { + usrCoords: [1, (bb[0] + bb[2]) / 2, (bb[1] + bb[3]) / 2] + } + }; - // Remove all objects from the board. - for (el in board.objects) { - if (board.objects.hasOwnProperty(el)) { - board.objects[el].remove(); + // If dp is on the line, Geometry.perpendicular will return a point not on the line. + // Since this somewhat odd behavior of Geometry.perpendicular is needed in GEONExT, + // it is circumvented here. + if (Math.abs(Mat.innerProduct(dp.coords.usrCoords, parents[0].stdform, 3)) >= Mat.eps) { + dp = Geometry.perpendicular(parents[0], dp, board)[0].usrCoords; + } else { + dp = dp.coords.usrCoords; } - } + i1 = [1, dp[1] + slope1[1] * w, dp[2] - slope1[0] * w]; + i2 = [1, dp[1] - slope2[1] * w, dp[2] + slope2[0] * w]; - // Remove all the other things, left on the board, XHTML save - while (board.containerObj.firstChild) { - board.containerObj.removeChild(board.containerObj.firstChild); - } + // One of the vectors based in i1 and orthogonal to the parent line has the direction d1 = (slope1, -1) + // We will go from i1 to to i1 + h*d1, from there to i2 + h*d2 (with d2 calculated equivalent to d1) and + // end up in i2. + this.dataX = [i1[1], i1[1] + slope1[0] * h, i2[1] + slope2[0] * h, i2[1], i1[1]]; + this.dataY = [i1[2], i1[2] + slope1[1] * h, i2[2] + slope2[1] * h, i2[2], i1[2]]; + }; + } else if (parents[0].elementClass === Const.OBJECT_CLASS_CURVE && + parents[0].visProp.curvetype === 'functiongraph') { - // Tell the browser the objects aren't needed anymore - for (el in board.objects) { - if (board.objects.hasOwnProperty(el)) { - delete board.objects[el]; - } - } + a = board.create('curve', [[], []], attr); + a.updateDataArray = function() { + var bbox = this.board.getBoundingBox(), + points = [], + infty, first, last, + len, i, + mi = parents[0].minX(), + ma = parents[0].maxX(), + curve_mi, curve_ma, + firstx, + lastx, + enlarge = (bbox[1] - bbox[3]) * 0.3, // enlarge the bbox vertically by this amount + inverse = Type.evaluate(this.visProp.inverse); - // Free the renderer and the algebra object - delete board.renderer; + // inverse == true <=> Fill area with y >= f(x) + infty = (inverse) ? 1 : 3; // we will use either bbox[1] or bbox[3] below - // clear the creator cache - board.jc.creator.clearCache(); - delete board.jc; + this.dataX = []; + this.dataY = []; + len = parents[0].points.length; + if (len === 0) { + return; + } - // Finally remove the board itself from the boards array - delete JXG.boards[board.id]; - }, + bbox[1] += enlarge; + bbox[3] -= enlarge; - /** - * @deprecated Use JXG#registerElement - * @param element - * @param creator - */ - registerElement: function (element, creator) { - JXG.deprecated('JXG.JSXGraph.registerElement()', 'JXG.registerElement()'); - JXG.registerElement(element, creator); - } - }; + last = -1; + while (last < len - 1) { - // JessieScript/JessieCode startup: Search for script tags of type text/jessiescript and interprete them. - if (Env.isBrowser && typeof window === 'object' && typeof document === 'object') { - Env.addEvent(window, 'load', function () { - var type, i, j, div, id, board, width, height, bbox, axis, grid, code, - scripts = document.getElementsByTagName('script'), - init = function (code, type, bbox) { - var board = JXG.JSXGraph.initBoard(id, {boundingbox: bbox, keepaspectratio: true, grid: grid, axis: axis, showReload: true}); + // Find the first point with real coordinates on this curve segment + for (i = last + 1, first = len; i < len; i++) { + if (parents[0].points[i].isReal()) { + first = i; + break; + } + } + // No real points found -> exit + if (first >= len) { + break; + } - if (type.toLowerCase().indexOf('script') > -1) { - board.construct(code); - } else { - try { - board.jc.parse(code); - } catch (e2) { - JXG.debug(e2); + // Find the last point with real coordinates on this curve segment + for (i = first, last = len - 1; i < len - 1; i++) { + if (!parents[0].points[i + 1].isReal()) { + last = i; + break; } } - return board; - }, - makeReload = function (board, code, type, bbox) { - return function () { - var newBoard; + firstx = parents[0].points[first].usrCoords[1]; + lastx = parents[0].points[last].usrCoords[1]; - JXG.JSXGraph.freeBoard(board); - newBoard = init(code, type, bbox); - newBoard.reload = makeReload(newBoard, code, type, bbox); - }; - }; + // Restrict the plot interval if the function ends inside of the board + curve_mi = (bbox[0] < mi) ? mi : bbox[0]; + curve_ma = (bbox[2] > ma) ? ma : bbox[2]; - for (i = 0; i < scripts.length; i++) { - type = scripts[i].getAttribute('type', false); + // Found NaNs + curve_mi = (first === 0) ? curve_mi : Math.max(curve_mi, firstx); + curve_ma = (last === len - 1) ? curve_ma : Math.min(curve_ma, lastx); - if (Type.exists(type) && - (type.toLowerCase() === 'text/jessiescript' || type.toLowerCase() === 'jessiescript' || - type.toLowerCase() === 'text/jessiecode' || type.toLowerCase() === 'jessiecode')) { - width = scripts[i].getAttribute('width', false) || '500px'; - height = scripts[i].getAttribute('height', false) || '500px'; - bbox = scripts[i].getAttribute('boundingbox', false) || '-5, 5, 5, -5'; - id = scripts[i].getAttribute('container', false); + // First and last relevant x-coordinate of the curve + curve_mi = (first === 0) ? mi: firstx; + curve_ma = (last === len - 1)? ma: lastx; - bbox = bbox.split(','); - if (bbox.length !== 4) { - bbox = [-5, 5, 5, -5]; - } else { - for (j = 0; j < bbox.length; j++) { - bbox[j] = parseFloat(bbox[j]); - } + + // Copy the curve points + points = []; + + points.push([1, curve_mi, bbox[infty]]); + points.push([1, curve_mi, parents[0].points[first].usrCoords[2]]); + for (i = first; i <= last; i++) { + points.push(parents[0].points[i].usrCoords); } - axis = Type.str2Bool(scripts[i].getAttribute('axis', false) || 'false'); - grid = Type.str2Bool(scripts[i].getAttribute('grid', false) || 'false'); + points.push([1, curve_ma, parents[0].points[last].usrCoords[2]]); + points.push([1, curve_ma, bbox[infty]]); + points.push(points[0]); - if (!Type.exists(id)) { - id = 'jessiescript_autgen_jxg_' + i; - div = document.createElement('div'); - div.setAttribute('id', id); - div.setAttribute('style', 'width:' + width + '; height:' + height + '; float:left'); - div.setAttribute('class', 'jxgbox'); - try { - document.body.insertBefore(div, scripts[i]); - } catch (e) { - // there's probably jquery involved... - if (typeof jQuery === 'object') { - jQuery(div).insertBefore(scripts[i]); - } - } - } else { - div = document.getElementById(id); + for (i = 0; i < points.length; i++) { + this.dataX.push(points[i][1]); + this.dataY.push(points[i][2]); } - if (document.getElementById(id)) { - code = scripts[i].innerHTML; - code = code.replace(/<!\[CDATA\[/g, '').replace(/\]\]>/g, ''); - scripts[i].innerHTML = code; - board = init(code, type, bbox); - board.reload = makeReload(board, code, type, bbox); - } else { - JXG.debug('JSXGraph: Apparently the div injection failed. Can\'t create a board, sorry.'); + if (last < len - 1) { + this.dataX.push(NaN); + this.dataY.push(NaN); } - } + } + + }; + + // Previous code: + a.hasPoint = function () { + return false; + }; + } else { + // Not yet practical? + f = Type.createFunction(parents[0]); + if (!Type.exists(f)) { + throw new Error("JSXGraph: Can't create area with the given parents." + + "\nPossible parent types: [line], [function]"); } - }, window); - } + } - return JXG.JSXGraph; + a.addParents(parents[0]); + return a; + }; + + + JXG.registerElement('arrowparallel', JXG.createArrowParallel); + JXG.registerElement('bisector', JXG.createBisector); + JXG.registerElement('bisectorlines', JXG.createAngularBisectorsOfTwoLines); + JXG.registerElement('msector', JXG.createMsector); + JXG.registerElement('circumcircle', JXG.createCircumcircle); + JXG.registerElement('circumcirclemidpoint', JXG.createCircumcenter); + JXG.registerElement('circumcenter', JXG.createCircumcenter); + JXG.registerElement('incenter', JXG.createIncenter); + JXG.registerElement('incircle', JXG.createIncircle); + JXG.registerElement('integral', JXG.createIntegral); + JXG.registerElement('midpoint', JXG.createMidpoint); + JXG.registerElement('mirrorelement', JXG.createMirrorElement); + JXG.registerElement('mirrorpoint', JXG.createMirrorPoint); + JXG.registerElement('normal', JXG.createNormal); + JXG.registerElement('orthogonalprojection', JXG.createOrthogonalProjection); + JXG.registerElement('parallel', JXG.createParallel); + JXG.registerElement('parallelpoint', JXG.createParallelPoint); + JXG.registerElement('perpendicular', JXG.createPerpendicular); + JXG.registerElement('perpendicularpoint', JXG.createPerpendicularPoint); + JXG.registerElement('perpendicularsegment', JXG.createPerpendicularSegment); + JXG.registerElement('reflection', JXG.createReflection); + JXG.registerElement('grid', JXG.createGrid); + JXG.registerElement('inequality', JXG.createInequality); + + return { + createArrowParallel: JXG.createArrowParallel, + createBisector: JXG.createBisector, + createAngularBisectorOfTwoLines: JXG.createAngularBisectorsOfTwoLines, + createCircumcircle: JXG.createCircumcircle, + createCircumcenter: JXG.createCircumcenter, + createIncenter: JXG.createIncenter, + createIncircle: JXG.createIncircle, + createIntegral: JXG.createIntegral, + createMidpoint: JXG.createMidpoint, + createMirrorElement: JXG.createMirrorElement, + createMirrorPoint: JXG.createMirrorPoint, + createNormal: JXG.createNormal, + createOrthogonalProjection: JXG.createOrthogonalProjection, + createParallel: JXG.createParallel, + createParallelPoint: JXG.createParallelPoint, + createPerpendicular: JXG.createPerpendicular, + createPerpendicularPoint: JXG.createPerpendicularPoint, + createPerpendicularSegmen: JXG.createPerpendicularSegment, + createReflection: JXG.createReflection, + createGrid: JXG.createGrid, + createInequality: JXG.createInequality + }; }); /* - Copyright 2008-2021 - Matthias Ehmann, - Michael Gerhaeuser, - Carsten Miller, - Bianca Valentin, - Alfred Wassermann, - Peter Wilfahrt + Copyright 2008-2022 + Matthias Ehmann, + Michael Gerhaeuser, + Carsten Miller, + Bianca Valentin, + Alfred Wassermann, + Peter Wilfahrt - This file is part of JSXGraph. + This file is part of JSXGraph. - JSXGraph is free software dual licensed under the GNU LGPL or MIT License. + JSXGraph is free software dual licensed under the GNU LGPL or MIT License. - You can redistribute it and/or modify it under the terms of the + You can redistribute it and/or modify it under the terms of the - * GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version - OR - * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT + * GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version + OR + * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT - JSXGraph is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. + JSXGraph is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. - You should have received a copy of the GNU Lesser General Public License and - the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> - and <http://opensource.org/licenses/MIT/>. + You should have received a copy of the GNU Lesser General Public License and + the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> + and <http://opensource.org/licenses/MIT/>. */ @@ -61811,923 +71529,570 @@ define('jsxgraph',[ /* depends: jxg + math/math + math/geometry + math/numerics + math/statistics + math/symbolic + base/composition + base/coords base/constants utils/type + elements: + line + circle + transform + point + glider + text + curve */ -/** - * @fileoverview In this file the class Group is defined, a class for - * managing grouping of points. - */ - -define('base/group',[ - 'jxg', 'base/constants', 'math/math', 'math/geometry', 'utils/type' -], function (JXG, Const, Mat, Geometry, Type) { +define('element/locus',[ + 'jxg', 'math/symbolic', 'utils/type' +], function (JXG, Symbolic, Type) { "use strict"; /** - * Creates a new instance of Group. - * @class In this class all group management is done. - * @param {JXG.Board} board - * @param {String} id Unique identifier for this object. If null or an empty string is given, - * an unique id will be generated by Board - * @param {String} name Not necessarily unique name, displayed on the board. If null or an - * empty string is given, an unique name will be generated. - * @param {Array} objects Array of points to add to this group. - * @param {Object} attributes Defines the visual appearance of the group. + * @class This element is used to visualize the locus of a given dependent point. + * @pseudo + * @description The locus element is used to visualize the curve a given point describes. * @constructor - */ - JXG.Group = function (board, id, name, objects, attributes) { - var number, objArray, i, obj; - - this.board = board; - this.objects = {}; - number = this.board.numObjects; - this.board.numObjects += 1; - - if ((id === '') || !Type.exists(id)) { - this.id = this.board.id + 'Group' + number; - } else { - this.id = id; - } - this.board.groups[this.id] = this; - - this.type = Const.OBJECT_TYPE_POINT; - this.elementClass = Const.OBJECT_CLASS_POINT; - - if ((name === '') || !Type.exists(name)) { - this.name = 'group_' + this.board.generateName(this); - } else { - this.name = name; - } - delete this.type; - - /** - * Cache coordinates of points. From this and the actual position - * of the points, the translation is determined. - * It has to be kept updated in this class "by hand"- - * - * @private - * @type {Object} - * @see JXG.Group#_updateCoordsCache - */ - this.coords = {}; - this.needsRegularUpdate = attributes.needsregularupdate; - - this.rotationCenter = 'centroid'; - this.scaleCenter = null; - this.rotationPoints = []; - this.translationPoints = []; - this.scalePoints = []; - this.scaleDirections = {}; - - this.parents = []; - - if (Type.isArray(objects)) { - objArray = objects; - } else { - objArray = Array.prototype.slice.call(arguments, 3); - } - - for (i = 0; i < objArray.length; i++) { - obj = this.board.select(objArray[i]); - - if ((!Type.evaluate(obj.visProp.fixed)) && Type.exists(obj.coords)) { - this.addPoint(obj); - } - } - - this.methodMap = { - ungroup: 'ungroup', - add: 'addPoint', - addPoint: 'addPoint', - addPoints: 'addPoints', - addGroup: 'addGroup', - remove: 'removePoint', - removePoint: 'removePoint', - setAttribute: 'setAttribute', - setProperty: 'setAttribute' - }; - }; - - JXG.extend(JXG.Group.prototype, /** @lends JXG.Group.prototype */ { - /** - * Releases all elements of this group. - * @returns {JXG.Group} returns this (empty) group - */ - ungroup: function () { - var el, p, i; - for (el in this.objects) { - if (this.objects.hasOwnProperty(el)) { - p = this.objects[el].point; - if (Type.isArray(p.groups)) { - i = Type.indexOf(p.groups, this.id); - if (i >= 0) { - delete p.groups[i]; - } - } - } - } - - this.objects = {}; - return this; - }, - - /** - * Adds ids of elements to the array this.parents. This is a copy - * of {@link Element.addParents}. - * @param {Array} parents Array of elements or ids of elements. - * Alternatively, one can give a list of objects as parameters. - * @returns {JXG.Object} reference to the object itself. - **/ - addParents: function (parents) { - var i, len, par; - - if (Type.isArray(parents)) { - par = parents; - } else { - par = arguments; - } + * @name Locus + * @type JXG.Curve + * @augments JXG.Curve + * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {JXG.Point} p The constructed curve is the geometric locus of the given point. + * @example + * // This examples needs JXG.Server up and running, otherwise it won't work. + * p1 = board.create('point', [0, 0]); + * p2 = board.create('point', [6, -1]); + * c1 = board.create('circle', [p1, 2]); + * c2 = board.create('circle', [p2, 1.5]); + * g1 = board.create('glider', [6, 3, c1]); + * c3 = board.create('circle', [g1, 4]); + * g2 = board.create('intersection', [c2,c3,0]); + * m1 = board.create('midpoint', [g1,g2]); + * loc = board.create('locus', [m1], {strokeColor: 'red'}); + * </pre><div class="jxgbox" id="JXGd45d7188-6624-4d6e-bebb-1efa2a305c8a" style="width: 400px; height: 400px;"></div> + * <script type="text/javascript"> + * lcex_board = JXG.JSXGraph.initBoard('JXGd45d7188-6624-4d6e-bebb-1efa2a305c8a', {boundingbox:[-4, 6, 10, -6], axis: true, grid: false, keepaspectratio: true}); + * lcex_p1 = lcex_board.create('point', [0, 0]); + * lcex_p2 = lcex_board.create('point', [6, -1]); + * lcex_c1 = lcex_board.create('circle', [lcex_p1, 2]); + * lcex_c2 = lcex_board.create('circle', [lcex_p2, 1.5]); + * lcex_g1 = lcex_board.create('glider', [6, 3, lcex_c1]); + * lcex_c3 = lcex_board.create('circle', [lcex_g1, 4]); + * lcex_g2 = lcex_board.create('intersection', [lcex_c2,lcex_c3,0]); + * lcex_m1 = lcex_board.create('midpoint', [lcex_g1,lcex_g2]); + * lcex_loc = board.create('locus', [lcex_m1], {strokeColor: 'red'}); + * </script><pre> + */ + JXG.createLocus = function (board, parents, attributes) { + var c, p; - len = par.length; - for (i = 0; i < len; ++i) { - if (Type.isId(this.board, par[i])) { - this.parents.push(par[i]); - } else if (Type.exists(par[i].id)) { - this.parents.push(par[i].id); - } - } + if (Type.isArray(parents) && parents.length === 1 && Type.isPoint(parents[0])) { + p = parents[0]; + } else { + throw new Error("JSXGraph: Can't create locus with parent of type other than point." + + "\nPossible parent types: [point]"); + } - this.parents = Type.uniqueArray(this.parents); - }, + c = board.create('curve', [[null], [null]], attributes); + c.dontCallServer = false; - /** - * Sets ids of elements to the array this.parents. This is a copy - * of {@link Element.setParents} - * First, this.parents is cleared. See {@link Group#addParents}. - * @param {Array} parents Array of elements or ids of elements. - * Alternatively, one can give a list of objects as parameters. - * @returns {JXG.Object} reference to the object itself. - **/ - setParents: function(parents) { - this.parents = []; - this.addParents(parents); - }, + c.elType = 'locus'; + c.setParents([p.id]); /** - * List of the element ids resp. values used as parents in {@link JXG.Board#create}. - * @returns {Array} + * Should be documented in JXG.Curve + * @ignore */ - getParents: function () { - return Type.isArray(this.parents) ? this.parents : []; - }, + c.updateDataArray = function () { + var spe, cb, data; - /** - * Update the cached coordinates of a group element. - * @param {String} el element id of the group element whose cached coordinates - * are going to be updated. - * @return null - */ - _updateCoordsCache: function(el) { - var obj; - if (el !== "" && Type.exists(this.objects[el])) { - obj = this.objects[el].point; - this.coords[obj.id] = {usrCoords: obj.coords.usrCoords.slice(0)}; + if (c.board.mode > 0) { + return; } - }, - - /** - * Sends an update to all group members. - * This method is called from the points' coords object event listeners - * and not by the board. - * @param{JXG.GeometryElement} drag Element that caused the update. - * @returns {JXG.Group} returns this group - */ - update: function (drag) { - var el, actionCenter, desc, s, sx, sy, alpha, t, center, obj = null; - if (!this.needsUpdate) { - return this; + spe = Symbolic.generatePolynomials(board, p, true).join('|'); + if (spe === c.spe) { + return; } - drag = this._update_find_drag_type(); - if (drag.action === 'nothing') { - this._updateCoordsCache(drag.id); - return this; - } + c.spe = spe; - obj = this.objects[drag.id].point; + cb = function (x, y, eq, t) { + c.dataX = x; + c.dataY = y; - // Prepare translation, scaling or rotation - if (drag.action === 'translation') { - t = [ - obj.coords.usrCoords[1] - this.coords[drag.id].usrCoords[1], - obj.coords.usrCoords[2] - this.coords[drag.id].usrCoords[2] - ]; + /** + * The implicit definition of the locus. + * @memberOf Locus.prototype + * @name eq + * @type String + */ + c.eq = eq; - } else if (drag.action === 'rotation' || drag.action === 'scaling') { - if (drag.action === 'rotation') { - actionCenter = 'rotationCenter'; - } else { - actionCenter = 'scaleCenter'; - } + /** + * The time it took to calculate the locus + * @memberOf Locus.prototype + * @name ctime + * @type Number + */ + c.ctime = t; - if (Type.isPoint(this[actionCenter])) { - center = this[actionCenter].coords.usrCoords.slice(1); - } else if (this[actionCenter] === 'centroid') { - center = this._update_centroid_center(); - } else if (Type.isArray(this[actionCenter])) { - center = this[actionCenter]; - } else if (Type.isFunction(this[actionCenter])) { - center = this[actionCenter](); - } else { - return this; - } + // convert equation and use it to build a generatePolynomial-method + c.generatePolynomial = (function (equations) { + return function (point) { + var i, + x = '(' + point.symbolic.x + ')', + y = '(' + point.symbolic.y + ')', + res = []; - if (drag.action === 'rotation') { - alpha = Geometry.rad(this.coords[drag.id].usrCoords.slice(1), center, this.objects[drag.id].point); - t = this.board.create('transform', [alpha, center[0], center[1]], {type: 'rotate'}); - t.update(); // This initializes t.matrix, which is needed if the action element is the first group element. - } else if (drag.action === 'scaling') { - s = Geometry.distance(this.coords[drag.id].usrCoords.slice(1), center); - if (Math.abs(s) < Mat.eps) { - return this; - } - s = Geometry.distance(obj.coords.usrCoords.slice(1), center) / s; - sx = (this.scaleDirections[drag.id].indexOf('x') >= 0) ? s : 1.0; - sy = (this.scaleDirections[drag.id].indexOf('y') >= 0) ? s : 1.0; + for (i = 0; i < equations.length; i++) { + res[i] = equations[i].replace(/\*\*/g, '^').replace(/x/g, x).replace(/y/g, y); + } - // Shift scale center to origin, scale and shift the scale center back. - t = this.board.create('transform', - [1, 0, 0, - center[0] * (1 - sx), sx, 0, - center[1] * (1 - sy), 0, sy], {type: 'generic'}); - t.update(); // This initializes t.matrix, which is needed if the action element is the first group element. - } else { - return this; - } - } + return res; + }; + }(eq)); + }; + data = Symbolic.geometricLocusByGroebnerBase(board, p, cb); - this._update_apply_transformation(drag, t); + cb(data.datax, data.datay, data.polynomial, data.exectime); + }; + return c; + }; - this.needsUpdate = false; // This is needed here to prevent infinite recursion because - // of the board.updateElements call below, + JXG.registerElement('locus', JXG.createLocus); - // Prepare dependent objects for update - for (el in this.objects) { - if (this.objects.hasOwnProperty(el)) { - for (desc in this.objects[el].descendants) { - if (this.objects[el].descendants.hasOwnProperty(desc)) { - this.objects[el].descendants.needsUpdate = this.objects[el].descendants.needsRegularUpdate || this.board.needsFullUpdate; - } - } - } - } - this.board.updateElements(drag); + return { + createLocus: JXG.createLocus + }; +}); - // Now, all group elements have their new position and - // we can update the bookkeeping of the coordinates of the group elements. - for (el in this.objects) { - if (this.objects.hasOwnProperty(el)) { - this._updateCoordsCache(el); - } - } +/* + Copyright 2008-2022 + Matthias Ehmann, + Michael Gerhaeuser, + Carsten Miller, + Bianca Valentin, + Alfred Wassermann, + Peter Wilfahrt - return this; - }, + This file is part of JSXGraph. - /** - * @private - * Determine what the dragging of a group element should do: - * rotation, translation, scaling or nothing. - */ - _update_find_drag_type: function () { - var el, obj, - action = 'nothing', - changed = [], - dragObjId; + JSXGraph is free software dual licensed under the GNU LGPL or MIT License. - // Determine how many elements have changed their position - // If more than one element changed its position, it is a translation. - // If exactly one element changed its position we have to find the type of the point. - for (el in this.objects) { - if (this.objects.hasOwnProperty(el)) { - obj = this.objects[el].point; + You can redistribute it and/or modify it under the terms of the - if (obj.coords.distance(Const.COORDS_BY_USER, this.coords[el]) > Mat.eps) { - changed.push(obj.id); - } - } - } + * GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version + OR + * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT - // Determine type of action: translation, scaling or rotation - if (changed.length === 0) { - return { - 'action': action, - 'id': '', - 'changed': changed - }; - } + JSXGraph is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. - dragObjId = changed[0]; - obj = this.objects[dragObjId].point; + You should have received a copy of the GNU Lesser General Public License and + the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> + and <http://opensource.org/licenses/MIT/>. + */ - if (changed.length > 1) { // More than one point moved => translation - action = 'translation'; - } else { // One point moved => we have to determine the type - if (Type.isInArray(this.rotationPoints, obj) && Type.exists(this.rotationCenter)) { - action = 'rotation'; - } else if (Type.isInArray(this.scalePoints, obj) && Type.exists(this.scaleCenter)) { - action = 'scaling'; - } else if (Type.isInArray(this.translationPoints, obj)) { - action = 'translation'; - } - } - return { - 'action': action, - 'id': dragObjId, - 'changed': changed - }; - }, +/*global JXG: true, define: true*/ +/*jslint nomen: true, plusplus: true*/ - /** - * @private - * Determine the Euclidean coordinates of the centroid of the group. - * @returns {Array} array of length two, - */ - _update_centroid_center: function () { - var center, len, el; +/* depends: + jxg + base/constants + base/coords + base/element + math/math + utils/type + */ - center = [0, 0]; - len = 0; - for (el in this.coords) { - if (this.coords.hasOwnProperty(el)) { - center[0] += this.coords[el].usrCoords[1]; - center[1] += this.coords[el].usrCoords[2]; - ++len; - } - } - if (len > 0) { - center[0] /= len; - center[1] /= len; - } +/** + * @fileoverview In this file the geometry element Image is defined. + */ - return center; - }, +define('base/image',[ + 'jxg', 'base/constants', 'base/coords', 'base/element', 'math/math', 'utils/type', 'base/coordselement' +], function (JXG, Const, Coords, GeometryElement, Mat, Type, CoordsElement) { - /** - * @private - * Apply the transformation to all elements of the group - */ - _update_apply_transformation: function (drag, t) { - var el, obj; + "use strict"; - for (el in this.objects) { - if (this.objects.hasOwnProperty(el)) { - if (Type.exists(this.board.objects[el])) { - obj = this.objects[el].point; + /** + * Construct and handle images + * + * The image can be supplied as an URL or an base64 encoded inline image + * like "data:image/png;base64, /9j/4AAQSkZJRgA..." or a function returning + * an URL: function(){ return 'xxx.png; }. + * + * @class Creates a new image object. Do not use this constructor to create a image. Use {@link JXG.Board#create} with + * type {@link Image} instead. + * @augments JXG.GeometryElement + * @augments JXG.CoordsElement + * @param {string|JXG.Board} board The board the new image is drawn on. + * @param {Array} coordinates An array with the user coordinates of the image. + * @param {Object} attributes An object containing visual and - optionally - a name and an id. + * @param {string|function} url An URL string or a function returning an URL string. + * @param {Array} size Array containing width and height of the image in user coordinates. + * + */ + JXG.Image = function (board, coords, attributes, url, size) { + this.constructor(board, attributes, Const.OBJECT_TYPE_IMAGE, Const.OBJECT_CLASS_OTHER); + this.element = this.board.select(attributes.anchor); + this.coordsConstructor(coords); - // Here, it is important that we change the position - // of elements by using setCoordinates. - // Thus, we avoid the call of snapToGrid(). - // This is done in the subsequent call of board.updateElements() - // in Group.update() above. - if (obj.id !== drag.id) { - if (drag.action === 'translation') { - if (!Type.isInArray(drag.changed, obj.id)) { - obj.coords.setCoordinates(Const.COORDS_BY_USER, - [this.coords[el].usrCoords[1] + t[0], - this.coords[el].usrCoords[2] + t[1]]); - } - } else if (drag.action === 'rotation' || drag.action === 'scaling') { - t.applyOnce([obj]); - } - } else { - if (drag.action === 'rotation' || drag.action === 'scaling') { - obj.coords.setCoordinates(Const.COORDS_BY_USER, - Mat.matVecMult(t.matrix, this.coords[obj.id].usrCoords)); - } - } - } else { - delete this.objects[el]; - } - } - } - }, + this.W = Type.createFunction(size[0], this.board, ''); + this.H = Type.createFunction(size[1], this.board, ''); + + this.usrSize = [this.W(), this.H()]; /** - * Adds an Point to this group. - * @param {JXG.Point} object The point added to the group. - * @returns {JXG.Group} returns this group + * Array of length two containing [width, height] of the image in pixel. + * @type array */ - addPoint: function (object) { - this.objects[object.id] = {point: this.board.select(object)}; - this._updateCoordsCache(object.id); - //this.coords[object.id] = {usrCoords: object.coords.usrCoords.slice(0) }; - this.translationPoints.push(object); - - object.groups.push(this.id); - object.groups = Type.uniqueArray(object.groups); - - return this; - }, + this.size = [Math.abs(this.usrSize[0] * board.unitX), Math.abs(this.usrSize[1] * board.unitY)]; /** - * Adds multiple points to this group. - * @param {Array} objects An array of points to add to the group. - * @returns {JXG.Group} returns this group + * 'href' of the image. This might be an URL, but also a data-uri is allowed. + * @type string */ - addPoints: function (objects) { - var p; + this.url = url; - for (p = 0; p < objects.length; p++) { - this.addPoint(objects[p]); - } + this.elType = 'image'; - return this; - }, + // span contains the anchor point and the two vectors + // spanning the image rectangle. + this.span = [ + this.coords.usrCoords.slice(0), + [this.coords.usrCoords[0], this.W(), 0], + [this.coords.usrCoords[0], 0, this.H()] + ]; - /** - * Adds all points in a group to this group. - * @param {JXG.Group} group The group added to this group. - * @returns {JXG.Group} returns this group - */ - addGroup: function (group) { - var el; + //this.parent = board.select(attributes.anchor); + this.id = this.board.setId(this, 'Im'); - for (el in group.objects) { - if (group.objects.hasOwnProperty(el)) { - this.addPoint(group.objects[el].point); - } - } + this.board.renderer.drawImage(this); + this.board.finalizeAdding(this); - return this; - }, + this.methodMap = JXG.deepCopy(this.methodMap, { + addTransformation: 'addTransform', + trans: 'addTransform' + }); + }; - /** - * Removes a point from the group. - * @param {JXG.Point} point - * @returns {JXG.Group} returns this group - */ - removePoint: function (point) { - delete this.objects[point.id]; + JXG.Image.prototype = new GeometryElement(); + Type.copyPrototypeMethods(JXG.Image, CoordsElement, 'coordsConstructor'); - return this; - }, + JXG.extend(JXG.Image.prototype, /** @lends JXG.Image.prototype */ { /** - * Sets the center of rotation for the group. This is either a point or the centroid of the group. - * @param {JXG.Point|String} object A point which will be the center of rotation, the string "centroid", or - * an array of length two, or a function returning an array of length two. - * @default 'centroid' - * @returns {JXG.Group} returns this group + * Checks whether (x,y) is over or near the image; + * @param {Number} x Coordinate in x direction, screen coordinates. + * @param {Number} y Coordinate in y direction, screen coordinates. + * @returns {Boolean} True if (x,y) is over the image, False otherwise. */ - setRotationCenter: function (object) { - this.rotationCenter = object; + hasPoint: function (x, y) { + var dx, dy, r, type, prec, + c, v, p, dot, + len = this.transformations.length; - return this; - }, + if (Type.isObject(Type.evaluate(this.visProp.precision))) { + type = this.board._inputDevice; + prec = Type.evaluate(this.visProp.precision[type]); + } else { + // 'inherit' + prec = this.board.options.precision.hasPoint; + } - /** - * Sets the rotation points of the group. Dragging at one of these points results into a rotation of the whole group around - * the rotation center of the group {@see JXG.Group#setRotationCenter}. - * @param {Array|JXG.Point} objects Array of {@link JXG.Point} or arbitrary number of {@link JXG.Point} elements. - * @returns {JXG.Group} returns this group - */ - setRotationPoints: function (objects) { - return this._setActionPoints('rotation', objects); - }, + // Easy case: no transformation + if (len === 0) { + dx = x - this.coords.scrCoords[1]; + dy = this.coords.scrCoords[2] - y; + r = prec; - /** - * Adds a point to the set of rotation points of the group. Dragging at one of these points results into a rotation of the whole group around - * the rotation center of the group {@see JXG.Group#setRotationCenter}. - * @param {JXG.Point} point {@link JXG.Point} element. - * @returns {JXG.Group} returns this group - */ - addRotationPoint: function (point) { - return this._addActionPoint('rotation', point); - }, + return dx >= -r && dx - this.size[0] <= r && + dy >= -r && dy - this.size[1] <= r; + } - /** - * Removes the rotation property from a point of the group. - * @param {JXG.Point} point {@link JXG.Point} element. - * @returns {JXG.Group} returns this group - */ - removeRotationPoint: function (point) { - return this._removeActionPoint('rotation', point); - }, + // Image is transformed + c = new Coords(Const.COORDS_BY_SCREEN, [x, y], this.board); + // v is the vector from anchor point to the drag point + c = c.usrCoords; + v = [c[0] - this.span[0][0], + c[1] - this.span[0][1], + c[2] - this.span[0][2]]; + dot = Mat.innerProduct; // shortcut - /** - * Sets the translation points of the group. Dragging at one of these points results into a translation of the whole group. - * @param {Array|JXG.Point} objects Array of {@link JXG.Point} or arbitrary number of {@link JXG.Point} elements. - * - * By default, all points of the group are translation points. - * @returns {JXG.Group} returns this group - */ - setTranslationPoints: function (objects) { - return this._setActionPoints('translation', objects); + // Project the drag point to the sides. + p = dot(v, this.span[1]); + if (0 <= p && p <= dot(this.span[1], this.span[1])) { + p = dot(v, this.span[2]); + + if (0 <= p && p <= dot(this.span[2], this.span[2])) { + return true; + } + } + return false; }, /** - * Adds a point to the set of the translation points of the group. - * Dragging one of these points results into a translation of the whole group. - * @param {JXG.Point} point {@link JXG.Point} element. - * @returns {JXG.Group} returns this group + * Recalculate the coordinates of lower left corner and the width and height. + * + * @returns {JXG.GeometryElement} A reference to the element + * @private */ - addTranslationPoint: function (point) { - return this._addActionPoint('translation', point); + update: function (fromParent) { + if (!this.needsUpdate) { + return this; + } + + this.updateCoords(fromParent); + this.updateSize(); + this.updateSpan(); + + return this; }, /** - * Removes the translation property from a point of the group. - * @param {JXG.Point} point {@link JXG.Point} element. - * @returns {JXG.Group} returns this group + * Send an update request to the renderer. + * @private */ - removeTranslationPoint: function (point) { - return this._removeActionPoint('translation', point); + updateRenderer: function () { + return this.updateRendererGeneric('updateImage'); }, /** - * Sets the center of scaling for the group. This is either a point or the centroid of the group. - * @param {JXG.Point|String} object A point which will be the center of scaling, the string "centroid", or - * an array of length two, or a function returning an array of length two. - * @returns {JXG.Group} returns this group + * Updates the internal arrays containing size of the image. + * @returns {JXG.GeometryElement} A reference to the element + * @private */ - setScaleCenter: function (object) { - this.scaleCenter = object; + updateSize: function () { + this.usrSize = [this.W(), this.H()]; + this.size = [Math.abs(this.usrSize[0] * this.board.unitX), Math.abs(this.usrSize[1] * this.board.unitY)]; return this; }, /** - * Sets the scale points of the group. Dragging at one of these points results into a scaling of the whole group. - * @param {Array|JXG.Point} objects Array of {@link JXG.Point} or arbitrary number of {@link JXG.Point} elements. - * @param {String} direction Restricts the directions to be scaled. Possible values are 'x', 'y', 'xy'. Default value is 'xy'. + * Update the anchor point of the image, i.e. the lower left corner + * and the two vectors which span the rectangle. + * @returns {JXG.GeometryElement} A reference to the element + * @private * - * By default, all points of the group are translation points. - * @returns {JXG.Group} returns this group */ - setScalePoints: function (objects, direction) { - var objs, i, len; - if (Type.isArray(objects)) { - objs = objects; + updateSpan: function () { + var i, j, len = this.transformations.length, v = []; + + if (len === 0) { + this.span = [[this.Z(), this.X(), this.Y()], + [this.Z(), this.W(), 0], + [this.Z(), 0, this.H()]]; } else { - objs = arguments; - } + // v contains the three defining corners of the rectangle/image + v[0] = [this.Z(), this.X(), this.Y()]; + v[1] = [this.Z(), this.X() + this.W(), this.Y()]; + v[2] = [this.Z(), this.X(), this.Y() + this.H()]; - len = objs.length; - for (i = 0; i < len; ++i) { - this.scaleDirections[this.board.select(objs[i]).id] = direction || 'xy'; + // Transform the three corners + for (i = 0; i < len; i++) { + for (j = 0; j < 3; j++) { + v[j] = Mat.matVecMult(this.transformations[i].matrix, v[j]); + } + } + // Normalize the vectors + for (j = 0; j < 3; j++) { + v[j][1] /= v[j][0]; + v[j][2] /= v[j][0]; + v[j][0] /= v[j][0]; + } + // Compute the two vectors spanning the rectangle + // by subtracting the anchor point. + for (j = 1; j < 3; j++) { + v[j][0] -= v[0][0]; + v[j][1] -= v[0][1]; + v[j][2] -= v[0][2]; + } + this.span = v; } - return this._setActionPoints('scale', objects); - }, - - /** - * Adds a point to the set of the scale points of the group. Dragging at one of these points results into a scaling of the whole group. - * @param {JXG.Point} point {@link JXG.Point} element. - * @param {String} direction Restricts the directions to be scaled. Possible values are 'x', 'y', 'xy'. Default value is 'xy'. - * @returns {JXG.Group} returns this group - */ - addScalePoint: function (point, direction) { - this._addActionPoint('scale', point); - this.scaleDirections[this.board.select(point).id] = direction || 'xy'; - return this; }, - /** - * Removes the scaling property from a point of the group. - * @param {JXG.Point} point {@link JXG.Point} element. - * @returns {JXG.Group} returns this group - */ - removeScalePoint: function (point) { - return this._removeActionPoint('scale', point); - }, + addTransform: function (transform) { + var i; - /** - * Generic method for {@link JXG.Group@setTranslationPoints} and {@link JXG.Group@setRotationPoints} - * @private - */ - _setActionPoints: function (action, objects) { - var objs, i, len; - if (Type.isArray(objects)) { - objs = objects; + if (Type.isArray(transform)) { + for (i = 0; i < transform.length; i++) { + this.transformations.push(transform[i]); + } } else { - objs = arguments; - } - - len = objs.length; - this[action + 'Points'] = []; - for (i = 0; i < len; ++i) { - this._addActionPoint(action, objs[i]); + this.transformations.push(transform); } return this; }, - /** - * Generic method for {@link JXG.Group@addTranslationPoint} and {@link JXG.Group@addRotationPoint} - * @private - */ - _addActionPoint: function (action, point) { - this[action + 'Points'].push(this.board.select(point)); + // Documented in element.js + getParents: function () { + var p = [this.url, [this.Z(), this.X(), this.Y()], this.usrSize]; - return this; + if (this.parents.length !== 0) { + p = this.parents; + } + + return p; }, /** - * Generic method for {@link JXG.Group@removeTranslationPoint} and {@link JXG.Group@removeRotationPoint} - * @private + * Set the width and height of the image. After setting a new size, + * board.update() or image.fullUpdate() + * has to be called to make the change visible. + * @param {number, function, string} width Number, function or string + * that determines the new width of the image + * @param {number, function, string} height Number, function or string + * that determines the new height of the image + * @returns {JXG.GeometryElement} A reference to the element + * + * @example + * var im = board.create('image', ['https://jsxgraph.org/distrib/images/uccellino.jpg', + * [-3,-2], [3,3]]); + * im.setSize(4, 4); + * board.update(); + * + * </pre><div id="JXG8411e60c-f009-11e5-b1bf-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG8411e60c-f009-11e5-b1bf-901b0e1b8723', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * var im = board.create('image', ['https://jsxgraph.org/distrib/images/uccellino.jpg', [-3,-2], [3,3]]); + * //im.setSize(4, 4); + * //board.update(); + * + * })(); + * + * </script><pre> + * + * @example + * var p0 = board.create('point', [-3, -2]), + * im = board.create('image', ['https://jsxgraph.org/distrib/images/uccellino.jpg', + * [function(){ return p0.X(); }, function(){ return p0.Y(); }], + * [3,3]]), + * p1 = board.create('point', [1, 2]); + * + * im.setSize(function(){ return p1.X() - p0.X(); }, function(){ return p1.Y() - p0.Y(); }); + * board.update(); + * + * </pre><div id="JXG4ce706c0-f00a-11e5-b1bf-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG4ce706c0-f00a-11e5-b1bf-901b0e1b8723', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * var p0 = board.create('point', [-3, -2]), + * im = board.create('image', ['https://jsxgraph.org/distrib/images/uccellino.jpg', + * [function(){ return p0.X(); }, function(){ return p0.Y(); }], + * [3,3]]), + * p1 = board.create('point', [1, 2]); + * + * im.setSize(function(){ return p1.X() - p0.X(); }, function(){ return p1.Y() - p0.Y(); }); + * board.update(); + * + * })(); + * + * </script><pre> + * */ - _removeActionPoint: function (action, point) { - var idx = this[action + 'Points'].indexOf(this.board.select(point)); - if (idx > -1) { - this[action + 'Points'].splice(idx, 1); - } + setSize: function(width, height) { + this.W = Type.createFunction(width, this.board, ''); + this.H = Type.createFunction(height, this.board, ''); + + // this.fullUpdate(); return this; }, /** - * @deprecated - * Use setAttribute + * Returns the width of the image in user coordinates. + * @returns {number} width of the image in user coordinates */ - setProperty: function () { - JXG.deprecated('Group.setProperty', 'Group.setAttribute()'); - this.setAttribute.apply(this, arguments); - }, - - setAttribute: function () { - var el; + W: function() {}, // Needed for docs, defined in constructor - for (el in this.objects) { - if (this.objects.hasOwnProperty(el)) { - this.objects[el].point.setAttribute.apply(this.objects[el].point, arguments); - } - } + /** + * Returns the height of the image in user coordinates. + * @returns {number} height of the image in user coordinates + */ + H: function() {} // Needed for docs, defined in constructor - return this; - } }); /** - * @class This element combines a given set of {@link JXG.Point} elements to a - * group. The elements of the group and dependent elements can be translated, rotated and scaled by - * dragging one of the group elements. - * - * + * @class Displays an image. * @pseudo * @description - * @name Group - * @augments JXG.Group + * @name Image + * @type JXG.Image + * @augments JXG.Image * @constructor - * @type JXG.Group - * @param {JXG.Board} board The board the points are on. - * @param {Array} parents Array of points to group. - * @param {Object} attributes Visual properties (unused). - * @returns {JXG.Group} - * - * @example - * - * // Create some free points. e.g. A, B, C, D - * // Create a group - * - * var p, col, g; - * col = 'blue'; - * p = []; - * p.push(board.create('point',[-2, -1 ], {size: 5, strokeColor:col, fillColor:col})); - * p.push(board.create('point',[2, -1 ], {size: 5, strokeColor:col, fillColor:col})); - * p.push(board.create('point',[2, 1 ], {size: 5, strokeColor:col, fillColor:col})); - * p.push(board.create('point',[-2, 1], {size: 5, strokeColor:col, fillColor:col})); - * g = board.create('group', p); - * - * </pre><div class="jxgbox" id="JXGa2204533-db91-4af9-b720-70394de4d367" style="width: 400px; height: 300px;"></div> - * <script type="text/javascript"> - * (function () { - * var board, p, col, g; - * board = JXG.JSXGraph.initBoard('JXGa2204533-db91-4af9-b720-70394de4d367', {boundingbox:[-5,5,5,-5], keepaspectratio:true, axis:true, showcopyright: false}); - * col = 'blue'; - * p = []; - * p.push(board.create('point',[-2, -1 ], {size: 5, strokeColor:col, fillColor:col})); - * p.push(board.create('point',[2, -1 ], {size: 5, strokeColor:col, fillColor:col})); - * p.push(board.create('point',[2, 1 ], {size: 5, strokeColor:col, fillColor:col})); - * p.push(board.create('point',[-2, 1], {size: 5, strokeColor:col, fillColor:col})); - * g = board.create('group', p); - * })(); - * </script><pre> - * - * + * @constructor + * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {string,function_Array_Array} url,coords,size url defines the location of the image data. The array coords contains the user coordinates + * of the lower left corner of the image. + * It can consist of two or three elements of type number, a string containing a GEONE<sub>x</sub>T + * constraint, or a function which takes no parameter and returns a number. Every element determines one coordinate. If a coordinate is + * given by a number, the number determines the initial position of a free image. If given by a string or a function that coordinate will be constrained + * that means the user won't be able to change the image's position directly by mouse because it will be calculated automatically depending on the string + * or the function's return value. If two parent elements are given the coordinates will be interpreted as 2D affine Euclidean coordinates, if three such + * parent elements are given they will be interpreted as homogeneous coordinates. + * <p> + * The array size defines the image's width and height in user coordinates. * @example + * var im = board.create('image', ['https://jsxgraph.org/jsxgraph/distrib/images/uccellino.jpg', [-3,-2], [3,3]]); * - * // Create some free points. e.g. A, B, C, D - * // Create a group - * // If the points define a polygon and the polygon has the attribute hasInnerPoints:true, - * // the polygon can be dragged around. - * - * var p, col, pol, g; - * col = 'blue'; - * p = []; - * p.push(board.create('point',[-2, -1 ], {size: 5, strokeColor:col, fillColor:col})); - * p.push(board.create('point',[2, -1 ], {size: 5, strokeColor:col, fillColor:col})); - * p.push(board.create('point',[2, 1 ], {size: 5, strokeColor:col, fillColor:col})); - * p.push(board.create('point',[-2, 1], {size: 5, strokeColor:col, fillColor:col})); - * - * pol = board.create('polygon', p, {hasInnerPoints: true}); - * g = board.create('group', p); - * - * </pre><div class="jxgbox" id="JXG781b5564-a671-4327-81c6-de915c8f924e" style="width: 400px; height: 300px;"></div> - * <script type="text/javascript"> - * (function () { - * var board, p, col, pol, g; - * board = JXG.JSXGraph.initBoard('JXG781b5564-a671-4327-81c6-de915c8f924e', {boundingbox:[-5,5,5,-5], keepaspectratio:true, axis:true, showcopyright: false}); - * col = 'blue'; - * p = []; - * p.push(board.create('point',[-2, -1 ], {size: 5, strokeColor:col, fillColor:col})); - * p.push(board.create('point',[2, -1 ], {size: 5, strokeColor:col, fillColor:col})); - * p.push(board.create('point',[2, 1 ], {size: 5, strokeColor:col, fillColor:col})); - * p.push(board.create('point',[-2, 1], {size: 5, strokeColor:col, fillColor:col})); - * pol = board.create('polygon', p, {hasInnerPoints: true}); - * g = board.create('group', p); - * })(); - * </script><pre> - * - * @example - * - * // Allow rotations: - * // Define a center of rotation and declare points of the group as "rotation points". - * - * var p, col, pol, g; - * col = 'blue'; - * p = []; - * p.push(board.create('point',[-2, -1 ], {size: 5, strokeColor:col, fillColor:col})); - * p.push(board.create('point',[2, -1 ], {size: 5, strokeColor:'red', fillColor:'red'})); - * p.push(board.create('point',[2, 1 ], {size: 5, strokeColor:'red', fillColor:'red'})); - * p.push(board.create('point',[-2, 1], {size: 5, strokeColor:col, fillColor:col})); - * - * pol = board.create('polygon', p, {hasInnerPoints: true}); - * g = board.create('group', p); - * g.setRotationCenter(p[0]); - * g.setRotationPoints([p[1], p[2]]); - * - * </pre><div class="jxgbox" id="JXGf0491b62-b377-42cb-b55c-4ef5374b39fc" style="width: 400px; height: 300px;"></div> - * <script type="text/javascript"> - * (function () { - * var board, p, col, pol, g; - * board = JXG.JSXGraph.initBoard('JXGf0491b62-b377-42cb-b55c-4ef5374b39fc', {boundingbox:[-5,5,5,-5], keepaspectratio:true, axis:true, showcopyright: false}); - * col = 'blue'; - * p = []; - * p.push(board.create('point',[-2, -1 ], {size: 5, strokeColor:col, fillColor:col})); - * p.push(board.create('point',[2, -1 ], {size: 5, strokeColor:'red', fillColor:'red'})); - * p.push(board.create('point',[2, 1 ], {size: 5, strokeColor:'red', fillColor:'red'})); - * p.push(board.create('point',[-2, 1], {size: 5, strokeColor:col, fillColor:col})); - * pol = board.create('polygon', p, {hasInnerPoints: true}); - * g = board.create('group', p); - * g.setRotationCenter(p[0]); - * g.setRotationPoints([p[1], p[2]]); - * })(); - * </script><pre> - * - * @example - * - * // Allow rotations: - * // As rotation center, arbitrary points, coordinate arrays, - * // or functions returning coordinate arrays can be given. - * // Another possibility is to use the predefined string 'centroid'. - * - * // The methods to define the rotation points can be chained. - * - * var p, col, pol, g; - * col = 'blue'; - * p = []; - * p.push(board.create('point',[-2, -1 ], {size: 5, strokeColor:col, fillColor:col})); - * p.push(board.create('point',[2, -1 ], {size: 5, strokeColor:'red', fillColor:'red'})); - * p.push(board.create('point',[2, 1 ], {size: 5, strokeColor:'red', fillColor:'red'})); - * p.push(board.create('point',[-2, 1], {size: 5, strokeColor:col, fillColor:col})); - * - * pol = board.create('polygon', p, {hasInnerPoints: true}); - * g = board.create('group', p).setRotationCenter('centroid').setRotationPoints([p[1], p[2]]); - * - * </pre><div class="jxgbox" id="JXG8785b099-a75e-4769-bfd8-47dd4376fe27" style="width: 400px; height: 300px;"></div> - * <script type="text/javascript"> - * (function () { - * var board, p, col, pol, g; - * board = JXG.JSXGraph.initBoard('JXG8785b099-a75e-4769-bfd8-47dd4376fe27', {boundingbox:[-5,5,5,-5], keepaspectratio:true, axis:true, showcopyright: false}); - * col = 'blue'; - * p = []; - * p.push(board.create('point',[-2, -1 ], {size: 5, strokeColor:col, fillColor:col})); - * p.push(board.create('point',[2, -1 ], {size: 5, strokeColor:'red', fillColor:'red'})); - * p.push(board.create('point',[2, 1 ], {size: 5, strokeColor:'red', fillColor:'red'})); - * p.push(board.create('point',[-2, 1], {size: 5, strokeColor:col, fillColor:col})); - * pol = board.create('polygon', p, {hasInnerPoints: true}); - * g = board.create('group', p).setRotationCenter('centroid').setRotationPoints([p[1], p[2]]); - * })(); - * </script><pre> - * - * @example - * - * // Allow scaling: - * // As for rotation one can declare points of the group to trigger a scaling operation. - * // For this, one has to define a scaleCenter, in analogy to rotations. - * - * // Here, the yellow point enables scaling, the red point a rotation. - * - * var p, col, pol, g; - * col = 'blue'; - * p = []; - * p.push(board.create('point',[-2, -1 ], {size: 5, strokeColor:col, fillColor:col})); - * p.push(board.create('point',[2, -1 ], {size: 5, strokeColor:'yellow', fillColor:'yellow'})); - * p.push(board.create('point',[2, 1 ], {size: 5, strokeColor:'red', fillColor:'red'})); - * p.push(board.create('point',[-2, 1], {size: 5, strokeColor:col, fillColor:col})); - * - * pol = board.create('polygon', p, {hasInnerPoints: true}); - * g = board.create('group', p).setRotationCenter('centroid').setRotationPoints([p[2]]); - * g.setScaleCenter(p[0]).setScalePoints(p[1]); - * - * </pre><div class="jxgbox" id="JXGc3ca436b-e4fc-4de5-bab4-09790140c675" style="width: 400px; height: 300px;"></div> - * <script type="text/javascript"> - * (function () { - * var board, p, col, pol, g; - * board = JXG.JSXGraph.initBoard('JXGc3ca436b-e4fc-4de5-bab4-09790140c675', {boundingbox:[-5,5,5,-5], keepaspectratio:true, axis:true, showcopyright: false}); - * col = 'blue'; - * p = []; - * p.push(board.create('point',[-2, -1 ], {size: 5, strokeColor:col, fillColor:col})); - * p.push(board.create('point',[2, -1 ], {size: 5, strokeColor:'yellow', fillColor:'yellow'})); - * p.push(board.create('point',[2, 1 ], {size: 5, strokeColor:'red', fillColor:'red'})); - * p.push(board.create('point',[-2, 1], {size: 5, strokeColor:col, fillColor:col})); - * pol = board.create('polygon', p, {hasInnerPoints: true}); - * g = board.create('group', p).setRotationCenter('centroid').setRotationPoints([p[2]]); - * g.setScaleCenter(p[0]).setScalePoints(p[1]); - * })(); - * </script><pre> - * - * @example - * - * // Allow Translations: - * // By default, every point of a group triggers a translation. - * // There may be situations, when this is not wanted. - * - * // In this example, E triggers nothing, but itself is rotation center - * // and is translated, if other points are moved around. - * - * var p, q, col, pol, g; - * col = 'blue'; - * p = []; - * p.push(board.create('point',[-2, -1 ], {size: 5, strokeColor:col, fillColor:col})); - * p.push(board.create('point',[2, -1 ], {size: 5, strokeColor:'yellow', fillColor:'yellow'})); - * p.push(board.create('point',[2, 1 ], {size: 5, strokeColor:'red', fillColor:'red'})); - * p.push(board.create('point',[-2, 1], {size: 5, strokeColor:col, fillColor:col})); - * q = board.create('point',[0, 0], {size: 5, strokeColor:col, fillColor:col}); - * - * pol = board.create('polygon', p, {hasInnerPoints: true}); - * g = board.create('group', p.concat(q)).setRotationCenter('centroid').setRotationPoints([p[2]]); - * g.setScaleCenter(p[0]).setScalePoints(p[1]); - * g.removeTranslationPoint(q); - * - * </pre><div class="jxgbox" id="JXGd19b800a-57a9-4303-b49a-8f5b7a5488f0" style="width: 400px; height: 300px;"></div> + * </pre><div class="jxgbox" id="JXG9850cda0-7ea0-4750-981c-68bacf9cca57" style="width: 400px; height: 400px;"></div> * <script type="text/javascript"> - * (function () { - * var board, p, q, col, pol, g; - * board = JXG.JSXGraph.initBoard('JXGd19b800a-57a9-4303-b49a-8f5b7a5488f0', {boundingbox:[-5,5,5,-5], keepaspectratio:true, axis:true, showcopyright: false}); - * col = 'blue'; - * p = []; - * p.push(board.create('point',[-2, -1 ], {size: 5, strokeColor:col, fillColor:col})); - * p.push(board.create('point',[2, -1 ], {size: 5, strokeColor:'yellow', fillColor:'yellow'})); - * p.push(board.create('point',[2, 1 ], {size: 5, strokeColor:'red', fillColor:'red'})); - * p.push(board.create('point',[-2, 1], {size: 5, strokeColor:col, fillColor:col})); - * q = board.create('point',[0, 0], {size: 5, strokeColor:col, fillColor:col}); - * - * pol = board.create('polygon', p, {hasInnerPoints: true}); - * g = board.create('group', p.concat(q)).setRotationCenter('centroid').setRotationPoints([p[2]]); - * g.setScaleCenter(p[0]).setScalePoints(p[1]); - * g.removeTranslationPoint(q); - * })(); + * var image_board = JXG.JSXGraph.initBoard('JXG9850cda0-7ea0-4750-981c-68bacf9cca57', {boundingbox: [-4, 4, 4, -4], axis: true, showcopyright: false, shownavigation: false}); + * var image_im = image_board.create('image', ['https://jsxgraph.org/distrib/images/uccellino.jpg', [-3,-2],[3,3]]); * </script><pre> - * - * */ - JXG.createGroup = function (board, parents, attributes) { - var attr = Type.copyAttributes(attributes, board.options, 'group'), - g = new JXG.Group(board, attr.id, attr.name, parents, attr); + JXG.createImage = function (board, parents, attributes) { + var attr, im, + url = parents[0], + coords = parents[1], + size = parents[2]; - g.elType = 'group'; - g.setParents(parents); + attr = Type.copyAttributes(attributes, board.options, 'image'); + im = CoordsElement.create(JXG.Image, board, coords, attr, url, size); + if (!im) { + throw new Error("JSXGraph: Can't create image with parent types '" + + (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + + "\nPossible parent types: [x,y], [z,x,y], [element,transformation]"); + } - return g; + if (attr.rotate !== 0) { // This is the default value, i.e. no rotation + im.addRotation(attr.rotate); + } + + return im; }; - JXG.registerElement('group', JXG.createGroup); + JXG.registerElement('image', JXG.createImage); return { - Group: JXG.Group, - createGroup: JXG.createGroup + Image: JXG.Image, + createImage: JXG.createImage }; }); /* - Copyright 2008-2021 + Copyright 2008-2022 Matthias Ehmann, Michael Gerhaeuser, Carsten Miller, @@ -62763,2624 +72128,2350 @@ define('base/group',[ /* depends: jxg - math/geometry math/math - base/coords - base/circle - utils/type base/constants + base/point + utils/type elements: - curve - midpoint - circumcenter + point + group + segment + ticks + glider + text */ /** - * @fileoverview In this file the geometry object Arc is defined. Arc stores all - * style and functional properties that are required to draw an arc on a board. + * @fileoverview The geometry object slider is defined in this file. Slider stores all + * style and functional properties that are required to draw and use a slider on + * a board. */ -define('element/arc',[ - 'jxg', 'math/geometry', 'math/math', 'base/coords', 'base/circle', 'utils/type', 'base/constants' -], function (JXG, Geometry, Mat, Coords, Circle, Type, Const) { +define('element/slider',[ + 'jxg', 'math/math', 'base/constants', 'base/coords', 'utils/type', 'base/point' +], function (JXG, Mat, Const, Coords, Type, Point) { "use strict"; /** - * @class An arc is a segment of the circumference of a circle. It is defined by a center, one point that - * defines the radius, and a third point that defines the angle of the arc. - * + * @class A slider can be used to choose values from a given range of numbers. * @pseudo - * @name Arc - * @augments Curve + * @description + * @name Slider + * @augments Glider * @constructor - * @type JXG.Curve - * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The result will be an arc of a circle around p1 through p2. The arc is drawn - * counter-clockwise from p2 to p3. + * @type JXG.Point + * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {Array_Array_Array} start,end,data The first two arrays give the start and the end where the slider is drawn + * on the board. The third array gives the start and the end of the range the slider operates as the first resp. the + * third component of the array. The second component of the third array gives its start value. * @example - * // Create an arc out of three free points - * var p1 = board.create('point', [2.0, 2.0]); - * var p2 = board.create('point', [1.0, 0.5]); - * var p3 = board.create('point', [3.5, 1.0]); + * // Create a slider with values between 1 and 10, initial position is 5. + * var s = board.create('slider', [[1, 2], [3, 2], [1, 5, 10]]); + * </pre><div class="jxgbox" id="JXGcfb51cde-2603-4f18-9cc4-1afb452b374d" style="width: 200px; height: 200px;"></div> + * <script type="text/javascript"> + * (function () { + * var board = JXG.JSXGraph.initBoard('JXGcfb51cde-2603-4f18-9cc4-1afb452b374d', {boundingbox: [-1, 5, 5, -1], axis: true, showcopyright: false, shownavigation: false}); + * var s = board.create('slider', [[1, 2], [3, 2], [1, 5, 10]]); + * })(); + * </script><pre> + * @example + * // Create a slider taking integer values between 1 and 50. Initial value is 50. + * var s = board.create('slider', [[1, 3], [3, 1], [0, 10, 50]], {snapWidth: 1, ticks: { drawLabels: true }}); + * </pre><div class="jxgbox" id="JXGe17128e6-a25d-462a-9074-49460b0d66f4" style="width: 200px; height: 200px;"></div> + * <script type="text/javascript"> + * (function () { + * var board = JXG.JSXGraph.initBoard('JXGe17128e6-a25d-462a-9074-49460b0d66f4', {boundingbox: [-1, 5, 5, -1], axis: true, showcopyright: false, shownavigation: false}); + * var s = board.create('slider', [[1, 3], [3, 1], [1, 10, 50]], {snapWidth: 1, ticks: { drawLabels: true }}); + * })(); + * </script><pre> + * @example + * // Draggable slider + * var s1 = board.create('slider', [[-3,1], [2,1],[-10,1,10]], { + * visible: true, + * snapWidth: 2, + * point1: {fixed: false}, + * point2: {fixed: false}, + * baseline: {fixed: false, needsRegularUpdate: true} + * }); * - * var a = board.create('arc', [p1, p2, p3]); - * board.create('text',[1,6,function(){return 'arclength: '+Math.round(a.Value()*100)/100}]) - * </pre><div class="jxgbox" id="JXG114ef584-4a5e-4686-8392-c97501befb5b" style="width: 300px; height: 300px;"></div> + * </pre><div id="JXGbfc67817-2827-44a1-bc22-40bf312e76f8" class="jxgbox" style="width: 300px; height: 300px;"></div> * <script type="text/javascript"> - * (function () { - * var board = JXG.JSXGraph.initBoard('JXG114ef584-4a5e-4686-8392-c97501befb5b', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}), - * p1 = board.create('point', [2.0, 2.0]), - * p2 = board.create('point', [1.0, 0.5]), - * p3 = board.create('point', [3.5, 1.0]), + * (function() { + * var board = JXG.JSXGraph.initBoard('JXGbfc67817-2827-44a1-bc22-40bf312e76f8', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * var s1 = board.create('slider', [[-3,1], [2,1],[-10,1,10]], { + * visible: true, + * snapWidth: 2, + * point1: {fixed: false}, + * point2: {fixed: false}, + * baseline: {fixed: false, needsRegularUpdate: true} + * }); + * + * })(); * - * a = board.create('arc', [p1, p2, p3]); - * board.create('text',[1,6,function(){return 'arclength: '+Math.round(a.Value()*100)/100}]) - * })(); * </script><pre> * * @example - * var t = board.create('transform', [2, 1.5], {type: 'scale'}); - * var a1 = board.create('arc', [[1, 1], [0, 1], [1, 0]], {strokeColor: 'red'}); - * var a2 = board.create('curve', [a1, t], {strokeColor: 'red'}); + * // Set the slider by clicking on the base line: attribute 'moveOnUp' + * var s1 = board.create('slider', [[-3,1], [2,1],[-10,1,10]], { + * snapWidth: 2, + * moveOnUp: true // default value + * }); * - * </pre><div id="JXG1949da46-6339-11e8-9fb9-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div> + * </pre><div id="JXGc0477c8a-b1a7-4111-992e-4ceb366fbccc" class="jxgbox" style="width: 300px; height: 300px;"></div> * <script type="text/javascript"> * (function() { - * var board = JXG.JSXGraph.initBoard('JXG1949da46-6339-11e8-9fb9-901b0e1b8723', + * var board = JXG.JSXGraph.initBoard('JXGc0477c8a-b1a7-4111-992e-4ceb366fbccc', * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); - * var t = board.create('transform', [2, 1.5], {type: 'scale'}); - * var a1 = board.create('arc', [[1, 1], [0, 1], [1, 0]], {strokeColor: 'red'}); - * var a2 = board.create('curve', [a1, t], {strokeColor: 'red'}); + * var s1 = board.create('slider', [[-3,1], [2,1],[-10,1,10]], { + * snapWidth: 2, + * moveOnUp: true // default value + * }); * * })(); * * </script><pre> * - */ - JXG.createArc = function (board, parents, attributes) { - var el, attr, points; - - points = Type.providePoints(board, parents, attributes, 'arc', ['center', 'radiuspoint', 'anglepoint']); - if (points === false || points.length < 3) { - throw new Error("JSXGraph: Can't create Arc with parent types '" + - (typeof parents[0]) + "' and '" + (typeof parents[1]) + "' and '" + - (typeof parents[2]) + "'." + - "\nPossible parent types: [point,point,point], [arc, transformation]"); - } - - attr = Type.copyAttributes(attributes, board.options, 'arc'); - el = board.create('curve', [[0], [0]], attr); - - el.elType = 'arc'; - el.setParents(points); - - /** - * documented in JXG.GeometryElement - * @ignore - */ - el.type = Const.OBJECT_TYPE_ARC; - - /** - * Center of the arc. - * @memberOf Arc.prototype - * @name center - * @type JXG.Point - */ - el.center = points[0]; - - /** - * Point defining the arc's radius. - * @memberOf Arc.prototype - * @name radiuspoint - * @type JXG.Point - */ - el.radiuspoint = points[1]; - el.point2 = el.radiuspoint; - - /** - * The point defining the arc's angle. - * @memberOf Arc.prototype - * @name anglepoint - * @type JXG.Point - */ - el.anglepoint = points[2]; - el.point3 = el.anglepoint; - - // Add arc as child to defining points - el.center.addChild(el); - el.radiuspoint.addChild(el); - el.anglepoint.addChild(el); - - // should be documented in options - el.useDirection = attr.usedirection; - - // documented in JXG.Curve - el.updateDataArray = function () { - var ar, phi, det, p0c, p1c, p2c, - sgn = 1, - A = this.radiuspoint, - B = this.center, - C = this.anglepoint, - ev_s = Type.evaluate(this.visProp.selection); + * @example + * // Set colors + * var sl = board.create('slider', [[-3, 1], [1, 1], [-10, 1, 10]], { + * + * baseline: { strokeColor: 'blue'}, + * highline: { strokeColor: 'red'}, + * fillColor: 'yellow', + * label: {fontSize: 24, strokeColor: 'orange'}, + * name: 'xyz', // Not shown, if suffixLabel is set + * suffixLabel: 'x = ', + * postLabel: ' u' + * + * }); + * + * </pre><div id="JXGd96c9e2c-2c25-4131-b6cf-9dbb80819401" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXGd96c9e2c-2c25-4131-b6cf-9dbb80819401', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * var sl = board.create('slider', [[-3, 1], [1, 1], [-10, 1, 10]], { + * + * baseline: { strokeColor: 'blue'}, + * highline: { strokeColor: 'red'}, + * fillColor: 'yellow', + * label: {fontSize: 24, strokeColor: 'orange'}, + * name: 'xyz', // Not shown, if suffixLabel is set + * suffixLabel: 'x = ', + * postLabel: ' u' + * + * }); + * + * })(); + * + * </script><pre> + * + */ + JXG.createSlider = function (board, parents, attributes) { + var pos0, pos1, smin, start, smax, sdiff, + p1, p2, l1, ticks, ti, startx, starty, p3, l2, t, + withText, withTicks, snapWidth, sw, s, attr, digits; - phi = Geometry.rad(A, B, C); - if ((ev_s === 'minor' && phi > Math.PI) || - (ev_s === 'major' && phi < Math.PI)) { - sgn = -1; - } + attr = Type.copyAttributes(attributes, board.options, 'slider'); + withTicks = attr.withticks; + withText = attr.withlabel; + snapWidth = attr.snapwidth; - // This is true for circumCircleArcs. In that case there is - // a fourth parent element: [center, point1, point3, point2] - if (this.useDirection) { - p0c = points[1].coords.usrCoords; - p1c = points[3].coords.usrCoords; - p2c = points[2].coords.usrCoords; - det = (p0c[1] - p2c[1]) * (p0c[2] - p1c[2]) - (p0c[2] - p2c[2]) * (p0c[1] - p1c[1]); + // start point + attr = Type.copyAttributes(attributes, board.options, 'slider', 'point1'); + p1 = board.create('point', parents[0], attr); - if (det < 0) { - this.radiuspoint = points[1]; - this.anglepoint = points[2]; - } else { - this.radiuspoint = points[2]; - this.anglepoint = points[1]; - } - } + // end point + attr = Type.copyAttributes(attributes, board.options, 'slider', 'point2'); + p2 = board.create('point', parents[1], attr); + //g = board.create('group', [p1, p2]); - A = A.coords.usrCoords; - B = B.coords.usrCoords; - C = C.coords.usrCoords; + // Base line + attr = Type.copyAttributes(attributes, board.options, 'slider', 'baseline'); + l1 = board.create('segment', [p1, p2], attr); - ar = Geometry.bezierArc(A, B, C, false, sgn); + // This is required for a correct projection of the glider onto the segment below + l1.updateStdform(); - this.dataX = ar[0]; - this.dataY = ar[1]; + pos0 = p1.coords.usrCoords.slice(1); + pos1 = p2.coords.usrCoords.slice(1); + smin = parents[2][0]; + start = parents[2][1]; + smax = parents[2][2]; + sdiff = smax - smin; - this.bezierDegree = 3; + sw = Type.evaluate(snapWidth); + s = (sw === -1) ? start : Math.round(start / sw) * sw; + startx = pos0[0] + (pos1[0] - pos0[0]) * (s - smin) / (smax - smin); + starty = pos0[1] + (pos1[1] - pos0[1]) * (s - smin) / (smax - smin); - this.updateStdform(); - this.updateQuadraticform(); - }; + // glider point + attr = Type.copyAttributes(attributes, board.options, 'slider'); + // overwrite this in any case; the sliders label is a special text element, not the gliders label. + // this will be set back to true after the text was created (and only if withlabel was true initially). + attr.withLabel = false; + // gliders set snapwidth=-1 by default (i.e. deactivate them) + p3 = board.create('glider', [startx, starty, l1], attr); + p3.setAttribute({snapwidth: snapWidth}); - /** - * Determines the arc's current radius. I.e. the distance between {@link Arc#center} and {@link Arc#radiuspoint}. - * @memberOf Arc.prototype - * @name Radius - * @function - * @returns {Number} The arc's radius - */ - el.Radius = function () { - return this.radiuspoint.Dist(this.center); - }; + // Segment from start point to glider point: highline + attr = Type.copyAttributes(attributes, board.options, 'slider', 'highline'); + l2 = board.create('segment', [p1, p3], attr); /** - * @deprecated Use {@link Arc#Radius} - * @memberOf Arc.prototype - * @name getRadius + * Returns the current slider value. + * @memberOf Slider.prototype + * @name Value * @function * @returns {Number} */ - el.getRadius = function () { - JXG.deprecated('Arc.getRadius()', 'Arc.Radius()'); - return this.Radius(); - }; + p3.Value = function () { + var sdiff = this._smax - this._smin, + ev_sw = Type.evaluate(this.visProp.snapwidth); - /** - * Returns the length of the arc. - * @memberOf Arc.prototype - * @name Value - * @function - * @returns {Number} The arc length - */ - el.Value = function () { - return this.Radius() * Geometry.rad(this.radiuspoint, this.center, this.anglepoint); + return ev_sw === -1 ? + this.position * sdiff + this._smin : + Math.round((this.position * sdiff + this._smin) / ev_sw) * ev_sw; }; - // documented in geometry element - el.hasPoint = function (x, y) { - var dist, checkPoint, - has, angle, alpha, beta, - invMat, c, - prec, type, - r = this.Radius(), - ev_s = Type.evaluate(this.visProp.selection); - - if (Type.evaluate(this.visProp.hasinnerpoints)) { - return this.hasPointSector(x, y); - } - - if (Type.isObject(Type.evaluate(this.visProp.precision))) { - type = this.board._inputDevice; - prec = Type.evaluate(this.visProp.precision[type]); - } else { - // 'inherit' - prec = this.board.options.precision.hasPoint; - } - prec /= Math.min(this.board.unitX, this.board.unitY); - checkPoint = new Coords(Const.COORDS_BY_SCREEN, [x, y], this.board); - - if (this.transformations.length > 0) { - // Transform the mouse/touch coordinates - // back to the original position of the curve. - this.updateTransformMatrix(); - invMat = Mat.inverse(this.transformMat); - c = Mat.matVecMult(invMat, checkPoint.usrCoords); - checkPoint = new Coords(Const.COORDS_BY_USER, c, this.board); - } - - dist = this.center.coords.distance(Const.COORDS_BY_USER, checkPoint); - has = (Math.abs(dist - r) < prec); - - /** - * At that point we know that the user has touched the circle line. - * Now, we have to check, if the user has hit the arc path. - */ - if (has) { - angle = Geometry.rad(this.radiuspoint, this.center, checkPoint.usrCoords.slice(1)); - alpha = 0.0; - beta = Geometry.rad(this.radiuspoint, this.center, this.anglepoint); - - if ((ev_s === 'minor' && beta > Math.PI) || - (ev_s === 'major' && beta < Math.PI)) { - alpha = beta; - beta = 2 * Math.PI; - } - if (angle < alpha || angle > beta) { - has = false; - } - } - - return has; - }; + p3.methodMap = Type.deepCopy(p3.methodMap, { + Value: 'Value', + setValue: 'setValue', + smax: '_smax', + smin: '_smin', + setMax: 'setMax', + setMin: 'setMin' + }); /** - * Checks whether (x,y) is within the sector defined by the arc. - * @memberOf Arc.prototype - * @name hasPointSector - * @function - * @param {Number} x Coordinate in x direction, screen coordinates. - * @param {Number} y Coordinate in y direction, screen coordinates. - * @returns {Boolean} True if (x,y) is within the sector defined by the arc, False otherwise. + * End value of the slider range. + * @memberOf Slider.prototype + * @name _smax + * @type Number */ - el.hasPointSector = function (x, y) { - var angle, alpha, beta, - checkPoint = new Coords(Const.COORDS_BY_SCREEN, [x, y], this.board), - r = this.Radius(), - dist = this.center.coords.distance(Const.COORDS_BY_USER, checkPoint), - has = (dist < r), - ev_s = Type.evaluate(this.visProp.selection); - - if (has) { - angle = Geometry.rad(this.radiuspoint, this.center, checkPoint.usrCoords.slice(1)); - alpha = 0; - beta = Geometry.rad(this.radiuspoint, this.center, this.anglepoint); - - if ((ev_s === 'minor' && beta > Math.PI) || - (ev_s === 'major' && beta < Math.PI)) { - alpha = beta; - beta = 2 * Math.PI; - } - if (angle < alpha || angle > beta) { - has = false; - } - } - - return has; - }; - - // documented in geometry element - el.getTextAnchor = function () { - return this.center.coords; - }; - - // documented in geometry element - el.getLabelAnchor = function () { - var coords, vec, vecx, vecy, len, - angle = Geometry.rad(this.radiuspoint, this.center, this.anglepoint), - dx = 10 / this.board.unitX, - dy = 10 / this.board.unitY, - p2c = this.point2.coords.usrCoords, - pmc = this.center.coords.usrCoords, - bxminusax = p2c[1] - pmc[1], - byminusay = p2c[2] - pmc[2], - ev_s = Type.evaluate(this.visProp.selection), - l_vp = this.label ? this.label.visProp : this.visProp.label; - - // If this is uncommented, the angle label can not be dragged - //if (Type.exists(this.label)) { - // this.label.relativeCoords = new Coords(Const.COORDS_BY_SCREEN, [0, 0], this.board); - //} - - if ((ev_s === 'minor' && angle > Math.PI) || - (ev_s === 'major' && angle < Math.PI)) { - angle = -(2 * Math.PI - angle); - } - - coords = new Coords(Const.COORDS_BY_USER, [ - pmc[1] + Math.cos(angle * 0.5) * bxminusax - Math.sin(angle * 0.5) * byminusay, - pmc[2] + Math.sin(angle * 0.5) * bxminusax + Math.cos(angle * 0.5) * byminusay - ], this.board); - - vecx = coords.usrCoords[1] - pmc[1]; - vecy = coords.usrCoords[2] - pmc[2]; - - len = Math.sqrt(vecx * vecx + vecy * vecy); - vecx = vecx * (len + dx) / len; - vecy = vecy * (len + dy) / len; - vec = [pmc[1] + vecx, pmc[2] + vecy]; - - l_vp.position = Geometry.calcLabelQuadrant(Geometry.rad([1,0],[0,0],vec)); - - return new Coords(Const.COORDS_BY_USER, vec, this.board); - }; - - // documentation in jxg.circle - el.updateQuadraticform = Circle.Circle.prototype.updateQuadraticform; - - // documentation in jxg.circle - el.updateStdform = Circle.Circle.prototype.updateStdform; - - el.methodMap = JXG.deepCopy(el.methodMap, { - getRadius: 'getRadius', - radius: 'Radius', - center: 'center', - radiuspoint: 'radiuspoint', - anglepoint: 'anglepoint', - Value: 'Value' - }); - - el.prepareUpdate().update(); - return el; - }; - - JXG.registerElement('arc', JXG.createArc); + p3._smax = smax; - /** - * @class A semicircle is a special arc defined by two points. The arc hits both points. - * @pseudo - * @name Semicircle - * @augments Arc - * @constructor - * @type Arc - * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {JXG.Point_JXG.Point} p1,p2 The result will be a composition of an arc drawn clockwise from <tt>p1</tt> and - * <tt>p2</tt> and the midpoint of <tt>p1</tt> and <tt>p2</tt>. - * @example - * // Create an arc out of three free points - * var p1 = board.create('point', [4.5, 2.0]); - * var p2 = board.create('point', [1.0, 0.5]); - * - * var a = board.create('semicircle', [p1, p2]); - * </pre><div class="jxgbox" id="JXG5385d349-75d7-4078-b732-9ae808db1b0e" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function () { - * var board = JXG.JSXGraph.initBoard('JXG5385d349-75d7-4078-b732-9ae808db1b0e', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}), - * p1 = board.create('point', [4.5, 2.0]), - * p2 = board.create('point', [1.0, 0.5]), - * - * sc = board.create('semicircle', [p1, p2]); - * })(); - * </script><pre> - */ - JXG.createSemicircle = function (board, parents, attributes) { - var el, mp, attr, points; + /** + * Start value of the slider range. + * @memberOf Slider.prototype + * @name _smin + * @type Number + */ + p3._smin = smin; - // we need 2 points - points = Type.providePoints(board, parents, attributes, 'point'); - if (points === false || points.length !== 2) { - throw new Error("JSXGraph: Can't create Semicircle with parent types '" + - (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + - "\nPossible parent types: [point,point]"); - } + /** + * Sets the maximum value of the slider. + * @memberOf Slider.prototype + * @name setMax + * @param {Number} val New maximum value + * @returns {Object} this object + */ + p3.setMax = function(val) { + this._smax = val; + return this; + }; - attr = Type.copyAttributes(attributes, board.options, 'semicircle', 'center'); - mp = board.create('midpoint', points, attr); - mp.dump = false; + /** + * Sets the value of the slider. This call must be followed + * by a board update call. + * @memberOf Slider.prototype + * @name setValue + * @param {Number} val New value + * @returns {Object} this object + */ + p3.setValue = function(val) { + var sdiff = this._smax - this._smin; - attr = Type.copyAttributes(attributes, board.options, 'semicircle'); - el = board.create('arc', [mp, points[1], points[0]], attr); - el.elType = 'semicircle'; - el.setParents([points[0].id, points[1].id]); - el.subs = { - midpoint: mp + if (Math.abs(sdiff) > Mat.eps) { + this.position = (val - this._smin) / sdiff; + } else { + this.position = 0.0; //this._smin; + } + this.position = Math.max(0.0, Math.min(1.0, this.position)); + return this; }; - el.inherits.push(mp); /** - * The midpoint of the two defining points. - * @memberOf Semicircle.prototype - * @name midpoint - * @type Midpoint + * Sets the minimum value of the slider. + * @memberOf Slider.prototype + * @name setMin + * @param {Number} val New minimum value + * @returns {Object} this object */ - el.midpoint = el.center = mp; + p3.setMin = function(val) { + this._smin = val; + return this; + }; - return el; - }; + if (withText) { + attr = Type.copyAttributes(attributes, board.options, 'slider', 'label'); + t = board.create('text', [ + function () { + return (p2.X() - p1.X()) * 0.05 + p2.X(); + }, + function () { + return (p2.Y() - p1.Y()) * 0.05 + p2.Y(); + }, + function () { + var n, + d = Type.evaluate(p3.visProp.digits), + sl = Type.evaluate(p3.visProp.suffixlabel), + ul = Type.evaluate(p3.visProp.unitlabel), + pl = Type.evaluate(p3.visProp.postlabel); - JXG.registerElement('semicircle', JXG.createSemicircle); + if (d === 2 && Type.evaluate(p3.visProp.precision) !== 2) { + // Backwards compatibility + d = Type.evaluate(p3.visProp.precision); + } - /** - * @class A circumcircle arc is an {@link Arc} defined by three points. All three points lie on the arc. - * @pseudo - * @name CircumcircleArc - * @augments Arc - * @constructor - * @type Arc - * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 The result will be a composition of an arc of the circumcircle of - * <tt>p1</tt>, <tt>p2</tt>, and <tt>p3</tt> and the midpoint of the circumcircle of the three points. The arc is drawn - * counter-clockwise from <tt>p1</tt> over <tt>p2</tt> to <tt>p3</tt>. - * @example - * // Create a circum circle arc out of three free points - * var p1 = board.create('point', [2.0, 2.0]); - * var p2 = board.create('point', [1.0, 0.5]); - * var p3 = board.create('point', [3.5, 1.0]); - * - * var a = board.create('circumcirclearc', [p1, p2, p3]); - * </pre><div class="jxgbox" id="JXG87125fd4-823a-41c1-88ef-d1a1369504e3" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function () { - * var board = JXG.JSXGraph.initBoard('JXG87125fd4-823a-41c1-88ef-d1a1369504e3', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}), - * p1 = board.create('point', [2.0, 2.0]), - * p2 = board.create('point', [1.0, 0.5]), - * p3 = board.create('point', [3.5, 1.0]), - * - * cca = board.create('circumcirclearc', [p1, p2, p3]); - * })(); - * </script><pre> - */ - JXG.createCircumcircleArc = function (board, parents, attributes) { - var el, mp, attr, points; + if (sl !== null) { + n = sl; + } else if (p3.name && p3.name !== '') { + n = p3.name + ' = '; + } else { + n = ''; + } - // We need three points - points = Type.providePoints(board, parents, attributes, 'point'); - if (points === false || points.length !== 3) { - throw new Error("JSXGraph: create Circumcircle Arc with parent types '" + - (typeof parents[0]) + "' and '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'." + - "\nPossible parent types: [point,point,point]"); + n += Type.toFixed(p3.Value(), d); + + if (ul !== null) { + n += ul; + } + if (pl !== null) { + n += pl; + } + + return n; + } + ], attr); + + /** + * The text element to the right of the slider, indicating its current value. + * @memberOf Slider.prototype + * @name label + * @type JXG.Text + */ + p3.label = t; + + // reset the withlabel attribute + p3.visProp.withlabel = true; + p3.hasLabel = true; } - attr = Type.copyAttributes(attributes, board.options, 'circumcirclearc', 'center'); - mp = board.create('circumcenter', points, attr); - mp.dump = false; + /** + * Start point of the base line. + * @memberOf Slider.prototype + * @name point1 + * @type JXG.Point + */ + p3.point1 = p1; - attr = Type.copyAttributes(attributes, board.options, 'circumcirclearc'); - attr.usedirection = true; - el = board.create('arc', [mp, points[0], points[2], points[1]], attr); + /** + * End point of the base line. + * @memberOf Slider.prototype + * @name point2 + * @type JXG.Point + */ + p3.point2 = p2; - el.elType = 'circumcirclearc'; - el.setParents([points[0].id, points[1].id, points[2].id]); - el.subs = { - center: mp - }; - el.inherits.push(mp); + /** + * The baseline the glider is bound to. + * @memberOf Slider.prototype + * @name baseline + * @type JXG.Line + */ + p3.baseline = l1; /** - * The midpoint of the circumcircle of the three points defining the circumcircle arc. - * @memberOf CircumcircleArc.prototype - * @name center - * @type Circumcenter + * A line on top of the baseline, indicating the slider's progress. + * @memberOf Slider.prototype + * @name highline + * @type JXG.Line */ - el.center = mp; + p3.highline = l2; - return el; - }; + if (withTicks) { + // Function to generate correct label texts - JXG.registerElement('circumcirclearc', JXG.createCircumcircleArc); + attr = Type.copyAttributes(attributes, board.options, 'slider', 'ticks'); + if (!Type.exists(attr.generatelabeltext)) { + attr.generateLabelText = function(tick, zero, value) { + var labelText, + dFull = p3.point1.Dist(p3.point2), + smin = p3._smin, smax = p3._smax, + val = this.getDistanceFromZero(zero, tick) * (smax - smin) / dFull + smin; - /** - * @class A minor arc is a segment of the circumference of a circle having measure less than or equal to - * 180 degrees (pi radians). It is defined by a center, one point that - * defines the radius, and a third point that defines the angle of the arc. - * @pseudo - * @name MinorArc - * @augments Curve - * @constructor - * @type JXG.Curve - * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 . Minor arc is an arc of a circle around p1 having measure less than or equal to - * 180 degrees (pi radians) and starts at p2. The radius is determined by p2, the angle by p3. - * @example - * // Create an arc out of three free points - * var p1 = board.create('point', [2.0, 2.0]); - * var p2 = board.create('point', [1.0, 0.5]); - * var p3 = board.create('point', [3.5, 1.0]); - * - * var a = board.create('arc', [p1, p2, p3]); - * </pre><div class="jxgbox" id="JXG64ba7ca2-8728-45f3-96e5-3c7a4414de2f" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function () { - * var board = JXG.JSXGraph.initBoard('JXG64ba7ca2-8728-45f3-96e5-3c7a4414de2f', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}), - * p1 = board.create('point', [2.0, 2.0]), - * p2 = board.create('point', [1.0, 0.5]), - * p3 = board.create('point', [3.5, 1.0]), - * - * a = board.create('minorarc', [p1, p2, p3]); - * })(); - * </script><pre> - */ + if (dFull < Mat.eps || Math.abs(val) < Mat.eps) { // Point is zero + labelText = '0'; + } else { + labelText = this.formatLabelText(val); + } + return labelText; + }; + } + ticks = 2; + ti = board.create('ticks', [ + p3.baseline, + p3.point1.Dist(p1) / ticks, - JXG.createMinorArc = function (board, parents, attributes) { - attributes.selection = 'minor'; - return JXG.createArc(board, parents, attributes); - }; + function (tick) { + var dFull = p3.point1.Dist(p3.point2), + d = p3.point1.coords.distance(Const.COORDS_BY_USER, tick); - JXG.registerElement('minorarc', JXG.createMinorArc); + if (dFull < Mat.eps) { + return 0; + } - /** - * @class A major arc is a segment of the circumference of a circle having measure greater than or equal to - * 180 degrees (pi radians). It is defined by a center, one point that - * defines the radius, and a third point that defines the angle of the arc. - * @pseudo - * @name MajorArc - * @augments Curve - * @constructor - * @type JXG.Curve - * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 . Major arc is an arc of a circle around p1 having measure greater than or equal to - * 180 degrees (pi radians) and starts at p2. The radius is determined by p2, the angle by p3. - * @example - * // Create an arc out of three free points - * var p1 = board.create('point', [2.0, 2.0]); - * var p2 = board.create('point', [1.0, 0.5]); - * var p3 = board.create('point', [3.5, 1.0]); - * - * var a = board.create('minorarc', [p1, p2, p3]); - * </pre><div class="jxgbox" id="JXG17a10d38-5629-40a4-b150-f41806edee9f" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function () { - * var board = JXG.JSXGraph.initBoard('JXG17a10d38-5629-40a4-b150-f41806edee9f', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}), - * p1 = board.create('point', [2.0, 2.0]), - * p2 = board.create('point', [1.0, 0.5]), - * p3 = board.create('point', [3.5, 1.0]), - * - * a = board.create('majorarc', [p1, p2, p3]); - * })(); - * </script><pre> - */ - JXG.createMajorArc = function (board, parents, attributes) { - attributes.selection = 'major'; - return JXG.createArc(board, parents, attributes); - }; + return d / dFull * sdiff + smin; + } + ], attr); - JXG.registerElement('majorarc', JXG.createMajorArc); + /** + * Ticks give a rough indication about the slider's current value. + * @memberOf Slider.prototype + * @name ticks + * @type JXG.Ticks + */ + p3.ticks = ti; + } - return { - createArc: JXG.createArc, - createSemicircle: JXG.createSemicircle, - createCircumcircleArc: JXG.createCircumcircleArc, - createMinorArc: JXG.createMinorArc, - createMajorArc: JXG.createMajorArc - }; -}); + // override the point's remove method to ensure the removal of all elements + p3.remove = function () { + if (withText) { + board.removeObject(t); + } -/* - Copyright 2008-2021 - Matthias Ehmann, - Michael Gerhaeuser, - Carsten Miller, - Bianca Valentin, - Alfred Wassermann, - Peter Wilfahrt + board.removeObject(l2); + board.removeObject(l1); + board.removeObject(p2); + board.removeObject(p1); - This file is part of JSXGraph. - JSXGraph is free software dual licensed under the GNU LGPL or MIT License. + Point.Point.prototype.remove.call(p3); + }; - You can redistribute it and/or modify it under the terms of the + p1.dump = false; + p2.dump = false; + l1.dump = false; + l2.dump = false; + if (withText) { + t.dump = false; + } - * GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version - OR - * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT - JSXGraph is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. + p3.elType = 'slider'; + p3.parents = parents; + p3.subs = { + point1: p1, + point2: p2, + baseLine: l1, + highLine: l2 + }; + p3.inherits.push(p1, p2, l1, l2); - You should have received a copy of the GNU Lesser General Public License and - the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> - and <http://opensource.org/licenses/MIT/>. - */ + if (withTicks) { + ti.dump = false; + p3.subs.ticks = ti; + p3.inherits.push(ti); + } + p3.getParents = function() { + return [ + this.point1.coords.usrCoords.slice(1), + this.point2.coords.usrCoords.slice(1), + [this._smin, this.position * (this._smax - this._smin) + this._smin, this._smax] + ]; + }; -/*global JXG: true, define: true*/ -/*jslint nomen: true, plusplus: true*/ + p3.baseline.on('up', function(evt) { + var pos, c; -/* depends: - jxg - math/geometry - math/math - base/coords - base/constants - utils/type - elements: - point - curve - circumcentre - transform - */ + if (Type.evaluate(p3.visProp.moveonup) && !Type.evaluate(p3.visProp.fixed) ) { + pos = l1.board.getMousePosition(evt, 0); + c = new Coords(Const.COORDS_BY_SCREEN, pos, this.board); + p3.moveTo([c.usrCoords[1], c.usrCoords[2]]); + } + }); -define('element/sector',[ - 'jxg', 'math/geometry', 'math/math', 'math/statistics', 'base/coords', 'base/constants', 'utils/type', 'base/point', 'base/curve', - 'base/transformation', 'element/composition' -], function (JXG, Geometry, Mat, Statistics, Coords, Const, Type, Point, Curve, Transform, Compositions) { + // Save the visibility attribute of the sub-elements + // for (el in p3.subs) { + // p3.subs[el].status = { + // visible: p3.subs[el].visProp.visible + // }; + // } - "use strict"; + // p3.hideElement = function () { + // var el; + // GeometryElement.prototype.hideElement.call(this); + // + // for (el in this.subs) { + // // this.subs[el].status.visible = this.subs[el].visProp.visible; + // this.subs[el].hideElement(); + // } + // }; - /** - * @class A circular sector is a subarea of the area enclosed by a circle. It is enclosed by two radii and an arc. - * @pseudo - * @name Sector - * @augments JXG.Curve - * @constructor - * @type JXG.Curve - * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. - * - * First possiblity of input parameters are: - * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p1 A sector is defined by three points: The sector's center <tt>p1</tt>, - * a second point <tt>p2</tt> defining the radius and a third point <tt>p3</tt> defining the angle of the sector. The - * Sector is always drawn counter clockwise from <tt>p2</tt> to <tt>p3</tt> - * <p> - * Second possibility of input parameters are: - * @param {JXG.Line_JXG.Line_array,number_array,number_number,function} line, line2, coords1 or direction1, coords2 or direction2, radius The sector is defined by two lines. - * The two legs which define the sector are given by two coordinates arrays which are project initially two the two lines or by two directions (+/- 1). - * The last parameter is the radius of the sector. - * - * - * @example - * // Create a sector out of three free points - * var p1 = board.create('point', [1.5, 5.0]), - * p2 = board.create('point', [1.0, 0.5]), - * p3 = board.create('point', [5.0, 3.0]), - * - * a = board.create('sector', [p1, p2, p3]); - * </pre><div class="jxgbox" id="JXG49f59123-f013-4681-bfd9-338b89893156" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function () { - * var board = JXG.JSXGraph.initBoard('JXG49f59123-f013-4681-bfd9-338b89893156', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}), - * p1 = board.create('point', [1.5, 5.0]), - * p2 = board.create('point', [1.0, 0.5]), - * p3 = board.create('point', [5.0, 3.0]), - * - * a = board.create('sector', [p1, p2, p3]); - * })(); - * </script><pre> - * - * @example - * // Create a sector out of two lines, two directions and a radius - * var p1 = board.create('point', [-1, 4]), - * p2 = board.create('point', [4, 1]), - * q1 = board.create('point', [-2, -3]), - * q2 = board.create('point', [4,3]), - * - * li1 = board.create('line', [p1,p2], {strokeColor:'black', lastArrow:true}), - * li2 = board.create('line', [q1,q2], {lastArrow:true}), - * - * sec1 = board.create('sector', [li1, li2, [5.5, 0], [4, 3], 3]), - * sec2 = board.create('sector', [li1, li2, 1, -1, 4]); - * - * </pre><div class="jxgbox" id="JXGbb9e2809-9895-4ff1-adfa-c9c71d50aa53" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function () { - * var board = JXG.JSXGraph.initBoard('JXGbb9e2809-9895-4ff1-adfa-c9c71d50aa53', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}), - * p1 = board.create('point', [-1, 4]), - * p2 = board.create('point', [4, 1]), - * q1 = board.create('point', [-2, -3]), - * q2 = board.create('point', [4,3]), - * - * li1 = board.create('line', [p1,p2], {strokeColor:'black', lastArrow:true}), - * li2 = board.create('line', [q1,q2], {lastArrow:true}), - * - * sec1 = board.create('sector', [li1, li2, [5.5, 0], [4, 3], 3]), - * sec2 = board.create('sector', [li1, li2, 1, -1, 4]); - * })(); - * </script><pre> - * - * @example - * var t = board.create('transform', [2, 1.5], {type: 'scale'}); - * var s1 = board.create('sector', [[-3.5,-3], [-3.5, -2], [-3.5,-4]], { - * anglePoint: {visible:true}, center: {visible: true}, radiusPoint: {visible: true}, - * fillColor: 'yellow', strokeColor: 'black'}); - * var s2 = board.create('curve', [s1, t], {fillColor: 'yellow', strokeColor: 'black'}); - * - * </pre><div id="JXG2e70ee14-6339-11e8-9fb9-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function() { - * var board = JXG.JSXGraph.initBoard('JXG2e70ee14-6339-11e8-9fb9-901b0e1b8723', - * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); - * var t = board.create('transform', [2, 1.5], {type: 'scale'}); - * var s1 = board.create('sector', [[-3.5,-3], [-3.5, -2], [-3.5,-4]], { - * anglePoint: {visible:true}, center: {visible: true}, radiusPoint: {visible: true}, - * fillColor: 'yellow', strokeColor: 'black'}); - * var s2 = board.create('curve', [s1, t], {fillColor: 'yellow', strokeColor: 'black'}); - * - * })(); - * - * </script><pre> - * - */ - JXG.createSector = function (board, parents, attributes) { - var el, attr, - type = 'invalid', - s, v, - attrPoints = ['center', 'radiuspoint', 'anglepoint'], - points; +// p3.showElement = function () { +// var el; +// GeometryElement.prototype.showElement.call(this); +// +// for (el in this.subs) { +// // if (this.subs[el].status.visible) { +// this.subs[el].showElement(); +// // } +// } +// }; - // Three points? - if (parents[0].elementClass === Const.OBJECT_CLASS_LINE && - parents[1].elementClass === Const.OBJECT_CLASS_LINE && - (Type.isArray(parents[2]) || Type.isNumber(parents[2])) && - (Type.isArray(parents[3]) || Type.isNumber(parents[3])) && - (Type.isNumber(parents[4]) || Type.isFunction(parents[4]))) { - type = '2lines'; - } else { - points = Type.providePoints(board, parents, attributes, 'sector', attrPoints); - if (points === false) { - throw new Error("JSXGraph: Can't create Sector with parent types '" + - (typeof parents[0]) + "' and '" + (typeof parents[1]) + "' and '" + - (typeof parents[2]) + "'."); + + // This is necessary to show baseline, highline and ticks + // when opening the board in case the visible attributes are set + // to 'inherit'. + p3.prepareUpdate().update(); + if (!board.isSuspendedUpdate) { + p3.updateVisibility().updateRenderer(); + p3.baseline.updateVisibility().updateRenderer(); + p3.highline.updateVisibility().updateRenderer(); + if (withTicks) { + p3.ticks.updateVisibility().updateRenderer(); } - type = '3points'; } + return p3; + }; - attr = Type.copyAttributes(attributes, board.options, 'sector'); - el = board.create('curve', [[0], [0]], attr); - el.type = Const.OBJECT_TYPE_SECTOR; - el.elType = 'sector'; + JXG.registerElement('slider', JXG.createSlider); - if (type === '2lines') { - el.Radius = function () { - return Type.evaluate(parents[4]); - }; + return { + createSlider: JXG.createSlider + }; +}); - el.line1 = board.select(parents[0]); - el.line2 = board.select(parents[1]); +/* + Copyright 2008-2022 + Matthias Ehmann, + Michael Gerhaeuser, + Carsten Miller, + Bianca Valentin, + Alfred Wassermann, + Peter Wilfahrt - el.line1.addChild(el); - el.line2.addChild(el); - el.setParents(parents); + This file is part of JSXGraph. - el.point1 = {visProp: {}}; - el.point2 = {visProp: {}}; - el.point3 = {visProp: {}}; + JSXGraph is free software dual licensed under the GNU LGPL or MIT License. - /* Intersection point */ - s = Geometry.meetLineLine(el.line1.stdform, el.line2.stdform, 0, board); + You can redistribute it and/or modify it under the terms of the - if (Type.isArray(parents[2])) { - /* project p1 to l1 */ - if (parents[2].length === 2) { - parents[2] = [1].concat(parents[2]); - } - /* - v = [0, el.line1.stdform[1], el.line1.stdform[2]]; - v = Mat.crossProduct(v, parents[2]); - v = Geometry.meetLineLine(v, el.line1.stdform, 0, board); - */ - v = Geometry.projectPointToLine({coords: {usrCoords: parents[2]}}, el.line1, board); - v = Statistics.subtract(v.usrCoords, s.usrCoords); - el.direction1 = (Mat.innerProduct(v, [0, el.line1.stdform[2], -el.line1.stdform[1]], 3) >= 0) ? +1 : -1; - } else { - el.direction1 = (parents[2] >= 0) ? 1 : -1; - } + * GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version + OR + * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT - if (Type.isArray(parents[3])) { - /* project p2 to l2 */ - if (parents[3].length === 2) { - parents[3] = [1].concat(parents[3]); - } - /* - v = [0, el.line2.stdform[1], el.line2.stdform[2]]; - v = Mat.crossProduct(v, parents[3]); - v = Geometry.meetLineLine(v, el.line2.stdform, 0, board); - */ - v = Geometry.projectPointToLine({coords: {usrCoords: parents[3]}}, el.line2, board); - v = Statistics.subtract(v.usrCoords, s.usrCoords); - el.direction2 = (Mat.innerProduct(v, [0, el.line2.stdform[2], -el.line2.stdform[1]], 3) >= 0) ? +1 : -1; - } else { - el.direction2 = (parents[3] >= 0) ? 1 : -1; - } + JSXGraph is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. - el.updateDataArray = function () { - var r, l1, l2, - A = [0, 0, 0], - B = [0, 0, 0], - C = [0, 0, 0], - ar; + You should have received a copy of the GNU Lesser General Public License and + the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> + and <http://opensource.org/licenses/MIT/>. + */ - l1 = this.line1; - l2 = this.line2; - // Intersection point of the lines - B = Mat.crossProduct(l1.stdform, l2.stdform); +/*global JXG: true, define: true*/ +/*jslint nomen: true, plusplus: true*/ - if (Math.abs(B[0]) > Mat.eps * Mat.eps) { - B[1] /= B[0]; - B[2] /= B[0]; - B[0] /= B[0]; - } - // First point - r = this.direction1 * this.Radius(); - A = Statistics.add(B, [0, r * l1.stdform[2], -r * l1.stdform[1]]); +/* depends: + jxg + utils/type + base/element + elements: + point + segment + ticks + */ - // Second point - r = this.direction2 * this.Radius(); - C = Statistics.add(B, [0, r * l2.stdform[2], -r * l2.stdform[1]]); +/** + * @fileoverview Geometry objects for measurements are defined in this file. This file stores all + * style and functional properties that are required to use a tape measure on + * a board. + */ - this.point2.coords = new Coords(Const.COORDS_BY_USER, A, el.board); - this.point1.coords = new Coords(Const.COORDS_BY_USER, B, el.board); - this.point3.coords = new Coords(Const.COORDS_BY_USER, C, el.board); +define('element/measure',[ + 'jxg', 'utils/type', 'base/element' +], function (JXG, Type, GeometryElement) { - if (Math.abs(A[0]) < Mat.eps || Math.abs(B[0]) < Mat.eps || Math.abs(C[0]) < Mat.eps) { - this.dataX = [NaN]; - this.dataY = [NaN]; - return; - } + "use strict"; - ar = Geometry.bezierArc(A, B, C, true, 1); + /** + * @class A tape measure can be used to measure distances between points. + * @pseudo + * @description + * @name Tapemeasure + * @augments Segment + * @constructor + * @type JXG.Segment + * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {Array_Array} start,end, The two arrays give the initial position where the tape measure + * is drawn on the board. + * @example + * // Create a tape measure + * var p1 = board.create('point', [0,0]); + * var p2 = board.create('point', [1,1]); + * var p3 = board.create('point', [3,1]); + * var tape = board.create('tapemeasure', [[1, 2], [4, 2]], {name:'dist'}); + * </pre><div class="jxgbox" id="JXG6d9a2cda-22fe-4cd1-9d94-34283b1bdc01" style="width: 200px; height: 200px;"></div> + * <script type="text/javascript"> + * (function () { + * var board = JXG.JSXGraph.initBoard('JXG6d9a2cda-22fe-4cd1-9d94-34283b1bdc01', {boundingbox: [-1, 5, 5, -1], axis: true, showcopyright: false, shownavigation: false}); + * var p1 = board.create('point', [0,0]); + * var p2 = board.create('point', [1,1]); + * var p3 = board.create('point', [3,1]); + * var tape = board.create('tapemeasure', [[1, 2], [4, 2]], {name:'dist'} ); + * })(); + * </script><pre> + */ + JXG.createTapemeasure = function (board, parents, attributes) { + var pos0, pos1, + attr, withTicks, withText, digits, + li, p1, p2, n, ti; - this.dataX = ar[0]; - this.dataY = ar[1]; + pos0 = parents[0]; + pos1 = parents[1]; - this.bezierDegree = 3; - }; + // start point + attr = Type.copyAttributes(attributes, board.options, 'tapemeasure', 'point1'); + p1 = board.create('point', pos0, attr); - el.methodMap = JXG.deepCopy(el.methodMap, { - radius: 'getRadius', - getRadius: 'getRadius', - setRadius: 'setRadius' - }); + // end point + attr = Type.copyAttributes(attributes, board.options, 'tapemeasure', 'point2'); + p2 = board.create('point', pos1, attr); - el.prepareUpdate().update(); + p1.setAttribute({ignoredSnapToPoints: [p2]}); + p2.setAttribute({ignoredSnapToPoints: [p1]}); - // end '2lines' + // tape measure line + attr = Type.copyAttributes(attributes, board.options, 'tapemeasure'); + withTicks = attr.withticks; + withText = attr.withlabel; + digits = attr.digits; - } else if (type === '3points') { + if (digits === 2 && attr.precision !== 2) { + // Backward compatibility + digits = attr.precision; + } - /** - * Midpoint of the sector. - * @memberOf Sector.prototype - * @name point1 - * @type JXG.Point - */ - el.point1 = points[0]; + // Below, we will replace the label by the measurement function. + if (withText) { + attr.withlabel = true; + } + li = board.create('segment', [p1, p2], attr); + // p1, p2 are already added to li.inherits - /** - * This point together with {@link Sector#point1} defines the radius.. - * @memberOf Sector.prototype - * @name point2 - * @type JXG.Point - */ - el.point2 = points[1]; + if (withText) { + if (attributes.name && attributes.name !== '') { + n = attributes.name + ' = '; + } else { + n = ''; + } + li.label.setText(function () { + return n + Type.toFixed(p1.Dist(p2), digits); + }); + } - /** - * Defines the sector's angle. - * @memberOf Sector.prototype - * @name point3 - * @type JXG.Point - */ - el.point3 = points[2]; + if (withTicks) { + attr = Type.copyAttributes(attributes, board.options, 'tapemeasure', 'ticks'); + //ticks = 2; + ti = board.create('ticks', [li, 0.1], attr); + li.inherits.push(ti); + } - /* Add arc as child to defining points */ - el.point1.addChild(el); - el.point2.addChild(el); - el.point3.addChild(el); + // override the segments's remove method to ensure the removal of all elements + /** @ignore */ + li.remove = function () { + if (withTicks) { + li.removeTicks(ti); + } - // useDirection is necessary for circumCircleSectors - el.useDirection = attributes.usedirection; - el.setParents(points); + board.removeObject(p2); + board.removeObject(p1); - /** - * Defines the sectors orientation in case of circumCircleSectors. - * @memberOf Sector.prototype - * @name point4 - * @type JXG.Point - */ - if (Type.exists(points[3])) { - el.point4 = points[3]; - el.point4.addChild(el); - } + GeometryElement.prototype.remove.call(this); + }; - el.methodMap = JXG.deepCopy(el.methodMap, { - arc: 'arc', - center: 'center', - radiuspoint: 'radiuspoint', - anglepoint: 'anglepoint', - radius: 'getRadius', - getRadius: 'getRadius', - setRadius: 'setRadius' - }); + /** + * Returns the length of the tape measure. + * @name Value + * @memberOf Tapemeasure.prototype + * @function + * @returns {Number} length of tape measure. + */ + li.Value = function () { + return p1.Dist(p2); + }; - /** - * documented in JXG.Curve - * @ignore - */ - el.updateDataArray = function () { - var ar, det, p0c, p1c, p2c, - A = this.point2, - B = this.point1, - C = this.point3, - phi, sgn = 1, - vp_s = Type.evaluate(this.visProp.selection); + p1.dump = false; + p2.dump = false; - if (!A.isReal || !B.isReal || !C.isReal) { - this.dataX = [NaN]; - this.dataY = [NaN]; - return; - } + li.elType = 'tapemeasure'; + li.getParents = function() { + return [[p1.X(), p1.Y()], [p2.X(), p2.Y()]]; + }; - phi = Geometry.rad(A, B, C); - if ((vp_s === 'minor' && phi > Math.PI) || - (vp_s === 'major' && phi < Math.PI)) { - sgn = -1; - } + li.subs = { + point1: p1, + point2: p2 + }; - // This is true for circumCircleSectors. In that case there is - // a fourth parent element: [midpoint, point1, point3, point2] - if (this.useDirection && Type.exists(this.point4)) { - p0c = this.point2.coords.usrCoords; - p1c = this.point4.coords.usrCoords; - p2c = this.point3.coords.usrCoords; - det = (p0c[1] - p2c[1]) * (p0c[2] - p1c[2]) - (p0c[2] - p2c[2]) * (p0c[1] - p1c[1]); + if (withTicks) { + ti.dump = false; + } - if (det >= 0.0) { - C = this.point2; - A = this.point3; - } - } + li.methodMap = JXG.deepCopy(li.methodMap, { + Value: 'Value' + }); - A = A.coords.usrCoords; - B = B.coords.usrCoords; - C = C.coords.usrCoords; + li.prepareUpdate().update(); + if (!board.isSuspendedUpdate) { + li.updateVisibility().updateRenderer(); + // The point updates are necessary in case of snapToGrid==true + li.point1.updateVisibility().updateRenderer(); + li.point2.updateVisibility().updateRenderer(); + } - ar = Geometry.bezierArc(A, B, C, true, sgn); + return li; + }; - this.dataX = ar[0]; - this.dataY = ar[1]; - this.bezierDegree = 3; - }; + JXG.registerElement('tapemeasure', JXG.createTapemeasure); - /** - * Returns the radius of the sector. - * @memberOf Sector.prototype - * @name Radius - * @function - * @returns {Number} The distance between {@link Sector#point1} and {@link Sector#point2}. - */ - el.Radius = function () { - return this.point2.Dist(this.point1); - }; + return { + createTapemeasure: JXG.createTapemeasure + }; +}); - attr = Type.copyAttributes(attributes, board.options, 'sector', 'arc'); - attr.withLabel = false; - attr.name += '_arc'; - el.arc = board.create('arc', [el.point1, el.point2, el.point3], attr); - el.addChild(el.arc); - } // end '3points' +/* + Copyright 2008-2022 + Matthias Ehmann, + Michael Gerhaeuser, + Carsten Miller, + Bianca Valentin, + Alfred Wassermann, + Peter Wilfahrt - el.center = el.point1; - el.radiuspoint = el.point2; - el.anglepoint = el.point3; + This file is part of JSXGraph. - // Default hasPoint method. Documented in geometry element - el.hasPointCurve = function (x, y) { - var angle, alpha, beta, - prec, type, - checkPoint = new Coords(Const.COORDS_BY_SCREEN, [x, y], this.board), - r = this.Radius(), - dist = this.center.coords.distance(Const.COORDS_BY_USER, checkPoint), - has, - vp_s = Type.evaluate(this.visProp.selection); + JSXGraph is free software dual licensed under the GNU LGPL or MIT License. - if (Type.isObject(Type.evaluate(this.visProp.precision))) { - type = this.board._inputDevice; - prec = Type.evaluate(this.visProp.precision[type]); - } else { - // 'inherit' - prec = this.board.options.precision.hasPoint; - } - prec /= Math.min(this.board.unitX, this.board.unitY); - has = (Math.abs(dist - r) < prec); - if (has) { - angle = Geometry.rad(this.point2, this.center, checkPoint.usrCoords.slice(1)); - alpha = 0; - beta = Geometry.rad(this.point2, this.center, this.point3); + You can redistribute it and/or modify it under the terms of the - if ((vp_s === 'minor' && beta > Math.PI) || - (vp_s === 'major' && beta < Math.PI)) { - alpha = beta; - beta = 2 * Math.PI; - } + * GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version + OR + * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT - if (angle < alpha || angle > beta) { - has = false; - } - } + JSXGraph is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. - return has; - }; + You should have received a copy of the GNU Lesser General Public License and + the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> + and <http://opensource.org/licenses/MIT/>. + */ - /** - * Checks whether (x,y) is within the area defined by the sector. - * @memberOf Sector.prototype - * @name hasPointSector - * @function - * @param {Number} x Coordinate in x direction, screen coordinates. - * @param {Number} y Coordinate in y direction, screen coordinates. - * @returns {Boolean} True if (x,y) is within the sector defined by the arc, False otherwise. - */ - el.hasPointSector = function (x, y) { - var angle, - checkPoint = new Coords(Const.COORDS_BY_SCREEN, [x, y], this.board), - r = this.Radius(), - dist = this.point1.coords.distance(Const.COORDS_BY_USER, checkPoint), - alpha, - beta, - has = (dist < r), - vp_s = Type.evaluate(this.visProp.selection); - if (has) { - angle = Geometry.rad(this.radiuspoint, this.center, checkPoint.usrCoords.slice(1)); - alpha = 0.0; - beta = Geometry.rad(this.radiuspoint, this.center, this.anglepoint); +/*global JXG: true, define: true, document: true*/ +/*jslint nomen: true, plusplus: true*/ - if ((vp_s === 'minor' && beta > Math.PI) || - (vp_s === 'major' && beta < Math.PI)) { - alpha = beta; - beta = 2 * Math.PI; - } - //if (angle > Geometry.rad(this.point2, this.point1, this.point3)) { - if (angle < alpha || angle > beta) { - has = false; - } - } - return has; - }; +/* depends: + jxg + utils/type + */ - el.hasPoint = function (x, y) { - if (Type.evaluate(this.visProp.highlightonsector) || - Type.evaluate(this.visProp.hasinnerpoints)) { - return this.hasPointSector(x, y); - } +/** + * @fileoverview The JXG.DataSource is a helper class for data organization. Currently supported data sources are + * javascript arrays and HTML tables. + */ - return this.hasPointCurve(x, y); - }; +define('parser/datasource',['jxg', 'utils/type'], function (JXG, Type) { - // documented in GeometryElement - el.getTextAnchor = function () { - return this.point1.coords; - }; + "use strict"; - // documented in GeometryElement - // this method is very similar to arc.getLabelAnchor() - // there are some additions in the arc version though, mainly concerning - // "major" and "minor" arcs. but maybe these methods can be merged. - el.getLabelAnchor = function () { - var coords, vec, vecx, vecy, len, - angle = Geometry.rad(this.point2, this.point1, this.point3), - dx = 13 / this.board.unitX, - dy = 13 / this.board.unitY, - p2c = this.point2.coords.usrCoords, - pmc = this.point1.coords.usrCoords, - bxminusax = p2c[1] - pmc[1], - byminusay = p2c[2] - pmc[2], - vp_s = Type.evaluate(this.visProp.selection), - l_vp = this.label ? this.label.visProp : this.visProp.label; + JXG.DataSource = function () { + this.data = []; + this.columnHeaders = []; + this.rowHeaders = []; - // If this is uncommented, the angle label can not be dragged - //if (Type.exists(this.label)) { - // this.label.relativeCoords = new Coords(Const.COORDS_BY_SCREEN, [0, 0], this.board); - //} + return this; + }; - if ((vp_s === 'minor' && angle > Math.PI) || - (vp_s === 'major' && angle < Math.PI)) { - angle = -(2 * Math.PI - angle); + JXG.extend(JXG.DataSource.prototype, /** @lends JXG.DataSource.prototype */ { + loadFromArray: function (table, columnHeader, rowHeader) { + var i, j, cell; + + if (Type.isArray(columnHeader)) { + this.columnHeaders = columnHeader; + columnHeader = false; } - coords = new Coords(Const.COORDS_BY_USER, [ - pmc[1] + Math.cos(angle * 0.5) * bxminusax - Math.sin(angle * 0.5) * byminusay, - pmc[2] + Math.sin(angle * 0.5) * bxminusax + Math.cos(angle * 0.5) * byminusay - ], this.board); + if (Type.isArray(rowHeader)) { + this.rowHeaders = rowHeader; + rowHeader = false; + } - vecx = coords.usrCoords[1] - pmc[1]; - vecy = coords.usrCoords[2] - pmc[2]; + this.data = []; - len = Math.sqrt(vecx * vecx + vecy * vecy); - vecx = vecx * (len + dx) / len; - vecy = vecy * (len + dy) / len; - vec = [pmc[1] + vecx, pmc[2] + vecy]; + if (columnHeader) { + this.columnHeaders = []; + } - l_vp.position = Geometry.calcLabelQuadrant(Geometry.rad([1,0],[0,0],vec)); + if (rowHeader) { + this.rowHeaders = []; + } - return new Coords(Const.COORDS_BY_USER, vec, this.board); - }; + if (Type.exists(table)) { + // extract the data + this.data = []; - /** - * Overwrite the Radius method of the sector. - * Used in {@link GeometryElement#setAttribute}. - * @param {Number, Function} value New radius. - */ - el.setRadius = function (value) { - el.Radius = function () { - return Type.evaluate(value); - }; - }; + for (i = 0; i < table.length; i++) { + this.data[i] = []; - /** - * @deprecated - * @ignore - */ - el.getRadius = function () { - JXG.deprecated('Sector.getRadius()', 'Sector.Radius()'); - return this.Radius(); - }; + for (j = 0; j < table[i].length; j++) { + cell = table[i][j]; + if (parseFloat(cell).toString() === cell) { + this.data[i][j] = parseFloat(cell); + } else if (cell !== '-') { + this.data[i][j] = cell; + } else { + this.data[i][j] = NaN; + } + } + } - /** - * Moves the sector by the difference of two coordinates. - * @param {Number} method The type of coordinates used here. Possible values are {@link JXG.COORDS_BY_USER} and {@link JXG.COORDS_BY_SCREEN}. - * @param {Array} coords coordinates in screen/user units - * @param {Array} oldcoords previous coordinates in screen/user units - * @returns {JXG.Curve} this element - */ - if (type === '3points') { - el.setPositionDirectly = function (method, coords, oldcoords) { - var dc, t, i, - c = new Coords(method, coords, this.board), - oldc = new Coords(method, oldcoords, this.board); + if (columnHeader) { + this.columnHeaders = this.data[0].slice(1); + this.data = this.data.slice(1); + } - if (!el.point1.draggable() || !el.point2.draggable() || !el.point3.draggable()) { - return this; + if (rowHeader) { + this.rowHeaders = []; + for (i = 0; i < this.data.length; i++) { + this.rowHeaders.push(this.data[i][0]); + this.data[i] = this.data[i].slice(1); + } } + } - dc = Statistics.subtract(c.usrCoords, oldc.usrCoords); - t = this.board.create('transform', dc.slice(1), {type: 'translate'}); - t.applyOnce([el.point1, el.point2, el.point3]); + return this; + }, - return this; - }; - } + loadFromTable: function (table, columnHeader, rowHeader) { + var row, i, j, col, cell, name; - el.prepareUpdate().update(); + if (Type.isArray(columnHeader)) { + this.columnHeaders = columnHeader; + columnHeader = false; + } - return el; - }; + if (Type.isArray(rowHeader)) { + this.rowHeaders = rowHeader; + rowHeader = false; + } - JXG.registerElement('sector', JXG.createSector); + this.data = []; - /** - * @class A circumcircle sector is different from a {@link Sector} mostly in the way the parent elements are interpreted. - * At first, the circum centre is determined from the three given points. Then the sector is drawn from <tt>p1</tt> through - * <tt>p2</tt> to <tt>p3</tt>. - * @pseudo - * @name CircumcircleSector - * @augments Sector - * @constructor - * @type Sector - * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p1 A circumcircle sector is defined by the circumcircle which is determined - * by these three given points. The circumcircle sector is always drawn from <tt>p1</tt> through <tt>p2</tt> to <tt>p3</tt>. - * @example - * // Create an arc out of three free points - * var p1 = board.create('point', [1.5, 5.0]), - * p2 = board.create('point', [1.0, 0.5]), - * p3 = board.create('point', [5.0, 3.0]), - * - * a = board.create('circumcirclesector', [p1, p2, p3]); - * </pre><div class="jxgbox" id="JXG695cf0d6-6d7a-4d4d-bfc9-34c6aa28cd04" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function () { - * var board = JXG.JSXGraph.initBoard('JXG695cf0d6-6d7a-4d4d-bfc9-34c6aa28cd04', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}), - * p1 = board.create('point', [1.5, 5.0]), - * p2 = board.create('point', [1.0, 0.5]), - * p3 = board.create('point', [5.0, 3.0]), - * - * a = board.create('circumcirclesector', [p1, p2, p3]); - * })(); - * </script><pre> - */ - JXG.createCircumcircleSector = function (board, parents, attributes) { - var el, mp, attr, points, i; + if (columnHeader) { + this.columnHeaders = []; + } - points = Type.providePoints(board, parents, attributes, 'point'); - if (points === false) { - throw new Error("JSXGraph: Can't create circumcircle sector with parent types '" + - (typeof parents[0]) + "' and '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'."); - } + if (rowHeader) { + this.rowHeaders = []; + } - mp = board.create('circumcenter', points.slice(0, 3), attr); - mp.dump = false; + // to adjust: examples in examples folder & wiki + table = document.getElementById(table); - attr = Type.copyAttributes(attributes, board.options, 'circumcirclesector'); - el = board.create('sector', [mp, points[0], points[2], points[1]], attr); + if (Type.exists(table)) { + // extract the data + row = table.getElementsByTagName('tr'); + this.data = []; - el.elType = 'circumcirclesector'; - el.setParents(points); + for (i = 0; i < row.length; i++) { + col = row[i].getElementsByTagName('td'); + this.data[i] = []; - /** - * Center of the circumcirclesector - * @memberOf CircumcircleSector.prototype - * @name center - * @type Circumcenter - */ - el.center = mp; - el.subs = { - center: mp - }; + for (j = 0; j < col.length; j++) { + cell = col[j].innerHTML; - return el; - }; + if (parseFloat(cell).toString() === cell) { + this.data[i][j] = parseFloat(cell); + } else if (cell !== '-') { + this.data[i][j] = cell; + } else { + this.data[i][j] = NaN; + } + } + } - JXG.registerElement('circumcirclesector', JXG.createCircumcircleSector); + if (columnHeader) { + this.columnHeaders = this.data[0].slice(1); + this.data = this.data.slice(1); + } - /** - * @class A minor sector is a sector of a circle having measure less than or equal to - * 180 degrees (pi radians). It is defined by a center, one point that - * defines the radius, and a third point that defines the angle of the sector. - * @pseudo - * @name MinorSector - * @augments Curve - * @constructor - * @type JXG.Curve - * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 . Minor sector is a sector of a circle around p1 having measure less than or equal to - * 180 degrees (pi radians) and starts at p2. The radius is determined by p2, the angle by p3. - * @example - * // Create sector out of three free points - * var p1 = board.create('point', [2.0, 2.0]); - * var p2 = board.create('point', [1.0, 0.5]); - * var p3 = board.create('point', [3.5, 1.0]); - * - * var a = board.create('minorsector', [p1, p2, p3]); - * </pre><div class="jxgbox" id="JXGaf27ddcc-265f-428f-90dd-d31ace945800" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function () { - * var board = JXG.JSXGraph.initBoard('JXGaf27ddcc-265f-428f-90dd-d31ace945800', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}), - * p1 = board.create('point', [2.0, 2.0]), - * p2 = board.create('point', [1.0, 0.5]), - * p3 = board.create('point', [3.5, 1.0]), - * - * a = board.create('minorsector', [p1, p2, p3]); - * })(); - * </script><pre> - */ - JXG.createMinorSector = function (board, parents, attributes) { - attributes.selection = 'minor'; - return JXG.createSector(board, parents, attributes); - }; + if (rowHeader) { + this.rowHeaders = []; + for (i = 0; i < this.data.length; i++) { + this.rowHeaders.push(this.data[i][0]); + this.data[i] = this.data[i].slice(1); + } + } + } - JXG.registerElement('minorsector', JXG.createMinorSector); + return this; + }, - /** - * @class A major sector is a sector of a circle having measure greater than or equal to - * 180 degrees (pi radians). It is defined by a center, one point that - * defines the radius, and a third point that defines the angle of the sector. - * @pseudo - * @name MajorSector - * @augments Curve - * @constructor - * @type JXG.Curve - * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 . Major sector is a sector of a circle around p1 having measure greater than or equal to - * 180 degrees (pi radians) and starts at p2. The radius is determined by p2, the angle by p3. - * @example - * // Create an arc out of three free points - * var p1 = board.create('point', [2.0, 2.0]); - * var p2 = board.create('point', [1.0, 0.5]); - * var p3 = board.create('point', [3.5, 1.0]); - * - * var a = board.create('majorsector', [p1, p2, p3]); - * </pre><div class="jxgbox" id="JXG83c6561f-7561-4047-b98d-036248a00932" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function () { - * var board = JXG.JSXGraph.initBoard('JXG83c6561f-7561-4047-b98d-036248a00932', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}), - * p1 = board.create('point', [2.0, 2.0]), - * p2 = board.create('point', [1.0, 0.5]), - * p3 = board.create('point', [3.5, 1.0]), - * - * a = board.create('majorsector', [p1, p2, p3]); - * })(); - * </script><pre> - */ - JXG.createMajorSector = function (board, parents, attributes) { - attributes.selection = 'major'; - return JXG.createSector(board, parents, attributes); - }; + addColumn: function (name, pos, data) { + throw new Error('not implemented'); + }, - JXG.registerElement('majorsector', JXG.createMajorSector); + addRow: function (name, pos, data) { + throw new Error('not implemented'); + }, - /** - * @class The angle element is used to denote an angle defined by three points. Visually it is just a {@link Sector} - * element with a radius not defined by the parent elements but by an attribute <tt>radius</tt>. As opposed to the sector, - * an angle has two angle points and no radius point. - * Sector is displayed if type=="sector". - * If type=="square", instead of a sector a parallelogram is displayed. - * In case of type=="auto", a square is displayed if the angle is near orthogonal. - * If no name is provided the angle label is automatically set to a lower greek letter. - * @pseudo - * @name Angle - * @augments Sector - * @constructor - * @type Sector - * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. - * First possiblity of input parameters are: - * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p1 An angle is always drawn counterclockwise from <tt>p1</tt> to - * <tt>p3</tt> around <tt>p2</tt>. - * - * Second possibility of input parameters are: - * @param {JXG.Line_JXG.Line_array|number_array|number} line, line2, coords1 or direction1, coords2 or direction2, radius The angle is defined by two lines. - * The two legs which define the angle are given by two coordinate arrays. - * The points given by these coordinate arrays are projected initially (i.e. only once) onto the two lines. - * The other possibility is to supply directions (+/- 1). - * - * @example - * // Create an angle out of three free points - * var p1 = board.create('point', [5.0, 3.0]), - * p2 = board.create('point', [1.0, 0.5]), - * p3 = board.create('point', [1.5, 5.0]), - * - * a = board.create('angle', [p1, p2, p3]), - * t = board.create('text', [4, 4, function() { return JXG.toFixed(a.Value(), 2); }]); - * </pre><div class="jxgbox" id="JXGa34151f9-bb26-480a-8d6e-9b8cbf789ae5" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function () { - * var board = JXG.JSXGraph.initBoard('JXGa34151f9-bb26-480a-8d6e-9b8cbf789ae5', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}), - * p1 = board.create('point', [5.0, 3.0]), - * p2 = board.create('point', [1.0, 0.5]), - * p3 = board.create('point', [1.5, 5.0]), - * - * a = board.create('angle', [p1, p2, p3]), - * t = board.create('text', [4, 4, function() { return JXG.toFixed(a.Value(), 2); }]); - * })(); - * </script><pre> - * - * @example - * // Create an angle out of two lines and two directions - * var p1 = board.create('point', [-1, 4]), - * p2 = board.create('point', [4, 1]), - * q1 = board.create('point', [-2, -3]), - * q2 = board.create('point', [4,3]), - * - * li1 = board.create('line', [p1,p2], {strokeColor:'black', lastArrow:true}), - * li2 = board.create('line', [q1,q2], {lastArrow:true}), - * - * a1 = board.create('angle', [li1, li2, [5.5, 0], [4, 3]], { radius:1 }), - * a2 = board.create('angle', [li1, li2, 1, -1], { radius:2 }); - * - * - * </pre><div class="jxgbox" id="JXG3a667ddd-63dc-4594-b5f1-afac969b371f" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function () { - * var board = JXG.JSXGraph.initBoard('JXG3a667ddd-63dc-4594-b5f1-afac969b371f', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}), - * p1 = board.create('point', [-1, 4]), - * p2 = board.create('point', [4, 1]), - * q1 = board.create('point', [-2, -3]), - * q2 = board.create('point', [4,3]), - * - * li1 = board.create('line', [p1,p2], {strokeColor:'black', lastArrow:true}), - * li2 = board.create('line', [q1,q2], {lastArrow:true}), - * - * a1 = board.create('angle', [li1, li2, [5.5, 0], [4, 3]], { radius:1 }), - * a2 = board.create('angle', [li1, li2, 1, -1], { radius:2 }); - * })(); - * </script><pre> - * - * - * @example - * // Display the angle value instead of the name - * var p1 = board.create('point', [0,2]); - * var p2 = board.create('point', [0,0]); - * var p3 = board.create('point', [-2,0.2]); - * - * var a = board.create('angle', [p1, p2, p3], { - * radius: 1, - * name: function() { - * return JXG.Math.Geometry.trueAngle(p1, p2, p3).toFixed(1) + '°'; - * }}); - * - * </pre><div id="JXGc813f601-8dd3-4030-9892-25c6d8671512" class="jxgbox" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function() { - * var board = JXG.JSXGraph.initBoard('JXGc813f601-8dd3-4030-9892-25c6d8671512', - * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); - * - * var p1 = board.create('point', [0,2]); - * var p2 = board.create('point', [0,0]); - * var p3 = board.create('point', [-2,0.2]); - * - * var a = board.create('angle', [p1, p2, p3], { - * radius: 1, - * name: function() { - * return JXG.Math.Geometry.trueAngle(p1, p2, p3).toFixed(1) + '°'; - * }}); - * - * })(); - * - * </script><pre> - * - * - * @example - * // Apply a transformation to an angle. - * var t = board.create('transform', [2, 1.5], {type: 'scale'}); - * var an1 = board.create('angle', [[-4,3.9], [-3, 4], [-3, 3]]); - * var an2 = board.create('curve', [an1, t]); - * - * </pre><div id="JXG4c8d9ed8-6339-11e8-9fb9-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function() { - * var board = JXG.JSXGraph.initBoard('JXG4c8d9ed8-6339-11e8-9fb9-901b0e1b8723', - * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); - * var t = board.create('transform', [2, 1.5], {type: 'scale'}); - * var an1 = board.create('angle', [[-4,3.9], [-3, 4], [-3, 3]]); - * var an2 = board.create('curve', [an1, t]); - * - * })(); - * - * </script><pre> - * - */ - JXG.createAngle = function (board, parents, attributes) { - var el, radius, attr, attrsub, - i, points, - type = 'invalid'; + getColumn: function (col) { + var i, + result = []; - // Two lines or three points? - if (parents[0].elementClass === Const.OBJECT_CLASS_LINE && - parents[1].elementClass === Const.OBJECT_CLASS_LINE && - (Type.isArray(parents[2]) || Type.isNumber(parents[2])) && - (Type.isArray(parents[3]) || Type.isNumber(parents[3]))) { + // get column index if column is given as column header title + if (Type.isString(col)) { + for (i = 0; i < this.columnHeaders.length; i++) { + if (col === this.columnHeaders[i]) { + col = i; + break; + } + } + } - type = '2lines'; - } else { - points = Type.providePoints(board, parents, attributes, 'point'); - if (points === false) { - throw new Error("JSXGraph: Can't create angle with parent types '" + - (typeof parents[0]) + "' and '" + (typeof parents[1]) + "' and '" + (typeof parents[2]) + "'."); + // build column array + for (i = 0; i < this.data.length; i++) { + if (this.data[i].length > col) { + result[i] = parseFloat(this.data[i][col]); + } } - type = '3points'; - } - attr = Type.copyAttributes(attributes, board.options, 'angle'); + return result; + }, - // If empty, create a new name - if (!Type.exists(attr.name) || attr.name === '') { - attr.name = board.generateName({type: Const.OBJECT_TYPE_ANGLE}); - } + getRow: function (row) { + var result, i; - if (Type.exists(attr.radius)) { - radius = attr.radius; - } else { - radius = 0; - } + // get column index if column is given as column header title + if (Type.isString(row)) { + for (i = 0; i < this.rowHeaders.length; i++) { + if (row === this.rowHeaders[i]) { + row = i; + break; + } + } + } - if (type === '2lines') { - parents.push(radius); - el = board.create('sector', parents, attr); - el.updateDataArraySector = el.updateDataArray; + // allocate memory for result array + result = []; - // TODO - el.setAngle = function (val) {}; - el.free = function (val) {}; + // build column array. result = this.data[row] is a flat copy and will + // destroy our local data copy, that's why we're copying it element wise. + for (i = 0; i < this.data[row].length; i++) { + result[i] = this.data[row][i]; + } - } else { - el = board.create('sector', [points[1], points[0], points[2]], attr); - el.arc.visProp.priv = true; + return result; + } + }); - /** - * The point defining the radius of the angle element. - * Alias for {@link Sector#radiuspoint}. - * @type JXG.Point - * @name point - * @memberOf Angle.prototype - * - */ - el.point = el.point2 = el.radiuspoint = points[0]; + return JXG.DataSource; +}); - /** - * Helper point for angles of type 'square'. - * @type JXG.Point - * @name pointsquare - * @memberOf Angle.prototype - */ - el.pointsquare = el.point3 = el.anglepoint = points[2]; +/* + Copyright 2008-2022 + Matthias Ehmann, + Michael Gerhaeuser, + Carsten Miller, + Bianca Valentin, + Alfred Wassermann, + Peter Wilfahrt - el.Radius = function () { - return Type.evaluate(radius); - }; + This file is part of JSXGraph. - el.updateDataArraySector = function () { - var A = this.point2, - B = this.point1, - C = this.point3, - r = this.Radius(), - d = B.Dist(A), - ar, - phi, - sgn = 1, - vp_s = Type.evaluate(this.visProp.selection); + JSXGraph is free software dual licensed under the GNU LGPL or MIT License. - phi = Geometry.rad(A, B, C); - if ((vp_s === 'minor' && phi > Math.PI) || - (vp_s === 'major' && phi < Math.PI)) { - sgn = -1; - } + You can redistribute it and/or modify it under the terms of the - A = A.coords.usrCoords; - B = B.coords.usrCoords; - C = C.coords.usrCoords; + * GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version + OR + * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT - A = [1, B[1] + (A[1] - B[1]) * r / d, B[2] + (A[2] - B[2]) * r / d]; - C = [1, B[1] + (C[1] - B[1]) * r / d, B[2] + (C[2] - B[2]) * r / d]; + JSXGraph is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. - ar = Geometry.bezierArc(A, B, C, true, sgn); + You should have received a copy of the GNU Lesser General Public License and + the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> + and <http://opensource.org/licenses/MIT/>. + */ - this.dataX = ar[0]; - this.dataY = ar[1]; - this.bezierDegree = 3; - }; - /** - * Set an angle to a prescribed value given in radians. This is only possible if the third point of the angle, i.e. - * the anglepoint is a free point. - * @name setAngle - * @function - * @param {Number|Function} val Number or Function which returns the size of the angle in Radians - * @returns {Object} Pointer to the angle element.. - * @memberOf Angle.prototype - * - * @example - * var p1, p2, p3, c, a, s; - * - * p1 = board.create('point',[0,0]); - * p2 = board.create('point',[5,0]); - * p3 = board.create('point',[0,5]); - * - * c1 = board.create('circle',[p1, p2]); - * - * a = board.create('angle',[p2, p1, p3], {radius:3}); - * - * a.setAngle(function() { - * return Math.PI / 3; - * }); - * board.update(); - * - * </pre><div id="JXG987c-394f-11e6-af4a-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function() { - * var board = JXG.JSXGraph.initBoard('JXG987c-394f-11e6-af4a-901b0e1b8723', - * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); - * var p1, p2, p3, c, a, s; - * - * p1 = board.create('point',[0,0]); - * p2 = board.create('point',[5,0]); - * p3 = board.create('point',[0,5]); - * - * c1 = board.create('circle',[p1, p2]); - * - * a = board.create('angle',[p2, p1, p3], {radius: 3}); - * - * a.setAngle(function() { - * return Math.PI / 3; - * }); - * board.update(); - * - * })(); - * - * </script><pre> - * - * @example - * var p1, p2, p3, c, a, s; - * - * p1 = board.create('point',[0,0]); - * p2 = board.create('point',[5,0]); - * p3 = board.create('point',[0,5]); - * - * c1 = board.create('circle',[p1, p2]); - * - * a = board.create('angle',[p2, p1, p3], {radius:3}); - * s = board.create('slider',[[-2,1], [2,1], [0, Math.PI*0.5, 2*Math.PI]]); - * - * a.setAngle(function() { - * return s.Value(); - * }); - * board.update(); - * - * </pre><div id="JXG99957b1c-394f-11e6-af4a-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function() { - * var board = JXG.JSXGraph.initBoard('JXG99957b1c-394f-11e6-af4a-901b0e1b8723', - * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); - * var p1, p2, p3, c, a, s; - * - * p1 = board.create('point',[0,0]); - * p2 = board.create('point',[5,0]); - * p3 = board.create('point',[0,5]); - * - * c1 = board.create('circle',[p1, p2]); - * - * a = board.create('angle',[p2, p1, p3], {radius: 3}); - * s = board.create('slider',[[-2,1], [2,1], [0, Math.PI*0.5, 2*Math.PI]]); - * - * a.setAngle(function() { - * return s.Value(); - * }); - * board.update(); - * - * })(); - * - * </script><pre> - * - */ - el.setAngle = function (val) { - var t, - p = this.anglepoint, - q = this.radiuspoint; +/*global JXG: true, define: true, document: true*/ +/*jslint nomen: true, plusplus: true*/ - if (p.draggable()) { - t = this.board.create('transform', [val, this.center], {type: 'rotate'}); - p.addTransform(q, t); - p.isDraggable = false; - p.setParents(q); - } - return this; - }; +/* depends: + jxg + math/numerics + math/statistics + base/constants + base/coords + base/element + parser/datasource + utils/color + utils/type + utils/env + elements: + curve + spline + functiongraph + point + text + polygon + sector + transform + line + legend + circle + */ - /** - * Frees an angle from a prescribed value. This is only relevant if the angle size has been set by - * setAngle() previously. The anglepoint is set to a free point. - * @name free - * @function - * @returns {Object} Pointer to the angle element.. - * @memberOf Angle.prototype - */ - el.free = function () { - var p = this.anglepoint; - if (p.transformations.length > 0) { - p.transformations.pop(); - p.isDraggable = true; - p.parents = []; - } - return this; - }; +define('base/chart',[ + 'jxg', 'math/numerics', 'math/statistics', 'base/constants', 'base/coords', 'base/element', 'parser/datasource', + 'utils/color', 'utils/type', 'utils/env', 'base/curve', 'base/point', 'base/text', 'base/polygon', 'element/sector', + 'base/transformation', 'base/line', 'base/circle' +], function (JXG, Numerics, Statistics, Const, Coords, GeometryElement, DataSource, Color, Type, Env, Curve, Point, Text, + Polygon, Sector, Transform, Line, Circle) { - el.setParents(points); // Important: This overwrites the parents order in underlying sector + "use strict"; - } // end '3points' + /** + * + * The Chart class is a basic class for the chart object. + * @class Creates a new basic chart object. Do not use this constructor to create a chart. + * Use {@link JXG.Board#create} with type {@link Chart} instead. + * @constructor + * @augments JXG.GeometryElement + * @param {String,JXG.Board} board The board the new chart is drawn on. + * @param {Array} parent data arrays for the chart + * @param {Object} attributes Javascript object containing attributes like name, id and colors. + * + */ + JXG.Chart = function (board, parents, attributes) { + this.constructor(board, attributes); - // GEONExT compatible labels. - if (Type.exists(el.visProp.text)) { - el.label.setText(Type.evaluate(el.visProp.text)); - } + var x, y, i, c, style, len; - el.elType = 'angle'; - el.type = Const.OBJECT_TYPE_ANGLE; - el.subs = {}; + if (!Type.isArray(parents) || parents.length === 0) { + throw new Error('JSXGraph: Can\'t create a chart without data'); + } - el.updateDataArraySquare = function () { - var A, B, C, - r = this.Radius(), - d1, d2, - v, l1, l2; + /** + * Contains pointers to the various subelements of the chart. + */ + this.elements = []; + if (Type.isNumber(parents[0])) { + // parents looks like [a,b,c,..] + // x has to be filled - if (type === '2lines') { - // This is necessary to update this.point1, this.point2, this.point3. - this.updateDataArraySector(); + y = parents; + x = []; + for (i = 0; i < y.length; i++) { + x[i] = i + 1; } + } else if (parents.length === 1 && Type.isArray(parents[0])) { + // parents looks like [[a,b,c,..]] + // x has to be filled - A = this.point2; - B = this.point1; - C = this.point3; + y = parents[0]; + x = []; - A = A.coords.usrCoords; - B = B.coords.usrCoords; - C = C.coords.usrCoords; + len = Type.evaluate(y).length; + for (i = 0; i < len; i++) { + x[i] = i + 1; + } + } else if (parents.length === 2) { + // parents looks like [[x0,x1,x2,...],[y1,y2,y3,...]] + len = Math.min(parents[0].length, parents[1].length); + x = parents[0].slice(0, len); + y = parents[1].slice(0, len); + } - d1 = Geometry.distance(A, B, 3); - d2 = Geometry.distance(C, B, 3); + if (Type.isArray(y) && y.length === 0) { + throw new Error('JSXGraph: Can\'t create charts without data.'); + } - // In case of type=='2lines' this is redundant, because r == d1 == d2 - A = [1, B[1] + (A[1] - B[1]) * r / d1, B[2] + (A[2] - B[2]) * r / d1]; - C = [1, B[1] + (C[1] - B[1]) * r / d2, B[2] + (C[2] - B[2]) * r / d2]; + // does this really need to be done here? this should be done in createChart and then + // there should be an extra chart for each chartstyle + style = attributes.chartstyle.replace(/ /g, '').split(','); + for (i = 0; i < style.length; i++) { + switch (style[i]) { + case 'bar': + c = this.drawBar(board, x, y, attributes); + break; + case 'line': + c = this.drawLine(board, x, y, attributes); + break; + case 'fit': + c = this.drawFit(board, x, y, attributes); + break; + case 'spline': + c = this.drawSpline(board, x, y, attributes); + break; + case 'pie': + c = this.drawPie(board, y, attributes); + break; + case 'point': + c = this.drawPoints(board, x, y, attributes); + break; + case 'radar': + c = this.drawRadar(board, parents, attributes); + break; + } + this.elements.push(c); + } + this.id = this.board.setId(this, 'Chart'); - v = Mat.crossProduct(C, B); - l1 = [-A[1] * v[1] - A[2] * v[2], A[0] * v[1], A[0] * v[2]]; - v = Mat.crossProduct(A, B); - l2 = [-C[1] * v[1] - C[2] * v[2], C[0] * v[1], C[0] * v[2]]; + return this.elements; + }; - v = Mat.crossProduct(l1, l2); - v[1] /= v[0]; - v[2] /= v[0]; + JXG.Chart.prototype = new GeometryElement(); - this.dataX = [B[1], A[1], v[1], C[1], B[1]]; - this.dataY = [B[2], A[2], v[2], C[2], B[2]]; + JXG.extend(JXG.Chart.prototype, /** @lends JXG.Chart.prototype */ { + /** + * Create line chart defined by two data arrays. + * + * @param {String,JXG.Board} board The board the chart is drawn on + * @param {Array} x Array of x-coordinates + * @param {Array} y Array of y-coordinates + * @param {Object} attributes Javascript object containing attributes like colors + * @returns {JXG.Curve} JSXGraph curve + */ + drawLine: function (board, x, y, attributes) { + // we don't want the line chart to be filled + attributes.fillcolor = 'none'; + attributes.highlightfillcolor = 'none'; - this.bezierDegree = 1; - }; + return board.create('curve', [x, y], attributes); + }, - el.updateDataArrayNone = function () { - this.dataX = [NaN]; - this.dataY = [NaN]; - this.bezierDegree = 1; - }; + /** + * Create line chart that consists of a natural spline curve + * defined by two data arrays. + * + * @param {String,JXG.Board} board The board the chart is drawn on + * @param {Array} x Array of x-coordinates + * @param {Array} y Array of y-coordinates + * @param {Object} attributes Javascript object containing attributes like colors + * @returns {JXG.Curve} JSXGraph (natural) spline curve + */ + drawSpline: function (board, x, y, attributes) { + // we don't want the spline chart to be filled + attributes.fillColor = 'none'; + attributes.highlightfillcolor = 'none'; - el.updateDataArray = function () { - var type = Type.evaluate(this.visProp.type), - deg = Geometry.trueAngle(this.point2, this.point1, this.point3), - vp_s = Type.evaluate(this.visProp.selection); + return board.create('spline', [x, y], attributes); + }, - if ((vp_s === 'minor' && deg > 180.0) || - (vp_s === 'major' && deg < 180.0)) { - deg = 360.0 - deg; - } + /** + * Create line chart where the curve is given by a regression polynomial + * defined by two data arrays. The degree of the polynomial is supplied + * through the attribute "degree" in attributes. + * + * @param {String,JXG.Board} board The board the chart is drawn on + * @param {Array} x Array of x-coordinates + * @param {Array} y Array of y-coordinates + * @param {Object} attributes Javascript object containing attributes like colors + * @returns {JXG.Curve} JSXGraph function graph object + */ + drawFit: function (board, x, y, attributes) { + var deg = attributes.degree; - if (Math.abs(deg - 90.0) < Type.evaluate(this.visProp.orthosensitivity) + Mat.eps) { - type = Type.evaluate(this.visProp.orthotype); - } + deg = Math.max(parseInt(deg, 10), 1) || 1; - if (type === 'none') { - this.updateDataArrayNone(); - } else if (type === 'square') { - this.updateDataArraySquare(); - } else if (type === 'sector') { - this.updateDataArraySector(); - } else if (type === 'sectordot') { - this.updateDataArraySector(); - if (!this.dot.visProp.visible) { - this.dot.setAttribute({visible: true}); - } - } + // never fill + attributes.fillcolor = 'none'; + attributes.highlightfillcolor = 'none'; - if (!this.visProp.visible || (type !== 'sectordot' && this.dot.visProp.visible)) { - this.dot.setAttribute({visible: false}); - } - }; + return board.create('functiongraph', [Numerics.regressionPolynomial(deg, x, y)], attributes); + }, /** - * Indicates a right angle. Invisible by default, use <tt>dot.visible: true</tt> to show. - * Though this dot indicates a right angle, it can be visible even if the angle is not a right - * one. - * @type JXG.Point - * @name dot - * @memberOf Angle.prototype + * Create bar chart defined by two data arrays. + * Attributes to change the layout of the bar chart are: + * <ul> + * <li> width (optional) + * <li> dir: 'horizontal' or 'vertical' + * <li> colors: array of colors + * <li> labels: array of labels + * </ul> + * + * @param {String,JXG.Board} board The board the chart is drawn on + * @param {Array} x Array of x-coordinates + * @param {Array} y Array of y-coordinates + * @param {Object} attributes Javascript object containing attributes like colors + * @returns {Array} Array of JXG polygons defining the bars */ - attrsub = Type.copyAttributes(attributes, board.options, 'angle', 'dot'); - el.dot = board.create('point', [function () { - var A, B, r, d, a2, co, si, mat, - vp_s; + drawBar: function (board, x, y, attributes) { + var i, strwidth, text, w, xp0, xp1, xp2, yp, colors, + pols = [], + p = [], + attr, attrSub, + makeXpFun = function (i, f) { + return function () { + return x[i]() - f * w; + }; + }, + hiddenPoint = { + fixed: true, + withLabel: false, + visible: false, + name: '' + }; - if (Type.exists(el.dot) && !el.dot.visProp.visible) { - return [0, 0]; + attr = Type.copyAttributes(attributes, board.options, 'chart'); + + // Determine the width of the bars + if (attr && attr.width) { // width given + w = attr.width; + } else { + if (x.length <= 1) { + w = 1; + } else { + // Find minimum distance between to bars. + w = x[1] - x[0]; + for (i = 1; i < x.length - 1; i++) { + w = (x[i + 1] - x[i] < w) ? x[i + 1] - x[i] : w; + } + } + w *= 0.8; } - A = el.point2.coords.usrCoords; - B = el.point1.coords.usrCoords; - r = el.Radius(); - d = Geometry.distance(A, B, 3); - a2 = Geometry.rad(el.point2, el.point1, el.point3); + attrSub = Type.copyAttributes(attributes, board.options, 'chart', 'label'); + + for (i = 0; i < x.length; i++) { + if (Type.isFunction(x[i])) { + xp0 = makeXpFun(i, -0.5); + xp1 = makeXpFun(i, 0); + xp2 = makeXpFun(i, 0.5); + } else { + xp0 = x[i] - w * 0.5; + xp1 = x[i]; + xp2 = x[i] + w * 0.5; + } + if (Type.isFunction(y[i])) { + yp = y[i](); + } else { + yp = y[i]; + } + yp = y[i]; + + if (attr.dir === 'horizontal') { // horizontal bars + p[0] = board.create('point', [0, xp0], hiddenPoint); + p[1] = board.create('point', [yp, xp0], hiddenPoint); + p[2] = board.create('point', [yp, xp2], hiddenPoint); + p[3] = board.create('point', [0, xp2], hiddenPoint); + + if (Type.exists(attr.labels) && Type.exists(attr.labels[i])) { + attrSub.anchorY = 'middle'; + text = board.create('text', [ + yp, + xp1, + attr.labels[i]], attrSub); + text.visProp.anchorx = (function(txt) { return function() { + return (txt.X() >= 0) ? 'left' : 'right'; + }; })(text); + + } + } else { // vertical bars + p[0] = board.create('point', [xp0, 0], hiddenPoint); + p[1] = board.create('point', [xp0, yp], hiddenPoint); + p[2] = board.create('point', [xp2, yp], hiddenPoint); + p[3] = board.create('point', [xp2, 0], hiddenPoint); + + if (Type.exists(attr.labels) && Type.exists(attr.labels[i])) { + attrSub.anchorX = 'middle'; + + text = board.create('text', [ + xp1, + yp, + attr.labels[i]], attrSub); + + text.visProp.anchory = (function(txt) { + return function() { + return (txt.Y() >= 0) ? 'bottom' : 'top'; + }; + })(text); - vp_s = Type.evaluate(el.visProp.selection); - if ((vp_s === 'minor' && a2 > Math.PI) || - (vp_s === 'major' && a2 < Math.PI)) { - a2 = -(2 * Math.PI - a2); - } - a2 *= 0.5; + } + } - co = Math.cos(a2); - si = Math.sin(a2); + if (Type.isArray(attr.colors)) { + colors = attr.colors; + attr.fillcolor = colors[i % colors.length]; + } - A = [1, B[1] + (A[1] - B[1]) * r / d, B[2] + (A[2] - B[2]) * r / d]; + pols[i] = board.create('polygon', p, attr); + if (Type.exists(attr.labels) && Type.exists(attr.labels[i])) { + pols[i].text = text; + } + } - mat = [ - [1, 0, 0], - [B[1] - 0.5 * B[1] * co + 0.5 * B[2] * si, co * 0.5, -si * 0.5], - [B[2] - 0.5 * B[1] * si - 0.5 * B[2] * co, si * 0.5, co * 0.5] - ]; - return Mat.matVecMult(mat, A); - }], attrsub); + return pols; + }, - el.dot.dump = false; - el.subs.dot = el.dot; + /** + * Create chart consisting of JSXGraph points. + * Attributes to change the layout of the point chart are: + * <ul> + * <li> fixed (Boolean) + * <li> infoboxArray (Array): Texts for the infobox + * </ul> + * + * @param {String,JXG.Board} board The board the chart is drawn on + * @param {Array} x Array of x-coordinates + * @param {Array} y Array of y-coordinates + * @param {Object} attributes Javascript object containing attributes like colors + * @returns {Array} Array of JSXGraph points + */ + drawPoints: function (board, x, y, attributes) { + var i, + points = [], + infoboxArray = attributes.infoboxarray; - if (type === '2lines') { - for (i = 0; i < 2; i++) { - board.select(parents[i]).addChild(el.dot); - } - } else { - for (i = 0; i < 3; i++) { - board.select(points[i]).addChild(el.dot); + attributes.fixed = true; + attributes.name = ''; + + for (i = 0; i < x.length; i++) { + attributes.infoboxtext = infoboxArray ? infoboxArray[i % infoboxArray.length] : false; + points[i] = board.create('point', [x[i], y[i]], attributes); } - } - // documented in GeometryElement - el.getLabelAnchor = function () { - var vec, dx = 12, - A, B, r, d, a2, co, si, mat, - vp_s = Type.evaluate(el.visProp.selection), - l_vp = this.label ? this.label.visProp : this.visProp.label; + return points; + }, - // If this is uncommented, the angle label can not be dragged - //if (Type.exists(this.label)) { - // this.label.relativeCoords = new Coords(Const.COORDS_BY_SCREEN, [0, 0], this.board); - //} + /** + * Create pie chart. + * Attributes to change the layout of the pie chart are: + * <ul> + * <li> labels: array of labels + * <li> colors: (Array) + * <li> highlightColors (Array) + * <li> radius + * <li> center (coordinate array) + * <li> highlightOnSector (Boolean) + * </ul> + * + * @param {String,JXG.Board} board The board the chart is drawn on + * @param {Array} y Array of x-coordinates + * @param {Object} attributes Javascript object containing attributes like colors + * @returns {Object} with keys: "{sectors, points, midpoint}" + */ + drawPie: function (board, y, attributes) { + var i, center, + p = [], + sector = [], + s = Statistics.sum(y), + colorArray = attributes.colors, + highlightColorArray = attributes.highlightcolors, + labelArray = attributes.labels, + r = attributes.radius || 4, + radius = r, + cent = attributes.center || [0, 0], + xc = cent[0], + yc = cent[1], - if (Type.exists(this.label.visProp.fontSize)) { - dx = Type.evaluate(this.label.visProp.fontSize); - } - dx /= this.board.unitX; + makeRadPointFun = function (j, fun, xc) { + return function () { + var s, i, rad, + t = 0; - A = el.point2.coords.usrCoords; - B = el.point1.coords.usrCoords; - r = el.Radius(); - d = Geometry.distance(A, B, 3); - a2 = Geometry.rad(el.point2, el.point1, el.point3); - if ((vp_s === 'minor' && a2 > Math.PI) || - (vp_s === 'major' && a2 < Math.PI)) { - a2 = -(2 * Math.PI - a2); - } - a2 *= 0.5; - co = Math.cos(a2); - si = Math.sin(a2); + for (i = 0; i <= j; i++) { + t += parseFloat(Type.evaluate(y[i])); + } - A = [1, B[1] + (A[1] - B[1]) * r / d, B[2] + (A[2] - B[2]) * r / d]; + s = t; + for (i = j + 1; i < y.length; i++) { + s += parseFloat(Type.evaluate(y[i])); + } + rad = (s !== 0) ? (2 * Math.PI * t / s) : 0; - mat = [ - [1, 0, 0], - [B[1] - 0.5 * B[1] * co + 0.5 * B[2] * si, co * 0.5, -si * 0.5], - [B[2] - 0.5 * B[1] * si - 0.5 * B[2] * co, si * 0.5, co * 0.5] - ]; - vec = Mat.matVecMult(mat, A); - vec[1] /= vec[0]; - vec[2] /= vec[0]; - vec[0] /= vec[0]; + return radius() * Math[fun](rad) + xc; + }; + }, - d = Geometry.distance(vec, B, 3); - vec = [vec[0], B[1] + (vec[1] - B[1]) * (r + dx) / d, B[2] + (vec[2] - B[2]) * (r + dx) / d]; + highlightHandleLabel = function (f, s) { + var dx = -this.point1.coords.usrCoords[1] + this.point2.coords.usrCoords[1], + dy = -this.point1.coords.usrCoords[2] + this.point2.coords.usrCoords[2]; - l_vp.position = Geometry.calcLabelQuadrant(Geometry.rad([1,0],[0,0],vec)); + if (Type.exists(this.label)) { + this.label.rendNode.style.fontSize = (s * Type.evaluate(this.label.visProp.fontsize)) + 'px'; + this.label.fullUpdate(); + } - return new Coords(Const.COORDS_BY_USER, vec, this.board); - }; + this.point2.coords = new Coords(Const.COORDS_BY_USER, [ + this.point1.coords.usrCoords[1] + dx * f, + this.point1.coords.usrCoords[2] + dy * f + ], this.board); + this.fullUpdate(); + }, - /** - * Returns the value of the angle in Radians. - * @memberOf Angle.prototype - * @name Value - * @function - * @returns {Number} The angle value in Radians - */ - el.Value = function () { - return Geometry.rad(this.point2, this.point1, this.point3); - }; + highlightFun = function () { + if (!this.highlighted) { + this.highlighted = true; + this.board.highlightedObjects[this.id] = this; + this.board.renderer.highlight(this); - el.methodMap = Type.deepCopy(el.methodMap, { - Value: 'Value', - setAngle: 'setAngle', - free: 'free' - }); + highlightHandleLabel.call(this, 1.1, 2); + } + }, - return el; - }; + noHighlightFun = function () { + if (this.highlighted) { + this.highlighted = false; + this.board.renderer.noHighlight(this); - JXG.registerElement('angle', JXG.createAngle); + highlightHandleLabel.call(this, 0.90909090, 1); + } + }, - /** - * @class A non-reflex angle is the acute or obtuse instance of an angle. - * It is defined by a center, one point that - * defines the radius, and a third point that defines the angle of the sector. - * @pseudo - * @name NonReflexAngle - * @augments Angle - * @constructor - * @type Sector - * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 . Minor sector is a sector of a circle around p1 having measure less than or equal to - * 180 degrees (pi radians) and starts at p2. The radius is determined by p2, the angle by p3. - * @example - * // Create a non-reflex angle out of three free points - * var p1 = board.create('point', [5.0, 3.0]), - * p2 = board.create('point', [1.0, 0.5]), - * p3 = board.create('point', [1.5, 5.0]), - * - * a = board.create('nonreflexangle', [p1, p2, p3], {radius: 2}), - * t = board.create('text', [4, 4, function() { return JXG.toFixed(a.Value(), 2); }]); - * </pre><div class="jxgbox" id="JXGd0ab6d6b-63a7-48b2-8749-b02bb5e744f9" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function () { - * var board = JXG.JSXGraph.initBoard('JXGd0ab6d6b-63a7-48b2-8749-b02bb5e744f9', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}), - * p1 = board.create('point', [5.0, 3.0]), - * p2 = board.create('point', [1.0, 0.5]), - * p3 = board.create('point', [1.5, 5.0]), - * - * a = board.create('nonreflexangle', [p1, p2, p3], {radius: 2}), - * t = board.create('text', [4, 4, function() { return JXG.toFixed(a.Value(), 2); }]); - * })(); - * </script><pre> - */ - JXG.createNonreflexAngle = function (board, parents, attributes) { - var el; + hiddenPoint = { + fixed: true, + withLabel: false, + visible: false, + name: '' + }; - attributes.selection = 'minor'; - el = JXG.createAngle(board, parents, attributes); + if (!Type.isArray(labelArray)) { + labelArray = []; + for (i = 0; i < y.length; i++) { + labelArray[i] = ''; + } + } - // Documented in createAngle - el.Value = function () { - var v = Geometry.rad(this.point2, this.point1, this.point3); - return (v < Math.PI) ? v : 2.0 * Math.PI - v; - }; - return el; - }; + if (!Type.isFunction(r)) { + radius = function () { + return r; + }; + } - JXG.registerElement('nonreflexangle', JXG.createNonreflexAngle); + attributes.highlightonsector = attributes.highlightonsector || false; + attributes.straightfirst = false; + attributes.straightlast = false; - /** - * @class A reflex angle is the neither acute nor obtuse instance of an angle. - * It is defined by a center, one point that - * defines the radius, and a third point that defines the angle of the sector. - * @pseudo - * @name ReflexAngle - * @augments Angle - * @constructor - * @type Sector - * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {JXG.Point_JXG.Point_JXG.Point} p1,p2,p3 . Minor sector is a sector of a circle around p1 having measure less than or equal to - * 180 degrees (pi radians) and starts at p2. The radius is determined by p2, the angle by p3. - * @example - * // Create a non-reflex angle out of three free points - * var p1 = board.create('point', [5.0, 3.0]), - * p2 = board.create('point', [1.0, 0.5]), - * p3 = board.create('point', [1.5, 5.0]), - * - * a = board.create('reflexangle', [p1, p2, p3], {radius: 2}), - * t = board.create('text', [4, 4, function() { return JXG.toFixed(a.Value(), 2); }]); - * </pre><div class="jxgbox" id="JXGf2a577f2-553d-4f9f-a895-2d6d4b8c60e8" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function () { - * var board = JXG.JSXGraph.initBoard('JXGf2a577f2-553d-4f9f-a895-2d6d4b8c60e8', {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false}), - * p1 = board.create('point', [5.0, 3.0]), - * p2 = board.create('point', [1.0, 0.5]), - * p3 = board.create('point', [1.5, 5.0]), - * - * a = board.create('reflexangle', [p1, p2, p3], {radius: 2}), - * t = board.create('text', [4, 4, function() { return JXG.toFixed(a.Value(), 2); }]); - * })(); - * </script><pre> - */ - JXG.createReflexAngle = function (board, parents, attributes) { - var el; + center = board.create('point', [xc, yc], hiddenPoint); + p[0] = board.create('point', [ + function () { + return radius() + xc; + }, + function () { + return yc; + } + ], hiddenPoint); - attributes.selection = 'major'; - el = JXG.createAngle(board, parents, attributes); + for (i = 0; i < y.length; i++) { + p[i + 1] = board.create('point', [makeRadPointFun(i, 'cos', xc), makeRadPointFun(i, 'sin', yc)], hiddenPoint); - // Documented in createAngle - el.Value = function () { - var v = Geometry.rad(this.point2, this.point1, this.point3); - return (v >= Math.PI) ? v : 2.0 * Math.PI - v; - }; - return el; - }; + attributes.name = labelArray[i]; + attributes.withlabel = attributes.name !== ''; + attributes.fillcolor = colorArray && colorArray[i % colorArray.length]; + attributes.labelcolor = colorArray && colorArray[i % colorArray.length]; + attributes.highlightfillcolor = highlightColorArray && highlightColorArray[i % highlightColorArray.length]; - JXG.registerElement('reflexangle', JXG.createReflexAngle); + sector[i] = board.create('sector', [center, p[i], p[i + 1]], attributes); - return { - createSector: JXG.createSector, - createCircumcircleSector: JXG.createCircumcircleSector, - createMinorSector: JXG.createMinorSector, - createMajorSector: JXG.createMajorSector, - createAngle: JXG.createAngle, - createReflexAngle: JXG.createReflexAngle, - createNonreflexAngle: JXG.createNonreflexAngle - }; -}); + if (attributes.highlightonsector) { + // overwrite hasPoint so that the whole sector is used for highlighting + sector[i].hasPoint = sector[i].hasPointSector; + } + if (attributes.highlightbysize) { + sector[i].highlight = highlightFun; -/* - Copyright 2008-2021 - Matthias Ehmann, - Michael Gerhaeuser, - Carsten Miller, - Bianca Valentin, - Alfred Wassermann, - Peter Wilfahrt + sector[i].noHighlight = noHighlightFun; + } - This file is part of JSXGraph. + } - JSXGraph is free software dual licensed under the GNU LGPL or MIT License. + // Not enough! We need points, but this gives an error in setAttribute. + return {sectors: sector, points: p, midpoint: center}; + }, - You can redistribute it and/or modify it under the terms of the + /** + * Create radar chart. + * Attributes to change the layout of the pie chart are: + * <ul> + * <li> paramArray: labels for axes, [ paramx, paramy, paramz ] + * <li> startShiftRatio: 0 <= offset from chart center <=1 + * <li> endShiftRatio: 0 <= offset from chart radius <=1 + * <li> startShiftArray: Adjust offsets per each axis + * <li> endShiftArray: Adjust offsets per each axis + * <li> startArray: Values for inner circle. Default values: minimums + * <li> start: one value to overwrite all startArray values + * <li> endArray: Values for outer circle, maximums by default + * <li> end: one value to overwrite all endArray values + * <li> labelArray + * <li> polyStrokeWidth + * <li> colors + * <li> highlightcolors + * <li> labelArray: [ row1, row2, row3 ] + * <li> radius + * <li> legendPosition + * <li> showCircles + * <li> circleLabelArray + * <li> circleStrokeWidth + * </ul> + * + * @param {String,JXG.Board} board The board the chart is drawn on + * @param {Array} parents Array of coordinates, e.g. [[x1, y1, z1], [x2, y2, z2], [x3, y3, z3]] + * @param {Object} attributes Javascript object containing attributes like colors + * @returns {Object} with keys "{circles, lines, points, midpoint, polygons}" + */ + drawRadar: function (board, parents, attributes) { + var i, j, paramArray, numofparams, maxes, mins, + la, pdata, ssa, esa, ssratio, esratio, + sshifts, eshifts, starts, ends, + labelArray, colorArray, highlightColorArray, radius, myAtts, + cent, xc, yc, center, start_angle, rad, p, line, t, + xcoord, ycoord, polygons, legend_position, circles, lxoff, lyoff, + cla, clabelArray, ncircles, pcircles, angle, dr, sw, data, + len = parents.length, - * GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version - OR - * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT + get_anchor = function () { + var x1, x2, y1, y2, + relCoords = Type.evaluate(this.visProp.label.offset).slice(0); - JSXGraph is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. + x1 = this.point1.X(); + x2 = this.point2.X(); + y1 = this.point1.Y(); + y2 = this.point2.Y(); + if (x2 < x1) { + relCoords[0] = -relCoords[0]; + } - You should have received a copy of the GNU Lesser General Public License and - the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> - and <http://opensource.org/licenses/MIT/>. - */ + if (y2 < y1) { + relCoords[1] = -relCoords[1]; + } + this.setLabelRelativeCoords(relCoords); -/*global JXG: true, define: true*/ -/*jslint nomen: true, plusplus: true*/ + return new Coords(Const.COORDS_BY_USER, [this.point2.X(), this.point2.Y()], this.board); + }, -/* depends: - jxg - math/math - math/geometry - math/numerics - math/statistics - math/symbolic - base/composition - base/coords - base/constants - utils/type - elements: - line - circle - transform - point - glider - text - curve - */ + get_transform = function (angle, i) { + var t, tscale, trot; -define('element/locus',[ - 'jxg', 'math/symbolic', 'utils/type' -], function (JXG, Symbolic, Type) { + t = board.create('transform', [-(starts[i] - sshifts[i]), 0], {type: 'translate'}); + tscale = board.create('transform', [radius / ((ends[i] + eshifts[i]) - (starts[i] - sshifts[i])), 1], {type: 'scale'}); + t.melt(tscale); + trot = board.create('transform', [angle], {type: 'rotate'}); + t.melt(trot); - "use strict"; + return t; + }; - /** - * @class This element is used to visualize the locus of a given dependent point. - * @pseudo - * @description The locus element is used to visualize the curve a given point describes. - * @constructor - * @name Locus - * @type JXG.Curve - * @augments JXG.Curve - * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {JXG.Point} p The constructed curve is the geometric locus of the given point. - * @example - * // This examples needs JXG.Server up and running, otherwise it won't work. - * p1 = board.create('point', [0, 0]); - * p2 = board.create('point', [6, -1]); - * c1 = board.create('circle', [p1, 2]); - * c2 = board.create('circle', [p2, 1.5]); - * g1 = board.create('glider', [6, 3, c1]); - * c3 = board.create('circle', [g1, 4]); - * g2 = board.create('intersection', [c2,c3,0]); - * m1 = board.create('midpoint', [g1,g2]); - * loc = board.create('locus', [m1], {strokeColor: 'red'}); - * </pre><div class="jxgbox" id="JXGd45d7188-6624-4d6e-bebb-1efa2a305c8a" style="width: 400px; height: 400px;"></div> - * <script type="text/javascript"> - * lcex_board = JXG.JSXGraph.initBoard('JXGd45d7188-6624-4d6e-bebb-1efa2a305c8a', {boundingbox:[-4, 6, 10, -6], axis: true, grid: false, keepaspectratio: true}); - * lcex_p1 = lcex_board.create('point', [0, 0]); - * lcex_p2 = lcex_board.create('point', [6, -1]); - * lcex_c1 = lcex_board.create('circle', [lcex_p1, 2]); - * lcex_c2 = lcex_board.create('circle', [lcex_p2, 1.5]); - * lcex_g1 = lcex_board.create('glider', [6, 3, lcex_c1]); - * lcex_c3 = lcex_board.create('circle', [lcex_g1, 4]); - * lcex_g2 = lcex_board.create('intersection', [lcex_c2,lcex_c3,0]); - * lcex_m1 = lcex_board.create('midpoint', [lcex_g1,lcex_g2]); - * lcex_loc = board.create('locus', [lcex_m1], {strokeColor: 'red'}); - * </script><pre> - */ - JXG.createLocus = function (board, parents, attributes) { - var c, p; + if (len <= 0) { + throw new Error('JSXGraph radar chart: no data'); + } + // labels for axes + paramArray = attributes.paramarray; + if (!Type.exists(paramArray)) { + throw new Error('JSXGraph radar chart: need paramArray attribute'); + } + numofparams = paramArray.length; + if (numofparams <= 1) { + throw new Error('JSXGraph radar chart: need more than one param in paramArray'); + } + + for (i = 0; i < len; i++) { + if (numofparams !== parents[i].length) { + throw new Error('JSXGraph radar chart: use data length equal to number of params (' + parents[i].length + ' != ' + numofparams + ')'); + } + } - if (Type.isArray(parents) && parents.length === 1 && Type.isPoint(parents[0])) { - p = parents[0]; - } else { - throw new Error("JSXGraph: Can't create locus with parent of type other than point." + - "\nPossible parent types: [point]"); - } + maxes = []; + mins = []; - c = board.create('curve', [[null], [null]], attributes); - c.dontCallServer = false; + for (j = 0; j < numofparams; j++) { + maxes[j] = parents[0][j]; + mins[j] = maxes[j]; + } - c.elType = 'locus'; - c.setParents([p.id]); + for (i = 1; i < len; i++) { + for (j = 0; j < numofparams; j++) { + if (parents[i][j] > maxes[j]) { + maxes[j] = parents[i][j]; + } - /** - * should be documented in JXG.Curve - * @ignore - */ - c.updateDataArray = function () { - var spe, cb, data; + if (parents[i][j] < mins[j]) { + mins[j] = parents[i][j]; + } + } + } - if (c.board.mode > 0) { - return; + la = []; + pdata = []; + + for (i = 0; i < len; i++) { + la[i] = ''; + pdata[i] = []; } - spe = Symbolic.generatePolynomials(board, p, true).join('|'); - if (spe === c.spe) { - return; + ssa = []; + esa = []; + + // 0 <= Offset from chart center <=1 + ssratio = attributes.startshiftratio || 0; + // 0 <= Offset from chart radius <=1 + esratio = attributes.endshiftratio || 0; + + for (i = 0; i < numofparams; i++) { + ssa[i] = (maxes[i] - mins[i]) * ssratio; + esa[i] = (maxes[i] - mins[i]) * esratio; } - c.spe = spe; + // Adjust offsets per each axis + sshifts = attributes.startshiftarray || ssa; + eshifts = attributes.endshiftarray || esa; + // Values for inner circle, minimums by default + starts = attributes.startarray || mins; - cb = function (x, y, eq, t) { - c.dataX = x; - c.dataY = y; + if (Type.exists(attributes.start)) { + for (i = 0; i < numofparams; i++) { + starts[i] = attributes.start; + } + } - /** - * The implicit definition of the locus. - * @memberOf Locus.prototype - * @name eq - * @type String - */ - c.eq = eq; + // Values for outer circle, maximums by default + ends = attributes.endarray || maxes; + if (Type.exists(attributes.end)) { + for (i = 0; i < numofparams; i++) { + ends[i] = attributes.end; + } + } - /** - * The time it took to calculate the locus - * @memberOf Locus.prototype - * @name ctime - * @type Number - */ - c.ctime = t; + if (sshifts.length !== numofparams) { + throw new Error('JSXGraph radar chart: start shifts length is not equal to number of parameters'); + } - // convert equation and use it to build a generatePolynomial-method - c.generatePolynomial = (function (equations) { - return function (point) { - var i, - x = '(' + point.symbolic.x + ')', - y = '(' + point.symbolic.y + ')', - res = []; + if (eshifts.length !== numofparams) { + throw new Error('JSXGraph radar chart: end shifts length is not equal to number of parameters'); + } - for (i = 0; i < equations.length; i++) { - res[i] = equations[i].replace(/\*\*/g, '^').replace(/x/g, x).replace(/y/g, y); - } + if (starts.length !== numofparams) { + throw new Error('JSXGraph radar chart: starts length is not equal to number of parameters'); + } - return res; - }; - }(eq)); + if (ends.length !== numofparams) { + throw new Error('JSXGraph radar chart: snds length is not equal to number of parameters'); + } + + // labels for legend + labelArray = attributes.labelarray || la; + colorArray = attributes.colors; + highlightColorArray = attributes.highlightcolors; + radius = attributes.radius || 10; + sw = attributes.strokewidth || 1; + + if (!Type.exists(attributes.highlightonsector)) { + attributes.highlightonsector = false; + } + + myAtts = { + name: attributes.name, + id: attributes.id, + strokewidth: sw, + polystrokewidth: attributes.polystrokewidth || sw, + strokecolor: attributes.strokecolor || 'black', + straightfirst: false, + straightlast: false, + fillcolor: attributes.fillColor || '#FFFF88', + fillopacity: attributes.fillOpacity || 0.4, + highlightfillcolor: attributes.highlightFillColor || '#FF7400', + highlightstrokecolor: attributes.highlightStrokeColor || 'black', + gradient: attributes.gradient || 'none' }; - data = Symbolic.geometricLocusByGroebnerBase(board, p, cb); - cb(data.datax, data.datay, data.polynomial, data.exectime); - }; - return c; - }; + cent = attributes.center || [0, 0]; + xc = cent[0]; + yc = cent[1]; + center = board.create('point', [xc, yc], {name: '', fixed: true, withlabel: false, visible: false}); + start_angle = Math.PI / 2 - Math.PI / numofparams; + start_angle = attributes.startangle || 0; + rad = start_angle; + p = []; + line = []; - JXG.registerElement('locus', JXG.createLocus); + for (i = 0; i < numofparams; i++) { + rad += 2 * Math.PI / numofparams; + xcoord = radius * Math.cos(rad) + xc; + ycoord = radius * Math.sin(rad) + yc; - return { - createLocus: JXG.createLocus - }; -}); + p[i] = board.create('point', [xcoord, ycoord], {name: '', fixed: true, withlabel: false, visible: false}); + line[i] = board.create('line', [center, p[i]], { + name: paramArray[i], + strokeColor: myAtts.strokecolor, + strokeWidth: myAtts.strokewidth, + strokeOpacity: 1.0, + straightFirst: false, + straightLast: false, + withLabel: true, + highlightStrokeColor: myAtts.highlightstrokecolor + }); + line[i].getLabelAnchor = get_anchor; + t = get_transform(rad, i); -/* - Copyright 2008-2021 - Matthias Ehmann, - Michael Gerhaeuser, - Carsten Miller, - Bianca Valentin, - Alfred Wassermann, - Peter Wilfahrt + for (j = 0; j < parents.length; j++) { + data = parents[j][i]; + pdata[j][i] = board.create('point', [data, 0], {name: '', fixed: true, withlabel: false, visible: false}); + pdata[j][i].addTransform(pdata[j][i], t); + } + } - This file is part of JSXGraph. + polygons = []; + for (i = 0; i < len; i++) { + myAtts.labelcolor = colorArray && colorArray[i % colorArray.length]; + myAtts.strokecolor = colorArray && colorArray[i % colorArray.length]; + myAtts.fillcolor = colorArray && colorArray[i % colorArray.length]; + polygons[i] = board.create('polygon', pdata[i], { + withLines: true, + withLabel: false, + fillColor: myAtts.fillcolor, + fillOpacity: myAtts.fillopacity, + highlightFillColor: myAtts.highlightfillcolor + }); - JSXGraph is free software dual licensed under the GNU LGPL or MIT License. + for (j = 0; j < numofparams; j++) { + polygons[i].borders[j].setAttribute('strokecolor:' + colorArray[i % colorArray.length]); + polygons[i].borders[j].setAttribute('strokewidth:' + myAtts.polystrokewidth); + } + } - You can redistribute it and/or modify it under the terms of the + legend_position = attributes.legendposition || 'none'; + switch (legend_position) { + case 'right': + lxoff = attributes.legendleftoffset || 2; + lyoff = attributes.legendtopoffset || 1; - * GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version - OR - * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT + this.legend = board.create('legend', [xc + radius + lxoff, yc + radius - lyoff], { + labels: labelArray, + colors: colorArray + }); + break; + case 'none': + break; + default: + JXG.debug('Unknown legend position'); + } - JSXGraph is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. + circles = []; + if (attributes.showcircles) { + cla = []; + for (i = 0; i < 6; i++) { + cla[i] = 20 * i; + } + cla[0] = "0"; + clabelArray = attributes.circlelabelarray || cla; + ncircles = clabelArray.length; - You should have received a copy of the GNU Lesser General Public License and - the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> - and <http://opensource.org/licenses/MIT/>. - */ + if (ncircles < 2) { + throw new Error('JSXGraph radar chart: too less circles in circleLabelArray'); + } + pcircles = []; + angle = start_angle + Math.PI / numofparams; + t = get_transform(angle, 0); -/*global JXG: true, define: true*/ -/*jslint nomen: true, plusplus: true*/ + myAtts.fillcolor = 'none'; + myAtts.highlightfillcolor = 'none'; + myAtts.strokecolor = attributes.strokecolor || 'black'; + myAtts.strokewidth = attributes.circlestrokewidth || 0.5; + myAtts.layer = 0; -/* depends: - jxg - base/constants - base/coords - base/element - math/math - math/statistics - utils/type - */ + // we have ncircles-1 intervals between ncircles circles + dr = (ends[0] - starts[0]) / (ncircles - 1); -/** - * @fileoverview In this file the geometry element Image is defined. - */ + for (i = 0; i < ncircles; i++) { + pcircles[i] = board.create('point', [starts[0] + i * dr, 0], { + name: clabelArray[i], + size: 0, + fixed: true, + withLabel: true, + visible: true + }); + pcircles[i].addTransform(pcircles[i], t); + circles[i] = board.create('circle', [center, pcircles[i]], myAtts); + } -define('base/image',[ - 'jxg', 'base/constants', 'base/coords', 'base/element', 'math/math', 'utils/type', 'base/coordselement' -], function (JXG, Const, Coords, GeometryElement, Mat, Type, CoordsElement) { + } + this.rendNode = polygons[0].rendNode; + return { + circles: circles, + lines: line, + points: pdata, + midpoint: center, + polygons: polygons + }; + }, - "use strict"; + /** + * Uses the boards renderer to update the chart. + * @private + */ + updateRenderer: function () { + return this; + }, + + // documented in base/element + update: function () { + if (this.needsUpdate) { + this.updateDataArray(); + } + + return this; + }, + + /** + * Template for dynamic charts update. + * This method is used to compute new entries + * for the arrays this.dataX and + * this.dataY. It is used in update. + * Default is an empty method, can be overwritten + * by the user. + * + * @returns {JXG.Chart} Reference to this chart object. + */ + updateDataArray: function () { return this; } + }); /** - * Construct and handle images - * The coordinates can be relative to the coordinates of an element - * given in {@link JXG.Options#text.anchor}. + * @class Constructor for a chart. + * @pseudo + * @description + * @name Chart + * @augments JXG.Chart + * @constructor + * @type JXG.Chart + * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {Array} x Array of x-coordinates (default case, see below for alternatives) + * @param {Array} y Array of y-coordinates (default case, see below for alternatives) + * <p> + * The parent array may be of one of the following forms: + * <ol> + * <li> Parents array looks like [number, number, number, ...]. It is interpreted as array of y-coordinates. + * The x coordinates are automatically set to [1, 2, ...] + * <li> Parents array looks like [[number, number, number, ...]]. The content is interpreted as array of y-coordinates. + * The x coordinates are automatically set to [1, 2, ...]x coordinates are automatically set to [1, 2, ...] + * Default case: [[x0,x1,x2,...],[y1,y2,y3,...]] + * </ol> + * + * The attribute value for the key 'chartStyle' determines the type(s) of the chart. 'chartStyle' is a comma + * separated list of strings of the possible chart types + * 'bar', 'fit', 'line', 'pie', 'point', 'radar', 'spline'. + * + * @see JXG.Chart#drawBar + * @see JXG.Chart#drawFit + * @see JXG.Chart#drawLine + * @see JXG.Chart#drawPie + * @see JXG.Chart#drawPoints + * @see JXG.Chart#drawRadar + * @see JXG.Chart#drawSpline + * + * @example + * board = JXG.JSXGraph.initBoard('jxgbox', {boundingbox:[-0.5,8,9,-2],axis:true}); + * + * var f = [4, 2, -1, 3, 6, 7, 2]; + * var chart = board.create('chart', f, + * {chartStyle:'bar', + * width:0.8, + * labels:f, + * colorArray:['#8E1B77','#BE1679','#DC1765','#DA2130','#DB311B','#DF4917','#E36317','#E87F1A', + * '#F1B112','#FCF302','#C1E212'], + * label: {fontSize:30, display:'internal', anchorX:'left', rotate:90} + * }); + * + * </pre><div id="JXG1528c395-9fa4-4210-ada6-7fc5652ed920" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG1528c395-9fa4-4210-ada6-7fc5652ed920', + * {boundingbox: [-0.5,8,9,-2], axis: true, showcopyright: false, shownavigation: false}); + * var f = [4,2,-1,3,6,7,2]; + * var chart = board.create('chart', f, + * {chartStyle:'bar', + * width:0.8, + * labels:f, + * colorArray:['#8E1B77','#BE1679','#DC1765','#DA2130','#DB311B','#DF4917','#E36317','#E87F1A', + * '#F1B112','#FCF302','#C1E212'], + * label: {fontSize:30, display:'internal', anchorX:'left', rotate:90} + * }); + * + * })(); + * + * </script><pre> + * + * @example + * board = JXG.JSXGraph.initBoard('jxgbox', {boundingbox: [-1, 9, 13, -3], axis:true}); + * + * var s = board.create('slider', [[4,7],[8,7],[1,1,1.5]], {name:'S', strokeColor:'black', fillColor:'white'}); + * var f = [function(){return (s.Value()*4.5).toFixed(2);}, + * function(){return (s.Value()*(-1)).toFixed(2);}, + * function(){return (s.Value()*3).toFixed(2);}, + * function(){return (s.Value()*2).toFixed(2);}, + * function(){return (s.Value()*(-0.5)).toFixed(2);}, + * function(){return (s.Value()*5.5).toFixed(2);}, + * function(){return (s.Value()*2.5).toFixed(2);}, + * function(){return (s.Value()*(-0.75)).toFixed(2);}, + * function(){return (s.Value()*3.5).toFixed(2);}, + * function(){return (s.Value()*2).toFixed(2);}, + * function(){return (s.Value()*(-1.25)).toFixed(2);} + * ]; + * var chart = board.create('chart', [f], + * {chartStyle:'bar',width:0.8,labels:f, + * colorArray:['#8E1B77','#BE1679','#DC1765','#DA2130','#DB311B','#DF4917','#E36317','#E87F1A', + * '#F1B112','#FCF302','#C1E212']}); + * + * var dataArr = [4,1,3,2,5,6.5,1.5,2,0.5,1.5,-1]; + * var chart2 = board.create('chart', dataArr, {chartStyle:'line,point'}); + * chart2[0].setAttribute('strokeColor:black','strokeWidth:2pt'); + * for(var i=0; i<11;i++) { + * chart2[1][i].setAttribute({strokeColor:'black',fillColor:'white',face:'[]', size:4, strokeWidth:'2pt'}); + * } + * board.unsuspendUpdate(); + * + * </pre><div id="JXG22deb158-48c6-41c3-8157-b88b4b968a55" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG22deb158-48c6-41c3-8157-b88b4b968a55', + * {boundingbox: [-1, 9, 13, -3], axis: true, showcopyright: false, shownavigation: false}); + * var s = board.create('slider', [[4,7],[8,7],[1,1,1.5]], {name:'S', strokeColor:'black', fillColor:'white'}); + * var f = [function(){return (s.Value()*4.5).toFixed(2);}, + * function(){return (s.Value()*(-1)).toFixed(2);}, + * function(){return (s.Value()*3).toFixed(2);}, + * function(){return (s.Value()*2).toFixed(2);}, + * function(){return (s.Value()*(-0.5)).toFixed(2);}, + * function(){return (s.Value()*5.5).toFixed(2);}, + * function(){return (s.Value()*2.5).toFixed(2);}, + * function(){return (s.Value()*(-0.75)).toFixed(2);}, + * function(){return (s.Value()*3.5).toFixed(2);}, + * function(){return (s.Value()*2).toFixed(2);}, + * function(){return (s.Value()*(-1.25)).toFixed(2);} + * ]; + * var chart = board.create('chart', [f], + * {chartStyle:'bar',width:0.8,labels:f, + * colorArray:['#8E1B77','#BE1679','#DC1765','#DA2130','#DB311B','#DF4917','#E36317','#E87F1A', + * '#F1B112','#FCF302','#C1E212']}); + * + * var dataArr = [4,1,3,2,5,6.5,1.5,2,0.5,1.5,-1]; + * var chart2 = board.create('chart', dataArr, {chartStyle:'line,point'}); + * chart2[0].setAttribute('strokeColor:black','strokeWidth:2pt'); + * for(var i=0; i<11;i++) { + * chart2[1][i].setAttribute({strokeColor:'black',fillColor:'white',face:'[]', size:4, strokeWidth:'2pt'}); + * } + * board.unsuspendUpdate(); + * + * })(); + * + * </script><pre> + * + * @example + * var dataArr = [4, 1.2, 3, 7, 5, 4, 1.54, function () { return 2; }]; + * var a = board.create('chart', dataArr, { + * chartStyle:'pie', colors:['#B02B2C','#3F4C6B','#C79810','#D15600'], + * fillOpacity:0.9, + * center:[5,2], + * strokeColor:'#ffffff', + * strokeWidth:6, + * highlightBySize:true, + * highlightOnSector:true + * }); + * + * </pre><div id="JXG1180b7dd-b048-436a-a5ad-87ffa82d5aff" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG1180b7dd-b048-436a-a5ad-87ffa82d5aff', + * {boundingbox: [0, 8, 12, -4], axis: true, showcopyright: false, shownavigation: false}); + * var dataArr = [4, 1.2, 3, 7, 5, 4, 1.54, function () { return 2; }]; + * var a = board.create('chart', dataArr, { + * chartStyle:'pie', colors:['#B02B2C','#3F4C6B','#C79810','#D15600'], + * fillOpacity:0.9, + * center:[5,2], + * strokeColor:'#ffffff', + * strokeWidth:6, + * highlightBySize:true, + * highlightOnSector:true + * }); + * + * })(); + * + * </script><pre> + * + * @example + * board = JXG.JSXGraph.initBoard('jxgbox', {boundingbox: [-12, 12, 20, -12], axis: false}); + * board.suspendUpdate(); + * // See labelArray and paramArray + * var dataArr = [[23, 14, 15.0], [60, 8, 25.0], [0, 11.0, 25.0], [10, 15, 20.0]]; + * + * var a = board.create('chart', dataArr, { + * chartStyle:'radar', + * colorArray:['#0F408D','#6F1B75','#CA147A','#DA2228','#E8801B','#FCF302','#8DC922','#15993C','#87CCEE','#0092CE'], + * //fillOpacity:0.5, + * //strokeColor:'black', + * //strokeWidth:1, + * //polyStrokeWidth:1, + * paramArray:['Speed','Flexibility', 'Costs'], + * labelArray:['Ruby','JavaScript', 'PHP', 'Python'], + * //startAngle:Math.PI/4, + * legendPosition:'right', + * //"startShiftRatio": 0.1, + * //endShiftRatio:0.1, + * //startShiftArray:[0,0,0], + * //endShiftArray:[0.5,0.5,0.5], + * start:0 + * //end:70, + * //startArray:[0,0,0], + * //endArray:[7,7,7], + * //radius:3, + * //showCircles:true, + * //circleLabelArray:[1,2,3,4,5], + * //highlightColorArray:['#E46F6A','#F9DF82','#F7FA7B','#B0D990','#69BF8E','#BDDDE4','#92C2DF','#637CB0','#AB91BC','#EB8EBF'], + * }); + * board.unsuspendUpdate(); * - * The image can be supplied as an URL or an base64 encoded inline image - * like "data:image/png;base64, /9j/4AAQSkZJRgA..." or a function returning - * an URL: function(){ return 'xxx.png; }. + * </pre><div id="JXG985fbbe6-0488-4073-b73b-cb3ebaea488a" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG985fbbe6-0488-4073-b73b-cb3ebaea488a', + * {boundingbox: [-12, 12, 20, -12], axis: false, showcopyright: false, shownavigation: false}); + * board.suspendUpdate(); + * // See labelArray and paramArray + * var dataArr = [[23, 14, 15.0], [60, 8, 25.0], [0, 11.0, 25.0], [10, 15, 20.0]]; * - * @class Creates a new image object. Do not use this constructor to create a image. Use {@link JXG.Board#create} with - * type {@link Image} instead. - * @augments JXG.GeometryElement - * @augments JXG.CoordsElement - * @param {string|JXG.Board} board The board the new text is drawn on. - * @param {Array} coordinates An array with the user coordinates of the text. - * @param {Object} attributes An object containing visual and - optionally - a name and an id. - * @param {string|function} url An URL string or a function returning an URL string. - * @param {Array} size Array containing width and height of the image in user coordinates. + * var a = board.create('chart', dataArr, { + * chartStyle:'radar', + * colorArray:['#0F408D','#6F1B75','#CA147A','#DA2228','#E8801B','#FCF302','#8DC922','#15993C','#87CCEE','#0092CE'], + * //fillOpacity:0.5, + * //strokeColor:'black', + * //strokeWidth:1, + * //polyStrokeWidth:1, + * paramArray:['Speed','Flexibility', 'Costs'], + * labelArray:['Ruby','JavaScript', 'PHP', 'Python'], + * //startAngle:Math.PI/4, + * legendPosition:'right', + * //"startShiftRatio": 0.1, + * //endShiftRatio:0.1, + * //startShiftArray:[0,0,0], + * //endShiftArray:[0.5,0.5,0.5], + * start:0 + * //end:70, + * //startArray:[0,0,0], + * //endArray:[7,7,7], + * //radius:3, + * //showCircles:true, + * //circleLabelArray:[1,2,3,4,5], + * //highlightColorArray:['#E46F6A','#F9DF82','#F7FA7B','#B0D990','#69BF8E','#BDDDE4','#92C2DF','#637CB0','#AB91BC','#EB8EBF'], + * }); + * board.unsuspendUpdate(); + * + * })(); * + * </script><pre> + * + * For more examples see + * <ul> + * <li><a href="https://jsxgraph.org/wiki/index.php/Charts_from_HTML_tables_-_tutorial">JSXgraph wiki: Charts from HTML tables - tutorial</a> + * <li><a href="https://jsxgraph.org/wiki/index.php/Pie_chart">JSXgraph wiki: Pie chart</a> + * <li><a href="https://jsxgraph.org/wiki/index.php/Different_chart_styles">JSXgraph wiki: Various chart styles</a> + * <li><a href="https://jsxgraph.org/wiki/index.php/Dynamic_bar_chart">JSXgraph wiki: Dynamic bar chart</a> + * </ul> */ - JXG.Image = function (board, coords, attributes, url, size) { - this.constructor(board, attributes, Const.OBJECT_TYPE_IMAGE, Const.OBJECT_CLASS_OTHER); - this.element = this.board.select(attributes.anchor); - this.coordsConstructor(coords); - - this.W = Type.createFunction(size[0], this.board, ''); - this.H = Type.createFunction(size[1], this.board, ''); - - this.usrSize = [this.W(), this.H()]; - - /** - * Array of length two containing [width, height] of the image in pixel. - * @type {array} - */ - this.size = [Math.abs(this.usrSize[0] * board.unitX), Math.abs(this.usrSize[1] * board.unitY)]; - - /** - * 'href' of the image. This might be an URL, but also a data-uri is allowed. - * @type {string} - */ - this.url = url; - - this.elType = 'image'; - - // span contains the anchor point and the two vectors - // spanning the image rectangle. - this.span = [ - this.coords.usrCoords.slice(0), - [this.coords.usrCoords[0], this.W(), 0], - [this.coords.usrCoords[0], 0, this.H()] - ]; - - //this.parent = board.select(attributes.anchor); - this.id = this.board.setId(this, 'Im'); - - this.board.renderer.drawImage(this); - this.board.finalizeAdding(this); + JXG.createChart = function (board, parents, attributes) { + var data, row, i, j, col, + charts = [], + w, x, showRows, attr, + originalWidth, name, strokeColor, fillColor, + hStrokeColor, hFillColor, len, + table = Env.isBrowser ? board.document.getElementById(parents[0]) : null; - this.methodMap = JXG.deepCopy(this.methodMap, { - addTransformation: 'addTransform', - trans: 'addTransform' - }); - }; + if ((parents.length === 1) && (Type.isString(parents[0]))) { + if (Type.exists(table)) { + // extract the data + attr = Type.copyAttributes(attributes, board.options, 'chart'); - JXG.Image.prototype = new GeometryElement(); - Type.copyPrototypeMethods(JXG.Image, CoordsElement, 'coordsConstructor'); + table = (new DataSource()).loadFromTable(parents[0], attr.withheaders, attr.withheaders); + data = table.data; + col = table.columnHeaders; + row = table.rowHeaders; - JXG.extend(JXG.Image.prototype, /** @lends JXG.Image.prototype */ { + originalWidth = attr.width; + name = attr.name; + strokeColor = attr.strokecolor; + fillColor = attr.fillcolor; + hStrokeColor = attr.highlightstrokecolor; + hFillColor = attr.highlightfillcolor; - /** - * Checks whether (x,y) is over or near the image; - * @param {Number} x Coordinate in x direction, screen coordinates. - * @param {Number} y Coordinate in y direction, screen coordinates. - * @returns {Boolean} True if (x,y) is over the image, False otherwise. - */ - hasPoint: function (x, y) { - var dx, dy, r, type, prec, - c, v, p, dot, - len = this.transformations.length; + board.suspendUpdate(); - if (Type.isObject(Type.evaluate(this.visProp.precision))) { - type = this.board._inputDevice; - prec = Type.evaluate(this.visProp.precision[type]); + len = data.length; + showRows = []; + if (attr.rows && Type.isArray(attr.rows)) { + for (i = 0; i < len; i++) { + for (j = 0; j < attr.rows.length; j++) { + if ((attr.rows[j] === i) || (attr.withheaders && attr.rows[j] === row[i])) { + showRows.push(data[i]); + break; + } + } + } } else { - // 'inherit' - prec = this.board.options.precision.hasPoint; + showRows = data; } - // Easy case: no transformation - if (len === 0) { - dx = x - this.coords.scrCoords[1]; - dy = this.coords.scrCoords[2] - y; - r = prec; - - return dx >= -r && dx - this.size[0] <= r && - dy >= -r && dy - this.size[1] <= r; - } - - // Image is transformed - c = new Coords(Const.COORDS_BY_SCREEN, [x, y], this.board); - // v is the vector from anchor point to the drag point - c = c.usrCoords; - v = [c[0] - this.span[0][0], - c[1] - this.span[0][1], - c[2] - this.span[0][2]]; - dot = Mat.innerProduct; // shortcut + len = showRows.length; - // Project the drag point to the sides. - p = dot(v, this.span[1]); - if (0 <= p && p <= dot(this.span[1], this.span[1])) { - p = dot(v, this.span[2]); + for (i = 0; i < len; i++) { - if (0 <= p && p <= dot(this.span[2], this.span[2])) { - return true; - } - } - return false; - }, + x = []; + if (attr.chartstyle && attr.chartstyle.indexOf('bar') !== -1) { + if (originalWidth) { + w = originalWidth; + } else { + w = 0.8; + } - /** - * Recalculate the coordinates of lower left corner and the width and height. - * - * @returns {JXG.GeometryElement} A reference to the element - * @private - */ - update: function (fromParent) { - if (!this.needsUpdate) { - return this; - } + x.push(1 - w / 2 + (i + 0.5) * w / len); - this.updateCoords(fromParent); - this.updateSize(); - this.updateSpan(); + for (j = 1; j < showRows[i].length; j++) { + x.push(x[j - 1] + 1); + } - return this; - }, + attr.width = w / len; + } - /** - * Send an update request to the renderer. - * @private - */ - updateRenderer: function () { - return this.updateRendererGeneric('updateImage'); - }, + if (name && name.length === len) { + attr.name = name[i]; + } else if (attr.withheaders) { + attr.name = col[i]; + } - /** - * Updates the internal arrays containing size of the image. - * @returns {JXG.GeometryElement} A reference to the element - * @private - */ - updateSize: function () { - this.usrSize = [this.W(), this.H()]; - this.size = [Math.abs(this.usrSize[0] * this.board.unitX), Math.abs(this.usrSize[1] * this.board.unitY)]; + if (strokeColor && strokeColor.length === len) { + attr.strokecolor = strokeColor[i]; + } else { + attr.strokecolor = Color.hsv2rgb(((i + 1) / len) * 360, 0.9, 0.6); + } - return this; - }, + if (fillColor && fillColor.length === len) { + attr.fillcolor = fillColor[i]; + } else { + attr.fillcolor = Color.hsv2rgb(((i + 1) / len) * 360, 0.9, 1.0); + } - /** - * Update the anchor point of the image, i.e. the lower left corner - * and the two vectors which span the rectangle. - * @returns {JXG.GeometryElement} A reference to the element - * @private - * - */ - updateSpan: function () { - var i, j, len = this.transformations.length, v = []; + if (hStrokeColor && hStrokeColor.length === len) { + attr.highlightstrokecolor = hStrokeColor[i]; + } else { + attr.highlightstrokecolor = Color.hsv2rgb(((i + 1) / len) * 360, 0.9, 1.0); + } - if (len === 0) { - this.span = [[this.Z(), this.X(), this.Y()], - [this.Z(), this.W(), 0], - [this.Z(), 0, this.H()]]; - } else { - // v contains the three defining corners of the rectangle/image - v[0] = [this.Z(), this.X(), this.Y()]; - v[1] = [this.Z(), this.X() + this.W(), this.Y()]; - v[2] = [this.Z(), this.X(), this.Y() + this.H()]; + if (hFillColor && hFillColor.length === len) { + attr.highlightfillcolor = hFillColor[i]; + } else { + attr.highlightfillcolor = Color.hsv2rgb(((i + 1) / len) * 360, 0.9, 0.6); + } - // Transform the three corners - for (i = 0; i < len; i++) { - for (j = 0; j < 3; j++) { - v[j] = Mat.matVecMult(this.transformations[i].matrix, v[j]); + if (attr.chartstyle && attr.chartstyle.indexOf('bar') !== -1) { + charts.push(new JXG.Chart(board, [x, showRows[i]], attr)); + } else { + charts.push(new JXG.Chart(board, [showRows[i]], attr)); } } - // Normalize the vectors - for (j = 0; j < 3; j++) { - v[j][1] /= v[j][0]; - v[j][2] /= v[j][0]; - v[j][0] /= v[j][0]; - } - // Compute the two vectors spanning the rectangle - // by subtracting the anchor point. - for (j = 1; j < 3; j++) { - v[j][0] -= v[0][0]; - v[j][1] -= v[0][1]; - v[j][2] -= v[0][2]; - } - this.span = v; + + board.unsuspendUpdate(); + } + return charts; + } - return this; - }, + attr = Type.copyAttributes(attributes, board.options, 'chart'); + return new JXG.Chart(board, parents, attr); + }; - addTransform: function (transform) { - var i; + JXG.registerElement('chart', JXG.createChart); - if (Type.isArray(transform)) { - for (i = 0; i < transform.length; i++) { - this.transformations.push(transform[i]); - } - } else { - this.transformations.push(transform); - } + /** + * Legend for chart + * TODO + * + * The Legend class is a basic class for legends. + * @class Creates a new Lgend object. Do not use this constructor to create a legend. + * Use {@link JXG.Board#create} with type {@link Legend} instead. + * <p> + * The legend object consists of segements with labels. These lines can be + * access with the property "lines" of the element. + * @constructor + * @augments JXG.GeometryElement + * @param {String,JXG.Board} board The board the new legend is drawn on. + * @param {Array} coords Coordinates of the left top point of the legend. + * @param {Object} attributes Attributes of the legend + */ + JXG.Legend = function (board, coords, attributes) { + var attr; - return this; - }, + /* Call the constructor of GeometryElement */ + this.constructor(); - // documented in element.js - getParents: function () { - var p = [this.url, [this.Z(), this.X(), this.Y()], this.usrSize]; + attr = Type.copyAttributes(attributes, board.options, 'legend'); - if (this.parents.length !== 0) { - p = this.parents; - } + this.board = board; + this.coords = new Coords(Const.COORDS_BY_USER, coords, this.board); + this.myAtts = {}; + this.label_array = attr.labelarray || attr.labels; + this.color_array = attr.colorarray || attr.colors; + this.lines = []; + this.myAtts.strokewidth = attr.strokewidth || 5; + this.myAtts.straightfirst = false; + this.myAtts.straightlast = false; + this.myAtts.withlabel = true; + this.myAtts.fixed = true; + this.style = attr.legendstyle || attr.style; - return p; - }, + if (this.style === 'vertical') { + this.drawVerticalLegend(board, attr); + } else { + throw new Error('JSXGraph: Unknown legend style: ' + this.style); + } + }; - /** - * Set the width and height of the image. After setting a new size, - * board.update() or image.fullUpdate() - * has to be called to make the change visible. - * @param {number, function, string} width Number, function or string - * that determines the new width of the image - * @param {number, function, string} height Number, function or string - * that determines the new height of the image - * @returns {JXG.GeometryElement} A reference to the element - * - * @example - * var im = board.create('image', ['http://jsxgraph.uni-bayreuth.de/distrib/images/uccellino.jpg', - * [-3,-2], [3,3]]); - * im.setSize(4, 4); - * board.update(); - * - * </pre><div id="JXG8411e60c-f009-11e5-b1bf-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function() { - * var board = JXG.JSXGraph.initBoard('JXG8411e60c-f009-11e5-b1bf-901b0e1b8723', - * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); - * var im = board.create('image', ['http://jsxgraph.uni-bayreuth.de/distrib/images/uccellino.jpg', [-3,-2], [3,3]]); - * //im.setSize(4, 4); - * //board.update(); - * - * })(); - * - * </script><pre> - * - * @example - * var p0 = board.create('point', [-3, -2]), - * im = board.create('image', ['http://jsxgraph.uni-bayreuth.de/distrib/images/uccellino.jpg', - * [function(){ return p0.X(); }, function(){ return p0.Y(); }], - * [3,3]]), - * p1 = board.create('point', [1, 2]); - * - * im.setSize(function(){ return p1.X() - p0.X(); }, function(){ return p1.Y() - p0.Y(); }); - * board.update(); - * - * </pre><div id="JXG4ce706c0-f00a-11e5-b1bf-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function() { - * var board = JXG.JSXGraph.initBoard('JXG4ce706c0-f00a-11e5-b1bf-901b0e1b8723', - * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); - * var p0 = board.create('point', [-3, -2]), - * im = board.create('image', ['http://jsxgraph.uni-bayreuth.de/distrib/images/uccellino.jpg', - * [function(){ return p0.X(); }, function(){ return p0.Y(); }], - * [3,3]]), - * p1 = board.create('point', [1, 2]); - * - * im.setSize(function(){ return p1.X() - p0.X(); }, function(){ return p1.Y() - p0.Y(); }); - * board.update(); - * - * })(); - * - * </script><pre> - * - */ - setSize: function(width, height) { - this.W = Type.createFunction(width, this.board, ''); - this.H = Type.createFunction(height, this.board, ''); + JXG.Legend.prototype = new GeometryElement(); - // this.fullUpdate(); + /** + * Draw a vertical legend. + * + * @private + * @param {String,JXG.Board} board The board the legend is drawn on + * @param {Object} attributes Attributes of the legend + */ + JXG.Legend.prototype.drawVerticalLegend = function (board, attributes) { + var i, + line_length = attributes.linelength || 1, + offy = (attributes.rowheight || 20) / this.board.unitY, - return this; - }, + getLabelAnchor = function () { + this.setLabelRelativeCoords(this.visProp.label.offset); + return new Coords(Const.COORDS_BY_USER, [this.point2.X(), this.point2.Y()], this.board); + }; - /** - * Returns the width of the image in user coordinates. - * @returns {number} width of the image in user coordinates - */ - W: function() {}, // Needed for docs, defined in constructor + for (i = 0; i < this.label_array.length; i++) { + this.myAtts.name = this.label_array[i]; + this.myAtts.strokecolor = this.color_array[i % this.color_array.length]; + this.myAtts.highlightstrokecolor = this.color_array[i % this.color_array.length]; + this.myAtts.label = { + offset: [10, 0], + strokeColor: this.color_array[i % this.color_array.length ], + strokeWidth: this.myAtts.strokewidth + }; - /** - * Returns the height of the image in user coordinates. - * @returns {number} height of the image in user coordinates - */ - H: function() {} // Needed for docs, defined in constructor + this.lines[i] = board.create('line', [ + [this.coords.usrCoords[1], this.coords.usrCoords[2] - i * offy], + [this.coords.usrCoords[1] + line_length, this.coords.usrCoords[2] - i * offy]], + this.myAtts); - }); + this.lines[i].getLabelAnchor = getLabelAnchor; + this.lines[i].prepareUpdate().update().updateVisibility(Type.evaluate(this.lines[i].visProp.visible)).updateRenderer(); + } + }; /** - * @class Displays an image. + * @class This element is used to provide a constructor for a chart legend. + * Parameter is a pair of coordinates. The label names and the label colors are + * supplied in the attributes: + * <ul> + * <li> labels (Array): array of strings containing label names + * <li> labelArray (Array): alternative array for label names (has precedence over 'labels') + * <li> colors (Array): array of color values + * <li> colorArray (Array): alternative array for color values (has precedence over 'colors') + * <li> legendStyle or style: at the time being only 'vertical' is supported. + * <li> rowHeight. + * </ul> + * * @pseudo * @description - * @name Image - * @type JXG.Image - * @augments JXG.Image - * @constructor + * @name Legend + * @augments JXG.Legend * @constructor + * @type JXG.Legend * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {string,function_Array_Array} url,coords,size url defines the location of the image data. The array coords contains the user coordinates - * of the lower left corner of the image. - * It can consist of two or three elements of type number, a string containing a GEONE<sub>x</sub>T - * constraint, or a function which takes no parameter and returns a number. Every element determines one coordinate. If a coordinate is - * given by a number, the number determines the initial position of a free image. If given by a string or a function that coordinate will be constrained - * that means the user won't be able to change the image's position directly by mouse because it will be calculated automatically depending on the string - * or the function's return value. If two parent elements are given the coordinates will be interpreted as 2D affine Euclidean coordinates, if three such - * parent elements are given they will be interpreted as homogeneous coordinates. - * <p> - * The array size defines the image's width and height in user coordinates. + * @param {Number} x Horizontal coordinate of the left top point of the legend + * @param {Number} y Vertical coordinate of the left top point of the legend + * * @example - * var im = board.create('image', ['http://jsxgraph.uni-bayreuth.de/jsxgraph/distrib/images/uccellino.jpg', [-3,-2], [3,3]]); + * var board = JXG.JSXGraph.initBoard('jxgbox', {axis:true,boundingbox:[-4,48.3,12.0,-2.3]}); + * var x = [-3,-2,-1,0,1,2,3,4,5,6,7,8]; + * var dataArr = [4,7,7,27,33,37,46,22,11,4,1,0]; * - * </pre><div class="jxgbox" id="JXG9850cda0-7ea0-4750-981c-68bacf9cca57" style="width: 400px; height: 400px;"></div> + * colors = ['green', 'yellow', 'red', 'blue']; + * board.create('chart', [x,dataArr], {chartStyle:'bar', width:1.0, labels:dataArr, colors: colors} ); + * board.create('legend', [8, 45], {labels:dataArr, colors: colors, strokeWidth:5} ); + * + * </pre><div id="JXGeeb588d9-a4fd-41bf-93f4-cd6f7a016682" class="jxgbox" style="width: 300px; height: 300px;"></div> * <script type="text/javascript"> - * var image_board = JXG.JSXGraph.initBoard('JXG9850cda0-7ea0-4750-981c-68bacf9cca57', {boundingbox: [-4, 4, 4, -4], axis: true, showcopyright: false, shownavigation: false}); - * var image_im = image_board.create('image', ['http://jsxgraph.uni-bayreuth.de/distrib/images/uccellino.jpg', [-3,-2],[3,3]]); + * (function() { + * var board = JXG.JSXGraph.initBoard('JXGeeb588d9-a4fd-41bf-93f4-cd6f7a016682', + * {boundingbox: [-4,48.3,12.0,-2.3], axis: true, showcopyright: false, shownavigation: false}); + * var x = [-3,-2,-1,0,1,2,3,4,5,6,7,8]; + * var dataArr = [4,7,7,27,33,37,46,22,11,4,1,0]; + * + * colors = ['green', 'yellow', 'red', 'blue']; + * board.create('chart', [x,dataArr], {chartStyle:'bar', width:1.0, labels:dataArr, colors: colors} ); + * board.create('legend', [8, 45], {labels:dataArr, colors: colors, strokeWidth:5} ); + * + * })(); + * * </script><pre> + * + * */ - JXG.createImage = function (board, parents, attributes) { - var attr, im, - url = parents[0], - coords = parents[1], - size = parents[2]; - - attr = Type.copyAttributes(attributes, board.options, 'image'); - im = CoordsElement.create(JXG.Image, board, coords, attr, url, size); - if (!im) { - throw new Error("JSXGraph: Can't create image with parent types '" + - (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + - "\nPossible parent types: [x,y], [z,x,y], [element,transformation]"); - } + JXG.createLegend = function (board, parents, attributes) { + //parents are coords of left top point of the legend + var start_from = [0, 0]; - if (attr.rotate !== 0) { // This is the default value, i.e. no rotation - im.addRotation(attr.rotate); + if (Type.exists(parents) && parents.length === 2) { + start_from = parents; + } else { + throw new Error('JSXGraph: Legend element needs two numbers as parameters'); } - return im; + return new JXG.Legend(board, start_from, attributes); }; - JXG.registerElement('image', JXG.createImage); + JXG.registerElement('legend', JXG.createLegend); return { - Image: JXG.Image, - createImage: JXG.createImage + Chart: JXG.Chart, + Legend: JXG.Legend, + createChart: JXG.createChart, + createLegend: JXG.createLegend }; }); /* - Copyright 2008-2021 + Copyright 2008-2022 Matthias Ehmann, Michael Gerhaeuser, Carsten Miller, @@ -65416,2184 +74507,2320 @@ define('base/image',[ /* depends: jxg - math/math - math/geometry base/constants base/element - base/coords utils/type elements: - text + curve + point + line + transform */ /** - * @fileoverview In this file the geometry object Ticks is defined. Ticks provides - * methods for creation and management of ticks on an axis. - * @author graphjs - * @version 0.1 + * @fileoverview The JSXGraph object Turtle is defined. It acts like + * "turtle graphics". + * @author A.W. */ -define('base/ticks',[ - 'jxg', 'math/math', 'math/geometry', 'math/numerics', 'base/constants', 'base/element', 'base/coords', 'utils/type', 'base/text' -], function (JXG, Mat, Geometry, Numerics, Const, GeometryElement, Coords, Type, Text) { +define('base/turtle',[ + 'jxg', 'base/constants', 'base/element', 'utils/type' +], function (JXG, Const, GeometryElement, Type) { "use strict"; /** - * Creates ticks for an axis. - * @class Ticks provides methods for creation and management - * of ticks on an axis. - * @param {JXG.Line} line Reference to the axis the ticks are drawn on. - * @param {Number|Array} ticks Number defining the distance between two major ticks or an array defining static ticks. - * @param {Object} attributes Properties - * @see JXG.Line#addTicks + * Constructs a new Turtle object. + * @class This is the Turtle class. + * It is derived from {@link JXG.GeometryElement}. + * It stores all properties required + * to move a turtle. * @constructor - * @extends JXG.GeometryElement + * @param {JXG.Board} board The board the new turtle is drawn on. + * @param {Array} parents Start position and start direction of the turtle. Possible values are + * [x, y, angle] + * [[x, y], angle] + * [x, y] + * [[x, y]] + * @param {Object} attributes Attributes to change the visual properties of the turtle object + * All angles are in degrees. + * + * @example + * + * //creates a figure 8 animation + * var board = JXG.JSXGraph.initBoard('jxgbox',{boundingbox: [-250, 250, 250, -250]}); + * var t = board.create('turtle',[0, 0], {strokeOpacity:0.5}); + * t.setPenSize(3); + * t.right(90); + * var alpha = 0; + * + * var run = function() { + * t.forward(2); + * if (Math.floor(alpha / 360) % 2 === 0) { + * t.left(1); // turn left by 1 degree + * } else { + * t.right(1); // turn right by 1 degree + * } + * alpha += 1; + * + * if (alpha < 1440) { // stop after two rounds + * setTimeout(run, 20); + * } + * } + * + *run(); + * + * </pre><div class="jxgbox" id="JXG14167b1c-2ad3-11e5-8dd9-901b0e1b8723" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var brd = JXG.JSXGraph.initBoard('JXG14167b1c-2ad3-11e5-8dd9-901b0e1b8723', + * {boundingbox: [-250, 250, 250, -250], axis: true, showcopyright: false, shownavigation: false}); + * var t = brd.create('turtle',[0, 0], {strokeOpacity:0.5}); + * t.setPenSize(3); + * t.right(90); + * var alpha = 0; + * + * var run = function() { + * t.forward(2); + * if (Math.floor(alpha / 360) % 2 === 0) { + * t.left(1); // turn left by 1 degree + * } else { + * t.right(1); // turn right by 1 degree + * } + * alpha += 1; + * + * if (alpha < 1440) { // stop after two rounds + * setTimeout(run, 20); + * } + * } + * + * run(); + * + * })(); + * + * </script><pre> */ - JXG.Ticks = function (line, ticks, attributes) { - this.constructor(line.board, attributes, Const.OBJECT_TYPE_TICKS, Const.OBJECT_CLASS_OTHER); + JXG.Turtle = function (board, parents, attributes) { + var x, y, dir; - /** - * The line the ticks belong to. - * @type JXG.Line - */ - this.line = line; + this.constructor(board, attributes, Const.OBJECT_TYPE_TURTLE, Const.OBJECT_CLASS_OTHER); - /** - * The board the ticks line is drawn on. - * @type JXG.Board - */ - this.board = this.line.board; + this.turtleIsHidden = false; + this.board = board; + this.visProp.curveType = 'plot'; - /** - * A function calculating ticks delta depending on the ticks number. - * @type Function - */ - this.ticksFunction = null; + // Save visProp in this._attributes. + // this._attributes is overwritten by setPenSize, setPenColor... + // Setting the color or size affects the turtle from the time of + // calling the method, + // whereas Turtle.setAttribute affects all turtle curves. + this._attributes = Type.copyAttributes(this.visProp, board.options, 'turtle'); + delete this._attributes.id; + + x = 0; + y = 0; + dir = 90; + + if (parents.length !== 0) { + // [x,y,dir] + if (parents.length === 3) { + // Only numbers are accepted at the moment + x = parents[0]; + y = parents[1]; + dir = parents[2]; + } else if (parents.length === 2) { + // [[x,y],dir] + if (Type.isArray(parents[0])) { + x = parents[0][0]; + y = parents[0][1]; + dir = parents[1]; + // [x,y] + } else { + x = parents[0]; + y = parents[1]; + } + // [[x,y]] + } else { + x = parents[0][0]; + y = parents[0][1]; + } + } + + this.init(x, y, dir); + + this.methodMap = Type.deepCopy(this.methodMap, { + forward: 'forward', + fd: 'forward', + back: 'back', + bk: 'back', + right: 'right', + rt: 'right', + left: 'left', + lt: 'left', + penUp: 'penUp', + pu: 'penUp', + penDown: 'penDown', + pd: 'penDown', + clearScreen: 'clearScreen', + cs: 'clearScreen', + clean: 'clean', + setPos: 'setPos', + home: 'home', + hideTurtle: 'hideTurtle', + ht: 'hideTurtle', + showTurtle: 'showTurtle', + st: 'showTurtle', + penSize: 'setPenSize', + penColor: 'setPenColor', + pushTurtle: 'pushTurtle', + push: 'pushTurtle', + popTurtle: 'popTurtle', + pop: 'popTurtle', + lookTo: 'lookTo', + pos: 'pos', + moveTo: 'moveTo', + X: 'X', + Y: 'Y' + }); + + return this; + }; + + JXG.Turtle.prototype = new GeometryElement(); + JXG.extend(JXG.Turtle.prototype, /** @lends JXG.Turtle.prototype */ { /** - * Array of fixed ticks. - * @type Array + * Initialize a new turtle or reinitialize a turtle after {@link JXG.Turtle#clearScreen}. + * @private */ - this.fixedTicks = null; + init: function (x, y, dir) { + var hiddenPointAttr = { + fixed: true, + name: '', + visible: false, + withLabel: false + }; + + this.arrowLen = 20 / Math.sqrt(this.board.unitX * this.board.unitX + this.board.unitY * this.board.unitY); + + this.pos = [x, y]; + this.isPenDown = true; + this.dir = 90; + this.stack = []; + this.objects = []; + this.curve = this.board.create('curve', [[this.pos[0]], [this.pos[1]]], this._attributes); + this.objects.push(this.curve); + + this.turtle = this.board.create('point', this.pos, hiddenPointAttr); + this.objects.push(this.turtle); + + this.turtle2 = this.board.create('point', [this.pos[0], this.pos[1] + this.arrowLen], hiddenPointAttr); + this.objects.push(this.turtle2); + + this.visProp.arrow.lastArrow = true; + this.visProp.arrow.straightFirst = false; + this.visProp.arrow.straightLast = false; + this.arrow = this.board.create('line', [this.turtle, this.turtle2], this.visProp.arrow); + this.objects.push(this.arrow); + + this.subs = { + arrow: this.arrow + }; + this.inherits.push(this.arrow); + + this.right(90 - dir); + this.board.update(); + }, /** - * Equidistant ticks. Distance is defined by ticksFunction - * @type Boolean + * Move the turtle forward. + * @param {Number} len of forward move in user coordinates + * @returns {JXG.Turtle} pointer to the turtle object */ - this.equidistant = false; + forward: function (len) { + if (len === 0) { + return this; + } - this.labelsData = []; + var t, + dx = len * Math.cos(this.dir * Math.PI / 180), + dy = len * Math.sin(this.dir * Math.PI / 180); - if (Type.isFunction(ticks)) { - this.ticksFunction = ticks; - throw new Error("Function arguments are no longer supported."); - } + if (!this.turtleIsHidden) { + t = this.board.create('transform', [dx, dy], {type: 'translate'}); - if (Type.isArray(ticks)) { - this.fixedTicks = ticks; - } else { - if (Math.abs(ticks) < Mat.eps || ticks < 0) { - ticks = attributes.defaultdistance; + t.applyOnce(this.turtle); + t.applyOnce(this.turtle2); } - /* - * Ticks function: - * determines the distance (in user units) of two major ticks - */ - this.ticksFunction = this.makeTicksFunction(ticks); + if (this.isPenDown) { + // IE workaround + if (this.curve.dataX.length >= 8192) { + this.curve = this.board.create('curve', [[this.pos[0]], [this.pos[1]]], this._attributes); + this.objects.push(this.curve); + } + } - this.equidistant = true; - } + this.pos[0] += dx; + this.pos[1] += dy; + + if (this.isPenDown) { + this.curve.dataX.push(this.pos[0]); + this.curve.dataY.push(this.pos[1]); + } + + this.board.update(); + return this; + }, /** - * Least distance between two ticks, measured in pixels. - * @type int + * Move the turtle backwards. + * @param {Number} len of backwards move in user coordinates + * @returns {JXG.Turtle} pointer to the turtle object */ - this.minTicksDistance = attributes.minticksdistance; + back: function (len) { + return this.forward(-len); + }, /** - * Stores the ticks coordinates - * @type {Array} + * Rotate the turtle direction to the right + * @param {Number} angle of the rotation in degrees + * @returns {JXG.Turtle} pointer to the turtle object */ - this.ticks = []; + right: function (angle) { + this.dir -= angle; + this.dir %= 360; + + if (!this.turtleIsHidden) { + var t = this.board.create('transform', [-angle * Math.PI / 180, this.turtle], {type: 'rotate'}); + t.applyOnce(this.turtle2); + } + + this.board.update(); + return this; + }, /** - * Distance between two major ticks in user coordinates - * @type {Number} + * Rotate the turtle direction to the right. + * @param {Number} angle of the rotation in degrees + * @returns {JXG.Turtle} pointer to the turtle object */ - this.ticksDelta = 1; + left: function (angle) { + return this.right(-angle); + }, /** - * Array where the labels are saved. There is an array element for every tick, - * even for minor ticks which don't have labels. In this case the array element - * contains just <tt>null</tt>. - * @type Array + * Pen up, stops visible drawing + * @returns {JXG.Turtle} pointer to the turtle object */ - this.labels = []; + penUp: function () { + this.isPenDown = false; + return this; + }, /** - * A list of labels which have to be displayed in updateRenderer. - * @type {Array} + * Pen down, continues visible drawing + * @returns {JXG.Turtle} pointer to the turtle object */ - this.labelData = []; + penDown: function () { + this.isPenDown = true; + this.curve = this.board.create('curve', [[this.pos[0]], [this.pos[1]]], this._attributes); + this.objects.push(this.curve); + + return this; + }, /** - * To ensure the uniqueness of label ids this counter is used. - * @type {number} + * Removes the turtle curve from the board. The turtle stays in its position. + * @returns {JXG.Turtle} pointer to the turtle object */ - this.labelCounter = 0; + clean: function () { + var i, el; - this.id = this.line.addTicks(this); - this.elType = 'ticks'; - this.inherits.push(this.labels); - this.board.setId(this, 'Ti'); - }; + for (i = 0; i < this.objects.length; i++) { + el = this.objects[i]; + if (el.type === Const.OBJECT_TYPE_CURVE) { + this.board.removeObject(el); + this.objects.splice(i, 1); + } + } - JXG.Ticks.prototype = new GeometryElement(); + this.curve = this.board.create('curve', [[this.pos[0]], [this.pos[1]]], this._attributes); + this.objects.push(this.curve); + this.board.update(); - JXG.extend(JXG.Ticks.prototype, /** @lends JXG.Ticks.prototype */ { + return this; + }, /** - * Ticks function: - * determines the distance (in user units) of two major ticks. - * See above in constructor and in @see JXG.GeometryElement#setAttribute - * - * @private - * @param {Number} ticks Distance between two major ticks - * @returns {Function} returns method ticksFunction + * Removes the turtle completely and resets it to its initial position and direction. + * @returns {JXG.Turtle} pointer to the turtle object */ - makeTicksFunction: function (ticks) { - return function () { - var delta, b, dist; - - if (Type.evaluate(this.visProp.insertticks)) { - b = this.getLowerAndUpperBounds(this.getZeroCoordinates(), 'ticksdistance'); - dist = b.upper - b.lower; + clearScreen: function () { + var i, el, + len = this.objects.length; - delta = Math.pow(10, Math.floor(Math.log(0.6 * dist) / Math.LN10)); - if (dist <= 6 * delta) { - delta *= 0.5; - } - return delta; - } + for (i = 0; i < len; i++) { + el = this.objects[i]; + this.board.removeObject(el); + } - // upto 0.99.1: - return ticks; - }; + this.init(0, 0, 90); + return this; }, /** - * Checks whether (x,y) is near the line. - * Only available for line elements, not for ticks on curves. - * @param {Number} x Coordinate in x direction, screen coordinates. - * @param {Number} y Coordinate in y direction, screen coordinates. - * @returns {Boolean} True if (x,y) is near the line, False otherwise. + * Moves the turtle without drawing to a new position + * @param {Number} x new x- coordinate + * @param {Number} y new y- coordinate + * @returns {JXG.Turtle} pointer to the turtle object */ - hasPoint: function (x, y) { - var i, t, - len = (this.ticks && this.ticks.length) || 0, - r, type; + setPos: function (x, y) { + var t; - if (Type.isObject(Type.evaluate(this.visProp.precision))) { - type = this.board._inputDevice; - r = Type.evaluate(this.visProp.precision[type]); + if (Type.isArray(x)) { + this.pos = x; } else { - // 'inherit' - r = this.board.options.precision.hasPoint; - } - r += Type.evaluate(this.visProp.strokewidth) * 0.5; - if (!Type.evaluate(this.line.visProp.scalable) || - this.line.elementClass === Const.OBJECT_CLASS_CURVE) { - return false; - } - - // Ignore non-axes and axes that are not horizontal or vertical - if (this.line.stdform[1] !== 0 && this.line.stdform[2] !== 0 && this.line.type !== Const.OBJECT_TYPE_AXIS) { - return false; + this.pos = [x, y]; } - for (i = 0; i < len; i++) { - t = this.ticks[i]; - - // Skip minor ticks - if (t[2]) { - // Ignore ticks at zero - if (!((this.line.stdform[1] === 0 && Math.abs(t[0][0] - this.line.point1.coords.scrCoords[1]) < Mat.eps) || - (this.line.stdform[2] === 0 && Math.abs(t[1][0] - this.line.point1.coords.scrCoords[2]) < Mat.eps))) { - // tick length is not zero, ie. at least one pixel - if (Math.abs(t[0][0] - t[0][1]) >= 1 || Math.abs(t[1][0] - t[1][1]) >= 1) { - if (this.line.stdform[1] === 0) { - // Allow dragging near axes only. - if (Math.abs(y - (t[1][0] + t[1][1]) * 0.5) < 2 * r && t[0][0] - r < x && x < t[0][1] + r) { - return true; - } - } else if (this.line.stdform[2] === 0) { - if (Math.abs(x - (t[0][0] + t[0][1]) * 0.5) < 2 * r && t[1][0] - r < y && y < t[1][1] + r) { - return true; - } - } - } - } - } + if (!this.turtleIsHidden) { + this.turtle.setPositionDirectly(Const.COORDS_BY_USER, [x, y]); + this.turtle2.setPositionDirectly(Const.COORDS_BY_USER, [x, y + this.arrowLen]); + t = this.board.create('transform', [-(this.dir - 90) * Math.PI / 180, this.turtle], {type: 'rotate'}); + t.applyOnce(this.turtle2); } - return false; + this.curve = this.board.create('curve', [[this.pos[0]], [this.pos[1]]], this._attributes); + this.objects.push(this.curve); + this.board.update(); + + return this; }, /** - * Sets x and y coordinate of the tick. - * @param {number} method The type of coordinates used here. Possible values are {@link JXG.COORDS_BY_USER} and {@link JXG.COORDS_BY_SCREEN}. - * @param {Array} coords coordinates in screen/user units - * @param {Array} oldcoords previous coordinates in screen/user units - * @returns {JXG.Ticks} this element + * Sets the pen size. Equivalent to setAttribute({strokeWidth:size}) + * but affects only the future turtle. + * @param {Number} size + * @returns {JXG.Turtle} pointer to the turtle object */ - setPositionDirectly: function (method, coords, oldcoords) { - var dx, dy, - c = new Coords(method, coords, this.board), - oldc = new Coords(method, oldcoords, this.board), - bb = this.board.getBoundingBox(); + setPenSize: function (size) { + //this.visProp.strokewidth = size; + this.curve = this.board.create('curve', [[this.pos[0]], [this.pos[1]]], this.copyAttr('strokeWidth', size)); + this.objects.push(this.curve); + return this; + }, - if (this.line.type !== Const.OBJECT_TYPE_AXIS || - !Type.evaluate(this.line.visProp.scalable)) { + /** + * Sets the pen color. Equivalent to setAttribute({strokeColor:color}) + * but affects only the future turtle. + * @param {String} color + * @returns {JXG.Turtle} pointer to the turtle object + */ + setPenColor: function (color) { + this.curve = this.board.create('curve', [[this.pos[0]], [this.pos[1]]], this.copyAttr('strokeColor', color)); + this.objects.push(this.curve); - return this; - } + return this; + }, - // horizontal line - if (Math.abs(this.line.stdform[1]) < Mat.eps && - Math.abs(c.usrCoords[1] * oldc.usrCoords[1]) > Mat.eps) { + /** + * Sets the highlight pen color. Equivalent to setAttribute({highlightStrokeColor:color}) + * but affects only the future turtle. + * @param {String} color + * @returns {JXG.Turtle} pointer to the turtle object + */ + setHighlightPenColor: function (color) { + //this.visProp.highlightstrokecolor = colStr; + this.curve = this.board.create('curve', [[this.pos[0]], [this.pos[1]]], this.copyAttr('highlightStrokeColor', color)); + this.objects.push(this.curve); + return this; + }, - dx = oldc.usrCoords[1] / c.usrCoords[1]; - bb[0] *= dx; - bb[2] *= dx; - this.board.setBoundingBox(bb, false); - // vertical line - } else if (Math.abs(this.line.stdform[2]) < Mat.eps && - Math.abs(c.usrCoords[2] * oldc.usrCoords[2]) > Mat.eps) { + /** + * Sets properties of the turtle, see also {@link JXG.GeometryElement#setAttribute}. + * Sets the property for all curves of the turtle in the past and in the future. + * @param {Object} attributes key:value pairs + * @returns {JXG.Turtle} pointer to the turtle object + */ + setAttribute: function (attributes) { + var i, el, tmp, + len = this.objects.length; - dy = oldc.usrCoords[2] / c.usrCoords[2]; - bb[3] *= dy; - bb[1] *= dy; - this.board.setBoundingBox(bb, false); + for (i = 0; i < len; i++) { + el = this.objects[i]; + if (el.type === Const.OBJECT_TYPE_CURVE) { + el.setAttribute(attributes); + } } + // Set visProp of turtle + tmp = this.visProp.id; + this.visProp = Type.deepCopy(this.curve.visProp); + this.visProp.id = tmp; + this._attributes = Type.deepCopy(this.visProp); + delete this._attributes.id; + return this; }, /** - * (Re-)calculates the ticks coordinates. + * Set a future attribute of the turtle. * @private + * @param {String} key + * @param {Number|String} val + * @returns {Object} pointer to the attributes object */ - calculateTicksCoordinates: function () { - var coordsZero, bounds, - r_max, bb; - - if (this.line.elementClass === Const.OBJECT_CLASS_LINE) { - // Calculate Ticks width and height in Screen and User Coordinates - this.setTicksSizeVariables(); + copyAttr: function (key, val) { + this._attributes[key.toLowerCase()] = val; + return this._attributes; + }, - // If the parent line is not finite, we can stop here. - if (Math.abs(this.dx) < Mat.eps && - Math.abs(this.dy) < Mat.eps) { - return; - } - } + /** + * Sets the visibility of the turtle head to true, + * @returns {JXG.Turtle} pointer to the turtle object + */ + showTurtle: function () { + this.turtleIsHidden = false; + this.arrow.setAttribute({visible: true}); + this.visProp.arrow.visible = false; + this.setPos(this.pos[0], this.pos[1]); + this.board.update(); - // Get Zero (coords element for lines , number for curves) - coordsZero = this.getZeroCoordinates(); + return this; + }, - // Calculate lower bound and upper bound limits based on distance - // between p1 and center and p2 and center - if (this.line.elementClass === Const.OBJECT_CLASS_LINE) { - bounds = this.getLowerAndUpperBounds(coordsZero); - } else { - bounds = { - lower: this.line.minX(), - upper: this.line.maxX() - }; - } + /** + * Sets the visibility of the turtle head to false, + * @returns {JXG.Turtle} pointer to the turtle object + */ + hideTurtle: function () { + this.turtleIsHidden = true; + this.arrow.setAttribute({visible: false}); + this.visProp.arrow.visible = false; + this.board.update(); - if (Type.evaluate(this.visProp.type) === 'polar') { - bb = this.board.getBoundingBox(); - r_max = Math.max(Math.sqrt(bb[0] * bb[0] + bb[1] * bb[1]), - Math.sqrt(bb[2] * bb[2] + bb[3] * bb[3])); - bounds.upper = r_max; - } + return this; + }, - // Clean up - this.ticks = []; - this.labelsData = []; - // Create Ticks Coordinates and Labels - if (this.equidistant) { - this.generateEquidistantTicks(coordsZero, bounds); - } else { - this.generateFixedTicks(coordsZero, bounds); - } + /** + * Moves the turtle to position [0,0]. + * @returns {JXG.Turtle} pointer to the turtle object + */ + home: function () { + this.pos = [0, 0]; + this.setPos(this.pos[0], this.pos[1]); return this; }, /** - * Sets the variables used to set the height and slope of each tick. - * - * @private + * Pushes the position of the turtle on the stack. + * @returns {JXG.Turtle} pointer to the turtle object */ - setTicksSizeVariables: function (pos) { - var d, mi, ma, len, - distMaj = Type.evaluate(this.visProp.majorheight) * 0.5, - distMin = Type.evaluate(this.visProp.minorheight) * 0.5; - - // For curves: - if (Type.exists(pos)) { - mi = this.line.minX(); - ma = this.line.maxX(); - len = this.line.points.length; - if (len < 2) { - this.dxMaj = 0; - this.dyMaj = 0; - } else if (Mat.relDif(pos, mi) < Mat.eps) { - this.dxMaj = this.line.points[0].usrCoords[2] - this.line.points[1].usrCoords[2]; - this.dyMaj = this.line.points[1].usrCoords[1] - this.line.points[0].usrCoords[1]; - } else if (Mat.relDif(pos, ma) < Mat.eps) { - this.dxMaj = this.line.points[len - 2].usrCoords[2] - this.line.points[len - 1].usrCoords[2]; - this.dyMaj = this.line.points[len - 1].usrCoords[1] - this.line.points[len - 2].usrCoords[1]; - } else { - this.dxMaj = -Numerics.D(this.line.Y)(pos); - this.dyMaj = Numerics.D(this.line.X)(pos); - } - } else { - // ticks width and height in screen units - this.dxMaj = this.line.stdform[1]; - this.dyMaj = this.line.stdform[2]; - } - this.dxMin = this.dxMaj; - this.dyMin = this.dyMaj; + pushTurtle: function () { + this.stack.push([this.pos[0], this.pos[1], this.dir]); - // ticks width and height in user units - this.dx = this.dxMaj; - this.dy = this.dyMaj; + return this; + }, - // After this, the length of the vector (dxMaj, dyMaj) in screen coordinates is equal to distMaj pixel. - d = Math.sqrt( - this.dxMaj * this.dxMaj * this.board.unitX * this.board.unitX + - this.dyMaj * this.dyMaj * this.board.unitY * this.board.unitY - ); - this.dxMaj *= distMaj / d * this.board.unitX; - this.dyMaj *= distMaj / d * this.board.unitY; - this.dxMin *= distMin / d * this.board.unitX; - this.dyMin *= distMin / d * this.board.unitY; + /** + * Gets the last position of the turtle on the stack, sets the turtle to this position and removes this + * position from the stack. + * @returns {JXG.Turtle} pointer to the turtle object + */ + popTurtle: function () { + var status = this.stack.pop(); + this.pos[0] = status[0]; + this.pos[1] = status[1]; + this.dir = status[2]; + this.setPos(this.pos[0], this.pos[1]); - // Grid-like ticks? - this.minStyle= (Type.evaluate(this.visProp.minorheight) < 0) ? 'infinite' : 'finite'; - this.majStyle= (Type.evaluate(this.visProp.majorheight) < 0) ? 'infinite' : 'finite'; + return this; }, /** - * Returns the coordinates of the point zero of the line. - * - * If the line is an {@link Axis}, the coordinates of the projection of the board's zero point is returned - * - * Otherwise, the coordinates of the point that acts as zero are - * established depending on the value of {@link JXG.Ticks#anchor} - * - * @returns {JXG.Coords} Coords object for the zero point on the line - * @private + * Rotates the turtle into a new direction. + * There are two possibilities: + * @param {Number|Array} target If a number is given, it is interpreted as the new direction to look to; If an array + * consisting of two Numbers is given targeted is used as a pair coordinates. + * @returns {JXG.Turtle} pointer to the turtle object */ - getZeroCoordinates: function () { - var c1x, c1y, c1z, c2x, c2y, c2z, t, mi, ma, - ev_a = Type.evaluate(this.visProp.anchor); + lookTo: function (target) { + var ax, ay, bx, by, beta; - if (this.line.elementClass === Const.OBJECT_CLASS_LINE) { - if (this.line.type === Const.OBJECT_TYPE_AXIS) { - return Geometry.projectPointToLine({ - coords: { - usrCoords: [1, 0, 0] - } - }, this.line, this.board); - } - c1z = this.line.point1.coords.usrCoords[0]; - c1x = this.line.point1.coords.usrCoords[1]; - c1y = this.line.point1.coords.usrCoords[2]; - c2z = this.line.point2.coords.usrCoords[0]; - c2x = this.line.point2.coords.usrCoords[1]; - c2y = this.line.point2.coords.usrCoords[2]; + if (Type.isArray(target)) { + ax = this.pos[0]; + ay = this.pos[1]; + bx = target[0]; + by = target[1]; - if (ev_a === 'right') { - return this.line.point2.coords; - } - if (ev_a === 'middle') { - return new Coords(Const.COORDS_BY_USER, [ - (c1z + c2z) * 0.5, - (c1x + c2x) * 0.5, - (c1y + c2y) * 0.5 - ], this.board); - } - if (Type.isNumber(ev_a)) { - return new Coords(Const.COORDS_BY_USER, [ - c1z + (c2z - c1z) * ev_a, - c1x + (c2x - c1x) * ev_a, - c1y + (c2y - c1y) * ev_a - ], this.board); - } - return this.line.point1.coords; - } - mi = this.line.minX(); - ma = this.line.maxX(); - if (ev_a === 'right') { - t = ma; - } else if (ev_a === 'middle') { - t = (mi + ma) * 0.5; - } else if (Type.isNumber(ev_a)) { - t = mi * (1 - ev_a) + ma * ev_a; - // t = ev_a; - } else { - t = mi; + // Rotate by the slope of the line [this.pos, target] + beta = Math.atan2(by - ay, bx - ax); + this.right(this.dir - (beta * 180 / Math.PI)); + } else if (Type.isNumber(target)) { + this.right(this.dir - target); } - return t; + return this; }, /** - * Calculate the lower and upper bounds for tick rendering - * If {@link JXG.Ticks#includeBoundaries} is false, the boundaries will exclude point1 and point2 - * - * @param {JXG.Coords} coordsZero - * @returns {String} type (Optional) If type=='ticksdistance' the bounds are - * the intersection of the line with the bounding box of the board. - * Otherwise, it is the projection of the corners of the bounding box - * to the line. The first case is needed to automatically - * generate ticks. The second case is for drawing of the ticks. - * @returns {Object} contains the lower and upper bounds - * - * @private + * Moves the turtle to a given coordinate pair. + * The direction is not changed. + * @param {Array} target Coordinates of the point where the turtle looks to. + * @returns {JXG.Turtle} pointer to the turtle object */ - getLowerAndUpperBounds: function (coordsZero, type) { - var lowerBound, upperBound, - fA, lA, - point1, point2, isPoint1inBoard, isPoint2inBoard, - // We use the distance from zero to P1 and P2 to establish lower and higher points - dZeroPoint1, dZeroPoint2, - ev_sf = Type.evaluate(this.line.visProp.straightfirst), - ev_sl = Type.evaluate(this.line.visProp.straightlast), - ev_i = Type.evaluate(this.visProp.includeboundaries); - - // The line's defining points that will be adjusted to be within the board limits - if (this.line.elementClass === Const.OBJECT_CLASS_CURVE) { - return { - lower: this.line.minX(), - upper: this.line.maxX() - }; - } - - point1 = new Coords(Const.COORDS_BY_USER, this.line.point1.coords.usrCoords, this.board); - point2 = new Coords(Const.COORDS_BY_USER, this.line.point2.coords.usrCoords, this.board); - // Are the original defining points within the board? - isPoint1inBoard = (Math.abs(point1.usrCoords[0]) >= Mat.eps && - point1.scrCoords[1] >= 0.0 && point1.scrCoords[1] <= this.board.canvasWidth && - point1.scrCoords[2] >= 0.0 && point1.scrCoords[2] <= this.board.canvasHeight); - isPoint2inBoard = (Math.abs(point2.usrCoords[0]) >= Mat.eps && - point2.scrCoords[1] >= 0.0 && point2.scrCoords[1] <= this.board.canvasWidth && - point2.scrCoords[2] >= 0.0 && point2.scrCoords[2] <= this.board.canvasHeight); - - // Adjust line limit points to be within the board - if (Type.exists(type) || type === 'tickdistance') { - // The good old calcStraight is needed for determining the distance between major ticks. - // Here, only the visual area is of importance - Geometry.calcStraight(this.line, point1, point2, Type.evaluate(this.line.visProp.margin)); - } else { - // This function projects the corners of the board to the line. - // This is important for diagonal lines with infinite tick lines. - Geometry.calcLineDelimitingPoints(this.line, point1, point2); - } + moveTo: function (target) { + var dx, dy, t; - // Shorten ticks bounds such that ticks are not through arrow heads - fA = Type.evaluate(this.line.visProp.firstarrow); - lA = Type.evaluate(this.line.visProp.lastarrow); - if (fA || lA) { - this.board.renderer.getPositionArrowHead(this.line, point1, point2, - Type.evaluate(this.line.visProp.strokewidth)); + if (Type.isArray(target)) { + dx = target[0] - this.pos[0]; + dy = target[1] - this.pos[1]; - if (fA) { - point1.setCoordinates(Const.COORDS_BY_SCREEN, [ - point1.scrCoords[1], - point1.scrCoords[2] - ]); - } - if (lA) { - point2.setCoordinates(Const.COORDS_BY_SCREEN, [ - point2.scrCoords[1], - point2.scrCoords[2] - ]); + if (!this.turtleIsHidden) { + t = this.board.create('transform', [dx, dy], {type: 'translate'}); + t.applyOnce(this.turtle); + t.applyOnce(this.turtle2); } - // if (fA) { - // point1.setCoordinates(Const.COORDS_BY_SCREEN, [ - // point1.scrCoords[1] - obj.d1x, - // point1.scrCoords[2] - obj.d1y - // ]); - // } - // if (lA) { - // point2.setCoordinates(Const.COORDS_BY_SCREEN, [ - // point2.scrCoords[1] - obj.d2x, - // point2.scrCoords[2] - obj.d2y - // ]); - // } - } + if (this.isPenDown) { + // IE workaround + if (this.curve.dataX.length >= 8192) { + this.curve = this.board.create('curve', [[this.pos[0]], [this.pos[1]]], this._attributes); + this.objects.push(this.curve); + } + } - // Calculate (signed) distance from Zero to P1 and to P2 - dZeroPoint1 = this.getDistanceFromZero(coordsZero, point1); - dZeroPoint2 = this.getDistanceFromZero(coordsZero, point2); + this.pos[0] = target[0]; + this.pos[1] = target[1]; - // We have to establish if the direction is P1->P2 or P2->P1 to set the lower and upper - // boundaries appropriately. As the distances contain also a sign to indicate direction, - // we can compare dZeroPoint1 and dZeroPoint2 to establish the line direction - if (dZeroPoint1 < dZeroPoint2) { // Line goes P1->P2 - lowerBound = dZeroPoint1; - if (!ev_sf && isPoint1inBoard && !ev_i) { - lowerBound += Mat.eps; - } - upperBound = dZeroPoint2; - if (!ev_sl && isPoint2inBoard && !ev_i) { - upperBound -= Mat.eps; - } - } else if (dZeroPoint2 < dZeroPoint1) { // Line goes P2->P1 - lowerBound = dZeroPoint2; - if (!ev_sl && isPoint2inBoard && !ev_i) { - lowerBound += Mat.eps; - } - upperBound = dZeroPoint1; - if (!ev_sf && isPoint1inBoard && !ev_i) { - upperBound -= Mat.eps; + if (this.isPenDown) { + this.curve.dataX.push(this.pos[0]); + this.curve.dataY.push(this.pos[1]); } - } else { // P1 = P2 = Zero, we can't do a thing - lowerBound = 0; - upperBound = 0; + this.board.update(); } - return { - lower: lowerBound, - upper: upperBound - }; + return this; }, /** - * Calculates the distance in user coordinates from zero to a given point including its sign. - * Sign is positive, if the direction from zero to point is the same as the direction - * zero to point2 of the line. - * - * @param {JXG.Coords} zero coordinates of the point considered zero - * @param {JXG.Coords} point coordinates of the point to find out the distance - * @returns {Number} distance between zero and point, including its sign - * @private + * Alias for {@link JXG.Turtle#forward} */ - getDistanceFromZero: function (zero, point) { - var p1, p2, - dirLine, dirPoint, - distance; - - p1 = this.line.point1.coords; - p2 = this.line.point2.coords; - distance = zero.distance(Const.COORDS_BY_USER, point); - - // Establish sign - dirLine = [p2.usrCoords[0] - p1.usrCoords[0], - p2.usrCoords[1] - p1.usrCoords[1], - p2.usrCoords[2] - p1.usrCoords[2]]; - dirPoint = [point.usrCoords[0] - zero.usrCoords[0], - point.usrCoords[1] - zero.usrCoords[1], - point.usrCoords[2] - zero.usrCoords[2]]; - if (Mat.innerProduct(dirLine, dirPoint, 3) < 0) { - distance *= -1; - } - - return distance; - }, + fd: function (len) { return this.forward(len); }, + /** + * Alias for {@link JXG.Turtle#back} + */ + bk: function (len) { return this.back(len); }, + /** + * Alias for {@link JXG.Turtle#left} + */ + lt: function (angle) { return this.left(angle); }, + /** + * Alias for {@link JXG.Turtle#right} + */ + rt: function (angle) { return this.right(angle); }, + /** + * Alias for {@link JXG.Turtle#penUp} + */ + pu: function () { return this.penUp(); }, + /** + * Alias for {@link JXG.Turtle#penDown} + */ + pd: function () { return this.penDown(); }, + /** + * Alias for {@link JXG.Turtle#hideTurtle} + */ + ht: function () { return this.hideTurtle(); }, + /** + * Alias for {@link JXG.Turtle#showTurtle} + */ + st: function () { return this.showTurtle(); }, + /** + * Alias for {@link JXG.Turtle#clearScreen} + */ + cs: function () { return this.clearScreen(); }, + /** + * Alias for {@link JXG.Turtle#pushTurtle} + */ + push: function () { return this.pushTurtle(); }, + /** + * Alias for {@link JXG.Turtle#popTurtle} + */ + pop: function () { return this.popTurtle(); }, /** - * Creates ticks coordinates and labels automatically. - * The frequency of ticks is affected by the values of {@link JXG.Ticks#insertTicks} and {@link JXG.Ticks#ticksDistance} + * The "co"-coordinate of the turtle curve at position t is returned. * - * @param {JXG.Coords} coordsZero coordinates of the point considered zero - * @param {Object} bounds contains the lower and upper boundaries for ticks placement - * @private + * @param {Number} t parameter + * @param {String} co. Either 'X' or 'Y'. + * @returns {Number} x-coordinate of the turtle position or x-coordinate of turtle at position t */ - generateEquidistantTicks: function (coordsZero, bounds) { - var tickPosition, - eps2 = Mat.eps, - deltas, - // Distance between two major ticks in user coordinates - ticksDelta = (this.equidistant ? this.ticksFunction(1) : this.ticksDelta), - ev_it = Type.evaluate(this.visProp.insertticks), - ev_mt = Type.evaluate(this.visProp.minorticks); - - if (this.line.elementClass === Const.OBJECT_CLASS_LINE) { - // Calculate X and Y distance between two major ticks - deltas = this.getXandYdeltas(); - } - - // adjust ticks distance - ticksDelta *= Type.evaluate(this.visProp.scale); - if (ev_it && this.minTicksDistance > Mat.eps) { - ticksDelta = this.adjustTickDistance(ticksDelta, coordsZero, deltas); - ticksDelta /= (ev_mt + 1); - } else if (!ev_it) { - ticksDelta /= (ev_mt + 1); - } - this.ticksDelta = ticksDelta; + evalAt: function (t, co) { + var i, j, el, tc, + len = this.objects.length; - if (ticksDelta < Mat.eps) { - return; - } + for (i = 0, j = 0; i < len; i++) { + el = this.objects[i]; - // Position ticks from zero to the positive side while not reaching the upper boundary - tickPosition = 0; - if (!Type.evaluate(this.visProp.drawzero)) { - tickPosition = ticksDelta; - } - while (tickPosition <= bounds.upper + eps2) { - // Only draw ticks when we are within bounds, ignore case where tickPosition < lower < upper - if (tickPosition >= bounds.lower - eps2) { - this.processTickPosition(coordsZero, tickPosition, ticksDelta, deltas); + if (el.elementClass === Const.OBJECT_CLASS_CURVE) { + if (j <= t && t < j + el.numberPoints) { + tc = (t - j); + return el[co](tc); + } + j += el.numberPoints; } - tickPosition += ticksDelta; } - // Position ticks from zero (not inclusive) to the negative side while not reaching the lower boundary - tickPosition = -ticksDelta; - while (tickPosition >= bounds.lower - eps2) { - // Only draw ticks when we are within bounds, ignore case where lower < upper < tickPosition - if (tickPosition <= bounds.upper + eps2) { - this.processTickPosition(coordsZero, tickPosition, ticksDelta, deltas); - } - tickPosition -= ticksDelta; - } + return this[co](); }, /** - * Auxiliary method used by {@link JXG.Ticks#generateEquidistantTicks} to adjust the - * distance between two ticks depending on {@link JXG.Ticks#minTicksDistance} value - * - * @param {Number} ticksDelta distance between two major ticks in user coordinates - * @param {JXG.Coords} coordsZero coordinates of the point considered zero - * @param {Object} deltas x and y distance in pixel between two user units - * @param {Object} bounds upper and lower bound of the tick positions in user units. - * @private + * if t is not supplied the x-coordinate of the turtle is returned. Otherwise + * the x-coordinate of the turtle curve at position t is returned. + * @param {Number} t parameter + * @returns {Number} x-coordinate of the turtle position or x-coordinate of turtle at position t */ - adjustTickDistance: function (ticksDelta, coordsZero, deltas) { - var nx, ny, bounds, - distScr, - sgn = 1, - ev_minti = Type.evaluate(this.visProp.minorticks); - - if (this.line.elementClass === Const.OBJECT_CLASS_CURVE) { - return ticksDelta; - } - bounds = this.getLowerAndUpperBounds(coordsZero, 'ticksdistance'); - nx = coordsZero.usrCoords[1] + deltas.x * ticksDelta; - ny = coordsZero.usrCoords[2] + deltas.y * ticksDelta; - distScr = coordsZero.distance(Const.COORDS_BY_SCREEN, new Coords(Const.COORDS_BY_USER, [nx, ny], this.board)); - - if (ticksDelta === 0.0) { - return 0.0; + X: function (t) { + if (!Type.exists(t)) { + return this.pos[0]; } - while (distScr / (ev_minti + 1) < this.minTicksDistance) { - if (sgn === 1) { - ticksDelta *= 2; - } else { - ticksDelta *= 5; - } - sgn *= -1; + return this.evalAt(t, 'X'); + }, - nx = coordsZero.usrCoords[1] + deltas.x * ticksDelta; - ny = coordsZero.usrCoords[2] + deltas.y * ticksDelta; - distScr = coordsZero.distance(Const.COORDS_BY_SCREEN, new Coords(Const.COORDS_BY_USER, [nx, ny], this.board)); + /** + * if t is not supplied the y-coordinate of the turtle is returned. Otherwise + * the y-coordinate of the turtle curve at position t is returned. + * @param {Number} t parameter + * @returns {Number} x-coordinate of the turtle position or x-coordinate of turtle at position t + */ + Y: function (t) { + if (!Type.exists(t)) { + return this.pos[1]; } - return ticksDelta; + return this.evalAt(t, 'Y'); }, /** - * Auxiliary method used by {@link JXG.Ticks#generateEquidistantTicks} to create a tick - * in the line at the given tickPosition. - * - * @param {JXG.Coords} coordsZero coordinates of the point considered zero - * @param {Number} tickPosition current tick position relative to zero - * @param {Number} ticksDelta distance between two major ticks in user coordinates - * @param {Object} deltas x and y distance between two major ticks - * @private + * @returns {Number} z-coordinate of the turtle position */ - processTickPosition: function (coordsZero, tickPosition, ticksDelta, deltas) { - var x, y, tickCoords, ti, - labelVal = null; - - // Calculates tick coordinates - if (this.line.elementClass === Const.OBJECT_CLASS_LINE) { - x = coordsZero.usrCoords[1] + tickPosition * deltas.x; - y = coordsZero.usrCoords[2] + tickPosition * deltas.y; - } else { - x = this.line.X(coordsZero + tickPosition); - y = this.line.Y(coordsZero + tickPosition); - } - tickCoords = new Coords(Const.COORDS_BY_USER, [x, y], this.board); - if (this.line.elementClass === Const.OBJECT_CLASS_CURVE) { - labelVal = coordsZero + tickPosition; - this.setTicksSizeVariables(labelVal); + Z: function (t) { + return 1.0; + }, - } + /** + * Gives the lower bound of the parameter if the the turtle is treated as parametric curve. + */ + minX: function () { + return 0; + }, - // Test if tick is a major tick. - // This is the case if tickPosition/ticksDelta is - // a multiple of the number of minorticks+1 - tickCoords.major = Math.round(tickPosition / ticksDelta) % (Type.evaluate(this.visProp.minorticks) + 1) === 0; + /** + * Gives the upper bound of the parameter if the the turtle is treated as parametric curve. + * May be overwritten in @see generateTerm. + */ + maxX: function () { + var i, el, + len = this.objects.length, + np = 0; - // Compute the start position and the end position of a tick. - // If both positions are out of the canvas, ti is empty. - ti = this.createTickPath(tickCoords, tickCoords.major); - if (ti.length === 3) { - this.ticks.push(ti); - if (tickCoords.major && Type.evaluate(this.visProp.drawlabels)) { - // major tick label - this.labelsData.push( - this.generateLabelData( - this.generateLabelText(tickCoords, coordsZero, labelVal), - tickCoords, - this.ticks.length - ) - ); - } else { - // minor ticks have no labels - this.labelsData.push(null); + for (i = 0; i < len; i++) { + el = this.objects[i]; + if (el.elementClass === Const.OBJECT_CLASS_CURVE) { + np += this.objects[i].numberPoints; } } + return np; }, /** - * Creates ticks coordinates and labels based on {@link JXG.Ticks#fixedTicks} and {@link JXG.Ticks#labels}. - * - * @param {JXG.Coords} coordsZero Coordinates of the point considered zero - * @param {Object} bounds contains the lower and upper boundaries for ticks placement - * @private + * Checks whether (x,y) is near the curve. + * @param {Number} x Coordinate in x direction, screen coordinates. + * @param {Number} y Coordinate in y direction, screen coordinates. + * @returns {Boolean} True if (x,y) is near the curve, False otherwise. */ - generateFixedTicks: function (coordsZero, bounds) { - var tickCoords, labelText, i, ti, - x, y, - eps2 = Mat.eps, fixedTick, - hasLabelOverrides = Type.isArray(this.visProp.labels), - deltas, - ev_dl = Type.evaluate(this.visProp.drawlabels); - - // Calculate X and Y distance between two major points in the line - if (this.line.elementClass === Const.OBJECT_CLASS_LINE) { - deltas = this.getXandYdeltas(); - } - for (i = 0; i < this.fixedTicks.length; i++) { - if (this.line.elementClass === Const.OBJECT_CLASS_LINE) { - fixedTick = this.fixedTicks[i]; - x = coordsZero.usrCoords[1] + fixedTick * deltas.x; - y = coordsZero.usrCoords[2] + fixedTick * deltas.y; - } else { - fixedTick = coordsZero + this.fixedTicks[i]; - x = this.line.X(fixedTick); - y = this.line.Y(fixedTick); - } - tickCoords = new Coords(Const.COORDS_BY_USER, [x, y], this.board); - - if (this.line.elementClass === Const.OBJECT_CLASS_CURVE) { - this.setTicksSizeVariables(fixedTick); - } + hasPoint: function (x, y) { + var i, el; - // Compute the start position and the end position of a tick. - // If tick is out of the canvas, ti is empty. - ti = this.createTickPath(tickCoords, true); - if (ti.length === 3 && fixedTick >= bounds.lower - eps2 && - fixedTick <= bounds.upper + eps2) { - this.ticks.push(ti); + // run through all curves of this turtle + for (i = 0; i < this.objects.length; i++) { + el = this.objects[i]; - if (ev_dl && - (hasLabelOverrides || Type.exists(this.visProp.labels[i]))) { - labelText = hasLabelOverrides ? - Type.evaluate(this.visProp.labels[i]) : fixedTick; - this.labelsData.push( - this.generateLabelData( - this.generateLabelText(tickCoords, coordsZero, labelText), - tickCoords, - i - ) - ); - } else { - this.labelsData.push(null); + if (el.type === Const.OBJECT_TYPE_CURVE) { + if (el.hasPoint(x, y)) { + // So what??? All other curves have to be notified now (for highlighting) + return true; + // This has to be done, yet. } } } - }, + return false; + } + }); - /** - * Calculates the x and y distance in pixel between two units in user space. - * - * @returns {Object} - * @private - */ - getXandYdeltas: function () { - var - // Auxiliary points to store the start and end of the line according to its direction - point1UsrCoords, point2UsrCoords, - distP1P2 = this.line.point1.Dist(this.line.point2); + /** + * @class This element is used to provide a constructor for a turtle. + * @pseudo + * @description Creates a new turtle + * @name Turtle + * @augments JXG.Turtle + * @constructor + * @type JXG.Turtle + * + * @param {JXG.Board} board The board the turtle is put on. + * @param {Array} parents + * @param {Object} attributes Object containing properties for the element such as stroke-color and visibility. See {@link JXG.GeometryElement#setAttribute} + * @returns {JXG.Turtle} Reference to the created turtle object. + */ + JXG.createTurtle = function (board, parents, attributes) { + var attr; + parents = parents || []; - if (this.line.type === Const.OBJECT_TYPE_AXIS) { - // When line is an Axis, direction depends on Board Coordinates system + attr = Type.copyAttributes(attributes, board.options, 'turtle'); + return new JXG.Turtle(board, parents, attr); + }; - // assume line.point1 and line.point2 are in correct order - point1UsrCoords = this.line.point1.coords.usrCoords; - point2UsrCoords = this.line.point2.coords.usrCoords; + JXG.registerElement('turtle', JXG.createTurtle); - // Check if direction is incorrect, then swap - if (point1UsrCoords[1] > point2UsrCoords[1] || - (Math.abs(point1UsrCoords[1] - point2UsrCoords[1]) < Mat.eps && - point1UsrCoords[2] > point2UsrCoords[2])) { - point1UsrCoords = this.line.point2.coords.usrCoords; - point2UsrCoords = this.line.point1.coords.usrCoords; - } - } else /* if (this.line.elementClass === Const.OBJECT_CLASS_LINE)*/ { - // line direction is always from P1 to P2 for non Axis types - point1UsrCoords = this.line.point1.coords.usrCoords; - point2UsrCoords = this.line.point2.coords.usrCoords; - } - return { - x: (point2UsrCoords[1] - point1UsrCoords[1]) / distP1P2, - y: (point2UsrCoords[2] - point1UsrCoords[2]) / distP1P2 - }; - }, + return { + Turtle: JXG.Turtle, + createTurtle: JXG.createTurtle + }; +}); - /** - * Check if (parts of) the tick is inside the canvas. The tick intersects the boundary - * at two positions: [x[0], y[0]] and [x[1], y[1]] in screen coordinates. - * @param {Array} x Array of length two - * @param {Array} y Array of length two - * @return {Boolean} true if parts of the tick are inside of the canvas or on the boundary. - */ - _isInsideCanvas: function(x, y, m) { - var cw = this.board.canvasWidth, - ch = this.board.canvasHeight; +/* + Copyright 2008-2022 + Matthias Ehmann, + Michael Gerhaeuser, + Carsten Miller, + Bianca Valentin, + Alfred Wassermann, + Peter Wilfahrt - if (m === undefined) { - m = 0; - } - return (x[0] >= m && x[0] <= cw - m && y[0] >= m && y[0] <= ch - m) || - (x[1] >= m && x[1] <= cw - m && y[1] >= m && y[1] <= ch - m); - }, + This file is part of JSXGraph. - /** - * @param {JXG.Coords} coords Coordinates of the tick on the line. - * @param {Boolean} major True if tick is major tick. - * @returns {Array} Array of length 3 containing path coordinates in screen coordinates - * of the tick (arrays of length 2). 3rd entry is true if major tick otherwise false. - * If the tick is outside of the canvas, the return array is empty. - * @private - */ - createTickPath: function (coords, major) { - var c, lineStdForm, intersection, - dxs, dys, dxr, dyr, alpha, - style, - x = [-2000000, -2000000], - y = [-2000000, -2000000], - i, r, r_max, bb, full, delta; + JSXGraph is free software dual licensed under the GNU LGPL or MIT License. - c = coords.scrCoords; - if (major) { - dxs = this.dxMaj; - dys = this.dyMaj; - style = this.majStyle; - } else { - dxs = this.dxMin; - dys = this.dyMin; - style = this.minStyle; - } - lineStdForm = [-dys * c[1] - dxs * c[2], dys, dxs]; + You can redistribute it and/or modify it under the terms of the - // For all ticks regardless if of finite or infinite - // tick length the intersection with the canvas border is - // computed. - if (major && Type.evaluate(this.visProp.type) === 'polar') { - // polar style - bb = this.board.getBoundingBox(); - full = 2.0 * Math.PI; - delta = full / 180; - //ratio = this.board.unitY / this.board.X; + * GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version + OR + * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT - // usrCoords: Test if 'circle' is inside of the canvas - c = coords.usrCoords; - r = Math.sqrt(c[1] * c[1] + c[2] * c[2]); - r_max = Math.max(Math.sqrt(bb[0] * bb[0] + bb[1] * bb[1]), - Math.sqrt(bb[2] * bb[2] + bb[3] * bb[3])); + JSXGraph is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. - if (r < r_max) { - // Now, switch to screen coords - x = []; - y = []; - for (i = 0; i <= full; i += delta) { - x.push(this.board.origin.scrCoords[1] + r * Math.cos(i) * this.board.unitX); - y.push(this.board.origin.scrCoords[2] + r * Math.sin(i) * this.board.unitY); - } - return [x, y, major]; - } + You should have received a copy of the GNU Lesser General Public License and + the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> + and <http://opensource.org/licenses/MIT/>. + */ - } else { - // line style - if (style === 'infinite') { - intersection = Geometry.meetLineBoard(lineStdForm, this.board); - x[0] = intersection[0].scrCoords[1]; - x[1] = intersection[1].scrCoords[1]; - y[0] = intersection[0].scrCoords[2]; - y[1] = intersection[1].scrCoords[2]; - } else { - if (Type.evaluate(this.visProp.face) === '>') { - alpha = Math.PI/4; - } else if (Type.evaluate(this.visProp.face) === '<') { - alpha = -Math.PI/4; - } else { - alpha = 0; - } - dxr = Math.cos(alpha) * dxs - Math.sin(alpha) * dys; - dyr = Math.sin(alpha) * dxs + Math.cos(alpha) * dys; - x[0] = c[1] + dxr * Type.evaluate(this.visProp.tickendings[0]); - y[0] = c[2] - dyr * Type.evaluate(this.visProp.tickendings[0]); - x[1] = c[1]; - y[1] = c[2]; +/*global JXG: true, define: true*/ +/*jslint nomen: true, plusplus: true*/ - alpha = -alpha; - dxr = Math.cos(alpha) * dxs - Math.sin(alpha) * dys; - dyr = Math.sin(alpha) * dxs + Math.cos(alpha) * dys; +/* depends: + jxg + math/math + math/geometry + base/constants + base/element + base/coords + utils/type + elements: + text + */ - x[2] = c[1] - dxr * Type.evaluate(this.visProp.tickendings[1]); - y[2] = c[2] + dyr * Type.evaluate(this.visProp.tickendings[1]); - } +/** + * @fileoverview In this file the geometry object Ticks is defined. Ticks provides + * methods for creation and management of ticks on an axis. + * @author graphjs + * @version 0.1 + */ - // Check if (parts of) the tick is inside the canvas. - if (this._isInsideCanvas(x, y)) { - return [x, y, major]; - } - } +define('base/ticks',[ + 'jxg', 'math/math', 'math/geometry', 'math/numerics', 'base/constants', 'base/element', 'base/coords', 'utils/type', 'base/text' +], function (JXG, Mat, Geometry, Numerics, Const, GeometryElement, Coords, Type, Text) { - return []; - }, + "use strict"; + + /** + * Creates ticks for an axis. + * @class Ticks provides methods for creation and management + * of ticks on an axis. + * @param {JXG.Line} line Reference to the axis the ticks are drawn on. + * @param {Number|Array} ticks Number defining the distance between two major ticks or an array defining static ticks. + * @param {Object} attributes Properties + * @see JXG.Line#addTicks + * @constructor + * @extends JXG.GeometryElement + */ + JXG.Ticks = function (line, ticks, attributes) { + this.constructor(line.board, attributes, Const.OBJECT_TYPE_TICKS, Const.OBJECT_CLASS_OTHER); /** - * Format label texts. Show the desired number of digits - * and use utf-8 minus sign. - * @param {Number} value Number to be displayed - * @return {String} The value converted into a string. - * @private + * The line the ticks belong to. + * @type JXG.Line */ - formatLabelText: function(value) { - var labelText = value.toString(), - ev_s = Type.evaluate(this.visProp.scalesymbol); - - // if value is Number - if (Type.isNumber(value)) { - if (labelText.length > Type.evaluate(this.visProp.maxlabellength) || - labelText.indexOf('e') !== -1) { - labelText = value.toPrecision(Type.evaluate(this.visProp.precision)).toString(); - } - - if (Type.evaluate(this.visProp.beautifulscientificticklabels)) { - labelText = this.beautifyScientificNotationLabel(labelText); - } + this.line = line; - if (labelText.indexOf('.') > -1 && labelText.indexOf('e') === -1) { - // trim trailing zeros - labelText = labelText.replace(/0+$/, ''); - // trim trailing . - labelText = labelText.replace(/\.$/, ''); - } - } + /** + * The board the ticks line is drawn on. + * @type JXG.Board + */ + this.board = this.line.board; - if (ev_s.length > 0) { - if (labelText === '1') { - labelText = ev_s; - } else if (labelText === '-1') { - labelText = '-' + ev_s; - } else if (labelText !== '0') { - labelText = labelText + ev_s; - } - } + /** + * A function calculating ticks delta depending on the ticks number. + * @type Function + */ + this.ticksFunction = null; - if (Type.evaluate(this.visProp.useunicodeminus)) { - labelText = labelText.replace(/-/g, '\u2212'); - } - return labelText; - }, + /** + * Array of fixed ticks. + * @type Array + */ + this.fixedTicks = null; /** - * Formats label texts to make labels displayed in scientific notation look beautiful. - * For example, label 5.00e+6 will become 5•10⁶, label -1.00e-7 will become into -1•10⁻⁷ - * @param {String} labelText - The label that we want to convert - * @returns {String} If labelText was not in scientific notation, return labelText without modifications. - * Otherwise returns beautified labelText with proper superscript notation. + * Equidistant ticks. Distance is defined by ticksFunction + * @type Boolean */ - beautifyScientificNotationLabel: function(labelText) { - var returnString; + this.equidistant = false; - if (labelText.indexOf('e') === -1) { - return labelText; + this.labelsData = []; + + if (Type.isFunction(ticks)) { + this.ticksFunction = ticks; + throw new Error("Function arguments are no longer supported."); + } + + if (Type.isArray(ticks)) { + this.fixedTicks = ticks; + } else { + if (Math.abs(ticks) < Mat.eps || ticks < 0) { + ticks = attributes.defaultdistance; } - // Clean up trailing 0's, so numbers like 5.00e+6.0 for example become into 5e+6 - returnString = parseFloat(labelText.substring(0, labelText.indexOf('e'))) + - labelText.substring(labelText.indexOf('e')); + /* + * Ticks function: + * determines the distance (in user units) of two major ticks + */ + this.ticksFunction = this.makeTicksFunction(ticks); - // Replace symbols like -,0,1,2,3,4,5,6,7,8,9 with their superscript version. - // Gets rid of + symbol since there is no need for it anymore. - returnString = returnString.replace(/e(.*)$/g, function(match,$1){ - var temp = '\u2022' + '10'; - // Note: Since board ticks do not support HTTP elements like <sub>, we need to replace - // all the numbers with superscript Unicode characters. - temp += $1 - .replace(/-/g, "\u207B") - .replace(/\+/g, '') - .replace(/0/g,'\u2070') - .replace(/1/g,'\u00B9') - .replace(/2/g,'\u00B2') - .replace(/3/g,'\u00B3') - .replace(/4/g,'\u2074') - .replace(/5/g,'\u2075') - .replace(/6/g,'\u2076') - .replace(/7/g,'\u2077') - .replace(/8/g,'\u2078') - .replace(/9/g,'\u2079'); + this.equidistant = true; + } - return temp; - }); + /** + * Least distance between two ticks, measured in pixels. + * @type int + */ + this.minTicksDistance = attributes.minticksdistance; - return returnString; - }, + /** + * Stores the ticks coordinates + * @type Array + */ + this.ticks = []; /** - * Creates the label text for a given tick. A value for the text can be provided as a number or string - * - * @param {JXG.Coords} tick The Coords-object of the tick to create a label for - * @param {JXG.Coords} zero The Coords-object of line's zero - * @param {Number|String} value A predefined value for this tick - * @returns {String} - * @private + * Distance between two major ticks in user coordinates + * @type Number */ - generateLabelText: function (tick, zero, value) { - var labelText, distance; + this.ticksDelta = 1; - // No value provided, equidistant, so assign distance as value - if (!Type.exists(value)) { // could be null or undefined - distance = this.getDistanceFromZero(zero, tick); - if (Math.abs(distance) < Mat.eps) { // Point is zero - return '0'; - } - value = distance / Type.evaluate(this.visProp.scale); - } - labelText = this.formatLabelText(value); + /** + * Array where the labels are saved. There is an array element for every tick, + * even for minor ticks which don't have labels. In this case the array element + * contains just <tt>null</tt>. + * @type Array + */ + this.labels = []; - return labelText; - }, + /** + * A list of labels which have to be displayed in updateRenderer. + * @type Array + */ + this.labelData = []; /** - * Create a tick label data, i.e. text and coordinates - * @param {String} labelText - * @param {JXG.Coords} tick - * @param {Number} tickNumber - * @returns {Object} with properties 'x', 'y', 't' (text), 'i' (tick number) or null in case of o label - * @private + * To ensure the uniqueness of label ids this counter is used. + * @type number */ - generateLabelData: function (labelText, tick, tickNumber) { - var xa, ya, m, fs; + this.labelCounter = 0; - // Test if large portions of the label are inside of the canvas - // This is the last chance to abandon the creation of the label if it is mostly - // outside of the canvas. - fs = Type.evaluate(this.visProp.label.fontsize); - xa = [tick.scrCoords[1], tick.scrCoords[1]]; - ya = [tick.scrCoords[2], tick.scrCoords[2]]; - m = (fs === undefined) ? 12 : fs; - m *= 0.5; - if (!this._isInsideCanvas(xa, ya, m)) { - return null; - } + this.id = this.line.addTicks(this); + this.elType = 'ticks'; + this.inherits.push(this.labels); + this.board.setId(this, 'Ti'); + }; - xa = Type.evaluate(this.visProp.label.offset[0]); - ya = Type.evaluate(this.visProp.label.offset[1]); + JXG.Ticks.prototype = new GeometryElement(); - return { - x: tick.usrCoords[1] + xa / (this.board.unitX), - y: tick.usrCoords[2] + ya / (this.board.unitY), - t: labelText, - i: tickNumber - }; - }, + JXG.extend(JXG.Ticks.prototype, /** @lends JXG.Ticks.prototype */ { /** - * Recalculate the tick positions and the labels. - * @returns {JXG.Ticks} + * Ticks function: + * determines the distance (in user units) of two major ticks. + * See above in constructor and in @see JXG.GeometryElement#setAttribute + * + * @private + * @param {Number} ticks Distance between two major ticks + * @returns {Function} returns method ticksFunction */ - update: function () { - if (this.needsUpdate) { - //this.visPropCalc.visible = Type.evaluate(this.visProp.visible); - // A canvas with no width or height will create an endless loop, so ignore it - if (this.board.canvasWidth !== 0 && this.board.canvasHeight !== 0) { - this.calculateTicksCoordinates(); + makeTicksFunction: function (ticks) { + return function () { + var delta, b, dist; + + if (Type.evaluate(this.visProp.insertticks)) { + b = this.getLowerAndUpperBounds(this.getZeroCoordinates(), 'ticksdistance'); + dist = b.upper - b.lower; + + delta = Math.pow(10, Math.floor(Math.log(0.6 * dist) / Math.LN10)); + if (dist <= 6 * delta) { + delta *= 0.5; + } + return delta; } - // this.updateVisibility(this.line.visPropCalc.visible); - // - // for (var i = 0; i < this.labels.length; i++) { - // if (this.labels[i] !== null) { - // this.labels[i].prepareUpdate() - // .updateVisibility(this.line.visPropCalc.visible) - // .updateRenderer(); - // } - // } - } - return this; + // upto 0.99.1: + return ticks; + }; }, /** - * Uses the boards renderer to update the arc. - * @returns {JXG.Ticks} Reference to the object. + * Checks whether (x,y) is near the line. + * Only available for line elements, not for ticks on curves. + * @param {Number} x Coordinate in x direction, screen coordinates. + * @param {Number} y Coordinate in y direction, screen coordinates. + * @returns {Boolean} True if (x,y) is near the line, False otherwise. */ - updateRenderer: function () { - if (!this.needsUpdate) { - return this; + hasPoint: function (x, y) { + var i, t, + len = (this.ticks && this.ticks.length) || 0, + r, type; + + if (Type.isObject(Type.evaluate(this.visProp.precision))) { + type = this.board._inputDevice; + r = Type.evaluate(this.visProp.precision[type]); + } else { + // 'inherit' + r = this.board.options.precision.hasPoint; + } + r += Type.evaluate(this.visProp.strokewidth) * 0.5; + if (!Type.evaluate(this.line.visProp.scalable) || + this.line.elementClass === Const.OBJECT_CLASS_CURVE) { + return false; } - if (this.visPropCalc.visible) { - this.board.renderer.updateTicks(this); + // Ignore non-axes and axes that are not horizontal or vertical + if (this.line.stdform[1] !== 0 && this.line.stdform[2] !== 0 && this.line.type !== Const.OBJECT_TYPE_AXIS) { + return false; } - this.updateRendererLabels(); - this.setDisplayRendNode(); - // if (this.visPropCalc.visible != this.visPropOld.visible) { - // this.board.renderer.display(this, this.visPropCalc.visible); - // this.visPropOld.visible = this.visPropCalc.visible; - // } + for (i = 0; i < len; i++) { + t = this.ticks[i]; - this.needsUpdate = false; - return this; + // Skip minor ticks + if (t[2]) { + // Ignore ticks at zero + if (!((this.line.stdform[1] === 0 && Math.abs(t[0][0] - this.line.point1.coords.scrCoords[1]) < Mat.eps) || + (this.line.stdform[2] === 0 && Math.abs(t[1][0] - this.line.point1.coords.scrCoords[2]) < Mat.eps))) { + // tick length is not zero, ie. at least one pixel + if (Math.abs(t[0][0] - t[0][1]) >= 1 || Math.abs(t[1][0] - t[1][1]) >= 1) { + if (this.line.stdform[1] === 0) { + // Allow dragging near axes only. + if (Math.abs(y - (t[1][0] + t[1][1]) * 0.5) < 2 * r && t[0][0] - r < x && x < t[0][1] + r) { + return true; + } + } else if (this.line.stdform[2] === 0) { + if (Math.abs(x - (t[0][0] + t[0][1]) * 0.5) < 2 * r && t[1][0] - r < y && y < t[1][1] + r) { + return true; + } + } + } + } + } + } + + return false; }, /** - * Updates the label elements of the major ticks. - * - * @private - * @returns {JXG.Ticks} Reference to the object. + * Sets x and y coordinate of the tick. + * @param {number} method The type of coordinates used here. Possible values are {@link JXG.COORDS_BY_USER} and {@link JXG.COORDS_BY_SCREEN}. + * @param {Array} coords coordinates in screen/user units + * @param {Array} oldcoords previous coordinates in screen/user units + * @returns {JXG.Ticks} this element */ - updateRendererLabels: function() { - var i, j, - lenData, lenLabels, - attr, - label, ld, - visible; - - // The number of labels needed - lenData = this.labelsData.length; - // The number of labels which already exist - // The existing labels are stored in this.labels[] - // The new label positions and label values are stored in this.labelsData[] - lenLabels = this.labels.length; - - for (i = 0, j = 0; i < lenData; i++) { - if (this.labelsData[i] === null) { - // This is a tick without label - continue; - } - - ld = this.labelsData[i]; - if (j < lenLabels) { - // Take an already existing text element - label = this.labels[j]; - label.setText(ld.t); - label.setCoords(ld.x, ld.y); - j++; - } else { - // A new text element is needed - this.labelCounter += 1; + setPositionDirectly: function (method, coords, oldcoords) { + var dx, dy, + c = new Coords(method, coords, this.board), + oldc = new Coords(method, oldcoords, this.board), + bb = this.board.getBoundingBox(); - attr = { - isLabel: true, - layer: this.board.options.layer.line, - highlightStrokeColor: this.board.options.text.strokeColor, - highlightStrokeWidth: this.board.options.text.strokeWidth, - highlightStrokeOpacity: this.board.options.text.strokeOpacity, - priv: this.visProp.priv - }; - attr = Type.deepCopy(attr, this.visProp.label); - attr.id = this.id + ld.i + 'Label' + this.labelCounter; + if (this.line.type !== Const.OBJECT_TYPE_AXIS || + !Type.evaluate(this.line.visProp.scalable)) { - label = Text.createText(this.board, [ld.x, ld.y, ld.t], attr); - label.isDraggable = false; - label.dump = false; - this.labels.push(label); - } + return this; + } - // Look-ahead if the label inherits visiblity. - // If yes, update label. - visible = Type.evaluate(this.visProp.label.visible); - if (visible === 'inherit') { - visible = this.visPropCalc.visible; - } + if (Math.abs(this.line.stdform[1]) < Mat.eps && + Math.abs(c.usrCoords[1] * oldc.usrCoords[1]) > Mat.eps) { - label.prepareUpdate() - .updateVisibility(visible) - .updateRenderer(); + // Horizontal line + dx = oldc.usrCoords[1] / c.usrCoords[1]; + bb[0] *= dx; + bb[2] *= dx; + this.board.setBoundingBox(bb, this.board.keepaspectratio, 'update'); - label.distanceX = Type.evaluate(this.visProp.label.offset[0]); - label.distanceY = Type.evaluate(this.visProp.label.offset[1]); - } + } else if (Math.abs(this.line.stdform[2]) < Mat.eps && + Math.abs(c.usrCoords[2] * oldc.usrCoords[2]) > Mat.eps) { - // Hide unused labels - lenData = j; - for (j = lenData; j < lenLabels; j++) { - this.board.renderer.display(this.labels[j], false); - // Tick labels have the attribute "visible: 'inherit'" - // This must explicitely set to false, otherwise - // this labels would be set to visible in the upcoming - // update of the labels. - this.labels[j].visProp.visible = this.labels[j].visPropCalc.visible = false; + // Vertical line + dy = oldc.usrCoords[2] / c.usrCoords[2]; + bb[3] *= dy; + bb[1] *= dy; + this.board.setBoundingBox(bb, this.board.keepaspectratio, 'update'); } return this; }, - hideElement: function () { - var i; + /** + * (Re-)calculates the ticks coordinates. + * @private + */ + calculateTicksCoordinates: function () { + var coordsZero, bounds, + r_max, bb; - JXG.deprecated('Element.hideElement()', 'Element.setDisplayRendNode()'); + if (this.line.elementClass === Const.OBJECT_CLASS_LINE) { + // Calculate Ticks width and height in Screen and User Coordinates + this.setTicksSizeVariables(); - this.visPropCalc.visible = false; - this.board.renderer.display(this, false); - for (i = 0; i < this.labels.length; i++) { - if (Type.exists(this.labels[i])) { - this.labels[i].hideElement(); + // If the parent line is not finite, we can stop here. + if (Math.abs(this.dx) < Mat.eps && + Math.abs(this.dy) < Mat.eps) { + return; } } - return this; - }, - - showElement: function () { - var i; + // Get Zero (coords element for lines , number for curves) + coordsZero = this.getZeroCoordinates(); - JXG.deprecated('Element.showElement()', 'Element.setDisplayRendNode()'); + // Calculate lower bound and upper bound limits based on distance + // between p1 and center and p2 and center + if (this.line.elementClass === Const.OBJECT_CLASS_LINE) { + bounds = this.getLowerAndUpperBounds(coordsZero); + } else { + bounds = { + lower: this.line.minX(), + upper: this.line.maxX() + }; + } - this.visPropCalc.visible = true; - this.board.renderer.display(this, false); + if (Type.evaluate(this.visProp.type) === 'polar') { + bb = this.board.getBoundingBox(); + r_max = Math.max(Math.sqrt(bb[0] * bb[0] + bb[1] * bb[1]), + Math.sqrt(bb[2] * bb[2] + bb[3] * bb[3])); + bounds.upper = r_max; + } - for (i = 0; i < this.labels.length; i++) { - if (Type.exists(this.labels[i])) { - this.labels[i].showElement(); - } + // Clean up + this.ticks = []; + this.labelsData = []; + // Create Ticks Coordinates and Labels + if (this.equidistant) { + this.generateEquidistantTicks(coordsZero, bounds); + } else { + this.generateFixedTicks(coordsZero, bounds); } return this; - } - }); - - /** - * @class Ticks are used as distance markers on a line or curve. - * They are - * mainly used for axis elements and slider elements. Ticks may stretch infinitely - * or finitely, which can be set with {@link Ticks#majorHeight} and {@link Ticks#minorHeight}. - * - * @pseudo - * @description Ticks are markers on straight line elements or curves. - * @name Ticks - * @augments JXG.Ticks - * @constructor - * @type JXG.Ticks - * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {JXG.Line|JXG.Curve} line The parents consist of the line or curve the ticks are going to be attached to. - * @param {Number|Array} distance Number defining the distance between two major ticks or an - * array defining static ticks. In case a number is specified, the ticks are <i>equidistant</i>, - * in case of an array, a fixed number of static ticks is created at user-supplied positions. - * Alternatively, the distance can be specified with the attribute - * "ticksDistance". For arbitrary lines (and not axes) a "zero coordinate" is determined - * which defines where the first tick is positioned. This zero coordinate - * can be altered with the attribute "anchor". Possible values are "left", "middle", "right" or a number. - * The default value is "left". - * - * @example - * // Create an axis providing two coordinate pairs. - * var p1 = board.create('point', [0, 3]); - * var p2 = board.create('point', [1, 3]); - * var l1 = board.create('line', [p1, p2]); - * var t = board.create('ticks', [l1], {ticksDistance: 2}); - * </pre><div class="jxgbox" id="JXGee7f2d68-75fc-4ec0-9931-c76918427e63" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function () { - * var board = JXG.JSXGraph.initBoard('JXGee7f2d68-75fc-4ec0-9931-c76918427e63', {boundingbox: [-1, 7, 7, -1], showcopyright: false, shownavigation: false}); - * var p1 = board.create('point', [0, 3]); - * var p2 = board.create('point', [1, 3]); - * var l1 = board.create('line', [p1, p2]); - * var t = board.create('ticks', [l1, 2], {ticksDistance: 2}); - * })(); - * </script><pre> - */ - JXG.createTicks = function (board, parents, attributes) { - var el, dist, - attr = Type.copyAttributes(attributes, board.options, 'ticks'); - - if (parents.length < 2) { - dist = attr.ticksdistance; - } else { - dist = parents[1]; - } + }, - if (parents[0].elementClass === Const.OBJECT_CLASS_LINE || - parents[0].elementClass === Const.OBJECT_CLASS_CURVE) { - el = new JXG.Ticks(parents[0], dist, attr); - } else { - throw new Error("JSXGraph: Can't create Ticks with parent types '" + (typeof parents[0]) + "'."); - } + /** + * Sets the variables used to set the height and slope of each tick. + * + * @private + */ + setTicksSizeVariables: function (pos) { + var d, mi, ma, len, + distMaj = Type.evaluate(this.visProp.majorheight) * 0.5, + distMin = Type.evaluate(this.visProp.minorheight) * 0.5; - // deprecated - if (Type.isFunction(attr.generatelabelvalue)) { - el.generateLabelText = attr.generatelabelvalue; - } - if (Type.isFunction(attr.generatelabeltext)) { - el.generateLabelText = attr.generatelabeltext; - } + // For curves: + if (Type.exists(pos)) { + mi = this.line.minX(); + ma = this.line.maxX(); + len = this.line.points.length; + if (len < 2) { + this.dxMaj = 0; + this.dyMaj = 0; + } else if (Mat.relDif(pos, mi) < Mat.eps) { + this.dxMaj = this.line.points[0].usrCoords[2] - this.line.points[1].usrCoords[2]; + this.dyMaj = this.line.points[1].usrCoords[1] - this.line.points[0].usrCoords[1]; + } else if (Mat.relDif(pos, ma) < Mat.eps) { + this.dxMaj = this.line.points[len - 2].usrCoords[2] - this.line.points[len - 1].usrCoords[2]; + this.dyMaj = this.line.points[len - 1].usrCoords[1] - this.line.points[len - 2].usrCoords[1]; + } else { + this.dxMaj = -Numerics.D(this.line.Y)(pos); + this.dyMaj = Numerics.D(this.line.X)(pos); + } + } else { + // ticks width and height in screen units + this.dxMaj = this.line.stdform[1]; + this.dyMaj = this.line.stdform[2]; + } + this.dxMin = this.dxMaj; + this.dyMin = this.dyMaj; - el.setParents(parents[0]); - el.isDraggable = true; - el.fullUpdate(parents[0].visPropCalc.visible); + // ticks width and height in user units + this.dx = this.dxMaj; + this.dy = this.dyMaj; - return el; - }; + // After this, the length of the vector (dxMaj, dyMaj) in screen coordinates is equal to distMaj pixel. + d = Math.sqrt( + this.dxMaj * this.dxMaj * this.board.unitX * this.board.unitX + + this.dyMaj * this.dyMaj * this.board.unitY * this.board.unitY + ); + this.dxMaj *= distMaj / d * this.board.unitX; + this.dyMaj *= distMaj / d * this.board.unitY; + this.dxMin *= distMin / d * this.board.unitX; + this.dyMin *= distMin / d * this.board.unitY; - /** - * @class Hatches can be used to mark congruent lines or curves. - * @pseudo - * @description - * @name Hatch - * @augments JXG.Ticks - * @constructor - * @type JXG.Ticks - * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {JXG.Line|JXG.curve} line The line or curve the hatch marks are going to be attached to. - * @param {Number} numberofhashes Number of dashes. - * @example - * // Create an axis providing two coords pairs. - * var p1 = board.create('point', [0, 3]); - * var p2 = board.create('point', [1, 3]); - * var l1 = board.create('line', [p1, p2]); - * var t = board.create('hatch', [l1, 3]); - * </pre><div class="jxgbox" id="JXG4a20af06-4395-451c-b7d1-002757cf01be" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function () { - * var board = JXG.JSXGraph.initBoard('JXG4a20af06-4395-451c-b7d1-002757cf01be', {boundingbox: [-1, 7, 7, -1], showcopyright: false, shownavigation: false}); - * var p1 = board.create('point', [0, 3]); - * var p2 = board.create('point', [1, 3]); - * var l1 = board.create('line', [p1, p2]); - * var t = board.create('hatch', [l1, 3]); - * })(); - * </script><pre> - * - * @example - * // Alter the position of the hatch - * - * var p = board.create('point', [-5, 0]); - * var q = board.create('point', [5, 0]); - * var li = board.create('line', [p, q]); - * var h = board.create('hatch', [li, 2], {anchor: 0.2}); - * - * </pre><div id="JXG05d720ee-99c9-11e6-a9c7-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function() { - * var board = JXG.JSXGraph.initBoard('JXG05d720ee-99c9-11e6-a9c7-901b0e1b8723', - * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); - * - * var p = board.create('point', [-5, 0]); - * var q = board.create('point', [5, 0]); - * var li = board.create('line', [p, q]); - * var h = board.create('hatch', [li, 2], {anchor: 0.2}); - * - * })(); - * - * </script><pre> - * - * @example - * // Alternative hatch faces - * - * var li = board.create('line', [[-6,0], [6,3]]); - * var h1 = board.create('hatch', [li, 2], {tickEndings: [1,1], face:'|'}); - * var h2 = board.create('hatch', [li, 2], {tickEndings: [1,1], face:'>', anchor: 0.3}); - * var h3 = board.create('hatch', [li, 2], {tickEndings: [1,1], face:'<', anchor: 0.7}); - * - * </pre><div id="JXG974f7e89-eac8-4187-9aa3-fb8068e8384b" class="jxgbox" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function() { - * var board = JXG.JSXGraph.initBoard('JXG974f7e89-eac8-4187-9aa3-fb8068e8384b', - * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); - * // Alternative hatch faces - * - * var li = board.create('line', [[-6,0], [6,3]]); - * var h1 = board.create('hatch', [li, 2], {tickEndings: [1,1], face:'|'}); - * var h2 = board.create('hatch', [li, 2], {tickEndings: [1,1], face:'>', anchor: 0.3}); - * var h3 = board.create('hatch', [li, 2], {tickEndings: [1,1], face:'<', anchor: 0.7}); - * - * })(); - * - * </script><pre> - * - */ - JXG.createHatchmark = function (board, parents, attributes) { - var num, i, base, width, totalwidth, el, - pos = [], - attr = Type.copyAttributes(attributes, board.options, 'hatch'); + // Grid-like ticks? + this.minStyle= (Type.evaluate(this.visProp.minorheight) < 0) ? 'infinite' : 'finite'; + this.majStyle= (Type.evaluate(this.visProp.majorheight) < 0) ? 'infinite' : 'finite'; + }, - if ((parents[0].elementClass !== Const.OBJECT_CLASS_LINE && - parents[0].elementClass !== Const.OBJECT_CLASS_CURVE) || typeof parents[1] !== 'number') { - throw new Error("JSXGraph: Can't create Hatch mark with parent types '" + (typeof parents[0]) + "' and '" + (typeof parents[1]) + " and ''" + (typeof parents[2]) + "'."); - } + /** + * Returns the coordinates of the point zero of the line. + * + * If the line is an {@link Axis}, the coordinates of the projection of the board's zero point is returned + * + * Otherwise, the coordinates of the point that acts as zero are + * established depending on the value of {@link JXG.Ticks#anchor} + * + * @returns {JXG.Coords} Coords object for the zero point on the line + * @private + */ + getZeroCoordinates: function () { + var c1x, c1y, c1z, c2x, c2y, c2z, t, mi, ma, + ev_a = Type.evaluate(this.visProp.anchor); - num = parents[1]; - width = attr.ticksdistance; - totalwidth = (num - 1) * width; - base = -totalwidth * 0.5; + if (this.line.elementClass === Const.OBJECT_CLASS_LINE) { + if (this.line.type === Const.OBJECT_TYPE_AXIS) { + return Geometry.projectPointToLine({ + coords: { + usrCoords: [1, 0, 0] + } + }, this.line, this.board); + } + c1z = this.line.point1.coords.usrCoords[0]; + c1x = this.line.point1.coords.usrCoords[1]; + c1y = this.line.point1.coords.usrCoords[2]; + c2z = this.line.point2.coords.usrCoords[0]; + c2x = this.line.point2.coords.usrCoords[1]; + c2y = this.line.point2.coords.usrCoords[2]; - for (i = 0; i < num; i++) { - pos[i] = base + i * width; - } + if (ev_a === 'right') { + return this.line.point2.coords; + } + if (ev_a === 'middle') { + return new Coords(Const.COORDS_BY_USER, [ + (c1z + c2z) * 0.5, + (c1x + c2x) * 0.5, + (c1y + c2y) * 0.5 + ], this.board); + } + if (Type.isNumber(ev_a)) { + return new Coords(Const.COORDS_BY_USER, [ + c1z + (c2z - c1z) * ev_a, + c1x + (c2x - c1x) * ev_a, + c1y + (c2y - c1y) * ev_a + ], this.board); + } + return this.line.point1.coords; + } + mi = this.line.minX(); + ma = this.line.maxX(); + if (ev_a === 'right') { + t = ma; + } else if (ev_a === 'middle') { + t = (mi + ma) * 0.5; + } else if (Type.isNumber(ev_a)) { + t = mi * (1 - ev_a) + ma * ev_a; + // t = ev_a; + } else { + t = mi; + } + return t; + }, - el = board.create('ticks', [parents[0], pos], attr); - el.elType = 'hatch'; + /** + * Calculate the lower and upper bounds for tick rendering + * If {@link JXG.Ticks#includeBoundaries} is false, the boundaries will exclude point1 and point2 + * + * @param {JXG.Coords} coordsZero + * @returns {String} type (Optional) If type=='ticksdistance' the bounds are + * the intersection of the line with the bounding box of the board. + * Otherwise, it is the projection of the corners of the bounding box + * to the line. The first case is needed to automatically + * generate ticks. The second case is for drawing of the ticks. + * @returns {Object} contains the lower and upper bounds + * + * @private + */ + getLowerAndUpperBounds: function (coordsZero, type) { + var lowerBound, upperBound, + fA, lA, + point1, point2, isPoint1inBoard, isPoint2inBoard, + // We use the distance from zero to P1 and P2 to establish lower and higher points + dZeroPoint1, dZeroPoint2, + ev_sf = Type.evaluate(this.line.visProp.straightfirst), + ev_sl = Type.evaluate(this.line.visProp.straightlast), + ev_i = Type.evaluate(this.visProp.includeboundaries); - return el; - }; + // The line's defining points that will be adjusted to be within the board limits + if (this.line.elementClass === Const.OBJECT_CLASS_CURVE) { + return { + lower: this.line.minX(), + upper: this.line.maxX() + }; + } - JXG.registerElement('ticks', JXG.createTicks); - JXG.registerElement('hash', JXG.createHatchmark); - JXG.registerElement('hatch', JXG.createHatchmark); + point1 = new Coords(Const.COORDS_BY_USER, this.line.point1.coords.usrCoords, this.board); + point2 = new Coords(Const.COORDS_BY_USER, this.line.point2.coords.usrCoords, this.board); + // Are the original defining points within the board? + isPoint1inBoard = (Math.abs(point1.usrCoords[0]) >= Mat.eps && + point1.scrCoords[1] >= 0.0 && point1.scrCoords[1] <= this.board.canvasWidth && + point1.scrCoords[2] >= 0.0 && point1.scrCoords[2] <= this.board.canvasHeight); + isPoint2inBoard = (Math.abs(point2.usrCoords[0]) >= Mat.eps && + point2.scrCoords[1] >= 0.0 && point2.scrCoords[1] <= this.board.canvasWidth && + point2.scrCoords[2] >= 0.0 && point2.scrCoords[2] <= this.board.canvasHeight); - return { - Ticks: JXG.Ticks, - createTicks: JXG.createTicks, - createHashmark: JXG.createHatchmark, - createHatchmark: JXG.createHatchmark - }; -}); + // Adjust line limit points to be within the board + if (Type.exists(type) || type === 'tickdistance') { + // The good old calcStraight is needed for determining the distance between major ticks. + // Here, only the visual area is of importance + Geometry.calcStraight(this.line, point1, point2, Type.evaluate(this.line.visProp.margin)); + } else { + // This function projects the corners of the board to the line. + // This is important for diagonal lines with infinite tick lines. + Geometry.calcLineDelimitingPoints(this.line, point1, point2); + } -/* - Copyright 2008-2021 - Matthias Ehmann, - Michael Gerhaeuser, - Carsten Miller, - Bianca Valentin, - Alfred Wassermann, - Peter Wilfahrt + // Shorten ticks bounds such that ticks are not through arrow heads + fA = Type.evaluate(this.line.visProp.firstarrow); + lA = Type.evaluate(this.line.visProp.lastarrow); + if (fA || lA) { + this.board.renderer.getPositionArrowHead(this.line, point1, point2, + Type.evaluate(this.line.visProp.strokewidth)); - This file is part of JSXGraph. + if (fA) { + point1.setCoordinates(Const.COORDS_BY_SCREEN, [ + point1.scrCoords[1], + point1.scrCoords[2] + ]); + } + if (lA) { + point2.setCoordinates(Const.COORDS_BY_SCREEN, [ + point2.scrCoords[1], + point2.scrCoords[2] + ]); + } + // if (fA) { + // point1.setCoordinates(Const.COORDS_BY_SCREEN, [ + // point1.scrCoords[1] - obj.d1x, + // point1.scrCoords[2] - obj.d1y + // ]); + // } + // if (lA) { + // point2.setCoordinates(Const.COORDS_BY_SCREEN, [ + // point2.scrCoords[1] - obj.d2x, + // point2.scrCoords[2] - obj.d2y + // ]); + // } + } - JSXGraph is free software dual licensed under the GNU LGPL or MIT License. - You can redistribute it and/or modify it under the terms of the + // Calculate (signed) distance from Zero to P1 and to P2 + dZeroPoint1 = this.getDistanceFromZero(coordsZero, point1); + dZeroPoint2 = this.getDistanceFromZero(coordsZero, point2); - * GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version - OR - * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT + // We have to establish if the direction is P1->P2 or P2->P1 to set the lower and upper + // boundaries appropriately. As the distances contain also a sign to indicate direction, + // we can compare dZeroPoint1 and dZeroPoint2 to establish the line direction + if (dZeroPoint1 < dZeroPoint2) { // Line goes P1->P2 + lowerBound = dZeroPoint1; + if (!ev_sf && isPoint1inBoard && !ev_i) { + lowerBound += Mat.eps; + } + upperBound = dZeroPoint2; + if (!ev_sl && isPoint2inBoard && !ev_i) { + upperBound -= Mat.eps; + } + } else if (dZeroPoint2 < dZeroPoint1) { // Line goes P2->P1 + lowerBound = dZeroPoint2; + if (!ev_sl && isPoint2inBoard && !ev_i) { + lowerBound += Mat.eps; + } + upperBound = dZeroPoint1; + if (!ev_sf && isPoint1inBoard && !ev_i) { + upperBound -= Mat.eps; + } + } else { // P1 = P2 = Zero, we can't do a thing + lowerBound = 0; + upperBound = 0; + } - JSXGraph is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. + return { + lower: lowerBound, + upper: upperBound + }; + }, - You should have received a copy of the GNU Lesser General Public License and - the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> - and <http://opensource.org/licenses/MIT/>. - */ + /** + * Calculates the distance in user coordinates from zero to a given point including its sign. + * Sign is positive, if the direction from zero to point is the same as the direction + * zero to point2 of the line. + * + * @param {JXG.Coords} zero coordinates of the point considered zero + * @param {JXG.Coords} point coordinates of the point to find out the distance + * @returns {Number} distance between zero and point, including its sign + * @private + */ + getDistanceFromZero: function (zero, point) { + var p1, p2, + dirLine, dirPoint, + distance; + p1 = this.line.point1.coords; + p2 = this.line.point2.coords; + distance = zero.distance(Const.COORDS_BY_USER, point); -/*global JXG: true, define: true*/ -/*jslint nomen: true, plusplus: true*/ + // Establish sign + dirLine = [p2.usrCoords[0] - p1.usrCoords[0], + p2.usrCoords[1] - p1.usrCoords[1], + p2.usrCoords[2] - p1.usrCoords[2]]; + dirPoint = [point.usrCoords[0] - zero.usrCoords[0], + point.usrCoords[1] - zero.usrCoords[1], + point.usrCoords[2] - zero.usrCoords[2]]; + if (Mat.innerProduct(dirLine, dirPoint, 3) < 0) { + distance *= -1; + } -/* depends: - jxg - math/math - base/constants - base/point - utils/type - elements: - point - group - segment - ticks - glider - text - */ + return distance; + }, -/** - * @fileoverview The geometry object slider is defined in this file. Slider stores all - * style and functional properties that are required to draw and use a slider on - * a board. - */ + /** + * Creates ticks coordinates and labels automatically. + * The frequency of ticks is affected by the values of {@link JXG.Ticks#insertTicks} and {@link JXG.Ticks#ticksDistance} + * + * @param {JXG.Coords} coordsZero coordinates of the point considered zero + * @param {Object} bounds contains the lower and upper boundaries for ticks placement + * @private + */ + generateEquidistantTicks: function (coordsZero, bounds) { + var tickPosition, + eps2 = Mat.eps, + deltas, + // Distance between two major ticks in user coordinates + ticksDelta = (this.equidistant ? this.ticksFunction(1) : this.ticksDelta), + ev_it = Type.evaluate(this.visProp.insertticks), + ev_mt = Type.evaluate(this.visProp.minorticks); -define('element/slider',[ - 'jxg', 'math/math', 'base/constants', 'base/coords', 'utils/type', 'base/point', 'base/group', - 'base/element', 'base/line', 'base/ticks', 'base/text' -], function (JXG, Mat, Const, Coords, Type, Point, Group, GeometryElement, Line, Ticks, Text) { + if (this.line.elementClass === Const.OBJECT_CLASS_LINE) { + // Calculate X and Y distance between two major ticks + deltas = this.getXandYdeltas(); + } - "use strict"; + // adjust ticks distance + ticksDelta *= Type.evaluate(this.visProp.scale); + if (ev_it && this.minTicksDistance > Mat.eps) { + ticksDelta = this.adjustTickDistance(ticksDelta, coordsZero, deltas); + ticksDelta /= (ev_mt + 1); + } else if (!ev_it) { + ticksDelta /= (ev_mt + 1); + } + this.ticksDelta = ticksDelta; - /** - * @class A slider can be used to choose values from a given range of numbers. - * @pseudo - * @description - * @name Slider - * @augments Glider - * @constructor - * @type JXG.Point - * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {Array_Array_Array} start,end,data The first two arrays give the start and the end where the slider is drawn - * on the board. The third array gives the start and the end of the range the slider operates as the first resp. the - * third component of the array. The second component of the third array gives its start value. - * @example - * // Create a slider with values between 1 and 10, initial position is 5. - * var s = board.create('slider', [[1, 2], [3, 2], [1, 5, 10]]); - * </pre><div class="jxgbox" id="JXGcfb51cde-2603-4f18-9cc4-1afb452b374d" style="width: 200px; height: 200px;"></div> - * <script type="text/javascript"> - * (function () { - * var board = JXG.JSXGraph.initBoard('JXGcfb51cde-2603-4f18-9cc4-1afb452b374d', {boundingbox: [-1, 5, 5, -1], axis: true, showcopyright: false, shownavigation: false}); - * var s = board.create('slider', [[1, 2], [3, 2], [1, 5, 10]]); - * })(); - * </script><pre> - * @example - * // Create a slider taking integer values between 1 and 50. Initial value is 50. - * var s = board.create('slider', [[1, 3], [3, 1], [0, 10, 50]], {snapWidth: 1, ticks: { drawLabels: true }}); - * </pre><div class="jxgbox" id="JXGe17128e6-a25d-462a-9074-49460b0d66f4" style="width: 200px; height: 200px;"></div> - * <script type="text/javascript"> - * (function () { - * var board = JXG.JSXGraph.initBoard('JXGe17128e6-a25d-462a-9074-49460b0d66f4', {boundingbox: [-1, 5, 5, -1], axis: true, showcopyright: false, shownavigation: false}); - * var s = board.create('slider', [[1, 3], [3, 1], [1, 10, 50]], {snapWidth: 1, ticks: { drawLabels: true }}); - * })(); - * </script><pre> - * @example - * // Draggable slider - * var s1 = board.create('slider', [[-3,1], [2,1],[-10,1,10]], { - * visible: true, - * snapWidth: 2, - * point1: {fixed: false}, - * point2: {fixed: false}, - * baseline: {fixed: false, needsRegularUpdate: true} - * }); - * - * </pre><div id="JXGbfc67817-2827-44a1-bc22-40bf312e76f8" class="jxgbox" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function() { - * var board = JXG.JSXGraph.initBoard('JXGbfc67817-2827-44a1-bc22-40bf312e76f8', - * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); - * var s1 = board.create('slider', [[-3,1], [2,1],[-10,1,10]], { - * visible: true, - * snapWidth: 2, - * point1: {fixed: false}, - * point2: {fixed: false}, - * baseline: {fixed: false, needsRegularUpdate: true} - * }); - * - * })(); - * - * </script><pre> - * - * @example - * // Set the slider by clicking on the base line: attribute 'moveOnUp' - * var s1 = board.create('slider', [[-3,1], [2,1],[-10,1,10]], { - * snapWidth: 2, - * moveOnUp: true // default value - * }); - * - * </pre><div id="JXGc0477c8a-b1a7-4111-992e-4ceb366fbccc" class="jxgbox" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function() { - * var board = JXG.JSXGraph.initBoard('JXGc0477c8a-b1a7-4111-992e-4ceb366fbccc', - * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); - * var s1 = board.create('slider', [[-3,1], [2,1],[-10,1,10]], { - * snapWidth: 2, - * moveOnUp: true // default value - * }); - * - * })(); - * - * </script><pre> - * - */ - JXG.createSlider = function (board, parents, attributes) { - var pos0, pos1, smin, start, smax, sdiff, - p1, p2, l1, ticks, ti, startx, starty, p3, l2, t, - withText, withTicks, snapWidth, sw, s, attr, precision; + if (ticksDelta < Mat.eps) { + return; + } - attr = Type.copyAttributes(attributes, board.options, 'slider'); - withTicks = attr.withticks; - withText = attr.withlabel; - snapWidth = attr.snapwidth; - precision = attr.precision; + // Position ticks from zero to the positive side while not reaching the upper boundary + tickPosition = 0; + if (!Type.evaluate(this.visProp.drawzero)) { + tickPosition = ticksDelta; + } + while (tickPosition <= bounds.upper + eps2) { + // Only draw ticks when we are within bounds, ignore case where tickPosition < lower < upper + if (tickPosition >= bounds.lower - eps2) { + this.processTickPosition(coordsZero, tickPosition, ticksDelta, deltas); + } + tickPosition += ticksDelta; - // start point - attr = Type.copyAttributes(attributes, board.options, 'slider', 'point1'); - p1 = board.create('point', parents[0], attr); + // Emergency out + if ((bounds.upper - tickPosition) > ticksDelta * 10000) { + break; + } + } - // end point - attr = Type.copyAttributes(attributes, board.options, 'slider', 'point2'); - p2 = board.create('point', parents[1], attr); - //g = board.create('group', [p1, p2]); + // Position ticks from zero (not inclusive) to the negative side while not reaching the lower boundary + tickPosition = -ticksDelta; + while (tickPosition >= bounds.lower - eps2) { + // Only draw ticks when we are within bounds, ignore case where lower < upper < tickPosition + if (tickPosition <= bounds.upper + eps2) { + this.processTickPosition(coordsZero, tickPosition, ticksDelta, deltas); + } + tickPosition -= ticksDelta; - // Base line - attr = Type.copyAttributes(attributes, board.options, 'slider', 'baseline'); - l1 = board.create('segment', [p1, p2], attr); + // Emergency out + if ((tickPosition - bounds.lower) > ticksDelta * 10000) { + break; + } + } + }, - // This is required for a correct projection of the glider onto the segment below - l1.updateStdform(); + /** + * Auxiliary method used by {@link JXG.Ticks#generateEquidistantTicks} to adjust the + * distance between two ticks depending on {@link JXG.Ticks#minTicksDistance} value + * + * @param {Number} ticksDelta distance between two major ticks in user coordinates + * @param {JXG.Coords} coordsZero coordinates of the point considered zero + * @param {Object} deltas x and y distance in pixel between two user units + * @param {Object} bounds upper and lower bound of the tick positions in user units. + * @private + */ + adjustTickDistance: function (ticksDelta, coordsZero, deltas) { + var nx, ny, bounds, + distScr, + sgn = 1, + ev_minti = Type.evaluate(this.visProp.minorticks); - pos0 = p1.coords.usrCoords.slice(1); - pos1 = p2.coords.usrCoords.slice(1); - smin = parents[2][0]; - start = parents[2][1]; - smax = parents[2][2]; - sdiff = smax - smin; + if (this.line.elementClass === Const.OBJECT_CLASS_CURVE) { + return ticksDelta; + } + bounds = this.getLowerAndUpperBounds(coordsZero, 'ticksdistance'); + nx = coordsZero.usrCoords[1] + deltas.x * ticksDelta; + ny = coordsZero.usrCoords[2] + deltas.y * ticksDelta; + distScr = coordsZero.distance(Const.COORDS_BY_SCREEN, new Coords(Const.COORDS_BY_USER, [nx, ny], this.board)); - sw = Type.evaluate(snapWidth); - s = (sw == -1) ? start : Math.round(start / sw) * sw; - startx = pos0[0] + (pos1[0] - pos0[0]) * (s - smin) / (smax - smin); - starty = pos0[1] + (pos1[1] - pos0[1]) * (s - smin) / (smax - smin); + if (ticksDelta === 0.0) { + return 0.0; + } - // glider point - attr = Type.copyAttributes(attributes, board.options, 'slider'); - // overwrite this in any case; the sliders label is a special text element, not the gliders label. - // this will be set back to true after the text was created (and only if withlabel was true initially). - attr.withLabel = false; - // gliders set snapwidth=-1 by default (i.e. deactivate them) - p3 = board.create('glider', [startx, starty, l1], attr); - p3.setAttribute({snapwidth: snapWidth}); + while (distScr / (ev_minti + 1) < this.minTicksDistance) { + if (sgn === 1) { + ticksDelta *= 2; + } else { + ticksDelta *= 5; + } + sgn *= -1; - // Segment from start point to glider point: highline - attr = Type.copyAttributes(attributes, board.options, 'slider', 'highline'); - l2 = board.create('segment', [p1, p3], attr); + nx = coordsZero.usrCoords[1] + deltas.x * ticksDelta; + ny = coordsZero.usrCoords[2] + deltas.y * ticksDelta; + distScr = coordsZero.distance(Const.COORDS_BY_SCREEN, new Coords(Const.COORDS_BY_USER, [nx, ny], this.board)); + } + return ticksDelta; + }, /** - * Returns the current slider value. - * @memberOf Slider.prototype - * @name Value - * @function - * @returns {Number} + * Auxiliary method used by {@link JXG.Ticks#generateEquidistantTicks} to create a tick + * in the line at the given tickPosition. + * + * @param {JXG.Coords} coordsZero coordinates of the point considered zero + * @param {Number} tickPosition current tick position relative to zero + * @param {Number} ticksDelta distance between two major ticks in user coordinates + * @param {Object} deltas x and y distance between two major ticks + * @private */ - p3.Value = function () { - var sdiff = this._smax - this._smin, - ev_sw = Type.evaluate(this.visProp.snapwidth); + processTickPosition: function (coordsZero, tickPosition, ticksDelta, deltas) { + var x, y, tickCoords, ti, + labelVal = null; - return ev_sw === -1 ? - this.position * sdiff + this._smin : - Math.round((this.position * sdiff + this._smin) / ev_sw) * ev_sw; - }; + // Calculates tick coordinates + if (this.line.elementClass === Const.OBJECT_CLASS_LINE) { + x = coordsZero.usrCoords[1] + tickPosition * deltas.x; + y = coordsZero.usrCoords[2] + tickPosition * deltas.y; + } else { + x = this.line.X(coordsZero + tickPosition); + y = this.line.Y(coordsZero + tickPosition); + } + tickCoords = new Coords(Const.COORDS_BY_USER, [x, y], this.board); + if (this.line.elementClass === Const.OBJECT_CLASS_CURVE) { + labelVal = coordsZero + tickPosition; + this.setTicksSizeVariables(labelVal); - p3.methodMap = Type.deepCopy(p3.methodMap, { - Value: 'Value', - setValue: 'setValue', - smax: '_smax', - smin: '_smin', - setMax: 'setMax', - setMin: 'setMin' - }); + } + + // Test if tick is a major tick. + // This is the case if tickPosition/ticksDelta is + // a multiple of the number of minorticks+1 + tickCoords.major = Math.round(tickPosition / ticksDelta) % (Type.evaluate(this.visProp.minorticks) + 1) === 0; + + // Compute the start position and the end position of a tick. + // If both positions are out of the canvas, ti is empty. + ti = this.createTickPath(tickCoords, tickCoords.major); + if (ti.length === 3) { + this.ticks.push(ti); + if (tickCoords.major && Type.evaluate(this.visProp.drawlabels)) { + // major tick label + this.labelsData.push( + this.generateLabelData( + this.generateLabelText(tickCoords, coordsZero, labelVal), + tickCoords, + this.ticks.length + ) + ); + } else { + // minor ticks have no labels + this.labelsData.push(null); + } + } + }, /** - * End value of the slider range. - * @memberOf Slider.prototype - * @name _smax - * @type Number + * Creates ticks coordinates and labels based on {@link JXG.Ticks#fixedTicks} and {@link JXG.Ticks#labels}. + * + * @param {JXG.Coords} coordsZero Coordinates of the point considered zero + * @param {Object} bounds contains the lower and upper boundaries for ticks placement + * @private */ - p3._smax = smax; + generateFixedTicks: function (coordsZero, bounds) { + var tickCoords, labelText, i, ti, + x, y, + eps2 = Mat.eps, fixedTick, + hasLabelOverrides = Type.isArray(this.visProp.labels), + deltas, + ev_dl = Type.evaluate(this.visProp.drawlabels); + + // Calculate X and Y distance between two major points in the line + if (this.line.elementClass === Const.OBJECT_CLASS_LINE) { + deltas = this.getXandYdeltas(); + } + for (i = 0; i < this.fixedTicks.length; i++) { + if (this.line.elementClass === Const.OBJECT_CLASS_LINE) { + fixedTick = this.fixedTicks[i]; + x = coordsZero.usrCoords[1] + fixedTick * deltas.x; + y = coordsZero.usrCoords[2] + fixedTick * deltas.y; + } else { + fixedTick = coordsZero + this.fixedTicks[i]; + x = this.line.X(fixedTick); + y = this.line.Y(fixedTick); + } + tickCoords = new Coords(Const.COORDS_BY_USER, [x, y], this.board); + + if (this.line.elementClass === Const.OBJECT_CLASS_CURVE) { + this.setTicksSizeVariables(fixedTick); + } + + // Compute the start position and the end position of a tick. + // If tick is out of the canvas, ti is empty. + ti = this.createTickPath(tickCoords, true); + if (ti.length === 3 && fixedTick >= bounds.lower - eps2 && + fixedTick <= bounds.upper + eps2) { + this.ticks.push(ti); + + if (ev_dl && + (hasLabelOverrides || Type.exists(this.visProp.labels[i]))) { + labelText = hasLabelOverrides ? + Type.evaluate(this.visProp.labels[i]) : fixedTick; + this.labelsData.push( + this.generateLabelData( + this.generateLabelText(tickCoords, coordsZero, labelText), + tickCoords, + i + ) + ); + } else { + this.labelsData.push(null); + } + } + } + }, /** - * Start value of the slider range. - * @memberOf Slider.prototype - * @name _smin - * @type Number + * Calculates the x and y distance in pixel between two units in user space. + * + * @returns {Object} + * @private */ - p3._smin = smin; + getXandYdeltas: function () { + var + // Auxiliary points to store the start and end of the line according to its direction + point1UsrCoords, point2UsrCoords, + distP1P2 = this.line.point1.Dist(this.line.point2); + + if (this.line.type === Const.OBJECT_TYPE_AXIS) { + // When line is an Axis, direction depends on Board Coordinates system + + // assume line.point1 and line.point2 are in correct order + point1UsrCoords = this.line.point1.coords.usrCoords; + point2UsrCoords = this.line.point2.coords.usrCoords; + + // Check if direction is incorrect, then swap + if (point1UsrCoords[1] > point2UsrCoords[1] || + (Math.abs(point1UsrCoords[1] - point2UsrCoords[1]) < Mat.eps && + point1UsrCoords[2] > point2UsrCoords[2])) { + point1UsrCoords = this.line.point2.coords.usrCoords; + point2UsrCoords = this.line.point1.coords.usrCoords; + } + } else /* if (this.line.elementClass === Const.OBJECT_CLASS_LINE)*/ { + // line direction is always from P1 to P2 for non Axis types + point1UsrCoords = this.line.point1.coords.usrCoords; + point2UsrCoords = this.line.point2.coords.usrCoords; + } + return { + x: (point2UsrCoords[1] - point1UsrCoords[1]) / distP1P2, + y: (point2UsrCoords[2] - point1UsrCoords[2]) / distP1P2 + }; + }, /** - * Sets the maximum value of the slider. - * @memberOf Slider.prototype - * @name setMax - * @param {Number} val New maximum value - * @returns {Object} this object + * Check if (parts of) the tick is inside the canvas. The tick intersects the boundary + * at two positions: [x[0], y[0]] and [x[1], y[1]] in screen coordinates. + * @param {Array} x Array of length two + * @param {Array} y Array of length two + * @return {Boolean} true if parts of the tick are inside of the canvas or on the boundary. */ - p3.setMax = function(val) { - this._smax = val; - return this; - }; + _isInsideCanvas: function(x, y, m) { + var cw = this.board.canvasWidth, + ch = this.board.canvasHeight; + + if (m === undefined) { + m = 0; + } + return (x[0] >= m && x[0] <= cw - m && y[0] >= m && y[0] <= ch - m) || + (x[1] >= m && x[1] <= cw - m && y[1] >= m && y[1] <= ch - m); + }, /** - * Sets the value of the slider. This call must be followed - * by a board update call. - * @memberOf Slider.prototype - * @name setValue - * @param {Number} val New value - * @returns {Object} this object + * @param {JXG.Coords} coords Coordinates of the tick on the line. + * @param {Boolean} major True if tick is major tick. + * @returns {Array} Array of length 3 containing path coordinates in screen coordinates + * of the tick (arrays of length 2). 3rd entry is true if major tick otherwise false. + * If the tick is outside of the canvas, the return array is empty. + * @private */ - p3.setValue = function(val) { - var sdiff = this._smax - this._smin; + createTickPath: function (coords, major) { + var c, lineStdForm, intersection, + dxs, dys, dxr, dyr, alpha, + style, + x = [-2000000, -2000000], + y = [-2000000, -2000000], + i, r, r_max, bb, full, delta; - if (Math.abs(sdiff) > Mat.eps) { - this.position = (val - this._smin) / sdiff; + c = coords.scrCoords; + if (major) { + dxs = this.dxMaj; + dys = this.dyMaj; + style = this.majStyle; } else { - this.position = 0.0; //this._smin; + dxs = this.dxMin; + dys = this.dyMin; + style = this.minStyle; } - this.position = Math.max(0.0, Math.min(1.0, this.position)); - return this; - }; + lineStdForm = [-dys * c[1] - dxs * c[2], dys, dxs]; - /** - * Sets the minimum value of the slider. - * @memberOf Slider.prototype - * @name setMin - * @param {Number} val New minimum value - * @returns {Object} this object - */ - p3.setMin = function(val) { - this._smin = val; - return this; - }; + // For all ticks regardless if of finite or infinite + // tick length the intersection with the canvas border is + // computed. + if (major && Type.evaluate(this.visProp.type) === 'polar') { + // polar style + bb = this.board.getBoundingBox(); + full = 2.0 * Math.PI; + delta = full / 180; + //ratio = this.board.unitY / this.board.X; - if (withText) { - attr = Type.copyAttributes(attributes, board.options, 'slider', 'label'); - t = board.create('text', [ - function () { - return (p2.X() - p1.X()) * 0.05 + p2.X(); - }, - function () { - return (p2.Y() - p1.Y()) * 0.05 + p2.Y(); - }, - function () { - var n, - sl = Type.evaluate(p3.visProp.suffixlabel), - ul = Type.evaluate(p3.visProp.unitlabel), - pl = Type.evaluate(p3.visProp.postlabel); + // usrCoords: Test if 'circle' is inside of the canvas + c = coords.usrCoords; + r = Math.sqrt(c[1] * c[1] + c[2] * c[2]); + r_max = Math.max(Math.sqrt(bb[0] * bb[0] + bb[1] * bb[1]), + Math.sqrt(bb[2] * bb[2] + bb[3] * bb[3])); - if (sl !== null) { - n = sl; - } else if (p3.name && p3.name !== '') { - n = p3.name + ' = '; + if (r < r_max) { + // Now, switch to screen coords + x = []; + y = []; + for (i = 0; i <= full; i += delta) { + x.push(this.board.origin.scrCoords[1] + r * Math.cos(i) * this.board.unitX); + y.push(this.board.origin.scrCoords[2] + r * Math.sin(i) * this.board.unitY); + } + return [x, y, major]; + } + + } else { + // line style + if (style === 'infinite') { + intersection = Geometry.meetLineBoard(lineStdForm, this.board); + x[0] = intersection[0].scrCoords[1]; + x[1] = intersection[1].scrCoords[1]; + y[0] = intersection[0].scrCoords[2]; + y[1] = intersection[1].scrCoords[2]; + } else { + if (Type.evaluate(this.visProp.face) === '>') { + alpha = Math.PI/4; + } else if (Type.evaluate(this.visProp.face) === '<') { + alpha = -Math.PI/4; } else { - n = ''; + alpha = 0; } + dxr = Math.cos(alpha) * dxs - Math.sin(alpha) * dys; + dyr = Math.sin(alpha) * dxs + Math.cos(alpha) * dys; - n += Type.toFixed(p3.Value(), precision); + x[0] = c[1] + dxr * Type.evaluate(this.visProp.tickendings[0]); + y[0] = c[2] - dyr * Type.evaluate(this.visProp.tickendings[0]); + x[1] = c[1]; + y[1] = c[2]; - if (ul !== null) { - n += ul; - } - if (pl !== null) { - n += pl; + alpha = -alpha; + dxr = Math.cos(alpha) * dxs - Math.sin(alpha) * dys; + dyr = Math.sin(alpha) * dxs + Math.cos(alpha) * dys; + + x[2] = c[1] - dxr * Type.evaluate(this.visProp.tickendings[1]); + y[2] = c[2] + dyr * Type.evaluate(this.visProp.tickendings[1]); + } + + // Check if (parts of) the tick is inside the canvas. + if (this._isInsideCanvas(x, y)) { + return [x, y, major]; + } + } + + return []; + }, + + /** + * Format label texts. Show the desired number of digits + * and use utf-8 minus sign. + * @param {Number} value Number to be displayed + * @return {String} The value converted into a string. + * @private + */ + formatLabelText: function(value) { + var labelText, + digits, + ev_s = Type.evaluate(this.visProp.scalesymbol); + + // if value is Number + if (Type.isNumber(value)) { + labelText = (Math.round(value * 1.e13) / 1.e13).toString(); + if (labelText.length > Type.evaluate(this.visProp.maxlabellength) || + labelText.indexOf('e') !== -1) { + + digits = Type.evaluate(this.visProp.digits); + if (Type.evaluate(this.visProp.precision) !== 3 && digits === 3) { + // Use the deprecated attribute "precision" + digits = Type.evaluate(this.visProp.precision); } - return n; + //labelText = value.toPrecision(digits).toString(); + labelText = value.toExponential(digits).toString(); } - ], attr); - /** - * The text element to the right of the slider, indicating its current value. - * @memberOf Slider.prototype - * @name label - * @type JXG.Text - */ - p3.label = t; + if (Type.evaluate(this.visProp.beautifulscientificticklabels)) { + labelText = this.beautifyScientificNotationLabel(labelText); + } + + if (labelText.indexOf('.') > -1 && labelText.indexOf('e') === -1) { + // trim trailing zeros + labelText = labelText.replace(/0+$/, ''); + // trim trailing . + labelText = labelText.replace(/\.$/, ''); + } + } else { + labelText = value.toString(); + } + + if (ev_s.length > 0) { + if (labelText === '1') { + labelText = ev_s; + } else if (labelText === '-1') { + labelText = '-' + ev_s; + } else if (labelText !== '0') { + labelText = labelText + ev_s; + } + } + + if (Type.evaluate(this.visProp.useunicodeminus)) { + labelText = labelText.replace(/-/g, '\u2212'); + } + return labelText; + }, + + /** + * Formats label texts to make labels displayed in scientific notation look beautiful. + * For example, label 5.00e+6 will become 5•10⁶, label -1.00e-7 will become into -1•10⁻⁷ + * @param {String} labelText - The label that we want to convert + * @returns {String} If labelText was not in scientific notation, return labelText without modifications. + * Otherwise returns beautified labelText with proper superscript notation. + */ + beautifyScientificNotationLabel: function(labelText) { + var returnString; + + if (labelText.indexOf('e') === -1) { + return labelText; + } + + // Clean up trailing 0's, so numbers like 5.00e+6.0 for example become into 5e+6 + returnString = parseFloat(labelText.substring(0, labelText.indexOf('e'))) + + labelText.substring(labelText.indexOf('e')); + + // Replace symbols like -,0,1,2,3,4,5,6,7,8,9 with their superscript version. + // Gets rid of + symbol since there is no need for it anymore. + returnString = returnString.replace(/e(.*)$/g, function(match,$1){ + var temp = '\u2022' + '10'; + // Note: Since board ticks do not support HTTP elements like <sub>, we need to replace + // all the numbers with superscript Unicode characters. + temp += $1 + .replace(/-/g, "\u207B") + .replace(/\+/g, '') + .replace(/0/g,'\u2070') + .replace(/1/g,'\u00B9') + .replace(/2/g,'\u00B2') + .replace(/3/g,'\u00B3') + .replace(/4/g,'\u2074') + .replace(/5/g,'\u2075') + .replace(/6/g,'\u2076') + .replace(/7/g,'\u2077') + .replace(/8/g,'\u2078') + .replace(/9/g,'\u2079'); + + return temp; + }); - // reset the withlabel attribute - p3.visProp.withlabel = true; - p3.hasLabel = true; - } + return returnString; + }, /** - * Start point of the base line. - * @memberOf Slider.prototype - * @name point1 - * @type JXG.Point + * Creates the label text for a given tick. A value for the text can be provided as a number or string + * + * @param {JXG.Coords} tick The Coords-object of the tick to create a label for + * @param {JXG.Coords} zero The Coords-object of line's zero + * @param {Number|String} value A predefined value for this tick + * @returns {String} + * @private */ - p3.point1 = p1; + generateLabelText: function (tick, zero, value) { + var labelText, distance; - /** - * End point of the base line. - * @memberOf Slider.prototype - * @name point2 - * @type JXG.Point - */ - p3.point2 = p2; + // No value provided, equidistant, so assign distance as value + if (!Type.exists(value)) { // could be null or undefined + distance = this.getDistanceFromZero(zero, tick); + if (Math.abs(distance) < Mat.eps) { // Point is zero + return '0'; + } + value = distance / Type.evaluate(this.visProp.scale); + } + labelText = this.formatLabelText(value); - /** - * The baseline the glider is bound to. - * @memberOf Slider.prototype - * @name baseline - * @type JXG.Line - */ - p3.baseline = l1; + return labelText; + }, /** - * A line on top of the baseline, indicating the slider's progress. - * @memberOf Slider.prototype - * @name highline - * @type JXG.Line + * Create a tick label data, i.e. text and coordinates + * @param {String} labelText + * @param {JXG.Coords} tick + * @param {Number} tickNumber + * @returns {Object} with properties 'x', 'y', 't' (text), 'i' (tick number) or null in case of o label + * @private */ - p3.highline = l2; - - if (withTicks) { - // Function to generate correct label texts - - attr = Type.copyAttributes(attributes, board.options, 'slider', 'ticks'); - if (!Type.exists(attr.generatelabeltext)) { - attr.generateLabelText = function(tick, zero, value) { - var labelText, - dFull = p3.point1.Dist(p3.point2), - smin = p3._smin, smax = p3._smax, - val = this.getDistanceFromZero(zero, tick) * (smax - smin) / dFull + smin; + generateLabelData: function (labelText, tick, tickNumber) { + var xa, ya, m, fs; - if (dFull < Mat.eps || Math.abs(val) < Mat.eps) { // Point is zero - labelText = '0'; - } else { - labelText = this.formatLabelText(val); - } - return labelText; - }; - } - ticks = 2; - ti = board.create('ticks', [ - p3.baseline, - p3.point1.Dist(p1) / ticks, + // Test if large portions of the label are inside of the canvas + // This is the last chance to abandon the creation of the label if it is mostly + // outside of the canvas. + fs = Type.evaluate(this.visProp.label.fontsize); + xa = [tick.scrCoords[1], tick.scrCoords[1]]; + ya = [tick.scrCoords[2], tick.scrCoords[2]]; + m = (fs === undefined) ? 12 : fs; + m *= 0.5; + if (!this._isInsideCanvas(xa, ya, m)) { + return null; + } - function (tick) { - var dFull = p3.point1.Dist(p3.point2), - d = p3.point1.coords.distance(Const.COORDS_BY_USER, tick); + xa = Type.evaluate(this.visProp.label.offset[0]); + ya = Type.evaluate(this.visProp.label.offset[1]); - if (dFull < Mat.eps) { - return 0; - } + return { + x: tick.usrCoords[1] + xa / (this.board.unitX), + y: tick.usrCoords[2] + ya / (this.board.unitY), + t: labelText, + i: tickNumber + }; + }, - return d / dFull * sdiff + smin; + /** + * Recalculate the tick positions and the labels. + * @returns {JXG.Ticks} + */ + update: function () { + if (this.needsUpdate) { + //this.visPropCalc.visible = Type.evaluate(this.visProp.visible); + // A canvas with no width or height will create an endless loop, so ignore it + if (this.board.canvasWidth !== 0 && this.board.canvasHeight !== 0) { + this.calculateTicksCoordinates(); } - ], attr); - - /** - * Ticks give a rough indication about the slider's current value. - * @memberOf Slider.prototype - * @name ticks - * @type JXG.Ticks - */ - p3.ticks = ti; - } - - // override the point's remove method to ensure the removal of all elements - p3.remove = function () { - if (withText) { - board.removeObject(t); + // this.updateVisibility(this.line.visPropCalc.visible); + // + // for (var i = 0; i < this.labels.length; i++) { + // if (this.labels[i] !== null) { + // this.labels[i].prepareUpdate() + // .updateVisibility(this.line.visPropCalc.visible) + // .updateRenderer(); + // } + // } } - board.removeObject(l2); - board.removeObject(l1); - board.removeObject(p2); - board.removeObject(p1); - - - Point.Point.prototype.remove.call(p3); - }; - - p1.dump = false; - p2.dump = false; - l1.dump = false; - l2.dump = false; - - p3.elType = 'slider'; - p3.parents = parents; - p3.subs = { - point1: p1, - point2: p2, - baseLine: l1, - highLine: l2 - }; - p3.inherits.push(p1, p2, l1, l2); - - if (withTicks) { - ti.dump = false; - p3.subs.ticks = ti; - p3.inherits.push(ti); - } + return this; + }, - p3.baseline.on('up', function(evt) { - var pos, c; + /** + * Uses the boards renderer to update the arc. + * @returns {JXG.Ticks} Reference to the object. + */ + updateRenderer: function () { + if (!this.needsUpdate) { + return this; + } - if (Type.evaluate(p3.visProp.moveonup) && !Type.evaluate(p3.visProp.fixed) ) { - pos = l1.board.getMousePosition(evt, 0); - c = new Coords(Const.COORDS_BY_SCREEN, pos, this.board); - p3.moveTo([c.usrCoords[1], c.usrCoords[2]]); + if (this.visPropCalc.visible) { + this.board.renderer.updateTicks(this); } - }); + this.updateRendererLabels(); - // Save the visibility attribute of the sub-elements - // for (el in p3.subs) { - // p3.subs[el].status = { - // visible: p3.subs[el].visProp.visible - // }; - // } + this.setDisplayRendNode(); + // if (this.visPropCalc.visible != this.visPropOld.visible) { + // this.board.renderer.display(this, this.visPropCalc.visible); + // this.visPropOld.visible = this.visPropCalc.visible; + // } - // p3.hideElement = function () { - // var el; - // GeometryElement.prototype.hideElement.call(this); - // - // for (el in this.subs) { - // // this.subs[el].status.visible = this.subs[el].visProp.visible; - // this.subs[el].hideElement(); - // } - // }; + this.needsUpdate = false; + return this; + }, -// p3.showElement = function () { -// var el; -// GeometryElement.prototype.showElement.call(this); -// -// for (el in this.subs) { -// // if (this.subs[el].status.visible) { -// this.subs[el].showElement(); -// // } -// } -// }; + /** + * Updates the label elements of the major ticks. + * + * @private + * @returns {JXG.Ticks} Reference to the object. + */ + updateRendererLabels: function() { + var i, j, + lenData, lenLabels, + attr, + label, ld, + visible; + // The number of labels needed + lenData = this.labelsData.length; + // The number of labels which already exist + // The existing labels are stored in this.labels[] + // The new label positions and label values are stored in this.labelsData[] + lenLabels = this.labels.length; + for (i = 0, j = 0; i < lenData; i++) { + if (this.labelsData[i] === null) { + // This is a tick without label + continue; + } - // This is necessary to show baseline, highline and ticks - // when opening the board in case the visible attributes are set - // to 'inherit'. - p3.prepareUpdate().update(); - if (!board.isSuspendedUpdate) { - p3.updateVisibility().updateRenderer(); - p3.baseline.updateVisibility().updateRenderer(); - p3.highline.updateVisibility().updateRenderer(); - if (withTicks) { - p3.ticks.updateVisibility().updateRenderer(); - } - } + ld = this.labelsData[i]; + if (j < lenLabels) { + // Take an already existing text element + label = this.labels[j]; + label.setText(ld.t); + label.setCoords(ld.x, ld.y); + j++; + } else { + // A new text element is needed + this.labelCounter += 1; - return p3; - }; + attr = { + isLabel: true, + layer: this.board.options.layer.line, + highlightStrokeColor: this.board.options.text.strokeColor, + highlightStrokeWidth: this.board.options.text.strokeWidth, + highlightStrokeOpacity: this.board.options.text.strokeOpacity, + priv: this.visProp.priv + }; + attr = Type.deepCopy(attr, this.visProp.label); + attr.id = this.id + ld.i + 'Label' + this.labelCounter; - JXG.registerElement('slider', JXG.createSlider); + label = Text.createText(this.board, [ld.x, ld.y, ld.t], attr); + this.addChild(label); + label.setParents(this); + label.isDraggable = false; + label.dump = false; + this.labels.push(label); + } - return { - createSlider: JXG.createSlider - }; -}); + // Look-ahead if the label inherits visiblity. + // If yes, update label. + visible = Type.evaluate(this.visProp.label.visible); + if (visible === 'inherit') { + visible = this.visPropCalc.visible; + } -/* - Copyright 2008-2021 - Matthias Ehmann, - Michael Gerhaeuser, - Carsten Miller, - Bianca Valentin, - Alfred Wassermann, - Peter Wilfahrt + label.prepareUpdate() + .updateVisibility(visible) + .updateRenderer(); - This file is part of JSXGraph. + label.distanceX = Type.evaluate(this.visProp.label.offset[0]); + label.distanceY = Type.evaluate(this.visProp.label.offset[1]); + } - JSXGraph is free software dual licensed under the GNU LGPL or MIT License. + // Hide unused labels + lenData = j; + for (j = lenData; j < lenLabels; j++) { + this.board.renderer.display(this.labels[j], false); + // Tick labels have the attribute "visible: 'inherit'" + // This must explicitely set to false, otherwise + // this labels would be set to visible in the upcoming + // update of the labels. + this.labels[j].visProp.visible = this.labels[j].visPropCalc.visible = false; + } - You can redistribute it and/or modify it under the terms of the + return this; + }, - * GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version - OR - * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT + hideElement: function () { + var i; - JSXGraph is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. + JXG.deprecated('Element.hideElement()', 'Element.setDisplayRendNode()'); - You should have received a copy of the GNU Lesser General Public License and - the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> - and <http://opensource.org/licenses/MIT/>. - */ + this.visPropCalc.visible = false; + this.board.renderer.display(this, false); + for (i = 0; i < this.labels.length; i++) { + if (Type.exists(this.labels[i])) { + this.labels[i].hideElement(); + } + } + return this; + }, -/*global JXG: true, define: true*/ -/*jslint nomen: true, plusplus: true*/ + showElement: function () { + var i; -/* depends: - jxg - utils/type - base/element - elements: - point - segment - ticks - */ + JXG.deprecated('Element.showElement()', 'Element.setDisplayRendNode()'); -/** - * @fileoverview Geometry objects for measurements are defined in this file. This file stores all - * style and functional properties that are required to use a tape measure on - * a board. - */ + this.visPropCalc.visible = true; + this.board.renderer.display(this, false); -define('element/measure',[ - 'jxg', 'utils/type', 'base/element', 'base/point', 'base/line', 'base/ticks' -], function (JXG, Type, GeometryElement, Point, Line, Ticks) { + for (i = 0; i < this.labels.length; i++) { + if (Type.exists(this.labels[i])) { + this.labels[i].showElement(); + } + } - "use strict"; + return this; + } + }); /** - * @class A tape measure can be used to measure distances between points. + * @class Ticks are used as distance markers on a line or curve. + * They are + * mainly used for axis elements and slider elements. Ticks may stretch infinitely + * or finitely, which can be set with {@link Ticks#majorHeight} and {@link Ticks#minorHeight}. + * * @pseudo - * @description - * @name Tapemeasure - * @augments Segment + * @description Ticks are markers on straight line elements or curves. + * @name Ticks + * @augments JXG.Ticks * @constructor - * @type JXG.Segment + * @type JXG.Ticks * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {Array_Array} start,end, The two arrays give the initial position where the tape measure - * is drawn on the board. + * @param {JXG.Line|JXG.Curve} line The parents consist of the line or curve the ticks are going to be attached to. + * @param {Number|Array} distance Number defining the distance between two major ticks or an + * array defining static ticks. In case a number is specified, the ticks are <i>equidistant</i>, + * in case of an array, a fixed number of static ticks is created at user-supplied positions. + * Alternatively, the distance can be specified with the attribute + * "ticksDistance". For arbitrary lines (and not axes) a "zero coordinate" is determined + * which defines where the first tick is positioned. This zero coordinate + * can be altered with the attribute "anchor". Possible values are "left", "middle", "right" or a number. + * The default value is "left". + * * @example - * // Create atape measure - * var p1 = board.create('point', [0,0]); - * var p2 = board.create('point', [1,1]); - * var p3 = board.create('point', [3,1]); - * var tape = board.create('tapemeasure', [[1, 2], [4, 2]], {name:'dist'}); - * </pre><div class="jxgbox" id="JXG6d9a2cda-22fe-4cd1-9d94-34283b1bdc01" style="width: 200px; height: 200px;"></div> + * // Create an axis providing two coordinate pairs. + * var p1 = board.create('point', [0, 3]); + * var p2 = board.create('point', [1, 3]); + * var l1 = board.create('line', [p1, p2]); + * var t = board.create('ticks', [l1], {ticksDistance: 2}); + * </pre><div class="jxgbox" id="JXGee7f2d68-75fc-4ec0-9931-c76918427e63" style="width: 300px; height: 300px;"></div> * <script type="text/javascript"> - * (function () { - * var board = JXG.JSXGraph.initBoard('JXG6d9a2cda-22fe-4cd1-9d94-34283b1bdc01', {boundingbox: [-1, 5, 5, -1], axis: true, showcopyright: false, shownavigation: false}); - * var p1 = board.create('point', [0,0]); - * var p2 = board.create('point', [1,1]); - * var p3 = board.create('point', [3,1]); - * var tape = board.create('tapemeasure', [[1, 2], [4, 2]], {name:'dist'} ); - * })(); + * (function () { + * var board = JXG.JSXGraph.initBoard('JXGee7f2d68-75fc-4ec0-9931-c76918427e63', {boundingbox: [-1, 7, 7, -1], showcopyright: false, shownavigation: false}); + * var p1 = board.create('point', [0, 3]); + * var p2 = board.create('point', [1, 3]); + * var l1 = board.create('line', [p1, p2]); + * var t = board.create('ticks', [l1, 2], {ticksDistance: 2}); + * })(); * </script><pre> */ - JXG.createTapemeasure = function (board, parents, attributes) { - var pos0, pos1, - attr, withTicks, withText, precision, - li, p1, p2, n, ti; - - pos0 = parents[0]; - pos1 = parents[1]; - - // start point - attr = Type.copyAttributes(attributes, board.options, 'tapemeasure', 'point1'); - p1 = board.create('point', pos0, attr); - - // end point - attr = Type.copyAttributes(attributes, board.options, 'tapemeasure', 'point2'); - p2 = board.create('point', pos1, attr); - - p1.setAttribute({ignoredSnapToPoints: [p2]}); - p2.setAttribute({ignoredSnapToPoints: [p1]}); - - // tape measure line - attr = Type.copyAttributes(attributes, board.options, 'tapemeasure'); - withTicks = attr.withticks; - withText = attr.withlabel; - precision = attr.precision; - - // Below, we will replace the label by the measurement function. - if (withText) { - attr.withlabel = true; - } - li = board.create('segment', [p1, p2], attr); - // p1, p2 are already added to li.inherits + JXG.createTicks = function (board, parents, attributes) { + var el, dist, + attr = Type.copyAttributes(attributes, board.options, 'ticks'); - if (withText) { - if (attributes.name && attributes.name !== '') { - n = attributes.name + ' = '; - } else { - n = ''; - } - li.label.setText(function () { - return n + Type.toFixed(p1.Dist(p2), precision); - }); + if (parents.length < 2) { + dist = attr.ticksdistance; + } else { + dist = parents[1]; } - if (withTicks) { - attr = Type.copyAttributes(attributes, board.options, 'tapemeasure', 'ticks'); - //ticks = 2; - ti = board.create('ticks', [li, 0.1], attr); - li.inherits.push(ti); + if (parents[0].elementClass === Const.OBJECT_CLASS_LINE || + parents[0].elementClass === Const.OBJECT_CLASS_CURVE) { + el = new JXG.Ticks(parents[0], dist, attr); + } else { + throw new Error("JSXGraph: Can't create Ticks with parent types '" + (typeof parents[0]) + "'."); } - // override the segments's remove method to ensure the removal of all elements - /** @ignore */ - li.remove = function () { - if (withTicks) { - li.removeTicks(ti); - } - - board.removeObject(p2); - board.removeObject(p1); - - GeometryElement.prototype.remove.call(this); - }; - - /** - * Returns the length of the tape measure. - * @name Value - * @memberOf Tapemeasure.prototype - * @function - * @returns {Number} length of tape measure. - */ - li.Value = function () { - return p1.Dist(p2); - }; + // deprecated + if (Type.isFunction(attr.generatelabelvalue)) { + el.generateLabelText = attr.generatelabelvalue; + } + if (Type.isFunction(attr.generatelabeltext)) { + el.generateLabelText = attr.generatelabeltext; + } - p1.dump = false; - p2.dump = false; + el.setParents(parents[0]); + el.isDraggable = true; + el.fullUpdate(parents[0].visPropCalc.visible); - li.elType = 'tapemeasure'; - li.getParents = function() { - return [[p1.X(), p1.Y()], [p2.X(), p2.Y()]]; - }; + return el; + }; - li.subs = { - point1: p1, - point2: p2 - }; + /** + * @class Hatches can be used to mark congruent lines or curves. + * @pseudo + * @description + * @name Hatch + * @augments JXG.Ticks + * @constructor + * @type JXG.Ticks + * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {JXG.Line|JXG.curve} line The line or curve the hatch marks are going to be attached to. + * @param {Number} numberofhashes Number of dashes. + * @example + * // Create an axis providing two coords pairs. + * var p1 = board.create('point', [0, 3]); + * var p2 = board.create('point', [1, 3]); + * var l1 = board.create('line', [p1, p2]); + * var t = board.create('hatch', [l1, 3]); + * </pre><div class="jxgbox" id="JXG4a20af06-4395-451c-b7d1-002757cf01be" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function () { + * var board = JXG.JSXGraph.initBoard('JXG4a20af06-4395-451c-b7d1-002757cf01be', {boundingbox: [-1, 7, 7, -1], showcopyright: false, shownavigation: false}); + * var p1 = board.create('point', [0, 3]); + * var p2 = board.create('point', [1, 3]); + * var l1 = board.create('line', [p1, p2]); + * var t = board.create('hatch', [l1, 3]); + * })(); + * </script><pre> + * + * @example + * // Alter the position of the hatch + * + * var p = board.create('point', [-5, 0]); + * var q = board.create('point', [5, 0]); + * var li = board.create('line', [p, q]); + * var h = board.create('hatch', [li, 2], {anchor: 0.2}); + * + * </pre><div id="JXG05d720ee-99c9-11e6-a9c7-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG05d720ee-99c9-11e6-a9c7-901b0e1b8723', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * + * var p = board.create('point', [-5, 0]); + * var q = board.create('point', [5, 0]); + * var li = board.create('line', [p, q]); + * var h = board.create('hatch', [li, 2], {anchor: 0.2}); + * + * })(); + * + * </script><pre> + * + * @example + * // Alternative hatch faces + * + * var li = board.create('line', [[-6,0], [6,3]]); + * var h1 = board.create('hatch', [li, 2], {tickEndings: [1,1], face:'|'}); + * var h2 = board.create('hatch', [li, 2], {tickEndings: [1,1], face:'>', anchor: 0.3}); + * var h3 = board.create('hatch', [li, 2], {tickEndings: [1,1], face:'<', anchor: 0.7}); + * + * </pre><div id="JXG974f7e89-eac8-4187-9aa3-fb8068e8384b" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG974f7e89-eac8-4187-9aa3-fb8068e8384b', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * // Alternative hatch faces + * + * var li = board.create('line', [[-6,0], [6,3]]); + * var h1 = board.create('hatch', [li, 2], {tickEndings: [1,1], face:'|'}); + * var h2 = board.create('hatch', [li, 2], {tickEndings: [1,1], face:'>', anchor: 0.3}); + * var h3 = board.create('hatch', [li, 2], {tickEndings: [1,1], face:'<', anchor: 0.7}); + * + * })(); + * + * </script><pre> + * + */ + JXG.createHatchmark = function (board, parents, attributes) { + var num, i, base, width, totalwidth, el, + pos = [], + attr = Type.copyAttributes(attributes, board.options, 'hatch'); - if (withTicks) { - ti.dump = false; + if ((parents[0].elementClass !== Const.OBJECT_CLASS_LINE && + parents[0].elementClass !== Const.OBJECT_CLASS_CURVE) || typeof parents[1] !== 'number') { + throw new Error("JSXGraph: Can't create Hatch mark with parent types '" + (typeof parents[0]) + "' and '" + (typeof parents[1]) + " and ''" + (typeof parents[2]) + "'."); } - li.methodMap = JXG.deepCopy(li.methodMap, { - Value: 'Value' - }); + num = parents[1]; + width = attr.ticksdistance; + totalwidth = (num - 1) * width; + base = -totalwidth * 0.5; - li.prepareUpdate().update(); - if (!board.isSuspendedUpdate) { - li.updateVisibility().updateRenderer(); - // The point updates are necessary in case of snapToGrid==true - li.point1.updateVisibility().updateRenderer(); - li.point2.updateVisibility().updateRenderer(); + for (i = 0; i < num; i++) { + pos[i] = base + i * width; } - return li; + el = board.create('ticks', [parents[0], pos], attr); + el.elType = 'hatch'; + + return el; }; - JXG.registerElement('tapemeasure', JXG.createTapemeasure); + JXG.registerElement('ticks', JXG.createTicks); + JXG.registerElement('hash', JXG.createHatchmark); + JXG.registerElement('hatch', JXG.createHatchmark); return { - createTapemeasure: JXG.createTapemeasure + Ticks: JXG.Ticks, + createTicks: JXG.createTicks, + createHashmark: JXG.createHatchmark, + createHatchmark: JXG.createHatchmark }; }); /* - Copyright 2008-2021 - Matthias Ehmann, - Michael Gerhaeuser, - Carsten Miller, - Bianca Valentin, - Alfred Wassermann, - Peter Wilfahrt + JessieCode Computer algebra algorithms - This file is part of JSXGraph. + Copyright 2011-2019 + Michael Gerhaeuser, + Alfred Wassermann - JSXGraph is free software dual licensed under the GNU LGPL or MIT License. + JessieCode is free software dual licensed under the GNU LGPL or MIT License. You can redistribute it and/or modify it under the terms of the @@ -67603,1606 +76830,1995 @@ define('element/measure',[ OR * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT - JSXGraph is distributed in the hope that it will be useful, + JessieCode is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License and - the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> + the MIT License along with JessieCode. If not, see <http://www.gnu.org/licenses/> and <http://opensource.org/licenses/MIT/>. */ - -/*global JXG: true, define: true, document: true*/ +/*global JXG: true, define: true, window: true, console: true, self: true, document: true, parser: true*/ /*jslint nomen: true, plusplus: true*/ +/*eslint eqeqeq: "off"*/ /* depends: jxg + parser/geonext + base/constants + base/text + math/math + math/geometry + math/statistics utils/type + utils/uuid */ /** - * @fileoverview The JXG.DataSource is a helper class for data organization. Currently supported data sources are - * javascript arrays and HTML tables. + * @fileoverview Here, the computer algebra algorithms are implemented. */ -define('parser/datasource',['jxg', 'utils/type'], function (JXG, Type) { +define('parser/ca',[ + 'jxg', 'base/constants', 'base/text', 'math/math', 'math/geometry', 'math/statistics', 'utils/type', 'utils/env' +], function (JXG, Const, Text, Mat, Geometry, Statistics, Type, Env) { "use strict"; - JXG.DataSource = function () { - this.data = []; - this.columnHeaders = []; - this.rowHeaders = []; - - return this; + /** + * A JessieCode object provides an interface to the parser and stores all variables and objects used within a JessieCode script. + * The optional argument <tt>code</tt> is interpreted after initializing. To evaluate more code after initializing a JessieCode instance + * please use {@link JXG.JessieCode#parse}. For code snippets like single expressions use {@link JXG.JessieCode#snippet}. + * @constructor + * @param {String} [code] Code to parse. + * @param {Boolean} [geonext=false] Geonext compatibility mode. + */ + JXG.CA = function (node, createNode, parser) { + this.node = node; + this.createNode = createNode; + this.parser = parser; }; - JXG.extend(JXG.DataSource.prototype, /** @lends JXG.DataSource.prototype */ { - loadFromArray: function (table, columnHeader, rowHeader) { - var i, j, cell; - - if (Type.isArray(columnHeader)) { - this.columnHeaders = columnHeader; - columnHeader = false; - } + JXG.extend(JXG.CA.prototype, /** @lends JXG.CA.prototype */ { + findMapNode: function (mapname, node) { + var i, len, ret; - if (Type.isArray(rowHeader)) { - this.rowHeaders = rowHeader; - rowHeader = false; + //console.log("FINDMAP", node); + if (node.value === 'op_assign' && node.children[0].value === mapname) { + return node.children[1]; + } else if (node.children) { + len = node.children.length; + for (i = 0; i < len; ++i) { + ret = this.findMapNode(mapname, node.children[i]); + if (ret !== null) { + return ret; + } + } } + return null; + }, - this.data = []; + /** + * Declare all subnodes as math nodes, + * i.e recursively set node.isMath = true; + */ + setMath: function (node) { + var i, len; - if (columnHeader) { - this.columnHeaders = []; - } + if ((node.type == 'node_op' && ( + node.value == 'op_add' || node.value == 'op_sub' || + node.value == 'op_mul' || node.value == 'op_div' || + node.value == 'op_neg' || node.value == 'op_execfun' || + node.value == 'op_exp')) || + node.type == 'node_var' || node.type == 'node_const') { - if (rowHeader) { - this.rowHeaders = []; + node.isMath = true; } - - if (Type.exists(table)) { - // extract the data - this.data = []; - - for (i = 0; i < table.length; i++) { - this.data[i] = []; - - for (j = 0; j < table[i].length; j++) { - cell = table[i][j]; - if (parseFloat(cell).toString() === cell) { - this.data[i][j] = parseFloat(cell); - } else if (cell !== '-') { - this.data[i][j] = cell; - } else { - this.data[i][j] = NaN; - } - } - } - - if (columnHeader) { - this.columnHeaders = this.data[0].slice(1); - this.data = this.data.slice(1); - } - - if (rowHeader) { - this.rowHeaders = []; - for (i = 0; i < this.data.length; i++) { - this.rowHeaders.push(this.data[i][0]); - this.data[i] = this.data[i].slice(1); - } + if (node.children) { + len = node.children.length; + for (i = 0; i < len; ++i) { + this.setMath(node.children[i]); } } - - return this; }, - loadFromTable: function (table, columnHeader, rowHeader) { - var row, i, j, col, cell, name; - - if (Type.isArray(columnHeader)) { - this.columnHeaders = columnHeader; - columnHeader = false; - } + deriveElementary: function (node, varname) { + var fun = node.children[0].value, + arg = node.children[1], + newNode; - if (Type.isArray(rowHeader)) { - this.rowHeaders = rowHeader; - rowHeader = false; - } - this.data = []; + switch (fun) { + case 'abs': + // x / sqrt(x * x) + newNode = this.createNode('node_op', 'op_div', + arg[0], + this.createNode('node_op', 'op_execfun', + this.createNode('node_var', 'sqrt'), + [this.createNode('node_op', 'op_mul', + Type.deepCopy(arg[0]), + Type.deepCopy(arg[0]) + )] + ) + ); + break; - if (columnHeader) { - this.columnHeaders = []; - } + case 'sqrt': + newNode = this.createNode('node_op', 'op_div', + this.createNode('node_const', 1.0), + this.createNode('node_op', 'op_mul', + this.createNode('node_const', 2.0), + this.createNode(node.type, node.value, + Type.deepCopy(node.children[0]), + Type.deepCopy(node.children[1]) + ) + ) + ); + break; - if (rowHeader) { - this.rowHeaders = []; - } + case 'sin': + newNode = this.createNode('node_op', 'op_execfun', + this.createNode('node_var', 'cos'), + Type.deepCopy(arg) + ); + break; - // to adjust: examples in examples folder & wiki - table = document.getElementById(table); + case 'cos': + newNode = this.createNode('node_op', 'op_neg', + this.createNode('node_op', 'op_execfun', + this.createNode('node_var', 'sin'), + Type.deepCopy(arg) + ) + ); + break; - if (Type.exists(table)) { - // extract the data - row = table.getElementsByTagName('tr'); - this.data = []; + case 'tan': + newNode = this.createNode('node_op', 'op_div', + this.createNode('node_const', 1.0), + this.createNode('node_op', 'op_exp', + this.createNode('node_op', 'op_execfun', + this.createNode('node_var', 'cos'), + Type.deepCopy(arg) + ), + this.createNode('node_const', 2) + ) + ); + break; - for (i = 0; i < row.length; i++) { - col = row[i].getElementsByTagName('td'); - this.data[i] = []; + case 'cot': + newNode = this.createNode('node_op', 'op_neg', + this.createNode('node_op', 'op_div', + this.createNode('node_const', 1.0), + this.createNode('node_op', 'op_exp', + this.createNode('node_op', 'op_execfun', + this.createNode('node_var', 'sin'), + Type.deepCopy(arg) + ), + this.createNode('node_const', 2) + ) + ) + ); + break; - for (j = 0; j < col.length; j++) { - cell = col[j].innerHTML; + case 'exp': + newNode = this.createNode(node.type, node.value, + Type.deepCopy(node.children[0]), + Type.deepCopy(node.children[1]) + ); + break; - if (parseFloat(cell).toString() === cell) { - this.data[i][j] = parseFloat(cell); - } else if (cell !== '-') { - this.data[i][j] = cell; - } else { - this.data[i][j] = NaN; - } - } - } + case 'pow': + // (f^g)' = f^g*(f'g/f + g' log(f)) + newNode = this.createNode('node_op', 'op_mul', + this.createNode('node_op', 'op_execfun', + Type.deepCopy(node.children[0]), + Type.deepCopy(node.children[1]) + ), + this.createNode('node_op', 'op_add', + this.createNode('node_op', 'op_mul', + this.derivative(node.children[1][0], varname), + this.createNode('node_op', 'op_div', + Type.deepCopy(node.children[1][1]), + Type.deepCopy(node.children[1][0]) + ) + ), + this.createNode('node_op', 'op_mul', + this.derivative(node.children[1][1], varname), + this.createNode('node_op', 'op_execfun', + this.createNode('node_var', 'log'), + [Type.deepCopy(node.children[1][0])] + ) + ) + ) + ); + break; - if (columnHeader) { - this.columnHeaders = this.data[0].slice(1); - this.data = this.data.slice(1); - } + case 'log': + case 'ln': + newNode = this.createNode('node_op', 'op_div', + this.createNode('node_const', 1.0), + // Attention: single variable mode + Type.deepCopy(arg[0]) + ); + break; - if (rowHeader) { - this.rowHeaders = []; - for (i = 0; i < this.data.length; i++) { - this.rowHeaders.push(this.data[i][0]); - this.data[i] = this.data[i].slice(1); - } - } - } + case 'log2': + case 'lb': + case 'ld': + newNode = this.createNode('node_op', 'op_mul', + this.createNode('node_op', 'op_div', + this.createNode('node_const', 1.0), + // Attention: single variable mode + Type.deepCopy(arg[0]) + ), + this.createNode('node_const', 1.4426950408889634) // 1/log(2) + ); + break; - return this; - }, + case 'log10': + case 'lg': + newNode = this.createNode('node_op', 'op_mul', + this.createNode('node_op', 'op_div', + this.createNode('node_const', 1.0), + // Attention: single variable mode + Type.deepCopy(arg[0]) + ), + this.createNode('node_const', 0.43429448190325176) // 1/log(10) + ); + break; - addColumn: function (name, pos, data) { - throw new Error('not implemented'); - }, + case 'asin': + newNode = this.createNode('node_op', 'op_div', + this.createNode('node_const', 1.0), + this.createNode('node_op', 'op_execfun', + this.createNode('node_var', 'sqrt'), + [ + this.createNode('node_op', 'op_sub', + this.createNode('node_const', 1.0), + this.createNode('node_op', 'op_mul', + Type.deepCopy(arg[0]), + Type.deepCopy(arg[0]) + ) + ) + ] + ) + ); + break; - addRow: function (name, pos, data) { - throw new Error('not implemented'); - }, + case 'acos': + newNode = this.createNode('node_op', 'op_neg', + this.createNode('node_op', 'op_div', + this.createNode('node_const', 1.0), + this.createNode('node_op', 'op_execfun', + this.createNode('node_var', 'sqrt'), + [ + this.createNode('node_op', 'op_sub', + this.createNode('node_const', 1.0), + this.createNode('node_op', 'op_mul', + Type.deepCopy(arg[0]), + Type.deepCopy(arg[0]) + ) + ) + ] + ) + ) + ); + break; - getColumn: function (col) { - var i, - result = []; + //case 'atan2': - // get column index if column is given as column header title - if (Type.isString(col)) { - for (i = 0; i < this.columnHeaders.length; i++) { - if (col === this.columnHeaders[i]) { - col = i; - break; - } - } - } + case 'atan': + newNode = this.createNode('node_op', 'op_div', + this.createNode('node_const', 1.0), + this.createNode('node_op', 'op_add', + this.createNode('node_const', 1.0), + this.createNode('node_op', 'op_mul', + Type.deepCopy(arg[0]), + Type.deepCopy(arg[0]) + ) + ) + ); + break; - // build column array - for (i = 0; i < this.data.length; i++) { - if (this.data[i].length > col) { - result[i] = parseFloat(this.data[i][col]); - } - } + case 'acot': + newNode = this.createNode('node_op', 'op_neg', + this.createNode('node_op', 'op_div', + this.createNode('node_const', 1.0), + this.createNode('node_op', 'op_add', + this.createNode('node_const', 1.0), + this.createNode('node_op', 'op_mul', + Type.deepCopy(arg[0]), + Type.deepCopy(arg[0]) + ) + ) + ) + ); + break; - return result; - }, + case 'sinh': + newNode = this.createNode('node_op', 'op_execfun', + this.createNode('node_var', 'cosh'), + [Type.deepCopy(arg[0])] + ); + break; - getRow: function (row) { - var result, i; + case 'cosh': + newNode = this.createNode('node_op', 'op_execfun', + this.createNode('node_var', 'sinh'), + [Type.deepCopy(arg[0])] + ); + break; - // get column index if column is given as column header title - if (Type.isString(row)) { - for (i = 0; i < this.rowHeaders.length; i++) { - if (row === this.rowHeaders[i]) { - row = i; - break; - } - } - } + case 'tanh': + newNode = this.createNode('node_op', 'op_sub', + this.createNode('node_const', 1.0), + this.createNode('node_op', 'op_exp', + this.createNode('node_op', 'op_execfun', + this.createNode('node_var', 'tanh'), + [Type.deepCopy(arg[0])] + ), + this.createNode('node_const', 2.0) + ) + ); + break; - // allocate memory for result array - result = []; + case 'asinh': + newNode = this.createNode('node_op', 'op_div', + this.createNode('node_const', 1.0), + this.createNode('node_op', 'op_execfun', + this.createNode('node_var', 'sqrt'), + [ + this.createNode('node_op', 'op_add', + this.createNode('node_op', 'op_mul', + Type.deepCopy(arg[0]), + Type.deepCopy(arg[0]) + ), + this.createNode('node_const', 1.0) + ) + ] + ) + ); + break; - // build column array. result = this.data[row] is a flat copy and will - // destroy our local data copy, that's why we're copying it element wise. - for (i = 0; i < this.data[row].length; i++) { - result[i] = this.data[row][i]; - } + case 'acosh': + newNode = this.createNode('node_op', 'op_div', + this.createNode('node_const', 1.0), + this.createNode('node_op', 'op_execfun', + this.createNode('node_var', 'sqrt'), + [ + this.createNode('node_op', 'op_sub', + this.createNode('node_op', 'op_mul', + Type.deepCopy(arg[0]), + Type.deepCopy(arg[0]) + ), + this.createNode('node_const', 1.0) + ) + ] + ) + ); + break; - return result; - } - }); + case 'atanh': + newNode = this.createNode('node_op', 'op_div', + this.createNode('node_const', 1.0), + this.createNode('node_op', 'op_sub', + this.createNode('node_const', 1.0), + this.createNode('node_op', 'op_mul', + Type.deepCopy(arg[0]), + Type.deepCopy(arg[0]) + ) + ) + ); + break; - return JXG.DataSource; -}); + default: + newNode = this.createNode('node_const', 0.0); + console.log('Derivative of "' + fun + '" not yet implemented'); + throw new Error('Error(' + this.line + '): '); + // this._error('Derivative of "' + fun + '" not yet implemented'); -/* - Copyright 2008-2021 - Matthias Ehmann, - Michael Gerhaeuser, - Carsten Miller, - Bianca Valentin, - Alfred Wassermann, - Peter Wilfahrt + } - This file is part of JSXGraph. + return newNode; + }, - JSXGraph is free software dual licensed under the GNU LGPL or MIT License. + derivative: function (node, varname) { + var newNode; - You can redistribute it and/or modify it under the terms of the + switch (node.type) { + case 'node_op': + switch (node.value) { + /* + case 'op_map': + if (true) { + newNode = this.createNode('node_op', 'op_map', + Type.deepCopy(node.children[0]), + this.derivative(node.children[1], varname) + ); + } else { + newNode = this.derivative(node.children[1], varname); + } + break; + */ + case 'op_execfun': + // f'(g(x))g'(x) + if (node.children[0].value == 'pow') { + newNode = this.deriveElementary(node, varname); + } else { + if (node.children[1].length === 0) { + newNode = this.createNode('node_const', 0.0); + } else { + newNode = this.createNode('node_op', 'op_mul', + this.deriveElementary(node, varname), + // Warning: single variable mode + this.derivative(node.children[1][0], varname) + ); + } + } + break; - * GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version - OR - * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT + case 'op_div': + // (f'g − g'f )/(g*g) + newNode = this.createNode('node_op', 'op_div', + this.createNode('node_op', 'op_sub', + this.createNode('node_op', 'op_mul', + this.derivative(node.children[0], varname), + Type.deepCopy(node.children[1]) + ), + this.createNode('node_op', 'op_mul', + Type.deepCopy(node.children[0]), + this.derivative(node.children[1], varname) + ) + ), + this.createNode('node_op', 'op_mul', + Type.deepCopy(node.children[1]), + Type.deepCopy(node.children[1]) + ) + ); + break; - JSXGraph is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. + case 'op_mul': + // fg' + f'g + newNode = this.createNode('node_op', 'op_add', + this.createNode('node_op', 'op_mul', + Type.deepCopy(node.children[0]), + this.derivative(node.children[1], varname)), + this.createNode('node_op', 'op_mul', + this.derivative(node.children[0], varname), + Type.deepCopy(node.children[1])) + ); + break; - You should have received a copy of the GNU Lesser General Public License and - the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> - and <http://opensource.org/licenses/MIT/>. - */ + case 'op_neg': + newNode = this.createNode('node_op', 'op_neg', + this.derivative(node.children[0], varname) + ); + break; + case 'op_add': + case 'op_sub': + newNode = this.createNode('node_op', node.value, + this.derivative(node.children[0], varname), + this.derivative(node.children[1], varname) + ); + break; -/*global JXG: true, define: true, document: true*/ -/*jslint nomen: true, plusplus: true*/ + case 'op_exp': + // (f^g)' = f^g*(f'g/f + g' log(f)) + newNode = this.createNode('node_op', 'op_mul', + Type.deepCopy(node), + this.createNode('node_op', 'op_add', + this.createNode('node_op', 'op_mul', + this.derivative(node.children[0], varname), + this.createNode('node_op', 'op_div', + Type.deepCopy(node.children[1]), + Type.deepCopy(node.children[0]) + ) + ), + this.createNode('node_op', 'op_mul', + this.derivative(node.children[1], varname), + this.createNode('node_op', 'op_execfun', + this.createNode('node_var', 'log'), + [Type.deepCopy(node.children[0])] + ) + ) + ) + ); + break; + } + break; -/* depends: - jxg - math/numerics - math/statistics - base/constants - base/coords - base/element - parser/datasource - utils/color - utils/type - utils/env - elements: - curve - spline - functiongraph - point - text - polygon - sector - transform - line - legend - circle - */ + case 'node_var': + //console.log('node_var', node); + if (node.value === varname) { + newNode = this.createNode('node_const', 1.0); + } else { + newNode = this.createNode('node_const', 0.0); + } + break; -define('base/chart',[ - 'jxg', 'math/numerics', 'math/statistics', 'base/constants', 'base/coords', 'base/element', 'parser/datasource', - 'utils/color', 'utils/type', 'utils/env', 'base/curve', 'base/point', 'base/text', 'base/polygon', 'element/sector', - 'base/transformation', 'base/line', 'base/circle' -], function (JXG, Numerics, Statistics, Const, Coords, GeometryElement, DataSource, Color, Type, Env, Curve, Point, Text, - Polygon, Sector, Transform, Line, Circle) { + case 'node_const': + newNode = this.createNode('node_const', 0.0); + break; - "use strict"; + case 'node_const_bool': + break; - /** - * - * The Chart class is a basic class for the chart object. - * @class Creates a new basic chart object. Do not use this constructor to create a chart. - * Use {@link JXG.Board#create} with type {@link Chart} instead. - * @constructor - * @augments JXG.GeometryElement - * @param {String,JXG.Board} board The board the new chart is drawn on. - * @param {Array} parent data arrays for the chart - * @param {Object} attributes Javascript object containing attributes like name, id and colors. - * - */ - JXG.Chart = function (board, parents, attributes) { - this.constructor(board, attributes); + case 'node_str': + break; - var x, y, i, c, style, len; + } - if (!Type.isArray(parents) || parents.length === 0) { - throw new Error('JSXGraph: Can\'t create a chart without data'); - } + return newNode; + }, /** - * Contains pointers to the various subelements of the chart. + * f = map (x) -> x*sin(x); + * Usages: + * h = D(f, x); + * h = map (x) -> D(f, x); + * */ - this.elements = []; + expandDerivatives: function (node, parent, ast) { + var len, i, j, mapNode, codeNode, ret, node2, newNode, + mapName, varname, vArray, order; - if (Type.isNumber(parents[0])) { - // parents looks like [a,b,c,..] - // x has to be filled + ret = 0; + if (!node) { + return ret; + } - y = parents; - x = []; - for (i = 0; i < y.length; i++) { - x[i] = i + 1; + this.line = node.line; + this.col = node.col; + + // First we have to go down in the tree. + // This ensures that in cases like D(D(f,x),x) the inner D is expanded first. + len = node.children.length; + for (i = 0; i < len; ++i) { + if (node.children[i] && node.children[i].type) { + node.children[i] = this.expandDerivatives(node.children[i], node, ast); + } else if (Type.isArray(node.children[i])) { + for (j = 0; j < node.children[i].length; ++j) { + if (node.children[i][j] && node.children[i][j].type) { + node.children[i][j] = this.expandDerivatives(node.children[i][j], node, ast); + } + } + } } - } else if (parents.length === 1 && Type.isArray(parents[0])) { - // parents looks like [[a,b,c,..]] - // x has to be filled - y = parents[0]; - x = []; + switch (node.type) { + case 'node_op': + switch (node.value) { + case 'op_execfun': + if (node.children[0] && node.children[0].value === 'D') { + if (node.children[1][0].type == 'node_var') { + /* + * Derive map, that is compute D(f,x) + * where e.g. f = map (x) -> x^2 + * + * First step: find node where the map is defined + */ + mapName = node.children[1][0].value; + mapNode = this.findMapNode(mapName, ast); + vArray = mapNode.children[0]; + + // Variable name for differentiation + if (node.children[1].length >= 2) { + varname = node.children[1][1].value; + } else { + varname = mapNode.children[0][0]; // Usually it's 'x' + } + codeNode = mapNode.children[1]; + } else { + /* + * Derive expression, e.g. + * D(2*x, x) + */ + codeNode = node.children[1][0]; + vArray = ['x']; + + // Variable name for differentiation and order + if (node.children[1].length >= 2) { + varname = node.children[1][1].value; + } else { + varname = 'x'; + } + } - len = Type.evaluate(y).length; - for (i = 0; i < len; i++) { - x[i] = i + 1; + // Differentiation order + if (node.children[1].length >= 3) { + order = node.children[1][2].value; + } else { + order = 1; + } + + // Create node which contains the derivative + newNode = codeNode; + //newNode = this.removeTrivialNodes(newNode); + if (order >= 1) { + while (order >= 1) { + newNode = this.derivative(newNode, varname); + newNode = this.removeTrivialNodes(newNode); + order--; + } + } + + // Replace the node containing e.g. D(f,x) by the derivative. + if (parent.type == 'node_op' && parent.value == 'op_assign') { + // If D is an assignment it has to be replaced by a map + // h = D(f, x) + node2 = this.createNode('node_op', 'op_map', + vArray, + newNode + ); + } else { + node2 = newNode; + } + + this.setMath(node2); + node.type = node2.type; + node.value = node2.value; + node.children[0] = node2.children[0]; + node.children[1] = node2.children[1]; + } + } + break; + + case 'node_var': + case 'node_const': + case 'node_const_bool': + case 'node_str': + break; } - } else if (parents.length === 2) { - // parents looks like [[x0,x1,x2,...],[y1,y2,y3,...]] - len = Math.min(parents[0].length, parents[1].length); - x = parents[0].slice(0, len); - y = parents[1].slice(0, len); - } - if (Type.isArray(y) && y.length === 0) { - throw new Error('JSXGraph: Can\'t create charts without data.'); - } + return node; + }, - // does this really need to be done here? this should be done in createChart and then - // there should be an extra chart for each chartstyle - style = attributes.chartstyle.replace(/ /g, '').split(','); - for (i = 0; i < style.length; i++) { - switch (style[i]) { - case 'bar': - c = this.drawBar(board, x, y, attributes); - break; - case 'line': - c = this.drawLine(board, x, y, attributes); - break; - case 'fit': - c = this.drawFit(board, x, y, attributes); - break; - case 'spline': - c = this.drawSpline(board, x, y, attributes); - break; - case 'pie': - c = this.drawPie(board, y, attributes); - break; - case 'point': - c = this.drawPoints(board, x, y, attributes); - break; - case 'radar': - c = this.drawRadar(board, parents, attributes); - break; + removeTrivialNodes: function (node) { + var i, len, n0, n1, swap; + + // In case of 'op_execfun' the children[1] node is an array. + if (Type.isArray(node)) { + len = node.length; + for (i = 0; i < len; ++i) { + node[i] = this.removeTrivialNodes(node[i]); + } + } + if (node.type != 'node_op' || !node.children) { + return node; } - this.elements.push(c); - } - this.id = this.board.setId(this, 'Chart'); - return this.elements; - }; + len = node.children.length; + for (i = 0; i < len; ++i) { + this.mayNotBeSimplified = false; + do { + node.children[i] = this.removeTrivialNodes(node.children[i]); + } while (this.mayNotBeSimplified); - JXG.Chart.prototype = new GeometryElement(); + } - JXG.extend(JXG.Chart.prototype, /** @lends JXG.Chart.prototype */ { - /** - * Create line chart defined by two data arrays. - * - * @param {String,JXG.Board} board The board the chart is drawn on - * @param {Array} x Array of x-coordinates - * @param {Array} y Array of y-coordinates - * @param {Object} attributes Javascript object containing attributes like colors - * @returns {JXG.Curve} JSXGraph curve - */ - drawLine: function (board, x, y, attributes) { - // we don't want the line chart to be filled - attributes.fillcolor = 'none'; - attributes.highlightfillcolor = 'none'; + switch (node.value) { + // Allow maps of the form + // map (x) -> x; + case 'op_map': + n0 = node.children[0]; + n1 = node.children[1]; + if (n1.type == 'node_var') { + for (i = 0; i < n0.length; ++i) { + // Allow maps of the form map(x) -> x + if (n0[i] == n1.value) { + n1.isMath = true; + break; + } + } + } + break; - return board.create('curve', [x, y], attributes); - }, + // a + 0 -> a + // 0 + a -> a + case 'op_add': + n0 = node.children[0]; + n1 = node.children[1]; + if (n0.type == 'node_const' && n0.value === 0.0) { + return n1; + } + if (n1.type == 'node_const' && n1.value === 0.0) { + return n0; + } - /** - * Create line chart that consists of a natural spline curve - * defined by two data arrays. - * - * @param {String,JXG.Board} board The board the chart is drawn on - * @param {Array} x Array of x-coordinates - * @param {Array} y Array of y-coordinates - * @param {Object} attributes Javascript object containing attributes like colors - * @returns {JXG.Curve} JSXGraph (natural) spline curve - */ - drawSpline: function (board, x, y, attributes) { - // we don't want the spline chart to be filled - attributes.fillColor = 'none'; - attributes.highlightfillcolor = 'none'; + // const + const -> const + if (n0.type == 'node_const' && n1.type == 'node_const') { + n0.value += n1.value; + return n0; + } + break; - return board.create('spline', [x, y], attributes); - }, + // 1 * a = a + // a * 1 = a + // a * 0 = 0 + // 0 * a = 0 + // - * - = + + // Order children + case 'op_mul': + n0 = node.children[0]; + n1 = node.children[1]; + if (n0.type == 'node_const' && n0.value == 1.0) { + return n1; + } + if (n1.type == 'node_const' && n1.value == 1.0) { + return n0; + } + if (n0.type == 'node_const' && n0.value === 0.0) { + return n0; + } + if (n1.type == 'node_const' && n1.value === 0.0) { + return n1; + } + if (n1.type == 'node_const' && n1.value === 0.0) { + return n1; + } - /** - * Create line chart where the curve is given by a regression polynomial - * defined by two data arrays. The degree of the polynomial is supplied - * through the attribute "degree" in attributes. - * - * @param {String,JXG.Board} board The board the chart is drawn on - * @param {Array} x Array of x-coordinates - * @param {Array} y Array of y-coordinates - * @param {Object} attributes Javascript object containing attributes like colors - * @returns {JXG.Curve} JSXGraph function graph object - */ - drawFit: function (board, x, y, attributes) { - var deg = attributes.degree; + // (-a) * (-b) -> a*b + if (n0.type == 'node_op' && n0.value == 'op_neg' && + n1.type == 'node_op' && n1.value == 'op_neg') { + node.children = [n0.children[0], n1.children[0]]; + this.mayNotBeSimplified = true; + return node; + } + // (-a) * b -> -(a*b) + if (n0.value == 'op_neg' && n1.value != 'op_neg') { + node.type = 'node_op'; + node.value = 'op_neg'; + node.children = [this.createNode('node_op', 'op_mul', n0.children[0], n1)]; + this.mayNotBeSimplified = true; + return node; + } + // a * (-b) -> -(a*b) + if (n0.value != 'op_neg' && n1.value == 'op_neg') { + node.type = 'node_op'; + node.value = 'op_neg'; + node.children = [this.createNode('node_op', 'op_mul', n0, n1.children[0])]; + this.mayNotBeSimplified = true; + return node; + } + // (1 / a) * b -> a / b + if (n0.value == 'op_div' && + n0.children[0].type == 'node_const' && n0.children[0].value == 1.0) { + node.type = 'node_op'; + node.value = 'op_div'; + node.children = [n1, n0.children[1]]; + this.mayNotBeSimplified = true; + return node; + } + // a * (1 / b) -> a / b + if (n1.value == 'op_div' && + n1.children[0].type == 'node_const' && n1.children[0].value == 1.0) { + node.type = 'node_op'; + node.value = 'op_div'; + node.children = [n0, n1.children[1]]; + this.mayNotBeSimplified = true; + return node; + } - deg = Math.max(parseInt(deg, 10), 1) || 1; + // Order children + // a * const -> const * a + if (n0.type != 'node_const' && n1.type == 'node_const') { + node.children = [n1, n0]; + this.mayNotBeSimplified = true; + return node; + } + // a + (-const) -> -const * a + if (n0.type != 'node_const' && n1.type == 'node_op' && + n1.value == 'op_neg' && n1.children[0].type == 'node_const') { + node.children = [n1, n0]; + this.mayNotBeSimplified = true; + return node; + } - // never fill - attributes.fillcolor = 'none'; - attributes.highlightfillcolor = 'none'; + // a * var -> var * a + // a * fun -> fun * a + if (n0.type == 'node_op' && n0.value != 'op_execfun' && + (n1.type == 'node_var' || (n1.type == 'node_op' && n1.value == 'op_execfun'))) { + node.children = [n1, n0]; + this.mayNotBeSimplified = true; + return node; + } - return board.create('functiongraph', [Numerics.regressionPolynomial(deg, x, y)], attributes); - }, + // a + (-var) -> -var * a + if (n0.type != 'node_op' && n1.type == 'node_op' && + n1.value == 'op_neg' && n1.children[0].type == 'node_var') { + node.children = [n1, n0]; + this.mayNotBeSimplified = true; + return node; + } + // a * (const * b) -> const * (a*b) + // a * (const / b) -> const * (a/b) + if (n0.type != 'node_const' && n1.type == 'node_op' && + (n1.value == 'op_mul' || n1.value == 'op_div') && + n1.children[0].type == 'node_const') { + swap = n1.children[0]; + n1.children[0] = n0; + node.children = [swap, n1]; + this.mayNotBeSimplified = true; + return node; + } - /** - * Create bar chart defined by two data arrays. - * Attributes to change the layout of the bar chart are: - * <ul> - * <li> width (optional) - * <li> dir: 'horizontal' or 'vertical' - * <li> colors: array of colors - * <li> labels: array of labels - * </ul> - * - * @param {String,JXG.Board} board The board the chart is drawn on - * @param {Array} x Array of x-coordinates - * @param {Array} y Array of y-coordinates - * @param {Object} attributes Javascript object containing attributes like colors - * @returns {Array} Array of JXG polygons defining the bars - */ - drawBar: function (board, x, y, attributes) { - var i, strwidth, text, w, xp0, xp1, xp2, yp, colors, - pols = [], - p = [], - attr, attrSub, - makeXpFun = function (i, f) { - return function () { - return x[i]() - f * w; - }; - }, - hiddenPoint = { - fixed: true, - withLabel: false, - visible: false, - name: '' - }; + // (const * a) * b -> const * (a * b) + if (n1.type != 'node_const' && n0.type == 'node_op' && + n0.value == 'op_mul' && + n0.children[0].type == 'node_const') { + node.children = [ + n0.children[0], + this.createNode('node_op', 'op_mul', n0.children[1], n1) + ]; + this.mayNotBeSimplified = true; + return node; + } - attr = Type.copyAttributes(attributes, board.options, 'chart'); + // const * const -> const + if (n0.type == 'node_const' && n1.type == 'node_const') { + n0.value *= n1.value; + return n0; + } - // Determine the width of the bars - if (attr && attr.width) { // width given - w = attr.width; - } else { - if (x.length <= 1) { - w = 1; - } else { - // Find minimum distance between to bars. - w = x[1] - x[0]; - for (i = 1; i < x.length - 1; i++) { - w = (x[i + 1] - x[i] < w) ? x[i + 1] - x[i] : w; + // const * (const * a) -> const * a + // const * (const / a) -> const / a + if (n0.type == 'node_const' && n1.type == 'node_op' && + (n1.value == 'op_mul' || n1.value == 'op_div') && + n1.children[0].type == 'node_const') { + n1.children[0].value *= n0.value; + return n1; } - } - w *= 0.8; - } - attrSub = Type.copyAttributes(attributes, board.options, 'chart', 'label'); + // a * a-> a^2 + n0.hash = this.parser.compile(n0); + n1.hash = this.parser.compile(n1); + if (n0.hash === n1.hash) { + node.value = 'op_exp'; + node.children[1] = this.createNode('node_const', 2.0); + return node; + } - for (i = 0; i < x.length; i++) { - if (Type.isFunction(x[i])) { - xp0 = makeXpFun(i, -0.5); - xp1 = makeXpFun(i, 0); - xp2 = makeXpFun(i, 0.5); - } else { - xp0 = x[i] - w * 0.5; - xp1 = x[i]; - xp2 = x[i] + w * 0.5; - } - if (Type.isFunction(y[i])) { - yp = y[i](); - } else { - yp = y[i]; - } - yp = y[i]; + if (n0.type == 'node_const' && n1.type == 'node_op' && + (n1.value == 'op_mul' || n1.value == 'op_div') && + n1.children[0].type == 'node_const') { + n1.children[0].value *= n0.value; + return n1; + } - if (attr.dir === 'horizontal') { // horizontal bars - p[0] = board.create('point', [0, xp0], hiddenPoint); - p[1] = board.create('point', [yp, xp0], hiddenPoint); - p[2] = board.create('point', [yp, xp2], hiddenPoint); - p[3] = board.create('point', [0, xp2], hiddenPoint); + // a * a^b -> a^(b+1) + if (n1.type == 'node_op' && n1.value == 'op_exp') { + if (!n0.hash) { + n0.hash = this.parser.compile(n0); + } + if (!n1.children[0].hash) { + n1.children[0].hash = this.parser.compile(n1.children[0]); + } + if (n0.hash === n1.children[0].hash) { + n1.children[1] = this.createNode('node_op', 'op_add', + n1.children[1], + this.createNode('node_const', 1.0) + ); + this.mayNotBeSimplified = true; + return n1; + } + } - if (Type.exists(attr.labels) && Type.exists(attr.labels[i])) { - attrSub.anchorY = 'middle'; - text = board.create('text', [ - yp, - xp1, - attr.labels[i]], attrSub); - text.visProp.anchorx = (function(txt) { return function() { - return (txt.X() >= 0) ? 'left' : 'right'; - }; })(text); + // a^b * a^c -> a^(b+c) + if (n0.type == 'node_op' && n0.value == 'op_exp' && + n1.type == 'node_op' && n1.value == 'op_exp') { + n0.children[0].hash = this.parser.compile(n0.children[0]); + n1.children[0].hash = this.parser.compile(n1.children[0]); + if (n0.children[0].hash === n1.children[0].hash) { + n0.children[1] = this.createNode('node_op', 'op_add', + n0.children[1], + n1.children[1] + ); + this.mayNotBeSimplified = true; + return n0; + } + } + + break; + // 0 - a -> -a + // a - 0 -> a + // a - a -> 0 + case 'op_sub': + n0 = node.children[0]; + n1 = node.children[1]; + if (n0.type == 'node_const' && n0.value === 0.0) { + node.value = 'op_neg'; + node.children[0] = n1; + return node; + } + if (n1.type == 'node_const' && n1.value === 0.0) { + return n0; + } + if (n0.type == 'node_const' && n1.type == 'node_const' && + n0.value == n1.value) { + return this.createNode('node_const', 0.0); + } + if (n0.type == 'node_var' && n1.type == 'node_var' && + n0.value == n1.value) { + return this.createNode('node_const', 0.0); } - } else { // vertical bars - p[0] = board.create('point', [xp0, 0], hiddenPoint); - p[1] = board.create('point', [xp0, yp], hiddenPoint); - p[2] = board.create('point', [xp2, yp], hiddenPoint); - p[3] = board.create('point', [xp2, 0], hiddenPoint); - if (Type.exists(attr.labels) && Type.exists(attr.labels[i])) { - attrSub.anchorX = 'middle'; + // const - const -> const + if (n0.type == 'node_const' && n1.type == 'node_const') { + n0.value -= n1.value; + return n0; + } - text = board.create('text', [ - xp1, - yp, - attr.labels[i]], attrSub); + // const * a - const * a -> const * a + if (n0.type == 'node_op' && n0.value == 'op_mul' && + n1.type == 'node_op' && n1.value == 'op_mul') { - text.visProp.anchory = (function(txt) { - return function() { - return (txt.Y() >= 0) ? 'bottom' : 'top'; - }; - })(text); + n0.children[1].hash = this.parser.compile(n0.children[1]); + n1.children[1].hash = this.parser.compile(n1.children[1]); + if (n0.children[1].hash === n1.children[1].hash) { + node.value = 'op_mul'; + node.children = [ + this.createNode('node_op', 'op_sub', + n0.children[0], + n1.children[0]), + n0.children[1] + ]; + this.mayNotBeSimplified = true; + return node; + } } - } + // const * a - a -> (const - 1) * a + if (n0.type == 'node_op' && n0.value == 'op_mul') { - if (Type.isArray(attr.colors)) { - colors = attr.colors; - attr.fillcolor = colors[i % colors.length]; - } + n0.children[1].hash = this.parser.compile(n0.children[1]); + n1.hash = this.parser.compile(n1); + if (n0.children[1].hash === n1.hash) { - pols[i] = board.create('polygon', p, attr); - if (Type.exists(attr.labels) && Type.exists(attr.labels[i])) { - pols[i].text = text; - } - } + node.value = 'op_mul'; + node.children = [ + this.createNode('node_op', 'op_sub', + n0.children[0], + this.createNode('node_const', 1.0)), + n1 + ]; + this.mayNotBeSimplified = true; + return node; + } + } + // a - const*a -> (const - 1) * a + if (n1.type == 'node_op' && n1.value == 'op_mul') { - return pols; - }, + n1.children[1].hash = this.parser.compile(n1.children[1]); + n0.hash = this.parser.compile(n0); + if (n1.children[1].hash === n0.hash) { - /** - * Create chart consisting of JSXGraph points. - * Attributes to change the layout of the point chart are: - * <ul> - * <li> fixed (Boolean) - * <li> infoboxArray (Array): Texts for the infobox - * </ul> - * - * @param {String,JXG.Board} board The board the chart is drawn on - * @param {Array} x Array of x-coordinates - * @param {Array} y Array of y-coordinates - * @param {Object} attributes Javascript object containing attributes like colors - * @returns {Array} Array of JSXGraph points - */ - drawPoints: function (board, x, y, attributes) { - var i, - points = [], - infoboxArray = attributes.infoboxarray; + node.value = 'op_mul'; + node.children = [ + this.createNode('node_op', 'op_sub', + this.createNode('node_const', 1.0), + n1.children[0]), + n0 + ]; + this.mayNotBeSimplified = true; + return node; + } + } - attributes.fixed = true; - attributes.name = ''; + break; - for (i = 0; i < x.length; i++) { - attributes.infoboxtext = infoboxArray ? infoboxArray[i % infoboxArray.length] : false; - points[i] = board.create('point', [x[i], y[i]], attributes); + // -0 -> 0 + // -(-b) = b + case 'op_neg': + n0 = node.children[0]; + if (n0.type == 'node_const' && n0.value === 0.0) { + return n0; + } + if (n0.type == 'node_op' && n0.value == 'op_neg') { + return n0.children[0]; + } + break; + + // a / a -> 1, a != 0 + // 0 / a -> 0, a != 0 + // a / 0 -> Infinity, a != 0 + // 0 / 0 -> NaN, a == 0 + case 'op_div': + n0 = node.children[0]; + n1 = node.children[1]; + if (n0.type == 'node_const' && n1.type == 'node_const' && + n0.value == n1.value && n0.value !== 0) { + n0.value = 1.0; + return n0; + } + if (n0.type == 'node_const' && n0.value === 0 && + n1.type == 'node_const' && n1.value !== 0) { + n0.value = 0.0; + return n0; + } + + // Risky: 0 / (something != 0) -> 0.0 + if (n0.type == 'node_const' && n0.value === 0 && + (n1.type == 'node_op' || n1.type == 'node_var')) { + node.type = 'node_const'; + node.value = 0.0; + return node; + } + + if (n0.type == 'node_var' && n1.type == 'node_var' && + n0.value == n1.value) { + return this.createNode('node_const', 1.0); + } + if (n0.type == 'node_const' && n0.value !== 0 && + n1.type == 'node_const' && n1.value === 0) { + if (n0.value > 0.0) { + n0.value = Infinity; + } else { + n0.value = -Infinity; // Do we ever need this? + } + return n0; + } + + // (-a) / (-b) -> a/b + if (n0.type == 'node_op' && n0.value == 'op_neg' && + n1.type == 'node_op' && n1.value == 'op_neg') { + node.children = [n0.children[0], n1.children[0]]; + this.mayNotBeSimplified = true; + return node; + } + // (-a) / b -> -(a/b) + if (n0.value == 'op_neg' && n1.value != 'op_neg') { + node.type = 'node_op'; + node.value = 'op_neg'; + node.children = [this.createNode('node_op', 'op_div', n0.children[0], n1)]; + this.mayNotBeSimplified = true; + return node; + } + // a / (-b) -> -(a/b) + if (n0.value != 'op_neg' && n1.value == 'op_neg') { + node.type = 'node_op'; + node.value = 'op_neg'; + node.children = [this.createNode('node_op', 'op_div', n0, n1.children[0])]; + this.mayNotBeSimplified = true; + return node; + } + + // a^b / a -> a^(b-1) + if (n0.type == 'node_op' && n0.value == 'op_exp') { + if (!n1.hash) { + n1.hash = this.parser.compile(n1); + } + if (!n0.children[0].hash) { + n0.children[0].hash = this.parser.compile(n0.children[0]); + } + if (n1.hash === n0.children[0].hash) { + n0.children[1] = this.createNode('node_op', 'op_sub', + n0.children[1], + this.createNode('node_const', 1.0) + ); + this.mayNotBeSimplified = true; + return n0; + } + } + + // (const * a) / b -> const * (a / b) + if (n1.type != 'node_const' && n0.type == 'node_op' && + n0.value == 'op_mul' && + n0.children[0].type == 'node_const') { + node.value = 'op_mul'; + node.children = [ + n0.children[0], + this.createNode('node_op', 'op_div', n0.children[1], n1) + ]; + this.mayNotBeSimplified = true; + return node; + } + + // a^b / a^c -> a^(b-c) + if (n0.type == 'node_op' && n0.value == 'op_exp' && + n1.type == 'node_op' && n1.value == 'op_exp') { + n0.children[0].hash = this.parser.compile(n0.children[0]); + n1.children[0].hash = this.parser.compile(n1.children[0]); + if (n0.children[0].hash === n1.children[0].hash) { + n0.children[1] = this.createNode('node_op', 'op_sub', + n0.children[1], + n1.children[1] + ); + this.mayNotBeSimplified = true; + return n0; + } + } + + + break; + + // a^0 = 1 + // a^1 -> a + // 1^a -> 1 + // 0^a -> 0: a const != 0 + case 'op_exp': + n0 = node.children[0]; + n1 = node.children[1]; + if (n1.type == 'node_const' && n1.value === 0.0) { + n1.value = 1.0; + return n1; + } + if (n1.type == 'node_const' && n1.value == 1.0) { + return n0; + } + if (n0.type == 'node_const' && n0.value == 1.0) { + return n0; + } + if (n0.type == 'node_const' && n0.value === 0.0 && + n1.type == 'node_const' && n1.value !== 0.0) { + return n0; + } + + // (a^b)^c -> a^(b*c) + if (n0.type == 'node_op' && n0.value == 'op_exp') { + node.children = [ + n0.children[0], + this.createNode('node_op', 'op_mul', + n0.children[1], + n1) + ]; + return node; + } + break; } - return points; - }, + switch (node.value) { + // const_1 + const_2 -> (const_1 + const_2) + // a + a -> 2*a + // a + (-b) = a - b + case 'op_add': + n0 = node.children[0]; + n1 = node.children[1]; + if (n0.type == 'node_const' && n1.type == 'node_const' && + n0.value == n1.value) { + n0.value += n1.value; + return n0; + } - /** - * Create pie chart. - * Attributes to change the layout of the pie chart are: - * <ul> - * <li> labels: array of labels - * <li> colors: (Array) - * <li> highlightColors (Array) - * <li> radius - * <li> center (coordinate array) - * <li> highlightOnSector (Boolean) - * </ul> - * - * @param {String,JXG.Board} board The board the chart is drawn on - * @param {Array} y Array of x-coordinates - * @param {Object} attributes Javascript object containing attributes like colors - * @returns {Object} with keys: "{sectors, points, midpoint}" - */ - drawPie: function (board, y, attributes) { - var i, center, - p = [], - sector = [], - s = Statistics.sum(y), - colorArray = attributes.colors, - highlightColorArray = attributes.highlightcolors, - labelArray = attributes.labels, - r = attributes.radius || 4, - radius = r, - cent = attributes.center || [0, 0], - xc = cent[0], - yc = cent[1], + if (n0.type == 'node_var' && n1.type == 'node_var' && + n0.value == n1.value) { + node.children[0] = this.createNode('node_const', 2.0); + node.value = 'op_mul'; + return node; + } - makeRadPointFun = function (j, fun, xc) { - return function () { - var s, i, rad, - t = 0; + if (n0.type == 'node_op' && n0.value == 'op_neg') { + node.value = 'op_sub'; + node.children[0] = n1; + node.children[1] = n0.children[0]; + this.mayNotBeSimplified = true; + return node; + } - for (i = 0; i <= j; i++) { - t += parseFloat(Type.evaluate(y[i])); + if (n1.type == 'node_op' && n1.value == 'op_neg') { + node.value = 'op_sub'; + node.children[1] = n1.children[0]; + this.mayNotBeSimplified = true; + return node; + } + + // const * a + const * a -> const * a + if (n0.type == 'node_op' && n0.value == 'op_mul' && + n1.type == 'node_op' && n1.value == 'op_mul') { + + n0.children[1].hash = this.parser.compile(n0.children[1]); + n1.children[1].hash = this.parser.compile(n1.children[1]); + if (n0.children[1].hash === n1.children[1].hash) { + + node.value = 'op_mul'; + node.children = [ + this.createNode('node_op', 'op_add', + n0.children[0], + n1.children[0]), + n0.children[1] + ]; + this.mayNotBeSimplified = true; + return node; } + } + // const * a + a -> (const + 1) * a + if (n0.type == 'node_op' && n0.value == 'op_mul') { - s = t; - for (i = j + 1; i < y.length; i++) { - s += parseFloat(Type.evaluate(y[i])); + n0.children[1].hash = this.parser.compile(n0.children[1]); + n1.hash = this.parser.compile(n1); + if (n0.children[1].hash === n1.hash) { + + node.value = 'op_mul'; + node.children = [ + this.createNode('node_op', 'op_add', + n0.children[0], + this.createNode('node_const', 1.0)), + n1 + ]; + this.mayNotBeSimplified = true; + return node; } - rad = (s !== 0) ? (2 * Math.PI * t / s) : 0; + } + // a + const*a -> (const + 1) * a + if (n1.type == 'node_op' && n1.value == 'op_mul') { - return radius() * Math[fun](rad) + xc; - }; - }, + n1.children[1].hash = this.parser.compile(n1.children[1]); + n0.hash = this.parser.compile(n0); + if (n1.children[1].hash === n0.hash) { - highlightHandleLabel = function (f, s) { - var dx = -this.point1.coords.usrCoords[1] + this.point2.coords.usrCoords[1], - dy = -this.point1.coords.usrCoords[2] + this.point2.coords.usrCoords[2]; + node.value = 'op_mul'; + node.children = [ + this.createNode('node_op', 'op_add', + this.createNode('node_const', 1.0), + n1.children[0]), + n0 + ]; + this.mayNotBeSimplified = true; + return node; + } + } - if (Type.exists(this.label)) { - this.label.rendNode.style.fontSize = (s * Type.evaluate(this.label.visProp.fontsize)) + 'px'; - this.label.fullUpdate(); + break; + + // a - (-b) = a + b + case 'op_sub': + n0 = node.children[0]; + n1 = node.children[1]; + if (n1.type == 'node_op' && n1.value == 'op_neg') { + node.value = 'op_add'; + node.children[1] = n1.children[0]; + this.mayNotBeSimplified = true; + return node; } + break; - this.point2.coords = new Coords(Const.COORDS_BY_USER, [ - this.point1.coords.usrCoords[1] + dx * f, - this.point1.coords.usrCoords[2] + dy * f - ], this.board); - this.fullUpdate(); - }, + case 'op_execfun': + return this.simplifyElementary(node); + } - highlightFun = function () { - if (!this.highlighted) { - this.highlighted = true; - this.board.highlightedObjects[this.id] = this; - this.board.renderer.highlight(this); + return node; + }, - highlightHandleLabel.call(this, 1.1, 2); - } - }, + simplifyElementary: function (node) { + var fun = node.children[0].value, + arg = node.children[1]; - noHighlightFun = function () { - if (this.highlighted) { - this.highlighted = false; - this.board.renderer.noHighlight(this); + // Catch errors of the form sin() + if (arg.length == 0) { + return node; + } - highlightHandleLabel.call(this, 0.90909090, 1); + switch (fun) { + // sin(0) -> 0 + // sin(PI) -> 0 + // sin (int * PI) -> 0 + // sin (PI * int) -> 0 + // Same for tan() + case 'sin': + case 'tan': + if (arg[0].type == 'node_const' && arg[0].value === 0) { + node.type = 'node_const'; + node.value = 0.0; + return node; } - }, + if (arg[0].type == 'node_var' && arg[0].value == 'PI') { + node.type = 'node_const'; + node.value = 0.0; + return node; + } + if (arg[0].type == 'node_op' && arg[0].value == 'op_mul' && + arg[0].children[0].type == 'node_const' && arg[0].children[0].value % 1 === 0 && + arg[0].children[1].type == 'node_var' && arg[0].children[1].value == 'PI') { + node.type = 'node_const'; + node.value = 0.0; + return node; + } + break; - hiddenPoint = { - fixed: true, - withLabel: false, - visible: false, - name: '' - }; + // cos(0) -> 1.0 + // cos(PI) -> -1.0 + // cos(int * PI) -> +/- 1.0 + // cos(PI * int) -> +/- 1.0 + case 'cos': + if (arg[0].type == 'node_const' && arg[0].value === 0) { + node.type = 'node_const'; + node.value = 1.0; + return node; + } + if (arg[0].type == 'node_var' && arg[0].value == 'PI') { + node.type = 'node_op'; + node.value = 'op_neg'; + node.children = [this.createNode('node_const', 1.0)]; + return node; + } + /* + if (arg[0].type == 'node_op' && arg[0].value == 'op_mul' && + ((arg[0].children[0].type == 'node_const' && arg[0].children[0].value % 1 === 0 && + arg[0].children[1].type == 'node_var' && arg[0].children[1].value == 'PI') || + (arg[0].children[1].type == 'node_const' && arg[0].children[1].value % 1 === 0 && + arg[0].children[0].type == 'node_var' && arg[0].children[0].value == 'PI'))) { + node.type = 'node_const'; + node.value = 1.0; + return node; + } + */ + break; - if (!Type.isArray(labelArray)) { - labelArray = []; - for (i = 0; i < y.length; i++) { - labelArray[i] = ''; - } - } + // exp(0) -> 1 + case 'exp': + if (arg[0].type == 'node_const' && arg[0].value === 0) { + node.type = 'node_const'; + node.value = 1.0; + return node; + } + break; + + // pow(a, 0) -> 1 + case 'pow': + if (arg[1].type == 'node_const' && arg[1].value === 0) { + node.type = 'node_const'; + node.value = 1.0; + return node; + } + break; - if (!Type.isFunction(r)) { - radius = function () { - return r; - }; } - attributes.highlightonsector = attributes.highlightonsector || false; - attributes.straightfirst = false; - attributes.straightlast = false; + return node; + } - center = board.create('point', [xc, yc], hiddenPoint); - p[0] = board.create('point', [ - function () { - return radius() + xc; - }, - function () { - return yc; - } - ], hiddenPoint); + }); - for (i = 0; i < y.length; i++) { - p[i + 1] = board.create('point', [makeRadPointFun(i, 'cos', xc), makeRadPointFun(i, 'sin', yc)], hiddenPoint); + return JXG.CA; +}); - attributes.name = labelArray[i]; - attributes.withlabel = attributes.name !== ''; - attributes.fillcolor = colorArray && colorArray[i % colorArray.length]; - attributes.labelcolor = colorArray && colorArray[i % colorArray.length]; - attributes.highlightfillcolor = highlightColorArray && highlightColorArray[i % highlightColorArray.length]; +/* + Copyright 2008-2022 + Matthias Ehmann, + Michael Gerhaeuser, + Carsten Miller, + Bianca Valentin, + Alfred Wassermann, + Peter Wilfahrt - sector[i] = board.create('sector', [center, p[i], p[i + 1]], attributes); + This file is part of JSXGraph. - if (attributes.highlightonsector) { - // overwrite hasPoint so that the whole sector is used for highlighting - sector[i].hasPoint = sector[i].hasPointSector; - } - if (attributes.highlightbysize) { - sector[i].highlight = highlightFun; + JSXGraph is free software dual licensed under the GNU LGPL or MIT License. - sector[i].noHighlight = noHighlightFun; - } + You can redistribute it and/or modify it under the terms of the - } + * GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version + OR + * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT - // Not enough! We need points, but this gives an error in setAttribute. - return {sectors: sector, points: p, midpoint: center}; - }, + JSXGraph is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. - /** - * Create radar chart. - * Attributes to change the layout of the pie chart are: - * <ul> - * <li> paramArray: labels for axes, [ paramx, paramy, paramz ] - * <li> startShiftRatio: 0 <= offset from chart center <=1 - * <li> endShiftRatio: 0 <= offset from chart radius <=1 - * <li> startShiftArray: Adjust offsets per each axis - * <li> endShiftArray: Adjust offsets per each axis - * <li> startArray: Values for inner circle. Default values: minimums - * <li> start: one value to overwrite all startArray values - * <li> endArray: Values for outer circle, maximums by default - * <li> end: one value to overwrite all endArray values - * <li> labelArray - * <li> polyStrokeWidth - * <li> colors - * <li> highlightcolors - * <li> labelArray: [ row1, row2, row3 ] - * <li> radius - * <li> legendPosition - * <li> showCircles - * <li> circleLabelArray - * <li> circleStrokeWidth - * </ul> - * - * @param {String,JXG.Board} board The board the chart is drawn on - * @param {Array} parents Array of coordinates, e.g. [[x1, y1, z1], [x2, y2, z2], [x3, y3, z3]] - * @param {Object} attributes Javascript object containing attributes like colors - * @returns {Object} with keys "{circles, lines, points, midpoint, polygons}" - */ - drawRadar: function (board, parents, attributes) { - var i, j, paramArray, numofparams, maxes, mins, - la, pdata, ssa, esa, ssratio, esratio, - sshifts, eshifts, starts, ends, - labelArray, colorArray, highlightColorArray, radius, myAtts, - cent, xc, yc, center, start_angle, rad, p, line, t, - xcoord, ycoord, polygons, legend_position, circles, lxoff, lyoff, - cla, clabelArray, ncircles, pcircles, angle, dr, sw, data, - len = parents.length, + You should have received a copy of the GNU Lesser General Public License and + the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> + and <http://opensource.org/licenses/MIT/>. + */ - get_anchor = function () { - var x1, x2, y1, y2, - relCoords = Type.evaluate(this.visProp.label.offset).slice(0); - x1 = this.point1.X(); - x2 = this.point2.X(); - y1 = this.point1.Y(); - y2 = this.point2.Y(); - if (x2 < x1) { - relCoords[0] = -relCoords[0]; - } +/*global JXG: true, define: true*/ +/*jslint nomen: true, plusplus: true*/ - if (y2 < y1) { - relCoords[1] = -relCoords[1]; - } +/* depends: + jxg + utils/type + */ - this.setLabelRelativeCoords(relCoords); +/** + * @fileoverview The JXG.Dump namespace provides methods to save a board to javascript. + */ - return new Coords(Const.COORDS_BY_USER, [this.point2.X(), this.point2.Y()], this.board); - }, +define('utils/dump',['jxg', 'utils/type'], function (JXG, Type) { - get_transform = function (angle, i) { - var t, tscale, trot; + "use strict"; - t = board.create('transform', [-(starts[i] - sshifts[i]), 0], {type: 'translate'}); - tscale = board.create('transform', [radius / ((ends[i] + eshifts[i]) - (starts[i] - sshifts[i])), 1], {type: 'scale'}); - t.melt(tscale); - trot = board.create('transform', [angle], {type: 'rotate'}); - t.melt(trot); + /** + * The JXG.Dump namespace provides classes and methods to save a board to javascript. + * @namespace + */ + JXG.Dump = { - return t; - }; + /** + * Adds markers to every element of the board + * @param {JXG.Board} board + * @param {Array|String} markers + * @param {Array} values + */ + addMarkers: function (board, markers, values) { + var e, l, i; - if (len <= 0) { - throw new Error('JSXGraph radar chart: no data'); - } - // labels for axes - paramArray = attributes.paramarray; - if (!Type.exists(paramArray)) { - throw new Error('JSXGraph radar chart: need paramArray attribute'); - } - numofparams = paramArray.length; - if (numofparams <= 1) { - throw new Error('JSXGraph radar chart: need more than one param in paramArray'); + if (!Type.isArray(markers)) { + markers = [markers]; } - for (i = 0; i < len; i++) { - if (numofparams !== parents[i].length) { - throw new Error('JSXGraph radar chart: use data length equal to number of params (' + parents[i].length + ' != ' + numofparams + ')'); - } + if (!Type.isArray(values)) { + values = [values]; } - maxes = []; - mins = []; - - for (j = 0; j < numofparams; j++) { - maxes[j] = parents[0][j]; - mins[j] = maxes[j]; - } + l = Math.min(markers.length, values.length); - for (i = 1; i < len; i++) { - for (j = 0; j < numofparams; j++) { - if (parents[i][j] > maxes[j]) { - maxes[j] = parents[i][j]; - } + markers.length = l; + values.length = l; - if (parents[i][j] < mins[j]) { - mins[j] = parents[i][j]; + for (e in board.objects) { + if (board.objects.hasOwnProperty(e)) { + for (i = 0; i < l; i++) { + board.objects[e][markers[i]] = values[i]; } } } + }, - la = []; - pdata = []; + /** + * Removes markers from every element on the board. + * @param {JXG.Board} board + * @param {Array|String} markers + */ + deleteMarkers: function (board, markers) { + var e, l, i; - for (i = 0; i < len; i++) { - la[i] = ''; - pdata[i] = []; + if (!Type.isArray(markers)) { + markers = [markers]; } - ssa = []; - esa = []; - - // 0 <= Offset from chart center <=1 - ssratio = attributes.startshiftratio || 0; - // 0 <= Offset from chart radius <=1 - esratio = attributes.endshiftratio || 0; - - for (i = 0; i < numofparams; i++) { - ssa[i] = (maxes[i] - mins[i]) * ssratio; - esa[i] = (maxes[i] - mins[i]) * esratio; - } + l = markers.length; - // Adjust offsets per each axis - sshifts = attributes.startshiftarray || ssa; - eshifts = attributes.endshiftarray || esa; - // Values for inner circle, minimums by default - starts = attributes.startarray || mins; + markers.length = l; - if (Type.exists(attributes.start)) { - for (i = 0; i < numofparams; i++) { - starts[i] = attributes.start; + for (e in board.objects) { + if (board.objects.hasOwnProperty(e)) { + for (i = 0; i < l; i++) { + delete board.objects[e][markers[i]]; + } } } + }, - // Values for outer circle, maximums by default - ends = attributes.endarray || maxes; - if (Type.exists(attributes.end)) { - for (i = 0; i < numofparams; i++) { - ends[i] = attributes.end; - } + /** + * Stringifies a string, i.e. puts some quotation marks around <tt>s</tt> if it is of type string. + * @param {*} s + * @returns {String} " + s + " + */ + str: function (s) { + if (typeof s === 'string' && s.substr(0, 7) !== 'function') { + s = '"' + s + '"'; } - if (sshifts.length !== numofparams) { - throw new Error('JSXGraph radar chart: start shifts length is not equal to number of parameters'); - } + return s; + }, - if (eshifts.length !== numofparams) { - throw new Error('JSXGraph radar chart: end shifts length is not equal to number of parameters'); - } + /** + * Eliminate default values given by {@link JXG.Options} from the attributes object. + * @param {Object} instance Attribute object of the element + * @param {Object} s Arbitrary number of objects <tt>instance</tt> will be compared to. Usually these are + * sub-objects of the {@link JXG.Board#options} structure. + * @returns {Object} Minimal attributes object + */ + minimizeObject: function (instance, s) { + var p, pl, i, + def = {}, + copy = Type.deepCopy(instance), + defaults = []; - if (starts.length !== numofparams) { - throw new Error('JSXGraph radar chart: starts length is not equal to number of parameters'); + for (i = 1; i < arguments.length; i++) { + defaults.push(arguments[i]); } - if (ends.length !== numofparams) { - throw new Error('JSXGraph radar chart: snds length is not equal to number of parameters'); + def = Type.deepCopy(def, JXG.Options.elements, true); + for (i = defaults.length; i > 0; i--) { + def = Type.deepCopy(def, defaults[i - 1], true); } - // labels for legend - labelArray = attributes.labelarray || la; - colorArray = attributes.colors; - highlightColorArray = attributes.highlightcolors; - radius = attributes.radius || 10; - sw = attributes.strokewidth || 1; + for (p in def) { + if (def.hasOwnProperty(p)) { + pl = p.toLowerCase(); - if (!Type.exists(attributes.highlightonsector)) { - attributes.highlightonsector = false; + if (typeof def[p] !== 'object' && def[p] === copy[pl]) { + // console.log("delete", p); + delete copy[pl]; + } + } } - myAtts = { - name: attributes.name, - id: attributes.id, - strokewidth: sw, - polystrokewidth: attributes.polystrokewidth || sw, - strokecolor: attributes.strokecolor || 'black', - straightfirst: false, - straightlast: false, - fillcolor: attributes.fillColor || '#FFFF88', - fillopacity: attributes.fillOpacity || 0.4, - highlightfillcolor: attributes.highlightFillColor || '#FF7400', - highlightstrokecolor: attributes.highlightStrokeColor || 'black', - gradient: attributes.gradient || 'none' - }; - - cent = attributes.center || [0, 0]; - xc = cent[0]; - yc = cent[1]; - center = board.create('point', [xc, yc], {name: '', fixed: true, withlabel: false, visible: false}); - start_angle = Math.PI / 2 - Math.PI / numofparams; - start_angle = attributes.startangle || 0; - rad = start_angle; - p = []; - line = []; + return copy; + }, - for (i = 0; i < numofparams; i++) { - rad += 2 * Math.PI / numofparams; - xcoord = radius * Math.cos(rad) + xc; - ycoord = radius * Math.sin(rad) + yc; + /** + * Prepare the attributes object for an element to be dumped as JavaScript or JessieCode code. + * @param {JXG.Board} board + * @param {JXG.GeometryElement} obj Geometry element which attributes object is generated + * @returns {Object} An attributes object. + */ + prepareAttributes: function (board, obj) { + var a, s; - p[i] = board.create('point', [xcoord, ycoord], {name: '', fixed: true, withlabel: false, visible: false}); - line[i] = board.create('line', [center, p[i]], { - name: paramArray[i], - strokeColor: myAtts.strokecolor, - strokeWidth: myAtts.strokewidth, - strokeOpacity: 1.0, - straightFirst: false, - straightLast: false, - withLabel: true, - highlightStrokeColor: myAtts.highlightstrokecolor - }); - line[i].getLabelAnchor = get_anchor; - t = get_transform(rad, i); + a = this.minimizeObject(obj.getAttributes(), JXG.Options[obj.elType]); - for (j = 0; j < parents.length; j++) { - data = parents[j][i]; - pdata[j][i] = board.create('point', [data, 0], {name: '', fixed: true, withlabel: false, visible: false}); - pdata[j][i].addTransform(pdata[j][i], t); + for (s in obj.subs) { + if (obj.subs.hasOwnProperty(s)) { + a[s] = this.minimizeObject(obj.subs[s].getAttributes(), + JXG.Options[obj.elType][s], + JXG.Options[obj.subs[s].elType]); + a[s].id = obj.subs[s].id; + a[s].name = obj.subs[s].name; } } - polygons = []; - for (i = 0; i < len; i++) { - myAtts.labelcolor = colorArray && colorArray[i % colorArray.length]; - myAtts.strokecolor = colorArray && colorArray[i % colorArray.length]; - myAtts.fillcolor = colorArray && colorArray[i % colorArray.length]; - polygons[i] = board.create('polygon', pdata[i], { - withLines: true, - withLabel: false, - fillColor: myAtts.fillcolor, - fillOpacity: myAtts.fillopacity, - highlightFillColor: myAtts.highlightfillcolor - }); + a.id = obj.id; + a.name = obj.name; - for (j = 0; j < numofparams; j++) { - polygons[i].borders[j].setAttribute('strokecolor:' + colorArray[i % colorArray.length]); - polygons[i].borders[j].setAttribute('strokewidth:' + myAtts.polystrokewidth); - } - } + return a; + }, - legend_position = attributes.legendposition || 'none'; - switch (legend_position) { - case 'right': - lxoff = attributes.legendleftoffset || 2; - lyoff = attributes.legendtopoffset || 1; + setBoundingBox: function(methods, board, boardVarName) { + methods.push({ + obj: boardVarName, + method: 'setBoundingBox', + params: [board.getBoundingBox(), board.keepaspectratio] + }); - this.legend = board.create('legend', [xc + radius + lxoff, yc + radius - lyoff], { - labels: labelArray, - colors: colorArray - }); - break; - case 'none': - break; - default: - JXG.debug('Unknown legend position'); - } + return methods; + }, - circles = []; - if (attributes.showcircles) { - cla = []; - for (i = 0; i < 6; i++) { - cla[i] = 20 * i; - } - cla[0] = "0"; - clabelArray = attributes.circlelabelarray || cla; - ncircles = clabelArray.length; + /** + * Generate a save-able structure with all elements. This is used by {@link JXG.Dump#toJessie} and + * {@link JXG.Dump#toJavaScript} to generate the script. + * @param {JXG.Board} board + * @returns {Array} An array with all metadata necessary to save the construction. + */ + dump: function (board) { + var e, obj, element, s, + props = [], + methods = [], + elementList = [], + len = board.objectsList.length; - if (ncircles < 2) { - throw new Error('JSXGraph radar chart: too less circles in circleLabelArray'); - } + this.addMarkers(board, 'dumped', false); - pcircles = []; - angle = start_angle + Math.PI / numofparams; - t = get_transform(angle, 0); + for (e = 0; e < len; e++) { + obj = board.objectsList[e]; + element = {}; - myAtts.fillcolor = 'none'; - myAtts.highlightfillcolor = 'none'; - myAtts.strokecolor = attributes.strokecolor || 'black'; - myAtts.strokewidth = attributes.circlestrokewidth || 0.5; - myAtts.layer = 0; + if (!obj.dumped && obj.dump) { + element.type = obj.getType(); + element.parents = obj.getParents().slice(); - // we have ncircles-1 intervals between ncircles circles - dr = (ends[0] - starts[0]) / (ncircles - 1); + // Extract coordinates of a point + if (element.type === 'point' && element.parents[0] === 1) { + element.parents = element.parents.slice(1); + } + + for (s = 0; s < element.parents.length; s++) { + if (Type.isString(element.parents[s]) && + element.parents[s][0] !== "'" && + element.parents[s][0] !== '"') { + + element.parents[s] = '"' + element.parents[s] + '"'; + } else if (Type.isArray( element.parents[s]) ) { + element.parents[s] = '[' + element.parents[s].toString() + ']'; + } + } + + element.attributes = this.prepareAttributes(board, obj); + if (element.type === 'glider' && obj.onPolygon) { + props.push({ + obj: obj.id, + prop: 'onPolygon', + val: true + }); + } - for (i = 0; i < ncircles; i++) { - pcircles[i] = board.create('point', [starts[0] + i * dr, 0], { - name: clabelArray[i], - size: 0, - fixed: true, - withLabel: true, - visible: true - }); - pcircles[i].addTransform(pcircles[i], t); - circles[i] = board.create('circle', [center, pcircles[i]], myAtts); + elementList.push(element); } - } - this.rendNode = polygons[0].rendNode; + + this.deleteMarkers(board, 'dumped'); + return { - circles: circles, - lines: line, - points: pdata, - midpoint: center, - polygons: polygons + elements: elementList, + props: props, + methods: methods }; }, - /** - * Uses the boards renderer to update the chart. - * @private - */ - updateRenderer: function () { - return this; - }, + /** + * Converts an array of different values into a parameter string that can be used by the code generators. + * @param {Array} a + * @param {function} converter A function that is used to transform the elements of <tt>a</tt>. Usually + * {@link JXG.toJSON} or {@link JXG.Dump.toJCAN} are used. + * @returns {String} + */ + arrayToParamStr: function (a, converter) { + var i, + s = []; - // documented in base/element - update: function () { - if (this.needsUpdate) { - this.updateDataArray(); + for (i = 0; i < a.length; i++) { + s.push(converter.call(this, a[i])); } - return this; + return s.join(', '); }, /** - * Template for dynamic charts update. - * This method is used to compute new entries - * for the arrays this.dataX and - * this.dataY. It is used in update. - * Default is an empty method, can be overwritten - * by the user. - * - * @returns {JXG.Chart} Reference to this chart object. + * Converts a JavaScript object into a JCAN (JessieCode Attribute Notation) string. + * @param {Object} obj A JavaScript object, functions will be ignored. + * @returns {String} The given object stored in a JCAN string. */ - updateDataArray: function () { return this; } - }); - - /** - * @class Constructor for a chart. - * @pseudo - * @description - * @name Chart - * @augments JXG.Chart - * @constructor - * @type JXG.Chart - * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {Array} x Array of x-coordinates (default case, see below for alternatives) - * @param {Array} y Array of y-coordinates (default case, see below for alternatives) - * <p> - * The parent array may be of one of the following forms: - * <ol> - * <li> Parents array looks like [number, number, number, ...]. It is interpreted as array of y-coordinates. - * The x coordinates are automatically set to [1, 2, ...] - * <li> Parents array looks like [[number, number, number, ...]]. The content is interpreted as array of y-coordinates. - * The x coordinates are automatically set to [1, 2, ...]x coordinates are automatically set to [1, 2, ...] - * Default case: [[x0,x1,x2,...],[y1,y2,y3,...]] - * </ol> - * - * The attribute value for the key 'chartStyle' determines the type(s) of the chart. 'chartStyle' is a comma - * separated list of strings of the possible chart types - * 'bar', 'fit', 'line', 'pie', 'point', 'radar', 'spline'. - * - * @see JXG.Chart#drawBar - * @see JXG.Chart#drawFit - * @see JXG.Chart#drawLine - * @see JXG.Chart#drawPie - * @see JXG.Chart#drawPoints - * @see JXG.Chart#drawRadar - * @see JXG.Chart#drawSpline - * - * @example - * board = JXG.JSXGraph.initBoard('jxgbox', {boundingbox:[-0.5,8,9,-2],axis:true}); - * - * var f = [4, 2, -1, 3, 6, 7, 2]; - * var chart = board.create('chart', f, - * {chartStyle:'bar', - * width:0.8, - * labels:f, - * colorArray:['#8E1B77','#BE1679','#DC1765','#DA2130','#DB311B','#DF4917','#E36317','#E87F1A', - * '#F1B112','#FCF302','#C1E212'], - * label: {fontSize:30, display:'internal', anchorX:'left', rotate:90} - * }); - * - * </pre><div id="JXG1528c395-9fa4-4210-ada6-7fc5652ed920" class="jxgbox" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function() { - * var board = JXG.JSXGraph.initBoard('JXG1528c395-9fa4-4210-ada6-7fc5652ed920', - * {boundingbox: [-0.5,8,9,-2], axis: true, showcopyright: false, shownavigation: false}); - * var f = [4,2,-1,3,6,7,2]; - * var chart = board.create('chart', f, - * {chartStyle:'bar', - * width:0.8, - * labels:f, - * colorArray:['#8E1B77','#BE1679','#DC1765','#DA2130','#DB311B','#DF4917','#E36317','#E87F1A', - * '#F1B112','#FCF302','#C1E212'], - * label: {fontSize:30, display:'internal', anchorX:'left', rotate:90} - * }); - * - * })(); - * - * </script><pre> - * - * @example - * board = JXG.JSXGraph.initBoard('jxgbox', {boundingbox: [-1, 9, 13, -3], axis:true}); - * - * var s = board.create('slider', [[4,7],[8,7],[1,1,1.5]], {name:'S', strokeColor:'black', fillColor:'white'}); - * var f = [function(){return (s.Value()*4.5).toFixed(2);}, - * function(){return (s.Value()*(-1)).toFixed(2);}, - * function(){return (s.Value()*3).toFixed(2);}, - * function(){return (s.Value()*2).toFixed(2);}, - * function(){return (s.Value()*(-0.5)).toFixed(2);}, - * function(){return (s.Value()*5.5).toFixed(2);}, - * function(){return (s.Value()*2.5).toFixed(2);}, - * function(){return (s.Value()*(-0.75)).toFixed(2);}, - * function(){return (s.Value()*3.5).toFixed(2);}, - * function(){return (s.Value()*2).toFixed(2);}, - * function(){return (s.Value()*(-1.25)).toFixed(2);} - * ]; - * var chart = board.create('chart', [f], - * {chartStyle:'bar',width:0.8,labels:f, - * colorArray:['#8E1B77','#BE1679','#DC1765','#DA2130','#DB311B','#DF4917','#E36317','#E87F1A', - * '#F1B112','#FCF302','#C1E212']}); - * - * var dataArr = [4,1,3,2,5,6.5,1.5,2,0.5,1.5,-1]; - * var chart2 = board.create('chart', dataArr, {chartStyle:'line,point'}); - * chart2[0].setAttribute('strokeColor:black','strokeWidth:2pt'); - * for(var i=0; i<11;i++) { - * chart2[1][i].setAttribute({strokeColor:'black',fillColor:'white',face:'[]', size:4, strokeWidth:'2pt'}); - * } - * board.unsuspendUpdate(); - * - * </pre><div id="JXG22deb158-48c6-41c3-8157-b88b4b968a55" class="jxgbox" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function() { - * var board = JXG.JSXGraph.initBoard('JXG22deb158-48c6-41c3-8157-b88b4b968a55', - * {boundingbox: [-1, 9, 13, -3], axis: true, showcopyright: false, shownavigation: false}); - * var s = board.create('slider', [[4,7],[8,7],[1,1,1.5]], {name:'S', strokeColor:'black', fillColor:'white'}); - * var f = [function(){return (s.Value()*4.5).toFixed(2);}, - * function(){return (s.Value()*(-1)).toFixed(2);}, - * function(){return (s.Value()*3).toFixed(2);}, - * function(){return (s.Value()*2).toFixed(2);}, - * function(){return (s.Value()*(-0.5)).toFixed(2);}, - * function(){return (s.Value()*5.5).toFixed(2);}, - * function(){return (s.Value()*2.5).toFixed(2);}, - * function(){return (s.Value()*(-0.75)).toFixed(2);}, - * function(){return (s.Value()*3.5).toFixed(2);}, - * function(){return (s.Value()*2).toFixed(2);}, - * function(){return (s.Value()*(-1.25)).toFixed(2);} - * ]; - * var chart = board.create('chart', [f], - * {chartStyle:'bar',width:0.8,labels:f, - * colorArray:['#8E1B77','#BE1679','#DC1765','#DA2130','#DB311B','#DF4917','#E36317','#E87F1A', - * '#F1B112','#FCF302','#C1E212']}); - * - * var dataArr = [4,1,3,2,5,6.5,1.5,2,0.5,1.5,-1]; - * var chart2 = board.create('chart', dataArr, {chartStyle:'line,point'}); - * chart2[0].setAttribute('strokeColor:black','strokeWidth:2pt'); - * for(var i=0; i<11;i++) { - * chart2[1][i].setAttribute({strokeColor:'black',fillColor:'white',face:'[]', size:4, strokeWidth:'2pt'}); - * } - * board.unsuspendUpdate(); - * - * })(); - * - * </script><pre> - * - * @example - * var dataArr = [4, 1.2, 3, 7, 5, 4, 1.54, function () { return 2; }]; - * var a = board.create('chart', dataArr, { - * chartStyle:'pie', colors:['#B02B2C','#3F4C6B','#C79810','#D15600'], - * fillOpacity:0.9, - * center:[5,2], - * strokeColor:'#ffffff', - * strokeWidth:6, - * highlightBySize:true, - * highlightOnSector:true - * }); - * - * </pre><div id="JXG1180b7dd-b048-436a-a5ad-87ffa82d5aff" class="jxgbox" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function() { - * var board = JXG.JSXGraph.initBoard('JXG1180b7dd-b048-436a-a5ad-87ffa82d5aff', - * {boundingbox: [0, 8, 12, -4], axis: true, showcopyright: false, shownavigation: false}); - * var dataArr = [4, 1.2, 3, 7, 5, 4, 1.54, function () { return 2; }]; - * var a = board.create('chart', dataArr, { - * chartStyle:'pie', colors:['#B02B2C','#3F4C6B','#C79810','#D15600'], - * fillOpacity:0.9, - * center:[5,2], - * strokeColor:'#ffffff', - * strokeWidth:6, - * highlightBySize:true, - * highlightOnSector:true - * }); - * - * })(); - * - * </script><pre> - * - * @example - * board = JXG.JSXGraph.initBoard('jxgbox', {boundingbox: [-12, 12, 20, -12], axis: false}); - * board.suspendUpdate(); - * // See labelArray and paramArray - * var dataArr = [[23, 14, 15.0], [60, 8, 25.0], [0, 11.0, 25.0], [10, 15, 20.0]]; - * - * var a = board.create('chart', dataArr, { - * chartStyle:'radar', - * colorArray:['#0F408D','#6F1B75','#CA147A','#DA2228','#E8801B','#FCF302','#8DC922','#15993C','#87CCEE','#0092CE'], - * //fillOpacity:0.5, - * //strokeColor:'black', - * //strokeWidth:1, - * //polyStrokeWidth:1, - * paramArray:['Speed','Flexibility', 'Costs'], - * labelArray:['Ruby','JavaScript', 'PHP', 'Python'], - * //startAngle:Math.PI/4, - * legendPosition:'right', - * //"startShiftRatio": 0.1, - * //endShiftRatio:0.1, - * //startShiftArray:[0,0,0], - * //endShiftArray:[0.5,0.5,0.5], - * start:0 - * //end:70, - * //startArray:[0,0,0], - * //endArray:[7,7,7], - * //radius:3, - * //showCircles:true, - * //circleLabelArray:[1,2,3,4,5], - * //highlightColorArray:['#E46F6A','#F9DF82','#F7FA7B','#B0D990','#69BF8E','#BDDDE4','#92C2DF','#637CB0','#AB91BC','#EB8EBF'], - * }); - * board.unsuspendUpdate(); - * - * </pre><div id="JXG985fbbe6-0488-4073-b73b-cb3ebaea488a" class="jxgbox" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function() { - * var board = JXG.JSXGraph.initBoard('JXG985fbbe6-0488-4073-b73b-cb3ebaea488a', - * {boundingbox: [-12, 12, 20, -12], axis: false, showcopyright: false, shownavigation: false}); - * board.suspendUpdate(); - * // See labelArray and paramArray - * var dataArr = [[23, 14, 15.0], [60, 8, 25.0], [0, 11.0, 25.0], [10, 15, 20.0]]; - * - * var a = board.create('chart', dataArr, { - * chartStyle:'radar', - * colorArray:['#0F408D','#6F1B75','#CA147A','#DA2228','#E8801B','#FCF302','#8DC922','#15993C','#87CCEE','#0092CE'], - * //fillOpacity:0.5, - * //strokeColor:'black', - * //strokeWidth:1, - * //polyStrokeWidth:1, - * paramArray:['Speed','Flexibility', 'Costs'], - * labelArray:['Ruby','JavaScript', 'PHP', 'Python'], - * //startAngle:Math.PI/4, - * legendPosition:'right', - * //"startShiftRatio": 0.1, - * //endShiftRatio:0.1, - * //startShiftArray:[0,0,0], - * //endShiftArray:[0.5,0.5,0.5], - * start:0 - * //end:70, - * //startArray:[0,0,0], - * //endArray:[7,7,7], - * //radius:3, - * //showCircles:true, - * //circleLabelArray:[1,2,3,4,5], - * //highlightColorArray:['#E46F6A','#F9DF82','#F7FA7B','#B0D990','#69BF8E','#BDDDE4','#92C2DF','#637CB0','#AB91BC','#EB8EBF'], - * }); - * board.unsuspendUpdate(); - * - * })(); - * - * </script><pre> - * - * For more examples see - * <ul> - * <li><a href="https://jsxgraph.org/wiki/index.php/Charts_from_HTML_tables_-_tutorial">JSXgraph wiki: Charts from HTML tables - tutorial</a> - * <li><a href="https://jsxgraph.org/wiki/index.php/Pie_chart">JSXgraph wiki: Pie chart</a> - * <li><a href="https://jsxgraph.org/wiki/index.php/Different_chart_styles">JSXgraph wiki: Various chart styles</a> - * <li><a href="https://jsxgraph.org/wiki/index.php/Dynamic_bar_chart">JSXgraph wiki: Dynamic bar chart</a> - * </ul> - */ - JXG.createChart = function (board, parents, attributes) { - var data, row, i, j, col, - charts = [], - w, x, showRows, attr, - originalWidth, name, strokeColor, fillColor, - hStrokeColor, hFillColor, len, - table = Env.isBrowser ? board.document.getElementById(parents[0]) : null; - - if ((parents.length === 1) && (Type.isString(parents[0]))) { - if (Type.exists(table)) { - // extract the data - attr = Type.copyAttributes(attributes, board.options, 'chart'); + toJCAN: function (obj) { + var i, list, prop; - table = (new DataSource()).loadFromTable(parents[0], attr.withheaders, attr.withheaders); - data = table.data; - col = table.columnHeaders; - row = table.rowHeaders; + switch (typeof obj) { + case 'object': + if (obj) { + list = []; - originalWidth = attr.width; - name = attr.name; - strokeColor = attr.strokecolor; - fillColor = attr.fillcolor; - hStrokeColor = attr.highlightstrokecolor; - hFillColor = attr.highlightfillcolor; + if (Type.isArray(obj)) { + for (i = 0; i < obj.length; i++) { + list.push(this.toJCAN(obj[i])); + } - board.suspendUpdate(); + return '[' + list.join(',') + ']'; + } - len = data.length; - showRows = []; - if (attr.rows && Type.isArray(attr.rows)) { - for (i = 0; i < len; i++) { - for (j = 0; j < attr.rows.length; j++) { - if ((attr.rows[j] === i) || (attr.withheaders && attr.rows[j] === row[i])) { - showRows.push(data[i]); - break; - } + for (prop in obj) { + if (obj.hasOwnProperty(prop)) { + list.push(prop + ': ' + this.toJCAN(obj[prop])); } } - } else { - showRows = data; - } - len = showRows.length; + return '<<' + list.join(', ') + '>> '; + } + return 'null'; + case 'string': + return '\'' + obj.replace(/\\/g,'\\\\').replace(/(["'])/g, '\\$1') + '\''; + case 'number': + case 'boolean': + return obj.toString(); + case 'null': + return 'null'; + } + }, - for (i = 0; i < len; i++) { + /** + * Saves the construction in <tt>board</tt> to JessieCode. + * @param {JXG.Board} board + * @returns {String} JessieCode + */ + toJessie: function (board) { + var i, elements, id, + dump = this.dump(board), + script = []; - x = []; - if (attr.chartstyle && attr.chartstyle.indexOf('bar') !== -1) { - if (originalWidth) { - w = originalWidth; - } else { - w = 0.8; - } + dump.methods = this.setBoundingBox(dump.methods, board, '$board'); - x.push(1 - w / 2 + (i + 0.5) * w / len); + elements = dump.elements; - for (j = 1; j < showRows[i].length; j++) { - x.push(x[j - 1] + 1); - } + for (i = 0; i < elements.length; i++) { + if (elements[i].attributes.name.length > 0) { + script.push('// ' + elements[i].attributes.name); + } + script.push('s' + i + ' = ' + elements[i].type + '(' + elements[i].parents.join(', ') + ') ' + this.toJCAN(elements[i].attributes).replace(/\n/, '\\n') + ';'); - attr.width = w / len; + if (elements[i].type === 'axis') { + // Handle the case that remove[All]Ticks had been called. + id = elements[i].attributes.id; + if (board.objects[id].defaultTicks === null) { + script.push('s' + i + '.removeAllTicks();'); } + } + script.push(''); + } - if (name && name.length === len) { - attr.name = name[i]; - } else if (attr.withheaders) { - attr.name = col[i]; - } + for (i = 0; i < dump.methods.length; i++) { + script.push(dump.methods[i].obj + '.' + dump.methods[i].method + '(' + this.arrayToParamStr(dump.methods[i].params, this.toJCAN) + ');'); + script.push(''); + } - if (strokeColor && strokeColor.length === len) { - attr.strokecolor = strokeColor[i]; - } else { - attr.strokecolor = Color.hsv2rgb(((i + 1) / len) * 360, 0.9, 0.6); - } + for (i = 0; i < dump.props.length; i++) { + script.push(dump.props[i].obj + '.' + dump.props[i].prop + ' = ' + this.toJCAN(dump.props[i].val) + ';'); + script.push(''); + } - if (fillColor && fillColor.length === len) { - attr.fillcolor = fillColor[i]; - } else { - attr.fillcolor = Color.hsv2rgb(((i + 1) / len) * 360, 0.9, 1.0); - } + return script.join('\n'); + }, - if (hStrokeColor && hStrokeColor.length === len) { - attr.highlightstrokecolor = hStrokeColor[i]; - } else { - attr.highlightstrokecolor = Color.hsv2rgb(((i + 1) / len) * 360, 0.9, 1.0); - } + /** + * Saves the construction in <tt>board</tt> to JavaScript. + * @param {JXG.Board} board + * @returns {String} JavaScript + */ + toJavaScript: function (board) { + var i, elements, id, + dump = this.dump(board), + script = []; - if (hFillColor && hFillColor.length === len) { - attr.highlightfillcolor = hFillColor[i]; - } else { - attr.highlightfillcolor = Color.hsv2rgb(((i + 1) / len) * 360, 0.9, 0.6); - } + dump.methods = this.setBoundingBox(dump.methods, board, 'board'); - if (attr.chartstyle && attr.chartstyle.indexOf('bar') !== -1) { - charts.push(new JXG.Chart(board, [x, showRows[i]], attr)); - } else { - charts.push(new JXG.Chart(board, [showRows[i]], attr)); + elements = dump.elements; + + for (i = 0; i < elements.length; i++) { + script.push('board.create("' + elements[i].type + '", [' + elements[i].parents.join(', ') + '], ' + Type.toJSON(elements[i].attributes) + ');'); + + if (elements[i].type === 'axis') { + // Handle the case that remove[All]Ticks had been called. + id = elements[i].attributes.id; + if (board.objects[id].defaultTicks === null) { + script.push('board.objects["' + id + '"].removeTicks(board.objects["' + id + '"].defaultTicks);'); } } + } - board.unsuspendUpdate(); + for (i = 0; i < dump.methods.length; i++) { + script.push(dump.methods[i].obj + '.' + dump.methods[i].method + '(' + this.arrayToParamStr(dump.methods[i].params, Type.toJSON) + ');'); + script.push(''); + } + for (i = 0; i < dump.props.length; i++) { + script.push(dump.props[i].obj + '.' + dump.props[i].prop + ' = ' + Type.toJSON(dump.props[i].val) + ';'); + script.push(''); } - return charts; - } - attr = Type.copyAttributes(attributes, board.options, 'chart'); - return new JXG.Chart(board, parents, attr); + return script.join('\n'); + } }; - JXG.registerElement('chart', JXG.createChart); + return JXG.Dump; +}); - /** - * Legend for chart - * TODO - * - * The Legend class is a basic class for legends. - * @class Creates a new Lgend object. Do not use this constructor to create a legend. - * Use {@link JXG.Board#create} with type {@link Legend} instead. - * <p> - * The legend object consists of segements with labels. These lines can be - * access with the property "lines" of the element. - * @constructor - * @augments JXG.GeometryElement - * @param {String,JXG.Board} board The board the new legend is drawn on. - * @param {Array} coords Coordinates of the left top point of the legend. - * @param {Object} attributes Attributes of the legend - */ - JXG.Legend = function (board, coords, attributes) { - var attr; +/* + Copyright 2018-2022 + Alfred Wassermann, + Tigran Saluev - /* Call the constructor of GeometryElement */ - this.constructor(); + This file is part of JSXGraph. - attr = Type.copyAttributes(attributes, board.options, 'legend'); + JSXGraph is free software dual licensed under the GNU LGPL or MIT License. - this.board = board; - this.coords = new Coords(Const.COORDS_BY_USER, coords, this.board); - this.myAtts = {}; - this.label_array = attr.labelarray || attr.labels; - this.color_array = attr.colorarray || attr.colors; - this.lines = []; - this.myAtts.strokewidth = attr.strokewidth || 5; - this.myAtts.straightfirst = false; - this.myAtts.straightlast = false; - this.myAtts.withlabel = true; - this.myAtts.fixed = true; - this.style = attr.legendstyle || attr.style; + You can redistribute it and/or modify it under the terms of the + + * GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version + OR + * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT - if (this.style === 'vertical') { - this.drawVerticalLegend(board, attr); - } else { - throw new Error('JSXGraph: Unknown legend style: ' + this.style); - } - }; + JSXGraph is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. - JXG.Legend.prototype = new GeometryElement(); + You should have received a copy of the GNU Lesser General Public License and + the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> + and <http://opensource.org/licenses/MIT/>. + */ - /** - * Draw a vertical legend. - * - * @private - * @param {String,JXG.Board} board The board the legend is drawn on - * @param {Object} attributes Attributes of the legend - */ - JXG.Legend.prototype.drawVerticalLegend = function (board, attributes) { - var i, - line_length = attributes.linelength || 1, - offy = (attributes.rowheight || 20) / this.board.unitY, - getLabelAnchor = function () { - this.setLabelRelativeCoords(this.visProp.label.offset); - return new Coords(Const.COORDS_BY_USER, [this.point2.X(), this.point2.Y()], this.board); - }; +/*global JXG: true, define: true*/ +/*jslint nomen: true, plusplus: true*/ - for (i = 0; i < this.label_array.length; i++) { - this.myAtts.name = this.label_array[i]; - this.myAtts.strokecolor = this.color_array[i % this.color_array.length]; - this.myAtts.highlightstrokecolor = this.color_array[i % this.color_array.length]; - this.myAtts.label = { - offset: [10, 0], - strokeColor: this.color_array[i % this.color_array.length ], - strokeWidth: this.myAtts.strokewidth - }; +/* depends: + see define call + */ - this.lines[i] = board.create('line', [ - [this.coords.usrCoords[1], this.coords.usrCoords[2] - i * offy], - [this.coords.usrCoords[1] + line_length, this.coords.usrCoords[2] - i * offy]], - this.myAtts); +/** + * @fileoverview In this file the Comb element is defined. + */ - this.lines[i].getLabelAnchor = getLabelAnchor; - this.lines[i].prepareUpdate().update().updateVisibility(Type.evaluate(this.lines[i].visProp.visible)).updateRenderer(); - } - }; +define('element/comb',[ + 'jxg', 'utils/type', 'base/point' +], function (JXG, Type, Point) { + + "use strict"; /** - * @class This element is used to provide a constructor for a chart legend. - * Parameter is a pair of coordinates. The label names and the label colors are - * supplied in the attributes: - * <ul> - * <li> labels (Array): array of strings containing label names - * <li> labelArray (Array): alternative array for label names (has precedence over 'labels') - * <li> colors (Array): array of color values - * <li> colorArray (Array): alternative array for color values (has precedence over 'colors') - * <li> legendStyle or style: at the time being only 'vertical' is supported. - * <li> rowHeight. - * </ul> - * + * @class A comb to display domains of inequalities. * @pseudo - * @description - * @name Legend - * @augments JXG.Legend + * @name Comb + * @augments JXG.Curve * @constructor - * @type JXG.Legend - * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. - * @param {Number} x Horizontal coordinate of the left top point of the legend - * @param {Number} y Vertical coordinate of the left top point of the legend - * + * @type JXG.Curve + * @throws {Error} If the element cannot be constructed with the given parent + * objects an exception is thrown. + * Parameter options: + * @param {JXG.Point,array,function_JXG.Point,array,function} point1,point2 Parent elements + * can be two elements either of type {@link JXG.Point} or array of + * numbers describing the coordinates of a point. In the latter case the point + * will be constructed automatically as a fixed invisible point. + * It is possible to provide a function returning an array or a point, + * instead of providing an array or a point. * @example - * var board = JXG.JSXGraph.initBoard('jxgbox', {axis:true,boundingbox:[-4,48.3,12.0,-2.3]}); - * var x = [-3,-2,-1,0,1,2,3,4,5,6,7,8]; - * var dataArr = [4,7,7,27,33,37,46,22,11,4,1,0]; + * // Create a simple horizontal comb with invisible endpoints + * var c = board.create('comb', [[1, 0], [3, 0]]); * - * colors = ['green', 'yellow', 'red', 'blue']; - * board.create('chart', [x,dataArr], {chartStyle:'bar', width:1.0, labels:dataArr, colors: colors} ); - * board.create('legend', [8, 45], {labels:dataArr, colors: colors, strokeWidth:5} ); + * </pre><div class="jxgbox" id="JXG951ccb6a-52bc-4dc2-80e9-43db064f0f1b" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function () { + * var board = JXG.JSXGraph.initBoard('JXG951ccb6a-52bc-4dc2-80e9-43db064f0f1b', {boundingbox: [-5, 5, 5, -5], axis: true, showcopyright: false, shownavigation: false}), + * c = board.create('comb', [[1, 0], [3, 0]]); + * })(); + * </script><pre> * - * </pre><div id="JXGeeb588d9-a4fd-41bf-93f4-cd6f7a016682" class="jxgbox" style="width: 300px; height: 300px;"></div> + * @example + * var p1 = board.create('glider', [-3, 0, board.defaultAxes.x]); + * var p2 = board.create('glider', [-1, 0, board.defaultAxes.x]); + * var c1 = board.create('comb', [p1, p2], {width: 0.2, frequency: 0.1, angle: Math.PI / 4}); + * + * </pre><div id="JXG04186fd2-6340-11e8-9fb9-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div> * <script type="text/javascript"> * (function() { - * var board = JXG.JSXGraph.initBoard('JXGeeb588d9-a4fd-41bf-93f4-cd6f7a016682', - * {boundingbox: [-4,48.3,12.0,-2.3], axis: true, showcopyright: false, shownavigation: false}); - * var x = [-3,-2,-1,0,1,2,3,4,5,6,7,8]; - * var dataArr = [4,7,7,27,33,37,46,22,11,4,1,0]; - * - * colors = ['green', 'yellow', 'red', 'blue']; - * board.create('chart', [x,dataArr], {chartStyle:'bar', width:1.0, labels:dataArr, colors: colors} ); - * board.create('legend', [8, 45], {labels:dataArr, colors: colors, strokeWidth:5} ); + * var board = JXG.JSXGraph.initBoard('JXG04186fd2-6340-11e8-9fb9-901b0e1b8723', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * var p1 = board.create('glider', [-3, 0, board.defaultAxes.x]); + * var p2 = board.create('glider', [-1, 0, board.defaultAxes.x]); + * var c1 = board.create('comb', [p1, p2], {width: 0.2, frequency: 0.1, angle: Math.PI / 4}); * * })(); * * </script><pre> * + * @example + * var s = board.create('slider', [[1,3], [4,3], [0.1, 0.3, 0.8]]); + * var p1 = board.create('glider', [-3, 0, board.defaultAxes.x]); + * var p2 = board.create('glider', [-1, 0, board.defaultAxes.x]); + * var c1 = board.create('comb', [p1, p2], { + * width: function(){ return 4*s.Value(); }, + * reverse: function(){ return (s.Value()<0.5) ? false : true; }, + * frequency: function(){ return s.Value(); }, + * angle: function(){ return s.Value() * Math.PI / 2; }, + * curve: { + * strokeColor: 'red' + * } + * }); + * + * </pre><div id="JXG6eb1bcd1-407e-4f13-8f0c-45ef39a0cfb3" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG6eb1bcd1-407e-4f13-8f0c-45ef39a0cfb3', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * var s = board.create('slider', [[1,3], [4,3], [0.1, 0.3, 0.8]]); + * var p1 = board.create('glider', [-3, 0, board.defaultAxes.x]); + * var p2 = board.create('glider', [-1, 0, board.defaultAxes.x]); + * var c1 = board.create('comb', [p1, p2], { + * width: function(){ return 4*s.Value(); }, + * reverse: function(){ return (s.Value()<0.5) ? false : true; }, + * frequency: function(){ return s.Value(); }, + * angle: function(){ return s.Value() * Math.PI / 2; }, + * curve: { + * strokeColor: 'red' + * } + * }); + * + * })(); + * + * </script><pre> * */ - JXG.createLegend = function (board, parents, attributes) { - //parents are coords of left top point of the legend - var start_from = [0, 0]; + JXG.createComb = function(board, parents, attributes) { + var p1, p2, c, attr, parent_types; + //ds, angle, width, p; - if (Type.exists(parents) && parents.length === 2) { - start_from = parents; + if (parents.length === 2) { + // point 1 given by coordinates + if (Type.isArray(parents[0]) && parents[0].length > 1) { + attr = Type.copyAttributes(attributes, board.options, 'comb', 'point1'); + p1 = board.create('point', parents[0], attr); + } else if (Type.isString(parents[0]) || Type.isPoint(parents[0])) { + p1 = board.select(parents[0]); + } else if (Type.isFunction(parents[0]) && Type.isPoint(parents[0]())) { + p1 = parents[0](); + } else if (Type.isFunction(parents[0]) && parents[0]().length && parents[0]().length >= 2) { + attr = Type.copyAttributes(attributes, board.options, 'comb', 'point1'); + p1 = Point.createPoint(board, parents[0](), attr); + } else { + throw new Error("JSXGraph: Can't create comb with parent types '" + + (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + + "\nPossible parent types: [point,point], [[x1,y1],[x2,y2]]"); + } + + // point 2 given by coordinates + if (Type.isArray(parents[1]) && parents[1].length > 1) { + attr = Type.copyAttributes(attributes, board.options, 'comb', 'point2'); + p2 = board.create('point', parents[1], attr); + } else if (Type.isString(parents[1]) || Type.isPoint(parents[1])) { + p2 = board.select(parents[1]); + } else if (Type.isFunction(parents[1]) && Type.isPoint(parents[1]()) ) { + p2 = parents[1](); + } else if (Type.isFunction(parents[1]) && parents[1]().length && parents[1]().length >= 2) { + attr = Type.copyAttributes(attributes, board.options, 'comb', 'point2'); + p2 = Point.createPoint(board, parents[1](), attr); + } else { + throw new Error("JSXGraph: Can't create comb with parent types '" + + (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + + "\nPossible parent types: [point,point], [[x1,y1],[x2,y2]]"); + } } else { - throw new Error('JSXGraph: Legend element needs two numbers as parameters'); + parent_types = parents.map(function(parent) { return "'" + (typeof parent) + "'"; }); + throw new Error("JSXGraph: Can't create comb with parent types " + + parent_types.join(", ") + "." + + "\nPossible parent types: [point,point], [[x1,y1],[x2,y2]]"); } - return new JXG.Legend(board, start_from, attributes); + // attr = Type.copyAttributes(attributes, board.options, 'comb', 'curve'); + attr = Type.copyAttributes(attributes, board.options, 'comb'); + Type.merge(attr, Type.copyAttributes(attributes, board.options, 'comb', 'curve')); + c = board.create('curve', [[0], [0]], attr); + + /** + * @ignore + */ + c.updateDataArray = function() { + var s = 0, + max_s = p1.Dist(p2), + cs, sn, dx, dy, + x, y, f, + p1_inner = p1, + p2_inner = p2, + ds, angle, width; + + ds = Type.evaluate(c.visProp.frequency); + angle = -Type.evaluate(c.visProp.angle); + width = Type.evaluate(c.visProp.width); + if (Type.evaluate(c.visProp.reverse)) { + p1_inner = p2; + p2_inner = p1; + angle = -angle; + } + cs = Math.cos(angle); + sn = Math.sin(angle); + dx = (p2_inner.X() - p1_inner.X()) / max_s; + dy = (p2_inner.Y() - p1_inner.Y()) / max_s; + + // But instead of lifting by sin(angle), we want lifting by width. + cs *= width / Math.abs(sn); + sn *= width / Math.abs(sn); + + this.dataX = []; + this.dataY = []; + // TODO Handle infinite boundaries? + while (s < max_s) { + x = p1_inner.X() + dx * s; + y = p1_inner.Y() + dy * s; + + // We may need to cut the last piece of a comb. + f = Math.min(cs, max_s - s) / Math.abs(cs); + sn *= f; + cs *= f; + + this.dataX.push(x); + this.dataY.push(y); + + this.dataX.push(x + dx * cs + dy * sn); + this.dataY.push(y - dx * sn + dy * cs); + + this.dataX.push(NaN); // Force a jump + this.dataY.push(NaN); + s += ds; + } + }; + + return c; }; - JXG.registerElement('legend', JXG.createLegend); + JXG.registerElement('comb', JXG.createComb); return { - Chart: JXG.Chart, - Legend: JXG.Legend, - createChart: JXG.createChart, - createLegend: JXG.createLegend + createComb: JXG.createComb }; + }); /* - Copyright 2008-2021 + Copyright 2008-2022 Matthias Ehmann, Michael Gerhaeuser, Carsten Miller, @@ -69237,797 +78853,940 @@ define('base/chart',[ /*jslint nomen: true, plusplus: true*/ /* depends: - jxg - base/constants - base/element - utils/type - elements: - curve - point - line - transform + see define call */ /** - * @fileoverview The JSXGraph object Turtle is defined. It acts like - * "turtle graphics". - * @author A.W. + * @fileoverview Example file for a triangle implemented as a extension to JSXGraph. */ -define('base/turtle',[ - 'jxg', 'base/constants', 'base/element', 'utils/type', 'base/curve', 'base/point', 'base/line', 'base/transformation' -], function (JXG, Const, GeometryElement, Type, Curve, Point, Line, Transform) { +define('element/slopetriangle',[ + 'jxg', 'utils/type', 'base/constants', 'base/polygon' +], function (JXG, Type, Const, Polygon) { "use strict"; + var priv = { + removeSlopeTriangle: function () { + Polygon.Polygon.prototype.remove.call(this); + + this.board.removeObject(this.toppoint); + this.board.removeObject(this.glider); + + this.board.removeObject(this.baseline); + this.board.removeObject(this.basepoint); + + this.board.removeObject(this.label); + + if (this._isPrivateTangent) { + this.board.removeObject(this.tangent); + } + }, + Value: function () { + return this.tangent.getSlope(); + } + }; + /** - * Constructs a new Turtle object. - * @class This is the Turtle class. - * It is derived from {@link JXG.GeometryElement}. - * It stores all properties required - * to move a turtle. + * @class Slope triangle for a point on a line. + * @pseudo + * @name Slopetriangle + * @augments JXG.Line * @constructor - * @param {JXG.Board} board The board the new turtle is drawn on. - * @param {Array} parents Start position and start direction of the turtle. Possible values are - * [x, y, angle] - * [[x, y], angle] - * [x, y] - * [[x, y]] - * @param {Object} attributes Attributes to change the visual properties of the turtle object - * All angles are in degrees. - * + * @type JXG.Polygon + * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. + * Parameter options: + * @param {JXG.Line} t A tangent based on a glider on some object, e.g. curve, circle, line or turtle. + * @param {JXG.Line_JXG.Point} li, p A line and a point on that line. + * The user has to take care that the point is a member of the line. * @example + * // Create a slopetriangle on a tangent + * var f = board.create('plot', ['sin(x)']), + * g = board.create('glider', [1, 2, f]), + * t = board.create('tangent', [g]), * - * //creates a figure 8 animation - * var board = JXG.JSXGraph.initBoard('jxgbox',{boundingbox: [-250, 250, 250, -250]}); - * var t = board.create('turtle',[0, 0], {strokeOpacity:0.5}); - * t.setPenSize(3); - * t.right(90); - * var alpha = 0; - * - * var run = function() { - * t.forward(2); - * if (Math.floor(alpha / 360) % 2 === 0) { - * t.left(1); // turn left by 1 degree - * } else { - * t.right(1); // turn right by 1 degree - * } - * alpha += 1; - * - * if (alpha < 1440) { // stop after two rounds - * setTimeout(run, 20); - * } - * } - * - *run(); + * st = board.create('slopetriangle', [t]); * - * </pre><div class="jxgbox" id="JXG14167b1c-2ad3-11e5-8dd9-901b0e1b8723" style="width: 300px; height: 300px;"></div> + * </pre><div class="jxgbox" id="JXG951ccb6a-52bc-4dc2-80e9-43db064f0f1b" style="width: 300px; height: 300px;"></div> * <script type="text/javascript"> - * (function() { - * var brd = JXG.JSXGraph.initBoard('JXG14167b1c-2ad3-11e5-8dd9-901b0e1b8723', - * {boundingbox: [-250, 250, 250, -250], axis: true, showcopyright: false, shownavigation: false}); - * var t = brd.create('turtle',[0, 0], {strokeOpacity:0.5}); - * t.setPenSize(3); - * t.right(90); - * var alpha = 0; + * (function () { + * var board = JXG.JSXGraph.initBoard('JXG951ccb6a-52bc-4dc2-80e9-43db064f0f1b', {boundingbox: [-5, 5, 5, -5], axis: true, showcopyright: false, shownavigation: false}), + * f = board.create('plot', ['sin(x)']), + * g = board.create('glider', [1, 2, f]), + * t = board.create('tangent', [g]), * - * var run = function() { - * t.forward(2); - * if (Math.floor(alpha / 360) % 2 === 0) { - * t.left(1); // turn left by 1 degree - * } else { - * t.right(1); // turn right by 1 degree - * } - * alpha += 1; + * st = board.create('slopetriangle', [t]); + * })(); + * </script><pre> * - * if (alpha < 1440) { // stop after two rounds - * setTimeout(run, 20); - * } - * } + * @example + * // Create a on a line and a point on that line + * var p1 = board.create('point', [-2, 3]), + * p2 = board.create('point', [2, -3]), + * li = board.create('line', [p1, p2]), + * p = board.create('glider', [0, 0, li]), * - * run(); + * st = board.create('slopetriangle', [li, p]); * - * })(); + * </pre><div class="jxgbox" id="JXGb52f451c-22cf-4677-852a-0bb9d764ee95" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function () { + * var board = JXG.JSXGraph.initBoard('JXGb52f451c-22cf-4677-852a-0bb9d764ee95', {boundingbox: [-5, 5, 5, -5], axis: true, showcopyright: false, shownavigation: false}), + * p1 = board.create('point', [-2, 3]), + * p2 = board.create('point', [2, -3]), + * li = board.create('line', [p1, p2]), + * p = board.create('glider', [0, 0, li]), * + * st = board.create('slopetriangle', [li, p]); + * })(); * </script><pre> */ - JXG.Turtle = function (board, parents, attributes) { - var x, y, dir; + JXG.createSlopeTriangle = function (board, parents, attributes) { + var el, tangent, tglide, glider, toppoint, baseline, basepoint, label, attr, + isPrivateTangent = false; - this.constructor(board, attributes, Const.OBJECT_TYPE_TURTLE, Const.OBJECT_CLASS_OTHER); + if (parents.length === 1 && parents[0].type === Const.OBJECT_TYPE_TANGENT) { + tangent = parents[0]; + tglide = tangent.glider; + } else if (parents.length === 1 && parents[0].type === Const.OBJECT_TYPE_GLIDER) { + tglide = parents[0]; + attr = Type.copyAttributes(attributes, board.options, 'slopetriangle', 'tangent'); + tangent = board.create('tangent', [tglide], attr); + isPrivateTangent = true; + } else if (parents.length === 2 && + parents[0].elementClass === Const.OBJECT_CLASS_LINE && Type.isPoint(parents[1])) { + tangent = parents[0]; + tglide = parents[1]; + } else { + throw new Error("JSXGraph: Can't create slope triangle with parent types '" + (typeof parents[0]) + "'."); + } - this.turtleIsHidden = false; - this.board = board; - this.visProp.curveType = 'plot'; + attr = Type.copyAttributes(attributes, board.options, 'slopetriangle', 'basepoint'); + basepoint = board.create('point', [function () { + return [tglide.X() + 1, tglide.Y()]; + }], attr); - // Save visProp in this._attributes. - // this._attributes is overwritten by setPenSize, setPenColor... - // Setting the color or size affects the turtle from the time of - // calling the method, - // whereas Turtle.setAttribute affects all turtle curves. - this._attributes = Type.copyAttributes(this.visProp, board.options, 'turtle'); - delete this._attributes.id; + attr = Type.copyAttributes(attributes, board.options, 'slopetriangle', 'baseline'); + baseline = board.create('line', [tglide, basepoint], attr); - x = 0; - y = 0; - dir = 90; + attr = Type.copyAttributes(attributes, board.options, 'slopetriangle', 'glider'); + glider = board.create('glider', [tglide.X() + 1, tglide.Y(), baseline], attr); - if (parents.length !== 0) { - // [x,y,dir] - if (parents.length === 3) { - // Only numbers are accepted at the moment - x = parents[0]; - y = parents[1]; - dir = parents[2]; - } else if (parents.length === 2) { - // [[x,y],dir] - if (Type.isArray(parents[0])) { - x = parents[0][0]; - y = parents[0][1]; - dir = parents[1]; - // [x,y] - } else { - x = parents[0]; - y = parents[1]; - } - // [[x,y]] - } else { - x = parents[0][0]; - y = parents[0][1]; - } - } + attr = Type.copyAttributes(attributes, board.options, 'slopetriangle', 'toppoint'); + toppoint = board.create('point', [function () { + return [glider.X(), glider.Y() + (glider.X() - tglide.X()) * tangent.getSlope()]; + }], attr); + + attr = Type.copyAttributes(attributes, board.options, 'slopetriangle'); + attr.borders = Type.copyAttributes(attr.borders, board.options, 'slopetriangle', 'borders'); + el = board.create('polygon', [tglide, glider, toppoint], attr); + + /** + * Returns the value of the slope triangle, that is the slope of the tangent. + * @name Value + * @memberOf Slopetriangle.prototype + * @function + * @returns {Number} slope of the tangent. + */ + el.Value = priv.Value; + el.tangent = tangent; + el._isPrivateTangent = isPrivateTangent; + + //el.borders[0].setArrow(false, {type: 2, size: 10}); + //el.borders[1].setArrow(false, {type: 2, size: 10}); + el.borders[2].setArrow(false, false); + + attr = Type.copyAttributes(attributes, board.options, 'slopetriangle', 'label'); + label = board.create('text', [ + function () { return glider.X() + 0.1; }, + function () { return (glider.Y() + toppoint.Y()) * 0.5; }, + function () { return ''; } + ], attr); + + label._setText(function () { + return Type.toFixed(el.Value(), Type.evaluate(label.visProp.digits)); + }); + label.fullUpdate(); - this.init(x, y, dir); + el.glider = glider; + el.basepoint = basepoint; + el.baseline = baseline; + el.toppoint = toppoint; + el.label = label; - this.methodMap = Type.deepCopy(this.methodMap, { - forward: 'forward', - fd: 'forward', - back: 'back', - bk: 'back', - right: 'right', - rt: 'right', - left: 'left', - lt: 'left', - penUp: 'penUp', - pu: 'penUp', - penDown: 'penDown', - pd: 'penDown', - clearScreen: 'clearScreen', - cs: 'clearScreen', - clean: 'clean', - setPos: 'setPos', - home: 'home', - hideTurtle: 'hideTurtle', - ht: 'hideTurtle', - showTurtle: 'showTurtle', - st: 'showTurtle', - penSize: 'setPenSize', - penColor: 'setPenColor', - pushTurtle: 'pushTurtle', - push: 'pushTurtle', - popTurtle: 'popTurtle', - pop: 'popTurtle', - lookTo: 'lookTo', - pos: 'pos', - moveTo: 'moveTo', - X: 'X', - Y: 'Y' + el.subs = { + glider: glider, + basePoint: basepoint, + baseLine: baseline, + topPoint: toppoint, + label: label + }; + el.inherits.push(glider, basepoint, baseline, toppoint, label); + + el.methodMap = JXG.deepCopy(el.methodMap, { + tangent: 'tangent', + glider: 'glider', + basepoint: 'basepoint', + baseline: 'baseline', + toppoint: 'toppoint', + label: 'label', + Value: 'Value', + V: 'Value' }); - return this; + el.remove = priv.removeSlopeTriangle; + + return el; }; - JXG.Turtle.prototype = new GeometryElement(); + JXG.registerElement('slopetriangle', JXG.createSlopeTriangle); - JXG.extend(JXG.Turtle.prototype, /** @lends JXG.Turtle.prototype */ { - /** - * Initialize a new turtle or reinitialize a turtle after {@link JXG.Turtle#clearScreen}. - * @private - */ - init: function (x, y, dir) { - var hiddenPointAttr = { - fixed: true, - name: '', - visible: false, - withLabel: false - }; + return { + createSlopeTriangle: JXG.createSlopeTriangle + }; +}); - this.arrowLen = 20 / Math.sqrt(this.board.unitX * this.board.unitX + this.board.unitY * this.board.unitY); +/* + Copyright 2008-2022 + Matthias Ehmann, + Michael Gerhaeuser, + Carsten Miller, + Bianca Valentin, + Alfred Wassermann, + Peter Wilfahrt - this.pos = [x, y]; - this.isPenDown = true; - this.dir = 90; - this.stack = []; - this.objects = []; - this.curve = this.board.create('curve', [[this.pos[0]], [this.pos[1]]], this._attributes); - this.objects.push(this.curve); + This file is part of JSXGraph. - this.turtle = this.board.create('point', this.pos, hiddenPointAttr); - this.objects.push(this.turtle); + JSXGraph is free software dual licensed under the GNU LGPL or MIT License. - this.turtle2 = this.board.create('point', [this.pos[0], this.pos[1] + this.arrowLen], hiddenPointAttr); - this.objects.push(this.turtle2); + You can redistribute it and/or modify it under the terms of the - this.visProp.arrow.lastArrow = true; - this.visProp.arrow.straightFirst = false; - this.visProp.arrow.straightLast = false; - this.arrow = this.board.create('line', [this.turtle, this.turtle2], this.visProp.arrow); - this.objects.push(this.arrow); + * GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version + OR + * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT - this.subs = { - arrow: this.arrow - }; - this.inherits.push(this.arrow); + JSXGraph is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. - this.right(90 - dir); - this.board.update(); - }, + You should have received a copy of the GNU Lesser General Public License and + the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> + and <http://opensource.org/licenses/MIT/>. + */ - /** - * Move the turtle forward. - * @param {Number} len of forward move in user coordinates - * @returns {JXG.Turtle} pointer to the turtle object - */ - forward: function (len) { - if (len === 0) { - return this; - } - var t, - dx = len * Math.cos(this.dir * Math.PI / 180), - dy = len * Math.sin(this.dir * Math.PI / 180); +/*global JXG: true, define: true, window: true*/ +/*jslint nomen: true, plusplus: true*/ - if (!this.turtleIsHidden) { - t = this.board.create('transform', [dx, dy], {type: 'translate'}); +/* depends: + jxg + utils/env + utils/type + */ - t.applyOnce(this.turtle); - t.applyOnce(this.turtle2); - } +/** + * @fileoverview In this file the Text element is defined. + */ - if (this.isPenDown) { - // IE workaround - if (this.curve.dataX.length >= 8192) { - this.curve = this.board.create('curve', [[this.pos[0]], [this.pos[1]]], this._attributes); - this.objects.push(this.curve); - } - } +define('element/checkbox',[ + 'jxg', 'utils/env', 'utils/type' +], function (JXG, Env, Type) { - this.pos[0] += dx; - this.pos[1] += dy; + "use strict"; - if (this.isPenDown) { - this.curve.dataX.push(this.pos[0]); - this.curve.dataY.push(this.pos[1]); + var priv = { + CheckboxChangeEventHandler: function () { + this._value = this.rendNodeCheckbox.checked; + this.board.update(); } + }; - this.board.update(); - return this; - }, + /** + * @class This element is used to provide a constructor for special texts containing a + * form checkbox element. + * <p> + * For this element, the attribute "display" has to have the value 'html' (which is the default). + * + * @pseudo + * @description + * @name Checkbox + * @augments Text + * @constructor + * @type JXG.Text + * + * @param {number,function_number,function_String_String} x,y,label Parent elements for checkbox elements. + * <p> + * x and y are the coordinates of the lower left corner of the text box. + * The position of the text is fixed, + * x and y are numbers. The position is variable if x or y are functions. + * <p> + * The label of the input element may be given as string. + * <p> + * The value of the checkbox can be controlled with the attribute <tt>checked</tt> + * <p>The HTML node can be accessed with <tt>element.rendNodeCheckbox</tt> + * + * @example + * // Create a checkbox element at position [0,3]. + * var checkbox = board.create('checkbox', [0, 3, 'Change Y'], {}); + * var p = board.create('point', [ + * function(){ return 0.5;}, // X-coordinate + * function() { + * y = 0.5; + * if (checkbox.Value()) { + * y += 0.5; + * } + * return y; + * }]); + * </pre><div class="jxgbox" id="JXG0e835e0b-ed0c-4b85-b682-78158c0e6f5c" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var t1_board = JXG.JSXGraph.initBoard('JXG0e835e0b-ed0c-4b85-b682-78158c0e6f5c', {boundingbox: [-3, 6, 5, -3], axis: true, showcopyright: false, shownavigation: false}); + * var checkbox = t1_board.create('checkbox', [0, 3, 'Change Y'], {}); + * var p = t1_board.create('point', [ + * function(){ return 0.5;}, // X-coordinate + * function() { + * y = 0.5; + * if (checkbox.Value()) { + * y += 0.5; + * } + * return y; + * }]); + * })(); + * </script><pre> + * + * The checkbox can be supplied with custom-made events by using the property rendNodeCheckbox. + * @example + * var checkbox = board.create('checkbox', [0, 4, 'Click me']), + * p = board.create('point', [1, 1]); + * + * JXG.addEvent(checkbox.rendNodeCheckbox, 'change', function() { + * if (this.Value()) { + * p.moveTo([4, 1]); + * } else { + * p.moveTo([1, 1]); + * } + * }, checkbox); + * </pre><div class="jxgbox" id="JXGb2f2345a-057d-44ce-bd7a-6aaff70bc810" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXGb2f2345a-057d-44ce-bd7a-6aaff70bc810', {boundingbox: [-3, 6, 5, -3], axis: true, showcopyright: false, shownavigation: false}); + * var checkbox = board.create('checkbox', [0, 4, 'Click me']), + * p = board.create('point', [1, 1]); + * + * JXG.addEvent(checkbox.rendNodeCheckbox, 'change', function() { + * if (this.Value()) { + * p.moveTo([4, 1]); + * } else { + * p.moveTo([1, 1]); + * } + * }, checkbox); + * })(); + * </script><pre> + * + * @example + * var i1 = board.create('input', [-3, 4, 'sin(x)', 'f(x)='], {cssStyle: 'width:4em', maxlength: 2}); + * var c1 = board.create('checkbox', [-3, 2, 'label 1'], {}); + * var b1 = board.create('button', [-3, -1, 'Change texts', function () { + * i1.setText('g(x)'); + * i1.set('cos(x)'); + * c1.setText('label 2'); + * b1.setText('Texts are changed'); + * }], + * {cssStyle: 'width:400px'}); + * + * </pre><div id="JXG11cac8gg-2354-47e7-9da4-eb298e53de05" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG11cac8gg-2354-47e7-9da4-eb298e53de05', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * var i1 = board.create('input', [-3, 4, 'sin(x)', 'f(x)='], {cssStyle: 'width:4em', maxlength: 2}); + * var c1 = board.create('checkbox', [-3, 2, 'label 1'], {}); + * var b1 = board.create('button', [-3, -1, 'Change texts', function () { + * i1.setText('g(x)'); + * i1.set('cos(x)'); + * c1.setText('label 2'); + * b1.setText('Texts are changed'); + * }], + * {cssStyle: 'width:400px'}); + * + * })(); + * + * </script><pre> + */ + JXG.createCheckbox = function (board, parents, attributes) { + var t, par, + attr = Type.copyAttributes(attributes, board.options, 'checkbox'); - /** - * Move the turtle backwards. - * @param {Number} len of backwards move in user coordinates - * @returns {JXG.Turtle} pointer to the turtle object - */ - back: function (len) { - return this.forward(-len); - }, + //if (parents.length !== 3) { + //throw new Error("JSXGraph: Can't create checkbox with parent types '" + + // (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + + // "\nPossible parents are: [[x,y], label]"); + //} - /** - * Rotate the turtle direction to the right - * @param {Number} angle of the rotation in degrees - * @returns {JXG.Turtle} pointer to the turtle object - */ - right: function (angle) { - this.dir -= angle; - this.dir %= 360; + par = [parents[0], parents[1], + '<span style="display:inline">' + + '<input type="checkbox" /><label for=""></label>' + + '</span>' + ]; - if (!this.turtleIsHidden) { - var t = this.board.create('transform', [-angle * Math.PI / 180, this.turtle], {type: 'rotate'}); - t.applyOnce(this.turtle2); - } + //t = JXG.createText(board, par, attr); + t = board.create('text', par, attr); + t.type = Type.OBJECT_TYPE_CHECKBOX; - this.board.update(); - return this; - }, + t.rendNodeCheckbox = t.rendNode.childNodes[0].childNodes[0]; + t.rendNodeLabel = t.rendNode.childNodes[0].childNodes[1]; - /** - * Rotate the turtle direction to the right. - * @param {Number} angle of the rotation in degrees - * @returns {JXG.Turtle} pointer to the turtle object - */ - left: function (angle) { - return this.right(-angle); - }, + t.rendNodeTag = t.rendNodeCheckbox; // Needed for unified treatment in setAttribute + t.rendNodeTag.disabled = !!attr.disabled; - /** - * Pen up, stops visible drawing - * @returns {JXG.Turtle} pointer to the turtle object - */ - penUp: function () { - this.isPenDown = false; - return this; - }, + t.rendNodeLabel.innerHTML = parents[2]; + t.rendNodeCheckbox.id = t.rendNode.id + '_checkbox'; + t.rendNodeLabel.id = t.rendNode.id + '_label'; + t.rendNodeLabel.setAttribute('for', t.rendNodeCheckbox.id); - /** - * Pen down, continues visible drawing - * @returns {JXG.Turtle} pointer to the turtle object - */ - penDown: function () { - this.isPenDown = true; - this.curve = this.board.create('curve', [[this.pos[0]], [this.pos[1]]], this._attributes); - this.objects.push(this.curve); + // This sets the font-size of the checkbox itself + t.visPropOld.fontsize = "0px"; + board.renderer.updateTextStyle(t, false); - return this; - }, + t.rendNodeCheckbox.checked = attr.checked; + + t._value = attr.checked; /** - * Removes the turtle curve from the board. The turtle stays in its position. - * @returns {JXG.Turtle} pointer to the turtle object + * Returns the value of the checkbox element + * @name Value + * @memberOf Checkbox.prototype + * @function + * @returns {String} value of the checkbox. */ - clean: function () { - var i, el; + t.Value = function () { + return this._value; + }; - for (i = 0; i < this.objects.length; i++) { - el = this.objects[i]; - if (el.type === Const.OBJECT_TYPE_CURVE) { - this.board.removeObject(el); - this.objects.splice(i, 1); - } + t.update = function () { + if (this.needsUpdate) { + JXG.Text.prototype.update.call(this); + this._value = this.rendNodeCheckbox.checked; } - - this.curve = this.board.create('curve', [[this.pos[0]], [this.pos[1]]], this._attributes); - this.objects.push(this.curve); - this.board.update(); - return this; - }, + }; - /** - * Removes the turtle completely and resets it to its initial position and direction. - * @returns {JXG.Turtle} pointer to the turtle object - */ - clearScreen: function () { - var i, el, - len = this.objects.length; + Env.addEvent(t.rendNodeCheckbox, 'change', priv.CheckboxChangeEventHandler, t); - for (i = 0; i < len; i++) { - el = this.objects[i]; - this.board.removeObject(el); - } + return t; + }; - this.init(0, 0, 90); - return this; - }, + JXG.registerElement('checkbox', JXG.createCheckbox); - /** - * Moves the turtle without drawing to a new position - * @param {Number} x new x- coordinate - * @param {Number} y new y- coordinate - * @returns {JXG.Turtle} pointer to the turtle object - */ - setPos: function (x, y) { - var t; + return { + createCheckbox: JXG.createCheckbox + }; +}); - if (Type.isArray(x)) { - this.pos = x; - } else { - this.pos = [x, y]; - } +/* + Copyright 2008-2022 + Matthias Ehmann, + Michael Gerhaeuser, + Carsten Miller, + Bianca Valentin, + Alfred Wassermann, + Peter Wilfahrt - if (!this.turtleIsHidden) { - this.turtle.setPositionDirectly(Const.COORDS_BY_USER, [x, y]); - this.turtle2.setPositionDirectly(Const.COORDS_BY_USER, [x, y + this.arrowLen]); - t = this.board.create('transform', [-(this.dir - 90) * Math.PI / 180, this.turtle], {type: 'rotate'}); - t.applyOnce(this.turtle2); - } + This file is part of JSXGraph. - this.curve = this.board.create('curve', [[this.pos[0]], [this.pos[1]]], this._attributes); - this.objects.push(this.curve); - this.board.update(); + JSXGraph is free software dual licensed under the GNU LGPL or MIT License. - return this; - }, + You can redistribute it and/or modify it under the terms of the - /** - * Sets the pen size. Equivalent to setAttribute({strokeWidth:size}) - * but affects only the future turtle. - * @param {Number} size - * @returns {JXG.Turtle} pointer to the turtle object - */ - setPenSize: function (size) { - //this.visProp.strokewidth = size; - this.curve = this.board.create('curve', [[this.pos[0]], [this.pos[1]]], this.copyAttr('strokeWidth', size)); - this.objects.push(this.curve); - return this; - }, + * GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version + OR + * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT - /** - * Sets the pen color. Equivalent to setAttribute({strokeColor:color}) - * but affects only the future turtle. - * @param {String} color - * @returns {JXG.Turtle} pointer to the turtle object - */ - setPenColor: function (color) { - this.curve = this.board.create('curve', [[this.pos[0]], [this.pos[1]]], this.copyAttr('strokeColor', color)); - this.objects.push(this.curve); + JSXGraph is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. - return this; - }, + You should have received a copy of the GNU Lesser General Public License and + the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> + and <http://opensource.org/licenses/MIT/>. + */ - /** - * Sets the highlight pen color. Equivalent to setAttribute({highlightStrokeColor:color}) - * but affects only the future turtle. - * @param {String} color - * @returns {JXG.Turtle} pointer to the turtle object - */ - setHighlightPenColor: function (color) { - //this.visProp.highlightstrokecolor = colStr; - this.curve = this.board.create('curve', [[this.pos[0]], [this.pos[1]]], this.copyAttr('highlightStrokeColor', color)); - this.objects.push(this.curve); - return this; - }, - /** - * Sets properties of the turtle, see also {@link JXG.GeometryElement#setAttribute}. - * Sets the property for all curves of the turtle in the past and in the future. - * @param {Object} attributes key:value pairs - * @returns {JXG.Turtle} pointer to the turtle object - */ - setAttribute: function (attributes) { - var i, el, tmp, - len = this.objects.length; +/*global JXG: true, define: true, window: true*/ +/*jslint nomen: true, plusplus: true*/ - for (i = 0; i < len; i++) { - el = this.objects[i]; - if (el.type === Const.OBJECT_TYPE_CURVE) { - el.setAttribute(attributes); - } - } +/* depends: + jxg + utils/env + utils/type + */ - // Set visProp of turtle - tmp = this.visProp.id; - this.visProp = Type.deepCopy(this.curve.visProp); - this.visProp.id = tmp; - this._attributes = Type.deepCopy(this.visProp); - delete this._attributes.id; +/** + * @fileoverview In this file the Text element is defined. + */ - return this; - }, +define('element/input',[ + 'jxg', 'utils/env', 'utils/type' +], function (JXG, Env, Type) { - /** - * Set a future attribute of the turtle. - * @private - * @param {String} key - * @param {Number|String} val - * @returns {Object} pointer to the attributes object - */ - copyAttr: function (key, val) { - this._attributes[key.toLowerCase()] = val; - return this._attributes; - }, + "use strict"; - /** - * Sets the visibility of the turtle head to true, - * @returns {JXG.Turtle} pointer to the turtle object - */ - showTurtle: function () { - this.turtleIsHidden = false; - this.arrow.setAttribute({visible: true}); - this.visProp.arrow.visible = false; - this.setPos(this.pos[0], this.pos[1]); - this.board.update(); + var priv = { + InputInputEventHandler: function (evt) { + this._value = this.rendNodeInput.value; + this.board.update(); + } + }; - return this; - }, + /** + * @class This element is used to provide a constructor for special texts containing a + * HTML form input element. + * <p> + * If the width of element is set with the attribute "cssStyle", the width of the + * label must be added. + * <p> + * For this element, the attribute "display" has to have the value 'html' (which is the default). + * @pseudo + * @description + * @name Input + * @augments Text + * @constructor + * @type JXG.Text + * + * @param {number,function_number,function_String_String} x,y,value,label Parent elements for input elements. + * <p> + * x and y are the coordinates of the lower left corner of the text box. The position of the text is fixed, + * x and y are numbers. The position is variable if x or y are functions. + * <p> + * The default value of the input element may be given as string. + * <p> + * The label of the input element may be given as string. + * + * @example + * // Create an input element at position [1,4]. + * var input = board.create('input', [0, 1, 'sin(x)*x', 'f(x)='], {cssStyle: 'width: 100px'}); + * var f = board.jc.snippet(input.Value(), true, 'x', false); + * var graph = board.create('functiongraph',[f, + * function() { + * var c = new JXG.Coords(JXG.COORDS_BY_SCREEN,[0,0],board); + * return c.usrCoords[1]; + * }, + * function() { + * var c = new JXG.Coords(JXG.COORDS_BY_SCREEN,[board.canvasWidth,0],board); + * return c.usrCoords[1]; + * } + * ]); + * + * board.create('text', [1, 3, '<button onclick="updateGraph()">Update graph</button>']); + * + * var updateGraph = function() { + * graph.Y = board.jc.snippet(input.Value(), true, 'x', false); + * graph.updateCurve(); + * board.update(); + * } + * </pre><div class="jxgbox" id="JXGc70f55f1-21ba-4719-a37d-a93ae2943faa" style="width: 500px; height: 300px;"></div> + * <script type="text/javascript"> + * var t1_board = JXG.JSXGraph.initBoard('JXGc70f55f1-21ba-4719-a37d-a93ae2943faa', {boundingbox: [-3, 6, 5, -3], axis: true, showcopyright: false, shownavigation: false}); + * var input = t1_board.create('input', [1, 4, 'sin(x)*x', 'f(x)='], {cssStyle: 'width: 100px'}); + * var f = t1_board.jc.snippet(input.Value(), true, 'x', false); + * var graph = t1_board.create('functiongraph',[f, + * function() { + * var c = new JXG.Coords(JXG.COORDS_BY_SCREEN,[0,0],t1_board); + * return c.usrCoords[1]; + * }, + * function() { + * var c = new JXG.Coords(JXG.COORDS_BY_SCREEN,[t1_board.canvasWidth,0],t1_board); + * return c.usrCoords[1]; + * } + * ]); + * + * t1_board.create('text', [1, 3, '<button onclick="updateGraph()">Update graph</button>']); + * + * var updateGraph = function() { + * graph.Y = t1_board.jc.snippet(input.Value(), true, 'x', false); + * graph.updateCurve(); + * t1_board.update(); + * } + * </script><pre> + */ + JXG.createInput = function (board, parents, attributes) { + var t, par, + attr = Type.copyAttributes(attributes, board.options, 'input'); - /** - * Sets the visibility of the turtle head to false, - * @returns {JXG.Turtle} pointer to the turtle object - */ - hideTurtle: function () { - this.turtleIsHidden = true; - this.arrow.setAttribute({visible: false}); - this.visProp.arrow.visible = false; - this.board.update(); + par = [parents[0], parents[1], + '<span style="display:inline; white-space:nowrap; padding:0px;">' + + '<span></span><input type="text" maxlength="' + + attr.maxlength + + '" style="width:100%"/>' + + '</span>' + ]; - return this; - }, + //t = JXG.createText(board, par, attr); + t = board.create('text', par, attr); + t.type = Type.OBJECT_TYPE_INPUT; - /** - * Moves the turtle to position [0,0]. - * @returns {JXG.Turtle} pointer to the turtle object - */ - home: function () { - this.pos = [0, 0]; - this.setPos(this.pos[0], this.pos[1]); + t.rendNodeLabel = t.rendNode.childNodes[0].childNodes[0]; + t.rendNodeInput = t.rendNode.childNodes[0].childNodes[1]; + t.rendNodeLabel.innerHTML = parents[3]; + t.rendNodeInput.value = parents[2]; + t.rendNodeTag = t.rendNodeInput; // Needed for unified treatment in setAttribute + t.rendNodeTag.disabled = !!attr.disabled; + t.rendNodeLabel.id = t.rendNode.id + '_label'; + t.rendNodeInput.id = t.rendNode.id + '_input'; + t._value = parents[2]; + t.update = function () { + if (this.needsUpdate) { + JXG.Text.prototype.update.call(this); + this._value = this.rendNodeInput.value; + } return this; - }, + }; /** - * Pushes the position of the turtle on the stack. - * @returns {JXG.Turtle} pointer to the turtle object + * Returns the value (content) of the input element + * @name Value + * @memberOf Input.prototype + * @function + * @returns {String} content of the input field. */ - pushTurtle: function () { - this.stack.push([this.pos[0], this.pos[1], this.dir]); - - return this; - }, + t.Value = function () { + return this._value; + }; /** - * Gets the last position of the turtle on the stack, sets the turtle to this position and removes this - * position from the stack. - * @returns {JXG.Turtle} pointer to the turtle object + * Sets value of the input element. + * @name set + * @memberOf Input.prototype + * @function + * + * @param {String} val + * @returns {JXG.GeometryElement} Reference to the element. + * + * @example + * var i1 = board.create('input', [-3, 4, 'sin(x)', 'f(x)='], {cssStyle: 'width:4em', maxlength: 2}); + * var c1 = board.create('checkbox', [-3, 2, 'label 1'], {}); + * var b1 = board.create('button', [-3, -1, 'Change texts', function () { + * i1.setText('g(x)'); + * i1.set('cos(x)'); + * c1.setText('label 2'); + * b1.setText('Texts are changed'); + * }], + * {cssStyle: 'width:400px'}); + * + * </pre><div id="JXG11cac8ff-2354-47e7-9da4-eb298e53de05" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG11cac8ff-2354-47e7-9da4-eb298e53de05', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * var i1 = board.create('input', [-3, 4, 'sin(x)', 'f(x)='], {cssStyle: 'width:4em', maxlength: 2}); + * var c1 = board.create('checkbox', [-3, 2, 'label 1'], {}); + * var b1 = board.create('button', [-3, -1, 'Change texts', function () { + * i1.setText('g(x)'); + * i1.set('cos(x)'); + * c1.setText('label 2'); + * b1.setText('Texts are changed'); + * }], + * {cssStyle: 'width:400px'}); + * + * })(); + * + * </script><pre> + * */ - popTurtle: function () { - var status = this.stack.pop(); - this.pos[0] = status[0]; - this.pos[1] = status[1]; - this.dir = status[2]; - this.setPos(this.pos[0], this.pos[1]); - + t.set = function (val) { + this._value = val; + this.rendNodeInput.value = val; return this; - }, + }; - /** - * Rotates the turtle into a new direction. - * There are two possibilities: - * @param {Number|Array} target If a number is given, it is interpreted as the new direction to look to; If an array - * consisting of two Numbers is given targeted is used as a pair coordinates. - * @returns {JXG.Turtle} pointer to the turtle object - */ - lookTo: function (target) { - var ax, ay, bx, by, beta; + Env.addEvent(t.rendNodeInput, 'input', priv.InputInputEventHandler, t); + Env.addEvent(t.rendNodeInput, 'mousedown', function(evt) { if (Type.exists(evt.stopPropagation)) { evt.stopPropagation(); } }, t); + Env.addEvent(t.rendNodeInput, 'touchstart', function(evt) { if (Type.exists(evt.stopPropagation)) { evt.stopPropagation(); } }, t); + Env.addEvent(t.rendNodeInput, 'pointerdown', function(evt) { if (Type.exists(evt.stopPropagation)) { evt.stopPropagation(); } }, t); - if (Type.isArray(target)) { - ax = this.pos[0]; - ay = this.pos[1]; - bx = target[0]; - by = target[1]; + // This sets the font-size of the input HTML element + t.visPropOld.fontsize = "0px"; + board.renderer.updateTextStyle(t, false); - // Rotate by the slope of the line [this.pos, target] - beta = Math.atan2(by - ay, bx - ax); - this.right(this.dir - (beta * 180 / Math.PI)); - } else if (Type.isNumber(target)) { - this.right(this.dir - target); - } - return this; - }, + return t; + }; - /** - * Moves the turtle to a given coordinate pair. - * The direction is not changed. - * @param {Array} target Coordinates of the point where the turtle looks to. - * @returns {JXG.Turtle} pointer to the turtle object - */ - moveTo: function (target) { - var dx, dy, t; + JXG.registerElement('input', JXG.createInput); - if (Type.isArray(target)) { - dx = target[0] - this.pos[0]; - dy = target[1] - this.pos[1]; + return { + createInput: JXG.createInput + }; +}); - if (!this.turtleIsHidden) { - t = this.board.create('transform', [dx, dy], {type: 'translate'}); - t.applyOnce(this.turtle); - t.applyOnce(this.turtle2); - } +/* + Copyright 2008-2022 + Matthias Ehmann, + Michael Gerhaeuser, + Carsten Miller, + Bianca Valentin, + Alfred Wassermann, + Peter Wilfahrt - if (this.isPenDown) { - // IE workaround - if (this.curve.dataX.length >= 8192) { - this.curve = this.board.create('curve', [[this.pos[0]], [this.pos[1]]], this._attributes); - this.objects.push(this.curve); - } - } + This file is part of JSXGraph. - this.pos[0] = target[0]; - this.pos[1] = target[1]; + JSXGraph is free software dual licensed under the GNU LGPL or MIT License. - if (this.isPenDown) { - this.curve.dataX.push(this.pos[0]); - this.curve.dataY.push(this.pos[1]); - } - this.board.update(); - } + You can redistribute it and/or modify it under the terms of the - return this; - }, + * GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version + OR + * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT - /** - * Alias for {@link JXG.Turtle#forward} - */ - fd: function (len) { return this.forward(len); }, - /** - * Alias for {@link JXG.Turtle#back} - */ - bk: function (len) { return this.back(len); }, - /** - * Alias for {@link JXG.Turtle#left} - */ - lt: function (angle) { return this.left(angle); }, - /** - * Alias for {@link JXG.Turtle#right} - */ - rt: function (angle) { return this.right(angle); }, - /** - * Alias for {@link JXG.Turtle#penUp} - */ - pu: function () { return this.penUp(); }, - /** - * Alias for {@link JXG.Turtle#penDown} - */ - pd: function () { return this.penDown(); }, - /** - * Alias for {@link JXG.Turtle#hideTurtle} - */ - ht: function () { return this.hideTurtle(); }, - /** - * Alias for {@link JXG.Turtle#showTurtle} - */ - st: function () { return this.showTurtle(); }, - /** - * Alias for {@link JXG.Turtle#clearScreen} - */ - cs: function () { return this.clearScreen(); }, - /** - * Alias for {@link JXG.Turtle#pushTurtle} - */ - push: function () { return this.pushTurtle(); }, - /** - * Alias for {@link JXG.Turtle#popTurtle} - */ - pop: function () { return this.popTurtle(); }, + JSXGraph is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. - /** - * The "co"-coordinate of the turtle curve at position t is returned. - * - * @param {Number} t parameter - * @param {String} co. Either 'X' or 'Y'. - * @returns {Number} x-coordinate of the turtle position or x-coordinate of turtle at position t - */ - evalAt: function (t, co) { - var i, j, el, tc, - len = this.objects.length; + You should have received a copy of the GNU Lesser General Public License and + the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> + and <http://opensource.org/licenses/MIT/>. + */ - for (i = 0, j = 0; i < len; i++) { - el = this.objects[i]; - if (el.elementClass === Const.OBJECT_CLASS_CURVE) { - if (j <= t && t < j + el.numberPoints) { - tc = (t - j); - return el[co](tc); - } - j += el.numberPoints; - } - } +/*global JXG: true, define: true, window: true*/ +/*jslint nomen: true, plusplus: true*/ - return this[co](); - }, +/* depends: + jxg + utils/env + utils/type + */ - /** - * if t is not supplied the x-coordinate of the turtle is returned. Otherwise - * the x-coordinate of the turtle curve at position t is returned. - * @param {Number} t parameter - * @returns {Number} x-coordinate of the turtle position or x-coordinate of turtle at position t - */ - X: function (t) { - if (!Type.exists(t)) { - return this.pos[0]; - } +/** + * @fileoverview In this file the Text element is defined. + */ - return this.evalAt(t, 'X'); - }, +define('element/button',[ + 'jxg', 'utils/env', 'utils/type' +], function (JXG, Env, Type) { - /** - * if t is not supplied the y-coordinate of the turtle is returned. Otherwise - * the y-coordinate of the turtle curve at position t is returned. - * @param {Number} t parameter - * @returns {Number} x-coordinate of the turtle position or x-coordinate of turtle at position t - */ - Y: function (t) { - if (!Type.exists(t)) { - return this.pos[1]; + "use strict"; + + var priv = { + ButtonClickEventHandler: function () { + if (this._handler) { + this._handler(); + } + this.board.update(); } - return this.evalAt(t, 'Y'); - }, + }; - /** - * @returns {Number} z-coordinate of the turtle position - */ - Z: function (t) { - return 1.0; - }, + /** + * @class This element is used to provide a constructor for special texts containing a + * form button element. + * <p> + * For this element, the attribute "display" has to have the value 'html' (which is the default). + * + * @pseudo + * @description + * @name Button + * @augments Text + * @constructor + * @type JXG.Text + * + * @param {number,function_number,function_String_function} x,y,label,handler Parent elements for button elements. + * <p> + * x and y are the coordinates of the lower left corner of the text box. + * The position of the text is fixed, + * x and y are numbers. The position is variable if x or y are functions. + * <p> + * The label of the input element may be given as string. + * <p> + * The (optional) handler function which is called when the button is pressed. + * + * @example + * var p = board.create('point', [0.5, 0.5], {id: 'p1'}); + * + * // Create a button element at position [1,2]. + * var button1 = board.create('button', [1, 2, 'Change Y with JavaScript', function() { + * p.moveTo([p.X(), p.Y() + 0.5], 100); + * }], {}); + * + * // Create a button element at position [1,4]. + * var button2 = board.create('button', [1, 4, 'Change Y with JessieCode', + * "$('p1').Y = $('p1').Y() - 0.5;" + * ], {}); + * + * </pre><div class="jxgbox" id="JXGf19b1bce-dd00-4e35-be97-ff1817d11514" style="width: 500px; height: 300px;"></div> + * <script type="text/javascript"> + * var t1_board = JXG.JSXGraph.initBoard('JXGf19b1bce-dd00-4e35-be97-ff1817d11514', {boundingbox: [-3, 6, 5, -3], axis: true, showcopyright: false, shownavigation: false}); + * var p = t1_board.create('point', [0, -1], {id: 'p1'}); + * + * // Create a button element at position [1,2]. + * var button1 = t1_board.create('button', [1, 2, 'Change Y with JavaScript', function() { + * p.moveTo([p.X(), p.Y() + 0.5], 100); + * }], {}); + * + * // Create a button element at position [1,4]. + * var button2 = t1_board.create('button', [1, 4, 'Change Y with JessieCode', + * "$('p1').Y = $('p1').Y() - 0.5;" + * ], {}); + * + * </script><pre> + * + * @example + * // A toggle button + * var butt = board.create('button', [-2, -2, 'Off', function() { + * var txt; + * butt.value = !butt.value; + * if (butt.value) { + * txt = 'On'; + * } else { + * txt = 'Off'; + * } + * butt.rendNodeButton.innerHTML = txt; + * }]); + * + * // Set initial value for the button + * if (!JXG.exists(butt.value)) { + * butt.value = false; + * } + * + * var p = board.create('point', [2, -2], { + * visible: () => butt.value + * }); + * + * + * + * </pre><div id="JXGa1eaab8f-c73b-4660-96ce-4ca17bcac4d6" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXGa1eaab8f-c73b-4660-96ce-4ca17bcac4d6', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * var butt = board.create('button', [-2, -2, 'Off', function() { + * var txt; + * butt.value = !butt.value; + * if (butt.value) { + * txt = 'On'; + * } else { + * txt = 'Off'; + * } + * butt.rendNodeButton.innerHTML = txt; + * }]); + * + * // Set initial value for the button + * if (!JXG.exists(butt.value)) { + * butt.value = false; + * } + * + * var p = board.create('point', [2, -2], { + * visible: () => butt.value + * }); + * + * })(); + * + * </script><pre> + * + * @example + * var i1 = board.create('input', [-3, 4, 'sin(x)', 'f(x)='], {cssStyle: 'width:4em', maxlength: 2}); + * var c1 = board.create('checkbox', [-3, 2, 'label 1'], {}); + * var b1 = board.create('button', [-3, -1, 'Change texts', function () { + * i1.setText('g(x)'); + * i1.set('cos(x)'); + * c1.setText('label 2'); + * b1.setText('Texts are changed'); + * }], + * {cssStyle: 'width:400px'}); + * + * </pre><div id="JXG11cac8ff-2354-47e7-9da4-eb928e53de05" class="jxgbox" style="width: 300px; height: 300px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG11cac8ff-2354-47e7-9da4-eb928e53de05', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * var i1 = board.create('input', [-3, 4, 'sin(x)', 'f(x)='], {cssStyle: 'width:4em', maxlength: 2}); + * var c1 = board.create('checkbox', [-3, 2, 'label 1'], {}); + * var b1 = board.create('button', [-3, -1, 'Change texts', function () { + * i1.setText('g(x)'); + * i1.set('cos(x)'); + * c1.setText('label 2'); + * b1.setText('Texts are changed'); + * }], + * {cssStyle: 'width:400px'}); + * + * })(); + * + * </script><pre> + * + */ + JXG.createButton = function (board, parents, attributes) { + var t, par, + attr = Type.copyAttributes(attributes, board.options, 'button'); - /** - * Gives the lower bound of the parameter if the the turtle is treated as parametric curve. - */ - minX: function () { - return 0; - }, + //if (parents.length < 3) { + //throw new Error("JSXGraph: Can't create button with parent types '" + + // (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + + // "\nPossible parents are: [x, y, label, handler]"); + //} + + par = [parents[0], parents[1], '<button type="button" style="width:100%;"></button>']; - /** - * Gives the upper bound of the parameter if the the turtle is treated as parametric curve. - * May be overwritten in @see generateTerm. - */ - maxX: function () { - var i, el, - len = this.objects.length, - np = 0; + t = board.create('text', par, attr); + t.type = Type.OBJECT_TYPE_BUTTON; - for (i = 0; i < len; i++) { - el = this.objects[i]; - if (el.elementClass === Const.OBJECT_CLASS_CURVE) { - np += this.objects[i].numberPoints; - } - } - return np; - }, + t.rendNodeButton = t.rendNode.childNodes[0]; + t.rendNodeButton.id = t.rendNode.id + '_button'; + t.rendNodeButton.innerHTML = parents[2]; - /** - * Checks whether (x,y) is near the curve. - * @param {Number} x Coordinate in x direction, screen coordinates. - * @param {Number} y Coordinate in y direction, screen coordinates. - * @returns {Boolean} True if (x,y) is near the curve, False otherwise. - */ - hasPoint: function (x, y) { - var i, el; + t.rendNodeTag = t.rendNodeButton; // Needed for unified treatment in setAttribute + t.rendNodeTag.disabled = !!attr.disabled; - // run through all curves of this turtle - for (i = 0; i < this.objects.length; i++) { - el = this.objects[i]; + // This sets the font-size of the button text + t.visPropOld.fontsize = "0px"; + board.renderer.updateTextStyle(t, false); - if (el.type === Const.OBJECT_TYPE_CURVE) { - if (el.hasPoint(x, y)) { - // So what??? All other curves have to be notified now (for highlighting) - return true; - // This has to be done, yet. - } - } + if (parents[3]) { + if (Type.isString(parents[3])) { + t._jc = new JXG.JessieCode(); + t._jc.use(board); + t._handler = function () { + t._jc.parse(parents[3]); + }; + } else { + t._handler = parents[3]; } - return false; } - }); - /** - * @class This element is used to provide a constructor for a turtle. - * @pseudo - * @description Creates a new turtle - * @name Turtle - * @augments JXG.Turtle - * @constructor - * @type JXG.Turtle - * - * @param {JXG.Board} board The board the turtle is put on. - * @param {Array} parents - * @param {Object} attributes Object containing properties for the element such as stroke-color and visibility. See {@link JXG.GeometryElement#setAttribute} - * @returns {JXG.Turtle} Reference to the created turtle object. - */ - JXG.createTurtle = function (board, parents, attributes) { - var attr; - parents = parents || []; + Env.addEvent(t.rendNodeButton, 'click', priv.ButtonClickEventHandler, t); + Env.addEvent(t.rendNodeButton, 'mousedown', function (evt) { if (Type.exists(evt.stopPropagation)) { evt.stopPropagation(); } }, t); + Env.addEvent(t.rendNodeButton, 'touchstart', function (evt) { if (Type.exists(evt.stopPropagation)) { evt.stopPropagation(); } }, t); + Env.addEvent(t.rendNodeButton, 'pointerdown', function (evt) { if (Type.exists(evt.stopPropagation)) { evt.stopPropagation(); } }, t); - attr = Type.copyAttributes(attributes, board.options, 'turtle'); - return new JXG.Turtle(board, parents, attr); + return t; }; - JXG.registerElement('turtle', JXG.createTurtle); + JXG.registerElement('button', JXG.createButton); return { - Turtle: JXG.Turtle, - createTurtle: JXG.createTurtle + createButton: JXG.createButton }; }); /* - JessieCode Computer algebra algorithms - - Copyright 2011-2021 + Copyright 2008-2022 + Matthias Ehmann, Michael Gerhaeuser, - Alfred Wassermann + Carsten Miller, + Bianca Valentin, + Alfred Wassermann, + Peter Wilfahrt - JessieCode is free software dual licensed under the GNU LGPL or MIT License. + This file is part of JSXGraph. + + JSXGraph is free software dual licensed under the GNU LGPL or MIT License. You can redistribute it and/or modify it under the terms of the @@ -70037,1352 +79796,727 @@ define('base/turtle',[ OR * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT - JessieCode is distributed in the hope that it will be useful, + JSXGraph is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License and - the MIT License along with JessieCode. If not, see <http://www.gnu.org/licenses/> + the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> and <http://opensource.org/licenses/MIT/>. */ - /*global JXG: true, define: true, window: true, console: true, self: true, document: true, parser: true*/ - /*jslint nomen: true, plusplus: true*/ - /* depends: - jxg - parser/geonext - base/constants - base/text - math/math - math/geometry - math/statistics - utils/type - utils/uuid - */ +/*global JXG: true, define: true, window: true*/ +/*jslint nomen: true, plusplus: true*/ - /** - * @fileoverview Here, the computer algebra algorithms are implemented. - */ +/* depends: + jxg + base/constants + base/coords + base/element + math/math + utils/type + */ - define('parser/ca',[ - 'jxg', 'base/constants', 'base/text', 'math/math', 'math/geometry', 'math/statistics', 'utils/type', 'utils/env' - ], function (JXG, Const, Text, Mat, Geometry, Statistics, Type, Env) { +/** + * @fileoverview In this file the ForeignObject element is defined. + */ - "use strict"; + define('base/foreignobject',[ + 'jxg', 'base/constants', 'base/coords', 'base/element', 'math/math', 'utils/type', 'base/coordselement' +], function (JXG, Const, Coords, GeometryElement, Mat, Type, CoordsElement) { - /** - * A JessieCode object provides an interface to the parser and stores all variables and objects used within a JessieCode script. - * The optional argument <tt>code</tt> is interpreted after initializing. To evaluate more code after initializing a JessieCode instance - * please use {@link JXG.JessieCode#parse}. For code snippets like single expressions use {@link JXG.JessieCode#snippet}. - * @constructor - * @param {String} [code] Code to parse. - * @param {Boolean} [geonext=false] Geonext compatibility mode. - */ - JXG.CA = function (node, createNode, parser) { - this.node = node; - this.createNode = createNode; - this.parser = parser; - }; - - JXG.extend(JXG.CA.prototype, /** @lends JXG.CA.prototype */ { - findMapNode: function(mapname, node) { - var i, len, ret; - - //console.log("FINDMAP", node); - if (node.value === 'op_assign' && node.children[0].value === mapname) { - return node.children[1]; - } else if (node.children) { - len = node.children.length; - for (i = 0; i < len; ++i) { - ret = this.findMapNode(mapname, node.children[i]); - if (ret !== null) { - return ret; - } - } - } - return null; - }, + "use strict"; - /** - * Declare all subnodes as math nodes, - * i.e recursively set node.isMath = true; - */ - setMath: function(node) { - var i, len; + /** + * Construct and handle SVG foreignObjects. + * + * @class Creates a new foreignObject object. Do not use this constructor to create a foreignObject. Use {@link JXG.Board#create} with + * type {@link foreignobject} instead. + * @augments JXG.GeometryElement + * @augments JXG.CoordsElement + * @param {string|JXG.Board} board The board the new foreignObject is drawn on. + * @param {Array} coordinates An array with the user coordinates of the foreignObject. + * @param {Object} attributes An object containing visual and - optionally - a name and an id. + * @param {string|function} url An URL string or a function returning an URL string. + * @param {Array} size Array containing width and height of the foreignObject in user coordinates. + * + */ + JXG.ForeignObject = function (board, coords, attributes, content, size) { + this.constructor(board, attributes, Const.OBJECT_TYPE_FOREIGNOBJECT, Const.OBJECT_CLASS_OTHER); + this.element = this.board.select(attributes.anchor); + this.coordsConstructor(coords); - if ((node.type == 'node_op' && ( - node.value == 'op_add' || node.value == 'op_sub' || - node.value == 'op_mul' || node.value == 'op_div' || - node.value == 'op_neg' || node.value == 'op_execfun' || - node.value == 'op_exp')) || - node.type == 'node_var' || node.type == 'node_const') { + this._useUserSize = false; - node.isMath = true; - } - if (node.children) { - len = node.children.length; - for (i = 0; i < len; ++i) { - this.setMath(node.children[i]); - } - } - }, + /** + * Array of length two containing [width, height] of the foreignObject in pixel. + * @type Array + */ + this.size = [1, 1]; + if (Type.exists(size) && size.length > 0) { + this._useUserSize = true; - deriveElementary: function(node, varname) { - var fun = node.children[0].value, - arg = node.children[1], - newNode; - - - switch (fun) { - case 'abs': - // x / sqrt(x * x) - newNode = this.createNode('node_op', 'op_div', - arg[0], - this.createNode('node_op', 'op_execfun', - this.createNode('node_var', 'sqrt'), - [this.createNode('node_op', 'op_mul', - Type.deepCopy(arg[0]), - Type.deepCopy(arg[0]) - )] - ) - ); - break; - - case 'sqrt': - newNode = this.createNode('node_op', 'op_div', - this.createNode('node_const', 1.0), - this.createNode('node_op', 'op_mul', - this.createNode('node_const', 2.0), - this.createNode(node.type, node.value, - Type.deepCopy(node.children[0]), - Type.deepCopy(node.children[1]) - ) - ) - ); - break; - - case 'sin': - newNode = this.createNode('node_op', 'op_execfun', - this.createNode('node_var', 'cos'), - Type.deepCopy(arg) - ); - break; - - case 'cos': - newNode = this.createNode('node_op', 'op_neg', - this.createNode('node_op', 'op_execfun', - this.createNode('node_var', 'sin'), - Type.deepCopy(arg) - ) - ); - break; - - case 'tan': - newNode = this.createNode('node_op', 'op_div', - this.createNode('node_const', 1.0), - this.createNode('node_op', 'op_exp', - this.createNode('node_op', 'op_execfun', - this.createNode('node_var', 'cos'), - Type.deepCopy(arg) - ), - this.createNode('node_const', 2) - ) - ); - break; - - case 'cot': - newNode = this.createNode('node_op', 'op_neg', - this.createNode('node_op', 'op_div', - this.createNode('node_const', 1.0), - this.createNode('node_op', 'op_exp', - this.createNode('node_op', 'op_execfun', - this.createNode('node_var', 'sin'), - Type.deepCopy(arg) - ), - this.createNode('node_const', 2) - ) - ) - ); - break; - - case 'exp': - newNode = this.createNode(node.type, node.value, - Type.deepCopy(node.children[0]), - Type.deepCopy(node.children[1]) - ); - break; - - case 'pow': - // (f^g)' = f^g*(f'g/f + g' log(f)) - newNode = this.createNode('node_op', 'op_mul', - this.createNode('node_op', 'op_execfun', - Type.deepCopy(node.children[0]), - Type.deepCopy(node.children[1]) - ), - this.createNode('node_op', 'op_add', - this.createNode('node_op', 'op_mul', - this.derivative(node.children[1][0], varname), - this.createNode('node_op', 'op_div', - Type.deepCopy(node.children[1][1]), - Type.deepCopy(node.children[1][0]) - ) - ), - this.createNode('node_op', 'op_mul', - this.derivative(node.children[1][1], varname), - this.createNode('node_op', 'op_execfun', - this.createNode('node_var', 'log'), - [Type.deepCopy(node.children[1][0])] - ) - ) - ) - ); - break; - - case 'log': - case 'ln': - newNode = this.createNode('node_op', 'op_div', - this.createNode('node_const', 1.0), - // Attention: single variable mode - Type.deepCopy(arg[0]) - ); - break; - - case 'log2': - case 'lb': - case 'ld': - newNode = this.createNode('node_op', 'op_mul', - this.createNode('node_op', 'op_div', - this.createNode('node_const', 1.0), - // Attention: single variable mode - Type.deepCopy(arg[0]) - ), - this.createNode('node_const', 1.4426950408889634) // 1/log(2) - ); - break; - - case 'log10': - case 'lg': - newNode = this.createNode('node_op', 'op_mul', - this.createNode('node_op', 'op_div', - this.createNode('node_const', 1.0), - // Attention: single variable mode - Type.deepCopy(arg[0]) - ), - this.createNode('node_const', 0.43429448190325176) // 1/log(10) - ); - break; - - case 'asin': - newNode = this.createNode('node_op', 'op_div', - this.createNode('node_const', 1.0), - this.createNode('node_op', 'op_execfun', - this.createNode('node_var', 'sqrt'), - [ - this.createNode('node_op', 'op_sub', - this.createNode('node_const', 1.0), - this.createNode('node_op', 'op_mul', - Type.deepCopy(arg[0]), - Type.deepCopy(arg[0]) - ) - ) - ] - ) - ); - break; - - case 'acos': - newNode = this.createNode('node_op', 'op_neg', - this.createNode('node_op', 'op_div', - this.createNode('node_const', 1.0), - this.createNode('node_op', 'op_execfun', - this.createNode('node_var', 'sqrt'), - [ - this.createNode('node_op', 'op_sub', - this.createNode('node_const', 1.0), - this.createNode('node_op', 'op_mul', - Type.deepCopy(arg[0]), - Type.deepCopy(arg[0]) - ) - ) - ] - ) - ) - ); - break; - - //case 'atan2': - - case 'atan': - newNode = this.createNode('node_op', 'op_div', - this.createNode('node_const', 1.0), - this.createNode('node_op', 'op_add', - this.createNode('node_const', 1.0), - this.createNode('node_op', 'op_mul', - Type.deepCopy(arg[0]), - Type.deepCopy(arg[0]) - ) - ) - ); - break; - - case 'acot': - newNode = this.createNode('node_op', 'op_neg', - this.createNode('node_op', 'op_div', - this.createNode('node_const', 1.0), - this.createNode('node_op', 'op_add', - this.createNode('node_const', 1.0), - this.createNode('node_op', 'op_mul', - Type.deepCopy(arg[0]), - Type.deepCopy(arg[0]) - ) - ) - ) - ); - break; - - case 'sinh': - newNode = this.createNode('node_op', 'op_execfun', - this.createNode('node_var', 'cosh'), - [Type.deepCopy(arg[0])] - ); - break; - - case 'cosh': - newNode = this.createNode('node_op', 'op_execfun', - this.createNode('node_var', 'sinh'), - [Type.deepCopy(arg[0])] - ); - break; - - case 'tanh': - newNode = this.createNode('node_op', 'op_sub', - this.createNode('node_const', 1.0), - this.createNode('node_op', 'op_exp', - this.createNode('node_op', 'op_execfun', - this.createNode('node_var', 'tanh'), - [Type.deepCopy(arg[0])] - ), - this.createNode('node_const', 2.0) - ) - ); - break; - - case 'asinh': - newNode = this.createNode('node_op', 'op_div', - this.createNode('node_const', 1.0), - this.createNode('node_op', 'op_execfun', - this.createNode('node_var', 'sqrt'), - [ - this.createNode('node_op', 'op_add', - this.createNode('node_op', 'op_mul', - Type.deepCopy(arg[0]), - Type.deepCopy(arg[0]) - ), - this.createNode('node_const', 1.0) - ) - ] - ) - ); - break; - - case 'acosh': - newNode = this.createNode('node_op', 'op_div', - this.createNode('node_const', 1.0), - this.createNode('node_op', 'op_execfun', - this.createNode('node_var', 'sqrt'), - [ - this.createNode('node_op', 'op_sub', - this.createNode('node_op', 'op_mul', - Type.deepCopy(arg[0]), - Type.deepCopy(arg[0]) - ), - this.createNode('node_const', 1.0) - ) - ] - ) - ); - break; - - case 'atanh': - newNode = this.createNode('node_op', 'op_div', - this.createNode('node_const', 1.0), - this.createNode('node_op', 'op_sub', - this.createNode('node_const', 1.0), - this.createNode('node_op', 'op_mul', - Type.deepCopy(arg[0]), - Type.deepCopy(arg[0]) - ) - ) - ); - break; + this.W = Type.createFunction(size[0], this.board, ''); + this.H = Type.createFunction(size[1], this.board, ''); + this.usrSize = [this.W(), this.H()]; + } - default: - newNode = this.createNode('node_const', 0.0); - this._error('Derivative of "' + fun + '" not yet implemented'); - } + // this.size = [Math.abs(this.usrSize[0] * board.unitX), Math.abs(this.usrSize[1] * board.unitY)]; - return newNode; - }, + /** + * 'href' of the foreignObject. + * @type {string} + */ + this.content = content; - derivative: function(node, varname) { - var i, len, newNode; - - switch (node.type) { - case 'node_op': - switch (node.value) { - /* - case 'op_map': - if (true) { - newNode = this.createNode('node_op', 'op_map', - Type.deepCopy(node.children[0]), - this.derivative(node.children[1], varname) - ); - } else { - newNode = this.derivative(node.children[1], varname); - } - break; - */ - case 'op_execfun': - // f'(g(x))g'(x) - if (node.children[0].value == 'pow') { - newNode = this.deriveElementary(node, varname); - } else { - newNode = this.createNode('node_op', 'op_mul', - this.deriveElementary(node, varname), - // Warning: single variable mode - this.derivative(node.children[1][0], varname) - ); - - } - break; - - case 'op_div': - // (f'g − g'f )/(g*g) - newNode = this.createNode('node_op', 'op_div', - this.createNode('node_op', 'op_sub', - this.createNode('node_op', 'op_mul', - this.derivative(node.children[0], varname), - Type.deepCopy(node.children[1]) - ), - this.createNode('node_op', 'op_mul', - Type.deepCopy(node.children[0]), - this.derivative(node.children[1], varname) - ) - ), - this.createNode('node_op', 'op_mul', - Type.deepCopy(node.children[1]), - Type.deepCopy(node.children[1]) - ) - ); - break; - - case 'op_mul': - // fg' + f'g - newNode = this.createNode('node_op', 'op_add', - this.createNode('node_op', 'op_mul', - Type.deepCopy(node.children[0]), - this.derivative(node.children[1], varname)), - this.createNode('node_op', 'op_mul', - this.derivative(node.children[0], varname), - Type.deepCopy(node.children[1])) - ); - break; - - case 'op_neg': - newNode = this.createNode('node_op', 'op_neg', - this.derivative(node.children[0], varname) - ); - break; - - case 'op_add': - case 'op_sub': - newNode = this.createNode('node_op', node.value, - this.derivative(node.children[0], varname), - this.derivative(node.children[1], varname) - ); - break; - - case 'op_exp': - // (f^g)' = f^g*(f'g/f + g' log(f)) - newNode = this.createNode('node_op', 'op_mul', - Type.deepCopy(node), - this.createNode('node_op', 'op_add', - this.createNode('node_op', 'op_mul', - this.derivative(node.children[0], varname), - this.createNode('node_op', 'op_div', - Type.deepCopy(node.children[1]), - Type.deepCopy(node.children[0]) - ) - ), - this.createNode('node_op', 'op_mul', - this.derivative(node.children[1], varname), - this.createNode('node_op', 'op_execfun', - this.createNode('node_var', 'log'), - [Type.deepCopy(node.children[0])] - ) - ) - ) - ); - break; - } - break; + this.elType = 'foreignobject'; - case 'node_var': - //console.log('node_var', node); - if (node.value === varname) { - newNode = this.createNode('node_const', 1.0); - } else { - newNode = this.createNode('node_const', 0.0); - } - break; + // span contains the anchor point and the two vectors + // spanning the foreignObject rectangle. + // this.span = [ + // this.coords.usrCoords.slice(0), + // [this.coords.usrCoords[0], this.W(), 0], + // [this.coords.usrCoords[0], 0, this.H()] + // ]; + //this.parent = board.select(attributes.anchor); - case 'node_const': - newNode = this.createNode('node_const', 0.0); - break; + this.id = this.board.setId(this, 'Im'); - case 'node_const_bool': - break; + this.board.renderer.drawForeignObject(this); + this.board.finalizeAdding(this); - case 'node_str': - break; + this.methodMap = JXG.deepCopy(this.methodMap, { + addTransformation: 'addTransform', + trans: 'addTransform' + }); + }; - } + JXG.ForeignObject.prototype = new GeometryElement(); + Type.copyPrototypeMethods(JXG.ForeignObject, CoordsElement, 'coordsConstructor'); - return newNode; - }, + JXG.extend(JXG.ForeignObject.prototype, /** @lends JXG.ForeignObject.prototype */ { - /** - * f = map (x) -> x*sin(x); - * Usages: - * h = D(f, x); - * h = map (x) -> D(f, x); - * - */ - expandDerivatives: function(node, parent, ast) { - var len, i, j, mapNode, codeNode, ret, node2, newNode, - mapName, varname, vArray, order; + /** + * Checks whether (x,y) is over or near the image; + * @param {Number} x Coordinate in x direction, screen coordinates. + * @param {Number} y Coordinate in y direction, screen coordinates. + * @returns {Boolean} True if (x,y) is over the image, False otherwise. + */ + hasPoint: function (x, y) { + var dx, dy, r, type, prec, + c, v, p, dot, + len = this.transformations.length; - ret = 0; - if (!node) { - return ret; - } + if (Type.isObject(Type.evaluate(this.visProp.precision))) { + type = this.board._inputDevice; + prec = Type.evaluate(this.visProp.precision[type]); + } else { + // 'inherit' + prec = this.board.options.precision.hasPoint; + } - this.line = node.line; - this.col = node.col; - - // First we have to go down in the tree. - // This ensures that in cases like D(D(f,x),x) the inner D is expanded first. - len = node.children.length; - for (i = 0; i < len; ++i) { - if (node.children[i] && node.children[i].type) { - node.children[i] = this.expandDerivatives(node.children[i], node, ast); - } else if (Type.isArray(node.children[i])) { - for (j = 0; j < node.children[i].length; ++j) { - if (node.children[i][j] && node.children[i][j].type) { - node.children[i][j] = this.expandDerivatives(node.children[i][j], node, ast); - } - } - } - } + // Easy case: no transformation + if (len === 0) { + dx = x - this.coords.scrCoords[1]; + dy = this.coords.scrCoords[2] - y; + r = prec; - switch (node.type) { - case 'node_op': - switch (node.value) { - case 'op_execfun': - if (node.children[0] && node.children[0].value === 'D') { - if (node.children[1][0].type == 'node_var') { - /* - * Derive map, that is compute D(f,x) - * where e.g. f = map (x) -> x^2 - * - * First step: find node where the map is defined - */ - mapName = node.children[1][0].value; - mapNode = this.findMapNode(mapName, ast); - vArray = mapNode.children[0]; - - // Variable name for differentiation - if (node.children[1].length >= 2) { - varname = node.children[1][1].value; - } else { - varname = mapNode.children[0][0]; // Usually it's 'x' - } - codeNode = mapNode.children[1]; - } else { - /* - * Derive expression, e.g. - * D(2*x, x) - */ - codeNode = node.children[1][0]; - vArray = ['x']; - - // Variable name for differentiation and order - if (node.children[1].length >= 2) { - varname = node.children[1][1].value; - } else { - varname = 'x'; - } - } - - // Differentiation order - if (node.children[1].length >= 3) { - order = node.children[1][2].value; - } else { - order = 1; - } - - // Create node which contains the derivative - newNode = codeNode; - //newNode = this.removeTrivialNodes(newNode); - if (order >= 1) { - while (order >= 1) { - newNode = this.derivative(newNode, varname); - newNode = this.removeTrivialNodes(newNode); - order--; - } - } - - // Replace the node containing e.g. D(f,x) by the derivative. - if (parent.type == 'node_op' && parent.value == 'op_assign') { - // If D is an assignment it has to be replaced by a map - // h = D(f, x) - node2 = this.createNode('node_op', 'op_map', - vArray, - newNode - ); - } else { - node2 = newNode; - } - - this.setMath(node2); - node.type = node2.type; - node.value = node2.value; - node.children[0] = node2.children[0]; - node.children[1] = node2.children[1]; - } - } - break; + return dx >= -r && dx - this.size[0] <= r && + dy >= -r && dy - this.size[1] <= r; + } - case 'node_var': - case 'node_const': - case 'node_const_bool': - case 'node_str': - break; - } + // foreignObject is transformed + c = new Coords(Const.COORDS_BY_SCREEN, [x, y], this.board); + // v is the vector from anchor point to the drag point + c = c.usrCoords; + v = [c[0] - this.span[0][0], + c[1] - this.span[0][1], + c[2] - this.span[0][2]]; + dot = Mat.innerProduct; // shortcut - return node; - }, + // Project the drag point to the sides. + p = dot(v, this.span[1]); + if (0 <= p && p <= dot(this.span[1], this.span[1])) { + p = dot(v, this.span[2]); - removeTrivialNodes: function(node) { - var i, len, n0, n1, swap; + if (0 <= p && p <= dot(this.span[2], this.span[2])) { + return true; + } + } + return false; + }, - // In case of 'op_execfun' the children[1] node is an array. - if (Type.isArray(node)) { - len = node.length; - for (i = 0; i < len; ++i) { - node[i] = this.removeTrivialNodes(node[i]); - } - } - if (node.type != 'node_op' || !node.children) { - return node; - } + /** + * Recalculate the coordinates of lower left corner and the width and height. + * + * @returns {JXG.ForeignObject} A reference to the element + * @private + */ + update: function (fromParent) { + if (!this.needsUpdate) { + return this; + } + this.updateCoords(fromParent); + this.updateSize(); + // this.updateSpan(); + return this; + }, - len = node.children.length; - for (i = 0; i < len; ++i) { - this.mayNotBeSimplified = false; - do { - node.children[i] = this.removeTrivialNodes(node.children[i]); - } while (this.mayNotBeSimplified); + /** + * Send an update request to the renderer. + * @private + */ + updateRenderer: function () { + return this.updateRendererGeneric('updateForeignObject'); + }, - } + /** + * Updates the internal arrays containing size of the foreignObject. + * @returns {JXG.ForeignObject} A reference to the element + * @private + */ + updateSize: function () { + var bb = [0, 0]; - switch (node.value) { - // Allow maps of the form - // map (x) -> x; - case 'op_map': - n0 = node.children[0]; - n1 = node.children[1]; - if (n1.type == 'node_var') { - for (i = 0; i < n0.length; ++i) { - // Allow maps of the form map(x) -> x - if (n0[i] == n1.value) { - n1.isMath = true; - break; - } - } - } - break; - - // a + 0 -> a - // 0 + a -> a - case 'op_add': - n0 = node.children[0]; - n1 = node.children[1]; - if (n0.type == 'node_const' && n0.value === 0.0) { - return n1; - } - if (n1.type == 'node_const' && n1.value === 0.0) { - return n0; - } + if (this._useUserSize) { + this.usrSize = [this.W(), this.H()]; + this.size = [Math.abs(this.usrSize[0] * this.board.unitX), + Math.abs(this.usrSize[1] * this.board.unitY)]; + } else { + if (this.rendNode.hasChildNodes()) { + bb = this.rendNode.childNodes[0].getBoundingClientRect(); + this.size = [bb.width, bb.height]; + } + } - // const + const -> const - if (n0.type == 'node_const' && n1.type == 'node_const') { - n0.value += n1.value; - return n0; - } - break; - - // 1 * a = a - // a * 1 = a - // a * 0 = 0 - // 0 * a = 0 - // - * - = + - // Order children - case 'op_mul': - n0 = node.children[0]; - n1 = node.children[1]; - if (n0.type == 'node_const' && n0.value == 1.0) { - return n1; - } - if (n1.type == 'node_const' && n1.value == 1.0) { - return n0; - } - if (n0.type == 'node_const' && n0.value === 0.0) { - return n0; - } - if (n1.type == 'node_const' && n1.value === 0.0) { - return n1; - } - if (n1.type == 'node_const' && n1.value === 0.0) { - return n1; - } + return this; + }, - // (-a) * (-b) -> a*b - if (n0.type == 'node_op' && n0.value == 'op_neg' && - n1.type == 'node_op' && n1.value == 'op_neg' ) { - node.children = [n0.children[0], n1.children[0]]; - this.mayNotBeSimplified = true; - return node; - } - // (-a) * b -> -(a*b) - if (n0.value == 'op_neg' && n1.value != 'op_neg' ) { - node.type = 'node_op'; - node.value = 'op_neg'; - node.children = [this.createNode('node_op', 'op_mul', n0.children[0], n1)]; - this.mayNotBeSimplified = true; - return node; - } - // a * (-b) -> -(a*b) - if (n0.value != 'op_neg' && n1.value == 'op_neg' ) { - node.type = 'node_op'; - node.value = 'op_neg'; - node.children = [this.createNode('node_op', 'op_mul', n0, n1.children[0])]; - this.mayNotBeSimplified = true; - return node; - } - // (1 / a) * b -> a / b - if (n0.value == 'op_div' && - n0.children[0].type == 'node_const' && n0.children[0].value == 1.0) { - node.type = 'node_op'; - node.value = 'op_div'; - node.children = [n1, n0.children[1]]; - this.mayNotBeSimplified = true; - return node; - } - // a * (1 / b) -> a / b - if (n1.value == 'op_div' && - n1.children[0].type == 'node_const' && n1.children[0].value == 1.0) { - node.type = 'node_op'; - node.value = 'op_div'; - node.children = [n0, n1.children[1]]; - this.mayNotBeSimplified = true; - return node; - } + /** + * Update the anchor point of the foreignObject, i.e. the lower left corner + * and the two vectors which span the rectangle. + * @returns {JXG.ForeignObject} A reference to the element + * @private + * + */ + updateSpan: function () { + var i, j, len = this.transformations.length, v = []; - // Order children - // a * const -> const * a - if (n0.type != 'node_const' && n1.type == 'node_const') { - node.children = [n1, n0]; - this.mayNotBeSimplified = true; - return node; - } - // a + (-const) -> -const * a - if (n0.type != 'node_const' && n1.type == 'node_op' && - n1.value == 'op_neg' && n1.children[0].type == 'node_const') { - node.children = [n1, n0]; - this.mayNotBeSimplified = true; - return node; - } + if (len === 0) { + this.span = [[this.Z(), this.X(), this.Y()], + [this.Z(), this.W(), 0], + [this.Z(), 0, this.H()]]; + } else { + // v contains the three defining corners of the rectangle/image + v[0] = [this.Z(), this.X(), this.Y()]; + v[1] = [this.Z(), this.X() + this.W(), this.Y()]; + v[2] = [this.Z(), this.X(), this.Y() + this.H()]; - // a * var -> var * a - // a * fun -> fun * a - if (n0.type == 'node_op' && n0.value != 'op_execfun' && - (n1.type == 'node_var' || (n1.type == 'node_op' && n1.value == 'op_execfun'))) { - node.children = [n1, n0]; - this.mayNotBeSimplified = true; - return node; - } + // Transform the three corners + for (i = 0; i < len; i++) { + for (j = 0; j < 3; j++) { + v[j] = Mat.matVecMult(this.transformations[i].matrix, v[j]); + } + } + // Normalize the vectors + for (j = 0; j < 3; j++) { + v[j][1] /= v[j][0]; + v[j][2] /= v[j][0]; + v[j][0] /= v[j][0]; + } + // Compute the two vectors spanning the rectangle + // by subtracting the anchor point. + for (j = 1; j < 3; j++) { + v[j][0] -= v[0][0]; + v[j][1] -= v[0][1]; + v[j][2] -= v[0][2]; + } + this.span = v; + } - // a + (-var) -> -var * a - if (n0.type != 'node_op' && n1.type == 'node_op' && - n1.value == 'op_neg' && n1.children[0].type == 'node_var') { - node.children = [n1, n0]; - this.mayNotBeSimplified = true; - return node; - } - // a * (const * b) -> const * (a*b) - // a * (const / b) -> const * (a/b) - if (n0.type != 'node_const' && n1.type == 'node_op' && - (n1.value == 'op_mul' || n1.value == 'op_div') && - n1.children[0].type == 'node_const') { - swap = n1.children[0]; - n1.children[0] = n0; - node.children = [swap, n1]; - this.mayNotBeSimplified = true; - return node; - } + return this; + }, - // (const * a) * b -> const * (a * b) - if (n1.type != 'node_const' && n0.type == 'node_op' && - n0.value == 'op_mul' && - n0.children[0].type == 'node_const') { - node.children = [ - n0.children[0], - this.createNode('node_op', 'op_mul', n0.children[1], n1) - ]; - this.mayNotBeSimplified = true; - return node; - } + addTransform: function (transform) { + var i; - // const * const -> const - if (n0.type == 'node_const' && n1.type == 'node_const') { - n0.value *= n1.value; - return n0; - } + if (Type.isArray(transform)) { + for (i = 0; i < transform.length; i++) { + this.transformations.push(transform[i]); + } + } else { + this.transformations.push(transform); + } - // const * (const * a) -> const * a - // const * (const / a) -> const / a - if (n0.type == 'node_const' && n1.type == 'node_op' && - (n1.value == 'op_mul' || n1.value == 'op_div') && - n1.children[0].type == 'node_const') { - n1.children[0].value *= n0.value; - return n1; - } + return this; + }, - // a * a-> a^2 - n0.hash = this.parser.compile(n0); - n1.hash = this.parser.compile(n1); - if (n0.hash === n1.hash) { - node.value = 'op_exp'; - node.children[1] = this.createNode('node_const', 2.0); - return node; - } + // Documented in element.js + getParents: function () { + var p = [this.url, [this.Z(), this.X(), this.Y()], this.usrSize]; - if (n0.type == 'node_const' && n1.type == 'node_op' && - (n1.value == 'op_mul' || n1.value == 'op_div') && - n1.children[0].type == 'node_const') { - n1.children[0].value *= n0.value; - return n1; - } + if (this.parents.length !== 0) { + p = this.parents; + } - // a * a^b -> a^(b+1) - if (n1.type == 'node_op' && n1.value == 'op_exp') { - if (!n0.hash) { - n0.hash = this.parser.compile(n0); - } - if (!n1.children[0].hash) { - n1.children[0].hash = this.parser.compile(n1.children[0]); - } - if (n0.hash === n1.children[0].hash) { - n1.children[1] = this.createNode('node_op', 'op_add', - n1.children[1], - this.createNode('node_const', 1.0) - ); - this.mayNotBeSimplified = true; - return n1; - } - } + return p; + }, - // a^b * a^c -> a^(b+c) - if (n0.type == 'node_op' && n0.value == 'op_exp' && - n1.type == 'node_op' && n1.value == 'op_exp') { - n0.children[0].hash = this.parser.compile(n0.children[0]); - n1.children[0].hash = this.parser.compile(n1.children[0]); - if (n0.children[0].hash === n1.children[0].hash) { - n0.children[1] = this.createNode('node_op', 'op_add', - n0.children[1], - n1.children[1] - ); - this.mayNotBeSimplified = true; - return n0; - } - } + /** + * Set the width and height of the foreignObject. After setting a new size, + * board.update() or foreignobject.fullUpdate() + * has to be called to make the change visible. + * @param {number, function, string} width Number, function or string + * that determines the new width of the foreignObject + * @param {number, function, string} height Number, function or string + * that determines the new height of the foreignObject + * @returns {JXG.ForeignObject} A reference to the element + * + */ + setSize: function(width, height) { + this.W = Type.createFunction(width, this.board, ''); + this.H = Type.createFunction(height, this.board, ''); + this._useUserSize = true; - break; - - // 0 - a -> -a - // a - 0 -> a - // a - a -> 0 - case 'op_sub': - n0 = node.children[0]; - n1 = node.children[1]; - if (n0.type == 'node_const' && n0.value === 0.0) { - node.value = 'op_neg'; - node.children[0] = n1; - return node; - } - if (n1.type == 'node_const' && n1.value === 0.0) { - return n0; - } - if (n0.type == 'node_const' && n1.type == 'node_const' && - n0.value == n1.value) { - return this.createNode('node_const', 0.0); - } - if (n0.type == 'node_var' && n1.type == 'node_var' && - n0.value == n1.value) { - return this.createNode('node_const', 0.0); - } + return this; + }, - // const - const -> const - if (n0.type == 'node_const' && n1.type == 'node_const') { - n0.value -= n1.value; - return n0; - } + /** + * Returns the width of the foreignObject in user coordinates. + * @returns {number} width of the image in user coordinates + */ + W: function() {}, // Needed for docs, defined in constructor + + /** + * Returns the height of the foreignObject in user coordinates. + * @returns {number} height of the image in user coordinates + */ + H: function() {} // Needed for docs, defined in constructor + }); + + /** + * @class This element is used to provide a constructor for arbitrary content in + * an SVG foreignObject container. + * <p> + * Instead of board.create('foreignobject') the shortcut board.create('fo') may be used. + * + * <p style="background-color:#dddddd; padding:10px"><b>NOTE:</b> In Safari up to version 15, a foreignObject does not obey the layer structure + * if it contains <video> or <iframe> tags, as well as elements which are + * positioned with <tt>position:absolute|relative|fixed</tt>. In this case, the foreignobject will be + * "above" the JSXGraph construction. + * </p> + * + * @pseudo + * @description + * @name ForeignObject + * @augments JXG.ForeignObject + * @constructor + * @type JXG.ForeignObject + * + * @param {String} content HTML content of the foreignObject. May also be <video> or <iframe> + * @param {Array} position Position of the foreignObject given by [x, y] in user coordinates. Same as for images. + * @param {Array} [size] (Optional) argument size of the foreignObject in user coordinates. If not given, size is specified by the HTML attributes + * or CSS properties of the content. + * + * @see Image + * + * @example + * var p = board.create('point', [1, 7], {size: 16}); + * var fo = board.create('foreignobject', [ + * '<video width="300" height="200" src="https://eucbeniki.sio.si/vega2/278/Video_metanje_oge_.mp4" type="html5video" controls>', + * [0, -3], [9, 6]], + * {layer: 8, fixed: true} + * ); + * + * </pre><div id="JXG0c122f2c-3671-4a28-80a9-f4c523eeda89" class="jxgbox" style="width: 500px; height: 500px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG0c122f2c-3671-4a28-80a9-f4c523eeda89', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * var p = board.create('point', [1, 7], {size: 16}); + * var fo = board.create('foreignobject', [ + * '<video width="300" height="200" src="https://eucbeniki.sio.si/vega2/278/Video_metanje_oge_.mp4" type="html5video" controls>', + * [0, -3], [9, 6]], + * {layer: 8, fixed: true} + * ); + * + * })(); + * + * </script><pre> + * + * @example + * var p = board.create('point', [1, 7], {size: 16}); + * var fo = board.create('fo', [ + * '<div style="background-color:blue; color: yellow; padding:20px; width:200px; height:50px; ">Hello</div>', + * [-7, -6]], + * {layer: 1, fixed: false} + * ); + * + * </pre><div id="JXG1759c868-1a4a-4767-802c-91f84902e3ec" class="jxgbox" style="width: 500px; height: 500px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG1759c868-1a4a-4767-802c-91f84902e3ec', + * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); + * var p = board.create('point', [1, 7], {size: 16}); + * var fo = board.create('foreignobject', [ + * '<div style="background-color:blue; color: yellow; padding:20px; width:200px; height:50px; ">Hello</div>', + * [-7, -6]], + * {layer: 1, fixed: false} + * ); + * + * })(); + * + * </script><pre> + * + * @example + * board.renderer.container.style.backgroundColor = 'lightblue'; + * var points = []; + * points.push( board.create('point', [-2, 3.5], {fixed:false,color: 'yellow', size: 6,name:'6 am'}) ); + * points.push( board.create('point', [0, 3.5], {fixed:false,color: 'yellow', size: 6,name:'12 pm'}) ); + * points.push( board.create('point', [2, 3.5], {fixed:false,color: 'yellow', size: 6,name:'6 pm'}) ); + * + * var fo = board.create('fo', [ + * '<video width="100%" height="100%" src="https://benedu.net/moodle/aaimg/ajx_img/astro/tr/1vd.mp4" type="html5video" controls>', + * [-6, -4], [12, 8]], + * {layer: 0, fixed: true} + * ); + * + * var f = JXG.Math.Numerics.lagrangePolynomial(points); + * var graph = board.create('functiongraph', [f, -10, 10], {fixed:true,strokeWidth:3, layer: 8}); + * + * </pre><div id="JXGc3fc5520-13aa-4f66-abaa-42e9dc3fbf3f" class="jxgbox" style="width: 500px; height: 500px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXGc3fc5520-13aa-4f66-abaa-42e9dc3fbf3f', + * {boundingbox: [-6,4,6,-4], axis: true, showcopyright: false, shownavigation: false}); + * board.renderer.container.style.backgroundColor = 'lightblue'; + * var points = []; + * points.push( board.create('point', [-2, 3.5], {fixed:false,color: 'yellow', size: 6,name:'6 am'}) ); + * points.push( board.create('point', [0, 3.5], {fixed:false,color: 'yellow', size: 6,name:'12 pm'}) ); + * points.push( board.create('point', [2, 3.5], {fixed:false,color: 'yellow', size: 6,name:'6 pm'}) ); + * + * var fo = board.create('fo', [ + * '<video width="100%" height="100%" src="https://benedu.net/moodle/aaimg/ajx_img/astro/tr/1vd.mp4" type="html5video" controls>', + * [-6, -4], [12, 8]], + * {layer: 0, fixed: true} + * ); + * + * var f = JXG.Math.Numerics.lagrangePolynomial(points); + * var graph = board.create('functiongraph', [f, -10, 10], {fixed:true,strokeWidth:3, layer: 8}); + * + * })(); + * + * </script><pre> + * + * Video "24-hour time-lapse in Cascais, Portugal. Produced by Nuno Miguel Duarte" adapted from + * <a href="https://www.pbslearningmedia.org/resource/buac18-k2-sci-ess-sunposition/changing-position-of-the-sun-in-the-sky/">https://www.pbslearningmedia.org/resource/buac18-k2-sci-ess-sunposition/changing-position-of-the-sun-in-the-sky/</a>, + * ©2016 Nuno Miguel Duarte. + * + */ + JXG.createForeignObject = function (board, parents, attributes) { + var attr, fo, + content = parents[0], + coords = parents[1], + size = []; - // const * a - const * a -> const * a - if (n0.type == 'node_op' && n0.value == 'op_mul' && - n1.type == 'node_op' && n1.value == 'op_mul') { + if (parents.length >= 2) { + size = parents[2]; + } - n0.children[1].hash = this.parser.compile(n0.children[1]); - n1.children[1].hash = this.parser.compile(n1.children[1]); - if (n0.children[1].hash === n1.children[1].hash) { + attr = Type.copyAttributes(attributes, board.options, 'foreignobject'); + fo = CoordsElement.create(JXG.ForeignObject, board, coords, attr, content, size); + if (!fo) { + throw new Error("JSXGraph: Can't create foreignObject with parent types '" + + (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + + "\nPossible parent types: [string, [x, y], [w, h]], [string, [x, y]], [element,transformation]"); + } - node.value = 'op_mul'; - node.children = [ - this.createNode('node_op', 'op_sub', - n0.children[0], - n1.children[0]), - n0.children[1] - ]; - this.mayNotBeSimplified = true; - return node; - } - } - // const * a - a -> (const - 1) * a - if (n0.type == 'node_op' && n0.value == 'op_mul') { + return fo; + }; - n0.children[1].hash = this.parser.compile(n0.children[1]); - n1.hash = this.parser.compile(n1); - if (n0.children[1].hash === n1.hash) { + JXG.registerElement('foreignobject', JXG.createForeignObject); + JXG.registerElement('fo', JXG.createForeignObject); - node.value = 'op_mul'; - node.children = [ - this.createNode('node_op', 'op_sub', - n0.children[0], - this.createNode('node_const', 1.0)), - n1 - ]; - this.mayNotBeSimplified = true; - return node; - } - } - // a - const*a -> (const - 1) * a - if (n1.type == 'node_op' && n1.value == 'op_mul') { + return { + ForeignObject: JXG.ForeignObject, + createForeignobject: JXG.createForeignObject + }; +}); - n1.children[1].hash = this.parser.compile(n1.children[1]); - n0.hash = this.parser.compile(n0); - if (n1.children[1].hash === n0.hash) { +/*global JXG:true, define: true*/ - node.value = 'op_mul'; - node.children = [ - this.createNode('node_op', 'op_sub', - this.createNode('node_const', 1.0), - n1.children[0]), - n0 - ]; - this.mayNotBeSimplified = true; - return node; - } - } +define('options3d',[ + 'jxg', 'options' +], function (JXG, Options) { - break; + "use strict"; - // -0 -> 0 - // -(-b) = b - case 'op_neg': - n0 = node.children[0]; - if (n0.type == 'node_const' && n0.value === 0.0) { - return n0; - } - if (n0.type == 'node_op' && n0.value == 'op_neg') { - return n0.children[0]; - } - break; - - // a / a -> 1, a != 0 - // 0 / a -> 0, a != 0 - // a / 0 -> Infinity, a != 0 - // 0 / 0 -> NaN, a == 0 - case 'op_div': - n0 = node.children[0]; - n1 = node.children[1]; - if (n0.type == 'node_const' && n1.type == 'node_const' && - n0.value == n1.value && n0.value !== 0) { - n0.value = 1.0; - return n0; - } - if (n0.type == 'node_const' && n0.value === 0 && - n1.type == 'node_const' && n1.value !== 0) { - n0.value = 0.0; - return n0; - } + JXG.extend(Options, { - // Risky: 0 / (something != 0) -> 0.0 - if (n0.type == 'node_const' && n0.value === 0 && - (n1.type == 'node_op' || n1.type == 'node_var')) { - node.type = 'node_const'; - node.value = 0.0; - return node; - } + infobox: { + strokeColor: 'black' + }, - if (n0.type == 'node_var' && n1.type == 'node_var' && - n0.value == n1.value) { - return this.createNode('node_const', 1.0); - } - if (n0.type == 'node_const' && n0.value !== 0 && - n1.type == 'node_const' && n1.value === 0) { - if (n0.value > 0.0) { - n0.value = Infinity; - } else { - n0.value = -Infinity; // Do we ever need this? - } - return n0; - } + axes3d: { + /**#@+ + * @visprop + */ - // (-a) / (-b) -> a/b - if (n0.type == 'node_op' && n0.value == 'op_neg' && - n1.type == 'node_op' && n1.value == 'op_neg' ) { - node.children = [n0.children[0], n1.children[0]]; - this.mayNotBeSimplified = true; - return node; - } - // (-a) / b -> -(a/b) - if (n0.value == 'op_neg' && n1.value != 'op_neg' ) { - node.type = 'node_op'; - node.value = 'op_neg'; - node.children = [this.createNode('node_op', 'op_div', n0.children[0], n1)]; - this.mayNotBeSimplified = true; - return node; - } - // a / (-b) -> -(a/b) - if (n0.value != 'op_neg' && n1.value == 'op_neg' ) { - node.type = 'node_op'; - node.value = 'op_neg'; - node.children = [this.createNode('node_op', 'op_div', n0, n1.children[0])]; - this.mayNotBeSimplified = true; - return node; - } + /** + * Position of the main axes in a View3D element. Possible values are + * 'center' and 'border'. + * + * @type String + * @name View3D#axesPosition + * @default 'center' + */ + axesPosition: 'center', // Possible values: 'center', otherwise: border - // a^b / a -> a^(b-1) - if (n0.type == 'node_op' && n0.value == 'op_exp') { - if (!n1.hash) { - n1.hash = this.parser.compile(n1); - } - if (!n0.children[0].hash) { - n0.children[0].hash = this.parser.compile(n0.children[0]); - } - if (n1.hash === n0.children[0].hash) { - n0.children[1] = this.createNode('node_op', 'op_sub', - n0.children[1], - this.createNode('node_const', 1.0) - ); - this.mayNotBeSimplified = true; - return n0; - } - } + // Main axes - // (const * a) / b -> const * (a / b) - if (n1.type != 'node_const' && n0.type == 'node_op' && - n0.value == 'op_mul' && - n0.children[0].type == 'node_const') { - node.value = 'op_mul'; - node.children = [ - n0.children[0], - this.createNode('node_op', 'op_div', n0.children[1], n1) - ]; - this.mayNotBeSimplified = true; - return node; - } + /** + * Attributes of the 3D x-axis. + * + * @type Line3D + * @name View3D#xAxis + */ + xAxis: { visible: true, point2: {name: 'x'}}, - // a^b / a^c -> a^(b-c) - if (n0.type == 'node_op' && n0.value == 'op_exp' && - n1.type == 'node_op' && n1.value == 'op_exp') { - n0.children[0].hash = this.parser.compile(n0.children[0]); - n1.children[0].hash = this.parser.compile(n1.children[0]); - if (n0.children[0].hash === n1.children[0].hash) { - n0.children[1] = this.createNode('node_op', 'op_sub', - n0.children[1], - n1.children[1] - ); - this.mayNotBeSimplified = true; - return n0; - } - } + /** + * Attributes of the 3D y-axis. + * + * @type Line3D + * @name View3D#yAxis + */ + yAxis: { visible: true, point2: {name: 'y'}}, + + /** + * Attributes of the 3D z-axis. + * + * @type Line3D + * @name View3D#zAxis + */ + zAxis: { visible: true, point2: {name: 'z'}}, + // Planes + /** + * Attributes of the 3D plane orthogonal to the x-axis at the "rear" of the cube. + * @type Plane3D + * @name View3D#xPlaneRear + */ + xPlaneRear: { visible: true, layer: 0, mesh3d: { layer: 1 } }, + /** + * Attributes of the 3D plane orthogonal to the y-axis at the "rear" of the cube. + * @type Plane3D + * @name View3D#yPlaneRear + */ + yPlaneRear: { visible: true, layer: 0, mesh3d: { layer: 1 } }, + /** + * Attributes of the 3D plane orthogonal to the z-axis at the "rear" of the cube. + * @type Plane3D + * @name View3D#zPlaneRear + */ + zPlaneRear: { visible: true, layer: 0, mesh3d: { layer: 1 } }, - break; + /** + * Attributes of the 3D plane orthogonal to the x-axis at the "front" of the cube. + * @type Plane3D + * @name View3D#xPlaneFront + */ + xPlaneFront: { visible: false, layer: 0, mesh3d: { layer: 1 } }, + /** + * Attributes of the 3D plane orthogonal to the y-axis at the "front" of the cube. + * @type Plane3D + * @name View3D#yPlaneFront + */ + yPlaneFront: { visible: false, layer: 0, mesh3d: { layer: 1 } }, + /** + * Attributes of the 3D plane orthogonal to the z-axis at the "front" of the cube. + * @type Plane3D + * @name View3D#zPlaneFront + */ + zPlaneFront: { visible: false, layer: 0, mesh3d: { layer: 1 } }, - // a^0 = 1 - // a^1 -> a - // 1^a -> 1 - // 0^a -> 0: a const != 0 - case 'op_exp': - n0 = node.children[0]; - n1 = node.children[1]; - if (n1.type == 'node_const' && n1.value === 0.0) { - n1.value = 1.0; - return n1; - } - if (n1.type == 'node_const' && n1.value == 1.0) { - return n0; - } - if (n0.type == 'node_const' && n0.value == 1.0) { - return n0; - } - if (n0.type == 'node_const' && n0.value === 0.0 && - n1.type == 'node_const' && n1.value !== 0.0) { - return n0; - } + // Axes on the planes + /** + * Attributes of the 3D y-axis on the 3D plane orthogonal to the x-axis at the "rear" of the cube. + * @type Plane3D + * @name View3D#xPlaneRearYAxis + */ + xPlaneRearYAxis: {visible: 'inherit', strokeColor: '#888888', strokeWidth: 1}, + /** + * Attributes of the 3D z-axis on the 3D plane orthogonal to the x-axis at the "rear" of the cube. + * @type Plane3D + * @name View3D#xPlaneRearZAxis + */ + xPlaneRearZAxis: {visible: 'inherit', strokeColor: '#888888', strokeWidth: 1}, + /** + * Attributes of the 3D y-axis on the 3D plane orthogonal to the x-axis at the "front" of the cube. + * @type Plane3D + * @name View3D#xPlaneFrontYAxis + */ + xPlaneFrontYAxis: {visible: 'inherit', strokeColor: '#888888', strokeWidth: 1}, + /** + * Attributes of the 3D z-axis on the 3D plane orthogonal to the x-axis at the "front" of the cube. + * @type Plane3D + * @name View3D#xPlaneFrontZAxis + */ + xPlaneFrontZAxis: {visible: 'inherit', strokeColor: '#888888', strokeWidth: 1}, - // (a^b)^c -> a^(b*c) - if (n0.type == 'node_op' && n0.value == 'op_exp') { - node.children = [ - n0.children[0], - this.createNode('node_op', 'op_mul', - n0.children[1], - n1) - ]; - return node; - } - break; - } + /** + * Attributes of the 3D x-axis on the 3D plane orthogonal to the y-axis at the "rear" of the cube. + * @type Plane3D + * @name View3D#yPlaneRearXAxis + */ + yPlaneRearXAxis: {visible: 'inherit', strokeColor: '#888888', strokeWidth: 1}, + /** + * Attributes of the 3D z-axis on the 3D plane orthogonal to the y-axis at the "rear" of the cube. + * @type Plane3D + * @name View3D#yPlaneRearZAxis + */ + yPlaneRearZAxis: {visible: 'inherit', strokeColor: '#888888', strokeWidth: 1}, + /** + * Attributes of the 3D x-axis on the 3D plane orthogonal to the y-axis at the "front" of the cube. + * @type Plane3D + * @name View3D#yPlaneFrontXAxis + */ + yPlaneFrontXAxis: {visible: 'inherit', strokeColor: '#888888', strokeWidth: 1}, + /** + * Attributes of the 3D z-axis on the 3D plane orthogonal to the y-axis at the "front" of the cube. + * @type Plane3D + * @name View3D#yPlaneFrontZAxis + */ + yPlaneFrontZAxis: {visible: 'inherit', strokeColor: '#888888', strokeWidth: 1}, - switch (node.value) { - // const_1 + const_2 -> (const_1 + const_2) - // a + a -> 2*a - // a + (-b) = a - b - case 'op_add': - n0 = node.children[0]; - n1 = node.children[1]; - if (n0.type == 'node_const' && n1.type == 'node_const' && - n0.value == n1.value) { - n0.value += n1.value; - return n0; - } + /** + * Attributes of the 3D x-axis on the 3D plane orthogonal to the z-axis at the "rear" of the cube. + * @type Plane3D + * @name View3D#zPlaneRearXAxis + */ + zPlaneRearXAxis: {visible: 'inherit', strokeColor: '#888888', strokeWidth: 1}, + /** + * Attributes of the 3D y-axis on the 3D plane orthogonal to the z-axis at the "rear" of the cube. + * @type Plane3D + * @name View3D#zPlaneRearYAxis + */ + zPlaneRearYAxis: {visible: 'inherit', strokeColor: '#888888', strokeWidth: 1}, + /** + * Attributes of the 3D x-axis on the 3D plane orthogonal to the z-axis at the "front" of the cube. + * @type Plane3D + * @name View3D#zPlaneFrontXAxis + */ + zPlaneFrontXAxis: {visible: 'inherit', strokeColor: '#888888', strokeWidth: 1}, + /** + * Attributes of the 3D y-axis on the 3D plane orthogonal to the z-axis at the "front" of the cube. + * @type Plane3D + * @name View3D#zPlaneFrontYAxis + */ + zPlaneFrontYAxis: {visible: 'inherit', strokeColor: '#888888', strokeWidth: 1} - if (n0.type == 'node_var' && n1.type == 'node_var' && - n0.value == n1.value) { - node.children[0] = this.createNode('node_const', 2.0); - node.value = 'op_mul'; - return node; - } + /**#@-*/ + }, - if (n0.type == 'node_op' && n0.value == 'op_neg') { - node.value = 'op_sub'; - node.children[0] = n1; - node.children[1] = n0.children[0]; - this.mayNotBeSimplified = true; - return node; - } + axis3d: { + highlight: false, + strokecolor: 'black', + strokeWidth: 1, + tabindex: null, - if (n1.type == 'node_op' && n1.value == 'op_neg') { - node.value = 'op_sub'; - node.children[1] = n1.children[0]; - this.mayNotBeSimplified = true; - return node; - } + point1: { visible: false, name: '' }, + point2: { visible: false, name: '', label: { visible: true } } + }, - // const * a + const * a -> const * a - if (n0.type == 'node_op' && n0.value == 'op_mul' && - n1.type == 'node_op' && n1.value == 'op_mul') { + mesh3d: { + strokeWidth: 1, + strokeColor: '#9a9a9a', + strokeOpacity: 0.6, + highlight: false, + fillColor: '#9a9a9a', + fillOpacity: 0.1, + tabindex: null, - n0.children[1].hash = this.parser.compile(n0.children[1]); - n1.children[1].hash = this.parser.compile(n1.children[1]); - if (n0.children[1].hash === n1.children[1].hash) { + visible: 'inherit' + }, - node.value = 'op_mul'; - node.children = [ - this.createNode('node_op', 'op_add', - n0.children[0], - n1.children[0]), - n0.children[1] - ]; - this.mayNotBeSimplified = true; - return node; - } - } - // const * a + a -> (const + 1) * a - if (n0.type == 'node_op' && n0.value == 'op_mul') { + line3d: { + strokeWidth: 1, + strokeColor: 'black', + fixed: true, + tabindex: null, - n0.children[1].hash = this.parser.compile(n0.children[1]); - n1.hash = this.parser.compile(n1); - if (n0.children[1].hash === n1.hash) { + gradient: 'linear', + gradientSecondColor: '#ffffff', - node.value = 'op_mul'; - node.children = [ - this.createNode('node_op', 'op_add', - n0.children[0], - this.createNode('node_const', 1.0)), - n1 - ]; - this.mayNotBeSimplified = true; - return node; - } - } - // a + const*a -> (const + 1) * a - if (n1.type == 'node_op' && n1.value == 'op_mul') { + point1: {visible: false, name: ''}, + point2: {visible: false, name: ''} + }, - n1.children[1].hash = this.parser.compile(n1.children[1]); - n0.hash = this.parser.compile(n0); - if (n1.children[1].hash === n0.hash) { + plane3d: { + strokeWidth: 0, + strokeColor: 'black', + strokeOpacity: 1, + highlight: false, + tabindex: null, - node.value = 'op_mul'; - node.children = [ - this.createNode('node_op', 'op_add', - this.createNode('node_const', 1.0), - n1.children[0]), - n0 - ]; - this.mayNotBeSimplified = true; - return node; - } - } + gradient: 'linear', + gradientSecondColor: '#ffffff', + gradientAngle: Math.PI, + fillColor: '#a7a7a7', + fillOpacity: 0.6 + }, - break; - - // a - (-b) = a + b - case 'op_sub': - n0 = node.children[0]; - n1 = node.children[1]; - if (n1.type == 'node_op' && n1.value == 'op_neg') { - node.value = 'op_add'; - node.children[1] = n1.children[0]; - this.mayNotBeSimplified = true; - return node; - } - break; + point3d: { + strokeWidth: 0, + gradient: 'radial', + gradientSecondColor: '#555555', + fillColor: 'yellow', + highlightStrokeColor: '#555555' + }, - case 'op_execfun': - return this.simplifyElementary(node); - } + surface3d: { + /**#@+ + * @visprop + */ - return node; - }, + highlight: false, + tabindex: -1, + strokeWidth: 1, - simplifyElementary: function(node) { - var fun = node.children[0].value, - arg = node.children[1], - newNode; + /** + * Number of intervals the mesh is divided into in direction of parameter u. + * @type Number + * @name Surface3D#stepsU + */ + stepsU: 30, - // Catch errors of the form sin() - if (arg.length == 0) { - return node; - } + /** + * Number of intervals the mesh is divided into in direction of parameter v. + * @type Number + * @name Surface3D#stepsV + */ + stepsV: 30 - switch (fun) { - // sin(0) -> 0 - // sin(PI) -> 0 - // sin (int * PI) -> 0 - // sin (PI * int) -> 0 - // Same for tan() - case 'sin': - case 'tan': - if (arg[0].type == 'node_const' && arg[0].value === 0) { - node.type = 'node_const'; - node.value = 0.0; - return node; - } - if (arg[0].type == 'node_var' && arg[0].value == 'PI') { - node.type = 'node_const'; - node.value = 0.0; - return node; - } - if (arg[0].type == 'node_op' && arg[0].value == 'op_mul' && - arg[0].children[0].type == 'node_const' && arg[0].children[0].value % 1 === 0 && - arg[0].children[1].type == 'node_var' && arg[0].children[1].value == 'PI') { - node.type = 'node_const'; - node.value = 0.0; - return node; - } - break; - - // cos(0) -> 1.0 - // cos(PI) -> -1.0 - // cos(int * PI) -> +/- 1.0 - // cos(PI * int) -> +/- 1.0 - case 'cos': - if (arg[0].type == 'node_const' && arg[0].value === 0) { - node.type = 'node_const'; - node.value = 1.0; - return node; - } - if (arg[0].type == 'node_var' && arg[0].value == 'PI') { - node.type = 'node_op'; - node.value = 'op_neg'; - node.children = [this.createNode('node_const', 1.0)]; - return node; - } - /* - if (arg[0].type == 'node_op' && arg[0].value == 'op_mul' && - ((arg[0].children[0].type == 'node_const' && arg[0].children[0].value % 1 === 0 && - arg[0].children[1].type == 'node_var' && arg[0].children[1].value == 'PI') || - (arg[0].children[1].type == 'node_const' && arg[0].children[1].value % 1 === 0 && - arg[0].children[0].type == 'node_var' && arg[0].children[0].value == 'PI'))) { - node.type = 'node_const'; - node.value = 1.0; - return node; - } - */ - break; - - // exp(0) -> 1 - case 'exp': - if (arg[0].type == 'node_const' && arg[0].value === 0) { - node.type = 'node_const'; - node.value = 1.0; - return node; - } - break; - - // pow(a, 0) -> 1 - case 'pow': - if (arg[1].type == 'node_const' && arg[1].value === 0) { - node.type = 'node_const'; - node.value = 1.0; - return node; - } - break; + /**#@-*/ + }, - } + view3d: { + needsRegularUpdate: true + } - return node; - } + }); - }); + return JXG.Options; +}); - return JXG.CA; - }); /* - Copyright 2008-2021 + Copyright 2008-2022 Matthias Ehmann, - Michael Gerhaeuser, Carsten Miller, - Bianca Valentin, - Alfred Wassermann, - Peter Wilfahrt + Andreas Walter, + Alfred Wassermann This file is part of JSXGraph. @@ -71405,618 +80539,553 @@ define('base/turtle',[ the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> and <http://opensource.org/licenses/MIT/>. */ +/*global JXG:true, define: true*/ +define('3d/threed',['jxg' +], function (JXG) { + "use strict"; -/*global JXG: true, define: true*/ -/*jslint nomen: true, plusplus: true*/ + JXG.ThreeD = {}; -/* depends: - jxg - utils/type - */ + return JXG.ThreeD; +}); -/** - * @fileoverview The JXG.Dump namespace provides methods to save a board to javascript. - */ +/* + Copyright 2008-2022 + Matthias Ehmann, + Carsten Miller, + Andreas Walter, + Alfred Wassermann -define('utils/dump',['jxg', 'utils/type'], function (JXG, Type) { + This file is part of JSXGraph. - "use strict"; + JSXGraph is free software dual licensed under the GNU LGPL or MIT License. - /** - * The JXG.Dump namespace provides classes and methods to save a board to javascript. - * @namespace - */ - JXG.Dump = { + You can redistribute it and/or modify it under the terms of the - /** - * Adds markers to every element of the board - * @param {JXG.Board} board - * @param {Array|String} markers - * @param {Array} values - */ - addMarkers: function (board, markers, values) { - var e, l, i; + * GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version + OR + * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT - if (!Type.isArray(markers)) { - markers = [markers]; - } + JSXGraph is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. - if (!Type.isArray(values)) { - values = [values]; - } + You should have received a copy of the GNU Lesser General Public License and + the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> + and <http://opensource.org/licenses/MIT/>. + */ +/*global JXG:true, define: true*/ - l = Math.min(markers.length, values.length); +define('3d/view3d',['jxg', 'options', 'base/constants', 'utils/type', 'math/math', 'base/element', '3d/threed', +], function (JXG, Options, Const, Type, Mat, GeometryElement, ThreeD) { + "use strict"; - markers.length = l; - values.length = l; + ThreeD.View3D = function (board, parents, attributes) { + var bbox3d, coords, size; + this.constructor(board, attributes, Const.OBJECT_TYPE_VIEW3D, Const.OBJECT_CLASS_CURVE); - for (e in board.objects) { - if (board.objects.hasOwnProperty(e)) { - for (i = 0; i < l; i++) { - board.objects[e][markers[i]] = values[i]; - } - } - } - }, + bbox3d = parents[2]; // [[x1, x2], [y1,y2], [z1,z2]] + coords = parents[0]; // llft corner + size = parents[1]; // [w, h] /** - * Removes markers from every element on the board. - * @param {JXG.Board} board - * @param {Array|String} markers + * "Namespace" for all 3D handling */ - deleteMarkers: function (board, markers) { - var e, l, i; - - if (!Type.isArray(markers)) { - markers = [markers]; - } - - l = markers.length; - - markers.length = l; - - for (e in board.objects) { - if (board.objects.hasOwnProperty(e)) { - for (i = 0; i < l; i++) { - delete board.objects[e][markers[i]]; - } - } - } - }, + this.D3 = {}; /** - * Stringifies a string, i.e. puts some quotation marks around <tt>s</tt> if it is of type string. - * @param {*} s - * @returns {String} " + s + " + * An associative array containing all geometric objects belonging to the view. + * Key is the id of the object and value is a reference to the object. + * @type Object */ - str: function (s) { - if (typeof s === 'string' && s.substr(0, 7) !== 'function') { - s = '"' + s + '"'; - } - - return s; - }, + this.D3.objects = {}; /** - * Eliminate default values given by {@link JXG.Options} from the attributes object. - * @param {Object} instance Attribute object of the element - * @param {Object} s Arbitrary number of objects <tt>instance</tt> will be compared to. Usually these are - * sub-objects of the {@link JXG.Board#options} structure. - * @returns {Object} Minimal attributes object + * An array containing all geometric objects in this view in the order of construction. + * @type Array */ - minimizeObject: function (instance, s) { - var p, pl, i, - def = {}, - copy = Type.deepCopy(instance), - defaults = []; - - for (i = 1; i < arguments.length; i++) { - defaults.push(arguments[i]); - } - - def = Type.deepCopy(def, JXG.Options.elements, true); - for (i = defaults.length; i > 0; i--) { - def = Type.deepCopy(def, defaults[i - 1], true); - } + this.D3.objectsList = []; - for (p in def) { - if (def.hasOwnProperty(p)) { - pl = p.toLowerCase(); + /** + * @type {Object} contains the axes of the view or null + * @default null + */ + this.D3.defaultAxes = null; - if (typeof def[p] !== 'object' && def[p] === copy[pl]) { - // console.log("delete", p); - delete copy[pl]; - } - } - } + /** + * 3D-to-2D transformation matrix + * @type {Array} 3 x 4 mattrix + */ + this.D3.matrix = [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 1, 0] + ]; - return copy; - }, + // Bounding box (cube) [[x1, x2], [y1,y2], [z1,z2]]: + this.D3.bbox3d = bbox3d; + this.D3.coords = coords; + this.D3.size = size; /** - * Prepare the attributes object for an element to be dumped as JavaScript or JessieCode code. - * @param {JXG.Board} board - * @param {JXG.GeometryElement} obj Geometry element which attributes object is generated - * @returns {Object} An attributes object. + * Distance of the view to the origin. In other words, its + * the radius of the sphere where the camera sits. */ - prepareAttributes: function (board, obj) { - var a, s; + this.D3.r = -1; - a = this.minimizeObject(obj.getAttributes(), JXG.Options[obj.elType]); + this.timeoutAzimuth = null; - for (s in obj.subs) { - if (obj.subs.hasOwnProperty(s)) { - a[s] = this.minimizeObject(obj.subs[s].getAttributes(), - JXG.Options[obj.elType][s], - JXG.Options[obj.subs[s].elType]); - a[s].id = obj.subs[s].id; - a[s].name = obj.subs[s].name; - } - } + this.id = this.board.setId(this, 'V'); + this.board.finalizeAdding(this); + this.elType = 'view3d'; + this.methodMap = Type.deepCopy(this.methodMap, { + }); + }; + ThreeD.View3D.prototype = new GeometryElement(); - a.id = obj.id; - a.name = obj.name; + JXG.extend(ThreeD.View3D.prototype, /** @lends ThreeD.View3D.prototype */ { + create: function (elementType, parents, attributes) { + var prefix = [], + is3D = false, + el; - return a; + if (elementType.indexOf('3d') > 0) { + is3D = true; + prefix.push(this); + } + el = this.board.create(elementType, prefix.concat(parents), attributes); + if (true || is3D) { + this.add(el); + } + return el; }, - setBoundingBox: function(methods, board, boardVarName) { - methods.push({ - obj: boardVarName, - method: 'setBoundingBox', - params: [board.getBoundingBox(), true] - }); - - return methods; + add: function (el) { + this.D3.objects[el.id] = el; + this.D3.objectsList.push(el); }, /** - * Generate a save-able structure with all elements. This is used by {@link JXG.Dump#toJessie} and - * {@link JXG.Dump#toJavaScript} to generate the script. - * @param {JXG.Board} board - * @returns {Array} An array with all metadata necessary to save the construction. + * Update 3D-to-2D transformation matrix with the actual + * elevation and azimuth angles. + * + * @private */ - dump: function (board) { - var e, obj, element, s, - props = [], - methods = [], - elementList = [], - len = board.objectsList.length; - - this.addMarkers(board, 'dumped', false); - - // This has been moved to toJavaScript and toJessie - /* - methods.push({ - obj: '$board', - method: 'setBoundingBox', - params: [board.getBoundingBox(), true] - }); - */ - - for (e = 0; e < len; e++) { - obj = board.objectsList[e]; - element = {}; + update: function () { + var D3 = this.D3, + e, r, a, f, mat; - if (!obj.dumped && obj.dump) { - element.type = obj.getType(); - element.parents = obj.getParents().slice(); + if (!Type.exists(D3.el_slide) || + !Type.exists(D3.az_slide) || + !this.needsUpdate) { + return this; + } - // Extract coordinates of a point - if (element.type === 'point' && element.parents[0] === 1) { - element.parents = element.parents.slice(1); - } + e = D3.el_slide.Value(); + r = D3.r; + a = D3.az_slide.Value(); + f = r * Math.sin(e); + mat = [[1, 0, 0,], [0, 1, 0], [0, 0, 1]]; - for (s = 0; s < element.parents.length; s++) { - if (Type.isString(element.parents[s]) && - element.parents[s][0] !== "'" && - element.parents[s][0] !== '"') { + D3.matrix = [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 1, 0] + ]; - element.parents[s] = '"' + element.parents[s] + '"'; - } else if (Type.isArray( element.parents[s]) ) { - element.parents[s] = '[' + element.parents[s].toString() + ']'; - } - } + D3.matrix[1][1] = r * Math.cos(a); + D3.matrix[1][2] = -r * Math.sin(a); + D3.matrix[2][1] = f * Math.sin(a); + D3.matrix[2][2] = f * Math.cos(a); + D3.matrix[2][3] = Math.cos(e); - element.attributes = this.prepareAttributes(board, obj); - if (element.type === 'glider' && obj.onPolygon) { - props.push({ - obj: obj.id, - prop: 'onPolygon', - val: true - }); - } + if (true) { + mat[1][1] = D3.size[0] / (D3.bbox3d[0][1] - D3.bbox3d[0][0]); // w / d_x + mat[2][2] = D3.size[1] / (D3.bbox3d[1][1] - D3.bbox3d[1][0]); // h / d_y + mat[1][0] = D3.coords[0] - mat[1][1] * D3.bbox3d[0][0]; // llft_x + mat[2][0] = D3.coords[1] - mat[2][2] * D3.bbox3d[1][0]; // llft_y - elementList.push(element); - } + D3.matrix = Mat.matMatMult(mat, D3.matrix); } - this.deleteMarkers(board, 'dumped'); + return this; + }, - return { - elements: elementList, - props: props, - methods: methods - }; + updateRenderer: function () { + this.needsUpdate = false; + return this; }, /** - * Converts an array of different values into a parameter string that can be used by the code generators. - * @param {Array} a - * @param {function} converter A function that is used to transform the elements of <tt>a</tt>. Usually - * {@link JXG.toJSON} or {@link JXG.Dump.toJCAN} are used. - * @returns {String} + * Project 3D coordinates to 2D board coordinates + * The 3D coordinates are provides as three numbers x, y, z or one array of length 3. + * + * @param {Number|Array} x + * @param {[Number]} y + * @param {[Number]} z + * @returns {Array} Array of length 3 containing the projection on to the board + * in homogeneous user coordinates. */ - arrayToParamStr: function (a, converter) { - var i, - s = []; - - for (i = 0; i < a.length; i++) { - s.push(converter.call(this, a[i])); + project3DTo2D: function (x, y, z) { + var vec; + if (arguments.length === 3) { + vec = [1, x, y, z]; + } else { + // Argument is an array + if (x.length === 3) { + vec = [1].concat(x); + } else { + vec = x; + } } - - return s.join(', '); + return Mat.matVecMult(this.D3.matrix, vec); }, /** - * Converts a JavaScript object into a JCAN (JessieCode Attribute Notation) string. - * @param {Object} obj A JavaScript object, functions will be ignored. - * @returns {String} The given object stored in a JCAN string. + * Project a 2D coordinate to the plane through the origin + * defined by its normal vector `normal`. + * + * @param {JXG.Point} point + * @param {Array} normal + * @returns Array of length 4 containing the projected + * point in homogeneous coordinates. */ - toJCAN: function (obj) { - var i, list, prop; - - switch (typeof obj) { - case 'object': - if (obj) { - list = []; - - if (Type.isArray(obj)) { - for (i = 0; i < obj.length; i++) { - list.push(this.toJCAN(obj[i])); - } + project2DTo3DPlane: function (point, normal, foot) { + var mat, rhs, d, le, + n = normal.slice(1), + sol = [1, 0, 0, 0]; - return '[' + list.join(',') + ']'; - } + foot = foot || [1, 0, 0, 0]; + le = Mat.norm(n, 3); + d = Mat.innerProduct(foot.slice(1), n, 3) / le; - for (prop in obj) { - if (obj.hasOwnProperty(prop)) { - list.push(prop + ': ' + this.toJCAN(obj[prop])); - } - } + mat = this.D3.matrix.slice(0, 3); // True copy + mat.push([0].concat(n)); - return '<<' + list.join(', ') + '>> '; + // 2D coordinates of point: + rhs = point.coords.usrCoords.concat([d]); + try { + // Prevent singularity in case elevation angle is zero + if (mat[2][3] === 1.0) { + mat[2][1] = mat[2][2] = Mat.eps * 0.001; } - return 'null'; - case 'string': - return '\'' + obj.replace(/(["'])/g, '\\$1') + '\''; - case 'number': - case 'boolean': - return obj.toString(); - case 'null': - return 'null'; + sol = Mat.Numerics.Gauss(mat, rhs); + } catch (err) { + sol = [0, NaN, NaN, NaN]; } + + return sol; }, - /** - * Saves the construction in <tt>board</tt> to JessieCode. - * @param {JXG.Board} board - * @returns {String} JessieCode - */ - toJessie: function (board) { - var i, elements, - dump = this.dump(board), - script = []; + project3DToCube: function (c3d) { + var cube = this.D3.bbox3d; + if (c3d[1] < cube[0][0]) { c3d[1] = cube[0][0]; } + if (c3d[1] > cube[0][1]) { c3d[1] = cube[0][1]; } + if (c3d[2] < cube[1][0]) { c3d[2] = cube[1][0]; } + if (c3d[2] > cube[1][1]) { c3d[2] = cube[1][1]; } + if (c3d[3] < cube[2][0]) { c3d[3] = cube[2][0]; } + if (c3d[3] > cube[2][1]) { c3d[3] = cube[2][1]; } - dump.methods = this.setBoundingBox(dump.methods, board, '$board'); + return c3d; + }, - elements = dump.elements; + intersectionLineCube: function (p, d, r) { + var rnew, i, r0, r1; - for (i = 0; i < elements.length; i++) { - if (elements[i].attributes.name.length > 0) { - script.push('// ' + elements[i].attributes.name); + rnew = r; + for (i = 0; i < 3; i++) { + if (d[i] !== 0) { + r0 = (this.D3.bbox3d[i][0] - p[i]) / d[i]; + r1 = (this.D3.bbox3d[i][1] - p[i]) / d[i]; + if (r < 0) { + rnew = Math.max(rnew, Math.min(r0, r1)); + } else { + rnew = Math.min(rnew, Math.max(r0, r1)); + } } - - script.push('s' + i + ' = ' + elements[i].type + '(' + elements[i].parents.join(', ') + ') ' + this.toJCAN(elements[i].attributes).replace(/\n/, '\\n') + ';'); - script.push(''); - } - - for (i = 0; i < dump.methods.length; i++) { - script.push(dump.methods[i].obj + '.' + dump.methods[i].method + '(' + this.arrayToParamStr(dump.methods[i].params, this.toJCAN) + ');'); - script.push(''); - } - - for (i = 0; i < dump.props.length; i++) { - script.push(dump.props[i].obj + '.' + dump.props[i].prop + ' = ' + this.toJCAN(dump.props[i].val) + ';'); - script.push(''); } + return rnew; + }, - return script.join('\n'); + isInCube: function (q) { + return q[0] > this.D3.bbox3d[0][0] - Mat.eps && q[0] < this.D3.bbox3d[0][1] + Mat.eps && + q[1] > this.D3.bbox3d[1][0] - Mat.eps && q[1] < this.D3.bbox3d[1][1] + Mat.eps && + q[2] > this.D3.bbox3d[2][0] - Mat.eps && q[2] < this.D3.bbox3d[2][1] + Mat.eps; }, /** - * Saves the construction in <tt>board</tt> to JavaScript. - * @param {JXG.Board} board - * @returns {String} JavaScript + * + * @param {*} plane1 + * @param {*} plane2 + * @param {*} d + * @returns Array of length 2 containing the coordinates of the defining points of + * of the intersection segment. */ - toJavaScript: function (board) { - var i, elements, - dump = this.dump(board), - script = []; - - dump.methods = this.setBoundingBox(dump.methods, board, 'board'); - - elements = dump.elements; + intersectionPlanePlane: function(plane1, plane2, d) { + var ret = [[], []], + p, dir, r, q; - for (i = 0; i < elements.length; i++) { - script.push('board.create("' + elements[i].type + '", [' + elements[i].parents.join(', ') + '], ' + Type.toJSON(elements[i].attributes) + ');'); - } + d = d || plane2.D3.d; - for (i = 0; i < dump.methods.length; i++) { - script.push(dump.methods[i].obj + '.' + dump.methods[i].method + '(' + this.arrayToParamStr(dump.methods[i].params, Type.toJSON) + ');'); - script.push(''); + p = Mat.Geometry.meet3Planes(plane1.D3.normal, plane1.D3.d, plane2.D3.normal, d, + Mat.crossProduct(plane1.D3.normal, plane2.D3.normal), 0); + dir = Mat.Geometry.meetPlanePlane(plane1.D3.dir1, plane1.D3.dir2, plane2.D3.dir1, plane2.D3.dir2); + r = this.intersectionLineCube(p, dir, Infinity); + q = Mat.axpy(r, dir, p); + if (this.isInCube(q)) { + ret[0] = q; } - - for (i = 0; i < dump.props.length; i++) { - script.push(dump.props[i].obj + '.' + dump.props[i].prop + ' = ' + Type.toJSON(dump.props[i].val) + ';'); - script.push(''); + r = this.intersectionLineCube(p, dir, -Infinity); + q = Mat.axpy(r, dir, p); + if (this.isInCube(q) ) { + ret[1] = q; } + return ret; + }, - return script.join('\n'); - } - }; - - return JXG.Dump; -}); - -/* - Copyright 2018-2021 - Alfred Wassermann, - Tigran Saluev - - This file is part of JSXGraph. - - JSXGraph is free software dual licensed under the GNU LGPL or MIT License. - - You can redistribute it and/or modify it under the terms of the + getMesh: function (X, Y, Z, interval_u, interval_v) { + var i_u, i_v, u, v, c2d, + delta_u, delta_v, + p = [0, 0, 0], + steps_u = interval_u[2], + steps_v = interval_v[2], - * GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version - OR - * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT + dataX = [], + dataY = []; - JSXGraph is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. + delta_u = (Type.evaluate(interval_u[1]) - Type.evaluate(interval_u[0])) / (steps_u); + delta_v = (Type.evaluate(interval_v[1]) - Type.evaluate(interval_v[0])) / (steps_v); - You should have received a copy of the GNU Lesser General Public License and - the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> - and <http://opensource.org/licenses/MIT/>. - */ + for (i_u = 0; i_u <= steps_u; i_u++) { + u = interval_u[0] + delta_u * i_u; + for (i_v = 0; i_v <= steps_v; i_v++) { + v = interval_v[0] + delta_v * i_v; + p[0] = X(u, v); + p[1] = Y(u, v); + p[2] = Z(u, v); + c2d = this.project3DTo2D(p); + dataX.push(c2d[1]); + dataY.push(c2d[2]); + } + dataX.push(NaN); + dataY.push(NaN); + } + for (i_v = 0; i_v <= steps_v; i_v++) { + v = interval_v[0] + delta_v * i_v; + for (i_u = 0; i_u <= steps_u; i_u++) { + u = interval_u[0] + delta_u * i_u; + p[0] = X(u, v); + p[1] = Y(u, v); + p[2] = Z(u, v); + c2d = this.project3DTo2D(p); + dataX.push(c2d[1]); + dataY.push(c2d[2]); + } + dataX.push(NaN); + dataY.push(NaN); + } -/*global JXG: true, define: true*/ -/*jslint nomen: true, plusplus: true*/ + return [dataX, dataY]; + }, -/* depends: - see define call - */ + animateAzimuth: function () { + var s = this.D3.az_slide._smin, + e = this.D3.az_slide._smax, + sdiff = e - s, + newVal = this.D3.az_slide.Value() + 0.1; -/** - * @fileoverview In this file the Comb element is defined. - */ + this.D3.az_slide.position = ((newVal - s) / sdiff); + if (this.D3.az_slide.position > 1) { + this.D3.az_slide.position = 0.0; + } + this.board.update(); -define('element/comb',[ - 'jxg', 'options', 'utils/type', 'base/constants', 'base/line', 'base/polygon', 'base/point' -], function (JXG, Options, Type, Const, Line, Polygon, Point) { + this.timeoutAzimuth = setTimeout(function () { this.animateAzimuth(); }.bind(this), 200); + }, - "use strict"; + stopAzimuth: function () { + clearTimeout(this.timeoutAzimuth); + this.timeoutAzimuth = null; + } + }); /** - * @class A comb to display domains of inequalities. + * @class This element creates a 3D view. * @pseudo - * @name Comb - * @augments JXG.Curve - * @constructor - * @type JXG.Curve - * @throws {Error} If the element cannot be constructed with the given parent - * objects an exception is thrown. - * Parameter options: - * @param {JXG.Point,array,function_JXG.Point,array,function} point1,point2 Parent elements - * can be two elements either of type {@link JXG.Point} or array of - * numbers describing the coordinates of a point. In the latter case the point - * will be constructed automatically as a fixed invisible point. - * It is possible to provide a function returning an array or a point, - * instead of providing an array or a point. - * @example - * // Create a simple horizontal comb with invisible endpoints - * var c = board.create('comb', [[1, 0], [3, 0]]); - * - * </pre><div class="jxgbox" id="JXG951ccb6a-52bc-4dc2-80e9-43db064f0f1b" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function () { - * var board = JXG.JSXGraph.initBoard('JXG951ccb6a-52bc-4dc2-80e9-43db064f0f1b', {boundingbox: [-5, 5, 5, -5], axis: true, showcopyright: false, shownavigation: false}), - * c = board.create('comb', [[1, 0], [3, 0]]); - * })(); - * </script><pre> + * @description A View3D element provides the container and the methods to create and display 3D elements. + * It is contained in a JSXGraph board. + * @name View3D + * @augments JXG.View3D + * @constructor + * @type Object + * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {Array_Array_Array} lower,dim,cube Here, lower is an array of the form [x, y] and + * dim is an array of the form [w, h]. + * The arrays [x, y] and [w, h] define the 2D frame into which the 3D cube is + * (roughly) projected. + * cube is an array of the form [[x1, x2], [y1, y2], [z1, z2]] + * which determines the coordinate ranges of the 3D cube. * * @example - * var p1 = board.create('glider', [-3, 0, board.defaultAxes.x]); - * var p2 = board.create('glider', [-1, 0, board.defaultAxes.x]); - * var c1 = board.create('comb', [p1, p2], {width: 0.2, frequency: 0.1, angle: Math.PI / 4}); + * var bound = [-5, 5]; + * var view = board.create('view3d', + * [[-6, -3], + * [8, 8], + * [bound, bound, bound]], + * { + * // Main axes + * axesPosition: 'center', + * xAxis: { strokeColor: 'blue', strokeWidth: 3}, * - * </pre><div id="JXG04186fd2-6340-11e8-9fb9-901b0e1b8723" class="jxgbox" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function() { - * var board = JXG.JSXGraph.initBoard('JXG04186fd2-6340-11e8-9fb9-901b0e1b8723', - * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); - * var p1 = board.create('glider', [-3, 0, board.defaultAxes.x]); - * var p2 = board.create('glider', [-1, 0, board.defaultAxes.x]); - * var c1 = board.create('comb', [p1, p2], {width: 0.2, frequency: 0.1, angle: Math.PI / 4}); + * // Planes + * xPlaneRear: { fillColor: 'yellow', mesh3d: {visible: false}}, + * yPlaneFront: { visible: true, fillColor: 'blue'}, * - * })(); + * // Axes on planes + * xPlaneRearYAxis: {strokeColor: 'red'}, + * xPlaneRearZAxis: {strokeColor: 'red'}, * - * </script><pre> + * yPlaneFrontXAxis: {strokeColor: 'blue'}, + * yPlaneFrontZAxis: {strokeColor: 'blue'}, * - * @example - * var s = board.create('slider', [[1,3], [4,3], [0.1, 0.3, 0.8]]); - * var p1 = board.create('glider', [-3, 0, board.defaultAxes.x]); - * var p2 = board.create('glider', [-1, 0, board.defaultAxes.x]); - * var c1 = board.create('comb', [p1, p2], { - * width: function(){ return 4*s.Value(); }, - * reverse: function(){ return (s.Value()<0.5) ? false : true; }, - * frequency: function(){ return s.Value(); }, - * angle: function(){ return s.Value() * Math.PI / 2; }, - * curve: { - * strokeColor: 'red' - * } - * }); + * zPlaneFrontXAxis: {visible: false}, + * zPlaneFrontYAxis: {visible: false} + * }); * - * </pre><div id="JXG6eb1bcd1-407e-4f13-8f0c-45ef39a0cfb3" class="jxgbox" style="width: 300px; height: 300px;"></div> + * </pre><div id="JXGdd06d90e-be5d-4531-8f0b-65fc30b1a7c7" class="jxgbox" style="width: 500px; height: 500px;"></div> * <script type="text/javascript"> * (function() { - * var board = JXG.JSXGraph.initBoard('JXG6eb1bcd1-407e-4f13-8f0c-45ef39a0cfb3', - * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); - * var s = board.create('slider', [[1,3], [4,3], [0.1, 0.3, 0.8]]); - * var p1 = board.create('glider', [-3, 0, board.defaultAxes.x]); - * var p2 = board.create('glider', [-1, 0, board.defaultAxes.x]); - * var c1 = board.create('comb', [p1, p2], { - * width: function(){ return 4*s.Value(); }, - * reverse: function(){ return (s.Value()<0.5) ? false : true; }, - * frequency: function(){ return s.Value(); }, - * angle: function(){ return s.Value() * Math.PI / 2; }, - * curve: { - * strokeColor: 'red' - * } - * }); + * var board = JXG.JSXGraph.initBoard('JXGdd06d90e-be5d-4531-8f0b-65fc30b1a7c7', + * {boundingbox: [-8, 8, 8,-8], axis: false, showcopyright: false, shownavigation: false}); + * var bound = [-5, 5]; + * var view = board.create('view3d', + * [[-6, -3], [8, 8], + * [bound, bound, bound]], + * { + * // Main axes + * axesPosition: 'center', + * xAxis: { strokeColor: 'blue', strokeWidth: 3}, + * + * // Planes + * xPlaneRear: { fillColor: 'yellow', mesh3d: {visible: false}}, + * yPlaneFront: { visible: true, fillColor: 'blue'}, + * + * // Axes on planes + * xPlaneRearYAxis: {strokeColor: 'red'}, + * xPlaneRearZAxis: {strokeColor: 'red'}, + * + * yPlaneFrontXAxis: {strokeColor: 'blue'}, + * yPlaneFrontZAxis: {strokeColor: 'blue'}, + * + * zPlaneFrontXAxis: {visible: false}, + * zPlaneFrontYAxis: {visible: false} + * }); * * })(); * * </script><pre> * */ - JXG.createComb = function(board, parents, attributes) { - var p1, p2, c, attr, attr2, parent_types; - //ds, angle, width, p; - - if (parents.length === 2) { - // point 1 given by coordinates - if (Type.isArray(parents[0]) && parents[0].length > 1) { - attr = Type.copyAttributes(attributes, board.options, 'comb', 'point1'); - p1 = board.create('point', parents[0], attr); - } else if (Type.isString(parents[0]) || Type.isPoint(parents[0])) { - p1 = board.select(parents[0]); - } else if (Type.isFunction(parents[0]) && Type.isPoint(parents[0]())) { - p1 = parents[0](); - } else if (Type.isFunction(parents[0]) && parents[0]().length && parents[0]().length >= 2) { - attr = Type.copyAttributes(attributes, board.options, 'comb', 'point1'); - p1 = Point.createPoint(board, parents[0](), attr); - } else { - throw new Error("JSXGraph: Can't create comb with parent types '" + - (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + - "\nPossible parent types: [point,point], [[x1,y1],[x2,y2]]"); - } - - // point 2 given by coordinates - if (Type.isArray(parents[1]) && parents[1].length > 1) { - attr = Type.copyAttributes(attributes, board.options, 'comb', 'point2'); - p2 = board.create('point', parents[1], attr); - } else if (Type.isString(parents[1]) || Type.isPoint(parents[1])) { - p2 = board.select(parents[1]); - } else if (Type.isFunction(parents[1]) && Type.isPoint(parents[1]()) ) { - p2 = parents[1](); - } else if (Type.isFunction(parents[1]) && parents[1]().length && parents[1]().length >= 2) { - attr = Type.copyAttributes(attributes, board.options, 'comb', 'point2'); - p2 = Point.createPoint(board, parents[1](), attr); - } else { - throw new Error("JSXGraph: Can't create comb with parent types '" + - (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + - "\nPossible parent types: [point,point], [[x1,y1],[x2,y2]]"); - } - } else { - parent_types = parents.map(function(parent) { return "'" + (typeof parent) + "'"; }); - throw new Error("JSXGraph: Can't create comb with parent types " + - parent_types.join(", ") + "." + - "\nPossible parent types: [point,point], [[x1,y1],[x2,y2]]"); + ThreeD.createView3D = function (board, parents, attributes) { + var view, frame, attr, + x, y, w, h, + coords = parents[0], // llft corner + size = parents[1]; // [w, h] + + attr = Type.copyAttributes(attributes, board.options, 'view3d'); + view = new ThreeD.View3D(board, parents, attr); + view.defaultAxes = view.create('axes3d', parents, attributes); + + x = coords[0]; + y = coords[1]; + w = size[0]; + h = size[1]; + + /** + * Frame around the view object + */ + if (false) { + frame = board.create('polygon', [ + [coords[0], coords[1] + size[1]], // ulft + [coords[0], coords[1]], // llft + [coords[0] + size[0], coords[1]], // lrt + [coords[0] + size[0], coords[1] + size[1]], // urt + ], { + fillColor: 'none', + highlightFillColor: 'none', + highlight: false, + vertices: { + fixed: true, + visible: false + }, + borders: { + strokeColor: 'black', + highlight: false, + strokeWidth: 0.5, + dash: 4 + } + }); + //view.add(frame); } - // attr = Type.copyAttributes(attributes, board.options, 'comb', 'curve'); - attr = Type.copyAttributes(attributes, board.options, 'comb'); - Type.merge(attr, Type.copyAttributes(attributes, board.options, 'comb', 'curve')); - c = board.create('curve', [[0], [0]], attr); - - c.updateDataArray = function() { - var s = 0, - max_s = p1.Dist(p2), - cs, sn, dx, dy, - x, y, f, - p1_inner = p1, - p2_inner = p2, - ds, angle, width; - - ds = Type.evaluate(c.visProp.frequency); - angle = -Type.evaluate(c.visProp.angle); - width = Type.evaluate(c.visProp.width); - if (Type.evaluate(c.visProp.reverse)) { - p1_inner = p2; - p2_inner = p1; - angle = -angle; - } - cs = Math.cos(angle); - sn = Math.sin(angle); - dx = (p2_inner.X() - p1_inner.X()) / max_s; - dy = (p2_inner.Y() - p1_inner.Y()) / max_s; - - // But instead of lifting by sin(angle), we want lifting by width. - cs *= width / Math.abs(sn); - sn *= width / Math.abs(sn); - - this.dataX = []; - this.dataY = []; - // TODO Handle infinite boundaries? - while (s < max_s) { - x = p1_inner.X() + dx * s; - y = p1_inner.Y() + dy * s; - - // We may need to cut the last piece of a comb. - f = Math.min(cs, max_s - s) / Math.abs(cs); - sn *= f; - cs *= f; + /** + * Slider to adapt azimuth angle + */ + view.D3.az_slide = board.create('slider', [[x - 1, y - 2], [x + w + 1, y - 2], [0, 1.0, 2 * Math.PI]], { + style: 6, name: 'az', + point1: { frozen: true }, + point2: { frozen: true } + }); - this.dataX.push(x); - this.dataY.push(y); + /** + * Slider to adapt elevation angle + */ + view.D3.el_slide = board.create('slider', [[x - 1, y], [x - 1, y + h], [0, 0.30, Math.PI / 2]], { + style: 6, name: 'el', + point1: { frozen: true }, + point2: { frozen: true } + }); - this.dataX.push(x + dx * cs + dy * sn); - this.dataY.push(y - dx * sn + dy * cs); + view.board.highlightInfobox = function (x, y, el) { + var d; - this.dataX.push(NaN); // Force a jump - this.dataY.push(NaN); - s += ds; + if (Type.exists(el.D3)) { + d = Type.evaluate(el.visProp.infoboxdigits); + if (d === 'auto') { + view.board.highlightCustomInfobox('(' + + Type.autoDigits(el.D3.X()) + ' | ' + + Type.autoDigits(el.D3.Y()) + ' | ' + + Type.autoDigits(el.D3.Z()) + ')', el); + } else { + view.board.highlightCustomInfobox('(' + + Type.toFixed(el.D3.X(), d) + ' | ' + + Type.toFixed(el.D3.Y(), d) + ' | ' + + Type.toFixed(el.D3.Z(), d) + ')', el); + } + } else { + view.board.highlightCustomInfobox('(' + x + ', ' + y + ')', el); } }; - return c; - }; - - JXG.registerElement('comb', JXG.createComb); - - return { - createComb: JXG.createComb + return view; }; + JXG.registerElement('view3d', ThreeD.createView3D); + return ThreeD.View3D; }); + /* - Copyright 2008-2021 + Copyright 2008-2022 Matthias Ehmann, - Michael Gerhaeuser, Carsten Miller, - Bianca Valentin, - Alfred Wassermann, - Peter Wilfahrt + Andreas Walter, + Alfred Wassermann This file is part of JSXGraph. @@ -72039,213 +81108,349 @@ define('element/comb',[ the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> and <http://opensource.org/licenses/MIT/>. */ +/*global JXG:true, define: true*/ +/** + * Create axes and rear and front walls of the + * view3d bounding box bbox3d. + */ +define('3d/box3d',['jxg', 'utils/type', 'math/math', 'math/geometry', '3d/view3d' +], function (JXG, Type, Mat, Geometry, ThreeD) { + "use strict"; -/*global JXG: true, define: true*/ -/*jslint nomen: true, plusplus: true*/ + ThreeD.createAxes = function (board, parents, attributes) { + var view = parents[0], + i, j, k, i1, i2, + attr, + pos, + directions = ['x', 'y', 'z'], + suffixAxis = 'Axis', + dir, dir1, + sides = ['Rear', 'Front'], + rear = [0, 0, 0], // x, y, z + front = [0, 0, 0], // x, y, z + from, to, + vec1, vec2, range1, range2, + na, na_parent, + ticks_attr, + axes = {}; + + if (Type.exists(view.D3)) { + for (i = 0; i < directions.length; i++) { + rear[i] = view.D3.bbox3d[i][0]; + front[i] = view.D3.bbox3d[i][1]; + } + } else { + for (i = 0; i < directions.length; i++) { + rear[i] = parents[1][i]; + front[i] = parents[2][1]; + } + } -/* depends: - see define call - */ + // Main 3D axes + attr = Type.copyAttributes(attributes, board.options, 'axes3d'); + pos = attr.axesposition; + for (i = 0; i < directions.length; i++) { + // Run through ['x', 'y', 'z'] + dir = directions[i]; + na = dir + suffixAxis; + + if (pos === 'center') { // Axes centered + from = [0, 0, 0]; + to = [0, 0, 0]; + to[i] = front[i]; + axes[na] = view.create('axis3d', [from, to], attr[na.toLowerCase()]); + } else { + na += 'Border'; // Axes bordered + from = rear.slice(); + to = front.slice(); + if (i === 2) { + from[1] = front[1]; + to[0] = rear[0]; + } else { + from[i] = front[i]; + to[2] = rear[2]; + } + to[i] = front[i]; + attr[na.toLowerCase()].lastArrow = false; + axes[na] = view.create('axis3d', [from, to], attr[na.toLowerCase()]); + + // TODO + ticks_attr = { + visible: true, // Für z-Ticks wird path nicht berechnet + minorTicks: 0, + tickEndings: [0, 1], + drawLabels: false + }; + if (i === 2) { + ticks_attr.tickEndings = [1, 0]; + } + axes[na + 'Ticks'] = view.create('ticks', [axes[na], 1], ticks_attr); + } + } -/** - * @fileoverview Example file for a triangle implemented as a extension to JSXGraph. - */ + // Origin (2D point) + axes.O = board.create('intersection', [ + axes[directions[0] + suffixAxis], + axes[directions[1] + suffixAxis] + ], { + name: '', visible: false, withLabel: false + }); -define('element/slopetriangle',[ - 'jxg', 'options', 'utils/type', 'base/constants', 'base/line', 'base/polygon', 'base/point', 'base/element' -], function (JXG, Options, Type, Const, Line, Polygon, Point, GeometryElement) { + // Front and rear planes + for (i = 0; i < directions.length; i++) { + // Run through ['x', 'y', 'z'] + i1 = (i + 1) % 3; + i2 = (i + 2) % 3; + + dir = directions[i]; + for (j = 0; j < sides.length; j++) { + // Run through ['Rear', 'Front'] + + from = [0, 0, 0]; + from[i] = (j === 0) ? rear[i] : front[i]; + vec1 = [0, 0, 0]; + vec2 = [0, 0, 0]; + vec1[i1] = 1; + vec2[i2] = 1; + range1 = [rear[i1], front[i1]]; + range2 = [rear[i2], front[i2]]; + na = dir + 'Plane' + sides[j]; + + attr = Type.copyAttributes(attributes, board.options, 'axes3d', na); + axes[na] = + view.create('plane3d', [from, vec1, vec2, range1, range2], attr); + axes[na].D3.elType = 'axisplane3d'; + } + } - "use strict"; + // Axes on front and rear planes + for (i = 0; i < directions.length; i++) { + // Run through ['x', 'y', 'z'] + dir = directions[i]; + for (j = 0; j < sides.length; j++) { + for (k = 1; k <= 2; k++) { + i1 = (i + k) % 3; + dir1 = directions[i1]; + na = dir + 'Plane' + sides[j] + dir1.toUpperCase() + 'Axis'; + na_parent = dir + 'Plane' + sides[j]; - var priv = { - removeSlopeTriangle: function () { - Polygon.Polygon.prototype.remove.call(this); + from = [0, 0, 0]; + to = [0, 0, 0]; + from[i] = to[i] = (j === 0) ? rear[i] : front[i]; - this.board.removeObject(this.toppoint); - this.board.removeObject(this.glider); + from[i1] = rear[i1]; + to[i1] = front[i1]; - this.board.removeObject(this.baseline); - this.board.removeObject(this.basepoint); + attr = Type.copyAttributes(attributes, board.options, 'axes3d', na); + axes[na] = view.create('axis3d', [from, to], attr); + axes[na_parent].addChild(axes[na]); + axes[na_parent].inherits.push(axes[na]); + } + } + } - this.board.removeObject(this.label); + return axes; + }; + JXG.registerElement('axes3d', ThreeD.createAxes); + + ThreeD.createAxis = function (board, parents, attributes) { + var view = parents[0], + attr, + start = parents[1], + end = parents[2], + el_start, el_end, el; + + // Use 2D points to create axis + attr = Type.copyAttributes(attributes.point1, board.options, 'axis3d', 'point1'); + el_start = board.create('point', [ + (function (xx, yy, zz) { + return function () { return view.project3DTo2D(xx, yy, zz)[1]; }; + })(start[0], start[1], start[2]), + (function (xx, yy, zz) { + return function () { return view.project3DTo2D(xx, yy, zz)[2]; }; + })(start[0], start[1], start[2]) + ], attr); - if (this._isPrivateTangent) { - this.board.removeObject(this.tangent); + attr = Type.copyAttributes(attributes.point2, board.options, 'axis3d', 'point2'); + el_end = board.create('point', [ + (function (xx, yy, zz) { + return function () { return view.project3DTo2D(xx, yy, zz)[1]; }; + })(end[0], end[1], end[2]), + (function (xx, yy, zz) { + return function () { return view.project3DTo2D(xx, yy, zz)[2]; }; + })(end[0], end[1], end[2]) + ], attr); + + attr = Type.copyAttributes(attributes, board.options, 'axis3d'); + el = board.create('arrow', [el_start, el_end], attr); + + return el; + }; + JXG.registerElement('axis3d', ThreeD.createAxis); + + ThreeD.createMesh = function (board, parents, attr) { + var view = parents[0], + point = parents[1], + vec1 = parents[2], + range1 = parents[3], + vec2 = parents[4], + range2 = parents[5], + el; + + el = board.create('curve', [[], []], attr); + el.updateDataArray = function () { + var s1 = range1[0], + e1 = range1[1], + s2 = range2[0], + e2 = range2[1], + l1, l2, res, i, sol, + v1 = [0, 0, 0], + v2 = [0, 0, 0], + step = 1, + q = [0, 0, 0]; + + this.dataX = []; + this.dataY = []; + + for (i = 0; i < 3; i++) { + q[i] = Type.evaluate(point[i]); + v1[i] = Type.evaluate(vec1[i]); + v2[i] = Type.evaluate(vec2[i]); + } + l1 = JXG.Math.norm(v1, 3); + l2 = JXG.Math.norm(v2, 3); + for (i = 0; i < 3; i++) { + v1[i] /= l1; + v2[i] /= l2; + } + if (false) { + sol = Mat.Geometry.getPlaneBounds(v1, v2, q, s1, e1); + if (sol !== null) { + s1 = sol[0]; + e1 = sol[1]; + s2 = sol[2]; + e2 = sol[3]; } - }, - Value: function () { - return this.tangent.getSlope(); } + + res = view.getMesh( + function(u, v) { return q[0] + u * v1[0] + v * v2[0]; }, + function(u, v) { return q[1] + u * v1[1] + v * v2[1]; }, + function(u, v) { return q[2] + u * v1[2] + v * v2[2]; }, + [Math.ceil(s1), Math.floor(e1), (Math.ceil(e1) - Math.floor(s1)) / step], + [Math.ceil(s2), Math.floor(e2), (Math.ceil(e2) - Math.floor(s2)) / step]); + this.dataX = res[0]; + this.dataY = res[1]; }; + return el; + }; + JXG.registerElement('mesh3d', ThreeD.createMesh); - /** - * @class Slope triangle for a point on a line. - * @pseudo - * @name Slopetriangle - * @augments JXG.Line - * @constructor - * @type JXG.Polygon - * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown. - * Parameter options: - * @param {JXG.Line} t A tangent based on a glider on some object, e.g. curve, circle, line or turtle. - * @param {JXG.Line_JXG.Point} li, p A line and a point on that line. - * The user has to take care that the point is a member of the line. - * @example - * // Create a slopetriangle on a tangent - * var f = board.create('plot', ['sin(x)']), - * g = board.create('glider', [1, 2, f]), - * t = board.create('tangent', [g]), - * - * st = board.create('slopetriangle', [t]); - * - * </pre><div class="jxgbox" id="JXG951ccb6a-52bc-4dc2-80e9-43db064f0f1b" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function () { - * var board = JXG.JSXGraph.initBoard('JXG951ccb6a-52bc-4dc2-80e9-43db064f0f1b', {boundingbox: [-5, 5, 5, -5], axis: true, showcopyright: false, shownavigation: false}), - * f = board.create('plot', ['sin(x)']), - * g = board.create('glider', [1, 2, f]), - * t = board.create('tangent', [g]), - * - * st = board.create('slopetriangle', [t]); - * })(); - * </script><pre> - * - * @example - * // Create a on a line and a point on that line - * var p1 = board.create('point', [-2, 3]), - * p2 = board.create('point', [2, -3]), - * li = board.create('line', [p1, p2]), - * p = board.create('glider', [0, 0, li]), - * - * st = board.create('slopetriangle', [li, p]); - * - * </pre><div class="jxgbox" id="JXGb52f451c-22cf-4677-852a-0bb9d764ee95" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function () { - * var board = JXG.JSXGraph.initBoard('JXGb52f451c-22cf-4677-852a-0bb9d764ee95', {boundingbox: [-5, 5, 5, -5], axis: true, showcopyright: false, shownavigation: false}), - * p1 = board.create('point', [-2, 3]), - * p2 = board.create('point', [2, -3]), - * li = board.create('line', [p1, p2]), - * p = board.create('glider', [0, 0, li]), - * - * st = board.create('slopetriangle', [li, p]); - * })(); - * </script><pre> - */ - JXG.createSlopeTriangle = function (board, parents, attributes) { - var el, tangent, tglide, glider, toppoint, baseline, basepoint, label, attr, - isPrivateTangent = false; +}); +/* + Copyright 2008-2022 + Matthias Ehmann, + Carsten Miller, + Andreas Walter, + Alfred Wassermann - if (parents.length === 1 && parents[0].type === Const.OBJECT_TYPE_TANGENT) { - tangent = parents[0]; - tglide = tangent.glider; - } else if (parents.length === 1 && parents[0].type === Const.OBJECT_TYPE_GLIDER) { - tglide = parents[0]; - attr = Type.copyAttributes(attributes, board.options, 'slopetriangle', 'tangent'); - tangent = board.create('tangent', [tglide], attr); - isPrivateTangent = true; - } else if (parents.length === 2 && - parents[0].elementClass === Const.OBJECT_CLASS_LINE && Type.isPoint(parents[1])) { - tangent = parents[0]; - tglide = parents[1]; - } else { - throw new Error("JSXGraph: Can't create slope triangle with parent types '" + (typeof parents[0]) + "'."); - } + This file is part of JSXGraph. - attr = Type.copyAttributes(attributes, board.options, 'slopetriangle', 'basepoint'); - basepoint = board.create('point', [function () { - return [tglide.X() + 1, tglide.Y()]; - }], attr); + JSXGraph is free software dual licensed under the GNU LGPL or MIT License. - attr = Type.copyAttributes(attributes, board.options, 'slopetriangle', 'baseline'); - baseline = board.create('line', [tglide, basepoint], attr); + You can redistribute it and/or modify it under the terms of the - attr = Type.copyAttributes(attributes, board.options, 'slopetriangle', 'glider'); - glider = board.create('glider', [tglide.X() + 1, tglide.Y(), baseline], attr); + * GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version + OR + * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT - attr = Type.copyAttributes(attributes, board.options, 'slopetriangle', 'toppoint'); - toppoint = board.create('point', [function () { - return [glider.X(), glider.Y() + (glider.X() - tglide.X()) * tangent.getSlope()]; - }], attr); + JSXGraph is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. - attr = Type.copyAttributes(attributes, board.options, 'slopetriangle'); - attr.borders = Type.copyAttributes(attr.borders, board.options, 'slopetriangle', 'borders'); - el = board.create('polygon', [tglide, glider, toppoint], attr); + You should have received a copy of the GNU Lesser General Public License and + the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> + and <http://opensource.org/licenses/MIT/>. + */ +/*global JXG:true, define: true*/ - /** - * Returns the value of the slope triangle, that is the slope of the tangent. - * @name Value - * @memberOf Slopetriangle.prototype - * @function - * @returns {Number} slope of the tangent. - */ - el.Value = priv.Value; - el.tangent = tangent; - el._isPrivateTangent = isPrivateTangent; +define('3d/curve3d',['jxg', 'utils/type', '3d/view3d' +], function (JXG, Type, ThreeD) { + "use strict"; - //el.borders[0].setArrow(false, {type: 2, size: 10}); - //el.borders[1].setArrow(false, {type: 2, size: 10}); - el.borders[2].setArrow(false, false); + ThreeD.createCurve = function (board, parents, attr) { + var view = parents[0], + D3, el; - attr = Type.copyAttributes(attributes, board.options, 'slopetriangle', 'label'); - label = board.create('text', [ - function () { return glider.X() + 0.1; }, - function () { return (glider.Y() + toppoint.Y()) * 0.5; }, - function () { return ''; } - ], attr); + D3 = { + elType: 'curve3D', + X: parents[1], + Y: parents[2], + Z: parents[3], + }; + D3.F = [D3.X, D3.Y, D3.Z]; - label._setText(function () { - return Type.toFixed(el.Value(), Type.evaluate(label.visProp.digits)); - }); - label.fullUpdate(); + el = board.create('curve', [[], []], attr); + el.D3 = D3; - el.glider = glider; - el.basepoint = basepoint; - el.baseline = baseline; - el.toppoint = toppoint; - el.label = label; + if (Type.isFunction(el.D3.X)) { + // 3D curve given as t -> [X(t), Y(t), Z(t)] - el.subs = { - glider: glider, - basePoint: basepoint, - baseLine: baseline, - topPoint: toppoint, - label: label - }; - el.inherits.push(glider, basepoint, baseline, toppoint, label); + el.D3.range = parents[4]; + el.updateDataArray = function () { + var steps = Type.evaluate(this.visProp.numberpointshigh), + s = Type.evaluate(this.D3.range[0]), + e = Type.evaluate(this.D3.range[1]), + delta = (e - s) / (steps - 1), + c2d, t, i, + p = [0, 0, 0]; - el.methodMap = JXG.deepCopy(el.methodMap, { - tangent: 'tangent', - glider: 'glider', - basepoint: 'basepoint', - baseline: 'baseline', - toppoint: 'toppoint', - label: 'label', - Value: 'Value', - V: 'Value' - }); + this.dataX = []; + this.dataY = []; - el.remove = priv.removeSlopeTriangle; + for (t = s; t <= e; t += delta) { + for (i = 0; i < 3; i++) { + p[i] = this.D3.F[i](t); + } + c2d = view.project3DTo2D(p); + this.dataX.push(c2d[1]); + this.dataY.push(c2d[2]); + } + }; + } else if (Type.isArray(el.D3.X)) { + // 3D curve given as array of 3D points - return el; - }; + el.updateDataArray = function () { + var i, + le = this.D3.X.length, + c2d; - JXG.registerElement('slopetriangle', JXG.createSlopeTriangle); + this.dataX = []; + this.dataY = []; - return { - createSlopeTriangle: JXG.createSlopeTriangle + for (i = 0; i < le; i++) { + c2d = view.project3DTo2D([this.D3.X[i], this.D3.Y[i], this.D3.Z[i]]); + this.dataX.push(c2d[1]); + this.dataY.push(c2d[2]); + } + }; + } + + return el; }; -}); + JXG.registerElement('curve3d', ThreeD.createCurve); +}); /* - Copyright 2008-2021 + Copyright 2008-2022 Matthias Ehmann, - Michael Gerhaeuser, Carsten Miller, - Bianca Valentin, - Alfred Wassermann, - Peter Wilfahrt + Andreas Walter, + Alfred Wassermann This file is part of JSXGraph. @@ -72268,194 +81473,359 @@ define('element/slopetriangle',[ the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> and <http://opensource.org/licenses/MIT/>. */ - - -/*global JXG: true, define: true, window: true*/ -/*jslint nomen: true, plusplus: true*/ - -/* depends: - jxg - utils/env - utils/type - */ +/*global JXG:true, define: true*/ /** - * @fileoverview In this file the Text element is defined. + * Create linear spaces of dimension at least one, + * i.e. lines and planes. */ - -define('element/checkbox',[ - 'jxg', 'utils/env', 'utils/type' -], function (JXG, Env, Type) { - +define('3d/linspace3d',['jxg', 'utils/type', 'math/math', 'math/geometry', '3d/view3d' +], function (JXG, Type, Mat, Geometry, ThreeD) { "use strict"; - var priv = { - CheckboxChangeEventHandler: function () { - this._value = this.rendNodeCheckbox.checked; - this.board.update(); - } - }; - /** - * @class This element is used to provide a constructor for special texts containing a - * form checkbox element. - * <p> - * For this element, the attribute "display" has to have the value 'html' (which is the default). - * + * @class This element is used to provide a constructor for a 3D line. * @pseudo - * @description - * @name Checkbox - * @augments Text - * @constructor - * @type JXG.Text - * - * @param {number,function_number,function_String_String} x,y,label Parent elements for checkbox elements. - * <p> - * x and y are the coordinates of the lower left corner of the text box. - * The position of the text is fixed, - * x and y are numbers. The position is variable if x or y are functions. - * <p> - * The label of the input element may be given as string. - * <p> - * The value of the checkbox can be controlled with the attribute <tt>checked</tt> - * <p>The HTML node can be accessed with <tt>element.rendNodeCheckbox</tt> - * - * @example - * // Create a checkbox element at position [0,3]. - * var checkbox = board.create('checkbox', [0, 3, 'Change Y'], {}); - * var p = board.create('point', [ - * function(){ return 0.5;}, // X-coordinate - * function() { - * y = 0.5; - * if (checkbox.Value()) { - * y += 0.5; - * } - * return y; - * }]); - * </pre><div class="jxgbox" id="JXG0e835e0b-ed0c-4b85-b682-78158c0e6f5c" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function() { - * var t1_board = JXG.JSXGraph.initBoard('JXG0e835e0b-ed0c-4b85-b682-78158c0e6f5c', {boundingbox: [-3, 6, 5, -3], axis: true, showcopyright: false, shownavigation: false}); - * var checkbox = t1_board.create('checkbox', [0, 3, 'Change Y'], {}); - * var p = t1_board.create('point', [ - * function(){ return 0.5;}, // X-coordinate - * function() { - * y = 0.5; - * if (checkbox.Value()) { - * y += 0.5; - * } - * return y; - * }]); - * })(); - * </script><pre> - * - * The checkbox can be supplied with custom-made events by using the property rendNodeCheckbox. - * @example - * var checkbox = board.create('checkbox', [0, 4, 'Click me']), - * p = board.create('point', [1, 1]); - * - * JXG.addEvent(checkbox.rendNodeCheckbox, 'change', function() { - * if (this.Value()) { - * p.moveTo([4, 1]); - * } else { - * p.moveTo([1, 1]); - * } - * }, checkbox); - * </pre><div class="jxgbox" id="JXGb2f2345a-057d-44ce-bd7a-6aaff70bc810" style="width: 300px; height: 300px;"></div> - * <script type="text/javascript"> - * (function() { - * var board = JXG.JSXGraph.initBoard('JXGb2f2345a-057d-44ce-bd7a-6aaff70bc810', {boundingbox: [-3, 6, 5, -3], axis: true, showcopyright: false, shownavigation: false}); - * var checkbox = board.create('checkbox', [0, 4, 'Click me']), - * p = board.create('point', [1, 1]); + * @description There are two possibilities to create a Line3D object. + * <p> + * First: the line in 3D is defined by two points in 3D (Point3D). + * The points can be either existing points or coordinate arrays of + * the form [x, y, z]. + * <p>Second: the line in 3D is defined by a point (or coordinate array [x, y, z]) + * a direction given as array [x, y, z] and an optional range + * given as array [s, e]. The default value for the range is [-Infinity, Infinity]. + * <p> + * All numbers can also be provided as functions returning a number. + * + * @name Line3D + * @augments JXG.Curve + * @constructor + * @type JXG.Curve + * @throws {Exception} If the element cannot be constructed with the given parent + * objects an exception is thrown. + * @param {JXG.Point_number,JXG.Point,JXG.Line,JXG.Circle} center,radius The center must be given as a {@link JXG.Point}, see {@link JXG.providePoints}, but the radius can be given + * as a number (which will create a circle with a fixed radius), another {@link JXG.Point}, a {@link JXG.Line} (the distance of start and end point of the + * line will determine the radius), or another {@link JXG.Circle}. * - * JXG.addEvent(checkbox.rendNodeCheckbox, 'change', function() { - * if (this.Value()) { - * p.moveTo([4, 1]); - * } else { - * p.moveTo([1, 1]); - * } - * }, checkbox); - * })(); - * </script><pre> */ - JXG.createCheckbox = function (board, parents, attributes) { - var t, par, - attr = Type.copyAttributes(attributes, board.options, 'checkbox'); + ThreeD.createLine = function (board, parents, attributes) { + var view = parents[0], + attr, D3, point, point1, point2, + el; + + // Range + D3 = { + elType: 'line3d', + range: parents[3] || [-Infinity, Infinity] + }; - //if (parents.length !== 3) { - //throw new Error("JSXGraph: Can't create checkbox with parent types '" + - // (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + - // "\nPossible parents are: [[x,y], label]"); - //} + // Point + if (Type.isPoint(parents[1])) { + point = parents[1]; + } else { + point = view.create('point3d', parents[1], { visible: false, name: '', withLabel: false }); + } + D3.point = point; - par = [parents[0], parents[1], - '<span style="display:inline">' + - '<input type="checkbox" /><label for=""></label>' + - '</span>' - ]; + // Direction + if (Type.isPoint(parents[2]) && Type.exists(parents[2].D3)) { + // Line defined by two points - //t = JXG.createText(board, par, attr); - t = board.create('text', par, attr); - t.type = Type.OBJECT_TYPE_CHECKBOX; + point1 = point; + point2 = parents[2]; + D3.direction = function () { + return [ + point2.D3.X() - point.D3.X(), + point2.D3.Y() - point.D3.Y(), + point2.D3.Z() - point.D3.Z() + ]; + }; + D3.range = [0, 1]; + } else { + // Line defined by point, direction and range + + // Directions are handled as arrays of length 4, + // i.e. with homogeneous coordinates. + if (Type.isFunction(parents[2])) { + D3.direction = parents[2]; + } else if (parents[2].length === 3) { + D3.direction = [1].concat(parents[2]); + } else if (parents[2].length === 4) { + D3.direction = parents[2]; + } else { + // Throw error + } - t.rendNodeCheckbox = t.rendNode.childNodes[0].childNodes[0]; - t.rendNodeLabel = t.rendNode.childNodes[0].childNodes[1]; + // Direction given as array + D3.getPointCoords = function (r) { + var p = [], + d = [], + i; - t.rendNodeTag = t.rendNodeCheckbox; // Needed for unified treatment in setAttribute - t.rendNodeTag.disabled = !!attr.disabled; + p.push(point.D3.X()); + p.push(point.D3.Y()); + p.push(point.D3.Z()); - t.rendNodeLabel.innerHTML = parents[2]; - t.rendNodeCheckbox.id = t.rendNode.id + '_checkbox'; - t.rendNodeLabel.id = t.rendNode.id + '_label'; - t.rendNodeLabel.setAttribute('for', t.rendNodeCheckbox.id); + if (Type.isFunction(D3.direction)) { + d = D3.direction(); + } else { + for (i = 1; i < 4; i++) { + d.push(Type.evaluate(D3.direction[i])); + } + } + if (Math.abs(r) === Infinity) { + r = view.intersectionLineCube(p, d, r); + } + return [ + p[0] + d[0] * r, + p[1] + d[1] * r, + p[2] + d[2] * r + ]; - // This sets the font-size of the checkbox itself - t.visPropOld.fontsize = "0px"; - board.renderer.updateTextStyle(t, false); + }; - t.rendNodeCheckbox.checked = attr.checked; + attr = Type.copyAttributes(attributes, board.options, 'line3d', 'point1'); + point1 = view.create('point3d', [ + function () { + return D3.getPointCoords(Type.evaluate(D3.range[0])); + } + ], attr); + attr = Type.copyAttributes(attributes, board.options, 'line3d', 'point2'); + point2 = view.create('point3d', [ + function () { + return D3.getPointCoords(Type.evaluate(D3.range[1])); + } + ], attr); + } - t._value = attr.checked; + attr = Type.copyAttributes(attributes, board.options, 'line3d'); + el = view.create('segment', [point1, point2], attr); + el.point1 = point1; + el.point2 = point2; + point1.addChild(el); + point2.addChild(el); + el.D3 = D3; - /** - * Returns the value of the checkbox element - * @name Value - * @memberOf Checkbox.prototype - * @function - * @returns {String} value of the checkbox. - */ - t.Value = function () { - return this._value; + return el; + }; + JXG.registerElement('line3d', ThreeD.createLine); + + ThreeD.createPlane = function (board, parents, attributes) { + var view = parents[0], + attr, D3, + point, + vec1 = parents[2], + vec2 = parents[3], + el, grid, update; + + // D3: { + // point, + // vec1, + // vec2, + // poin1, + // point2, + // normal array of len 3 + // d + // } + D3 = { + elType: 'plane3d', + dir1: [], + dir2: [], + range1: parents[4], + range2: parents[5], + vec1: vec1, + vec2: vec2 }; - t.update = function () { - if (this.needsUpdate) { - JXG.Text.prototype.update.call(this); - this._value = this.rendNodeCheckbox.checked; + if (Type.isPoint(parents[1])) { + point = parents[1]; + } else { + point = view.create('point3d', parents[1], { visible: false, name: '', withLabel: false }); + } + D3.point = point; + + D3.updateNormal = function () { + var i; + for (i = 0; i < 3; i++) { + D3.dir1[i] = Type.evaluate(D3.vec1[i]); + D3.dir2[i] = Type.evaluate(D3.vec2[i]); } - return this; + D3.normal = Mat.crossProduct(D3.dir1, D3.dir2); + D3.d = Mat.innerProduct(D3.point.D3.coords.slice(1), D3.normal, 3); }; + D3.updateNormal(); - Env.addEvent(t.rendNodeCheckbox, 'change', priv.CheckboxChangeEventHandler, t); + attr = Type.copyAttributes(attributes, board.options, 'plane3d'); + el = board.create('curve', [[], []], attr); + el.D3 = D3; - return t; - }; + el.updateDataArray = function () { + var s1, e1, s2, e2, + c2d, l1, l2, + planes = ['xPlaneRear', 'yPlaneRear', 'zPlaneRear'], + points = [], + v1 = [0, 0, 0], + v2 = [0, 0, 0], + q = [0, 0, 0], + p = [0, 0, 0], d, i, j, a, b, first, pos, pos_akt; - JXG.registerElement('checkbox', JXG.createCheckbox); + this.dataX = []; + this.dataY = []; - return { - createCheckbox: JXG.createCheckbox + this.D3.updateNormal(); + + // Infinite plane + if (this.D3.elType !== 'axisplane3d' && view.defaultAxes && + (!D3.range1 || !D3.range2) + ) { + + // Start with the rear plane. + // Determine the intersections with the view bbox3d + // For each face of the bbox3d we determine two points + // which are the ends of the intersection line. + // We start with the three rear planes. + for (j = 0; j < planes.length; j++) { + p = view.intersectionPlanePlane(this, view.defaultAxes[planes[j]]); + + if (p[0].length === 3 && p[1].length === 3) { + // This test is necessary to filter out intersection lines which are + // identical to intersections of axis planes (they would occur twice). + for (i = 0; i < points.length; i++) { + if ((Geometry.distance(p[0], points[i][0], 3) < Mat.eps && Geometry.distance(p[1], points[i][1], 3) < Mat.eps) || + (Geometry.distance(p[0], points[i][1], 3) < Mat.eps && Geometry.distance(p[1], points[i][0], 3) < Mat.eps)) { + break; + } + } + if (i === points.length) { + points.push(p.slice()); + } + } + + // Point on the front plane of the bbox3d + p = [0, 0, 0]; + p[j] = view.D3.bbox3d[j][1]; + + // d is the rhs of the Hesse normal form of the front plane. + d = Mat.innerProduct(p, view.defaultAxes[planes[j]].D3.normal, 3); + p = view.intersectionPlanePlane(this, view.defaultAxes[planes[j]], d); + + if (p[0].length === 3 && p[1].length === 3) { + // Do the same test as above + for (i = 0; i < points.length; i++) { + if ((Geometry.distance(p[0], points[i][0], 3) < Mat.eps && Geometry.distance(p[1], points[i][1], 3) < Mat.eps) || + (Geometry.distance(p[0], points[i][1], 3) < Mat.eps && Geometry.distance(p[1], points[i][0], 3) < Mat.eps)) { + break; + } + } + if (i === points.length) { + points.push(p.slice()); + } + } + } + + // Concatenate the intersection points to a polygon. + // If all wents well, each intersection should appear + // twice in the list. + first = 0; + pos = first; + i = 0; + do { + p = points[pos][i]; + if (p.length === 3) { + c2d = view.project3DTo2D(p); + this.dataX.push(c2d[1]); + this.dataY.push(c2d[2]); + } + i = (i + 1) % 2; + p = points[pos][i]; + + pos_akt = pos; + for (j = 0; j < points.length; j++) { + if (j !== pos && Geometry.distance(p, points[j][0]) < Mat.eps) { + pos = j; + i = 0; + break; + } + if (j !== pos && Geometry.distance(p, points[j][1]) < Mat.eps) { + pos = j; + i = 1; + break; + } + } + if (pos === pos_akt) { + console.log("Error: update plane3d: did not find next", pos); + break; + } + } while (pos !== first); + c2d = view.project3DTo2D(points[first][0]); + this.dataX.push(c2d[1]); + this.dataY.push(c2d[2]); + + } else { + // 3D bounded flat + s1 = Type.evaluate(this.D3.range1[0]); + e1 = Type.evaluate(this.D3.range1[1]); + s2 = Type.evaluate(this.D3.range2[0]); + e2 = Type.evaluate(this.D3.range2[1]); + + q = this.D3.point.D3.coords.slice(1); + + v1 = this.D3.dir1.slice(); + v2 = this.D3.dir2.slice(); + l1 = Mat.norm(v1, 3); + l2 = Mat.norm(v2, 3); + for (i = 0; i < 3; i++) { + v1[i] /= l1; + v2[i] /= l2; + } + + for (j = 0; j < 4; j++) { + switch (j) { + case 0: a = s1; b = s2; break; + case 1: a = e1; b = s2; break; + case 2: a = e1; b = e2; break; + case 3: a = s1; b = e2; + } + for (i = 0; i < 3; i++) { + p[i] = q[i] + a * v1[i] + b * v2[i]; + } + c2d = view.project3DTo2D(p); + this.dataX.push(c2d[1]); + this.dataY.push(c2d[2]); + } + // Close the curve + this.dataX.push(this.dataX[0]); + this.dataY.push(this.dataY[0]); + } + }; + + attr = Type.copyAttributes(attributes.mesh3d, board.options, 'mesh3d'); + + if (D3.range1 && D3.range2) { + grid = view.create('mesh3d', [point.D3.coords.slice(1), vec1, D3.range1, vec2, D3.range2], attr); + el.grid = grid; + el.inherits.push(grid); + } + + // update = el.update; + // el.update = function () { + // if (el.needsUpdate) { + // update.apply(el); + // } + // return this; + // }; + + return el; }; -}); + JXG.registerElement('plane3d', ThreeD.createPlane); +}); /* - Copyright 2008-2021 + Copyright 2008-2022 Matthias Ehmann, - Michael Gerhaeuser, Carsten Miller, - Bianca Valentin, - Alfred Wassermann, - Peter Wilfahrt + Andreas Walter, + Alfred Wassermann This file is part of JSXGraph. @@ -72478,192 +81848,184 @@ define('element/checkbox',[ the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> and <http://opensource.org/licenses/MIT/>. */ +/*global JXG:true, define: true*/ - -/*global JXG: true, define: true, window: true*/ -/*jslint nomen: true, plusplus: true*/ - -/* depends: - jxg - utils/env - utils/type - */ - -/** - * @fileoverview In this file the Text element is defined. - */ - -define('element/input',[ - 'jxg', 'utils/env', 'utils/type' -], function (JXG, Env, Type) { - +define('3d/point3d',['jxg', 'base/constants', 'math/math', 'math/geometry', 'utils/type', '3d/view3d' +], function (JXG, Const, Mat, Geometry, Type, ThreeD) { "use strict"; - var priv = { - InputInputEventHandler: function (evt) { - this._value = this.rendNodeInput.value; - this.board.update(); - } - }; - /** - * @class This element is used to provide a constructor for special texts containing a - * HTML form input element. + * @class This element is used to provide a constructor for a 3D Point. + * @pseudo + * @description There are two possibilities to create a Line3D object. * <p> - * If the width of element is set with the attribute "cssStyle", the width of the - * label must be added. + * First: the line in 3D is defined by two points in 3D (Point3D). + * The points can be either existing points or coordinate arrays of + * the form [x, y, z]. + * <p>Second: the line in 3D is defined by a point (or coordinate array [x, y, z]) + * a direction given as array [x, y, z] and an optional range + * given as array [s, e]. The default value for the range is [-Infinity, Infinity]. * <p> - * For this element, the attribute "display" has to have the value 'html' (which is the default). - * @pseudo - * @description - * @name Input - * @augments Text - * @constructor - * @type JXG.Text - * - * @param {number,function_number,function_String_String} x,y,value,label Parent elements for input elements. - * <p> - * x and y are the coordinates of the lower left corner of the text box. The position of the text is fixed, - * x and y are numbers. The position is variable if x or y are functions. - * <p> - * The default value of the input element may be given as string. - * <p> - * The label of the input element may be given as string. - * - * @example - * // Create an input element at position [1,4]. - * var input = board.create('input', [0, 1, 'sin(x)*x', 'f(x)='], {cssStyle: 'width: 100px'}); - * var f = board.jc.snippet(input.Value(), true, 'x', false); - * var graph = board.create('functiongraph',[f, - * function() { - * var c = new JXG.Coords(JXG.COORDS_BY_SCREEN,[0,0],board); - * return c.usrCoords[1]; - * }, - * function() { - * var c = new JXG.Coords(JXG.COORDS_BY_SCREEN,[board.canvasWidth,0],board); - * return c.usrCoords[1]; - * } - * ]); - * - * board.create('text', [1, 3, '<button onclick="updateGraph()">Update graph</button>']); - * - * var updateGraph = function() { - * graph.Y = board.jc.snippet(input.Value(), true, 'x', false); - * graph.updateCurve(); - * board.update(); - * } - * </pre><div class="jxgbox" id="JXGc70f55f1-21ba-4719-a37d-a93ae2943faa" style="width: 500px; height: 300px;"></div> - * <script type="text/javascript"> - * var t1_board = JXG.JSXGraph.initBoard('JXGc70f55f1-21ba-4719-a37d-a93ae2943faa', {boundingbox: [-3, 6, 5, -3], axis: true, showcopyright: false, shownavigation: false}); - * var input = t1_board.create('input', [1, 4, 'sin(x)*x', 'f(x)='], {cssStyle: 'width: 100px'}); - * var f = t1_board.jc.snippet(input.Value(), true, 'x', false); - * var graph = t1_board.create('functiongraph',[f, - * function() { - * var c = new JXG.Coords(JXG.COORDS_BY_SCREEN,[0,0],t1_board); - * return c.usrCoords[1]; - * }, - * function() { - * var c = new JXG.Coords(JXG.COORDS_BY_SCREEN,[t1_board.canvasWidth,0],t1_board); - * return c.usrCoords[1]; - * } - * ]); + * All numbers can also be provided as functions returning a number. * - * t1_board.create('text', [1, 3, '<button onclick="updateGraph()">Update graph</button>']); + * @name Point3D + * @augments JXG.Point + * @constructor + * @type JXG.Point + * @throws {Exception} If the element cannot be constructed with the given parent + * objects an exception is thrown. + * @param {JXG.Point_number,JXG.Point,JXG.Line,JXG.Circle} center,radius The center must be given as a {@link JXG.Point}, see {@link JXG.providePoints}, but the radius can be given + * as a number (which will create a circle with a fixed radius), another {@link JXG.Point}, a {@link JXG.Line} (the distance of start and end point of the + * line will determine the radius), or another {@link JXG.Circle}. * - * var updateGraph = function() { - * graph.Y = t1_board.jc.snippet(input.Value(), true, 'x', false); - * graph.updateCurve(); - * t1_board.update(); - * } - * </script><pre> */ - JXG.createInput = function (board, parents, attributes) { - var t, par, - attr = Type.copyAttributes(attributes, board.options, 'input'); - - par = [parents[0], parents[1], - '<span style="display:inline; white-space:nowrap; padding:0px;">' + - '<span></span><input type="text" maxlength="' + - attr.maxlength + - '" style="width:100%"/>' + - '</span>' - ]; - - //t = JXG.createText(board, par, attr); - t = board.create('text', par, attr); - t.type = Type.OBJECT_TYPE_INPUT; + ThreeD.createPoint = function (board, parents, attributes) { + var view = parents[0], + attr, update2D, D3, + i, c2d, + el; + + attr = Type.copyAttributes(attributes, board.options, 'point3d'); + + D3 = { + elType: 'point3d', + coords: [1, 0, 0, 0], + X: function () { return this.coords[1]; }, + Y: function () { return this.coords[2]; }, + Z: function () { return this.coords[3]; } + }; - t.rendNodeLabel = t.rendNode.childNodes[0].childNodes[0]; - t.rendNodeInput = t.rendNode.childNodes[0].childNodes[1]; - t.rendNodeLabel.innerHTML = parents[3]; - t.rendNodeInput.value = parents[2]; - t.rendNodeTag = t.rendNodeInput; // Needed for unified treatment in setAttribute - t.rendNodeTag.disabled = !!attr.disabled; - t.rendNodeLabel.id = t.rendNode.id + '_label'; - t.rendNodeInput.id = t.rendNode.id + '_input'; + // If the last element of partents is a 3D object, the point is a glider + // on that element. + if (parents.length > 2 && Type.exists(parents[parents.length - 1].D3)) { + D3.slide = parents.pop(); + } else { + D3.slide = null; + } - t._value = parents[2]; - t.update = function () { - if (this.needsUpdate) { - JXG.Text.prototype.update.call(this); - this._value = this.rendNodeInput.value; + if (parents.length === 2) { + D3.F = parents[1]; // (Array [x, y, z] | function) returning [x, y, z] + D3.coords = [1].concat(Type.evaluate(D3.F)); + } else if (parents.length === 4) { + D3.F = parents.slice(1); // 3 numbers | functions + for (i = 0; i < 3; i++) { + D3.coords[i + 1] = Type.evaluate(D3.F[i]); } - return this; - }; + } else { + // Throw error + } /** - * Returns the value (content) of the input element - * @name Value - * @memberOf Input.prototype - * @function - * @returns {String} content of the input field. - */ - t.Value = function () { - return this._value; - }; - /** - * Sets value of the input element. - * @name set - * @memberOf Input.prototype - * @function - * - * @param {String} val - * @returns {JXG.GeometryElement} Reference to the element. - * + * Update the 4D coords array + * @returns Object */ - t.set = function (val) { - this._value = val; - this.rendNodeInput.value = val; + D3.updateCoords = function () { + var res, i; + if (Type.isFunction(this.F)) { + res = Type.evaluate(this.F); + this.coords = [1, res[0], res[1], res[2]]; + } else { + this.coords[0] = 1; + for (i = 0; i < 3; i++) { + if (Type.isFunction(this.F[i])) { + this.coords[i + 1] = Type.evaluate(this.F[i]); + } + } + } return this; }; + D3.updateCoords(); - Env.addEvent(t.rendNodeInput, 'input', priv.InputInputEventHandler, t); - Env.addEvent(t.rendNodeInput, 'mousedown', function(evt) { if (Type.exists(evt.stopPropagation)) { evt.stopPropagation(); } }, t); - Env.addEvent(t.rendNodeInput, 'touchstart', function(evt) { if (Type.exists(evt.stopPropagation)) { evt.stopPropagation(); } }, t); - Env.addEvent(t.rendNodeInput, 'pointerdown', function(evt) { if (Type.exists(evt.stopPropagation)) { evt.stopPropagation(); } }, t); + c2d = view.project3DTo2D(D3.coords); + el = board.create('point', c2d, attr); + el.D3 = D3; + el.D3.c2d = el.coords.usrCoords.slice(); // Copy of the coordinates to detect dragging + update2D = el.update; - // This sets the font-size of the input HTML element - t.visPropOld.fontsize = "0px"; - board.renderer.updateTextStyle(t, false); + if (el.D3.slide) { + el._minFunc = function (n, m, x, con) { + var surface = el.D3.slide.D3, + c3d = [1, surface.X(x[0], x[1]), surface.Y(x[0], x[1]), surface.Z(x[0], x[1])], + c2d = view.project3DTo2D(c3d); - return t; - }; + con[0] = el.X() - c2d[1]; + con[1] = el.Y() - c2d[2]; - JXG.registerElement('input', JXG.createInput); + return con[0] * con[0] + con[1] * con[1]; + }; - return { - createInput: JXG.createInput + el.projectCoords2Surface = function () { + var n = 2, // # of variables + m = 2, // number of constraints + x = [0, 0], + // Various Cobyla constants, see Cobyla docs in Cobyja.js + rhobeg = 5.0, + rhoend = 1.0e-6, + iprint = 0, + maxfun = 200, + surface = this.D3.slide.D3, + r, c3d, c2d; + + if (Type.exists(this.D3.params)) { + x = this.D3.params.slice(); + } + r = Mat.Nlp.FindMinimum(this._minFunc, n, m, x, rhobeg, rhoend, iprint, maxfun); + + c3d = [1, surface.X(x[0], x[1]), surface.Y(x[0], x[1]), surface.Z(x[0], x[1])]; + c2d = view.project3DTo2D(c3d); + this.D3.params = x; + this.D3.coords = c3d; + this.coords.setCoordinates(Const.COORDS_BY_USER, c2d); + this.D3.c2d = c2d; + }; + } + + el.update = function (drag) { + var c3d, foot; + if (!this.needsUpdate) { + return this; + } + + // Update is called in from two methods: + // Once in setToPositionDirectly and + // once in the subsequent board.update + if (this.draggable() && + Geometry.distance(this.D3.c2d, this.coords.usrCoords) !== 0) { + + if (this.D3.slide) { + this.projectCoords2Surface(); + } else { + // Drag the point in its xy plane + foot = [1, 0, 0, this.D3.coords[3]]; + c3d = view.project2DTo3DPlane(el, [1, 0, 0, 1], foot); + if (c3d[0] !== 0) { + this.D3.coords = view.project3DToCube(c3d); + } + } + } else { + this.D3.updateCoords(); + // Update 2D point from its 3D view + el.coords.setCoordinates(Const.COORDS_BY_USER, + view.project3DTo2D([1, this.D3.X(), this.D3.Y(), this.D3.Z()]) + ); + } + this.D3.c2d = el.coords.usrCoords.slice(); + + update2D.apply(this, [drag]); + return this; + }; + + return el; }; -}); + JXG.registerElement('point3d', ThreeD.createPoint); +}); /* - Copyright 2008-2021 + Copyright 2008-2022 Matthias Ehmann, - Michael Gerhaeuser, Carsten Miller, - Bianca Valentin, - Alfred Wassermann, - Peter Wilfahrt + Andreas Walter, + Alfred Wassermann This file is part of JSXGraph. @@ -72686,142 +82048,197 @@ define('element/input',[ the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/> and <http://opensource.org/licenses/MIT/>. */ +/*global JXG:true, define: true*/ - -/*global JXG: true, define: true, window: true*/ -/*jslint nomen: true, plusplus: true*/ - -/* depends: - jxg - utils/env - utils/type - */ - -/** - * @fileoverview In this file the Text element is defined. - */ - -define('element/button',[ - 'jxg', 'utils/env', 'utils/type' -], function (JXG, Env, Type) { - +define('3d/surface3d',['jxg', 'utils/type', '3d/view3d' +], function (JXG, Type, ThreeD) { "use strict"; - var priv = { - ButtonClickEventHandler: function () { - if (this._handler) { - this._handler(); - } - this.board.update(); - } - }; /** - * @class This element is used to provide a constructor for special texts containing a - * form button element. - * <p> - * For this element, the attribute "display" has to have the value 'html' (which is the default). - * + * @class This element creates a 3D parametric surface. * @pseudo - * @description - * @name Button - * @augments Text + * @description A 3D parametric surface is defined by a function + * <i>F: R<sup>2</sup> → R<sup>3</sup></i>. + * + * @name ParametricSurface3D + * @augments Curve * @constructor - * @type JXG.Text + * @type Object + * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {Function_Function_Function_Array_Array} F<sub>X</sub>,F<sub>Y</sub>,F<sub>Z</sub>,rangeX,rangeY + * F<sub>X</sub>(u,v), F<sub>Y</sub>(u,v), F<sub>Z</sub>(u,v) are functions returning a number, rangeU is the array containing + * lower and upper bound for the range of parameter u, rangeV is the array containing + * lower and upper bound for the range of parameter v. rangeU and rangeV may also be functions returning an array of length two. + * @example + * var view = board.create('view3d', + * [[-6, -3], [8, 8], + * [[-5, 5], [-5, 5], [-5, 5]]]); * - * @param {number,function_number,function_String_function} x,y,label,handler Parent elements for button elements. - * <p> - * x and y are the coordinates of the lower left corner of the text box. - * The position of the text is fixed, - * x and y are numbers. The position is variable if x or y are functions. - * <p> - * The label of the input element may be given as string. - * <p> - * The (optional) handler function which is called when the button is pressed. + * // Sphere + * var c = view.create('parametricsurface3d', [ + * (u, v) => 2 * Math.sin(u) * Math.cos(v), + * (u, v) => 2 * Math.sin(u) * Math.sin(v), + * (u, v) => 2 * Math.cos(u), + * [0, 2 * Math.PI], + * [0, Math.PI] + * ], { + * strokeColor: '#ff0000', + * stepsU: 30, + * stepsV: 30 + * }); + * + * </pre><div id="JXG52da0ecc-1ba9-4d41-850c-36e5120025a5" class="jxgbox" style="width: 500px; height: 500px;"></div> + * <script type="text/javascript"> + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG52da0ecc-1ba9-4d41-850c-36e5120025a5', + * {boundingbox: [-8, 8, 8,-8], axis: false, showcopyright: false, shownavigation: false}); + * var view = board.create('view3d', + * [[-6, -3], [8, 8], + * [[-5, 5], [-5, 5], [-5, 5]]]); + * + * // Sphere + * var c = view.create('parametricsurface3d', [ + * (u, v) => 2 * Math.sin(u) * Math.cos(v), + * (u, v) => 2 * Math.sin(u) * Math.sin(v), + * (u, v) => 2 * Math.cos(u), + * [0, 2 * Math.PI], + * [0, Math.PI] + * ], { + * strokeColor: '#ff0000', + * stepsU: 20, + * stepsV: 20 + * }); + * + * })(); + * + * </script><pre> + * + */ + ThreeD.createParametricSurface = function (board, parents, attributes) { + var view = parents[0], + attr, + X = parents[1], + Y = parents[2], + Z = parents[3], + range_u = parents[4], + range_v = parents[5], + D3, el; + + D3 = { + elType: 'surface3d', + X: X, + Y: Y, + Z: Z, + range_u: range_u, + range_v: range_v + }; + attr = Type.copyAttributes(attributes, board.options, 'surface3d'); + el = board.create('curve', [[], []], attr); + el.updateDataArray = function () { + var steps_u = Type.evaluate(this.visProp.stepsu), + steps_v = Type.evaluate(this.visProp.stepsv), + r_u = Type.evaluate(this.D3.range_u), // Type.evaluate(range_u), + r_v = Type.evaluate(this.D3.range_v), // Type.evaluate(range_v), + res = view.getMesh(this.D3.X, this.D3.Y, this.D3.Z, + r_u.concat([steps_u]), + r_v.concat([steps_v])); + this.dataX = res[0]; + this.dataY = res[1]; + }; + el.D3 = D3; + + return el; + }; + JXG.registerElement('parametricsurface3d', ThreeD.createParametricSurface); + + /** + * @class This element creates a 3D function graph. + * @pseudo + * @description A 3D function graph is defined by a function + * <i>F: R<sup>2</sup> → R</i>. * + * @name Functiongraph3D + * @augments ParametricSurface3D + * @constructor + * @type Object + * @throws {Exception} If the element cannot be constructed with the given parent objects an exception is thrown. + * @param {Function_Array_Array} F,rangeX,rangeY F(x,y) is a function returning a number, rangeX is the array containing + * lower and upper bound for the range of x, rangeY is the array containing + * lower and upper bound for the range of y. * @example - * var p = board.create('point', [0.5, 0.5], {id: 'p1'}); + * var box = [-5, 5]; + * var view = board.create('view3d', + * [ + * [-6, -3], [8, 8], + * [box, box, box] + * ], + * { + * xPlaneRear: {visible: false}, + * yPlaneRear: {visible: false}, + * }); * - * // Create a button element at position [1,2]. - * var button1 = board.create('button', [1, 2, 'Change Y with JavaScript', function() { - * p.moveTo([p.X(), p.Y() + 0.5], 100); - * }], {}); + * // Function F to be plotted + * var F = (x, y) => Math.sin(x * y / 4); * - * // Create a button element at position [1,4]. - * var button2 = board.create('button', [1, 4, 'Change Y with JessieCode', - * "$('p1').Y = $('p1').Y() - 0.5;" - * ], {}); + * // 3D surface + * var c = view.create('functiongraph3d', [ + * F, + * box, // () => [-s.Value()*5, s.Value() * 5], + * box, // () => [-s.Value()*5, s.Value() * 5], + * ], { + * strokeWidth: 0.5, + * stepsU: 70, + * stepsV: 70 + * }); * - * </pre><div class="jxgbox" id="JXGf19b1bce-dd00-4e35-be97-ff1817d11514" style="width: 500px; height: 300px;"></div> + * </pre><div id="JXG87646dd4-9fe5-4c21-8734-089abc612515" class="jxgbox" style="width: 500px; height: 500px;"></div> * <script type="text/javascript"> - * var t1_board = JXG.JSXGraph.initBoard('JXGf19b1bce-dd00-4e35-be97-ff1817d11514', {boundingbox: [-3, 6, 5, -3], axis: true, showcopyright: false, shownavigation: false}); - * var p = t1_board.create('point', [0, -1], {id: 'p1'}); + * (function() { + * var board = JXG.JSXGraph.initBoard('JXG87646dd4-9fe5-4c21-8734-089abc612515', + * {boundingbox: [-8, 8, 8,-8], axis: false, showcopyright: false, shownavigation: false}); + * var box = [-5, 5]; + * var view = board.create('view3d', + * [ + * [-6, -3], [8, 8], + * [box, box, box] + * ], + * { + * xPlaneRear: {visible: false}, + * yPlaneRear: {visible: false}, + * }); * - * // Create a button element at position [1,2]. - * var button1 = t1_board.create('button', [1, 2, 'Change Y with JavaScript', function() { - * p.moveTo([p.X(), p.Y() + 0.5], 100); - * }], {}); + * // Function F to be plotted + * var F = (x, y) => Math.sin(x * y / 4); * - * // Create a button element at position [1,4]. - * var button2 = t1_board.create('button', [1, 4, 'Change Y with JessieCode', - * "$('p1').Y = $('p1').Y() - 0.5;" - * ], {}); + * // 3D surface + * var c = view.create('functiongraph3d', [ + * F, + * box, // () => [-s.Value()*5, s.Value() * 5], + * box, // () => [-s.Value()*5, s.Value() * 5], + * ], { + * strokeWidth: 0.5, + * stepsU: 70, + * stepsV: 70 + * }); + * + * })(); * * </script><pre> - * [x, y, label, handler] + * */ - JXG.createButton = function (board, parents, attributes) { - var t, par, - attr = Type.copyAttributes(attributes, board.options, 'button'); - - //if (parents.length < 3) { - //throw new Error("JSXGraph: Can't create button with parent types '" + - // (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + - // "\nPossible parents are: [x, y, label, handler]"); - //} - - par = [parents[0], parents[1], '<button type="button" style="width:100%;"></button>']; - - t = board.create('text', par, attr); - t.type = Type.OBJECT_TYPE_BUTTON; - - t.rendNodeButton = t.rendNode.childNodes[0]; - t.rendNodeButton.id = t.rendNode.id + '_button'; - t.rendNodeButton.innerHTML = parents[2]; - - t.rendNodeTag = t.rendNodeButton; // Needed for unified treatment in setAttribute - t.rendNodeTag.disabled = !!attr.disabled; - - // This sets the font-size of the button text - t.visPropOld.fontsize = "0px"; - board.renderer.updateTextStyle(t, false); - - if (parents[3]) { - if (Type.isString(parents[3])) { - t._jc = new JXG.JessieCode(); - t._jc.use(board); - t._handler = function () { - t._jc.parse(parents[3]); - }; - } else { - t._handler = parents[3]; - } - } - - Env.addEvent(t.rendNodeButton, 'click', priv.ButtonClickEventHandler, t); - - Env.addEvent(t.rendNodeButton, 'mousedown', function (evt) { if (Type.exists(evt.stopPropagation)) { evt.stopPropagation(); } }, t); - Env.addEvent(t.rendNodeButton, 'touchstart', function (evt) { if (Type.exists(evt.stopPropagation)) { evt.stopPropagation(); } }, t); - Env.addEvent(t.rendNodeButton, 'pointerdown', function (evt) { if (Type.exists(evt.stopPropagation)) { evt.stopPropagation(); } }, t); - - return t; + ThreeD.createFunctiongraph = function (board, parents, attributes) { + var view = parents[0], + X = function(u, v) { return u; }, + Y = function(u, v) { return v; }, + Z = parents[1], + range_u = parents[2], + range_v = parents[3]; + + return view.create('parametricsurface3d', [X, Y, Z, range_u, range_v], attributes); }; + JXG.registerElement('functiongraph3d', ThreeD.createFunctiongraph); - JXG.registerElement('button', JXG.createButton); - - return { - createButton: JXG.createButton - }; }); /*global define: true*/ @@ -72834,10 +82251,12 @@ define('../build/core.deps.js',[ 'utils/event', 'utils/expect', 'math/math', + 'math/probfuncs', 'math/ia', 'math/extrapolate', 'math/qdt', 'math/numerics', + 'math/nlp', 'math/plot', 'math/metapost', 'math/statistics', @@ -72893,7 +82312,16 @@ define('../build/core.deps.js',[ 'element/slopetriangle', 'element/checkbox', 'element/input', - 'element/button' + 'element/button', + 'base/foreignobject', + 'options3d', + '3d/box3d', + '3d/curve3d', + '3d/linspace3d', + '3d/point3d', + '3d/surface3d', + '3d/threed', + '3d/view3d' ], function (JXG, Env) { "use strict"; diff --git a/backup/moodle2/backup_qtype_stack_plugin.class.php b/backup/moodle2/backup_qtype_stack_plugin.class.php index 0bb25ba50..cf7a491fc 100644 --- a/backup/moodle2/backup_qtype_stack_plugin.class.php +++ b/backup/moodle2/backup_qtype_stack_plugin.class.php @@ -21,10 +21,6 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ - -defined('MOODLE_INTERNAL') || die(); - - /** * Provides the information to backup STACK questions * diff --git a/classes/privacy/provider.php b/classes/privacy/provider.php index b2db6b4b0..804089f34 100644 --- a/classes/privacy/provider.php +++ b/classes/privacy/provider.php @@ -21,7 +21,6 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace qtype_stack\privacy; -defined('MOODLE_INTERNAL') || die(); /** * Privacy Subsystem for qtype_stack implementing null_provider. * diff --git a/cli/ast_test_generator.php b/cli/ast_test_generator.php index f03642531..7caefb33b 100644 --- a/cli/ast_test_generator.php +++ b/cli/ast_test_generator.php @@ -186,6 +186,12 @@ foreach ($filters as $key => $filter) { // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_ast_testcase; +use stack_cas_security; +use stack_parsing_rule_factory; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../tests/fixtures/ast_filter_test_base.php'); diff --git a/doc/en/Developer/Development_history.md b/doc/en/Developer/Development_history.md index e29176b7e..c97314d05 100644 --- a/doc/en/Developer/Development_history.md +++ b/doc/en/Developer/Development_history.md @@ -2,6 +2,13 @@ For current and future plans, see [Development track](Development_track.md) and [Future plans](Future_plans.md). +## Version 4.3.11 + +Released June 2022. + +1. This release contains an update of JSXGraph (in advance of the forthcoming 4.4 release) to facilitate immediate materials development. +2. Adopt moodle-ci. + ## Version 4.3.10 Released December 2021. diff --git a/doc/en/Developer/Development_track.md b/doc/en/Developer/Development_track.md index 0c6ce93df..caef291e4 100644 --- a/doc/en/Developer/Development_track.md +++ b/doc/en/Developer/Development_track.md @@ -5,8 +5,6 @@ past development history is documented on [Development history](Development_hist How to report bugs and make suggestions is described on the [community](../About/Community.md) page. -## Version 4.3.11 - ## Version 4.4 1. Caching validation. diff --git a/doc/en/Developer/Future_plans.md b/doc/en/Developer/Future_plans.md index 16065079c..b80b76aae 100644 --- a/doc/en/Developer/Future_plans.md +++ b/doc/en/Developer/Future_plans.md @@ -48,6 +48,12 @@ Note, where the feature is listed as "(done)" means we have prototype code in th * Decimal separator, both input and output. * Check CAS/maxima literature on -inf=minf. +* add in support for pdf_binomial, in particular add in these test cases to `studentinput_test.php`. + + array('pdf_binomial(n,m,p)', 'php_true', 'pdf_binomial(n,m,p)', 'cas_true', '{{m}\choose{n}}\cdot p^{n}\cdot {\left(1-p\right)}^{m-n}', '', ""), + array('pdf_binomial(2,6,0.07)', 'php_true', 'pdf_binomial(6,2,0.07)', 'cas_true', '{{6}\choose{2}}\cdot 0.07^{2}\cdot {\left(1-0.07\right)}^{6-2}', '', ""), + + * (Done in Stateful) Make the mark and penalty fields accept arbitrary maxima statements. * (Done in Stateful) Introduce a variable so the maxima code "knows the attempt number". [Note to self: check how this changes reporting]. This is now being done with the "state" code in the abacus branch. * (Done in Stateful) Make the PRT Score element CAS, so that a value calculated in the "Feedback variables" could be included here. diff --git a/doc/en/Developer/Releasing.md b/doc/en/Developer/Releasing.md index 41d34faec..a70a4e1c5 100644 --- a/doc/en/Developer/Releasing.md +++ b/doc/en/Developer/Releasing.md @@ -30,18 +30,18 @@ Check * check both the Moodle versions, and the required number. (https://docs.moodle.org/dev/Releases) * `MATURITY_STABLE`? * Check version numbers on stackmaxima.mac. -* Run unit tests. +* Run [unit tests](Unit_tests.md). * Run code checker. -* Commit all changes to git, e.g. "Update version number for the 4.3.6 release." +* Commit all changes to git, e.g. "Update version number for the 4.3.11 release." ## 2. Create new tag with version name -E.g. "v4.3.6". +E.g. "v4.3.11". * Push to GitHub. * Push tags to GitHub * Tortoise git: pulldown from push - * Linux: `git tag -a v4.3.6 -m "Update version number for the 4.3.6 release."` + * Linux: `git tag -a v4.3.11 -m "Update version number for the 4.3.11 release."` * Linux: `git push` * Linux: `git push --tags` @@ -65,3 +65,4 @@ Add a new version to the Moodle plugins database entry for the plugin. Then check updated information on the form. (don't add "master" to branch info) + diff --git a/doc/en/Developer/Unit_tests.md b/doc/en/Developer/Unit_tests.md index d0755b556..f61ad5244 100644 --- a/doc/en/Developer/Unit_tests.md +++ b/doc/en/Developer/Unit_tests.md @@ -8,16 +8,11 @@ Unit testing for STACK comes in the following three parts. These three mechanisms aim to provide comprehensive testing of STACK. The last category are a compromise, and are designed to expose the results of unit tests to question authors in a reasonably attractive manner to inform them of what each answer test is actually supposed to do. Links to these tests are in the healthcheck page. -STACK uses the Travis continuous integration mechanism so that all unit tests are triggered when a commit is pushed to GitHub. -See [https://travis-ci.org/maths/moodle-qtype_stack](https://travis-ci.org/maths/moodle-qtype_stack). +STACK uses the moodle-ci continuous integration mechanism via github actions so that all unit tests are triggered when a commit is pushed to github. # PHP Unit tests -Moodle uses PHPUnit for its unit tests. Setting this up and getting it working -is a bit of a pain, but you only have to follow the instructions in -[the Moodle PHPUnit documentation](http://docs.moodle.org/dev/PHPUnit) once to get it working. - -**NOTE: do not use linux-optimised when running the unit tests.** The STACK installation must be set to `linux` (or `win` of course). +Moodle uses PHPUnit for its unit tests. Setting this up and getting it working is a bit of a pain, but you only have to follow the instructions in [the Moodle PHPUnit documentation](http://docs.moodle.org/dev/PHPUnit) once to get it working. ## STACK-specific set-up steps ## diff --git a/doc/en/Developer/Updating_JSXGraph.md b/doc/en/Developer/Updating_JSXGraph.md new file mode 100644 index 000000000..b85984421 --- /dev/null +++ b/doc/en/Developer/Updating_JSXGraph.md @@ -0,0 +1,48 @@ +# Updating JSXGraph + +JSXGraph support in STACK relies on two parts. + +1. `jsxgraph.js` is not part of jsxgraph. Its task is to include the (modified) official jsxgraph file and it adds some additional functions (like bind_point). +2. `jsxgraphcore-lazy.js` is the official jsxgraph fil. + +These, and other JS, files are in `amd/src`. + +## 1. Get JSXGraph + +Download JSXGraph from here: [https://github.com/jsxgraph/jsxgraph](https://github.com/jsxgraph/jsxgraph). + +We need just need the file `distrib/jsxgraphsrc.js`. + +## 2. Rename and Modify + +Rename the file to `jsxgraphcore-lazy.js`. + +Open the file and delete the first lines up to the line + + var requirejs, require, define; + +Insert + + define(function () { + +as the new first line. + +Change the last line from + + })); + +to + + }()); + + + +## 3. Replace + +Copy the file to `amd/src`. + +## 4. Create minified file + +Use `grunt amd` in the `amd` folder to create the minified versions in `amd/build`. + +See [https://docs.moodle.org/dev/Javascript_Modules](https://docs.moodle.org/dev/Javascript_Modules) on how to properly setup nodejs and grunt. diff --git a/doc/meta_en.json b/doc/meta_en.json index c1890212a..c81ab6983 100644 --- a/doc/meta_en.json +++ b/doc/meta_en.json @@ -539,6 +539,11 @@ "description":"Information on the three types of unit tests supported by STACK; PHP Unit tests, Maxima unit tests and tests scripts exposed to the question author." }, { + "file":"Updating_JSXGraph.md", + "title":"Updating JSXGraph - STACK Documentation", + "description":"How to obtain, edit and minify the JSXGraph javascript." + }, + { "file":"UpgradeDefaults.md", "title":"Upgrading Question Details - STACK Documentation", "description":"Information on upgrading question defaults. This may be necessary if you have recently upgraded from an old version of STACK." diff --git a/lib.php b/lib.php index 5cfedbcea..b57f93210 100644 --- a/lib.php +++ b/lib.php @@ -22,10 +22,6 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ - -defined('MOODLE_INTERNAL') || die(); - - /** * Checks file access for matching questions. * @param stdClass $course course object diff --git a/questiontestrun.php b/questiontestrun.php index 91d29500a..3d18f1e7e 100644 --- a/questiontestrun.php +++ b/questiontestrun.php @@ -75,7 +75,7 @@ $editparams['id'] = $question->id; $qbankparams['qperpage'] = 1000; // Should match MAXIMUM_QUESTIONS_PER_PAGE but that constant is not easily accessible. $qbankparams['category'] = $questiondata->category . ',' . $question->contextid; $qbankparams['lastchanged'] = $question->id; -if ($questiondata->hidden) { +if (property_exists($questiondata, 'hidden') && $questiondata->hidden) { $qbankparams['showhidden'] = 1; } $questionbanklinkedit = new moodle_url('/question/question.php', $editparams); @@ -461,7 +461,8 @@ foreach ($testresults as $key => $result) { if (is_null($state->expectedpenalty) || '' === $state->expectedpenalty) { $expectedpenalty = stack_string('questiontestsdefault'); } else { - $expectedpenalty = $state->expectedpenalty + 0; + // Single PRTs only work to four decimal places, so we only expect that level. + $expectedpenalty = round($state->expectedpenalty + 0, 4); } $prtstable->data[] = array( diff --git a/renderer.php b/renderer.php index 058439b8d..1cc21bfcd 100644 --- a/renderer.php +++ b/renderer.php @@ -22,8 +22,6 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -defined('MOODLE_INTERNAL') || die(); - /** * Generates the output for Stack questions. * diff --git a/stack/answertest/anstest.class.php b/stack/answertest/anstest.class.php index 66b081e23..bf9194763 100644 --- a/stack/answertest/anstest.class.php +++ b/stack/answertest/anstest.class.php @@ -14,8 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. -defined('MOODLE_INTERNAL') || die(); - /** * Answer test base class. * diff --git a/stack/bulktester.class.php b/stack/bulktester.class.php index 7e1091895..ca3534741 100644 --- a/stack/bulktester.class.php +++ b/stack/bulktester.class.php @@ -19,9 +19,7 @@ // @copyright 2015 The Open University. // @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later. -defined('MOODLE_INTERNAL') || die(); - -class stack_bulk_tester { +class stack_bulk_tester { /** * Get all the contexts that contain at least one STACK question, with a diff --git a/stack/cas/castext/block.factory.php b/stack/cas/castext/block.factory.php index 2960cbdba..48e2bdbe4 100644 --- a/stack/cas/castext/block.factory.php +++ b/stack/cas/castext/block.factory.php @@ -14,8 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. -defined('MOODLE_INTERNAL') || die(); - // Functions related to dealing with scientific units in STACK. // // @copyright 2017 Aalto University. diff --git a/stack/cas/connector.dbcache.class.php b/stack/cas/connector.dbcache.class.php index 0c0706f9e..add1a5951 100644 --- a/stack/cas/connector.dbcache.class.php +++ b/stack/cas/connector.dbcache.class.php @@ -14,8 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. -defined('MOODLE_INTERNAL') || die(); - /** * Class which undertakes process control to connect to Maxima. * diff --git a/stack/cas/connector.interface.php b/stack/cas/connector.interface.php index eadd1bc6e..671fb5f9f 100644 --- a/stack/cas/connector.interface.php +++ b/stack/cas/connector.interface.php @@ -14,8 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. -defined('MOODLE_INTERNAL') || die(); - /** * Defines the stack_cas_connection interface. * diff --git a/stack/cas/connector.linux.class.php b/stack/cas/connector.linux.class.php index ddce431fb..cc308e48b 100644 --- a/stack/cas/connector.linux.class.php +++ b/stack/cas/connector.linux.class.php @@ -14,8 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. -defined('MOODLE_INTERNAL') || die(); - /** * Connection to Maxima for linux-like systems. * diff --git a/stack/cas/connector.server.class.php b/stack/cas/connector.server.class.php index 6018488d6..3bcd54982 100644 --- a/stack/cas/connector.server.class.php +++ b/stack/cas/connector.server.class.php @@ -14,8 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. -defined('MOODLE_INTERNAL') || die(); - /** * Connection to Maxima running in a tomcat-server using the MaximaPool-servlet. * This version handles transfer of the plots generated on possibly remote servlet. diff --git a/stack/cas/connector.windows.class.php b/stack/cas/connector.windows.class.php index cea7771e5..bfd3bbdb2 100644 --- a/stack/cas/connector.windows.class.php +++ b/stack/cas/connector.windows.class.php @@ -14,8 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. -defined('MOODLE_INTERNAL') || die(); - /** * Connection to Maxima for Windows systems. * diff --git a/stack/cas/parsingrules/542_no_functions_at_all.filter.php b/stack/cas/parsingrules/542_no_functions_at_all.filter.php index 6aa6e41cd..c8ea90143 100644 --- a/stack/cas/parsingrules/542_no_functions_at_all.filter.php +++ b/stack/cas/parsingrules/542_no_functions_at_all.filter.php @@ -29,7 +29,7 @@ class stack_ast_filter_542_no_functions_at_all implements stack_cas_astfilter_ex $hasany = true; // Insert stars into the pattern. // Probably not very sensible to end up with sin(x) -> sin*(x) but ho hum. - $errors [] = stack_string('stackCas_noFunction', + $errors[] = stack_string('stackCas_noFunction', array('forbid' => stack_maxima_format_casstring($node->name->toString()), 'term' => stack_maxima_format_casstring($node->toString()))); $node->position['invalid'] = true; diff --git a/stack/graphlayout/graphclump.php b/stack/graphlayout/graphclump.php index 50f112412..beab08edd 100644 --- a/stack/graphlayout/graphclump.php +++ b/stack/graphlayout/graphclump.php @@ -23,10 +23,6 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ - -defined('MOODLE_INTERNAL') || die(); - - /** * Used by {@link stack_abstract_graph} during the layout algorithm. * This represents a group of nodes that have been laid out relative to each other. diff --git a/stack/graphlayout/graphnode.php b/stack/graphlayout/graphnode.php index 906e18ada..dafb6e425 100644 --- a/stack/graphlayout/graphnode.php +++ b/stack/graphlayout/graphnode.php @@ -22,10 +22,6 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ - -defined('MOODLE_INTERNAL') || die(); - - /** * Represents a node in a {@link stack_abstract_graph}. * diff --git a/stack/graphlayout/svgrenderer.php b/stack/graphlayout/svgrenderer.php index 48bc96d45..dfcd60438 100644 --- a/stack/graphlayout/svgrenderer.php +++ b/stack/graphlayout/svgrenderer.php @@ -23,10 +23,6 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ - -defined('MOODLE_INTERNAL') || die(); - - /** * Displays a {@link stack_abstract_graph} as SVG. * diff --git a/stack/input/algebraic/algebraic.class.php b/stack/input/algebraic/algebraic.class.php index 024affa80..7e9774a92 100644 --- a/stack/input/algebraic/algebraic.class.php +++ b/stack/input/algebraic/algebraic.class.php @@ -14,8 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. -defined('MOODLE_INTERNAL') || die(); - /** * A basic text-field input. * diff --git a/stack/input/boolean/boolean.class.php b/stack/input/boolean/boolean.class.php index 6b2877ace..5cbf61daf 100644 --- a/stack/input/boolean/boolean.class.php +++ b/stack/input/boolean/boolean.class.php @@ -14,8 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. -defined('MOODLE_INTERNAL') || die(); - /** * Input for entering true/false using a select dropdown. * diff --git a/stack/input/dropdown/dropdown.class.php b/stack/input/dropdown/dropdown.class.php index 5f8740801..de05f7657 100644 --- a/stack/input/dropdown/dropdown.class.php +++ b/stack/input/dropdown/dropdown.class.php @@ -14,8 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. -defined('MOODLE_INTERNAL') || die(); - /** * Input that is a dropdown list/multiple choice that the teacher * has specified. diff --git a/stack/input/matrix/matrix.class.php b/stack/input/matrix/matrix.class.php index 6ce256383..425cf4c29 100644 --- a/stack/input/matrix/matrix.class.php +++ b/stack/input/matrix/matrix.class.php @@ -14,8 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. -defined('MOODLE_INTERNAL') || die(); - /** * A basic text-field input. * diff --git a/stack/input/numerical/numerical.class.php b/stack/input/numerical/numerical.class.php index 59816bb1a..64e5cb04e 100644 --- a/stack/input/numerical/numerical.class.php +++ b/stack/input/numerical/numerical.class.php @@ -14,8 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. -defined('MOODLE_INTERNAL') || die(); - /** * A basic text-field input. * diff --git a/stack/input/singlechar/singlechar.class.php b/stack/input/singlechar/singlechar.class.php index 9f06b2fcd..23d711302 100644 --- a/stack/input/singlechar/singlechar.class.php +++ b/stack/input/singlechar/singlechar.class.php @@ -14,8 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. -defined('MOODLE_INTERNAL') || die(); - /** * Input that accepts a single character. * diff --git a/stack/input/units/units.class.php b/stack/input/units/units.class.php index 2adaa3c08..5f94cc895 100644 --- a/stack/input/units/units.class.php +++ b/stack/input/units/units.class.php @@ -14,8 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. -defined('MOODLE_INTERNAL') || die(); - /** * An input to support scientific units. Heavily based on algebraic. * diff --git a/stack/input/varmatrix/varmatrix.class.php b/stack/input/varmatrix/varmatrix.class.php index e3ac2992b..3a00504ef 100644 --- a/stack/input/varmatrix/varmatrix.class.php +++ b/stack/input/varmatrix/varmatrix.class.php @@ -14,8 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. -defined('MOODLE_INTERNAL') || die(); - /** * An input which provides a matrix input of variable size. * Lots in common with the textarea class. diff --git a/stack/mathsoutput/fact_sheets.class.php b/stack/mathsoutput/fact_sheets.class.php index c8634dcec..dab0063e5 100644 --- a/stack/mathsoutput/fact_sheets.class.php +++ b/stack/mathsoutput/fact_sheets.class.php @@ -14,8 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. -defined('MOODLE_INTERNAL') || die(); - /** * The fact sheets class for STACK. * diff --git a/stack/maxima/stackmaxima.mac b/stack/maxima/stackmaxima.mac index 2399b45fa..de643113e 100644 --- a/stack/maxima/stackmaxima.mac +++ b/stack/maxima/stackmaxima.mac @@ -3105,5 +3105,5 @@ load(linearalgebra); /* Stack expects some output with the version number the output happens at */ /* maximalocal.mac after additional library loading */ -stackmaximaversion:2021120900$ +stackmaximaversion:2022053001$ diff --git a/stack/options.class.php b/stack/options.class.php index 41e0db1b6..0758e8b96 100644 --- a/stack/options.class.php +++ b/stack/options.class.php @@ -14,8 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. -defined('MOODLE_INTERNAL') || die(); - /** * Options enable a context to be set for each question, and information * made generally available to other classes. diff --git a/stack/questiontestresult.php b/stack/questiontestresult.php index 695126e91..0bfdfc3b5 100644 --- a/stack/questiontestresult.php +++ b/stack/questiontestresult.php @@ -14,8 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. -defined('MOODLE_INTERNAL') || die(); - // Holds the results of one {@link stack_question_test). // // @copyright 2012 The Open University. diff --git a/styles.css b/styles.css index 616dc70fe..b2980d983 100644 --- a/styles.css +++ b/styles.css @@ -368,7 +368,7 @@ body.path-question-type-stack table.stacktestsuite .expectedfail td { } body.path-question-type-stack table.stacktestsuite pre { font-size: 0.7em; - background: #ffffff99; + background: #fff9; padding: 0.25rem; max-width: 60em; } diff --git a/tests/answertest_general_cas_test.php b/tests/answertest_general_cas_test.php index 0bdee6ea3..565564879 100644 --- a/tests/answertest_general_cas_test.php +++ b/tests/answertest_general_cas_test.php @@ -14,6 +14,15 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_testcase; +use stack_ans_test_controller; +use stack_answertest_general_cas; +use stack_ast_container; +use stack_cas_security; + + defined('MOODLE_INTERNAL') || die(); // Unit tests for stack_answertest_general_cas. @@ -28,6 +37,8 @@ require_once(__DIR__ . '/../locallib.php'); /** * @group qtype_stack + * @covers \stack_answertest_general_cas + * @covers \stack_anstest */ class answertest_general_cas_test extends qtype_stack_testcase { diff --git a/tests/answertest_general_fixtures_test.php b/tests/answertest_general_fixtures_test.php index f0d40160f..3c0141bbb 100644 --- a/tests/answertest_general_fixtures_test.php +++ b/tests/answertest_general_fixtures_test.php @@ -14,10 +14,15 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_testcase; +use stack_answertest_test_data; + defined('MOODLE_INTERNAL') || die(); // Add in all the tests from answertestsfixtures.class into the unit testing framework. -// These are exposed to users as documentation and Travis integration should also run all the tests. +// These are exposed to users as documentation and google-ci should also run all the tests. // // @copyright 2016 The University of Edinburgh. // @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later. diff --git a/tests/ast_container_test.php b/tests/ast_container_test.php index af81b6583..4cb0d46c5 100644 --- a/tests/ast_container_test.php +++ b/tests/ast_container_test.php @@ -14,6 +14,13 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_testcase; +use stack_ast_container; +use stack_cas_security; +use stack_numbers_test_data; + defined('MOODLE_INTERNAL') || die(); // Unit tests for various AST container features. diff --git a/tests/ast_filter_000_099_common_core_auto_generated_test.php b/tests/ast_filter_000_099_common_core_auto_generated_test.php index ccd303da7..b577db69d 100644 --- a/tests/ast_filter_000_099_common_core_auto_generated_test.php +++ b/tests/ast_filter_000_099_common_core_auto_generated_test.php @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_ast_testcase; +use stack_cas_security; +use stack_parsing_rule_factory; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../tests/fixtures/ast_filter_test_base.php'); diff --git a/tests/ast_filter_001_fix_call_of_a_group_or_function_auto_generated_test.php b/tests/ast_filter_001_fix_call_of_a_group_or_function_auto_generated_test.php index 010a1c38a..1618c8799 100644 --- a/tests/ast_filter_001_fix_call_of_a_group_or_function_auto_generated_test.php +++ b/tests/ast_filter_001_fix_call_of_a_group_or_function_auto_generated_test.php @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_ast_testcase; +use stack_cas_security; +use stack_parsing_rule_factory; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../tests/fixtures/ast_filter_test_base.php'); diff --git a/tests/ast_filter_002_log_candy_auto_generated_test.php b/tests/ast_filter_002_log_candy_auto_generated_test.php index 9af456a5e..67022d6d1 100644 --- a/tests/ast_filter_002_log_candy_auto_generated_test.php +++ b/tests/ast_filter_002_log_candy_auto_generated_test.php @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_ast_testcase; +use stack_cas_security; +use stack_parsing_rule_factory; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../tests/fixtures/ast_filter_test_base.php'); diff --git a/tests/ast_filter_003_no_dot_dot_auto_generated_test.php b/tests/ast_filter_003_no_dot_dot_auto_generated_test.php index 0ef4929d1..0647cb3a2 100644 --- a/tests/ast_filter_003_no_dot_dot_auto_generated_test.php +++ b/tests/ast_filter_003_no_dot_dot_auto_generated_test.php @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_ast_testcase; +use stack_cas_security; +use stack_parsing_rule_factory; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../tests/fixtures/ast_filter_test_base.php'); diff --git a/tests/ast_filter_005_i_is_never_a_function_auto_generated_test.php b/tests/ast_filter_005_i_is_never_a_function_auto_generated_test.php index 9e7261aa9..7d6773089 100644 --- a/tests/ast_filter_005_i_is_never_a_function_auto_generated_test.php +++ b/tests/ast_filter_005_i_is_never_a_function_auto_generated_test.php @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_ast_testcase; +use stack_cas_security; +use stack_parsing_rule_factory; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../tests/fixtures/ast_filter_test_base.php'); diff --git a/tests/ast_filter_022_trig_replace_synonyms_auto_generated_test.php b/tests/ast_filter_022_trig_replace_synonyms_auto_generated_test.php index 92de82a2d..f5b1ac08e 100644 --- a/tests/ast_filter_022_trig_replace_synonyms_auto_generated_test.php +++ b/tests/ast_filter_022_trig_replace_synonyms_auto_generated_test.php @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_ast_testcase; +use stack_cas_security; +use stack_parsing_rule_factory; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../tests/fixtures/ast_filter_test_base.php'); diff --git a/tests/ast_filter_025_no_trig_power_auto_generated_test.php b/tests/ast_filter_025_no_trig_power_auto_generated_test.php index 79e76b6fb..ebdc44a35 100644 --- a/tests/ast_filter_025_no_trig_power_auto_generated_test.php +++ b/tests/ast_filter_025_no_trig_power_auto_generated_test.php @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_ast_testcase; +use stack_cas_security; +use stack_parsing_rule_factory; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../tests/fixtures/ast_filter_test_base.php'); diff --git a/tests/ast_filter_030_no_trig_space_auto_generated_test.php b/tests/ast_filter_030_no_trig_space_auto_generated_test.php index 4883981b2..5155836c7 100644 --- a/tests/ast_filter_030_no_trig_space_auto_generated_test.php +++ b/tests/ast_filter_030_no_trig_space_auto_generated_test.php @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_ast_testcase; +use stack_cas_security; +use stack_parsing_rule_factory; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../tests/fixtures/ast_filter_test_base.php'); diff --git a/tests/ast_filter_031_no_trig_brackets_auto_generated_test.php b/tests/ast_filter_031_no_trig_brackets_auto_generated_test.php index f28d3ebdb..91d3f409c 100644 --- a/tests/ast_filter_031_no_trig_brackets_auto_generated_test.php +++ b/tests/ast_filter_031_no_trig_brackets_auto_generated_test.php @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_ast_testcase; +use stack_cas_security; +use stack_parsing_rule_factory; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../tests/fixtures/ast_filter_test_base.php'); diff --git a/tests/ast_filter_050_no_chained_inequalities_auto_generated_test.php b/tests/ast_filter_050_no_chained_inequalities_auto_generated_test.php index 75050fad4..9d77f32b2 100644 --- a/tests/ast_filter_050_no_chained_inequalities_auto_generated_test.php +++ b/tests/ast_filter_050_no_chained_inequalities_auto_generated_test.php @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_ast_testcase; +use stack_cas_security; +use stack_parsing_rule_factory; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../tests/fixtures/ast_filter_test_base.php'); diff --git a/tests/ast_filter_090_special_forbidden_characters_auto_generated_test.php b/tests/ast_filter_090_special_forbidden_characters_auto_generated_test.php index 3552d4f5a..685ee53eb 100644 --- a/tests/ast_filter_090_special_forbidden_characters_auto_generated_test.php +++ b/tests/ast_filter_090_special_forbidden_characters_auto_generated_test.php @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_ast_testcase; +use stack_cas_security; +use stack_parsing_rule_factory; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../tests/fixtures/ast_filter_test_base.php'); diff --git a/tests/ast_filter_101_no_floats_auto_generated_test.php b/tests/ast_filter_101_no_floats_auto_generated_test.php index 1fdd22b1d..730c4d2cc 100644 --- a/tests/ast_filter_101_no_floats_auto_generated_test.php +++ b/tests/ast_filter_101_no_floats_auto_generated_test.php @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_ast_testcase; +use stack_cas_security; +use stack_parsing_rule_factory; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../tests/fixtures/ast_filter_test_base.php'); diff --git a/tests/ast_filter_102_no_strings_auto_generated_test.php b/tests/ast_filter_102_no_strings_auto_generated_test.php index bc59a7d2f..85064c4e9 100644 --- a/tests/ast_filter_102_no_strings_auto_generated_test.php +++ b/tests/ast_filter_102_no_strings_auto_generated_test.php @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_ast_testcase; +use stack_cas_security; +use stack_parsing_rule_factory; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../tests/fixtures/ast_filter_test_base.php'); diff --git a/tests/ast_filter_103_no_lists_auto_generated_test.php b/tests/ast_filter_103_no_lists_auto_generated_test.php index 6fa3cc226..b7fc573f8 100644 --- a/tests/ast_filter_103_no_lists_auto_generated_test.php +++ b/tests/ast_filter_103_no_lists_auto_generated_test.php @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_ast_testcase; +use stack_cas_security; +use stack_parsing_rule_factory; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../tests/fixtures/ast_filter_test_base.php'); diff --git a/tests/ast_filter_104_no_sets_auto_generated_test.php b/tests/ast_filter_104_no_sets_auto_generated_test.php index 9631910bd..1b074857e 100644 --- a/tests/ast_filter_104_no_sets_auto_generated_test.php +++ b/tests/ast_filter_104_no_sets_auto_generated_test.php @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_ast_testcase; +use stack_cas_security; +use stack_parsing_rule_factory; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../tests/fixtures/ast_filter_test_base.php'); diff --git a/tests/ast_filter_105_no_grouppings_auto_generated_test.php b/tests/ast_filter_105_no_grouppings_auto_generated_test.php index 0459fc154..6f2705244 100644 --- a/tests/ast_filter_105_no_grouppings_auto_generated_test.php +++ b/tests/ast_filter_105_no_grouppings_auto_generated_test.php @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_ast_testcase; +use stack_cas_security; +use stack_parsing_rule_factory; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../tests/fixtures/ast_filter_test_base.php'); diff --git a/tests/ast_filter_106_no_control_flow_auto_generated_test.php b/tests/ast_filter_106_no_control_flow_auto_generated_test.php index 0fdbe1a3e..b4f2af518 100644 --- a/tests/ast_filter_106_no_control_flow_auto_generated_test.php +++ b/tests/ast_filter_106_no_control_flow_auto_generated_test.php @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_ast_testcase; +use stack_cas_security; +use stack_parsing_rule_factory; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../tests/fixtures/ast_filter_test_base.php'); diff --git a/tests/ast_filter_120_no_arc_auto_generated_test.php b/tests/ast_filter_120_no_arc_auto_generated_test.php index 6ae575b80..ae1057541 100644 --- a/tests/ast_filter_120_no_arc_auto_generated_test.php +++ b/tests/ast_filter_120_no_arc_auto_generated_test.php @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_ast_testcase; +use stack_cas_security; +use stack_parsing_rule_factory; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../tests/fixtures/ast_filter_test_base.php'); diff --git a/tests/ast_filter_201_sig_figs_validation_auto_generated_test.php b/tests/ast_filter_201_sig_figs_validation_auto_generated_test.php index 1de613135..08ef1b7ef 100644 --- a/tests/ast_filter_201_sig_figs_validation_auto_generated_test.php +++ b/tests/ast_filter_201_sig_figs_validation_auto_generated_test.php @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_ast_testcase; +use stack_cas_security; +use stack_parsing_rule_factory; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../tests/fixtures/ast_filter_test_base.php'); diff --git a/tests/ast_filter_202_decimal_places_validation_auto_generated_test.php b/tests/ast_filter_202_decimal_places_validation_auto_generated_test.php index 42a5e428f..4aa09f74f 100644 --- a/tests/ast_filter_202_decimal_places_validation_auto_generated_test.php +++ b/tests/ast_filter_202_decimal_places_validation_auto_generated_test.php @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_ast_testcase; +use stack_cas_security; +use stack_parsing_rule_factory; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../tests/fixtures/ast_filter_test_base.php'); diff --git a/tests/ast_filter_210_x_used_as_multiplication_auto_generated_test.php b/tests/ast_filter_210_x_used_as_multiplication_auto_generated_test.php index d37499718..1637413a0 100644 --- a/tests/ast_filter_210_x_used_as_multiplication_auto_generated_test.php +++ b/tests/ast_filter_210_x_used_as_multiplication_auto_generated_test.php @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_ast_testcase; +use stack_cas_security; +use stack_parsing_rule_factory; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../tests/fixtures/ast_filter_test_base.php'); diff --git a/tests/ast_filter_402_split_prefix_from_common_function_name_auto_generated_test.php b/tests/ast_filter_402_split_prefix_from_common_function_name_auto_generated_test.php index 68911b7c6..8ac077085 100644 --- a/tests/ast_filter_402_split_prefix_from_common_function_name_auto_generated_test.php +++ b/tests/ast_filter_402_split_prefix_from_common_function_name_auto_generated_test.php @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_ast_testcase; +use stack_cas_security; +use stack_parsing_rule_factory; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../tests/fixtures/ast_filter_test_base.php'); diff --git a/tests/ast_filter_403_split_at_number_letter_boundary_auto_generated_test.php b/tests/ast_filter_403_split_at_number_letter_boundary_auto_generated_test.php index fb325551a..e2aae7a9a 100644 --- a/tests/ast_filter_403_split_at_number_letter_boundary_auto_generated_test.php +++ b/tests/ast_filter_403_split_at_number_letter_boundary_auto_generated_test.php @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_ast_testcase; +use stack_cas_security; +use stack_parsing_rule_factory; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../tests/fixtures/ast_filter_test_base.php'); diff --git a/tests/ast_filter_404_split_at_number_letter_number_boundary_auto_generated_test.php b/tests/ast_filter_404_split_at_number_letter_number_boundary_auto_generated_test.php index 97b05abfa..db1cea644 100644 --- a/tests/ast_filter_404_split_at_number_letter_number_boundary_auto_generated_test.php +++ b/tests/ast_filter_404_split_at_number_letter_number_boundary_auto_generated_test.php @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_ast_testcase; +use stack_cas_security; +use stack_parsing_rule_factory; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../tests/fixtures/ast_filter_test_base.php'); diff --git a/tests/ast_filter_406_split_implied_variable_names_auto_generated_test.php b/tests/ast_filter_406_split_implied_variable_names_auto_generated_test.php index 010fe3ff2..16aafbf33 100644 --- a/tests/ast_filter_406_split_implied_variable_names_auto_generated_test.php +++ b/tests/ast_filter_406_split_implied_variable_names_auto_generated_test.php @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_ast_testcase; +use stack_cas_security; +use stack_parsing_rule_factory; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../tests/fixtures/ast_filter_test_base.php'); diff --git a/tests/ast_filter_410_single_char_vars_auto_generated_test.php b/tests/ast_filter_410_single_char_vars_auto_generated_test.php index c68a5f59b..895ebf271 100644 --- a/tests/ast_filter_410_single_char_vars_auto_generated_test.php +++ b/tests/ast_filter_410_single_char_vars_auto_generated_test.php @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_ast_testcase; +use stack_cas_security; +use stack_parsing_rule_factory; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../tests/fixtures/ast_filter_test_base.php'); diff --git a/tests/ast_filter_420_consolidate_subscripts_auto_generated_test.php b/tests/ast_filter_420_consolidate_subscripts_auto_generated_test.php index b3c942595..2d999a7ee 100644 --- a/tests/ast_filter_420_consolidate_subscripts_auto_generated_test.php +++ b/tests/ast_filter_420_consolidate_subscripts_auto_generated_test.php @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_ast_testcase; +use stack_cas_security; +use stack_parsing_rule_factory; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../tests/fixtures/ast_filter_test_base.php'); diff --git a/tests/ast_filter_441_split_unknown_functions_auto_generated_test.php b/tests/ast_filter_441_split_unknown_functions_auto_generated_test.php index 0c350ebd9..4df1dd17d 100644 --- a/tests/ast_filter_441_split_unknown_functions_auto_generated_test.php +++ b/tests/ast_filter_441_split_unknown_functions_auto_generated_test.php @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_ast_testcase; +use stack_cas_security; +use stack_parsing_rule_factory; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../tests/fixtures/ast_filter_test_base.php'); diff --git a/tests/ast_filter_442_split_all_functions_auto_generated_test.php b/tests/ast_filter_442_split_all_functions_auto_generated_test.php index 084ecd9bc..424285b34 100644 --- a/tests/ast_filter_442_split_all_functions_auto_generated_test.php +++ b/tests/ast_filter_442_split_all_functions_auto_generated_test.php @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_ast_testcase; +use stack_cas_security; +use stack_parsing_rule_factory; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../tests/fixtures/ast_filter_test_base.php'); diff --git a/tests/ast_filter_450_split_floats_auto_generated_test.php b/tests/ast_filter_450_split_floats_auto_generated_test.php index c83b9d87f..81f2d6156 100644 --- a/tests/ast_filter_450_split_floats_auto_generated_test.php +++ b/tests/ast_filter_450_split_floats_auto_generated_test.php @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_ast_testcase; +use stack_cas_security; +use stack_parsing_rule_factory; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../tests/fixtures/ast_filter_test_base.php'); diff --git a/tests/ast_filter_502_replace_pm_auto_generated_test.php b/tests/ast_filter_502_replace_pm_auto_generated_test.php index feb10e79d..3ec2892b6 100644 --- a/tests/ast_filter_502_replace_pm_auto_generated_test.php +++ b/tests/ast_filter_502_replace_pm_auto_generated_test.php @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_ast_testcase; +use stack_cas_security; +use stack_parsing_rule_factory; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../tests/fixtures/ast_filter_test_base.php'); diff --git a/tests/ast_filter_504_insert_tuples_for_groups_auto_generated_test.php b/tests/ast_filter_504_insert_tuples_for_groups_auto_generated_test.php index 32f066735..320770ae0 100644 --- a/tests/ast_filter_504_insert_tuples_for_groups_auto_generated_test.php +++ b/tests/ast_filter_504_insert_tuples_for_groups_auto_generated_test.php @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_ast_testcase; +use stack_cas_security; +use stack_parsing_rule_factory; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../tests/fixtures/ast_filter_test_base.php'); diff --git a/tests/ast_filter_505_no_evaluation_groups_auto_generated_test.php b/tests/ast_filter_505_no_evaluation_groups_auto_generated_test.php index 9d859c695..cac31ff4a 100644 --- a/tests/ast_filter_505_no_evaluation_groups_auto_generated_test.php +++ b/tests/ast_filter_505_no_evaluation_groups_auto_generated_test.php @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_ast_testcase; +use stack_cas_security; +use stack_parsing_rule_factory; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../tests/fixtures/ast_filter_test_base.php'); diff --git a/tests/ast_filter_520_no_equality_with_logic_auto_generated_test.php b/tests/ast_filter_520_no_equality_with_logic_auto_generated_test.php index bbc85f5aa..d92a63587 100644 --- a/tests/ast_filter_520_no_equality_with_logic_auto_generated_test.php +++ b/tests/ast_filter_520_no_equality_with_logic_auto_generated_test.php @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_ast_testcase; +use stack_cas_security; +use stack_parsing_rule_factory; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../tests/fixtures/ast_filter_test_base.php'); diff --git a/tests/ast_filter_541_no_unknown_functions_auto_generated_test.php b/tests/ast_filter_541_no_unknown_functions_auto_generated_test.php index 149759e56..c1f902097 100644 --- a/tests/ast_filter_541_no_unknown_functions_auto_generated_test.php +++ b/tests/ast_filter_541_no_unknown_functions_auto_generated_test.php @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_ast_testcase; +use stack_cas_security; +use stack_parsing_rule_factory; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../tests/fixtures/ast_filter_test_base.php'); diff --git a/tests/ast_filter_542_no_functions_at_all_auto_generated_test.php b/tests/ast_filter_542_no_functions_at_all_auto_generated_test.php index e7b7a4f3b..21971b2b5 100644 --- a/tests/ast_filter_542_no_functions_at_all_auto_generated_test.php +++ b/tests/ast_filter_542_no_functions_at_all_auto_generated_test.php @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_ast_testcase; +use stack_cas_security; +use stack_parsing_rule_factory; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../tests/fixtures/ast_filter_test_base.php'); diff --git a/tests/ast_filter_801_singleton_numeric_auto_generated_test.php b/tests/ast_filter_801_singleton_numeric_auto_generated_test.php index 278152532..75cdf0661 100644 --- a/tests/ast_filter_801_singleton_numeric_auto_generated_test.php +++ b/tests/ast_filter_801_singleton_numeric_auto_generated_test.php @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_ast_testcase; +use stack_cas_security; +use stack_parsing_rule_factory; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../tests/fixtures/ast_filter_test_base.php'); diff --git a/tests/ast_filter_802_singleton_units_auto_generated_test.php b/tests/ast_filter_802_singleton_units_auto_generated_test.php index 7dab8f4ae..14460dd58 100644 --- a/tests/ast_filter_802_singleton_units_auto_generated_test.php +++ b/tests/ast_filter_802_singleton_units_auto_generated_test.php @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_ast_testcase; +use stack_cas_security; +use stack_parsing_rule_factory; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../tests/fixtures/ast_filter_test_base.php'); diff --git a/tests/ast_filter_910_inert_float_for_display_auto_generated_test.php b/tests/ast_filter_910_inert_float_for_display_auto_generated_test.php index 2de5e0e65..e1fa2ce0e 100644 --- a/tests/ast_filter_910_inert_float_for_display_auto_generated_test.php +++ b/tests/ast_filter_910_inert_float_for_display_auto_generated_test.php @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_ast_testcase; +use stack_cas_security; +use stack_parsing_rule_factory; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../tests/fixtures/ast_filter_test_base.php'); diff --git a/tests/ast_filter_990_no_fixing_spaces_auto_generated_test.php b/tests/ast_filter_990_no_fixing_spaces_auto_generated_test.php index d9ee69cf7..8330ca7c0 100644 --- a/tests/ast_filter_990_no_fixing_spaces_auto_generated_test.php +++ b/tests/ast_filter_990_no_fixing_spaces_auto_generated_test.php @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_ast_testcase; +use stack_cas_security; +use stack_parsing_rule_factory; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../tests/fixtures/ast_filter_test_base.php'); diff --git a/tests/ast_filter_991_no_fixing_stars_auto_generated_test.php b/tests/ast_filter_991_no_fixing_stars_auto_generated_test.php index d9d2fcc38..ac1e23538 100644 --- a/tests/ast_filter_991_no_fixing_stars_auto_generated_test.php +++ b/tests/ast_filter_991_no_fixing_stars_auto_generated_test.php @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_ast_testcase; +use stack_cas_security; +use stack_parsing_rule_factory; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../tests/fixtures/ast_filter_test_base.php'); diff --git a/tests/ast_filter_997_string_security_auto_generated_test.php b/tests/ast_filter_997_string_security_auto_generated_test.php index 49c9f34ec..50d0fa517 100644 --- a/tests/ast_filter_997_string_security_auto_generated_test.php +++ b/tests/ast_filter_997_string_security_auto_generated_test.php @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_ast_testcase; +use stack_cas_security; +use stack_parsing_rule_factory; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../tests/fixtures/ast_filter_test_base.php'); diff --git a/tests/ast_filter_998_security_auto_generated_test.php b/tests/ast_filter_998_security_auto_generated_test.php index 1cc7aae63..424659981 100644 --- a/tests/ast_filter_998_security_auto_generated_test.php +++ b/tests/ast_filter_998_security_auto_generated_test.php @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_ast_testcase; +use stack_cas_security; +use stack_parsing_rule_factory; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../tests/fixtures/ast_filter_test_base.php'); diff --git a/tests/ast_filter_999_strict_auto_generated_test.php b/tests/ast_filter_999_strict_auto_generated_test.php index 6eddfa4c1..d32ffd206 100644 --- a/tests/ast_filter_999_strict_auto_generated_test.php +++ b/tests/ast_filter_999_strict_auto_generated_test.php @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_ast_testcase; +use stack_cas_security; +use stack_parsing_rule_factory; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../tests/fixtures/ast_filter_test_base.php'); diff --git a/tests/behat/create_preview_edit.feature b/tests/behat/create_preview_edit.feature index d88865b9e..392592bd8 100644 --- a/tests/behat/create_preview_edit.feature +++ b/tests/behat/create_preview_edit.feature @@ -21,8 +21,9 @@ Feature: Create, preview, test, tidy and edit STACK questions @javascript Scenario: Create, preview, test, tidy and edit STACK questions + And I am on the "Course 1" "core_question > course question bank" page logged in as "teacher" # Create a new question. - When I add a "STACK" question filling the form with: + And I add a "STACK" question filling the form with: | Question name | Test STACK question | | Question variables | p : (x-1)^3; | | Question text | Differentiate {@p@} with respect to \(x\). [[input:ans1]] [[validation:ans1]] | @@ -32,8 +33,7 @@ Feature: Create, preview, test, tidy and edit STACK questions Then I should see "Test STACK question" # Preview it. - When I choose "Preview" action for "Test STACK question" in the question bank - And I switch to "questionpreview" window + When I am on the "Test STACK question" "core_question > preview" page logged in as teacher And I set the following fields to these values: | How questions behave | Adaptive | | Marks | Show mark and max | @@ -84,10 +84,9 @@ Feature: Create, preview, test, tidy and edit STACK questions And I follow "Question tests & deployed variants" Then I should see "All tests passed!" When I follow "Preview" - And I switch to the main window # Edit the question, verify the form field contents, then change some. - When I choose "Edit question" action for "Test STACK question" in the question bank + When I am on the "Test STACK question" "core_question > edit" page Then the following fields match these values: | Question name | Test STACK question | | Question variables | p : (x-1)^3; | diff --git a/tests/behat/restore_demo.feature b/tests/behat/restore_demo.feature index 0fdf9b45d..a779882b3 100644 --- a/tests/behat/restore_demo.feature +++ b/tests/behat/restore_demo.feature @@ -16,6 +16,6 @@ Feature: Test restoring the STACK demo course When I restore "STACK-demo.mbz" backup into a new course using this options: And I am on "Demonstrating STACK (v4.3.9)" course homepage Then I should see "Demonstration quiz" - And I navigate to "Question bank" in current page administration + And I am on the "Demonstrating STACK (v4.3.9)" "core_question > course question bank" page And I set the field "Select a category" to "Example_questions" And I should see "Cart speed analysis" diff --git a/tests/behat/validation_no_maths_in_question.feature b/tests/behat/validation_no_maths_in_question.feature index 364c4d22c..b57004103 100644 --- a/tests/behat/validation_no_maths_in_question.feature +++ b/tests/behat/validation_no_maths_in_question.feature @@ -15,14 +15,12 @@ Feature: STACK input vaidation works even if there is no maths in the question And the following "course enrolments" exist: | user | course | role | | teacher | C1 | editingteacher | - And I log in as "teacher" - And I am on "Course 1" course homepage - And I navigate to "Question bank" in current page administration @javascript Scenario: Create, preview, test, tidy and edit STACK questions # Create a new question. - When I add a "STACK" question filling the form with: + When I am on the "Course 1" "core_question > course question bank" page logged in as "teacher" + And I add a "STACK" question filling the form with: | Question name | Test STACK question | | Question text | What is 1 + 1? [[input:ans1]] [[validation:ans1]] | | Model answer | 2 | @@ -31,8 +29,7 @@ Feature: STACK input vaidation works even if there is no maths in the question Then I should see "Test STACK question" # Preview it. - When I choose "Preview" action for "Test STACK question" in the question bank - And I switch to "questionpreview" window + When I am on the "Test STACK question" "core_question > preview" page logged in as teacher And I set the following fields to these values: | How questions behave | Adaptive | | Marks | Show mark and max | @@ -41,4 +38,3 @@ Feature: STACK input vaidation works even if there is no maths in the question And I wait "2" seconds Then I should see "Your last answer was interpreted as follows" And I should not see "\(" - And I switch to the main window diff --git a/tests/behat/xml_import.feature b/tests/behat/xml_import.feature index 54e1eeec8..b29c15100 100644 --- a/tests/behat/xml_import.feature +++ b/tests/behat/xml_import.feature @@ -14,12 +14,10 @@ Feature: Test importing STACK questions from Moodle XML files. And the following "course enrolments" exist: | user | course | role | | teacher | C1 | editingteacher | - And I log in as "teacher" - And I am on "Course 1" course homepage @javascript @_file_upload Scenario: import a STACK question from a Moodle XML file - When I navigate to "Question bank > Import" in current page administration + When I am on the "Course 1" "core_question > course question import" page logged in as "teacher" And I set the field "id_format_xml" to "1" And I upload "question/type/stack/samplequestions/sample_questions.xml" file to "Import" filemanager And I press "id_submitbutton" @@ -30,8 +28,7 @@ Feature: Test importing STACK questions from Moodle XML files. And I should see "test_5_cubic_spline" # Now export again. - And I am on "Course 1" course homepage - And I navigate to "Question bank > Export" in current page administration + And I am on the "Course 1" "core_question > course question export" page And I set the field "id_format_xml" to "1" And I press "Export questions to file" And following "click here" should download between "50000" and "70000" bytes diff --git a/tests/caskeyval_exception_test.php b/tests/caskeyval_exception_test.php index 1aa97a422..4057709c5 100644 --- a/tests/caskeyval_exception_test.php +++ b/tests/caskeyval_exception_test.php @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_testcase; +use stack_cas_keyval; +use stack_exception; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../locallib.php'); @@ -26,7 +32,7 @@ require_once(__DIR__ . '/../stack/cas/keyval.class.php'); /** * @group qtype_stack */ -class caskeyval_exception_test extends basic_testcase { +class caskeyval_exception_test extends qtype_stack_testcase { public function test_exception_1() { $this->expectException(stack_exception::class); diff --git a/tests/caskeyval_test.php b/tests/caskeyval_test.php index 47bf71c0b..27788da90 100644 --- a/tests/caskeyval_test.php +++ b/tests/caskeyval_test.php @@ -14,6 +14,14 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_testcase; +use stack_ast_container; +use stack_cas_keyval; +use stack_cas_security; +use stack_cas_session2; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../locallib.php'); diff --git a/tests/cassession2_exception_test.php b/tests/cassession2_exception_test.php index 72866b737..6272d277d 100644 --- a/tests/cassession2_exception_test.php +++ b/tests/cassession2_exception_test.php @@ -14,6 +14,14 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use TypeError; +use qtype_stack_testcase; +use stack_cas_session2; +use stack_exception; +use stack_options; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../locallib.php'); diff --git a/tests/cassession2_test.php b/tests/cassession2_test.php index f8d353e75..cf21414bf 100644 --- a/tests/cassession2_test.php +++ b/tests/cassession2_test.php @@ -14,6 +14,18 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_testcase; +use stack_ast_container; +use stack_ast_container_silent; +use stack_cas_keyval; +use stack_cas_security; +use stack_cas_session2; +use stack_numbers_test_data; +use stack_options; +use function stack_utils\get_config; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../locallib.php'); @@ -39,7 +51,7 @@ class cassession2_test extends qtype_stack_testcase { $ast = $at1->get_by_key('m'); $maximaversion = '5.' . $ast->get_value(); - $maximaconfig = get_config('qtype_stack', 'maximaversion'); + $maximaconfig = \get_config('qtype_stack', 'maximaversion'); $this->assertEquals($maximaconfig, $maximaversion); } diff --git a/tests/castext_exception_test.php b/tests/castext_exception_test.php index 1037c22b8..76a0c62b7 100644 --- a/tests/castext_exception_test.php +++ b/tests/castext_exception_test.php @@ -14,6 +14,13 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_testcase; +use stack_cas_session2; +use stack_cas_text; +use stack_exception; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../locallib.php'); @@ -25,7 +32,7 @@ require_once(__DIR__ . '/../stack/cas/castext.class.php'); /** * @group qtype_stack */ -class castext_exception_test extends basic_testcase { +class castext_exception_test extends qtype_stack_testcase { public function test_exception_1() { $session = new stack_cas_session2(array()); diff --git a/tests/castext_test.php b/tests/castext_test.php index 6c551c03a..a58a749e6 100644 --- a/tests/castext_test.php +++ b/tests/castext_test.php @@ -14,6 +14,17 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_testcase; +use stack_ast_container; +use stack_cas_keyval; +use stack_cas_security; +use stack_cas_session2; +use stack_cas_text; +use stack_maths; +use stack_options; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../locallib.php'); diff --git a/tests/connection_test.php b/tests/connection_test.php index 0e64899c2..b2a73fd2a 100644 --- a/tests/connection_test.php +++ b/tests/connection_test.php @@ -14,6 +14,11 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_testcase; +use stack_connection_helper; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../locallib.php'); diff --git a/tests/docslib_test.php b/tests/docslib_test.php index 10ed93fe5..c9c266076 100644 --- a/tests/docslib_test.php +++ b/tests/docslib_test.php @@ -14,6 +14,10 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_testcase; + defined('MOODLE_INTERNAL') || die(); // Unit tests for the documentation library functions. diff --git a/tests/fact_sheets_test.php b/tests/fact_sheets_test.php index 4e06337c6..2636a6d8c 100644 --- a/tests/fact_sheets_test.php +++ b/tests/fact_sheets_test.php @@ -14,6 +14,11 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_testcase; +use stack_fact_sheets; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../locallib.php'); diff --git a/tests/fixtures/answertestfixtures.class.php b/tests/fixtures/answertestfixtures.class.php index ee06d13cf..8f525510b 100644 --- a/tests/fixtures/answertestfixtures.class.php +++ b/tests/fixtures/answertestfixtures.class.php @@ -440,7 +440,7 @@ class stack_answertest_test_data { array('AlgEquiv', '', 'abs(x)<1', 'abs(x)<2', 0, '', ''), array('AlgEquiv', '', 'abs(x)<1', 'abs(x)>1', 0, 'ATInequality_backwards.', ''), array('AlgEquiv', '', 'abs(x)<2', '-2<x and x<2', -3, '', ''), - array('AlgEquiv', '', '-2<x and x<2', 'abs(x)<2',-3, '', ''), + array('AlgEquiv', '', '-2<x and x<2', 'abs(x)<2', -3, '', ''), array('AlgEquiv', '', 'abs(x)<2', '-1<x and x<1', 0, '', ''), array('AlgEquiv', '', 'x^2<=9', 'abs(x)<3', 0, '', ''), array('AlgEquiv', '', 'x^2<=9', 'abs(x)<=3', -3, '', ''), @@ -559,8 +559,9 @@ class stack_answertest_test_data { array('AlgEquivNouns', '', 'subst(y,y(x),\'diff(y(x),x)+y(x)=1)', '\'diff(y,x)+y=1', 1, 'ATEquation_sides', ''), array('AlgEquivNouns', '', 'subst(y(x),y,\'diff(y,x)+y=1)', '\'diff(y(x),x)+y(x)=1', 1, 'ATEquation_sides', ''), array('AlgEquivNouns', '', 'subst(y(x),y,\'diff(y,x)+y=1)', '\'diff(y,x)+y=1', 0, 'ATEquation_default', ''), - array('AlgEquivNouns', '', 'subst(y(x),y,\'diff(y(x),x)+y(x)=1)', '\'diff(y,x)+y=1', -1, 'ATAlgEquivNouns_STACKERROR_SAns.', ''), - // y_x is an atom in Maxima and we can't have subscripts as a derivative operator. + array('AlgEquivNouns', '', 'subst(y(x),y,\'diff(y(x),x)+y(x)=1)', '\'diff(y,x)+y=1', -1, + 'ATAlgEquivNouns_STACKERROR_SAns.', ''), + // The Maxima atom y_x means we can't have subscripts as a derivative operator. array('AlgEquivNouns', '', 'y_x', '\'diff(y,x)', 0, '', ''), array('AlgEquivNouns', '', 'noundiff(f,x,1,y,1)', 'noundiff(noundiff(f,x),y)', 1, '', 'Partials'), array('AlgEquivNouns', '', 'noundiff(noundiff(f,y),x)', 'noundiff(noundiff(f,x),y)', 1, '', ''), @@ -788,7 +789,8 @@ class stack_answertest_test_data { array('EqualComAssRules', 'ID_TRANS', '2+1*i', '2+i', 1, '', ''), array('EqualComAssRules', 'ID_TRANS', 'x^0+x^1/1+x^2/2+x^3/3!+x^4/4!', '1+x+x^2/2+x^3/3!+x^4/4!', 1, '', ''), // Illustrate the difference between exp and e^x. - array('EqualComAssRules', '[testdebug,ID_TRANS]', '%e^x', 'exp(x)', 1, 'ATEqualComAssRules: [%e nounpow x,%e nounpow x].', ''), + array('EqualComAssRules', '[testdebug,ID_TRANS]', '%e^x', 'exp(x)', 1, + 'ATEqualComAssRules: [%e nounpow x,%e nounpow x].', ''), array('EqualComAssRules', 'ID_TRANS', '12*%e^((2*(%pi/2)*%i)/2)', '12*exp(%i*(%pi/2))', 0, '', ''), array('EqualComAssRules', '[ID_TRANS,[negNeg,negDiv,negOrd],' . '[recipMul,divDiv,divCancel],[intAdd,intMul,intPow]]', '12*%e^((2*(%pi/2)*%i)/2)', '12*exp(%i*(%pi/2))', 1, '', ''), @@ -856,12 +858,14 @@ class stack_answertest_test_data { array('EqualComAssRules', '[ID_TRANS,intMul,negNeg]', '(-7*x)*(-3*x)', '21*x*x', 1, '', ''), // This next example is parsing rules. In Maxima ev(a/b/c, simp)=a/(b*c). array('EqualComAssRules', '[testdebug,ID_TRANS]', 'a/b/c', 'a/(b*c)', 0, - 'ATEqualComAssRules: [a nounmul (UNARY_RECIP b) nounmul UNARY_RECIP c,a nounmul UNARY_RECIP b nounmul c].', 'ev(a/b/c, simp)=a/(b*c)'), + 'ATEqualComAssRules: [a nounmul (UNARY_RECIP b) nounmul UNARY_RECIP c,a nounmul UNARY_RECIP b nounmul c].', + 'ev(a/b/c, simp)=a/(b*c)'), array('EqualComAssRules', '[ID_TRANS,recipMul]', 'a/b/c', 'a/(b*c)', 1, '', ''), array('EqualComAssRules', '[ID_TRANS,recipMul]', '(a/b)/c', 'a/(b*c)', 1, '', ''), // This next example is parsing rules. In Maxima ev(a/(b/c), simp)=(a*c)/b. array('EqualComAssRules', '[testdebug,ID_TRANS]', 'a/(b/c)', '(a*c)/b', 0, - 'ATEqualComAssRules: [a nounmul UNARY_RECIP b nounmul UNARY_RECIP c,a nounmul c nounmul UNARY_RECIP b].', 'ev(a/(b/c), simp)=(a*c)/b'), + 'ATEqualComAssRules: [a nounmul UNARY_RECIP b nounmul UNARY_RECIP c,a nounmul c nounmul UNARY_RECIP b].', + 'ev(a/(b/c), simp)=(a*c)/b'), array('EqualComAssRules', '[testdebug,ID_TRANS,recipMul]', 'a/(b/c)', '(a*c)/b', 0, 'ATEqualComAssRules: [a nounmul UNARY_RECIP b nounmul UNARY_RECIP c,a nounmul c nounmul UNARY_RECIP b].', ''), array('EqualComAssRules', '[ID_TRANS,divDiv]', 'a/(b/c)', '(a*c)/b', 1, '', ''), diff --git a/tests/fixtures/equivfixtures.class.php b/tests/fixtures/equivfixtures.class.php index 3e952168c..83013192b 100644 --- a/tests/fixtures/equivfixtures.class.php +++ b/tests/fixtures/equivfixtures.class.php @@ -156,8 +156,6 @@ class stack_equiv_test_data { $newarg['outcome'] = true; $samplearguments[] = $newarg; - /* ....................................... */ - $newarg = array(); $newarg['section'] = 'Numerical arguments.'; $samplearguments[] = $newarg; @@ -210,8 +208,6 @@ class stack_equiv_test_data { $newarg['outcome'] = true; $samplearguments[] = $newarg; - /* ....................................... */ - $newarg = array(); $newarg['section'] = 'Things students will get wrong.'; $samplearguments[] = $newarg; @@ -240,8 +236,6 @@ class stack_equiv_test_data { $newarg['outcome'] = false; $samplearguments[] = $newarg; - /* ....................................... */ - $newarg = array(); $newarg['section'] = 'Roots, powers and absolute value'; $samplearguments[] = $newarg; @@ -286,18 +280,6 @@ class stack_equiv_test_data { $newarg['outcome'] = true; $samplearguments[] = $newarg; - $newarg = array(); - $newarg['title'] = "More substantial example involving (+-)"; - $newarg['narrative'] = ''; - $newarg['casstring'] = "[9*x^2/2-81*x/2+90=5*x^2/2-5*x-20 nounor 9*x^2/2-81*x/2+90=-(5*x^2/2-5*x-20)," . - "9*x^2-81*x+180=5*x^2-10*x-40 nounor 9*x^2-81*x+180=-5*x^2+10*x+40," . - "4*x^2-71*x+220=0 nounor 14*x^2-91*x+140=0," . - "x=(71 #pm# sqrt(71^2-4*4*220))/(2*4) nounor x=(91 #pm# sqrt(91^2-4*14*140))/(2*14)," . - "x=55/4 nounor x=4 nounor x=5/2]"; - $newarg['debuglist'] = "[EMPTYCHAR,EQUIVCHAR,EQUIVCHAR,EQUIVCHAR,SAMEROOTS]"; - $newarg['outcome'] = true; - $samplearguments[] = $newarg; - $newarg = array(); $newarg['title'] = "Absolute value"; $newarg['narrative'] = ''; @@ -355,8 +337,6 @@ class stack_equiv_test_data { $newarg['outcome'] = true; $samplearguments[] = $newarg; - /* ....................................... */ - $newarg = array(); $newarg['section'] = 'Assume positive values, to condone squaring.'; $samplearguments[] = $newarg; @@ -509,8 +489,6 @@ class stack_equiv_test_data { $newarg['assumepos'] = true; $samplearguments[] = $newarg; - /* ....................................... */ - $newarg = array(); $newarg['section'] = 'Solving simple equations'; $samplearguments[] = $newarg; @@ -732,8 +710,6 @@ class stack_equiv_test_data { $newarg['outcome'] = false; $samplearguments[] = $newarg; - /* ....................................... */ - $newarg = array(); $newarg['section'] = 'Multiplicities of roots'; $samplearguments[] = $newarg; @@ -770,8 +746,6 @@ class stack_equiv_test_data { $newarg['outcome'] = true; $samplearguments[] = $newarg; - /* ....................................... */ - $newarg = array(); $newarg['section'] = 'Exponential and logarithmic equations'; $samplearguments[] = $newarg; @@ -809,8 +783,6 @@ class stack_equiv_test_data { $newarg['outcome'] = 'unspported'; $samplearguments[] = $newarg; - /* ....................................... */ - $newarg = array(); $newarg['section'] = 'Working over the real numbers'; $samplearguments[] = $newarg; @@ -842,8 +814,6 @@ class stack_equiv_test_data { $newarg['outcome'] = true; $samplearguments[] = $newarg; - /* ....................................... */ - $newarg = array(); $newarg['section'] = 'Difficult cases and nonsense arguments'; $samplearguments[] = $newarg; @@ -905,8 +875,6 @@ class stack_equiv_test_data { $newarg['outcome'] = true; $samplearguments[] = $newarg; - /* ....................................... */ - $newarg = array(); $newarg['section'] = 'Rational expressions'; $samplearguments[] = $newarg; @@ -966,8 +934,6 @@ class stack_equiv_test_data { $newarg['outcome'] = true; $samplearguments[] = $newarg; - /* ....................................... */ - $newarg = array(); $newarg['section'] = 'Equate coefficients'; $samplearguments[] = $newarg; @@ -988,8 +954,6 @@ class stack_equiv_test_data { $newarg['outcome'] = true; $samplearguments[] = $newarg; - /* ....................................... */ - $newarg = array(); $newarg['section'] = 'Equational reasoning'; $samplearguments[] = $newarg; @@ -1138,8 +1102,6 @@ class stack_equiv_test_data { $newarg['outcome'] = true; $samplearguments[] = $newarg; - /* ....................................... */ - $newarg = array(); $newarg['section'] = 'Mix of equations and expressions'; $samplearguments[] = $newarg; @@ -1176,8 +1138,6 @@ class stack_equiv_test_data { $newarg['outcome'] = true; $samplearguments[] = $newarg; - /* ....................................... */ - $newarg = array(); $newarg['section'] = 'Simultaneous equations and substitution'; $samplearguments[] = $newarg; @@ -1277,9 +1237,7 @@ class stack_equiv_test_data { $newarg['debuglist'] = "[EMPTYCHAR,EMPTYCHAR,EQUIVCHAR,EQUATECOEFFLOSS(x),EQUIVCHAR,EQUIVCHAR,EMPTYCHAR,EQUIVCHAR," . "EQUIVCHAR,EQUIVCHAR,EMPTYCHAR,EQUIVCHAR,EQUIVCHAR,EMPTYCHAR,EMPTYCHAR]"; $newarg['outcome'] = 'unsupported'; - $samplearguments[] = $newarg; - - /* ....................................... */ + $samplearguments[] = $newarg; $newarg = array(); $newarg['section'] = 'Inequalities'; @@ -1293,7 +1251,7 @@ class stack_equiv_test_data { "(x>=3/2 and x>=-2) or (x<=3/2 and x<=-2), x>=3/2 or x <=-2]"; $newarg['debuglist'] = "[EMPTYCHAR,EQUIVCHAR,EQUIVCHAR,EQUIVCHAR,EQUIVCHAR,EQUIVCHAR]"; $newarg['outcome'] = true; - $samplearguments[] = $newarg; + $samplearguments[] = $newarg; $newarg = array(); $newarg['title'] = "Solving a quadratic inequality"; @@ -1303,7 +1261,7 @@ class stack_equiv_test_data { "(x>=3/2 and x>=-2) or (x<=3/2 and x<=-2), x>=3/2 or x <=-2]"; $newarg['debuglist'] = "[EMPTYCHAR,EQUIVCHAR,EQUIVCHAR,EQUIVCHAR,EQUIVCHAR,EQUIVCHAR]"; $newarg['outcome'] = true; - $samplearguments[] = $newarg; + $samplearguments[] = $newarg; $newarg = array(); $newarg['title'] = "Solving a quadratic inequality"; @@ -1313,7 +1271,7 @@ class stack_equiv_test_data { "(x>=3/2 and x>=-2) or (x<=3/2 and x<=-2), x>=3/2 or x <=2]"; $newarg['debuglist'] = "[EMPTYCHAR,EQUIVCHAR,EQUIVCHAR,EQUIVCHAR,EQUIVCHAR,QMCHAR]"; $newarg['outcome'] = false; - $samplearguments[] = $newarg; + $samplearguments[] = $newarg; $newarg = array(); $newarg['title'] = "Solving an inequality (remove redundant inequalities)"; @@ -1321,7 +1279,7 @@ class stack_equiv_test_data { $newarg['casstring'] = "[x^2>=9 and x>3, x^2-9>=0 and x>3, (x>=3 or x<=-3) and x>3, x>3]"; $newarg['debuglist'] = "[EMPTYCHAR,EQUIVCHAR,EQUIVCHAR,EQUIVCHAR]"; $newarg['outcome'] = true; - $samplearguments[] = $newarg; + $samplearguments[] = $newarg; $newarg = array(); $newarg['title'] = "Find the values of a which satisfy this inequality for all x."; @@ -1423,8 +1381,6 @@ class stack_equiv_test_data { $newarg['outcome'] = true; $samplearguments[] = $newarg; - /* ....................................... */ - $newarg = array(); $newarg['section'] = 'Limits'; $samplearguments[] = $newarg; @@ -1447,8 +1403,6 @@ class stack_equiv_test_data { $newarg['outcome'] = true; $samplearguments[] = $newarg; - /* ....................................... */ - $newarg = array(); $newarg['section'] = 'Calculus'; $samplearguments[] = $newarg; @@ -1572,8 +1526,6 @@ class stack_equiv_test_data { $newarg['outcome'] = 'unsupported'; $samplearguments[] = $newarg; - /* ....................................... */ - $newarg = array(); $newarg['section'] = 'Other cases'; $samplearguments[] = $newarg; diff --git a/tests/fixtures/inputfixtures.class.php b/tests/fixtures/inputfixtures.class.php index 3bc2710bd..a89879b54 100644 --- a/tests/fixtures/inputfixtures.class.php +++ b/tests/fixtures/inputfixtures.class.php @@ -124,7 +124,7 @@ class stack_inputvalidation_test_data { array('[[1,2],[3,4]]', 'php_true', '[[1,2],[3,4]]', 'cas_true', '\left[ \left[ 1 , 2 \right] , \left[ 3 , 4 \right] \right]', '', ""), array('{}', 'php_true', '{}', 'cas_true', '\left \{ \right \}', '', "Sets"), - array('{1}', 'php_true', '{1}', 'cas_true', '\left \{1 \right \}', '', ""), + array('{1}', 'php_true', '{1}', 'cas_true', '\left \{1 \right \}', '', ""), array('{1,2,3.4}', 'php_true', '{1,2,3.4}', 'cas_true', '\left \{1 , 2 , 3.4 \right \}', '', ""), array('{x, y, z }', 'php_true', '{x,y,z}', 'cas_true', '\left \{x , y , z \right \}', '', ""), array('set(x, y, z)', 'php_false', '', '', '', 'forbiddenFunction', ""), @@ -144,7 +144,8 @@ class stack_inputvalidation_test_data { array('a[1,2]', 'php_true', 'a[1,2]', 'cas_true', 'a_{1,2}', '', ""), array('(a,b,c)', 'php_true', 'ntuple(a,b,c)', 'cas_true', '\left(a, b, c\right)', '', "In Maxima this syntax is a programme block which we turn into an inert function for student's input."), - array('{(x,y),(b,c)}', 'php_true', '{ntuple(x,y),ntuple(b,c)}', 'cas_true', '\left \{\left(x, y\right) , \left(b, c\right) \right \}', '', ""), + array('{(x,y),(b,c)}', 'php_true', '{ntuple(x,y),ntuple(b,c)}', 'cas_true', + '\left \{\left(x, y\right) , \left(b, c\right) \right \}', '', ""), array('((x,y),a)', 'php_true', 'ntuple(ntuple(x,y),a)', 'cas_true', '\left(\left(x, y\right), a\right)', '', ""), array('((x,y)/2,a)', 'php_false', 'ntuple((x,y)/2,a)', 'cas_true', '', 'Illegal_groups', ""), array('(x,y)+3', 'php_false', 'ntuple(x,y)+3', 'cas_true', '', 'Illegal_groups', ""), @@ -429,10 +430,6 @@ class stack_inputvalidation_test_data { array('mod(x,y)', 'php_true', 'mod(x,y)', 'cas_true', 'x \rm{mod} y', '', ""), array('binomial(n,m)', 'php_true', 'binomial(n,m)', 'cas_true', '{{n}\choose{m}}', '', ""), array('binomial(8,4)', 'php_true', 'binomial(8,4)', 'cas_true', '{{8}\choose{4}}', '', ""), -// array('pdf_binomial(n,m,p)', 'php_true', 'pdf_binomial(n,m,p)', 'cas_true', -// '{{m}\choose{n}}\cdot p^{n}\cdot {\left(1-p\right)}^{m-n}', '', ""), -// array('pdf_binomial(2,6,0.07)', 'php_true', 'pdf_binomial(6,2,0.07)', 'cas_true', -// '{{6}\choose{2}}\cdot 0.07^{2}\cdot {\left(1-0.07\right)}^{6-2}', '', ""), array('perm(x,y)', 'php_false', '', '', '', 'forbiddenFunction', ""), array('comb(x,y)', 'php_false', '', '', '', 'forbiddenFunction', ""), array('switch(x,a,y,b,c)', 'php_false', '', '', '', 'forbiddenFunction', ""), @@ -672,7 +669,8 @@ class stack_inputvalidation_test_data { } if ($casdisplay != $test->display) { $passed = false; - $errors .= ' ' . stack_string('displaymismatch') . html_writer::tag('pre', s($test->display)) . html_writer::tag('pre', s($casdisplay)); + $errors .= ' ' . stack_string('displaymismatch') . html_writer::tag('pre', s($test->display)) . + html_writer::tag('pre', s($casdisplay)); } } diff --git a/tests/fixtures/maximacorrectiveparser.class.php b/tests/fixtures/maximacorrectiveparser.class.php index d1f849b7a..834fe1c37 100644 --- a/tests/fixtures/maximacorrectiveparser.class.php +++ b/tests/fixtures/maximacorrectiveparser.class.php @@ -14,8 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. -defined('MOODLE_INTERNAL') || die(); - /** * This script runs the answers tests and verifies the results. * @@ -105,4 +103,4 @@ class maxima_corrective_parser_test_data { $test->notes = $notes; return($test); } -} \ No newline at end of file +} diff --git a/tests/fixtures/numbersfixtures.class.php b/tests/fixtures/numbersfixtures.class.php index 903823b32..410c0eda5 100644 --- a/tests/fixtures/numbersfixtures.class.php +++ b/tests/fixtures/numbersfixtures.class.php @@ -14,8 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. -defined('MOODLE_INTERNAL') || die(); - /** * This script provides test cases for the numerical rounding tests. * @@ -24,7 +22,6 @@ defined('MOODLE_INTERNAL') || die(); * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ - class stack_numbers_test_data { // In this text digits are 1-9 and 0 is not a digit. @@ -94,4 +91,4 @@ class stack_numbers_test_data { public static function get_raw_test_data_utils() { return self::$rawdatautils; } -} \ No newline at end of file +} diff --git a/tests/fixtures/subscriptsfixtures.class.php b/tests/fixtures/subscriptsfixtures.class.php index aea34443c..37e98f6ee 100644 --- a/tests/fixtures/subscriptsfixtures.class.php +++ b/tests/fixtures/subscriptsfixtures.class.php @@ -14,8 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. -defined('MOODLE_INTERNAL') || die(); - /** * This script checks display of subscript elements. * diff --git a/tests/fixtures/test_base.php b/tests/fixtures/test_base.php index 4f2bcfd50..cb5acfe5e 100644 --- a/tests/fixtures/test_base.php +++ b/tests/fixtures/test_base.php @@ -14,14 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. -/** - * Base class for Stack unit tests. - * - * @package qtype_stack - * @copyright 2012 The Open University - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - defined('MOODLE_INTERNAL') || die(); global $CFG; @@ -190,10 +182,10 @@ abstract class qtype_stack_testcase extends advanced_testcase { public function assert_equals_ignore_spaces_and_e(string $expected, string $actual) { // Data gathered on 26/06/2021. - // Maxima 5.38.0 SBCL 1.2.4.debian. 1.0e-5 - // Maxima 5.43.2 SBCL 1.4.14 (x86_64-w64-mingw32). 1.0e-5 - // Maxima 5.42.1 GCL 2.6.12. 1.0E-5 - // Maxima 5.44.0 CLISP 2.49 (2010-07-07). 1.0E-5 + // Maxima 5.38.0 SBCL 1.2.4.debian. 1.0e-5. + // Maxima 5.43.2 SBCL 1.4.14 (x86_64-w64-mingw32). 1.0e-5. + // Maxima 5.42.1 GCL 2.6.12. 1.0E-5. + // Maxima 5.44.0 CLISP 2.49 (2010-07-07). 1.0E-5. $e = trim(preg_replace('/[\t\n\r\s]+/', ' ', $expected)); $a = trim(preg_replace('/[\t\n\r\s]+/', ' ', $actual)); @@ -206,6 +198,7 @@ abstract class qtype_stack_testcase extends advanced_testcase { $this->assertEquals($e, $a); } + // phpcs:ignore moodle.NamingConventions.ValidFunctionName.LowercaseMethod public static function assertMatchesRegularExpression(string $pattern, string $string, string $message = '') : void { // TODO remove this once Moodle 3.11 is the lowest supported version. if (method_exists('advanced_testcase', 'assertMatchesRegularExpression')) { @@ -214,7 +207,9 @@ abstract class qtype_stack_testcase extends advanced_testcase { parent::assertRegExp($pattern, $string); } } + // phpcs:enable + // phpcs:ignore moodle.NamingConventions.ValidFunctionName.LowercaseMethod public static function assertDoesNotMatchRegularExpression(string $pattern, string $string, string $message = '') : void { // TODO remove this once Moodle 3.11 is the lowest supported version. if (method_exists('advanced_testcase', 'assertDoesNotMatchRegularExpression')) { @@ -223,6 +218,7 @@ abstract class qtype_stack_testcase extends advanced_testcase { parent::assertNotRegExp($pattern, $string); } } + // phpcs:enable } @@ -234,7 +230,7 @@ abstract class qtype_stack_testcase extends advanced_testcase { * @copyright 2012 The Open University * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -abstract class qtype_stack_walkthrough_test_base extends qbehaviour_walkthrough_test_base { +abstract class qtype_stack_walkthrough_test_base extends \qbehaviour_walkthrough_test_base { protected $currentoutput = null; public function setUp() :void { @@ -452,6 +448,7 @@ abstract class qtype_stack_walkthrough_test_base extends qbehaviour_walkthrough_ $this->assertEquals($expected, $actual); } + // phpcs:ignore moodle.NamingConventions.ValidFunctionName.LowercaseMethod public static function assertMatchesRegularExpression(string $pattern, string $string, string $message = '') : void { // TODO remove this once Moodle 3.11 is the lowest supported version. if (method_exists('advanced_testcase', 'assertMatchesRegularExpression')) { @@ -460,7 +457,9 @@ abstract class qtype_stack_walkthrough_test_base extends qbehaviour_walkthrough_ parent::assertRegExp($pattern, $string); } } + // phpcs:enable + // phpcs:ignore moodle.NamingConventions.ValidFunctionName.LowercaseMethod public static function assertDoesNotMatchRegularExpression(string $pattern, string $string, string $message = '') : void { // TODO remove this once Moodle 3.11 is the lowest supported version. if (method_exists('advanced_testcase', 'assertDoesNotMatchRegularExpression')) { @@ -469,4 +468,5 @@ abstract class qtype_stack_walkthrough_test_base extends qbehaviour_walkthrough_ parent::assertNotRegExp($pattern, $string); } } + // phpcs:enable } diff --git a/tests/generator/behat_qtype_stack_generator.php b/tests/generator/behat_qtype_stack_generator.php index 0acfc9285..53fa9a6cf 100644 --- a/tests/generator/behat_qtype_stack_generator.php +++ b/tests/generator/behat_qtype_stack_generator.php @@ -23,9 +23,6 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -defined('MOODLE_INTERNAL') || die(); - - /** * Behat data generator for qtype_stack. */ diff --git a/tests/generator/lib.php b/tests/generator/lib.php index d68b47a3e..55d23e8c9 100644 --- a/tests/generator/lib.php +++ b/tests/generator/lib.php @@ -14,8 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. -defined('MOODLE_INTERNAL') || die(); - /** * STACK question type test data generator class * diff --git a/tests/graphlayout_test.php b/tests/graphlayout_test.php index e930fb027..367fbdd10 100644 --- a/tests/graphlayout_test.php +++ b/tests/graphlayout_test.php @@ -14,6 +14,11 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use stack_abstract_graph; +use basic_testcase; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../stack/graphlayout/graph.php'); @@ -137,7 +142,7 @@ class graphlayout_test extends basic_testcase { * This graph has a link to a non-existent node. We verify that throws an exception. */ public function test_missing_node() { - $this->expectException(coding_exception::class); + $this->expectException(\coding_exception::class); $graph = new stack_abstract_graph(); $graph->add_node(1, null, 2, '=1', '=0'); diff --git a/tests/helper.php b/tests/helper.php index b82980abf..04f9dd326 100644 --- a/tests/helper.php +++ b/tests/helper.php @@ -14,8 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. -defined('MOODLE_INTERNAL') || die(); - // Test helper code for the Stack question type. // // @package qtype_stack. diff --git a/tests/input_algebraic_test.php b/tests/input_algebraic_test.php index 540950e41..c063cf0ea 100644 --- a/tests/input_algebraic_test.php +++ b/tests/input_algebraic_test.php @@ -14,6 +14,15 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_testcase; +use stack_cas_security; +use stack_input; +use stack_input_factory; +use stack_input_state; +use stack_options; + defined('MOODLE_INTERNAL') || die(); global $CFG; diff --git a/tests/input_boolean_validation_test.php b/tests/input_boolean_validation_test.php index 72d891c1b..2cc87a030 100644 --- a/tests/input_boolean_validation_test.php +++ b/tests/input_boolean_validation_test.php @@ -14,6 +14,14 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_testcase; +use stack_cas_security; +use stack_input; +use stack_input_factory; +use stack_options; + defined('MOODLE_INTERNAL') || die(); global $CFG; diff --git a/tests/input_checkbox_test.php b/tests/input_checkbox_test.php index fa17b1e42..1c4f97ea8 100644 --- a/tests/input_checkbox_test.php +++ b/tests/input_checkbox_test.php @@ -14,6 +14,15 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_testcase; +use stack_cas_security; +use stack_input; +use stack_input_factory; +use stack_input_state; +use stack_options; + defined('MOODLE_INTERNAL') || die(); global $CFG; @@ -29,7 +38,7 @@ require_once(__DIR__ . '/../stack/input/factory.class.php'); /** * @group qtype_stack */ -class input_checkbox_test extends qtype_stack_walkthrough_test_base { +class input_checkbox_test extends qtype_stack_testcase { protected function expected_choices() { return array( diff --git a/tests/input_dropdown_exception_test.php b/tests/input_dropdown_exception_test.php index 13d0c7833..97beb5034 100644 --- a/tests/input_dropdown_exception_test.php +++ b/tests/input_dropdown_exception_test.php @@ -14,6 +14,14 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_testcase; +use stack_cas_security; +use stack_exception; +use stack_input_factory; +use stack_options; + defined('MOODLE_INTERNAL') || die(); global $CFG; @@ -29,7 +37,7 @@ require_once(__DIR__ . '/../stack/input/factory.class.php'); /** * @group qtype_stack */ -class input_dropdown_exception_test extends basic_testcase { +class input_dropdown_exception_test extends qtype_stack_testcase { protected function make_dropdown($parameters = array()) { $el = stack_input_factory::make('dropdown', 'ans1', $this->make_ta(), null, $parameters); diff --git a/tests/input_equiv_test.php b/tests/input_equiv_test.php index 599b128ec..295205834 100644 --- a/tests/input_equiv_test.php +++ b/tests/input_equiv_test.php @@ -14,12 +14,14 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. -/** - * Unit tests for the stack_algebra_input class. - * - * @copyright 2015 The University of Edinburgh - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ +namespace qtype_stack; + +use qtype_stack_testcase; +use stack_cas_security; +use stack_input; +use stack_input_factory; +use stack_input_state; +use stack_options; defined('MOODLE_INTERNAL') || die(); diff --git a/tests/input_matrix_test.php b/tests/input_matrix_test.php index 1074d22d8..797672aff 100644 --- a/tests/input_matrix_test.php +++ b/tests/input_matrix_test.php @@ -14,6 +14,16 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_testcase; +use stack_cas_security; +use stack_input; +use stack_input_factory; +use stack_input_state; +use stack_options; +use function stack_utils\get_config; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/fixtures/test_base.php'); @@ -55,7 +65,7 @@ class input_matrix_test extends qtype_stack_testcase { $el = stack_input_factory::make('matrix', 'ans1', 'M', $options); $el->adapt_to_model_answer('[[1,0],[0,1]]'); - $versionused = get_config('qtype_stack', 'maximaversion'); + $versionused = \get_config('qtype_stack', 'maximaversion'); $errmsg = '<div class="error"><p><i class="icon fa fa-exclamation-circle text-danger fa-fw " title="The input has ' . 'generated the following runtime error which prevents you from answering. Please contact your teacher." ' . 'aria-label="The input has generated the following runtime error which prevents you from answering. Please ' . @@ -68,7 +78,7 @@ class input_matrix_test extends qtype_stack_testcase { 'aria-label="The input has generated the following runtime error which prevents you from answering. Please ' . 'contact your teacher."></i>The input has generated the following runtime error which prevents you from ' . 'answering. Please contact your teacher.</p>' . - '<p>The first argument of the function matrix_size must be a matrix</p></div>'; + '<p>The $first argument of the function $matrix_size must be a matrix</p></div>'; } $this->assertEquals($errmsg, $el->render(new stack_input_state(stack_input::VALID, array(), '', '', '', '', ''), 'ans1', false, null)); diff --git a/tests/input_notes_test.php b/tests/input_notes_test.php index 0a9a697aa..a2fb2e363 100644 --- a/tests/input_notes_test.php +++ b/tests/input_notes_test.php @@ -14,6 +14,16 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_testcase; +use stack_cas_security; +use stack_input; +use stack_input_factory; +use stack_input_state; +use stack_options; + + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/fixtures/test_base.php'); diff --git a/tests/input_numerical_test.php b/tests/input_numerical_test.php index 094cd3dc8..00991efe6 100644 --- a/tests/input_numerical_test.php +++ b/tests/input_numerical_test.php @@ -14,6 +14,16 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_testcase; +use stack_cas_security; +use stack_input; +use stack_input_factory; +use stack_input_state; +use stack_options; + + defined('MOODLE_INTERNAL') || die(); global $CFG; diff --git a/tests/input_singlechar_test.php b/tests/input_singlechar_test.php index 6a96f2cb9..1e61bab1d 100644 --- a/tests/input_singlechar_test.php +++ b/tests/input_singlechar_test.php @@ -14,6 +14,16 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_testcase; +use stack_cas_security; +use stack_input; +use stack_input_factory; +use stack_input_state; +use stack_options; + + defined('MOODLE_INTERNAL') || die(); global $CFG; diff --git a/tests/input_singlechar_validation_test.php b/tests/input_singlechar_validation_test.php index 751b2aa04..3424ad1c2 100644 --- a/tests/input_singlechar_validation_test.php +++ b/tests/input_singlechar_validation_test.php @@ -14,6 +14,15 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_testcase; +use stack_cas_security; +use stack_input; +use stack_input_factory; +use stack_options; + + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/fixtures/test_base.php'); diff --git a/tests/input_string_test.php b/tests/input_string_test.php index 7d6347d5c..b7bb790aa 100644 --- a/tests/input_string_test.php +++ b/tests/input_string_test.php @@ -14,6 +14,16 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_testcase; +use stack_cas_security; +use stack_input; +use stack_input_factory; +use stack_input_state; +use stack_options; + + defined('MOODLE_INTERNAL') || die(); global $CFG; diff --git a/tests/input_textarea_test.php b/tests/input_textarea_test.php index c1bd25010..bc3d7ecb2 100644 --- a/tests/input_textarea_test.php +++ b/tests/input_textarea_test.php @@ -14,7 +14,15 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. -defined('MOODLE_INTERNAL') || die(); +namespace qtype_stack; + +use qtype_stack_testcase; +use stack_cas_security; +use stack_input; +use stack_input_factory; +use stack_input_state; +use stack_options; +use stack_textarea_input; defined('MOODLE_INTERNAL') || die(); diff --git a/tests/input_units_test.php b/tests/input_units_test.php index c9daa9ffd..9c7103aab 100644 --- a/tests/input_units_test.php +++ b/tests/input_units_test.php @@ -14,6 +14,15 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_testcase; +use stack_cas_security; +use stack_input; +use stack_input_factory; +use stack_input_state; +use stack_options; + defined('MOODLE_INTERNAL') || die(); global $CFG; diff --git a/tests/input_varmatrix_test.php b/tests/input_varmatrix_test.php index ef3792d68..8a1356fe7 100644 --- a/tests/input_varmatrix_test.php +++ b/tests/input_varmatrix_test.php @@ -14,6 +14,15 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_testcase; +use stack_cas_security; +use stack_input; +use stack_input_factory; +use stack_input_state; +use stack_options; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/fixtures/test_base.php'); diff --git a/tests/inputstate_test.php b/tests/inputstate_test.php index 25c0cbbe5..cc3192be9 100644 --- a/tests/inputstate_test.php +++ b/tests/inputstate_test.php @@ -14,6 +14,13 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use stack_exception; +use stack_input; +use stack_input_state; +use basic_testcase; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../stack/input/inputbase.class.php'); diff --git a/tests/mathsoutputmathjax_test.php b/tests/mathsoutputmathjax_test.php index 283db7e99..6ddbb89ca 100644 --- a/tests/mathsoutputmathjax_test.php +++ b/tests/mathsoutputmathjax_test.php @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_testcase; +use stack_maths; +use stack_utils; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/fixtures/test_base.php'); diff --git a/tests/mathsoutputtex_test.php b/tests/mathsoutputtex_test.php index 190fa11be..df0a55369 100644 --- a/tests/mathsoutputtex_test.php +++ b/tests/mathsoutputtex_test.php @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_testcase; +use stack_maths; +use stack_utils; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../stack/mathsoutput/mathsoutput.class.php'); diff --git a/tests/maxima_corrective_parser_test.php b/tests/maxima_corrective_parser_test.php index c35b18955..963bd40c2 100644 --- a/tests/maxima_corrective_parser_test.php +++ b/tests/maxima_corrective_parser_test.php @@ -14,6 +14,11 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use maxima_corrective_parser_test_data; +use qtype_stack_testcase; + defined('MOODLE_INTERNAL') || die(); // Unit tests for verious AST filters. diff --git a/tests/multilang_test.php b/tests/multilang_test.php index b4e334707..a5be5c031 100644 --- a/tests/multilang_test.php +++ b/tests/multilang_test.php @@ -14,6 +14,11 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_testcase; +use stack_multilang; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/fixtures/test_base.php'); diff --git a/tests/parser_rule_201_test.php b/tests/parser_rule_201_test.php index 0a963e2aa..f80d7a0a3 100644 --- a/tests/parser_rule_201_test.php +++ b/tests/parser_rule_201_test.php @@ -14,6 +14,13 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use maxima_parser_utils; +use qtype_stack_testcase; +use stack_ast_filter_201_sig_figs_validation; +use stack_cas_security; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../locallib.php'); diff --git a/tests/parser_rule_202_test.php b/tests/parser_rule_202_test.php index 3d97ecfd0..6fd83eec3 100644 --- a/tests/parser_rule_202_test.php +++ b/tests/parser_rule_202_test.php @@ -14,6 +14,13 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use maxima_parser_utils; +use qtype_stack_testcase; +use stack_ast_filter_202_decimal_places_validation; +use stack_cas_security; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../locallib.php'); diff --git a/tests/parser_rule_410_test.php b/tests/parser_rule_410_test.php index dbb9d0154..9539321f9 100644 --- a/tests/parser_rule_410_test.php +++ b/tests/parser_rule_410_test.php @@ -14,6 +14,13 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use maxima_parser_utils; +use qtype_stack_testcase; +use stack_ast_filter_410_single_char_vars; +use stack_cas_security; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../locallib.php'); diff --git a/tests/parser_rule_541_test.php b/tests/parser_rule_541_test.php index 54b36d24b..aa63cdfb4 100644 --- a/tests/parser_rule_541_test.php +++ b/tests/parser_rule_541_test.php @@ -14,6 +14,13 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use maxima_parser_utils; +use qtype_stack_testcase; +use stack_ast_filter_541_no_unknown_functions; +use stack_cas_security; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../locallib.php'); diff --git a/tests/parser_rule_542_test.php b/tests/parser_rule_542_test.php index 77a5441ff..81809ec30 100644 --- a/tests/parser_rule_542_test.php +++ b/tests/parser_rule_542_test.php @@ -14,6 +14,13 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use maxima_parser_utils; +use qtype_stack_testcase; +use stack_ast_filter_542_no_functions_at_all; +use stack_cas_security; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../locallib.php'); diff --git a/tests/parser_rule_801_test.php b/tests/parser_rule_801_test.php index ca66d0840..f760c3da1 100644 --- a/tests/parser_rule_801_test.php +++ b/tests/parser_rule_801_test.php @@ -14,6 +14,13 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use maxima_parser_utils; +use qtype_stack_testcase; +use stack_ast_filter_801_singleton_numeric; +use stack_cas_security; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../locallib.php'); diff --git a/tests/parser_test.php b/tests/parser_test.php index d9063a3ac..0b8d87176 100644 --- a/tests/parser_test.php +++ b/tests/parser_test.php @@ -14,6 +14,13 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use maxima_corrective_parser; +use qtype_stack_testcase; +use stack_cas_castext_castextparser; +use stack_cas_castext_parsetreenode; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../locallib.php'); diff --git a/tests/potentialresponsenode_test.php b/tests/potentialresponsenode_test.php index 86f1d241d..95384f064 100644 --- a/tests/potentialresponsenode_test.php +++ b/tests/potentialresponsenode_test.php @@ -14,6 +14,14 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_testcase; +use stack_ast_container; +use stack_options; +use stack_potentialresponse_node; +use stack_potentialresponse_tree_state; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../stack/potentialresponsetree.class.php'); diff --git a/tests/potentialresponsetree_test.php b/tests/potentialresponsetree_test.php index dab8ab1eb..f46074de7 100644 --- a/tests/potentialresponsetree_test.php +++ b/tests/potentialresponsetree_test.php @@ -14,6 +14,17 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_testcase; +use stack_ast_container; +use stack_cas_keyval; +use stack_cas_session2; +use stack_options; +use stack_potentialresponse_node; +use stack_potentialresponse_tree; + + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../stack/potentialresponsetree.class.php'); diff --git a/tests/restore_logic_test.php b/tests/restore_logic_test.php index e27e75545..cb591c77d 100644 --- a/tests/restore_logic_test.php +++ b/tests/restore_logic_test.php @@ -14,22 +14,17 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. -/** - * Unit tests for the restore logic. - * - * @copyright 2017 The Open University - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - defined('MOODLE_INTERNAL') || die(); global $CFG; require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php'); require_once($CFG->dirroot . '/question/type/stack/backup/moodle2/restore_qtype_stack_plugin.class.php'); - /** + * Unit tests for the restore logic. * + * @copyright 2017 The Open University + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class restore_logic_test extends restore_qtype_stack_plugin { private $log = ''; diff --git a/tests/stack_options_test.php b/tests/stack_options_test.php index dde6b9ae2..dc90314ed 100644 --- a/tests/stack_options_test.php +++ b/tests/stack_options_test.php @@ -14,9 +14,16 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_testcase; +use stack_exception; +use stack_options; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../locallib.php'); +require_once(__DIR__ . '/fixtures/test_base.php'); require_once(__DIR__ . '/../stack/options.class.php'); // Unit tests for stack_options. @@ -27,7 +34,7 @@ require_once(__DIR__ . '/../stack/options.class.php'); /** * @group qtype_stack */ -class stack_options_test extends basic_testcase { +class stack_options_test extends qtype_stack_testcase { public function test_set_exception_1() { $opts = new stack_options(); diff --git a/tests/stack_utils_test.php b/tests/stack_utils_test.php index 99db1d0c3..9c9a2e6ee 100644 --- a/tests/stack_utils_test.php +++ b/tests/stack_utils_test.php @@ -14,6 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_testcase; +use stack_exception; +use stack_utils; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/fixtures/test_base.php'); diff --git a/tests/studentinput_test.php b/tests/studentinput_test.php index 35611d2c6..493f644dc 100644 --- a/tests/studentinput_test.php +++ b/tests/studentinput_test.php @@ -14,6 +14,11 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_testcase; +use stack_inputvalidation_test_data; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../locallib.php'); @@ -23,7 +28,7 @@ require_once(__DIR__ . '/fixtures/test_base.php'); require_once(__DIR__ . '/fixtures/inputfixtures.class.php'); // Add in all the tests from studentinputs.php into the unit testing framework. -// These are exposed to users as documentation and the Travis integration should also run all the tests. +// These are exposed to users as documentation and google-ci should also run all the tests. // // @copyright 2016 The University of Edinburgh. // @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later. diff --git a/tests/subscript_test.php b/tests/subscript_test.php index 4916320f0..eedddd29c 100644 --- a/tests/subscript_test.php +++ b/tests/subscript_test.php @@ -14,6 +14,11 @@ // You should have received a copy of the GNU General Public License // along with Stack. If not, see <http://www.gnu.org/licenses/>. +namespace qtype_stack; + +use qtype_stack_testcase; +use stack_subscripts_test_data; + defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../locallib.php'); @@ -23,7 +28,7 @@ require_once(__DIR__ . '/fixtures/test_base.php'); require_once(__DIR__ . '/fixtures/subscriptsfixtures.class.php'); // Add in all the tests from subscriptsfixtures.php into the unit testing framework. -// These are exposed to users as documentation and the Travis integration should also run all the tests. +// These are exposed to users as documentation and google-ci should also run all the tests. // // @copyright 2016 The University of Edinburgh. // @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later. diff --git a/thirdpartylibs.xml b/thirdpartylibs.xml index ba2e87487..9fe57891f 100644 --- a/thirdpartylibs.xml +++ b/thirdpartylibs.xml @@ -1,9 +1,9 @@ <?xml version="1.0"?> <libraries> <library> - <location>amd</location> + <location>amd/src/jsxgraphcore-lazy.js</location> <name>JSXGraph</name> - <version>0.99.7</version> + <version>1.4.4</version> <license>GNU LGPL or MIT License</license> </library> <library> @@ -26,6 +26,3 @@ </library> </libraries> - - - diff --git a/version.php b/version.php index 70342682c..7f87a78ed 100644 --- a/version.php +++ b/version.php @@ -24,12 +24,12 @@ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2021120900; +$plugin->version = 2022053001; $plugin->requires = 2018051700; $plugin->cron = 0; $plugin->component = 'qtype_stack'; $plugin->maturity = MATURITY_STABLE; -$plugin->release = '4.3.10 for Moodle 3.9+'; +$plugin->release = '4.3.11 for Moodle 3.9+'; $plugin->dependencies = array( 'qbehaviour_adaptivemultipart' => 2020103000, -- GitLab