eunoia 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. eunoia-0.1.0/.envrc +12 -0
  2. eunoia-0.1.0/.github/FUNDING.yml +1 -0
  3. eunoia-0.1.0/.github/dependabot.yml +26 -0
  4. eunoia-0.1.0/.github/workflows/ci.yml +98 -0
  5. eunoia-0.1.0/.github/workflows/docs.yml +44 -0
  6. eunoia-0.1.0/.github/workflows/publish-test.yml +130 -0
  7. eunoia-0.1.0/.github/workflows/publish.yml +123 -0
  8. eunoia-0.1.0/.gitignore +196 -0
  9. eunoia-0.1.0/.versionary-manifest.json +11 -0
  10. eunoia-0.1.0/AGENTS.md +141 -0
  11. eunoia-0.1.0/CHANGELOG.md +6 -0
  12. eunoia-0.1.0/CLAUDE.md +1 -0
  13. eunoia-0.1.0/Cargo.lock +735 -0
  14. eunoia-0.1.0/Cargo.toml +23 -0
  15. eunoia-0.1.0/LICENSE +21 -0
  16. eunoia-0.1.0/PKG-INFO +132 -0
  17. eunoia-0.1.0/README.md +96 -0
  18. eunoia-0.1.0/TODO.md +91 -0
  19. eunoia-0.1.0/Taskfile.yml +64 -0
  20. eunoia-0.1.0/devenv.lock +146 -0
  21. eunoia-0.1.0/devenv.nix +53 -0
  22. eunoia-0.1.0/devenv.yaml +13 -0
  23. eunoia-0.1.0/docs/_static/css/custom.css +3 -0
  24. eunoia-0.1.0/docs/api.md +35 -0
  25. eunoia-0.1.0/docs/conf.py +77 -0
  26. eunoia-0.1.0/docs/exts/github_link.py +66 -0
  27. eunoia-0.1.0/docs/generated/eunoia.Circle.rst +30 -0
  28. eunoia-0.1.0/docs/generated/eunoia.Ellipse.rst +32 -0
  29. eunoia-0.1.0/docs/generated/eunoia.EulerFit.rst +37 -0
  30. eunoia-0.1.0/docs/generated/eunoia.EunoiaError.rst +6 -0
  31. eunoia-0.1.0/docs/generated/eunoia.Point.rst +29 -0
  32. eunoia-0.1.0/docs/generated/eunoia.euler.rst +6 -0
  33. eunoia-0.1.0/docs/index.md +33 -0
  34. eunoia-0.1.0/docs/quickstart.md +75 -0
  35. eunoia-0.1.0/pyproject.toml +72 -0
  36. eunoia-0.1.0/python/eunoia/__init__.py +22 -0
  37. eunoia-0.1.0/python/eunoia/_eunoia.pyi +70 -0
  38. eunoia-0.1.0/python/eunoia/_fit.py +149 -0
  39. eunoia-0.1.0/python/eunoia/_models.py +158 -0
  40. eunoia-0.1.0/python/eunoia/_parse.py +43 -0
  41. eunoia-0.1.0/python/eunoia/_plot.py +169 -0
  42. eunoia-0.1.0/python/eunoia/py.typed +0 -0
  43. eunoia-0.1.0/src/lib.rs +228 -0
  44. eunoia-0.1.0/tests/test_fit.py +83 -0
  45. eunoia-0.1.0/tests/test_plot.py +81 -0
  46. eunoia-0.1.0/tests/test_repr.py +41 -0
  47. eunoia-0.1.0/tests/test_smoke.py +12 -0
  48. eunoia-0.1.0/uv.lock +2482 -0
  49. eunoia-0.1.0/versionary.jsonc +28 -0
