[
  {
    "path": ".coveragerc",
    "content": "[run]\nbranch = True\nomit =\n    */nafas/__main__.py\n    */nafas/__init__.py\n[report]\n# Regexes for lines to exclude from consideration\nexclude_lines =\n    pragma: no cover\n"
  },
  {
    "path": ".github/CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as\ncontributors and maintainers pledge to making participation in our project and\nour community a harassment-free experience for everyone, regardless of age, body\nsize, disability, ethnicity, sex characteristics, gender identity and expression,\nlevel of experience, education, socio-economic status, nationality, personal\nappearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment\ninclude:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or\n advances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic\n address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable\nbehavior and are expected to take appropriate and fair corrective action in\nresponse to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or\nreject comments, commits, code, wiki edits, issues, and other contributions\nthat are not aligned to this Code of Conduct, or to ban temporarily or\npermanently any contributor for other behaviors that they deem inappropriate,\nthreatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces\nwhen an individual is representing the project or its community. Examples of\nrepresenting a project or community include using an official project e-mail\naddress, posting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event. Representation of a project may be\nfurther defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported by contacting the project team at me@sepand.tech. All\ncomplaints will be reviewed and investigated and will result in a response that\nis deemed necessary and appropriate to the circumstances. The project team is\nobligated to maintain confidentiality with regard to the reporter of an incident.\nFurther details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good\nfaith may face temporary or permanent repercussions as determined by other\nmembers of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,\navailable at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html\n\n[homepage]: https://www.contributor-covenant.org\n\nFor answers to common questions about this code of conduct, see\nhttps://www.contributor-covenant.org/faq\n"
  },
  {
    "path": ".github/CONTRIBUTING.md",
    "content": "# Contribution\t\t\t\n\nChanges and improvements are more than welcome! ❤️ Feel free to fork and open a pull request.\t\t\n\n\nPlease consider the following :\n\n\n1. Fork it!\n2. Create your feature branch (under `dev` branch)\n3. Add your functions/methods to proper files\n4. Add standard `docstring` to your functions/methods\n5. Add tests for your functions/methods (`doctest` testcases in `test` folder)\n6. Pass all CI tests\n7. Update `CHANGELOG.md`\n\t- Describe changes under `[Unreleased]` section\n8. Submit a pull request into `dev` (please complete the pull request template)"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "custom: https://github.com/sepandhaghighi/nafas#show-your-support"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.yml",
    "content": "name: Bug Report\ndescription: File a bug report\ntitle: \"[Bug]: \"\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Thanks for your time to fill out this bug report!\n  - type: input\n    id: contact\n    attributes:\n      label: Contact details\n      description: How can we get in touch with you if we need more info?\n      placeholder: ex. email@example.com\n    validations:\n      required: false\n  - type: textarea\n    id: what-happened\n    attributes:\n      label: What happened?\n      description: Provide a clear and concise description of what the bug is.\n      placeholder: >\n        Tell us a description of the bug.\n    validations:\n      required: true\n  - type: textarea\n    id: step-to-reproduce\n    attributes:\n      label: Steps to reproduce\n      description: Provide details of how to reproduce the bug.\n      placeholder: >\n        ex. 1. Go to '...'\n    validations:\n      required: true\n  - type: textarea\n    id: expected-behavior\n    attributes:\n      label: Expected behavior\n      description: What did you expect to happen?\n      placeholder: >\n        ex. I expected '...' to happen\n    validations:\n      required: true\n  - type: textarea\n    id: actual-behavior\n    attributes:\n      label: Actual behavior\n      description: What did actually happen?\n      placeholder: >\n        ex. Instead '...' happened\n    validations:\n      required: true\n  - type: dropdown\n    id: operating-system\n    attributes:\n      label: Operating system\n      description: Which operating system are you using?\n      options:\n        - Windows\n        - macOS\n        - Linux\n      default: 0\n    validations:\n      required: true\n  - type: dropdown\n    id: python-version\n    attributes:\n      label: Python version\n      description: Which version of Python are you using?\n      options:\n        - Python 3.14\n        - Python 3.13\n        - Python 3.12\n        - Python 3.11\n        - Python 3.10\n        - Python 3.9\n        - Python 3.8\n        - Python 3.7\n        - Python 3.6\n      default: 1\n    validations:\n      required: true\n  - type: dropdown\n    id: nafas-version\n    attributes:\n      label: Nafas version\n      description: Which version of Nafas are you using?\n      options:\n        - Nafas 1.5\n        - Nafas 1.4\n        - Nafas 1.3\n        - Nafas 1.2\n        - Nafas 1.1\n        - Nafas 1.0\n        - Nafas 0.9\n        - Nafas 0.8\n        - Nafas 0.7\n        - Nafas 0.6\n        - Nafas 0.5\n        - Nafas 0.4\n        - Nafas 0.3\n        - Nafas 0.2\n        - Nafas 0.1\n      default: 0\n    validations:\n      required: true\n  - type: textarea\n    id: logs\n    attributes:\n      label: Relevant log output\n      description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.\n      render: shell\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\ncontact_links:\n  - name: Discord\n    url: https://discord.com/invite/CtZUNKJHP4\n    about: Ask questions and discuss with other Nafas community members \n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.yml",
    "content": "name: Feature Request\ndescription: Suggest a feature for this project\ntitle: \"[Feature]: \"\nbody:\n  - type: textarea\n    id: description\n    attributes:\n      label: Describe the feature you want to add\n      placeholder: >\n        I'd like to be able to [...]\n    validations:\n      required: true\n  - type: textarea\n    id: possible-solution\n    attributes:\n      label: Describe your proposed solution\n      placeholder: >\n        I think this could be done by [...]\n    validations:\n      required: false\n  - type: textarea\n    id: alternatives\n    attributes:\n      label: Describe alternatives you've considered, if relevant\n      placeholder: >\n        Another way to do this would be [...]\n    validations:\n      required: false\n  - type: textarea\n    id: additional-context\n    attributes:\n      label: Additional context\n      placeholder: >\n        Add any other context or screenshots about the feature request here.\n    validations:\n      required: false\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "#### Reference Issues/PRs\n\n#### What does this implement/fix? Explain your changes.\n\n\n#### Any other comments?\n\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "version: 2\nupdates:\n- package-ecosystem: pip\n  directory: \"/\"\n  schedule:\n    interval: weekly\n    time: \"01:30\"\n  open-pull-requests-limit: 10\n  target-branch: dev\n  assignees:\n      - \"sepandhaghighi\"\n"
  },
  {
    "path": ".github/workflows/publish.yml",
    "content": "# This workflow will upload a Python Package using Twine when a release is created\n# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries\n\nname: Upload Python Package\n\non:\n  push:\n    # Sequence of patterns matched against refs/tags\n    tags:\n      - '*' # Push events to matching v*, i.e. v1.0, v20.15.10\n\njobs:\n  deploy:\n\n    runs-on: ubuntu-22.04\n\n    steps:\n    - uses: actions/checkout@v4\n    - name: Set up Python\n      uses: actions/setup-python@v5\n      with:\n        python-version: '3.x'\n    - name: Install dependencies\n      run: |\n        python -m pip install --upgrade pip\n        pip install setuptools wheel twine\n    - name: Build and publish\n      env:\n        TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}\n        TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}\n      run: |\n        python setup.py sdist bdist_wheel\n        twine upload dist/*.tar.gz\n        twine upload dist/*.whl\n"
  },
  {
    "path": ".github/workflows/test.yml",
    "content": "# This workflow will install Python dependencies, run tests and lint with a variety of Python versions\n# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions\n\nname: CI\n\non:\n  push:\n    branches:\n      - master\n      - dev\n\n  pull_request:\n    branches:\n      - master\n      - dev\n\nenv:\n  TEST_PYTHON_VERSION: 3.9\n  TEST_OS: 'ubuntu-22.04'\n\njobs:\n  build:\n\n    runs-on: ${{ matrix.os }}\n    strategy:\n      fail-fast: false\n      matrix:\n        os: [ubuntu-22.04, windows-2022, macos-15-intel]\n        python-version: [3.7, 3.8, 3.9, 3.10.5, 3.11.0, 3.12.0, 3.13.0, 3.14.0]\n    steps:\n    - uses: actions/checkout@v4\n    - name: Set up Python ${{ matrix.python-version }}\n      uses: actions/setup-python@v5\n      with:\n        python-version: ${{ matrix.python-version }}\n    - name: Installation\n      run: |\n        python -m pip install --upgrade pip\n        pip install .\n    - name: First test\n      run: |\n        nafas --version --color=\"red\" --bg-color=\"blue\" --intensity=\"bright\"\n        nafas --generate-config=\"test.json\"\n    - name: Install dev-requirements\n      run: |\n        python otherfiles/requirements-splitter.py\n        pip install --upgrade --upgrade-strategy=only-if-needed -r test-requirements.txt\n    - name: Version check\n      run: |\n        python otherfiles/version_check.py\n      if: matrix.python-version == env.TEST_PYTHON_VERSION\n    - name: Test with pytest\n      run: |\n        python -m pytest test --cov=nafas --cov-report=term\n    - name: Other tests\n      run: |\n        python -m vulture nafas/ setup.py --min-confidence 65 --exclude=__init__.py --sort-by-size\n        python -m bandit -r nafas -s B311,B605,B607\n        python -m pydocstyle --match-dir=nafas -v\n      if: matrix.python-version == env.TEST_PYTHON_VERSION\n    - name: Upload coverage to Codecov\n      uses: codecov/codecov-action@v4\n      with:\n          fail_ci_if_error: true\n          token: ${{ secrets.CODECOV_TOKEN }}\n      if: matrix.python-version == env.TEST_PYTHON_VERSION && matrix.os == env.TEST_OS\n"
  },
  {
    "path": ".gitignore",
    "content": "# Created by .ignore support plugin (hsz.mobi)\n### Python template\n# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C extensions\n*.so\n\n# Distribution / packaging\n.Python\nenv/\nbuild/\ndevelop-eggs/\ndist/\ndownloads/\neggs/\n.eggs/\nlib/\nlib64/\nparts/\nsdist/\nvar/\n*.egg-info/\n.installed.cfg\n*.egg\n\n# PyInstaller\n#  Usually these files are written by a python script from a template\n#  before PyInstaller builds the exe, so as to inject date/other infos into it.\n*.manifest\n\n# Installer logs\npip-log.txt\npip-delete-this-directory.txt\n\n# Unit test / coverage reports\nhtmlcov/\n.tox/\n.coverage\n.coverage.*\n.cache\nnosetests.xml\ncoverage.xml\n*,cover\n.hypothesis/\n\n# Translations\n*.mo\n*.pot\n\n# Django stuff:\n*.log\nlocal_settings.py\n\n# Flask stuff:\ninstance/\n.webassets-cache\n\n# Scrapy stuff:\n.scrapy\n\n# Sphinx documentation\ndocs/_build/\n\n# PyBuilder\ntarget/\n\n# Jupyter Notebook\n.ipynb_checkpoints\n\n# pyenv\n.python-version\n\n# celery beat schedule file\ncelerybeat-schedule\n\n# dotenv\n.env\n\n# virtualenv\n.venv/\nvenv/\nENV/\n\n# Spyder project settings\n.spyderproject\n\n# Rope project settings\n.ropeproject\n### Example user template template\n### Example user template\n\n# IntelliJ project files\n.idea\n*.iml\nout\ngen\n"
  },
  {
    "path": "AUTHORS.md",
    "content": "# Core Developers\n----------\n- [@sepandhaghighi](http://github.com/sepandhaghighi)\n- [@sadrasabouri](https://github.com/sadrasabouri)\n\n\n# Other Contributors\n----------\n- [@sarahfard](https://github.com/sarahfard) **\n- [@oscarArismendi](https://github.com/oscarArismendi)\n- [@AHReccese](https://github.com/AHReccese)\n\n\n** Graphic designer\n\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)\nand this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).\n\n## [Unreleased]\n## [1.5] - 2026-05-04\n### Added\n- Fire program\n- Retention program\n- Swooning program\n- `--generate-config` argument\n- `--color` argument\n- `--bg-color` argument\n- `--intensity` argument\n### Changed\n- `README.md` modified\n- `Python 3.14` added to `test.yml`\n- Test system modified\n- CLI functions modified\n## [1.4] - 2025-07-29\n### Added\n- `ca1` speaker audio files\n- `ca2` speaker audio files\n- `au1` speaker audio files\n- `au2` speaker audio files\n- `uk1` speaker audio files\n- `uk2` speaker audio files\n### Changed\n- Build script updated\n- `README.md` modified\n- `line` function renamed to `print_line`\n- `bpm_calc` function renamed to `calculate_bpm`\n- `time_calc` function renamed to `calculate_time`\n- `time_average_calc` function renamed to `calculate_average_time`\n- `time_convert` function renamed to `convert_time`\n- `left_justify` function renamed to `justify_left`\n- `justify` function renamed to `justify_text`\n- `sound_check` function renamed to `check_sound`\n- `nafas_description_print` function renamed to `print_nafas_description`\n- `program_details_print` function renamed to `print_program_details`\n- `input_filter` function renamed to `filter_input`\n- `get_input_standard` function renamed to `get_standard_input`\n- `run` function renamed to `run_program`\n## [1.3] - 2025-06-27\n### Added\n- `--speaker` argument\n- `us2` speaker audio files\n- `in1` speaker audio files\n- `in2` speaker audio files\n- `cn1` speaker audio files\n- `cn2` speaker audio files\n### Changed\n- `README.md` modified\n## [1.2] - 2025-06-04\n### Added\n- Coherent program\n- Breaths Per Minute (BPM)\n### Changed\n- `description_print` function renamed to `nafas_description_print`\n- `program_description_print` function renamed to `program_details_print`\n-  Python typing features added to all modules\n-  `Python 3.6` support dropped\n-  Test system modified\n-  `PROGRAMS.md` updated\n## [1.1] - 2025-04-10\n### Added\n- Survey form\n- `--config` argument\n- `--skip-intro` argument\n### Changed\n- `README.md` modified\n## [1.0] - 2025-03-10\n### Added\n- Calming3 program\n- Box program\n### Changed\n- `README.md` modified\n- String templates modified\n- `PROGRAMS.md` updated\n## [0.9] - 2025-01-06\n### Added\n- Energizing program\n- `PROGRAMS.md`\n- Cautions message\n### Changed\n- `README.md` modified\n- `AUTHORS.md` updated\n- Menu updated\n- Exit bug fixed\n- Program details updated\n## [0.8] - 2024-11-04\n### Added\n- Balancing program\n- `--silent` argument\n- `clear_screen` function\n### Changed\n- GitHub actions are limited to the `dev` and `master` branches\n- Restart mode updated\n- Exit bug fixed\n- `Python 3.13` added to `test.yml`\n- Messages and templates moved to `params.py`\n## [0.7] - 2024-08-27\n### Added\n- `feature_request.yml` template\n- `config.yml` for issue template\n- `sound_check` function\n- `SECURITY.md`\n### Changed\n- Silence added to the start of sounds\n- Bug report template modified\n- `playsound` replaced with `nava`\n- `nava` added to `requirements.txt`\n- Test system modified\n- Build system modified\n- `get_input_standard` function modified\n- `Python 3.11` added to `test.yml`\n- `Python 3.12` added to `test.yml`\n- `Python 3.5` support dropped\n- CLI mode updated\n- Exit message updated\n- `README.md` modified\n## [0.6] - 2022-06-22\n### Added\n- Calming2 program\n### Changed\n- Calming program renamed to Calming1\n- Logo updated\n- `README.md` modified\n## [0.5] - 2022-05-09\n### Added\n- Decision-Making program\n- `time_calc` function\n- `time_average_calc` function\n### Changed\n- `AUTHORS.md` updated\n- License updated\n- `README.md` modified\n- `Python 3.10` added to `test.yml`\n- `time_convert` function modified\n- `get_input_standard` function modified\n- Menu updated\n- Relax program renamed to Relax1\n- 4-7-8 program renamed to Relax2\n- 7-11 program renamed to Relax3\n## [0.4] - 2021-05-12\n### Added\n- `start.wav`\n- `well_done.wav`\n- `preparing.wav`\n- `requirements-splitter.py`\n- 4-7-8 program\n- 7-11 program\n### Changed\n- Sound speaker changed\n- Test system modified\n- Menu optimized\n## [0.3] - 2021-02-09\n### Changed\n- Sounds bug in pypi fixed\n- Icon modified\n- Menu optimized\n## [0.2] - 2021-01-29\n### Added\n- `_playsound_async` function\n- `play_sound` function\n- `inhale.wav`\n- `exhale.wav`\n- `sustain.wav`\n- `retain.wav`\n- `get_sound_path` function\n- `program_description_print` function\n- `time_convert` function\n### Changed\n- Menu optimized\n- Test system modified\n- `get_program_dict` function renamed to `get_program_data`\n- `program_dict` parameter renamed to `program_data`\n- `input_dict` parameter renamed to `input_data`\n- `README.md` updated\n## [0.1] - 2020-10-30\n### Added\n- Clear Mind program\n- Relax program\n- Calming program\n- Power program\n- Anti-Stress program\n- Anti-Appetite program \n- Cigarette Replace program\n\n[Unreleased]: https://github.com/sepandhaghighi/nafas/compare/v1.5...dev\n[1.5]: https://github.com/sepandhaghighi/nafas/compare/v1.4...v1.5\n[1.4]: https://github.com/sepandhaghighi/nafas/compare/v1.3...v1.4\n[1.3]: https://github.com/sepandhaghighi/nafas/compare/v1.2...v1.3\n[1.2]: https://github.com/sepandhaghighi/nafas/compare/v1.1...v1.2\n[1.1]: https://github.com/sepandhaghighi/nafas/compare/v1.0...v1.1\n[1.0]: https://github.com/sepandhaghighi/nafas/compare/v0.9...v1.0\n[0.9]: https://github.com/sepandhaghighi/nafas/compare/v0.8...v0.9\n[0.8]: https://github.com/sepandhaghighi/nafas/compare/v0.7...v0.8\n[0.7]: https://github.com/sepandhaghighi/nafas/compare/v0.6...v0.7\n[0.6]: https://github.com/sepandhaghighi/nafas/compare/v0.5...v0.6\n[0.5]: https://github.com/sepandhaghighi/nafas/compare/v0.4...v0.5\n[0.4]: https://github.com/sepandhaghighi/nafas/compare/v0.3...v0.4\n[0.3]: https://github.com/sepandhaghighi/nafas/compare/v0.2...v0.3\n[0.2]: https://github.com/sepandhaghighi/nafas/compare/v0.1...v0.2\n[0.1]: https://github.com/sepandhaghighi/nafas/compare/c58087a...v0.1\n\n\n\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2020 Sepand Haghighi\n\nCopyright (c) 2020 Sadra Sabouri\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "MANIFEST.in",
    "content": "include LICENSE\ninclude *.md\ninclude *.spec\ninclude *.txt\ninclude *.yml\ninclude *.ini\ninclude nafas/sounds/*.wav\ninclude nafas/sounds/*/*.wav"
  },
  {
    "path": "NAFAS.spec",
    "content": "# -*- mode: python -*-\n\nblock_cipher = None\n\nnafas_version = \"1.5\"\n\na = Analysis(['nafas/__main__.py'],\n             pathex=['nafas'],\n             binaries=[],\n             datas=[('nafas/sounds/silence.wav', 'nafas/sounds'), ('nafas/sounds/us1/*.wav', 'nafas/sounds/us1')],\n             hiddenimports=[],\n             hookspath=[],\n             runtime_hooks=[],\n             excludes=[],\n             win_no_prefer_redirects=False,\n             win_private_assemblies=False,\n             cipher=block_cipher)\npyz = PYZ(a.pure, a.zipped_data,\n             cipher=block_cipher)\nexe = EXE(pyz,\n          a.scripts,\n          a.binaries,\n          a.zipfiles,\n          a.datas,\n          name='NAFAS-'+nafas_version,\n          debug=False,\n          strip=False,\n          upx=True,\n          runtime_tmpdir=None,\n\t\t  icon='otherfiles/icon.ico',\n\t\t  version=\"otherfiles/Version.rc\",\n          console=True )\n"
  },
  {
    "path": "PROGRAMS.md",
    "content": "# Nafas Breathing Programs\n\n**Last Update: 2026-02-19**\n\n| **Program**         | **Description**                                                                                                                 | **Level**         | **Ratios**<br>**(I:R:E:S)**            | **Unit**<br>**(Seconds)** | **Cycles**      |\n|----------------------|-------------------------------------------------------------------------------------------------------------------------------|-------------------|-----------------------|--------------------------|----------------|\n| Clear Mind           | Short program to reduce mental fog and improve focus. Useful for developers during coding breaks. Beneficial for those needing quick mental refreshment. | B<br>M<br>A       | 1:0:3:0<br>1:0:4:0<br>1:0:5:0 | 3<br>3<br>3                | 35<br>28<br>24 |\n| Relax1               | Relaxation-focused program to calm nerves. Ideal for use after intense coding sessions. Useful for programmers managing stress.       | B<br>M<br>A       | 1:0:2:2<br>1:0:2:3<br>1:0:2:4 | 3<br>3<br>3                | 28<br>24<br>22 |\n| Relax2               | Enhanced relaxation program with a focus on breathing depth. Suitable for unwinding after long work sessions.               | B<br>M<br>A       | 4:7:8:0<br>4:7:8:0<br>4:7:8:0 | 1<br>1<br>1                | 4<br>8<br>12   |\n| Relax3               | Deeper relaxation exercise for stress relief and a more meditative state. Ideal for unwinding after complex projects.        | B<br>M<br>A       | 7:0:11:0<br>7:0:11:0<br>7:0:11:0 | 1<br>1<br>1                | 15<br>20<br>24 |\n| Calming1             | Soothing breathing pattern, helpful for reducing anxiety. Beneficial for long working hours and maintaining calm.           | B<br>M<br>A       | 1:2:1:2<br>1:3:1:3<br>1:4:1:4 | 3<br>3<br>3                | 24<br>22<br>20 |\n| Calming2             | An extended version of the calming routine, providing a longer period of relaxation and anxiety reduction. Useful for balancing high-stress situations. | B<br>M<br>A       | 5:0:5:5<br>5:0:5:5<br>5:0:5:5 | 1<br>1<br>1                | 4<br>6<br>8    |\n| Calming3             | A breathing routine designed to deepen relaxation and improve focus. Suitable for transitioning from mild stress to a state of balance and tranquility. | B<br>M<br>A       | 4:0:6:0<br>6:1:8:4<br>4:1:12:1 | 1<br>1<br>1               | 6<br>8<br>10    |\n| Power                | Energizing breathing, designed for boosting energy and alertness. Suitable for users feeling fatigue.                       | B<br>M<br>A       | 1:2:2:0<br>1:3:2:0<br>1:4:2:0 | 3<br>3<br>3                | 28<br>24<br>20 |\n| Harmony              | Balancing exercise to promote relaxation and focus. Ideal for programmers looking to maintain concentration.                | B<br>M<br>A       | 1:3:2:1<br>1:4:2:1<br>1:5:2:1 | 3<br>3<br>3                | 20<br>18<br>16 |\n| Anti-Stress          | Specialized for stress relief, particularly useful during high-stress tasks or debugging sessions.                             | B<br>M<br>A       | 3:0:0.66:0<br>4:0:0.66:0<br>5:0:0.66:0 | 3<br>3<br>3                | 20<br>17<br>14 |\n| Anti-Appetite        | Breathing program to manage cravings and avoid unnecessary snacking during work. Beneficial for users seeking appetite control. | B<br>M<br>A       | 5:0:5:5<br>6:0:5:5<br>7:0:5:5 | 1<br>1<br>1                | 40<br>38<br>36 |\n| Cigarette Replace    | Alternative to smoking breaks, encouraging mindful breathing. Suitable for smokers looking to reduce habit triggers.        | B<br>M<br>A       | 2:1.1:2.2:0.8<br>3:1.1:2.2:0.8<br>4:1.1:2.2:0.8 | 2<br>2<br>2                | 23<br>21<br>19 |\n| Decision-Making      | Breathing exercise to improve focus before making critical decisions. Useful for developers or managers.                    | B<br>M<br>A       | 5:2:7:0<br>5:2:7:0<br>5:2:7:0 | 1<br>1<br>1                | 6<br>10<br>14  |\n| Balancing            | Designed for achieving inner balance. Useful for users needing a brief grounding exercise during hectic schedules.          | B<br>M<br>A       | 6:0:6:0<br>8:1:8:1<br>6:2:6:2 | 1<br>1<br>1                | 6<br>8<br>10   |\n| Energizing           | Breathing program to recharge energy levels and improve alertness. Ideal for users or professionals needing a quick boost of focus and energy. | B<br>M<br>A | 6:0:4:0<br>6:4:6:1<br>6:6:6:1 | 1<br>1<br>1   | 6<br>8<br>10   | \n| Box                  | A breathing technique involving equal counts of inhaling, retaining, exhaling, and sustaining to enhance focus and calm. | B<br>M<br>A | 4:4:4:4<br>4:4:4:4<br>4:4:4:4 | 1<br>1<br>1   | 4<br>8<br>15   | \n| Coherent             | Breathing program for optimizing heart rate variability (HRV). It triggers the ideal breath rate for relaxation and emotional regulation. Useful for daily stress management or biofeedback training. | B<br>M<br>A | 5:0:5:0<br>5:0:5:0<br>5:0:5:0 | 1<br>1<br>1 | 30<br>50<br>70 |\n| Fire          | Agnisar Pranayama, or Fire Breath, is a powerful yoga breathing technique, Agni means fire, and Sara stands for movement; Agnisara Kriya is the process of cleansing or purifying the organs of the abdomen, by the heat (fire) generated during the practice of this breathing technique. | B<br>M<br>A | 3:0:5:12<br>3:0:5:12<br>3:0:5:12 | 1<br>1<br>1 | 10<br>20<br>30 |\n| Retention     | Kevala Kumbhaka, or Breath Retention, is an advanced yogic practice involving holding the breath after exhalation. This technique promotes deep inner stillness, enhances concentration, and balances the nervous system, making it a powerful tool for achieving mental clarity and heightened awareness. | B<br>M<br>A | 2:0:2:12<br>2:0:2:12<br>2:0:2:12 | 1<br>1<br>1 | 5<br>10<br>15 |\n| Swooning      | It is a calming yogic breathing technique that promotes relaxation and heightened consciousness. By extending breath retention and focusing inward, it helps to quiet the mind, reduce stress, and promote mental stillness. | B<br>M<br>A | 5:10:7:0<br>5:10:7:0<br>5:10:7:0 | 1<br>1<br>1 | 7<br>12<br>21 |\n\n**Notes**:\n- *I: Inhale, R: Retain, E: Exhale, S: Sustain, B: Beginner, M: Medium, A: Advanced*\n"
  },
  {
    "path": "README.md",
    "content": "<div align=\"center\">\n<img src=\"https://github.com/sepandhaghighi/nafas/raw/master/otherfiles/logo.png\" width=320px>\n<h1>Nafas: A Breathing Gymnastics Application</h1>\n<hr>\n<a href=\"https://badge.fury.io/py/nafas\"><img src=\"https://badge.fury.io/py/nafas.svg\" alt=\"PyPI version\"></a>\n<a href=\"https://codecov.io/gh/sepandhaghighi/nafas\"><img src=\"https://codecov.io/gh/sepandhaghighi/nafas/branch/master/graph/badge.svg\" alt=\"Codecov\"></a>\n<a href=\"https://www.python.org/\"><img src=\"https://img.shields.io/badge/built%20with-Python3-green.svg\" alt=\"built with Python3\"></a>\n<a href=\"https://github.com/sepandhaghighi/nafas\"><img alt=\"GitHub repo size\" src=\"https://img.shields.io/github/repo-size/sepandhaghighi/nafas\"></a>\n<a href=\"https://discord.gg/CtZUNKJHP4\"><img src=\"https://img.shields.io/discord/901570530145107978.svg\" alt=\"Discord Channel\"></a>\n</div>\t\n\n\t\t\t\t\n## Overview\t\t\t\t\t\t\nBreathing gymnastics is a system of breathing exercises that focuses on the treatment of various diseases and general health promotion.\n**Nafas** is a collection of breathing gymnastics designed to reduce the exhaustion of long working hours.\nWith multiple breathing patterns, **Nafas** helps you find your way to a detoxified energetic workday and also improves your concentration by increasing the oxygen level.\nNo need to walk away to take a break, just sit comfortably, run **Nafas** and let the journey begin.\n**Nafas** means breath in Persian.\n\n**Nafas** offers a selection of predefined breathing exercise programs.\nEach program consists of multiple cycles.\nThe exercises begin with a gentle preparation phase to help users settle in and focus, followed by a series of timed inhales and exhales.\nBetween these breaths, the programs incorporate deliberate pauses that allow users to retain and sustain their breath.\nThese cycles aim to enhance both physical and mental well-being.\n\n<div align=\"center\">\n\t<img src=\"https://github.com/sepandhaghighi/nafas/raw/master/otherfiles/overview.png\" width=300px alt=\"Nafas Programs' Cycle\">\n\t<p>Nafas Programs' Cycle</p>\n</div>\n\n<table>\n\t<tr> \n\t\t<td align=\"center\">Open Hub</td>\n\t\t<td align=\"center\"><a href=\"https://www.openhub.net/p/nafas\"><img src=\"https://www.openhub.net/p/nafas/widgets/project_thin_badge.gif\"></a></td>\t\n\t</tr>\n\t<tr>\n\t\t<td align=\"center\">PyPI Counter</td>\n\t\t<td align=\"center\"><a href=\"http://pepy.tech/project/nafas\"><img src=\"http://pepy.tech/badge/nafas\"></a></td>\n\t</tr>\n\t<tr>\n\t\t<td align=\"center\">Github Stars</td>\n\t\t<td align=\"center\"><a href=\"https://github.com/sepandhaghighi/nafas\"><img src=\"https://img.shields.io/github/stars/sepandhaghighi/nafas.svg?style=social&label=Stars\"></a></td>\n\t</tr>\n</table>\n\n\n\n<table>\n\t<tr> \n\t\t<td align=\"center\">Branch</td>\n\t\t<td align=\"center\">master</td>\t\n\t\t<td align=\"center\">dev</td>\t\n\t</tr>\n\t<tr>\n\t\t<td align=\"center\">CI</td>\n\t\t<td align=\"center\"><img src=\"https://github.com/sepandhaghighi/nafas/actions/workflows/test.yml/badge.svg?branch=master\"></td>\n\t\t<td align=\"center\"><img src=\"https://github.com/sepandhaghighi/nafas/actions/workflows/test.yml/badge.svg?branch=dev\"></td>\n\t</tr>\n</table>\n\n\n<table>\n\t<tr> \n\t\t<td align=\"center\">Code Quality</td>\n\t\t<td align=\"center\"><a href=\"https://app.codacy.com/gh/sepandhaghighi/nafas/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade\"><img src=\"https://app.codacy.com/project/badge/Grade/b2be5ce052bc43a89713ac4aec6f8d11\"/></a></td>\n\t\t<td align=\"center\"><a href=\"https://www.codefactor.io/repository/github/sepandhaghighi/nafas\"><img src=\"https://www.codefactor.io/repository/github/sepandhaghighi/nafas/badge\" alt=\"CodeFactor\" /></a></td>\t\t\n\t</tr>\n</table>\n\n\n## Installation\t\t\n\n### Source Code\n- Download [Version 1.5](https://github.com/sepandhaghighi/nafas/archive/v1.5.zip) or [Latest Source](https://github.com/sepandhaghighi/nafas/archive/dev.zip)\n- `pip install .`\t\t\t\t\n\n### PyPI\n\n- Check [Python Packaging User Guide](https://packaging.python.org/installing/)     \n- `pip install nafas==1.5`\n\n\n## Usage\t\n\nℹ️ You can use `nafas`, `python -m nafas` to run this program\n\nℹ️ Checkout the available programs in [PROGRAMS.md](https://github.com/sepandhaghighi/nafas/blob/master/PROGRAMS.md)\n\n### Version\n\n```console\nnafas --version\n```\n\n### Basic\n\n```console\nnafas\n```\n\n### Silent Mode\n\nℹ️ This mode will disable the sound playing system\n\n```console\nnafas --silent\n```\t\n\n### Speaker\n\n⚠️ This mode may not be supported on all systems\n\nℹ️ Customize your experience by choosing from a set of speaker voices to guide you through the exercises\n\nℹ️ The default speaker is `us1`\n\nℹ️ You can specify the speaker using the `--speaker`:\n\n```console\nnafas --speaker=us1\n```\n\nChoose your speaker from the following list:\n| ID | Description |\n|:--:|:-----------:|\n| `us1` | Feminine voice with a US accent |\n| `us2` | Masculine voice with a US accent |\n| `in1` | Feminine voice with an Indian accent |\n| `in2` | Masculine voice with an Indian accent |\n| `cn1` | Feminine voice with a Chinese accent |\n| `cn2` | Masculine voice with a Chinese accent |\n| `ca1` | Feminine voice with a Canadian accent |\n| `ca2` | Masculine voice with a Canadian accent |\n| `au1` | Feminine voice with an Australian accent |\n| `au2` | Masculine voice with an Australian accent |\n| `uk1` | Feminine voice with a British accent |\n| `uk2` | Masculine voice with a British accent |\n\n\n### Skip Intro\n\nℹ️ This mode will skip the introduction\n\n```console\nnafas --skip-intro\n```\t\n\n### Color\n\n⚠️ This mode may not be supported on all systems\n\nℹ️ This mode will change the text color\n\nℹ️ Valid choices: [`black`, `red`, `green`, `yellow`, `blue`, `magenta`, `cyan`, `white`, `lightblack`, `lightred`, `lightgreen`, `lightyellow`, `lightblue`, `lightmagenta`, `lightcyan`, `lightwhite`]\n\nℹ️ The default color is `white`\n\n```console\nnafas --color=\"red\"\n```\n\n### Background Color\n\n⚠️ This mode may not be supported on all systems\n\nℹ️ This mode will change the background color\n\nℹ️ Valid choices: [`black`, `red`, `green`, `yellow`, `blue`, `magenta`, `cyan`, `white`, `lightblack`, `lightred`, `lightgreen`, `lightyellow`, `lightblue`, `lightmagenta`, `lightcyan`, `lightwhite`]\n\nℹ️ The default background color is `black`\n\n```console\nnafas --color=\"red\" --bg-color=\"blue\"\n```\n\n### Intensity\n\n⚠️ This mode may not be supported on all systems\n\nℹ️ This mode will change the text intensity\n\nℹ️ Valid choices: [`normal`, `bright`, `dim`]\n\nℹ️ The default intensity is `normal`\n\n```console\nnafas --color=\"red\" --intensity=\"bright\"\n```\n\n### Custom Config\n\nℹ️ Users can either generate a starter configuration file or load their own custom configurations\n\n#### Generate a Starter Config\n\nℹ️ This will create a base configuration file at the specified path\n\n```console\nnafas --generate-config=\"new_program.json\"\n```\n\n#### Load an Existing Config\n\n```console\nnafas --config=\"program1.json\"\n```\n\nConfig example:\n\n```json\n{\n    \"name\": \"program1\",\n    \"unit\": 2,\n    \"pre\": 3,\n    \"cycle\": 10,\n    \"ratio\": {\n        \"inhale\": 2,\n        \"exhale\": 2,\n        \"retain\": 3,\n        \"sustain\": 4\n    }\n}\n```\n\n## Screen Record\n\n<div align=\"center\">\n\n<img src=\"https://github.com/sepandhaghighi/nafas/raw/master/otherfiles/help.gif\" alt=\"Screen Record\">\n\n</div>\n\n\n## Issues & Bug Reports\t\t\t\n\nJust fill an issue and describe it. We'll check it ASAP!\n\n- Please complete the issue template\n\nYou can also join our discord server\n\n<a href=\"https://discord.gg/CtZUNKJHP4\">\n  <img src=\"https://img.shields.io/discord/901570530145107978.svg?style=for-the-badge\" alt=\"Discord Channel\">\n</a>\n \t\t\t\n\n## References\n\n<blockquote>1- <a href=\"https://pranabreath.info\">Prana Breath</a> </blockquote>\n\n<blockquote>2- Rickard, Kathleen Benjamin, Dorothy J. Dunn, and Virginia M. Brouch. \"Breathing techniques associated with improved health outcomes.\" (2015). </blockquote>\n\n<blockquote>3- Zaccaro, Andrea, Andrea Piarulli, Marco Laurino, Erika Garbella, Danilo Menicucci, Bruno Neri, and Angelo Gemignani. \"How breath-control can change your life: a systematic review on psycho-physiological correlates of slow breathing.\" Frontiers in human neuroscience 12 (2018): 353. </blockquote>\n\n<blockquote>4- Brook, Robert D., Lawrence J. Appel, Melvyn Rubenfire, Gbenga Ogedegbe, John D. Bisognano, William J. Elliott, Flavio D. Fuchs et al. \"Beyond medications and diet: alternative approaches to lowering blood pressure: a scientific statement from the American Heart Association.\" Hypertension 61, no. 6 (2013): 1360-1383. </blockquote>\t\n\n<blockquote>5- Russo, Marc A., Danielle M. Santarelli, and Dean O’Rourke. \"The physiological effects of slow breathing in the healthy human.\" Breathe 13, no. 4 (2017): 298-309. </blockquote>\t\n\n<blockquote>6- Bujatti, M., and P. Biederer. \"Serotonin, noradrenaline, dopamine metabolites in transcendental meditation-technique.\" Journal of Neural Transmission 39, no. 3 (1976): 257-267. </blockquote>\n\n<blockquote>7- Martarelli, Daniele, Mario Cocchioni, Stefania Scuri, and Pierluigi Pompei. \"Diaphragmatic breathing reduces exercise-induced oxidative stress.\" Evidence-Based Complementary and Alternative Medicine 2011 (2011). </blockquote>\t\t\n\n<blockquote>8- <a href=\"https://www.drweil.com/videos-features/videos/breathing-exercises-4-7-8-breath/\">DrWeil, Integrative Medicine & Healthy Living</a> </blockquote>\n\n<blockquote>9- <a href=\"https://www.hgi.org.uk/resources/delve-our-extensive-library/resources-and-techniques/7-11-breathing-how-does-deep\">Human Givens Institute</a> </blockquote>\n\n<blockquote>10- <a href=\"https://www.inc.com/mithu-storoni/this-2-minute-breathing-exercise-can-help-you-make-better-decisions-according-to-a-new-study.html\">This 2-Minute Breathing Exercise Can Help You Make Better Decisions</a> </blockquote>\n\n<blockquote>11- <a href=\"https://k12.thoughtfullearning.com/minilesson/using-5-5-5-breathing-calm-down\">Using 5-5-5 Breathing to Calm Down</a> </blockquote>\n\t\t\t\t\t\n<blockquote>12- <a href=\"https://ttsmp3.com/\">Free Text-To-Speech and Text-to-MP3 for US English</a> </blockquote>\n\n<blockquote>13- <a href=\"https://www.yogabasics.com/practice/pranayama/\">Pranayama Breathing Techniques and Tips</a> </blockquote>\n\n<blockquote>14- <a href=\"https://health.clevelandclinic.org/box-breathing-benefits\">Box Breathing Benefits and Techniques</a> </blockquote>\n\n<blockquote>15- <a href=\"https://www.medicalnewstoday.com/articles/321805#how-to-do-it\">Box breathing: How to do it, benefits, and tips</a> </blockquote>\n\n<blockquote>16- <a href=\"https://pubmed.ncbi.nlm.nih.gov/24380741/\">Breathing at a rate of 5.5 breaths per minute with equal inhalation-to-exhalation ratio increases heart rate variability</a> </blockquote>\n\n<blockquote>17- <a href=\"https://www.youtube.com/watch?v=dPkpW5lqL3E\">Coherent Breathing Timer - 6 Breaths Per Minute | 5 Seconds in / 5 Seconds Out | With Bells</a> </blockquote>\n\n<blockquote>18- <a href=\"https://play.google.com/store/apps/details?id=pranayama.yoga.breathingexercises&hl=en\">Pranayama : Breathing Exercise</a></blockquote>\n\n## Cite\n\nIf you use **Nafas** in your research, we would appreciate citations to the following paper:\n\n\n[Sabouri, Sadra, and Sepand Haghighi. \"Nafas: Breathing Gymnastics Application.\" *arXiv preprint arXiv:2412.04667* (2024).](https://arxiv.org/abs/2412.04667)\n\n\n```bibtex\n@article{sabouri2024nafas,\n  title={Nafas: Breathing Gymnastics Application},\n  author={Sabouri, Sadra and Haghighi, Sepand},\n  journal={arXiv preprint arXiv:2412.04667},\n  year={2024}\n}\n```\n\n## Show Your Support\n\t\t\t\t\t\t\t\t\n<h3>Star This Repo</h3>\t\t\t\t\t\n\nGive a ⭐️ if this project helped you!\n\n<h3>Donate to Our Project</h3>\t\n\n<h4>Bitcoin</h4>\n1KtNLEEeUbTEK9PdN6Ya3ZAKXaqoKUuxCy\n<h4>Ethereum</h4>\n0xcD4Db18B6664A9662123D4307B074aE968535388\n<h4>Litecoin</h4>\nLdnz5gMcEeV8BAdsyf8FstWDC6uyYR6pgZ\n<h4>Doge</h4>\nDDUnKpFQbBqLpFVZ9DfuVysBdr249HxVDh\n<h4>Tron</h4>\nTCZxzPZLcJHr2qR3uPUB1tXB6L3FDSSAx7\n<h4>Ripple</h4>\nrN7ZuRG7HDGHR5nof8nu5LrsbmSB61V1qq\n<h4>Binance Coin</h4>\nbnb1zglwcf0ac3d0s2f6ck5kgwvcru4tlctt4p5qef\n<h4>Tether</h4>\n0xcD4Db18B6664A9662123D4307B074aE968535388\n<h4>Dash</h4>\nXd3Yn2qZJ7VE8nbKw2fS98aLxR5M6WUU3s\n<h4>Stellar</h4>\t\t\nGALPOLPISRHIYHLQER2TLJRGUSZH52RYDK6C3HIU4PSMNAV65Q36EGNL\n<h4>Zilliqa</h4>\nzil1knmz8zj88cf0exr2ry7nav9elehxfcgqu3c5e5\n<h4>Coffeete</h4>\n<a href=\"http://www.coffeete.ir/opensource\">\n<img src=\"http://www.coffeete.ir/images/buttons/lemonchiffon.png\" style=\"width:260px;\" />\n</a>\n"
  },
  {
    "path": "SECURITY.md",
    "content": "# Security Policy\n\n## Supported Versions\n\n| Version       | Supported          |\n| ------------- | ------------------ |\n| 1.5           | :white_check_mark: |\n| < 1.5         | :x:                |\n\n## Reporting a Vulnerability\n\nPlease report security vulnerabilities by email to [me@sepand.tech](mailto:me@sepand.tech \"me@sepand.tech\").\n\nIf the security vulnerability is accepted, a dedicated bugfix release will be issued as soon as possible (depending on the complexity of the fix)."
  },
  {
    "path": "autopep8.bat",
    "content": "python -m autopep8 nafas --recursive --aggressive --aggressive --in-place --pep8-passes 2000 --max-line-length 120 --verbose\npython -m autopep8 setup.py --recursive --aggressive --aggressive --in-place --pep8-passes 2000 --max-line-length 120 --verbose\npython -m autopep8 otherfiles --recursive --aggressive --aggressive --in-place --pep8-passes 2000 --max-line-length 120 --verbose\n"
  },
  {
    "path": "autopep8.sh",
    "content": "#!/bin/sh\npython -m autopep8 nafas --recursive --aggressive --aggressive --in-place --pep8-passes 2000 --max-line-length 120 --verbose\npython -m autopep8 setup.py --recursive --aggressive --aggressive --in-place --pep8-passes 2000 --max-line-length 120 --verbose\npython -m autopep8 otherfiles --recursive --aggressive --aggressive --in-place --pep8-passes 2000 --max-line-length 120 --verbose\n"
  },
  {
    "path": "build_exe.bat",
    "content": "@echo off\nFOR /F \"tokens=* USEBACKQ\" %%F IN (`python --version`) DO (\nSET py_version_str=%%F\n)\nSET py_version=%py_version_str:~7%\n\necho Your Python Version : %py_version%\necho Recommended Python Version : ^>= 3.7\necho -----\necho -----\npython -m PyInstaller NAFAS.spec\npause\n"
  },
  {
    "path": "codecov.yml",
    "content": "codecov:\n  require_ci_to_pass: yes\n\ncoverage:\n  precision: 2\n  round: up\n  range: \"70...100\"\n  status:\n    patch:\n      default:\n        enabled: no\n    project:\n      default:\n        threshold: 1%\n"
  },
  {
    "path": "dev-requirements.txt",
    "content": "art==6.5\nnava==0.8\ncolorama==0.4.6\npytest>=4.3.1\npytest-cov>=2.6.1\nsetuptools>=40.8.0\nvulture>=1.0\nbandit>=1.5.1\npydocstyle>=6.3.0\n\n"
  },
  {
    "path": "nafas/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n\"\"\"nafas modules.\"\"\"\nfrom nafas.params import NAFAS_VERSION\n__version__ = NAFAS_VERSION\n"
  },
  {
    "path": "nafas/__main__.py",
    "content": "# -*- coding: utf-8 -*-\n\"\"\"nafas main.\"\"\"\n\nimport sys\nimport webbrowser\nimport argparse\nfrom nafas.functions import print_nafas_description, get_standard_input, filter_input\nfrom nafas.functions import get_program_data, print_program_details, run_program, clear_screen\nfrom nafas.functions import generate_config, load_config, get_rendered_survey_link, print_line\nfrom nafas.functions import set_color, set_bg_color, set_intensity\nfrom nafas.params import NAFAS_VERSION, EXIT_MESSAGE\nfrom nafas.params import CONFIG_GENERATE_SUCCESS_MESSAGE, CONFIG_GENERATE_ERROR_MESSAGE, CONFIG_LOAD_ERROR_MESSAGE\nfrom nafas.params import SURVEY_MESSAGE_1, SURVEY_MESSAGE_2\nfrom nafas.params import SPEAKER_LIST, COLOR_LIST, INTENSITY_LIST\nfrom art import tprint\n\n\ndef parse_args() -> argparse.Namespace:\n    \"\"\"Parse arguments.\"\"\"\n    parser = argparse.ArgumentParser()\n    parser.add_argument('--version', help='version', nargs=\"?\", const=1)\n    parser.add_argument('--silent', help='silent mode', nargs=\"?\", const=1)\n    parser.add_argument('--skip-intro', help='skip intro', nargs=\"?\", const=1)\n    parser.add_argument(\n        '--generate-config',\n        help='generate a starter configuration file at the given path',\n        type=str)\n    parser.add_argument('--config', help='load an existing configuration file from the given path', type=str)\n    parser.add_argument(\n        '--speaker',\n        help='speaker id',\n        choices=SPEAKER_LIST,\n        default=SPEAKER_LIST[0],\n        type=str.lower)\n    parser.add_argument('--color', help='text color', type=str.lower, choices=COLOR_LIST)\n    parser.add_argument('--bg-color', help='background color', type=str.lower, choices=COLOR_LIST)\n    parser.add_argument('--intensity', help='text intensity', type=str.lower, choices=INTENSITY_LIST)\n    args = parser.parse_args()\n    return args\n\n\ndef run(args: argparse.Namespace) -> None:\n    \"\"\"\n    Run nafas CLI.\n\n    :param args: arguments\n    \"\"\"\n    set_color(args.color)\n    set_bg_color(args.bg_color)\n    set_intensity(args.intensity)\n    silent_flag = args.silent\n    if args.version:\n        print(NAFAS_VERSION)\n    elif args.generate_config:\n            result = generate_config(args.generate_config)\n            if not result:\n                print(CONFIG_GENERATE_ERROR_MESSAGE)\n            else:\n                print(CONFIG_GENERATE_SUCCESS_MESSAGE)\n            sys.exit()\n    else:\n        clear_screen()\n        if not args.skip_intro:\n            tprint(\"Nafas\")\n            tprint(\"v\" + str(NAFAS_VERSION))\n            if silent_flag:\n                tprint(\"Silent Mode\")\n            print_nafas_description()\n            _ = input(\"Press any key to continue.\\n\")\n        exit_flag = False\n        while not exit_flag:\n            if args.config:\n                result = load_config(args.config)\n                if result[\"status\"]:\n                    data = result[\"data\"]\n                    program_name, level, program_data = data[\"program_name\"], data[\"program_level\"], data[\"program_data\"]\n                else:\n                    print(CONFIG_LOAD_ERROR_MESSAGE)\n                    sys.exit()\n            else:\n                input_data = get_standard_input()\n                filtered_data = filter_input(input_data)\n                program_name, level, program_data = get_program_data(filtered_data)\n            clear_screen()\n            print_program_details(program_name, level, program_data)\n            run_program(program_data, args.speaker, silent=silent_flag)\n            print_line()\n            survey_link = get_rendered_survey_link(program_name, level, program_data)\n            print(SURVEY_MESSAGE_1)\n            print(\"Survey Link: {link}\\n\".format(link=survey_link))\n            if input(SURVEY_MESSAGE_2).lower() == \"y\":\n                webbrowser.open(survey_link)\n            INPUTINDEX = str(\n                input(\"Press [R] to restart or any other key to exit.\"))\n            if INPUTINDEX.upper() != \"R\":\n                exit_flag = True\n                print(EXIT_MESSAGE)\n            else:\n                clear_screen()\n\n\ndef main() -> None:\n    \"\"\"CLI main function.\"\"\"\n    try:\n        args = parse_args()\n        run(args)\n    except (KeyboardInterrupt, EOFError):\n        print(EXIT_MESSAGE)\n        sys.exit(1)\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "nafas/functions.py",
    "content": "# -*- coding: utf-8 -*-\n\"\"\"nafas functions.\"\"\"\n\nfrom typing import Dict, List, Tuple\nfrom typing import Generator, Callable, Any, Union, Optional\nimport time\nimport json\nfrom nafas.params import NAFAS_LINKS, NAFAS_DESCRIPTION, NAFAS_TIPS, NAFAS_CAUTIONS\nfrom nafas.params import STANDARD_MENU, STANDARD_MENU_ORDER, STEP_MAP\nfrom nafas.params import PROGRAMS, PROGRAM_DETAILS, SOUND_MAP, STEP_TEMPLATE, CYCLE_TEMPLATE\nfrom nafas.params import SOUND_WARNING_MESSAGE, EXIT_MESSAGE, BAD_INPUT_MESSAGE, PROGRAM_END_MESSAGE\nfrom nafas.params import MINUTES_TEMPLATE, SECONDS_TEMPLATE, PROGRAM_TIME_TEMPLATE\nfrom nafas.params import MENU_TEMPLATE_1, MENU_TEMPLATE_2\nfrom nafas.params import CONFIG_VALIDATION_MAP, CONFIG_EXAMPLE\nfrom nafas.params import SURVEY_LINK_TEMPLATE, SURVEY_DATA_TEMPLATE\nfrom nafas.params import NAFAS_VERSION\nimport nava\nfrom colorama import Fore, Back, Style\nimport os\nfrom warnings import warn\nimport sys\n\n\ndef print_line(num: int = 70, char: str = \"#\") -> None:\n    \"\"\"\n    Print line.\n\n    :param num: number of characters\n    :param char: character\n    \"\"\"\n    print(num * char)\n\n\ndef is_int(number: Union[int, float]) -> bool:\n    \"\"\"\n    Check that input number is int or not.\n\n    :param number: input number\n    \"\"\"\n    if int(number) == number:\n        return True\n    return False\n\n\ndef calculate_bpm(program_data: Dict[str, Any]) -> float:\n    \"\"\"\n    Calculate Breaths Per Minute (BPM).\n\n    :param program_data: program data\n    \"\"\"\n    total_time_per_breath = sum(program_data[\"ratio\"]) * program_data[\"unit\"]\n    bpm = round(60 / total_time_per_breath, 2)\n    if is_int(bpm):\n        bpm = int(bpm)\n    return bpm\n\n\ndef calculate_time(program_data: Dict[str, Any]) -> float:\n    \"\"\"\n    Calculate and return the program time.\n\n    :param program_data: program data\n    \"\"\"\n    result = sum(program_data[\"ratio\"]) * program_data[\"unit\"] * \\\n        program_data[\"cycle\"] + program_data[\"pre\"]\n    return result\n\n\ndef calculate_average_time(program_data: Dict[str, Any]) -> float:\n    \"\"\"\n    Calculate and return average time of a program in all levels.\n\n    :param program_data: program data in all levels\n    \"\"\"\n    result = 0\n    level_number = len(program_data)\n    for program in program_data.values():\n        result += calculate_time(program)\n    return result / level_number\n\n\ndef convert_time(input_time: float, average: bool = False) -> str:\n    \"\"\"\n    Convert input time from sec to MM,SS format.\n\n    :param input_time: input time in sec\n    :param average: average flag\n    \"\"\"\n    sec = float(input_time)\n    _days, sec = divmod(sec, 24 * 3600)\n    _hours, sec = divmod(sec, 3600)\n    minutes, sec = divmod(sec, 60)\n    result = \", \".join([\n        MINUTES_TEMPLATE.format(minutes=minutes),\n        SECONDS_TEMPLATE.format(seconds=sec),\n    ])\n    if average:\n        if sec >= 30:\n            minutes += 1\n        result = MINUTES_TEMPLATE.format(minutes=minutes).lstrip(\"0\")\n    return result\n\n\ndef get_rendered_survey_link(program_name: str, level: str, program_data: Dict[str, Any]) -> str:\n    \"\"\"\n    Get rendered survey link.\n\n    :param program_name: program name\n    :param level: program level\n    :param program_data: program data\n    \"\"\"\n    data = SURVEY_DATA_TEMPLATE.format(\n        program_name=program_name,\n        level=level,\n        ratio_rendered=\"+%5B\" + \",+\".join([str(item) for item in program_data['ratio']]) + \"%5D\",\n        program_data_unit=program_data['unit'],\n        program_data_pre=program_data['pre'],\n        program_data_cycle=program_data['cycle'],\n    )\n    return SURVEY_LINK_TEMPLATE.format(data=data, version=NAFAS_VERSION)\n\n\ndef justify_left(words: List[str], width: int) -> str:\n    \"\"\"\n    Left justify words.\n\n    :param words: list of words\n    :param width: width of each line\n    \"\"\"\n    return ' '.join(words).ljust(width)\n\n\ndef justify_text(words: List[str], width: int) -> Generator[str, None, None]:\n    \"\"\"\n    Justify input words.\n\n    :param words: list of words\n    :param width: width of each line\n    \"\"\"\n    line = []\n    col = 0\n    for word in words:\n        if line and col + len(word) > width:\n            if len(line) == 1:\n                yield justify_left(line, width)\n            else:\n                # After n + 1 spaces are placed between each pair of\n                # words, there are r spaces left over; these result in\n                # wider spaces at the left.\n                n, r = divmod(width - col + 1, len(line) - 1)\n                narrow = ' ' * (n + 1)\n                if r == 0:\n                    yield narrow.join(line)\n                else:\n                    wide = ' ' * (n + 2)\n                    yield wide.join(line[:r] + [narrow.join(line[r:])])\n            line, col = [], 0\n        line.append(word)\n        col += len(word) + 1\n    if line:\n        yield justify_left(line, width)\n\n\ndef check_sound() -> bool:\n    \"\"\"Check sound playing device, return True if sound device is available.\"\"\"\n    sound_path = get_sound_path(SOUND_MAP['Silence'])\n    try:\n        nava.play(sound_path)\n        return True\n    except Exception:\n        warn(SOUND_WARNING_MESSAGE, RuntimeWarning)\n        return False\n\n\ndef print_nafas_description() -> None:\n    \"\"\"Print Nafas description.\"\"\"\n    print(NAFAS_LINKS)\n    print_line()\n    print(\"\\n\".join(justify_text(NAFAS_DESCRIPTION.split(), 100)))\n    print_line()\n    print(NAFAS_TIPS)\n    print_line()\n    print(NAFAS_CAUTIONS)\n\n\ndef print_program_details(program_name: str, level: str, program_data: Dict[str, Any]) -> None:\n    \"\"\"\n    Print program details.\n\n    :param program_name: program name\n    :param level: program level\n    :param program_data: program data\n    \"\"\"\n    cycle = program_data[\"cycle\"]\n    ratio = program_data[\"ratio\"]\n    unit = program_data[\"unit\"]\n    sequence = []\n    for index, item in enumerate(ratio):\n        sequence.append(\"{step}({ratio})\".format(step=STEP_MAP[index], ratio=item))\n    sequence = \", \".join(sequence)\n    total_time = calculate_time(program_data)\n    bpm = calculate_bpm(program_data)\n    print_line()\n    print(\n        PROGRAM_DETAILS.format(\n            name=program_name,\n            level=level,\n            cycles=str(cycle),\n            unit=str(unit),\n            total_time=convert_time(total_time),\n            bpm=bpm,\n            sequence=sequence))\n    print_line()\n    time.sleep(1)\n\n\ndef filter_input(input_data: Dict[str, Any]) -> Dict[str, Any]:\n    \"\"\"\n    Filter input data.\n\n    :param input_data: input data\n    \"\"\"\n    filtered_data = input_data.copy()\n    if filtered_data[\"program\"] not in STANDARD_MENU[\"program\"]:\n        filtered_data[\"program\"] = 1\n    if filtered_data[\"level\"] not in STANDARD_MENU[\"level\"]:\n        filtered_data[\"level\"] = 1\n    return filtered_data\n\n\ndef load_config(config_path: str) -> Dict[str, Any]:\n    \"\"\"\n    Load configuration from a JSON file.\n\n    :param config_path: config path\n    \"\"\"\n    try:\n        with open(config_path, 'r') as config_file:\n            config_data = json.load(config_file)\n        if not validate_config(config_data):\n            raise Exception\n        program_data = {\n            'ratio': [\n                config_data['ratio']['inhale'],\n                config_data['ratio']['retain'],\n                config_data['ratio']['exhale'],\n                config_data['ratio']['sustain']\n            ],\n            'unit': config_data['unit'],\n            'pre': config_data['pre'],\n            'cycle': config_data['cycle'],\n        }\n        return {\n            \"status\": True,\n            \"data\": {\n                \"program_name\": config_data['name'],\n                \"program_level\": \"Custom\",\n                \"program_data\": program_data\n            }\n        }\n    except Exception:\n        return {\"status\": False, \"data\": dict()}\n\n\ndef generate_config(config_path: str) -> bool:\n    \"\"\"\n    Generate a starter configuration file.\n\n    :param config_path: config path\n    \"\"\"\n    try:\n        with open(config_path, 'w') as config_file:\n            json.dump(CONFIG_EXAMPLE, config_file)\n        return True\n    except Exception:\n        return False\n\n\ndef validate_config(config_data: Dict[str, Any]) -> bool:\n    \"\"\"\n    Validate config data. Return True if config data is valid.\n\n    :param config_data: config data\n    \"\"\"\n    result = []\n    for item1 in CONFIG_VALIDATION_MAP:\n        if item1 not in config_data:\n            return False\n        if isinstance(CONFIG_VALIDATION_MAP[item1], dict):\n            for item2 in CONFIG_VALIDATION_MAP[item1]:\n                if item2 not in config_data[item1]:\n                    return False\n                result.append(isinstance(config_data[item1][item2], CONFIG_VALIDATION_MAP[item1][item2]))\n        else:\n            result.append(isinstance(config_data[item1], CONFIG_VALIDATION_MAP[item1]))\n    return all(result)\n\n\ndef get_standard_input(input_func: Callable = input) -> Dict[str, Any]:\n    \"\"\"\n    Get inputs from user.\n\n    :param input_func : input function\n    \"\"\"\n    input_data = {\"program\": 1, \"level\": 1}\n    for item in STANDARD_MENU_ORDER:\n        exit_flag = False\n        sorted_list = sorted(STANDARD_MENU[item])\n        print(MENU_TEMPLATE_1.format(item=item))\n        for i in sorted_list:\n            if item == \"program\":\n                program_name = STANDARD_MENU[item][i]\n                program_average_time = calculate_average_time(PROGRAMS[program_name])\n                print(\n                    PROGRAM_TIME_TEMPLATE.format(\n                        index=i,\n                        name=program_name,\n                        average_time=convert_time(\n                            program_average_time,\n                            True)))\n            else:\n                print(MENU_TEMPLATE_2.format(index=i, item=STANDARD_MENU[item][i]))\n        while not exit_flag:\n            try:\n                input_data[item] = int(input_func(\"\"))\n                exit_flag = True\n            except (KeyboardInterrupt, EOFError):\n                print(\"\\n\" + EXIT_MESSAGE)\n                sys.exit()\n            except Exception:\n                print(BAD_INPUT_MESSAGE)\n    return input_data\n\n\ndef get_program_data(input_data: Dict[str, Any]) -> Tuple:\n    \"\"\"\n    Get program data as program name, level and program data.\n\n    :param input_data: input data\n    \"\"\"\n    program_name = STANDARD_MENU[\"program\"][input_data[\"program\"]]\n    level = STANDARD_MENU[\"level\"][input_data[\"level\"]]\n    return program_name, level, PROGRAMS[program_name][level]\n\n\ndef get_sound_path(sound_name: str, speaker_id: Optional[str] = None) -> str:\n    \"\"\"\n    Return direct sound path.\n\n    :param sound_name: .wav sound name\n    :param speaker_id: speaker id\n    \"\"\"\n    cd, _ = os.path.split(__file__)\n    if speaker_id is None:\n        return os.path.join(cd, \"sounds\", sound_name)\n    return os.path.join(cd, \"sounds\", speaker_id, sound_name)\n\n\ndef set_color(color: str) -> None:\n    \"\"\"\n    Set text color.\n\n    :param color: color name\n    \"\"\"\n    if color:\n        color = color.strip().upper()\n        if color.startswith(\"LIGHT\"):\n            color += \"_EX\"\n        print(getattr(Fore, color, \"\"), end=\"\")\n\n\ndef set_bg_color(bg_color: str) -> None:\n    \"\"\"\n    Set background color.\n\n    :param bg_color: background color name\n    \"\"\"\n    if bg_color:\n        bg_color = bg_color.strip().upper()\n        if bg_color.startswith(\"LIGHT\"):\n            bg_color += \"_EX\"\n        print(getattr(Back, bg_color, \"\"))\n\n\ndef set_intensity(intensity: str) -> None:\n    \"\"\"\n    Set text intensity.\n\n    :param intensity: intensity name\n    \"\"\"\n    if intensity:\n        intensity = intensity.strip().upper()\n        print(getattr(Style, intensity, \"\"), end=\"\")\n\n\ndef graphic_counter(delay_time: float) -> None:\n    \"\"\"\n    Print dots during cycles.\n\n    :param delay_time: delay time\n    \"\"\"\n    for _ in range(int(delay_time)):\n        time.sleep(1)\n        print('.', end=' ', flush=True)\n    remain_time = delay_time - int(delay_time)\n    time.sleep(remain_time)\n    if remain_time != 0:\n        print('.', end=' ', flush=True)\n    print(\"\")\n\n\ndef play_sound(sound_path: str, enable: bool = True) -> None:\n    \"\"\"\n    Play inputted sound file.\n\n    :param sound_path: sound path\n    :param enable: enable flag\n    \"\"\"\n    if enable:\n        _ = nava.play(sound_path, async_mode=True)\n\n\ndef run_program(program_data: Dict[str, Any], speaker_id: str, silent: bool = False) -> None:\n    \"\"\"\n    Run program.\n\n    :param program_data: program data\n    :param speaker_id: speaker id\n    :param silent: silent mode flag\n    \"\"\"\n    check_sound_flag = False\n    if not silent:\n        check_sound_flag = check_sound()\n    cycle = program_data[\"cycle\"]\n    ratio = program_data[\"ratio\"]\n    unit = program_data[\"unit\"]\n    pre = program_data[\"pre\"]\n    print(\"Preparing \", end=\"\", flush=True)\n    play_sound(get_sound_path(SOUND_MAP['Prepare'], speaker_id), enable=check_sound_flag)\n    graphic_counter(pre)\n    print_line()\n    time.sleep(1)\n    play_sound(get_sound_path(SOUND_MAP['Start'], speaker_id), enable=check_sound_flag)\n    print(\"Start\", flush=True)\n    time.sleep(1)\n    print_line()\n    time.sleep(1)\n    for i in range(cycle):\n        print(CYCLE_TEMPLATE.format(cycle=str(i + 1), remaining=str(cycle - i - 1)))\n        time.sleep(1)\n        for index, item in enumerate(ratio):\n            if item != 0:\n                item_name = STEP_MAP[index]\n                play_sound(get_sound_path(SOUND_MAP[item_name], speaker_id), enable=check_sound_flag)\n                print(\n                    STEP_TEMPLATE.format(\n                        step=item_name,\n                        time=str(unit * item)), flush=True)\n                graphic_counter(item * unit)\n        time.sleep(1)\n        print_line()\n    play_sound(get_sound_path(SOUND_MAP['End'], speaker_id), enable=check_sound_flag)\n    print(PROGRAM_END_MESSAGE, flush=True)\n    time.sleep(2)\n\n\ndef clear_screen() -> None:\n    \"\"\"Clear screen.\"\"\"\n    if sys.platform == \"win32\":\n        os.system('cls')\n    else:\n        os.system('clear')\n"
  },
  {
    "path": "nafas/params.py",
    "content": "# -*- coding: utf-8 -*-\n\"\"\"nafas parameters.\"\"\"\n\nNAFAS_VERSION = \"1.5\"\n\nNAFAS_DESCRIPTION = \"\"\"\nBreathing gymnastics is a system of breathing exercises that focuses on the treatment of various diseases and general health promotion.\nNafas is a collection of breathing gymnastics designed to reduce the exhaustion of long working hours.\nWith multiple breathing patterns, Nafas helps you find your way to a detoxified energetic workday and also improves your concentration by increasing the oxygen level.\nNo need to walk away to take a break, just sit comfortably, run Nafas and let the journey begin.\n\"\"\"\n\nNAFAS_LINKS = \"\"\"\nRepository: https://github.com/sepandhaghighi/nafas\nPaper: https://arxiv.org/abs/2412.04667\n* If you use Nafas in your research, please cite our paper\n\"\"\"\n\nNAFAS_TIPS = \"\"\"\nBreathing tips:\n\n1. Inhaling is only done through the nose\n2. Exhaling, you can use both nose and mouth\n3. When exhaling through your mouth, it is recommended to fold the lips\n\"\"\"\n\nNAFAS_CAUTIONS = \"\"\"\nCautions:\n\n1. If you have any breathing or respiratory issues, consult your doctor before using Nafas\n2. If you have asthma or high blood pressure should not hold the breath\n3. If you feel dizzy, nauseous, or lightheaded stop practicing and rest\n\"\"\"\n\nSOUND_WARNING_MESSAGE = \"Your device is not compatible with our underlying sound-playing library. You can refer to https://github.com/openscilab/nava.\"\n\nEXIT_MESSAGE = \"See you. Bye!\"\n\nBAD_INPUT_MESSAGE = \"[Error] Bad input!\"\n\nCONFIG_LOAD_ERROR_MESSAGE = \"[Error] Failed to load the configuration file!\"\nCONFIG_GENERATE_ERROR_MESSAGE = \"[Error] Failed to generate the configuration file!\"\nCONFIG_GENERATE_SUCCESS_MESSAGE = \"Configuration file generated successfully!\"\n\nPROGRAM_END_MESSAGE = \"Well done!\"\n\nSURVEY_LINK_TEMPLATE = \"https://opsclb.li/nafas/form?version={version}&data={data}\"\nSURVEY_DATA_TEMPLATE = \"%7B\\\"name\\\":+\\\"{program_name}\\\",+\\\"level\\\":+\\\"{level}\\\",+\\\"data\\\":+%7B\\\"ratio\\\":+{ratio_rendered},+\\\"unit\\\":+{program_data_unit},+\\\"pre\\\":+{program_data_pre},+\\\"cycle\\\":+{program_data_cycle}%7D%7D\"\nSURVEY_MESSAGE_1 = \"We are conducting a study to evaluate the usability of Nafas. By taking the following survey, you will contribute to our research and help us improve Nafas. The survey takes less than 5 minutes to complete.\\n\"\nSURVEY_MESSAGE_2 = \"Do you want to participate in the survey? (Y/[N])\"\n\nPROGRAM_DETAILS = \"\"\"Program Details:\n\nName                     : {name}\n\nLevel                    : {level}\n\nNumber of Cycles         : {cycles}\n\nUnit                     : {unit} seconds\n\nTotal Time               : {total_time}\n\nBreaths per Minute (BPM) : {bpm}\n\nSequence                 : {sequence}\n\"\"\"\n\nMINUTES_TEMPLATE = \"{minutes:02.0f} minutes\"\n\nSECONDS_TEMPLATE = \"{seconds:02.0f} seconds\"\n\nPROGRAM_TIME_TEMPLATE = \"{index}- {name} (~ {average_time})\"\n\nMENU_TEMPLATE_1 = \"- Choose a {item}: \\n\"\n\nMENU_TEMPLATE_2 = \"{index}- {item}\"\n\nCYCLE_TEMPLATE = \"Cycle: {cycle} (Remaining: {remaining})\"\n\nSTEP_TEMPLATE = \"- {step} for {time} seconds\"\n\nSTANDARD_MENU = {\n    \"program\": {\n        1: \"Clear Mind\",\n        2: \"Relax1\",\n        3: \"Relax2\",\n        4: \"Relax3\",\n        5: \"Calming1\",\n        6: \"Calming2\",\n        7: \"Calming3\",\n        8: \"Power\",\n        9: \"Harmony\",\n        10: \"Anti-Stress\",\n        11: \"Anti-Appetite\",\n        12: \"Cigarette Replace\",\n        13: \"Decision-Making\",\n        14: \"Balancing\",\n        15: \"Energizing\",\n        16: \"Box\",\n        17: \"Coherent\",\n        18: \"Fire\",\n        19: \"Retention\",\n        20: \"Swooning\"},\n    \"level\": {\n        1: \"Beginner\",\n        2: \"Medium\",\n        3: \"Advanced\"}}\n\nSTANDARD_MENU_ORDER = [\"program\", \"level\"]\n\nSTEP_MAP = {0: \"Inhale\", 1: \"Retain\", 2: \"Exhale\", 3: \"Sustain\"}\n\nCLEAR_MIND_BEGINNER = {\"ratio\": [1, 0, 3, 0], \"unit\": 3, \"pre\": 3, \"cycle\": 35}\n\nCLEAR_MIND_MEDIUM = {\"ratio\": [1, 0, 4, 0], \"unit\": 3, \"pre\": 3, \"cycle\": 28}\n\nCLEAR_MIND_ADVANCED = {\"ratio\": [1, 0, 5, 0], \"unit\": 3, \"pre\": 3, \"cycle\": 24}\n\nRELAX_BEGINNER = {\"ratio\": [1, 0, 2, 2], \"unit\": 3, \"pre\": 3, \"cycle\": 28}\n\nRELAX_MEDIUM = {\"ratio\": [1, 0, 2, 3], \"unit\": 3, \"pre\": 3, \"cycle\": 24}\n\nRELAX_ADVANCED = {\"ratio\": [1, 0, 2, 4], \"unit\": 3, \"pre\": 3, \"cycle\": 22}\n\nCALMING_BEGINNER = {\"ratio\": [1, 2, 1, 2], \"unit\": 3, \"pre\": 3, \"cycle\": 24}\n\nCALMING_MEDIUM = {\"ratio\": [1, 3, 1, 3], \"unit\": 3, \"pre\": 3, \"cycle\": 22}\n\nCALMING_ADVANCED = {\"ratio\": [1, 4, 1, 4], \"unit\": 3, \"pre\": 3, \"cycle\": 20}\n\nCALMING2_BEGINNER = {\"ratio\": [5, 0, 5, 5], \"unit\": 1, \"pre\": 3, \"cycle\": 4}\n\nCALMING2_MEDIUM = {\"ratio\": [5, 0, 5, 5], \"unit\": 1, \"pre\": 3, \"cycle\": 6}\n\nCALMING2_ADVANCED = {\"ratio\": [5, 0, 5, 5], \"unit\": 1, \"pre\": 3, \"cycle\": 8}\n\nCALMING3_BEGINNER = {\"ratio\": [4, 0, 6, 0], \"unit\": 1, \"pre\": 3, \"cycle\": 6}\n\nCALMING3_MEDIUM = {\"ratio\": [6, 1, 8, 4], \"unit\": 1, \"pre\": 3, \"cycle\": 8}\n\nCALMING3_ADVANCED = {\"ratio\": [4, 1, 12, 1], \"unit\": 1, \"pre\": 3, \"cycle\": 10}\n\nPOWER_BEGINNER = {\"ratio\": [1, 2, 2, 0], \"unit\": 3, \"pre\": 3, \"cycle\": 28}\n\nPOWER_MEDIUM = {\"ratio\": [1, 3, 2, 0], \"unit\": 3, \"pre\": 3, \"cycle\": 24}\n\nPOWER_ADVANCED = {\"ratio\": [1, 4, 2, 0], \"unit\": 3, \"pre\": 3, \"cycle\": 20}\n\nHARMONY_BEGINNER = {\"ratio\": [1, 3, 2, 1], \"unit\": 3, \"pre\": 3, \"cycle\": 20}\n\nHARMONY_MEDIUM = {\"ratio\": [1, 4, 2, 1], \"unit\": 3, \"pre\": 3, \"cycle\": 18}\n\nHARMONY_ADVANCED = {\"ratio\": [1, 5, 2, 1], \"unit\": 3, \"pre\": 3, \"cycle\": 16}\n\nFIRE_BEGINNER = {\"ratio\": [3, 0, 5, 12], \"unit\": 1, \"pre\": 3, \"cycle\": 10}\n\nFIRE_MEDIUM = {\"ratio\": [3, 0, 5, 12], \"unit\": 1, \"pre\": 3, \"cycle\": 20}\n\nFIRE_ADVANCED = {\"ratio\": [3, 0, 5, 12], \"unit\": 1, \"pre\": 3, \"cycle\": 30}\n\nRETENTION_BEGINNER = {\"ratio\": [2, 0, 2, 12], \"unit\": 1, \"pre\": 3, \"cycle\": 5}\n\nRETENTION_MEDIUM = {\"ratio\": [2, 0, 2, 12], \"unit\": 1, \"pre\": 3, \"cycle\": 10}\n\nRETENTION_ADVANCED = {\"ratio\": [2, 0, 2, 12], \"unit\": 1, \"pre\": 3, \"cycle\": 15}\n\nSWOONING_BEGINNER = {\"ratio\": [5, 10, 7, 0], \"unit\": 1, \"pre\": 3, \"cycle\": 7}\n\nSWOONING_MEDIUM = {\"ratio\": [5, 10, 7, 0], \"unit\": 1, \"pre\": 3, \"cycle\": 12}\n\nSWOONING_ADVANCED = {\"ratio\": [5, 10, 7, 0], \"unit\": 1, \"pre\": 3, \"cycle\": 21}\n\n\nRELAX2_BEGINNER = {\n    \"ratio\": [\n        4,\n        7,\n        8,\n        0],\n    \"unit\": 1,\n    \"pre\": 3,\n    \"cycle\": 4}\n\nRELAX2_MEDIUM = {\n    \"ratio\": [\n        4,\n        7,\n        8,\n        0],\n    \"unit\": 1,\n    \"pre\": 3,\n    \"cycle\": 8}\n\nRELAX2_ADVANCED = {\n    \"ratio\": [\n        4,\n        7,\n        8,\n        0],\n    \"unit\": 1,\n    \"pre\": 3,\n    \"cycle\": 12}\n\nRELAX3_BEGINNER = {\n    \"ratio\": [\n        7,\n        0,\n        11,\n        0],\n    \"unit\": 1,\n    \"pre\": 3,\n    \"cycle\": 15}\n\nRELAX3_MEDIUM = {\n    \"ratio\": [\n        7,\n        0,\n        11,\n        0],\n    \"unit\": 1,\n    \"pre\": 3,\n    \"cycle\": 20}\n\nRELAX3_ADVANCED = {\n    \"ratio\": [\n        7,\n        0,\n        11,\n        0],\n    \"unit\": 1,\n    \"pre\": 3,\n    \"cycle\": 24}\n\nANTI_STRESS_BEGINNER = {\n    \"ratio\": [\n        3,\n        0,\n        0.66,\n        0],\n    \"unit\": 3,\n    \"pre\": 3,\n    \"cycle\": 20}\n\nANTI_STRESS_MEDIUM = {\n    \"ratio\": [\n        4,\n        0,\n        0.66,\n        0],\n    \"unit\": 3,\n    \"pre\": 3,\n    \"cycle\": 17}\n\nANTI_STRESS_ADVANCED = {\n    \"ratio\": [\n        5,\n        0,\n        0.66,\n        0],\n    \"unit\": 3,\n    \"pre\": 3,\n    \"cycle\": 14}\n\nANTI_APPETITE_BEGINNER = {\n    \"ratio\": [\n        5,\n        0,\n        5,\n        5],\n    \"unit\": 1,\n    \"pre\": 3,\n    \"cycle\": 40}\n\nANTI_APPETITE_MEDIUM = {\n    \"ratio\": [\n        6,\n        0,\n        5,\n        5],\n    \"unit\": 1,\n    \"pre\": 3,\n    \"cycle\": 38}\n\nANTI_APPETITE_ADVANCED = {\n    \"ratio\": [\n        7,\n        0,\n        5,\n        5],\n    \"unit\": 1,\n    \"pre\": 3,\n    \"cycle\": 36}\n\nCIGARETTE_REPLACE_BEGINNER = {\n    \"ratio\": [\n        2,\n        1.1,\n        2.2,\n        0.8],\n    \"unit\": 2,\n    \"pre\": 3,\n    \"cycle\": 23}\n\nCIGARETTE_REPLACE_MEDIUM = {\n    \"ratio\": [\n        3,\n        1.1,\n        2.2,\n        0.8],\n    \"unit\": 2,\n    \"pre\": 3,\n    \"cycle\": 21}\n\nCIGARETTE_REPLACE_ADVANCED = {\n    \"ratio\": [\n        4,\n        1.1,\n        2.2,\n        0.8],\n    \"unit\": 2,\n    \"pre\": 3,\n    \"cycle\": 19}\n\n\nDECISION_MAKING_BEGINNER = {\n    \"ratio\": [\n        5,\n        2,\n        7,\n        0],\n    \"unit\": 1,\n    \"pre\": 3,\n    \"cycle\": 6}\n\nDECISION_MAKING_MEDIUM = {\n    \"ratio\": [\n        5,\n        2,\n        7,\n        0],\n    \"unit\": 1,\n    \"pre\": 3,\n    \"cycle\": 10}\n\nDECISION_MAKING_ADVANCED = {\n    \"ratio\": [\n        5,\n        2,\n        7,\n        0],\n    \"unit\": 1,\n    \"pre\": 3,\n    \"cycle\": 14}\n\nBALANCING_BEGINNER = {\n    \"ratio\": [\n        6,\n        0,\n        6,\n        0],\n    \"unit\": 1,\n    \"pre\": 3,\n    \"cycle\": 6}\n\nBALANCING_MEDIUM = {\n    \"ratio\": [\n        8,\n        1,\n        8,\n        1],\n    \"unit\": 1,\n    \"pre\": 3,\n    \"cycle\": 8}\n\nBALANCING_ADVANCED = {\n    \"ratio\": [\n        6,\n        2,\n        6,\n        2],\n    \"unit\": 1,\n    \"pre\": 3,\n    \"cycle\": 10}\n\nENERGIZING_BEGINNER = {\n    \"ratio\": [\n        6,\n        0,\n        4,\n        0],\n    \"unit\": 1,\n    \"pre\": 3,\n    \"cycle\": 6}\n\nENERGIZING_MEDIUM = {\n    \"ratio\": [\n        6,\n        4,\n        6,\n        1],\n    \"unit\": 1,\n    \"pre\": 3,\n    \"cycle\": 8}\n\nENERGIZING_ADVANCED = {\n    \"ratio\": [\n        6,\n        6,\n        6,\n        1],\n    \"unit\": 1,\n    \"pre\": 3,\n    \"cycle\": 10}\n\n\nBOX_BEGINNER = {\n    \"ratio\": [\n        4,\n        4,\n        4,\n        4],\n    \"unit\": 1,\n    \"pre\": 3,\n    \"cycle\": 4}\n\n\nBOX_MEDIUM = {\n    \"ratio\": [\n        4,\n        4,\n        4,\n        4],\n    \"unit\": 1,\n    \"pre\": 3,\n    \"cycle\": 8}\n\n\nBOX_ADVANCED = {\n    \"ratio\": [\n        4,\n        4,\n        4,\n        4],\n    \"unit\": 1,\n    \"pre\": 3,\n    \"cycle\": 15}\n\n\nCOHERENT_BEGINNER = {\n    \"ratio\": [\n        5,\n        0,\n        5,\n        0],\n    \"unit\": 1,\n    \"pre\": 3,\n    \"cycle\": 30}\n\n\nCOHERENT_MEDIUM = {\n    \"ratio\": [\n        5,\n        0,\n        5,\n        0],\n    \"unit\": 1,\n    \"pre\": 3,\n    \"cycle\": 50}\n\n\nCOHERENT_ADVANCED = {\n    \"ratio\": [\n        5,\n        0,\n        5,\n        0],\n    \"unit\": 1,\n    \"pre\": 3,\n    \"cycle\": 70}\n\n\nPROGRAMS = {\"Clear Mind\": {\"Beginner\": CLEAR_MIND_BEGINNER,\n                           \"Medium\": CLEAR_MIND_MEDIUM,\n                           \"Advanced\": CLEAR_MIND_ADVANCED},\n            \"Relax1\": {\"Beginner\": RELAX_BEGINNER,\n                       \"Medium\": RELAX_MEDIUM,\n                       \"Advanced\": RELAX_ADVANCED},\n            \"Calming1\": {\"Beginner\": CALMING_BEGINNER,\n                         \"Medium\": CALMING_MEDIUM,\n                         \"Advanced\": CALMING_ADVANCED},\n            \"Calming2\": {\"Beginner\": CALMING2_BEGINNER,\n                         \"Medium\": CALMING2_MEDIUM,\n                         \"Advanced\": CALMING2_ADVANCED},\n            \"Calming3\": {\"Beginner\": CALMING3_BEGINNER,\n                         \"Medium\": CALMING3_MEDIUM,\n                         \"Advanced\": CALMING3_ADVANCED},\n            \"Power\": {\"Beginner\": POWER_BEGINNER,\n                      \"Medium\": POWER_MEDIUM,\n                      \"Advanced\": POWER_ADVANCED},\n            \"Anti-Stress\": {\"Beginner\": ANTI_STRESS_BEGINNER,\n                            \"Medium\": ANTI_STRESS_MEDIUM,\n                            \"Advanced\": ANTI_STRESS_ADVANCED},\n            \"Anti-Appetite\": {\"Beginner\": ANTI_APPETITE_BEGINNER,\n                              \"Medium\": ANTI_APPETITE_MEDIUM,\n                              \"Advanced\": ANTI_APPETITE_ADVANCED},\n            \"Cigarette Replace\": {\"Beginner\": CIGARETTE_REPLACE_BEGINNER,\n                                  \"Medium\": CIGARETTE_REPLACE_MEDIUM,\n                                  \"Advanced\": CIGARETTE_REPLACE_ADVANCED},\n            \"Harmony\": {\"Beginner\": HARMONY_BEGINNER,\n                        \"Medium\": HARMONY_MEDIUM,\n                        \"Advanced\": HARMONY_ADVANCED},\n            \"Relax2\": {\"Beginner\": RELAX2_BEGINNER,\n                       \"Medium\": RELAX2_MEDIUM,\n                       \"Advanced\": RELAX2_ADVANCED},\n            \"Relax3\": {\"Beginner\": RELAX3_BEGINNER,\n                       \"Medium\": RELAX3_MEDIUM,\n                       \"Advanced\": RELAX3_ADVANCED},\n            \"Decision-Making\": {\"Beginner\": DECISION_MAKING_BEGINNER,\n                                \"Medium\": DECISION_MAKING_MEDIUM,\n                                \"Advanced\": DECISION_MAKING_ADVANCED},\n            \"Balancing\": {\"Beginner\": BALANCING_BEGINNER,\n                          \"Medium\": BALANCING_MEDIUM,\n                          \"Advanced\": BALANCING_ADVANCED},\n            \"Energizing\": {\"Beginner\": ENERGIZING_BEGINNER,\n                           \"Medium\": ENERGIZING_MEDIUM,\n                           \"Advanced\": ENERGIZING_ADVANCED},\n            \"Box\": {\"Beginner\": BOX_BEGINNER,\n                    \"Medium\": BOX_MEDIUM,\n                    \"Advanced\": BOX_ADVANCED},\n            \"Coherent\": {\"Beginner\": COHERENT_BEGINNER,\n                         \"Medium\": COHERENT_MEDIUM,\n                         \"Advanced\": COHERENT_ADVANCED},\n            \"Fire\": {\"Beginner\": FIRE_BEGINNER,\n                     \"Medium\": FIRE_MEDIUM,\n                     \"Advanced\": FIRE_ADVANCED},\n            \"Retention\": {\"Beginner\": RETENTION_BEGINNER,\n                          \"Medium\": RETENTION_MEDIUM,\n                          \"Advanced\": RETENTION_ADVANCED},\n            \"Swooning\": {\"Beginner\": SWOONING_BEGINNER,\n                         \"Medium\": SWOONING_MEDIUM,\n                         \"Advanced\": SWOONING_ADVANCED},\n            }\n\nSPEAKER_LIST = [\n    \"us1\", \"us2\",\n    \"in1\", \"in2\",\n    \"cn1\", \"cn2\",\n    \"ca1\", \"ca2\",\n    \"au1\", \"au2\",\n    \"uk1\", \"uk2\",\n]\n\nSOUND_MAP = {\n    \"Silence\": \"silence.wav\",\n    \"Start\": \"start.wav\",\n    \"Prepare\": \"preparing.wav\",\n    \"Inhale\": \"inhale.wav\",\n    \"Exhale\": \"exhale.wav\",\n    \"Retain\": \"retain.wav\",\n    \"Sustain\": \"sustain.wav\",\n    \"End\": \"well_done.wav\",\n}\n\nCONFIG_VALIDATION_MAP = {\n    \"name\": str,\n    \"ratio\": {\n        \"inhale\": (int, float),\n        \"exhale\": (int, float),\n        \"retain\": (int, float),\n        \"sustain\": (int, float),\n    },\n    \"unit\": (int, float),\n    \"pre\": (int, float),\n    \"cycle\": int\n}\n\nCONFIG_EXAMPLE = {\n    \"name\": \"unknown\",\n    \"unit\": 1,\n    \"pre\": 3,\n    \"cycle\": 5,\n    \"ratio\": {\n        \"inhale\": 1,\n        \"exhale\": 1,\n        \"retain\": 1,\n        \"sustain\": 1\n    }\n}\n\nCOLOR_LIST = [\n    \"black\",\n    \"red\",\n    \"green\",\n    \"yellow\",\n    \"blue\",\n    \"magenta\",\n    \"cyan\",\n    \"white\",\n    \"lightblack\",\n    \"lightred\",\n    \"lightgreen\",\n    \"lightyellow\",\n    \"lightblue\",\n    \"lightmagenta\",\n    \"lightcyan\",\n    \"lightwhite\",\n]\n\nINTENSITY_LIST = [\"normal\", \"bright\", \"dim\"]\n"
  },
  {
    "path": "otherfiles/RELEASE.md",
    "content": "# Nafas Release Instructions\n\n**Last Update: 2025-06-30**\n\n1. Create the `release` branch under `dev`\n2. Update all version tags\n\t1. `setup.py`\n\t2. `README.md`\n\t3. `SECURITY.md`\n\t4. `NAFAS.spec`\n\t5. `otherfiles/version_check.py`\n\t6. `nafas/params.py`\n\t7. `otherfiles/Version.rc`\n\t8. `test/test.py`\n3. Update `CHANGELOG.md`\n\t1. Add a new header under `Unreleased` section (Example: `## [0.1] - 2022-08-17`)\n\t2. Add a new compare link to the end of the file (Example: `[0.2]: https://github.com/sepandhaghighi/nafas/compare/v0.1...v0.2`)\n\t3. Update `dev` compare link (Example: `[Unreleased]: https://github.com/sepandhaghighi/nafas/compare/v0.2...dev`)\n4. Update `.github/ISSUE_TEMPLATE/bug_report.yml`\n   1. Add new version tag to `Nafas version` dropbox options\n5. Create a PR from `release` to `dev`\n\t1. Title: `Version x.x` (Example: `Version 0.1`)\n\t2. Tag all related issues\n\t3. Labels: `release`\n\t4. Set milestone\n\t5. Wait for all CI pass\n\t6. Need review (**1** reviewer)\n\t7. Squash and merge\n\t8. Delete `release` branch\n6. Merge `dev` branch into `master`\n\t1. `git checkout master`\n\t2. `git merge dev`\n\t3. `git push origin master`\n\t4. Wait for all CI pass\n7. Build EXE file\n\t1. Run `build_exe.bat` (Use `Python >= 3.7`)\n8. Create a new release\n\t1. Target branch: `master`\n\t2. Tag: `vx.x` (Example: `v0.1`)\n\t3. Title: `Version x.x` (Example: `Version 0.1`)\n\t4. Copy changelogs\n\t5. Tag all related issues\n\t6. Upload EXE file\n9. Bump!!\n10. Close this version issues\n11. Close milestone\n"
  },
  {
    "path": "otherfiles/Version.rc",
    "content": "VSVersionInfo(\n  ffi=FixedFileInfo(\n    filevers=(1, 5, 0, 0),\n    prodvers=(1, 5, 0, 0),\n    mask=0x3f,\n    flags=0x0,\n    OS=0x40004,\n    fileType=0x1,\n    subtype=0x0,\n    date=(0, 0)\n    ),\n  kids=[\n    StringFileInfo(\n      [\n    StringTable(\n        u'040904B0',\n        [StringStruct(u'CompanyName', u'Nafas Development Team'),\n        StringStruct(u'FileDescription', u'NAFAS.exe'),\n        StringStruct(u'FileVersion', u'1.5.0.0'),\n        StringStruct(u'InternalName', u'NAFAS.exe'),\n        StringStruct(u'LegalCopyright', u'Copyright (c) 2020-2026 Nafas Development Team'),\n        StringStruct(u'OriginalFilename', u'NAFAS.exe'),\n        StringStruct(u'ProductName', u'NAFAS'),\n        StringStruct(u'ProductVersion', u'1, 5, 0, 0')])\n    ]), \n    VarFileInfo([VarStruct(u'Translation', [1033, 1200])])\n  ]\n)"
  },
  {
    "path": "otherfiles/requirements-splitter.py",
    "content": "# -*- coding: utf-8 -*-\n\"\"\"Requirements splitter.\"\"\"\n\ntest_req = \"\"\n\nwith open('dev-requirements.txt', 'r') as f:\n    for line in f:\n        if '==' not in line:\n            test_req += line\n\nwith open('test-requirements.txt', 'w') as f:\n    f.write(test_req)\n"
  },
  {
    "path": "otherfiles/version_check.py",
    "content": "# -*- coding: utf-8 -*-\n\"\"\"Version-check script.\"\"\"\nimport os\nimport sys\nimport codecs\nFailed = 0\nVERSION = \"1.5\"\n\nVERSION_1 = VERSION.split(\".\")[0]\nVERSION_2 = str(int(float(VERSION) * 10 - int(VERSION_1) * 10))\nVERSION_3 = str(int(float(VERSION) * 100 - int(VERSION_1)\n                    * 100 - int(VERSION_2) * 10))\nVERSION_4 = \"0\"\n\nSETUP_ITEMS = [\n    \"version='{0}'\",\n    'https://github.com/sepandhaghighi/nafas/tarball/v{0}']\nREADME_ITEMS = [\n    \"[Version {0}](https://github.com/sepandhaghighi/nafas/archive/v{0}.zip)\",\n    #\"[Exe-Version {0}](https://github.com/sepandhaghighi/nafas/releases/download/v{0}/NAFAS-{0}.exe)\",\n    #\"Run `NAFAS-{0}.exe`\",\n    \"pip install nafas=={0}\"]\nCHANGELOG_ITEMS = [\n    \"## [{0}]\",\n    \"https://github.com/sepandhaghighi/nafas/compare/v{0}...dev\",\n    \"[{0}]:\"]\nRC_ITEMS = [\n    \"filevers=({0}, {1}, {2}, {3})\",\n    \"prodvers=({0}, {1}, {2}, {3})\",\n    \"(u'FileVersion', u'{0}.{1}.{2}.{3}'),\",\n    \"(u'ProductVersion', u'{0}, {1}, {2}, {3}')\"]\nPARAMS_ITEMS = ['NAFAS_VERSION = \"{0}\"']\nSPEC_ITEMS = ['nafas_version = \"{0}\"']\nISSUE_TEMPLATE_ITEMS = [\"- Nafas {0}\"]\nSECURITY_ITEMS = [\"| {0}           | :white_check_mark: |\", \"| < {0}         | :x:                |\"]\nFILES = {\n    \"setup.py\": SETUP_ITEMS,\n    \"NAFAS.spec\": SPEC_ITEMS,\n    \"README.md\": README_ITEMS,\n    \"CHANGELOG.md\": CHANGELOG_ITEMS,\n    \"SECURITY.md\": SECURITY_ITEMS,\n    os.path.join(\n        \"nafas\",\n        \"params.py\"): PARAMS_ITEMS,\n    os.path.join(\n        \".github\",\n        \"ISSUE_TEMPLATE\",\n        \"bug_report.yml\"): ISSUE_TEMPLATE_ITEMS,\n}\n\nTEST_NUMBER = len(FILES.keys()) + 1\n\n\ndef print_result(failed: bool = False) -> None:\n    \"\"\"\n    Print final result.\n\n    :param failed: failed flag\n    :type failed: bool\n    :return: None\n    \"\"\"\n    message = \"Version tag tests \"\n    if not failed:\n        print(\"\\n\" + message + \"passed!\")\n    else:\n        print(\"\\n\" + message + \"failed!\")\n    print(\"Passed : \" + str(TEST_NUMBER - Failed) + \"/\" + str(TEST_NUMBER))\n\n\nif __name__ == \"__main__\":\n    for file_name in FILES.keys():\n        try:\n            file_content = codecs.open(\n                file_name, \"r\", \"utf-8\", 'ignore').read()\n            for test_item in FILES[file_name]:\n                if file_content.find(test_item.format(VERSION)) == -1:\n                    print(\"Incorrect version tag in \" + file_name)\n                    Failed += 1\n                    break\n        except Exception as e:\n            Failed += 1\n            print(\"Error in \" + file_name + \"\\n\" + \"Message : \" + str(e))\n    try:\n        file_content = codecs.open(\n            os.path.join(\n                \"otherfiles\",\n                \"Version.rc\"),\n            \"r\",\n            \"utf-8\",\n            'ignore').read()\n        for test_item in RC_ITEMS:\n            if file_content.find(\n                test_item.format(\n                    VERSION_1,\n                    VERSION_2,\n                    VERSION_3,\n                    VERSION_4)) == -1:\n                print(\"Incorrect version tag in \" + \"Version.rc\")\n                Failed += 1\n                break\n    except Exception as e:\n        Failed += 1\n        print(\"Error in Version.rc\" + \"\\n\" + \"Message : \" + str(e))\n\n    if Failed == 0:\n        print_result(False)\n        sys.exit(0)\n    else:\n        print_result(True)\n        sys.exit(1)\n"
  },
  {
    "path": "pytest.ini",
    "content": "# content of pytest.ini\n[pytest]\naddopts = --doctest-modules\ndoctest_optionflags= NORMALIZE_WHITESPACE IGNORE_EXCEPTION_DETAIL ELLIPSIS"
  },
  {
    "path": "requirements.txt",
    "content": "art>=1.8\nnava>=0.4\ncolorama>=0.4.5\n"
  },
  {
    "path": "setup.py",
    "content": "# -*- coding: utf-8 -*-\n\"\"\"Setup module.\"\"\"\nfrom typing import List\ntry:\n    from setuptools import setup\nexcept ImportError:\n    from distutils.core import setup\n\n\ndef get_requires() -> List[str]:\n    \"\"\"Read requirements.txt.\"\"\"\n    requirements = open(\"requirements.txt\", \"r\").read()\n    return list(filter(lambda x: x != \"\", requirements.split()))\n\n\ndef read_description() -> str:\n    \"\"\"Read README.md and CHANGELOG.md.\"\"\"\n    try:\n        with open(\"README.md\") as r:\n            description = \"\\n\"\n            description += r.read()\n        with open(\"CHANGELOG.md\") as c:\n            description += \"\\n\"\n            description += c.read()\n        return description\n    except Exception:\n        return '''Breathing gymnastics application'''\n\n\nsetup(\n    name='nafas',\n    packages=['nafas'],\n    version='1.5',\n    description='Breathing gymnastics application',\n    long_description=read_description(),\n    long_description_content_type='text/markdown',\n    include_package_data=True,\n    author='Nafas Development Team',\n    author_email='me@sepand.tech',\n    url='https://github.com/sepandhaghighi/nafas',\n    download_url='https://github.com/sepandhaghighi/nafas/tarball/v1.5',\n    keywords=\"breath breathing meditation yoga pranayama\",\n    project_urls={\n        'Source': 'https://github.com/sepandhaghighi/nafas',\n        'Discord': 'https://discord.gg/CtZUNKJHP4',\n    },\n    install_requires=get_requires(),\n    python_requires='>=3.7',\n    classifiers=[\n        'Development Status :: 5 - Production/Stable',\n        'Natural Language :: English',\n        'License :: OSI Approved :: MIT License',\n        'Operating System :: OS Independent',\n        'Programming Language :: Python :: 3.7',\n        'Programming Language :: Python :: 3.8',\n        'Programming Language :: Python :: 3.9',\n        'Programming Language :: Python :: 3.10',\n        'Programming Language :: Python :: 3.11',\n        'Programming Language :: Python :: 3.12',\n        'Programming Language :: Python :: 3.13',\n        'Programming Language :: Python :: 3.14',\n        'Intended Audience :: Developers',\n        'Intended Audience :: Education',\n        'Intended Audience :: End Users/Desktop',\n        'Intended Audience :: Other Audience',\n        'Topic :: Games/Entertainment',\n        'Topic :: Utilities',\n    ],\n    license='MIT',\n    entry_points={\n        'console_scripts': [\n            'nafas = nafas.__main__:main',\n        ]}\n)\n"
  },
  {
    "path": "test/test.py",
    "content": "# -*- coding: utf-8 -*-\n\"\"\"\n>>> import os\n>>> import doctest\n>>> import io\n>>> import contextlib\n>>> doctest.ELLIPSIS_MARKER = \"ignore_this_message\"\n>>> from pytest import warns\n>>> import shutil\n>>> from nafas.functions import *\n>>> set_color(None)\n>>> f = io.StringIO()\n>>> with contextlib.redirect_stdout(f):\n...     set_color(\"blue\")\n>>> \"\\x1b[34m\" in f.getvalue()\nTrue\n>>> with contextlib.redirect_stdout(f):\n...     set_color(\"lightblue\")\n>>> \"\\x1b[94m\" in f.getvalue()\nTrue\n>>> set_bg_color(None)\n>>> with contextlib.redirect_stdout(f):\n...     set_bg_color(\"yellow\")\n>>> \"\\x1b[43m\" in f.getvalue()\nTrue\n>>> with contextlib.redirect_stdout(f):\n...     set_bg_color(\"lightyellow\")\n>>> \"\\x1b[103m\" in f.getvalue()\nTrue\n>>> set_intensity(None)\n>>> with contextlib.redirect_stdout(f):\n...     set_intensity(\"dim\")\n>>> \"\\x1b[2m\" in f.getvalue()\nTrue\n>>> clear_screen()\n\n>>> print_line(10,\"*\")\n**********\n>>> print_nafas_description()\n<BLANKLINE>\nRepository: https://github.com/sepandhaghighi/nafas\nPaper: https://arxiv.org/abs/2412.04667\n* If you use Nafas in your research, please cite our paper\n<BLANKLINE>\n######################################################################\nBreathing  gymnastics  is  a  system of breathing exercises that focuses on the treatment of various\ndiseases  and  general  health  promotion. Nafas is a collection of breathing gymnastics designed to\nreduce  the exhaustion of long working hours. With multiple breathing patterns, Nafas helps you find\nyour  way  to  a detoxified energetic workday and also improves your concentration by increasing the\noxygen  level.  No  need  to  walk away to take a break, just sit comfortably, run Nafas and let the\njourney begin.\n######################################################################\n<BLANKLINE>\nBreathing tips:\n<BLANKLINE>\n1. Inhaling is only done through the nose\n2. Exhaling, you can use both nose and mouth\n3. When exhaling through your mouth, it is recommended to fold the lips\n<BLANKLINE>\n######################################################################\n<BLANKLINE>\nCautions:\n<BLANKLINE>\n1. If you have any breathing or respiratory issues, consult your doctor before using Nafas\n2. If you have asthma or high blood pressure should not hold the breath\n3. If you feel dizzy, nauseous, or lightheaded stop practicing and rest\n<BLANKLINE>\n>>> is_int(2)\nTrue\n>>> is_int(2.1)\nFalse\n>>> validate_config({\"item\":2})\nFalse\n>>> validate_config({\"name\": \"program1\", \"unit\": 2, \"pre\": 3, \"cycle\": 5, \"ratio\":{\"inhale\": 1, \"exhale\":1, \"retain\":1, \"sustain\":1}})\nTrue\n>>> validate_config({\"name\": \"program1\", \"unit\": 2, \"pre\": 3, \"cycle\": 5.2, \"ratio\":{\"inhale\": 1, \"exhale\":1, \"retain\":1, \"sustain\":1}})\nFalse\n>>> result = load_config(os.path.join(\"test\", \"test_config1.json\"))\n>>> result[\"status\"]\nTrue\n>>> result[\"data\"][\"program_name\"]\n'program1'\n>>> result[\"data\"][\"program_level\"]\n'Custom'\n>>> result[\"data\"][\"program_data\"][\"cycle\"]\n10\n>>> result[\"data\"][\"program_data\"][\"unit\"]\n2\n>>> result[\"data\"][\"program_data\"][\"pre\"]\n3\n>>> result[\"data\"][\"program_data\"][\"ratio\"] == [2,3,2,4]\nTrue\n>>> result = load_config(os.path.join(\"test\", \"test_config2.json\"))\n>>> result[\"status\"]\nFalse\n>>> result = load_config(os.path.join(\"test\", \"test_config3.json\"))\n>>> result[\"status\"]\nFalse\n>>> result = generate_config(\".\")\n>>> result\nFalse\n>>> result = generate_config(\"test_config4.json\")\n>>> result\nTrue\n>>> result = load_config(\"test_config4.json\")\n>>> result[\"status\"]\nTrue\n>>> result[\"data\"][\"program_name\"]\n'unknown'\n>>> result[\"data\"][\"program_level\"]\n'Custom'\n>>> result[\"data\"][\"program_data\"][\"cycle\"]\n5\n>>> result[\"data\"][\"program_data\"][\"unit\"]\n1\n>>> result[\"data\"][\"program_data\"][\"pre\"]\n3\n>>> result[\"data\"][\"program_data\"][\"ratio\"] == [1,1,1,1]\nTrue\n>>> print(\"\\\\n\".join(justify_text([\"123\"], 2)))\n123\n>>> print(\"\\\\n\".join(justify_text([\"123\"], 1)))\n123\n>>> print(\"\\\\n\".join(justify_text([\"123\"], 0)))\n123\n>>> print(\"\\\\n\".join(justify_text(\"\", 2)))\n<BLANKLINE>\n>>> print(\"\\\\n\".join(justify_text([\" 1\", \"2\", \"3\"], 2)))\n1\n2\n3\n>>> print(\"\\\\n\".join(justify_text([\" 1\", \"2\", \"3\"], 3)))\n1\n2\n3\n>>> input_data = filter_input({\"program\":1,\"level\":1})\n>>> input_data[\"program\"] == 1\nTrue\n>>> input_data[\"level\"] == 1\nTrue\n>>> input_data = filter_input({\"program\":200,\"level\":5})\n>>> input_data[\"program\"] == 1\nTrue\n>>> input_data[\"level\"] == 1\nTrue\n>>> def test_keyboard_interrupt(i):\n...     raise KeyboardInterrupt\n>>> input_data = get_standard_input(lambda x: \"1\")\n- Choose a program:\n<BLANKLINE>\n1- Clear Mind (~ 7 minutes)\n2- Relax1 (~ 7 minutes)\n3- Relax2 (~ 3 minutes)\n4- Relax3 (~ 6 minutes)\n5- Calming1 (~ 9 minutes)\n6- Calming2 (~ 2 minutes)\n7- Calming3 (~ 2 minutes)\n8- Power (~ 7 minutes)\n9- Harmony (~ 7 minutes)\n10- Anti-Stress (~ 4 minutes)\n11- Anti-Appetite (~ 10 minutes)\n12- Cigarette Replace (~ 5 minutes)\n13- Decision-Making (~ 2 minutes)\n14- Balancing (~ 2 minutes)\n15- Energizing (~ 2 minutes)\n16- Box (~ 2 minutes)\n17- Coherent (~ 8 minutes)\n18- Fire (~ 7 minutes)\n19- Retention (~ 3 minutes)\n20- Swooning (~ 5 minutes)\n- Choose a level:\n<BLANKLINE>\n1- Beginner\n2- Medium\n3- Advanced\n>>> get_standard_input(test_keyboard_interrupt)\nTraceback (most recent call last):\n...\nSystemExit\n>>> input_data[\"program\"] == 1\nTrue\n>>> input_data[\"level\"] == 1\nTrue\n>>> program_name,level,program_data = get_program_data({\"program\":1,\"level\":1})\n>>> program_data[\"pre\"] == 3\nTrue\n>>> program_data[\"unit\"] == 3\nTrue\n>>> print_program_details(\"Clear Mind\",\"Beginner\",{\"ratio\": [1, 0, 3, 0], \"unit\": 3, \"pre\": 3, \"cycle\": 35})\n######################################################################\nProgram Details:\n<BLANKLINE>\nName                     : Clear Mind\n<BLANKLINE>\nLevel                    : Beginner\n<BLANKLINE>\nNumber of Cycles         : 35\n<BLANKLINE>\nUnit                     : 3 seconds\n<BLANKLINE>\nTotal Time               : 07 minutes, 03 seconds\n<BLANKLINE>\nBreaths per Minute (BPM) : 5\n<BLANKLINE>\nSequence                 : Inhale(1), Retain(0), Exhale(3), Sustain(0)\n<BLANKLINE>\n######################################################################\n>>> print_program_details(\"Custom\",\"Beginner\",{\"ratio\": [1, 1, 3, 2], \"unit\": 1, \"pre\": 3, \"cycle\": 35})\n######################################################################\nProgram Details:\n<BLANKLINE>\nName                     : Custom\n<BLANKLINE>\nLevel                    : Beginner\n<BLANKLINE>\nNumber of Cycles         : 35\n<BLANKLINE>\nUnit                     : 1 seconds\n<BLANKLINE>\nTotal Time               : 04 minutes, 08 seconds\n<BLANKLINE>\nBreaths per Minute (BPM) : 8.57\n<BLANKLINE>\nSequence                 : Inhale(1), Retain(1), Exhale(3), Sustain(2)\n<BLANKLINE>\n######################################################################\n>>> run_program({'cycle': 2, 'pre': 3, 'unit': 1, 'ratio': [1, 0, 3, 0]}, 'us1')\nPreparing . . .\n######################################################################\nStart\n######################################################################\nCycle: 1 (Remaining: 1)\n- Inhale for 1 seconds\n.\n- Exhale for 3 seconds\n. . .\n######################################################################\nCycle: 2 (Remaining: 0)\n- Inhale for 1 seconds\n.\n- Exhale for 3 seconds\n. . .\n######################################################################\nWell done!\n>>> run_program({'cycle': 2, 'pre': 3, 'unit': 1, 'ratio': [1, 0, 3, 0]}, 'us2', silent=True)\nPreparing . . .\n######################################################################\nStart\n######################################################################\nCycle: 1 (Remaining: 1)\n- Inhale for 1 seconds\n.\n- Exhale for 3 seconds\n. . .\n######################################################################\nCycle: 2 (Remaining: 0)\n- Inhale for 1 seconds\n.\n- Exhale for 3 seconds\n. . .\n######################################################################\nWell done!\n>>> run_program({'cycle': 2, 'pre': 3, 'unit': 1, 'ratio': [1, 0, 3.3, 0]}, 'in1')\nPreparing . . . \n######################################################################\nStart\n######################################################################\nCycle: 1 (Remaining: 1)\n- Inhale for 1 seconds\n.\n- Exhale for 3.3 seconds\n. . . .\n######################################################################\nCycle: 2 (Remaining: 0)\n- Inhale for 1 seconds\n.\n- Exhale for 3.3 seconds\n. . . .\n######################################################################\nWell done!\n>>> run_program({'cycle': 2, 'pre': 3, 'unit': 1, 'ratio': [1, 0, 3.3, 0]}, 'in2')\nPreparing . . . \n######################################################################\nStart\n######################################################################\nCycle: 1 (Remaining: 1)\n- Inhale for 1 seconds\n.\n- Exhale for 3.3 seconds\n. . . .\n######################################################################\nCycle: 2 (Remaining: 0)\n- Inhale for 1 seconds\n.\n- Exhale for 3.3 seconds\n. . . .\n######################################################################\nWell done!\n>>> run_program({'cycle': 2, 'pre': 3, 'unit': 1, 'ratio': [1, 0, 3.3, 0]}, 'cn1')\nPreparing . . . \n######################################################################\nStart\n######################################################################\nCycle: 1 (Remaining: 1)\n- Inhale for 1 seconds\n.\n- Exhale for 3.3 seconds\n. . . .\n######################################################################\nCycle: 2 (Remaining: 0)\n- Inhale for 1 seconds\n.\n- Exhale for 3.3 seconds\n. . . .\n######################################################################\nWell done!\n>>> run_program({'cycle': 2, 'pre': 3, 'unit': 1, 'ratio': [1, 0, 3.3, 0]}, 'cn2')\nPreparing . . . \n######################################################################\nStart\n######################################################################\nCycle: 1 (Remaining: 1)\n- Inhale for 1 seconds\n.\n- Exhale for 3.3 seconds\n. . . .\n######################################################################\nCycle: 2 (Remaining: 0)\n- Inhale for 1 seconds\n.\n- Exhale for 3.3 seconds\n. . . .\n######################################################################\nWell done!\n>>> run_program({'cycle': 2, 'pre': 3, 'unit': 1, 'ratio': [1, 0, 3.3, 0]}, 'ca1')\nPreparing . . . \n######################################################################\nStart\n######################################################################\nCycle: 1 (Remaining: 1)\n- Inhale for 1 seconds\n.\n- Exhale for 3.3 seconds\n. . . .\n######################################################################\nCycle: 2 (Remaining: 0)\n- Inhale for 1 seconds\n.\n- Exhale for 3.3 seconds\n. . . .\n######################################################################\nWell done!\n>>> run_program({'cycle': 2, 'pre': 3, 'unit': 1, 'ratio': [1, 0, 3.3, 0]}, 'ca2')\nPreparing . . . \n######################################################################\nStart\n######################################################################\nCycle: 1 (Remaining: 1)\n- Inhale for 1 seconds\n.\n- Exhale for 3.3 seconds\n. . . .\n######################################################################\nCycle: 2 (Remaining: 0)\n- Inhale for 1 seconds\n.\n- Exhale for 3.3 seconds\n. . . .\n######################################################################\nWell done!\n>>> run_program({'cycle': 2, 'pre': 3, 'unit': 1, 'ratio': [1, 0, 3.3, 0]}, 'au1')\nPreparing . . . \n######################################################################\nStart\n######################################################################\nCycle: 1 (Remaining: 1)\n- Inhale for 1 seconds\n.\n- Exhale for 3.3 seconds\n. . . .\n######################################################################\nCycle: 2 (Remaining: 0)\n- Inhale for 1 seconds\n.\n- Exhale for 3.3 seconds\n. . . .\n######################################################################\nWell done!\n>>> run_program({'cycle': 2, 'pre': 3, 'unit': 1, 'ratio': [1, 0, 3.3, 0]}, 'au2')\nPreparing . . .\n######################################################################\nStart\n######################################################################\nCycle: 1 (Remaining: 1)\n- Inhale for 1 seconds\n.\n- Exhale for 3.3 seconds\n. . . .\n######################################################################\nCycle: 2 (Remaining: 0)\n- Inhale for 1 seconds\n.\n- Exhale for 3.3 seconds\n. . . .\n######################################################################\nWell done!\n>>> run_program({'cycle': 2, 'pre': 3, 'unit': 1, 'ratio': [1, 0, 3.3, 0]}, 'uk1')\nPreparing . . .\n######################################################################\nStart\n######################################################################\nCycle: 1 (Remaining: 1)\n- Inhale for 1 seconds\n.\n- Exhale for 3.3 seconds\n. . . .\n######################################################################\nCycle: 2 (Remaining: 0)\n- Inhale for 1 seconds\n.\n- Exhale for 3.3 seconds\n. . . .\n######################################################################\nWell done!\n>>> run_program({'cycle': 2, 'pre': 3, 'unit': 1, 'ratio': [1, 0, 3.3, 0]}, 'uk2')\nPreparing . . .\n######################################################################\nStart\n######################################################################\nCycle: 1 (Remaining: 1)\n- Inhale for 1 seconds\n.\n- Exhale for 3.3 seconds\n. . . .\n######################################################################\nCycle: 2 (Remaining: 0)\n- Inhale for 1 seconds\n.\n- Exhale for 3.3 seconds\n. . . .\n######################################################################\nWell done!\n>>> sid = play_sound(1)\nTraceback (most recent call last):\n        ...\nnava.errors.NavaBaseError: Sound file's path should be a string.\n>>> try:\n...     wave_path = os.path.join(\"nafas\", \"sounds\", \"silence.wav\")\n...     temp_path = os.path.join(\"nafas\", \"sounds\", \"temp.wav\")\n...     _ = shutil.move(wave_path, temp_path)\n...     with warns(RuntimeWarning, match=\"Your device is not compatible with our underlying sound-playing library. You can refer to https://github.com/openscilab/nava.\"):\n...         check_sound_flag = check_sound()\n...     _ = shutil.move(temp_path, wave_path)\n... except Exception:\n...     pass\n>>> check_sound_flag\nFalse\n>>> # testing get_rendered_survey_link for multiple cases\n>>> get_rendered_survey_link(\"X\", \"Medium\", {\"ratio\": [1, 0, 4, 0], \"unit\": 3, \"pre\": 3, \"cycle\": 28})\n'https://opsclb.li/nafas/form?version=1.5&data=%7B\"name\":+\"X\",+\"level\":+\"Medium\",+\"data\":+%7B\"ratio\":++%5B1,+0,+4,+0%5D,+\"unit\":+3,+\"pre\":+3,+\"cycle\":+28%7D%7D'\n>>> os.remove(\"test_config4.json\")\n\"\"\"\n"
  },
  {
    "path": "test/test_config1.json",
    "content": "{\n    \"name\": \"program1\",\n    \"unit\": 2,\n    \"pre\": 3,\n    \"cycle\": 10,\n    \"ratio\": {\n        \"inhale\": 2,\n        \"exhale\": 2,\n        \"retain\": 3,\n        \"sustain\": 4\n    }\n}\n"
  },
  {
    "path": "test/test_config2.json",
    "content": "{\n    \"name\": \"program2\",\n    \"unit\": 2,\n    \"pre\": 3,\n    \"cycle\": 10.2,\n    \"ratio\": {\n        \"inhale\": 2,\n        \"exhale\": 2,\n        \"retain\": 2,\n        \"sustain\": 2\n    }\n}\n"
  },
  {
    "path": "test/test_config3.json",
    "content": "{\n    \"name\": \"program3\",\n    \"unit\": 2,\n    \"pre\": 3,\n    \"cycle\": 10,\n    \"ratio\": {\n        \"inhale\": 2,\n        \"exhale\": 2,\n        \"retain\": 2\n    }\n}\n"
  }
]