[
  {
    "path": ".eslintrc.json",
    "content": "{\n  \"env\": {\n    \"browser\": true,\n    \"es6\": true,\n    \"jquery\": true\n  },\n  \"globals\": {\n    \"initial_data\": true,\n    \"module\": true,\n    \"_\": true,\n    \"moment\": true\n  },\n  \"extends\": \"eslint:recommended\",\n  \"parserOptions\": {\n    \"ecmaFeatures\": {\n      \"experimentalObjectRestSpread\": true,\n      \"jsx\": true\n    },\n    \"sourceType\": \"module\"\n  },\n  \"plugins\": [\"react\"],\n  \"rules\": {\n    \"no-console\": [0],\n    \"react/jsx-uses-vars\": 1\n  },\n  \"parser\": \"babel-eslint\"\n}\n"
  },
  {
    "path": ".flake8",
    "content": "[flake8]\nmax-line-length = 88\nignore = E501, E203, W503, E402, E231\n# line length, whitespace before ':', line break before binary operator,  module level import not at top of file\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\n\n---\n\n**Describe the bug**\nA clear and concise description of what the bug is.\n\n**To Reproduce**\nSteps to reproduce the behavior:\n1. Go to '...'\n2. Click on '....'\n3. Scroll down to '....'\n4. See error\n\n**Expected behavior**\nA clear and concise description of what you expected to happen.\n\n**Screenshots**\nIf applicable, add screenshots to help explain your problem.\n\n**Please complete the following information:**\n* OS: \n* gdbgui version (`gdbgui -v`):\n* gdb version (`gdb -v`):\n* browser [e.g. chrome, safari]:\n* python packages (`pip freeze`):\n\n\n**Additional context**\nAdd any other context about the problem here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\n\n---\n\n**Is your feature request related to a problem? Please describe.**\nA clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n\n**Describe the solution you'd like**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nA clear and concise description of any alternative solutions or features you've considered.\n\n**Additional context**\nAdd any other context or screenshots about the feature request here.\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "<!-- add an 'x' in the brackets below -->\n- [] I have added an entry to `CHANGELOG.md`, or an entry is not needed for this change\n\n## Summary of changes\n<!-- \n* fixed bug\n* added new feature \n-->\n\n## Test plan\n<!-- provide evidence of testing, preferably with command(s) that can be copy+pasted by others -->\nTested by running\n```\n# command(s) to exercise these changes\n```\n"
  },
  {
    "path": ".github/workflows/build_executable.yml",
    "content": "name: Build native gdbgui executables with pyinstaller and pex\n\non:\n  pull_request:\n  push:\n    branches:\n      - master\n  release:\n\njobs:\n  build:\n    runs-on: ${{ matrix.os }}\n    strategy:\n      matrix:\n        os: [ubuntu-latest, macos-latest]\n        python-version: [\"3.13\"]\n        include:\n          - os: ubuntu-latest\n            buildname: linux\n          # - os: windows-latest\n          #   buildname: windows\n          - os: macos-latest\n            buildname: mac\n    steps:\n      - uses: actions/checkout@v1\n      - name: Set up Python ${{ matrix.python-version }}\n        uses: actions/setup-python@v2\n        with:\n          python-version: ${{ matrix.python-version }}\n      - name: Install dependencies\n        run: |\n          python -m pip install --upgrade pip\n          python -m pip install nox\n      - name: Compile ${{ matrix.buildname }} gdbgui executable\n        run: |\n          nox --non-interactive --session build_executables_${{ matrix.buildname }}\n      - name: Upload ${{ matrix.buildname }} executable\n        uses: actions/upload-artifact@v4\n        with:\n          name: gdbgui_${{ matrix.buildname }}\n          path: ./build/executable\n          if-no-files-found: error  # Optional: warn, error, or ignore\n          retention-days: 90      # Optional: 1-90 days, or repo default            \n\n"
  },
  {
    "path": ".github/workflows/tests.yml",
    "content": "# https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions\n\nname: Tests\n\non:\n  pull_request:\n  push:\n    branches:\n      - master\n  release:\n\njobs:\n  run_tests:\n    runs-on: ${{ matrix.os }}\n    strategy:\n      matrix:\n        os: [ubuntu-latest]\n        python-version: [\"3.13\"]\n\n    steps:\n      - uses: actions/checkout@v2\n      - name: Set up Python ${{ matrix.python-version }}\n        uses: actions/setup-python@v2\n        with:\n          python-version: ${{ matrix.python-version }}\n      - name: Install dependencies\n        run: |\n          python -m pip install --upgrade pip\n          pip install nox\n      - name: Install gdb ubuntu\n        run: |\n          sudo apt update\n          sudo apt upgrade\n          sudo apt install gdb\n      - name: Execute Tests\n        run: |\n          nox --non-interactive --session tests-${{ matrix.python-version }}\n\n  build:\n    runs-on: ${{ matrix.os }}\n    strategy:\n      matrix:\n        os: [ubuntu-latest]\n        python-version: [\"3.13\"]\n\n    steps:\n      - uses: actions/checkout@v2\n      - name: Set up Python ${{ matrix.python-version }}\n        uses: actions/setup-python@v2\n        with:\n          python-version: ${{ matrix.python-version }}\n      - name: Install dependencies\n        run: |\n          python -m pip install --upgrade pip\n          pip install nox\n      - name: Execute Tests\n        run: |\n          nox --non-interactive --session build\n\n  lint:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v2\n      - name: Set up Python\n        uses: actions/setup-python@v2\n        with:\n          python-version: 3.13\n      - name: Install dependencies\n        run: |\n          python -m pip install --upgrade pip\n          pip install nox\n      - name: Lint\n        run: |\n          nox --non-interactive --session lint\n\n  docs:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v2\n      - name: Set up Python\n        uses: actions/setup-python@v2\n        with:\n          python-version: \"3.13\"\n      - name: Install dependencies\n        run: |\n          python -m pip install --upgrade pip\n          pip install nox\n      - name: Verify Docs\n        run: |\n          nox --non-interactive --session docs\n"
  },
  {
    "path": ".gitignore",
    "content": "dist\n*egg*\nnode_modules\nbuild\nexecutable\n.DS_Store\n*.a.dSYM\ngdbgui_pyinstaller.spec\n*-link\n*-link.c\n*-link.dSYM\n*.pyc\nyarn-error.log\nvenv\nsite\ngdbgui/static/js/*\n__pycache__\n.coverage*\n"
  },
  {
    "path": ".prettierrc.js",
    "content": "module.exports = {\n  printWidth: 90,\n}\n"
  },
  {
    "path": ".vscode/settings.json",
    "content": "{\n    \"python.formatting.provider\": \"none\",\n    \"[python]\": {\n        \"editor.formatOnSave\": true,\n        \"editor.defaultFormatter\": \"ms-python.black-formatter\"\n    },\n    \"[json]\": {\n        \"editor.formatOnSave\": true\n    },\n    \"files.associations\": {\n        \"*.spec\": \"python\"\n    }\n}"
  },
  {
    "path": ".vulture_whitelist.py",
    "content": "_.sessions  # unused attribute (noxfile.py:7)\n_.reuse_existing_virtualenvs  # unused attribute (noxfile.py:6)\n_.secret_key  # unused attribute (gdbgui/backend.py:104)\n_.reuse_existing_virtualenvs  # unused attribute (noxfile.py:6)\n_.sessions  # unused attribute (noxfile.py:7)\ncover  # unused function (noxfile.py:50)\nlint  # unused function (noxfile.py:78)\nautoformat  # unused function (noxfile.py:94)\ndocs  # unused function (noxfile.py:103)\ndevelop  # unused function (noxfile.py:109)\nserve  # unused function (noxfile.py:118)\npublish  # unused function (noxfile.py:133)\nwatch_docs  # unused function (noxfile.py:142)\nbuild_executable_current_platform  # unused function (noxfile.py:154)\nbuild_executable_mac  # unused function (noxfile.py:162)\nbuild_executable_linux  # unused function (noxfile.py:169)\nbuild_executable_windows  # unused function (noxfile.py:176)\non_connect  # unused function (tests/test_backend.py:14)\nmonkeypatch  # unused variable (tests/test_cli.py:23)\nmonkeypatch  # unused variable (tests/test_cli.py:33)\nmonkeypatch  # unused variable (tests/test_cli.py:43)\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# gdbgui release history\n\n## 0.15.3.0\n- Update default python version to 3.13\n\n## 0.15.2.0\n- Update default python version to 3.12\n- utf-8 decode error bugfix\n- fix registers cannot be displayed bug\n\n## 0.15.1.0\n\n- Compatibility with Werkzeug 2.1. Use the eventlet server instead of\n  the Werkzeug development server.\n- Use pinned requirements instead of abstract requirements to ensure reproducability of pip installs\n\n## 0.15.0.1\n\nThis release has no changes to features or usability. The only change is to include a file used by other package maintainers.\n\n- Include all files needed to rebuild from source (#403)\n\n## 0.15.0.0\n\nThis release is focused mostly on Python 3.9 compatibility and updating dependencies\n\n- Support only Python 3.9 (though other Python versions may still work)\n- Build gdbgui as a [pex](https://pypi.org/project/pex/) executable.\n  - These are executable Python environments that are self-contained with the exception of requiring a specific Python version installed in the environment running the executable. The pex executables should have better compatibility than PyInstaller executables, which sometimes have missing shared libraries depending on the operating system.\n- Use only the threading async model for flask-socketio. No longer support gevent or eventlet.\n- [bugfix] Catch exception if gdb used in tty window crashes instead of gdbgui crashing along with it\n- Disable pagination in gdb tty by default. It can be turned back on with `set pagination off`.\n- Upgrade various dependencies for both the backend and frontend (Python and JavaScript)\n- Display gdbgui version in \"about\" and \"session information\"\n\n## 0.14.0.2\n\n- Pinned python-socketio version\n- Pinned mypy version to unbreak linting\n- Fixed reverse debugging commands that were broken when `--gdb` flag was removed\n\n## 0.14.0.1\n\n- Fix import paths\n- Pin broken dependency to avoid segfault\n- Hide \"No registers.\" message\n\n## 0.14.0.0\n\n**Breaking Changes**\n\n- Removed support for Windows\n- Replaced `--gdb` flag with `--gdb-cmd`. The `--gdb-cmd` argument specifies the gdb executable as well as all arguments you wish to pass to gdb at startup, for example `--gdb-cmd \"gdb -nx\"`. The existing `-g` argument is an alias for `--gdb-cmd`.\n- Removed `--rr` flag. Use `--gdb-cmd \"rr replay --\"` instead.\n- Removed deprecated and hidden `--hide-gdbgui-upgrades` argument. It will now raise an error.\n\n**Additional Changes**\n\n- Replaced single terminal on frontend with three terminals: an interactive xterm terminal running gdb, a gdbgui console for diagnostic messages, and a terminal connected to the inferior application being debugged.\n- Updates to the dashboard\n- Add ability to specify gdb command from the browser. This can now be accomplished from the dashboard.\n- Removed gdbgui binaries from source control. They can now be downloaded as artifacts of [releases](https://github.com/cs01/gdbgui/releases).\n- [documentation] Fix bug when generating md5 checksum for binary releases\n- Remove \"shutdown\" button in UI\n\n## 0.13.2.1\n\n- No end user changes. This release builds the gdbgui executables with GitHub actions.\n\n## 0.13.2.0\n\n- Print number of times a breakpoint was hit (@MatthiasKreileder).\n- Publish sdist to PyPI (this was overlooked in previous release).\n- Do not notify users of gdbgui upgrades (deprecate `--hide-gdbgui-upgrades` flag)\n- Drop support for Python 3.4\n- [dev] Some infrastructure changes to gdbgui. End users should not be affected.\n- [dev] Fix build error due to webpack bug (https://github.com/webpack/webpack/issues/8082).\n\n## 0.13.1.2\n\n- Exclude \"tests\" directory from Python package\n- Remove analytics from documentation\n\n## 0.13.1.1\n\n- Add `__main__` entrypoint\n\n## 0.13.1.0\n\n- Remove automatic flushing of stdout and require newer version of pygdbmi\n- Add flake8 tests to CI build\n\n## 0.13.0.0\n\n- Add ability to re-map source file paths. Added flags `--remap-sources` and `-m` to replace compile-time source paths to local source paths. i.e. `gdbgui --remap-sources='{\"/buildmachine\": \"/home/chad\"}'` (#158)\n- Add shift keyboard shortcut to go in reverse when using rr (#201)\n- Pass arbitrary gdb arguments directly to gdb: added `--gdb-args` flag\n- Removed `-x` CLI option, which caused major version to change. New way to pass is `gdbgui --gdb-args='-x=FILE'` (#205)\n- Add \"name\" to Threads (new gdb 8.1 feature) (@P4Cu)\n- Fix crash/black screen from \"Python Exception <class NameError> name long is not defined\" #212\n- Fix bug when debugging filenames with spaces (Fix Cannot create breakpoint: -break-insert: Garbage following <location> #211\")\n- Fix empty frame causes the ui to crash/black screen #216\n- Update npm packages; update react to 16.4\n- Update prettier rules\n- Update tour text + fix typo in tour (@nkirkby)\n\n## 0.12.0.0\n\n- Add pause button\n- Update command line parsing for cmd and --args, change arguments from underscore to hyphen, add option to specify browser (@fritzr)\n- Add tour\n- Run `set breakpoint pending on` on initial connection\n- Allow signal to be sent to arbitrary PIDs\n- Fix bug when sending signals in Python2\n- Move signal component lower in side pane\n- Update Rust documentation\n- Make requirements.txt point to setup.py's dependencies\n\n## 0.11.3.1\n\n- Limit maximum Flask version to prevent `Session expired. Please refresh this webpage.` error\n- Rename \"premium\" to \"ad-free\"\n- Do smarter version checking\n- Fix bug when trying to view \"about\"\n\n## 0.11.3.0\n\n- ensure expressions with hex values are parsed and updated appropriately (#182)\n- improve command line arguments\n- use python logging module\n\n## 0.11.2.1\n\n- Small bugfix for specific platforms when reading version number\n\n## 0.11.2.0\n\n- add option to remove fflush command (#179)\n- remove react-treebeard and render filesystem w/ new component\n\n## 0.11.1.1\n\n- Bugfix displaying upgrade text\n\n## 0.11.1.0\n\n- Add csrf and cross origin protection\n- Convert backslashes to forward slashes when entering windows binary paths (#167)\n- Fix safari ui issue (#164)\n- Update text on reload file button, and disable when no file is loaded (#165)\n- When disassembly can't be fetched in mode 4, fetch in mode 3 and assume gdb version is 7.6.0 (#166)\n- Add copy to clipboard icon for files and variables\n- Allow SSL module import to fail and print warning (#170)\n- Cleanup menu, add license info, bugfixes, etc. (#169, #136, #163, #172)\n\n## 0.11.0.0\n\n- Replace `--auth` cli option with `--user` and `--password`\n\n## 0.10.3.0\n\n- Added resizer buttons to components on right pane\n\n## 0.10.2.1\n\n- Add link for fix for macOS users\n- Update version of React to 16.2\n- Remove unused links\n\n## 0.10.2.0\n\n- Add folders view, rearrange layout (@martin-der)\n- Add settings cog button\n- Add message when sending signal to inferior process (#156)\n- Change default theme to monokai, rename 'default' theme to 'light'\n- Minor bugfixes\n\n## 0.10.1.0\n\n- Display descriptions of registers\n- Do not try to fetch Registers when they cannot be read\n\n## 0.10.0.2\n\n- Add support for rr (--rr flag)\n- Add dashboard to connect to/kill existing gdb processes\n- Add option to specify SSL key and certificate to enable https\n- Add option to connect to process\n- Add option to connect to gdbserver\n- Add infinite scrolling\n\n## 0.9.4.1\n\n- Remove `pypugjs` dependency\n\n## 0.9.4.0\n\n- Add native Windows support (no longer relies on Cygwin)\n\n## 0.9.3.0\n\n- Only display assembly flavor is assembly is displayed\n- Add new output type to console (gdbgui output)\n- Add dashboard link and dropdown for gdb server/pid attach\n- Handle invalid signal choice better\n- Print gdb mi log messages to console\n- Remove localStorage keys when they are invalid\n\n## 0.9.2.0\n\n- Add signals component and allow signals to be sent to gdb (issue ##141)\n- Fix bug when jumping to line of source file\n\n## 0.9.1.1\n\n- Fix bug when passing arguments to gdb\n- Require latest version of pygdbmi for faster parsing of large gdb output\n\n## 0.9.1.0\n\n- Lazily load files (issue #131)\n- Update setup.py to build wheels\n\n## 0.9.0.1\n\n- Reupload to fix setup.cfg PyPI bug\n\n## 0.9.0.0\n\n- Compress responses from server (massive bandwidth improvement)\n- Add button to toggle assembly flavors (issue #110)\n- Parse executable+args with spaces (issue #116)\n- Turn modals into components\n- Move everything into a single root React component\n- Refresh state when clicking \"return\" button\n- Add javascript unit tests\n\n## 0.8.2.0\n\n- Add optional authentication (@nickamon, issue #132)\n- Support the `--args` flag (issue #126)\n- Ensure code is correct and adheres to recommended Python style when running tests/building (flake8)\n- Display source when running `backtrace` (fix regression, #134)\n\n## 0.8.1.0\n\n- Add autocomplete functionality (@bobthekingofegypt, issue #129)\n- Rearranged and improved alignment of assembly\n- Fixed bug when fetching variable fails\n- Plot floating point values instead of casting to int\n\n## 0.8.0.3\n\n- modify component initialization order so that store updates are better sequenced\n\n## 0.8.0.2\n\n- display bracket instead of `&lt;` when exploring gdb variables\n\n## 0.8.0.1\n\n- fix bug when restoring old settings\n\n## 0.8.0.0\n\n- Add ability to change radix of variables (issue #102)\n- Add component to send signals to inferior program (issues #31, #90)\n- Parse gdb version from arm-non-eabi-gdb (issue #83)\n- Rewrite most components to React (issue #17)\n- Improve CSS in various components\n\n## 0.7.9.5\n\n- re-fetch registers if name/value count does not match\n\n## 0.7.9.4\n\n- add inputs to resize Tree view\n- add menu in top right\n- css updates to preserve whitespace in terminal\n- add top-level html to wrap body+head elements in gdbgui.pug\n- add help file\n- add donate page\n\n## 0.7.9.3\n\n- Changes to layout\n- Fix character escaping in breakpoint line display\n\n## 0.7.9.2\n\n- Fix firefox css bug\n- Update examples\n- Update readme for windows (cygwin) users (thanks tgharib)\n\n## 0.7.9.1\n\n- Collapse simple fields to the parent node in tree explorer\n- Add button to re-enter program state when signals are received (i.e. SEGFAULT)\n\n## 0.7.9.0\n\n- Add interactive tree explorer of variables\n\n## 0.7.8.3\n\n- Remove optimization for fetching registers due to potential bug\n\n## 0.7.8.2\n\n- bugfix in logic when jumping to source code line\n- bugfix for when variable goes from`empty -> 1 element`\n- add CODE OF CONDUCT, CONTRIBUTING, and CHANGELOG files\n\n## 0.7.8.1\n\n- correctly display `<` and `>` in console widget\n\n## 0.7.8.0\n\n- show disassembly when file is unknown or missing\n- show new children in expressions widget when they are dynamically added by application (@wuyihao)\n- suppress nuisance errors when hover variable or fflush command is not found\n- improve logic when source code line should be jumped to\n- escape brackets in disassembly, and gracefully hide missing opcodes\n- update socketio version for more reliable websocket connection\n\n## 0.7.7.0\n\n- Show variable values when hovering in source code\n- gracefully handle hostname not being present in /etc/hosts when running with remote flag\n- Use external state management library (`stator.js`) for client ui\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "Thanks for your interest in contributing to gdbgui!\n\nIf your change is small, go ahead and submit a pull request. If it is substantial, create a GitHub issue to discuss it before making the change.\n\n## Dependencies\n\n1.) [nox](https://github.com/theacodes/nox) is used to automate various tasks. You will need it installed on your system before continuing.\n\nYou can install it with pipx (recommended):\n```\n> pipx install nox\n```\nor pip:\n```\n> pip install --user nox\n```\n\n2.) [yarn](https://yarnpkg.com/) is used for managing JavaScript files\n\n## Developing\nDevelopment can be done with one simple step:\n```\n> nox -s develop\n```\nThis will install all Python and JavaScript dependencies, and build and watch Python and JavaScript files for changes, automatically reloading as things are changed.\n\nMake sure you [turn your cache off](https://www.technipages.com/google-chrome-how-to-completely-disable-cache) so that changes made locally are reflected in the page.\n\n## Running and Adding tests\n```bash\n> nox\n```\n\nruns all applicable tests and linting.\n\nPython tests are in `gdbgui/tests`. They are run as part of the above command, but can be run with\n```\n> nox -s python_tests\n```\n\nJavaScript tests are in `gdbgui/src/js/tests`. They are run as part of the above command, but can be run with\n```\n> nox -s js_tests\n```\n\n## Documentation\n\n### Modifying Documentation\nDocumentation is made with `mkdocs`. Then make changes to `mkdocs.yml` or md files in the `docs` directory.\n\nTo build docs, run\n```\nnox -s docs\n```\n\nTo see a live preview of current documentation, run\n```\nnox -s watch_docs\n```\n\n### Publishing Documentation\nThe generated documentation is published to the `gh-pages` branch.\n```\nnox -s publish_docs\n```\n\n### Building Binary Executables\n\nThese are automatically built on CI, but can be built locally with corresponding `nox` commands, such as:\n\n```\nnox -s build_executables_current_platform\n```\n\n## Publishing a New Version\n1. Make sure the version number is incremented in `VERSION.txt`.\n1. The version to release must be on the master branch and have all CI tests pass and new binary executable artifacts attached to the GitHub action results\n1. Publish the package to PyPI and update documentation. Both are done with this `nox -s publish`.\n1. Create a \"release\" in GitHub and attach the gdbgui binary executable artifacts to it.\n\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (C) Chad Smith (Grass Fed Code)\n\n                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The GNU General Public License is a free, copyleft license for\nsoftware and other kinds of works.\n\n  The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works.  By contrast,\nthe GNU General Public License is intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users.  We, the Free Software Foundation, use the\nGNU General Public License for most of our software; it applies also to\nany other work released this way by its authors.  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n  To protect your rights, we need to prevent others from denying you\nthese rights or asking you to surrender the rights.  Therefore, you have\ncertain responsibilities if you distribute copies of the software, or if\nyou modify it: responsibilities to respect the freedom of others.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must pass on to the recipients the same\nfreedoms that you received.  You must make sure that they, too, receive\nor can get the source code.  And you must show them these terms so they\nknow their rights.\n\n  Developers that use the GNU GPL protect your rights with two steps:\n(1) assert copyright on the software, and (2) offer you this License\ngiving you legal permission to copy, distribute and/or modify it.\n\n  For the developers' and authors' protection, the GPL clearly explains\nthat there is no warranty for this free software.  For both users' and\nauthors' sake, the GPL requires that modified versions be marked as\nchanged, so that their problems will not be attributed erroneously to\nauthors of previous versions.\n\n  Some devices are designed to deny users access to install or run\nmodified versions of the software inside them, although the manufacturer\ncan do so.  This is fundamentally incompatible with the aim of\nprotecting users' freedom to change the software.  The systematic\npattern of such abuse occurs in the area of products for individuals to\nuse, which is precisely where it is most unacceptable.  Therefore, we\nhave designed this version of the GPL to prohibit the practice for those\nproducts.  If such problems arise substantially in other domains, we\nstand ready to extend this provision to those domains in future versions\nof the GPL, as needed to protect the freedom of users.\n\n  Finally, every program is threatened constantly by software patents.\nStates should not allow patents to restrict development and use of\nsoftware on general-purpose computers, but in those that do, we wish to\navoid the special danger that patents applied to a free program could\nmake it effectively proprietary.  To prevent this, the GPL assures that\npatents cannot be used to render the program non-free.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                       TERMS AND CONDITIONS\n\n  0. Definitions.\n\n  \"This License\" refers to version 3 of the GNU General Public License.\n\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n  \"The Program\" refers to any copyrightable work licensed under this\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n  To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy.  The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n  A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n  To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy.  Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n  To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies.  Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n  An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License.  If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n  1. Source Code.\n\n  The \"source code\" for a work means the preferred form of the work\nfor making modifications to it.  \"Object code\" means any non-source\nform of a work.\n\n  A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n  The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form.  A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n  The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities.  However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work.  For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n  The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n  The Corresponding Source for a work in source code form is that\nsame work.\n\n  2. Basic Permissions.\n\n  All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met.  This License explicitly affirms your unlimited\npermission to run the unmodified Program.  The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work.  This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n  You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force.  You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright.  Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n  Conveying under any other circumstances is permitted solely under\nthe conditions stated below.  Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n  No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n  When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n  4. Conveying Verbatim Copies.\n\n  You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n  You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n  5. Conveying Modified Source Versions.\n\n  You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n    a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n\n    b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under section\n    7.  This requirement modifies the requirement in section 4 to\n    \"keep intact all notices\".\n\n    c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy.  This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged.  This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n\n    d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\n  A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit.  Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n  6. Conveying Non-Source Forms.\n\n  You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n    a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n\n    b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the\n    Corresponding Source from a network server at no charge.\n\n    c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source.  This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n\n    d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge.  You need not require recipients to copy the\n    Corresponding Source along with the object code.  If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source.  Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n\n    e) Convey the object code using peer-to-peer transmission, provided\n    you inform other peers where the object code and Corresponding\n    Source of the work are being offered to the general public at no\n    charge under subsection 6d.\n\n  A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n  A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling.  In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage.  For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product.  A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n  \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source.  The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n  If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information.  But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n  The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed.  Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n  Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n  7. Additional Terms.\n\n  \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law.  If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n  When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit.  (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.)  You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n  Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n    a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n\n    b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n\n    c) Prohibiting misrepresentation of the origin of that material, or\n    requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n\n    d) Limiting the use for publicity purposes of names of licensors or\n    authors of the material; or\n\n    e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n\n    f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions of\n    it) with contractual assumptions of liability to the recipient, for\n    any liability that these contractual assumptions directly impose on\n    those licensors and authors.\n\n  All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10.  If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term.  If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n  If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n  Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n  8. Termination.\n\n  You may not propagate or modify a covered work except as expressly\nprovided under this License.  Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n  However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n  Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n  Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License.  If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n  9. Acceptance Not Required for Having Copies.\n\n  You are not required to accept this License in order to receive or\nrun a copy of the Program.  Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance.  However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work.  These actions infringe copyright if you do\nnot accept this License.  Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n  10. Automatic Licensing of Downstream Recipients.\n\n  Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License.  You are not responsible\nfor enforcing compliance by third parties with this License.\n\n  An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations.  If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n  You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License.  For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n  11. Patents.\n\n  A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based.  The\nwork thus licensed is called the contributor's \"contributor version\".\n\n  A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version.  For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n  In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement).  To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n  If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients.  \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n  If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n  A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License.  You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n  Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n  12. No Surrender of Others' Freedom.\n\n  If conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all.  For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n  13. Use with the GNU Affero General Public License.\n\n  Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU Affero General Public License into a single\ncombined work, and to convey the resulting work.  The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the special requirements of the GNU Affero General Public License,\nsection 13, concerning interaction through a network will apply to the\ncombination as such.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\n  Each version is given a distinguishing version number.  If the\nProgram specifies that a certain numbered version of the GNU General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation.  If the Program does not specify a version number of the\nGNU General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n  If the Program specifies that a proxy can decide which future\nversions of the GNU General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n  Later license versions may give you additional or different\npermissions.  However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n  15. Disclaimer of Warranty.\n\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. Limitation of Liability.\n\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n  17. Interpretation of Sections 15 and 16.\n\n  If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nstate the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    {one line to give the program's name and a brief idea of what it does.}\n    Copyright (C) {year}  {name of author}\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n  If the program does terminal interaction, make it output a short\nnotice like this when it starts in an interactive mode:\n\n    {project}  Copyright (C) {year}  {fullname}\n    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, your program's commands\nmight be different; for a GUI interface, you would use an \"about box\".\n\n  You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU GPL, see\n<http://www.gnu.org/licenses/>.\n\n  The GNU General Public License does not permit incorporating your program\ninto proprietary programs.  If your program is a subroutine library, you\nmay consider it more useful to permit linking proprietary applications with\nthe library.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.  But first, please read\n<http://www.gnu.org/philosophy/why-not-lgpl.html>.\n"
  },
  {
    "path": "MANIFEST.in",
    "content": "include README.md\ninclude LICENSE\ninclude requirements.txt\n\ngraft gdbgui\n# these files are built and must be included in distribution\n# but shouldn't be included in git repository since they\n# are generated\ngraft gdbgui/static/js\n\nprune examples\nprune .vscode\nprune downloads\nprune screenshots\nprune tests\nprune docs\nprune docker\nprune images\nprune gdbgui/__pycache__\nprune gdbgui/server/__pycache__\nprune gdbgui/src\n\nexclude mypy.ini\nexclude .eslintrc.json\nexclude .coveragerc\nexclude .flake8\nexclude .vulture_whitelist.py\nexclude .prettierrc.js\nexclude jest.config.js\nexclude make_executable.py\nexclude mkdocs.yml\nexclude package.json\nexclude requirements.in\nexclude tsconfig.json\nexclude tslint.json\nexclude webpack.config.js\nexclude yarn.lock\nexclude noxfile.py\nexclude CHANGELOG.md\nexclude CONTRIBUTING.md\nexclude postcss.config.js\nexclude tailwind.config.js\n"
  },
  {
    "path": "README.md",
    "content": "<p align=\"center\">\n<a href=\"http://gdbgui.com\"><img src=\"https://github.com/cs01/gdbgui/raw/master/images/gdbgui_banner.png\"></a>\n</p>\n\n<h3 align=\"center\">\nA browser-based frontend to gdb (gnu debugger)\n</h3>\n\n<p align=\"center\">\n\n<a href=\"https://github.com/cs01/gdbgui/actions\">\n<img src=\"https://github.com/cs01/gdbgui/workflows/Tests/badge.svg?branch=master\" alt=\"image\" /></a>\n\n<a href=\"https://badge.fury.io/py/gdbgui\">\n<img src=\"https://badge.fury.io/py/gdbgui.svg\" alt=\"PyPI version\" >\n</a>\n\n<img src=\"https://pepy.tech/badge/gdbgui\" alt=\"image\" />\n\n</p>\n\n---\n\n**Documentation**: https://gdbgui.com\n\n**Source Code**: https://github.com/cs01/gdbgui/\n"
  },
  {
    "path": "docs/CNAME",
    "content": "www.gdbgui.com"
  },
  {
    "path": "docs/api.md",
    "content": "This is the command line help output of gdbgui.\n\n```\nusage: gdbgui [-h] [-g GDB_CMD] [-p PORT] [--host HOST] [-r]\n              [--auth-file AUTH_FILE] [--user USER] [--password PASSWORD]\n              [--key KEY] [--cert CERT] [--remap-sources REMAP_SOURCES]\n              [--project PROJECT] [-v] [-n] [-b BROWSER] [--debug]\n              [--args ...]\n              [debug_program]\n\nA server that provides a graphical user interface to the gnu debugger (gdb).\nhttps://github.com/cs01/gdbgui\n\npositional arguments:\n  debug_program         The executable file you wish to debug, and any\n                        arguments to pass to it. To pass flags to the\n                        binary, wrap in quotes, or use --args instead.\n                        Example: gdbgui ./mybinary [other-gdbgui-args...]\n                        Example: gdbgui './mybinary myarg -flag1 -flag2'\n                        [other gdbgui args...] (default: None)\n\noptional arguments:\n  -h, --help            show this help message and exit\n  --args ...            Specify the executable file you wish to debug and\n                        any arguments to pass to it. All arguments are taken\n                        literally, so if used, this must be the last\n                        argument. This can also be specified later in the\n                        frontend. passed to gdbgui. Example: gdbgui [...]\n                        --args ./mybinary myarg -flag1 -flag2 (default: [])\n\ngdb settings:\n  -g GDB_CMD, --gdb-cmd GDB_CMD\n                        gdb binary and arguments to run. If passing\n                        arguments, enclose in quotes. If using rr, it should\n                        be specified here with 'rr replay'. Examples: gdb,\n                        /path/to/gdb, 'gdb --command=FILE -ix', 'rr replay'\n                        (default: gdb)\n\ngdbgui network settings:\n  -p PORT, --port PORT  The port on which gdbgui will be hosted (default:\n                        5000)\n  --host HOST           The host ip address on which gdbgui serve (default:\n                        127.0.0.1)\n  -r, --remote          Shortcut to set host to 0.0.0.0 and suppress browser\n                        from opening. This allows remote access to gdbgui\n                        and is useful when running on a remote machine that\n                        you want to view/debug from your local browser, or\n                        let someone else debug your application remotely.\n                        (default: False)\n\nsecurity settings:\n  --auth-file AUTH_FILE\n                        Require authentication before accessing gdbgui in\n                        the browser. Specify a file that contains the HTTP\n                        Basic auth username and password separate by\n                        newline. (default: None)\n  --user USER           Username when authenticating (default: None)\n  --password PASSWORD   Password when authenticating (default: None)\n  --key KEY             SSL private key. Generate with:openssl req -newkey\n                        rsa:2048 -nodes -keyout host.key -x509 -days 365\n                        -out host.cert (default: None)\n  --cert CERT           SSL certificate. Generate with:openssl req -newkey\n                        rsa:2048 -nodes -keyout host.key -x509 -days 365\n                        -out host.cert (default: None)\n\nother settings:\n  --remap-sources REMAP_SOURCES, -m REMAP_SOURCES\n                        Replace compile-time source paths to local source\n                        paths. Pass valid JSON key/value pairs.i.e. --remap-\n                        sources='{\"/buildmachine\": \"/current/machine\"}'\n                        (default: None)\n  --project PROJECT     Set the project directory. When viewing the\n                        \"folders\" pane, paths are shown relative to this\n                        directory. (default: None)\n  -v, --version         Print version (default: False)\n  -n, --no-browser      By default, the browser will open with gdbgui. Pass\n                        this flag so the browser does not open. (default:\n                        False)\n  -b BROWSER, --browser BROWSER\n                        Use the given browser executable instead of the\n                        system default. (default: None)\n  --debug               The debug flag of this Flask application. Pass this\n                        flag when debugging gdbgui itself to automatically\n                        reload the server when changes are detected\n                        (default: False)\n```\n"
  },
  {
    "path": "docs/contact.md",
    "content": "* Email: chadsmith.software@gmail.com"
  },
  {
    "path": "docs/examples.md",
    "content": "\n# Examples\n## Code Examples\nView code examples on [GitHub](https://github.com/cs01/gdbgui/tree/master/examples).\n\n## gdbgui Invocation Examples\n\nlaunch gdbgui\n\n```\ngdbgui\n```\n\nset the inferior program, pass argument, set a breakpoint at main\n\n```\ngdbgui --args ./myprogram myarg -myflag\n```\n\n\n```\ngdbgui \"./myprogram myarg -myflag\"\n```\n\nuse gdb binary not on your $PATH\n\n```\ngdbgui --gdb-cmd build/mygdb\n```\n\nPass arbitrary arguments directly to gdb when it is launched\n\n```\ngdbgui --gdb-cmd=\"gdb -x gdbcmds.txt\"\n```\n\nrun on port 8080 instead of the default port\n\n```\ngdbgui --port 8080\n```\n\n\n\nrun on a server and host on 0.0.0.0. Accessible to the outside world as long as port 80 is not blocked.\n\n```\ngdbgui -r\n```\n\nSame as previous but will prompt for a username and password\n\n```\ngdbgui -r --auth\n```\n\nSame as previous but with encrypted https connection.\n```\nopenssl req -newkey rsa:2048 -nodes -keyout private.key -x509 -days 365 -out host.cert\n```\n```\ngdbgui -r --auth --key private.key --cert host.cert\n```\n\nUse Mozilla's [record and replay](https://rr-project.org) (rr) debugging supplement to gdb. rr lets your record a program (usually with a hard-to-reproduce bug in it), then deterministically replay it as many times as you want. You can even step forwards and backwards.\n```\ngdbgui --gdb-cmd \"rr replay --\"\n```\n\nUse recording other than the most recent one\n\n```\ngdbgui --gdb-cmd \"rr replay RECORDED_DIRECTORY --\"\n```\n\nDon't automatically open the browser when launching\n\n```\ngdbgui -n\n```\n"
  },
  {
    "path": "docs/faq.md",
    "content": "## How can I see what commands are being sent to gdb?\nGo to Settings and check the box that says `Print all sent commands in console, including those sent automatically by gdbgui`\n\n## How can I see gdb's raw output?\nLaunch gdbgui with the debug flag, `gdbgui --debug`, then a new component will appear on the bottom right side of UI.\n\n## Can I use a different gdb executable?\nYes, use `gdbgui -g <gdb executable>`\n\n## Does this work with LLDB?\nNo, only gdb.\n\n## Can this debug Python?\nNo. It uses gdb on the backend which does not debug Python code.\n\n## How do I make program output appear in a different terminal?\nOn linux terminals are named. You can get a terminal's name by running `tty` which will print something like `/dev/ttys3`. Tell gdb to use the terminal gdbgui was launched from with\n\n```bash\ngdbgui --gdb-args=\"--tty=$(tty)\"\n```\n\nor if you want to set it from the UI after gdbgui has been opened, run\n\n```bash\nset inferior-tty /dev/ttys3  # replace /dev/ttys3 with desired tty name\n```\n\n## Help! There isn't a button for something I want to do. What should I do?\nThe vast majority of common use cases are handled in the UI, and to keep the UI somewhat simple I do not intend on making UI support for every single gdb command. You can search gdb documentation and use any gdb command you want in the console at the bottom of the window. If you think there should be a UI element for a command or function, create an issue on GitHub and I will consider it.\n"
  },
  {
    "path": "docs/gettingstarted.md",
    "content": "Before running `gdbgui`, you should compile your program with debug symbols and a lower level of optimization, so code isn't optimized out before runtime. To include debug symbols with `gcc` use `-ggdb`, with `rustc` use `-g`. To disable most optimizations in `gcc` use the `-O0` flag, with `rustc` use `-O`.\n\nFor more details, consult your compiler's documentation or a search engine.\n\nNow that you have `gdbgui` installed and your program compiled with debug symbols, all you need to do is run\n```\ngdbgui\n```\n\nThis will start gdbgui's server and open a new tab in your browser. That tab contains a fully functional frontend running `gdb`!\n\nYou can see gdbgui in action on [YouTube](https://www.youtube.com/channel/UCUCOSclB97r9nd54NpXMV5A).\n\nTo see the full list of options gdbgui offers, you can view command line options by running\n```\ngdbgui --help\n```\n\nIf you have a question about something\n\n* Read documentation on the [homepage](https://github.com/cs01/gdbgui/)\n* [Ask question in an issue on github](https://github.com/cs01/gdbgui/issues)\n\n\n## Settings\n`gdbgui` settings can be accessed by clicking the gear icon in the top right of the frontend. Most of these settings persist between sessions for a given url and port.\n\n\n## Keyboard Shortcuts\nThe following keyboard shortcuts are available when the focus is not in an input field. They have the same effect as when the button is pressed.\n\n* Run: r\n* Continue: c\n* Next: n or right arrow\n* Step: s or down arrow\n* Up: u or up arrow\n* Next Instruction: m\n* Step Instruction: ,\n"
  },
  {
    "path": "docs/guides.md",
    "content": "gdb can be used in a plethora of environments. These guides help you get gdb and gdbgui working in specific environments.\n\nRemember, these guides, like gdbgui, are **open source** and can be edited by you, the users! See [contributing](contributing) to modify these docs.\n\n## Running Locally\n\nAfter downloading gdbgui, you can launch it like so:\n\n* `gdbgui` (or whatever the binary name is, i.e. `gdbgui_0.10.0.0`)\n* `gdbgui --args ./mybinary -myarg value -flag1 -flag2`\n\nMake sure the program you want to debug was compiled with debug symbols. See the getting started section for more details.\n\nA new tab in your browser will open with gdbgui in it. If a browser tab did not open, navigate to the ip/port that gdbgui is being served on (i.e. http://localhost:5000).\n\nNow that gdbgui is open, you can interactively run a program with it.\n* Type the path to the executable in the input at the top (next to \"Load Binary\"). The executable should already exist and have been compiled with the `-g` flag.\n* Click `Load Binary`. The program and symbols will load, but will not begin running. A breakpoint will be added to main automatically. This can be changed in settings if you prefer not to do this.\n* The line of source code corresponding to main will display if the program was compiled with the `-g` flag debug symbols.\n* Click the Run button, which is on the top right and looks like a circular arrow.\n* Step through the program by clicking the Next, Step, Continue, icons as desired. These are also on the top right.\n\nFor a list of gdbgui arguments, run `gdbgui --help`.\n\n## Running Remotely\nBecause gdbgui is a server, it naturally allows you to debug programs running on other computers.\n\n* ssh into the computer with the program that needs to be debugged.\n* run `gdbgui -r` on the remote machine (this will serve publicly so beware of security here)\n* on your local machine, open your browser and access the remote machine's ip and port\n* debug the remote computer in your local browser\n\nNote that gnu also distrubutes a program called `gdbserver` which gdbgui is compatible with. See the relevant section in this doc.\n\n## Debugging Rust Programs\n\n`gdbgui` can be used to debug programs written in Rust. Assuming you use [Cargo](https://doc.rust-lang.org/stable/cargo/) to create a new program\nand build it in Debug mode in the standard way:\n\n```\ncargo new myprog\ncd myprog\ncargo build\n```\n\nYou can start debugging with\n\n```\ngdbgui --args target/debug/myprog\n```\n\nThere are a couple of small difficulties.\n\n1.) Instead of showing your `main` function the initial screen will be blank and `gdbgui` will print `File not found: main`.\nYou need to help `gdbgui` out by typing `main` into the file browser box:\n\n![](https://raw.githubusercontent.com/cs01/gdbgui/master/screenshots/rust_main.png)\n\nand selecting the `main.rs` file. The source code should then appear in the browser and you can click to set breakpoints\nand run the program. Of course, if you want to break in some other file, you can find that in the file browser instead.\n\n### Rust on macOS\n\nWhen you load your rust binary on a mac, you may see many warnings like this\n\n> warning /Users/user/examples/rust/target/debug/deps/hello-486956f9dde465e5.9elsx31vb4it187.rcgu.o': can't open to read symbols: No such file or directory.\n\nSymbols are names of variables, functions and types defined in your program. You can define symbols for your program by loading symbol files. gdb usually does this automatically for you, but sometimes has trouble finding the right paths.\n\nIn this case, you need to manually tell gdb where the symbol files is; it's usually the first part of the missing file. In the above example, it's `hello-486956f9dde465e5.9elsx31vb4it187.rcgu.o`.\n\nYou can load this into gdb with the following command (changed as appropriate):\n\n```\nsymbol-file /Users/user/git/gdbgui/examples/rust/target/debug/deps/hello-486956f9dde465e5\n```\n\n2.) The GDB pretty-printing macros that Rust ships with. GDB can't find these by default, which makes it print the message\n\n```\nwarning: Missing auto-load script at offset 0 in section .debug_gdb_scripts of file /home/temp/myprog/target/debug/myprog.\nUse `info auto-load python-scripts [REGEXP]' to list them.\n```\n\nYou can safely ignore this, but the [Rust issue](https://github.com/rust-lang/rust/issues/33159#issuecomment-384073290)\ndescribes the workarounds necessary (create a `.gdbinit` file and paste a few lines into the Python helper script).\n\n* On Windows Rust defaults to the MSVC toolchain, and `gdbgui` can't debug binaries compiled that way. If you want to use `gdbgui`, you'll have to [switch to the GNU toolchain](https://github.com/rust-lang-nursery/rustup.rs#working-with-rust-on-windows).\n* If you want to debug programs compiled in Release mode, you will need to create a `profile.release` section in your\n  `Cargo.toml` and add `debug = true` to it. See the [Cargo manifest](https://doc.rust-lang.org/stable/cargo/reference/manifest.html) for details.\n\nand now gdb will be able to see which files were used to compile your binary, among other things.\n\n\n## Connecting to gdbserver\nLike gdb, [`gdbserver`](https://sourceware.org/gdb/onlinedocs/gdb/Server.html) is also made by gnu, but with the following important differences:\n\n* it is much smaller than gdb\n* it is easier to port to other architectures than all of gdb\n\ngdbserver runs on a remote machine or embedded target, which, as the name suggests, runs a server. gdb communicates with gdbserver so you can debug on your local machine. To do this, the remote machine must run the server and program:\n\n`gdbserver :9000 mybinary.a`\n\nThen you can launch `gdb` or `gdbgui` and connect to it. In `gdbgui`, use the dropdown to select `Connect to gdbserver`, and enter\n\n`<remote ip address>:9000`\n\nRead more at the [gdbserver homepage](https://sourceware.org/gdb/onlinedocs/gdb/Server.html).\n\nIf the machine gdbgui is running on and the target being debugged have different architectures, make sure gdb is built properly (see `Remote Debugging Between Different Architectures`).\n\n## Remote Debugging Between Different Architectures\n\nFor example, this is useful if you are working from an x86_64 based PC gdb client with gdbgui, to ARM arch gdbserver.\n\nYou need to build the `gdb` client with the `--host` and `--target` flags. You need to build the `gdbserver` for the correct architecture.\n\nBuild the `gdb` client that `gdbgui` will use. This example applies to an x86_64 pc running gdbgui that connects to an arm device running gdbserver, so you will need to ensure the targets apply to the environments you are working in:\n\n1. downloaded latest gdb source code\n2. unzip it, go into folder\n3.\n```bash\n./configure  --host=x86_64-pc-linux-gnu --build=x86_64-pc-linux-gnu --target=arm-linux-gnuabi &&\nmake -j8 &&\nsudo make install\n```\n4. Now arm-linux-gnuabi-gdb is installed by default to `/usr/local/bin`, but you can instead provide `prefix=<path>` to where you want it to install in the ./configure script above\n5. The `arm-linux-gnuabi-gdb` binary can now be used by gdbgui to connect to the ARM device:\n\n```bash\ngdbgui -g arm-linux-gnuabi-gdb\n```\n\nLinks:\n* [Building GDB and GDBserver for cross debugging](https://sourceware.org/gdb/wiki/BuildingCrossGDBandGDBserver)\n* [http://www.brain-dump.org/blog/entry/138/Cross_Arch_Remote_Debugging_with_gdb_and_gdbserver](Cross Arch Remote Debugging with gdb and gdbserver)\n* [support remote debug from x86_64 based PC gdb client with gdbgui, to ARM arch gdbserver (multiarch)](https://github.com/cs01/gdbgui/issues/237)"
  },
  {
    "path": "docs/howitworks.md",
    "content": "gdbgui consists of two main parts: the frontend and the backend\n\n## Backend\n\nThe backend is written in Python and consists of a Flask server with websocket capability thanks to the `python-socketio` package.\n\nWhen a new websocket connection from a browser is established, the server starts a new gdb subprocess and associates it with this websocket. This gdb process is told to use gdb's [machine interface](https://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI.html) interpreter, which enables gdb's input and output to be programatically parsed so you can write code to do further processing with it, such as build a user interface.\n\nThe [pygdbmi library](https://github.com/cs01/pygdbmi) is used to manage the gdb subprocess and parse its output. It returns key/value pairs (dictionaries) that can be used to create a frontend. I wrote pygdbmi as a building block for gdbgui, but it is useful for any type of programmatic control over gdb.\n\nIn summary, the backend is used to:\n\n- create endpoints for the browser, including http and websocket.\n  - The server can access the operating system and do things like read source files or send signals to processes.\n- create a managed gdb subprocess and parse output with pygdbmi\n- spawn a separate thread to constantly check for output from the gdb subprocess\n- forward output to the client through a websocket as it is parsed in the reader thread\n\n## Frontend\n\nThe frontend is written in JavaScript and uses React. It establishes a websocket connection to the server, at which time the server starts a new gdb subprocess for that particular websocket connection as mentioned above. Commands can be sent from the browser through the websocket to the server which writes to gdb, and output from gdb is forwarded from the server through the websocket to the browser.\n\nAs the browser receives websocket messages from the server, it maintains the state of gdb, such as whether it's running, paused, or exited, where breakpoints are, what the stack is, etc. As this state changes, React performs the necessary DOM updates.\n\nIn summary, the frontend is used to:\n\n* Convert key/value pairs of gdb's machine interface output into a user interface\n* Maintain the state of gdb\n* Provide UI elements that can send gdb machine interface commands to gdb"
  },
  {
    "path": "docs/index.md",
    "content": "<p align=\"center\">\n<a href=\"http://gdbgui.com\"><img src=\"https://github.com/cs01/gdbgui/raw/master/images/gdbgui_banner.png\"></a>\n</p>\n\n<h3 align=\"center\">\nA browser-based frontend to gdb (gnu debugger)\n</h3>\n\n<p align=\"center\">\n\n<a href=\"https://github.com/cs01/gdbgui/actions\">\n<img src=\"https://github.com/cs01/gdbgui/workflows/Tests/badge.svg?branch=master\" alt=\"CI Tests\" /></a>\n\n<a href=\"https://badge.fury.io/py/gdbgui\">\n<img src=\"https://badge.fury.io/py/gdbgui.svg\" alt=\"PyPI version\" >\n</a>\n\n<img src=\"https://pepy.tech/badge/gdbgui\" alt=\"Download Count\" />\n\n</p>\n\n---\n\n<p align=\"center\">\n<a href=\"https://github.com/cs01/gdbgui/raw/master/screenshots/gdbgui_animation.gif\">\n<img src=\"https://github.com/cs01/gdbgui/raw/master/screenshots/gdbgui_animation.gif\">\n</a>\n\n</p>\n\n`gdbgui` is a browser-based frontend to `gdb`, the [gnu debugger](https://www.gnu.org/software/gdb/). You can add breakpoints, view stack traces, and more in C, C++, Go, and Rust!\n\nIt's perfect for beginners and experts. Simply run `gdbgui` from the terminal to start the gdbgui server, and a new tab will open in your browser.\n\n**Sound Good? Get started with [installation](installation)**.\n\n## Testimonials\n\n\"*Definitely worth checking out.*\"\n\n<div style=\"text-align: right; margin-right: 10%;\">\n—<a href=\"https://www.youtube.com/user/lefticus1\">Jason Turner</a>, host of C++ weekly on <a href=\"https://www.youtube.com/watch?v=em842geJhfk\">YouTube</a>\n</div>\n\n\"_Seriously, great front-end to gdb for those of us who are not always using a full IDE. Great project._\"\n\n<div style=\"text-align: right; margin-right: 10%;\">\n—Jefferson on <a href=\"https://twitter.com/jeffamstutz/status/955647577373978624\">Twitter</a>\n</div>\n\n\"_Where were you all my life? And why did I use DDD?_\"\n\n<div style=\"text-align: right; margin-right: 10%;\">\n—<a href=\"https://github.com/badlogic\">Mario Zechner</a>, author, game engine developer on <a href=\"https://twitter.com/badlogicgames/status/925079139446591490\">Twitter</a>\n</div>\n\ngdbgui is used by thousands of developers around the world including engineers at Google and college computer science course instructions. It even made its way into the Rust programming language's [source code](https://github.com/rust-lang/rust/blob/master/src/etc/rust-gdbgui) and appeared on episode [110 of C++ Weekly](https://youtu.be/em842geJhfk).\n\n\n\n## License\n\ngdbgui's license is GNU GPLv3. To summarize it, you\n\n- can use it for free at work or for personal use\n- can modify its source code\n- must disclose your source code if you redistribute any part of gdbgui\n\n## Distribution\n\ngdbgui is distributed through\n\n- github ([https://github.com/cs01/gdbgui](https://github.com/cs01/gdbgui))\n- [PyPI](https://pypi.python.org/pypi/gdbgui/)\n\n## Authors\n\n- Chad Smith, creator/maintainer\n- @bobthekingofegypt, contibutor\n- [Community contributions](https://github.com/cs01/gdbgui/graphs/contributors)\n\n## Donate\n\n[Paypal](https://www.paypal.me/grassfedcode/20)\n\n## Contact\n\nhttps://chadsmith.dev\nchadsmith.software@gmail.com\n"
  },
  {
    "path": "docs/installation.md",
    "content": "# gdbgui installation\n\nThere are a few ways to install gdbgui on your machine. There is even a way to run gdbgui without installing it. Read on to to find the one that's right for you.\n\n## Method 1: Using `pipx` (recommended)\n\ngdbgui recommends using [pipx](https://github.com/pipxproject/pipx), a program to run Python CLI binaries in isolated environments.\n\nYou can install pipx like this:\n\n```\npython3 -m pip install --user pipx\npython3 -m userpath append ~/.local/bin\n```\n\nRestart/re-source your console to make sure the userpath is up to date.\n\nThen, install gdbgui with pipx:\n\n```\npipx install gdbgui\n```\n\nTo upgrade run\n\n```\npipx upgrade gdbgui\n```\n\nWhen installation is finished, type `gdbgui` from the command line to run it, or `gdbgui -h` for help.\n\nTo uninstall, run\n\n```\npipx uninstall gdbgui\n```\n\n### Try Without Installing\n\nBy using [pipx](https://github.com/pipxproject/pipx), you can run Python CLI programs in ephemeral one-time virtual environments.\n\n```\npipx run gdbgui\n```\n\nA new tab running the latest version of gdbgui will open in your browser. Press CTRL+C to end the process, and your system will remain untouched.\n\n## Method 2: Using `pip`\n\n`pip` is a popular installer for Python packages. gdbgui is a Python package and as such can be installed with pip, though we recommend using `pipx` rather than `pip` if possible.\n\nIf you prefer to use Virtual Environments, you can activate one and then run\n\n```\npip install gdbgui\n```\n\nYou can get upgrades with\n\n```\npip install --upgrade gdbgui\n```\n\nTo uninstall, run\n\n```\npip uninstall gdbgui\n```\n\n## Method 3: Download and Run Binary Executable\n\nDownload and run the binary executable for your system from [GitHub Releases](https://github.com/cs01/gdbgui/releases).\n\n## System Dependencies for Python Package\n\nNote that this only applies if you are installing the Python package, and not using the binary executable.\n\n- gdb (gnu debugger)\n- Python 3.4+ (recommended) or 2.7\n- pip version 8 or higher\n\n### Linux Dependencies\n\n    sudo apt install gdb python3\n\n### macOS Dependencies\n\n    brew install python3\n    brew install gdb --with-python --with-all-targets\n\nmacOS users must also codesign gdb: follow [these\ninstructions](http://andresabino.com/2015/04/14/codesign-gdb-on-mac-os-x-yosemite-10-10-2/). This will fix the error\n`please check gdb is codesigned - see taskgated(8)`.\n\n### Windows Dependencies\n\nNote that windows is only supported for gdbgui versions less than 0.14.\n\n- [Python 3](https://www.python.org/downloads/windows/)\n- gdb, make, gcc\n\nIf you do not have already have gdb/make/gcc installed, there are two options to install them on Windows: `MinGW` and `cygwin`.\n\n##### MinGW (recommended)\n\nMinimal GNU for Windows ([`MinGW`]([http://mingw.org/)) is the recommended Windows option. [Install MinGW](https://sourceforge.net/projects/mingw/files/Installer/mingw-get-setup.exe/download) with the \"MinGW Base System\" package. This is the default package which contains `make`, `gcc`, and `gdb`.\n\nIt will install to somewhere like `C:\\MinGW\\bin\\...`. For example `C:\\MinGW\\bin\\gdb.exe`, `C:\\MinGW\\bin\\mingw32-make.exe`, etc.\n\nEnsure this MinGW binary directory (i.e. `C:\\MinGW\\bin\\`) is on your \"Path\" environment variable: Go to `Control Panel > System Properties > Environment Variables > System Variables > Path` and make sure `C:\\MinGW\\bin\\` is added to that list. If it is not added to your \"Path\", you will have to run gdbgui with the path explicitly called out, such as `gdbgui -g C:\\MinGW\\bin\\gdb.exe`.\n\n##### Cygwin\n\nCygwin is a more UNIX-like compatibility layer on Windows, and `gdbgui` works with it as well.\n\n- Install [cygwin](https://cygwin.com/install.html)\n\nWhen installing cygwin packages, add the following:\n\n- python3\n- python3-pip\n- python3-devel\n- gdb\n- gcc-core\n- gcc-g++\n\n### Running from Source\n\nSee the [contributing](/contributing) section.\n"
  },
  {
    "path": "docs/screenshots.md",
    "content": "![image](https://github.com/cs01/gdbgui/raw/master/screenshots/gdbgui.png)\n![image](https://github.com/cs01/gdbgui/raw/master/screenshots/gdbgui2.png)\n\nEnter the binary and args just as you'd call them on the command line.\nThe binary is restored when gdbgui is opened at a later time.\n\n![image](https://github.com/cs01/gdbgui/raw/master/screenshots/load_binary_and_args.png)\n\nIntuitive control of your program. From left to right: Run, Continue,\nNext, Step, Return, Next Instruction, Step Instruction.\n\n![image](https://github.com/cs01/gdbgui/raw/master/screenshots/controls.png)\n\nIf the environment supports reverse debugging, such as when using an Intel CPU and running Linux and debugging with [rr](http://rr-project.org/), gdbgui allows you to debug in reverse.\n![image](https://github.com/cs01/gdbgui/raw/master/screenshots/reverse_debugging.png)\n\n## Stack/Threads\n\nView all threads, the full stack on the active thread, the current frame\non inactive threads. Switch between frames on the stack, or threads by\npointing and clicking.\n\n![image](https://github.com/cs01/gdbgui/raw/master/screenshots/stack_and_threads.png)\n\n## Send Signal to Inferior (debugged) Process\nChoose from any signal your OS supports to send to the inferior. For example, to mock `CTRL+C` in plain gdb, you can send `SIGINT` to interrupt the inferior process. If the inferior process is hung for some reason, you can send `SIGKILL`, etc.\n![image](https://github.com/cs01/gdbgui/raw/master/screenshots/send_signal.png)\n\n\n## Source Code\nView source, assembly, add breakpoints. All symbols used to compile the\ntarget are listed in a dropdown above the source code viewer, and have\nautocompletion capabilities. There are two different color schemes: dark (monokai), and a light theme (default).\n\n![image](https://github.com/cs01/gdbgui/raw/master/screenshots/source.png)\n\nWith assembly. Note the bold line is the current instruction that gdb is\nstopped on.\n\n![image](https://github.com/cs01/gdbgui/raw/master/screenshots/source_with_assembly.png)\n\nIf the source file is not found, it will display assembly, and allow you to step through it as desired.\n![image](https://github.com/cs01/gdbgui/raw/master/screenshots/assembly.png)\n\n\n## Variables and Expressions\n\nAll local variables are automatically displayed, and are clickable to\nexplore their fields.\n\n![image](https://github.com/cs01/gdbgui/raw/master/screenshots/locals.png)\n\nHover over a variable and explore it, just like in the Chrome debugger.\n\n![image](https://github.com/cs01/gdbgui/raw/master/screenshots/hover.png)\n\nArbitrary expressions can be evaluated as well. These expressions persist as the program is stepped through. The base/radix can be modified as desired.\n\n![image](https://github.com/cs01/gdbgui/raw/master/screenshots/radix.gif)\n\n![image](https://github.com/cs01/gdbgui/raw/master/screenshots/expressions.png)\n\nExpressions record their previous values, and can be displayed in an x/y\nplot.\n\n![image](https://github.com/cs01/gdbgui/raw/master/screenshots/plots.png)\n\nExpressions can be interactively explored in a tree view.\n\n![image](https://github.com/cs01/gdbgui/raw/master/screenshots/tree_explorer.png)\n\n\n## Memory Viewer\n\nAll hex addresses are automatically converted to clickable links to\nexplore memory. Length of memory is configurable. In this case 10 bytes\nare displayed per row.\n\n![image](https://github.com/cs01/gdbgui/raw/master/screenshots/memory.png)\n\n## Registers\n\nView all registers. If a register was updated it is highlighted in\nyellow.\n\n![image](https://github.com/cs01/gdbgui/raw/master/screenshots/registers.png)\n\n## gdb console\n\n* Prints gdb output\n* Allows you to write directly to the underlying gdb subprocess as if you were using it in the terminal\n* Tab completion works, and displays a button to view help on gdb commands\n* Can be used to ease into learning gdb\n* Can be used as a fallback for commands that don't have a UI widget\n* History can be accessed using up/down arrows\n\n![image](https://github.com/cs01/gdbgui/raw/master/screenshots/console.png)\n\n## authentication\nAuthentication can be enabled when serving on a publicly accessible IP address. See `gdbgui --help` for instructions on how to enable authentication.\n\n![image](https://github.com/cs01/gdbgui/raw/master/screenshots/authentication.png)\n\n\n## Dashboard\nA dashboard is available to let you look at all gdb instances managed by gdbgui. You can kill them, or attach to them. More than one person can attach to a managed gdb subprocess and participate in the debugging session simultaneously. i.e. if one person steps forward, all connected users see the program step forward in real time.\n\n![image](https://github.com/cs01/gdbgui/raw/master/screenshots/dashboard.png)\n\n## gdbgui at launch\n\n![image](https://github.com/cs01/gdbgui/raw/master/screenshots/ready.png)\n"
  },
  {
    "path": "examples/.gitignore",
    "content": "*.a\n"
  },
  {
    "path": "examples/README.md",
    "content": "# Examples\n\n## Overview\n`gdbgui` can debug executables generated from various languages. This folder contains example source code and makefiles to build and automatically launch `gdbgui`.\n\n## Clone\nTo get started, first clone this repository:\n```\ngit clone https://github.com/cs01/gdbgui.git\n```\n\n## Install Dependencies\nIf you already installed `gdbgui` with `pip`, you have all dependencies installed. If not, you need to install them manually:\n```bash\npip install -r gdbgui/requirements.txt  # run as sudo if this fails\n```\n\n## Build Executables and Debug with gdbgui\nEnter the directory with the language of your choice in `gdbgui/examples/*` (`c`, `cpp`, `rust`, `golang`, `fortran`), then type `make` and hit the `tab` to see the make targets.\n\nFor example, in `gdbgui/examples/c`, running `make hello` will:\n\n* build the binary (assuming you have the right compilers and libraries installed)\n* open a new tab in your browser\n* load the executable for the make target you just built\n* insert a breakpoint at main (Rust and Go users may see machine code displayed rather than source code. This is a `gdb` limitation.)\n* **Note: Although the program has loaded, you still must click the run icon to actually begin running the program.**\n"
  },
  {
    "path": "examples/c/debug_segfault.c",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n\nint main(void)\n{\n    char* badstring = 0;\n    const char* s = \"gdbgui\";\n\n    int myvar = 100;\n    unsigned int myvar2 = 200;\n\n    printf(\"The next function call will cause a segfault. With gdbgui, the state of the program\\n\"\n        \"can be debugged at the time the program exited by running the command\\n\"\n        \"\\\"backtrace\\\" or \\\"bt\\\" in the gdb console.\\n\\n\"\n        \"It will re-enter the state the\\n\"\n        \"program was in, including the stack trace: you'll end up in `main -> _IO_puts -> strlen`.\\n\"\n        \"If you click on the `main` function in the call stack, gdbgui will put you in the main function\\n\"\n        \"where you can inspect your local\\n\"\n        \"variables and determine how the segfault occured.\\n\\n\"\n        );\n\n\n    printf(\"%s\\n\", badstring);\n\n    printf(\"This line is never reached because the above line causes a segfault\\n\");\n    return 0;\n}\n"
  },
  {
    "path": "examples/c/hello.c",
    "content": "#include <stdio.h>\n#include <string.h>\nvoid say_something(const char *str)\n{\n  printf(\"%s\\n\", str);\n}\n\nstruct mystruct_t\n{\n  int value;\n  char letter;\n  char *string;\n\n  struct\n  {\n    double dbl;\n  } substruct; /* named sub-struct */\n\n  struct\n  {\n    float fp;\n  }; /* anonymous struct */\n\n  void *ptr;\n  size_t struct_size;\n  union {\n    int unionint;\n    double uniondouble;\n  };\n};\n\nint main(int argc, char **argv)\n{\n  printf(\"Hello World\\n\");\n\n  int retval = 1;\n\n  /* bytes are allocated for s,\n  but still contain garbage */\n  struct mystruct_t s;\n  s.value = 100;\n  s.string = \"pass\";\n  s.substruct.dbl = 567.8;\n  s.letter = 'P';\n  s.fp = 123.4;\n  s.ptr = say_something;  /* address of function */\n  s.ptr = &say_something; /* also address of function */\n  s.unionint = 0;\n  s.uniondouble = 1.0;\n\n  for (int i = 0; i < 2; i++)\n  {\n    printf(\"i is %d\\n\", i);\n  }\n\n  if (!strcmp(s.string, \"pass\"))\n  {\n    retval = 0;\n  }\n\n  printf(\"returning %d\\n\", retval);\n  say_something(\"Goodbye\");\n  return retval;\n}\n"
  },
  {
    "path": "examples/c/input.c",
    "content": "#include <stdio.h>\n#include <string.h>\n\nint main(int argc, char **argv)\n{\n    char name[20];\n    printf(\"Hello. What's your name?\\n\");\n    fgets(name, 20, stdin);\n    printf(\"Hi there, %s\", name);\n    return 0;\n}\n"
  },
  {
    "path": "examples/c/makefile",
    "content": "ROOT:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))\n\nhello: hello.c\n\tgcc hello.c -o hello_c.a -std=c99 -g\n\t@echo Run with gdbgui: gdbgui --args $(ROOT)/hello_c.a\n\ninput: input.c\n\tgcc input.c -o input.a -std=c99 -g\n\t@echo Run with gdbgui: gdbgui --args $(ROOT)/input.a\n\ndebug_segfault: debug_segfault.c\n\tgcc debug_segfault.c -g -o debug_segfault.a -std=c99\n\t@echo Run with gdbgui: gdbgui --args $(ROOT)/debug_segfault.a\n\nthreads: threads.c\n\tgcc threads.c -o threads.a -std=c99 -lpthread -g\n\t@echo Run with gdbgui: gdbgui --args $(ROOT)/threads.a\n\nsleeper: sleeper.c\n\tgcc sleeper.c -o sleeper.a -std=c99 -g\n\t@echo Run with gdbgui: gdbgui --args $(ROOT)/sleeper.a\n"
  },
  {
    "path": "examples/c/sleeper.c",
    "content": "#include <stdio.h>\n#include <string.h>\n#include <unistd.h>\n\nint main(int argc, char **argv) {\n  printf(\"entering\\n\");\n  while(1){\n    // while this loop is running, you cannot interact with\n    // gdb until you interrupt (send signal SIGINT) to gdb\n    // or the inferior process\n    printf(\"sleeping...\\n\");\n    sleep(2);\n    printf(\"Finished sleeping. Repeating.\\n\");\n  }\n  printf(\"exiting\\n\");\n  return 0;\n}\n"
  },
  {
    "path": "examples/c/threads.c",
    "content": "#include <pthread.h>\n#include <stdio.h>\n\nstatic const int num_increments = 2;\n\n/* this function is run by the second thread */\nvoid *thread_callback(void *arg)\n{\n    int *val = (int*)arg;\n    while((*val) < num_increments){\n        printf(\"incrementing\\n\");\n        (*val)++;\n    }\n    printf(\"increment finished\\n\");\n}\n\nint main()\n{\n    int x = 0, y = 0;\n    printf(\"x: %d, y: %d\\n\", x, y);\n    pthread_t thread_to_increment_x, thread_to_increment_y;\n\n    /* create and run threads */\n    if(pthread_create(&thread_to_increment_x, NULL, thread_callback, &x)) {\n        printf(\"error: pthread_create returned non-zero value\\n\");\n        return 1;\n    }\n    if(pthread_create(&thread_to_increment_y, NULL, thread_callback, &y)) {\n        printf(\"error: pthread_create returned non-zero value\\n\");\n        return 1;\n    }\n\n    /* wait for threads to finish */\n    if(pthread_join(thread_to_increment_x, NULL)) {\n        printf(\"error: pthread_join returned non-zero value\\n\");\n        return 1;\n    }\n    if(pthread_join(thread_to_increment_y, NULL)) {\n        printf(\"error: pthread_join returned non-zero value\\n\");\n        return 1;\n    }\n    printf(\"x: %d, y: %d\\n\", x, y);\n\n    return 0;\n\n}\n"
  },
  {
    "path": "examples/c/tree.c",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n\nstruct Node\n{\n    struct Node* left;\n    struct Node* right;\n    char* name;\n};\n\nvoid visit(struct Node* node)\n{\n    printf(\"visiting node '%s'\\n\", node->name);\n}\n\nvoid dfs(struct Node *node)\n{\n    if (node == NULL)\n    {\n        return;\n    }\n\n    visit(node);\n    dfs(node->left);\n    dfs(node->right);\n}\n\nint main(void)\n{\n    printf(\"gdbgui has a widget that allows interactive tree exploration. \"\n        \"Enter 'root' in  'Expressions' widget, then hover over root and click the tree icon next to 'root' to draw the tree. \"\n        \"The tree is automatically updated as the program's state changes changed.\\n\\n\");\n    /* initialize nodes so that left/right are NULL and each\n    node has a name */\n    struct Node\n        root = {.name = \"root\"},\n        a = {.name = \"a\"},\n        b = {.name = \"b\"},\n        c = {.name = \"c\"},\n        d = {.name = \"d\"},\n        e = {.name = \"e\"},\n        f = {.name = \"f\"};\n\n    /* connect nodes */\n    printf(\"As you step through the following code, you can see the graph grow and change as assignments are made\\n\");\n    root.left = &a;\n    root.right = &b;\n    a.left = &c;\n    a.right = &d;\n    d.left = &e;\n    b.right = &f;\n\n    printf(\"beginning depth first search. We can verify the dfs algorithm is accurate by comparing it to gdbgui's graph view.\\n\");\n    dfs(&root);\n    printf(\"finished depth first search\\n\");\n    return 0;\n}\n"
  },
  {
    "path": "examples/cpp/hello.cpp",
    "content": "#include <iostream>\n#include <vector>\n#include <map>\n\nint main(void)\n{\n    std::cout << \"Hello World\" << std::endl;\n\n    std::cout << \"Example vector\" << std::endl;\n    std::vector<double> myvector {};\n    myvector.push_back(1.1);\n    myvector.push_back(2.2);\n    myvector.push_back(3.3);\n    myvector.push_back(4.4);\n    for (auto i : myvector){\n        std::cout << i << \" is an element in a vector\" << std::endl;\n    }\n\n    std::cout << \"Example map\" << std::endl;\n    std::map<char,int> mymap;\n    mymap['a'] = 10;\n    mymap['b'] = 30;\n    mymap['c'] = 50;\n    mymap['d'] = 70;\n    for (auto i : mymap){\n        std::cout << i.first << \" is a key in a map with a value of \" << i.second << std::endl;\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "examples/cpp/linked_list.cpp",
    "content": "#include <iostream>\n\nclass Node{\n\nprivate:\n    Node* next = 0;\n    Node* prev = 0;\n    int value;\n\npublic:\n    Node(int v){\n        value = v;\n    }\n\n    int get_value() const{\n        return value;\n    }\n\n    void print_values() const{\n        std::cout << this->get_value() << std::endl;\n        if(this->next){\n            this->next->print_values();\n        }\n    }\n\n    void append(int v){\n        Node* new_node = new Node(v);\n        Node* iter = this;\n        while(iter->next){\n            iter = iter->next;\n        }\n        iter->next = new_node;\n        new_node->prev = iter;\n    }\n};\n\nint main(){\n    Node* linked_list = new Node(0);\n    linked_list->print_values();\n    linked_list->append(1);\n    linked_list->append(2);\n    linked_list->append(3);\n    linked_list->append(4);\n    linked_list->print_values();\n    return 0;\n}\n"
  },
  {
    "path": "examples/cpp/makefile",
    "content": "GDBGUI=../../gdbgui/backend.py\n\nhello: hello.cpp\n\tg++ hello.cpp -o hello_cpp.a -std=c++11 -g\n\t@echo Run with gdbgui: gdbgui --args hello_cpp.a\n\nlinked_list: linked_list.cpp\n\tg++ linked_list.cpp -o linked_list_cpp.a -std=c++11 -g\n\t@echo Run with gdbgui: gdbgui --args linked_list_cpp.a\n\nsmart_ptr_demo: smart_ptr_demo.cpp\n\tg++ smart_ptr_demo.cpp -o smart_ptr_demo_cpp.a -std=c++11 -g\n\t@echo Run with gdbgui: gdbgui --args smart_ptr_demo_cpp.a\n\nsin: sin.cpp\n\tg++ sin.cpp -o sin_cpp.a -std=c++11 -g\n\t@echo Run with gdbgui: gdbgui --args sin_cpp.a\n"
  },
  {
    "path": "examples/cpp/sin.cpp",
    "content": "#include <math.h>       /* sin */\n\nint main ()\n{\n  double angle = 0, result = 0;\n  static const double RAD_TO_DEG = 3.14159265 / 180;\n  while (angle <= 360){\n    result = sin(angle * RAD_TO_DEG);\n    angle += 20;\n  }\n  return 0;\n}\n"
  },
  {
    "path": "examples/cpp/smart_ptr_demo.cpp",
    "content": "// A demonstration of unique, smart, weak, and raw pointers in C++11.\n// compile with:\n//  g++ smart_ptr_demo.cpp -std=c++11 -o smart_ptr_cpp_demo.a -g\n//\n// running yields:\n// >> ./smart_ptr_demo_cpp.a\n// constructed raw pointer, at address 0x169fc20\n// entering local scope\n// entered local scope\n// constructed unique (only one reference) pointer, at address 0x16a0090\n// constructed shared (local and global reference) pointer, at address 0x16a00f0\n// constructed shared (one shared reference, two weak references) pointer, at address 0x16a0060\n// local weak pointer has valid reference\n// global weak pointer has valid reference\n// smart pointers can be accessed like regular pointers\n// This is my type: unique (only one reference)\n// This is my type: shared (local and global reference)\n// leaving local scope\n// destroyed shared (one shared reference, two weak references) pointer, at address 0x16a0060\n// destroyed unique (only one reference) pointer, at address 0x16a0090\n// left local scope\n// global weak pointer has no reference\n// destroyed raw pointer, at address 0x169fc20\n// leaving main\n// destroyed shared (local and global reference) pointer, at address 0x16a00f0\n\n\n#include <iostream>\n#include <memory>\n#include <string>\n\n// A class that prints metadata when constructed and destroyed\nclass SimpleType\n{\n    std::string m_ptr_type;\n\npublic:\n    SimpleType(const std::string& ptr_type){\n        m_ptr_type = ptr_type;\n        std::cout << \"constructed \" << m_ptr_type << \" pointer, at address \" << this << std::endl;\n    }\n    ~SimpleType(){\n        std::cout << \"destroyed \" << m_ptr_type << \" pointer, at address \" << this << std::endl;\n    }\n    void identify(){\n        std::cout << \"This is my type: \" << m_ptr_type << std::endl;\n    }\n};\n\nint main()\n{\n    std::unique_ptr<SimpleType> globalunique;\n    std::shared_ptr<SimpleType> globalshared;\n    std::weak_ptr<SimpleType> globalweak;\n    SimpleType* raw_ptr = new SimpleType(\"raw\");\n\n    // locally scoped operations will cause smart pointers to automatically\n    // be deleted (garbage collected) if no owners remain at the end of the scope\n    std::cout << \"entering local scope\" << std::endl;\n    {\n        std::cout << \"entered local scope\" << std::endl;\n        // unique (deleted upon exit of this local scope)\n        std::unique_ptr<SimpleType> localunique = std::unique_ptr<SimpleType>(new SimpleType(\"unique (only one reference)\"));\n\n        // shared with > 1 owner (not deleted upon exit of this local scope)\n        std::shared_ptr<SimpleType> localshared = std::shared_ptr<SimpleType>(new SimpleType(\"shared (local and global reference)\"));\n        globalshared = localshared;  // assign global reference\n\n        // shared with exactly 1 owner (deleted upon exit of this local scope)\n        std::shared_ptr<SimpleType> localshared2 = std::shared_ptr<SimpleType>(new SimpleType(\"shared (one shared reference, two weak references)\"));\n        std::weak_ptr<SimpleType> localweak = localshared2;  // shared_ptr reference count does not increment here, because weak pointers don't \"own\" the pointer\n        globalweak = localweak;  // again, the shared_ptr reference count does not increment\n        // prove that the weak pointer references the shared pointer (but it does not own it!)\n        std::cout << (localweak.lock() ? \"local weak pointer has valid reference\" : \"local weak pointer has no reference\") << std::endl;\n        std::cout << (globalweak.lock() ? \"global weak pointer has valid reference\" : \"global weak pointer has no reference\") << std::endl;\n\n        std::cout << \"smart pointers can be accessed like regular pointers\" << std::endl;\n        localunique->identify();\n        (*globalshared).identify();\n\n        std::cout << \"leaving local scope\" << std::endl;\n    } // localshared is not deleted here because the globalshared reference still exists and shares ownership of it.\n      // localshared2/globalweak's object is deleted here. Even though globalweak still references it, it doesn't own it, so it's deleted.\n\n    std::cout << \"left local scope\" << std::endl;\n    std::cout << (globalweak.lock() ? \"global weak pointer has valid reference\" : \"global weak pointer has no reference\") << std::endl;\n    delete raw_ptr;  // this needs to be done manually\n\n    std::cout << \"leaving main\" << std::endl;\n}\n"
  },
  {
    "path": "examples/fortran/fortran_array.f90",
    "content": "program array\n  integer, parameter :: n=3\n  integer :: ii\n  real, dimension(n) :: a, b\n  real, dimension(n,n) :: c\n\n  a = [( real(ii), ii=1, n )]\n\n  do ii = 1,n\n    print *, a(ii)\n  enddo\n\n  b = 0.\n  do ii = 1, n\n    ! You could just write b = a ** 2., but I want to see the loop progress\n    b(ii) = a(ii) ** 2.\n  enddo\n\n  do ii = 1, n\n    print *, b(ii)\n  enddo\n\n  c = reshape( [( real(ii), ii=1,n**2 )], [n,n] )\n  do ii = 1, n\n    print *, c(ii,:)\n  enddo\n\nend program\n"
  },
  {
    "path": "examples/fortran/makefile",
    "content": "GDBGUI=../../gdbgui/backend.py\n\narray_demo: fortran_array.f90\n\tgfortran fortran_array.f90 -o array_f90.a -g\n\t@echo Run with gdbgui: gdbgui --args array_f90.a\n"
  },
  {
    "path": "examples/golang/hello.go",
    "content": "package main\nimport \"fmt\"\n\nfunc main() {\n    fmt.Println(\"hello world\")\n    // Create an array of three ints.\n    array := [...]int{10, 20, 30}\n\n    // Loop over three ints and print them.\n    for i := 0; i < len(array); i++ {\n        fmt.Println(array[i])\n    }\n}\n"
  },
  {
    "path": "examples/golang/makefile",
    "content": "GDBGUI=../../gdbgui/backend.py\n\nhello: hello.go\n\tgo build -o hello_go.a -gccgoflags \"-w\" hello.go\n\t@echo Run with gdbgui: gdbgui --args hello_go.a\n"
  },
  {
    "path": "examples/rust/.gitignore",
    "content": "/target/\n**/*.rs.bk\n\n# User-specific stuff:\n.idea/**/workspace.xml\n.idea/**/tasks.xml\n.idea/dictionaries\n"
  },
  {
    "path": "examples/rust/Cargo.toml",
    "content": "[package]\nname = \"hello\"\nversion = \"0.1.0\"\nauthors = [\"Your Name <YourName@example.com>\"]\n\n[dependencies]\n"
  },
  {
    "path": "examples/rust/README.md",
    "content": "This directory contains a very simple Rust program to demonstrate\nhow to run gdbgui.\n\nRun the shell script `compile_and_debug.sh` which will use Cargo\nto build the program in debug mode and then launch `gdbgui` to\ndebug the program.\n"
  },
  {
    "path": "examples/rust/compile_and_debug.sh",
    "content": "#!/usr/bin/env bash\n\nGDBGUI=../../gdbgui/backend.py\n\ncargo build && $GDBGUI ./target/debug/hello\n"
  },
  {
    "path": "examples/rust/src/main.rs",
    "content": "use std::mem;\n\n// This function borrows a slice\nfn analyze_slice(slice: &[i32]) {\n    println!(\"first element of the slice: {}\", slice[0]);\n    println!(\"the slice has {} elements\", slice.len());\n}\n\nfn main() {\n    println!(\"Hello World!\");\n    // Fixed-size array (type signature is superfluous)\n    let xs: [i32; 5] = [1, 2, 3, 4, 5];\n\n    // All elements can be initialized to the same value\n    let ys: [i32; 9] = [0; 9];\n\n    // Indexing starts at 0\n    println!(\"first element of the array: {}\", xs[0]);\n    println!(\"second element of the array: {}\", xs[1]);\n\n    // `len` returns the size of the array\n    println!(\"array size: {}\", xs.len());\n\n    // Arrays are stack allocated\n    println!(\"array occupies {} bytes\", mem::size_of_val(&xs));\n\n    // Arrays can be automatically borrowed as slices\n    println!(\"borrow the whole array as a slice\");\n    analyze_slice(&xs);\n\n    // Slices can point to a section of an array\n    println!(\"borrow a section of the array as a slice\");\n    analyze_slice(&ys[1 .. 4]);\n}\n"
  },
  {
    "path": "gdbgui/SSLify.py",
    "content": "\"\"\"Module to enable SSL for Flask application. Adapted from\nhttps://github.com/kennethreitz/flask-sslify\n\"\"\"\n\nimport os\nimport ssl\n\nfrom flask import redirect, request\n\nYEAR_IN_SECS = 31536000\n\n\nclass SSLify(object):\n    \"\"\"Secures your Flask App.\"\"\"\n\n    def __init__(\n        self, app=None, age=YEAR_IN_SECS, subdomains=False, permanent=False, skips=None\n    ):\n        self.app = app\n        self.hsts_age = age\n\n        self.hsts_include_subdomains = subdomains\n        self.permanent = permanent\n        self.skip_list = skips\n\n        if app is not None:\n            self.init_app(app)\n\n    def init_app(self, app):\n        \"\"\"Configures the specified Flask app to enforce SSL.\"\"\"\n        app.config.setdefault(\"SSLIFY_SUBDOMAINS\", False)\n        app.config.setdefault(\"SSLIFY_PERMANENT\", False)\n        app.config.setdefault(\"SSLIFY_SKIPS\", None)\n\n        self.hsts_include_subdomains = (\n            self.hsts_include_subdomains or app.config[\"SSLIFY_SUBDOMAINS\"]\n        )\n        self.permanent = self.permanent or self.app.config[\"SSLIFY_PERMANENT\"]\n        self.skip_list = self.skip_list or self.app.config[\"SSLIFY_SKIPS\"]\n\n        app.before_request(self.redirect_to_ssl)\n        app.after_request(self.set_hsts_header)\n\n    @property\n    def hsts_header(self):\n        \"\"\"Returns the proper HSTS policy.\"\"\"\n        hsts_policy = \"max-age={0}\".format(self.hsts_age)\n\n        if self.hsts_include_subdomains:\n            hsts_policy += \"; includeSubDomains\"\n\n        return hsts_policy\n\n    @property\n    def skip(self):\n        \"\"\"Checks the skip list.\"\"\"\n        # Should we skip?\n        if self.skip_list and isinstance(self.skip_list, list):\n            for skip in self.skip_list:\n                if request.path.startswith(\"/{0}\".format(skip)):\n                    return True\n        return False\n\n    def redirect_to_ssl(self):\n        \"\"\"Redirect incoming requests to HTTPS.\"\"\"\n        # Should we redirect?\n        criteria = [\n            request.is_secure,\n            self.app.debug,\n            self.app.testing,\n            request.headers.get(\"X-Forwarded-Proto\", \"http\") == \"https\",\n        ]\n\n        if not any(criteria) and not self.skip:\n            if request.url.startswith(\"http://\"):\n                url = request.url.replace(\"http://\", \"https://\", 1)\n                code = 302\n                if self.permanent:\n                    code = 301\n                r = redirect(url, code=code)\n                return r\n\n    def set_hsts_header(self, response):\n        \"\"\"Adds HSTS header to each response.\"\"\"\n        # Should we add STS header?\n        if request.is_secure and not self.skip:\n            response.headers.setdefault(\"Strict-Transport-Security\", self.hsts_header)\n        return response\n\n\ndef get_ssl_context(private_key, certificate):\n    \"\"\"Get ssl context from private key and certificate paths.\n    The return value is used when calling Flask.\n    i.e. app.run(ssl_context=get_ssl_context(,,,))\n    \"\"\"\n    if (\n        certificate\n        and os.path.isfile(certificate)\n        and private_key\n        and os.path.isfile(private_key)\n    ):\n        context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)\n        context.load_cert_chain(certificate, private_key)\n        return context\n    return None\n"
  },
  {
    "path": "gdbgui/VERSION.txt",
    "content": "0.15.3.0\n"
  },
  {
    "path": "gdbgui/__init__.py",
    "content": "import io\nimport os\nimport sys\n\n_base_dir = getattr(sys, \"_MEIPASS\", os.path.dirname(os.path.realpath(__file__)))\n_version = (\n    io.open(os.path.join(_base_dir, \"VERSION.txt\"), \"r\", encoding=\"utf-8\")\n    .read()\n    .strip()\n)\n\n__title__ = \"gdbgui\"\n__version__ = _version\n__author__ = \"Chad Smith\"\n__copyright__ = \"Copyright Chad Smith\"\n"
  },
  {
    "path": "gdbgui/__main__.py",
    "content": "from . import cli\n\ncli.main()\n"
  },
  {
    "path": "gdbgui/cli.py",
    "content": "#!/usr/bin/env python\n\n\"\"\"\nA server that provides a graphical user interface to the gnu debugger (gdb).\nhttps://github.com/cs01/gdbgui\n\"\"\"\n\nimport argparse\nimport json\nimport logging\nimport os\nimport platform\nimport re\nimport shlex\nfrom typing import List, Optional\n\nfrom gdbgui import __version__\nfrom gdbgui.server.app import app, socketio\nfrom gdbgui.server.constants import DEFAULT_GDB_EXECUTABLE, DEFAULT_HOST, DEFAULT_PORT\nfrom gdbgui.server.server import run_server\n\n\nlogger = logging.getLogger(__name__)\nlogging.getLogger(\"werkzeug\").setLevel(logging.ERROR)\n\n\ndef get_gdbgui_auth_user_credentials(auth_file, user, password):\n    if auth_file and (user or password):\n        print(\"Cannot supply auth file and username/password\")\n        exit(1)\n    if auth_file:\n        if os.path.isfile(auth_file):\n            with open(auth_file, \"r\") as authFile:\n                data = authFile.read()\n                split_file_contents = data.split(\"\\n\")\n                if len(split_file_contents) < 2:\n                    print(\n                        'Auth file \"%s\" requires username on first line and password on second line'\n                        % auth_file\n                    )\n                    exit(1)\n                return split_file_contents\n\n        else:\n            print('Auth file \"%s\" for HTTP Basic auth not found' % auth_file)\n            exit(1)\n    elif user and password:\n        return [user, password]\n\n    else:\n        return None\n\n\ndef warn_startup_with_shell_off(platform: str, gdb_args: str):\n    \"\"\"return True if user may need to turn shell off\n    if mac OS version is 16 (sierra) or higher, may need to set shell off due\n    to os's security requirements\n    http://stackoverflow.com/questions/39702871/gdb-kind-of-doesnt-work-on-macos-sierra\n    \"\"\"\n    darwin_match = re.match(r\"darwin-(\\d+)\\..*\", platform)\n    on_darwin = darwin_match is not None and int(darwin_match.groups()[0]) >= 16\n    if on_darwin:\n        shell_is_off = \"startup-with-shell off\" in gdb_args\n        return not shell_is_off\n    return False\n\n\ndef get_parser():\n    parser = argparse.ArgumentParser(\n        description=__doc__, formatter_class=argparse.ArgumentDefaultsHelpFormatter\n    )\n\n    gdb_group = parser.add_argument_group(title=\"gdb settings\")\n    args_group = parser.add_mutually_exclusive_group()\n    network = parser.add_argument_group(title=\"gdbgui network settings\")\n    security = parser.add_argument_group(title=\"security settings\")\n    other = parser.add_argument_group(title=\"other settings\")\n\n    gdb_group.add_argument(\n        \"-g\",\n        \"--gdb-cmd\",\n        help=\"\"\"\n        gdb binary and arguments to run. If passing arguments,\n        enclose in quotes.\n        If using rr, it should be specified here with\n        'rr replay'.\n        Examples: gdb, /path/to/gdb, 'gdb --command=FILE -ix', 'rr replay'\n\n        \"\"\",\n        default=DEFAULT_GDB_EXECUTABLE,\n    )\n    network.add_argument(\n        \"-p\",\n        \"--port\",\n        help=\"The port on which gdbgui will be hosted\",\n        default=DEFAULT_PORT,\n    )\n    network.add_argument(\n        \"--host\", help=\"The host ip address on which gdbgui serve\", default=DEFAULT_HOST\n    )\n    network.add_argument(\n        \"-r\",\n        \"--remote\",\n        help=\"Shortcut to set host to 0.0.0.0 and suppress browser from opening. This allows remote access \"\n        \"to gdbgui and is useful when running on a remote machine that you want to view/debug from your local \"\n        \"browser, or let someone else debug your application remotely.\",\n        action=\"store_true\",\n    )\n\n    security.add_argument(\n        \"--auth-file\",\n        help=\"Require authentication before accessing gdbgui in the browser. \"\n        \"Specify a file that contains the HTTP Basic auth username and password separate by newline. \",\n    )\n\n    security.add_argument(\"--user\", help=\"Username when authenticating\")\n    security.add_argument(\"--password\", help=\"Password when authenticating\")\n    security.add_argument(\n        \"--key\",\n        default=None,\n        help=\"SSL private key. \"\n        \"Generate with:\"\n        \"openssl req -newkey rsa:2048 -nodes -keyout host.key -x509 -days 365 -out host.cert\",\n    )\n    # https://www.digitalocean.com/community/tutorials/openssl-essentials-working-with-ssl-certificates-private-keys-and-csrs\n    security.add_argument(\n        \"--cert\",\n        default=None,\n        help=\"SSL certificate. \"\n        \"Generate with:\"\n        \"openssl req -newkey rsa:2048 -nodes -keyout host.key -x509 -days 365 -out host.cert\",\n    )\n    # https://www.digitalocean.com/community/tutorials/openssl-essentials-working-with-ssl-certificates-private-keys-and-csrs\n\n    other.add_argument(\n        \"--remap-sources\",\n        \"-m\",\n        help=(\n            \"Replace compile-time source paths to local source paths. \"\n            \"Pass valid JSON key/value pairs.\"\n            'i.e. --remap-sources=\\'{\"/buildmachine\": \"/current/machine\"}\\''\n        ),\n    )\n    other.add_argument(\n        \"--project\",\n        help='Set the project directory. When viewing the \"folders\" pane, paths are shown relative to this directory.',\n    )\n    other.add_argument(\"-v\", \"--version\", help=\"Print version\", action=\"store_true\")\n\n    other.add_argument(\n        \"-n\",\n        \"--no-browser\",\n        help=\"By default, the browser will open with gdbgui. Pass this flag so the browser does not open.\",\n        action=\"store_true\",\n    )\n    other.add_argument(\n        \"-b\",\n        \"--browser\",\n        help=\"Use the given browser executable instead of the system default.\",\n        default=None,\n    )\n    other.add_argument(\n        \"--debug\",\n        help=\"The debug flag of this Flask application. \"\n        \"Pass this flag when debugging gdbgui itself to automatically reload the server when changes are detected\",\n        action=\"store_true\",\n    )\n    args_group.add_argument(\n        \"debug_program\",\n        nargs=\"?\",\n        help=\"The executable file you wish to debug, and any arguments to pass to it.\"\n        \" To pass flags to the binary, wrap in quotes, or use --args instead.\"\n        \" Example: gdbgui ./mybinary [other-gdbgui-args...]\"\n        \" Example: gdbgui './mybinary myarg -flag1 -flag2' [other gdbgui args...]\",\n        default=None,\n    )\n    args_group.add_argument(\n        \"--args\",\n        nargs=argparse.REMAINDER,\n        help=\"Specify the executable file you wish to debug and any arguments to pass to it. All arguments are\"\n        \" taken literally, so if used, this must be the last argument. This can also be specified later in the frontend.\"\n        \" passed to gdbgui.\"\n        \" Example: gdbgui [...] --args ./mybinary myarg -flag1 -flag2\",\n        default=[],\n    )\n    return parser\n\n\ndef get_initial_binary_and_args(\n    user_supplied_args: List[str], debug_program_and_args: Optional[str]\n) -> List[str]:\n    if debug_program_and_args:\n        # passed via positional\n        return shlex.split(debug_program_and_args)\n    else:\n        # passed via --args\n        return user_supplied_args\n\n\ndef main():\n    \"\"\"Entry point from command line\"\"\"\n    parser = get_parser()\n    args = parser.parse_args()\n    if args.version:\n        print(__version__)\n        return\n\n    if args.no_browser and args.browser:\n        print(\"Cannot specify no-browser and browser. Must specify one or the other.\")\n        exit(1)\n\n    app.config[\"gdb_command\"] = args.gdb_cmd\n    app.config[\"initial_binary_and_args\"] = get_initial_binary_and_args(\n        args.args, args.debug_program\n    )\n    app.config[\"gdbgui_auth_user_credentials\"] = get_gdbgui_auth_user_credentials(\n        args.auth_file, args.user, args.password\n    )\n    app.config[\"project_home\"] = args.project\n    if args.remap_sources:\n        try:\n            app.config[\"remap_sources\"] = json.loads(args.remap_sources)\n        except json.decoder.JSONDecodeError as e:\n            print(\n                \"The '--remap-sources' argument must be valid JSON. See gdbgui --help.\"\n            )\n            print(e)\n            exit(1)\n\n    if args.remote:\n        args.host = \"0.0.0.0\"\n        args.no_browser = True\n        if app.config[\"gdbgui_auth_user_credentials\"] is None:\n            print(\n                \"Warning: authentication is recommended when serving on a publicly \"\n                \"accessible IP address. See gdbgui --help.\"\n            )\n\n    if warn_startup_with_shell_off(platform.platform().lower(), args.gdb_cmd):\n        logger.warning(\n            \"You may need to set startup-with-shell off when running on a mac. i.e.\\n\"\n            \"  gdbgui --gdb-cmd='gdb --init-eval-command=\\\"set startup-with-shell off\\\"'\\n\"\n            \"see http://stackoverflow.com/questions/39702871/gdb-kind-of-doesnt-work-on-macos-sierra\\n\"\n            \"and https://sourceware.org/gdb/onlinedocs/gdb/Starting.html\"\n        )\n\n    logger.setLevel(logging.DEBUG if args.debug else logging.INFO)\n\n    run_server(\n        app=app,\n        socketio=socketio,\n        host=args.host,\n        port=int(args.port),\n        debug=bool(args.debug),\n        open_browser=(not args.no_browser),\n        browsername=args.browser,\n        private_key=args.key,\n        certificate=args.cert,\n    )\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "gdbgui/htmllistformatter.py",
    "content": "from pygments.formatters import HtmlFormatter  # type: ignore\n\n\nclass HtmlListFormatter(HtmlFormatter):\n    \"\"\"A custom pygments class to format html. Returns a list of source code.\n    Each element of the list corresponds to a line of (marked up) source code.\n    \"\"\"\n\n    def get_marked_up_list(self, tokensource):\n        \"\"\"an updated version of pygments.formatter.format_unencoded\"\"\"\n        source = self._format_lines(tokensource)\n        if self.hl_lines:\n            source = self._highlight_lines(source)\n        if not self.nowrap:\n            if self.linenos == 2:\n                source = self._wrap_inlinelinenos(source)\n            if self.lineanchors:\n                source = self._wrap_lineanchors(source)\n            if self.linespans:\n                source = self._wrap_linespans(source)\n            if self.linenos == 1:\n                source = self._wrap_tablelinenos(source)\n        # instead of this:\n        # for t, piece in source:\n        #     outfile.write(piece)\n        # evaluate the generator to a list of just source code:\n        IS_CODE_INDEX = 0\n        HTML_VALUE_INDEX = 1\n        IS_CODE_VAL = 1\n        source_list = [\n            html_line[HTML_VALUE_INDEX]\n            for html_line in self._wrap_div(self._wrap_pre(source))\n            if html_line[IS_CODE_INDEX] == IS_CODE_VAL\n        ]\n        return source_list\n"
  },
  {
    "path": "gdbgui/py.typed",
    "content": "# Marker file for PEP 561.  This package uses inline types.\n# https://mypy.readthedocs.io/en/latest/installed_packages.html#making-pep-561-compatible-packages"
  },
  {
    "path": "gdbgui/server/__init__.py",
    "content": ""
  },
  {
    "path": "gdbgui/server/app.py",
    "content": "import binascii\nimport logging\nimport os\nfrom typing import Dict, List\nimport traceback\nfrom flask import Flask, abort, request, session\nfrom flask_compress import Compress  # type: ignore\nfrom flask_socketio import SocketIO, emit  # type: ignore\n\nfrom .constants import DEFAULT_GDB_EXECUTABLE, STATIC_DIR, TEMPLATE_DIR\nfrom .http_routes import blueprint\nfrom .http_util import is_cross_origin\nfrom .sessionmanager import SessionManager, DebugSession\n\nlogger = logging.getLogger(__file__)\n# Create flask application and add some configuration keys to be used in various callbacks\napp = Flask(__name__, template_folder=str(TEMPLATE_DIR), static_folder=str(STATIC_DIR))\nCompress(\n    app\n)  # add gzip compression to Flask. see https://github.com/libwilliam/flask-compress\napp.register_blueprint(blueprint)\napp.config[\"initial_binary_and_args\"] = []\napp.config[\"gdb_path\"] = DEFAULT_GDB_EXECUTABLE\napp.config[\"gdb_command\"] = None\napp.config[\"TEMPLATES_AUTO_RELOAD\"] = True\napp.config[\"project_home\"] = None\napp.config[\"remap_sources\"] = {}\nmanager = SessionManager()\napp.config[\"_manager\"] = manager\napp.secret_key = binascii.hexlify(os.urandom(24)).decode(\"utf-8\")\nsocketio = SocketIO(manage_session=False)\n\n\n@app.before_request\ndef csrf_protect_all_post_and_cross_origin_requests():\n    \"\"\"returns None upon success\"\"\"\n    success = None\n    if is_cross_origin(request):\n        logger.warning(\"Received cross origin request. Aborting\")\n        abort(403)\n    if request.method in [\"POST\", \"PUT\"]:\n        server_token = session.get(\"csrf_token\")\n        if server_token == request.form.get(\"csrf_token\"):\n            return success\n        elif server_token == request.environ.get(\"HTTP_X_CSRFTOKEN\"):\n            return success\n        elif request.json and server_token == request.json.get(\"csrf_token\"):\n            return success\n        else:\n            logger.warning(\"Received invalid csrf token. Aborting\")\n            abort(403)\n\n\n@socketio.on(\"connect\", namespace=\"/gdb_listener\")\ndef client_connected():\n    \"\"\"Connect a websocket client to a debug session\n\n    This is the main intial connection.\n\n    Depending on the arguments passed, the client will connect\n    to an existing debug session, or create a new one.\n    A message is a emitted back to the client with details on\n    the debug session that was created or connected to.\n    \"\"\"\n    if is_cross_origin(request):\n        logger.warning(\"Received cross origin request. Aborting\")\n        abort(403)\n\n    csrf_token = request.args.get(\"csrf_token\")\n    if csrf_token is None:\n        logger.warning(\"Recieved invalid csrf token\")\n        emit(\"server_error\", {\"message\": \"Recieved invalid csrf token\"})\n        return\n\n    elif csrf_token != session.get(\"csrf_token\"):\n        # this can happen fairly often, so log debug message, not warning\n        logger.debug(\n            \"Recieved invalid csrf token %s (expected %s)\"\n            % (csrf_token, str(session.get(\"csrf_token\")))\n        )\n        emit(\n            \"server_error\", {\"message\": \"Session expired. Please refresh this webpage.\"}\n        )\n        return\n\n    desired_gdbpid = int(request.args.get(\"gdbpid\", 0))\n    try:\n        if desired_gdbpid:\n            # connect to exiting debug session\n            debug_session = manager.connect_client_to_debug_session(\n                desired_gdbpid=desired_gdbpid, client_id=request.sid\n            )\n            emit(\n                \"debug_session_connection_event\",\n                {\n                    \"ok\": True,\n                    \"started_new_gdb_process\": False,\n                    \"pid\": debug_session.pid,\n                    \"message\": f\"Connected to existing gdb process {desired_gdbpid}\",\n                },\n            )\n        else:\n            # start new debug session\n            gdb_command = request.args.get(\"gdb_command\", app.config[\"gdb_command\"])\n            mi_version = request.args.get(\"mi_version\", \"mi2\")\n            debug_session = manager.add_new_debug_session(\n                gdb_command=gdb_command, mi_version=mi_version, client_id=request.sid\n            )\n            emit(\n                \"debug_session_connection_event\",\n                {\n                    \"ok\": True,\n                    \"started_new_gdb_process\": True,\n                    \"message\": f\"Started new gdb process, pid {debug_session.pid}\",\n                    \"pid\": debug_session.pid,\n                },\n            )\n    except Exception as e:\n        emit(\n            \"debug_session_connection_event\",\n            {\"message\": f\"Failed to establish gdb session: {e}\", \"ok\": False},\n        )\n\n    # Make sure there is a reader thread reading. One thread reads all instances.\n    if manager.gdb_reader_thread is None:\n        manager.gdb_reader_thread = socketio.start_background_task(\n            target=read_and_forward_gdb_and_pty_output\n        )\n        logger.info(\"Created background thread to read gdb responses\")\n\n\n@socketio.on(\"pty_interaction\", namespace=\"/gdb_listener\")\ndef pty_interaction(message):\n    \"\"\"Write a character to the user facing pty\"\"\"\n    debug_session = manager.debug_session_from_client_id(request.sid)\n    if not debug_session:\n        emit(\n            \"error_running_gdb_command\",\n            {\"message\": f\"no gdb session available for client id {request.sid}\"},\n        )\n        return\n\n    try:\n        data = message.get(\"data\")\n        pty_name = data.get(\"pty_name\")\n        if pty_name == \"user_pty\":\n            pty = debug_session.pty_for_gdb\n        elif pty_name == \"program_pty\":\n            pty = debug_session.pty_for_debugged_program\n        else:\n            raise ValueError(f\"Unknown pty: {pty_name}\")\n\n        action = data.get(\"action\")\n        if action == \"write\":\n            key = data[\"key\"]\n            pty.write(key)\n        elif action == \"set_winsize\":\n            pty.set_winsize(data[\"rows\"], data[\"cols\"])\n        else:\n            raise ValueError(f\"Unknown action {action}\")\n    except Exception:\n        err = traceback.format_exc()\n        logger.error(err)\n        emit(\"error_running_gdb_command\", {\"message\": err})\n\n\n@socketio.on(\"run_gdb_command\", namespace=\"/gdb_listener\")\ndef run_gdb_command(message: Dict[str, str]):\n    \"\"\"Write commands to gdbgui's gdb mi pty\"\"\"\n    client_id = request.sid  # type: ignore\n    debug_session = manager.debug_session_from_client_id(client_id)\n    if not debug_session:\n        emit(\"error_running_gdb_command\", {\"message\": \"no session\"})\n        return\n    pty_mi = debug_session.pygdbmi_controller\n    if pty_mi is not None:\n        try:\n            # the command (string) or commands (list) to run\n            cmds = message[\"cmd\"]\n            for cmd in cmds:\n                pty_mi.write(\n                    cmd + \"\\n\",\n                    timeout_sec=0,\n                    raise_error_on_timeout=False,\n                    read_response=False,\n                )\n\n        except Exception:\n            err = traceback.format_exc()\n            logger.error(err)\n            emit(\"error_running_gdb_command\", {\"message\": err})\n    else:\n        emit(\"error_running_gdb_command\", {\"message\": \"gdb is not running\"})\n\n\ndef send_msg_to_clients(client_ids, msg, error=False):\n    \"\"\"Send message to all clients\"\"\"\n    if error:\n        stream = \"stderr\"\n    else:\n        stream = \"stdout\"\n\n    response = [{\"message\": None, \"type\": \"console\", \"payload\": msg, \"stream\": stream}]\n\n    for client_id in client_ids:\n        logger.info(\"emiting message to websocket client id \" + client_id)\n        socketio.emit(\n            \"gdb_response\", response, namespace=\"/gdb_listener\", room=client_id\n        )\n\n\n@socketio.on(\"disconnect\", namespace=\"/gdb_listener\")\ndef client_disconnected():\n    \"\"\"do nothing if client disconnects\"\"\"\n    manager.disconnect_client(request.sid)\n    logger.info(\"Client websocket disconnected, id %s\" % (request.sid))\n\n\n@socketio.on(\"Client disconnected\")\ndef test_disconnect():\n    print(\"Client websocket disconnected\", request.sid)\n\n\ndef read_and_forward_gdb_and_pty_output():\n    \"\"\"A task that runs on a different thread, and emits websocket messages\n    of gdb responses\"\"\"\n\n    while True:\n        socketio.sleep(0.05)\n        debug_sessions_to_remove = []\n        for debug_session, client_ids in manager.debug_session_to_client_ids.items():\n            try:\n                try:\n                    response = debug_session.pygdbmi_controller.get_gdb_response(\n                        timeout_sec=0, raise_error_on_timeout=False\n                    )\n\n                except Exception:\n                    response = None\n                    send_msg_to_clients(\n                        client_ids,\n                        \"The underlying gdb process has been killed. This tab will no longer function as expected.\",\n                        error=True,\n                    )\n                    debug_sessions_to_remove.append(debug_session)\n\n                if response:\n                    for client_id in client_ids:\n                        logger.info(\n                            \"emiting message to websocket client id \" + client_id\n                        )\n                        socketio.emit(\n                            \"gdb_response\",\n                            response,\n                            namespace=\"/gdb_listener\",\n                            room=client_id,\n                        )\n                else:\n                    # there was no queued response from gdb, not a problem\n                    pass\n\n            except Exception:\n                logger.error(\"caught exception, continuing:\" + traceback.format_exc())\n\n        debug_sessions_to_remove += check_and_forward_pty_output()\n        for debug_session in set(debug_sessions_to_remove):\n            manager.remove_debug_session(debug_session)\n\n\ndef check_and_forward_pty_output() -> List[DebugSession]:\n    debug_sessions_to_remove = []\n    for debug_session, client_ids in manager.debug_session_to_client_ids.items():\n        try:\n            response = debug_session.pty_for_gdb.read()\n            if response is not None:\n                for client_id in client_ids:\n                    socketio.emit(\n                        \"user_pty_response\",\n                        response,\n                        namespace=\"/gdb_listener\",\n                        room=client_id,\n                    )\n\n            response = debug_session.pty_for_debugged_program.read()\n            if response is not None:\n                for client_id in client_ids:\n                    socketio.emit(\n                        \"program_pty_response\",\n                        response,\n                        namespace=\"/gdb_listener\",\n                        room=client_id,\n                    )\n        except Exception as e:\n            debug_sessions_to_remove.append(debug_session)\n            for client_id in client_ids:\n                socketio.emit(\n                    \"fatal_server_error\",\n                    {\"message\": str(e)},\n                    namespace=\"/gdb_listener\",\n                    room=client_id,\n                )\n            logger.error(e, exc_info=True)\n    return debug_sessions_to_remove\n"
  },
  {
    "path": "gdbgui/server/constants.py",
    "content": "import os\nimport signal\nimport sys\nfrom pathlib import Path\n\nDEFAULT_GDB_EXECUTABLE = \"gdb\"\nDEFAULT_HOST = \"127.0.0.1\"\nDEFAULT_PORT = 5000\nUSING_WINDOWS = os.name == \"nt\"\nIS_A_TTY = sys.stdout.isatty()\npyinstaller_base_dir = getattr(sys, \"_MEIPASS\", None)\nusing_pyinstaller = pyinstaller_base_dir is not None\nif using_pyinstaller:\n    BASE_PATH = Path(pyinstaller_base_dir or \"\")\nelse:\n    BASE_PATH = Path(os.path.realpath(__file__)).parent.parent\n    PARENTDIR = BASE_PATH.parent\n    sys.path.append(str(PARENTDIR))\n\nTEMPLATE_DIR = BASE_PATH / \"templates\"\nSTATIC_DIR = BASE_PATH / \"static\"\n\n\ndef colorize(text):\n    if IS_A_TTY and not USING_WINDOWS:\n        return \"\\033[1;32m\" + text + \"\\x1b[0m\"\n\n    else:\n        return text\n\n\n# create dictionary of signal names\nSIGNAL_NAME_TO_OBJ = {}\nfor n in dir(signal):\n    if n.startswith(\"SIG\") and \"_\" not in n:\n        SIGNAL_NAME_TO_OBJ[n.upper()] = getattr(signal, n)\n"
  },
  {
    "path": "gdbgui/server/http_routes.py",
    "content": "import json\nimport logging\nimport os\n\nfrom flask import (\n    Blueprint,\n    current_app,\n    jsonify,\n    redirect,\n    render_template,\n    request,\n    session,\n    Response,\n)\nfrom pygments.lexers import get_lexer_for_filename  # type: ignore\n\nfrom gdbgui import htmllistformatter, __version__\n\nfrom .constants import TEMPLATE_DIR, USING_WINDOWS, SIGNAL_NAME_TO_OBJ\nfrom .http_util import (\n    add_csrf_token_to_session,\n    authenticate,\n    client_error,\n    csrf_protect,\n)\n\nlogger = logging.getLogger(__file__)\nblueprint = Blueprint(\"http_routes\", __name__, template_folder=str(TEMPLATE_DIR))\n\n\n@blueprint.route(\"/read_file\", methods=[\"GET\"])\n@csrf_protect\ndef read_file():\n    \"\"\"Read a file and return its contents as an array\"\"\"\n\n    def should_highlight():\n        try:\n            return json.loads(request.args.get(\"highlight\", \"true\"))\n        except Exception as e:\n            if current_app.debug:\n                print(\"Raising exception since debug is on\")\n                raise e\n\n            else:\n                return True  # highlight argument was invalid for some reason, default to true\n\n    path = request.args.get(\"path\")\n    start_line = int(request.args.get(\"start_line\"))\n    start_line = max(1, start_line)  # make sure it's not negative\n    end_line = int(request.args.get(\"end_line\"))\n\n    if path and os.path.isfile(path):\n        try:\n            last_modified = os.path.getmtime(path)\n            with open(path, \"r\") as f:\n                raw_source_code_list = f.read().split(\"\\n\")\n                num_lines_in_file = len(raw_source_code_list)\n                end_line = min(\n                    num_lines_in_file, end_line\n                )  # make sure we don't try to go too far\n\n                # if leading lines are '', then the lexer will strip them out, but we want\n                # to preserve blank lines. Insert a space whenever we find a blank line.\n                for i in range((start_line - 1), (end_line)):\n                    if raw_source_code_list[i] == \"\":\n                        raw_source_code_list[i] = \" \"\n                raw_source_code_lines_of_interest = raw_source_code_list[\n                    (start_line - 1) : (end_line)\n                ]\n            try:\n                lexer = get_lexer_for_filename(path)\n            except Exception:\n                lexer = None\n\n            if lexer and should_highlight():\n                highlighted = True\n                # convert string into tokens\n                tokens = lexer.get_tokens(\"\\n\".join(raw_source_code_lines_of_interest))\n                # format tokens into nice, marked up list of html\n                formatter = (\n                    htmllistformatter.HtmlListFormatter()\n                )  # Don't add newlines after each line\n                source_code = formatter.get_marked_up_list(tokens)\n            else:\n                highlighted = False\n                source_code = raw_source_code_lines_of_interest\n\n            return jsonify(\n                {\n                    \"source_code_array\": source_code,\n                    \"path\": path,\n                    \"last_modified_unix_sec\": last_modified,\n                    \"highlighted\": highlighted,\n                    \"start_line\": start_line,\n                    \"end_line\": end_line,\n                    \"num_lines_in_file\": num_lines_in_file,\n                }\n            )\n\n        except Exception as e:\n            return client_error({\"message\": \"%s\" % e})\n\n    else:\n        return client_error({\"message\": \"File not found: %s\" % path})\n\n\n@blueprint.route(\"/get_last_modified_unix_sec\", methods=[\"GET\"])\n@csrf_protect\ndef get_last_modified_unix_sec():\n    \"\"\"Get last modified unix time for a given file\"\"\"\n    path = request.args.get(\"path\")\n    if path and os.path.isfile(path):\n        try:\n            last_modified = os.path.getmtime(path)\n            return jsonify({\"path\": path, \"last_modified_unix_sec\": last_modified})\n\n        except Exception as e:\n            return client_error({\"message\": \"%s\" % e, \"path\": path})\n\n    else:\n        return client_error({\"message\": \"File not found: %s\" % path, \"path\": path})\n\n\n@blueprint.route(\"/help\")\ndef help_route():\n    return redirect(\"https://github.com/cs01/gdbgui/blob/master/HELP.md\")\n\n\n@blueprint.route(\"/dashboard\", methods=[\"GET\"])\n@authenticate\ndef dashboard():\n    manager = current_app.config.get(\"_manager\")\n\n    add_csrf_token_to_session()\n\n    \"\"\"display a dashboard with a list of all running gdb processes\n    and ability to kill them, or open a new tab to work with that\n    GdbController instance\"\"\"\n    return render_template(\n        \"dashboard.html\",\n        gdbgui_sessions=manager.get_dashboard_data(),\n        csrf_token=session[\"csrf_token\"],\n        default_command=current_app.config[\"gdb_command\"],\n    )\n\n\n@blueprint.route(\"/\", methods=[\"GET\"])\n@authenticate\ndef gdbgui():\n    \"\"\"Render the main gdbgui interface\"\"\"\n    gdbpid = request.args.get(\"gdbpid\", 0)\n    gdb_command = request.args.get(\"gdb_command\", current_app.config[\"gdb_command\"])\n    add_csrf_token_to_session()\n\n    THEMES = [\"monokai\", \"light\"]\n    initial_data = {\n        \"csrf_token\": session[\"csrf_token\"],\n        \"gdbgui_version\": __version__,\n        \"gdbpid\": gdbpid,\n        \"gdb_command\": gdb_command,\n        \"initial_binary_and_args\": current_app.config[\"initial_binary_and_args\"],\n        \"project_home\": current_app.config[\"project_home\"],\n        \"remap_sources\": current_app.config[\"remap_sources\"],\n        \"themes\": THEMES,\n        \"signals\": SIGNAL_NAME_TO_OBJ,\n        \"using_windows\": USING_WINDOWS,\n    }\n\n    return render_template(\n        \"gdbgui.html\",\n        version=__version__,\n        debug=current_app.debug,\n        initial_data=initial_data,\n        themes=THEMES,\n    )\n\n\n@blueprint.route(\"/dashboard_data\", methods=[\"GET\"])\n@authenticate\ndef dashboard_data():\n    manager = current_app.config.get(\"_manager\")\n\n    return jsonify(manager.get_dashboard_data())\n\n\n@blueprint.route(\"/kill_session\", methods=[\"PUT\"])\n@authenticate\ndef kill_session():\n    from .app import manager\n\n    pid = request.json.get(\"gdbpid\")\n    if pid:\n        manager.remove_debug_session_by_pid(pid)\n        return jsonify({\"success\": True})\n    else:\n        return Response(\n            \"Missing required parameter: gdbpid\",\n            401,\n        )\n\n\n@blueprint.route(\"/send_signal_to_pid\", methods=[\"POST\"])\ndef send_signal_to_pid():\n    signal_name = request.form.get(\"signal_name\", \"\").upper()\n    pid_str = str(request.form.get(\"pid\"))\n    try:\n        pid_int = int(pid_str)\n    except ValueError:\n        return (\n            jsonify(\n                {\n                    \"message\": \"The pid %s cannot be converted to an integer. Signal %s was not sent.\"\n                    % (pid_str, signal_name)\n                }\n            ),\n            400,\n        )\n\n    if signal_name not in SIGNAL_NAME_TO_OBJ:\n        raise ValueError(\"no such signal %s\" % signal_name)\n    signal_value = int(SIGNAL_NAME_TO_OBJ[signal_name])\n\n    try:\n        os.kill(pid_int, signal_value)\n    except Exception:\n        return (\n            jsonify(\n                {\n                    \"message\": \"Process could not be killed. Is %s an active PID?\"\n                    % pid_int\n                }\n            ),\n            400,\n        )\n    return jsonify(\n        {\n            \"message\": \"sent signal %s (%s) to process id %s\"\n            % (signal_name, signal_value, pid_str)\n        }\n    )\n"
  },
  {
    "path": "gdbgui/server/http_util.py",
    "content": "import binascii\nimport logging\nimport os\nfrom functools import wraps\n\nfrom flask import Response, abort, current_app, jsonify, request, session\n\nlogger = logging.getLogger(__file__)\n\n\ndef add_csrf_token_to_session():\n    if \"csrf_token\" not in session:\n        session[\"csrf_token\"] = binascii.hexlify(os.urandom(20)).decode(\"utf-8\")\n\n\ndef is_cross_origin(request):\n    \"\"\"Compare headers HOST and ORIGIN. Remove protocol prefix from ORIGIN, then\n    compare. Return true if they are not equal\n    example HTTP_HOST: '127.0.0.1:5000'\n    example HTTP_ORIGIN: 'http://127.0.0.1:5000'\n    \"\"\"\n    origin = request.environ.get(\"HTTP_ORIGIN\")\n    host = request.environ.get(\"HTTP_HOST\")\n    if origin is None:\n        # origin is sometimes omitted by the browser when origin and host are equal\n        return False\n\n    if origin.startswith(\"http://\"):\n        origin = origin.replace(\"http://\", \"\")\n    elif origin.startswith(\"https://\"):\n        origin = origin.replace(\"https://\", \"\")\n    return host != origin\n\n\ndef csrf_protect(f):\n    \"\"\"A decorator to add csrf protection by validing the X_CSRFTOKEN\n    field in request header\"\"\"\n\n    @wraps(f)\n    def wrapper(*args, **kwargs):\n        token = session.get(\"csrf_token\", None)\n        if token is None or token != request.environ.get(\"HTTP_X_CSRFTOKEN\"):\n            logger.warning(\"Received invalid csrf token. Aborting\")\n            abort(403)\n        # call original request handler\n        return f(*args, **kwargs)\n\n    return wrapper\n\n\ndef client_error(obj):\n    return jsonify(obj), 400\n\n\ndef authenticate(f):\n    @wraps(f)\n    def wrapper(*args, **kwargs):\n        if current_app.config.get(\"gdbgui_auth_user_credentials\") is not None:\n            auth = request.authorization\n            if (\n                not auth\n                or not auth.username\n                or not auth.password\n                or not credentials_are_valid(auth.username, auth.password)\n            ):\n                return Response(\n                    \"You must log in to continue.\",\n                    401,\n                    {\"WWW-Authenticate\": 'Basic realm=\"gdbgui_login\"'},\n                )\n\n        return f(*args, **kwargs)\n\n    return wrapper\n\n\ndef credentials_are_valid(username, password):\n    user_credentials = current_app.config.get(\"gdbgui_auth_user_credentials\")\n    if user_credentials is None:\n        return False\n\n    elif len(user_credentials) < 2:\n        return False\n\n    return user_credentials[0] == username and user_credentials[1] == password\n"
  },
  {
    "path": "gdbgui/server/ptylib.py",
    "content": "import os\n\nUSING_WINDOWS = os.name == \"nt\"\nif USING_WINDOWS:\n    raise RuntimeError(\n        \"Windows is not supported at this time. \"\n        + \"Versions lower than 0.14.x. are Windows compatible.\"\n    )\nimport fcntl\nimport pty\nimport select\nimport shlex\nimport signal\nimport struct\nimport termios\nfrom typing import Optional\n\n\nclass Pty:\n    max_read_bytes = 1024 * 20\n\n    def __init__(self, *, cmd: Optional[str] = None, echo: bool = True):\n        if cmd:\n            (child_pid, fd) = pty.fork()\n            if child_pid == 0:\n                # this is the child process fork.\n                # anything printed here will show up in the pty, including the output\n                # of this subprocess\n                def sigint_handler(_sig, _frame):\n                    # prevent SIGINT (ctrl+c) from exiting\n                    # the whole program\n                    pass\n\n                signal.signal(signal.SIGINT, sigint_handler)\n                args = shlex.split(cmd)\n                os.execvp(args[0], args)\n\n            else:\n                # this is the parent process fork.\n                # store child fd and pid\n                self.stdin = fd\n                self.stdout = fd\n                self.pid = child_pid\n        else:\n            (master, slave) = pty.openpty()\n            self.stdin = master\n            self.stdout = master\n            self.name = os.ttyname(slave)\n            self.set_echo(echo)\n\n    def set_echo(self, echo_on: bool) -> None:\n        (iflag, oflag, cflag, lflag, ispeed, ospeed, cc) = termios.tcgetattr(self.stdin)\n        if echo_on:\n            lflag = lflag & termios.ECHO  # type: ignore\n        else:\n            lflag = lflag & ~termios.ECHO  # type: ignore\n        termios.tcsetattr(\n            self.stdin,\n            termios.TCSANOW,\n            [iflag, oflag, cflag, lflag, ispeed, ospeed, cc],\n        )\n\n    def set_winsize(self, rows: int, cols: int):\n        xpix = 0\n        ypix = 0\n        winsize = struct.pack(\"HHHH\", rows, cols, xpix, ypix)\n        if self.stdin is None:\n            raise RuntimeError(\"fd stdin not assigned\")\n        fcntl.ioctl(self.stdin, termios.TIOCSWINSZ, winsize)\n\n    def read(self) -> Optional[str]:\n        if self.stdout is None:\n            return \"done\"\n        timeout_sec = 0\n        (data_to_read, _, _) = select.select([self.stdout], [], [], timeout_sec)\n        if data_to_read:\n            try:\n                response = os.read(self.stdout, self.max_read_bytes).decode()\n            except (OSError, UnicodeDecodeError):\n                return None\n            return response\n        return None\n\n    def write(self, data: str):\n        edata = data.encode()\n        os.write(self.stdin, edata)\n"
  },
  {
    "path": "gdbgui/server/server.py",
    "content": "import os\nimport socket\nimport webbrowser\n\nfrom .constants import DEFAULT_HOST, DEFAULT_PORT, colorize\n\ntry:\n    from gdbgui.SSLify import SSLify, get_ssl_context  # noqa\nexcept ImportError:\n    print(\"Warning: Optional SSL support is not available\")\n\n    def get_ssl_context(private_key, certificate):  # noqa\n        return None\n\n\ndef get_extra_files():\n    \"\"\"returns a list of files that should be watched by the Flask server\n    when in debug mode to trigger a reload of the server\n    \"\"\"\n    FILES_TO_SKIP = [\"src/gdbgui.js\"]\n    THIS_DIR = os.path.dirname(os.path.abspath(__file__))\n    extra_dirs = [THIS_DIR]\n    extra_files = []\n    for extra_dir in extra_dirs:\n        for dirname, _, files in os.walk(extra_dir):\n            for filename in files:\n                filepath = os.path.join(dirname, filename)\n                if os.path.isfile(filepath) and filepath not in extra_files:\n                    for skipfile in FILES_TO_SKIP:\n                        if skipfile not in filepath:\n                            extra_files.append(filepath)\n    return extra_files\n\n\ndef run_server(\n    *,\n    app=None,\n    socketio=None,\n    host=DEFAULT_HOST,\n    port=DEFAULT_PORT,\n    debug=False,\n    open_browser=True,\n    browsername=None,\n    testing=False,\n    private_key=None,\n    certificate=None,\n):\n    \"\"\"Run the server of the gdb gui\"\"\"\n\n    kwargs = {}\n    ssl_context = get_ssl_context(private_key, certificate)\n    if ssl_context:\n        # got valid ssl context\n        # force everything through https\n        SSLify(app)\n        # pass ssl_context to flask\n        kwargs[\"ssl_context\"] = ssl_context\n\n    url = \"%s:%s\" % (host, port)\n    if kwargs.get(\"ssl_context\"):\n        protocol = \"https://\"\n        url_with_prefix = \"https://\" + url\n    else:\n        protocol = \"http://\"\n        url_with_prefix = \"http://\" + url\n\n    socketio.server_options[\"allow_upgrades\"] = False\n    socketio.init_app(app)\n\n    if testing is False:\n        if host == DEFAULT_HOST:\n            url = (DEFAULT_HOST, port)\n        else:\n            try:\n                url = (socket.gethostbyname(socket.gethostname()), port)\n            except Exception:\n                url = (host, port)\n\n        if open_browser is True and debug is False:\n            browsertext = repr(browsername) if browsername else \"default browser\"\n            args = (browsertext,) + url\n            text = (\"Opening gdbgui with %s at \" + protocol + \"%s:%d\") % args\n            print(colorize(text))\n            b = webbrowser.get(browsername) if browsername else webbrowser\n            b.open(url_with_prefix)\n        else:\n            print(colorize(f\"View gdbgui at {protocol}{url[0]}:{url[1]}\"))\n        print(\n            colorize(f\"View gdbgui dashboard at {protocol}{url[0]}:{url[1]}/dashboard\")\n        )\n\n        print(\"exit gdbgui by pressing CTRL+C\")\n        try:\n            socketio.run(\n                app,\n                debug=debug,\n                port=int(port),\n                host=host,\n                extra_files=get_extra_files(),\n                **kwargs,\n            )\n        except KeyboardInterrupt:\n            # Process was interrupted by ctrl+c on keyboard, show message\n            pass\n"
  },
  {
    "path": "gdbgui/server/sessionmanager.py",
    "content": "import datetime\nimport logging\nimport os\nimport signal\nimport traceback\nfrom collections import defaultdict\nfrom typing import Dict, List, Optional, Set\n\nfrom pygdbmi.IoManager import IoManager\n\nfrom .ptylib import Pty\n\nlogger = logging.getLogger(__name__)\n\n\nclass DebugSession:\n    def __init__(\n        self,\n        *,\n        pygdbmi_controller: IoManager,\n        pty_for_gdbgui: Pty,\n        pty_for_gdb: Pty,\n        pty_for_debugged_program: Pty,\n        command: str,\n        mi_version: str,\n        pid: int,\n    ):\n        self.command = command\n        self.pygdbmi_controller = pygdbmi_controller\n        self.pty_for_gdbgui = pty_for_gdbgui\n        self.pty_for_gdb = pty_for_gdb\n        self.pty_for_debugged_program = pty_for_debugged_program\n        self.mi_version = mi_version\n        self.pid = pid\n        self.start_time = datetime.datetime.now().strftime(\"%Y-%m-%d %H:%M:%S\")\n        self.client_ids: Set[str] = set()\n\n    def terminate(self):\n        if self.pid:\n            try:\n                os.kill(self.pid, signal.SIGKILL)\n            except Exception as e:\n                logger.error(f\"Failed to kill pid {self.pid}: {str(e)}\")\n\n        self.pygdbmi_controller = None\n\n    def to_dict(self):\n        return {\n            \"pid\": self.pid,\n            \"start_time\": self.start_time,\n            \"command\": self.command,\n            \"c2\": \"hi\",\n            \"client_ids\": list(self.client_ids),\n        }\n\n    def add_client(self, client_id: str):\n        self.client_ids.add(client_id)\n\n    def remove_client(self, client_id: str):\n        self.client_ids.discard(client_id)\n        if len(self.client_ids) == 0:\n            self.terminate()\n\n\nclass SessionManager(object):\n    def __init__(self):\n        self.debug_session_to_client_ids: Dict[DebugSession, List[str]] = defaultdict(\n            list\n        )  # key is controller, val is list of client ids\n\n        self.gdb_reader_thread = None\n\n    def connect_client_to_debug_session(\n        self, *, desired_gdbpid: int, client_id: str\n    ) -> DebugSession:\n        debug_session = self.debug_session_from_pid(desired_gdbpid)\n\n        if not debug_session:\n            raise ValueError(f\"No existing gdb process with pid {desired_gdbpid}\")\n        debug_session.add_client(client_id)\n        self.debug_session_to_client_ids[debug_session].append(client_id)\n        return debug_session\n\n    def add_new_debug_session(\n        self, *, gdb_command: str, mi_version: str, client_id: str\n    ) -> DebugSession:\n        pty_for_debugged_program = Pty()\n        pty_for_gdbgui = Pty(echo=False)\n        gdbgui_startup_cmds = [\n            f\"new-ui {mi_version} {pty_for_gdbgui.name}\",\n            f\"set inferior-tty {pty_for_debugged_program.name}\",\n            \"set pagination off\",\n        ]\n        # instead of writing to the pty after it starts, add startup\n        # commands to gdb. This allows gdb to be run as sudo and prompt for a\n        # password, for example.\n        gdbgui_startup_cmds_str = \" \".join([f\"-iex='{c}'\" for c in gdbgui_startup_cmds])\n        pty_for_gdb = Pty(cmd=f\"{gdb_command} {gdbgui_startup_cmds_str}\")\n\n        pid = pty_for_gdb.pid\n        debug_session = DebugSession(\n            pygdbmi_controller=IoManager(\n                os.fdopen(pty_for_gdbgui.stdin, mode=\"wb\", buffering=0),  # type: ignore\n                os.fdopen(pty_for_gdbgui.stdout, mode=\"rb\", buffering=0),  # type: ignore\n                None,\n            ),\n            pty_for_gdbgui=pty_for_gdbgui,\n            pty_for_gdb=pty_for_gdb,\n            pty_for_debugged_program=pty_for_debugged_program,\n            command=gdb_command,\n            mi_version=mi_version,\n            pid=pid,\n        )\n        debug_session.add_client(client_id)\n        self.debug_session_to_client_ids[debug_session] = [client_id]\n        return debug_session\n\n    def remove_debug_session_by_pid(self, gdbpid: int) -> List[str]:\n        debug_session = self.debug_session_from_pid(gdbpid)\n        if debug_session:\n            orphaned_client_ids = self.remove_debug_session(debug_session)\n        else:\n            logger.info(f\"could not find debug session with gdb pid {gdbpid}\")\n            orphaned_client_ids = []\n        return orphaned_client_ids\n\n    def remove_debug_session(self, debug_session: DebugSession) -> List[str]:\n        logger.info(f\"Removing debug session for pid {debug_session.pid}\")\n        try:\n            debug_session.terminate()\n        except Exception:\n            logger.error(traceback.format_exc())\n        orphaned_client_ids = self.debug_session_to_client_ids.pop(debug_session, [])\n        return orphaned_client_ids\n\n    def remove_debug_sessions_with_no_clients(self) -> None:\n        to_remove = []\n        for debug_session, _ in self.debug_session_to_client_ids.items():\n            if len(debug_session.client_ids) == 0:\n                to_remove.append(debug_session)\n        for debug_session in to_remove:\n            self.remove_debug_session(debug_session)\n\n    def get_pid_from_debug_session(self, debug_session: DebugSession) -> Optional[int]:\n        if debug_session and debug_session.pid:\n            return debug_session.pid\n        return None\n\n    def debug_session_from_pid(self, pid: int) -> Optional[DebugSession]:\n        for debug_session in self.debug_session_to_client_ids:\n            this_pid = self.get_pid_from_debug_session(debug_session)\n            if this_pid == pid:\n                return debug_session\n        return None\n\n    def debug_session_from_client_id(self, client_id: str) -> Optional[DebugSession]:\n        for debug_session, client_ids in self.debug_session_to_client_ids.items():\n            if client_id in client_ids:\n                return debug_session\n        return None\n\n    def get_dashboard_data(self) -> List[DebugSession]:\n        return [\n            debug_session.to_dict()\n            for debug_session in self.debug_session_to_client_ids.keys()\n        ]\n\n    def disconnect_client(self, client_id: str):\n        for debug_session, client_ids in self.debug_session_to_client_ids.items():\n            if client_id in client_ids:\n                client_ids.remove(client_id)\n                debug_session.remove_client(client_id)\n        self.remove_debug_sessions_with_no_clients()\n"
  },
  {
    "path": "gdbgui/src/js/Actions.ts",
    "content": "import { store } from \"statorgfc\";\nimport GdbApi from \"./GdbApi\";\nimport SourceCode from \"./SourceCode\";\nimport Locals from \"./Locals\";\nimport Memory from \"./Memory\";\nimport constants from \"./constants\";\nimport React from \"react\";\nvoid React; // using jsx implicity uses React\n\nconst Actions = {\n  clear_program_state: function() {\n    store.set(\"line_of_source_to_flash\", undefined);\n    store.set(\"paused_on_frame\", undefined);\n    store.set(\"selected_frame_num\", 0);\n    store.set(\"current_thread_id\", undefined);\n    store.set(\"stack\", []);\n    store.set(\"threads\", []);\n    Memory.clear_cache();\n    Locals.clear();\n  },\n  inferior_program_starting: function() {\n    store.set(\"inferior_program\", constants.inferior_states.running);\n    Actions.clear_program_state();\n  },\n  inferior_program_resuming: function() {\n    store.set(\"inferior_program\", constants.inferior_states.running);\n  },\n  inferior_program_paused: function(frame = {}) {\n    store.set(\"inferior_program\", constants.inferior_states.paused);\n    store.set(\n      \"source_code_selection_state\",\n      constants.source_code_selection_states.PAUSED_FRAME\n    );\n    store.set(\"paused_on_frame\", frame);\n    // @ts-expect-error ts-migrate(2339) FIXME: Property 'fullname' does not exist on type '{}'.\n    store.set(\"fullname_to_render\", frame.fullname);\n    // @ts-expect-error ts-migrate(2339) FIXME: Property 'line' does not exist on type '{}'.\n    store.set(\"line_of_source_to_flash\", parseInt(frame.line));\n    // @ts-expect-error ts-migrate(2339) FIXME: Property 'addr' does not exist on type '{}'.\n    store.set(\"current_assembly_address\", frame.addr);\n    store.set(\"source_code_infinite_scrolling\", false);\n    SourceCode.make_current_line_visible();\n    Actions.refresh_state_for_gdb_pause();\n  },\n  inferior_program_exited: function() {\n    store.set(\"inferior_program\", constants.inferior_states.exited);\n    store.set(\"disassembly_for_missing_file\", []);\n    store.set(\"root_gdb_tree_var\", null);\n    store.set(\"previous_register_values\", {});\n    store.set(\"current_register_values\", {});\n    store.set(\"inferior_pid\", null);\n    Actions.clear_program_state();\n  },\n  /**\n   * Request relevant store information from gdb to refresh UI\n   */\n  refresh_state_for_gdb_pause: function() {\n    GdbApi.run_gdb_command(GdbApi._get_refresh_state_for_pause_cmds());\n  },\n  execute_console_command: function(command: any) {\n    if (store.get(\"refresh_state_after_sending_console_command\")) {\n      GdbApi.run_command_and_refresh_state(command);\n    } else {\n      GdbApi.run_gdb_command(command);\n    }\n  },\n  onConsoleCommandRun: function() {\n    if (store.get(\"refresh_state_after_sending_console_command\")) {\n      GdbApi.run_gdb_command(GdbApi._get_refresh_state_for_pause_cmds());\n    }\n  },\n  clear_console: function() {\n    store.set(\"gdb_console_entries\", []);\n  },\n  add_console_entries: function(entries: any, type: any) {\n    if (type === constants.console_entry_type.STD_OUT) {\n      // ignore\n      return;\n    }\n    if (!Array.isArray(entries)) {\n      entries = [entries];\n    }\n\n    const pty = store.get(\"gdbguiPty\");\n    if (pty) {\n      entries.forEach((data: string) => {\n        const entriesToIgnore = [\n          // No registers. appears when refresh commands are run when program hasn't started.\n          // TODO The real fix for this is to not refresh commands when the program is not running.\n          \"No registers.\"\n        ];\n        if (entriesToIgnore.indexOf(data) > -1) {\n          return;\n        }\n        // @ts-expect-error ts-migrate(2339) FIXME: Property 'colorTypeMap' does not exist on type 'Re... Remove this comment to see the full error message\n        pty.write(constants.colorTypeMap[type] ?? constants.xtermColors[\"reset\"]);\n        pty.writeln(data);\n        pty.write(constants.xtermColors[\"reset\"]);\n      });\n    } else {\n      console.error(\"Pty not available. New entries are:\", entries);\n    }\n  },\n  add_gdb_response_to_console(mi_obj: any) {\n    if (!mi_obj) {\n      return;\n    }\n    // Update status\n    let entries = [],\n      error = false;\n    if (mi_obj.message) {\n      if (mi_obj.message === \"error\") {\n        error = true;\n      } else {\n        entries.push(mi_obj.message);\n      }\n    }\n    if (mi_obj.payload) {\n      const interesting_keys = [\"msg\", \"reason\", \"signal-name\", \"signal-meaning\"];\n      for (let k of interesting_keys) {\n        if (mi_obj.payload[k]) {\n          entries.push(mi_obj.payload[k]);\n        }\n      }\n\n      if (mi_obj.payload.frame) {\n        for (let i of [\"file\", \"func\", \"line\", \"addr\"]) {\n          if (i in mi_obj.payload.frame) {\n            entries.push(`${i}: ${mi_obj.payload.frame[i]}`);\n          }\n        }\n      }\n    }\n    let type = error\n      ? constants.console_entry_type.STD_ERR\n      : constants.console_entry_type.STD_OUT;\n    Actions.add_console_entries(entries, type);\n  },\n  toggle_modal_visibility() {\n    store.set(\"show_modal\", !store.get(\"show_modal\"));\n  },\n  show_modal(header: any, body: any) {\n    store.set(\"modal_header\", header);\n    store.set(\"modal_body\", body);\n    store.set(\"show_modal\", true);\n  },\n  set_gdb_binary_and_arguments(binary: any, args: any) {\n    // remove list of source files associated with the loaded binary since we're loading a new one\n    store.set(\"source_file_paths\", []);\n    store.set(\"language\", \"c_family\");\n    store.set(\"inferior_binary_path\", null);\n    Actions.inferior_program_exited();\n    let cmds = GdbApi.get_load_binary_and_arguments_cmds(binary, args);\n    GdbApi.run_gdb_command(cmds);\n    GdbApi.get_inferior_binary_last_modified_unix_sec(binary);\n  },\n  connect_to_gdbserver(user_input: any) {\n    // https://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Target-Manipulation.html#GDB_002fMI-Target-Manipulation\n    store.set(\"source_file_paths\", []);\n    store.set(\"language\", \"c_family\");\n    store.set(\"inferior_binary_path\", null);\n    Actions.inferior_program_exited();\n    GdbApi.run_gdb_command([`-target-select remote ${user_input}`]);\n  },\n  remote_connected() {\n    Actions.inferior_program_paused();\n    let cmds = [];\n    if (store.get(\"auto_add_breakpoint_to_main\")) {\n      Actions.add_console_entries(\n        \"Connected to remote target! Adding breakpoint to main, then continuing target execution.\",\n        constants.console_entry_type.GDBGUI_OUTPUT\n      );\n      cmds.push(\"-break-insert main\");\n      cmds.push(\"-exec-continue\");\n      cmds.push(GdbApi.get_break_list_cmd());\n    } else {\n      Actions.add_console_entries(\n        'Connected to remote target! Add breakpoint(s), then press \"continue\" button (do not press \"run\").',\n        constants.console_entry_type.GDBGUI_OUTPUT\n      );\n    }\n    GdbApi.run_gdb_command(cmds);\n  },\n  attach_to_process(user_input: any) {\n    // https://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Target-Manipulation.html#GDB_002fMI-Target-Manipulation\n    GdbApi.run_gdb_command(`-target-attach ${user_input}`);\n  },\n  fetch_source_files() {\n    store.set(\"source_file_paths\", []);\n    GdbApi.run_gdb_command(\"-file-list-exec-source-files\");\n  },\n  view_file(fullname: any, line: any) {\n    store.set(\"fullname_to_render\", fullname);\n    store.set(\"source_code_infinite_scrolling\", false);\n    Actions.set_line_state(line);\n  },\n  set_line_state(line: any) {\n    store.set(\"source_code_infinite_scrolling\", false);\n    store.set(\n      \"source_code_selection_state\",\n      constants.source_code_selection_states.USER_SELECTION\n    );\n    store.set(\"line_of_source_to_flash\", parseInt(line));\n    store.set(\"make_current_line_visible\", true);\n  },\n  clear_cached_assembly() {\n    store.set(\"disassembly_for_missing_file\", []);\n    let cached_source_files = store.get(\"cached_source_files\");\n    for (let file of cached_source_files) {\n      file.assembly = {};\n    }\n    store.set(\"cached_source_files\", cached_source_files);\n  },\n  update_max_lines_of_code_to_fetch(new_value: any) {\n    if (new_value <= 0) {\n      new_value = constants.default_max_lines_of_code_to_fetch;\n    }\n    store.set(\"max_lines_of_code_to_fetch\", new_value);\n    localStorage.setItem(\"max_lines_of_code_to_fetch\", JSON.stringify(new_value));\n  },\n  send_signal(signal_name: any, pid: any) {\n    $.ajax({\n      beforeSend: function(xhr) {\n        xhr.setRequestHeader(\n          \"x-csrftoken\",\n          // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name 'initial_data'.\n          initial_data.csrf_token\n        ); /* global initial_data */\n      },\n      url: \"/send_signal_to_pid\",\n      cache: false,\n      type: \"POST\",\n      data: { signal_name: signal_name, pid: pid },\n      success: function(response) {\n        Actions.add_console_entries(\n          response.message,\n          constants.console_entry_type.GDBGUI_OUTPUT\n        );\n      },\n      error: function(response) {\n        if (response.responseJSON && response.responseJSON.message) {\n          Actions.add_console_entries(\n            // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name '_'.\n            _.escape(response.responseJSON.message),\n            constants.console_entry_type.STD_ERR\n          );\n        } else {\n          Actions.add_console_entries(\n            `${response.statusText} (${response.status} error)`,\n            constants.console_entry_type.STD_ERR\n          );\n        }\n        console.error(response);\n      },\n      complete: function() {}\n    });\n  }\n};\n\nexport default Actions;\n"
  },
  {
    "path": "gdbgui/src/js/BinaryLoader.tsx",
    "content": "import React from \"react\";\nimport constants from \"./constants\";\nimport Actions from \"./Actions\";\nimport Util from \"./Util\";\nimport ToolTipTourguide from \"./ToolTipTourguide\";\n\nconst TARGET_TYPES = {\n  file: \"file\",\n  server: \"server\",\n  process: \"process\",\n  target_download: \"target_download\"\n};\n\ntype State = any;\n\n/**\n * The BinaryLoader component allows the user to select their binary\n * and specify inputs\n */\nclass BinaryLoader extends React.Component<{}, State> {\n  constructor(props: {}) {\n    // @ts-expect-error ts-migrate(2554) FIXME: Expected 1-2 arguments, but got 0.\n    super();\n\n    this.state = {\n      past_binaries: [],\n      // @ts-expect-error ts-migrate(2339) FIXME: Property 'initial_user_input' does not exist on ty... Remove this comment to see the full error message\n      user_input: props.initial_user_input.join(\" \"),\n      // @ts-expect-error ts-migrate(2339) FIXME: Property 'initial_user_input' does not exist on ty... Remove this comment to see the full error message\n      initial_set_target_app: props.initial_user_input.length, // if user supplied initial binary, load it immediately\n      target_type: TARGET_TYPES.file\n    };\n    try {\n      // @ts-expect-error ts-migrate(2542) FIXME: Index signature in type 'Readonly<any>' only permi... Remove this comment to see the full error message\n      this.state.past_binaries = _.uniq(\n        // @ts-expect-error ts-migrate(2345) FIXME: Type 'null' is not assignable to type 'string'.\n        JSON.parse(localStorage.getItem(\"past_binaries\"))\n      );\n      if (!this.state.user_input) {\n        let most_recent_binary = this.state.past_binaries[0];\n        // @ts-expect-error ts-migrate(2542) FIXME: Index signature in type 'Readonly<any>' only permi... Remove this comment to see the full error message\n        this.state.user_input = most_recent_binary;\n      }\n    } catch (err) {\n      // @ts-expect-error ts-migrate(2542) FIXME: Index signature in type 'Readonly<any>' only permi... Remove this comment to see the full error message\n      this.state.past_binaries = [];\n    }\n  }\n  render() {\n    let button_text, title, placeholder;\n\n    if (this.state.target_type === TARGET_TYPES.file) {\n      button_text = \"Load Binary\";\n      title =\n        \"Loads the binary and any arguments present in the input to the right. Backslashes are treated as escape characters. Windows users can either use two backslashes in paths, or forward slashes.\";\n      placeholder = \"/path/to/target/executable -and -flags\";\n    } else if (this.state.target_type === TARGET_TYPES.server) {\n      // https://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Target-Manipulation.html#GDB_002fMI-Target-Manipulation\n      // -target-select\n      button_text = \"Connect to gdbserver\";\n      title = \"Connect GDB to the remote target.\";\n      placeholder = \"examples: 127.0.0.1:9999 | /dev/ttya\";\n    } else if (this.state.target_type === TARGET_TYPES.process) {\n      // -target-attach\n      button_text = \"Attach to Process\";\n      title =\n        \"Attach to a process pid or a file file outside of GDB, or a thread group gid. If attaching to a thread group, the id previously returned by ‘-list-thread-groups --available’ must be used. Note: to do this, you usually need to run gdbgui as sudo.\";\n      placeholder = \"pid | gid | file\";\n    }\n\n    return (\n      <form style={{ marginBottom: 1, flex: \"2 0 0\" }}>\n        <div className=\"input-group input-group-sm\">\n          <div className=\"dropdown input-group-btn\">\n            <button\n              className=\"btn btn-primary dropdown-toggle\"\n              type=\"button\"\n              data-toggle=\"dropdown\"\n            >\n              <span className=\"caret\" />\n            </button>\n\n            <ul className=\"dropdown-menu\">\n              <li>\n                <a\n                  className=\"pointer\"\n                  onClick={() => this.setState({ target_type: TARGET_TYPES.file })}\n                >\n                  Load Binary\n                </a>\n              </li>\n              <li>\n                <a\n                  className=\"pointer\"\n                  onClick={() => this.setState({ target_type: TARGET_TYPES.server })}\n                >\n                  Connect to gdbserver\n                </a>\n              </li>\n              <li>\n                <a\n                  className=\"pointer\"\n                  onClick={() => this.setState({ target_type: TARGET_TYPES.process })}\n                >\n                  Attach to Process\n                </a>\n              </li>\n            </ul>\n\n            <button\n              type=\"button\"\n              title={title}\n              onClick={this.click_set_target_app.bind(this)}\n              className=\"btn btn-primary\"\n            >\n              {button_text}\n            </button>\n          </div>\n\n          <input\n            type=\"text\"\n            placeholder={placeholder}\n            list=\"past_binaries\"\n            style={{ fontFamily: \"courier\" }}\n            className=\"form-control\"\n            onKeyUp={this.onkeyup_user_input.bind(this)}\n            onChange={this.onchange_user_inpu.bind(this)}\n            value={this.state.user_input}\n          />\n        </div>\n        <ToolTipTourguide\n          // @ts-expect-error ts-migrate(2322) FIXME: Property 'step_num' does not exist on type 'Intrin... Remove this comment to see the full error message\n          step_num={1}\n          position={\"bottomcenter\"}\n          content={\n            <div>\n              <h5>Enter the path to the binary you wish to debug here.</h5>\n              <p>This is the first thing you should do.</p>\n              <p>\n                The path can be absolute, or relative to where gdbgui was launched from.\n              </p>\n            </div>\n          }\n        />\n        <ToolTipTourguide\n          // @ts-expect-error ts-migrate(2322) FIXME: Property 'step_num' does not exist on type 'Intrin... Remove this comment to see the full error message\n          step_num={2}\n          position={\"bottomleft\"}\n          content={\n            <div>\n              <h5>Press this button to load the executable specified in the input.</h5>\n              <p>This is the second thing you should do.</p>\n\n              <p>\n                Debugging won't start, but you will be able to set breakpoints. If\n                present,{\" \"}\n                <a href=\"https://en.wikipedia.org/wiki/Debug_symbol\">debugging symbols</a>{\" \"}\n                in the binary are also loaded.\n              </p>\n              <p>\n                If you don't want to debug a binary, click the dropdown to choose a\n                different target type.\n              </p>\n            </div>\n          }\n        />\n        <datalist id=\"past_binaries\">\n          {this.state.past_binaries.map((b: any, i: any) => (\n            <option key={i}>{b}</option>\n          ))}\n        </datalist>\n      </form>\n    );\n  }\n  componentDidMount() {\n    if (this.state.initial_set_target_app) {\n      this.setState({ initial_set_target_app: false });\n      this.set_target_app();\n    }\n  }\n  onkeyup_user_input(e: any) {\n    if (e.keyCode === constants.ENTER_BUTTON_NUM) {\n      this.set_target_app();\n    }\n  }\n  onchange_user_inpu(e: any) {\n    // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name 'initial_data'.\n    if (initial_data.using_windows) {\n      // replace backslashes with forward slashes when using windows\n      this.setState({ user_input: e.target.value.replace(/\\\\/g, \"/\") });\n    } else {\n      this.setState({ user_input: e.target.value });\n    }\n  }\n  click_set_target_app() {\n    this.set_target_app();\n  }\n  // save to list of binaries used that autopopulates the input dropdown\n  _add_user_input_to_history(binary_and_args: any) {\n    // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name '_'.\n    _.remove(this.state.past_binaries, (i: any) => i === binary_and_args);\n    this.state.past_binaries.unshift(binary_and_args); // add to beginning\n    this.setState({ past_binaries: this.state.past_binaries });\n    // @ts-expect-error ts-migrate(2345) FIXME: Type 'never[]' is not assignable to type 'string'.\n    localStorage.setItem(\"past_binaries\", JSON.stringify(this.state.past_binaries) || []);\n\n    // @ts-expect-error ts-migrate(2345) FIXME: Type 'null' is not assignable to type 'string'.\n    let num_gdbgui_sessions = parseInt(localStorage.getItem(\"num_gdbgui_sessions\"));\n    if (isNaN(num_gdbgui_sessions)) {\n      num_gdbgui_sessions = 0;\n    }\n  }\n  /**\n   * parse tokens with awareness of double quotes\n   *\n   * @param      {string}  user_input raw input from user\n   * @return     {Object}  { the binary (string) and arguments (array) parsed from user input }\n   */\n  _parse_binary_and_args_from_user_input(user_input: any) {\n    let list_of_params = Util.string_to_array_safe_quotes(user_input),\n      binary = \"\",\n      args: any = [],\n      len = list_of_params.length;\n    if (len === 1) {\n      binary = list_of_params[0];\n    } else if (len > 1) {\n      binary = list_of_params[0];\n      args = list_of_params.slice(1, len);\n    }\n    return { binary: binary, args: args.join(\" \") };\n  }\n  set_target_app() {\n    let user_input = this.state.user_input.trim();\n\n    if (user_input === \"\") {\n      Actions.add_console_entries(\n        \"input cannot be empty\",\n        constants.console_entry_type.GDBGUI_OUTPUT\n      );\n      return;\n    }\n\n    this._add_user_input_to_history(user_input);\n\n    if (this.state.target_type === TARGET_TYPES.file) {\n      const { binary, args } = this._parse_binary_and_args_from_user_input(user_input);\n      Actions.set_gdb_binary_and_arguments(binary, args);\n    } else if (this.state.target_type === TARGET_TYPES.server) {\n      Actions.connect_to_gdbserver(user_input);\n    } else if (this.state.target_type === TARGET_TYPES.process) {\n      Actions.attach_to_process(user_input);\n    }\n  }\n}\n\nexport default BinaryLoader;\n"
  },
  {
    "path": "gdbgui/src/js/Breakpoints.tsx",
    "content": "import React from \"react\";\nimport { store } from \"statorgfc\";\nimport GdbApi from \"./GdbApi\";\nimport Actions from \"./Actions\";\nimport Util from \"./Util\";\nimport FileOps from \"./FileOps\";\nimport { FileLink } from \"./Links\";\nimport constants from \"./constants\";\n\nconst BreakpointSourceLineCache = {\n  _cache: {},\n  get_line: function(fullname: any, linenum: any) {\n    if (\n      // @ts-expect-error ts-migrate(7053) FIXME: Property 'fullname' does not exist on type '{}'.\n      BreakpointSourceLineCache._cache[\"fullname\"] !== undefined &&\n      // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name '_'.\n      _.isString(BreakpointSourceLineCache._cache[\"fullname\"][linenum])\n    ) {\n      // @ts-expect-error ts-migrate(7053) FIXME: Property 'fullname' does not exist on type '{}'.\n      return BreakpointSourceLineCache._cache[\"fullname\"][linenum];\n    }\n    return null;\n  },\n  add_line: function(fullname: any, linenum: any, escaped_text: any) {\n    // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name '_'.\n    if (!_.isObject(BreakpointSourceLineCache._cache[\"fullname\"])) {\n      // @ts-expect-error ts-migrate(7053) FIXME: Property 'fullname' does not exist on type '{}'.\n      BreakpointSourceLineCache._cache[\"fullname\"] = {};\n    }\n    // @ts-expect-error ts-migrate(7053) FIXME: Property 'fullname' does not exist on type '{}'.\n    BreakpointSourceLineCache._cache[\"fullname\"][linenum] = escaped_text;\n  }\n};\n\ntype BreakpointState = any;\n\nclass Breakpoint extends React.Component<{}, BreakpointState> {\n  constructor(props: {}) {\n    super(props);\n    this.state = {\n      breakpoint_condition: \"\",\n      editing_breakpoint_condition: false\n    };\n  }\n  get_source_line(fullname: any, linenum: any) {\n    // if we have the source file cached, we can display the line of text\n    const MAX_CHARS_TO_SHOW_FROM_SOURCE = 40;\n    let line = null;\n    if (BreakpointSourceLineCache.get_line(fullname, linenum)) {\n      line = BreakpointSourceLineCache.get_line(fullname, linenum);\n      // @ts-expect-error ts-migrate(2554) FIXME: Expected 3 arguments, but got 2.\n    } else if (FileOps.line_is_cached(fullname, linenum)) {\n      let syntax_highlighted_line = FileOps.get_line_from_file(fullname, linenum);\n      // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name '_'.\n      line = _.trim(Util.get_text_from_html(syntax_highlighted_line));\n\n      if (line.length > MAX_CHARS_TO_SHOW_FROM_SOURCE) {\n        line = line.slice(0, MAX_CHARS_TO_SHOW_FROM_SOURCE) + \"...\";\n      }\n      BreakpointSourceLineCache.add_line(fullname, linenum, line);\n    }\n\n    if (line) {\n      return (\n        <span className=\"monospace\" style={{ whiteSpace: \"nowrap\", fontSize: \"0.9em\" }}>\n          {line || <br />}\n        </span>\n      );\n    }\n    return \"(file not cached)\";\n  }\n  get_delete_jsx(bkpt_num_to_delete: any) {\n    return (\n      <div\n        style={{ width: \"10px\", display: \"inline\" }}\n        className=\"pointer breakpoint_trashcan\"\n        onClick={e => {\n          e.stopPropagation();\n          Breakpoints.delete_breakpoint(bkpt_num_to_delete);\n        }}\n        title={`Delete breakpoint ${bkpt_num_to_delete}`}\n      >\n        <span className=\"glyphicon glyphicon-trash\"> </span>\n      </div>\n    );\n  }\n  get_num_times_hit(bkpt: any) {\n    if (\n      bkpt.times === undefined || // E.g. 'bkpt' is a child breakpoint\n      bkpt.times == 0\n    ) {\n      return \"\";\n    } else if (bkpt.times == 1) {\n      return \"1 hit\";\n    } else {\n      return `${bkpt.times} hits`;\n    }\n  }\n  on_change_bkpt_cond(e: any) {\n    this.setState({\n      breakpoint_condition: e.target.value,\n      editing_breakpoint_condition: true\n    });\n  }\n  on_key_up_bktp_cond(number: any, e: any) {\n    if (e.keyCode === constants.ENTER_BUTTON_NUM) {\n      this.setState({ editing_breakpoint_condition: false });\n      Breakpoints.set_breakpoint_condition(e.target.value, number);\n    }\n  }\n  on_break_cond_click(e: any) {\n    this.setState({\n      editing_breakpoint_condition: true\n    });\n  }\n  render() {\n    // @ts-expect-error ts-migrate(2339) FIXME: Property 'bkpt' does not exist on type 'Readonly<{... Remove this comment to see the full error message\n    let b = this.props.bkpt,\n      checked = b.enabled === \"y\" ? \"checked\" : \"\",\n      source_line = this.get_source_line(b.fullname_to_display, b.line);\n\n    let info_glyph, function_jsx, bkpt_num_to_delete;\n    if (b.is_child_breakpoint) {\n      bkpt_num_to_delete = b.parent_breakpoint_number;\n      info_glyph = (\n        <span\n          className=\"glyphicon glyphicon-th-list\"\n          title=\"Child breakpoint automatically created from parent. If parent or any child of this tree is deleted, all related breakpoints will be deleted.\"\n        />\n      );\n    } else if (b.is_parent_breakpoint) {\n      info_glyph = (\n        <span\n          className=\"glyphicon glyphicon-th-list\"\n          title=\"Parent breakpoint with one or more child breakpoints. If parent or any child of this tree is deleted, all related breakpoints will be deleted.\"\n        />\n      );\n      bkpt_num_to_delete = b.number;\n    } else {\n      bkpt_num_to_delete = b.number;\n      info_glyph = \"\";\n    }\n\n    const delete_jsx = this.get_delete_jsx(bkpt_num_to_delete);\n    let location_jsx = (\n      <FileLink\n        fullname={b.fullname_to_display}\n        file={b.fullname_to_display}\n        line={b.line}\n      />\n    );\n\n    if (b.is_parent_breakpoint) {\n      function_jsx = (\n        <span className=\"placeholder\">\n          {info_glyph} parent breakpoint on inline, template, or ambiguous location\n        </span>\n      );\n    } else {\n      let func = b.func === undefined ? \"(unknown function)\" : b.func;\n      let break_condition = (\n        <div\n          onClick={this.on_break_cond_click.bind(this)}\n          className=\"inline\"\n          title={`${\n            this.state.breakpoint_condition ? \"Modify or remove\" : \"Add\"\n          } breakpoint condition`}\n        >\n          <span className=\"glyphicon glyphicon-edit\"></span>\n          <span className={`italic ${this.state.breakpoint_condition ? \"bold\" : \"\"}`}>\n            condition\n          </span>\n        </div>\n      );\n      if (this.state.editing_breakpoint_condition) {\n        break_condition = (\n          <input\n            type=\"text\"\n            style={{\n              display: \"inline\",\n              width: \"110px\",\n              padding: \"10px 10px\",\n              height: \"25px\",\n              fontSize: \"1em\"\n            }}\n            placeholder=\"Break condition\"\n            className=\"form-control\"\n            onKeyUp={this.on_key_up_bktp_cond.bind(this, b.number)}\n            onChange={this.on_change_bkpt_cond.bind(this)}\n            value={this.state.breakpoint_condition}\n          />\n        );\n      }\n\n      const times_hit = this.get_num_times_hit(b);\n      function_jsx = (\n        <div style={{ display: \"inline\" }}>\n          <span className=\"monospace\" style={{ paddingRight: \"5px\" }}>\n            {info_glyph} {func}\n          </span>\n          <span\n            style={{\n              color: \"#bbbbbb\",\n              fontStyle: \"italic\",\n              paddingRight: \"5px\"\n            }}\n          >\n            thread groups: {b[\"thread-groups\"]}\n          </span>\n          <span>{break_condition}</span>\n          <span\n            style={{\n              color: \"#bbbbbb\",\n              fontStyle: \"italic\",\n              paddingLeft: \"5px\"\n            }}\n          >\n            {times_hit}\n          </span>\n        </div>\n      );\n    }\n\n    return (\n      <div\n        className=\"breakpoint\"\n        onClick={() => Actions.view_file(b.fullname_to_display, b.line)}\n      >\n        <table\n          style={{\n            width: \"100%\",\n            fontSize: \"0.9em\",\n            borderWidth: \"0px\"\n          }}\n          className=\"lighttext table-condensed\"\n        >\n          <tbody>\n            <tr>\n              <td>\n                <input\n                  type=\"checkbox\"\n                  // @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'boolean |... Remove this comment to see the full error message\n                  checked={checked}\n                  onChange={() => Breakpoints.enable_or_disable_bkpt(checked, b.number)}\n                />\n                {function_jsx} {delete_jsx}\n              </td>\n            </tr>\n\n            <tr>\n              <td>{location_jsx}</td>\n            </tr>\n\n            <tr>\n              <td>{source_line}</td>\n            </tr>\n          </tbody>\n        </table>\n      </div>\n    );\n  } // render function\n}\n\nclass Breakpoints extends React.Component {\n  constructor() {\n    // @ts-expect-error ts-migrate(2554) FIXME: Expected 1-2 arguments, but got 0.\n    super();\n    // @ts-expect-error ts-migrate(2339) FIXME: Property 'connectComponentState' does not exist on... Remove this comment to see the full error message\n    store.connectComponentState(this, [\"breakpoints\"]);\n  }\n  render() {\n    let breakpoints_jsx = [];\n    for (let b of store.get(\"breakpoints\")) {\n      // @ts-expect-error ts-migrate(2322) FIXME: Property 'bkpt' does not exist on type 'IntrinsicA... Remove this comment to see the full error message\n      breakpoints_jsx.push(<Breakpoint bkpt={b} key={b.number} />);\n    }\n\n    if (breakpoints_jsx.length) {\n      return breakpoints_jsx;\n    } else {\n      return <span className=\"placeholder\">no breakpoints</span>;\n    }\n  }\n  static enable_or_disable_bkpt(checked: any, bkpt_num: any) {\n    if (checked) {\n      GdbApi.run_gdb_command([`-break-disable ${bkpt_num}`, GdbApi.get_break_list_cmd()]);\n    } else {\n      GdbApi.run_gdb_command([`-break-enable ${bkpt_num}`, GdbApi.get_break_list_cmd()]);\n    }\n  }\n  static set_breakpoint_condition(condition: any, bkpt_num: any) {\n    GdbApi.run_gdb_command([\n      `-break-condition ${bkpt_num} ${condition}`,\n      GdbApi.get_break_list_cmd()\n    ]);\n  }\n  static remove_breakpoint_if_present(fullname: any, line: any) {\n    if (Breakpoints.has_breakpoint(fullname, line)) {\n      let number = Breakpoints.get_breakpoint_number(fullname, line);\n      let cmd = [GdbApi.get_delete_break_cmd(number), GdbApi.get_break_list_cmd()];\n      GdbApi.run_gdb_command(cmd);\n    }\n  }\n  static add_or_remove_breakpoint(fullname: any, line: any) {\n    if (Breakpoints.has_breakpoint(fullname, line)) {\n      Breakpoints.remove_breakpoint_if_present(fullname, line);\n    } else {\n      Breakpoints.add_breakpoint(fullname, line);\n    }\n  }\n  static add_breakpoint(fullname: any, line: any) {\n    GdbApi.run_gdb_command(GdbApi.get_insert_break_cmd(fullname, line));\n  }\n  static has_breakpoint(fullname: any, line: any) {\n    let bkpts = store.get(\"breakpoints\");\n    for (let b of bkpts) {\n      if (b.fullname === fullname && b.line == line) {\n        return true;\n      }\n    }\n    return false;\n  }\n  static get_breakpoint_number(fullname: any, line: any) {\n    let bkpts = store.get(\"breakpoints\");\n    for (let b of bkpts) {\n      if (b.fullname === fullname && b.line == line) {\n        return b.number;\n      }\n    }\n    console.error(`could not find breakpoint for ${fullname}:${line}`);\n  }\n  static delete_breakpoint(breakpoint_number: any) {\n    GdbApi.run_gdb_command([\n      GdbApi.get_delete_break_cmd(breakpoint_number),\n      GdbApi.get_break_list_cmd()\n    ]);\n  }\n  static get_breakpoint_lines_for_file(fullname: any) {\n    return store\n      .get(\"breakpoints\")\n      .filter((b: any) => b.fullname_to_display === fullname && b.enabled === \"y\")\n      .map((b: any) => parseInt(b.line));\n  }\n  static get_disabled_breakpoint_lines_for_file(fullname: any) {\n    return store\n      .get(\"breakpoints\")\n      .filter((b: any) => b.fullname_to_display === fullname && b.enabled !== \"y\")\n      .map((b: any) => parseInt(b.line));\n  }\n  static get_conditional_breakpoint_lines_for_file(fullname: any) {\n    return store\n      .get(\"breakpoints\")\n      .filter((b: any) => b.fullname_to_display === fullname && b.cond !== undefined)\n      .map((b: any) => parseInt(b.line));\n  }\n  static save_breakpoints(payload: any) {\n    store.set(\"breakpoints\", []);\n    if (payload && payload.BreakpointTable && payload.BreakpointTable.body) {\n      for (let breakpoint of payload.BreakpointTable.body) {\n        Breakpoints.save_breakpoint(breakpoint);\n      }\n    }\n  }\n  static save_breakpoint(breakpoint: any) {\n    let bkpt = Object.assign({}, breakpoint);\n\n    bkpt.is_parent_breakpoint = bkpt.addr === \"(MULTIPLE)\";\n\n    // parent breakpoints have numbers like \"5.6\", whereas normal breakpoints and parent breakpoints have numbers like \"5\"\n    bkpt.is_child_breakpoint = parseInt(bkpt.number) !== parseFloat(bkpt.number);\n    bkpt.is_normal_breakpoint = !bkpt.is_parent_breakpoint && !bkpt.is_child_breakpoint;\n\n    if (bkpt.is_child_breakpoint) {\n      bkpt.parent_breakpoint_number = parseInt(bkpt.number);\n    }\n\n    if (\"fullname\" in breakpoint && breakpoint.fullname) {\n      // this is a normal/child breakpoint; gdb gives it the fullname\n      bkpt.fullname_to_display = breakpoint.fullname;\n    } else if (\"original-location\" in breakpoint && breakpoint[\"original-location\"]) {\n      // this breakpoint is the parent breakpoint of multiple other breakpoints. gdb does not give it\n      // the fullname field, but rather the \"original-location\" field.\n      // example breakpoint['original-location']: /home/file.h:19\n      // so we need to parse out the line number, and store it\n      [bkpt.fullname_to_display, bkpt.line] = Util.parse_fullname_and_line(\n        breakpoint[\"original-location\"]\n      );\n    } else {\n      bkpt.fullname_to_display = null;\n    }\n\n    // add the breakpoint if it's not stored already\n    let bkpts = store.get(\"breakpoints\");\n    if (bkpts.indexOf(bkpt) === -1) {\n      bkpts.push(bkpt);\n      store.set(\"breakpoints\", bkpts);\n    }\n    return bkpt;\n  }\n}\n\nexport default Breakpoints;\n"
  },
  {
    "path": "gdbgui/src/js/ControlButtons.tsx",
    "content": "import React from \"react\";\n\nimport Actions from \"./Actions\";\nimport GdbApi from \"./GdbApi\";\nimport { store } from \"statorgfc\";\n\ntype State = any;\n\nclass ControlButtons extends React.Component<{}, State> {\n  constructor() {\n    // @ts-expect-error ts-migrate(2554) FIXME: Expected 1-2 arguments, but got 0.\n    super();\n    // @ts-expect-error ts-migrate(2339) FIXME: Property 'connectComponentState' does not exist on... Remove this comment to see the full error message\n    store.connectComponentState(this, [\"gdb_pid\", \"reverse_supported\"]);\n  }\n  render() {\n    let btn_class = \"btn btn-default btn-sm\";\n\n    return (\n      <React.Fragment>\n        <button\n          id=\"run_button\"\n          onClick={() => GdbApi.click_run_button()}\n          type=\"button\"\n          title=\"Start inferior program from the beginning keyboard shortcut: r\"\n          className={btn_class}\n        >\n          <span className=\"glyphicon glyphicon-repeat\" />\n        </button>\n\n        <button\n          id=\"continue_button\"\n          onClick={() => GdbApi.click_continue_button()}\n          type=\"button\"\n          title={\n            \"Continue until breakpoint is hit or inferior program exits keyboard shortcut: c\" +\n            (this.state.reverse_supported ? \". shift + c for reverse.\" : \"\")\n          }\n          className={btn_class}\n        >\n          <span className=\"glyphicon glyphicon-play\" />\n        </button>\n\n        <button\n          onClick={() => Actions.send_signal(\"SIGINT\", this.state.gdb_pid)}\n          type=\"button\"\n          title=\"Send Interrupt signal (SIGINT) to gdb process to pause it (if it's running)\"\n          className={btn_class}\n        >\n          <span className=\"glyphicon glyphicon-pause\" />\n        </button>\n\n        <button\n          id=\"next_button\"\n          onClick={() => GdbApi.click_next_button()}\n          type=\"button\"\n          title={\n            \"Step over next function call keyboard shortcut: n or right arrow\" +\n            (this.state.reverse_supported ? \". shift + n for reverse.\" : \"\")\n          }\n          className={btn_class}\n        >\n          <span className=\"glyphicon glyphicon-step-forward\" />\n        </button>\n\n        <button\n          id=\"step_button\"\n          onClick={() => GdbApi.click_step_button()}\n          type=\"button\"\n          title={\n            \"Step into next function call keyboard shortcut: s or down arrow\" +\n            (this.state.reverse_supported ? \". shift + s for reverse.\" : \"\")\n          }\n          className={btn_class}\n        >\n          <span className=\"glyphicon glyphicon-arrow-down\" />\n        </button>\n\n        <button\n          id=\"return_button\"\n          onClick={() => GdbApi.click_return_button()}\n          type=\"button\"\n          title=\"Step out of current function keyboard shortcut: u or up arrow\"\n          className={btn_class}\n        >\n          <span className=\"glyphicon glyphicon-arrow-up\" />\n        </button>\n        <div role=\"group\" className=\"btn-group btn-group-xs\">\n          <button\n            id=\"next_instruction_button\"\n            onClick={() => GdbApi.click_next_instruction_button()}\n            type=\"button\"\n            title={\n              \"Next Instruction: Execute one machine instruction, stepping over function calls keyboard shortcut: m\" +\n              (this.state.reverse_supported ? \". shift + m for reverse.\" : \"\")\n            }\n            className=\"btn btn-default\"\n          >\n            NI\n          </button>\n          <button\n            id=\"step_instruction_button\"\n            onClick={() => GdbApi.click_step_instruction_button()}\n            type=\"button\"\n            title={\n              \"Step Instruction: Execute one machine instruction, stepping into function calls keyboard shortcut: ','\" +\n              (this.state.reverse_supported ? \". shift + , for reverse.\" : \"\")\n            }\n            className=\"btn btn-default\"\n          >\n            SI\n          </button>\n        </div>\n      </React.Fragment>\n    );\n  }\n}\n\nexport default ControlButtons;\n"
  },
  {
    "path": "gdbgui/src/js/CopyToClipboard.tsx",
    "content": "import * as React from \"react\";\nimport ToolTip from \"./ToolTip\";\nimport { store } from \"statorgfc\";\n\ntype Props = {\n  content: string | null;\n};\n\nclass CopyToClipboard extends React.Component<Props> {\n  node: HTMLSpanElement | null = null;\n  render() {\n    if (!this.props.content) {\n      return null;\n    }\n    return (\n      <span\n        className={\"pointer glyphicon glyphicon-book\"}\n        style={{ color: \"#ccc\", display: \"inline\" }}\n        ref={node => (this.node = node)}\n        onMouseOver={() => {\n          ToolTip.show_tooltip_on_node(\"copy to clipboard\", this.node);\n        }}\n        onMouseLeave={ToolTip.hide_tooltip}\n        onClick={() => {\n          try {\n            let textarea = store.get(\"textarea_to_copy_to_clipboard\");\n            textarea.value = this.props.content;\n            textarea.select();\n            if (document.execCommand(\"copy\") === true) {\n              ToolTip.show_copied_tooltip_on_node(this.node);\n            } else {\n              ToolTip.show_tooltip_on_node(\"unable to copy\", this.node);\n            }\n          } catch (err) {\n            ToolTip.show_tooltip_on_node(\"unable to copy\", this.node);\n          }\n        }}\n      />\n    );\n  }\n}\n\nexport default CopyToClipboard;\n"
  },
  {
    "path": "gdbgui/src/js/Expressions.tsx",
    "content": "import React from \"react\";\nimport { store } from \"statorgfc\";\nimport GdbVariable from \"./GdbVariable\";\nimport constants from \"./constants\";\n\nclass Expressions extends React.Component {\n  objs_to_delete: any;\n  objs_to_render: any;\n  constructor() {\n    // @ts-expect-error ts-migrate(2554) FIXME: Expected 1-2 arguments, but got 0.\n    super();\n    // @ts-expect-error ts-migrate(2339) FIXME: Property 'connectComponentState' does not exist on... Remove this comment to see the full error message\n    store.connectComponentState(this, [\"expressions\"]);\n  }\n\n  render() {\n    // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name '_'.\n    let sorted_expression_objs = _.sortBy(\n      store.get(\"expressions\"),\n      (unsorted_obj: any) => unsorted_obj.expression\n    );\n    // only render variables in scope that were not created for the Locals component\n    this.objs_to_render = sorted_expression_objs.filter(\n      (obj: any) => obj.in_scope === \"true\" && obj.expr_type === \"expr\"\n    );\n    this.objs_to_delete = sorted_expression_objs.filter(\n      (obj: any) => obj.in_scope === \"invalid\"\n    );\n\n    // delete invalid objects\n    this.objs_to_delete.map((obj: any) => GdbVariable.delete_gdb_variable(obj.name));\n\n    let content = this.objs_to_render.map((obj: any) => (\n      <GdbVariable\n        // @ts-expect-error ts-migrate(2769) FIXME: Property 'obj' does not exist on type 'IntrinsicAt... Remove this comment to see the full error message\n        obj={obj}\n        key={obj.expression}\n        expression={obj.expression}\n        expr_type=\"expr\"\n      />\n    ));\n    if (content.length === 0) {\n      content.push(\n        <span key=\"empty\" className=\"placeholder\">\n          no expressions in this context\n        </span>\n      );\n    }\n    content.push(\n      <div key=\"tt\" id=\"plot_coordinate_tooltip\" style={{ display: \"hidden\" }} />\n    );\n\n    return (\n      <div>\n        <input\n          id=\"expressions_input\"\n          className=\"form-control\"\n          placeholder=\"expression or variable\"\n          style={{\n            display: \"inline\",\n            padding: \"6px 6px\",\n            height: \"25px\",\n            fontSize: \"1em\",\n            marginTop: \"5px\"\n          }}\n          onKeyUp={Expressions.keydown_on_input}\n        />\n\n        <p />\n\n        {content}\n      </div>\n    );\n  }\n  componentDidUpdate() {\n    for (let obj of this.objs_to_render) {\n      GdbVariable.plot_var_and_children(obj);\n    }\n  }\n\n  static keydown_on_input(e: any) {\n    if (e.keyCode === constants.ENTER_BUTTON_NUM) {\n      let expr = e.currentTarget.value,\n        // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name '_'.\n        trimmed_expr = _.trim(expr);\n\n      if (trimmed_expr !== \"\") {\n        GdbVariable.create_variable(trimmed_expr, \"expr\");\n      }\n    }\n  }\n}\n\nexport default Expressions;\n"
  },
  {
    "path": "gdbgui/src/js/FileOps.tsx",
    "content": "import { store } from \"statorgfc\";\nimport GdbApi from \"./GdbApi\";\nimport constants from \"./constants\";\nimport Actions from \"./Actions\";\nimport React from \"react\"; // needed for jsx\nvoid React;\n\nlet debug_print: any;\n// @ts-expect-error ts-migrate(2304) FIXME: Cannot find name 'debug'.\nif (debug) {\n  /* global debug */\n  debug_print = console.info;\n} else {\n  debug_print = function() {\n    // stubbed out\n  };\n}\n\nlet FileFetcher = {\n  _is_fetching: false,\n  _queue: [],\n  _fetch: function(fullname: any, start_line: any, end_line: any) {\n    if (FileOps.is_missing_file(fullname)) {\n      // file doesn't exist and we already know about it\n      // don't keep trying to fetch disassembly\n      console.warn(`tried to fetch a file known to be missing ${fullname}`);\n      FileFetcher._is_fetching = false;\n      FileFetcher._fetch_next();\n      return;\n    }\n\n    // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name '_'.\n    if (!_.isString(fullname)) {\n      console.warn(`trying to fetch filename that is not a string`, fullname);\n      FileOps.add_missing_file(fullname);\n      FileFetcher._is_fetching = false;\n      FileFetcher._fetch_next();\n    }\n\n    FileFetcher._is_fetching = true;\n\n    const data = {\n      start_line: start_line,\n      end_line: end_line,\n      path: fullname,\n      highlight: store.get(\"highlight_source_code\")\n    };\n\n    $.ajax({\n      beforeSend: function(xhr) {\n        xhr.setRequestHeader(\n          \"x-csrftoken\",\n          // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name 'initial_data'.\n          initial_data.csrf_token\n        ); /* global initial_data */\n      },\n      url: \"/read_file\",\n      cache: false,\n      type: \"GET\",\n      data: data,\n      success: function(response) {\n        response.source_code;\n        let source_code_obj = {};\n        let linenum = response.start_line;\n        for (let line of response.source_code_array) {\n          // @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message\n          source_code_obj[linenum] = line;\n          linenum++;\n        }\n\n        FileOps.add_source_file_to_cache(\n          fullname,\n          source_code_obj,\n          response.last_modified_unix_sec,\n          response.num_lines_in_file\n        );\n      },\n      error: function(response) {\n        if (response.responseJSON && response.responseJSON.message) {\n          Actions.add_console_entries(\n            // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name '_'.\n            _.escape(response.responseJSON.message),\n            constants.console_entry_type.STD_ERR\n          );\n        } else {\n          Actions.add_console_entries(\n            `${response.statusText} (${response.status} error)`,\n            constants.console_entry_type.STD_ERR\n          );\n        }\n        FileOps.add_missing_file(fullname);\n      },\n      complete: function() {\n        FileFetcher._is_fetching = false;\n\n        // @ts-expect-error ts-migrate(2339) FIXME: Property 'fullname' does not exist on type 'never'... Remove this comment to see the full error message\n        FileFetcher._queue = FileFetcher._queue.filter(o => o.fullname !== fullname);\n\n        FileFetcher._fetch_next();\n      }\n    });\n  },\n  _fetch_next: function() {\n    if (FileFetcher._is_fetching) {\n      return;\n    }\n    if (FileFetcher._queue.length) {\n      let obj = FileFetcher._queue.shift();\n      // @ts-expect-error ts-migrate(2532) FIXME: Object is possibly 'undefined'.\n      FileFetcher._fetch(obj.fullname, obj.start_line, obj.end_line);\n    }\n  },\n  fetch_complete() {\n    FileFetcher._is_fetching = false;\n    FileFetcher._fetch_next();\n  },\n  fetch: function(fullname: any, start_line: any, end_line: any) {\n    if (!start_line) {\n      start_line = 1;\n      console.warn(\"expected start line\");\n    }\n    if (!end_line) {\n      end_line = start_line;\n      console.warn(\"expected end line\");\n    }\n\n    if (FileOps.lines_are_cached(fullname, start_line, end_line)) {\n      debug_print(\n        `not fetching ${fullname}:${start_line}:${end_line} because it's cached`\n      );\n      return;\n    }\n\n    // @ts-expect-error ts-migrate(2322) FIXME: Type 'any' is not assignable to type 'never'.\n    FileFetcher._queue.push({ fullname, start_line, end_line });\n    FileFetcher._fetch_next();\n  }\n};\n\nconst FileOps = {\n  warning_shown_for_old_binary: false,\n  unfetchable_disassembly_addresses: {},\n  disassembly_addr_being_fetched: null,\n  init: function() {\n    // @ts-expect-error ts-migrate(2339) FIXME: Property 'subscribeToKeys' does not exist on type ... Remove this comment to see the full error message\n    store.subscribeToKeys(\n      [\n        \"inferior_program\",\n        \"source_code_selection_state\",\n        \"paused_on_frame\",\n        \"current_assembly_address\",\n        \"disassembly_for_missing_file\",\n        \"highlight_source_code\",\n        \"missing_files\",\n        \"files_being_fetched\",\n        \"gdb_version_array\",\n        \"fullname_to_render\",\n        \"line_of_source_to_flash\",\n        \"cached_source_files\",\n        \"max_lines_of_code_to_fetch\"\n      ],\n      FileOps._store_change_callback\n    );\n  },\n  user_select_file_to_view: function(fullname: any, line: any) {\n    store.set(\n      \"source_code_selection_state\",\n      constants.source_code_selection_states.USER_SELECTION\n    );\n    store.set(\"fullname_to_render\", fullname);\n    store.set(\"line_of_source_to_flash\", line);\n    store.set(\"make_current_line_visible\", true);\n    store.set(\"source_code_infinite_scrolling\", false);\n  },\n  _store_change_callback: function() {\n    if (store.get(\"inferior_program\") === constants.inferior_states.running) {\n      return;\n    }\n\n    let source_code_selection_state = store.get(\"source_code_selection_state\"),\n      fullname = null,\n      is_paused = false,\n      paused_addr = null,\n      paused_frame_fullname = null,\n      paused_frame = store.get(\"paused_on_frame\");\n\n    if (paused_frame) {\n      paused_frame_fullname = paused_frame.fullname;\n    }\n\n    let require_cached_line_num;\n    if (\n      source_code_selection_state ===\n      constants.source_code_selection_states.USER_SELECTION\n    ) {\n      fullname = store.get(\"fullname_to_render\");\n      is_paused = false;\n      paused_addr = null;\n      require_cached_line_num = parseInt(store.get(\"line_of_source_to_flash\"));\n    } else if (\n      source_code_selection_state === constants.source_code_selection_states.PAUSED_FRAME\n    ) {\n      is_paused = store.get(\"inferior_program\") === constants.inferior_states.paused;\n      paused_addr = store.get(\"current_assembly_address\");\n      fullname = paused_frame_fullname;\n      require_cached_line_num = parseInt(store.get(\"line_of_source_to_flash\"));\n    }\n\n    let source_code_infinite_scrolling = store.get(\"source_code_infinite_scrolling\"),\n      assembly_is_cached = FileOps.assembly_is_cached(fullname),\n      file_is_missing = FileOps.is_missing_file(fullname),\n      start_line,\n      end_line;\n    ({ start_line, end_line, require_cached_line_num } = FileOps.get_start_and_end_lines(\n      fullname,\n      require_cached_line_num,\n      source_code_infinite_scrolling\n    ));\n\n    FileOps.update_source_code_state(\n      fullname,\n      start_line,\n      require_cached_line_num,\n      end_line,\n      assembly_is_cached,\n      file_is_missing,\n      is_paused,\n      paused_addr\n    );\n  },\n  get_start_and_end_lines(\n    fullname: any,\n    require_cached_line_num: any,\n    source_code_infinite_scrolling: any\n  ) {\n    let start_line, end_line;\n    if (source_code_infinite_scrolling) {\n      start_line = store.get(\"source_linenum_to_display_start\");\n      end_line = store.get(\"source_linenum_to_display_end\");\n      require_cached_line_num = start_line;\n    } else {\n      let source_file_obj = FileOps.get_source_file_obj_from_cache(fullname);\n      if (!require_cached_line_num) {\n        require_cached_line_num = 1;\n      }\n\n      start_line = Math.max(\n        Math.floor(require_cached_line_num - store.get(\"max_lines_of_code_to_fetch\") / 2),\n        1\n      );\n      end_line = Math.ceil(start_line + store.get(\"max_lines_of_code_to_fetch\"));\n\n      if (source_file_obj) {\n        // @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.\n        end_line = Math.ceil(Math.min(end_line, FileOps.get_num_lines_in_file(fullname))); // don't go past the end of the line\n      }\n      if (start_line > end_line) {\n        start_line = Math.floor(\n          Math.max(1, end_line - store.get(\"max_lines_of_code_to_fetch\"))\n        );\n      }\n      require_cached_line_num = Math.min(require_cached_line_num, end_line);\n    }\n\n    return { start_line, end_line, require_cached_line_num };\n  },\n  update_source_code_state(\n    fullname: any,\n    start_line: any,\n    require_cached_line_num: any,\n    end_line: any,\n    assembly_is_cached: any,\n    file_is_missing: any,\n    is_paused: any,\n    paused_addr: any\n  ) {\n    const states = constants.source_code_states,\n      // @ts-expect-error ts-migrate(2554) FIXME: Expected 3 arguments, but got 2.\n      line_is_cached = FileOps.line_is_cached(fullname, require_cached_line_num);\n\n    if (fullname && line_is_cached) {\n      // we have file cached. We may have assembly cached too.\n      store.set(\n        \"source_code_state\",\n        assembly_is_cached ? states.ASSM_AND_SOURCE_CACHED : states.SOURCE_CACHED\n      );\n      store.set(\"source_linenum_to_display_start\", start_line);\n      // @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.\n      end_line = Math.min(end_line, FileOps.get_num_lines_in_file(fullname));\n      store.set(\"source_linenum_to_display_end\", end_line);\n    } else if (fullname && !file_is_missing) {\n      // we don't have file cached, and it is not known to be missing on the file system, so try to get it\n      store.set(\"source_code_state\", states.FETCHING_SOURCE);\n\n      FileFetcher.fetch(fullname, start_line, end_line);\n    } else if (\n      is_paused &&\n      paused_addr &&\n      store\n        .get(\"disassembly_for_missing_file\")\n        .some((obj: any) => parseInt(obj.address, 16) === parseInt(paused_addr, 16))\n    ) {\n      store.set(\"source_code_state\", states.ASSM_CACHED);\n    } else if (is_paused && paused_addr) {\n      if (paused_addr in FileOps.unfetchable_disassembly_addresses) {\n        store.set(\"source_code_state\", states.ASSM_UNAVAILABLE);\n      } else {\n        // get disassembly\n        store.set(\"source_code_state\", states.FETCHING_ASSM);\n        FileOps.fetch_disassembly_for_missing_file(paused_addr);\n      }\n    } else if (file_is_missing) {\n      store.set(\"source_code_state\", states.FILE_MISSING);\n    } else {\n      store.set(\"source_code_state\", states.NONE_AVAILABLE);\n    }\n  },\n  get_num_lines_in_file: function(fullname: any, source_file_obj: any) {\n    if (!source_file_obj) {\n      source_file_obj = FileOps.get_source_file_obj_from_cache(fullname);\n    }\n    if (!source_file_obj) {\n      console.error(\"Developer error: expected to find file object for \" + fullname);\n      return;\n    }\n    if (!source_file_obj.num_lines_in_file) {\n      console.error('Developer error: expected key \"num_lines_in_file\"');\n      return Infinity;\n    }\n    return source_file_obj.num_lines_in_file;\n  },\n  lines_are_cached: function(fullname: any, start_line: any, end_line: any) {\n    let source_file_obj = FileOps.get_source_file_obj_from_cache(fullname),\n      linenum = start_line;\n    if (!source_file_obj) {\n      return false;\n    }\n\n    const num_lines_in_file = FileOps.get_num_lines_in_file(fullname, source_file_obj);\n    if (start_line > num_lines_in_file) {\n      return false;\n    }\n\n    let safe_end_line = Math.min(end_line, num_lines_in_file);\n\n    while (linenum <= safe_end_line) {\n      if (!FileOps.line_is_cached(fullname, linenum, source_file_obj)) {\n        return false;\n      }\n      linenum++;\n    }\n    return true;\n  },\n  line_is_cached: function(fullname: any, linenum: any, source_file_obj: any) {\n    if (!source_file_obj) {\n      source_file_obj = FileOps.get_source_file_obj_from_cache(fullname);\n    }\n    return (\n      source_file_obj &&\n      source_file_obj.source_code_obj &&\n      source_file_obj.source_code_obj[linenum] !== undefined\n    );\n  },\n  get_line_from_file: function(fullname: any, linenum: any) {\n    let source_file_obj = FileOps.get_source_file_obj_from_cache(fullname);\n    if (!source_file_obj) {\n      return null;\n    }\n    return source_file_obj.source_code_obj[linenum];\n  },\n  assembly_is_cached: function(fullname: any) {\n    let source_file_obj = FileOps.get_source_file_obj_from_cache(fullname);\n    return (\n      source_file_obj &&\n      source_file_obj.assembly &&\n      Object.keys(source_file_obj.assembly).length\n    );\n  },\n  get_source_file_obj_from_cache: function(fullname: any) {\n    let cached_files = store.get(\"cached_source_files\");\n    for (let sf of cached_files) {\n      if (sf.fullname === fullname) {\n        return sf;\n      }\n    }\n    return null;\n  },\n  add_source_file_to_cache: function(\n    fullname: any,\n    source_code_obj: any,\n    last_modified_unix_sec: any,\n    num_lines_in_file: any\n  ) {\n    let cached_file_obj = FileOps.get_source_file_obj_from_cache(fullname);\n    if (cached_file_obj === null) {\n      // nothing cached in the front end, add a new entry\n      let new_source_file = {\n          fullname: fullname,\n          source_code_obj: source_code_obj,\n          assembly: {},\n          last_modified_unix_sec: last_modified_unix_sec,\n          num_lines_in_file: num_lines_in_file,\n          exists: true\n        },\n        cached_source_files = store.get(\"cached_source_files\");\n\n      cached_source_files.push(new_source_file);\n      store.set(\"cached_source_files\", cached_source_files);\n      FileOps.warning_shown_for_old_binary = false;\n      FileOps.show_modal_if_file_modified_after_binary(\n        fullname,\n        new_source_file.last_modified_unix_sec\n      );\n    } else {\n      // mutate existing source code object by adding keys (lines) of the new source code object\n      Object.assign(cached_file_obj.source_code_obj, source_code_obj);\n      store.set(\"cached_source_files\", store.get(\"cached_source_files\"));\n    }\n  },\n  /**\n   * Show modal warning if user is trying to show a file that was modified after the binary was compiled\n   */\n  show_modal_if_file_modified_after_binary(\n    fullname: any,\n    src_last_modified_unix_sec: any\n  ) {\n    if (store.get(\"inferior_binary_path\")) {\n      if (\n        src_last_modified_unix_sec >\n          store.get(\"inferior_binary_path_last_modified_unix_sec\") &&\n        FileOps.warning_shown_for_old_binary === false\n      ) {\n        Actions.show_modal(\n          \"Warning\",\n          <div>\n            This source file was modified <span className=\"bold\">after</span> the binary\n            was compiled. Recompile the binary, then try again. Otherwise the source code\n            may not match the binary.\n            <p />\n            {/* @ts-expect-error ts-migrate(2304) FIXME: Cannot find name 'moment'. */}\n            <p>{`Source file: ${fullname}, modified ${moment(\n              src_last_modified_unix_sec * 1000\n            ).format(constants.DATE_FORMAT)}`}</p>\n            <p>\n              {/* @ts-expect-error ts-migrate(2304) FIXME: Cannot find name 'moment'. */}\n              {`Binary: ${store.get(\"inferior_binary_path\")}, modified ${moment(\n                store.get(\"inferior_binary_path_last_modified_unix_sec\") * 1000\n              ).format(constants.DATE_FORMAT)}`}\n              )\n            </p>\n          </div>\n        );\n        FileOps.warning_shown_for_old_binary = true;\n      }\n    }\n  },\n  get_cached_assembly_for_file: function(fullname: any) {\n    for (let file of store.get(\"cached_source_files\")) {\n      if (file.fullname === fullname) {\n        return file.assembly;\n      }\n    }\n    return [];\n  },\n  refresh_cached_source_files: function() {\n    FileOps.clear_cached_source_files();\n  },\n  clear_cached_source_files: function() {\n    store.set(\"cached_source_files\", []);\n  },\n  fetch_more_source_at_beginning() {\n    let fullname = store.get(\"fullname_to_render\");\n    let center_on_line = store.get(\"source_linenum_to_display_start\") - 1;\n    // store.set('source_code_infinite_scrolling', true)\n    store.set(\n      \"source_linenum_to_display_start\",\n      Math.max(\n        store.get(\"source_linenum_to_display_start\") -\n          Math.floor(store.get(\"max_lines_of_code_to_fetch\") / 2),\n        1\n      )\n    );\n    store.set(\n      \"source_linenum_to_display_end\",\n      Math.ceil(\n        store.get(\"source_linenum_to_display_start\") +\n          store.get(\"max_lines_of_code_to_fetch\")\n      )\n    );\n    Actions.view_file(fullname, center_on_line);\n    FileFetcher.fetch(\n      fullname,\n      store.get(\"source_linenum_to_display_start\"),\n      store.get(\"source_linenum_to_display_end\")\n    );\n  },\n  fetch_more_source_at_end() {\n    store.set(\"source_code_infinite_scrolling\", true);\n\n    let fullname = store.get(\"fullname_to_render\");\n    let end_line =\n      store.get(\"source_linenum_to_display_end\") +\n      Math.ceil(store.get(\"max_lines_of_code_to_fetch\") / 2);\n\n    let source_file_obj = FileOps.get_source_file_obj_from_cache(fullname);\n    if (source_file_obj) {\n      // @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.\n      end_line = Math.min(end_line, FileOps.get_num_lines_in_file(fullname)); // don't go past the end of the line\n    }\n\n    let start_line = end_line - store.get(\"max_lines_of_code_to_fetch\");\n    start_line = Math.max(1, start_line);\n    store.set(\"source_linenum_to_display_end\", end_line);\n    store.set(\"source_linenum_to_display_start\", start_line);\n\n    FileFetcher.fetch(\n      fullname,\n      store.get(\"source_linenum_to_display_start\"),\n      store.get(\"source_linenum_to_display_end\")\n    );\n  },\n  is_missing_file: function(fullname: any) {\n    return store.get(\"missing_files\").indexOf(fullname) !== -1;\n  },\n  add_missing_file: function(fullname: any) {\n    let missing_files = store.get(\"missing_files\");\n    missing_files.push(fullname);\n    store.set(\"missing_files\", missing_files);\n  },\n  /**\n   * gdb changed its api for the data-disassemble command\n   * see https://www.sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Data-Manipulation.html\n   * TODO not sure which version this change occured in. I know in 7.7 it needs the '3' option,\n   * and in 7.11 it needs the '4' option. I should test the various version at some point.\n   */\n  get_dissasembly_format_num: function(gdb_version_array: any) {\n    if (gdb_version_array.length === 0) {\n      // assuming new version, but we shouldn't ever not know the version...\n      return 4;\n    } else if (\n      gdb_version_array[0] < 7 ||\n      (parseInt(gdb_version_array[0]) === 7 && gdb_version_array[1] <= 7)\n    ) {\n      // this option has been deprecated in newer versions, but is required in older ones\n      return 3;\n    } else {\n      return 4;\n    }\n  },\n  get_fetch_disassembly_command: function(\n    fullname: any,\n    start_line: any,\n    mi_response_format: any\n  ) {\n    // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name '_'.\n    if (_.isString(fullname)) {\n      return (\n        constants.INLINE_DISASSEMBLY_STR +\n        `-data-disassemble -f ${fullname} -l ${start_line} -n 1000 -- ${mi_response_format}`\n      );\n    } else {\n      console.warn(\"not fetching undefined file\");\n    }\n  },\n  /**\n   * Fetch disassembly for current file/line.\n   */\n  fetch_assembly_cur_line: function(mi_response_format = null) {\n    // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name '_'.\n    if (mi_response_format === null || !_.isNumber(mi_response_format)) {\n      // try to determine response format based on our guess of the gdb version being used\n      // @ts-expect-error ts-migrate(2322) FIXME: Type '4' is not assignable to type 'null'.\n      mi_response_format = FileOps.get_dissasembly_format_num(\n        store.get(\"gdb_version_array\")\n      );\n    }\n\n    let fullname = store.get(\"fullname_to_render\"),\n      line = parseInt(store.get(\"line_of_source_to_flash\"));\n    if (!line) {\n      line = 1;\n    }\n    FileOps.fetch_disassembly(fullname, line, mi_response_format);\n  },\n  fetch_disassembly: function(fullname: any, start_line: any, mi_response_format: any) {\n    let cmd = FileOps.get_fetch_disassembly_command(\n      fullname,\n      start_line,\n      mi_response_format\n    );\n    if (cmd) {\n      GdbApi.run_gdb_command(cmd);\n    }\n  },\n  fetch_disassembly_for_missing_file: function(hex_addr: any) {\n    // https://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Data-Manipulation.html\n    if (window.isNaN(hex_addr)) {\n      return;\n    }\n    Actions.add_console_entries(\n      \"Fetching assembly since file is missing\",\n      constants.console_entry_type.GDBGUI_OUTPUT\n    );\n    let start = parseInt(hex_addr, 16),\n      end = start + 100;\n    FileOps.disassembly_addr_being_fetched = hex_addr;\n    GdbApi.run_gdb_command(\n      constants.DISASSEMBLY_FOR_MISSING_FILE_STR +\n        `-data-disassemble -s 0x${start.toString(16)} -e 0x${end.toString(16)} -- 0`\n    );\n  },\n  fetch_disassembly_for_missing_file_failed: function() {\n    let addr_being_fetched = FileOps.disassembly_addr_being_fetched;\n    // @ts-expect-error ts-migrate(2538) FIXME: Type 'null' cannot be used as an index type.\n    FileOps.unfetchable_disassembly_addresses[addr_being_fetched] = true;\n    FileOps.disassembly_addr_being_fetched = null;\n    Actions.add_console_entries(\n      \"Failed to retrieve assembly for missing file\",\n      constants.console_entry_type.GDBGUI_OUTPUT\n    );\n  },\n  /**\n   * Save assembly and render source code if desired\n   * @param mi_assembly: array of assembly instructions\n   * @param mi_token (int): corresponds to either null (when src file is known and exists),\n   *  constants.DISASSEMBLY_FOR_MISSING_FILE_INT when source file is undefined or does not exist on filesystem\n   */\n  save_new_assembly: function(mi_assembly: any, mi_token: any) {\n    FileOps.disassembly_addr_being_fetched = null;\n\n    if (!Array.isArray(mi_assembly) || mi_assembly.length === 0) {\n      console.error(\"Attempted to save unexpected assembly\", mi_assembly);\n    }\n\n    let fullname = mi_assembly[0].fullname;\n    // @ts-expect-error ts-migrate(2551) FIXME: Property 'DISASSEMBLY_FOR_MISSING_FILE_INT' does n... Remove this comment to see the full error message\n    if (mi_token === constants.DISASSEMBLY_FOR_MISSING_FILE_INT) {\n      store.set(\"disassembly_for_missing_file\", mi_assembly);\n      return;\n    }\n\n    // convert assembly to an object, with key corresponding to line numbers\n    // and values corresponding to asm instructions for that line\n    let assembly_to_save = {};\n    for (let obj of mi_assembly) {\n      // @ts-expect-error ts-migrate(7053) FIXME: No index signature with a parameter of type 'numbe... Remove this comment to see the full error message\n      assembly_to_save[parseInt(obj.line)] = obj.line_asm_insn;\n    }\n\n    let cached_source_files = store.get(\"cached_source_files\");\n    for (let cached_file of cached_source_files) {\n      if (cached_file.fullname === fullname) {\n        cached_file.assembly = Object.assign(cached_file.assembly, assembly_to_save);\n\n        // @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'string[]' is not assignable to p... Remove this comment to see the full error message\n        let max_assm_line = Math.max(Object.keys(cached_file.assembly)),\n          // @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'string[]' is not assignable to p... Remove this comment to see the full error message\n          max_source_line = Math.max(Object.keys(cached_file.source_code_obj));\n        if (max_assm_line > max_source_line) {\n          cached_file.source_code_obj[max_assm_line] = \"\";\n          for (let i = 0; i < max_assm_line; i++) {\n            if (!cached_file.source_code_obj[i]) {\n              cached_file.source_code_obj[i] = \"\";\n            }\n          }\n        }\n        store.set(\"cached_source_files\", cached_source_files);\n        break;\n      }\n    }\n  }\n};\nexport default FileOps;\n"
  },
  {
    "path": "gdbgui/src/js/FileSystem.tsx",
    "content": "import React from \"react\";\n\nclass FileSystem extends React.Component {\n  nodecount: any;\n  get_node_jsx(node: any, depth = 0) {\n    if (!node) {\n      return null;\n    }\n    this.nodecount++;\n\n    let get_child_jsx_for_node = (node: any) => {\n      if (!(node.children && node.toggled)) {\n        return null;\n      }\n      return (\n        <ul>{node.children.map((child: any) => this.get_node_jsx(child, depth + 1))}</ul>\n      );\n    };\n    let indent = \"\\u00A0\\u00A0\\u00A0\".repeat(depth),\n      glyph = null;\n    let is_file = !node.children,\n      is_dir = !is_file;\n    if (is_dir) {\n      glyph = node.toggled ? \"glyphicon-chevron-down\" : \"glyphicon-chevron-right\";\n    }\n\n    let onClickName = null;\n    if (is_file) {\n      onClickName = () => {\n        // @ts-expect-error ts-migrate(2339) FIXME: Property 'onClickName' does not exist on type 'Rea... Remove this comment to see the full error message\n        this.props.onClickName(node);\n      };\n    }\n\n    return (\n      <React.Fragment key={this.nodecount}>\n        <li className=\"pointer\">\n          {indent}\n          <span\n            className={\"glyphicon  \" + glyph}\n            onClick={() => {\n              // @ts-expect-error ts-migrate(2339) FIXME: Property 'onToggle' does not exist on type 'Readon... Remove this comment to see the full error message\n              this.props.onToggle(node);\n            }}\n          />\n          {/* @ts-expect-error ts-migrate(2322) FIXME: Type 'null' is not assignable to type '((event: Mo... Remove this comment to see the full error message */}\n          <span onClick={onClickName}>{node.name}</span>\n        </li>\n        {get_child_jsx_for_node(node)}\n      </React.Fragment>\n    );\n  }\n\n  render() {\n    this.nodecount = -1;\n    return (\n      <div id=\"filesystem\">\n        {/* @ts-expect-error ts-migrate(2339) FIXME: Property 'rootnode' does not exist on type 'Readon... Remove this comment to see the full error message */}\n        <ul style={{ color: \"#ccc\" }}>{this.get_node_jsx(this.props.rootnode)}</ul>\n      </div>\n    );\n  }\n}\n\nexport default FileSystem;\n"
  },
  {
    "path": "gdbgui/src/js/FoldersView.tsx",
    "content": "import React from \"react\";\nimport { store } from \"statorgfc\";\nimport FileOps from \"./FileOps\";\nimport constants from \"./constants\";\nimport SourceFileAutocomplete from \"./SourceFileAutocomplete\";\nimport FileSystem from \"./FileSystem\";\nimport Actions from \"./Actions\";\n\nconst default_rootnode = {\n  name: 'Load inferior program, then click \"Fetch source files\" to populate this window',\n  children: [],\n  toggled: false\n};\n\nfunction get_child_node_with_name(name: any, curnode: any) {\n  if (!curnode.children) {\n    return null;\n  }\n  for (let node of curnode.children) {\n    if (node.name === name) {\n      return node;\n    }\n  }\n  return null;\n}\n\ntype State = any;\n\nclass FoldersView extends React.Component<{}, State> {\n  max_filesystem_entries: any;\n  project_home: any;\n  constructor(props: {}) {\n    super(props);\n    this.state = {\n      rootnode: default_rootnode\n    };\n    // @ts-expect-error ts-migrate(2339) FIXME: Property 'connectComponentState' does not exist on... Remove this comment to see the full error message\n    store.connectComponentState(\n      this,\n      [\"source_code_state\", \"source_file_paths\"],\n      this.update_filesystem_data.bind(this)\n    );\n\n    this.max_filesystem_entries = 300;\n    // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name 'initial_data'.\n    this.project_home = initial_data.project_home; /* global initial_data */\n    this.onToggle = this.onToggle.bind(this);\n    this.onClickName = this.onClickName.bind(this);\n    this.reveal_path = this.reveal_path.bind(this);\n    this.expand_all = this.expand_all.bind(this);\n    this.collapse_all = this.collapse_all.bind(this);\n  }\n\n  render() {\n    let source_code_state = this.state.source_code_state,\n      file_is_rendered =\n        source_code_state === constants.source_code_states.SOURCE_CACHED ||\n        source_code_state === constants.source_code_states.ASSM_AND_SOURCE_CACHED,\n      can_reveal = file_is_rendered && this.state.source_file_paths.length,\n      hiding_entries = this.state.source_file_paths.length > this.max_filesystem_entries;\n\n    return (\n      <div>\n        <button\n          className=\"btn btn-xs btn-primary\"\n          onClick={Actions.fetch_source_files}\n          style={{ marginLeft: \"5px\", marginTop: \"5px\" }}\n        >\n          Fetch source files\n        </button>\n\n        <div style={{ width: \"100%\" }}>\n          <SourceFileAutocomplete />\n        </div>\n        <div role=\"group\" className=\"btn-group btn-group\" style={{ padding: \"4px\" }}>\n          <button className=\"btn btn-xs btn-default\" onClick={this.expand_all}>\n            Expand all\n          </button>\n\n          <button className=\"btn btn-xs btn-default\" onClick={this.collapse_all}>\n            Collapse all\n          </button>\n\n          <button\n            className={\"btn btn-xs btn-default \" + (can_reveal ? \"\" : \"hidden\")}\n            onClick={() => this.reveal_path(store.get(\"fullname_to_render\"))}\n          >\n            Reveal current file\n          </button>\n        </div>\n\n        {store.get(\"source_file_paths\").length ? (\n          <p style={{ color: \"white\", padding: \"4px\" }}>\n            {store.get(\"source_file_paths\").length} known files used to compile the\n            inferior program\n          </p>\n        ) : (\n          \"\"\n        )}\n\n        {hiding_entries ? (\n          <p style={{ color: \"black\", background: \"orange\", padding: \"4px\" }}>\n            Maximum entries in tree below is {this.max_filesystem_entries} (hiding{\" \"}\n            {store.get(\"source_file_paths\").length - this.max_filesystem_entries}). All\n            files can still be searched for in the input above.\n          </p>\n        ) : (\n          \"\"\n        )}\n\n        <FileSystem\n          // @ts-expect-error ts-migrate(2769) FIXME: Property 'rootnode' does not exist on type 'Intrin... Remove this comment to see the full error message\n          rootnode={this.state.rootnode}\n          onToggle={this.onToggle}\n          onClickName={this.onClickName}\n        />\n      </div>\n    );\n  }\n  onClickName(node: any) {\n    let curnode = node,\n      path = [];\n    while (curnode) {\n      if (curnode.name === \"root\") {\n        path.unshift(\"\");\n        break;\n      }\n      // prepend this file/directory to the path\n      path.unshift(curnode.name);\n      // try to prepend the parent\n      curnode = curnode.parent;\n    }\n    if (path.length) {\n      FileOps.user_select_file_to_view(path.join(\"/\"), 1);\n    }\n  }\n  reveal_path(path: any) {\n    if (!path) {\n      return;\n    }\n\n    if (this.state.cursor) {\n      this.state.cursor.active = false;\n    }\n\n    if (this.project_home) {\n      path = path.replace(this.project_home, \"\");\n    }\n\n    let names = path.split(\"/\").filter((n: any) => n !== \"\"),\n      curnode = this.state.rootnode;\n\n    curnode.toggled = true; // expand the root\n    for (let name of names) {\n      curnode = get_child_node_with_name(name, curnode);\n      if (curnode) {\n        curnode.toggled = true;\n      } else {\n        break;\n      }\n    }\n\n    if (curnode) {\n      curnode.active = true;\n    }\n    this.setState({ rootnode: this.state.rootnode, cursor: curnode });\n  }\n  update_filesystem_data(keys: any) {\n    if (keys.indexOf(\"source_file_paths\") === -1) {\n      return;\n    }\n\n    let source_paths = this.state.source_file_paths;\n    if (!Array.isArray(source_paths) || !source_paths.length) {\n      this.setState({\n        rootnode: default_rootnode\n      });\n      return;\n    }\n\n    let rootnode = {\n      name: this.project_home || \"root\",\n      toggled: true,\n      children: []\n    };\n\n    let relative_source_paths = source_paths;\n\n    if (this.project_home) {\n      let project_home = this.project_home;\n      relative_source_paths = source_paths\n        .filter(p => p.startsWith(project_home))\n        .map(p => {\n          p = p.replace(project_home, \"\");\n          return p;\n        });\n    }\n    for (let path of relative_source_paths) {\n      let new_node,\n        names = path.split(\"/\").filter((n: any) => n !== \"\"),\n        curnode = rootnode,\n        // @ts-expect-error ts-migrate(2448) FIXME: Block-scoped variable 'depth' used before its decl... Remove this comment to see the full error message\n        toggled = depth === 0;\n      let depth = 0;\n      for (let name of names) {\n        let child = get_child_node_with_name(name, curnode);\n        if (child) {\n          // found an existing child node, use it\n          curnode = child;\n        } else {\n          // add child and set it to cur node\n          // @ts-expect-error ts-migrate(2322) FIXME: Object literal may only specify known properties, ... Remove this comment to see the full error message\n          new_node = { name: name, toggled: toggled, parent: curnode };\n          if (curnode.children) {\n            // @ts-expect-error ts-migrate(2345) FIXME: Argument of type '{ name: any; toggled: boolean; p... Remove this comment to see the full error message\n            curnode.children.push(new_node);\n          } else {\n            // @ts-expect-error ts-migrate(2322) FIXME: Type '{ name: any; toggled: boolean; parent: { nam... Remove this comment to see the full error message\n            curnode.children = [new_node];\n          }\n          curnode = new_node;\n        }\n\n        depth++;\n      }\n    }\n    this.setState({ rootnode: rootnode });\n  }\n\n  onToggle(node: any) {\n    node.toggled = !node.toggled;\n    this.setState({ rootnode: this.state.rootnode });\n  }\n  expand_all() {\n    let callback = (node: any) => {\n      node.toggled = true;\n    };\n    for (let top_level_child of this.state.rootnode.children) {\n      this._dfs(top_level_child, callback);\n    }\n    this.setState({ rootnode: this.state.rootnode });\n  }\n  collapse_all() {\n    let callback = (node: any) => {\n      node.toggled = false;\n    };\n    for (let top_level_child of this.state.rootnode.children) {\n      this._dfs(top_level_child, callback);\n    }\n    this.setState({ rootnode: this.state.rootnode });\n  }\n  _dfs(node: any, callback: any) {\n    callback(node);\n    if (node.children) {\n      for (let child of node.children) {\n        this._dfs(child, callback);\n      }\n    }\n  }\n}\n\nexport default FoldersView;\n"
  },
  {
    "path": "gdbgui/src/js/GdbApi.tsx",
    "content": "/**\n * An object to manage the websocket connection to the python server that manages gdb,\n * to send various commands to gdb, to and to dispatch gdb responses to gdbgui.\n */\nimport { store } from \"statorgfc\";\nimport Registers from \"./Registers\";\nimport Memory from \"./Memory\";\nimport Actions from \"./Actions\";\nimport GdbVariable from \"./GdbVariable\";\nimport constants from \"./constants\";\nimport process_gdb_response from \"./process_gdb_response\";\nimport React from \"react\";\nimport io from \"socket.io-client\";\nvoid React; // needed when using JSX, but not marked as used\n/* global debug */\n\n// print to console if debug is true\nlet log: {\n  (arg0: string): void;\n  (...data: any[]): void;\n  (message?: any, ...optionalParams: any[]): void;\n  (): void;\n};\n// @ts-expect-error ts-migrate(2304) FIXME: Cannot find name 'debug'.\nif (debug) {\n  log = console.info;\n} else {\n  log = function() {\n    // stubbed out\n  };\n}\n\n/**\n * This object contains methods to interact with\n * gdb, but does not directly render anything in the DOM.\n */\n// @ts-expect-error ts-migrate(2339) FIXME: Property 'initial_data' does not exist on type 'Wi... Remove this comment to see the full error message\nconst initial_data = window.initial_data;\nlet socket: SocketIOClient.Socket;\nconst GdbApi = {\n  getSocket: function() {\n    return socket;\n  },\n  init: function() {\n    const TIMEOUT_MIN = 5;\n    socket = io.connect(`/gdb_listener`, {\n      timeout: TIMEOUT_MIN * 60 * 1000,\n      query: {\n        csrf_token: initial_data.csrf_token,\n        gdbpid: initial_data.gdbpid,\n        gdb_command: initial_data.gdb_command\n      }\n    });\n\n    socket.on(\"connect\", function() {\n      log(\"connected\");\n      const queuedGdbCommands = store.get(\"queuedGdbCommands\");\n      if (queuedGdbCommands) {\n        GdbApi.run_gdb_command(queuedGdbCommands);\n        store.set(\"queuedGdbCommands\", []);\n      }\n    });\n\n    socket.on(\"gdb_response\", function(response_array: any) {\n      // @ts-expect-error ts-migrate(2769) FIXME: Argument of type 'null' is not assignable to param... Remove this comment to see the full error message\n      clearTimeout(GdbApi._waiting_for_response_timeout);\n      store.set(\"waiting_for_response\", false);\n      process_gdb_response(response_array);\n    });\n    socket.on(\"fatal_server_error\", function(data: { message: null | string }) {\n      Actions.add_console_entries(\n        `Message from server: ${data.message}`,\n        constants.console_entry_type.STD_ERR\n      );\n      socket.close();\n    });\n    socket.on(\"error_running_gdb_command\", function(data: { message: any }) {\n      Actions.add_console_entries(\n        `Error occurred on server when running gdb command: ${data.message}`,\n        constants.console_entry_type.STD_ERR\n      );\n      socket.close();\n    });\n\n    socket.on(\"server_error\", function(data: { message: any }) {\n      Actions.add_console_entries(\n        `Server message: ${data.message}`,\n        constants.console_entry_type.STD_ERR\n      );\n    });\n\n    socket.on(\"debug_session_connection_event\", function(gdb_pid_obj: {\n      pid: number;\n      message: string | void;\n      ok: boolean;\n      started_new_gdb_process: boolean;\n    }) {\n      const gdb_pid = gdb_pid_obj.pid;\n      const message = gdb_pid_obj.message;\n      const error = !gdb_pid_obj.ok;\n      const started_new_gdb_process = gdb_pid_obj.started_new_gdb_process;\n\n      if (message) {\n        Actions.add_console_entries(\n          message,\n          error\n            ? constants.console_entry_type.STD_ERR\n            : constants.console_entry_type.GDBGUI_OUTPUT\n        );\n      }\n      if (error) {\n        socket.close();\n        return;\n      }\n      store.set(\"gdb_pid\", gdb_pid);\n\n      if (started_new_gdb_process) {\n        GdbApi.run_initial_commands();\n      } else {\n        Actions.refresh_state_for_gdb_pause();\n      }\n    });\n\n    socket.on(\"disconnect\", function() {\n      // we no longer need to warn the user before they exit the page since the gdb process\n      // on the server is already gone\n      window.onbeforeunload = () => null;\n\n      Actions.show_modal(\n        \"\",\n        <>\n          <p>\n            The connection to the gdb session has been closed. This tab will no longer\n            function as expected.\n          </p>\n          <p className=\"font-bold\">\n            To start a new session or connect to a different session, go to the{\" \"}\n            <a href=\"/dashboard\">dashboard</a>.\n          </p>\n        </>\n      );\n      Actions.add_console_entries(\n        `The connection to the gdb session has been closed. To start a new session, go to ${window.location.origin}/dashboard`,\n        constants.console_entry_type.STD_ERR\n      );\n\n      // if (debug) {\n      //   window.location.reload(true);\n      // }\n    });\n  },\n  _waiting_for_response_timeout: null,\n  click_run_button: function() {\n    Actions.inferior_program_starting();\n    GdbApi.run_gdb_command(\"-exec-run\");\n  },\n  run_initial_commands: function() {\n    const cmds = [\"-list-features\", \"-list-target-features\"];\n    for (const src in initial_data.remap_sources) {\n      const dst = initial_data.remap_sources[src];\n      cmds.push(`set substitute-path \"${src}\" \"${dst}\"`);\n    }\n    GdbApi.run_gdb_command(cmds);\n  },\n  inferior_is_paused: function() {\n    return (\n      [constants.inferior_states.unknown, constants.inferior_states.paused].indexOf(\n        store.get(\"inferior_program\")\n      ) !== -1\n    );\n  },\n  click_continue_button: function(reverse = false) {\n    Actions.inferior_program_resuming();\n    GdbApi.run_gdb_command(\n      \"-exec-continue\" + (store.get(\"debug_in_reverse\") || reverse ? \" --reverse\" : \"\")\n    );\n  },\n  click_next_button: function(reverse = false) {\n    Actions.inferior_program_resuming();\n    GdbApi.run_gdb_command(\n      \"-exec-next\" + (store.get(\"debug_in_reverse\") || reverse ? \" --reverse\" : \"\")\n    );\n  },\n  click_step_button: function(reverse = false) {\n    Actions.inferior_program_resuming();\n    GdbApi.run_gdb_command(\n      \"-exec-step\" + (store.get(\"debug_in_reverse\") || reverse ? \" --reverse\" : \"\")\n    );\n  },\n  click_return_button: function() {\n    // From gdb mi docs (https://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Program-Execution.html#GDB_002fMI-Program-Execution):\n    // `-exec-return` Makes current function return immediately. Doesn't execute the inferior.\n    // That means we do NOT dispatch the event `event_inferior_program_resuming`, because it's not, in fact, running.\n    // The return also doesn't even indicate that it's paused, so we need to manually trigger the event here.\n    GdbApi.run_gdb_command(\"-exec-return\");\n    Actions.inferior_program_paused();\n  },\n  click_next_instruction_button: function(reverse = false) {\n    Actions.inferior_program_resuming();\n    GdbApi.run_gdb_command(\n      \"-exec-next-instruction\" +\n        (store.get(\"debug_in_reverse\") || reverse ? \" --reverse\" : \"\")\n    );\n  },\n  click_step_instruction_button: function(reverse = false) {\n    Actions.inferior_program_resuming();\n    GdbApi.run_gdb_command(\n      \"-exec-step-instruction\" +\n        (store.get(\"debug_in_reverse\") || reverse ? \" --reverse\" : \"\")\n    );\n  },\n  click_send_interrupt_button: function() {\n    Actions.inferior_program_resuming();\n    GdbApi.run_gdb_command(\"-exec-interrupt\");\n  },\n  send_autocomplete_command: function(command: string) {\n    Actions.inferior_program_resuming();\n    GdbApi.run_gdb_command(\"complete \" + command);\n  },\n  click_gdb_cmd_button: function(e: {\n    currentTarget: { dataset: { [x: string]: any; cmd: undefined; cmd0: undefined } };\n  }) {\n    if (e.currentTarget.dataset.cmd !== undefined) {\n      // run single command\n      // i.e. <a data-cmd='cmd' />\n      GdbApi.run_gdb_command(e.currentTarget.dataset.cmd);\n    } else if (e.currentTarget.dataset.cmd0 !== undefined) {\n      // run multiple commands\n      // i.e. <a data-cmd0='cmd 0' data-cmd1='cmd 1' data-...>\n      let cmds = [];\n      let i = 0;\n      let cmd = e.currentTarget.dataset[`cmd${i}`];\n      // extract all commands into an array, then run them\n      // (max of 100 commands)\n      while (cmd !== undefined && i < 100) {\n        cmds.push(cmd);\n        i++;\n        cmd = e.currentTarget.dataset[`cmd${i}`];\n      }\n      GdbApi.run_gdb_command(cmds);\n    } else {\n      console.error(\n        \"expected cmd or cmd0 [cmd1, cmd2, ...] data attribute(s) on element\"\n      );\n    }\n  },\n  select_frame: function(framenum: any) {\n    // TODO this command is deprecated (https://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Stack-Manipulation.html)\n    // This command in deprecated in favor of passing the ‘--frame’ option to every command.\n    GdbApi.run_command_and_refresh_state(`-stack-select-frame ${framenum}`);\n  },\n  select_thread_id: function(thread_id: any) {\n    // TODO this command is deprecated (http://www.sourceware.org/gdb/current/onlinedocs/gdb/GDB_002fMI-Thread-Commands.html)\n    // This command is deprecated in favor of explicitly using the ‘--thread’ option to each command.\n    GdbApi.run_command_and_refresh_state(`-thread-select ${thread_id}`);\n  },\n  /**\n   * Before sending a command, set a timeout to notify the user that something might be wrong\n   * if a response from gdb is not received\n   */\n  waiting_for_response: function() {\n    store.set(\"waiting_for_response\", true);\n    const WAIT_TIME_SEC = 10;\n    // @ts-expect-error ts-migrate(2769) FIXME: Argument of type 'null' is not assignable to param... Remove this comment to see the full error message\n    clearTimeout(GdbApi._waiting_for_response_timeout);\n    // @ts-expect-error ts-migrate(2322) FIXME: Type 'Timeout' is not assignable to type 'null'.\n    GdbApi._waiting_for_response_timeout = setTimeout(() => {\n      Actions.clear_program_state();\n      store.set(\"waiting_for_response\", false);\n      if (GdbApi.getSocket().disconnected) {\n        return;\n      }\n\n      Actions.add_console_entries(\n        `No gdb response received after ${WAIT_TIME_SEC} seconds.`,\n        constants.console_entry_type.GDBGUI_OUTPUT\n      );\n      Actions.add_console_entries(\n        \"Possible reasons include:\",\n        constants.console_entry_type.GDBGUI_OUTPUT\n      );\n      Actions.add_console_entries(\n        \"1) gdbgui, gdb, or the debugged process is not running.\",\n        constants.console_entry_type.GDBGUI_OUTPUT\n      );\n\n      Actions.add_console_entries(\n        \"2) gdb or the inferior process is busy running and needs to be \" +\n          \"interrupted (press the pause button up top).\",\n        constants.console_entry_type.GDBGUI_OUTPUT\n      );\n\n      Actions.add_console_entries(\n        \"3) Something is just taking a long time to finish and respond back to \" +\n          \"this browser window, in which case you can just keep waiting.\",\n        constants.console_entry_type.GDBGUI_OUTPUT\n      );\n    }, WAIT_TIME_SEC * 1000);\n  },\n  /**\n   * runs a gdb cmd (or commands) directly in gdb on the backend\n   * validates command before sending, and updates the gdb console and status bar\n   * @param cmd: a string or array of strings, that are directly evaluated by gdb\n   * @return nothing\n   */\n  run_gdb_command: function(cmd: any) {\n    // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name '_'.\n    if (_.trim(cmd) === \"\") {\n      return;\n    }\n\n    let cmds = cmd;\n    // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name '_'.\n    if (_.isString(cmds)) {\n      cmds = [cmds];\n    }\n\n    if (socket.connected) {\n      socket.emit(\"run_gdb_command\", { cmd: cmds });\n      GdbApi.waiting_for_response();\n      // add the send command to the console to show commands that are\n      // automatically run by gdb\n      if (store.get(\"show_all_sent_commands_in_console\")) {\n        Actions.add_console_entries(cmds, constants.console_entry_type.SENT_COMMAND);\n      }\n    } else {\n      log(\"queuing commands\");\n      const queuedGdbCommands = store.get(\"queuedGdbCommands\").concat(cmds);\n      store.set(\"queuedGdbCommands\", queuedGdbCommands);\n    }\n  },\n  run_command_and_refresh_state: function(user_cmd: string | any[]) {\n    let cmds: any[] = [];\n    if (Array.isArray(user_cmd)) {\n      cmds = cmds.concat(user_cmd);\n      // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name '_'.\n    } else if (_.isString(user_cmd) && user_cmd.length > 0) {\n      cmds.push(user_cmd);\n    }\n    cmds = cmds.concat(GdbApi._get_refresh_state_for_pause_cmds());\n    GdbApi.run_gdb_command(cmds);\n  },\n  backtrace: function() {\n    let cmds = [\"backtrace\"];\n    cmds = cmds.concat(GdbApi._get_refresh_state_for_pause_cmds());\n    store.set(\"inferior_program\", constants.inferior_states.paused);\n    GdbApi.run_gdb_command(cmds);\n  },\n  /**\n   * Get array of commands to send to gdb that refreshes everything in the\n   * frontend\n   */\n  _get_refresh_state_for_pause_cmds: function() {\n    let cmds = [\n      // get info on current thread\n      // TODO run -thread-list-ids to store list of thread id's and know\n      // which thread is the current thread\n      constants.IGNORE_ERRORS_TOKEN_STR + \"-thread-info\",\n      // print the name, type and value for simple data types,\n      // and the name and type for arrays, structures and unions.\n      constants.IGNORE_ERRORS_TOKEN_STR + \"-stack-list-variables --simple-values\"\n    ];\n    // update all user-defined variables in gdb\n    cmds.push(constants.IGNORE_ERRORS_TOKEN_STR + \"-var-update --all-values *\");\n\n    // update registers\n    cmds = cmds.concat(Registers.get_update_cmds());\n\n    // re-fetch memory over desired range as specified by DOM inputs\n    cmds = cmds.concat(Memory.get_gdb_commands_from_state());\n\n    // refresh breakpoints\n    cmds.push(GdbApi.get_break_list_cmd());\n\n    // List the frames currently on the stack.\n    // avoid the \"no registers\" error\n    cmds.push(constants.IGNORE_ERRORS_TOKEN_STR + \"-stack-list-frames\");\n    return cmds;\n  },\n  refresh_breakpoints: function() {\n    GdbApi.run_gdb_command([GdbApi.get_break_list_cmd()]);\n  },\n  get_inferior_binary_last_modified_unix_sec(path: any) {\n    $.ajax({\n      beforeSend: function(xhr: { setRequestHeader: (arg0: string, arg1: any) => void }) {\n        xhr.setRequestHeader(\"x-csrftoken\", initial_data.csrf_token);\n      },\n      url: \"/get_last_modified_unix_sec\",\n      cache: false,\n      method: \"GET\",\n      data: { path: path },\n      success: GdbApi._recieve_last_modified_unix_sec,\n      error: GdbApi._error_getting_last_modified_unix_sec\n    });\n  },\n  get_insert_break_cmd: function(fullname: any, line: any) {\n    return [`-break-insert \"${fullname}:${line}\"`];\n  },\n  get_delete_break_cmd: function(bkpt_num: any) {\n    return `-break-delete ${bkpt_num}`;\n  },\n  get_break_list_cmd: function() {\n    return \"-break-list\";\n  },\n  get_load_binary_and_arguments_cmds(binary: any, args: any) {\n    // tell gdb which arguments to use when calling the binary, before loading the binary\n    let cmds = [\n      `-exec-arguments ${args}`, // Set the inferior program arguments, to be used in the next `-exec-run`\n      `-file-exec-and-symbols ${binary}` // Specify the executable file to be debugged. This file is the one from which the symbol table is also read.\n    ];\n    // add breakpoint if we don't already have one\n    if (store.get(\"auto_add_breakpoint_to_main\")) {\n      cmds.push(\"-break-insert main\");\n    }\n    cmds.push(GdbApi.get_break_list_cmd());\n    return cmds;\n  },\n  set_assembly_flavor(flavor: string) {\n    GdbApi.run_gdb_command(`set disassembly-flavor ${flavor}`);\n  },\n  _recieve_last_modified_unix_sec(data: { path: any; last_modified_unix_sec: any }) {\n    if (data.path === store.get(\"inferior_binary_path\")) {\n      store.set(\n        \"inferior_binary_path_last_modified_unix_sec\",\n        data.last_modified_unix_sec\n      );\n    }\n  },\n  _error_getting_last_modified_unix_sec(data: any) {\n    void data;\n    store.set(\"inferior_binary_path\", null);\n  }\n};\n// @ts-expect-error ts-migrate(2339) FIXME: Property 'socket' does not exist on type '{ getSoc... Remove this comment to see the full error message\nGdbApi.socket = socket;\nexport default GdbApi;\n"
  },
  {
    "path": "gdbgui/src/js/GdbMiOutput.tsx",
    "content": "/**\n * A component to display, in gory detail, what is\n * returned from gdb's machine interface. This displays the\n * data source that is fed to all components and UI elements\n * in gdb gui, and is useful when debugging gdbgui, or\n * a command that failed but didn't have a useful failure\n * message in gdbgui.\n */\nimport React from \"react\";\nimport { store } from \"statorgfc\";\n\ntype State = any;\n\nclass GdbMiOutput extends React.Component<{}, State> {\n  static MAX_OUTPUT_ENTRIES = 500;\n  _debounced_scroll_to_bottom: any;\n  el: any;\n  constructor() {\n    // @ts-expect-error ts-migrate(2554) FIXME: Expected 1-2 arguments, but got 0.\n    super();\n    // @ts-expect-error ts-migrate(2339) FIXME: Property 'connectComponentState' does not exist on... Remove this comment to see the full error message\n    store.connectComponentState(this, [\"gdb_mi_output\"]);\n    // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name '_'.\n    this._debounced_scroll_to_bottom = _.debounce(\n      this._scroll_to_bottom.bind(this),\n      300,\n      {\n        leading: true\n      }\n    );\n  }\n  render() {\n    return (\n      <div>\n        <button\n          title=\"clear all mi output\"\n          className=\"pointer btn btn-default btn-xs\"\n          onClick={() => store.set(\"gdb_mi_output\", [])}\n        >\n          clear output\n          <span className=\"glyphicon glyphicon-ban-circle pointer\" />\n        </button>\n        <div id=\"gdb_mi_output\" className=\"otpt\" style={{ fontSize: \"0.8em\" }}>\n          {this.state.gdb_mi_output}\n        </div>\n      </div>\n    );\n  }\n  componentDidMount() {\n    this.el = document.getElementById(\"gdb_mi_output\");\n  }\n  componentDidUpdate() {\n    this._debounced_scroll_to_bottom();\n  }\n  _scroll_to_bottom() {\n    this.el.scrollTop = this.el.scrollHeight;\n  }\n  static add_mi_output(mi_obj: any) {\n    let new_str = JSON.stringify(mi_obj, null, 4)\n        // @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.\n        .replace(/[^(\\\\)]\\\\n/g)\n        .replace(\"<\", \"&lt;\")\n        .replace(\">\", \"&gt;\"),\n      gdb_mi_output = store.get(\"gdb_mi_output\");\n\n    while (gdb_mi_output.length > GdbMiOutput.MAX_OUTPUT_ENTRIES) {\n      gdb_mi_output.shift();\n    }\n    gdb_mi_output.push(new_str);\n\n    store.set(\"gdb_mi_output\", gdb_mi_output);\n  }\n}\n\nexport default GdbMiOutput;\n"
  },
  {
    "path": "gdbgui/src/js/GdbVariable.tsx",
    "content": "/**\n * A component to render gdb user variables, and\n * some library functions to interact with gdb. The library\n * functions create gdb variable objects locally, update them,\n * remove them, etc.\n */\nimport React from \"react\";\nimport Memory from \"./Memory\";\nimport constants from \"./constants\";\nimport { store } from \"statorgfc\";\nimport GdbApi from \"./GdbApi\";\nimport CopyToClipboard from \"./CopyToClipboard\";\nimport Actions from \"./Actions\";\n\n/**\n * Simple object to manage fetching of child variables. Maintains a queue of parent expressions\n * to fetch children for, and fetches them in serial.\n */\nlet ChildVarFetcher = {\n  expr_gdb_parent_var_currently_fetching_children: null, // parent gdb variable name (i.e. var7)\n  _is_fetching: false,\n  _queue: [], // objects with keys 'expr_gdb_parent_var_currently_fetching_children' and 'expr_type'\n  _fetch_next_in_queue: function() {\n    if (ChildVarFetcher._is_fetching) {\n      return;\n    }\n    if (ChildVarFetcher._queue.length) {\n      let obj = ChildVarFetcher._queue.shift();\n      ChildVarFetcher.expr_gdb_parent_var_currently_fetching_children =\n        // @ts-expect-error ts-migrate(2532) FIXME: Object is possibly 'undefined'.\n        obj.expr_of_parent;\n      ChildVarFetcher._is_fetching = true;\n      // @ts-expect-error ts-migrate(2532) FIXME: Object is possibly 'undefined'.\n      GdbApi.run_gdb_command(`-var-list-children --all-values \"${obj.expr_of_parent}\"`);\n    } else {\n      ChildVarFetcher.expr_gdb_parent_var_currently_fetching_children = null;\n    }\n  },\n  fetch_children(expr_of_parent: any, expr_type: any) {\n    // @ts-expect-error ts-migrate(2322) FIXME: Type 'any' is not assignable to type 'never'.\n    ChildVarFetcher._queue.push({ expr_of_parent: expr_of_parent, expr_type: expr_type });\n    ChildVarFetcher._fetch_next_in_queue();\n  },\n  fetch_complete() {\n    ChildVarFetcher._is_fetching = false;\n    ChildVarFetcher.expr_gdb_parent_var_currently_fetching_children = null;\n    ChildVarFetcher._fetch_next_in_queue();\n  }\n};\n\n/**\n * Simple object to manage fetching of variables. Maintains a queue of expressions\n * to fetch, and fetches them in serial.\n */\nlet VarCreator = {\n  _queue: [], // list of objs with keys expr_being_created, expr_type\n  _is_fetching: false,\n  expr_being_created: null,\n  expr_type: null,\n\n  _fetch_next_in_queue: function() {\n    if (VarCreator._is_fetching) {\n      return;\n    }\n    if (VarCreator._queue.length) {\n      let obj = VarCreator._queue.shift(),\n        // @ts-expect-error ts-migrate(2532) FIXME: Object is possibly 'undefined'.\n        expression = obj.expression,\n        // @ts-expect-error ts-migrate(2532) FIXME: Object is possibly 'undefined'.\n        expr_type = obj.expr_type;\n\n      VarCreator._is_fetching = true;\n\n      VarCreator.expr_being_created = expression;\n      VarCreator.expr_type = expr_type;\n\n      // surround in quotes if we found a quote\n      if (expression.length > 0 && expression.indexOf('\"') !== 0) {\n        expression = '\"' + expression + '\"';\n      }\n      let cmds = [];\n      if (store.get(\"pretty_print\")) {\n        cmds.push(\"-enable-pretty-printing\");\n      }\n\n      // - means auto assign variable name in gdb\n      // * means evaluate it at the current frame\n      let var_create_cmd = constants.CREATE_VAR_STR + `-var-create - * ${expression}`;\n      cmds.push(var_create_cmd);\n\n      GdbApi.run_gdb_command(cmds);\n    } else {\n      VarCreator._clear_state();\n    }\n  },\n  /**\n   * Create a new variable in gdb. gdb automatically chooses and assigns\n   * a unique variable name.\n   */\n  create_variable: function(expression: any, expr_type: any) {\n    // @ts-expect-error ts-migrate(2322) FIXME: Type 'any' is not assignable to type 'never'.\n    VarCreator._queue.push({ expression: expression, expr_type: expr_type });\n    VarCreator._fetch_next_in_queue();\n  },\n  /**\n   * After a variable is created, we need to link the gdb\n   * variable name (which is automatically created by gdb),\n   * and the expression the user wanted to evailuate. The\n   * new variable is saved locally. The variable UI element is then re-rendered\n   * @param r (object): gdb mi object\n   */\n  created_variable(r: any) {\n    let expr = VarCreator.expr_being_created;\n    if (expr) {\n      // example payload:\n      // \"payload\": {\n      //      \"has_more\": \"0\",\n      //      \"name\": \"var2\",\n      //      \"numchild\": \"0\",\n      //      \"thread-id\": \"1\",\n      //      \"type\": \"int\",\n      //      \"value\": \"0\"\n      //  },\n      GdbVariable.save_new_expression(expr, VarCreator.expr_type, r.payload);\n      VarCreator.expr_being_created = null;\n      // automatically fetch first level of children for root variables\n      GdbVariable.fetch_and_show_children_for_var(r.payload.name);\n    } else {\n      // gdbgui did not expect a new variable to be created here\n      // it's likely this tab is viewing an instance of gdb that multiple users\n      // are interacting with\n    }\n    VarCreator._fetch_complete();\n  },\n  fetch_failed(r: any) {\n    if (VarCreator.expr_type === \"hover\") {\n      // do nothing\n    } else {\n      Actions.add_gdb_response_to_console(r);\n    }\n    VarCreator._fetch_complete();\n  },\n  _fetch_complete() {\n    VarCreator._is_fetching = false;\n    VarCreator._clear_state();\n    VarCreator._fetch_next_in_queue();\n  },\n  _clear_state: function() {\n    VarCreator._is_fetching = false;\n  }\n};\n\nclass GdbVariable extends React.Component {\n  render() {\n    const is_root = true;\n\n    // @ts-expect-error ts-migrate(2339) FIXME: Property 'expr_type' does not exist on type 'Reado... Remove this comment to see the full error message\n    if (this.props.expr_type === \"local\") {\n      // @ts-expect-error ts-migrate(2339) FIXME: Property 'obj' does not exist on type 'Readonly<{}... Remove this comment to see the full error message\n      return this.get_ul_for_local(this.props.obj);\n    } else {\n      // @ts-expect-error ts-migrate(2339) FIXME: Property 'obj' does not exist on type 'Readonly<{}... Remove this comment to see the full error message\n      if (this.props.obj.numchild > 0) {\n        return this.get_ul_for_var_with_children(\n          // @ts-expect-error ts-migrate(2339) FIXME: Property 'expression' does not exist on type 'Read... Remove this comment to see the full error message\n          this.props.expression,\n          // @ts-expect-error ts-migrate(2339) FIXME: Property 'obj' does not exist on type 'Readonly<{}... Remove this comment to see the full error message\n          this.props.obj,\n          // @ts-expect-error ts-migrate(2339) FIXME: Property 'expr_type' does not exist on type 'Reado... Remove this comment to see the full error message\n          this.props.expr_type,\n          is_root\n        );\n      } else {\n        return this.get_ul_for_var_without_children(\n          // @ts-expect-error ts-migrate(2339) FIXME: Property 'expression' does not exist on type 'Read... Remove this comment to see the full error message\n          this.props.expression,\n          // @ts-expect-error ts-migrate(2339) FIXME: Property 'obj' does not exist on type 'Readonly<{}... Remove this comment to see the full error message\n          this.props.obj,\n          // @ts-expect-error ts-migrate(2339) FIXME: Property 'expr_type' does not exist on type 'Reado... Remove this comment to see the full error message\n          this.props.expr_type,\n          is_root\n        );\n      }\n    }\n  }\n  /**\n   * get unordered list for a \"local\" returned by gdb\n   * these are special snowflakes; gdb returns a small subset of information for\n   * locals. The list is useful to browse, but oftentimes needs to be expanded.\n   * If the user clicks on a local that can be expanded, gdbgui will ask gdb\n   * to create a full-fledged variable for the user to explore. gdbgui will then\n   * render that instead of the \"local\".\n   */\n  get_ul_for_local(local: any) {\n    let can_be_expanded = local.can_be_expanded,\n      // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name '_'.\n      value = _.isString(local.value)\n        ? Memory.make_addrs_into_links_react(local.value)\n        : local.value,\n      onclick = can_be_expanded\n        ? () => GdbVariable.create_variable(local.name, \"local\")\n        : () => {};\n\n    return (\n      <div>\n        <span onClick={onclick} className={can_be_expanded ? \"pointer\" : \"\"}>\n          {can_be_expanded ? \"+\" : \"\"} {local.name}&nbsp;\n        </span>\n        {value}\n\n        {/* @ts-expect-error ts-migrate(2304) FIXME: Cannot find name '_'. */}\n        <span className=\"var_type\">{_.trim(local.type)}</span>\n      </div>\n    );\n  }\n  /**\n   * get unordered list for a variable that has children\n   * @return unordered list, expanded or collapsed based on the key \"show_children_in_ui\"\n   */\n  get_ul_for_var_with_children(\n    expression: any,\n    mi_obj: any,\n    expr_type: any,\n    is_root = false\n  ) {\n    let child_tree;\n    if (mi_obj.show_children_in_ui) {\n      let content = [];\n      if (mi_obj.children.length > 0) {\n        for (let child of mi_obj.children) {\n          if (child.numchild > 0) {\n            content.push(\n              <li key={child.exp}>\n                {this.get_ul_for_var_with_children(child.exp, child, expr_type)}\n              </li>\n            );\n          } else {\n            content.push(\n              <li key={child.exp}>\n                {this.get_ul_for_var_without_children(child.exp, child, expr_type)}\n              </li>\n            );\n          }\n        }\n      }\n\n      child_tree = <ul key={mi_obj.exp}>{content}</ul>;\n    } else {\n      child_tree = \"\";\n    }\n\n    let plus_or_minus = mi_obj.show_children_in_ui ? \"-\" : \"+\";\n    return this._get_ul_for_var(\n      expression,\n      mi_obj,\n      expr_type,\n      is_root,\n      plus_or_minus,\n      // @ts-expect-error ts-migrate(2345) FIXME: Type 'Element' is not assignable to type 'string'.\n      child_tree,\n      mi_obj.numchild\n    );\n  }\n  get_ul_for_var_without_children(\n    expression: any,\n    mi_obj: any,\n    expr_type: any,\n    is_root = false\n  ) {\n    return this._get_ul_for_var(expression, mi_obj, expr_type, is_root);\n  }\n  static _get_value_jsx(obj: any) {\n    let val;\n    if (obj.is_int) {\n      val = (\n        <div className=\"inline\">\n          <span className=\"gdbVarValue\">\n            {Memory.make_addrs_into_links_react(obj._int_value_to_str_in_radix)}\n            <button\n              className=\"btn btn-default btn-xs btn-radix\"\n              onClick={() => {\n                GdbVariable.change_radix(obj);\n              }}\n              title=\"click to change radix\"\n              style={{ fontSize: \"60%\" }}\n            >\n              base {obj._radix}\n            </button>\n          </span>\n        </div>\n      );\n    } else {\n      // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name '_'.\n      val = _.isString(obj.value)\n        ? Memory.make_addrs_into_links_react(obj.value)\n        : obj.value;\n    }\n    return val;\n  }\n  static change_radix(obj: any) {\n    if (obj._radix === 16) {\n      obj._radix = 2;\n    } else {\n      obj._radix += 2;\n    }\n    GdbVariable._update_radix_values(obj);\n    store.set(\"expressions\", store.get(\"expressions\"));\n  }\n  /**\n   * Get ul for a variable with or without children\n   */\n  _get_ul_for_var(\n    expression: any,\n    mi_obj: any,\n    expr_type: any,\n    is_root: any,\n    plus_or_minus = \"\",\n    child_tree = \"\",\n    numchild = 0\n  ) {\n    let glyph_style = { fontSize: \"0.8em\", paddingLeft: \"5px\" },\n      delete_button =\n        is_root && expr_type === \"expr\" ? (\n          <span\n            style={glyph_style}\n            className=\"glyphicon glyphicon-trash pointer\"\n            onClick={() => GdbVariable.delete_gdb_variable(mi_obj.name)}\n          />\n        ) : (\n          \"\"\n        ),\n      has_children = numchild > 0,\n      can_draw_tree = has_children && (expr_type === \"expr\" || expr_type === \"local\"), // hover var can't draw tree\n      tree = can_draw_tree ? (\n        <span\n          style={glyph_style}\n          className=\"glyphicon glyphicon-tree-deciduous pointer\"\n          onClick={() => GdbVariable.click_draw_tree_gdb_variable(mi_obj.name)}\n        />\n      ) : (\n        \"\"\n      ),\n      toggle_classes = has_children ? \"pointer\" : \"\",\n      plot_content = \"\",\n      plot_button = \"\",\n      plusminus_click_callback = has_children\n        ? () => GdbVariable.click_toggle_children_visibility(mi_obj.name)\n        : () => {};\n    if (mi_obj.can_plot && mi_obj.show_plot) {\n      // dots are not allowed in the dom as id's. replace with '-'.\n      let id = mi_obj.dom_id_for_plot;\n      // @ts-expect-error ts-migrate(2322) FIXME: Type 'Element' is not assignable to type 'string'.\n      plot_button = (\n        <span\n          style={glyph_style}\n          className=\"pointer glyphicon glyphicon-ban-circle\"\n          onClick={() => GdbVariable.click_toggle_plot(mi_obj.name)}\n          title=\"remove x/y plot\"\n        />\n      );\n      // @ts-expect-error ts-migrate(2322) FIXME: Type 'Element' is not assignable to type 'string'.\n      plot_content = <div id={id} className=\"plot\" />;\n    } else if (mi_obj.can_plot && !mi_obj.show_plot) {\n      // @ts-expect-error ts-migrate(2322) FIXME: Type 'Element' is not assignable to type 'string'.\n      plot_button = (\n        <span\n          style={glyph_style}\n          className=\"glyphicon glyphicon glyphicon-equalizer pointer\"\n          onClick={() => GdbVariable.click_toggle_plot(mi_obj.name)}\n          title=\"show x/y plot\"\n        />\n      );\n    }\n\n    return (\n      <ul key={expression} className=\"varUL\">\n        <li className=\"varLI\">\n          <span className={toggle_classes} onClick={plusminus_click_callback}>\n            {plus_or_minus} {expression}&nbsp;\n          </span>\n\n          {GdbVariable._get_value_jsx(mi_obj)}\n\n          {/* @ts-expect-error ts-migrate(2304) FIXME: Cannot find name '_'. */}\n          <span className=\"var_type\">{_.trim(mi_obj.type) || \"\"}</span>\n\n          <div className=\"right_help_icon_show_on_hover\">\n            <CopyToClipboard content={GdbVariable._get_full_path(mi_obj)} />:{tree}\n            {plot_button}\n            {delete_button}\n          </div>\n\n          {plot_content}\n        </li>\n        {child_tree}\n      </ul>\n    );\n  }\n  static _get_full_path(obj: any) {\n    if (!obj) {\n      return \"\";\n    }\n\n    function update_path(path: any, obj: any) {\n      let potential_addition = obj.expression || obj.exp;\n      if (\n        potential_addition === \"public\" ||\n        potential_addition === \"private\" ||\n        potential_addition === \"protected\"\n      ) {\n        // these are inserted by gdb, and arent actually field names!\n        return path;\n      } else if (path) {\n        return potential_addition + \".\" + path;\n      } else {\n        return potential_addition;\n      }\n    }\n\n    let path = update_path(\"\", obj);\n    let cur_obj = obj.parent;\n    let depth = 0;\n    while (cur_obj) {\n      path = update_path(path, cur_obj);\n      cur_obj = cur_obj.parent;\n\n      depth += 1;\n      if (depth > 100) {\n        console.warn(\"exceeded maximum depth, breaking while loop\");\n        break;\n      }\n    }\n    return path;\n  }\n  static create_variable(expression: any, expr_type: any) {\n    VarCreator.create_variable(expression, expr_type);\n  }\n  static gdb_created_root_variable(r: any) {\n    VarCreator.created_variable(r);\n  }\n  static gdb_variable_fetch_failed(r: any) {\n    VarCreator.fetch_failed(r);\n  }\n  /**\n   * Got data regarding children of a gdb variable. It could be an immediate child, or grandchild, etc.\n   * This method stores this child array data to the appropriate locally stored\n   * object\n   * @param r (object): gdb mi object\n   */\n  static gdb_created_children_variables(r: any) {\n    // example reponse payload:\n    // \"payload\": {\n    //         \"has_more\": \"0\",\n    //         \"numchild\": \"2\",\n    //         \"children\": [\n    //             {\n    //                 \"name\": \"var9.a\",\n    //                 \"thread-id\": \"1\",\n    //                 \"numchild\": \"0\",\n    //                 \"value\": \"4195840\",\n    //                 \"exp\": \"a\",\n    //                 \"type\": \"int\"\n    //             }\n    //             {\n    //                 \"name\": \"var9.b\",\n    //                 \"thread-id\": \"1\",\n    //                 \"numchild\": \"0\",\n    //                 \"value\": \"0\",\n    //                 \"exp\": \"b\",\n    //                 \"type\": \"float\"\n    //             }\n    //         ]\n    //     }\n\n    let parent_name = ChildVarFetcher.expr_gdb_parent_var_currently_fetching_children;\n    if (!parent_name) {\n      // gdb created child variable, but the parent variable is unknown\n      // it's likely another tab interacting w/ the same gdb instance created this\n    }\n    ChildVarFetcher.fetch_complete();\n\n    // get the parent object of these children\n    let expressions = store.get(\"expressions\");\n    let parent_obj = GdbVariable.get_obj_from_gdb_var_name(expressions, parent_name);\n    if (parent_obj) {\n      // prepare all the child objects we received for local storage\n      let children = r.payload.children.map((child_obj: any) =>\n        GdbVariable.prepare_gdb_obj_for_storage(child_obj, parent_obj)\n      );\n      // save these children as a field to their parent\n      parent_obj.children = children;\n      parent_obj.numchild = children.length;\n      store.set(\"expressions\", expressions);\n\n      // if this field is an anonymous struct, the user will want to\n      // see this expanded by default\n      for (let child of parent_obj.children) {\n        if (child.exp.includes(\"<anonymous\")) {\n          GdbVariable.fetch_and_show_children_for_var(child.name);\n        }\n      }\n    } else {\n      // gdbgui did not expect this.\n      // another browser tab interacting w/ the same gdb instance likely created this\n    }\n  }\n  /**\n   * gdb returns objects for its variables,, but before we save that\n   * data locally, we will add more fields to make it more useful for gdbgui\n   * @param obj (object): mi object returned from gdb\n   * @param expr_type (str): type of expression being created (see store creation for documentation)\n   */\n  static prepare_gdb_obj_for_storage(obj: any, parent: any) {\n    let new_obj = Object.assign({}, obj);\n    // obj was copied, now add some additional fields used by gdbgui\n\n    new_obj.parent = parent;\n    // A varobj's contents may be provided by a Python-based pretty-printer.\n    // In this case the varobj is known as a dynamic varobj.\n    // Dynamic varobjs have slightly different semantics in some cases.\n    // https://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Variable-Objects.html#GDB_002fMI-Variable-Objects\n    new_obj.numchild = obj.dynamic ? parseInt(obj.has_more) : parseInt(obj.numchild);\n    new_obj.children = []; // actual child objects are fetched dynamically when the user requests them\n    new_obj.show_children_in_ui = false;\n\n    // this field is not returned when the variable is created, but\n    // it is returned when the variables are updated\n    // it is returned by gdb mi as a string, and we assume it starts out in scope\n    new_obj.in_scope = \"true\";\n    new_obj.expr_type = VarCreator.expr_type;\n\n    GdbVariable._update_numeric_properties(new_obj);\n\n    new_obj.dom_id_for_plot = new_obj.name\n      .replace(/\\./g, \"-\") // replace '.' with '-'\n      .replace(/\\$/g, \"_\") // replace '$' with '-'\n      .replace(/\\[/g, \"_\") // replace '[' with '_'\n      .replace(/\\]/g, \"_\"); // replace ']' with '_'\n    new_obj.show_plot = false; // used when rendering to decide whether to show plot or not\n    // push to this array each time a new value is assigned if value is numeric.\n    // Plots use this data\n    if (new_obj.value.indexOf(\"0x\") === 0) {\n      new_obj.values = [parseInt(new_obj.value, 16)];\n      new_obj._radix = 16;\n    } else if (!window.isNaN(parseFloat(new_obj.value))) {\n      new_obj.values = [parseFloat(new_obj.value)];\n      if (new_obj.is_int) {\n        new_obj._radix = 10;\n      } else {\n        new_obj._radix = 0;\n      }\n    } else {\n      new_obj.values = [];\n      new_obj._radix = 0;\n    }\n    GdbVariable._update_radix_values(new_obj); // mutates new_obj\n    return new_obj;\n  }\n  static _update_numeric_properties(obj: any) {\n    let value = obj.value;\n    if (obj.value.startsWith(\"0x\")) {\n      value = parseInt(obj.value, 16);\n    }\n    obj._float_value = parseFloat(value);\n    obj.is_numeric = !window.isNaN(obj._float_value);\n    obj.can_plot = obj.is_numeric && obj.expr_type === \"expr\";\n    obj.is_int = obj.is_numeric ? obj._float_value % 1 === 0 : false;\n  }\n  static _update_radix_values(obj: any) {\n    if (obj.is_int) {\n      obj._int_value_decimal = parseInt(obj.value);\n      if (obj._radix < 2 || obj._radix > 36) {\n        // defensive programming\n        console.warn(\"Got invalid radix. Setting to 10.\");\n        obj._radix = 10;\n      }\n      obj._int_value_to_str_in_radix = obj._int_value_decimal.toString(obj._radix);\n      if (obj._radix === 16) {\n        obj._int_value_to_str_in_radix = \"0x\" + obj._int_value_to_str_in_radix;\n      }\n    }\n  }\n  /**\n   * function render a plot on an existing element\n   * @param obj: object to make a plot for\n   */\n  static _make_plot(obj: any) {\n    let id = \"#\" + obj.dom_id_for_plot, // this div should have been created already\n      jq = $(id),\n      data = [],\n      i = 0;\n\n    // collect data\n    for (let val of obj.values) {\n      data.push([i, val]);\n      i++;\n    }\n\n    // make the plot\n    // @ts-expect-error ts-migrate(2339) FIXME: Property 'plot' does not exist on type 'JQueryStat... Remove this comment to see the full error message\n    $.plot(\n      jq,\n      [\n        {\n          data: data,\n          shadowSize: 0,\n          color: \"#33cdff\"\n        }\n      ],\n      {\n        series: {\n          lines: { show: true },\n          points: { show: true }\n        },\n        grid: { hoverable: true, clickable: false }\n      }\n    );\n\n    // add hover event to show tooltip\n    jq.bind(\"plothover\", function(event, pos, item) {\n      if (item) {\n        let x = item.datapoint[0],\n          y = item.datapoint[1];\n\n        $(\"#plot_coordinate_tooltip\")\n          .html(`(${x}, ${y})`)\n          .css({ top: item.pageY + 5, left: item.pageX + 5 })\n          .show();\n      } else {\n        $(\"#plot_coordinate_tooltip\").hide();\n      }\n    });\n  }\n  /**\n   * look through all expression objects and see if they are supposed to show their plot.\n   * If so, update the dom accordingly\n   * @param obj: expression object to plot (may have children to plot too)\n   */\n  static plot_var_and_children(obj: any) {\n    if (obj.show_plot) {\n      GdbVariable._make_plot(obj);\n    }\n    for (let child of obj.children) {\n      GdbVariable.plot_var_and_children(child);\n    }\n  }\n  static fetch_and_show_children_for_var(gdb_var_name: any) {\n    let expressions = store.get(\"expressions\");\n    let obj = GdbVariable.get_obj_from_gdb_var_name(expressions, gdb_var_name);\n    // mutate object by reference\n    obj.show_children_in_ui = true;\n    // update store\n    store.set(\"expressions\", expressions);\n    if (obj.numchild && obj.children.length === 0) {\n      // need to fetch child data\n      ChildVarFetcher.fetch_children(gdb_var_name, obj.expr_type);\n    } else {\n      // already have child data, re-render will occur from event dispatch\n    }\n  }\n  static hide_children_in_ui(gdb_var_name: any) {\n    let expressions = store.get(\"expressions\"),\n      obj = GdbVariable.get_obj_from_gdb_var_name(expressions, gdb_var_name);\n    if (obj) {\n      obj.show_children_in_ui = false;\n      store.set(\"expressions\", expressions);\n    }\n  }\n  static click_toggle_children_visibility(gdb_variable_name: any) {\n    GdbVariable._toggle_children_visibility(gdb_variable_name);\n  }\n  static _toggle_children_visibility(gdb_var_name: any) {\n    // get data object, which has field that says whether its expanded or not\n    let obj = GdbVariable.get_obj_from_gdb_var_name(\n      store.get(\"expressions\"),\n      gdb_var_name\n    );\n    if (obj) {\n      let showing_children_in_ui = obj.show_children_in_ui;\n\n      if (showing_children_in_ui) {\n        // collapse\n        GdbVariable.hide_children_in_ui(gdb_var_name);\n      } else {\n        // expand\n        GdbVariable.fetch_and_show_children_for_var(gdb_var_name);\n      }\n    } else {\n      console.error(\"developer error - expected to find gdb variable object\");\n    }\n  }\n  static click_toggle_plot(gdb_var_name: any) {\n    let expressions = store.get(\"expressions\"),\n      // get data object, which has field that says whether its expanded or not\n      obj = GdbVariable.get_obj_from_gdb_var_name(expressions, gdb_var_name);\n    if (obj) {\n      obj.show_plot = !obj.show_plot;\n      store.set(\"expressions\", expressions);\n    }\n  }\n  static get_update_cmds() {\n    function _get_cmds_for_obj(obj: any) {\n      let cmds = [`-var-update --all-values ${obj.name}`];\n      for (let child of obj.children) {\n        cmds = cmds.concat(_get_cmds_for_obj(child));\n      }\n      return cmds;\n    }\n\n    let cmds: any = [];\n    for (let obj of store.get(\"expressions\")) {\n      cmds = cmds.concat(_get_cmds_for_obj(obj));\n    }\n    return cmds;\n  }\n  static handle_changelist(changelist_array: any) {\n    for (let changelist of changelist_array) {\n      let expressions = store.get(\"expressions\"),\n        obj = GdbVariable.get_obj_from_gdb_var_name(expressions, changelist.name);\n      if (obj) {\n        if (parseInt(changelist[\"has_more\"]) === 1 && \"name\" in changelist) {\n          // already retrieved children of obj, but more fields were added.\n          // Re-fetch the object from gdb\n          ChildVarFetcher.fetch_children(changelist[\"name\"], obj.expr_type);\n        }\n        if (\"new_children\" in changelist) {\n          let new_children = changelist.new_children.map((child_obj: any) =>\n            GdbVariable.prepare_gdb_obj_for_storage(child_obj, obj)\n          );\n          obj.children = obj.children.concat(new_children);\n        }\n        // overwrite fields of obj with fields from changelist\n        obj = Object.assign(obj, changelist);\n        GdbVariable._update_numeric_properties(obj);\n        GdbVariable._update_radix_values(obj);\n        if (obj.can_plot) {\n          obj.values.push(obj._float_value);\n        }\n        store.set(\"expressions\", expressions);\n      } else {\n        // error\n      }\n    }\n  }\n  static click_draw_tree_gdb_variable(gdb_variable: any) {\n    store.set(\"root_gdb_tree_var\", gdb_variable);\n  }\n  static delete_gdb_variable(gdbvar: any) {\n    // delete locally\n    GdbVariable._delete_local_gdb_var_data(gdbvar);\n    // delete in gdb too\n    GdbApi.run_gdb_command(`-var-delete ${gdbvar}`);\n  }\n  /**\n   * Delete local copy of gdb variable (all its children are deleted too\n   * since they are stored as fields in the object)\n   */\n  static _delete_local_gdb_var_data(gdb_var_name: any) {\n    let expressions = store.get(\"expressions\");\n    // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name '_'.\n    _.remove(expressions, (v: any) => v.name === gdb_var_name);\n    store.set(\"expressions\", expressions);\n  }\n  /**\n   * Locally save the variable to our cached variables\n   */\n  static save_new_expression(expression: any, expr_type: any, obj: any) {\n    let new_obj = GdbVariable.prepare_gdb_obj_for_storage(obj, null);\n    new_obj.expression = expression;\n    let expressions = store.get(\"expressions\");\n    expressions.push(new_obj);\n    store.set(\"expressions\", expressions);\n  }\n  /**\n   * Get child variable with a particular name\n   */\n  static get_child_with_name(children: any, name: any) {\n    for (let child of children) {\n      if (child.name === name) {\n        return child;\n      }\n    }\n    return undefined;\n  }\n  static get_root_name_from_gdbvar_name(gdb_var_name: any) {\n    // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name '_'.\n    if (_.isString(gdb_var_name)) {\n      return gdb_var_name.split(\".\")[0];\n    } else {\n      return \"\";\n    }\n  }\n  static get_child_names_from_gdbvar_name(gdb_var_name: any) {\n    // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name '_'.\n    if (_.isString(gdb_var_name)) {\n      return gdb_var_name.split(\".\").slice(1, gdb_var_name.length);\n    } else {\n      return \"\";\n    }\n  }\n  /**\n   * Get object from gdb variable name. gdb variable names are unique, and don't match\n   * the expression being evaluated. If drilling down into fields of structures, the\n   * gdb variable name has dot notation, such as 'var.field1.field2'.\n   * @param gdb_var_name: gdb variable name to find corresponding cached object. Can have dot notation\n   * @return: object if found, or undefined if not found\n   */\n  static get_obj_from_gdb_var_name(expressions: any, gdb_var_name: any) {\n    // gdb provides names in dot notation\n    // let gdb_var_names = gdb_var_name.split('.'),\n    let top_level_var_name = GdbVariable.get_root_name_from_gdbvar_name(gdb_var_name),\n      children_names = GdbVariable.get_child_names_from_gdbvar_name(gdb_var_name);\n\n    let objs = expressions.filter((v: any) => v.name === top_level_var_name);\n\n    if (objs.length === 1) {\n      // we found our top level object\n      let obj = objs[0];\n      let name_to_find = top_level_var_name;\n      for (let i = 0; i < children_names.length; i++) {\n        // append the '.' and field name to find as a child of the object we're looking at\n        name_to_find += `.${children_names[i]}`;\n\n        let child_obj = GdbVariable.get_child_with_name(obj.children, name_to_find);\n\n        if (child_obj) {\n          // our new object to search is this child\n          obj = child_obj;\n        } else {\n          console.error(`could not find ${name_to_find}`);\n          return undefined;\n        }\n      }\n      return obj;\n    } else if (objs.length === 0) {\n      return undefined;\n    } else {\n      console.error(\n        `Somehow found multiple local gdb variables with the name ${top_level_var_name}. Not using any of them. File a bug report with the developer.`\n      );\n      return undefined;\n    }\n  }\n}\n\nexport default GdbVariable;\n"
  },
  {
    "path": "gdbgui/src/js/GdbguiModal.tsx",
    "content": "import React from \"react\";\nimport Actions from \"./Actions\";\nimport { store } from \"statorgfc\";\n\ntype State = any;\n\nclass Modal extends React.Component<{}, State> {\n  fullscreen_node: any;\n  constructor() {\n    // @ts-expect-error ts-migrate(2554) FIXME: Expected 1-2 arguments, but got 0.\n    super();\n    // @ts-expect-error ts-migrate(2339) FIXME: Property 'connectComponentState' does not exist on... Remove this comment to see the full error message\n    store.connectComponentState(this, [\"show_modal\", \"modal_body\", \"modal_header\"]);\n  }\n  render() {\n    return (\n      <div\n        className={this.state.show_modal ? \"fullscreen_modal\" : \"hidden\"}\n        ref={el => (this.fullscreen_node = el)}\n        onClick={e => {\n          if (e.target === this.fullscreen_node) {\n            Actions.toggle_modal_visibility();\n          }\n        }}\n      >\n        <div className=\"modal_content\">\n          <div>\n            <button\n              type=\"button\"\n              className=\"close\"\n              onClick={Actions.toggle_modal_visibility}\n            >\n              ×\n            </button>\n          </div>\n\n          <h4>{this.state.modal_header}</h4>\n\n          <div style={{ paddingBottom: \"20px\" }}>{this.state.modal_body}</div>\n\n          <button\n            style={{ float: \"right\" }}\n            type=\"button\"\n            className=\"btn btn-success\"\n            onClick={Actions.toggle_modal_visibility}\n          >\n            Close\n          </button>\n          <div style={{ paddingBottom: \"30px\" }} />\n        </div>\n      </div>\n    );\n  }\n}\n\nexport default Modal;\n"
  },
  {
    "path": "gdbgui/src/js/GlobalEvents.ts",
    "content": "/**\n * Setup global DOM events\n */\n\nimport constants from \"./constants\";\nimport GdbApi from \"./GdbApi\";\nimport { store } from \"statorgfc\";\n\nconst GlobalEvents = {\n  init: function() {\n    window.onkeydown = function(e: any) {\n      if (e.keyCode === constants.ENTER_BUTTON_NUM) {\n        // when pressing enter in an input, don't redirect entire page!\n        e.preventDefault();\n      }\n    };\n    $(\"body\").on(\"keydown\", GlobalEvents.body_keydown);\n    // @ts-expect-error ts-migrate(2339) FIXME: Property 'tooltip' does not exist on type 'JQuery<... Remove this comment to see the full error message\n    $('[data-toggle=\"tooltip\"]').tooltip();\n\n    window.onbeforeunload = () =>\n      \"text here makes dialog appear when exiting. Set function to back to null for nomal behavior.\";\n  },\n  /**\n   * keyboard shortcuts to interact with gdb.\n   * enabled only when key is depressed on a target that is NOT an input.\n   */\n  body_keydown: function(e: any) {\n    let modifier = e.altKey || e.ctrlKey || e.metaKey;\n\n    if (e.target.nodeName !== \"INPUT\" && !modifier) {\n      let char = String.fromCharCode(e.keyCode).toLowerCase();\n      if (e.keyCode === constants.DOWN_BUTTON_NUM || char === \"s\") {\n        GdbApi.click_step_button();\n      } else if (e.keyCode === constants.RIGHT_BUTTON_NUM) {\n        GdbApi.click_next_button();\n      } else if (char === \"n\") {\n        GdbApi.click_next_button(e.shiftKey);\n      } else if (char === \"c\") {\n        GdbApi.click_continue_button(e.shiftKey);\n      } else if (e.keyCode === constants.UP_BUTTON_NUM || char === \"u\") {\n        GdbApi.click_return_button();\n      } else if (char === \"r\") {\n        GdbApi.click_run_button();\n      } else if (char === \"m\") {\n        GdbApi.click_next_instruction_button(e.shiftKey);\n      } else if (e.keyCode === constants.COMMA_BUTTON_NUM) {\n        GdbApi.click_step_instruction_button(e.shiftKey);\n      } else if (\n        e.keyCode === constants.LEFT_BUTTON_NUM &&\n        store.get(\"reverse_supported\")\n      ) {\n        GdbApi.click_next_button(true);\n      }\n    }\n  }\n};\n\nexport default GlobalEvents;\n"
  },
  {
    "path": "gdbgui/src/js/HoverVar.tsx",
    "content": "/**\n * A component to show/hide variable exploration when hovering over a variable\n * in the source code\n */\n\nimport React from \"react\";\nimport { store } from \"statorgfc\";\nimport constants from \"./constants\";\nimport GdbVariable from \"./GdbVariable\";\n\nclass HoverVar extends React.Component {\n  static enter_timeout = undefined; // debounce fetching the expression\n  static exit_timeout = undefined; // debounce removing the box\n  static left = 0;\n  static top = 0;\n\n  obj: any;\n\n  constructor() {\n    // @ts-expect-error ts-migrate(2554) FIXME: Expected 1-2 arguments, but got 0.\n    super();\n\n    // when hovering over a potential variable\n    $(\"body\").on(\"mouseover\", \"#code_table span.n\", HoverVar.mouseover_variable);\n    $(\"body\").on(\"mouseleave\", \"#code_table span.n\", HoverVar.mouseout_variable);\n\n    $(\"body\").on(\"mouseover\", \"#code_table span.nx\", HoverVar.mouseover_variable);\n    $(\"body\").on(\"mouseleave\", \"#code_table span.nx\", HoverVar.mouseout_variable);\n\n    // when hovering over the hover var \"tooltip\"-like window\n    $(\"body\").on(\"mouseenter\", \"#hovervar\", HoverVar.mouseover_hover_window);\n    $(\"body\").on(\"mouseleave\", \"#hovervar\", HoverVar.mouseout_hover_window);\n\n    // @ts-expect-error ts-migrate(2339) FIXME: Property 'connectComponentState' does not exist on... Remove this comment to see the full error message\n    store.connectComponentState(this, [\"expressions\"]);\n  }\n  render() {\n    let hover_objs = store.get(\"expressions\").filter((o: any) => o.expr_type === \"hover\"),\n      obj;\n    if (Array.isArray(hover_objs) && hover_objs.length === 1) {\n      obj = hover_objs[0];\n    }\n    this.obj = obj;\n    if (obj) {\n      let style = {\n        position: \"absolute\",\n        left: HoverVar.left + \"px\",\n        top: HoverVar.top + \"px\",\n        backgroundColor: \"white\"\n      };\n      return (\n        // @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type '\"absolute... Remove this comment to see the full error message\n        <div style={style} id=\"hovervar\">\n          <GdbVariable\n            // @ts-expect-error ts-migrate(2769) FIXME: Property 'obj' does not exist on type 'IntrinsicAt... Remove this comment to see the full error message\n            obj={obj}\n            key={obj.expression}\n            expression={obj.expression}\n            expr_type=\"hover\"\n          />\n        </div>\n      );\n    } else {\n      return <div className=\"hidden\">no variable hovered</div>;\n    }\n  }\n  static mouseover_variable(e: any) {\n    HoverVar.clear_hover_state();\n\n    let rect = e.target.getBoundingClientRect(),\n      var_name = e.target.textContent;\n\n    // store coordinates of where the box should be displayed\n    HoverVar.left = rect.left;\n    HoverVar.top = rect.bottom;\n\n    const WAIT_TIME_SEC = 0.5;\n    // @ts-expect-error ts-migrate(2322) FIXME: Type 'Timeout' is not assignable to type 'undefine... Remove this comment to see the full error message\n    HoverVar.enter_timeout = setTimeout(() => {\n      if (store.get(\"inferior_program\") === constants.inferior_states.paused) {\n        let ignore_errors = true;\n        // @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 3.\n        GdbVariable.create_variable(var_name, \"hover\", ignore_errors);\n      }\n    }, WAIT_TIME_SEC * 1000);\n  }\n  static mouseout_variable(e: any) {\n    void e;\n    const WAIT_TIME_SEC = 0.1;\n    // @ts-expect-error ts-migrate(2322) FIXME: Type 'Timeout' is not assignable to type 'undefine... Remove this comment to see the full error message\n    HoverVar.exit_timeout = setTimeout(() => {\n      HoverVar.clear_hover_state();\n    }, WAIT_TIME_SEC * 1000);\n  }\n  static mouseover_hover_window(e: any) {\n    void e;\n    // Mouse went from hovering over variable name in source code to\n    // hovering over the window showing the contents of the variable.\n    // Don't remove the window in this case.\n    clearTimeout(HoverVar.exit_timeout);\n  }\n  static mouseout_hover_window(e: any) {\n    void e;\n    HoverVar.clear_hover_state();\n  }\n  static clear_hover_state() {\n    clearTimeout(HoverVar.enter_timeout);\n    clearTimeout(HoverVar.exit_timeout);\n    let exprs_objs_to_remove = store\n      .get(\"expressions\")\n      .filter((obj: any) => obj.expr_type === \"hover\");\n    exprs_objs_to_remove.map((obj: any) => GdbVariable.delete_gdb_variable(obj.name));\n  }\n}\n\nexport default HoverVar;\n"
  },
  {
    "path": "gdbgui/src/js/InferiorProgramInfo.tsx",
    "content": "import React from \"react\";\n\nimport Actions from \"./Actions\";\nimport { store } from \"statorgfc\";\n\ntype State = any;\n\nclass InferiorProgramInfo extends React.Component<{}, State> {\n  constructor() {\n    // @ts-expect-error ts-migrate(2554) FIXME: Expected 1-2 arguments, but got 0.\n    super();\n    this.get_li_for_signal = this.get_li_for_signal.bind(this);\n    this.get_dropdown = this.get_dropdown.bind(this);\n    this.state = {\n      selected_signal: \"SIGINT\",\n      other_pid: \"\"\n    };\n    // @ts-expect-error ts-migrate(2339) FIXME: Property 'connectComponentState' does not exist on... Remove this comment to see the full error message\n    store.connectComponentState(this, [\"inferior_pid\", \"gdb_pid\"]);\n  }\n  get_li_for_signal(s: any, signal_key: any) {\n    let onclick = function() {\n      let obj = {};\n      // @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message\n      obj[signal_key] = s;\n      // @ts-expect-error ts-migrate(2683) FIXME: 'this' implicitly has type 'any' because it does n... Remove this comment to see the full error message\n      this.setState(obj);\n    }.bind(this);\n\n    return (\n      <li key={s} className=\"pointer\" value={s} onClick={onclick}>\n        {/* @ts-expect-error ts-migrate(2339) FIXME: Property 'signals' does not exist on type 'Readonl... Remove this comment to see the full error message */}\n        <a>{`${s} (${this.props.signals[s]})`}</a>\n      </li>\n    );\n  }\n  get_signal_choices(signal_key: any) {\n    let signals = [];\n    // push SIGINT and SIGKILL to top\n    // @ts-expect-error ts-migrate(2339) FIXME: Property 'signals' does not exist on type 'Readonl... Remove this comment to see the full error message\n    for (let s in this.props.signals) {\n      if (s === \"SIGKILL\" || s === \"SIGINT\") {\n        signals.push(this.get_li_for_signal(s, signal_key));\n      }\n    }\n    // @ts-expect-error ts-migrate(2339) FIXME: Property 'signals' does not exist on type 'Readonl... Remove this comment to see the full error message\n    for (let s in this.props.signals) {\n      if (s !== \"SIGKILL\" && s !== \"SIGINT\") {\n        signals.push(this.get_li_for_signal(s, signal_key));\n      }\n    }\n    return signals;\n  }\n  get_dropdown() {\n    return (\n      <div className=\"dropdown btn-group\">\n        <button\n          className=\"btn btn-default btn-xs dropdown-toggle\"\n          type=\"button\"\n          data-toggle=\"dropdown\"\n        >\n          {this.state.selected_signal}\n          <span className=\"caret\" style={{ marginLeft: \"5px\" }}>\n            {\" \"}\n          </span>\n        </button>\n        <ul className=\"dropdown-menu\" style={{ maxHeight: \"300px\", overflow: \"auto\" }}>\n          {this.get_signal_choices(\"selected_signal\")}\n        </ul>\n      </div>\n    );\n  }\n  render() {\n    let gdb_button = (\n      <button\n        className=\"btn btn-default btn-xs\"\n        // id=\"step_instruction_button\"\n        // style={{marginLeft: '5px'}}\n        type=\"button\"\n        title={`Send signal to gdb`}\n        onClick={() =>\n          Actions.send_signal(this.state.selected_signal, this.state.gdb_pid)\n        }\n      >\n        {`gdb (pid ${this.state.gdb_pid})`}\n      </button>\n    );\n\n    let inferior_button = null;\n    if (this.state.inferior_pid) {\n      inferior_button = (\n        <button\n          className=\"btn btn-default btn-xs\"\n          type=\"button\"\n          title={`Send signal to program being debugged`}\n          onClick={() =>\n            Actions.send_signal(this.state.selected_signal, this.state.inferior_pid)\n          }\n        >\n          {`debug program (pid ${this.state.inferior_pid})`}\n        </button>\n      );\n    }\n\n    let other_input_and_button = (\n      <button\n        disabled={!this.state.other_pid}\n        className=\"btn btn-default btn-xs\"\n        type=\"button\"\n        title={`Send signal to custom PID. Enter PID to enable this button.`}\n        onClick={() =>\n          Actions.send_signal(this.state.selected_signal, this.state.other_pid)\n        }\n      >\n        {`other pid ${this.state.other_pid}`}\n      </button>\n    );\n    return (\n      <div>\n        send&nbsp;\n        {this.get_dropdown()}\n        &nbsp;to&nbsp;\n        <div className=\"btn-group\" role=\"group\">\n          {gdb_button}\n          {inferior_button}\n        </div>\n        <p>\n          {other_input_and_button}\n          <input\n            placeholder=\"pid\"\n            style={{\n              display: \"inline\",\n              height: \"25px\",\n              width: \"75px\",\n              border: \"1px solid #ccc\",\n              borderRadius: \"4px\"\n            }}\n            onChange={e => {\n              this.setState({ other_pid: e.currentTarget.value });\n            }}\n            value={this.state.other_pid}\n          />\n        </p>\n      </div>\n    ); // return\n  } // render\n} // component\n\nexport default InferiorProgramInfo;\n"
  },
  {
    "path": "gdbgui/src/js/InitialStoreData.ts",
    "content": "/* global initial_data */\n/* global debug */\nimport constants from \"./constants\";\n\n/**\n * The initial store data. Keys cannot be added after initialization.\n * All fields in here should be shared by > 1 component, otherwise they should\n * exist as local state for that component.\n */\nconst initial_store_data = {\n  // environment\n  // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name 'debug'.\n  debug: debug, // if gdbgui is run in debug mode\n  // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name 'initial_data'.\n  gdbgui_version: initial_data.gdbgui_version,\n  latest_gdbgui_version: \"(not fetched)\",\n  gdb_version: \"unknown\", // this is parsed from gdb's output\n  gdb_version_array: [], // this is parsed from gdb's output\n  gdb_pid: undefined,\n  // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name 'initial_data'.\n  gdb_command: initial_data.gdb_command,\n  can_fetch_register_values: true, // set to false if using Rust and gdb v7.12.x (see https://github.com/cs01/gdbgui/issues/64)\n  show_settings: false,\n\n  debug_in_reverse: false,\n  reverse_supported: false,\n  show_modal: false,\n  modal_header: null,\n  modal_body: null,\n\n  show_tour_guide: true,\n  tour_guide_step: 0,\n  num_tour_guide_steps: 0,\n  tooltip: { hidden: false, content: \"placeholder\", node: null, show_for_n_sec: null },\n  textarea_to_copy_to_clipboard: {}, // will be replaced with textarea dom node\n\n  // preferences\n  // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name 'initial_data'.\n  themes: initial_data.themes,\n  // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name 'initial_data'.\n  current_theme: localStorage.getItem(\"theme\") || initial_data.themes[0],\n  highlight_source_code: true, // get saved boolean to highlight source code\n  max_lines_of_code_to_fetch: constants.default_max_lines_of_code_to_fetch,\n  auto_add_breakpoint_to_main: true,\n\n  pretty_print: true, // whether gdb should \"pretty print\" variables. There is an option for this in Settings\n  refresh_state_after_sending_console_command: true, // If true, send commands to refresh GUI store after each command is sent from console\n  // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name 'debug'.\n  show_all_sent_commands_in_console: debug, // show all sent commands if in debug mode\n\n  inferior_program: constants.inferior_states.unknown,\n  inferior_pid: null,\n\n  paused_on_frame: undefined,\n  selected_frame_num: 0,\n  current_thread_id: undefined,\n  stack: [],\n  locals: [],\n  threads: [],\n\n  // source files\n  source_file_paths: [], // all the paths gdb says were used to compile the target binary\n  language: \"c_family\", // assume langage of program is c or c++. Language is determined by source file paths. Used to turn on/off certain features/warnings.\n  files_being_fetched: [],\n  fullname_to_render: null,\n  line_of_source_to_flash: null,\n  current_assembly_address: null,\n  // rendered_source: {},\n  make_current_line_visible: false, // set to true when source code window should jump to current line\n  cached_source_files: [], // list with keys fullname, source_code\n  disassembly_for_missing_file: [], // mi response object. Only fetched when there currently paused frame refers to a file that doesn't exist or is undefined\n  missing_files: [], // files that were attempted to be fetched but did not exist on the local filesystem\n  source_code_state: constants.source_code_states.NONE_AVAILABLE,\n  source_code_selection_state: constants.source_code_selection_states.PAUSED_FRAME,\n\n  source_code_infinite_scrolling: false,\n  source_linenum_to_display_start: 0,\n  source_linenum_to_display_end: 0,\n\n  // binary selection\n  inferior_binary_path: null,\n  inferior_binary_path_last_modified_unix_sec: null,\n\n  // registers\n  register_names: [],\n  previous_register_values: {},\n  current_register_values: {},\n\n  // memory\n  memory_cache: {},\n  start_addr: \"\",\n  end_addr: \"\",\n  bytes_per_line: \"8\",\n\n  // breakpoints\n  breakpoints: [],\n\n  // expressions\n  expressions: [], // array of dicts. Key is expression, value has various keys. See Expressions component.\n  root_gdb_tree_var: null, // draw tree for this variable\n\n  waiting_for_response: false,\n\n  gdb_mi_output: [],\n\n  gdb_autocomplete_options: [],\n\n  gdb_console_entries: [],\n\n  // if we try to write something before the websocket is connected, store it here\n  queuedGdbCommands: [],\n\n  show_filesystem: false,\n  middle_panes_split_obj: {},\n  gdbguiPty: null\n};\n\nfunction get_stored(key: any, default_val: any) {\n  try {\n    if (localStorage.hasOwnProperty(key)) {\n      // @ts-expect-error ts-migrate(2345) FIXME: Type 'null' is not assignable to type 'string'.\n      let cached = JSON.parse(localStorage.getItem(key));\n      if (typeof cached === typeof default_val) {\n        return cached;\n      }\n      return default_val;\n    }\n  } catch (err) {\n    console.error(err);\n  }\n  localStorage.removeItem(key);\n  return default_val;\n}\n\n// restore saved localStorage data\nfor (let key in initial_store_data) {\n  // @ts-expect-error ts-migrate(7053) FIXME: No index signature with a parameter of type 'strin... Remove this comment to see the full error message\n  let default_val = initial_store_data[key];\n  // @ts-expect-error ts-migrate(7053) FIXME: No index signature with a parameter of type 'strin... Remove this comment to see the full error message\n  initial_store_data[key] = get_stored(key, default_val);\n}\n\nif (localStorage.hasOwnProperty(\"max_lines_of_code_to_fetch\")) {\n  // @ts-expect-error ts-migrate(2345) FIXME: Type 'null' is not assignable to type 'string'.\n  let savedval = JSON.parse(localStorage.getItem(\"max_lines_of_code_to_fetch\"));\n  // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name '_'.\n  if (_.isInteger(savedval) && savedval > 0) {\n    initial_store_data[\"max_lines_of_code_to_fetch\"] = savedval;\n  }\n}\n\nexport default initial_store_data;\n"
  },
  {
    "path": "gdbgui/src/js/Links.tsx",
    "content": "import Actions from \"./Actions\";\nimport * as React from \"react\";\nimport CopyToClipboard from \"./CopyToClipboard\";\nimport MemoryLink from \"./MemoryLink\";\n\ntype Props = {\n  file?: string;\n  fullname?: string;\n  line: string;\n  num_lines?: number;\n};\n\nexport class FileLink extends React.Component<Props> {\n  render() {\n    let line = parseInt(this.props.line);\n    let onclick = () => {},\n      cls = \"\";\n    if (!this.props.file || !line) {\n      line = 0;\n    }\n    let sep = \"\";\n    if (line && line !== 0) {\n      sep = \":\";\n    }\n    if (this.props.fullname) {\n      onclick = () => Actions.view_file(this.props.fullname, line);\n      cls = \"pointer\";\n    }\n\n    let clipboard_content = null;\n    if (this.props.fullname || this.props.file) {\n      clipboard_content = (this.props.fullname || this.props.file) + sep + line;\n    }\n    return (\n      <div style={{ display: \"inline-block\", whiteSpace: \"nowrap\" }}>\n        <span\n          onClick={onclick}\n          className={cls}\n          title={`click to view ${this.props.fullname}`}\n          style={{ display: \"inline\" }}\n        >\n          {this.props.file}\n          {sep}\n          {line > 0 ? line : \"\"}\n        </span>\n\n        <CopyToClipboard content={clipboard_content} />\n        {this.props.num_lines ? `(${this.props.num_lines} lines total)` : \"\"}\n      </div>\n    );\n  }\n}\n\ntype FrameLinkProps = {\n  addr: string;\n  file?: string;\n  fullname?: string;\n  line: string;\n};\n\nexport class FrameLink extends React.Component<FrameLinkProps> {\n  render() {\n    return (\n      <div>\n        <FileLink\n          fullname={this.props.fullname}\n          file={this.props.file}\n          line={this.props.line}\n        />\n        <span style={{ whiteSpace: \"pre\" }}> </span>\n        <MemoryLink addr={this.props.addr} />\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "gdbgui/src/js/Locals.tsx",
    "content": "/**\n * A component to render \"local\" variables, as well as a few static methods to\n * assist in their creation and deletion.\n */\n\nimport React from \"react\";\nimport { store } from \"statorgfc\";\nimport GdbVariable from \"./GdbVariable\";\n\nclass Locals extends React.Component {\n  constructor() {\n    // @ts-expect-error ts-migrate(2554) FIXME: Expected 1-2 arguments, but got 0.\n    super();\n    // @ts-expect-error ts-migrate(2339) FIXME: Property 'connectComponentState' does not exist on... Remove this comment to see the full error message\n    store.connectComponentState(this, [\"expressions\", \"locals\"]);\n  }\n  render() {\n    let content = [];\n    // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name '_'.\n    let sorted_local_objs = _.sortBy(\n      store.get(\"locals\"),\n      (unsorted_obj: any) => unsorted_obj.name\n    );\n\n    for (let local of sorted_local_objs) {\n      let obj = this.get_autocreated_obj_from_expr(local.name);\n      if (obj) {\n        content.push(\n          <GdbVariable\n            // @ts-expect-error ts-migrate(2769) FIXME: Property 'obj' does not exist on type 'IntrinsicAt... Remove this comment to see the full error message\n            obj={obj}\n            key={obj.expression}\n            expression={obj.expression}\n            expr_type=\"expr\"\n          />\n        );\n      } else {\n        content.push(\n          <GdbVariable\n            // @ts-expect-error ts-migrate(2769) FIXME: Property 'obj' does not exist on type 'IntrinsicAt... Remove this comment to see the full error message\n            obj={local}\n            key={local.name}\n            expression={local.name}\n            expr_type=\"local\"\n          />\n        );\n      }\n    }\n\n    if (content.length === 0) {\n      return (\n        <span key=\"empty\" className=\"placeholder\">\n          no locals in this context\n        </span>\n      );\n    } else {\n      return content;\n    }\n  }\n  get_autocreated_obj_from_expr(expr: any) {\n    for (let obj of store.get(\"expressions\")) {\n      if (obj.expression === expr && obj.expr_type === \"local\") {\n        return obj;\n      }\n    }\n    return null;\n  }\n  static clear_autocreated_exprs() {\n    let exprs_objs_to_remove = store\n      .get(\"expressions\")\n      .filter((obj: any) => obj.expr_type === \"local\");\n    exprs_objs_to_remove.map((obj: any) => GdbVariable.delete_gdb_variable(obj.name));\n  }\n  static clear() {\n    store.set(\"locals\", []);\n    Locals.clear_autocreated_exprs();\n  }\n  static save_locals(locals: any) {\n    let locals_with_meta = locals.map((local: any) => {\n      // add field to local\n      local.can_be_expanded = Locals.can_local_be_expanded(local) ? true : false;\n      return local;\n    });\n    store.set(\"locals\", locals_with_meta);\n  }\n  static can_local_be_expanded(local: any) {\n    // gdb returns list of locals. We may want to turn that local into a GdbVariable\n    // to explore its children\n    if (\"value\" in local) {\n      // local has a value associated with it. It's either a native\n      // type or a pointer. It's not a complex type like a struct.\n      if (local.type.indexOf(\"*\") !== -1) {\n        // make plus if value is a pointer (has asterisk)\n        // and can therefore be evaluated further by gdb\n        return true;\n      } else {\n        return false;\n      }\n    } else {\n      // is a struct or object that can be evaluated further by gdb\n      return true;\n    }\n  }\n}\n\nexport default Locals;\n"
  },
  {
    "path": "gdbgui/src/js/Memory.tsx",
    "content": "/**\n * The Memory component allows the user to view\n * data stored at memory locations. It has some\n * static methods used by other objects to turn text into a clickable\n * address. It also has methods to manage the global store of memory data.\n */\n\nimport { store } from \"statorgfc\";\nimport GdbApi from \"./GdbApi\";\nimport constants from \"./constants\";\nimport ReactTable from \"./ReactTable\";\n// @ts-expect-error ts-migrate(2691) FIXME: An import path cannot end with a '.tsx' extension.... Remove this comment to see the full error message\nimport MemoryLink from \"./MemoryLink.tsx\";\nimport Actions from \"./Actions\";\nimport React from \"react\";\n\ntype State = any;\n\nclass Memory extends React.Component<{}, State> {\n  static MAX_ADDRESS_DELTA_BYTES = 1000;\n  static DEFAULT_ADDRESS_DELTA_BYTES = 31;\n  static DEFAULT_BYTES_PER_LINE = 8;\n\n  constructor() {\n    // @ts-expect-error ts-migrate(2554) FIXME: Expected 1-2 arguments, but got 0.\n    super();\n    // @ts-expect-error ts-migrate(2339) FIXME: Property 'connectComponentState' does not exist on... Remove this comment to see the full error message\n    store.connectComponentState(this, [\n      \"memory_cache\",\n      \"start_addr\",\n      \"end_addr\",\n      \"bytes_per_line\"\n    ]);\n  }\n  get_memory_component_jsx_content() {\n    if (Object.keys(store.get(\"memory_cache\")).length === 0) {\n      return (\n        <span key=\"nothing\" className=\"placeholder\">\n          no memory to display\n        </span>\n      );\n    }\n\n    let data = [],\n      hex_vals_for_this_addr = [],\n      char_vals_for_this_addr = [],\n      i = 0,\n      hex_addr_to_display = null;\n\n    let bytes_per_line =\n      parseInt(store.get(\"bytes_per_line\")) || Memory.DEFAULT_BYTES_PER_LINE;\n    bytes_per_line = Math.max(bytes_per_line, 1);\n\n    data.push([\n      <span\n        key=\"moretop\"\n        className=\"pointer\"\n        style={{ fontStyle: \"italic\", fontSize: \"0.8em\" }}\n        onClick={Memory.click_read_preceding_memory}\n      >\n        more\n      </span>,\n      \"\",\n      \"\"\n    ]);\n\n    for (let hex_addr in store.get(\"memory_cache\")) {\n      if (!hex_addr_to_display) {\n        hex_addr_to_display = hex_addr;\n      }\n\n      if (i % bytes_per_line === 0 && hex_vals_for_this_addr.length > 0) {\n        // begin new row\n        data.push([\n          Memory.make_addrs_into_links_react(hex_addr_to_display),\n          hex_vals_for_this_addr.join(\" \"),\n          char_vals_for_this_addr\n        ]);\n\n        // update which address we're collecting values for\n        i = 0;\n        hex_addr_to_display = hex_addr;\n        hex_vals_for_this_addr = [];\n        char_vals_for_this_addr = [];\n      }\n      let hex_value = store.get(\"memory_cache\")[hex_addr];\n      hex_vals_for_this_addr.push(hex_value);\n      let char = String.fromCharCode(parseInt(hex_value, 16)).replace(/\\W/g, \".\");\n      char_vals_for_this_addr.push(\n        <span key={i} className=\"memory_char\">\n          {char}\n        </span>\n      );\n      i++;\n    }\n\n    if (hex_vals_for_this_addr.length > 0) {\n      // memory range requested wasn't divisible by bytes per line\n      // add the remaining memory\n      data.push([\n        Memory.make_addrs_into_links_react(hex_addr_to_display),\n        hex_vals_for_this_addr.join(\" \"),\n        char_vals_for_this_addr\n      ]);\n    }\n\n    if (Object.keys(store.get(\"memory_cache\")).length > 0) {\n      data.push([\n        <span\n          key=\"morebottom\"\n          className=\"pointer\"\n          style={{ fontStyle: \"italic\", fontSize: \"0.8em\" }}\n          onClick={Memory.click_read_more_memory}\n        >\n          more\n        </span>,\n        \"\",\n        \"\"\n      ]);\n    }\n\n    // @ts-expect-error ts-migrate(2769) FIXME: Type 'string' is not assignable to type 'never'.\n    return <ReactTable data={data} header={[\"address\", \"hex\", \"char\"]} />;\n  }\n  render() {\n    let input_style = {\n        display: \"inline\",\n        width: \"100px\",\n        padding: \"6px 6px\",\n        height: \"25px\",\n        fontSize: \"1em\"\n      },\n      content = this.get_memory_component_jsx_content();\n    return (\n      <div>\n        <input\n          id=\"memory_start_address\"\n          className=\"form-control\"\n          placeholder=\"start address (hex)\"\n          style={input_style}\n          value={this.state.start_addr}\n          onKeyUp={Memory.keypress_on_input}\n          onChange={e => {\n            store.set(\"start_addr\", e.target.value);\n          }}\n        />\n        <input\n          id=\"memory_end_address\"\n          className=\"form-control\"\n          placeholder=\"end address (hex)\"\n          style={input_style}\n          value={this.state.end_addr}\n          onKeyUp={Memory.keypress_on_input}\n          onChange={e => {\n            store.set(\"end_addr\", e.target.value);\n          }}\n        />\n        <input\n          id=\"memory_bytes_per_line\"\n          className=\"form-control\"\n          placeholder=\"bytes per line (dec)\"\n          style={input_style}\n          value={this.state.bytes_per_line}\n          onKeyUp={Memory.keypress_on_input}\n          onChange={e => {\n            store.set(\"bytes_per_line\", e.target.value);\n          }}\n        />\n        {content}\n      </div>\n    );\n  }\n  static keypress_on_input(e: any) {\n    if (e.keyCode === constants.ENTER_BUTTON_NUM) {\n      Memory.fetch_memory_from_state();\n    }\n  }\n  static set_inputs_from_address(addr: any) {\n    // set inputs in DOM\n    store.set(\"start_addr\", \"0x\" + parseInt(addr, 16).toString(16));\n    store.set(\n      \"end_addr\",\n      \"0x\" + (parseInt(addr, 16) + Memory.DEFAULT_ADDRESS_DELTA_BYTES).toString(16)\n    );\n    Memory.fetch_memory_from_state();\n  }\n\n  static get_gdb_commands_from_state() {\n    // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name '_'.\n    let start_addr = parseInt(_.trim(store.get(\"start_addr\")), 16),\n      // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name '_'.\n      end_addr = parseInt(_.trim(store.get(\"end_addr\")), 16);\n\n    if (!window.isNaN(start_addr) && window.isNaN(end_addr)) {\n      end_addr = start_addr + Memory.DEFAULT_ADDRESS_DELTA_BYTES;\n    }\n\n    let cmds = [];\n    // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name '_'.\n    if (_.isInteger(start_addr) && end_addr) {\n      if (start_addr > end_addr) {\n        end_addr = start_addr + Memory.DEFAULT_ADDRESS_DELTA_BYTES;\n        store.set(\"end_addr\", \"0x\" + end_addr.toString(16));\n      } else if (end_addr - start_addr > Memory.MAX_ADDRESS_DELTA_BYTES) {\n        let orig_end_addr = end_addr;\n        end_addr = start_addr + Memory.MAX_ADDRESS_DELTA_BYTES;\n        store.set(\"end_addr\", \"0x\" + end_addr.toString(16));\n        Actions.add_console_entries(\n          `Cannot fetch ${orig_end_addr -\n            start_addr} bytes. Changed end address to ${store.get(\n            \"end_addr\"\n          )} since maximum bytes gdbgui allows is ${Memory.MAX_ADDRESS_DELTA_BYTES}.`,\n          constants.console_entry_type.STD_ERR\n        );\n      }\n\n      let cur_addr = start_addr;\n      while (cur_addr <= end_addr) {\n        // TODO read more than 1 byte at a time?\n        cmds.push(`-data-read-memory-bytes ${\"0x\" + cur_addr.toString(16)} 1`);\n        cur_addr = cur_addr + 1;\n      }\n    }\n\n    if (!window.isNaN(start_addr)) {\n      store.set(\"start_addr\", \"0x\" + start_addr.toString(16));\n    }\n    if (!window.isNaN(end_addr)) {\n      store.set(\"end_addr\", \"0x\" + end_addr.toString(16));\n    }\n\n    return cmds;\n  }\n\n  static fetch_memory_from_state() {\n    let cmds = Memory.get_gdb_commands_from_state();\n    Memory.clear_cache();\n    GdbApi.run_gdb_command(cmds);\n  }\n\n  static click_read_preceding_memory() {\n    // update starting value, then re-fetch\n    let NUM_ROWS = 3;\n    // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name '_'.\n    let start_addr = parseInt(_.trim(store.get(\"start_addr\")), 16),\n      byte_offset = store.get(\"bytes_per_line\") * NUM_ROWS;\n    store.set(\"start_addr\", \"0x\" + (start_addr - byte_offset).toString(16));\n    Memory.fetch_memory_from_state();\n  }\n\n  static click_read_more_memory() {\n    // update ending value, then re-fetch\n    let NUM_ROWS = 3;\n    // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name '_'.\n    let end_addr = parseInt(_.trim(store.get(\"end_addr\")), 16),\n      byte_offset = store.get(\"bytes_per_line\") * NUM_ROWS;\n    store.set(\"end_addr\", \"0x\" + (end_addr + byte_offset).toString(16));\n    Memory.fetch_memory_from_state();\n  }\n\n  /**\n   * @param text: string to convert address-like text into clickable components\n   * return react component\n   */\n  static make_addrs_into_links_react(text: any) {\n    let matches = text.match(/(0x[\\d\\w]+)/g);\n    if (text && matches && matches.length) {\n      let addr = matches[0];\n      let leading_text = text.slice(0, text.indexOf(addr));\n      let trailing_text = text.slice(text.indexOf(addr) + addr.length, text.length);\n      let suffix_component = trailing_text;\n      if (trailing_text) {\n        // recursive call to turn additional addressed after the first\n        suffix_component = Memory.make_addrs_into_links_react(trailing_text);\n      }\n      return (\n        <React.Fragment>\n          {leading_text}\n          <MemoryLink addr={addr} />\n          {suffix_component}\n        </React.Fragment>\n      );\n    } else {\n      return text;\n    }\n  }\n\n  static add_value_to_cache(hex_str: any, hex_val: any) {\n    // strip leading zeros off address provided by gdb\n    // i.e. 0x000123 turns to\n    // 0x123\n    let hex_str_truncated = \"0x\" + parseInt(hex_str, 16).toString(16);\n    let cache = store.get(\"memory_cache\");\n    cache[hex_str_truncated] = hex_val;\n    store.set(\"memory_cache\", cache);\n  }\n\n  static clear_cache() {\n    store.set(\"memory_cache\", {});\n  }\n}\n\nexport default Memory;\n"
  },
  {
    "path": "gdbgui/src/js/MemoryLink.tsx",
    "content": "import * as React from \"react\";\nimport Memory from \"./Memory\";\n\ntype OwnProps = {\n  addr: string;\n  style?: React.CSSProperties;\n};\n\ntype Props = OwnProps & typeof MemoryLink.defaultProps;\n\nclass MemoryLink extends React.Component<Props> {\n  render() {\n    // turn 0x00000000000000 into 0x0\n    const address_no_leading_zeros = \"0x\" + parseInt(this.props.addr, 16).toString(16);\n    return (\n      <span\n        className=\"pointer memadr_react\"\n        onClick={() => Memory.set_inputs_from_address(address_no_leading_zeros)}\n        title={`click to explore memory at ${address_no_leading_zeros}`}\n        style={this.props.style}\n      >\n        {address_no_leading_zeros}\n      </span>\n    );\n  }\n  static defaultProps = { style: { fontFamily: \"monospace\" } };\n}\n\nexport default MemoryLink;\n"
  },
  {
    "path": "gdbgui/src/js/MiddleLeft.tsx",
    "content": "/**\n * The middle left div will be rendered with this content\n */\n\nimport React from \"react\";\nimport SourceCode from \"./SourceCode\";\nimport FileOps from \"./FileOps\";\n\nclass MiddleLeft extends React.Component {\n  fetch_more_at_top_timeout: any;\n  onscroll_timeout: any;\n  source_code_container_node: any;\n  constructor() {\n    // @ts-expect-error ts-migrate(2554) FIXME: Expected 1-2 arguments, but got 0.\n    super();\n    this.onscroll_container = this.onscroll_container.bind(this);\n    this.onscroll_timeout = null;\n    this.fetch_more_at_top_timeout = null;\n  }\n  render() {\n    return (\n      <div\n        id=\"code_container\"\n        style={{ overflow: \"auto\", height: \"100%\" }}\n        ref={el => (this.source_code_container_node = el)}\n      >\n        <SourceCode />\n      </div>\n    );\n  }\n  componentDidMount() {\n    // @ts-expect-error ts-migrate(2322) FIXME: Type 'JQuery<HTMLElement>' is not assignable to ty... Remove this comment to see the full error message\n    SourceCode.el_code_container = $(\"#code_container\"); // todo: no jquery\n\n    if (this.source_code_container_node) {\n      this.source_code_container_node.onscroll = this.onscroll_container.bind(this);\n    }\n  }\n\n  onscroll_container() {\n    clearTimeout(this.onscroll_timeout);\n    this.onscroll_timeout = setTimeout(this.check_to_autofetch_more_source, 100);\n  }\n\n  check_to_autofetch_more_source() {\n    // test if \"view more\" buttons are visible, and if so, fetch more source\n\n    let fetching_for_top = false; // don't fetch for more at bottom and top at same time\n    if (SourceCode.view_more_top_node) {\n      let { is_visible } = SourceCode.is_source_line_visible(\n        // @ts-expect-error ts-migrate(2769) FIXME: Argument of type 'null' is not assignable to param... Remove this comment to see the full error message\n        $(SourceCode.view_more_top_node)\n      );\n      if (is_visible) {\n        fetching_for_top = true;\n        FileOps.fetch_more_source_at_beginning();\n      }\n    }\n\n    if (!fetching_for_top && SourceCode.view_more_bottom_node) {\n      let { is_visible } = SourceCode.is_source_line_visible(\n        // @ts-expect-error ts-migrate(2769) FIXME: Argument of type 'null' is not assignable to param... Remove this comment to see the full error message\n        $(SourceCode.view_more_bottom_node)\n      );\n      if (is_visible) {\n        FileOps.fetch_more_source_at_end();\n      }\n    }\n  }\n}\n\nexport default MiddleLeft;\n"
  },
  {
    "path": "gdbgui/src/js/ReactTable.tsx",
    "content": "import React from \"react\";\n\nclass TableRow extends React.Component {\n  className: any;\n  get_tds() {\n    let tds = [];\n    // @ts-expect-error ts-migrate(2339) FIXME: Property 'data' does not exist on type 'Readonly<{... Remove this comment to see the full error message\n    for (let i in this.props.data) {\n      // @ts-expect-error ts-migrate(2339) FIXME: Property 'data' does not exist on type 'Readonly<{... Remove this comment to see the full error message\n      tds.push(<td key={i}>{this.props.data[i]}</td>);\n    }\n    return tds;\n  }\n\n  render() {\n    return <tr className={this.className}>{this.get_tds()}</tr>;\n  }\n}\n\nclass ReactTable extends React.Component {\n  static defaultProps = { header: [] };\n  render_row(row_data: any, i: any) {\n    // @ts-expect-error ts-migrate(2769) FIXME: Property 'data' does not exist on type 'IntrinsicA... Remove this comment to see the full error message\n    return <TableRow data={row_data} key={i} />;\n  }\n\n  render_head() {\n    let ths = [],\n      i = 0;\n    // @ts-expect-error ts-migrate(2339) FIXME: Property 'header' does not exist on type 'Readonly... Remove this comment to see the full error message\n    for (let th_data of this.props.header) {\n      ths.push(<th key={i}>{th_data}</th>);\n      i++;\n    }\n    return ths;\n  }\n\n  render() {\n    // @ts-expect-error ts-migrate(2339) FIXME: Property 'classes' does not exist on type 'Readonl... Remove this comment to see the full error message\n    let classes = [\"table\", \"table-condensed\"].concat(this.props.classes);\n    return (\n      // @ts-expect-error ts-migrate(2339) FIXME: Property 'style' does not exist on type 'Readonly<... Remove this comment to see the full error message\n      <table className={classes.join(\" \")} style={this.props.style}>\n        <thead>\n          <tr>{this.render_head()}</tr>\n        </thead>\n        {/* @ts-expect-error ts-migrate(2339) FIXME: Property 'data' does not exist on type 'Readonly<{... Remove this comment to see the full error message */}\n        <tbody>{this.props.data.map(this.render_row)}</tbody>\n      </table>\n    );\n  }\n}\n\nexport default ReactTable;\n"
  },
  {
    "path": "gdbgui/src/js/Registers.tsx",
    "content": "/**\n * A component to display, fetch, and store register\n */\n\nimport React from \"react\";\nimport { store } from \"statorgfc\";\nimport constants from \"./constants\";\nimport ReactTable from \"./ReactTable\";\nimport Memory from \"./Memory\";\nimport GdbApi from \"./GdbApi\";\nimport register_descriptions from \"./register_descriptions\";\n\nconst MAX_REGISTER_NAME_FETCH_COUNT = 5;\nlet register_name_fetch_count = 0,\n  register_name_fetch_timeout: any = null;\n\ntype State = any;\n\nclass Registers extends React.Component<{}, State> {\n  constructor() {\n    // @ts-expect-error ts-migrate(2554) FIXME: Expected 1-2 arguments, but got 0.\n    super();\n    // @ts-expect-error ts-migrate(2339) FIXME: Property 'connectComponentState' does not exist on... Remove this comment to see the full error message\n    store.connectComponentState(this, [\n      \"inferior_program\",\n      \"previous_register_values\",\n      \"current_register_values\",\n      \"register_names\",\n      \"can_fetch_register_values\"\n    ]);\n  }\n  static get_update_cmds() {\n    let cmds: any = [];\n    if (\n      [constants.inferior_states.paused, constants.inferior_states.running].indexOf(\n        store.get(\"inferior_program\")\n      ) == -1\n    ) {\n      return cmds;\n    }\n    if (store.get(\"can_fetch_register_values\") === true) {\n      if (store.get(\"register_names\").length === 0) {\n        if (register_name_fetch_count <= MAX_REGISTER_NAME_FETCH_COUNT) {\n          clearTimeout(register_name_fetch_timeout);\n          register_name_fetch_count++;\n          // only fetch register names when we don't have them\n          // assumption is that the names don't change over time\n          cmds.push(constants.IGNORE_ERRORS_TOKEN_STR + \"-data-list-register-names\");\n        } else {\n          register_name_fetch_timeout = setTimeout(() => {\n            register_name_fetch_count--;\n          }, 5000);\n        }\n      }\n      // update all registers values\n      cmds.push(constants.IGNORE_ERRORS_TOKEN_STR + \"-data-list-register-values x\");\n    } else {\n      Registers.clear_cached_values();\n    }\n    return cmds;\n  }\n  static cache_register_names(names: any) {\n    // filter out non-empty names\n    store.set(\n      \"register_names\",\n      names.filter((name: any) => name)\n    );\n  }\n  static clear_register_name_cache() {\n    store.set(\"register_names\", []);\n  }\n  static clear_cached_values() {\n    store.set(\"previous_register_values\", {});\n    store.set(\"current_register_values\", {});\n  }\n  static inferior_program_exited() {\n    Registers.clear_cached_values();\n  }\n  render() {\n    let num_register_names = store.get(\"register_names\").length,\n      num_register_values = Object.keys(store.get(\"current_register_values\")).length;\n\n    if (this.state.inferior_program !== constants.inferior_states.paused) {\n      return <span className=\"placeholder\">no data to display</span>;\n    }\n\n    if (\n      (num_register_names > 0 &&\n        num_register_values > 0 &&\n        num_register_names !== num_register_values) ||\n      (num_register_names === 0 &&\n        register_name_fetch_count <= MAX_REGISTER_NAME_FETCH_COUNT)\n    ) {\n      // Somehow register names and values do not match. Clear cached values, then refetch both.\n      Registers.clear_register_name_cache();\n      Registers.clear_cached_values();\n      GdbApi.run_gdb_command(Registers.get_update_cmds());\n    } else if (num_register_names === num_register_values) {\n      let columns = [\"name\", \"value (hex)\", \"value (decimal)\", \"description\"],\n        register_table_data = [],\n        register_names = store.get(\"register_names\"),\n        register_values = store.get(\"current_register_values\"),\n        prev_register_values = store.get(\"previous_register_values\");\n\n      for (let i in register_names) {\n        let name = register_names[i],\n          // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name '_'.\n          obj = _.find(register_values, (v: any) => v[\"number\"] === i),\n          hex_val_raw = \"\",\n          disp_hex_val = \"\",\n          disp_dec_val = \"\",\n          // @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message\n          register_description = register_descriptions[name] || \"\";\n\n        if (obj && obj.value) {\n          hex_val_raw = obj[\"value\"];\n\n          // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name '_'.\n          let old_obj = _.find(prev_register_values, (v: any) => v[\"number\"] === i),\n            old_hex_val_raw,\n            changed = false;\n          if (old_obj) {\n            old_hex_val_raw = old_obj[\"value\"];\n          }\n\n          // if the value changed, highlight it\n          if (old_hex_val_raw !== undefined && hex_val_raw !== old_hex_val_raw) {\n            changed = true;\n          }\n\n          // if hex value is a valid value, convert it to a link\n          // and display decimal format too\n          if (obj[\"value\"].indexOf(\"0x\") === 0) {\n            disp_hex_val = Memory.make_addrs_into_links_react(hex_val_raw);\n            disp_dec_val = parseInt(obj[\"value\"], 16).toString(10);\n          }\n\n          if (changed) {\n            name = <span className=\"highlight bold\">{name}</span>;\n            // @ts-expect-error ts-migrate(2322) FIXME: Type 'Element' is not assignable to type 'string'.\n            disp_hex_val = <span className=\"highlight bold\">{disp_hex_val}</span>;\n            // @ts-expect-error ts-migrate(2322) FIXME: Type 'Element' is not assignable to type 'string'.\n            disp_dec_val = <span className=\"highlight bold\">{disp_dec_val}</span>;\n          }\n        }\n\n        register_table_data.push([\n          name,\n          disp_hex_val,\n          disp_dec_val,\n          register_description\n        ]);\n      }\n      return (\n        <ReactTable\n          data={register_table_data}\n          // @ts-expect-error ts-migrate(2769) FIXME: Type 'string[]' is not assignable to type 'never[]... Remove this comment to see the full error message\n          header={columns}\n          style={{ fontSize: \"0.9em\" }}\n        />\n      );\n    }\n    return <span className=\"placeholder\">no data to display</span>;\n  }\n}\n\nexport default Registers;\n"
  },
  {
    "path": "gdbgui/src/js/RightSidebar.tsx",
    "content": "/**\n * A component to show/hide variable exploration when hovering over a variable\n * in the source code\n */\n\nimport React from \"react\";\n\nimport Breakpoints from \"./Breakpoints\";\nimport constants from \"./constants\";\nimport Expressions from \"./Expressions\";\nimport GdbMiOutput from \"./GdbMiOutput\";\nimport InferiorProgramInfo from \"./InferiorProgramInfo\";\nimport Locals from \"./Locals\";\nimport Memory from \"./Memory\";\nimport Registers from \"./Registers\";\nimport Tree from \"./Tree\";\nimport Threads from \"./Threads\";\nimport ToolTipTourguide from \"./ToolTipTourguide\";\n\nlet onmouseup_in_parent_callbacks: any = [],\n  onmousemove_in_parent_callbacks: any = [];\n\nlet onmouseup_in_parent_callback = function() {\n  // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'fn' implicitly has an 'any' type.\n  onmouseup_in_parent_callbacks.map(fn => fn());\n};\nlet onmousemove_in_parent_callback = function(e: any) {\n  // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'fn' implicitly has an 'any' type.\n  onmousemove_in_parent_callbacks.map(fn => {\n    fn(e);\n  });\n};\n\ntype OwnCollapserState = any;\n\ntype CollapserState = OwnCollapserState & typeof Collapser.defaultProps;\n\nclass Collapser extends React.Component<{}, CollapserState> {\n  static defaultProps = { collapsed: false, id: \"\" };\n  _height_when_clicked: any;\n  _page_y_orig: any;\n  _resizing: any;\n  collapser_box_node: any;\n  constructor(props: {}) {\n    // @ts-expect-error ts-migrate(2554) FIXME: Expected 1-2 arguments, but got 0.\n    super();\n    this.state = {\n      // @ts-expect-error ts-migrate(2339) FIXME: Property 'collapsed' does not exist on type '{}'.\n      collapsed: props.collapsed,\n      autosize: true,\n      height_px: null, // if an integer, force height to this value\n      _mouse_y_click_pos_px: null,\n      _height_when_clicked: null\n    };\n    this.onmousedown_resizer = this.onmousedown_resizer.bind(this);\n    this.onmouseup_resizer = this.onmouseup_resizer.bind(this);\n    this.onmousemove_resizer = this.onmousemove_resizer.bind(this);\n    this.onclick_restore_autosize = this.onclick_restore_autosize.bind(this);\n\n    onmouseup_in_parent_callbacks.push(this.onmouseup_resizer.bind(this));\n    onmousemove_in_parent_callbacks.push(this.onmousemove_resizer.bind(this));\n  }\n  toggle_visibility() {\n    this.setState({ collapsed: !this.state.collapsed });\n  }\n  onmousedown_resizer(e: any) {\n    this._resizing = true;\n    this._page_y_orig = e.pageY;\n    this._height_when_clicked = this.collapser_box_node.clientHeight;\n  }\n  onmouseup_resizer() {\n    this._resizing = false;\n  }\n  onmousemove_resizer(e: any) {\n    if (this._resizing) {\n      let dh = e.pageY - this._page_y_orig;\n      this.setState({\n        height_px: this._height_when_clicked + dh,\n        autosize: false\n      });\n    }\n  }\n  onclick_restore_autosize() {\n    this.setState({ autosize: true });\n  }\n  render() {\n    let style = {\n      height: this.state.autosize ? \"auto\" : this.state.height_px + \"px\",\n      overflow: this.state.autosize ? \"visible\" : \"auto\"\n    };\n\n    let reset_size_button = \"\";\n    if (!this.state.autosize) {\n      // @ts-expect-error ts-migrate(2322) FIXME: Type 'Element' is not assignable to type 'string'.\n      reset_size_button = (\n        <span\n          onClick={this.onclick_restore_autosize}\n          className=\"placeholder\"\n          title={\n            \"Height frozen at \" + this.state.height_px + \"px. Click to restore autosize.\"\n          }\n          style={{\n            // @ts-expect-error ts-migrate(2322) FIXME: Object literal may only specify known properties, ... Remove this comment to see the full error message\n            align: \"right\",\n            position: \"relative\",\n            top: \"-10px\",\n            cursor: \"pointer\"\n          }}\n        >\n          reset height\n        </span>\n      );\n    }\n\n    let resizer = \"\";\n    if (!this.state.collapsed) {\n      // @ts-expect-error ts-migrate(2322) FIXME: Type 'Element' is not assignable to type 'string'.\n      resizer = (\n        <React.Fragment>\n          <div\n            className=\"rowresizer\"\n            onMouseDown={this.onmousedown_resizer}\n            style={{ textAlign: \"right\" }}\n            title=\"Click and drag to resize height\"\n          >\n            {\" \"}\n            {reset_size_button}\n          </div>\n        </React.Fragment>\n      );\n    }\n\n    return (\n      <div className=\"collapser\">\n        <div className=\"pointer titlebar\" onClick={this.toggle_visibility.bind(this)}>\n          <span\n            className={`glyphicon glyphicon-chevron-${\n              this.state.collapsed ? \"right\" : \"down\"\n            }`}\n            style={{ marginRight: \"6px\" }}\n          />\n          {/* @ts-expect-error ts-migrate(2339) FIXME: Property 'title' does not exist on type 'Readonly<... Remove this comment to see the full error message */}\n          <span className=\"lighttext\">{this.props.title}</span>\n        </div>\n\n        <div\n          className={this.state.collapsed ? \"hidden\" : \"\"}\n          // @ts-expect-error ts-migrate(2339) FIXME: Property 'id' does not exist on type 'Readonly<{}>... Remove this comment to see the full error message\n          id={this.props.id}\n          style={style}\n          ref={n => (this.collapser_box_node = n)}\n        >\n          {/* @ts-expect-error ts-migrate(2339) FIXME: Property 'content' does not exist on type 'Readonl... Remove this comment to see the full error message */}\n          {this.props.content}\n        </div>\n\n        {resizer}\n      </div>\n    );\n  }\n}\n\nclass RightSidebar extends React.Component {\n  render() {\n    let input_style = {\n        display: \"inline\",\n        width: \"100px\",\n        padding: \"6px 6px\",\n        height: \"25px\",\n        fontSize: \"1em\"\n      },\n      mi_output = \"\";\n    // @ts-expect-error ts-migrate(2339) FIXME: Property 'debug' does not exist on type 'Readonly<... Remove this comment to see the full error message\n    if (this.props.debug) {\n      // @ts-expect-error ts-migrate(2322) FIXME: Type 'Element' is not assignable to type 'string'.\n      mi_output = (\n        // @ts-expect-error ts-migrate(2322) FIXME: Property 'title' does not exist on type 'Intrinsic... Remove this comment to see the full error message\n        <Collapser title=\"gdb mi output\" content={<GdbMiOutput id=\"gdb_mi_output\" />} />\n      );\n    }\n\n    return (\n      <div\n        className=\"content\"\n        onMouseUp={onmouseup_in_parent_callback}\n        onMouseMove={onmousemove_in_parent_callback}\n      >\n        <ToolTipTourguide\n          // @ts-expect-error ts-migrate(2322) FIXME: Property 'position' does not exist on type 'Intrin... Remove this comment to see the full error message\n          position={\"topleft\"}\n          content={\n            <div>\n              <h5>\n                This sidebar contains a visual, interactive representation of the state of\n                your program\n              </h5>\n              <p>\n                You can see which function the process is stopped in, explore variables,\n                and much more.\n              </p>\n              <p>\n                There is more to discover, but this should be enough to get you started.\n              </p>\n              <p>\n                Something missing? Found a bug?{\" \"}\n                <a href=\"https://github.com/cs01/gdbgui/issues/\">Create an issue</a> on\n                github.\n              </p>\n\n              <p>Happy debugging!</p>\n            </div>\n          }\n          step_num={5}\n        />\n\n        {/* @ts-expect-error ts-migrate(2322) FIXME: Property 'title' does not exist on type 'Intrinsic... Remove this comment to see the full error message */}\n        <Collapser title=\"threads\" content={<Threads />} />\n\n        {/* @ts-expect-error ts-migrate(2322) FIXME: Property 'title' does not exist on type 'Intrinsic... Remove this comment to see the full error message */}\n        <Collapser id=\"locals\" title=\"local variables\" content={<Locals />} />\n        {/* @ts-expect-error ts-migrate(2322) FIXME: Property 'title' does not exist on type 'Intrinsic... Remove this comment to see the full error message */}\n        <Collapser id=\"expressions\" title=\"expressions\" content={<Expressions />} />\n        <Collapser\n          // @ts-expect-error ts-migrate(2322) FIXME: Property 'title' does not exist on type 'Intrinsic... Remove this comment to see the full error message\n          title=\"Tree\"\n          content={\n            <div>\n              <input\n                id=\"tree_width\"\n                className=\"form-control\"\n                placeholder=\"width (px)\"\n                style={input_style}\n              />\n              <input\n                id=\"tree_height\"\n                className=\"form-control\"\n                placeholder=\"height (px)\"\n                style={input_style}\n              />\n              <div id={constants.tree_component_id} />\n            </div>\n          }\n        />\n        {/* @ts-expect-error ts-migrate(2322) FIXME: Property 'title' does not exist on type 'Intrinsic... Remove this comment to see the full error message */}\n        <Collapser id=\"memory\" title=\"memory\" content={<Memory />} />\n        {/* @ts-expect-error ts-migrate(2322) FIXME: Property 'title' does not exist on type 'Intrinsic... Remove this comment to see the full error message */}\n        <Collapser title=\"breakpoints\" content={<Breakpoints />} />\n        <Collapser\n          // @ts-expect-error ts-migrate(2322) FIXME: Property 'title' does not exist on type 'Intrinsic... Remove this comment to see the full error message\n          title=\"signals\"\n          // @ts-expect-error ts-migrate(2322) FIXME: Property 'signals' does not exist on type 'Intrins... Remove this comment to see the full error message\n          content={<InferiorProgramInfo signals={this.props.signals} />}\n        />\n        {/* @ts-expect-error ts-migrate(2322) FIXME: Property 'title' does not exist on type 'Intrinsic... Remove this comment to see the full error message */}\n        <Collapser title=\"registers\" collapsed={true} content={<Registers />} />\n\n        {mi_output}\n      </div>\n    );\n  }\n  componentDidMount() {\n    Tree.init();\n  }\n}\nexport default RightSidebar;\n"
  },
  {
    "path": "gdbgui/src/js/Settings.tsx",
    "content": "import { store } from \"statorgfc\";\nimport Actions from \"./Actions\";\nimport ToolTip from \"./ToolTip\";\nimport React from \"react\";\n\n/**\n * Settings modal when clicking the gear icon\n */\nclass Settings extends React.Component {\n  max_source_file_lines_input: any;\n  save_button: any;\n  settings_node: any;\n  constructor() {\n    // @ts-expect-error ts-migrate(2554) FIXME: Expected 1-2 arguments, but got 0.\n    super();\n    // @ts-expect-error ts-migrate(2339) FIXME: Property 'connectComponentState' does not exist on... Remove this comment to see the full error message\n    store.connectComponentState(this, [\n      \"debug\",\n      \"current_theme\",\n      \"themes\",\n      \"gdb_version\",\n      \"gdb_pid\",\n      \"show_settings\",\n      \"auto_add_breakpoint_to_main\",\n      \"pretty_print\",\n      \"refresh_state_after_sending_console_command\",\n      \"show_all_sent_commands_in_console\",\n      \"highlight_source_code\"\n    ]);\n    this.get_update_max_lines_of_code_to_fetch = this.get_update_max_lines_of_code_to_fetch.bind(\n      this\n    );\n  }\n  static toggle_key(key: any) {\n    store.set(key, !store.get(key));\n    localStorage.setItem(key, JSON.stringify(store.get(key)));\n  }\n  static get_checkbox_row(store_key: any, text: any) {\n    return (\n      <tr>\n        <td>\n          <div className=\"checkbox\">\n            <label>\n              <input\n                type=\"checkbox\"\n                checked={store.get(store_key)}\n                onChange={() => Settings.toggle_key(store_key)}\n              />\n              {text}\n            </label>\n          </div>\n        </td>\n      </tr>\n    );\n  }\n  get_update_max_lines_of_code_to_fetch() {\n    return (\n      <tr>\n        <td>\n          Maximum number of source file lines to display:\n          <input\n            style={{ width: \"100px\", marginLeft: \"10px\" }}\n            defaultValue={store.get(\"max_lines_of_code_to_fetch\")}\n            ref={el => (this.max_source_file_lines_input = el)}\n          />\n          <button\n            ref={n => (this.save_button = n)}\n            onClick={() => {\n              let new_value = parseInt(this.max_source_file_lines_input.value);\n              Actions.update_max_lines_of_code_to_fetch(new_value);\n              // @ts-expect-error ts-migrate(2345) FIXME: Argument of type '1' is not assignable to paramete... Remove this comment to see the full error message\n              ToolTip.show_tooltip_on_node(\"saved!\", this.save_button, 1);\n            }}\n          >\n            save\n          </button>\n        </td>\n      </tr>\n    );\n  }\n  get_table() {\n    return (\n      <table className=\"table table-condensed\">\n        <tbody>\n          {Settings.get_checkbox_row(\n            \"auto_add_breakpoint_to_main\",\n            \"Add breakpoint to main after loading executable\"\n          )}\n          {this.get_update_max_lines_of_code_to_fetch()}\n          {Settings.get_checkbox_row(\n            \"pretty_print\",\n            \"Pretty print dynamic variables (requires restart)\"\n          )}\n          {Settings.get_checkbox_row(\n            \"refresh_state_after_sending_console_command\",\n            \"Refresh all components when a command is sent from the console\"\n          )}\n          {Settings.get_checkbox_row(\n            \"show_all_sent_commands_in_console\",\n            \"Print all sent commands in console, including those sent automatically by gdbgui\"\n          )}\n          {Settings.get_checkbox_row(\n            \"highlight_source_code\",\n            \"Add syntax highlighting to source files\"\n          )}\n\n          <tr>\n            <td>\n              Theme:{\" \"}\n              <select\n                value={store.get(\"current_theme\")}\n                onChange={function(e) {\n                  store.set(\"current_theme\", e.currentTarget.value);\n                  localStorage.setItem(\"theme\", e.currentTarget.value);\n                }}\n              >\n                {store.get(\"themes\").map((t: any) => (\n                  <option key={t}>{t}</option>\n                ))}\n              </select>\n            </td>\n          </tr>\n        </tbody>\n      </table>\n    );\n  }\n\n  render() {\n    return (\n      <div\n        className={store.get(\"show_settings\") ? \"fullscreen_modal\" : \"hidden\"}\n        ref={el => (this.settings_node = el)}\n        onClick={e => {\n          if (e.target === this.settings_node) {\n            Settings.toggle_key(\"show_settings\");\n          }\n        }}\n      >\n        <div id=\"gdb_settings_modal\">\n          <button className=\"close\" onClick={() => Settings.toggle_key(\"show_settings\")}>\n            ×\n          </button>\n          <h4>Settings</h4>\n          {this.get_table()}\n          <div className=\"modal-footer\" style={{ marginTop: \"20px\" }}>\n            <button\n              className=\"btn btn-success\"\n              onClick={() => Settings.toggle_key(\"show_settings\")}\n              data-dismiss=\"modal\"\n            >\n              Close\n            </button>\n          </div>\n        </div>\n      </div>\n    );\n  }\n}\n\nexport default Settings;\n"
  },
  {
    "path": "gdbgui/src/js/SourceCode.tsx",
    "content": "/**\n * A component to render source code, assembly, and break points\n */\n\nimport { store } from \"statorgfc\";\nimport React from \"react\";\nimport FileOps from \"./FileOps\";\nimport Breakpoints from \"./Breakpoints\";\nimport Memory from \"./Memory\";\nimport MemoryLink from \"./MemoryLink\";\nimport constants from \"./constants\";\nimport Actions from \"./Actions\";\n\ntype State = any;\n\nclass SourceCode extends React.Component<{}, State> {\n  static el_code_container = null; // todo: no jquery\n  static el_code_container_node = null;\n  static code_container_node = null;\n  static view_more_top_node = null;\n  static view_more_bottom_node = null;\n\n  constructor() {\n    // @ts-expect-error ts-migrate(2554) FIXME: Expected 1-2 arguments, but got 0.\n    super();\n    // @ts-expect-error ts-migrate(2339) FIXME: Property 'connectComponentState' does not exist on... Remove this comment to see the full error message\n    store.connectComponentState(this, [\n      \"fullname_to_render\",\n      \"cached_source_files\",\n      \"missing_files\",\n      \"disassembly_for_missing_file\",\n      \"line_of_source_to_flash\",\n      \"paused_on_frame\",\n      \"breakpoints\",\n      \"source_code_state\",\n      \"make_current_line_visible\",\n      \"source_code_selection_state\",\n      \"current_theme\",\n      \"inferior_binary_path\",\n      \"source_linenum_to_display_start\",\n      \"source_linenum_to_display_end\",\n      \"max_lines_of_code_to_fetch\",\n      \"source_code_infinite_scrolling\"\n    ]);\n\n    // bind methods\n    this.get_body_assembly_only = this.get_body_assembly_only.bind(this);\n    this._get_source_line = this._get_source_line.bind(this);\n    this._get_assm_row = this._get_assm_row.bind(this);\n    this.click_gutter = this.click_gutter.bind(this);\n    this.is_gdb_paused_on_this_line = this.is_gdb_paused_on_this_line.bind(this);\n  }\n\n  render() {\n    return (\n      <div className={this.state.current_theme} style={{ height: \"100%\" }}>\n        <table\n          id=\"code_table\"\n          className={this.state.current_theme}\n          style={{ width: \"100%\" }}\n        >\n          <tbody id=\"code_body\">{this.get_body()}</tbody>\n        </table>\n      </div>\n    );\n  }\n\n  componentDidUpdate() {\n    let source_is_displayed =\n      this.state.source_code_state === constants.source_code_states.SOURCE_CACHED ||\n      this.state.source_code_state ===\n        constants.source_code_states.ASSM_AND_SOURCE_CACHED;\n    if (source_is_displayed) {\n      if (this.state.make_current_line_visible) {\n        let success = SourceCode.make_current_line_visible();\n        if (success) {\n          store.set(\"make_current_line_visible\", false);\n        }\n      }\n    }\n  }\n\n  get_body() {\n    const states = constants.source_code_states;\n    switch (this.state.source_code_state) {\n      case states.ASSM_AND_SOURCE_CACHED: // fallthrough\n      case states.SOURCE_CACHED: {\n        let obj = FileOps.get_source_file_obj_from_cache(this.state.fullname_to_render);\n        if (!obj) {\n          console.error(\"expected to find source file\");\n          return this.get_body_empty();\n        }\n        let paused_addr = this.state.paused_on_frame\n            ? this.state.paused_on_frame.addr\n            : null,\n          start_linenum = store.get(\"source_linenum_to_display_start\"),\n          end_linenum = store.get(\"source_linenum_to_display_end\");\n        return this.get_body_source_and_assm(\n          obj.fullname,\n          obj.source_code_obj,\n          obj.assembly,\n          paused_addr,\n          start_linenum,\n          end_linenum,\n          obj.num_lines_in_file\n        );\n      }\n      case states.FETCHING_SOURCE: {\n        return (\n          <tr>\n            <td>fetching source, please wait</td>\n          </tr>\n        );\n      }\n      case states.ASSM_CACHED: {\n        let paused_addr = this.state.paused_on_frame\n            ? this.state.paused_on_frame.addr\n            : null,\n          assm_array = this.state.disassembly_for_missing_file;\n        return this.get_body_assembly_only(assm_array, paused_addr);\n      }\n      case states.FETCHING_ASSM: {\n        return (\n          <tr>\n            <td>fetching assembly, please wait</td>\n          </tr>\n        );\n      }\n      case states.ASSM_UNAVAILABLE: {\n        let paused_addr = this.state.paused_on_frame\n          ? this.state.paused_on_frame.addr\n          : null;\n        return (\n          <tr>\n            <td>cannot access address {paused_addr}</td>\n          </tr>\n        );\n      }\n      case states.FILE_MISSING: {\n        return (\n          <tr>\n            <td>file not found: {this.state.fullname_to_render}</td>\n          </tr>\n        );\n      }\n      case states.NONE_AVAILABLE: {\n        return this.get_body_empty();\n      }\n      default: {\n        console.error(\"developer error: unhandled state\");\n        return this.get_body_empty();\n      }\n    }\n  }\n  click_gutter(line_num: any) {\n    Breakpoints.add_or_remove_breakpoint(this.state.fullname_to_render, line_num);\n  }\n\n  _get_source_line(\n    source: any,\n    line_should_flash: any,\n    is_gdb_paused_on_this_line: any,\n    line_num_being_rendered: any,\n    has_bkpt: any,\n    has_disabled_bkpt: any,\n    has_conditional_bkpt: any,\n    assembly_for_line: any,\n    paused_addr: any\n  ) {\n    let row_class = [\"srccode\"];\n\n    if (is_gdb_paused_on_this_line) {\n      row_class.push(\"paused_on_line\");\n    } else if (line_should_flash) {\n      row_class.push(\"flash\");\n    }\n\n    let id = \"\";\n    if (\n      this.state.source_code_selection_state ===\n      constants.source_code_selection_states.PAUSED_FRAME\n    ) {\n      if (is_gdb_paused_on_this_line) {\n        id = \"scroll_to_line\";\n      }\n    } else if (\n      this.state.source_code_selection_state ===\n      constants.source_code_selection_states.USER_SELECTION\n    ) {\n      if (line_should_flash) {\n        id = \"scroll_to_line\";\n      }\n    }\n\n    let gutter_cls = \"\";\n    if (has_disabled_bkpt) {\n      gutter_cls = \"disabled_breakpoint\";\n    } else if (has_conditional_bkpt) {\n      gutter_cls = \"conditional_breakpoint\";\n    } else if (has_bkpt) {\n      gutter_cls = \"breakpoint\";\n    }\n\n    let assembly_content = [];\n    if (assembly_for_line) {\n      let i = 0;\n      for (let assm of assembly_for_line) {\n        assembly_content.push(SourceCode._get_assm_content(i, assm, paused_addr));\n        assembly_content.push(<br key={\"br\" + i} />);\n        i++;\n      }\n    }\n\n    return (\n      <tr id={id} key={line_num_being_rendered} className={`${row_class.join(\" \")}`}>\n        {this.get_linenum_td(line_num_being_rendered, gutter_cls)}\n\n        <td style={{ verticalAlign: \"top\" }} className=\"loc\">\n          <span className=\"wsp\" dangerouslySetInnerHTML={{ __html: source }} />\n        </td>\n\n        <td className=\"assembly\">{assembly_content}</td>\n      </tr>\n    );\n  }\n  get_linenum_td(linenum: any, gutter_cls = \"\") {\n    return (\n      <td\n        style={{ verticalAlign: \"top\", width: \"30px\" }}\n        className={\"line_num \" + gutter_cls}\n        onClick={() => {\n          this.click_gutter(linenum);\n        }}\n      >\n        <div>{linenum}</div>\n      </td>\n    );\n  }\n\n  /**\n   * example return value: mov $0x400684,%edi(00) main+8 0x0000000000400585\n   */\n  static _get_assm_content(key: any, assm: any, paused_addr: any) {\n    let opcodes = assm.opcodes ? (\n        <span className=\"instrContent\">{`(${assm.opcodes})`}</span>\n      ) : (\n        \"\"\n      ),\n      instruction = Memory.make_addrs_into_links_react(assm.inst),\n      func_name = assm[\"func-name\"],\n      offset = assm.offset,\n      addr = assm.address,\n      on_current_instruction = paused_addr === assm.address,\n      cls = on_current_instruction ? \"current_assembly_command\" : \"\",\n      asterisk = on_current_instruction ? (\n        <span\n          className=\"glyphicon glyphicon-chevron-right\"\n          style={{ width: \"10px\", display: \"inline-block\" }}\n        />\n      ) : (\n        <span style={{ width: \"10px\", display: \"inline-block\" }}> </span>\n      );\n    return (\n      <span key={key} style={{ whiteSpace: \"nowrap\" }} className={cls}>\n        {/* @ts-expect-error ts-migrate(2769) FIXME: Property 'fontFamily' is missing in type '{ paddin... Remove this comment to see the full error message */}\n        {asterisk} <MemoryLink addr={addr} style={{ paddingRight: \"5px\" }} />\n        {opcodes /* i.e. mov */}\n        <span className=\"instrContent\">{instruction}</span>\n        {func_name ? (\n          <span>\n            {func_name}+{offset}\n          </span>\n        ) : (\n          \"\"\n        )}\n      </span>\n    );\n  }\n\n  _get_assm_row(key: any, assm: any, paused_addr: any) {\n    return (\n      <tr key={key} className=\"srccode\">\n        <td className=\"assembly loc\">\n          {SourceCode._get_assm_content(key, assm, paused_addr)}\n        </td>\n      </tr>\n    );\n  }\n\n  is_gdb_paused_on_this_line(line_num_being_rendered: any, line_gdb_is_paused_on: any) {\n    if (this.state.paused_on_frame) {\n      return (\n        line_num_being_rendered === line_gdb_is_paused_on &&\n        this.state.paused_on_frame.fullname === this.state.fullname_to_render\n      );\n    } else {\n      return false;\n    }\n  }\n  get_view_more_tr(fullname: any, linenum: any, node_key: any) {\n    return (\n      // @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message\n      <tr key={linenum} className=\"srccode\" ref={el => (SourceCode[node_key] = el)}>\n        <td />\n        <td\n          onClick={() => {\n            Actions.view_file(fullname, linenum);\n          }}\n          style={{ fontStyle: \"italic\", paddingLeft: \"10px\" }}\n          className=\"pointer\"\n        >\n          view more\n        </td>\n      </tr>\n    );\n  }\n  get_end_of_file_tr(linenum: any) {\n    return (\n      <tr key={linenum}>\n        <td />\n        <td style={{ fontStyle: \"italic\", paddingLeft: \"10px\", fontSize: \"0.8em\" }}>\n          (end of file)\n        </td>\n      </tr>\n    );\n  }\n  get_line_nums_to_render(\n    source_code_obj: any,\n    start_linenum: any,\n    line_to_flash: any,\n    end_linenum: any\n  ) {\n    let start_linenum_to_render = start_linenum;\n    let end_linenum_to_render = end_linenum;\n    let linenum = start_linenum;\n\n    // go backwards from center until missing element is found\n    // linenum >= start_linenum &&\n    while (linenum < end_linenum) {\n      if (source_code_obj.hasOwnProperty(linenum)) {\n        start_linenum_to_render = linenum;\n        break;\n      } else {\n        linenum++;\n      }\n    }\n\n    linenum = end_linenum;\n    while (linenum > start_linenum) {\n      if (source_code_obj.hasOwnProperty(linenum)) {\n        end_linenum_to_render = linenum;\n        break;\n      } else {\n        linenum--;\n      }\n    }\n    return { start_linenum_to_render, end_linenum_to_render };\n  }\n  get_body_source_and_assm(\n    fullname: any,\n    source_code_obj: any,\n    assembly: any,\n    paused_addr: any,\n    start_linenum: any,\n    end_linenum: any,\n    num_lines_in_file: any\n  ) {\n    let body = [];\n\n    let bkpt_lines = Breakpoints.get_breakpoint_lines_for_file(\n        this.state.fullname_to_render\n      ),\n      disabled_breakpoint_lines = Breakpoints.get_disabled_breakpoint_lines_for_file(\n        this.state.fullname_to_render\n      ),\n      conditional_breakpoint_lines = Breakpoints.get_conditional_breakpoint_lines_for_file(\n        this.state.fullname_to_render\n      ),\n      line_gdb_is_paused_on = this.state.paused_on_frame\n        ? parseInt(this.state.paused_on_frame.line)\n        : 0;\n\n    const line_of_source_to_flash = this.state.line_of_source_to_flash;\n    const {\n      start_linenum_to_render,\n      end_linenum_to_render\n    } = this.get_line_nums_to_render(\n      source_code_obj,\n      start_linenum,\n      line_of_source_to_flash,\n      end_linenum\n    );\n\n    let line_num_being_rendered = start_linenum_to_render;\n    while (line_num_being_rendered <= end_linenum_to_render) {\n      let cur_line_of_code = source_code_obj[line_num_being_rendered];\n      let has_bkpt = bkpt_lines.indexOf(line_num_being_rendered) !== -1,\n        has_disabled_bkpt =\n          disabled_breakpoint_lines.indexOf(line_num_being_rendered) !== -1,\n        has_conditional_bkpt =\n          conditional_breakpoint_lines.indexOf(line_num_being_rendered) !== -1,\n        is_gdb_paused_on_this_line = this.is_gdb_paused_on_this_line(\n          line_num_being_rendered,\n          line_gdb_is_paused_on\n        ),\n        assembly_for_line = assembly[line_num_being_rendered];\n\n      body.push(\n        this._get_source_line(\n          cur_line_of_code,\n          line_of_source_to_flash === line_num_being_rendered,\n          is_gdb_paused_on_this_line,\n          line_num_being_rendered,\n          has_bkpt,\n          has_disabled_bkpt,\n          has_conditional_bkpt,\n          assembly_for_line,\n          paused_addr\n        )\n      );\n      line_num_being_rendered++;\n    }\n\n    SourceCode.view_more_top_node = null;\n    SourceCode.view_more_bottom_node = null;\n\n    // add \"view more\" buttons if necessary\n    if (start_linenum_to_render > start_linenum) {\n      body.unshift(\n        this.get_view_more_tr(fullname, start_linenum_to_render - 1, \"view_more_top_node\")\n      );\n    } else if (start_linenum !== 1) {\n      body.unshift(\n        this.get_view_more_tr(fullname, start_linenum - 1, \"view_more_top_node\")\n      );\n    }\n\n    if (end_linenum_to_render < end_linenum) {\n      body.push(\n        this.get_view_more_tr(\n          fullname,\n          end_linenum_to_render + 1,\n          \"view_more_bottom_node\"\n        )\n      );\n    } else if (end_linenum < num_lines_in_file) {\n      body.push(\n        this.get_view_more_tr(fullname, line_num_being_rendered, \"view_more_bottom_node\")\n      );\n    }\n\n    if (end_linenum_to_render === num_lines_in_file) {\n      body.push(this.get_end_of_file_tr(num_lines_in_file + 1));\n    }\n    return body;\n  }\n\n  get_body_assembly_only(assm_array: any, paused_addr: any) {\n    let body = [],\n      i = 0;\n    for (let assm of assm_array) {\n      body.push(this._get_assm_row(i, assm, paused_addr));\n      i++;\n    }\n    return body;\n  }\n\n  get_body_empty() {\n    return (\n      <tr>\n        <td>no source code or assembly to display</td>\n      </tr>\n    );\n  }\n  static make_current_line_visible() {\n    return SourceCode._make_jq_selector_visible($(\"#scroll_to_line\"));\n  }\n  static is_source_line_visible(jq_selector: any) {\n    if (jq_selector.length !== 1) {\n      // make sure something is selected before trying to scroll to it\n      throw \"Unexpected jquery selector\";\n    }\n\n    // @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.\n    let top_of_container = SourceCode.el_code_container.position().top,\n      // @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.\n      height_of_container = SourceCode.el_code_container.height(),\n      bottom_of_container = top_of_container + height_of_container,\n      top_of_line = jq_selector.position().top,\n      bottom_of_line = top_of_line + jq_selector.height(),\n      top_of_table = jq_selector.closest(\"table\").position().top,\n      is_visible =\n        top_of_line >= top_of_container && bottom_of_line <= bottom_of_container;\n\n    if (is_visible) {\n      return { is_visible: true, top_of_line, top_of_table, height_of_container };\n    } else {\n      return { is_visible: false, top_of_line, top_of_table, height_of_container };\n    }\n  }\n  /**\n   * Scroll to a jQuery selection in the source code table\n   * Used to jump around to various lines\n   * returns true on success\n   */\n  static _make_jq_selector_visible(jq_selector: any) {\n    if (jq_selector.length === 1) {\n      // make sure something is selected before trying to scroll to it\n      const {\n        is_visible,\n        top_of_line,\n        top_of_table,\n        height_of_container\n      } = SourceCode.is_source_line_visible(jq_selector);\n\n      if (!is_visible) {\n        // line is out of view, scroll so it's in the middle of the table\n        const time_to_scroll = 0;\n        let scroll_top = top_of_line - (top_of_table + height_of_container / 2);\n        // @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.\n        SourceCode.el_code_container.animate({ scrollTop: scroll_top }, time_to_scroll);\n      }\n      return true;\n    } else {\n      return false;\n    }\n  }\n}\n\nexport default SourceCode;\n"
  },
  {
    "path": "gdbgui/src/js/SourceCodeHeading.tsx",
    "content": "import React from \"react\";\nimport constants from \"./constants\";\nimport { store } from \"statorgfc\";\nimport { FileLink } from \"./Links\";\nimport FileOps from \"./FileOps\";\n\ntype State = any;\n\nclass SourceCodeHeading extends React.Component<{}, State> {\n  constructor() {\n    // @ts-expect-error ts-migrate(2554) FIXME: Expected 1-2 arguments, but got 0.\n    super();\n    // @ts-expect-error ts-migrate(2339) FIXME: Property 'connectComponentState' does not exist on... Remove this comment to see the full error message\n    store.connectComponentState(this, [\n      \"fullname_to_render\",\n      \"paused_on_frame\",\n      \"line_of_source_to_flash\",\n      \"source_code_selection_state\"\n    ]);\n  }\n  render() {\n    let line;\n    if (\n      this.state.source_code_selection_state ===\n        constants.source_code_selection_states.PAUSED_FRAME &&\n      this.state.paused_on_frame\n    ) {\n      line = this.state.paused_on_frame.line;\n    } else {\n      line = this.state.line_of_source_to_flash;\n    }\n\n    let num_lines = 0;\n    if (\n      this.state.fullname_to_render &&\n      FileOps.get_source_file_obj_from_cache(this.state.fullname_to_render)\n    ) {\n      // @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.\n      num_lines = FileOps.get_num_lines_in_file(this.state.fullname_to_render);\n    }\n    return (\n      <FileLink\n        fullname={this.state.fullname_to_render}\n        file={this.state.fullname_to_render}\n        line={line}\n        num_lines={num_lines}\n      />\n    );\n  }\n}\n\nexport default SourceCodeHeading;\n"
  },
  {
    "path": "gdbgui/src/js/SourceFileAutocomplete.tsx",
    "content": "import { store } from \"statorgfc\";\nimport constants from \"./constants\";\nimport Actions from \"./Actions\";\nimport Util from \"./Util\";\nimport FileOps from \"./FileOps\";\nimport React from \"react\";\n\n/**\n * The autocomplete dropdown of source files is complicated enough\n * to have its own component. It uses the awesomeplete library,\n * which is really nice: https://leaverou.github.io/awesomplete/\n */\n\nconst help_text = \"Enter file path to view, press enter\";\n/* global Awesomplete */\nclass SourceFileAutocomplete extends React.Component {\n  awesomeplete_input: any;\n  html_input: any;\n  constructor() {\n    // @ts-expect-error ts-migrate(2554) FIXME: Expected 1-2 arguments, but got 0.\n    super();\n    // @ts-expect-error ts-migrate(2339) FIXME: Property 'subscribeToKeys' does not exist on type ... Remove this comment to see the full error message\n    store.subscribeToKeys([\"source_file_paths\"], this.store_change_callback.bind(this));\n  }\n  store_change_callback() {\n    // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name '_'.\n    if (!_.isEqual(this.awesomeplete_input._list, store.get(\"source_file_paths\"))) {\n      this.awesomeplete_input.list = store.get(\"source_file_paths\");\n    }\n  }\n  render() {\n    return (\n      <div style={{ width: \"100%\", flex: \"1 0\", padding: \"5px\" }} className=\"flex\">\n        <input\n          id=\"source_file_input\"\n          autoComplete=\"off\"\n          placeholder={help_text}\n          title={help_text}\n          className=\"dropdown-input\"\n          onKeyUp={this.keyup_source_file_input.bind(this)}\n          role=\"combobox\"\n          ref={el => (this.html_input = el)}\n          style={{ width: \"100%\" }}\n        />\n        <button\n          id=\"source_file_dropdown_button\"\n          style={{ float: \"right\" }}\n          type=\"button\"\n          className=\"dropdown-btn\"\n          onClick={this.onclick_dropdown.bind(this)}\n        >\n          <span className=\"caret\" />\n        </button>\n      </div>\n    );\n  }\n  keyup_source_file_input(e: any) {\n    if (e.keyCode === constants.ENTER_BUTTON_NUM) {\n      // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name '_'.\n      let user_input = _.trim(e.currentTarget.value);\n\n      if (user_input.length === 0) {\n        return;\n      }\n\n      let fullname,\n        default_line = 0,\n        line;\n      // @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'number' is not assignable to par... Remove this comment to see the full error message\n      [fullname, line] = Util.parse_fullname_and_line(user_input, default_line);\n      FileOps.user_select_file_to_view(fullname, line);\n    } else if (store.get(\"source_file_paths\").length === 0) {\n      // source file list has not been fetched yet, so fetch it\n      Actions.fetch_source_files();\n    }\n  }\n  onclick_dropdown() {\n    if (store.get(\"source_file_paths\").length === 0) {\n      // we have not asked gdb to get the list of source paths yet, or it just doesn't have any.\n      // request that gdb populate this list.\n      Actions.fetch_source_files();\n      return;\n    }\n\n    if (this.awesomeplete_input.ul.childNodes.length === 0) {\n      this.awesomeplete_input.evaluate();\n    } else if (this.awesomeplete_input.ul.hasAttribute(\"hidden\")) {\n      this.awesomeplete_input.open();\n    } else {\n      this.awesomeplete_input.close();\n    }\n  }\n  componentDidMount() {\n    // initialize list of source files\n    // TODO maybe use a pre-built React component for this\n    // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name 'Awesomplete'.\n    this.awesomeplete_input = new Awesomplete(\"#source_file_input\", {\n      minChars: 0,\n      maxItems: 10000,\n      list: [],\n      // standard sort algorithm (the default Awesomeplete sort is weird)\n      sort: (a: any, b: any) => {\n        return a < b ? -1 : 1;\n      }\n    });\n\n    // perform action when an item is selected\n    this.html_input.addEventListener(\"awesomplete-selectcomplete\", function(e: any) {\n      let fullname = e.currentTarget.value;\n      FileOps.user_select_file_to_view(fullname, 1);\n    });\n  }\n}\n\nexport default SourceFileAutocomplete;\n"
  },
  {
    "path": "gdbgui/src/js/StatusBar.tsx",
    "content": "import React from \"react\";\nimport Util from \"./Util\";\nimport { store } from \"statorgfc\";\n\ntype State = any;\n\n/**\n * Component to render a status message with optional error/warning label\n */\nclass StatusBar extends React.Component<{}, State> {\n  render() {\n    if (this.state.waiting_for_response) {\n      return <span className=\"glyphicon glyphicon-refresh glyphicon-refresh-animate\" />;\n    } else {\n      return \"\";\n    }\n  }\n}\n\nexport default StatusBar;\n"
  },
  {
    "path": "gdbgui/src/js/Terminals.tsx",
    "content": "import React from \"react\";\nimport GdbApi from \"./GdbApi\";\nimport { Terminal } from \"xterm\";\nimport { FitAddon } from \"xterm-addon-fit\";\nimport { store } from \"statorgfc\";\nimport \"xterm/css/xterm.css\";\nimport constants from \"./constants\";\nimport Actions from \"./Actions\";\n\nfunction customKeyEventHandler(config: {\n  pty_name: string;\n  pty: Terminal;\n  canPaste: boolean;\n  pidStoreKey: string;\n}) {\n  return async (e: KeyboardEvent): Promise<boolean> => {\n    if (!(e.type === \"keydown\")) {\n      return true;\n    }\n    if (e.shiftKey && e.ctrlKey) {\n      const key = e.key.toLowerCase();\n      if (key === \"c\") {\n        const toCopy = config.pty.getSelection();\n        navigator.clipboard.writeText(toCopy);\n        config.pty.focus();\n        return false;\n      } else if (key === \"v\") {\n        if (!config.canPaste) {\n          return false;\n        }\n        const toPaste = await navigator.clipboard.readText();\n\n        GdbApi.getSocket().emit(\"pty_interaction\", {\n          data: { pty_name: config.pty_name, key: toPaste, action: \"write\" }\n        });\n        return false;\n      }\n    }\n    return true;\n  };\n}\nexport class Terminals extends React.Component {\n  userPtyRef: React.RefObject<any>;\n  programPtyRef: React.RefObject<any>;\n  gdbguiPtyRef: React.RefObject<any>;\n  constructor(props: any) {\n    super(props);\n    this.userPtyRef = React.createRef();\n    this.programPtyRef = React.createRef();\n    this.gdbguiPtyRef = React.createRef();\n    this.terminal = this.terminal.bind(this);\n  }\n\n  terminal(ref: React.RefObject<any>) {\n    let className = \" bg-black p-0 m-0 h-full align-baseline \";\n    return (\n      <div className={className}>\n        <div className=\"absolute h-full w-1/3 align-baseline  \" ref={ref}></div>\n      </div>\n    );\n  }\n  render() {\n    let terminalsClass = \"w-full h-full relative grid grid-cols-3 \";\n    return (\n      <div className={terminalsClass}>\n        {this.terminal(this.userPtyRef)}\n        {/* <GdbGuiTerminal /> */}\n        {this.terminal(this.gdbguiPtyRef)}\n        {this.terminal(this.programPtyRef)}\n      </div>\n    );\n  }\n\n  componentDidMount() {\n    const fitAddon = new FitAddon();\n    const programFitAddon = new FitAddon();\n    const gdbguiFitAddon = new FitAddon();\n\n    const userPty = new Terminal({\n      cursorBlink: true,\n      macOptionIsMeta: true,\n      scrollback: 9999\n    });\n    userPty.loadAddon(fitAddon);\n    userPty.open(this.userPtyRef.current);\n    userPty.writeln(`running command: ${store.get(\"gdb_command\")}`);\n    userPty.writeln(\"\");\n    userPty.attachCustomKeyEventHandler(\n      // @ts-expect-error\n      customKeyEventHandler({\n        pty_name: \"user_pty\",\n        pty: userPty,\n        canPaste: true,\n        pidStoreKey: \"gdb_pid\"\n      })\n    );\n    GdbApi.getSocket().on(\"user_pty_response\", function(data: string) {\n      userPty.write(data);\n    });\n    userPty.onKey((data, ev) => {\n      GdbApi.getSocket().emit(\"pty_interaction\", {\n        data: { pty_name: \"user_pty\", key: data.key, action: \"write\" }\n      });\n      if (data.domEvent.code === \"Enter\") {\n        Actions.onConsoleCommandRun();\n      }\n    });\n\n    const programPty = new Terminal({\n      cursorBlink: true,\n      macOptionIsMeta: true,\n      scrollback: 9999\n    });\n    programPty.loadAddon(programFitAddon);\n    programPty.open(this.programPtyRef.current);\n    programPty.attachCustomKeyEventHandler(\n      // @ts-expect-error\n      customKeyEventHandler({\n        pty_name: \"program_pty\",\n        pty: programPty,\n        canPaste: true,\n        pidStoreKey: \"inferior_pid\"\n      })\n    );\n    programPty.write(constants.xtermColors.grey);\n    programPty.write(\n      \"Program output -- Programs being debugged are connected to this terminal. \" +\n        \"You can read output and send input to the program from here.\"\n    );\n    programPty.writeln(constants.xtermColors.reset);\n    GdbApi.getSocket().on(\"program_pty_response\", function(pty_response: string) {\n      programPty.write(pty_response);\n    });\n    programPty.onKey((data, ev) => {\n      GdbApi.getSocket().emit(\"pty_interaction\", {\n        data: { pty_name: \"program_pty\", key: data.key, action: \"write\" }\n      });\n    });\n\n    const gdbguiPty = new Terminal({\n      cursorBlink: false,\n      macOptionIsMeta: true,\n      scrollback: 9999,\n      disableStdin: true\n      // theme: { background: \"#888\" }\n    });\n    gdbguiPty.write(constants.xtermColors.grey);\n    gdbguiPty.writeln(\"gdbgui output (read-only)\");\n    gdbguiPty.writeln(\n      \"Copy/Paste available in all terminals with ctrl+shift+c, ctrl+shift+v\"\n    );\n    gdbguiPty.write(constants.xtermColors.reset);\n\n    gdbguiPty.attachCustomKeyEventHandler(\n      // @ts-expect-error\n      customKeyEventHandler({ pty_name: \"unused\", pty: gdbguiPty, canPaste: false })\n    );\n\n    gdbguiPty.loadAddon(gdbguiFitAddon);\n    gdbguiPty.open(this.gdbguiPtyRef.current);\n    // gdbguiPty is written to elsewhere\n    store.set(\"gdbguiPty\", gdbguiPty);\n\n    const interval = setInterval(() => {\n      fitAddon.fit();\n      programFitAddon.fit();\n      gdbguiFitAddon.fit();\n      const socket = GdbApi.getSocket();\n\n      if (socket.disconnected) {\n        return;\n      }\n      socket.emit(\"pty_interaction\", {\n        data: {\n          pty_name: \"user_pty\",\n          rows: userPty.rows,\n          cols: userPty.cols,\n          action: \"set_winsize\"\n        }\n      });\n\n      socket.emit(\"pty_interaction\", {\n        data: {\n          pty_name: \"program_pty\",\n          rows: programPty.rows,\n          cols: programPty.cols,\n          action: \"set_winsize\"\n        }\n      });\n    }, 2000);\n\n    setTimeout(() => {\n      fitAddon.fit();\n      programFitAddon.fit();\n      gdbguiFitAddon.fit();\n    }, 0);\n  }\n}\n"
  },
  {
    "path": "gdbgui/src/js/Threads.tsx",
    "content": "import React from \"react\";\nimport ReactTable from \"./ReactTable\";\nimport { store } from \"statorgfc\";\nimport GdbApi from \"./GdbApi\";\nimport Memory from \"./Memory\";\nimport { FileLink } from \"./Links\";\nimport MemoryLink from \"./MemoryLink\";\n\nclass FrameArguments extends React.Component {\n  render_frame_arg(frame_arg: any) {\n    return [frame_arg.name, frame_arg.value];\n  }\n\n  render() {\n    // @ts-expect-error ts-migrate(2339) FIXME: Property 'args' does not exist on type 'Readonly<{... Remove this comment to see the full error message\n    let frame_args = this.props.args;\n    // @ts-expect-error ts-migrate(2339) FIXME: Property 'args' does not exist on type 'Readonly<{... Remove this comment to see the full error message\n    if (!this.props.args) {\n      frame_args = [];\n    }\n    return (\n      <ReactTable\n        // @ts-expect-error ts-migrate(2769) FIXME: Property 'data' does not exist on type 'IntrinsicA... Remove this comment to see the full error message\n        data={frame_args.map(this.render_frame_arg)}\n        style={{ fontSize: \"0.9em\", borderWidth: \"0\" }}\n      />\n    );\n  }\n}\n\ntype ThreadsState = any;\n\nclass Threads extends React.Component<{}, ThreadsState> {\n  constructor() {\n    // @ts-expect-error ts-migrate(2554) FIXME: Expected 1-2 arguments, but got 0.\n    super();\n    // @ts-expect-error ts-migrate(2339) FIXME: Property 'connectComponentState' does not exist on... Remove this comment to see the full error message\n    store.connectComponentState(this, [\n      \"threads\",\n      \"current_thread_id\",\n      \"stack\",\n      \"selected_frame_num\"\n    ]);\n  }\n\n  static select_thread_id(thread_id: any) {\n    GdbApi.select_thread_id(thread_id);\n  }\n\n  static select_frame(framenum: any) {\n    store.set(\"selected_frame_num\", framenum);\n    store.set(\"line_of_source_to_flash\", null);\n    store.set(\"make_current_line_visible\", true);\n    GdbApi.select_frame(framenum);\n  }\n\n  render() {\n    if (this.state.threads.length <= 0) {\n      return <span className=\"placeholder\" />;\n    }\n\n    let content = [];\n\n    for (let thread of this.state.threads) {\n      let is_current_thread_being_rendered =\n        parseInt(thread.id) === this.state.current_thread_id;\n      let stack = Threads.get_stack_for_thread(\n        thread.frame,\n        this.state.stack,\n        is_current_thread_being_rendered\n      );\n      let row_data;\n      try {\n        row_data = Threads.get_row_data_for_stack(\n          stack,\n          this.state.selected_frame_num,\n          thread.id,\n          is_current_thread_being_rendered\n        );\n      } catch (err) {\n        row_data = [\"unknown\", \"unknown\", \"unknown\"];\n        console.log(err);\n      }\n      content.push(Threads.get_thread_header(thread, is_current_thread_being_rendered));\n      content.push(\n        // @ts-expect-error ts-migrate(2769) FIXME: Type 'string' is not assignable to type 'never'.\n        <ReactTable\n          data={row_data}\n          style={{ fontSize: \"0.9em\", marginBottom: 0 }}\n          key={thread.id}\n          header={[\"func\", \"file\", \"addr\", \"args\"]}\n          classes={[\"table-bordered\", \"table-striped\"]}\n        />\n      );\n      content.push(<br key={thread.id + \"br\"} />);\n    }\n    return <div>{content}</div>;\n  }\n\n  static get_stack_for_thread(\n    cur_frame: any,\n    stack_data: any,\n    is_current_thread_being_rendered: any\n  ) {\n    // each thread provides only the frame that it's paused on (cur_frame).\n    // we also have the output of `-stack-list-frames` (stack_data), which\n    // is the full stack of the selected thread\n    if (is_current_thread_being_rendered) {\n      for (let frame of stack_data) {\n        if (frame && cur_frame && frame.addr === cur_frame.addr) {\n          return stack_data;\n        }\n      }\n    }\n    return [cur_frame];\n  }\n\n  static get_thread_header(thread: any, is_current_thread_being_rendered: any) {\n    let selected,\n      cls = \"\";\n    if (is_current_thread_being_rendered) {\n      cls = \"bold\";\n      selected = (\n        <span\n          className=\"label label-primary\"\n          title=\"This thread is selected. Variables can be inspected for the current frame of this thread.\"\n        >\n          selected\n        </span>\n      );\n    } else {\n      selected = (\n        <button\n          className=\"pointer btn btn-default btn-xs\"\n          onClick={() => {\n            Threads.select_thread_id(thread.id);\n          }}\n          title=\"Select this thread\"\n          style={{ fontSize: \"75%\" }}\n        >\n          select\n        </button>\n      );\n    }\n    const details = Memory.make_addrs_into_links_react(thread[\"target-id\"]);\n    const core = thread.core ? `, core ${thread.core}` : \"\";\n    const state = \", \" + thread.state;\n    const id = \", id \" + thread.id;\n    const name = thread.name ? `, ${thread.name}` : \"\";\n    return (\n      <span key={\"thread\" + thread.id} className={`${cls}`} style={{ fontSize: \"0.9em\" }}>\n        {selected} {details}\n        {id}\n        {core}\n        {state}\n        {name}\n      </span>\n    );\n  }\n  static get_frame_row(\n    frame: any,\n    is_selected_frame: any,\n    thread_id: any,\n    is_current_thread_being_rendered: any,\n    frame_num: any\n  ) {\n    let onclick;\n    let classes = [];\n    let title;\n\n    if (is_selected_frame) {\n      // current frame, current thread\n      onclick = () => {};\n      classes.push(\"bold\");\n      title = `this is the active frame of the selected thread (frame id ${frame_num})`;\n    } else if (is_current_thread_being_rendered) {\n      onclick = () => {\n        Threads.select_frame(frame_num);\n      };\n      classes.push(\"pointer\");\n      title = `click to select this frame (frame id ${frame_num})`;\n    } else {\n      // different thread, allow user to switch threads\n      onclick = () => {\n        Threads.select_thread_id(thread_id);\n      };\n      classes.push(\"pointer\");\n      title = `click to select this thead (thread id ${thread_id})`;\n    }\n    let key = thread_id + frame_num;\n\n    return [\n      <span key={key} title={title} className={classes.join(\" \")} onClick={onclick}>\n        {frame.func}\n      </span>,\n      <FileLink fullname={frame.fullname} file={frame.file} line={frame.line} />,\n      <MemoryLink addr={frame.addr} />,\n      // @ts-expect-error ts-migrate(2769) FIXME: Property 'args' does not exist on type 'IntrinsicA... Remove this comment to see the full error message\n      <FrameArguments args={frame.args} />\n    ];\n  }\n\n  static get_row_data_for_stack(\n    stack: any,\n    selected_frame_num: any,\n    thread_id: any,\n    is_current_thread_being_rendered: any\n  ) {\n    let row_data = [];\n    let frame_num = 0;\n    for (let frame of stack) {\n      let is_selected_frame =\n        selected_frame_num === frame_num && is_current_thread_being_rendered;\n      row_data.push(\n        Threads.get_frame_row(\n          frame || {},\n          is_selected_frame,\n          thread_id,\n          is_current_thread_being_rendered,\n          frame_num\n        )\n      );\n      frame_num++;\n    }\n\n    if (stack.length === 0) {\n      row_data.push([\"unknown\", \"unknown\", \"unknown\"]);\n    }\n    return row_data;\n  }\n  static update_stack(stack: any) {\n    store.set(\"stack\", stack);\n    store.set(\"paused_on_frame\", stack[store.get(\"selected_frame_num\") || 0]);\n    store.set(\n      \"fullname_to_render\",\n      store.get(\"paused_on_frame\") ? store.get(\"paused_on_frame\").fullname : {}\n    );\n    store.set(\"line_of_source_to_flash\", parseInt(store.get(\"paused_on_frame\").line));\n    store.set(\"current_assembly_address\", store.get(\"paused_on_frame\").addr);\n    store.set(\"make_current_line_visible\", true);\n  }\n  set_thread_id(id: any) {\n    store.set(\"current_thread_id\", parseInt(id));\n  }\n}\n\nexport default Threads;\n"
  },
  {
    "path": "gdbgui/src/js/ToolTip.tsx",
    "content": "import React from \"react\";\nimport { store } from \"statorgfc\";\n\nclass ToolTip extends React.Component {\n  timeout: any;\n  constructor() {\n    // @ts-expect-error ts-migrate(2554) FIXME: Expected 1-2 arguments, but got 0.\n    super();\n    // @ts-expect-error ts-migrate(2339) FIXME: Property 'connectComponentState' does not exist on... Remove this comment to see the full error message\n    store.connectComponentState(this, [\"tooltip\"]);\n    this.timeout = null;\n  }\n  static hide_tooltip() {\n    store.set(\"tooltip\", {\n      hidden: true,\n      show_for_n_sec: null,\n      node: null,\n      content: null\n    });\n  }\n  static show_tooltip_on_node(content: any, node: any, show_for_n_sec = null) {\n    store.set(\"tooltip\", {\n      hidden: false,\n      show_for_n_sec: show_for_n_sec,\n      node: node,\n      content: content\n    });\n  }\n  static show_copied_tooltip_on_node(node: any) {\n    // @ts-expect-error ts-migrate(2345) FIXME: Argument of type '1' is not assignable to paramete... Remove this comment to see the full error message\n    ToolTip.show_tooltip_on_node(\"copied!\", node, 1);\n  }\n  render() {\n    clearTimeout(this.timeout);\n    const tooltip = store.get(\"tooltip\");\n    if (!tooltip.node || tooltip.hidden) {\n      return null;\n    }\n    let rect = tooltip.node.getBoundingClientRect(),\n      assumed_width_px = 200,\n      distance_to_right_edge = window.innerWidth - rect.x,\n      horizontal_buffer =\n        distance_to_right_edge < assumed_width_px\n          ? assumed_width_px - distance_to_right_edge\n          : 0,\n      left = rect.x - horizontal_buffer + \"px\",\n      top = rect.y + tooltip.node.offsetHeight + \"px\";\n    // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name '_'.\n    if (_.isInteger(tooltip.show_for_n_sec)) {\n      this.timeout = setTimeout(ToolTip.hide_tooltip, tooltip.show_for_n_sec * 1000);\n    }\n    return (\n      <div\n        style={{\n          top: top,\n          left: left,\n          maxWidth: \"350px\",\n          background: \"white\",\n          border: \"1px solid\",\n          position: \"fixed\",\n          padding: \"5px\",\n          zIndex: \"121\"\n        }}\n      >\n        {tooltip.content}\n      </div>\n    );\n  }\n}\n\nexport default ToolTip;\n"
  },
  {
    "path": "gdbgui/src/js/ToolTipTourguide.tsx",
    "content": "import React from \"react\";\nimport Util from \"./Util\";\nimport { store } from \"statorgfc\";\n\ntype State = any;\n\nclass ToolTipTourguide extends React.Component<{}, State> {\n  constructor(props: {}) {\n    super(props);\n    // @ts-expect-error ts-migrate(2339) FIXME: Property 'position' does not exist on type '{}'.\n    if (!props.position && !(props.top && props.left)) {\n      console.warn(\"did not receive position\");\n    }\n    // @ts-expect-error ts-migrate(2551) FIXME: Property 'ref' does not exist on type 'ToolTipTour... Remove this comment to see the full error message\n    this.ref = React.createRef();\n    // @ts-expect-error ts-migrate(2339) FIXME: Property 'connectComponentState' does not exist on... Remove this comment to see the full error message\n    store.connectComponentState(this, [\n      \"tour_guide_step\",\n      \"num_tour_guide_steps\",\n      \"show_tour_guide\"\n    ]);\n  }\n  componentWillMount() {\n    store.set(\"num_tour_guide_steps\", store.get(\"num_tour_guide_steps\") + 1);\n  }\n  static dismiss() {\n    store.set(\"show_tour_guide\", false);\n    store.set(\"tour_guide_step\", 0);\n    Util.persist_value_for_key(\"show_tour_guide\");\n  }\n  static next() {\n    store.set(\"tour_guide_step\", store.get(\"tour_guide_step\") + 1);\n  }\n  guide_finshed() {\n    store.set(\"tour_guide_step\", 0);\n  }\n  static start_guide() {\n    store.set(\"tour_guide_step\", 0);\n    store.set(\"show_tour_guide\", true);\n    Util.persist_value_for_key(\"show_tour_guide\");\n  }\n  componentDidUpdate() {\n    // @ts-expect-error ts-migrate(2551) FIXME: Property 'ref' does not exist on type 'ToolTipTour... Remove this comment to see the full error message\n    if (this.state.show_tour_guide && this.ref.current) {\n      // need to ensure absolute position is respected  by setting parent to\n      // relative\n      // @ts-expect-error ts-migrate(2551) FIXME: Property 'ref' does not exist on type 'ToolTipTour... Remove this comment to see the full error message\n      this.ref.current.parentNode.style.position = \"relative\";\n    }\n  }\n  get_position(position_name: any) {\n    let top, left;\n    switch (position_name) {\n      case \"left\":\n        top = \"100%\";\n        left = \"-50%\";\n        break;\n      case \"right\":\n        top = \"50%\";\n        left = \"0px\";\n        break;\n      case \"bottom\":\n      case \"bottomcenter\":\n        top = \"100%\";\n        left = \"50%\";\n        break;\n      case \"bottomleft\":\n        top = \"100%\";\n        left = \"0\";\n        break;\n      case \"topleft\":\n        top = \"0\";\n        left = \"0\";\n        break;\n      case \"overlay\":\n        top = \"50%\";\n        left = \"50%\";\n        break;\n      default:\n        // @ts-expect-error ts-migrate(2339) FIXME: Property 'position' does not exist on type 'Readon... Remove this comment to see the full error message\n        console.warn(\"invalid position \" + this.props.position);\n        top = \"100%\";\n        left = \"50%\";\n        break;\n    }\n    return [top, left];\n  }\n  render() {\n    if (!this.state.show_tour_guide) {\n      return null;\n      // @ts-expect-error ts-migrate(2339) FIXME: Property 'step_num' does not exist on type 'Readon... Remove this comment to see the full error message\n    } else if (this.props.step_num !== this.state.tour_guide_step) {\n      return null;\n    }\n\n    let top, left;\n    // @ts-expect-error ts-migrate(2339) FIXME: Property 'top' does not exist on type 'Readonly<{}... Remove this comment to see the full error message\n    if (this.props.top && this.props.left) {\n      // @ts-expect-error ts-migrate(2339) FIXME: Property 'top' does not exist on type 'Readonly<{}... Remove this comment to see the full error message\n      top = this.props.top;\n      // @ts-expect-error ts-migrate(2339) FIXME: Property 'left' does not exist on type 'Readonly<{... Remove this comment to see the full error message\n      left = this.props.left;\n    } else {\n      // @ts-expect-error ts-migrate(2339) FIXME: Property 'position' does not exist on type 'Readon... Remove this comment to see the full error message\n      [top, left] = this.get_position(this.props.position);\n    }\n\n    // @ts-expect-error ts-migrate(2339) FIXME: Property 'step_num' does not exist on type 'Readon... Remove this comment to see the full error message\n    let is_last_step = this.props.step_num + 1 === this.state.num_tour_guide_steps,\n      dismiss = is_last_step ? null : (\n        <span className=\"btn btn-default pointer\" onClick={ToolTipTourguide.dismiss}>\n          Dismiss\n        </span>\n      );\n    return (\n      <div\n        // @ts-expect-error ts-migrate(2551) FIXME: Property 'ref' does not exist on type 'ToolTipTour... Remove this comment to see the full error message\n        ref={this.ref}\n        style={{\n          minWidth: \"200px\",\n          maxWidth: \"350px\",\n          background: \"white\",\n          border: \"1px solid\",\n          padding: \"5px\",\n          zIndex: \"1000\",\n          position: \"absolute\",\n          overflow: \"auto\",\n          whiteSpace: \"normal\",\n          left: left,\n          top: top,\n          fontSize: \"small\"\n        }}\n      >\n        {/* @ts-expect-error ts-migrate(2339) FIXME: Property 'content' does not exist on type 'Readonl... Remove this comment to see the full error message */}\n        {this.props.content}\n        <p />\n        {/* @ts-expect-error ts-migrate(2339) FIXME: Property 'step_num' does not exist on type 'Readon... Remove this comment to see the full error message */}\n        {this.props.step_num + 1} of {this.state.num_tour_guide_steps}\n        <p />\n        {dismiss}\n        <span className=\"btn btn-primary pointer\" onClick={ToolTipTourguide.next}>\n          {is_last_step ? \"Finish\" : \"Next\"}\n        </span>\n      </div>\n    );\n  }\n}\n\nexport default ToolTipTourguide;\n"
  },
  {
    "path": "gdbgui/src/js/TopBar.tsx",
    "content": "import React from \"react\";\n\nimport { store } from \"statorgfc\";\nimport BinaryLoader from \"./BinaryLoader\";\nimport ControlButtons from \"./ControlButtons\";\nimport Settings from \"./Settings\";\nimport SourceCodeHeading from \"./SourceCodeHeading\";\nimport ToolTipTourguide from \"./ToolTipTourguide\";\nimport FileOps from \"./FileOps\";\nimport GdbApi from \"./GdbApi\";\nimport Actions from \"./Actions\";\nimport constants from \"./constants\";\nimport Util from \"./Util\";\n\nlet onkeyup_jump_to_line = (e: any) => {\n  if (e.keyCode === constants.ENTER_BUTTON_NUM) {\n    Actions.set_line_state(e.currentTarget.value);\n  }\n};\n\nlet show_license = function() {\n  Actions.show_modal(\n    \"gdbgui license\",\n    <React.Fragment>\n      <a href=\"https://github.com/cs01/gdbgui/blob/master/LICENSE\">\n        GNU General Public License v3.0\n      </a>\n      <p>Copyright © Chad Smith</p>\n      <p>This software can be used personally or commercially for free.</p>\n      <p>\n        Permissions of this strong copyleft license are conditioned on making available\n        complete source code of licensed works and modifications, which include larger\n        works using a licensed work, under the same license. Copyright and license notices\n        must be preserved. Contributors provide an express grant of patent rights.\n      </p>\n      <p>\n        If you wish to redistribute gdbgui as part of a closed source product, you can do\n        so for a fee. Contact chadsmith.software@gmail.com for details.\n      </p>\n    </React.Fragment>\n  );\n};\n\nlet About = {\n  show_about: function() {\n    Actions.show_modal(\n      \"About gdbgui\",\n      <div>\n        <div>gdbgui, v{store.get(\"gdbgui_version\")}</div>\n        <div>Copyright © Chad Smith</div>\n        <div>\n          <a href=\"https://chadsmith.dev\">chadsmith.dev</a>\n        </div>\n      </div>\n    );\n  }\n};\n\nlet show_session_info = function() {\n  Actions.show_modal(\n    \"session information\",\n    <React.Fragment>\n      <table>\n        <tbody>\n          <tr>\n            <td>gdb version: {store.get(\"gdb_version\")}</td>\n          </tr>\n          <tr>\n            <td>gdb pid for this tab: {store.get(\"gdb_pid\")}</td>\n          </tr>\n          <tr>\n            <td>gdbgui v{store.get(\"gdbgui_version\")}</td>\n          </tr>\n        </tbody>\n      </table>\n    </React.Fragment>\n  );\n};\n\nconst menu = (\n  <ul\n    style={{ height: 25, padding: 0, paddingRight: \"15px\", fontSize: \"1.3em\" }}\n    className=\"nav navbar-nav navbar-right\"\n  >\n    <li id=\"menudropdown\" className=\"dropdown\">\n      <a\n        href=\"#\"\n        data-toggle=\"dropdown\"\n        role=\"button\"\n        style={{ height: 25, padding: 0, paddingRight: 20 }}\n        className=\"dropdown-toggle\"\n      >\n        <span className=\"glyphicon glyphicon-menu-hamburger\"> </span>\n      </a>\n      <ul className=\"dropdown-menu\">\n        <li>\n          <a title=\"dashboard\" className=\"pointer\" href=\"/dashboard\">\n            Dashboard\n          </a>\n        </li>\n        <li>\n          <a\n            title=\"show guide\"\n            className=\"pointer\"\n            onClick={ToolTipTourguide.start_guide}\n          >\n            Show Guide\n          </a>\n        </li>\n        <li>\n          <a onClick={show_session_info} className=\"pointer\">\n            Session Information\n          </a>\n        </li>\n\n        <li role=\"separator\" className=\"divider\" />\n        <li>\n          <a href=\"https://github.com/cs01/gdbgui\" className=\"pointer\">\n            GitHub\n          </a>\n        </li>\n        <li>\n          <a href=\"http://gdbgui.com\" className=\"pointer\">\n            Homepage\n          </a>\n        </li>\n\n        <li>\n          <a href=\"https://www.youtube.com/channel/UCUCOSclB97r9nd54NpXMV5A\">\n            YouTube Channel\n          </a>\n        </li>\n\n        <li role=\"separator\" className=\"divider\" />\n        <li>\n          <a onClick={show_license} className=\"pointer\">\n            License\n          </a>\n        </li>\n        <li>\n          <a onClick={About.show_about} className=\"pointer\">\n            About gdbgui\n          </a>\n        </li>\n      </ul>\n\n      <ToolTipTourguide\n        // @ts-expect-error ts-migrate(2322) FIXME: Property 'top' does not exist on type 'IntrinsicAt... Remove this comment to see the full error message\n        top={\"100%\"}\n        left={\"-300px\"}\n        step_num={0}\n        content={\n          <div>\n            <h5>Welcome to gdbgui.</h5>\n            <p>\n              This guide can be shown at any time by clicking the menu button,\n              <span className=\"glyphicon glyphicon-menu-hamburger\"> </span>, then clicking\n              \"Show Guide\".\n            </p>\n          </div>\n        }\n      />\n    </li>\n  </ul>\n);\n\ntype State = any;\n\nclass TopBar extends React.Component<{}, State> {\n  spinner_timeout: any;\n  spinner_timeout_msec: any;\n  constructor() {\n    // @ts-expect-error ts-migrate(2554) FIXME: Expected 1-2 arguments, but got 0.\n    super();\n    // state local to the component\n    this.state = {\n      assembly_flavor: \"intel\", // default to intel (choices are 'att' or 'intel')\n      show_spinner: false\n    };\n    // global state attached to this component\n    // @ts-expect-error ts-migrate(2339) FIXME: Property 'connectComponentState' does not exist on... Remove this comment to see the full error message\n    store.connectComponentState(\n      this,\n      [\n        \"debug_in_reverse\",\n        \"reverse_supported\",\n        \"source_code_state\",\n        \"waiting_for_response\",\n        \"show_filesystem\",\n        \"latest_gdbgui_version\",\n        \"gdbgui_version\"\n      ],\n      this.store_update_callback.bind(this)\n    );\n\n    this.spinner_timeout = null;\n    this.spinner_timeout_msec = 5000;\n  }\n  store_update_callback(keys: any) {\n    if (keys.indexOf(\"waiting_for_response\") !== -1) {\n      this._clear_spinner_timeout();\n      this.setState({ show_spinner: false });\n      if (this.state.waiting_for_response === true) {\n        // false to true\n        this._set_spinner_timeout();\n      }\n    }\n  }\n  _set_spinner_timeout() {\n    this.spinner_timeout = setTimeout(() => {\n      if (this.state.waiting_for_response) {\n        this.setState({ show_spinner: true });\n      }\n    }, this.spinner_timeout_msec);\n  }\n  _clear_spinner_timeout() {\n    clearTimeout(this.spinner_timeout);\n  }\n  toggle_assembly_flavor() {\n    const flavor = this.state.assembly_flavor === \"att\" ? \"intel\" : \"att\";\n    this.setState({ assembly_flavor: flavor });\n    GdbApi.set_assembly_flavor(flavor);\n    Actions.clear_cached_assembly();\n    FileOps.fetch_assembly_cur_line();\n  }\n  get_controls() {\n    return (\n      <div\n        role=\"group\"\n        style={{ marginBottom: 6, height: 25, width: 250 }}\n        className=\"btn-group btn-group\"\n      >\n        <ToolTipTourguide\n          // @ts-expect-error ts-migrate(2322) FIXME: Property 'step_num' does not exist on type 'Intrin... Remove this comment to see the full error message\n          step_num={3}\n          position={\"bottomleft\"}\n          onClick={(e: any) => e.stopPropagation()}\n          content={\n            <div>\n              <h5>\n                These buttons allow you to control execution of the target you are\n                debugging.\n              </h5>\n              <p>\n                Hover over these buttons to see a description of their action. For\n                example, the <span className=\"glyphicon glyphicon-repeat\" /> button starts\n                (or restarts) a program from the beginning.\n              </p>\n              <p>\n                Each button has a keyboard shortcut. For example, you can press \"r\" to\n                start running.\n              </p>\n            </div>\n          }\n        />\n        <ControlButtons />\n      </div>\n    );\n  }\n  render() {\n    let toggle_assm_button = \"\";\n    if (\n      this.state.source_code_state ===\n        constants.source_code_states.ASSM_AND_SOURCE_CACHED ||\n      this.state.source_code_state === constants.source_code_states.ASSM_CACHED\n    ) {\n      // @ts-expect-error ts-migrate(2322) FIXME: Type 'Element' is not assignable to type 'string'.\n      toggle_assm_button = (\n        <button\n          onClick={this.toggle_assembly_flavor.bind(this)}\n          type=\"button\"\n          title={\"Toggle between assembly flavors. The options are att or intel.\"}\n          className={\"btn btn-default btn-xs\"}\n        >\n          <span\n            title={`Currently displaying ${this.state.assembly_flavor}. Click to toggle.`}\n          >\n            {this.state.assembly_flavor}\n          </span>\n        </button>\n      );\n    }\n\n    let reload_button_disabled = \"disabled\";\n    if (\n      this.state.source_code_state ===\n        constants.source_code_states.ASSM_AND_SOURCE_CACHED ||\n      this.state.source_code_state === constants.source_code_states.SOURCE_CACHED\n    ) {\n      reload_button_disabled = \"\";\n    }\n    let reload_button = (\n      <button\n        onClick={FileOps.refresh_cached_source_files}\n        type=\"button\"\n        title=\"Erase file from local cache and re-fetch it\"\n        className={\"btn btn-default btn-xs \" + reload_button_disabled}\n      >\n        <span>reload file</span>\n      </button>\n    );\n\n    let spinner = (\n      <span className=\"\" style={{ height: \"100%\", margin: \"5px\", width: \"14px\" }} />\n    );\n    if (this.state.show_spinner) {\n      spinner = (\n        <span\n          className=\"glyphicon glyphicon-refresh glyphicon-refresh-animate\"\n          style={{ height: \"100%\", margin: \"5px\", width: \"14px\" }}\n        />\n      );\n    }\n\n    let reverse_checkbox = (\n      <label\n        title={\n          \"when clicking buttons to the right, pass the `--reverse` \" +\n          \"flag to gdb in an attempt to debug in reverse. This is not always supported. \" +\n          \"rr is known to support reverse debugging. Keyboard shortcuts go in \" +\n          \"reverse when pressed with the shift key.\"\n        }\n        style={{ fontWeight: \"normal\", fontSize: \"0.9em\", margin: \"5px\" }}\n      >\n        <input\n          type=\"checkbox\"\n          disabled={!this.state.reverse_supported}\n          checked={store.get(\"debug_in_reverse\")}\n          onChange={e => {\n            store.set(\"debug_in_reverse\", e.target.checked);\n          }}\n        />\n        reverse\n      </label>\n    );\n\n    return (\n      <div\n        id=\"top\"\n        style={{ background: \"#f5f6f7\", position: \"absolute\", width: \"100%\" }}\n      >\n        <div className=\"flexrow\">\n          {/* @ts-expect-error ts-migrate(2322) FIXME: Property 'initial_user_input' does not exist on ty... Remove this comment to see the full error message */}\n          <BinaryLoader initial_user_input={this.props.initial_user_input} />\n          {spinner}\n          {reverse_checkbox}\n\n          {this.get_controls()}\n\n          <span\n            onClick={() => Settings.toggle_key(\"show_settings\")}\n            title=\"settings\"\n            className=\"pointer glyphicon glyphicon-cog\"\n            style={{ marginRight: \"10px\", fontSize: \"1.3em\" }}\n          />\n          {menu}\n        </div>\n\n        {/* @ts-expect-error ts-migrate(2322) FIXME: Object literal may only specify known properties, ... Remove this comment to see the full error message */}\n        <div style={{ marginTop: 3, whitespace: \"nowrap\" }} className=\"flexrow\">\n          <div\n            role=\"group\"\n            style={{ height: \"25px\", marginRight: \"10px\" }}\n            className=\"btn-group btn-group\"\n          >\n            <button\n              className=\"btn btn-default btn-xs\"\n              title=\"Toggle file explorer visibility\"\n              onClick={() => {\n                let middle_pane_sizes = store.get(\"middle_panes_split_obj\").getSizes(),\n                  file_explorer_size = middle_pane_sizes[0],\n                  source_size = middle_pane_sizes[1],\n                  sidebar_size = middle_pane_sizes[2],\n                  new_file_explorer_size,\n                  new_source_size,\n                  new_sidebar_size;\n\n                if (store.get(\"show_filesystem\")) {\n                  // hide it since it's shown right now\n                  new_file_explorer_size = 0;\n                  new_source_size = source_size + file_explorer_size / 2;\n                  new_sidebar_size = sidebar_size + file_explorer_size / 2;\n                } else {\n                  new_file_explorer_size = 30;\n                  new_source_size = Math.max(\n                    30,\n                    source_size - new_file_explorer_size / 2\n                  );\n                  new_sidebar_size = 99 - new_file_explorer_size - new_source_size;\n                }\n\n                store.set(\"show_filesystem\", !store.get(\"show_filesystem\"));\n                localStorage.setItem(\n                  \"show_filesystem\",\n                  JSON.stringify(store.get(\"show_filesystem\"))\n                ); // save this for next session\n                store\n                  .get(\"middle_panes_split_obj\")\n                  .setSizes([new_file_explorer_size, new_source_size, new_sidebar_size]);\n              }}\n            >\n              {store.get(\"show_filesystem\") ? \"hide filesystem\" : \"show filesystem\"}\n            </button>\n\n            <button\n              onClick={() => FileOps.fetch_assembly_cur_line()}\n              type=\"button\"\n              title=\"fetch disassembly\"\n              className=\"btn btn-default btn-xs\"\n            >\n              <span>fetch disassembly</span>\n            </button>\n\n            {reload_button}\n            {toggle_assm_button}\n          </div>\n\n          <input\n            onKeyUp={onkeyup_jump_to_line}\n            autoComplete=\"on\"\n            title=\"Enter line number, then press enter\"\n            placeholder=\"jump to line\"\n            style={{ width: 150, height: 25, marginLeft: 10 }}\n            className=\"form-control dropdown-input\"\n          />\n\n          <div\n            style={{\n              marginRight: 5,\n              marginLeft: 5,\n              marginTop: 5,\n              whiteSpace: \"nowrap\",\n              fontFamily: \"monospace\",\n              fontSize: \"0.7em\",\n              display: \"flex\",\n              overflow: \"auto\"\n            }}\n            className=\"lighttext\"\n          >\n            <SourceCodeHeading />\n          </div>\n        </div>\n      </div>\n    );\n  }\n  static needs_to_update_gdbgui_version() {\n    // to actually check each value:\n    try {\n      return Util.is_newer(\n        store.get(\"latest_gdbgui_version\"),\n        store.get(\"gdbgui_version\")\n      );\n    } catch (err) {\n      console.error(err);\n      return true;\n    }\n  }\n}\n\nexport default TopBar;\n"
  },
  {
    "path": "gdbgui/src/js/Tree.ts",
    "content": "// a widget to visualize a tree view of a variable with children\n// utilizes the amazing http://visjs.org library\n\n/* global vis */\nimport { store } from \"statorgfc\";\nimport GdbVariable from \"./GdbVariable\";\nimport constants from \"./constants\";\n\nconst Tree = {\n  el: null, // tree id must be available in DOM before calling `init`\n  width_input: null,\n  height_input: null,\n  init: function() {\n    // @ts-expect-error ts-migrate(2339) FIXME: Property 'subscribeToKeys' does not exist on type ... Remove this comment to see the full error message\n    store.subscribeToKeys(\n      [\"root_gdb_tree_var\", \"expressions\", \"root_gdb_tree_var\"],\n      Tree._render\n    );\n    let render_on_enter = (e: any) => {\n      if (e.keyCode === 13) {\n        Tree._render();\n      }\n    };\n    // @ts-expect-error ts-migrate(2322) FIXME: Type 'HTMLElement' is not assignable to type 'null... Remove this comment to see the full error message\n    Tree.el = document.getElementById(constants.tree_component_id);\n    // @ts-expect-error ts-migrate(2322) FIXME: Type 'HTMLElement' is not assignable to type 'null... Remove this comment to see the full error message\n    Tree.width_input = document.getElementById(\"tree_width\");\n    // @ts-expect-error ts-migrate(2322) FIXME: Type 'HTMLElement' is not assignable to type 'null... Remove this comment to see the full error message\n    Tree.height_input = document.getElementById(\"tree_height\");\n\n    // @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.\n    Tree.width_input.onkeyup = render_on_enter;\n    // @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.\n    Tree.height_input.onkeyup = render_on_enter;\n  },\n  network: null, // initialize to null\n  rendered_gdb_var_tree_root: null,\n  gdb_var_being_updated: null, // if user clicks deep in a tree, only rerender that subtree, don't start from root again\n\n  _render: function() {\n    let gdbvar = store.get(\"root_gdb_tree_var\");\n    if (!gdbvar) {\n      // @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.\n      Tree.el.innerHTML = `\n            <span class=placeholder>\n                create an Expression, then click <span class='glyphicon glyphicon-tree-deciduous'></span>\n                when viewing a variable with children to interactively explore a tree view. You can click nodes to\n                expand/collapse them.\n            </span>`;\n      return;\n    }\n\n    let expressions = store.get(\"expressions\"),\n      gdb_root_var_to_update = Tree.gdb_var_being_updated\n        ? Tree.gdb_var_being_updated\n        : gdbvar,\n      gdb_var_obj = GdbVariable.get_obj_from_gdb_var_name(\n        expressions,\n        gdb_root_var_to_update\n      );\n\n    if (!gdb_var_obj) {\n      // couldn't find this variable name in our list of variables. Probably was a local variable the\n      // user graphed, then hit continue, and the variable was erased by gdb. This is expected.\n      // \"GdbVariable\" that users enter persist between stepping through the program though,\n      // so it's not expected that this line will be executed for an expression\n      store.set(\"root_gdb_tree_var\", \"\");\n      return;\n    }\n\n    if (gdbvar === Tree.rendered_gdb_var_tree_root) {\n      // nodes is an Object with keys corresponding to node id's (which are gdb_var_names)\n      Tree._add_nodes_and_edges(\n        gdb_var_obj,\n        undefined,\n        // @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.\n        Tree.network.body.nodes,\n        // @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.\n        Tree.network.body.edges\n      );\n    } else {\n      Tree.render_new_network(gdb_var_obj);\n    }\n    Tree._update_canvas_size();\n    Tree.rendered_gdb_var_tree_root = gdbvar;\n    Tree.gdb_var_being_updated = null;\n  },\n  _update_canvas_size: function() {\n    // @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.\n    if (Tree.network && Tree.network.canvas && Tree.network.canvas.options) {\n      // @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.\n      if (parseInt(Tree.width_input.value)) {\n        // @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.\n        Tree.network.canvas.options[\"width\"] = parseInt(Tree.width_input.value) + \"px\";\n      } else {\n        // @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.\n        Tree.network.canvas.options[\"width\"] = \"100%\";\n      }\n      // @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.\n      if (Tree.height_input.value) {\n        // @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.\n        Tree.network.canvas.options[\"height\"] = parseInt(Tree.height_input.value) + \"px\";\n      } else {\n        // @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.\n        Tree.network.canvas.options[\"height\"] = \"100%\";\n      }\n    }\n  },\n  // @param node: gdb variable object\n  // @return string for node label in the tree\n  _get_node_label: function(node: any) {\n    let label = [];\n    if (node.value) {\n      label.push(node.value);\n    }\n    if (node.type) {\n      label.push(node.type);\n    }\n\n    if (node.children.some((c: any) => c.numchild === 0)) {\n      label.push(\"field(s):\");\n    }\n    // children field is only populated when user expands a data structure\n    // numchild is always present\n    // if children have been fetched and are simple values (i.e. don't have children of their own),\n    // show them in the same node. If the child has children of its own, show it as a \"hidden child\" of this node\n    let hidden_children = 0;\n    for (let child of node.children) {\n      if (child.numchild === 0) {\n        label.push(`${child.exp}: ${child.value} (${child.type})`);\n      } else {\n        hidden_children++;\n      }\n    }\n\n    if (node.show_children_in_ui === false && hidden_children > 0) {\n      // children have previously been fetched but are now hidden since user toggled visibility\n      let child_text = hidden_children === 1 ? \"child\" : \"children\";\n      label.push(`+ ${hidden_children} ${child_text}`);\n    } else if (node.numchild !== node.children.length) {\n      // children have not yet been fetched, but gdb told us this node has children. We don't know if they\n      // are \"simple\" values, or complex with children of their own. We just know they exist.\n      let child_text = node.numchild === 1 ? \"child\" : \"children\";\n      label.push(`+ ${node.numchild} ${child_text}`);\n    }\n    return label.join(\"\\n\");\n  },\n  // mutates Tree.nodes and Tree.edges  to (recursively) reflect node and its children\n  // by either adding new nodes, modifying existing nodes, or deleting nodes that should be hidden\n  // depending on the store of the existing nodes.\n  // If updating a node, the background is highlighted yellow if the value changed\n  // @param node: gdb variable object that should be added to Tree.nodes\n  // @param parent: parent node of node. undefined when node is root.\n  // @return nothing\n  _add_nodes_and_edges: function(node: any, parent: any) {\n    // add/update this node\n    let node_label = Tree._get_node_label(node);\n    // @ts-expect-error ts-migrate(2339) FIXME: Property 'nodes' does not exist on type '{ el: nul... Remove this comment to see the full error message\n    if (node.name in Tree.nodes._data) {\n      // compare old value and new value\n      // if value changed, make it yellow!\n      // @ts-expect-error ts-migrate(2339) FIXME: Property 'nodes' does not exist on type '{ el: nul... Remove this comment to see the full error message\n      let old_label = Tree.nodes._data[node.name].label,\n        bgcolor = node_label === old_label ? \"white\" : \"yellow\";\n      // @ts-expect-error ts-migrate(2339) FIXME: Property 'nodes' does not exist on type '{ el: nul... Remove this comment to see the full error message\n      Tree.nodes.update({\n        id: node.name,\n        label: Tree._get_node_label(node),\n        color: { background: bgcolor }\n      });\n    } else {\n      // @ts-expect-error ts-migrate(2339) FIXME: Property 'nodes' does not exist on type '{ el: nul... Remove this comment to see the full error message\n      Tree.nodes.add({ id: node.name, label: Tree._get_node_label(node) });\n    }\n\n    // add edge from this node to parent if it's not there\n    // @ts-expect-error ts-migrate(2339) FIXME: Property 'edges' does not exist on type '{ el: nul... Remove this comment to see the full error message\n    if (parent && !(node.name in Tree.edges._data)) {\n      // @ts-expect-error ts-migrate(2339) FIXME: Property 'edges' does not exist on type '{ el: nul... Remove this comment to see the full error message\n      Tree.edges.add({\n        id: node.name,\n        from: parent.name,\n        to: node.name,\n        label: node.exp\n      });\n    }\n\n    // add/update/delete child nodes\n    if (node.show_children_in_ui) {\n      // add/update child nodes\n      for (let child of node.children) {\n        if (child.numchild > 0) {\n          Tree._add_nodes_and_edges(child, node);\n        }\n      }\n    } else {\n      // recursively delete to make invisible\n      for (let child of node.children) {\n        Tree._dfs(child, function(node: any) {\n          // @ts-expect-error ts-migrate(2339) FIXME: Property 'nodes' does not exist on type '{ el: nul... Remove this comment to see the full error message\n          Tree.nodes.remove({ id: node.name });\n          // @ts-expect-error ts-migrate(2339) FIXME: Property 'edges' does not exist on type '{ el: nul... Remove this comment to see the full error message\n          Tree.edges.remove({ id: node.name });\n        });\n      }\n    }\n  },\n  // depth-first search of node and its children. `callback` is run on each node as it is visited by\n  // this function\n  _dfs: function(node: any, callback: any) {\n    callback(node);\n    for (let child of node.children) {\n      Tree._dfs(child, callback);\n    }\n  },\n  // sets Tree.network to be a visjs network consisting of root_gdb_var_obj and all its children\n  // @param root_gdb_var_obj root gdb variable object for which a network should be rendered\n  // @return nothing\n  render_new_network: function(root_gdb_var_obj: any) {\n    // @ts-expect-error ts-migrate(2339) FIXME: Property 'nodes' does not exist on type '{ el: nul... Remove this comment to see the full error message\n    Tree.nodes = new vis.DataSet();\n    // @ts-expect-error ts-migrate(2339) FIXME: Property 'edges' does not exist on type '{ el: nul... Remove this comment to see the full error message\n    Tree.edges = new vis.DataSet();\n    // @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.\n    Tree._add_nodes_and_edges(root_gdb_var_obj);\n\n    // create the network\n    var data = {\n      // @ts-expect-error ts-migrate(2339) FIXME: Property 'nodes' does not exist on type '{ el: nul... Remove this comment to see the full error message\n      nodes: Tree.nodes,\n      // @ts-expect-error ts-migrate(2339) FIXME: Property 'edges' does not exist on type '{ el: nul... Remove this comment to see the full error message\n      edges: Tree.edges\n    };\n\n    // options found by browsing through examples here:\n    // http://visjs.org/network_examples.html\n    const options = {\n      nodes: {\n        shape: \"box\",\n        color: { background: \"white\" }\n      },\n      layout: {\n        randomSeed: 0,\n        hierarchical: {\n          direction: \"UD\",\n          sortMethod: \"directed\"\n        }\n      },\n      interaction: { dragNodes: true },\n      physics: {\n        enabled: false\n      }\n    };\n\n    // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name 'vis'.\n    Tree.network = new vis.Network(Tree.el, data, options);\n\n    // http://visjs.org/examples/network/events/interactionEvents.html\n    // @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.\n    Tree.network.on(\"click\", function(params: any) {\n      // left click toggles child visibility\n      // @ts-expect-error ts-migrate(2683) FIXME: 'this' implicitly has type 'any' because it does n... Remove this comment to see the full error message\n      let gdb_var_name = this.getNodeAt(params.pointer.DOM);\n      Tree.gdb_var_being_updated = gdb_var_name;\n      if (!gdb_var_name) {\n        return;\n      }\n      if (gdb_var_name) {\n        GdbVariable._toggle_children_visibility(gdb_var_name);\n      }\n    });\n  }\n};\n\nexport default Tree;\n"
  },
  {
    "path": "gdbgui/src/js/Util.ts",
    "content": "import { store } from \"statorgfc\";\n\n/**\n * Some general utility methods\n */\nconst Util = {\n  persist_value_for_key: function(key: any) {\n    try {\n      let value = store.get(key);\n      localStorage.setItem(key, JSON.stringify(value));\n    } catch (err) {\n      console.error(err);\n    }\n  },\n  /**\n   * Get html table\n   * @param columns: array of strings\n   * @param data: array of arrays of data\n   */\n  get_table: function(columns: any, data: any, style = \"\") {\n    var result = [\n      `<table class='table table-bordered table-condensed' style=\"${style}\">`\n    ];\n    if (columns) {\n      result.push(\"<thead>\");\n      result.push(\"<tr>\");\n      for (let h of columns) {\n        result.push(`<th>${h}</th>`);\n      }\n      result.push(\"</tr>\");\n      result.push(\"</thead>\");\n    }\n\n    if (data) {\n      result.push(\"<tbody>\");\n      for (let row of data) {\n        result.push(\"<tr>\");\n        for (let cell of row) {\n          result.push(`<td>${cell}</td>`);\n        }\n        result.push(\"</tr>\");\n      }\n    }\n    result.push(\"</tbody>\");\n    result.push(\"</table>\");\n    return result.join(\"\\n\");\n  },\n  /**\n   * Escape gdb's output to be browser compatible\n   * @param s: string to mutate\n   */\n  escape: function(s: any) {\n    return s\n      .replace(/>/g, \"&gt;\")\n      .replace(/</g, \"&lt;\")\n      .replace(/\\\\n/g, \"<br>\")\n      .replace(/\\\\r/g, \"\")\n      .replace(/\\\\\"/g, '\"')\n      .replace(/\\\\t/g, \"&nbsp\");\n  },\n  /**\n   * take a string of html in JavaScript and strip out the html\n   * http://stackoverflow.com/a/822486/2893090\n   */\n  get_text_from_html: function(html: any) {\n    var tmp = document.createElement(\"DIV\");\n    tmp.innerHTML = html;\n    return tmp.textContent || tmp.innerText || \"\";\n  },\n  /**\n   * @param fullname_and_line: i.e. /path/to/file.c:78\n   * @param default_line_if_not_found: i.e. 0\n   * @return: Array, with 0'th element == path, 1st element == line\n   */\n  parse_fullname_and_line: function(\n    fullname_and_line: any,\n    default_line_if_not_found = undefined\n  ) {\n    let user_input_array = fullname_and_line.split(\":\"),\n      fullname = user_input_array[0],\n      line = default_line_if_not_found;\n    if (user_input_array.length === 2) {\n      line = user_input_array[1];\n    }\n    // @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'undefined' is not assignable to ... Remove this comment to see the full error message\n    return [fullname, parseInt(line)];\n  },\n  string_to_array_safe_quotes(str: any) {\n    let output = [],\n      cur_str = \"\",\n      in_quotes = false;\n\n    for (let i = 0; i < str.length; i++) {\n      let char = str[i];\n\n      if (char === '\"') {\n        in_quotes = !in_quotes;\n        cur_str += char;\n      } else if (char !== \" \" || (char === \" \" && in_quotes)) {\n        cur_str += char;\n      } else if (char === \" \") {\n        // got a space outside of quotes\n        if (cur_str === \"\") {\n          // a consecutive space. do nothing.\n        } else {\n          // save this argument, and reset cur_str\n          output.push(cur_str);\n          cur_str = \"\";\n        }\n      }\n    }\n    if (cur_str !== \"\") {\n      output.push(cur_str);\n    }\n    return output;\n  },\n  /* Return true is latest is > current\n    1.0.0, 0.9.9 -> true\n    0.1.0, 0.0.9 -> true\n    0.0.9, 0.0.8 -> false\n  */\n  is_newer(latest: any, current: any) {\n    latest = latest.split(\".\");\n    current = current.split(\".\");\n    if (latest.length !== current.length) {\n      return true;\n    }\n    for (let i in latest) {\n      if (latest[i] > current[i]) {\n        return true;\n      }\n    }\n    return false;\n  }\n};\n\nexport default Util;\n"
  },
  {
    "path": "gdbgui/src/js/constants.ts",
    "content": "let constants = {\n  ENTER_BUTTON_NUM: 13,\n  TAB_BUTTON_NUM: 9,\n  LEFT_BUTTON_NUM: 37,\n  UP_BUTTON_NUM: 38,\n  RIGHT_BUTTON_NUM: 39,\n  DOWN_BUTTON_NUM: 40,\n  Y_BUTTON_NUM: 89,\n  N_BUTTON_NUM: 78,\n  COMMA_BUTTON_NUM: 188,\n  DATE_FORMAT: \"dddd, MMMM Do YYYY, h:mm:ss a\",\n  IGNORE_ERRORS_TOKEN_STR: \"1\",\n  DISASSEMBLY_FOR_MISSING_FILE_STR: \"2\",\n  CREATE_VAR_STR: \"3\",\n  INLINE_DISASSEMBLY_STR: \"4\",\n\n  console_entry_type: {\n    SENT_COMMAND: \"SENT_COMMAND\",\n    STD_ERR: \"STD_ERR\",\n    STD_OUT: \"STD_OUT\",\n    GDBGUI_OUTPUT: \"GDBGUI_OUTPUT\",\n    GDBGUI_OUTPUT_RAW: \"GDBGUI_OUTPUT_RAW\",\n    AUTOCOMPLETE_OPTION: \"AUTOCOMPLETE_OPTION\"\n  },\n\n  source_code_selection_states: {\n    USER_SELECTION: \"USER_SELECTION\",\n    PAUSED_FRAME: \"PAUSED_FRAME\"\n  },\n\n  source_code_states: {\n    ASSM_AND_SOURCE_CACHED: \"ASSM_AND_SOURCE_CACHED\",\n    SOURCE_CACHED: \"SOURCE_CACHED\",\n    FETCHING_SOURCE: \"FETCHING_SOURCE\",\n    ASSM_CACHED: \"ASSM_CACHED\",\n    FETCHING_ASSM: \"FETCHING_ASSM\",\n    ASSM_UNAVAILABLE: \"ASSM_UNAVAILABLE\",\n    FILE_MISSING: \"FILE_MISSING\",\n    NONE_AVAILABLE: \"NONE_AVAILABLE\"\n  },\n\n  inferior_states: {\n    unknown: \"unknown\",\n    running: \"running\",\n    paused: \"paused\",\n    exited: \"exited\"\n  },\n\n  tree_component_id: \"tree\",\n\n  default_max_lines_of_code_to_fetch: 500,\n\n  keys_to_not_log_changes_in_console: [\"gdb_mi_output\"],\n  xtermColors: {\n    reset: \"\\x1B[0m\",\n    red: \"\\x1B[31m\",\n    grey: \"\\x1b[1;30m\",\n    green: \"\\x1B[0;32m\",\n    lgreen: \"\\x1B[1;32m\",\n    blue: \"\\x1B[0;34m\",\n    lblue: \"\\x1B[1;34m\",\n    yellow: \"\\x1B[0;33m\"\n  }\n};\n\nconst colorTypeMap = {};\n// @ts-expect-error ts-migrate(7053) FIXME: No index signature with a parameter of type 'strin... Remove this comment to see the full error message\ncolorTypeMap[constants.console_entry_type.STD_OUT] = constants.xtermColors[\"reset\"];\n// @ts-expect-error ts-migrate(7053) FIXME: No index signature with a parameter of type 'strin... Remove this comment to see the full error message\ncolorTypeMap[constants.console_entry_type.STD_ERR] = constants.xtermColors[\"red\"];\n// @ts-expect-error ts-migrate(7053) FIXME: No index signature with a parameter of type 'strin... Remove this comment to see the full error message\ncolorTypeMap[constants.console_entry_type.SENT_COMMAND] = constants.xtermColors[\"lblue\"];\n// @ts-expect-error ts-migrate(7053) FIXME: No index signature with a parameter of type 'strin... Remove this comment to see the full error message\ncolorTypeMap[constants.console_entry_type.GDBGUI_OUTPUT] =\n  constants.xtermColors[\"yellow\"];\n// @ts-expect-error ts-migrate(7053) FIXME: No index signature with a parameter of type 'strin... Remove this comment to see the full error message\ncolorTypeMap[constants.console_entry_type.GDBGUI_OUTPUT_RAW] =\n  constants.xtermColors[\"green\"];\n\n// @ts-expect-error ts-migrate(7053) FIXME: Property 'colorTypeMap' does not exist on type '{ ... Remove this comment to see the full error message\nconstants[\"colorTypeMap\"] = colorTypeMap;\n\n// @ts-expect-error ts-migrate(2551) FIXME: Property 'IGNORE_ERRORS_TOKEN_INT' does not exist ... Remove this comment to see the full error message\nconstants[\"IGNORE_ERRORS_TOKEN_INT\"] = parseInt(constants.IGNORE_ERRORS_TOKEN_STR);\n// @ts-expect-error ts-migrate(2551) FIXME: Property 'DISASSEMBLY_FOR_MISSING_FILE_INT' does n... Remove this comment to see the full error message\nconstants[\"DISASSEMBLY_FOR_MISSING_FILE_INT\"] = parseInt(\n  constants.DISASSEMBLY_FOR_MISSING_FILE_STR\n);\n// @ts-expect-error ts-migrate(2551) FIXME: Property 'CREATE_VAR_INT' does not exist on type '... Remove this comment to see the full error message\nconstants[\"CREATE_VAR_INT\"] = parseInt(constants.CREATE_VAR_STR);\n// @ts-expect-error ts-migrate(2551) FIXME: Property 'INLINE_DISASSEMBLY_INT' does not exist o... Remove this comment to see the full error message\nconstants[\"INLINE_DISASSEMBLY_INT\"] = parseInt(constants.INLINE_DISASSEMBLY_STR);\n\nexport default Object.freeze(constants);\n"
  },
  {
    "path": "gdbgui/src/js/dashboard.tsx",
    "content": "import ReactDOM from \"react-dom\";\nimport React, { useState } from \"react\";\nimport \"../../static/css/tailwind.css\";\n\ntype GdbguiSession = {\n  pid: number;\n  start_time: string;\n  command: string;\n  client_ids: string[];\n};\nconst copyIcon = (\n  <svg className=\"h-6 w-6\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n    <path\n      strokeLinejoin=\"round\"\n      strokeWidth=\"2\"\n      d=\"M8 5H6a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2v-1M8 5a2 2 0 002 2h2a2 2 0 002-2M8 5a2 2 0 012-2h2a2 2 0 012 2m0 0h2a2 2 0 012 2v3m2 4H10m0 0l3-3m-3 3l3 3\"\n    />\n  </svg>\n);\n\n// @ts-expect-error ts-migrate(2339) FIXME: Property 'gdbgui_sessions' does not exist on type ... Remove this comment to see the full error message\nconst data: GdbguiSession[] = window.gdbgui_sessions;\n// @ts-expect-error ts-migrate(2339) FIXME: Property 'csrf_token' does not exist on type 'Wind... Remove this comment to see the full error message\nconst csrf_token: string = window.csrf_token;\n// @ts-expect-error ts-migrate(2339) FIXME: Property 'default_command' does not exist on type ... Remove this comment to see the full error message\nconst default_command: string = window.default_command;\nfunction GdbguiSession(props: { session: GdbguiSession; updateData: Function }) {\n  const session = props.session;\n  const params = new URLSearchParams({\n    gdbpid: session.pid.toString()\n  }).toString();\n  const url = `${window.location.origin}/?${params}`;\n  const [shareButtonText, setShareButtonText] = useState(copyIcon);\n  const [clickedKill, setClickedKill] = useState(false);\n  let timeout: NodeJS.Timeout;\n  return (\n    <tr>\n      <td className=\"border px-4 py-2\">{session.command}</td>\n      <td className=\"border px-4 py-2\">{session.pid}</td>\n      <td className=\"border px-4 py-2\">{session.client_ids.length}</td>\n      <td className=\"border px-4 py-2\">{session.start_time}</td>\n      <td className=\"border px-4 py-2\">\n        <a\n          href={url}\n          className=\"leading-7 bg-blue-500 hover:bg-blue-700 border-blue-500 hover:border-blue-700 border-4 text-white py-2 px-2 rounded\"\n          type=\"button\"\n        >\n          Connect to Session\n        </a>\n        <button\n          className=\"bg-blue-500 hover:bg-blue-700 border-blue-500 hover:border-blue-700 border-4 text-white m-1 p-2 rounded align-middle\"\n          title=\"Copy Sharable URL\"\n          type=\"button\"\n          onClick={async () => {\n            await navigator.clipboard.writeText(url);\n            setShareButtonText(<span>Copied!</span>);\n            if (timeout) {\n              clearTimeout(timeout);\n            }\n            timeout = setTimeout(() => setShareButtonText(copyIcon), 3000);\n          }}\n        >\n          {shareButtonText}\n        </button>\n      </td>\n      <td className=\"border px-4 py-2\">\n        <button\n          className=\"leading-7 bg-red-500 hover:bg-red-700 border-red-500 hover:border-red-700 border-4 text-white py-2 px-2 rounded\"\n          type=\"button\"\n          onClick={async () => {\n            if (clickedKill) {\n              await fetch(\"/kill_session\", {\n                method: \"PUT\",\n                headers: {\n                  \"Content-Type\": \"application/json\"\n                },\n                body: JSON.stringify({ gdbpid: session.pid, csrf_token })\n              });\n              await props.updateData();\n            } else {\n              setClickedKill(true);\n              setTimeout(() => {\n                setClickedKill(false);\n              }, 5000);\n            }\n          }}\n        >\n          {clickedKill ? \"Click Again to Confirm\" : \"Kill Session\"}\n        </button>\n      </td>\n    </tr>\n  );\n}\n\nfunction redirect(url: string) {\n  window.open(url, \"_blank\");\n  setTimeout(() => window.location.reload(), 500);\n}\nclass StartCommand extends React.Component<any, { value: string }> {\n  constructor(props: any) {\n    super(props);\n    // @ts-expect-error\n    this.state = { value: window.default_command };\n\n    this.handleChange = this.handleChange.bind(this);\n    this.handleSubmit = this.handleSubmit.bind(this);\n  }\n\n  handleChange(event: any) {\n    this.setState({ value: event.target.value });\n  }\n\n  handleSubmit() {\n    const params = new URLSearchParams({\n      gdb_command: this.state.value\n    }).toString();\n    redirect(`/?${params}`);\n  }\n\n  render() {\n    return (\n      <>\n        <div>Enter the gdb command to run in the session.</div>\n        <div className=\"flex w-full mx-auto items-center container\">\n          <input\n            type=\"text\"\n            className=\"flex-grow leading-9 bg-gray-900 text-gray-100 font-mono focus:outline-none focus:shadow-outline border border-gray-300 py-2 px-2 block appearance-none rounded-l-lg\"\n            value={this.state.value}\n            onChange={this.handleChange}\n            onKeyUp={event => {\n              if (event.key.toLowerCase() === \"enter\") {\n                this.handleSubmit();\n              }\n            }}\n            placeholder=\"gdb --flag args\"\n          />\n          <button\n            className=\"flex-grow-0 leading-7 bg-green-500 hover:bg-green-700 border-green-500 hover:border-green-700 border-4 text-white py-2 px-2 rounded-r-lg\"\n            type=\"button\"\n            onClick={this.handleSubmit}\n          >\n            Start New Session\n          </button>\n        </div>\n      </>\n    );\n  }\n}\n\nfunction Nav() {\n  return (\n    <nav className=\"flex items-center justify-between flex-wrap bg-blue-500 p-6\">\n      <div className=\"flex items-center flex-shrink-0 text-white mr-6\">\n        <a\n          href={`${window.location.origin}/dashboard`}\n          className=\"font-semibold text-xl tracking-tight\"\n        >\n          gdbgui\n        </a>\n      </div>\n\n      <div className=\"w-full block flex-grow lg:flex lg:items-center lg:w-auto\">\n        <div className=\"text-sm lg:flex-grow\">\n          <a\n            href=\"https://gdbgui.com\"\n            className=\"block mt-4 lg:inline-block lg:mt-0 text-blue-200 hover:text-white mr-4\"\n          >\n            Docs\n          </a>\n          <a\n            href=\"https://www.youtube.com/channel/UCUCOSclB97r9nd54NpXMV5A\"\n            className=\"block mt-4 lg:inline-block lg:mt-0 text-blue-200 hover:text-white mr-4\"\n          >\n            YouTube\n          </a>\n          <a\n            href=\"https://github.com/cs01/gdbgui\"\n            className=\"block mt-4 lg:inline-block lg:mt-0 text-blue-200 hover:text-white mr-4\"\n          >\n            GitHub\n          </a>\n          <a\n            href=\"https://www.paypal.com/paypalme/grassfedcode/20\"\n            className=\"block mt-4 lg:inline-block lg:mt-0 text-blue-200 hover:text-white mr-4\"\n          >\n            Donate\n          </a>\n        </div>\n      </div>\n    </nav>\n  );\n}\n\nclass Dashboard extends React.PureComponent<any, { sessions: GdbguiSession[] }> {\n  interval: NodeJS.Timeout | undefined;\n  constructor(props: any) {\n    super(props);\n    this.state = { sessions: data };\n    this.updateData = this.updateData.bind(this);\n  }\n  async updateData() {\n    const response = await fetch(\"/dashboard_data\");\n    const sessions = await response.json();\n    this.setState({ sessions });\n  }\n  componentDidMount() {\n    this.interval = setInterval(this.updateData, 5000);\n  }\n  componentWillUnmount() {\n    if (this.interval) {\n      clearInterval(this.interval);\n    }\n  }\n  render() {\n    const sessions = this.state.sessions.map((d, index) => (\n      <GdbguiSession key={index} session={d} updateData={this.updateData} />\n    ));\n    return (\n      <div className=\"w-full h-full min-h-screen flex flex-col\">\n        <Nav />\n        <div className=\"flex-grow w-full h-full bg-gray-300 text-center p-5\">\n          <div className=\"text-3xl font-semibold\">Start new session</div>\n          <StartCommand />\n          <div className=\"mt-5 text-3xl font-semibold\">\n            {sessions.length === 1\n              ? \"There is 1 gdbgui session running\"\n              : `There are ${sessions.length} gdbgui sessions running`}\n          </div>\n          <table className=\"table-auto mx-auto\">\n            <thead>\n              <tr>\n                <th className=\"px-4 py-2\">Command</th>\n                <th className=\"px-4 py-2\">PID</th>\n                <th className=\"px-4 py-2\">Connected Browsers</th>\n                <th className=\"px-4 py-2\">Start Time</th>\n                <th className=\"px-4 py-2\"></th>\n              </tr>\n            </thead>\n            <tbody>{sessions}</tbody>\n          </table>\n        </div>\n        <footer className=\"h-40 bold text-lg bg-black text-gray-500 text-center flex flex-col justify-center\">\n          <p>gdbgui</p>\n          <p>The browser-based frontend to gdb</p>\n          <a href=\"https://chadsmith.dev\">Copyright Chad Smith</a>\n        </footer>\n      </div>\n    );\n  }\n}\n\nReactDOM.render(<Dashboard />, document.getElementById(\"dashboard\"));\n"
  },
  {
    "path": "gdbgui/src/js/gdbgui.tsx",
    "content": "/**\n * This is the entrypoint to the frontend applicaiton.\n *\n * store (global state) is managed in a single location, and each time the store\n * changes, components are notified and update accordingly.\n *\n */\n\n/* global Split */\n/* global initial_data */\n/* global debug */\n\nimport ReactDOM from \"react-dom\";\nimport React from \"react\";\n// @ts-expect-error ts-migrate(2305) FIXME: Module '\"statorgfc\"' has no exported member 'middl... Remove this comment to see the full error message\nimport { store, middleware } from \"statorgfc\";\n\nimport constants from \"./constants\";\nimport GdbApi from \"./GdbApi\";\nimport FileOps from \"./FileOps\";\nimport FoldersView from \"./FoldersView\";\nimport GlobalEvents from \"./GlobalEvents\";\nimport HoverVar from \"./HoverVar\";\nimport initial_store_data from \"./InitialStoreData\";\nimport MiddleLeft from \"./MiddleLeft\";\nimport Modal from \"./GdbguiModal\";\nimport RightSidebar from \"./RightSidebar\";\nimport Settings from \"./Settings\";\nimport ToolTip from \"./ToolTip\";\nimport TopBar from \"./TopBar\";\nimport ToolTipTourguide from \"./ToolTipTourguide\";\n\nimport \"../../static/css/gdbgui.css\";\nimport \"../../static/css/splitjs-gdbgui.css\";\nimport { Terminals } from \"./Terminals\";\n\nconst store_options = {\n  immutable: false,\n  debounce_ms: 10\n};\n// @ts-expect-error ts-migrate(2339) FIXME: Property 'initialize' does not exist on type '{ ge... Remove this comment to see the full error message\nstore.initialize(initial_store_data, store_options);\n// @ts-expect-error ts-migrate(2304) FIXME: Cannot find name 'debug'.\nif (debug) {\n  // log call store changes in console except if changed key was in\n  // constants.keys_to_not_log_changes_in_console\n  // @ts-expect-error ts-migrate(2339) FIXME: Property 'use' does not exist on type '{ get(key: ... Remove this comment to see the full error message\n  store.use(function(key: any, oldval: any, newval: any) {\n    if (constants.keys_to_not_log_changes_in_console.indexOf(key) === -1) {\n      middleware.logChanges(key, oldval, newval);\n    }\n    return true;\n  });\n}\n// make this visible in the console\n// @ts-expect-error ts-migrate(2339) FIXME: Property 'store' does not exist on type 'Window & ... Remove this comment to see the full error message\nwindow.store = store;\n\nclass Gdbgui extends React.PureComponent {\n  componentWillMount() {\n    GdbApi.init();\n    GlobalEvents.init();\n    FileOps.init(); // this should be initialized before components that use store key 'source_code_state'\n  }\n  render() {\n    return (\n      <div className=\"splitjs_container\">\n        {/* @ts-expect-error ts-migrate(2322) FIXME: Property 'initial_user_input' does not exist on ty... Remove this comment to see the full error message */}\n        <TopBar initial_user_input={initial_data.initial_binary_and_args} />\n\n        <div id=\"middle\" style={{ paddingTop: \"60px\" }}>\n          <div id=\"folders_view\" className=\"content\" style={{ backgroundColor: \"#333\" }}>\n            <FoldersView />\n          </div>\n\n          <div id=\"source_code_view\" className=\"content\">\n            <MiddleLeft />\n          </div>\n\n          <div id=\"controls_sidebar\" className=\"content\" style={{ overflowX: \"visible\" }}>\n            {/* @ts-expect-error ts-migrate(2769) FIXME: Property 'signals' does not exist on type 'Intrins... Remove this comment to see the full error message */}\n            <RightSidebar signals={initial_data.signals} debug={debug} />\n          </div>\n        </div>\n\n        <div\n          id=\"bottom\"\n          className=\"split split-horizontal\"\n          style={{ width: \"100%\", height: \"100%\" }}\n        >\n          <ToolTipTourguide\n            // @ts-expect-error ts-migrate(2322) FIXME: Property 'step_num' does not exist on type 'Intrin... Remove this comment to see the full error message\n            step_num={4}\n            position={\"topleft\"}\n            content={\n              <div>\n                <h5>You can view gdb's output here.</h5>\n                You usually don't need to enter commands here, but you have the option to\n                if there is something you can't do in the UI.\n              </div>\n            }\n          />\n\n          <div id=\"bottom_content\" className=\"split content\">\n            <Terminals />\n          </div>\n        </div>\n\n        {/* below are elements that are only displayed under certain conditions */}\n        <Modal />\n        <HoverVar />\n        <Settings />\n        <ToolTip />\n        <textarea\n          style={{\n            width: \"0px\",\n            height: \"0px\",\n            position: \"absolute\",\n            top: \"0\",\n            left: \"-1000px\"\n          }}\n          ref={node => {\n            store.set(\"textarea_to_copy_to_clipboard\", node);\n          }}\n        />\n      </div>\n    );\n  }\n  componentDidMount() {\n    // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name 'debug'.\n    if (debug) {\n      // @ts-expect-error ts-migrate(2339) FIXME: Property 'getUnwatchedKeys' does not exist on type... Remove this comment to see the full error message\n      console.warn(store.getUnwatchedKeys());\n    }\n    // Split the body into different panes using splitjs (https://github.com/nathancahill/Split.js)\n    // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name 'Split'.\n    let middle_panes_split_obj = Split(\n      [\"#folders_view\", \"#source_code_view\", \"#controls_sidebar\"],\n      {\n        gutterSize: 8,\n        minSize: 100,\n        cursor: \"col-resize\",\n        direction: \"horizontal\", // horizontal makes a left/right pane, and a divider running vertically\n        sizes: store.get(\"show_filesystem\") ? [30, 40, 29] : [0, 70, 29] // adding to exactly 100% is a little buggy due to splitjs, so keep it to 99\n      }\n    );\n\n    // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name 'Split'.\n    Split([\"#middle\", \"#bottom\"], {\n      gutterSize: 8,\n      cursor: \"row-resize\",\n      direction: \"vertical\", // vertical makes a top and bottom pane, and a divider running horizontally\n      sizes: [70, 30]\n    });\n\n    store.set(\"middle_panes_split_obj\", middle_panes_split_obj);\n\n    // Fetch the latest version only if using in normal mode. If debugging, we tend to\n    // refresh quite a bit, which might make too many requests to github and cause them\n    // to block our ip? Either way it just seems weird to make so many ajax requests.\n    if (!store.get(\"debug\")) {\n      // fetch version\n      $.ajax({\n        url: \"https://raw.githubusercontent.com/cs01/gdbgui/master/gdbgui/VERSION.txt\",\n        cache: false,\n        method: \"GET\",\n        success: data => {\n          // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name '_'.\n          store.set(\"latest_gdbgui_version\", _.trim(data));\n        },\n        error: data => {\n          void data;\n          store.set(\"latest_gdbgui_version\", \"(could not contact server)\");\n        }\n      });\n    }\n  }\n}\n\nReactDOM.render(<Gdbgui />, document.getElementById(\"gdbgui\"));\n"
  },
  {
    "path": "gdbgui/src/js/processFeatures.ts",
    "content": "// https://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Support-Commands.html#GDB_002fMI-Support-Commands\n\nimport { store } from \"statorgfc\";\ntype Feature =\n  | \"thread-info\"\n  | \"reverse\"\n  | \"async\"\n  | \"frozen-varobjs\"\n  | \"pending-breakpoints\"\n  | \"data-read-memory-bytes\"\n  | \"python\"\n  | \"ada-task-info\"\n  | \"language-option\"\n  | \"info-gdb-mi-command\"\n  | \"undefined-command-error-code\"\n  | \"exec-run-start-option\"\n  | \"data-disassemble-a-option\"\n  | \"breakpoint-notification\";\n\nexport function processFeatures(features: Array<Feature>) {\n  if (features.indexOf(\"reverse\") !== -1) {\n    store.set(\"reverse_supported\", true);\n  }\n}\n"
  },
  {
    "path": "gdbgui/src/js/process_gdb_response.tsx",
    "content": "/**\n * This is the main callback when receiving a response from gdb.\n * This callback generally updates the store, which causes components\n * to update.\n */\n\nimport React from \"react\";\nimport { store } from \"statorgfc\";\nimport GdbMiOutput from \"./GdbMiOutput\";\nimport Breakpoints from \"./Breakpoints\";\nimport constants from \"./constants\";\nimport Threads from \"./Threads\";\nimport FileOps from \"./FileOps\";\nimport Memory from \"./Memory\";\nimport GdbApi from \"./GdbApi\";\nimport Locals from \"./Locals\";\nimport GdbVariable from \"./GdbVariable\";\nimport Modal from \"./GdbguiModal\";\nimport Actions from \"./Actions\";\nimport { processFeatures } from \"./processFeatures\";\n\nconst process_gdb_response = function(response_array: any) {\n  /**\n   * Determines if response is an error and client does not want to be notified of errors for this particular response.\n   * @param response: gdb mi response object\n   * @return (bool): true if response should be ignored\n   */\n  const isError = (response: any) => {\n    return response.message === \"error\";\n  };\n  const ignoreError = (response: any) => {\n    return (\n      // @ts-expect-error ts-migrate(2551) FIXME: Property 'IGNOREERRORS_TOKEN_INT' does not exist o... Remove this comment to see the full error message\n      response.token === constants.IGNOREERRORS_TOKEN_INT ||\n      // @ts-expect-error ts-migrate(2551) FIXME: Property 'CREATE_VAR_INT' does not exist on type '... Remove this comment to see the full error message\n      response.token === constants.CREATE_VAR_INT\n    );\n  };\n  const isCreatingVar = (response: any) => {\n    // @ts-expect-error ts-migrate(2551) FIXME: Property 'CREATE_VAR_INT' does not exist on type '... Remove this comment to see the full error message\n    return response.token === constants.CREATE_VAR_INT;\n  };\n\n  for (let r of response_array) {\n    // gdb mi output\n    GdbMiOutput.add_mi_output(r);\n\n    if (isError(r)) {\n      if (isCreatingVar(r)) {\n        GdbVariable.gdb_variable_fetch_failed(r);\n        continue;\n      } else if (ignoreError(r)) {\n        continue;\n        // @ts-expect-error ts-migrate(2551) FIXME: Property 'DISASSEMBLY_FOR_MISSING_FILE_INT' does n... Remove this comment to see the full error message\n      } else if (r.token === constants.DISASSEMBLY_FOR_MISSING_FILE_INT) {\n        FileOps.fetch_disassembly_for_missing_file_failed();\n      } else if (\n        // @ts-expect-error ts-migrate(2551) FIXME: Property 'INLINE_DISASSEMBLY_INT' does not exist o... Remove this comment to see the full error message\n        r.token === constants.INLINE_DISASSEMBLY_INT &&\n        r.payload &&\n        r.payload.msg.indexOf(\"Mode argument must be 0, 1, 2, or 3.\") !== -1\n      ) {\n        // we tried to fetch disassembly for a newer version of gdb, but it didn't work\n        // try again with mode 3, for older gdb api's\n        store.set(\"gdb_version\", [\"7\", \"6\", \"0\"]);\n        // @ts-expect-error ts-migrate(2345) FIXME: Argument of type '3' is not assignable to paramete... Remove this comment to see the full error message\n        FileOps.fetch_assembly_cur_line(3);\n      } else if (\n        r.payload &&\n        r.payload.msg &&\n        r.payload.msg.startsWith(\"Unable to find Mach task port\")\n      ) {\n        Actions.add_gdb_response_to_console(r);\n        Actions.add_console_entries(\n          <React.Fragment>\n            <span>Follow </span>\n            <a href=\"https://github.com/cs01/gdbgui/issues/55#issuecomment-288209648\">\n              these instructions\n            </a>\n            <span> to fix this error</span>\n          </React.Fragment>,\n          constants.console_entry_type.GDBGUI_OUTPUT_RAW\n        );\n        continue;\n      }\n    }\n\n    if (r.type === \"result\" && r.message === \"done\" && r.payload) {\n      // This is special GDB Machine Interface structured data that we\n      // can render in the frontend\n      if (\"bkpt\" in r.payload) {\n        let new_bkpt = r.payload.bkpt;\n\n        // remove duplicate breakpoints\n        let cmds = store\n          .get(\"breakpoints\")\n          .filter(\n            (b: any) =>\n              new_bkpt.fullname === b.fullname &&\n              new_bkpt.func === b.func &&\n              new_bkpt.line === b.line\n          )\n          .map((b: any) => GdbApi.get_delete_break_cmd(b.number));\n        GdbApi.run_gdb_command(cmds);\n\n        // save this breakpoint\n        let bkpt = Breakpoints.save_breakpoint(r.payload.bkpt);\n\n        // if executable does not have debug symbols (i.e. not compiled with -g flag)\n        // gdb will not return a path, but rather the function name. The function name is\n        // not a file, and therefore it cannot be displayed. Make sure the path is known before\n        // trying to render the file of the newly created breakpoint.\n        // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name '_'.\n        if (_.isString(bkpt.fullname_to_display)) {\n          // a normal breakpoint or child breakpoint\n          Actions.view_file(bkpt.fullname_to_display, parseInt(bkpt.line));\n        }\n\n        // refresh all breakpoints\n        GdbApi.refresh_breakpoints();\n      }\n      if (\"BreakpointTable\" in r.payload) {\n        Breakpoints.save_breakpoints(r.payload);\n      }\n      if (\"stack\" in r.payload) {\n        Threads.update_stack(r.payload.stack);\n      }\n      if (\"threads\" in r.payload) {\n        store.set(\"threads\", r.payload.threads);\n        store.set(\"current_thread_id\", parseInt(r.payload[\"current-thread-id\"]));\n      }\n      if (\"register-names\" in r.payload) {\n        let names = r.payload[\"register-names\"];\n        // filter out empty names\n        store.set(\n          \"register_names\",\n          names.filter((name: any) => name !== \"\")\n        );\n      }\n      if (\"register-values\" in r.payload) {\n        store.set(\"previous_register_values\", store.get(\"current_register_values\"));\n        store.set(\"current_register_values\", r.payload[\"register-values\"]);\n      }\n      if (\"asm_insns\" in r.payload) {\n        FileOps.save_new_assembly(r.payload.asm_insns, r.token);\n      }\n      if (\"files\" in r.payload) {\n        if (r.payload.files.length > 0) {\n          // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name '_'.\n          let source_file_paths = _.uniq(\n            r.payload.files.map((f: any) => f.fullname)\n          ).sort();\n          store.set(\"source_file_paths\", source_file_paths);\n\n          let language = \"c_family\";\n          if (source_file_paths.some((p: any) => p.endsWith(\".rs\"))) {\n            language = \"rust\";\n            let gdb_version_array = store.get(\"gdb_version_array\");\n            // rust cannot view registers with gdb 7.12.x\n            if (gdb_version_array[0] == 7 && gdb_version_array[1] == 12) {\n              Actions.add_console_entries(\n                `Warning: Due to a bug in gdb version ${store.get(\n                  \"gdb_version\"\n                )}, gdbgui cannot show register values with rust executables. See https://github.com/cs01/gdbgui/issues/64 for details.`,\n                constants.console_entry_type.STD_ERR\n              );\n              store.set(\"can_fetch_register_values\", false);\n            }\n          } else if (source_file_paths.some((p: any) => p.endsWith(\".go\"))) {\n            language = \"go\";\n          }\n          store.set(\"language\", language);\n        } else {\n          store.set(\"source_file_paths\", [\n            \"Either no executable is loaded or the executable was compiled without debug symbols.\"\n          ]);\n\n          if (store.get(\"inferior_binary_path\")) {\n            // @ts-expect-error ts-migrate(2339) FIXME: Property 'render' does not exist on type 'typeof M... Remove this comment to see the full error message\n            Modal.render(\n              \"Warning\",\n              <div>\n                This binary was not compiled with debug symbols. Recompile with the -g\n                flag for a better debugging experience.\n                <p />\n                <p />\n                Read more:{\" \"}\n                <a href=\"http://www.delorie.com/gnu/docs/gdb/gdb_17.html\">\n                  http://www.delorie.com/gnu/docs/gdb/gdb_17.html\n                </a>\n              </div>\n            );\n          }\n        }\n      }\n      if (\"memory\" in r.payload) {\n        Memory.add_value_to_cache(\n          r.payload.memory[0].begin,\n          r.payload.memory[0].contents\n        );\n      }\n      // gdb returns local variables as \"variables\" which is confusing, because you can also create variables\n      // in gdb with '-var-create'. *Those* types of variables are referred to as \"expressions\" in gdbgui, and\n      // are returned by gdbgui as \"changelist\", or have the keys \"has_more\", \"numchild\", \"children\", or \"name\".\n      if (\"variables\" in r.payload) {\n        Locals.save_locals(r.payload.variables);\n      }\n      // gdbgui expression (aka a gdb variable was changed)\n      if (\"changelist\" in r.payload) {\n        GdbVariable.handle_changelist(r.payload.changelist);\n      }\n      // gdbgui expression was evaluated for the first time for a child variable\n      if (\"has_more\" in r.payload && \"numchild\" in r.payload && \"children\" in r.payload) {\n        GdbVariable.gdb_created_children_variables(r);\n      }\n      // gdbgui expression was evaluated for the first time for a root variable\n      if (\"name\" in r.payload) {\n        GdbVariable.gdb_created_root_variable(r);\n      }\n      // features list\n      if (\"features\" in r.payload) {\n        processFeatures(r.payload.features);\n      }\n      // features list\n      if (\"target_features\" in r.payload) {\n        // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name 'processTargetFeatures'.\n        processTargetFeatures(r.payload.target_features);\n      }\n    } else if (r.type === \"result\" && r.message === \"error\") {\n      // render it in the status bar, and don't render the last response in the array as it does by default\n      Actions.add_gdb_response_to_console(r);\n\n      // we tried to load a binary, but gdb couldn't find it\n      if (\n        r.payload.msg ===\n        `${store.get(\"inferior_binary_path\")}: No such file or directory.`\n      ) {\n        Actions.inferior_program_exited();\n      }\n    } else if (r.type === \"console\") {\n      Actions.add_console_entries(\n        r.payload,\n        r.stream === \"stderr\"\n          ? constants.console_entry_type.STD_ERR\n          : constants.console_entry_type.STD_OUT\n      );\n      if (store.get(\"gdb_version\") === undefined) {\n        // parse gdb version from string such as\n        // GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.2) 7.7.1\n        let m = /GNU gdb \\(.*\\)\\s+([0-9|.]*)\\\\n/g;\n        let a = m.exec(r.payload);\n        if (Array.isArray(a) && a.length === 2) {\n          store.set(\"gdb_version\", a[1]);\n          store.set(\"gdb_version_array\", a[1].split(\".\"));\n        }\n      }\n    } else if (r.type === \"output\" || r.type === \"target\" || r.type === \"log\") {\n      // output of program\n      Actions.add_console_entries(\n        r.payload,\n        r.stream === \"stderr\"\n          ? constants.console_entry_type.STD_ERR\n          : constants.console_entry_type.STD_OUT\n      );\n    } else if (r.type === \"notify\") {\n      if (r.message === \"thread-group-started\") {\n        store.set(\"inferior_pid\", parseInt(r.payload.pid));\n      }\n    }\n\n    if (r.message && r.message === \"stopped\") {\n      if (r.payload && r.payload.reason) {\n        if (r.payload.reason.includes(\"exited\")) {\n          Actions.inferior_program_exited();\n        } else if (\n          r.payload.reason.includes(\"breakpoint-hit\") ||\n          r.payload.reason.includes(\"end-stepping-range\")\n        ) {\n          if (r.payload[\"new-thread-id\"]) {\n            // @ts-expect-error ts-migrate(2339) FIXME: Property 'set_thread_id' does not exist on type 't... Remove this comment to see the full error message\n            Threads.set_thread_id(r.payload[\"new-thread-id\"]);\n          }\n          Actions.inferior_program_paused(r.payload.frame);\n        } else if (r.payload.reason === \"signal-received\") {\n          Actions.inferior_program_paused(r.payload.frame);\n\n          if (r.payload[\"signal-name\"] !== \"SIGINT\") {\n            Actions.add_console_entries(\n              `Signal received: (${r.payload[\"signal-meaning\"]}, ${r.payload[\"signal-name\"]}).`,\n              constants.console_entry_type.GDBGUI_OUTPUT\n            );\n            Actions.add_console_entries(\n              \"If the program exited due to a fault, you can attempt to re-enter \" +\n                \"the state of the program when the fault occurred by running the \" +\n                \"command 'backtrace' in the gdb terminal.\",\n              constants.console_entry_type.GDBGUI_OUTPUT\n            );\n          }\n        } else {\n          console.warn(\"TODO handle new reason for stopping. Notify developer of this.\");\n          console.warn(r);\n        }\n      } else {\n        Actions.inferior_program_paused(r.payload.frame);\n      }\n    } else if (r.message && r.message === \"connected\") {\n      Actions.remote_connected();\n    }\n  }\n};\n\nexport default process_gdb_response;\n"
  },
  {
    "path": "gdbgui/src/js/register_descriptions.ts",
    "content": "export default {\n  // x86_64\n  rax: \"register a extended (64-bit)\",\n  rbx: \"register b extended (64-bit)\",\n  rcx: \"register c extended (64-bit)\",\n  rdx: \"register d extended (64-bit)\",\n  rbp: \"base pointer (start of stack) (64-bit)\",\n  rsp: \"stack pointer (current location in stack, growing downwards) (64-bit)\",\n  rsi: \"source index (source for data copies) (64-bit)\",\n  rdi: \"destination index (destination for data copies) (64-bit)\",\n  r8: \"register 8 (64-bit)\",\n  r9: \"register 9 (64-bit)\",\n  r10: \"register 10 (64-bit)\",\n  r11: \"register 11 (64-bit)\",\n  r12: \"register 12 (64-bit)\",\n  r13: \"register 13 (64-bit)\",\n  r14: \"register 14 (64-bit)\",\n  r15: \"register 15 (64-bit)\",\n  rip: \"instruction pointer (points to next instruction to execute) (64-bit)\",\n  eflags:\n    \"32-bit register used as a collection of bits representing Boolean values to store the results of operations and the state of the processor\",\n  cs: \"\",\n  ss: \"\",\n  ds: \"\",\n  es: \"\",\n  fs: \"\",\n  gs: \"\",\n  st0: \"\",\n  st1: \"\",\n  st2: \"\",\n  st3: \"\",\n  st4: \"\",\n  st5: \"\",\n  st6: \"\",\n  st7: \"\",\n  fctrl: \"\",\n  fstat: \"\",\n  ftag: \"\",\n  fiseg: \"\",\n  fioff: \"\",\n  foseg: \"\",\n  fooff: \"\",\n  fop: \"\",\n  xmm0: \"128-bit floating point (four 32-bit singles or two 64-bit doubles)\",\n  xmm1: \"128-bit floating point (four 32-bit singles or two 64-bit doubles)\",\n  xmm2: \"128-bit floating point (four 32-bit singles or two 64-bit doubles)\",\n  xmm3: \"128-bit floating point (four 32-bit singles or two 64-bit doubles)\",\n  xmm4: \"128-bit floating point (four 32-bit singles or two 64-bit doubles)\",\n  xmm5: \"128-bit floating point (four 32-bit singles or two 64-bit doubles)\",\n  xmm6: \"128-bit floating point (four 32-bit singles or two 64-bit doubles)\",\n  xmm7: \"128-bit floating point (four 32-bit singles or two 64-bit doubles)\",\n  xmm8: \"128-bit floating point (four 32-bit singles or two 64-bit doubles)\",\n  xmm9: \"128-bit floating point (four 32-bit singles or two 64-bit doubles)\",\n  xmm10: \"128-bit floating point (four 32-bit singles or two 64-bit doubles)\",\n  xmm11: \"128-bit floating point (four 32-bit singles or two 64-bit doubles)\",\n  xmm12: \"128-bit floating point (four 32-bit singles or two 64-bit doubles)\",\n  xmm13: \"128-bit floating point (four 32-bit singles or two 64-bit doubles)\",\n  xmm14: \"128-bit floating point (four 32-bit singles or two 64-bit doubles)\",\n  xmm15: \"128-bit floating point (four 32-bit singles or two 64-bit doubles)\",\n  mxcsr: \"\",\n\n  ymm0h: \"256-bit floating point (eight 32-bit singles or four 64-bit doubles)\",\n  ymm1h: \"256-bit floating point (eight 32-bit singles or four 64-bit doubles)\",\n  ymm2h: \"256-bit floating point (eight 32-bit singles or four 64-bit doubles)\",\n  ymm3h: \"256-bit floating point (eight 32-bit singles or four 64-bit doubles)\",\n  ymm4h: \"256-bit floating point (eight 32-bit singles or four 64-bit doubles)\",\n  ymm5h: \"256-bit floating point (eight 32-bit singles or four 64-bit doubles)\",\n  ymm6h: \"256-bit floating point (eight 32-bit singles or four 64-bit doubles)\",\n  ymm7h: \"256-bit floating point (eight 32-bit singles or four 64-bit doubles)\",\n  ymm8h: \"256-bit floating point (eight 32-bit singles or four 64-bit doubles)\",\n  ymm9h: \"256-bit floating point (eight 32-bit singles or four 64-bit doubles)\",\n  ymm10h: \"256-bit floating point (eight 32-bit singles or four 64-bit doubles)\",\n  ymm11h: \"256-bit floating point (eight 32-bit singles or four 64-bit doubles)\",\n  ymm12h: \"256-bit floating point (eight 32-bit singles or four 64-bit doubles)\",\n  ymm13h: \"256-bit floating point (eight 32-bit singles or four 64-bit doubles)\",\n  ymm14h: \"256-bit floating point (eight 32-bit singles or four 64-bit doubles)\",\n  ymm15h: \"256-bit floating point (eight 32-bit singles or four 64-bit doubles)\",\n\n  ymm0: \"256-bit floating point (eight 32-bit singles or four 64-bit doubles)\",\n  ymm1: \"256-bit floating point (eight 32-bit singles or four 64-bit doubles)\",\n  ymm2: \"256-bit floating point (eight 32-bit singles or four 64-bit doubles)\",\n  ymm3: \"256-bit floating point (eight 32-bit singles or four 64-bit doubles)\",\n  ymm4: \"256-bit floating point (eight 32-bit singles or four 64-bit doubles)\",\n  ymm5: \"256-bit floating point (eight 32-bit singles or four 64-bit doubles)\",\n  ymm6: \"256-bit floating point (eight 32-bit singles or four 64-bit doubles)\",\n  ymm7: \"256-bit floating point (eight 32-bit singles or four 64-bit doubles)\",\n  ymm8: \"256-bit floating point (eight 32-bit singles or four 64-bit doubles)\",\n  ymm9: \"256-bit floating point (eight 32-bit singles or four 64-bit doubles)\",\n  ymm10: \"256-bit floating point (eight 32-bit singles or four 64-bit doubles)\",\n  ymm11: \"256-bit floating point (eight 32-bit singles or four 64-bit doubles)\",\n  ymm12: \"256-bit floating point (eight 32-bit singles or four 64-bit doubles)\",\n  ymm13: \"256-bit floating point (eight 32-bit singles or four 64-bit doubles)\",\n  ymm14: \"256-bit floating point (eight 32-bit singles or four 64-bit doubles)\",\n  ymm15: \"256-bit floating point (eight 32-bit singles or four 64-bit doubles)\",\n\n  orig_rax: \"\",\n  al: \"\",\n  bl: \"\",\n  cl: \"\",\n  dl: \"\",\n  sil: \"\",\n  dil: \"\",\n  bpl: \"\",\n  spl: \"\",\n  r8l: \"\",\n  r9l: \"\",\n  r10l: \"\",\n  r11l: \"\",\n  r12l: \"\",\n  r13l: \"\",\n  r14l: \"\",\n  r15l: \"\",\n  ah: \"\",\n  bh: \"\",\n  ch: \"\",\n  dh: \"\",\n  ax: \"lower 16-bits of eax (accumulator register, used in arithmetic operations)\",\n  bx: \"lower 16-bits of ebx (base register)\",\n  cx:\n    \"lower 16-bits of ecx (counter register, used in shift/rotate instructions and loops)\",\n  dx: \"lower 16-bits of edx (data register, used in arithmetic and I/O)\",\n  si: \"lower 16-bits of esi (source index register)\",\n  di: \"lower 16-bits of edi (destination index register)\",\n  bp: \"lower 16-bits of ebp (base pointer register, points to base of stack)\",\n  r8w: \"\",\n  r9w: \"\",\n  r10w: \"\",\n  r11w: \"\",\n  r12w: \"\",\n  r13w: \"\",\n  r14w: \"\",\n  r15w: \"\",\n  eax: \"general purpose 32-bit register\",\n  ebx: \"general purpose 32-bit register\",\n  ecx: \"general purpose 32-bit register\",\n  edx: \"general purpose 32-bit register\",\n  esi: \"general purpose 32-bit register\",\n  edi: \"general purpose 32-bit register\",\n  ebp: \"32-bit base pointer\",\n\n  // ARM\n  R0: \"Argument1, Return Value (Temporary register)\",\n  R1:\n    \"Argument2, Second 32-bits if double or 64-bit int return value (Temporary register)\",\n  R2: \"Arguments (Temporary register)\",\n  R3: \"Arguments (Temporary register)\",\n  R4: \"R7 is THUMB frame pointer (Permanent register)\",\n  R5: \"R7 is THUMB frame pointer (Permanent register)\",\n  R6: \"R7 is THUMB frame pointer (Permanent register)\",\n  R7: \"R7 is THUMB frame pointer (Permanent register)\",\n  R8: \"R7 is THUMB frame pointer (Permanent register)\",\n  R9: \"R7 is THUMB frame pointer (Permanent register)\",\n  R10: \"R7 is THUMB frame pointer (Permanent register)\",\n  R11: \"ARM frame pointer (Permanent register)\",\n  R12: \"(Temporary register)\",\n  R13: \"Stack pointer (Permanent register)\",\n  R14: \"Link register (Permanent register)\",\n  R15: \"Program counter\",\n\n  s0: \"VFP single-precision (Temporary register)\",\n  s1: \"VFP single-precision (Temporary register)\",\n  s2: \"VFP single-precision (Temporary register)\",\n  s3: \"VFP single-precision (Temporary register)\",\n  s4: \"VFP single-precision (Temporary register)\",\n  s5: \"VFP single-precision (Temporary register)\",\n  s6: \"VFP single-precision (Temporary register)\",\n  s7: \"VFP single-precision (Temporary register)\",\n  s8: \"VFP single-precision (Temporary register)\",\n  s9: \"VFP single-precision (Temporary register)\",\n  s10: \"VFP single-precision (Temporary register)\",\n  s11: \"VFP single-precision (Temporary register)\",\n  s12: \"VFP single-precision (Temporary register)\",\n  s13: \"VFP single-precision (Temporary register)\",\n  s14: \"VFP single-precision (Temporary register)\",\n  s15: \"VFP single-precision (Temporary register)\",\n\n  s16: \"VFP single-precision (Permanent register)\",\n  s17: \"VFP single-precision (Permanent register)\",\n  s18: \"VFP single-precision (Permanent register)\",\n  s19: \"VFP single-precision (Permanent register)\",\n  s20: \"VFP single-precision (Permanent register)\",\n  s21: \"VFP single-precision (Permanent register)\",\n  s22: \"VFP single-precision (Permanent register)\",\n  s23: \"VFP single-precision (Permanent register)\",\n  s24: \"VFP single-precision (Permanent register)\",\n  s25: \"VFP single-precision (Permanent register)\",\n  s26: \"VFP single-precision (Permanent register)\",\n  s27: \"VFP single-precision (Permanent register)\",\n  s28: \"VFP single-precision (Permanent register)\",\n  s29: \"VFP single-precision (Permanent register)\",\n  s30: \"VFP single-precision (Permanent register)\",\n  s31: \"VFP single-precision (Permanent register)\",\n\n  d0: \"VFP double-precision (Temporary register)\",\n  d1: \"VFP double-precision (Temporary register)\",\n  d2: \"VFP double-precision (Temporary register)\",\n  d3: \"VFP double-precision (Temporary register)\",\n  d4: \"VFP double-precision (Temporary register)\",\n  d5: \"VFP double-precision (Temporary register)\",\n  d6: \"VFP double-precision (Temporary register)\",\n  d7: \"VFP double-precision (Temporary register)\",\n\n  d8: \"VFP double-precision (Permanent register)\",\n  d9: \"VFP double-precision (Permanent register)\",\n  d10: \"VFP double-precision (Permanent register)\",\n  d11: \"VFP double-precision (Permanent register)\",\n  d12: \"VFP double-precision (Permanent register)\",\n  d13: \"VFP double-precision (Permanent register)\",\n  d14: \"VFP double-precision (Permanent register)\",\n  d15: \"VFP double-precision (Permanent register)\",\n\n  fpsid: \"VFP system ID register\",\n  fpscr: \"VFP status and control register\",\n  fpexc: \"VFP expception register\",\n\n  wr0: \"WMMX SIMD data register\",\n  wr1: \"WMMX SIMD data register\",\n  wr2: \"WMMX SIMD data register\",\n  wr3: \"WMMX SIMD data register\",\n  wr4: \"WMMX SIMD data register\",\n  wr5: \"WMMX SIMD data register\",\n  wr6: \"WMMX SIMD data register\",\n  wr7: \"WMMX SIMD data register\",\n  wr8: \"WMMX SIMD data register\",\n  wr9: \"WMMX SIMD data register\",\n  wr10: \"WMMX SIMD data register\",\n  wr11: \"WMMX SIMD data register\",\n  wr12: \"WMMX SIMD data register\",\n  wr13: \"WMMX SIMD data register\",\n  wr14: \"WMMX SIMD data register\",\n  wr15: \"WMMX SIMD data register\",\n  wr16: \"WMMX SIMD data register\",\n\n  wc0: \"WMMX status and control register\",\n  wc1: \"WMMX status and control register\",\n  wc2: \"WMMX status and control register\",\n  wc3: \"WMMX status and control register\",\n  wc4: \"WMMX status and control register\",\n  wc5: \"WMMX status and control register\",\n  wc6: \"WMMX status and control register\",\n  wc7: \"WMMX status and control register\",\n  wc8: \"WMMX status and control register\",\n  wc9: \"WMMX status and control register\",\n  wc10: \"WMMX status and control register\",\n  wc11: \"WMMX status and control register\",\n  wc12: \"WMMX status and control register\",\n  wc13: \"WMMX status and control register\",\n  wc14: \"WMMX status and control register\",\n  wc15: \"WMMX status and control register\",\n  wc16: \"WMMX status and control register\",\n\n  wcid: \"WMMX coprocessor ID register, synonymous with wc0\",\n  wcon: \"WMMX control register, synonymous with wc1\",\n  wcssf: \"WMMX saturation SIMD flags, synonymous with wc2\",\n  wcasf: \"WMMX saturation SIMD flags, synonymous with wc3\",\n\n  wcgr0: \"WMMX control general-purpose register, synonymous with wc8\",\n  wcgr1: \"WMMX control general-purpose register, synonymous with wc9\",\n  wcgr2: \"WMMX control general-purpose register, synonymous with wc10\",\n  wcgr3: \"WMMX control general-purpose register, synonymous with wc11\"\n};\n"
  },
  {
    "path": "gdbgui/src/js/tests/Util.jest.ts",
    "content": "import Util from \"../Util\";\n\n/* eslint-env jest */\n\ntest(\"parses spaces\", () => {\n  const fn = Util.string_to_array_safe_quotes;\n  expect(fn(\"hi\")).toEqual([\"hi\"]);\n  expect(fn('\"hi bye\"')).toEqual(['\"hi bye\"']);\n  expect(fn(\"hi bye\")).toEqual([\"hi\", \"bye\"]);\n  expect(fn('hi bye \"1 2, 3\" asdf\\n\\t')).toEqual([\"hi\", \"bye\", '\"1 2, 3\"', \"asdf\\n\\t\"]);\n  expect(fn('\"hi bye\" \"1 2, 3\" asdf\\n\\t')).toEqual(['\"hi bye\"', '\"1 2, 3\"', \"asdf\\n\\t\"]);\n});\n\ntest(\"dot version comparison\", () => {\n  expect(Util.is_newer(\"1.0.0\", \"1.0.0\")).toEqual(false);\n  expect(Util.is_newer(\"1.0.0\", \"0.9.9\")).toEqual(true);\n  expect(Util.is_newer(\"0.1.0\", \"0.0.9\")).toEqual(true);\n  expect(Util.is_newer(\"0.0.8\", \"0.0.9\")).toEqual(false);\n  expect(Util.is_newer(\"0.11.3.1\", \"0.11.3.0\")).toEqual(true);\n  expect(Util.is_newer(\"0.11.4.0\", \"0.11.3.0\")).toEqual(true);\n  expect(Util.is_newer(\"0.11.4.0\\n\", \"0.11.3.0\")).toEqual(true);\n  expect(Util.is_newer(\"0.11.3.0\", \"0.11.3.0\\n\")).toEqual(false);\n  expect(Util.is_newer(\"0.11.3.0\", \"0.11.4.0\\n\")).toEqual(false);\n  expect(Util.is_newer(\"0.12.0.0\", \"0.11.4.0\\n\")).toEqual(true);\n  expect(Util.is_newer(\"1.0.0\", \"0.11.4.0\\n\")).toEqual(true);\n  expect(Util.is_newer(\"1.0.1\", \"1.0.0\")).toEqual(true);\n});\n"
  },
  {
    "path": "gdbgui/src/js/types.d.ts",
    "content": "declare module \"statorgfc\" {\n  export let store: {\n    get(key: string): any;\n    set(key: string, value: any): any;\n  };\n}\n"
  },
  {
    "path": "gdbgui/static/css/gdbgui.css",
    "content": "@import \"tailwindcss/base\";\n@import \"tailwindcss/components\";\n@import \"tailwindcss/utilities\";\n\n/* styling for all html tags */\nbody {\n  background: #f5f6f7;\n  color: grey;\n  border-color: grey;\n  overflow: hidden;\n  padding: 0px;\n  height: 100%;\n}\npre {\n  overflow: visible !important;\n}\ntd {\n  vertical-align: top;\n}\n\n/* styling for generic classes */\n.flip180 {\n  -webkit-transform: rotate(180deg);\n  -moz-transform: rotate(180deg);\n  -o-transform: rotate(180deg);\n  -ms-transform: rotate(180deg);\n  transform: rotate(180deg);\n}\n.inline {\n  display: inline;\n}\n.bold {\n  font-weight: bold;\n}\n.italic {\n  font-style: italic;\n}\n.pre {\n  white-space: pre;\n}\n.monospace {\n  font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace;\n}\n.memadr,\n.memadr_react {\n  /* todo - migrate everything to react, then rename memadr_react to memadr  */\n  color: #489ce4;\n  text-decoration: none;\n}\n.lighttext {\n  color: #4a4a4a;\n}\n.glyphicon {\n  /* glyphicons are too bold, make them lighter*/\n  color: #848484;\n}\n.visibility_toggler {\n  cursor: pointer;\n}\n.placeholder {\n  color: #ccc;\n  font-style: italic;\n}\n.flex {\n  display: flex;\n}\n.flexrow {\n  display: flex;\n  flex-direction: row;\n}\n.flexcol {\n  display: flex;\n  flex-direction: column;\n}\n/* components get their own titlebars */\n.titlebar {\n  width: 100%;\n  color: black;\n  background-color: #ddf1ff;\n  border-color: #c3c3c3;\n  border-width: 1px;\n  border-style: solid;\n}\n.pointer {\n  cursor: pointer;\n}\n.collapser:hover .rowresizer {\n  cursor: row-resize;\n  height: 10px;\n  width: 100%;\n  background-color: white;\n  background-repeat: no-repeat;\n  background-position: 50%;\n  background-image: url(\"/static/vendor/images/splitjs/grips/horizontal.png\");\n}\n.collapser .rowresizer {\n  height: 10px;\n  width: 100%;\n  background-color: white;\n}\n\n.disabled {\n  background-color: lightgrey;\n  opacity: 0.6;\n  pointer-events: none;\n}\n.margin_sm {\n  margin: 2px;\n}\n.no_padding {\n  padding: 2px !important;\n}\n.highlight {\n  background: rgba(255, 255, 0, 0.5) !important;\n}\ndiv.breakpoint {\n  border: solid;\n  cursor: pointer;\n  /* need top and bottom border so when hovering and showing border on row, there is no \"jumping\" */\n  border-width: 0px;\n  border-top-width: 1px;\n  border-right-width: 1px;\n  border-bottom-width: 1px;\n  border-color: #f5f5f5; /* make border color the same as the background color */\n}\n.breakpoint td {\n  padding-top: 1px !important;\n  padding-bottom: 1px !important;\n}\n.breakpoint:hover {\n  background-color: #f5f5f5;\n}\n.breakpoint_trashcan,\n.right_help_icon_show_on_hover {\n  margin-right: 5px;\n  display: none !important;\n}\ndiv.breakpoint:hover div.breakpoint_trashcan,\n.varLI:hover .right_help_icon_show_on_hover {\n  display: inline !important;\n}\n.line_num {\n  width: 50px;\n  border-width: 0px;\n  border-top-width: 1px;\n  border-top-color: transparent;\n  border-right-width: 1px;\n  border-bottom-width: 0px;\n  border-style: solid;\n  border-right-color: #c7c7c7;\n  padding-left: 10px;\n  padding-right: 10px;\n  font-size: 0.9em;\n  color: #ababab;\n  cursor: pointer;\n}\n/* the line number has its style changed if it has a breakpoint */\n.line_num.breakpoint,\n.line_num.disabled_breakpoint {\n  color: black;\n}\n.line_num.breakpoint {\n  background: #33cdff !important;\n  border-style: solid;\n  /*border-top-width: 1px;*/\n  border-right-width: 0px;\n  /*border-bottom-width: 1px;*/\n  border-left-width: 0px;\n  border-color: transparent;\n}\n.line_num.disabled_breakpoint {\n  background: #ffd6d7 !important;\n}\n.line_num.conditional_breakpoint {\n  background: #ff9966 !important;\n  color: black;\n}\ntd.assembly {\n  padding-bottom: 0px;\n  padding-top: 0px;\n  white-space: nowrap;\n}\n/* instruction content */\n.instrContent {\n  min-width: 250px;\n  display: inline-block;\n}\n#code_table {\n  font-family: monospace;\n  border-collapse: separate;\n  font-size: 0.9em;\n}\n.srccode td {\n  padding-left: 3px;\n  padding-bottom: 0px;\n  padding-top: 0px;\n  border-style: solid;\n  border-top-width: 1px;\n  border-right-width: 1px;\n  border-bottom-width: 1px;\n  border-left-width: 0px;\n  border-color: transparent;\n}\ntd.line_num {\n  border-style: solid;\n  border-right-width: 1px;\n  border-top-width: 0px;\n  border-bottom-width: 0px;\n  border-left-width: 0px;\n  border-right-color: #d4d4d4;\n  border-top-color: transparent;\n  border-bottom-color: transparent;\n}\n/* wsp == whitespace. Needed to preserve leading whitespace.\n    this span wraps syntax-highlighted source code */\n.wsp {\n  white-space: pre;\n}\n\n.current_assembly_command {\n  font-weight: bold;\n}\n.padding_left {\n  padding-left: 5px;\n}\n.loc {\n  height: 18px;\n}\n.paused_on_line {\n  border-width: 0px;\n}\n.dropdown-btn {\n  vertical-align: top;\n  height: 30px;\n  border-top-left-radius: 0;\n  border-bottom-left-radius: 0;\n}\n#memory table {\n  font-family: monospace;\n}\n.memory_char:empty {\n  content: \"?\";\n}\n\n/* specific styling for ids or components */\n#always_on_top {\n  position: fixed;\n  top: 0;\n  margin-top: 0;\n  width: 100%;\n  border-bottom: black;\n  border-style: solid;\n  border-width: 0px;\n  z-index: 1000;\n  background: #f1f1f1;\n}\n/* .chad {\n  @apply font-bold py-2 px-4 rounded;\n}\n.btn-blue {\n  @apply bg-blue-500 text-white;\n}\n.btn-blue:hover {\n  @apply bg-red-700;\n} */\n\n#filesystem ul,\n#filesystem li {\n  list-style-type: none;\n  padding: 0;\n}\n#gdb_command_input,\n#gdb_command_input .gdb_command_input {\n  height: 30px;\n  border-width: 0;\n  background-color: #3c3c3c !important;\n  color: #f9f9f9 !important;\n  font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace !important;\n}\n#gdb_command_input {\n  width: 100%;\n  height: 30px;\n  position: absolute;\n  bottom: 0px;\n  left: 0px;\n}\n#gdb_command_input tr td:nth-child(1) {\n  width: 30px;\n  vertical-align: middle;\n}\n#gdb_command_input tr td:nth-child(2) {\n  width: 100%;\n}\n#gdb_command_input tr td:nth-child(3) {\n  width: 15px;\n  vertical-align: middle;\n  padding-right: 10px;\n}\n#gdb_command_input .gdb_command_input:focus {\n  outline-color: none;\n  box-shadow: none;\n}\n.fullscreen_modal {\n  padding: 10px;\n  width: 100%;\n  height: 100%;\n  position: fixed;\n  left: 0;\n  top: 0;\n  z-index: 120;\n  background: rgba(0, 0, 0, 0.8);\n  overflow: auto;\n}\n.blur {\n  filter: blur(3px);\n}\n#gdb_settings_modal {\n  width: 800px;\n  padding: 40px;\n  z-index: 120;\n  background: white;\n  max-height: 85%;\n  overflow: auto;\n  margin-left: auto;\n  margin-right: auto;\n}\n.modal_content {\n  padding: 20px;\n  margin-top: 10px;\n  margin-left: auto;\n  margin-right: auto;\n  background: white;\n  margin: auto;\n  border: 1px solid #888;\n  border-radius: 4px;\n  width: 500px;\n  box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);\n}\n\n#hovervar {\n  background: white;\n  width: 350px;\n  height: 200px;\n  position: absolute;\n  top: 0;\n  left: 0;\n  visibility: none;\n  overflow: auto;\n  padding: 10px;\n  border: solid 1px #989898;\n  border-radius: 4px;\n  /* http://www.cssmatic.com/box-shadow */\n  -webkit-box-shadow: 9px 10px 31px 0px rgba(0, 0, 0, 0.75);\n  -moz-box-shadow: 9px 10px 31px 0px rgba(0, 0, 0, 0.75);\n  box-shadow: 9px 10px 31px 0px rgba(0, 0, 0, 0.75);\n}\n\n#gdb_mi_output {\n  font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace;\n  overflow: auto;\n  font-size: 0.9em;\n  height: 300px;\n  width: 100%;\n}\n\n/* styling for \"Expressions\" component */\n#expressions li,\n#locals li,\n#hovervar li {\n  list-style: none;\n}\n#expressions,\n#locals,\n#hovervar {\n  white-space: nowrap;\n  font-family: monospace;\n  font-size: 0.9em;\n  overflow: auto;\n  margin: 0;\n  padding: 0;\n}\n\n.varLI .btn-radix {\n  display: none !important;\n}\n.varLI:hover .btn-radix {\n  display: inline !important;\n}\n\nul.varUL {\n  /* padding-top: 0; */\n  padding-left: 15px;\n  border: 0;\n  margin: 0;\n}\n/* Show type of variable in lighter text */\n.var_type {\n  color: #a0a0a0;\n  margin-left: 5px;\n  font-style: italic;\n}\n.plot {\n  width: 300px;\n  height: 200px;\n  display: visible;\n}\n#plot_coordinate_tooltip {\n  position: fixed;\n  display: none;\n  border: 1px solid #828282;\n  padding: 2px;\n  background-color: #f5f5f5;\n}\n#threads ul {\n  list-style: none;\n  padding: 0;\n}\n#memory table {\n  font-size: 0.9em;\n}\n\n/* Make refresh icon spin - http://www.bootply.com/128062*/\n.glyphicon-refresh-animate {\n  -animation: spin 0.7s infinite linear;\n  -webkit-animation: webkit-spin 0.7s infinite linear;\n}\n\n@-webkit-keyframes webkit-spin {\n  from {\n    -webkit-transform: rotate(0deg);\n  }\n  to {\n    -webkit-transform: rotate(360deg);\n  }\n}\n\n@keyframes spin {\n  from {\n    transform: scale(1) rotate(0deg);\n  }\n  to {\n    transform: scale(1) rotate(360deg);\n  }\n}\n\nbutton:focus {\n  /* For some reason normalize.css is getting injected into the html page, and it adds a 5px outline\n  on focused buttons */\n  outline-width: 0 !important;\n}\n"
  },
  {
    "path": "gdbgui/static/css/splitjs-gdbgui.css",
    "content": "/* splitjs is so unopinionated, it doesn't work without specific css classes (float: left) when splitting into two side-by-side\n panes (\"horizonal\" */\n/* splitjs classes for splitting the body of the webpage (https://github.com/nathancahill/Split.js) */\nhtml,\nbody,\n.splitjs_container {\n  /* for splitjs, it's important that html also has these properties, not just body */\n  height: 100%;\n  padding: 0;\n  margin: 0;\n  background-color: #333;\n  box-sizing: border-box;\n  overflow: hidden;\n  position: relative;\n}\n\n.split {\n  -webkit-box-sizing: border-box;\n  -moz-box-sizing: border-box;\n  box-sizing: border-box;\n\n  overflow-y: hidden;\n  overflow-x: hidden;\n}\n\n.content {\n  border: 0px solid #c0c0c0;\n  box-shadow: inset 0 1px 2px #e4e4e4;\n  background-color: #fff;\n  overflow: auto;\n  float: left;\n  height: 100%;\n  width: 100%;\n  position: relative;\n}\n\n.gutter {\n  background: lightgrey;\n}\n.gutter.gutter-horizontal {\n  cursor: col-resize;\n}\n\n.gutter.gutter-vertical {\n  cursor: row-resize;\n}\n\n.split.split-horizontal,\n.gutter.gutter-horizontal {\n  height: 100%;\n  float: left;\n}\n"
  },
  {
    "path": "gdbgui/static/css/tailwind.css",
    "content": "@import \"tailwindcss/base\";\n@import \"tailwindcss/components\";\n@import \"tailwindcss/utilities\";\n\nbutton:focus {\n  /* For some reason normalize.css is getting injected into the html page, and it adds a 5px outline\n  on focused buttons */\n  outline-width: 0;\n}\n"
  },
  {
    "path": "gdbgui/static/vendor/css/animate.css",
    "content": "@charset \"UTF-8\";\n\n/*!\n * animate.css -http://daneden.me/animate\n * Version - 3.5.2\n * Licensed under the MIT license - http://opensource.org/licenses/MIT\n *\n * Copyright (c) 2017 Daniel Eden\n */\n\n.animated {\n  animation-duration: 1s;\n  animation-fill-mode: both;\n}\n\n.animated.infinite {\n  animation-iteration-count: infinite;\n}\n\n.animated.hinge {\n  animation-duration: 2s;\n}\n\n.animated.flipOutX,\n.animated.flipOutY,\n.animated.bounceIn,\n.animated.bounceOut {\n  animation-duration: .75s;\n}\n\n@keyframes bounce {\n  from, 20%, 53%, 80%, to {\n    animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);\n    transform: translate3d(0,0,0);\n  }\n\n  40%, 43% {\n    animation-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);\n    transform: translate3d(0, -30px, 0);\n  }\n\n  70% {\n    animation-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);\n    transform: translate3d(0, -15px, 0);\n  }\n\n  90% {\n    transform: translate3d(0,-4px,0);\n  }\n}\n\n.bounce {\n  animation-name: bounce;\n  transform-origin: center bottom;\n}\n\n@keyframes flash {\n  from, 50%, to {\n    opacity: 1;\n  }\n\n  25%, 75% {\n    opacity: 0;\n  }\n}\n\n.flash {\n  animation-name: flash;\n}\n\n/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */\n\n@keyframes pulse {\n  from {\n    transform: scale3d(1, 1, 1);\n  }\n\n  50% {\n    transform: scale3d(1.05, 1.05, 1.05);\n  }\n\n  to {\n    transform: scale3d(1, 1, 1);\n  }\n}\n\n.pulse {\n  animation-name: pulse;\n}\n\n@keyframes rubberBand {\n  from {\n    transform: scale3d(1, 1, 1);\n  }\n\n  30% {\n    transform: scale3d(1.25, 0.75, 1);\n  }\n\n  40% {\n    transform: scale3d(0.75, 1.25, 1);\n  }\n\n  50% {\n    transform: scale3d(1.15, 0.85, 1);\n  }\n\n  65% {\n    transform: scale3d(.95, 1.05, 1);\n  }\n\n  75% {\n    transform: scale3d(1.05, .95, 1);\n  }\n\n  to {\n    transform: scale3d(1, 1, 1);\n  }\n}\n\n.rubberBand {\n  animation-name: rubberBand;\n}\n\n@keyframes shake {\n  from, to {\n    transform: translate3d(0, 0, 0);\n  }\n\n  10%, 30%, 50%, 70%, 90% {\n    transform: translate3d(-10px, 0, 0);\n  }\n\n  20%, 40%, 60%, 80% {\n    transform: translate3d(10px, 0, 0);\n  }\n}\n\n.shake {\n  animation-name: shake;\n}\n\n@keyframes headShake {\n  0% {\n    transform: translateX(0);\n  }\n\n  6.5% {\n    transform: translateX(-6px) rotateY(-9deg);\n  }\n\n  18.5% {\n    transform: translateX(5px) rotateY(7deg);\n  }\n\n  31.5% {\n    transform: translateX(-3px) rotateY(-5deg);\n  }\n\n  43.5% {\n    transform: translateX(2px) rotateY(3deg);\n  }\n\n  50% {\n    transform: translateX(0);\n  }\n}\n\n.headShake {\n  animation-timing-function: ease-in-out;\n  animation-name: headShake;\n}\n\n@keyframes swing {\n  20% {\n    transform: rotate3d(0, 0, 1, 15deg);\n  }\n\n  40% {\n    transform: rotate3d(0, 0, 1, -10deg);\n  }\n\n  60% {\n    transform: rotate3d(0, 0, 1, 5deg);\n  }\n\n  80% {\n    transform: rotate3d(0, 0, 1, -5deg);\n  }\n\n  to {\n    transform: rotate3d(0, 0, 1, 0deg);\n  }\n}\n\n.swing {\n  transform-origin: top center;\n  animation-name: swing;\n}\n\n@keyframes tada {\n  from {\n    transform: scale3d(1, 1, 1);\n  }\n\n  10%, 20% {\n    transform: scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg);\n  }\n\n  30%, 50%, 70%, 90% {\n    transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg);\n  }\n\n  40%, 60%, 80% {\n    transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg);\n  }\n\n  to {\n    transform: scale3d(1, 1, 1);\n  }\n}\n\n.tada {\n  animation-name: tada;\n}\n\n/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */\n\n@keyframes wobble {\n  from {\n    transform: none;\n  }\n\n  15% {\n    transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg);\n  }\n\n  30% {\n    transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg);\n  }\n\n  45% {\n    transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg);\n  }\n\n  60% {\n    transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg);\n  }\n\n  75% {\n    transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg);\n  }\n\n  to {\n    transform: none;\n  }\n}\n\n.wobble {\n  animation-name: wobble;\n}\n\n@keyframes jello {\n  from, 11.1%, to {\n    transform: none;\n  }\n\n  22.2% {\n    transform: skewX(-12.5deg) skewY(-12.5deg);\n  }\n\n  33.3% {\n    transform: skewX(6.25deg) skewY(6.25deg);\n  }\n\n  44.4% {\n    transform: skewX(-3.125deg) skewY(-3.125deg);\n  }\n\n  55.5% {\n    transform: skewX(1.5625deg) skewY(1.5625deg);\n  }\n\n  66.6% {\n    transform: skewX(-0.78125deg) skewY(-0.78125deg);\n  }\n\n  77.7% {\n    transform: skewX(0.390625deg) skewY(0.390625deg);\n  }\n\n  88.8% {\n    transform: skewX(-0.1953125deg) skewY(-0.1953125deg);\n  }\n}\n\n.jello {\n  animation-name: jello;\n  transform-origin: center;\n}\n\n@keyframes bounceIn {\n  from, 20%, 40%, 60%, 80%, to {\n    animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);\n  }\n\n  0% {\n    opacity: 0;\n    transform: scale3d(.3, .3, .3);\n  }\n\n  20% {\n    transform: scale3d(1.1, 1.1, 1.1);\n  }\n\n  40% {\n    transform: scale3d(.9, .9, .9);\n  }\n\n  60% {\n    opacity: 1;\n    transform: scale3d(1.03, 1.03, 1.03);\n  }\n\n  80% {\n    transform: scale3d(.97, .97, .97);\n  }\n\n  to {\n    opacity: 1;\n    transform: scale3d(1, 1, 1);\n  }\n}\n\n.bounceIn {\n  animation-name: bounceIn;\n}\n\n@keyframes bounceInDown {\n  from, 60%, 75%, 90%, to {\n    animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);\n  }\n\n  0% {\n    opacity: 0;\n    transform: translate3d(0, -3000px, 0);\n  }\n\n  60% {\n    opacity: 1;\n    transform: translate3d(0, 25px, 0);\n  }\n\n  75% {\n    transform: translate3d(0, -10px, 0);\n  }\n\n  90% {\n    transform: translate3d(0, 5px, 0);\n  }\n\n  to {\n    transform: none;\n  }\n}\n\n.bounceInDown {\n  animation-name: bounceInDown;\n}\n\n@keyframes bounceInLeft {\n  from, 60%, 75%, 90%, to {\n    animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);\n  }\n\n  0% {\n    opacity: 0;\n    transform: translate3d(-3000px, 0, 0);\n  }\n\n  60% {\n    opacity: 1;\n    transform: translate3d(25px, 0, 0);\n  }\n\n  75% {\n    transform: translate3d(-10px, 0, 0);\n  }\n\n  90% {\n    transform: translate3d(5px, 0, 0);\n  }\n\n  to {\n    transform: none;\n  }\n}\n\n.bounceInLeft {\n  animation-name: bounceInLeft;\n}\n\n@keyframes bounceInRight {\n  from, 60%, 75%, 90%, to {\n    animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);\n  }\n\n  from {\n    opacity: 0;\n    transform: translate3d(3000px, 0, 0);\n  }\n\n  60% {\n    opacity: 1;\n    transform: translate3d(-25px, 0, 0);\n  }\n\n  75% {\n    transform: translate3d(10px, 0, 0);\n  }\n\n  90% {\n    transform: translate3d(-5px, 0, 0);\n  }\n\n  to {\n    transform: none;\n  }\n}\n\n.bounceInRight {\n  animation-name: bounceInRight;\n}\n\n@keyframes bounceInUp {\n  from, 60%, 75%, 90%, to {\n    animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);\n  }\n\n  from {\n    opacity: 0;\n    transform: translate3d(0, 3000px, 0);\n  }\n\n  60% {\n    opacity: 1;\n    transform: translate3d(0, -20px, 0);\n  }\n\n  75% {\n    transform: translate3d(0, 10px, 0);\n  }\n\n  90% {\n    transform: translate3d(0, -5px, 0);\n  }\n\n  to {\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n.bounceInUp {\n  animation-name: bounceInUp;\n}\n\n@keyframes bounceOut {\n  20% {\n    transform: scale3d(.9, .9, .9);\n  }\n\n  50%, 55% {\n    opacity: 1;\n    transform: scale3d(1.1, 1.1, 1.1);\n  }\n\n  to {\n    opacity: 0;\n    transform: scale3d(.3, .3, .3);\n  }\n}\n\n.bounceOut {\n  animation-name: bounceOut;\n}\n\n@keyframes bounceOutDown {\n  20% {\n    transform: translate3d(0, 10px, 0);\n  }\n\n  40%, 45% {\n    opacity: 1;\n    transform: translate3d(0, -20px, 0);\n  }\n\n  to {\n    opacity: 0;\n    transform: translate3d(0, 2000px, 0);\n  }\n}\n\n.bounceOutDown {\n  animation-name: bounceOutDown;\n}\n\n@keyframes bounceOutLeft {\n  20% {\n    opacity: 1;\n    transform: translate3d(20px, 0, 0);\n  }\n\n  to {\n    opacity: 0;\n    transform: translate3d(-2000px, 0, 0);\n  }\n}\n\n.bounceOutLeft {\n  animation-name: bounceOutLeft;\n}\n\n@keyframes bounceOutRight {\n  20% {\n    opacity: 1;\n    transform: translate3d(-20px, 0, 0);\n  }\n\n  to {\n    opacity: 0;\n    transform: translate3d(2000px, 0, 0);\n  }\n}\n\n.bounceOutRight {\n  animation-name: bounceOutRight;\n}\n\n@keyframes bounceOutUp {\n  20% {\n    transform: translate3d(0, -10px, 0);\n  }\n\n  40%, 45% {\n    opacity: 1;\n    transform: translate3d(0, 20px, 0);\n  }\n\n  to {\n    opacity: 0;\n    transform: translate3d(0, -2000px, 0);\n  }\n}\n\n.bounceOutUp {\n  animation-name: bounceOutUp;\n}\n\n@keyframes fadeIn {\n  from {\n    opacity: 0;\n  }\n\n  to {\n    opacity: 1;\n  }\n}\n\n.fadeIn {\n  animation-name: fadeIn;\n}\n\n@keyframes fadeInDown {\n  from {\n    opacity: 0;\n    transform: translate3d(0, -100%, 0);\n  }\n\n  to {\n    opacity: 1;\n    transform: none;\n  }\n}\n\n.fadeInDown {\n  animation-name: fadeInDown;\n}\n\n@keyframes fadeInDownBig {\n  from {\n    opacity: 0;\n    transform: translate3d(0, -2000px, 0);\n  }\n\n  to {\n    opacity: 1;\n    transform: none;\n  }\n}\n\n.fadeInDownBig {\n  animation-name: fadeInDownBig;\n}\n\n@keyframes fadeInLeft {\n  from {\n    opacity: 0;\n    transform: translate3d(-100%, 0, 0);\n  }\n\n  to {\n    opacity: 1;\n    transform: none;\n  }\n}\n\n.fadeInLeft {\n  animation-name: fadeInLeft;\n}\n\n@keyframes fadeInLeftBig {\n  from {\n    opacity: 0;\n    transform: translate3d(-2000px, 0, 0);\n  }\n\n  to {\n    opacity: 1;\n    transform: none;\n  }\n}\n\n.fadeInLeftBig {\n  animation-name: fadeInLeftBig;\n}\n\n@keyframes fadeInRight {\n  from {\n    opacity: 0;\n    transform: translate3d(100%, 0, 0);\n  }\n\n  to {\n    opacity: 1;\n    transform: none;\n  }\n}\n\n.fadeInRight {\n  animation-name: fadeInRight;\n}\n\n@keyframes fadeInRightBig {\n  from {\n    opacity: 0;\n    transform: translate3d(2000px, 0, 0);\n  }\n\n  to {\n    opacity: 1;\n    transform: none;\n  }\n}\n\n.fadeInRightBig {\n  animation-name: fadeInRightBig;\n}\n\n@keyframes fadeInUp {\n  from {\n    opacity: 0;\n    transform: translate3d(0, 100%, 0);\n  }\n\n  to {\n    opacity: 1;\n    transform: none;\n  }\n}\n\n.fadeInUp {\n  animation-name: fadeInUp;\n}\n\n@keyframes fadeInUpBig {\n  from {\n    opacity: 0;\n    transform: translate3d(0, 2000px, 0);\n  }\n\n  to {\n    opacity: 1;\n    transform: none;\n  }\n}\n\n.fadeInUpBig {\n  animation-name: fadeInUpBig;\n}\n\n@keyframes fadeOut {\n  from {\n    opacity: 1;\n  }\n\n  to {\n    opacity: 0;\n  }\n}\n\n.fadeOut {\n  animation-name: fadeOut;\n}\n\n@keyframes fadeOutDown {\n  from {\n    opacity: 1;\n  }\n\n  to {\n    opacity: 0;\n    transform: translate3d(0, 100%, 0);\n  }\n}\n\n.fadeOutDown {\n  animation-name: fadeOutDown;\n}\n\n@keyframes fadeOutDownBig {\n  from {\n    opacity: 1;\n  }\n\n  to {\n    opacity: 0;\n    transform: translate3d(0, 2000px, 0);\n  }\n}\n\n.fadeOutDownBig {\n  animation-name: fadeOutDownBig;\n}\n\n@keyframes fadeOutLeft {\n  from {\n    opacity: 1;\n  }\n\n  to {\n    opacity: 0;\n    transform: translate3d(-100%, 0, 0);\n  }\n}\n\n.fadeOutLeft {\n  animation-name: fadeOutLeft;\n}\n\n@keyframes fadeOutLeftBig {\n  from {\n    opacity: 1;\n  }\n\n  to {\n    opacity: 0;\n    transform: translate3d(-2000px, 0, 0);\n  }\n}\n\n.fadeOutLeftBig {\n  animation-name: fadeOutLeftBig;\n}\n\n@keyframes fadeOutRight {\n  from {\n    opacity: 1;\n  }\n\n  to {\n    opacity: 0;\n    transform: translate3d(100%, 0, 0);\n  }\n}\n\n.fadeOutRight {\n  animation-name: fadeOutRight;\n}\n\n@keyframes fadeOutRightBig {\n  from {\n    opacity: 1;\n  }\n\n  to {\n    opacity: 0;\n    transform: translate3d(2000px, 0, 0);\n  }\n}\n\n.fadeOutRightBig {\n  animation-name: fadeOutRightBig;\n}\n\n@keyframes fadeOutUp {\n  from {\n    opacity: 1;\n  }\n\n  to {\n    opacity: 0;\n    transform: translate3d(0, -100%, 0);\n  }\n}\n\n.fadeOutUp {\n  animation-name: fadeOutUp;\n}\n\n@keyframes fadeOutUpBig {\n  from {\n    opacity: 1;\n  }\n\n  to {\n    opacity: 0;\n    transform: translate3d(0, -2000px, 0);\n  }\n}\n\n.fadeOutUpBig {\n  animation-name: fadeOutUpBig;\n}\n\n@keyframes flip {\n  from {\n    transform: perspective(400px) rotate3d(0, 1, 0, -360deg);\n    animation-timing-function: ease-out;\n  }\n\n  40% {\n    transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -190deg);\n    animation-timing-function: ease-out;\n  }\n\n  50% {\n    transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -170deg);\n    animation-timing-function: ease-in;\n  }\n\n  80% {\n    transform: perspective(400px) scale3d(.95, .95, .95);\n    animation-timing-function: ease-in;\n  }\n\n  to {\n    transform: perspective(400px);\n    animation-timing-function: ease-in;\n  }\n}\n\n.animated.flip {\n  -webkit-backface-visibility: visible;\n  backface-visibility: visible;\n  animation-name: flip;\n}\n\n@keyframes flipInX {\n  from {\n    transform: perspective(400px) rotate3d(1, 0, 0, 90deg);\n    animation-timing-function: ease-in;\n    opacity: 0;\n  }\n\n  40% {\n    transform: perspective(400px) rotate3d(1, 0, 0, -20deg);\n    animation-timing-function: ease-in;\n  }\n\n  60% {\n    transform: perspective(400px) rotate3d(1, 0, 0, 10deg);\n    opacity: 1;\n  }\n\n  80% {\n    transform: perspective(400px) rotate3d(1, 0, 0, -5deg);\n  }\n\n  to {\n    transform: perspective(400px);\n  }\n}\n\n.flipInX {\n  -webkit-backface-visibility: visible !important;\n  backface-visibility: visible !important;\n  animation-name: flipInX;\n}\n\n@keyframes flipInY {\n  from {\n    transform: perspective(400px) rotate3d(0, 1, 0, 90deg);\n    animation-timing-function: ease-in;\n    opacity: 0;\n  }\n\n  40% {\n    transform: perspective(400px) rotate3d(0, 1, 0, -20deg);\n    animation-timing-function: ease-in;\n  }\n\n  60% {\n    transform: perspective(400px) rotate3d(0, 1, 0, 10deg);\n    opacity: 1;\n  }\n\n  80% {\n    transform: perspective(400px) rotate3d(0, 1, 0, -5deg);\n  }\n\n  to {\n    transform: perspective(400px);\n  }\n}\n\n.flipInY {\n  -webkit-backface-visibility: visible !important;\n  backface-visibility: visible !important;\n  animation-name: flipInY;\n}\n\n@keyframes flipOutX {\n  from {\n    transform: perspective(400px);\n  }\n\n  30% {\n    transform: perspective(400px) rotate3d(1, 0, 0, -20deg);\n    opacity: 1;\n  }\n\n  to {\n    transform: perspective(400px) rotate3d(1, 0, 0, 90deg);\n    opacity: 0;\n  }\n}\n\n.flipOutX {\n  animation-name: flipOutX;\n  -webkit-backface-visibility: visible !important;\n  backface-visibility: visible !important;\n}\n\n@keyframes flipOutY {\n  from {\n    transform: perspective(400px);\n  }\n\n  30% {\n    transform: perspective(400px) rotate3d(0, 1, 0, -15deg);\n    opacity: 1;\n  }\n\n  to {\n    transform: perspective(400px) rotate3d(0, 1, 0, 90deg);\n    opacity: 0;\n  }\n}\n\n.flipOutY {\n  -webkit-backface-visibility: visible !important;\n  backface-visibility: visible !important;\n  animation-name: flipOutY;\n}\n\n@keyframes lightSpeedIn {\n  from {\n    transform: translate3d(100%, 0, 0) skewX(-30deg);\n    opacity: 0;\n  }\n\n  60% {\n    transform: skewX(20deg);\n    opacity: 1;\n  }\n\n  80% {\n    transform: skewX(-5deg);\n    opacity: 1;\n  }\n\n  to {\n    transform: none;\n    opacity: 1;\n  }\n}\n\n.lightSpeedIn {\n  animation-name: lightSpeedIn;\n  animation-timing-function: ease-out;\n}\n\n@keyframes lightSpeedOut {\n  from {\n    opacity: 1;\n  }\n\n  to {\n    transform: translate3d(100%, 0, 0) skewX(30deg);\n    opacity: 0;\n  }\n}\n\n.lightSpeedOut {\n  animation-name: lightSpeedOut;\n  animation-timing-function: ease-in;\n}\n\n@keyframes rotateIn {\n  from {\n    transform-origin: center;\n    transform: rotate3d(0, 0, 1, -200deg);\n    opacity: 0;\n  }\n\n  to {\n    transform-origin: center;\n    transform: none;\n    opacity: 1;\n  }\n}\n\n.rotateIn {\n  animation-name: rotateIn;\n}\n\n@keyframes rotateInDownLeft {\n  from {\n    transform-origin: left bottom;\n    transform: rotate3d(0, 0, 1, -45deg);\n    opacity: 0;\n  }\n\n  to {\n    transform-origin: left bottom;\n    transform: none;\n    opacity: 1;\n  }\n}\n\n.rotateInDownLeft {\n  animation-name: rotateInDownLeft;\n}\n\n@keyframes rotateInDownRight {\n  from {\n    transform-origin: right bottom;\n    transform: rotate3d(0, 0, 1, 45deg);\n    opacity: 0;\n  }\n\n  to {\n    transform-origin: right bottom;\n    transform: none;\n    opacity: 1;\n  }\n}\n\n.rotateInDownRight {\n  animation-name: rotateInDownRight;\n}\n\n@keyframes rotateInUpLeft {\n  from {\n    transform-origin: left bottom;\n    transform: rotate3d(0, 0, 1, 45deg);\n    opacity: 0;\n  }\n\n  to {\n    transform-origin: left bottom;\n    transform: none;\n    opacity: 1;\n  }\n}\n\n.rotateInUpLeft {\n  animation-name: rotateInUpLeft;\n}\n\n@keyframes rotateInUpRight {\n  from {\n    transform-origin: right bottom;\n    transform: rotate3d(0, 0, 1, -90deg);\n    opacity: 0;\n  }\n\n  to {\n    transform-origin: right bottom;\n    transform: none;\n    opacity: 1;\n  }\n}\n\n.rotateInUpRight {\n  animation-name: rotateInUpRight;\n}\n\n@keyframes rotateOut {\n  from {\n    transform-origin: center;\n    opacity: 1;\n  }\n\n  to {\n    transform-origin: center;\n    transform: rotate3d(0, 0, 1, 200deg);\n    opacity: 0;\n  }\n}\n\n.rotateOut {\n  animation-name: rotateOut;\n}\n\n@keyframes rotateOutDownLeft {\n  from {\n    transform-origin: left bottom;\n    opacity: 1;\n  }\n\n  to {\n    transform-origin: left bottom;\n    transform: rotate3d(0, 0, 1, 45deg);\n    opacity: 0;\n  }\n}\n\n.rotateOutDownLeft {\n  animation-name: rotateOutDownLeft;\n}\n\n@keyframes rotateOutDownRight {\n  from {\n    transform-origin: right bottom;\n    opacity: 1;\n  }\n\n  to {\n    transform-origin: right bottom;\n    transform: rotate3d(0, 0, 1, -45deg);\n    opacity: 0;\n  }\n}\n\n.rotateOutDownRight {\n  animation-name: rotateOutDownRight;\n}\n\n@keyframes rotateOutUpLeft {\n  from {\n    transform-origin: left bottom;\n    opacity: 1;\n  }\n\n  to {\n    transform-origin: left bottom;\n    transform: rotate3d(0, 0, 1, -45deg);\n    opacity: 0;\n  }\n}\n\n.rotateOutUpLeft {\n  animation-name: rotateOutUpLeft;\n}\n\n@keyframes rotateOutUpRight {\n  from {\n    transform-origin: right bottom;\n    opacity: 1;\n  }\n\n  to {\n    transform-origin: right bottom;\n    transform: rotate3d(0, 0, 1, 90deg);\n    opacity: 0;\n  }\n}\n\n.rotateOutUpRight {\n  animation-name: rotateOutUpRight;\n}\n\n@keyframes hinge {\n  0% {\n    transform-origin: top left;\n    animation-timing-function: ease-in-out;\n  }\n\n  20%, 60% {\n    transform: rotate3d(0, 0, 1, 80deg);\n    transform-origin: top left;\n    animation-timing-function: ease-in-out;\n  }\n\n  40%, 80% {\n    transform: rotate3d(0, 0, 1, 60deg);\n    transform-origin: top left;\n    animation-timing-function: ease-in-out;\n    opacity: 1;\n  }\n\n  to {\n    transform: translate3d(0, 700px, 0);\n    opacity: 0;\n  }\n}\n\n.hinge {\n  animation-name: hinge;\n}\n\n@keyframes jackInTheBox {\n  from {\n    opacity: 0;\n    transform: scale(0.1) rotate(30deg);\n    transform-origin: center bottom;\n  }\n\n  50% {\n    transform: rotate(-10deg);\n  }\n\n  70% {\n    transform: rotate(3deg);\n  }\n\n  to {\n    opacity: 1;\n    transform: scale(1);\n  }\n}\n\n.jackInTheBox {\n  animation-name: jackInTheBox;\n}\n\n/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */\n\n@keyframes rollIn {\n  from {\n    opacity: 0;\n    transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg);\n  }\n\n  to {\n    opacity: 1;\n    transform: none;\n  }\n}\n\n.rollIn {\n  animation-name: rollIn;\n}\n\n/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */\n\n@keyframes rollOut {\n  from {\n    opacity: 1;\n  }\n\n  to {\n    opacity: 0;\n    transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg);\n  }\n}\n\n.rollOut {\n  animation-name: rollOut;\n}\n\n@keyframes zoomIn {\n  from {\n    opacity: 0;\n    transform: scale3d(.3, .3, .3);\n  }\n\n  50% {\n    opacity: 1;\n  }\n}\n\n.zoomIn {\n  animation-name: zoomIn;\n}\n\n@keyframes zoomInDown {\n  from {\n    opacity: 0;\n    transform: scale3d(.1, .1, .1) translate3d(0, -1000px, 0);\n    animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);\n  }\n\n  60% {\n    opacity: 1;\n    transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0);\n    animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);\n  }\n}\n\n.zoomInDown {\n  animation-name: zoomInDown;\n}\n\n@keyframes zoomInLeft {\n  from {\n    opacity: 0;\n    transform: scale3d(.1, .1, .1) translate3d(-1000px, 0, 0);\n    animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);\n  }\n\n  60% {\n    opacity: 1;\n    transform: scale3d(.475, .475, .475) translate3d(10px, 0, 0);\n    animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);\n  }\n}\n\n.zoomInLeft {\n  animation-name: zoomInLeft;\n}\n\n@keyframes zoomInRight {\n  from {\n    opacity: 0;\n    transform: scale3d(.1, .1, .1) translate3d(1000px, 0, 0);\n    animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);\n  }\n\n  60% {\n    opacity: 1;\n    transform: scale3d(.475, .475, .475) translate3d(-10px, 0, 0);\n    animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);\n  }\n}\n\n.zoomInRight {\n  animation-name: zoomInRight;\n}\n\n@keyframes zoomInUp {\n  from {\n    opacity: 0;\n    transform: scale3d(.1, .1, .1) translate3d(0, 1000px, 0);\n    animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);\n  }\n\n  60% {\n    opacity: 1;\n    transform: scale3d(.475, .475, .475) translate3d(0, -60px, 0);\n    animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);\n  }\n}\n\n.zoomInUp {\n  animation-name: zoomInUp;\n}\n\n@keyframes zoomOut {\n  from {\n    opacity: 1;\n  }\n\n  50% {\n    opacity: 0;\n    transform: scale3d(.3, .3, .3);\n  }\n\n  to {\n    opacity: 0;\n  }\n}\n\n.zoomOut {\n  animation-name: zoomOut;\n}\n\n@keyframes zoomOutDown {\n  40% {\n    opacity: 1;\n    transform: scale3d(.475, .475, .475) translate3d(0, -60px, 0);\n    animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);\n  }\n\n  to {\n    opacity: 0;\n    transform: scale3d(.1, .1, .1) translate3d(0, 2000px, 0);\n    transform-origin: center bottom;\n    animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);\n  }\n}\n\n.zoomOutDown {\n  animation-name: zoomOutDown;\n}\n\n@keyframes zoomOutLeft {\n  40% {\n    opacity: 1;\n    transform: scale3d(.475, .475, .475) translate3d(42px, 0, 0);\n  }\n\n  to {\n    opacity: 0;\n    transform: scale(.1) translate3d(-2000px, 0, 0);\n    transform-origin: left center;\n  }\n}\n\n.zoomOutLeft {\n  animation-name: zoomOutLeft;\n}\n\n@keyframes zoomOutRight {\n  40% {\n    opacity: 1;\n    transform: scale3d(.475, .475, .475) translate3d(-42px, 0, 0);\n  }\n\n  to {\n    opacity: 0;\n    transform: scale(.1) translate3d(2000px, 0, 0);\n    transform-origin: right center;\n  }\n}\n\n.zoomOutRight {\n  animation-name: zoomOutRight;\n}\n\n@keyframes zoomOutUp {\n  40% {\n    opacity: 1;\n    transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0);\n    animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);\n  }\n\n  to {\n    opacity: 0;\n    transform: scale3d(.1, .1, .1) translate3d(0, -2000px, 0);\n    transform-origin: center bottom;\n    animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);\n  }\n}\n\n.zoomOutUp {\n  animation-name: zoomOutUp;\n}\n\n@keyframes slideInDown {\n  from {\n    transform: translate3d(0, -100%, 0);\n    visibility: visible;\n  }\n\n  to {\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n.slideInDown {\n  animation-name: slideInDown;\n}\n\n@keyframes slideInLeft {\n  from {\n    transform: translate3d(-100%, 0, 0);\n    visibility: visible;\n  }\n\n  to {\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n.slideInLeft {\n  animation-name: slideInLeft;\n}\n\n@keyframes slideInRight {\n  from {\n    transform: translate3d(100%, 0, 0);\n    visibility: visible;\n  }\n\n  to {\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n.slideInRight {\n  animation-name: slideInRight;\n}\n\n@keyframes slideInUp {\n  from {\n    transform: translate3d(0, 100%, 0);\n    visibility: visible;\n  }\n\n  to {\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n.slideInUp {\n  animation-name: slideInUp;\n}\n\n@keyframes slideOutDown {\n  from {\n    transform: translate3d(0, 0, 0);\n  }\n\n  to {\n    visibility: hidden;\n    transform: translate3d(0, 100%, 0);\n  }\n}\n\n.slideOutDown {\n  animation-name: slideOutDown;\n}\n\n@keyframes slideOutLeft {\n  from {\n    transform: translate3d(0, 0, 0);\n  }\n\n  to {\n    visibility: hidden;\n    transform: translate3d(-100%, 0, 0);\n  }\n}\n\n.slideOutLeft {\n  animation-name: slideOutLeft;\n}\n\n@keyframes slideOutRight {\n  from {\n    transform: translate3d(0, 0, 0);\n  }\n\n  to {\n    visibility: hidden;\n    transform: translate3d(100%, 0, 0);\n  }\n}\n\n.slideOutRight {\n  animation-name: slideOutRight;\n}\n\n@keyframes slideOutUp {\n  from {\n    transform: translate3d(0, 0, 0);\n  }\n\n  to {\n    visibility: hidden;\n    transform: translate3d(0, -100%, 0);\n  }\n}\n\n.slideOutUp {\n  animation-name: slideOutUp;\n}\n"
  },
  {
    "path": "gdbgui/static/vendor/css/gdbgui_awesomeplete.css",
    "content": "/* This is mostly from the vendor, with a few overrides for gdbgui */\n\n.awesomplete [hidden] {\n    display: none;\n}\n\n.awesomplete .visually-hidden {\n    position: absolute;\n    clip: rect(0, 0, 0, 0);\n}\n\n.awesomplete {\n    display: inline-block;\n    position: relative;\n    width: 100%;\n}\n\n.awesomplete > input {\n    display: block;\n    height: 2em;\n}\n#source_file_dropdown_button{\n    height: 2em;\n}\n.awesomplete > ul {\n    position: absolute;\n    left: 0;\n    z-index: 11; /* make dropdown stay above gdbgui's controls */\n    min-width: 100%;\n    box-sizing: border-box;\n    list-style: none;\n    padding: 0;\n    margin: 0;\n    background: #fff;\n\n    /* Limit to 200px high so it doesn't take over the page  */\n    max-height: 200px;\n    /* and add scrollbar */\n    overflow: auto;\n}\n\n.awesomplete > ul:empty {\n    display: none;\n}\n\n.awesomplete > ul {\n\tborder-radius: .3em;\n\tmargin: .2em 0 0;\n\tbackground: white;\n\tborder: 1px solid rgba(0,0,0,.3);\n\tbox-shadow: .05em .2em .6em rgba(0,0,0,.2);\n\ttext-shadow: none;\n}\n\n@supports (transform: scale(0)) {\n\t.awesomplete > ul {\n\t\ttransition: .3s cubic-bezier(.4,.2,.5,1.4);\n\t\ttransform-origin: 1.43em -.43em;\n\t}\n\n\t.awesomplete > ul[hidden],\n\t.awesomplete > ul:empty {\n\t\topacity: 0;\n\t\ttransform: scale(0);\n\t\tdisplay: block;\n\t\ttransition-timing-function: ease;\n\t}\n}\n\n\t/* Pointer */\n\t.awesomplete > ul:before {\n\t\tcontent: \"\";\n\t\tposition: absolute;\n\t\ttop: -.43em;\n\t\tleft: 1em;\n\t\twidth: 0; height: 0;\n\t\tpadding: .4em;\n\t\tbackground: white;\n\t\tborder: inherit;\n\t\tborder-right: 0;\n\t\tborder-bottom: 0;\n\t\t-webkit-transform: rotate(45deg);\n\t\ttransform: rotate(45deg);\n\t}\n\n\t.awesomplete > ul > li {\n\t\tposition: relative;\n\t\tpadding: .2em .5em;\n\t\tcursor: pointer;\n\t}\n\n\t.awesomplete > ul > li:hover {\n\t\tbackground: hsl(200, 40%, 80%);\n\t\tcolor: black;\n\t}\n\n\t.awesomplete > ul > li[aria-selected=\"true\"] {\n\t\tbackground: hsl(205, 40%, 40%);\n\t\tcolor: white;\n\t}\n\n\t\t.awesomplete mark {\n\t\t\tbackground: hsl(65, 100%, 50%);\n\t\t}\n\n\t\t.awesomplete li:hover mark {\n\t\t\tbackground: hsl(68, 100%, 41%);\n\t\t}\n\n\t\t.awesomplete li[aria-selected=\"true\"] mark {\n\t\t\tbackground: hsl(86, 100%, 21%);\n\t\t\tcolor: inherit;\n\t\t}\n/*# sourceMappingURL=awesomplete.css.map */\n"
  },
  {
    "path": "gdbgui/static/vendor/css/pygments/emacs.css",
    "content": ".emacs .hll { background-color: #ffffcc }\n.emacs .c { color: #008800; font-style: italic } /* Comment */\n.emacs .err { border: 1px solid #FF0000 } /* Error */\n.emacs .k { color: #AA22FF; font-weight: bold } /* Keyword */\n.emacs .o { color: #666666 } /* Operator */\n.emacs .ch { color: #008800; font-style: italic } /* Comment.Hashbang */\n.emacs .cm { color: #008800; font-style: italic } /* Comment.Multiline */\n.emacs .cp { color: #008800 } /* Comment.Preproc */\n.emacs .cpf { color: #008800; font-style: italic } /* Comment.PreprocFile */\n.emacs .c1 { color: #008800; font-style: italic } /* Comment.Single */\n.emacs .cs { color: #008800; font-weight: bold } /* Comment.Special */\n.emacs .gd { color: #A00000 } /* Generic.Deleted */\n.emacs .ge { font-style: italic } /* Generic.Emph */\n.emacs .gr { color: #FF0000 } /* Generic.Error */\n.emacs .gh { color: #000080; font-weight: bold } /* Generic.Heading */\n.emacs .gi { color: #00A000 } /* Generic.Inserted */\n.emacs .go { color: #888888 } /* Generic.Output */\n.emacs .gp { color: #000080; font-weight: bold } /* Generic.Prompt */\n.emacs .gs { font-weight: bold } /* Generic.Strong */\n.emacs .gu { color: #800080; font-weight: bold } /* Generic.Subheading */\n.emacs .gt { color: #0044DD } /* Generic.Traceback */\n.emacs .kc { color: #AA22FF; font-weight: bold } /* Keyword.Constant */\n.emacs .kd { color: #AA22FF; font-weight: bold } /* Keyword.Declaration */\n.emacs .kn { color: #AA22FF; font-weight: bold } /* Keyword.Namespace */\n.emacs .kp { color: #AA22FF } /* Keyword.Pseudo */\n.emacs .kr { color: #AA22FF; font-weight: bold } /* Keyword.Reserved */\n.emacs .kt { color: #00BB00; font-weight: bold } /* Keyword.Type */\n.emacs .m { color: #666666 } /* Literal.Number */\n.emacs .s { color: #BB4444 } /* Literal.String */\n.emacs .na { color: #BB4444 } /* Name.Attribute */\n.emacs .nb { color: #AA22FF } /* Name.Builtin */\n.emacs .nc { color: #0000FF } /* Name.Class */\n.emacs .no { color: #880000 } /* Name.Constant */\n.emacs .nd { color: #AA22FF } /* Name.Decorator */\n.emacs .ni { color: #999999; font-weight: bold } /* Name.Entity */\n.emacs .ne { color: #D2413A; font-weight: bold } /* Name.Exception */\n.emacs .nf { color: #00A000 } /* Name.Function */\n.emacs .nl { color: #A0A000 } /* Name.Label */\n.emacs .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */\n.emacs .nt { color: #008000; font-weight: bold } /* Name.Tag */\n.emacs .nv { color: #B8860B } /* Name.Variable */\n.emacs .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */\n.emacs .w { color: #bbbbbb } /* Text.Whitespace */\n.emacs .mb { color: #666666 } /* Literal.Number.Bin */\n.emacs .mf { color: #666666 } /* Literal.Number.Float */\n.emacs .mh { color: #666666 } /* Literal.Number.Hex */\n.emacs .mi { color: #666666 } /* Literal.Number.Integer */\n.emacs .mo { color: #666666 } /* Literal.Number.Oct */\n.emacs .sa { color: #BB4444 } /* Literal.String.Affix */\n.emacs .sb { color: #BB4444 } /* Literal.String.Backtick */\n.emacs .sc { color: #BB4444 } /* Literal.String.Char */\n.emacs .dl { color: #BB4444 } /* Literal.String.Delimiter */\n.emacs .sd { color: #BB4444; font-style: italic } /* Literal.String.Doc */\n.emacs .s2 { color: #BB4444 } /* Literal.String.Double */\n.emacs .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */\n.emacs .sh { color: #BB4444 } /* Literal.String.Heredoc */\n.emacs .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */\n.emacs .sx { color: #008000 } /* Literal.String.Other */\n.emacs .sr { color: #BB6688 } /* Literal.String.Regex */\n.emacs .s1 { color: #BB4444 } /* Literal.String.Single */\n.emacs .ss { color: #B8860B } /* Literal.String.Symbol */\n.emacs .bp { color: #AA22FF } /* Name.Builtin.Pseudo */\n.emacs .fm { color: #00A000 } /* Name.Function.Magic */\n.emacs .vc { color: #B8860B } /* Name.Variable.Class */\n.emacs .vg { color: #B8860B } /* Name.Variable.Global */\n.emacs .vi { color: #B8860B } /* Name.Variable.Instance */\n.emacs .vm { color: #B8860B } /* Name.Variable.Magic */\n.emacs .il { color: #666666 } /* Literal.Number.Integer.Long */\n"
  },
  {
    "path": "gdbgui/static/vendor/css/pygments/light.css",
    "content": "/* gdbgui-specific stuff */\n.light {\n    background-color: white;\n    color: black;\n}\n\n/* when hovering, set background color of entire row */\n.light .paused_on_line {\n    background-color: #bbefff;\n}\n\n.light .assembly { color: black; }\n\n/* show a flash of color */\n.light .flash {\n    -webkit-animation-name: flash-animation-default;\n    -webkit-animation-duration: 3.0s;\n\n    animation-name: flash-animation-default;\n    animation-duration: 3.0s;\n}\n\n@-webkit-keyframes flash-animation-default {\n    from { background: white; }\n    from { background: #fdfd54; }\n    to   { background: default; }\n}\n\n@keyframes flash-animation-default {\n    from { background: white; }\n    from { background: #fdfd54; }\n    to   { background: default; }\n}\n\n/* generated by pygments */\n.light .hll { background-color: #ffffcc }\n.light .c { color: #408080; font-style: italic } /* Comment */\n.light .err { border: 1px solid #FF0000 } /* Error */\n.light .k { color: #008000; font-weight: bold } /* Keyword */\n.light .o { color: #666666 } /* Operator */\n.light .ch { color: #408080; font-style: italic } /* Comment.Hashbang */\n.light .cm { color: #408080; font-style: italic } /* Comment.Multiline */\n.light .cp { color: #BC7A00 } /* Comment.Preproc */\n.light .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */\n.light .c1 { color: #408080; font-style: italic } /* Comment.Single */\n.light .cs { color: #408080; font-style: italic } /* Comment.Special */\n.light .gd { color: #A00000 } /* Generic.Deleted */\n.light .ge { font-style: italic } /* Generic.Emph */\n.light .gr { color: #FF0000 } /* Generic.Error */\n.light .gh { color: #000080; font-weight: bold } /* Generic.Heading */\n.light .gi { color: #00A000 } /* Generic.Inserted */\n.light .go { color: #888888 } /* Generic.Output */\n.light .gp { color: #000080; font-weight: bold } /* Generic.Prompt */\n.light .gs { font-weight: bold } /* Generic.Strong */\n.light .gu { color: #800080; font-weight: bold } /* Generic.Subheading */\n.light .gt { color: #0044DD } /* Generic.Traceback */\n.light .kc { color: #008000; font-weight: bold } /* Keyword.Constant */\n.light .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */\n.light .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */\n.light .kp { color: #008000 } /* Keyword.Pseudo */\n.light .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */\n.light .kt { color: #B00040 } /* Keyword.Type */\n.light .m { color: #666666 } /* Literal.Number */\n.light .s { color: #BA2121 } /* Literal.String */\n.light .na { color: #7D9029 } /* Name.Attribute */\n.light .nb { color: #008000 } /* Name.Builtin */\n.light .nc { color: #0000FF; font-weight: bold } /* Name.Class */\n.light .no { color: #880000 } /* Name.Constant */\n.light .nd { color: #AA22FF } /* Name.Decorator */\n.light .ni { color: #999999; font-weight: bold } /* Name.Entity */\n.light .ne { color: #D2413A; font-weight: bold } /* Name.Exception */\n.light .nf { color: #0000FF } /* Name.Function */\n.light .nl { color: #A0A000 } /* Name.Label */\n.light .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */\n.light .nt { color: #008000; font-weight: bold } /* Name.Tag */\n.light .nv { color: #19177C } /* Name.Variable */\n.light .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */\n.light .w { color: #bbbbbb } /* Text.Whitespace */\n.light .mb { color: #666666 } /* Literal.Number.Bin */\n.light .mf { color: #666666 } /* Literal.Number.Float */\n.light .mh { color: #666666 } /* Literal.Number.Hex */\n.light .mi { color: #666666 } /* Literal.Number.Integer */\n.light .mo { color: #666666 } /* Literal.Number.Oct */\n.light .sa { color: #BA2121 } /* Literal.String.Affix */\n.light .sb { color: #BA2121 } /* Literal.String.Backtick */\n.light .sc { color: #BA2121 } /* Literal.String.Char */\n.light .dl { color: #BA2121 } /* Literal.String.Delimiter */\n.light .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */\n.light .s2 { color: #BA2121 } /* Literal.String.Double */\n.light .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */\n.light .sh { color: #BA2121 } /* Literal.String.Heredoc */\n.light .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */\n.light .sx { color: #008000 } /* Literal.String.Other */\n.light .sr { color: #BB6688 } /* Literal.String.Regex */\n.light .s1 { color: #BA2121 } /* Literal.String.Single */\n.light .ss { color: #19177C } /* Literal.String.Symbol */\n.light .bp { color: #008000 } /* Name.Builtin.Pseudo */\n.light .fm { color: #0000FF } /* Name.Function.Magic */\n.light .vc { color: #19177C } /* Name.Variable.Class */\n.light .vg { color: #19177C } /* Name.Variable.Global */\n.light .vi { color: #19177C } /* Name.Variable.Instance */\n.light .vm { color: #19177C } /* Name.Variable.Magic */\n.light .il { color: #666666 } /* Literal.Number.Integer.Long */\n"
  },
  {
    "path": "gdbgui/static/vendor/css/pygments/monokai.css",
    "content": "/* gdbgui-specific stuff*/\n.monokai {\n    background-color: #333;\n    color: grey;\n}\n\n/* when hovering, set background color of entire row */\n.monokai .paused_on_line {\n    background-color: #444;\n}\n\n.monokai .assembly { color: #d8d8d8; }\n\n/* show a flash of color */\n.monokai .flash {\n    -webkit-animation-name: flash-animation-monokai;\n    -webkit-animation-duration: 3.0s;\n\n    animation-name: flash-animation-monokai;\n    animation-duration: 3.0s;\n}\n\n@-webkit-keyframes flash-animation-monokai {\n    from { background: white; }\n    from { background: #444; }\n    to   { background: default; }\n}\n\n@keyframes flash-animation-monokai {\n    from { background: white; }\n    from { background: #444; }\n    to   { background: default; }\n}\n\n\n/* generated by pygments */\n.monokai .hll { background-color: #49483e }\n.monokai .c { color: #75715e } /* Comment */\n.monokai .err { color: #960050; background-color: #1e0010 } /* Error */\n.monokai .k { color: #66d9ef } /* Keyword */\n.monokai .l { color: #ae81ff } /* Literal */\n.monokai .n { color: #f8f8f2 } /* Name */\n.monokai .o { color: #f92672 } /* Operator */\n.monokai .p { color: #f8f8f2 } /* Punctuation */\n.monokai .ch { color: #75715e } /* Comment.Hashbang */\n.monokai .cm { color: #75715e } /* Comment.Multiline */\n/*.monokai .cp { color: #75715e } /* Comment.Preproc  THIS IS PROVIDED BY PYGMENTS BUT LOOKS WRONG*/\n.monokai .cp { color: #e8636f } /* Comment.Preproc UPDATED FOR GDBGUI HERE (pink, not grey) */\n\n/*.monokai .cpf { color: #75715e } /* Comment.PreprocFile THIS IS PROVIDED BY PYGMENTS BUT LOOKS WRONG */\n.monokai .cpf { color: #fbff00 } /* Comment.PreprocFile UPDATED FOR GDBGUI HERE (yellow, not grey) */\n\n.monokai .c1 { color: #75715e } /* Comment.Single */\n.monokai .cs { color: #75715e } /* Comment.Special */\n.monokai .gd { color: #f92672 } /* Generic.Deleted */\n.monokai .ge { font-style: italic } /* Generic.Emph */\n.monokai .gi { color: #a6e22e } /* Generic.Inserted */\n.monokai .gs { font-weight: bold } /* Generic.Strong */\n.monokai .gu { color: #75715e } /* Generic.Subheading */\n.monokai .kc { color: #66d9ef } /* Keyword.Constant */\n.monokai .kd { color: #66d9ef } /* Keyword.Declaration */\n.monokai .kn { color: #f92672 } /* Keyword.Namespace */\n.monokai .kp { color: #66d9ef } /* Keyword.Pseudo */\n.monokai .kr { color: #66d9ef } /* Keyword.Reserved */\n.monokai .kt { color: #66d9ef } /* Keyword.Type */\n.monokai .ld { color: #e6db74 } /* Literal.Date */\n.monokai .m { color: #ae81ff } /* Literal.Number */\n.monokai .s { color: #e6db74 } /* Literal.String */\n.monokai .na { color: #a6e22e } /* Name.Attribute */\n.monokai .nb { color: #f8f8f2 } /* Name.Builtin */\n.monokai .nc { color: #a6e22e } /* Name.Class */\n.monokai .no { color: #66d9ef } /* Name.Constant */\n.monokai .nd { color: #a6e22e } /* Name.Decorator */\n.monokai .ni { color: #f8f8f2 } /* Name.Entity */\n.monokai .ne { color: #a6e22e } /* Name.Exception */\n.monokai .nf { color: #a6e22e } /* Name.Function */\n.monokai .nl { color: #f8f8f2 } /* Name.Label */\n.monokai .nn { color: #f8f8f2 } /* Name.Namespace */\n.monokai .nx { color: #a6e22e } /* Name.Other */\n.monokai .py { color: #f8f8f2 } /* Name.Property */\n.monokai .nt { color: #f92672 } /* Name.Tag */\n.monokai .nv { color: #f8f8f2 } /* Name.Variable */\n.monokai .ow { color: #f92672 } /* Operator.Word */\n.monokai .w { color: #f8f8f2 } /* Text.Whitespace */\n.monokai .mb { color: #ae81ff } /* Literal.Number.Bin */\n.monokai .mf { color: #ae81ff } /* Literal.Number.Float */\n.monokai .mh { color: #ae81ff } /* Literal.Number.Hex */\n.monokai .mi { color: #ae81ff } /* Literal.Number.Integer */\n.monokai .mo { color: #ae81ff } /* Literal.Number.Oct */\n.monokai .sa { color: #e6db74 } /* Literal.String.Affix */\n.monokai .sb { color: #e6db74 } /* Literal.String.Backtick */\n.monokai .sc { color: #e6db74 } /* Literal.String.Char */\n.monokai .dl { color: #e6db74 } /* Literal.String.Delimiter */\n.monokai .sd { color: #e6db74 } /* Literal.String.Doc */\n.monokai .s2 { color: #e6db74 } /* Literal.String.Double */\n.monokai .se { color: #ae81ff } /* Literal.String.Escape */\n.monokai .sh { color: #e6db74 } /* Literal.String.Heredoc */\n.monokai .si { color: #e6db74 } /* Literal.String.Interpol */\n.monokai .sx { color: #e6db74 } /* Literal.String.Other */\n.monokai .sr { color: #e6db74 } /* Literal.String.Regex */\n.monokai .s1 { color: #e6db74 } /* Literal.String.Single */\n.monokai .ss { color: #e6db74 } /* Literal.String.Symbol */\n.monokai .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */\n.monokai .fm { color: #a6e22e } /* Name.Function.Magic */\n.monokai .vc { color: #f8f8f2 } /* Name.Variable.Class */\n.monokai .vg { color: #f8f8f2 } /* Name.Variable.Global */\n.monokai .vi { color: #f8f8f2 } /* Name.Variable.Instance */\n.monokai .vm { color: #f8f8f2 } /* Name.Variable.Magic */\n.monokai .il { color: #ae81ff } /* Literal.Number.Integer.Long */\n"
  },
  {
    "path": "gdbgui/static/vendor/css/pygments/vim.css",
    "content": ".vim .hll { background-color: #222222 }\n.vim .c { color: #000080 } /* Comment */\n.vim .err { color: #cccccc; border: 1px solid #FF0000 } /* Error */\n.vim .esc { color: #cccccc } /* Escape */\n.vim .g { color: #cccccc } /* Generic */\n.vim .k { color: #cdcd00 } /* Keyword */\n.vim .l { color: #cccccc } /* Literal */\n.vim .n { color: #cccccc } /* Name */\n.vim .o { color: #3399cc } /* Operator */\n.vim .x { color: #cccccc } /* Other */\n.vim .p { color: #cccccc } /* Punctuation */\n.vim .ch { color: #000080 } /* Comment.Hashbang */\n.vim .cm { color: #000080 } /* Comment.Multiline */\n.vim .cp { color: #000080 } /* Comment.Preproc */\n.vim .cpf { color: #000080 } /* Comment.PreprocFile */\n.vim .c1 { color: #000080 } /* Comment.Single */\n.vim .cs { color: #cd0000; font-weight: bold } /* Comment.Special */\n.vim .gd { color: #cd0000 } /* Generic.Deleted */\n.vim .ge { color: #cccccc; font-style: italic } /* Generic.Emph */\n.vim .gr { color: #FF0000 } /* Generic.Error */\n.vim .gh { color: #000080; font-weight: bold } /* Generic.Heading */\n.vim .gi { color: #00cd00 } /* Generic.Inserted */\n.vim .go { color: #888888 } /* Generic.Output */\n.vim .gp { color: #000080; font-weight: bold } /* Generic.Prompt */\n.vim .gs { color: #cccccc; font-weight: bold } /* Generic.Strong */\n.vim .gu { color: #800080; font-weight: bold } /* Generic.Subheading */\n.vim .gt { color: #0044DD } /* Generic.Traceback */\n.vim .kc { color: #cdcd00 } /* Keyword.Constant */\n.vim .kd { color: #00cd00 } /* Keyword.Declaration */\n.vim .kn { color: #cd00cd } /* Keyword.Namespace */\n.vim .kp { color: #cdcd00 } /* Keyword.Pseudo */\n.vim .kr { color: #cdcd00 } /* Keyword.Reserved */\n.vim .kt { color: #00cd00 } /* Keyword.Type */\n.vim .ld { color: #cccccc } /* Literal.Date */\n.vim .m { color: #cd00cd } /* Literal.Number */\n.vim .s { color: #cd0000 } /* Literal.String */\n.vim .na { color: #cccccc } /* Name.Attribute */\n.vim .nb { color: #cd00cd } /* Name.Builtin */\n.vim .nc { color: #00cdcd } /* Name.Class */\n.vim .no { color: #cccccc } /* Name.Constant */\n.vim .nd { color: #cccccc } /* Name.Decorator */\n.vim .ni { color: #cccccc } /* Name.Entity */\n.vim .ne { color: #666699; font-weight: bold } /* Name.Exception */\n.vim .nf { color: #cccccc } /* Name.Function */\n.vim .nl { color: #cccccc } /* Name.Label */\n.vim .nn { color: #cccccc } /* Name.Namespace */\n.vim .nx { color: #cccccc } /* Name.Other */\n.vim .py { color: #cccccc } /* Name.Property */\n.vim .nt { color: #cccccc } /* Name.Tag */\n.vim .nv { color: #00cdcd } /* Name.Variable */\n.vim .ow { color: #cdcd00 } /* Operator.Word */\n.vim .w { color: #cccccc } /* Text.Whitespace */\n.vim .mb { color: #cd00cd } /* Literal.Number.Bin */\n.vim .mf { color: #cd00cd } /* Literal.Number.Float */\n.vim .mh { color: #cd00cd } /* Literal.Number.Hex */\n.vim .mi { color: #cd00cd } /* Literal.Number.Integer */\n.vim .mo { color: #cd00cd } /* Literal.Number.Oct */\n.vim .sa { color: #cd0000 } /* Literal.String.Affix */\n.vim .sb { color: #cd0000 } /* Literal.String.Backtick */\n.vim .sc { color: #cd0000 } /* Literal.String.Char */\n.vim .dl { color: #cd0000 } /* Literal.String.Delimiter */\n.vim .sd { color: #cd0000 } /* Literal.String.Doc */\n.vim .s2 { color: #cd0000 } /* Literal.String.Double */\n.vim .se { color: #cd0000 } /* Literal.String.Escape */\n.vim .sh { color: #cd0000 } /* Literal.String.Heredoc */\n.vim .si { color: #cd0000 } /* Literal.String.Interpol */\n.vim .sx { color: #cd0000 } /* Literal.String.Other */\n.vim .sr { color: #cd0000 } /* Literal.String.Regex */\n.vim .s1 { color: #cd0000 } /* Literal.String.Single */\n.vim .ss { color: #cd0000 } /* Literal.String.Symbol */\n.vim .bp { color: #cd00cd } /* Name.Builtin.Pseudo */\n.vim .fm { color: #cccccc } /* Name.Function.Magic */\n.vim .vc { color: #00cdcd } /* Name.Variable.Class */\n.vim .vg { color: #00cdcd } /* Name.Variable.Global */\n.vim .vi { color: #00cdcd } /* Name.Variable.Instance */\n.vim .vm { color: #00cdcd } /* Name.Variable.Magic */\n.vim .il { color: #cd00cd } /* Literal.Number.Integer.Long */\n"
  },
  {
    "path": "gdbgui/static/vendor/js/splitjs.min-1.2.0.js",
    "content": "/*! Split.js - v1.2.0 */\n\"use strict\";(function(){var a=this,b=a.attachEvent&&!a[d],c=a.document,d=\"addEventListener\",e=\"removeEventListener\",f=\"getBoundingClientRect\",g=.5,h=function(){for(var a,b=[\"\",\"-webkit-\",\"-moz-\",\"-o-\"],d=0;d<b.length;d++)if(a=c.createElement(\"div\"),a.style.cssText=\"width:\"+b[d]+\"calc(9px)\",a.style.length)return b[d]+\"calc\"}(),i=function(a){return\"string\"==typeof a||a instanceof String?c.querySelector(a):a},j=function(j,k){var l,m,n,o,p,q,r,s,t=[];k=\"undefined\"!=typeof k?k:{},\"undefined\"==typeof k.gutterSize&&(k.gutterSize=10),\"undefined\"==typeof k.minSize&&(k.minSize=100),\"undefined\"==typeof k.snapOffset&&(k.snapOffset=30),\"undefined\"==typeof k.direction&&(k.direction=\"horizontal\"),\"undefined\"==typeof k.elementStyle&&(k.elementStyle=function(a,c,d){var e={};return\"string\"==typeof c||c instanceof String?e[a]=c:b?e[a]=c+\"%\":e[a]=h+\"(\"+c+\"% - \"+d+\"px)\",e}),\"undefined\"==typeof k.gutterStyle&&(k.gutterStyle=function(a,b){var c={};return c[a]=b+\"px\",c}),\"horizontal\"==k.direction?(l=\"width\",n=\"clientWidth\",o=\"clientX\",p=\"left\",q=\"gutter gutter-horizontal\",r=\"paddingLeft\",s=\"paddingRight\",k.cursor||(k.cursor=\"ew-resize\")):\"vertical\"==k.direction&&(l=\"height\",n=\"clientHeight\",o=\"clientY\",p=\"top\",q=\"gutter gutter-vertical\",r=\"paddingTop\",s=\"paddingBottom\",k.cursor||(k.cursor=\"ns-resize\"));var u=function(b){var c=this,e=c.a,f=c.b;!c.dragging&&k.onDragStart&&k.onDragStart(),b.preventDefault(),c.dragging=!0,c.move=w.bind(c),c.stop=v.bind(c),a[d](\"mouseup\",c.stop),a[d](\"touchend\",c.stop),a[d](\"touchcancel\",c.stop),c.parent[d](\"mousemove\",c.move),c.parent[d](\"touchmove\",c.move),e[d](\"selectstart\",B),e[d](\"dragstart\",B),f[d](\"selectstart\",B),f[d](\"dragstart\",B),e.style.userSelect=\"none\",e.style.webkitUserSelect=\"none\",e.style.MozUserSelect=\"none\",e.style.pointerEvents=\"none\",f.style.userSelect=\"none\",f.style.webkitUserSelect=\"none\",f.style.MozUserSelect=\"none\",f.style.pointerEvents=\"none\",c.gutter.style.cursor=k.cursor,c.parent.style.cursor=k.cursor,x.call(c)},v=function(){var b=this,c=b.a,d=b.b;b.dragging&&k.onDragEnd&&k.onDragEnd(),b.dragging=!1,a[e](\"mouseup\",b.stop),a[e](\"touchend\",b.stop),a[e](\"touchcancel\",b.stop),b.parent[e](\"mousemove\",b.move),b.parent[e](\"touchmove\",b.move),delete b.stop,delete b.move,c[e](\"selectstart\",B),c[e](\"dragstart\",B),d[e](\"selectstart\",B),d[e](\"dragstart\",B),c.style.userSelect=\"\",c.style.webkitUserSelect=\"\",c.style.MozUserSelect=\"\",c.style.pointerEvents=\"\",d.style.userSelect=\"\",d.style.webkitUserSelect=\"\",d.style.MozUserSelect=\"\",d.style.pointerEvents=\"\",b.gutter.style.cursor=\"\",b.parent.style.cursor=\"\"},w=function(a){var b;this.dragging&&(b=\"touches\"in a?a.touches[0][o]-this.start:a[o]-this.start,b<=this.aMin+k.snapOffset+this.aGutterSize?b=this.aMin+this.aGutterSize:b>=this.size-(this.bMin+k.snapOffset+this.bGutterSize)&&(b=this.size-(this.bMin+this.bGutterSize)),b-=g,y.call(this,b),k.onDrag&&k.onDrag())},x=function(){var b=a.getComputedStyle(this.parent),c=this.parent[n]-parseFloat(b[r])-parseFloat(b[s]);this.size=this.a[f]()[l]+this.b[f]()[l]+this.aGutterSize+this.bGutterSize,this.percentage=Math.min(this.size/c*100,100),this.start=this.a[f]()[p]},y=function(a){z(this.a,a/this.size*this.percentage,this.aGutterSize),z(this.b,this.percentage-a/this.size*this.percentage,this.bGutterSize)},z=function(a,b,c){for(var d=k.elementStyle(l,b,c),e=Object.keys(d),f=0;f<e.length;f++)a.style[e[f]]=d[e[f]]},A=function(a,b){for(var c=k.gutterStyle(l,b),d=Object.keys(c),e=0;e<d.length;e++)a.style[d[e]]=c[d[e]]},B=function(){return!1},C=i(j[0]).parentNode;if(!k.sizes){var D=100/j.length;for(k.sizes=[],m=0;m<j.length;m++)k.sizes.push(D)}if(!Array.isArray(k.minSize)){var E=[];for(m=0;m<j.length;m++)E.push(k.minSize);k.minSize=E}for(m=0;m<j.length;m++){var F,G,H=i(j[m]),I=1==m,J=m==j.length-1,K=k.sizes[m],L=k.gutterSize,M=window.getComputedStyle(C).flexDirection;if(m>0&&(F={a:i(j[m-1]),b:H,aMin:k.minSize[m-1],bMin:k.minSize[m],dragging:!1,parent:C,isFirst:I,isLast:J,direction:k.direction},F.aGutterSize=k.gutterSize,F.bGutterSize=k.gutterSize,I&&(F.aGutterSize=k.gutterSize/2),J&&(F.bGutterSize=k.gutterSize/2),\"row-reverse\"!==M&&\"column-reverse\"!==M||(G=F.a,F.a=F.b,F.b=G)),!b){if(m>0){var N=c.createElement(\"div\");N.className=q,A(N,L),N[d](\"mousedown\",u.bind(F)),N[d](\"touchstart\",u.bind(F)),C.insertBefore(N,H),F.gutter=N}0!==m&&m!=j.length-1||(L=k.gutterSize/2)}if(z(H,K,L),m>0){var O=F.a[f]()[l],P=F.b[f]()[l];O<F.aMin&&(F.aMin=O),P<F.bMin&&(F.bMin=P)}m>0&&t.push(F)}return{setSizes:function(a){for(var b=0;b<a.length;b++)if(b>0){var c=t[b-1];z(c.a,a[b-1],c.aGutterSize),z(c.b,a[b],c.bGutterSize)}},getSizes:function(){for(var b=[],c=0;c<t.length;c++){var d=t[c],e=a.getComputedStyle(d.parent),g=d.parent[n]-parseFloat(e[r])-parseFloat(e[s]);b.push((d.a[f]()[l]+d.aGutterSize)/g*100),c===t.length-1&&b.push((d.b[f]()[l]+d.bGutterSize)/g*100)}return b},collapse:function(a){var b;a===t.length?(b=t[a-1],x.call(b),y.call(b,b.size-b.bGutterSize)):(b=t[a],x.call(b),y.call(b,b.aGutterSize))},destroy:function(){for(var a=0;a<t.length;a++)t[a].parent.removeChild(t[a].gutter),t[a].a.style[l]=\"\",t[a].b.style[l]=\"\"}}};\"undefined\"!=typeof exports?(\"undefined\"!=typeof module&&module.exports&&(exports=module.exports=j),exports.Split=j):a.Split=j}).call(window);\n"
  },
  {
    "path": "gdbgui/templates/dashboard.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\" class=\"text-gray-900 antialiased leading-tight font-sans\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n    <title>gdbgui - dashboard</title>\n    <link rel=\"shortcut icon\" href=\"{{ url_for('static', filename='favicon.ico') }}\" />\n  </head>\n\n  <body class=\"w-screen h-screen bg-gray-300\">\n    <div id=\"dashboard\">Loading dashboard...</div>\n  </body>\n  <script>\n    window.gdbgui_sessions = {{gdbgui_sessions | tojson}}\n    window.csrf_token = {{csrf_token | tojson}}\n    window.default_command = {{default_command | tojson}}\n  </script>\n  <script type=\"text/javascript\" src=\"static/js/dashboard.js?_={{version}}\"></script>\n</html>\n"
  },
  {
    "path": "gdbgui/templates/gdbgui.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n    <title>gdbgui - gdb in a browser</title>\n    <base target=\"_blank\" />\n    <link rel=\"shortcut icon\" href=\"{{ url_for('static', filename='favicon.ico') }}\" />\n  </head>\n  <body style=\"background-color: #333;\">\n    <div id=\"gdbgui\" class=\"splitjs_container\">\n      <div style=\"text-align: center; color: #ccc;\">\n        <h3>Loading application, please wait.</h3>\n        <p>\n          Note: JavaScript and cookies must be enabled.\n        </p>\n      </div>\n    </div>\n  </body>\n\n  <link href=\"static/vendor/css/bootstrap.min.css\" rel=\"stylesheet\" />\n  <link href=\"static/vendor/css/gdbgui_awesomeplete.css\" rel=\"stylesheet\" />\n  <script>\n    initial_data = {{initial_data | tojson}}\n    debug = {{debug | tojson}}\n  </script>\n  <script type=\"text/javascript\" src=\"static/vendor/js/jquery.min.js\"></script>\n  <script type=\"text/javascript\" src=\"static/vendor/js/jquery.flot-0.8.3.min.js\"></script>\n  <script type=\"text/javascript\" src=\"static/vendor/js/bootstrap.min.js\"></script>\n  <script type=\"text/javascript\" src=\"static/vendor/js/lodash.min.js\"></script>\n  <script type=\"text/javascript\" src=\"static/vendor/js/moment.min.js\"></script>\n  <script type=\"text/javascript\" src=\"static/vendor/js/vis-4.20.1.min.js\"></script>\n  <script type=\"text/javascript\" src=\"static/vendor/js/awesomeplete.min.js\"></script>\n  <script type=\"text/javascript\" src=\"static/vendor/js/splitjs.min-1.2.0.js\"></script>\n\n  <script type=\"text/javascript\" src=\"static/js/main.js?_={{version}}\"></script>\n\n  {% for theme in themes %}\n  <link href=\"static/vendor/css/pygments/{{theme}}.css\" rel=\"stylesheet\" />\n  {% endfor %}\n</html>\n"
  },
  {
    "path": "jest.config.js",
    "content": "module.exports = {\n    \"preset\": 'ts-jest',\n    \"verbose\": true,\n    \"testMatch\": [__dirname  + '/gdbgui/src/js/tests/**'],\n    \"transform\": {\n      '^.+\\.(j|t)sx?$': 'ts-jest'\n    }\n}\n"
  },
  {
    "path": "make_executable.py",
    "content": "#!/usr/bin/env python\n\n\"\"\"\nBuild an executable of gdbgui for the current platform\n\"\"\"\n\n\nimport subprocess\nfrom sys import platform\nfrom gdbgui import __version__\nimport hashlib\nfrom pathlib import Path\nimport logging\n\nlogging.basicConfig(level=logging.INFO)\n\n\ndef write_spec_with_gdbgui_version_in_name(spec_path, binary_name):\n\n    spec = f\"\"\"# This pyinstaller spec file was generated by {__file__}\n\nblock_cipher = None\n\n\na = Analysis(['gdbgui/cli.py'],  # noqa\n             pathex=['.'],\n             binaries=[],\n             datas=[\n              ('./gdbgui/static/*', './static'),\n              ('./gdbgui/templates/*', './templates'),\n              ('./gdbgui/VERSION.txt', './')\n            ],\n             hiddenimports=[\n               'engineio.async_threading',\n               'engineio.async_drivers.threading',\n               'pkg_resources.py2_warn',\n               ],\n             hookspath=[],\n             runtime_hooks=[],\n             excludes=[],\n             win_no_prefer_redirects=False,\n             win_private_assemblies=False,\n             cipher=block_cipher,\n             )\n\npyz = PYZ(a.pure, a.zipped_data,  # noqa\n             cipher=block_cipher)\n\nexe = EXE(pyz,  # noqa\n          a.scripts,\n          a.binaries,\n          a.zipfiles,\n          a.datas,\n          name=\"{binary_name}\",\n          debug=False,\n          strip=False,\n          upx=False,\n          runtime_tmpdir=None,\n          console=True)\n\n\"\"\"\n\n    with open(spec_path, \"w+\") as f:\n        f.write(spec)\n\n\ndef verify(binary_path: str, version: str):\n    cmd = [str(binary_path), \"--version\"]\n    logging.info(f\"Smoke test: Running {' '.join(cmd)}\")\n    proc = subprocess.run(cmd, stdout=subprocess.PIPE)\n    output = proc.stdout.decode().strip()\n    if output != __version__:\n        raise ValueError(f\"Expected {__version__}. Got {output}\")\n    logging.info(\"Success!\")\n\n\ndef generate_md5(binary: Path, output_file: Path):\n    checksum = hashlib.md5(binary.read_bytes()).hexdigest()\n    with open(output_file, \"w+\") as f:\n        f.write(checksum + \"\\n\")\n    logging.info(f\"Wrote md5 to {output_file}\")\n\n\ndef main():\n    binary_name = \"gdbgui_%s\" % __version__\n    spec_path = \"gdbgui_pyinstaller.spec\"\n    distpath = Path(\"build/executable\").resolve()\n    extension = \".exe\" if platform == \"win32\" else \"\"\n    binary_path = Path(distpath) / f\"{binary_name}{extension}\"\n\n    write_spec_with_gdbgui_version_in_name(spec_path, binary_name)\n    cmd = [\n        \"pyinstaller\",\n        spec_path,\n        \"--distpath\",\n        distpath,\n    ]\n    logging.info(f\"Running command {' '.join(str(c) for c in cmd)}\")\n    subprocess.run(\n        cmd,\n        check=True,\n    )\n    verify(binary_path, __version__)\n    generate_md5(binary_path, distpath / f\"{binary_name}.md5\")\n    logging.info(f\"Saved executable to {binary_path}\")\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "mkdocs.yml",
    "content": "site_name: gdbgui\nsite_description: A browser-based frontend to gdb (gnu debugger)\n\ntheme:\n  name: \"material\"\nrepo_name: cs01/gdbgui\nrepo_url: https://github.com/cs01/gdbgui\n\nnav:\n  - Home: \"index.md\"\n  - Screenshot Tour: \"screenshots.md\"\n  - Installation: \"installation.md\"\n  - Getting Started: \"gettingstarted.md\"\n  - Examples: \"examples.md\"\n  - Guides: \"guides.md\"\n  - API: \"api.md\"\n  - FAQ: \"faq.md\"\n  - Contributing: \"contributing.md\"\n  - How it Works: \"howitworks.md\"\n  - Contact: \"contact.md\"\n  - Changelog: \"changelog.md\"\n\nmarkdown_extensions:\n  - admonition #  note blocks, warning blocks -- https://github.com/mkdocs/mkdocs/issues/1659\n  - markdown.extensions.codehilite:\n      guess_lang: false\n\nextra:\n  analytics:\n    provider: google\n    property: UA-90243909-2    \n"
  },
  {
    "path": "noxfile.py",
    "content": "import subprocess\nfrom pathlib import Path\nfrom sys import platform\n\nimport hashlib\nimport nox  # type: ignore\nimport glob\n\nnox.options.reuse_existing_virtualenvs = True\nnox.options.sessions = [\"tests\", \"lint\", \"docs\"]\npython_version = [\"3.13\"]\n\nprettier_command = [\n    \"npx\",\n    \"prettier@1.19.1\",\n    \"--parser\",\n    \"typescript\",\n    \"--config\",\n    \".prettierrc.js\",\n    \"gdbgui/src/js/**/*\",\n]\n\ndoc_dependencies = [\".\", \"mkdocs\", \"mkdocs-material\"]\nlint_dependencies = [\n    \"black==22.10.0\",\n    \"vulture\",\n    \"flake8\",\n    \"mypy==1.6.1\",\n    \"check-manifest\",\n]\nvulture_whitelist = \".vulture_whitelist.py\"\nfiles_to_lint = [\"gdbgui\", \"tests\"] + [str(p) for p in Path(\".\").glob(\"*.py\")]\nfiles_to_lint.remove(vulture_whitelist)\npublish_deps = [\"setuptools\", \"wheel\", \"twine\"]\n\n\n@nox.session(reuse_venv=True)\ndef python_tests(session):\n    session.install(\".\", \"pytest\", \"pytest-cov\")\n    tests = session.posargs or [\"tests\"]\n    session.run(\n        \"pytest\", \"--cov=gdbgui\", \"--cov-config\", \".coveragerc\", \"--cov-report=\", *tests\n    )\n    session.notify(\"cover\")\n\n\n@nox.session(reuse_venv=True)\ndef js_tests(session):\n    session.run(\"yarn\", \"install\", external=True)\n    session.run(\"yarn\", \"test\", external=True)\n    session.run(\"yarn\", \"build\", external=True)\n\n\n@nox.session(reuse_venv=True, python=python_version)\ndef tests(session):\n    python_tests(session)\n    js_tests(session)\n\n\n@nox.session(reuse_venv=True)\ndef cover(session):\n    \"\"\"Coverage analysis\"\"\"\n    session.install(\"coverage\")\n    session.run(\n        \"coverage\",\n        \"report\",\n        \"--show-missing\",\n        \"--omit=gdbgui/SSLify.py\",\n        \"--fail-under=20\",\n    )\n    session.run(\"coverage\", \"erase\")\n\n\n@nox.session()\ndef vulture(session):\n    \"\"\"Find dead code\"\"\"\n    session.install(\"vulture\")\n    session.run(\n        \"vulture\",\n        \"--ignore-decorators\",\n        \"@app.*,@socketio.*,@nox.*,@blueprint.*\",\n        *files_to_lint,\n        vulture_whitelist,\n        *session.posargs,\n    )\n\n\n@nox.session()\ndef lint(session):\n    session.install(\".\", *lint_dependencies)\n    session.run(\"black\", \"--check\", *files_to_lint)\n    session.run(\"flake8\", *files_to_lint)\n    session.run(\"mypy\", *files_to_lint)\n    vulture(session)\n    session.run(\n        \"check-manifest\", \"--ignore\", \"gdbgui/static/js/*\", \"--ignore\", \"*pycache*\"\n    )\n    session.run(\"python\", \"setup.py\", \"check\", \"--metadata\", \"--strict\")\n    session.run(*prettier_command, \"--check\", external=True)\n\n\n@nox.session(reuse_venv=True)\ndef autoformat(session):\n    session.install(*lint_dependencies)\n    session.run(\"black\", *files_to_lint)\n    session.run(*prettier_command, \"--write\", external=True)\n\n\n@nox.session(reuse_venv=True)\ndef docs(session):\n    session.install(*doc_dependencies)\n    session.run(\"mkdocs\", \"build\")\n\n\n@nox.session(reuse_venv=True)\ndef develop(session):\n    session.install(\"-e\", \".\")\n    session.run(\"yarn\", \"install\", external=True)\n    print(\"Watching JavaScript file and Python files for changes\")\n    with subprocess.Popen([\"yarn\", \"start\"]):\n        session.run(\"python\", \"-m\", \"gdbgui\")\n\n\n@nox.session(reuse_venv=True)\ndef serve(session):\n    session.install(\"-e\", \".\")\n    session.run(\"python\", \"-m\", \"gdbgui\", *session.posargs)\n\n\n@nox.session(reuse_venv=True)\ndef build(session):\n    \"\"\"Build python distribution (sdist and wheels)\"\"\"\n    session.install(*publish_deps)\n    session.run(\"rm\", \"-rf\", \"dist\", \"build\", external=True)\n    session.run(\"yarn\", external=True)\n    session.run(\"yarn\", \"build\", external=True)\n    session.run(\"python\", \"setup.py\", \"--quiet\", \"sdist\", \"bdist_wheel\")\n    session.run(\"twine\", \"check\", \"dist/*\")\n    for built_package in glob.glob(\"dist/*\"):\n        # ensure we can install the built distributions\n        session.run(\"pip\", \"install\", \"--force-reinstall\", built_package)\n\n\n@nox.session(reuse_venv=True)\ndef publish(session):\n    session.install(*publish_deps)\n    build(session)\n    print(\"REMINDER: Has the changelog been updated?\")\n    session.run(\"python\", \"-m\", \"twine\", \"upload\", \"dist/*\")\n    publish_docs(session)\n\n\n@nox.session(reuse_venv=True)\ndef watch_docs(session):\n    session.install(*doc_dependencies)\n    session.run(\"mkdocs\", \"serve\")\n\n\n@nox.session(reuse_venv=True)\ndef publish_docs(session):\n    session.install(*doc_dependencies)\n    session.run(\"mkdocs\", \"gh-deploy\")\n\n\n@nox.session(reuse_venv=True, python=python_version)\ndef build_executables_current_platform(session):\n    session.run(\"yarn\", \"install\", external=True)\n    session.run(\"yarn\", \"build\", external=True)\n    session.install(\".\", \"PyInstaller==6.14\")\n    session.run(\"python\", \"make_executable.py\")\n    session.notify(\"build_pex\")\n\n\n@nox.session(reuse_venv=True)\ndef build_executables_mac(session):\n    if not platform.startswith(\"darwin\"):\n        raise Exception(f\"Unexpected platform {platform}\")\n    session.notify(\"build_executables_current_platform\")\n\n\n@nox.session(reuse_venv=True)\ndef build_executables_linux(session):\n    if not platform.startswith(\"linux\"):\n        raise Exception(f\"Unexpected platform {platform}\")\n    session.notify(\"build_executables_current_platform\")\n\n\n@nox.session(reuse_venv=True)\ndef build_executable_windows(session):\n    if not platform.startswith(\"win32\"):\n        raise Exception(f\"Unexpected platform {platform}\")\n    session.notify(\"build_executables_current_platform\")\n\n\n@nox.session\ndef build_pex(session):\n    \"\"\"Builds a pex of gdbgui\"\"\"\n    # NOTE: frontend must be built before running this\n    session.install(\"pex\")\n    pex_path = Path(\"build/executable/gdbgui.pex\")\n    session.run(\n        \"pex\",\n        \".\",\n        \"--console-script\",\n        \"gdbgui\",\n        \"--output-file\",\n        str(pex_path),\n        \"--sh-boot\",\n        \"--validate-entry-point\",\n        external=True,\n    )\n    checksum = hashlib.md5(pex_path.read_bytes()).hexdigest()\n    with open(f\"{pex_path}.md5\", \"w+\") as f:\n        f.write(checksum + \"\\n\")\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"gdbgui\",\n  \"version\": \"0.1.0\",\n  \"license\": \"GPL-3.0\",\n  \"scripts\": {\n    \"start\": \"cross-env NODE_OPTIONS=--openssl-legacy-provider NODE_ENV=development webpack --mode development --watch --config webpack.config.js\",\n    \"test\": \"jest\",\n    \"build\": \"cross-env NODE_OPTIONS=--openssl-legacy-provider NODE_ENV=production webpack --mode production --config webpack.config.js\",\n    \"format\": \"prettier ./gdbgui/src/js/** --write\",\n    \"lint\": \"prettier ./gdbgui/src/js/** --check\"\n  },\n  \"dependencies\": {\n    \"react\": \"^16.8\",\n    \"react-dom\": \"^16.4\",\n    \"socket.io\": \"^4.1\",\n    \"socket.io-client\": \"^4.1\",\n    \"statorgfc\": \"^0.1.6\",\n    \"xterm\": \"4.8.0\",\n    \"xterm-addon-fit\": \"^0.4.0\",\n    \"xterm-addon-web-links\": \"^0.4.0\",\n    \"xterm-addon-webgl\": \"^0.4.0\"\n  },\n  \"devDependencies\": {\n    \"@types/jest\": \"^24.0.11\",\n    \"@types/jquery\": \"^3.5.1\",\n    \"@types/react\": \"^16.8.7\",\n    \"@types/react-dom\": \"^16.8.2\",\n    \"@types/socket.io\": \"^2.1.11\",\n    \"@types/socket.io-client\": \"^1.4.33\",\n    \"autoprefixer\": \"^9.8.5\",\n    \"cross-env\": \"^7.0.2\",\n    \"css-loader\": \"^3.6.0\",\n    \"fork-ts-checker-webpack-plugin\": \"^1.0.0\",\n    \"jest\": \"^24.3.1\",\n    \"mini-css-extract-plugin\": \"^0.9.0\",\n    \"postcss-cli\": \"^7.1.1\",\n    \"postcss-loader\": \"^3.0.0\",\n    \"prettier\": \"^1.12.0\",\n    \"style-loader\": \"^1.2.1\",\n    \"tailwindcss\": \"^1.5.1\",\n    \"ts-jest\": \"^24.0.0\",\n    \"ts-loader\": \"^5.3.3\",\n    \"typescript\": \"^3.3.3333\",\n    \"webpack\": \"4.19.0\",\n    \"webpack-cli\": \"^2.0.14\"\n  }\n}"
  },
  {
    "path": "postcss.config.js",
    "content": "const tailwindcss = require(\"tailwindcss\");\nmodule.exports = {\n  plugins: [tailwindcss(\"./tailwind.config.js\"), require(\"autoprefixer\")]\n};\n"
  },
  {
    "path": "requirements.in",
    "content": "Flask-SocketIO>5.3, <6\nFlask-Compress>1.10, <1.11\npygdbmi>=0.10.0.2, <0.11\nPygments>=2.2.0, <3.0\neventlet\n"
  },
  {
    "path": "requirements.txt",
    "content": "#\n# This file is autogenerated by pip-compile with Python 3.14\n# by the following command:\n#\n#    pip-compile\n#\nbidict==0.23.1\n    # via python-socketio\nblinker==1.9.0\n    # via flask\nbrotli==1.1.0\n    # via flask-compress\nclick==8.2.1\n    # via flask\ndnspython==2.7.0\n    # via eventlet\neventlet==0.40.1\n    # via -r requirements.in\nflask==3.1.1\n    # via\n    #   flask-compress\n    #   flask-socketio\nflask-compress==1.10.1\n    # via -r requirements.in\nflask-socketio==5.5.1\n    # via -r requirements.in\ngreenlet==3.2.3\n    # via eventlet\nh11==0.16.0\n    # via wsproto\nitsdangerous==2.2.0\n    # via flask\njinja2==3.1.6\n    # via flask\nmarkupsafe==3.0.2\n    # via\n    #   flask\n    #   jinja2\n    #   werkzeug\npygdbmi==0.10.0.2\n    # via -r requirements.in\npygments==2.19.2\n    # via -r requirements.in\npython-engineio==4.12.2\n    # via python-socketio\npython-socketio==5.13.0\n    # via flask-socketio\nsimple-websocket==1.1.0\n    # via python-engineio\nwerkzeug==3.1.3\n    # via flask\nwsproto==1.2.0\n    # via simple-websocket\n"
  },
  {
    "path": "setup.py",
    "content": "#!/usr/bin/env python\n\nimport os\nimport distutils.text_file  # type: ignore\n\nUSING_WINDOWS = os.name == \"nt\"\nif USING_WINDOWS:\n    raise RuntimeError(\n        \"Windows is not supported at this time. \"\n        + \"Versions lower than 0.14.x. are Windows compatible.\"\n    )\nimport io\nfrom setuptools import find_packages, setup  # type: ignore\n\nCURDIR = os.path.abspath(os.path.dirname(__file__))\n\nEXCLUDE_FROM_PACKAGES = [\"tests\"]\n\nREADME = io.open(os.path.join(CURDIR, \"README.md\"), \"r\", encoding=\"utf-8\").read()\nVERSION = (\n    io.open(os.path.join(CURDIR, \"gdbgui/VERSION.txt\"), \"r\", encoding=\"utf-8\")\n    .read()\n    .strip()\n)\n\nsetup(\n    name=\"gdbgui\",\n    version=VERSION,\n    author=\"Chad Smith\",\n    author_email=\"chadsmith.software@gmail.com\",\n    description=\"Browser-based frontend to gdb. Debug C, C++, Go, or Rust.\",\n    long_description=README,\n    long_description_content_type=\"text/markdown\",\n    url=\"https://github.com/cs01/gdbgui\",\n    license=\"License :: GNU GPLv3\",\n    packages=find_packages(exclude=EXCLUDE_FROM_PACKAGES),\n    include_package_data=True,\n    keywords=[\n        \"gdb\",\n        \"debug\",\n        \"c\",\n        \"c++\",\n        \"go\",\n        \"rust\",\n        \"python\",\n        \"machine-interface\",\n        \"parse\",\n        \"frontend\",\n        \"flask\",\n        \"browser\",\n        \"gui\",\n    ],\n    scripts=[],\n    entry_points={\n        \"console_scripts\": [\n            # allow user to type gdbgui from terminal to automatically launch\n            # the server and a tab in a browser\n            \"gdbgui = gdbgui.cli:main\"\n        ]\n    },\n    zip_safe=False,\n    install_requires=distutils.text_file.TextFile(\n        filename=\"./requirements.txt\"\n    ).readlines(),\n    classifiers=[\n        \"Intended Audience :: Developers\",\n        \"Operating System :: MacOS\",\n        \"Operating System :: Unix\",\n        \"Operating System :: POSIX\",\n        \"Programming Language :: Python\",\n        \"Programming Language :: Python :: 3\",\n    ],\n    python_requires=\">=3.13\",\n    project_urls={\n        \"Documentation\": \"https://cs01.github.io/gdbgui/\",\n        \"Source Code\": \"https://github.com/cs01/gdbgui\",\n        \"Bug Tracker\": \"https://github.com/cs01/gdbgui/issues\",\n    },\n)\n"
  },
  {
    "path": "tailwind.config.js",
    "content": "module.exports = {\n  purge: [\"./gdbgui/src/js/**\", \"./gdbgui/templates/*.html\"],\n  theme: {\n    extend: {}\n  },\n  variants: {},\n  plugins: []\n};\n"
  },
  {
    "path": "tests/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_backend.py",
    "content": "from flask_socketio import send, SocketIO  # type: ignore\nimport pytest  # type: ignore\n\nfrom gdbgui.server.server import run_server\nfrom gdbgui.server.app import app, socketio\nfrom gdbgui import cli\n\nrun_server(testing=True, app=app, socketio=socketio)\n\n\ndef test_connect():\n    test_ws = SocketIO()\n\n    @test_ws.on(\"connect\")\n    def on_connect():\n        send({\"connected\": \"foo\"}, json=True)\n\n    test_ws.init_app(app, cookie=\"foo\")\n    client = test_ws.test_client(app)\n    received = client.get_received()\n    assert len(received) == 1\n    assert received[0][\"args\"] == {\"connected\": \"foo\"}\n\n\n@pytest.fixture\ndef test_client():\n    return app.test_client()\n\n\ndef test_load_main_page(test_client):\n    response = test_client.get(\"/\")\n    assert response.status_code == 200\n    assert \"<!DOCTYPE html>\" in response.data.decode()\n\n\ndef test_load_dashboard(test_client):\n    response = test_client.get(\"/dashboard\")\n    assert response.status_code == 200\n    assert \"<!DOCTYPE html>\" in response.data.decode()\n\n\ndef test_cant_load_bad_url(test_client):\n    response = test_client.get(\"/asdf\")\n    assert response.status_code == 404\n    assert \"404 Not Found\" in response.data.decode()\n\n\ndef test_same_port():\n    run_server(testing=True, app=app, socketio=socketio)\n\n\ndef test_get_initial_binary_and_args():\n    assert cli.get_initial_binary_and_args([], \"./program --args\") == [\n        \"./program\",\n        \"--args\",\n    ]\n    assert cli.get_initial_binary_and_args([\"./program\", \"--args\",], None) == [\n        \"./program\",\n        \"--args\",\n    ]\n"
  },
  {
    "path": "tests/test_cli.py",
    "content": "import sys\nfrom typing import List\nfrom unittest import mock\n\nimport gdbgui\nimport pytest  # type: ignore\n\n\ndef run_gdbgui_cli(gdbgui_args: List[str]):\n    with mock.patch.object(sys, \"argv\", [\"gdbgui\"] + gdbgui_args):\n        return gdbgui.cli.main()  # type: ignore\n\n\n# @pytest.mark.parametrize(\n#     \"argv\",\n#     (\n#         [],\n#         [\"-n\"],\n#         [\"myprogram\"],\n#         [\"-g\", \"gdb -nx\"],\n#         [\"--args\", \"can\", \"pass\", \"many\", \"args\"],\n#     ),\n# )\n# def skip_test_cli(monkeypatch, argv):\n#     # TODO fix this patch\n#     with mock.patch(\"gdbgui.server.server.run_server\") as mock_run_server:\n#         run_gdbgui_cli(argv)\n#         mock_run_server.assert_called_once()\n\n\n@mock.patch(\"gdbgui.server.server.run_server\")\n@pytest.mark.parametrize(\n    \"argv\", ([\"--gdb-cmd\"], [\"myprogram\", \"cannot pass second arg\"])\n)\ndef test_cli_fails(monkeypatch, argv):\n    mock_exit = mock.Mock(side_effect=ValueError(\"raised in test to exit early\"))\n    with mock.patch.object(sys, \"exit\", mock_exit), pytest.raises(\n        ValueError, match=\"raised in test to exit early\"\n    ):\n        run_gdbgui_cli(argv)\n    mock_exit.assert_called_once_with(2)\n\n\n@mock.patch(\"gdbgui.server.server.run_server\")\ndef test_cli_help(monkeypatch):\n    mock_exit = mock.Mock(side_effect=ValueError(\"raised in test to exit early\"))\n    with mock.patch.object(sys, \"exit\", mock_exit), pytest.raises(\n        ValueError, match=\"raised in test to exit early\"\n    ):\n        run_gdbgui_cli([\"--help\"])\n    mock_exit.assert_called_once_with(0)\n"
  },
  {
    "path": "tests/test_ptylib.py",
    "content": "from gdbgui.server import ptylib\n\nimport os\n\n\ndef test_pty():\n    pty = ptylib.Pty()\n    assert pty.name\n    os.write(pty.stdin, \"hello\".encode())\n    output = os.read(pty.stdout, 1024).decode()\n    assert output == \"hello\"\n"
  },
  {
    "path": "tests/test_sessionmanager.py",
    "content": "from gdbgui.server import sessionmanager\n\n\ndef test_SessionManager():\n    manager = sessionmanager.SessionManager()\n    db_session = manager.add_new_debug_session(\n        gdb_command=\"gdb\", mi_version=\"mi3\", client_id=\"test\"\n    )\n    pid = manager.get_pid_from_debug_session(db_session)\n    assert pid\n    dashboard_data = manager.get_dashboard_data()\n    assert len(dashboard_data) == 1\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"allowJs\": true,\n    \"downlevelIteration\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"jsx\": \"react\",\n    \"lib\": [\"dom\", \"es2015\", \"es2016.array.include\"],\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"node\",\n    \"newLine\": \"LF\",\n    \"noEmitOnError\": false,\n    \"outDir\": \"dist\",\n    \"preserveConstEnums\": true,\n    \"skipLibCheck\": true,\n    \"sourceMap\": true,\n    \"strict\": true,\n    \"target\": \"es5\",\n    \"allowSyntheticDefaultImports\": true\n  },\n  \"include\": [\"./gdbgui/src/js\"]\n}\n"
  },
  {
    "path": "tslint.json",
    "content": "{\n  \"env\": {\n    \"browser\": true,\n    \"es6\": true,\n    \"jquery\": true\n  },\n  \"extends\": [\"tslint-config-prettier\"],\n  \"globals\": {\n    \"initial_data\": true,\n    \"module\": true,\n    \"_\": true,\n    \"moment\": true\n  },\n  \"jsRules\": {\n    \"indent\": {\n      \"options\": [\"spaces\"]\n    }\n  },\n  \"rules\": {\n    \"quotemark\": true,\n    \"semicolon\": true\n  }\n}\n"
  },
  {
    "path": "webpack.config.js",
    "content": "const path = require(\"path\");\nconst ForkTsCheckerWebpackPlugin = require(\"fork-ts-checker-webpack-plugin\");\n\nmodule.exports = {\n  entry: {\n    main: \"./gdbgui/src/js/gdbgui.tsx\",\n    dashboard: \"./gdbgui/src/js/dashboard.tsx\"\n  },\n  devtool: \"source-map\",\n  output: {\n    path: path.resolve(__dirname, \"gdbgui/static/js/\")\n  },\n  module: {\n    rules: [\n      {\n        test: /\\.css$/,\n        use: [\"style-loader\", \"css-loader\", \"postcss-loader\"]\n      },\n      {\n        test: /\\.(j|t)sx?$/,\n        use: [\n          {\n            loader: \"ts-loader\",\n            options: {\n              experimentalFileCaching: true,\n              experimentalWatchApi: true,\n              transpileOnly: true\n            }\n          }\n        ],\n        exclude: /node_modules/\n      }\n    ]\n  },\n  plugins: [new ForkTsCheckerWebpackPlugin({})],\n  resolve: {\n    extensions: [\".js\", \".ts\", \".tsx\", \".css\"]\n  }\n};\n"
  }
]