eunoia-0.1.0/.envrc ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env bash
2
+
3
+ export DIRENV_WARN_TIMEOUT=20s
4
+
5
+ eval "$(devenv direnvrc)"
6
+
7
+ # `use devenv` supports the same options as the `devenv shell` command.
8
+ #
9
+ # To silence all output, use `--quiet`.
10
+ #
11
+ # Example usage: use devenv --quiet --impure --option services.postgres.enable:bool true
12
+ use devenv
@@ -0,0 +1 @@
1
+ github: jolars
@@ -0,0 +1,26 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: github-actions
4
+ directory: "/"
5
+ schedule:
6
+ interval: weekly
7
+ groups:
8
+ actions:
9
+ patterns: ["*"]
10
+
11
+ - package-ecosystem: cargo
12
+ directory: "/"
13
+ schedule:
14
+ interval: weekly
15
+ groups:
16
+ cargo:
17
+ patterns: ["*"]
18
+ exclude-patterns: ["eunoia"]
19
+
20
+ - package-ecosystem: uv
21
+ directory: "/"
22
+ schedule:
23
+ interval: weekly
24
+ groups:
25
+ python:
26
+ patterns: ["*"]
@@ -0,0 +1,98 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ concurrency:
12
+ group: ${{ github.workflow }}-${{ github.ref }}
13
+ cancel-in-progress: true
14
+
15
+ jobs:
16
+ lint:
17
+ runs-on: ubuntu-latest
18
+ steps:
19
+ - uses: actions/checkout@v6
20
+
21
+ - uses: astral-sh/setup-uv@v7
22
+ with:
23
+ python-version: "3.12"
24
+
25
+ - uses: dtolnay/rust-toolchain@stable
26
+
27
+ - uses: Swatinem/rust-cache@v2
28
+
29
+ - run: uv sync --all-extras --all-groups
30
+
31
+ - run: uv run maturin develop --uv
32
+
33
+ - name: Ruff check
34
+ run: |
35
+ uvx ruff check
36
+ uvx ruff format --check --diff
37
+
38
+ - name: mypy
39
+ run: uv run mypy
40
+
41
+ - name: pyright
42
+ run: uv run pyright
43
+
44
+ test:
45
+ strategy:
46
+ fail-fast: false
47
+ matrix:
48
+ os: [ubuntu-latest, macos-latest, windows-latest]
49
+ python: ["3.11", "3.13"]
50
+ runs-on: ${{ matrix.os }}
51
+ steps:
52
+ - uses: actions/checkout@v6
53
+ - uses: astral-sh/setup-uv@v7
54
+ with:
55
+ python-version: ${{ matrix.python }}
56
+ - uses: dtolnay/rust-toolchain@stable
57
+ - uses: Swatinem/rust-cache@v2
58
+ - run: uv sync --all-extras --all-groups
59
+ - run: uv run maturin develop --uv
60
+ - run: uv run pytest
61
+
62
+ docs:
63
+ runs-on: ubuntu-latest
64
+ steps:
65
+ - uses: actions/checkout@v6
66
+ - uses: astral-sh/setup-uv@v7
67
+ with:
68
+ python-version: "3.12"
69
+ - uses: dtolnay/rust-toolchain@stable
70
+ - uses: Swatinem/rust-cache@v2
71
+ - run: uv sync --all-extras --all-groups
72
+ - run: uv run maturin develop --uv
73
+ - run: uv run sphinx-build -b html docs docs/_build/html
74
+
75
+ versionary:
76
+ if: github.event_name == 'push' && github.ref == 'refs/heads/main'
77
+ needs: test
78
+ runs-on: ubuntu-latest
79
+ permissions:
80
+ contents: write
81
+ pull-requests: write
82
+ issues: write
83
+ steps:
84
+ - uses: actions/checkout@v6
85
+ with:
86
+ fetch-depth: 0
87
+ token: ${{ secrets.RELEASE_TOKEN }}
88
+
89
+ - uses: dtolnay/rust-toolchain@stable
90
+
91
+ - uses: astral-sh/setup-uv@v7
92
+ with:
93
+ python-version: "3.12"
94
+
95
+ - id: versionary
96
+ uses: jolars/versionary@v0
97
+ with:
98
+ github-token: ${{ secrets.RELEASE_TOKEN }}
@@ -0,0 +1,44 @@
1
+ name: Docs
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+ workflow_dispatch:
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ concurrency:
13
+ group: pages
14
+ cancel-in-progress: false
15
+
16
+ jobs:
17
+ build:
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - uses: actions/checkout@v6
21
+ - uses: astral-sh/setup-uv@v7
22
+ with:
23
+ python-version: "3.12"
24
+ - uses: dtolnay/rust-toolchain@stable
25
+ - uses: Swatinem/rust-cache@v2
26
+ - run: uv sync --all-extras --all-groups
27
+ - run: uv run maturin develop --uv
28
+ - run: uv run sphinx-build -b html docs docs/_build/html
29
+ - uses: actions/upload-pages-artifact@v5
30
+ with:
31
+ path: docs/_build/html
32
+
33
+ deploy:
34
+ needs: build
35
+ runs-on: ubuntu-latest
36
+ permissions:
37
+ pages: write
38
+ id-token: write
39
+ environment:
40
+ name: github-pages
41
+ url: ${{ steps.deployment.outputs.page_url }}
42
+ steps:
43
+ - id: deployment
44
+ uses: actions/deploy-pages@v5
@@ -0,0 +1,130 @@
1
+ name: Publish on TestPyPI
2
+
3
+ # Manual-only workflow for uploading to test.pypi.org. Mirrors the build
4
+ # matrix in `publish.yml` so the wheels published to TestPyPI are exactly
5
+ # what would ship to prod, then uploads to TestPyPI via Trusted Publishing
6
+ # (separate registration on test.pypi.org from the prod one).
7
+ #
8
+ # `skip-existing: true` so re-running for the same version is idempotent;
9
+ # TestPyPI will refuse to overwrite an existing file otherwise.
10
+
11
+ on:
12
+ workflow_dispatch:
13
+
14
+ permissions:
15
+ contents: read
16
+
17
+ jobs:
18
+ linux:
19
+ runs-on: ubuntu-latest
20
+ strategy:
21
+ fail-fast: false
22
+ matrix:
23
+ platform:
24
+ - target: x86_64-unknown-linux-gnu
25
+ manylinux: "2_28"
26
+ - target: aarch64-unknown-linux-gnu
27
+ manylinux: "2_28"
28
+ - target: x86_64-unknown-linux-musl
29
+ manylinux: musllinux_1_2
30
+ - target: aarch64-unknown-linux-musl
31
+ manylinux: musllinux_1_2
32
+ steps:
33
+ - uses: actions/checkout@v6
34
+ - uses: PyO3/maturin-action@v1
35
+ with:
36
+ target: ${{ matrix.platform.target }}
37
+ manylinux: ${{ matrix.platform.manylinux }}
38
+ args: --release --out dist --strip
39
+ - uses: actions/upload-artifact@v7
40
+ with:
41
+ name: wheels-${{ matrix.platform.target }}
42
+ path: dist
43
+
44
+ macos:
45
+ runs-on: macos-latest
46
+ strategy:
47
+ fail-fast: false
48
+ matrix:
49
+ target: [x86_64-apple-darwin, aarch64-apple-darwin]
50
+ steps:
51
+ - uses: actions/checkout@v6
52
+ - uses: PyO3/maturin-action@v1
53
+ with:
54
+ target: ${{ matrix.target }}
55
+ args: --release --out dist --strip
56
+ - uses: actions/upload-artifact@v7
57
+ with:
58
+ name: wheels-${{ matrix.target }}
59
+ path: dist
60
+
61
+ windows:
62
+ runs-on: windows-latest
63
+ steps:
64
+ - uses: actions/checkout@v6
65
+ - uses: PyO3/maturin-action@v1
66
+ with:
67
+ target: x86_64-pc-windows-msvc
68
+ args: --release --out dist --strip
69
+ - uses: actions/upload-artifact@v7
70
+ with:
71
+ name: wheels-windows-x86_64
72
+ path: dist
73
+
74
+ sdist:
75
+ runs-on: ubuntu-latest
76
+ steps:
77
+ - uses: actions/checkout@v6
78
+ - uses: PyO3/maturin-action@v1
79
+ with:
80
+ command: sdist
81
+ args: --out dist
82
+ - uses: actions/upload-artifact@v7
83
+ with:
84
+ name: wheels-sdist
85
+ path: dist
86
+
87
+ smoke-test:
88
+ needs: [linux]
89
+ runs-on: ubuntu-latest
90
+ steps:
91
+ - uses: actions/download-artifact@v8
92
+ with:
93
+ pattern: wheels-x86_64-unknown-linux-gnu
94
+ path: dist
95
+ merge-multiple: true
96
+ - uses: actions/setup-python@v6
97
+ with:
98
+ python-version: "3.12"
99
+ - name: Install built wheel
100
+ run: pip install dist/eunoia-*.whl
101
+ - name: Smoke test
102
+ run: |
103
+ python -c "
104
+ import matplotlib
105
+ matplotlib.use('Agg')
106
+ import eunoia as eu
107
+ fit = eu.euler({'A': 10, 'B': 5, 'A&B': 3})
108
+ assert fit.diag_error < 0.01, f'diag_error too high: {fit.diag_error}'
109
+ fit.plot()
110
+ print('eunoia', eu.__version__, 'wheel smoke test OK')
111
+ "
112
+
113
+ publish-testpypi:
114
+ name: Publish to TestPyPI
115
+ needs: [linux, macos, windows, sdist, smoke-test]
116
+ runs-on: ubuntu-latest
117
+ environment:
118
+ name: testpypi
119
+ url: https://test.pypi.org/p/eunoia
120
+ permissions:
121
+ id-token: write # required for trusted publishing
122
+ steps:
123
+ - uses: actions/download-artifact@v8
124
+ with:
125
+ path: dist
126
+ merge-multiple: true
127
+ - uses: pypa/gh-action-pypi-publish@release/v1
128
+ with:
129
+ repository-url: https://test.pypi.org/legacy/
130
+ skip-existing: true
@@ -0,0 +1,123 @@
1
+ name: Publish on PyPi
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+ workflow_dispatch:
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ jobs:
13
+ linux:
14
+ runs-on: ubuntu-latest
15
+ strategy:
16
+ fail-fast: false
17
+ matrix:
18
+ platform:
19
+ - target: x86_64-unknown-linux-gnu
20
+ manylinux: "2_28"
21
+ - target: aarch64-unknown-linux-gnu
22
+ manylinux: "2_28"
23
+ - target: x86_64-unknown-linux-musl
24
+ manylinux: musllinux_1_2
25
+ - target: aarch64-unknown-linux-musl
26
+ manylinux: musllinux_1_2
27
+ steps:
28
+ - uses: actions/checkout@v6
29
+ - uses: PyO3/maturin-action@v1
30
+ with:
31
+ target: ${{ matrix.platform.target }}
32
+ manylinux: ${{ matrix.platform.manylinux }}
33
+ args: --release --out dist --strip
34
+ - uses: actions/upload-artifact@v7
35
+ with:
36
+ name: wheels-${{ matrix.platform.target }}
37
+ path: dist
38
+
39
+ macos:
40
+ runs-on: macos-latest
41
+ strategy:
42
+ fail-fast: false
43
+ matrix:
44
+ target: [x86_64-apple-darwin, aarch64-apple-darwin]
45
+ steps:
46
+ - uses: actions/checkout@v6
47
+ - uses: PyO3/maturin-action@v1
48
+ with:
49
+ target: ${{ matrix.target }}
50
+ args: --release --out dist --strip
51
+ - uses: actions/upload-artifact@v7
52
+ with:
53
+ name: wheels-${{ matrix.target }}
54
+ path: dist
55
+
56
+ windows:
57
+ runs-on: windows-latest
58
+ steps:
59
+ - uses: actions/checkout@v6
60
+ - uses: PyO3/maturin-action@v1
61
+ with:
62
+ target: x86_64-pc-windows-msvc
63
+ args: --release --out dist --strip
64
+ - uses: actions/upload-artifact@v7
65
+ with:
66
+ name: wheels-windows-x86_64
67
+ path: dist
68
+
69
+ sdist:
70
+ runs-on: ubuntu-latest
71
+ steps:
72
+ - uses: actions/checkout@v6
73
+ - uses: PyO3/maturin-action@v1
74
+ with:
75
+ command: sdist
76
+ args: --out dist
77
+ - uses: actions/upload-artifact@v7
78
+ with:
79
+ name: wheels-sdist
80
+ path: dist
81
+
82
+ smoke-test:
83
+ needs: [linux]
84
+ runs-on: ubuntu-latest
85
+ steps:
86
+ - uses: actions/download-artifact@v8
87
+ with:
88
+ pattern: wheels-x86_64-unknown-linux-gnu
89
+ path: dist
90
+ merge-multiple: true
91
+ - uses: actions/setup-python@v6
92
+ with:
93
+ python-version: "3.12"
94
+ - name: Install built wheel
95
+ run: pip install dist/eunoia-*.whl
96
+ - name: Smoke test
97
+ run: |
98
+ python -c "
99
+ import matplotlib
100
+ matplotlib.use('Agg')
101
+ import eunoia as eu
102
+ fit = eu.euler({'A': 10, 'B': 5, 'A&B': 3})
103
+ assert fit.diag_error < 0.01, f'diag_error too high: {fit.diag_error}'
104
+ fit.plot()
105
+ print('eunoia', eu.__version__, 'wheel smoke test OK')
106
+ "
107
+
108
+ publish:
109
+ name: Publish to PyPI
110
+ needs: [linux, macos, windows, sdist, smoke-test]
111
+ runs-on: ubuntu-latest
112
+ if: startsWith(github.ref, 'refs/tags/v')
113
+ environment:
114
+ name: pypi
115
+ url: https://pypi.org/p/eunoia
116
+ permissions:
117
+ id-token: write # required for trusted publishing
118
+ steps:
119
+ - uses: actions/download-artifact@v8
120
+ with:
121
+ path: dist
122
+ merge-multiple: true
123
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,196 @@
1
+ # Devenv
2
+ .devenv*
3
+ devenv.local.nix
4
+ devenv.local.yaml
5
+
6
+ # direnv
7
+ .direnv
8
+
9
+ # pre-commit
10
+ .pre-commit-config.yaml
11
+
12
+ # python -----------------------------------------------
13
+
14
+ # Byte-compiled / optimized / DLL files
15
+ __pycache__/
16
+ *.py[cod]
17
+ *py.class
18
+
19
+ # C extensions
20
+ *.so
21
+
22
+ # Distribution / packaging
23
+ .Python
24
+ build/
25
+ develop-eggs/
26
+ dist/
27
+ downloads/
28
+ eggs/
29
+ .eggs/
30
+ lib/
31
+ lib64/
32
+ parts/
33
+ sdist/
34
+ var/
35
+ wheels/
36
+ share/python-wheels/
37
+ *.egg-info/
38
+ .installed.cfg
39
+ *.egg
40
+ MANIFEST
41
+
42
+ # PyInstaller
43
+ # Usually these files are written by a python script from a template
44
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
45
+ *.manifest
46
+ *.spec
47
+
48
+ # Installer logs
49
+ pip-log.txt
50
+ pip-delete-this-directory.txt
51
+
52
+ # Unit test / coverage reports
53
+ htmlcov/
54
+ .tox/
55
+ .nox/
56
+ .coverage
57
+ .coverage.*
58
+ .cache
59
+ nosetests.xml
60
+ coverage.xml
61
+ *.cover
62
+ *.py,cover
63
+ .hypothesis/
64
+ .pytest_cache/
65
+ cover/
66
+
67
+ # Translations
68
+ *.mo
69
+ *.pot
70
+
71
+ # Django stuff:
72
+ *.log
73
+ local_settings.py
74
+ db.sqlite3
75
+ db.sqlite3-journal
76
+
77
+ # Flask stuff:
78
+ instance/
79
+ .webassets-cache
80
+
81
+ # Scrapy stuff:
82
+ .scrapy
83
+
84
+ # Sphinx documentation
85
+ docs/_build/
86
+
87
+ # PyBuilder
88
+ .pybuilder/
89
+ target/
90
+
91
+ # Jupyter Notebook
92
+ .ipynb_checkpoints
93
+
94
+ # IPython
95
+ profile_default/
96
+ ipython_config.py
97
+
98
+ # pyenv
99
+ # For a library or package, you might want to ignore these files since the code is
100
+ # intended to run in multiple environments; otherwise, check them in:
101
+ # .python-version
102
+
103
+ # pipenv
104
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
105
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
106
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
107
+ # install all needed dependencies.
108
+ #Pipfile.lock
109
+
110
+ # poetry
111
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
112
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
113
+ # commonly ignored for libraries.
114
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
115
+ #poetry.lock
116
+
117
+ # pdm
118
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
119
+ #pdm.lock
120
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
121
+ # in version control.
122
+ # https://pdm.fming.dev/#use-with-ide
123
+ .pdm.toml
124
+
125
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
126
+ __pypackages__/
127
+
128
+ # Celery stuff
129
+ celerybeat-schedule
130
+ celerybeat.pid
131
+
132
+ # SageMath parsed files
133
+ *.sage.py
134
+
135
+ # Environments
136
+ .env
137
+ .venv
138
+ env/
139
+ venv/
140
+ ENV/
141
+ env.bak/
142
+ venv.bak/
143
+
144
+ # Spyder project settings
145
+ .spyderproject
146
+ .spyproject
147
+
148
+ # Rope project settings
149
+ .ropeproject
150
+
151
+ # mkdocs documentation
152
+ /site
153
+
154
+ # mypy
155
+ .mypy_cache/
156
+ .dmypy.json
157
+ dmypy.json
158
+
159
+ # Pyre type checker
160
+ .pyre/
161
+
162
+ # pytype static type analyzer
163
+ .pytype/
164
+
165
+ # Cython debug symbols
166
+ cython_debug/
167
+
168
+ # PyCharm
169
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
170
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
171
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
172
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
173
+ #.idea/
174
+
175
+ # rust -----------------------------------------------
176
+
177
+ # Generated by Cargo
178
+ # will have compiled files and executables
179
+ debug
180
+ target
181
+
182
+ # These are backup files generated by rustfmt
183
+ **/*.rs.bk
184
+
185
+ # MSVC Windows builds of rustc generate these, which store debugging information
186
+ *.pdb
187
+
188
+ # Generated by cargo mutants Contains mutation testing data
189
+ **/mutants.out*/
190
+
191
+ # RustRover
192
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
193
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
194
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
195
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
196
+ #.idea/
@@ -0,0 +1,11 @@
1
+ {
2
+ "manifest-version": 1,
3
+ "baseline-sha": "d003d79019139c6bb4f6f1f743ef68ba8d744fc1",
4
+ "release-targets": [
5
+ {
6
+ "path": ".",
7
+ "version": "0.1.0",
8
+ "tag": "v0.1.0"
9
+ }
10
+ ]
11
+ }